/* SPIN — base stylesheet.
 *
 * Built from the D0 Foundations deliverable
 * (specs/001-food-distribution-coordination/design/D0-foundations/).
 * Token values, the type scale, the spacing scale and the control rules are
 * copied from that deliverable verbatim — do not round or re-derive them.
 *
 * No third-party asset is referenced from this file: no font CDN, no icon
 * service, no remote stylesheet. SC-012 forbids a metered dependency on the
 * event-day path, and a webfont host would be one. D0's stacks are system
 * faces for that reason.
 */

/* ------------------------------------------------------------------ *
 * Tokens — verbatim from D0 § 02 Colour and § 01 Type
 * ------------------------------------------------------------------ */

:root {
  --page: #FBF9F7;  --surface: #FFFFFF;
  --ink: #1A1512;   --ink-muted: #5C534D;
  --line: #E2DBD5;
  --action: #B4472B; --action-press: #93361F; --action-tint: #F6E7E1;
  --on-action: #FFFFFF;  /* ink on an action fill only; identical in both palettes (D0, 2026-09-11) */

  --st-served:   #1E6B45;
  --st-assigned: #1F5FA8;
  --st-waiting:  #6B6259;
  --st-needs:    #C0341A;
  --st-missed:   #4A4550;

  /* Locked in from repeated use across D0-D3 — see D0's tokens-addendum.md */
  --ink-soft:  #463D37;  --ink-faint: #7A716A;
  --wash:      #F0EBE7;
  --field-line:   #C8BFB8;
  --danger:       #8E2F16;
  --disabled-bg:  #EFEAE6; --disabled-ink: #9A918A;
  --st-served-ink: #155334;

  /* D0's warning tier (T152, added 2026-09-13) — the third severity D3 has
   * always drawn (neutral / warning / blocking) and D0's token set did not
   * carry until now. Transcribed verbatim from D0-foundations; the only new
   * hex literals this phase permits. */
  --warn-tint:     #FFF8EA;
  --warn-line:     #E8D5A8;
  --warn-ink:      #7A5310;
  --warn-ink-soft: #5C4718;

  /* The inverted surface (T172/T173, added 2026-09-17 with D4's toast) — a
   * slab that reads *against* the page rather than on it. Unlike
   * --on-action (deliberately identical in both palettes, scoped to text on
   * an --action fill), this pair genuinely inverts: in dark mode the toast
   * becomes a light slab with dark text, because a dark toast on a dark
   * page is not a toast, it is a hole. See HANDBACK.md, "the toast's ink —
   * a new pair, and --on-action deliberately not widened". */
  --invert-fill: #1A1512;
  --invert-ink:  #FFFFFF;

  /* D0 2026-10-14: ink on a pressed/busy primary, ink on any filled state colour, and the
   * translucent ring round a glyph on one. --on-action stays scoped to the action fill. */
  --on-action-press: #FFFFFF;
  --on-state: #FFFFFF;
  --on-state-ring: rgba(255,255,255,.22);

  --font-ui: "Segoe UI", "Helvetica Neue", Helvetica, Roboto, "Noto Sans", Arial, sans-serif;
  --font-figure: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --fs-title:   clamp(2rem, 6vw, 2.75rem);  /* 32 → 44 */
  --fs-heading: 1.75rem;   /* 28 */
  --fs-lead:    1.3125rem; /* 21 — driver page body */
  --fs-body:    1.125rem;  /* 18 */
  --fs-small:   0.9375rem; /* 15 — hard floor */
  --fs-label:   0.8125rem; /* 13 — uppercase labels only */

  /* D0 § 04 — one 4px-rooted scale */
  --s-1: 4px;   /* icon to label */
  --s-2: 8px;   /* inside a control */
  --s-3: 12px;  /* label to field */
  --s-4: 16px;  /* card padding, list gap */
  --s-5: 24px;  /* page gutter, field to field */
  --s-6: 32px;  /* block to block */
  --s-7: 48px;  /* section separation */
  --s-8: 72px;  /* page top and tail */

  --radius: 10px;
  --measure: 720px; /* D0 § 04 — reading surfaces cap here and stay there */
}

@media (prefers-color-scheme: dark) {
  :root {
    --page: #17130F;  --surface: #221C17;
    --ink: #F2EDE9;   --ink-muted: #A79C94;
    --line: #3A322B;
    --action: #E4744F; --action-press: #F08D6B; --action-tint: #3A241C;
    --on-action: #FFFFFF;  /* deliberately identical - 18px bold minimum on a dark action fill */

    --st-served:   #4FBF88;
    --st-assigned: #6BA6E8;
    --st-waiting:  #A79C94;
    --st-needs:    #FF7C5C;
    --st-missed:   #B0A6BF;

    --ink-soft:  #D5CAC2;  --ink-faint: #8C8179;
    --wash:      #2C251F;
    --field-line:   #4C4239;
    --danger:       #D2593C;
    --disabled-bg:  #2A241E; --disabled-ink: #6E645B;
    --st-served-ink: #4FBF88;

    --warn-tint:     #2E2413;
    --warn-line:     #5A4A28;
    --warn-ink:      #F0C775;
    --warn-ink-soft: #E4D3AE;

    /* It inverts — it does not stay dark. */
    --invert-fill: #EDE6E0;
    --invert-ink:  #1A1512;

    --on-action-press: #1A1512;
    --on-state: #1A1512;
    --on-state-ring: rgba(26,21,18,.22);
  }
}

/* ------------------------------------------------------------------ *
 * Reset and page
 * ------------------------------------------------------------------ */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font: 400 var(--fs-body)/1.6 var(--font-ui);
  text-wrap: pretty;
}

h1, h2, h3 { margin: 0; line-height: 1.2; text-wrap: balance; }
h1 { font-size: var(--fs-title); }
h2 { font-size: var(--fs-heading); }
h3 { font-size: var(--fs-lead); }
p  { margin: 0; }

a { color: var(--action); text-underline-offset: 3px; }
a:hover { color: var(--action-press); }

img, svg { max-width: 100%; }

/* Figures — box counts, times, phone numbers. Tabular so columns align. */
.figure {
  font-family: var(--font-figure);
  font-variant-numeric: tabular-nums;
}

.label {
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.lead { font-size: var(--fs-lead); }
.small { font-size: var(--fs-small); }
.muted { color: var(--ink-muted); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

:where(a, button, input, select, textarea):focus-visible {
  outline: 3px solid var(--action-tint);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------ *
 * Layout — D0 § 04. Two breakpoints, no more.
 * ------------------------------------------------------------------ */

.page {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.page__body {
  flex-grow: 1;
  width: 100%;
  padding: var(--s-6) var(--s-4) var(--s-8);
}

/* Under 640px: one column, full-bleed cards, 16px gutters. */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s-4);
}

.stack { display: flex; flex-direction: column; gap: var(--s-5); }
.stack--tight { gap: var(--s-3); }
.stack--loose { gap: var(--s-7); }

.row { display: flex; align-items: center; gap: var(--s-2); }

/* The browser's own `[hidden] { display: none }` is a user-agent rule, and
 * every author rule above that sets `display` (`.stack`, `.row`, and any
 * future one) beats a user-agent rule regardless of specificity — so an
 * element carrying both `hidden` and one of those classes stays visible.
 * `!important` here wins the cascade outright, independent of source order
 * (T135/T137, Phase 14 — found in use: #signin-success and #recovery-form
 * in templates/signin/index.html were both stuck visible by this). */
[hidden] { display: none !important; }

/* 640–1024px: content caps at 720px and centres, 24px gutters. */
@media (min-width: 640px) {
  .page__body {
    max-width: var(--measure);
    margin-inline: auto;
    padding-inline: var(--s-5);
  }
  .card { border-radius: 12px; padding: var(--s-5); }
}

/* Above 1024px: reading surfaces stay at 720px. Only a surface that pairs a
 * list with a map — the live event page, and D2's location roster — widens
 * into that split at 1fr / 420px. Nothing else stretches. */
@media (min-width: 1024px) {
  .page__body--wide {
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 420px;
    gap: var(--s-6);
  }
}

/* ------------------------------------------------------------------ *
 * Controls — D0 § 05, copied verbatim
 * ------------------------------------------------------------------ */

.btn {
  min-height: 3.5rem;          /* 56px — driver-safe */
  padding: 0 1.625rem;
  font: 600 var(--fs-lead)/1 var(--font-ui);
  border: none; border-radius: 10px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  text-decoration: none;
}
.btn--primary   { background: var(--action); color: #fff; }
.btn--primary:hover { background: var(--action-press); color: var(--on-action-press); }
.btn--secondary { background: var(--surface); color: var(--action);
                  border: 2px solid var(--action); }
.btn--quiet     { background: none; color: var(--ink-muted);
                  text-decoration: underline; text-underline-offset: 3px; }
.btn--danger    { background: var(--danger); color: #fff; }
.btn[disabled]  { background: var(--disabled-bg); color: var(--disabled-ink); cursor: not-allowed; }

.field { display: flex; flex-direction: column; gap: var(--s-3); }
.field input, .field textarea, input.setup-field {
  font-size: var(--fs-body); border: 2px solid var(--field-line); border-radius: 10px;
  background: var(--surface); color: var(--ink); font-family: var(--font-ui); }
.field input, input.setup-field { min-height: 3.5rem; padding: 0 .875rem; }
.field textarea { padding: .75rem .875rem; resize: vertical; }
.field input:focus, .field textarea:focus, input.setup-field:focus {
  border-color: var(--action); outline: 3px solid var(--action-tint); }

/* The starting overlay on the event setup page (D3-6): against the viewport, not the
 * (much taller) page, so its card is in view wherever the start button was pressed. */
.starting-overlay {
  position: fixed; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: var(--s-5);
  background: color-mix(in srgb, var(--ink) 42%, transparent); }

/* Box count stepper — a driver never summons a keyboard with cold hands. */
.count { display: flex; gap: .75rem; }
.count button { width: 4.5rem; min-height: 4.5rem; font-size: 2rem;
  background: var(--surface); color: var(--ink);
  border: 2px solid var(--field-line); border-radius: 10px; cursor: pointer; }
.count input  { flex: 1; min-width: 0; text-align: center; min-height: 4.5rem;
  font: 700 2.125rem/1 var(--font-figure); font-variant-numeric: tabular-nums;
  border: 2px solid var(--field-line); border-radius: 10px;
  background: var(--surface); color: var(--ink); }

/* Yes / no — two adjacent targets never sit closer than 8px (D0 § 04). */
.choice { display: flex; gap: var(--s-2); }
.choice > * { flex: 1; }

/* Under 640px the primary action is a full-width button pinned to the
 * bottom of the viewport (D0 § 04). */
@media (max-width: 639px) {
  .action-bar {
    position: sticky; bottom: 0;
    padding: var(--s-3) var(--s-4) calc(var(--s-4) + env(safe-area-inset-bottom));
    background: var(--page);
    border-top: 1px solid var(--line);
  }
  .action-bar .btn { width: 100%; }
}

/* ------------------------------------------------------------------ *
 * The five states — D0 § 03.
 * Shape plus a written label, always. Colour is the third signal,
 * never the only one.
 * ------------------------------------------------------------------ */

.state { display: inline-flex; align-items: center; gap: var(--s-1);
  font-size: var(--fs-small); font-weight: 600; }

.state__glyph { width: 1rem; height: 1rem; flex-shrink: 0; }

.state--served   { color: var(--st-served-ink); }
.state--assigned { color: var(--st-assigned); }
.state--waiting  { color: var(--st-waiting); }
.state--needs    { color: var(--st-needs); }
.state--missed   { color: var(--st-missed); }

/* A `waiting` driver on the live event page (D6's revision, FR-119) — the
 * same blue as `--st-assigned`, drawn hollow, deliberately distinct from
 * `.state--waiting` above, which is a *location's* muted "not reached"
 * treatment. The two must never share a class: a driver's word carries
 * urgency a place's must not (`design/HANDBACK.md`, "Answered
 * 2026-09-25"). */
.state--waiting-driver { color: var(--st-assigned); }

/* D6's revision: past FR-057's interval, ending a waiting driver's night
 * and withdrawing her must not read as two variants of one control.
 * Withdrawal sits below this rule, keeping its own quiet-danger styling. */
.waiting-actions__rule { border-top: 1px solid var(--line); padding-top: var(--s-3); }

/* Waiting for a stop (D5 revision 2, driver page, FR-115) — a pill rather
 * than the plain `.state` label, because this is the one status a driver
 * herself sees about her own night, not a row in someone else's list. The
 * dot pulses so a glance at a locked phone reads "live", not "stuck" — the
 * same reasoning `.skeleton` above already established for this page. */
.pill--waiting {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-1) var(--s-3);
  border-radius: 999px;
  background: var(--action-tint);
  color: var(--action-press);
  font-weight: 700; font-size: var(--fs-small);
  letter-spacing: 0.04em; text-transform: uppercase;
  width: fit-content;
}
.pill--waiting .state__glyph {
  border-radius: 50%;
  background: var(--action);
  animation: pill-waiting-pulse 1.6s ease-in-out infinite;
}
@keyframes pill-waiting-pulse {
  0%, 100% { opacity: 0.3; }
  50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .pill--waiting .state__glyph { animation: none; }
}

/* Map pins are 44px so they can be tapped with cold hands, and the glyph
 * inside is white on every state so it survives a low-contrast background. */
.pin {
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff;
}

/* ------------------------------------------------------------------ *
 * Rows and tables — D0 § 07.
 * The same data twice: wide for a laptop, stacked for a phone.
 * ------------------------------------------------------------------ */

.table { width: 100%; border-collapse: collapse; }
.table th {
  text-align: left; padding: var(--s-3) var(--s-4);
  font-size: var(--fs-label); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-muted);
  border-bottom: 1px solid var(--line);
}
.table td { padding: var(--s-4); border-bottom: 1px solid var(--line); }
.table .num { text-align: right; font-family: var(--font-figure);
  font-variant-numeric: tabular-nums; }

/* Below 640px a row becomes a block: state label first, location as the
 * heading, figures underneath. No horizontal scrolling, no truncated
 * location names, no column a thumb has to find. */
@media (max-width: 639px) {
  .table, .table tbody, .table tr, .table td { display: block; width: 100%; }
  .table thead { display: none; }
  .table tr {
    padding: var(--s-4) 0;
    border-bottom: 1px solid var(--line);
  }
  .table td { border: none; padding: 0 0 var(--s-1); }
  .table td.num { text-align: left; }
  .table td[data-label]::before {
    content: attr(data-label) " ";
    color: var(--ink-muted);
    font-size: var(--fs-small);
  }
}

/* ------------------------------------------------------------------ *
 * Recurring states — D0 § 06. Every surface reuses these seven.
 * Copy is warm, plain, and never blames the person reading it.
 * ------------------------------------------------------------------ */

/* First use / empty */
.empty { display: flex; flex-direction: column; gap: var(--s-4);
  align-items: flex-start; padding: var(--s-7) 0; }

/* Loading — placeholders in the shape of the content, never a spinner over
 * an empty page. Under 300ms, show nothing at all. */
.skeleton {
  background: var(--line);
  border-radius: 6px;
  animation: skeleton-fade 1.4s ease-in-out infinite;
  animation-delay: 300ms;
  opacity: 0;
}
@keyframes skeleton-fade {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 0.9; }
}
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; opacity: 0.7; }
}

/* Saving — the button that was pressed becomes the progress indicator and
 * says what is being saved. Nothing else on the page moves. */
.btn[aria-busy="true"] { background: var(--action-press); color: var(--on-action-press); cursor: progress; }

/* Error — says what happened, what survived, and what to do next. */
.notice {
  border: 1px solid var(--line);
  border-left: 4px solid var(--action);
  border-radius: var(--radius);
  background: var(--surface);
  padding: var(--s-4);
  display: flex; flex-direction: column; gap: var(--s-3);
  align-items: flex-start;
}
.notice--error { border-left-color: var(--st-needs); }

/* A hard gate — D3's "an event is still running" / "over-allocated" / "no
 * drivers" / "no active locations" panels (T055). Built entirely from
 * existing tokens (`--danger`). */
.notice--block {
  border: 2px solid var(--danger);
  border-left: 4px solid var(--danger);
  background: color-mix(in srgb, var(--danger) 8%, var(--surface));
}

/* D0's warning tier (T152) — D3's third severity, between the neutral
 * `.notice` and the red `.notice--block`. A 1px border where `.notice--block`
 * takes 2px: severity reads by weight before it reads by hue. */
.notice--warn {
  border: 1px solid var(--warn-line);
  background: var(--warn-tint);
  color: var(--warn-ink-soft);
}

/* Offline / queued — a dark bar at the top of the driver page, not a dialog:
 * it must never block the next stop. It states the number held locally so a
 * driver can see nothing was lost. */
.offline-bar {
  background: #17130F; color: #F2EDE9;
  padding: var(--s-3) var(--s-4);
  font-size: var(--fs-small);
  display: flex; align-items: center; gap: var(--s-2);
}

/* Not permitted — controls are removed, not disabled: a greyed button
 * invites tapping. The panel explains who can act instead. */
.watching {
  background: var(--action-tint);
  border-radius: var(--radius);
  padding: var(--s-4);
  color: var(--ink);
}

/* ------------------------------------------------------------------ *
 * Map attribution — D0 § 08.
 * Bottom right of the map frame, on every surface that shows a map.
 * 15px minimum, always visible, never behind a tap. It sits inside the
 * map frame so it moves with the map and cannot be laid out away by a
 * surface that forgets it exists.
 * ------------------------------------------------------------------ */

.map { position: relative; overflow: hidden; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line); }

.map__attribution {
  position: absolute; right: var(--s-2); bottom: var(--s-2);
  /* Above Leaflet's panes (popup 700) and its own control corner (1000):
   * OSM's tile policy requires the credit to be visible (D2-6). */
  z-index: 1000;
  font-size: var(--fs-small); /* 15px floor */
  padding: var(--s-1) var(--s-2);
  border-radius: 6px;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  color: var(--ink-muted);
  pointer-events: none;
}

/* Attribution text sits inside an interactive Leaflet control by default;
 * `pointer-events: none` above is overridden here for the one element that
 * must stay clickable (the OpenStreetMap copyright link) — D0 § 08. */
.map__attribution a { pointer-events: auto; }

/* Centred fallback content inside a `.map` frame when tiles fail to load —
 * D2 "Map tiles unavailable". The frame keeps its footprint so the layout
 * doesn't jump, and the list beside it stays the source of truth. */
.map__fallback {
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; text-align: center; gap: var(--s-3);
  min-height: 320px; padding: var(--s-6);
}

/* The roster search draws its own clear (×) button (D2 2026-10-14); Chromium's
 * `type="search"` adds a second one on top of it unless it is switched off. */
#loc-search::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

/* Map pins — D2 roster map, reused wherever a location is plotted. 44px
 * per `.pin` above; colour comes from the same five-state tokens the list
 * view uses, so a pin and its list row always agree. */
.pin--marker {
  border-radius: 50% 50% 50% 4px;
  box-shadow: 0 2px 6px color-mix(in srgb, var(--ink) 28%, transparent);
}
.pin--active  { background: var(--st-served); }
.pin--retired { background: var(--st-missed); }
.pin__dot {
  width: 13px; height: 13px; border-radius: 50%;
  background: currentColor;
}
/* Retired pins are hatched, not just grey — shape carries the state too,
 * never colour alone (D0 § 03). */
.pin__dot--retired {
  background-color: transparent;
  background-image: repeating-linear-gradient(45deg, currentColor 0 2px, transparent 2px 4px);
  border: 2px solid currentColor;
  box-sizing: border-box;
}

/* Small metadata pill — e.g. D2's "Pin placed by hand" — distinct from
 * `.state`, which carries pin/route status. A tag never conveys status by
 * itself; it labels a fact about a record. */
.tag {
  display: inline-flex; align-items: center;
  font-size: var(--fs-label); font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1.5px solid var(--line); border-radius: 999px;
  padding: var(--s-1) var(--s-3);
  color: var(--ink-muted);
}

/* Access notes — D2 § "what it shows". Carries real operational weight, so
 * it is set off from the rest of a location row rather than read as plain
 * text among the other fields. */
.access-note {
  display: flex; gap: var(--s-3);
  background: var(--wash);
  border-left: 3px solid var(--action);
  border-radius: 0 8px 8px 0;
  padding: var(--s-3) var(--s-4);
}
.access-note__label {
  flex: none;
  font-size: var(--fs-label); font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--action-press);
}

/* First use / empty — D0 § 06 draws this as a dashed, centred box, which
 * `.empty` above (spacing/alignment only) does not itself provide. Additive
 * so `.empty`'s existing layout is untouched for any surface already using
 * it. */
.empty__box {
  width: 100%; max-width: 32rem; margin-inline: auto;
  text-align: center;
  border: 2px dashed var(--field-line);
  border-radius: var(--radius);
  padding: var(--s-6) var(--s-5);
}

/* Full-width primary action — D1's sign-in submit, D2's empty-state and
 * panel actions on a narrow viewport. */
.btn--block { width: 100%; }

/* D7-2: the dashboard's two-line history link grows with its label instead of
 * filling the 56px control box. D7 draws 18px 20px; D0 has no such tokens, so
 * the nearest spacing tokens are used (HANDBACK.md). */
.history-link { min-height: 0; padding: var(--s-4) var(--s-5); }

/* D7-4: the record header's link holds one line. */
.record-allevenings { white-space: nowrap; }

/* Invalid field — D1's expired/used code and unrecognised username. Shape
 * (the field itself) and the written message above/below it carry the
 * meaning; this border is the third signal, not the only one (D0 § 03). */
.field input[aria-invalid="true"] { border-color: var(--st-needs); }

/* Narrow, centred card — D1's sign-in panel. `.card` alone stretches to the
 * full reading measure; sign-in is two fields and reads better narrower. */
.auth-card { max-width: 30rem; margin-inline: auto; }

/* ------------------------------------------------------------------ *
 * Overlay panel — D2's add / edit / retire panel over the roster.
 * The native <dialog> element supplies focus trapping and Escape-to-close
 * for free; only its chrome needs resetting to the app's own tokens.
 * ------------------------------------------------------------------ */

dialog.panel {
  border: none;
  border-radius: var(--radius);
  padding: 0;
  background: var(--surface);
  color: var(--ink);
  max-width: min(40rem, calc(100vw - 2 * var(--s-4)));
  width: 100%;
  max-height: min(88vh, 100% - 2 * var(--s-4));
}
dialog.panel::backdrop {
  background: color-mix(in srgb, var(--ink) 42%, transparent);
}
.panel__header {
  display: flex; align-items: baseline; gap: var(--s-3);
  padding: var(--s-5); border-bottom: 1px solid var(--line);
}
.panel__body {
  padding: var(--s-5);
  display: flex; flex-direction: column; gap: var(--s-5);
  overflow-y: auto;
}
.panel__actions {
  display: flex; gap: var(--s-3); flex-wrap: wrap; align-items: center;
  padding-top: var(--s-3); border-top: 1px solid var(--line);
}

/* A confirmation that leads with what is *kept* — D2's retire dialog. Green,
 * because retiring is archiving, not deletion; the primary button stays the
 * normal action colour for the same reason. */
.kept {
  border: 1px solid var(--st-served);
  background: color-mix(in srgb, var(--st-served) 12%, var(--surface));
  border-radius: var(--radius);
  padding: var(--s-4);
}

/* "Driver links" — D6 revision 2, live event page. A quiet underlined text
 * link at the right-hand end of the Drivers heading row, colour and hover
 * transcribed verbatim from the artboard (`color:var(--ink-soft)`,
 * `style-hover="color:var(--ink)"`) rather than the global `a`/`a:hover`
 * treatment, which would tint it the action colour instead. */
.driverlinks-link { color: var(--ink-soft); }
.driverlinks-link:hover { color: var(--ink); }

/* "Fix name or number" — D4 revision 2, hand-out step. A quiet underlined
 * text link at the end of every driver row, sent and unsent alike ("the
 * number that needs fixing is usually one already texted") — never a form
 * on every row, which is D3's treatment and, on a page the lead leaves and
 * returns to twenty times, the wrong kind of busy. Colour and the
 * border-bottom underline transcribed verbatim from the artboard
 * (`color:#5C534D` / `var(--ink-muted)`, `border-bottom:1px solid #C8BFB8`
 * / `var(--field-line)`, hover `#1A1512` / `var(--ink)` on both
 * properties). */
.driver-fix-link {
  padding: 0; font: 600 var(--fs-lead)/1.4 var(--font-ui);
  color: var(--ink-muted); background: none; border: none;
  border-bottom: 1px solid var(--field-line); cursor: pointer;
}
.driver-fix-link:hover { color: var(--ink); border-bottom-color: var(--ink); }

/* ------------------------------------------------------------------ *
 * Admin navigation — D8. One row, on every signed-in admin surface
 * (FR-112). Hidden from print (D4's hand-out sheet must not name pages a
 * driver holding it cannot open) and from the driver, sign-in and public
 * surfaces, which never fill the `admin_nav` block that includes it.
 * ------------------------------------------------------------------ */

.adminnav { background: var(--surface); border-bottom: 1px solid var(--line); }
.adminnav__in {
  max-width: 1080px; margin: 0 auto; padding: 0 var(--s-5);
  display: flex; align-items: stretch; gap: var(--s-5); flex-wrap: wrap;
}
/* D8 revision 3: every item — link, empty-slot sentence and sign out alike
 * — sits on the same two-row grid, so the labels share a baseline. The
 * first drawing centred each item's whole block in the 56px bar, so an
 * item carrying a state line sat noticeably higher than one that did not;
 * the fixed label row plus 4px gap plus state row, centred with
 * `align-content:center`, is what fixes that. An item with no state line
 * (see `.adminnav small`'s absence on such an item) leaves the second row
 * empty rather than collapsing it — that empty row is what holds the
 * labels level with items that do carry one. */
.adminnav a, .adminnav__state {
  display: grid; grid-template-rows: 22px 13px; row-gap: var(--s-1);
  align-content: center; min-height: 3.5rem;
  /* D8 revision 4 (T174/T175, Phase 20) moves the bar onto D0's own scale —
   * "The 17px and 12px of the first drawing were mine and were off the
   * scale; naming two new tokens for one bar would have been the more
   * expensive way to be wrong." var(--fs-body) (18px) at the pinned 22px
   * line-height is 21.6px and fits the 22px track unchanged; the state row
   * widens from 12px to 13px to hold var(--fs-label) (13px) the same way.
   * Do not substitute var(--fs-lead) (21px) here — a 21px label at 1.2 is
   * 25.2px and overflows this fixed 22px row, which is exactly the failure
   * this revision exists to prevent. */
  font: 600 var(--fs-body)/22px var(--font-ui);
  color: var(--ink-muted); text-decoration: none;
}
.adminnav a:hover { color: var(--ink); }
.adminnav a[aria-current] { color: var(--ink); box-shadow: inset 0 -3px 0 var(--action); }
.adminnav small {
  font: 700 var(--fs-label)/13px var(--font-figure); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-faint);
}
.adminnav a.adminnav--action { color: var(--action); }
/* D8-5: D8's `item()` lets the item you are standing on win over the action
 * colour. Without this, first run's Locations stays orange while you are on
 * it: the action rule above is (0,2,1) and comes later than the
 * `a[aria-current]` rule, so it won. (0,3,1) beats it whatever the order. */
.adminnav a.adminnav--action[aria-current] { color: var(--ink); }

/* Sign out — quiet, underlined, behind a rule, far end of the row, never
 * adjacent to "New event" (D8 § 06). A `<button>` inside a `<form>` posting
 * to `POST /admin/signout` (that route returns JSON and 405s a GET), reset
 * to read as the same plain underlined link § 07 draws. */
.adminnav__signout {
  margin-left: auto; display: flex; align-items: stretch;
  border-left: 1px solid var(--line); padding-left: var(--s-5);
}
.adminnav__out {
  display: grid; grid-template-rows: 22px 13px; row-gap: var(--s-1);
  align-content: center; min-height: 3.5rem;
  font: 400 var(--fs-body)/22px var(--font-ui); color: var(--ink-muted);
  text-decoration: underline; text-underline-offset: 4px;
  background: none; border: none; padding: 0; cursor: pointer;
}
.adminnav__out:hover { color: var(--ink); }

/* D8 § 02: in the empty row only, "New event" shortens to "Start one" below
   640px, where it reads as the sentence's own verb. Both labels are in the
   markup — the server cannot know the viewport — so exactly one is shown at
   each width, and the wide one is the default for anything that ignores the
   query (print included). */
.adminnav__narrow { display: none; }

@media (max-width: 639px) {
  .adminnav__in { gap: 10px; padding: 0 12px; }
  .adminnav__mark, .adminnav small { display: none; }
  /* The sub-label row disappears with `.adminnav small` above, so the
     two-row grid degrades to one row here — without this, every item
     would keep the second state row and its 4px gap with nothing in them. */
  .adminnav a, .adminnav__state, .adminnav__out { grid-template-rows: 22px; row-gap: 0; }
  /* .adminnav__out must be listed on every rule here, not only the one
     above: it is a <button>, never matched by `.adminnav a`, so it silently
     keeps whatever a `.adminnav a, .adminnav__state`-only rule sets and
     drifts from its three neighbours — the exact defect recorded in
     CLAUDE.md from T151, recurring here for the same reason. */
  .adminnav a, .adminnav__state, .adminnav__out { min-height: 3rem; font-size: var(--fs-small); }
  /* D8 2026-10-14: the phone row is tight at 320px — 10px has no token on the
     4/8/12/16 scale, so the drawing's literal is used; 16px is --s-4. */
  .adminnav__signout { padding-left: var(--s-4); }
  .adminnav__wide { display: none; }
  .adminnav__narrow { display: inline; }
}

@media print { .adminnav { display: none; } }

/* D8 § 05's public-page line sits outside `.page__body`, so it takes the
 * page gutter itself (D8-6): 16px on a phone, 24px from 640px, held to the
 * reading measure like the content above it. */
.adminfoot { width: 100%; padding-inline: var(--s-4); }
@media (min-width: 640px) {
  .adminfoot { max-width: var(--measure); margin-inline: auto; padding-inline: var(--s-5); }
}
/* On a page whose content is `.page__body--wide` the line follows it: no
 * reading measure, no centring, the same gutter (D8-R1). */
@media (min-width: 1024px) {
  .adminfoot--wide { max-width: none; margin-inline: 0; padding-inline: var(--s-5); }
}

/* ------------------------------------------------------------------ *
 * Public surfaces — D7. No new colour token: every value below reuses
 * the existing D0 tokens verbatim (see design/D7-public/brief.md, which
 * confirms D7 needs none). Only sizing is new, which the "no new hex
 * literal" rule does not constrain.
 * ------------------------------------------------------------------ */

/* The dashboard's headline box count (D7 § 02) — larger than D0's own
 * type scale goes, because this is the one number the whole page exists
 * to state within ten seconds (SC-010). */
.figure--headline {
  font: 700 clamp(2.75rem, 11vw, 5rem)/1 var(--font-figure);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

/* A public event record's row list (D7 § "event record") — the same
 * `--wash` background `_live_state` uses elsewhere, stacked with 1px
 * gaps so each row reads as a distinct line without a ruled table. */
.record-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); padding: var(--s-4);
  background: var(--wash);
}
.record-row--lead {
  background: var(--action-tint);
  border-radius: var(--radius) var(--radius) 0 0;
}
.record-row--last { border-radius: 0 0 var(--radius) var(--radius); }
.record-row .figure { font-weight: 700; font-size: 1.3125rem; }
.record-row--lead .figure { font-size: 2.125rem; color: var(--action-press); }

/* A history row — one evening, tappable, matching `.table` row rhythm on
 * a surface that isn't otherwise a table (dates and a single number, not
 * columns of data). */
.history-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); width: 100%; padding: var(--s-4) 0;
  border-bottom: 1px solid var(--line);
  background: none; border-left: none; border-right: none; border-top: none;
  font: inherit; color: var(--ink); text-align: left; cursor: pointer;
}
.history-row:hover { background: var(--wash); }
.kept__title { font-weight: 700; color: var(--st-served-ink); margin: 0 0 var(--s-2); }

/* Setup page driver row (D3 2026-10-14, item 3). At 560px and up: the name and phone
 * beside the box stepper, one line. Below 560px: line one is name and phone, half each;
 * line two is - / box field / + at full width; the phone hint stays under line one. */
.setup-row {
  display: grid; grid-template-columns: minmax(0, 1fr) 212px; gap: var(--s-3);
  align-items: start; padding: var(--s-4); border-bottom: 1px solid var(--line);
}
.setup-row__who { min-width: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.setup-row__fields { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.setup-row__boxes { display: flex; align-items: center; gap: var(--s-2); }
.setup-row__boxes .btn { flex: none; width: 52px; padding: 0; }
@media (max-width: 559px) {
  .setup-row {
    grid-template-columns: minmax(0, 1fr);
  }
  .setup-row__fields {
    display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2);
  }
  .setup-row__boxes {
    display: grid; grid-template-columns: 3.5rem minmax(0, 1fr) 3.5rem; gap: var(--s-2);
  }
  .setup-row__boxes .btn { width: 100%; }
  .setup-row--head > :last-child { display: none; }
}
