/* tokens.css — the design token layer. Loaded BEFORE styles.css on every view.
 *
 * Nothing in here styles anything. It only names values, so that:
 *   1. a dark theme is a different set of values, not a different stylesheet;
 *   2. Phase 5's per-tenant branding overrides a handful of tokens rather than
 *      hunting hex literals through 750 lines of rules.
 *
 * Three things in here are load-bearing and easy to break:
 *
 * - `color-scheme` is the fix for a real bug, not a nicety. Before this file
 *   existed the app shipped light-only, and Chrome's Auto Dark Theme
 *   *algorithmically inverted* it on a phone set to dark: the token said
 *   #f5f5f5 and `body` measured rgb(24,26,27). That heuristic does not know the
 *   GPS pin colours and status badges carry meaning. Declaring `color-scheme`
 *   tells the browser we handle dark ourselves and it stops interfering.
 *
 * - The dark values are declared once, as `--d-*`, and then *mapped* twice
 *   (once for `prefers-color-scheme`, once for `[data-theme="dark"]`). The
 *   mapping is duplicated because CSS has no way to share it; the colours are
 *   not. Edit `--d-*`, never the mapping.
 *
 * - Dark is not an inversion. Cool near-black ground, text at 90% white rather
 *   than pure white, and every semantic colour re-picked at a lighter value so
 *   it still clears WCAG AA against that ground. Shadows go darker and more
 *   transparent, not the same values.
 */

:root {
  color-scheme: light;

  /* ── Base palette ────────────────────────────────────────────────────────
     Six names. Semantic, not literal — `--surface-raised`, never `--white` —
     because a tenant override of "white" is meaningless. */
  --graphite:   #5A6068;  /* muted text (6.1:1 on paper) */

  /* The one functional accent. This is the existing brand orange, measured,
     not re-chosen — so it survives a re-brand as a token swap.

     It takes DARK text, not white. White on #e8821a is 2.75:1, which the old
     `.btn-primary` shipped and which fails AA; #16181D on it is 6.5:1. That is
     also the useful side effect of keeping accent visually separate from the
     status badges, which are all light-tint-on-dark-text. */
  --accent:     #e8821a;
  --on-accent:  #16181D;

  /* The accent AS TEXT or as a hairline, which is a different problem: #e8821a
     on a light surface measures 2.75:1 (2.52:1 on the page ground), below both the 4.5:1 text bar and the
     3:1 non-text bar. This is the darkened form that clears AA (5.11:1 on a card, 4.69:1 on the page ground), and in
     dark theme it collapses back to --accent, which already clears it there
     (6.33:1). tests/tokenContrast.test.js owns the figures. Use --accent for fills, --accent-text for anything thin. */
  --l-accent-text: #AD5600;   /* the light value; a tenant's is set inline here, never on --accent-text (F-205) */
  --accent-text: var(--l-accent-text);

  /* ── Signal colours ──────────────────────────────────────────────────────
     Held deliberately distinct from --accent. The old palette had
     --color-primary #e8821a and --color-warning #f39c12 — both orange, near
     indistinguishable, and orange is *also* a GPS pin state. Brand and state
     were the same signal. Warning is now unambiguously yellow-amber.

     State is never encoded in hue alone anywhere in this app; see the badge
     and pin rules in styles.css. These values are the colour half only. */
  --signal-success: #15803D;
  --signal-warning: #A16207;
  --signal-danger:  #B91C1C;
  --signal-info:    #1D4ED8;

  /* Text on a signal-coloured FILL (a danger button, a toast). This has to flip
     with the theme: light theme's signals are 700-weights that take white, dark
     theme's are 400-weights that take near-black. White on dark-theme's
     #4ADE80 is 1.7:1. */
  --on-signal: #FAFAF8;

  /* Tints for badge/alert fills. Light theme only — dark theme uses a
     translucent wash of the signal colour instead, since a pale tint on a dark
     ground reads as a glowing block. */
  /* Measured, not eyeballed: the first pass used #E7F3EB / #FBF2DC and the badge
     label came out at 4.40:1 and 4.42:1 — under AA, and badge text is 12px bold,
     which is not "large text". These clear it at 4.58 and 4.57. */
  --tint-success: #EDF7F1;
  --tint-warning: #FDF6E6;
  --tint-danger:  #FBEAEA;
  --tint-info:    #E8EDFB;

  /* ── Surfaces ────────────────────────────────────────────────────────────
     Three depths, plus "chrome" for the sidebar/topbar/table-head band. Chrome
     used to be a navy (#2c5f8a) — a second brand hue doing structural work.
     It is now neutral, which is both more restrained and one less colour for a
     tenant theme to fight. */
  --surface-sunken: #F4F5F8;  /* page ground (look ii, 2026-11-03: cooler than the old #F1F0EB) */
  --surface:        #FFFFFF;  /* cards, modals */
  --surface-raised: #FFFFFF;  /* inputs, popovers, things on top of cards */
  --surface-chrome: #1F2227;  /* sidebar, topbar (the thead uses --surface) */
  --on-chrome:      rgba(255,255,255,0.92);

  /* A filled neutral block that is not chrome: the secondary button. Distinct
     from --surface-chrome because in dark theme chrome goes *darker* than the
     page (a topbar recedes) while a button has to come *forward*. */
  --fill-neutral:    #1F2227;
  --on-fill-neutral: rgba(255,255,255,0.92);

  --text:         #1B1E27;
  --text-muted:   #5E6472;   /* 5.9:1 on the card, 5.5:1 on the page ground: tests/tokenContrast.test.js */
  --text-inverse: #FFFFFF;

  --border:        #E3E5EB;
  /* --border is a decorative hairline; --border-strong is the edge of a CONTROL
     (a field, a ghost button, a chip) and WCAG 1.4.11 holds those to 3:1 against
     the surface behind them. #B9B8B0 measured 1.91:1 — a form field with no
     visible boundary. This clears it at 3.79:1 (3.48:1 on the page ground) without becoming a heavy rule. */
  --border-strong: #7D8393;
  --focus-ring:    #1D4ED8;
  --focus-glow:    rgba(29,78,216,0.24);

  /* Scrim behind modals and the mobile drawer. Theme-aware: the same 55% black
     over a near-black page is barely a scrim at all. */
  --scrim: rgba(14,16,19,0.55);

  /* Chrome drawn ON TOP of photography and map tiles — delete buttons, play
     badges, the tap-to-activate veil. Theme-independent by definition: a photo
     is a photo whatever the page around it is doing. */
  --overlay-fill: rgba(14,16,19,0.66);
  --on-overlay:   #FAFAF8;

  /* Map pins. Deliberately NOT remapped in the dark blocks below: a pin is drawn
     on OpenStreetMap tiles, which are light whatever the page is doing, so the
     dark-theme signal colours (picked to sit on a near-black ground) are the
     wrong ones there. The shape differences in makeIcon() carry the meaning;
     these only have to stay legible against a street map. */
  --pin-nav:  #C25E00;
  --pin-drop: #B91C1C;
  --pin-both: #15803D;

  /* Route lines and their pins (routing lab, later Phase 7). Same rule as the
     pins: drawn on light tiles, so not remapped for dark. Dark enough to carry
     white pin numbers and to read as a 4px line on a street map. Hue is never
     the only signal — every route pin is also labelled with its route letter
     and sequence number — so beyond eight routes the palette simply repeats. */
  --route-1: #1D4ED8;
  --route-2: #B91C1C;
  --route-3: #15803D;
  --route-4: #7E22CE;
  --route-5: #C25E00;
  --route-6: #0F766E;
  --route-7: #A21CAF;
  --route-8: #4B5563;

  /* Borders carry the hierarchy; shadows only lift things that genuinely
     float (modals, the driver's detail panel, toasts). */
  --shadow-sm: 0 1px 2px rgba(20,24,40,0.06);
  --shadow:    0 1px 2px rgba(20,24,40,0.06), 0 8px 20px rgba(20,24,40,0.08);
  --shadow-lg: 0 12px 24px rgba(20,24,40,0.12), 0 32px 64px rgba(20,24,40,0.12);
  /* Look (ii): cards sit on a soft shadow as well as a hairline. Compact pages keep it; it is quiet. */
  --shadow-card: 0 1px 2px rgba(20,24,40,0.06), 0 8px 20px rgba(20,24,40,0.05);

  /* ── Type ────────────────────────────────────────────────────────────────
     Inter for the interface (look ii). IBM Plex Mono for door PINs, key-safe codes,
     registrations, odometer readings, timestamps and money — functional, not
     decorative: it makes 0/O and 1/l unambiguous, which is a real failure mode
     reading a key-safe code off a phone in the dark. */
  --font-ui:   'Inter', 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;

  /* One strict scale, in px. Replaces the old scattered
     0.75/0.78/0.8/0.85/0.875/0.9/0.95/1rem. Nothing interactive is allowed
     below --text-base: under 16px, iOS zooms the viewport on field focus. */
  --text-xs:   0.75rem;   /* 12px — captions, table meta. Never interactive. */
  --text-sm:   0.875rem;  /* 14px — labels, hints */
  --text-base: 1rem;      /* 16px — body, every input, every button */
  --text-lg:   1.25rem;   /* 20px — card and modal titles */
  --text-xl:   1.5rem;    /* 24px — page titles */
  --text-2xl:  2rem;      /* 32px — stat values */

  --leading-tight: 1.25;
  --leading-body:  1.55;
  --tracking-tight: -0.01em;  /* Inter sets a touch wide at display sizes */

  /* ── Space ───────────────────────────────────────────────────────────────
     8px grid, with a 4px half-step. Every padding/margin/gap in styles.css
     resolves to one of these. */
  --space-1: 0.25rem;  /*  4px */
  --space-2: 0.5rem;   /*  8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-5: 1.5rem;   /* 24px */
  --space-6: 2rem;     /* 32px */
  --space-7: 3rem;     /* 48px */

  /* ── Geometry ────────────────────────────────────────────────────────────
     Rounding used sparingly and consistently: 4px on controls, 8px on the
     surfaces that contain them, full round only on things that are genuinely
     pills (badges) or circles (icons). */
  --radius-sm:   8px;    /* chips, small marks */
  --radius:      12px;   /* buttons, inputs, compact controls, dense tables */
  --radius-md:   16px;   /* small cards, dense-page cards */
  --radius-lg:   20px;   /* the big cards and modals */
  /* Run colours on the Routing map: one per run, for pins and lines on LIGHT map tiles, so like --pin-* they are NOT remapped for dark.
     White numbers sit on them, so each clears 4.5:1 against white (tests/tokenContrast.test.js). */
  --run-1: #1F6FB5; --run-2: #B84A00; --run-3: #0A7F5F; --run-4: #A8337F;
  --run-5: #7A5F00; --run-6: #4C5BD4; --run-7: #C0392B; --run-8: #566573;
  --radius-xl:   20px;   /* the one big card on a dense page: it does not shrink under .surface-compact */
  --radius-pill: 999px;
  --radius-table: var(--radius-lg);

  /* 44px is the floor, not a suggestion. The driver is gloved and moving. */
  --touch-min:     44px;
  --touch-comfort: 52px;

  --transition:      140ms ease;
  --transition-slow: 260ms ease;
  --sidebar-width:   240px;
}

/* ── Dark values ───────────────────────────────────────────────────────────
   Declared once here; mapped below. */
:root {
  --d-surface-sunken: #101218;
  --d-surface:        #171A22;
  --d-surface-raised: #1E222C;
  --d-surface-chrome: #101218;

  --d-fill-neutral:    #2B3038;
  --d-on-fill-neutral: rgba(255,255,255,0.90);

  --d-text:         rgba(255,255,255,0.90);
  --d-text-muted:   rgba(255,255,255,0.60);
  --d-text-inverse: #16181D;

  --d-border:        rgba(255,255,255,0.13);
  --d-border-strong: rgba(255,255,255,0.36);  /* 3.34:1, same reason as above */
  --d-focus-ring:    #93B4FD;
  --d-focus-glow:    rgba(147,180,253,0.30);
  --d-accent-text:   #e8821a;
  --d-scrim:         rgba(0,0,0,0.70);
  --d-on-signal:     #16181D;

  /* Re-picked, not lightened mechanically — each of these clears 4.5:1 against
     --d-surface (#171A22). The 700-weights used in light theme sit at ~1.5:1
     there and would be unreadable. */
  --d-signal-success: #4ADE80;
  --d-signal-warning: #FBBF24;
  --d-signal-danger:  #F87171;
  --d-signal-info:    #60A5FA;

  /* A wash of the signal colour rather than a pale tint. */
  --d-tint-success: rgba(74,222,128,0.14);
  --d-tint-warning: rgba(251,191,36,0.14);
  --d-tint-danger:  rgba(248,113,113,0.14);
  --d-tint-info:    rgba(96,165,250,0.14);

  --d-shadow-sm: 0 1px 2px rgba(0,0,0,0.40);
  --d-shadow:    0 4px 12px rgba(0,0,0,0.50);
  --d-shadow-lg: 0 12px 32px rgba(0,0,0,0.64);
  --d-shadow-card: 0 1px 0 rgba(255,255,255,0.05) inset, 0 12px 24px rgba(0,0,0,0.28);
}

/* Dense pages (admin, platform) take the smaller radii: big rounded corners waste space on tables and forms. The big
   cards keep 20px everywhere else. Put the class on <body>. */
.surface-compact {
  --radius-lg: var(--radius-md);      /* 16px */
  --radius-table: var(--radius);      /* 12px */
}

/* The mapping. Duplicated for the two triggers — system preference, and an
   explicit [data-theme]. `:root:not([data-theme="light"])` so a page or a user
   can force light back on even on a dark device. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --surface-sunken: var(--d-surface-sunken);
    --surface:        var(--d-surface);
    --surface-raised: var(--d-surface-raised);
    --surface-chrome: var(--d-surface-chrome);
    --fill-neutral:    var(--d-fill-neutral);
    --on-fill-neutral: var(--d-on-fill-neutral);
    --text:           var(--d-text);
    --text-muted:     var(--d-text-muted);
    --text-inverse:   var(--d-text-inverse);
    --border:         var(--d-border);
    --border-strong:  var(--d-border-strong);
    --focus-ring:     var(--d-focus-ring);
    --focus-glow:     var(--d-focus-glow);
    --accent-text:    var(--d-accent-text);
    --scrim:          var(--d-scrim);
    --on-signal:      var(--d-on-signal);
    --signal-success: var(--d-signal-success);
    --signal-warning: var(--d-signal-warning);
    --signal-danger:  var(--d-signal-danger);
    --signal-info:    var(--d-signal-info);
    --tint-success:   var(--d-tint-success);
    --tint-warning:   var(--d-tint-warning);
    --tint-danger:    var(--d-tint-danger);
    --tint-info:      var(--d-tint-info);
    --shadow-sm:      var(--d-shadow-sm);
    --shadow:         var(--d-shadow);
    --shadow-lg:      var(--d-shadow-lg);
    --shadow-card:    var(--d-shadow-card);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --surface-sunken: var(--d-surface-sunken);
  --surface:        var(--d-surface);
  --surface-raised: var(--d-surface-raised);
  --surface-chrome: var(--d-surface-chrome);
  --fill-neutral:    var(--d-fill-neutral);
  --on-fill-neutral: var(--d-on-fill-neutral);
  --text:           var(--d-text);
  --text-muted:     var(--d-text-muted);
  --text-inverse:   var(--d-text-inverse);
  --border:         var(--d-border);
  --border-strong:  var(--d-border-strong);
  --focus-ring:     var(--d-focus-ring);
  --focus-glow:     var(--d-focus-glow);
  --accent-text:    var(--d-accent-text);
  --scrim:          var(--d-scrim);
  --on-signal:      var(--d-on-signal);
  --signal-success: var(--d-signal-success);
  --signal-warning: var(--d-signal-warning);
  --signal-danger:  var(--d-signal-danger);
  --signal-info:    var(--d-signal-info);
  --tint-success:   var(--d-tint-success);
  --tint-warning:   var(--d-tint-warning);
  --tint-danger:    var(--d-tint-danger);
  --tint-info:      var(--d-tint-info);
  --shadow-sm:      var(--d-shadow-sm);
  --shadow:         var(--d-shadow);
  --shadow-lg:      var(--d-shadow-lg);
  --shadow-card:    var(--d-shadow-card);
}

