/* Integra — admin board (admin.html). The agency-wide view for the operations
   team: agency tiles, the creator roster, the phone fleet. Single column,
   1100px max, compact register. Hairlines and whitespace are the only
   structure: no cards, no shadows, no gradients.

   js/admin.js renders every row into the contracted containers
   (#agency-tiles, #roster-count, #roster-list, #fleet-chips, #fleet-list,
   #fleet-foot), so the classes below are the contract between the two files. */

/* --row-hover lives in tokens.css so the wash follows the theme (#F3F3F6 light
   / #1E1D25 dark). Redeclaring it here would pin this page to the light value,
   since this sheet loads after tokens.css. */

::selection { background: var(--blurple); color: var(--accent-ink); }

/* Subtle page-load fade — opacity only, gated on motion preference. */
@media (prefers-reduced-motion: no-preference) {
  body { animation: admin-page-in 150ms var(--ease); }
  @keyframes admin-page-in { from { opacity: 0; } }
}

.admin-page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* ---- Header ---- */

.admin-header {
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}

/* 1100px chrome, 41px content row: the same bar the setup and tracker pages
   carry, so the wordmark keeps its position and the header keeps its height as
   staff move between the three. 41px is a .btn-sm's own height (13px copy,
   13px padding above and below, 1px border), so a header with buttons and one
   without both measure 74px: 41 + --s4 twice, under the 1px hairline.
   (border-box, so the min-height carries the padding.) Rows gap at --s2, so
   the deliberate phone wrap below is a measured step and not a collapse. */
.admin-header .header-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--s4) var(--s5);
  min-height: calc(41px + var(--s4) * 2);
  display: flex;
  align-items: center;
  gap: var(--s2) var(--s3);
  flex-wrap: wrap;
}

.lockup-link { display: inline-flex; align-items: center; }
/* One height for both themes: light and dark ship the same 1080×267 badged
   lockup, so the identity never moves or changes size across a theme flip. */
.lockup { height: 28px; width: auto; display: block; }

.header-divider {
  width: 1px;
  height: 18px;
  background: var(--rule);
  flex: none;
}

/* margin-left:auto pushes the nav (and the toggle that follows it) to the
   right edge as one group. Under 600px the two are separated deliberately —
   see the phone header block at the end of the responsive section. */
.header-links {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--s2);
}

.admin-header .theme-toggle { margin-left: var(--s2); }

/* Compact button size — same values as the app shell's .btn-sm
   (app.css is not loaded on this page). */
.btn-sm { padding: 13px 16px; font-size: 13px; }

/* ---- Main column ---- */

.admin-main {
  flex: 1;
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--s6) var(--s5) var(--s8);
}

@media (min-width: 600px) {
  .admin-main { padding-top: var(--s7); }
}

.page-title {
  font-weight: 500;
  font-size: 24px;
  letter-spacing: -0.005em;
  line-height: 1.25;
  margin: 0 0 var(--s2);
}

.page-sub {
  font-size: 14px;
  margin: 0 0 var(--s6);
}

/* Page-level notes — demo mode, creator access, promote-first-admin hint.
   While #admin-note carries content the board stays out of the flow: the note
   replaces the sections per the access contract. */
.admin-note {
  color: var(--graphite);
  font-size: 15px;
  max-width: var(--measure);
  margin: 0 0 var(--s5);
}

/* The note's prose and its one action are separate blocks: the container
   already carries the bottom margin, so the prose adds none of its own, and the
   action line sits a clear --s4 below the last sentence rather than trailing
   off the end of it. */
.note-prose { margin: 0; }

.note-action {
  margin: var(--s4) 0 0;
  font-size: 15px;
}

#admin-note:not(:empty) { margin-bottom: var(--s5); }

#admin-note:not(:empty) ~ section { display: none; }

/* ---- Sections ---- */

.admin-section {
  border-top: 1px solid var(--rule);
  padding: var(--s5) 0;
}

.section-label { display: block; margin: 0 0 var(--s3); }

/* Shared quiet copy: empty states, footers, inline errors. */
.adm-empty {
  color: var(--graphite);
  font-size: 14px;
  margin: var(--s3) 0 0;
}

.adm-foot {
  font-size: 12px;
  color: var(--graphite);
  margin: var(--s3) 0 0;
  max-width: none;
}

.adm-foot:empty { margin: 0; }

.adm-error {
  color: var(--fault-text);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  margin: var(--s3) 0 0;
  max-width: var(--measure);
}

/* ---- Agency tiles ---- */
/* Same visual language as the dashboard stat tiles: hairline-separated
   columns, no boxes. app.css is not loaded here, so the values live locally. */

#agency-tiles {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  min-height: 96px; /* label + 24px figure + sub line, reserved pre-render */
}

.stat-tile {
  min-width: 0;
  padding: var(--s3) var(--s3) var(--s3) 0;
}

.stat-tile + .stat-tile {
  border-left: 1px solid var(--rule);
  padding-left: var(--s3);
}

.stat-value {
  font-weight: 500;
  font-size: 24px;
  line-height: 1.2;
  margin-top: var(--s2);
  overflow-wrap: anywhere;
}

.stat-sub {
  font-size: 13px;
  color: var(--graphite);
  margin-top: var(--s1);
}

/* ---- Agency growth ---- */
/* The dashboard's chart register (app.css), carried over: admin.html does not
   load app.css, so the toggle classes live here too, value for value. */

.growth-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3) var(--s4);
  flex-wrap: wrap;
  margin-bottom: var(--s4);
}

.growth-toggles {
  display: flex;
  gap: var(--s3) var(--s5);
  flex-wrap: wrap;
}

.toggle-group { display: flex; gap: var(--s3); }

.toggle-btn {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  position: relative;
  min-height: 40px;
  min-width: 40px;
  display: inline-flex;
  align-items: flex-end;
  justify-content: center;
  padding: 12px 6px 4px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--graphite);
  transition: color var(--t-fast) var(--ease);
}

/* Active underline slides/fades in over 150ms instead of snapping. The
   transparent 2px border above reserves its slot; ::after overlays it. */
.toggle-btn::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: var(--blurple);
  opacity: 0;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}

.toggle-btn:hover { color: var(--ink); }
.toggle-btn[aria-pressed="true"] { color: var(--ink); }
.toggle-btn[aria-pressed="true"]::after { opacity: 1; transform: scaleX(1); }

#agency-growth { min-height: 260px; }

/* ---- Tracker health ---- */
/* The collector's own record. One lead sentence stating the fact, then a
   hairline table of the last runs; a row expands in place into the per-account
   detail the agent wrote. No boxes — the expansion is a hairline sub-list. */

.health-summary {
  font-size: 15px;
  line-height: 1.5;
  max-width: var(--measure);
  margin: 0 0 var(--s4);
}

.health-summary:empty { margin: 0; }

/* Figures inside the sentence stay mono at the sentence's own size. */
.health-summary .data { font-size: 14px; }

.health-summary.is-error { color: var(--fault-text); }

/* A run that is neither wrong nor finished: the hollow dot, graphite ring
   only. Same 10px circle as every other status dot on the page. */
.status-idle { background: transparent; }

/* One grid template for the head and every run line. */
.run-head,
.run-line {
  display: grid;
  grid-template-columns: 10px minmax(96px, 1.4fr) 84px 84px 88px 76px 68px 16px;
  align-items: center;
  column-gap: var(--s4);
}

.run-head {
  padding: 0 0 var(--s2);
  border-bottom: 1px solid var(--rule);
}

.run-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.run-row + .run-row { border-top: 1px solid var(--rule); }

/* The whole line is the control: one button, no nested interactive targets.
   The hover wash sits on the button rather than the row, so an expanded run
   washes the line the pointer is on and never the detail below it. */
.run-line {
  appearance: none;
  background: none;
  border: 0;
  border-radius: var(--radius);
  position: relative;
  z-index: 0;
  width: 100%;
  margin: 0;
  padding: var(--s3) 0;
  font: inherit;
  font-size: 13px;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.run-line::before {
  content: '';
  position: absolute;
  inset: 0 calc(-1 * var(--s3));
  z-index: -1;
  border-radius: var(--radius);
  pointer-events: none;
  transition: background-color var(--t-fast) var(--ease);
}

.run-line:hover::before { background: var(--row-hover); }

.run-started {
  font-size: 13px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.run-num {
  text-align: right;
  white-space: nowrap;
}

.run-line .run-num { font-size: 13px; }

/* The duration is a fact about the run rather than a count of anything —
   graphite, like the roster's last-post column. */
.run-line .run-dur { color: var(--graphite); }

.run-dot-cell { display: block; }

.run-unit {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--graphite);
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  clip: rect(0 0 0 0);
  overflow: hidden;
  white-space: nowrap;
}

.run-caret {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  width: 16px;
  height: 16px;
  color: var(--graphite);
  transition: transform var(--t-fast) var(--ease);
}

.run-caret svg { width: 16px; height: 16px; display: block; }

.run-line[aria-expanded="true"] .run-caret { transform: rotate(90deg); }

/* Expansion — hairline sub-list, opacity-only reveal, same pattern as the
   fleet's assign form. */
/* Indented under the started column on the left, and stopping short of the
   caret column on the right, so the sub-list sits inside the table's figures
   rather than running past them. The top padding keeps the first line clear
   of the line's focus ring, which sits 2px outside the button above it. */
.run-detail {
  padding: var(--s2) calc(16px + var(--s4)) var(--s3) var(--s5);
}

@media (prefers-reduced-motion: no-preference) {
  .run-detail { animation: admin-reveal 150ms var(--ease); }
}

/* The window a run covered and what it found in it — context above the
   account rows, not a figure anyone reads twice. */
.run-context {
  font-size: 12px;
  color: var(--graphite);
  margin: 0 0 var(--s2);
  overflow-wrap: anywhere;
}

.run-acct-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule);
}

.run-acct { padding: var(--s3) 0; }

.run-acct + .run-acct { border-top: 1px solid var(--rule); }

/* The run line's own template, minus the caret column the detail's right
   padding already drops — so the sub-list's columns are the table's columns
   and no field reads as the value of a heading it has nothing to do with.
   Every column is fixed or fractional — nothing sized to its own content, so
   the rows line up with each other even though each is its own grid. */
.run-acct-line {
  display: grid;
  grid-template-columns: 10px minmax(0, 1.4fr) 84px 84px 88px 76px 68px;
  align-items: center;
  column-gap: var(--s4);
  row-gap: var(--s1);
}

/* Placed by hand: the handle under STARTED, the creator across DURATION and
   ACCOUNTS, the status word ending on the BLOCKED column it reports against.
   The figures are a sentence of facts rather than a column value, so they
   take the next line at the handle's left edge, where the note joins them. */
.run-acct-name {
  grid-column: 2;
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
}

.run-acct-name .fleet-glyph { color: var(--ink); }

.run-acct-handle {
  font-size: 13px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.run-acct-creator {
  grid-column: 3 / span 2;
  font-size: 13px;
  color: var(--graphite);
  min-width: 0;
  overflow-wrap: anywhere;
}

.run-acct-status {
  grid-column: 5 / span 2;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--graphite);
  text-align: right;
}

.run-acct-figures {
  grid-column: 2 / span 6;
  font-size: 13px;
  color: var(--graphite);
}

.run-acct-figures:empty { display: none; }

/* The reason, in plain words — the whole point of keeping the detail. */
.run-acct-note {
  font-size: 13px;
  color: var(--graphite);
  line-height: 1.5;
  max-width: var(--measure);
  margin: var(--s1) 0 0 calc(10px + var(--s4));
}

.run-detail .adm-empty { margin: var(--s3) 0 0; }

/* ---- Roster ---- */

.roster-count {
  font-size: 12px;
  color: var(--graphite);
  margin: 0 0 var(--s3);
  max-width: none;
}

.roster-count:empty { margin: 0; }

.roster-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* One grid template for the head and every row, so the columns line up.
   Eight columns wide; below 980px the Assigned-to cell drops to its own line
   (the media block after the unit label) and the template returns to seven. */
.roster-head,
.roster-row {
  display: grid;
  grid-template-columns:
    minmax(120px, 1.6fr) minmax(96px, 1fr)
    84px 84px 72px 96px minmax(120px, 1.1fr) 132px;
  align-items: center;
  column-gap: var(--s4);
}

.roster-head {
  padding: 0 0 var(--s2);
  border-bottom: 1px solid var(--rule);
}

.roster-row {
  position: relative;
  z-index: 0;
  padding: var(--s3) 0;
  font-size: 15px;
}

.roster-row + .roster-row { border-top: 1px solid var(--rule); }

/* Hover wash — rows are records, not buttons, so the cursor stays default.
   The wash bleeds var(--s3) past the text edge on a non-interactive pseudo
   layer, so the hairlines above and below keep exactly to the content column. */
.roster-row::before {
  content: '';
  position: absolute;
  inset: 0 calc(-1 * var(--s3));
  z-index: -1;
  border-radius: var(--radius);
  pointer-events: none;
  transition: background-color var(--t-fast) var(--ease);
}

.roster-row:hover::before { background: var(--row-hover); }

.roster-name {
  font-weight: 600;
  font-size: 15px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.roster-handle {
  font-size: 13px;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Alignment is shared by the head and the rows; the 13px figure size is
   scoped to the rows so the head keeps the 12px .label register. */
.roster-num,
.roster-last {
  text-align: right;
  white-space: nowrap;
}

.roster-row .roster-num,
.roster-row .roster-last { font-size: 13px; }

.roster-row .roster-last { color: var(--graphite); }

/* Per-figure unit label. The column head carries it for sighted users on wide
   screens, so here it is hidden the accessible way (base.css .visually-hidden
   values) and returns as visible copy when the head drops out under 760px. */
.roster-unit {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--graphite);
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  clip: rect(0 0 0 0);
  overflow: hidden;
  white-space: nowrap;
}

/* ---- Assigned-to (who runs whom) ---- */
/* The select is the admin's control; a manager gets the name as quiet mono
   text. The saved-note and error line reuse the fleet's confirmation set. */
.roster-assigned {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
}

.roster-assigned select {
  padding: 6px 8px;
  font-family: var(--font-mono);
  font-size: 13px;
  min-width: 0;
  max-width: 200px;
  flex: 0 1 auto;
}

.roster-assigned .assigned-name { font-size: 13px; }

/* Between 761px and here the eight-column grid does not fit, so the
   assignment drops to a line of its own under the row's figures, its unit
   label visible — the same device the fully wrapped rows use below 760px.
   The 900px block's tighter seven-column template composes with this. */
@media (max-width: 980px) {
  .roster-head .roster-assigned-head { display: none; }

  .roster-head,
  .roster-row {
    grid-template-columns:
      minmax(120px, 1.6fr) minmax(96px, 1fr)
      84px 84px 72px 96px 132px;
  }

  .roster-row { row-gap: var(--s1); }

  .roster-row .roster-assigned {
    grid-column: 1 / -1;
    flex: 1 1 100%; /* grid ignores this; the sub-760 flex rows use it */
  }

  .roster-row .roster-assigned .roster-unit {
    position: static;
    width: auto;
    height: auto;
    margin: 0 var(--s1) 0 0;
    clip: auto;
    overflow: visible;
  }
}

/* Two links per creator — the report reads the record, setup edits it. They
   sit as one right-aligned group so the column edge stays straight. */
.roster-actions {
  display: inline-flex;
  align-items: center;
  gap: var(--s3);
  justify-self: end;
  white-space: nowrap;
}

.roster-action {
  font-size: 13px;
  font-weight: 500;
}

/* ---- Fleet ---- */

/* Filter chips — the label-on-hairline chip used by the records table
   (assets/css/table.css is not loaded on this page). */
.adm-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin: 0 0 var(--s4);
}

.adm-chip {
  appearance: none;
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 7px 12px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--graphite);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}

.adm-chip:hover { color: var(--ink); border-color: var(--graphite); }

.adm-chip[aria-pressed="true"] {
  color: var(--blurple-text);
  border-color: var(--blurple-text);
}

.fleet-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.fleet-row {
  position: relative;
  z-index: 0;
  padding: var(--s3) 0;
}

.fleet-row + .fleet-row { border-top: 1px solid var(--rule); }

.fleet-row::before {
  content: '';
  position: absolute;
  inset: 0 calc(-1 * var(--s3));
  z-index: -1;
  border-radius: var(--radius);
  pointer-events: none;
  transition: background-color var(--t-fast) var(--ease);
}

.fleet-row:hover::before { background: var(--row-hover); }

.fleet-line {
  display: grid;
  grid-template-columns:
    10px minmax(130px, max-content) minmax(96px, 1fr)
    minmax(120px, 1fr) max-content max-content;
  align-items: center;
  column-gap: var(--s4);
}

.fleet-label {
  font-size: 13px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.fleet-creator {
  font-weight: 500;
  font-size: 14px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.fleet-acct {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
}

.fleet-glyph {
  display: inline-flex;
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--ink);
}
.fleet-glyph svg { width: 16px; height: 16px; display: block; }

.fleet-handle {
  font-size: 13px;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Last seen — plain graphite, including the stale suffix. Status colour is
   reserved for the status dot, which already carries the account's status. */
.fleet-seen {
  font-size: 13px;
  color: var(--graphite);
  text-align: right;
  white-space: nowrap;
}

.fleet-assign-btn {
  appearance: none;
  background: none;
  border: 0;
  border-radius: var(--radius);
  padding: 0;
  margin: 0;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  justify-self: end;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--blurple-text);
  cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}

.fleet-assign-btn:hover { color: var(--blurple-text-hover); }

/* Assign form — expands in place under a hairline, same pattern as the setup
   page's inline forms. Opacity-only reveal, no height animation. */
.fleet-assign {
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--s3) var(--s4);
}

@media (prefers-reduced-motion: no-preference) {
  .fleet-assign { animation: admin-reveal 150ms var(--ease); }
  @keyframes admin-reveal { from { opacity: 0; } }
}

.fleet-assign .field { margin: 0; }

.fleet-assign label {
  font-size: 13px;
  font-weight: 500;
  margin-bottom: var(--s1);
}

.fleet-assign input,
.fleet-assign select {
  width: auto;
  min-width: 220px;
  padding: 10px 12px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 14px;
}

.fleet-assign select { min-width: 140px; }

.fleet-assign-actions {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
}

/* "Saved HH:MM" — inline mono confirmation, same register as setup. */
.saved-note {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--graphite);
  font-size: 13px;
}

@media (prefers-reduced-motion: no-preference) {
  .saved-note.is-shown { animation: admin-confirm-in 120ms var(--ease); }
  @keyframes admin-confirm-in { from { opacity: 0; } }
}

.fleet-assign .adm-error {
  flex-basis: 100%;
  margin: 0;
}

/* ---- Responsive ---- */

@media (max-width: 900px) {
  .roster-head,
  .roster-row {
    grid-template-columns:
      minmax(110px, 1.4fr) minmax(88px, 1fr)
      72px 72px 64px 88px 124px;
    column-gap: var(--s3);
  }

  .run-head,
  .run-line {
    grid-template-columns: 10px minmax(88px, 1.3fr) 76px 76px 80px 68px 60px 16px;
    column-gap: var(--s3);
  }

  .run-acct-line {
    grid-template-columns: 10px minmax(0, 1.3fr) 76px 76px 80px 68px 60px;
    column-gap: var(--s3);
  }

  /* The caret column the detail drops is the caret plus this gap, not the
     wider one — otherwise the sub-list stops 4px short of the ERRORS edge.
     The note is indented past the same narrower dot column. */
  .run-detail { padding-right: calc(16px + var(--s3)); }
  .run-acct-note { margin-left: calc(10px + var(--s3)); }

  .fleet-line {
    grid-template-columns:
      10px minmax(120px, max-content) minmax(88px, 1fr)
      minmax(110px, 1fr) max-content max-content;
    column-gap: var(--s3);
  }
}

@media (max-width: 760px) {
  #agency-tiles { grid-template-columns: 1fr 1fr; }

  .stat-tile:nth-child(odd) { border-left: 0; padding-left: 0; }
  .stat-tile:nth-child(-n+2) { padding-top: var(--s2); }
  .stat-tile:nth-child(n+3) { border-top: 1px solid var(--rule); padding-bottom: var(--s2); }

  /* Rows reflow to wrapped lines; each figure carries its own label, so the
     column head is no longer needed. */
  .roster-head,
  .run-head { display: none; }

  .roster-row,
  .fleet-line {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--s1) var(--s4);
  }

  .roster-handle { flex: 1 1 auto; }

  .roster-num,
  .roster-last,
  .run-num { text-align: left; }

  .roster-unit,
  .run-unit {
    position: static;
    width: auto;
    height: auto;
    margin: 0 var(--s1) 0 0;
    clip: auto;
    overflow: visible;
  }

  .roster-actions { margin-left: auto; }

  /* The run row keeps a grid here rather than wrapping: the dot sits in its
     own gutter and the caret is pinned to the right edge, so the six figures
     pair off two to a line — one left edge for the whole row, and BLOCKED and
     ERRORS share the last line instead of ERRORS wrapping alone. */
  .run-line {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: baseline;
    column-gap: var(--s4);
    row-gap: var(--s1);
    padding-left: calc(10px + var(--s3));
    padding-right: calc(16px + var(--s3));
  }

  /* Centred on the first line's text, not on the row — the row is three lines
     tall and the dot belongs to the time at the top of it. */
  .run-line .status-dot {
    position: absolute;
    left: 0;
    top: calc(var(--s3) + 4px);
  }

  .run-line .run-caret {
    position: absolute;
    right: 0;
    top: var(--s3);
  }

  .run-detail { padding-left: 0; padding-right: 0; }

  /* Same gutter trick as the run line: the dot sits beside the account rather
     than inside its wrap flow, so the handle, the figures and the note all
     start on one edge instead of three. */
  .run-acct-line {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s1) var(--s3);
    padding-left: calc(10px + var(--s3));
  }

  .run-acct-line .status-dot {
    position: absolute;
    left: 0;
    top: 6px; /* half the 21px first line, less half the 10px dot */
  }

  .run-acct-creator { flex: 1 1 auto; }
  .run-acct-note { margin-left: calc(10px + var(--s3)); }

  .fleet-line { align-items: center; }
  .fleet-creator { flex: 1 1 auto; }
  .fleet-seen { text-align: left; white-space: normal; }
  .fleet-assign-btn { margin-left: auto; }

  .fleet-assign input,
  .fleet-assign select { min-width: 0; width: 100%; }

  .fleet-assign .field { flex: 1 1 200px; }
}

/* Phone header: the wrap is declared, not left to chance. Row 1 is the lockup,
   the eyebrow, and the toggle held at the right edge; row 2 is both page links,
   flush left under the lockup. Without the explicit order the row broke in a
   different place in each theme (the wider light lockup pushed the whole nav
   down, the dark one left the toggle stranded on its own line). Now the two
   themes lay out identically at every width, because they now also carry the
   same 113px lockup. */
@media (max-width: 600px) {
  .admin-header .header-links {
    order: 3;
    flex: 1 0 100%;
    margin-left: 0;
  }

  .admin-header .theme-toggle {
    order: 2;
    margin-left: auto;
  }

  /* Two buttons plus the 8px gap fit inside a 360px column at this size. */
  .admin-header .btn-sm { padding: 10px 12px; font-size: 12px; }
}

/* ---- Footer ---- */

.admin-footer { border-top: 1px solid var(--rule); }

.admin-footer .footer-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--s4) var(--s5);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.admin-footer .tagline { margin: 0; }
.admin-footer img { display: block; width: 16px; height: 16px; }

/* ---- People ---- */
/* The CMS permission tiers, one hairline row per person. Same visual language
   as the roster: a shared grid for the head and the rows, a non-interactive
   hover wash, and each figure reflowing under its own label below 760px. */

.people-sub {
  font-size: 12px;
  color: var(--graphite);
  margin: 0 0 var(--s3);
  max-width: none;
}
.people-sub:empty { margin: 0; }

.people-list-ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.people-head,
.people-row {
  display: grid;
  grid-template-columns: minmax(150px, 1.6fr) minmax(120px, 1fr) minmax(260px, 1.3fr);
  align-items: center;
  column-gap: var(--s4);
}

.people-head {
  padding: 0 0 var(--s2);
  border-bottom: 1px solid var(--rule);
}

.people-row {
  position: relative;
  z-index: 0;
  padding: var(--s3) 0;
  font-size: 15px;
}

.people-row + .people-row { border-top: 1px solid var(--rule); }

.people-row::before {
  content: '';
  position: absolute;
  inset: 0 calc(-1 * var(--s3));
  z-index: -1;
  border-radius: var(--radius);
  pointer-events: none;
  transition: background-color var(--t-fast) var(--ease);
}

.people-row:hover::before { background: var(--row-hover); }

.people-name {
  font-weight: 600;
  font-size: 15px;
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Two-letter initials, mono on a hairline — the same quiet marker the team
   page uses, so the two people views read as one system. */
.people-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--graphite);
}

.people-handle {
  font-size: 13px;
  color: var(--graphite);
  min-width: 0;
  overflow-wrap: anywhere;
}

.people-role {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  justify-self: start;
  min-width: 0;
}

.people-role select {
  padding: 8px 10px;
  font-family: var(--font-mono);
  font-size: 14px;
  min-width: 140px;
}

.people-role .btn-sm { padding: 8px 14px; }

/* The read-only render: a manager viewing the list, or the admin's own row. */
.people-role-label { color: var(--ink); }
.people-you {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--graphite);
}

.people-error {
  flex-basis: 100%;
  margin: 0;
}

@media (max-width: 900px) {
  .people-head,
  .people-row {
    grid-template-columns: minmax(130px, 1.4fr) minmax(96px, 1fr) minmax(240px, 1.2fr);
    column-gap: var(--s3);
  }
}

@media (max-width: 760px) {
  /* Rows reflow to wrapped lines; the head is no longer needed. */
  .people-head { display: none; }

  .people-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--s1) var(--s4);
  }

  .people-handle { flex: 1 1 auto; }

  .people-role {
    flex-basis: 100%;
    align-items: center;
  }

  .people-role select { flex: 1 1 160px; min-width: 0; }
}
