.roster-page { background:var(--page); color:var(--ink-2); font:var(--fs-base)/1.45 var(--font-sans); padding:24px 0 40px; }
.roster-page * { box-sizing:border-box; }
.roster-inner { max-width:var(--admin-max); margin:auto; padding:0 var(--page-pad); }
.roster-page .hidden { display:none !important; }
.roster-page .sr-only { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; }
.roster-page :is(a,button,input,select):focus-visible { outline:2px solid var(--sapd-gold); outline-offset:2px; }
.roster-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:18px; gap:16px; }
.roster-head h1 { font:600 var(--fs-2xl)/1.2 var(--font-sans); color:var(--ink); letter-spacing:var(--ls-title); margin:0; }
.roster-head h1 span { color:var(--ink-3); font-size:var(--fs-lg); font-weight:400; }
.roster-actions { display:flex; gap:10px; }
.roster-page button, .roster-page input, .roster-page select { font:inherit; }
.console-btn { display:inline-flex; align-items:center; justify-content:center; min-height:36px; padding:6px 12px; border:1px solid var(--rule-strong); background:transparent; color:var(--ink-2); font-size:var(--fs-sm); white-space:nowrap; cursor:pointer; }
.roster-page .console-btn:hover { background:var(--page-3); color:var(--ink); }
.console-inner { display:flex; align-items:flex-end; gap:12px; border-bottom:1px solid var(--rule); padding-bottom:16px; }
.console-search-wrap { flex:1; min-width:180px; }
.console-search-wrap label, .roster-control { display:flex; flex-direction:column; gap:5px; color:var(--ink-3); font-size:var(--fs-xs); }
.console-input, .console-select { height:36px; border:1px solid var(--rule-strong); border-radius:0; background:var(--page-2); color:var(--ink-2); padding:0 10px; width:100%; font-size:var(--fs-base) !important; }
.console-input { margin-top:5px; }
#mobileRosterFilters { display:none; }
.rank-group { margin-bottom:28px; }
/* Group: a filled band, the only one on the page, so each group clearly starts. */
.group-header { display:flex; align-items:center; justify-content:space-between; background:var(--page-2); border-top:1px solid var(--rule-strong); min-height:48px; padding:0 12px 0 16px; }
.group-header-left { display:flex; align-items:baseline; gap:12px; }
.group-name { font:600 var(--fs-xl)/1.1 var(--font-condensed); letter-spacing:.005em; color:var(--ink); margin:0; }
.group-count { font-size:var(--fs-sm); color:var(--ink-3); font-variant-numeric:tabular-nums; }
.toggle-group { border:0; background:none; color:var(--ink-3); width:32px; height:32px; display:grid; place-items:center; cursor:pointer; }
.toggle-group svg { width:16px; height:16px; }
.roster-table { width:100%; border-collapse:separate; border-spacing:0; table-layout:fixed; }
/* One visible column header for the whole roster, stuck under the masthead.
   Each group's table keeps its own header row for screen readers only; eight
   copies of the same header was the loudest thing on the page. */
.roster-colhead { position:sticky; top:var(--roster-nav-height,0px); z-index:3; background:var(--page); }
.roster-table .roster-thead-sr th { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
.roster-table col.c-officer { width:40%; }
.roster-table col.c-account { width:34%; }
.roster-table col.c-seen { width:26%; }
/* Page-coloured rather than a --page-2 band: the group header above it is
   the section marker, and a second filled strip directly under it read as
   two competing bands. Opaque so rows pass cleanly beneath when stuck. */
.roster-table th { height:30px; padding:5px 12px; text-align:left; background:var(--page); color:var(--ink-3); font:400 var(--fs-xs)/1.3 var(--font-sans); border-bottom:1px solid var(--rule); }
.roster-table td { height:46px; padding:5px 12px; border-bottom:1px solid var(--rule); overflow:hidden; text-overflow:ellipsis; }
/* Rank break inside a group. Subordinate to the group header (--ink, 600,
   --fs-base) and brighter than a row's own sub-line (--ink-3), so the order
   reads group > rank > officer. Separated by space rather than another rule —
   the rows already carry one each. */
/* height:auto matters — .roster-table td sets 64px for officer rows, and the
   divider inherited it, pushing the first officer past the fold. */
.rank-divider td { height:auto; padding:18px 16px 6px; border:0; }
.roster-table tbody tr.rank-divider:first-child td { padding-top:5px; }
.rank-divider-name { color:var(--ink-3); font-size:11px; font-weight:600; letter-spacing:.1em; text-transform:uppercase; }
.rank-divider-count { margin-left:10px; color:var(--ink-3); font-size:var(--fs-xs); font-variant-numeric:tabular-nums; }
.officer-row { cursor:pointer; }
.officer-row:hover, .officer-row:focus-within { background:var(--page-3); }
/* Discord avatar beside the name; the initial underneath shows through when
   there is no photo or it fails to load. Round, as avatars are allowed to be. */
.tbl-officer { display:flex; align-items:center; gap:12px; min-width:0; }
.tbl-officer-text { min-width:0; }
.tbl-avatar { position:relative; width:32px; height:32px; flex-shrink:0; display:grid; place-items:center; overflow:hidden; border-radius:var(--radius-full); background:var(--page-3); color:var(--ink-3); font:600 var(--fs-xs)/1 var(--font-sans); }
.tbl-avatar img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.card-avatar { width:30px; height:30px; flex-shrink:0; display:grid; place-items:center; overflow:hidden; background:var(--page-2); color:var(--ink-3); font-size:var(--fs-xs); }
.card-avatar img { width:100%; height:100%; object-fit:cover; }
.tbl-name { color:var(--ink); font-family:var(--font-condensed); font-size:19px; font-weight:600; letter-spacing:.01em; display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tbl-name:hover { text-decoration:underline; text-underline-offset:3px; }
.tbl-sub { display:block; color:var(--ink-3); font-size:var(--fs-sm); margin-top:3px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Status only speaks when it is not the normal case. Vacation keeps its
   amber marker because it is a real state; inactive is plain quiet text. */
.officer-status { color:var(--ink-3); }
.officer-status--vacation { color:var(--amber); }
.officer-row.is-inactive .tbl-name { color:var(--ink-2); font-weight:500; }
.tbl-code { color:var(--ink-3); font-weight:500; }
.officer-row:hover .tbl-code { color:var(--ink-2); }
.tbl-main { display:block; color:var(--ink); font-size:var(--fs-sm); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tbl-country { margin-left:12px; color:var(--ink-3); }
.tbl-quiet { color:var(--ink-4); font-size:var(--fs-sm); }
/* Last seen carries recency as brightness, not as a colour. */
.tbl-seen { font-size:var(--fs-sm); font-variant-numeric:tabular-nums; }
.tbl-seen--recent { color:var(--ink); }
.tbl-seen--month { color:var(--ink-2); }
.tbl-seen--old { color:var(--ink-3); }
.tbl-seen--never { color:var(--ink-4); }
.tbl-online { font-size:var(--fs-sm); color:var(--ink); }
.tbl-online::before { content:''; display:inline-block; width:6px; height:6px; border-radius:var(--radius-full); background:var(--green); margin-right:8px; vertical-align:1px; }
.empty-state { padding:36px 16px; text-align:center; border-bottom:1px solid var(--rule); }
.empty-title { font-size:var(--fs-lg); color:var(--ink); margin-bottom:6px; }
.empty-body { color:var(--ink-3); font-size:var(--fs-sm); }
/* The optional view stays available, composed as compact directory entries. */
.cards-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0 24px; }
.rank-band { grid-column:1/-1; padding:9px 0; color:var(--ink-3); font-size:var(--fs-xs); border-bottom:1px solid var(--rule); }
.rank-band-count { margin-left:8px; }
.officer-card { padding:14px 0; border-bottom:1px solid var(--rule); color:var(--ink-2); }
.officer-card:hover { background:var(--page-3); }
.card-head { display:flex; gap:12px; }
.card-name { font-weight:600; color:var(--ink); }
.card-rank, .card-pun { font-size:var(--fs-sm); color:var(--ink-3); }
.card-badges { display:flex; gap:12px; min-height:18px; padding-top:8px; font-size:var(--fs-xs); }
.card-badge.online { color:var(--green); }
.card-meta { display:flex; flex-wrap:wrap; gap:6px 16px; padding-top:8px; font-size:var(--fs-xs); }
.card-meta-row { display:flex; gap:6px; }
.card-meta-row > span:first-child { color:var(--ink-3); }
#backToTop { position:fixed; right:20px; bottom:20px; width:40px; height:40px; border:1px solid var(--rule-strong); background:var(--page-2); color:var(--ink-2); display:none; cursor:pointer; }
#backToTop.is-visible { display:grid; place-items:center; }
#backToTop svg { width:18px; height:18px; }
@media(max-width:1000px) {
  .console-inner { flex-wrap:wrap; }
  .console-search-wrap { flex-basis:240px; }
  /* Columns collapse to zero width rather than display:none, which would
     shift the cells after them under the wrong <col>. */
  .roster-table col.c-account { width:0; }
  .roster-table col.c-officer { width:60%; }
  .roster-table col.c-seen { width:40%; }
  .account-cell, .roster-table .col-account { padding:0 !important; font-size:0; }
  .account-cell > * { display:none; }
  .cards-grid { grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media(max-width:760px) {
  .roster-page { padding-top:18px; }
  .roster-inner { padding:0 var(--page-pad-sm); }
  .roster-head h1 { font-size:var(--fs-xl); }
  .roster-actions { gap:6px; }
  .roster-page :is(button,input,select), .roster-actions a { min-height:44px; }
  .roster-head { gap:8px; }
  .console-inner { gap:10px; }
  .console-search-wrap { flex:1 1 100%; order:-3; }
  .presence-control { flex:1 1 50%; order:-2; }
  #mobileRosterFilters { display:block; order:-1; flex:1 1 30%; }
  .console-inner:not(.filters-open) .secondary-control { display:none; }
  .secondary-control { flex:1 1 40%; }
  .roster-table td, .roster-table th { padding-left:6px; padding-right:6px; }
  .tbl-name { font-size:var(--fs-base); }
  .tbl-avatar { width:28px; height:28px; }
  .tbl-officer { gap:10px; }
  .tbl-sub { font-size:var(--fs-xs); }
  .group-header { padding-left:6px; padding-right:6px; }
  .cards-grid { grid-template-columns:1fr; }
}
@media print {
  body > nav, body > footer, .console-bar, .roster-actions, .toggle-group, #backToTop, .cards-grid { display:none !important; }
  .roster-page { background:white; color:black; padding:0; }
  .roster-page * { color:black !important; background:transparent !important; }
  .roster-inner { max-width:none; padding:0; }
  .roster-page .cards-list.hidden, .group-content { display:block !important; }
  .roster-table tr { break-inside:avoid; }
}

.roster-table td:first-child, .roster-colhead th:first-child { padding-left:16px; }
