/*
 * Rodeo Express — design system foundation (spec section 9).
 *
 * The three environmental facts in spec 1.2 drive everything here: users are
 * outdoors in February weather, on a phone, with cold or gloved hands. So
 * targets are large, contrast is high, nothing depends on hover, and the dark
 * theme is a requirement rather than a nicety — a white screen at 02:00 on a
 * dark tarmac destroys night vision.
 *
 * This file carries the tokens and the pieces the shipped screens use. Screen
 * specific styles arrive with their screens.
 */

/* ---------------------------------------------------------------------------
   Tokens
   --------------------------------------------------------------------------- */

:root {
    /* Brand palette, spec 9.1. Contrast figures are against white. */
    --rodeo-orange: #EF7622;  /* ~2.9:1 — accent only, never white text on it */
    --action-orange: #B85416; /* ~4.9:1 — buttons, white text is fine */
    --rodeo-brown: #7F5E46;   /* ~5.9:1 — body text, icons */
    --rodeo-dust: #C9B29B;    /* surfaces and borders, never text */
    --dust-light: #F2EAE2;    /* page and callout surfaces */
    --ink: #2B2018;           /* ~14:1 — primary text, and text on orange */

    /* Semantic tokens. Screens use these, not the palette above, so the dark
       theme is a matter of redefining a dozen values. */
    --surface: #FFFFFF;
    --surface-raised: var(--dust-light);
    --surface-sunken: #E7DACE;
    --border: var(--rodeo-dust);
    --text: var(--ink);
    --text-muted: var(--rodeo-brown);
    --accent: var(--rodeo-orange);
    --accent-text: var(--ink);
    --action-bg: var(--action-orange);
    --action-text: #FFFFFF;

    /* Status colours. Checked in and checked out must be tellable apart at
       arm's length in sunlight, and not by hue alone — every use pairs them
       with a word. */
    --ok: #2F6B3A;
    --ok-surface: #E4F0E5;
    --warn: #8A5A00;
    --warn-surface: #FBF0DA;
    --danger: #A32B1C;
    --danger-surface: #F8E3DF;

    /* Touch and type, spec 9.3. */
    --touch-min: 56px;      /* every interactive target */
    --touch-primary: 64px;  /* primary actions and the PIN keypad */
    --touch-gap: 8px;       /* so a mis-tap does not hit the wrong control */
    --tile-height: 72px;    /* main menu tiles */
    --font-status: 1.3rem;  /* assignment names and status values, 22px+ */
    --radius: 10px;
    --page-max: 34rem;      /* a phone column, centred on a desktop */
}

/* Dark theme. Follows the device by default; Tools sets data-theme to pin it.
   A warm near-black rather than a neutral one, with Rodeo Orange kept as the
   accent (spec 9.2). */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --surface: #14100D;
        --surface-raised: #1F1813;
        --surface-sunken: #0D0A08;
        --border: #3D3128;
        --text: #F6EFE8;
        --text-muted: #C9B29B;
        --accent: #EF7622;
        --accent-text: #14100D;

        /* On a dark surface the brand orange clears contrast comfortably with
           dark text on top, so primary actions use it directly. */
        --action-bg: #EF7622;
        --action-text: #14100D;

        --ok: #7BD48C;
        --ok-surface: #16241A;
        --warn: #E8B45C;
        --warn-surface: #2A2012;
        --danger: #FF9385;
        --danger-surface: #2E1512;
    }
}

:root[data-theme="dark"] {
    --surface: #14100D;
    --surface-raised: #1F1813;
    --surface-sunken: #0D0A08;
    --border: #3D3128;
    --text: #F6EFE8;
    --text-muted: #C9B29B;
    --accent: #EF7622;
    --accent-text: #14100D;
    --action-bg: #EF7622;
    --action-text: #14100D;
    --ok: #7BD48C;
    --ok-surface: #16241A;
    --warn: #E8B45C;
    --warn-surface: #2A2012;
    --danger: #FF9385;
    --danger-surface: #2E1512;
}

/* ---------------------------------------------------------------------------
   Base
   --------------------------------------------------------------------------- */

/* 106.25% is 17px at a default root size — the spec minimum — while still
   respecting a larger browser default set by someone who needs one. Large Text
   mode in Tools multiplies it. */
html {
    font-size: calc(106.25% * var(--text-scale, 1));
    -webkit-text-size-adjust: 100%;
}

:root[data-text="large"] {
    --text-scale: 1.25;
}

* {
    box-sizing: border-box;
}

/* The hidden attribute has to actually hide.
   [hidden] is display:none in the UA stylesheet, which any author rule setting
   display beats on specificity — so .keypad{display:grid} and
   .install__state{display:flex} both rendered while still marked hidden. That
   is not a cosmetic slip: it put a dead keypad on the login screen for anyone
   without JavaScript, and told a man in a browser tab that he was running the
   installed app. !important because the whole point is to outrank whatever a
   component sets. */
[hidden] {
    display: none !important;
}

body {
    margin: 0;
    padding: 0;
    background: var(--surface);
    color: var(--text);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    line-height: 1.5;

    /* Wet gloves and a scrolling list do not mix well with rubber-banding. */
    overscroll-behavior-y: contain;
}

.page {
    max-width: var(--page-max);
    margin: 0 auto;
    padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom, 0px));
}

h1, h2, h3 {
    line-height: 1.2;
    margin: 0 0 0.5rem;
}

h1 {
    font-size: 1.6rem;
}

h2 {
    font-size: 1.25rem;
    color: var(--text-muted);
}

p {
    margin: 0 0 1rem;
}

a {
    color: var(--action-bg);
}

/* No hover-dependent behaviour anywhere (spec 9.3) — hover does not exist on
   the devices this runs on. Focus, however, must always be visible. */
:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Components
   -------------------------------------------------------------------------- */

.masthead {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    border-bottom: 4px solid var(--accent);
    padding-bottom: 0.75rem;
    margin-bottom: 1.25rem;
}

.masthead__name {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: 0.01em;
}

.masthead__sub {
    color: var(--text-muted);
    font-size: 0.95rem;
}

.card {
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem;
    margin-bottom: var(--touch-gap);
}

.card__label {
    color: var(--text-muted);
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.card__value {
    font-size: var(--font-status);
    font-weight: 600;
}

.card__note {
    margin: 0;
}

/* Full-width tiles: the main menu's single vertical column (spec 6.2). */
.tile {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    min-height: var(--tile-height);
    margin-bottom: var(--touch-gap);
    padding: 0.75rem 1rem;
    background: var(--surface-raised);
    color: var(--text);
    border: 1px solid var(--border);
    border-left: 6px solid var(--accent);
    border-radius: var(--radius);
    font-size: 1.1rem;
    font-weight: 600;
    text-align: left;
    text-decoration: none;
}

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--touch-min);
    padding: 0 1.25rem;
    border: 0;
    border-radius: var(--radius);
    background: var(--action-bg);
    color: var(--action-text);
    font-size: 1.05rem;
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
}

.button--primary {
    width: 100%;
    min-height: var(--touch-primary);
    font-size: 1.15rem;
}

.button--quiet {
    background: transparent;
    color: var(--text);
    border: 2px solid var(--border);
}

/* Status and freshness. A stale screen must never look live (spec 6.3), so
   these are always paired with words, never colour alone. */
.badge {
    display: inline-block;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    font-size: 0.9rem;
    font-weight: 700;
}

.badge--ok {
    background: var(--ok-surface);
    color: var(--ok);
}

.badge--warn {
    background: var(--warn-surface);
    color: var(--warn);
}

.badge--danger {
    background: var(--danger-surface);
    color: var(--danger);
}

.notice {
    border: 1px solid var(--border);
    border-left: 6px solid var(--accent);
    border-radius: var(--radius);
    background: var(--surface-raised);
    padding: 0.875rem 1rem;
    margin-bottom: 1rem;
}

.muted {
    color: var(--text-muted);
}

.checks {
    width: 100%;
    border-collapse: collapse;
}

.checks th,
.checks td {
    text-align: left;
    padding: 0.5rem 0.5rem 0.5rem 0;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}

.checks th {
    color: var(--text-muted);
    font-weight: 600;
}

.footnote {
    color: var(--text-muted);
    font-size: 0.9rem;
    margin-top: 2rem;
}

/* An audit row's detail is JSON — one unbroken token can be wider than a
   phone, and unlike a table there is no natural scroll container, so the
   value breaks wherever it must. */
.audit-detail {
    overflow-wrap: anywhere;
}

/* A wide table scrolls inside itself. The page body never scrolls sideways —
   the export preview and the audit log both carry more columns than a phone
   is wide. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin-bottom: 1rem;
}

.table-scroll .checks th,
.table-scroll .checks td {
    white-space: nowrap;
    padding-right: 0.75rem;
}

@media (prefers-reduced-motion: reduce) {
    * {
        animation: none !important;
        transition: none !important;
    }
}

/* ---------------------------------------------------------------------------
   Forms
   --------------------------------------------------------------------------- */

.field {
    margin-bottom: 1rem;
}

.field__label {
    display: block;
    margin-bottom: 0.35rem;
    font-weight: 600;
}

.field__input {
    width: 100%;
    min-height: var(--touch-primary);
    padding: 0 0.875rem;
    border: 2px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text);
    font-size: 1.25rem;
    font-family: inherit;
}

.field__hint {
    margin-top: 0.35rem;
    color: var(--text-muted);
    font-size: 0.9rem;
}

/* A checkbox is a small target by default; the whole row is the target here. */
.check {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: var(--touch-min);
    padding: 0.5rem 0;
    font-size: 1.05rem;
    cursor: pointer;
}

.check input {
    width: 28px;
    height: 28px;
    accent-color: var(--action-bg);
    flex: none;
}

/* ---------------------------------------------------------------------------
   PIN keypad (spec 3.2) — 64px keys, the single most important accommodation
   for cold hands.
   --------------------------------------------------------------------------- */

.pin-dots {
    display: flex;
    justify-content: center;
    gap: 1rem;
    margin: 0.5rem 0 1rem;
}

.pin-dot {
    width: 20px;
    height: 20px;
    border: 3px solid var(--border);
    border-radius: 50%;
}

.pin-dot--filled {
    background: var(--accent);
    border-color: var(--accent);
}

.keypad {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--touch-gap);
    margin-bottom: 1rem;
}

.keypad__key {
    min-height: var(--touch-primary);
    border: 2px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
    color: var(--text);
    font-size: 1.6rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
}

.keypad__key--wide {
    font-size: 1.05rem;
}

.keypad__key:active {
    background: var(--accent);
    color: var(--accent-text);
}

/* ---------------------------------------------------------------------------
   Menu tiles
   --------------------------------------------------------------------------- */

.tile__icon {
    flex: none;
    width: 32px;
    height: 32px;
    color: var(--accent);
}

.tile__text {
    display: flex;
    flex-direction: column;
}

.tile__sub {
    color: var(--text-muted);
    font-size: 0.85rem;
    font-weight: 400;
}

.identity {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 1rem;
    color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
   Messages
   --------------------------------------------------------------------------- */

.alert {
    border-radius: var(--radius);
    padding: 0.875rem 1rem;
    margin-bottom: 1rem;
    font-weight: 600;
}

.alert--error {
    background: var(--danger-surface);
    color: var(--danger);
    border: 2px solid var(--danger);
}

.alert--ok {
    background: var(--ok-surface);
    color: var(--ok);
    border: 2px solid var(--ok);
}

/* Something worth reading that is not a failure — a repeated Member ID in an
   import file, which resolves rather than stopping the run. */
.alert--warn {
    background: var(--warn-surface);
    color: var(--warn);
    border: 2px solid var(--warn);
}

.stack > * + * {
    margin-top: var(--touch-gap);
}

.divider {
    border: 0;
    border-top: 1px solid var(--border);
    margin: 1.5rem 0;
}

/* The dots are the PIN's focus stop once the keypad replaces the field, so
   they need to show focus like any other control. */
.pin-dots:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 6px;
    border-radius: var(--radius);
}

/* ---------------------------------------------------------------------------
   Grouped checkboxes and disclosures — team assignment (spec 6.10.6), and the
   shift's active position groups after it.
   --------------------------------------------------------------------------- */

/* fieldset ships with a border and its own padding, which draws a box around
   a group the legend has already grouped. min-width:0 stops it refusing to
   shrink inside a grid. */
fieldset {
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
}

/* Ten teams is a long column on a phone and a wasteful one on a laptop. Each
   row keeps its own 56px target either way. */
.check-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 0 1rem;
}

/* A flex summary loses its disclosure triangle in Chrome and Safari, so the
   caret is drawn here rather than left to the browser. */
.disclosure {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: var(--touch-min);
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}

.disclosure::-webkit-details-marker {
    display: none;
}

.disclosure::before {
    content: "\25B8";
    color: var(--accent);
}

details[open] > .disclosure::before {
    content: "\25BE";
}

.disclosure:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--radius);
}

/* ---------------------------------------------------------------------------
   Status widget (spec 6.3) — the most-viewed element in the product, and the
   one that has to be readable at arm's length in Houston sunlight. Few things,
   large, with the state carried by a border rather than by colour alone.
   --------------------------------------------------------------------------- */

.widget {
    border: 2px solid var(--border);
    border-left-width: 8px;
    border-radius: var(--radius);
    background: var(--surface-raised);
    padding: 0.75rem 1rem;
    margin-bottom: var(--touch-gap);
}

.widget--in {
    border-color: var(--ok);
}

.widget--out {
    border-color: var(--text-muted);
}

.widget__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
}

.widget__state {
    font-weight: 700;
    letter-spacing: 0.06em;
    font-size: 0.95rem;
}

.widget--in .widget__state {
    color: var(--ok);
}

.widget__team {
    color: var(--text-muted);
    font-size: 0.95rem;
}

/* The one line a committeeman actually reads. */
.widget__assignment {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.2;
    margin: 0.35rem 0;
}

.widget__meta {
    color: var(--text-muted);
    font-size: 0.9rem;
    flex-wrap: wrap;
}

.widget__fresh {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
}

/* Past a minute the page is old enough that it must stop looking live. */
.widget__fresh--stale {
    color: var(--warn);
    font-weight: 600;
}

/* Red when the last ask failed (spec 6.3). Not hue alone: the strip says the
   word "offline" beside it, because a colour is the one cue that is gone in
   bright sun through a scratched screen protector. */
.widget__fresh--offline {
    color: var(--danger);
    font-weight: 700;
}

.widget__note {
    margin: 0.5rem 0 0;
    color: var(--warn);
    font-weight: 600;
    font-size: 0.95rem;
}

/* A message pinned to every committeeman on the shift (spec 6.9.10). */
.broadcast {
    border-radius: var(--radius);
    background: var(--accent);
    color: var(--accent-text);
    padding: 0.75rem 1rem;
    margin-bottom: var(--touch-gap);
    font-weight: 600;
}

/* Check In / Out (spec 6.4): one target, impossible to miss with gloves on. */
.check-button {
    width: 100%;
    min-height: 96px;
    font-size: 1.6rem;
    font-weight: 700;
    letter-spacing: 0.04em;
}

/* My Shift Status (spec 6.5): the position is the one thing a committeeman
   opens this screen to read, so it is the largest thing on it. */
.assignment {
    font-size: 2rem;
    font-weight: 700;
    line-height: 1.15;
}

/* ---------------------------------------------------------------------------
   Officer Menu (spec 6.9)
   --------------------------------------------------------------------------- */

/* Team and shift selectors. Side by side where there is room, stacked on a
   narrow phone, and the Show button is hidden by picker.js once the change
   handler is attached. */
.picker {
    display: flex;
    flex-wrap: wrap;
    gap: var(--touch-gap);
    align-items: flex-end;
    margin-bottom: 1rem;
}

.picker .field {
    flex: 1 1 10rem;
    margin-bottom: 0;
    min-width: 0;
}

/* The phase toggle, spec 6.9.1. The active half is filled Rodeo Orange with
   Ink on top — never white, which at 2.9:1 would fail contrast outright
   (spec 9.1). */
.phase {
    display: flex;
    gap: 0;
    border: 2px solid var(--accent);
    border-radius: var(--radius);
    overflow: hidden;
    margin-bottom: 1rem;
}

.phase__option {
    flex: 1 1 50%;
    min-height: var(--touch-min);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 0.5rem;
    border: 0;
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 1.05rem;
    font-weight: 700;
    text-align: center;
    cursor: pointer;
}

.phase__option--on {
    background: var(--accent);
    color: var(--accent-text);
}

/* The coverage counter, spec 6.9.2. Five figures, each one a tap target that
   filters the list behind it. */
.coverage {
    display: flex;
    gap: 2px;
    margin-bottom: 1.25rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--border);
    overflow: hidden;
}

.coverage__item {
    flex: 1 1 0;
    min-width: 0;
    min-height: var(--touch-min);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.1rem;
    padding: 0.5rem 0.15rem;
    background: var(--surface-raised);
    color: var(--text);
    text-decoration: none;
}

.coverage__figure {
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.1;
    white-space: nowrap;
}

.coverage__label {
    font-size: 0.75rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

/* Critical short is red on purpose and is not an error state: Bump and Run has
   37 critical positions against a shift that can run 25 people, so on a short
   night this is the board telling the truth (spec 5.4, 8.1). */
.coverage__item--short {
    background: var(--danger-surface);
}

.coverage__item--short .coverage__figure {
    color: var(--danger);
}

/* ---------------------------------------------------------------------------
   The assign board (spec 6.9.4)
   --------------------------------------------------------------------------- */

/* Position-first / roster-first. Both reach the same two sheets. */
.modes {
    display: flex;
    border: 2px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    margin-bottom: 1rem;
}

.modes__option {
    flex: 1 1 50%;
    min-height: var(--touch-min);
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--surface);
    color: var(--text);
    font-weight: 700;
    text-decoration: none;
    text-align: center;
    padding: 0 0.5rem;
}

.modes__option--on {
    background: var(--surface-sunken);
}

/* Search by last name, alongside the chip row. */
.filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--touch-gap);
    margin-bottom: 0.75rem;
}

.filters .field {
    flex: 1 1 12rem;
    margin-bottom: 0;
    min-width: 0;
}

/* The chip row scrolls sideways inside itself rather than widening the page. */
.chiprow {
    display: flex;
    gap: var(--touch-gap);
    overflow-x: auto;
    padding-bottom: 0.5rem;
    margin-bottom: 1rem;
    -webkit-overflow-scrolling: touch;
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-top: 0.2rem;
}

.chip {
    display: inline-flex;
    align-items: center;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--surface-raised);
    color: var(--text-muted);
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
}

/* Certified is what an officer signed off; preferred is what the man asked
   for. Two independent facts, told apart by shape as well as colour (7.3). */
.chip--certified {
    border-color: var(--rodeo-brown);
    color: var(--text);
}

.chip--preferred {
    border-style: dashed;
}

.chip--lunch {
    background: var(--warn-surface);
    color: var(--warn);
    border-color: var(--warn);
}

/* The 5.5 clash. The only place either officer can see it. */
.chip--overlap {
    background: var(--warn-surface);
    color: var(--warn);
    border-color: var(--warn);
    white-space: normal;
}

/* A filter chip is a tap target, so it is bigger than an informational one. */
.chip--filter {
    min-height: var(--touch-min);
    padding: 0 0.9rem;
    font-size: 0.95rem;
    text-decoration: none;
    color: var(--text);
    flex: 0 0 auto;
}

.chip--on {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-text);
}

/* The board and the sheets are all the same list of tappable rows. */
.picks {
    list-style: none;
    margin: 0 0 1.25rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--touch-gap);
}

.pick {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.15rem;
    width: 100%;
    min-height: var(--touch-min);
    padding: 0.6rem 0.9rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
    color: var(--text);
    text-align: left;
    text-decoration: none;
}

/* The <button> flavour has to match the <a> one exactly, or a board reads as
   two different kinds of thing depending on which mode you came in by. */
.pick--button {
    font-family: inherit;
    font-size: 1rem;
    cursor: pointer;
}

.pick--filled {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--touch-gap);
    flex-wrap: wrap;
}

/* Vacant and critical. Red is correct here and stays correct on a short
   night — 37 critical positions against 25 people (spec 5.4, 8.1). Paired
   with the word "vacant", never colour alone. */
.pick--critical {
    border-color: var(--danger);
    border-left-width: 6px;
    background: var(--danger-surface);
}

.pick__name {
    font-size: 1.1rem;
    font-weight: 700;
    overflow-wrap: anywhere;
}

.pick__meta {
    font-size: 0.9rem;
    color: var(--text-muted);
    overflow-wrap: anywhere;
}

.pick__holder {
    display: inline-block;
    margin-right: 0.4rem;
    color: var(--text);
    font-weight: 600;
}

.pinned__heading {
    color: var(--danger);
}

.group {
    margin-bottom: 0.75rem;
}

.group > .disclosure {
    display: flex;
    justify-content: space-between;
    gap: var(--touch-gap);
}

/* ---------------------------------------------------------------------------
   The people screens (spec 6.9.3, 6.9.8, 6.9.9, 6.9.11)
   --------------------------------------------------------------------------- */

.people {
    list-style: none;
    margin: 0 0 1.25rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--touch-gap);
}

.person {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
    padding: 0.75rem 0.9rem;
}

.person__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.2rem;
}

.person__name {
    font-size: 1.1rem;
    font-weight: 700;
    overflow-wrap: anywhere;
}

.person__meta {
    font-size: 0.95rem;
    color: var(--text-muted);
    overflow-wrap: anywhere;
}

/* Buttons wrap rather than widening the row: a long name and four actions
   must not push the page sideways on a 390px screen. */
.person__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--touch-gap);
    margin-top: 0.6rem;
}

.person__actions form {
    margin: 0;
}

.chip--equipment {
    border-style: dotted;
}

.coverage__item--on {
    background: var(--surface-sunken);
}

/* A destructive action opens its explanation before it can be taken
   (spec 9.3). No small dismiss control: closing it is the same summary. */
.confirm > summary {
    list-style: none;
}

.confirm > summary::-webkit-details-marker {
    display: none;
}

.confirm[open] {
    display: block;
    border: 1px solid var(--danger);
    border-radius: var(--radius);
    padding: 0.5rem;
}

.confirm form {
    margin: 0.5rem 0 0;
}

.disclosure-block {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
    padding: 0.75rem 0.9rem;
    margin-bottom: 1.25rem;
}

.disclosure-block[open] > .disclosure {
    margin-bottom: 0.75rem;
}

/* The read-only boards (spec 6.9.7): position left, whoever is there right.
   Scrolls inside itself so a long position name never widens the page. */
.board {
    table-layout: fixed;
    width: 100%;
}

.board th {
    width: 55%;
    font-weight: 600;
    overflow-wrap: anywhere;
}

.board td {
    overflow-wrap: anywhere;
}

textarea.field__input {
    font-family: inherit;
    resize: vertical;
}

/* ---------------------------------------------------------------------------
   Install instructions (spec 6.7)
   --------------------------------------------------------------------------- */

.install__state {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 1rem;
}

.install__how h3 {
    margin: 0 0 0.5rem;
}

/* Numbered because they are steps in order, and read one at a time by someone
   holding a phone in the other hand — hence the line height and the room
   between them rather than a tight list. */
.install__steps {
    margin: 0;
    padding-left: 1.4rem;
}

.install__steps li {
    margin-bottom: 0.6rem;
    line-height: 1.6;
}

.install__steps li:last-child {
    margin-bottom: 0;
}

/* ---------------------------------------------------------------------------
   Choice groups — Theme and Large Text (spec 9.2, 9.3)
   --------------------------------------------------------------------------- */

/* The same segmented shape as the phase toggle, which is the control officers
   already know, but two or three options wide instead of always two. */
.choice {
    display: flex;
    border: 2px solid var(--accent);
    border-radius: var(--radius);
    overflow: hidden;
    margin-bottom: 1.5rem;
}

.choice__option {
    flex: 1 1 0;
    min-height: var(--touch-min);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 0.5rem;
    border: 0;
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 1.05rem;
    font-weight: 700;
    text-align: center;
    cursor: pointer;
}

/* Rodeo Orange with dark text on top, never white — the fill is the accent and
   the accent is 2.9:1 against white (spec 9.1). */
.choice__option--on {
    background: var(--accent);
    color: var(--accent-text);
}

/* ---------------------------------------------------------------------------
   The staleness banner (spec 6.5, 10.3)
   --------------------------------------------------------------------------- */

/* Pinned to the bottom, where a thumb already is and where it cannot be
   scrolled past unnoticed. "A stale view must never be mistakable for a live
   one", and the strip's own counter is the version for someone who is reading
   rather than glancing. */
/* Room for it, so a banner pinned over the thumb-reach zone does not sit on
   top of the primary action that spec 9.3 puts there. Set by freshness.js at
   the same moment the banner appears. */
.has-stale .page {
    padding-bottom: 6rem;
}

.stale {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
    background: var(--danger-surface);
    color: var(--text);
    border-top: 3px solid var(--danger);
    font-weight: 600;
}

/* ---------------------------------------------------------------------------
   The offline queue (spec 6.4, 10.3)
   --------------------------------------------------------------------------- */

/* "1 pending" until it syncs. Amber rather than red: nothing is wrong, the tap
   was recorded and is waiting for signal. Red is reserved for the screen being
   stale, which is the thing that can mislead. */
.pending {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0 0 0.75rem;
    padding: 0.4rem 0.7rem;
    border: 2px solid var(--warn);
    border-radius: var(--radius);
    background: var(--warn-surface);
    color: var(--warn);
    font-weight: 700;
}

/* What the form says back when a tap could not reach the server. It names the
   time it was saved, because the whole promise of the queue is that the
   ORIGINAL moment is what gets recorded. */
.offline-note {
    margin: 0.75rem 0 0;
    padding: 0.6rem 0.75rem;
    border-left: 4px solid var(--warn);
    background: var(--warn-surface);
    color: var(--text);
    font-weight: 600;
}

/* ---------------------------------------------------------------------------
   The tarmac map (spec 6.5, 11.4)
   --------------------------------------------------------------------------- */

/* Scrolls inside itself. A site drawing is wider than a phone, and the page
   body must never scroll sideways. */
.map {
    overflow: auto;
    max-height: 70vh;
    margin-bottom: 1rem;
    border: 2px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
}

.map svg {
    display: block;
    max-width: none;
}

/* The drawing itself. tarmac.svg is generated (bin/gen-tarmac-map.php) with
   classes and no styling of its own: the page's CSP is style-src 'self', so
   an inline style could not apply anyway — and taking every colour from the
   theme tokens here is what makes the drawing follow the dark theme. */
.map svg text {
    font-size: 15px;
}

.map .tmap-tent {
    fill: none;
    stroke: var(--text-muted);
    stroke-width: 3;
}

.map .tmap-zone-a { fill: var(--surface-raised); }
.map .tmap-zone-b { fill: var(--surface); }

.map .tmap-lanes {
    fill: var(--surface-sunken);
}

.map .tmap-lane-line {
    stroke: var(--border);
    stroke-width: 1.5;
    stroke-dasharray: 7 7;
    fill: none;
}

.map .tmap-bldg {
    fill: var(--surface-sunken);
    stroke: var(--border);
    stroke-width: 1.5;
}

/* Ground beyond the drawing (Naomi, Curve, Holly Hall) and the approximate
   GB/LT area: dashed, so nobody reads them as surveyed. */
.map .tmap-off {
    fill: none;
    stroke: var(--border);
    stroke-width: 1.5;
    stroke-dasharray: 9 6;
}

.map .tmap-label {
    fill: var(--text);
    font-weight: 600;
}

.map .tmap-sublabel {
    fill: var(--text-muted);
    font-size: 12px;
}

.map .tmap-arrow {
    stroke: var(--text-muted);
    stroke-width: 2;
    fill: none;
}

.map .tmap-arrowhead {
    fill: var(--text-muted);
}

.map .tmap-walk {
    stroke: var(--text-muted);
    stroke-width: 1.5;
    stroke-dasharray: 2 6;
    fill: none;
}

/* A position nobody in view holds. Quiet, but present — an outline the
   highlights below can replace. */
.map .pos {
    fill: var(--surface-sunken);
    stroke: var(--text-muted);
    stroke-width: 1.25;
}

/* The tiny number that tells Runner 3 from Runner 1 inside a cluster. */
.map .pos-num {
    fill: var(--text-muted);
    font-size: 8px;
    text-anchor: middle;
    pointer-events: none;
}

/* His own spot. The accent, with a dark outline rather than white text on it —
   Rodeo Orange takes dark, never white (spec 9.1). */
.map .map__me {
    fill: var(--accent);
    stroke: var(--ink);
    stroke-width: 2;
    /* Grows his circle beyond the crowd — r is a geometry property on SVG
       circles, which is exactly what the markers are. */
    r: 11;
}

/* Everyone else in his group, in a secondary colour (spec 11.4). */
.map .map__mate {
    fill: var(--rodeo-dust);
    stroke: var(--rodeo-brown);
    stroke-width: 1.5;
    r: 8;
}

/* The key beneath it. Both marks are shapes as well as colours, because a
   legend that is colour alone is one nobody can use in direct sunlight. */
.map__key {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    margin-right: 0.15rem;
    vertical-align: -2px;
    border-radius: 3px;
}

.map__key--me {
    background: var(--accent);
    border: 2px solid var(--ink);
}

.map__key--mate {
    background: var(--rodeo-dust);
    border: 2px dashed var(--rodeo-brown);
}

/* ---------------------------------------------------------------------------
   "Someone else has changed this board" (spec 10.4)
   --------------------------------------------------------------------------- */

/* In the flow at the top of the board rather than fixed over it. The officer
   is mid-task and this is information, not an interruption — it must not cover
   the row he is reaching for. */
.board-moved {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--touch-gap);
    margin: 0 0 1rem;
    padding: 0.6rem 0.75rem;
    border: 2px solid var(--warn);
    border-radius: var(--radius);
    background: var(--warn-surface);
    font-weight: 600;
}

.board-moved .button {
    flex: 0 0 auto;
}
