[hidden] {
  display: none !important;
}

html,
body {
  margin: 0;
  padding: 0;
}

:root {
  /* App font: native system stack — no web-font download, renders instantly */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, "Noto Sans", sans-serif;
  /* NUMBER PLATES (QA re-check, 3 Oct 2026, §5b). A plate mixes letters and
     digits, and Company Six's CO6TRK is C, a LETTER O, then 6. Every plate
     chip used a monospace face, and monospace squeezes a capital O into the
     same narrow cell as a zero: the tester read the rig picker's badge as
     C06TRK twice, the second time after walk NF had slashed the zero,
     because the slash only marks a zero that is there and this plate has
     none. Plates now use the app's own face, where O is a round letter and
     0 a narrow digit, with font-variant-numeric: slashed-zero kept on every
     plate rule for the faces that have one. Every plate rule reads this
     token (tools/scan-plate-font.mjs holds it; tools/render-plate-glyphs.mjs
     measures O against 0 on each one). */
  --font-plate: var(--font);

  /* Dark defaults */
  --bg: #0b1727;
  --panel: #0c1a2b;
  --card: #111f32;
  --text: #e7eef9;
  --muted: #9bb0d3;
  --accent: #3cb4ff;
  --accent-strong: #2b8fd0;
  --border: #1e2d46;
  --shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
  /* Text colour on accent-filled buttons: dark on the bright dark-mode blue,
     white on the deeper light-mode blue. */
  --on-accent: #0a1422;

  /* Semantic state colours. One hex per meaning, app-wide — these were the
     most-used value of each family across the page stylesheets before the
     2026-09-04 consolidation (a dozen near-identical greens/ambers/reds had
     accreted page by page). Use these, not a fresh hex, for "worked",
     "needs attention", "failed/destructive" and "informational" states.
     Re-declared darker under body.light so they read as TEXT on white. */
  --ok: #4ade80;
  --warn: #f5a623;
  --danger: #f05d5e;
  --info: #a78bfa;

  /* Corner radius scale. Pages used to carry their own (8/12/16/999 in
     admin/fleet, 8/10/14 in orderpage, a lone 16 on the homepage); this is
     the shared one. Values other than these (6, 10, 14…) stay as raw px in
     page CSS — they were left alone on purpose so nothing shifted. */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-pill: 999px;

  /* Compatibility aliases. Many page stylesheets reference these -color / -text
     names, which were never defined and silently fell back to hardcoded DARK
     values (invisible in light mode — e.g. the transport-company setup page).
     Alias them to the real tokens. NOTE: var() in a custom property resolves at
     the element it's DECLARED on, so these are re-declared in body.light below
     (otherwise they'd stay pinned to the dark values). */
  --text-color: var(--text);
  --muted-text: var(--muted);
  --accent-color: var(--accent);
  --border-color: var(--border);
  /* Second alias family, found by the 2026-08-28 day-mode audit: these names
     are referenced WITHOUT fallbacks across driver/fleet, driver/tracking,
     driver/loads, admin/tracking, admin/loads, fleet-signup, paypage and the
     weighbridge — so text-secondary rendered at full text strength (hierarchy
     gone) and card/input surfaces fell to transparent on both themes. */
  --text-primary: var(--text);
  --text-secondary: var(--muted);
  --card-bg: var(--card);
  --input-bg: var(--panel);
  --surface: var(--card);
  --surface-alt: var(--panel);
  --bg-primary: var(--bg);
  --bg-secondary: var(--panel);
  --border-strong: var(--border);
  --primary: var(--accent);
}

body.light {
  --bg: #f5f7fb;
  --panel: #eef2f9;
  --card: #ffffff;
  --text: #14233b;
  --muted: #5b6a83;
  /* The accent is used as TEXT all over (links, prices, chips, headings), so
     it has to clear 4.5:1 on white AND on its own 10% tint (#ecf8ff — the
     payable/status chips). #1f7ae0 was 4.27 on white; #1a6fd0 is 4.97 on
     white, 4.60 on #ecf8ff, 4.51 on #e8f6ff (2026-09-04 contrast audit).
     It is still 4.42 on the --panel ground, so accent text sitting directly
     on --panel uses --accent-strong (6.25 white / 5.57 panel). */
  --accent: #1a6fd0;
  --accent-strong: #155fb8;
  --border: #e1e7f1;
  --shadow: 0 6px 22px rgba(20, 45, 90, 0.07);
  /* Semantic colours, deepened for a white ground: each is >= 4.5:1 on
     #ffffff so a plain `color: var(--danger)` line stays legible. The dark
     values are 2–3:1 on white — the day-mode audit's "amber on white"
     failure mode. All three also sit on their own tinted chips and on
     --panel (#eef2f9), so they are checked there too:
       --ok #116b34: 6.61 white, 5.89 --panel, 5.28 on the deepest green
         chip (#cfece3, admin-review "Approved"); the previous #15803d was
         4.00–4.26 on the green chips (Recommended / Approved / Active).
       --warn #9a4a0a: 6.25 white, 5.57 --panel, 5.22 on the pending
         badge's yellow tint (#f1ebd1).
       --danger #b53536: 5.95 white, 5.30 --panel, 4.82 on the dispute
         reason tint (#ede5ea), 4.90 on the 15% chip (#fde3e3); the previous
         #c03839 was 4.40 / 4.47 there. White on it is 5.95, so the deeper
         danger BUTTON fill (#c53c3d, see the .btn-danger rules) still reads. */
  --ok: #116b34;
  --warn: #9a4a0a;
  --danger: #b53536;
  --info: #7c3aed;
  /* Re-resolve the compatibility aliases in the light scope (see :root note). */
  --text-color: var(--text);
  --muted-text: var(--muted);
  --accent-color: var(--accent);
  --border-color: var(--border);
  --text-primary: var(--text);
  --text-secondary: var(--muted);
  --card-bg: var(--card);
  --input-bg: var(--panel);
  --surface: var(--card);
  --surface-alt: var(--panel);
  --bg-primary: var(--bg);
  --bg-secondary: var(--panel);
  --border-strong: var(--border);
  --primary: var(--accent);
  --on-accent: #ffffff;
}

/* ── THE PHONE'S OWN PREFERENCE, BEFORE ANYONE HAS CHOSEN ───────────────────
   Two jobs, both real.

   FIRST PAINT. The inline bootstrap at the top of every <body> resolves the
   theme and stamps the class, but it cannot run before the stylesheet is
   applied, and a reader with JS off never gets a class at all. This block is
   the default for that moment: whatever the phone is set to. Tokens only — the
   `body.light` rules in the page stylesheets need the class, which arrives a
   moment later.

   AND SAMSUNG INTERNET. Its dark mode defaults to "prefer media query over
   force dark": it uses the site's own styles WHEN prefers-color-scheme is
   implemented, and repaints the page itself when it is not. Declaring
   color-scheme is necessary but was not sufficient — measured on Joel's phone
   on 20 Sept 2026, after color-scheme shipped, the page still came back
   rgb(31,31,31) with the wordmark dimmed by ~0.42, because Samsung's filter
   covers bitmap images and SVG too. This query is the other half of the
   handshake, and it only works because the app really does follow the phone
   now (Joel's call, 20 Sept): no saved choice means the phone decides, and the
   toggle in Settings overrides it for good once touched.

   tools/scan-theme-bootstrap.mjs holds these values identical to body.light's,
   since a token that drifts here shows up as one frame of the wrong colour and
   nothing else. */
@media (prefers-color-scheme: light) {
  body:not(.dark):not(.light) {
    --bg: #f5f7fb;
    --panel: #eef2f9;
    --card: #ffffff;
    --text: #14233b;
    --muted: #5b6a83;
    --accent: #1a6fd0;
    --accent-strong: #155fb8;
    --border: #e1e7f1;
    --shadow: 0 6px 22px rgba(20, 45, 90, 0.07);
    --ok: #116b34;
    --warn: #9a4a0a;
    --danger: #b53536;
    --info: #7c3aed;
    --text-color: var(--text);
    --muted-text: var(--muted);
    --accent-color: var(--accent);
    --border-color: var(--border);
    --text-primary: var(--text);
    --text-secondary: var(--muted);
    --card-bg: var(--card);
    --input-bg: var(--panel);
    --surface: var(--card);
    --surface-alt: var(--panel);
    --bg-primary: var(--bg);
    --bg-secondary: var(--panel);
    --border-strong: var(--border);
    --primary: var(--accent);
    --on-accent: #ffffff;
  }
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body.light {
  background:
    radial-gradient(circle at 12% 0%, rgba(31, 122, 224, 0.05), transparent 42%),
    linear-gradient(180deg, #f8fafd 0%, #f2f5fb 100%);
  color: var(--text);
}

/* ── THE WORDMARK, ON WHATEVER IT LANDS ON ──────────────────────────────────
   TL.png is a two-tone mark and the two tones pull in opposite directions: on
   the 2026-09-20 measurement the TARE half sat at #172f57, which is 1.30:1 on
   the dark navbar (#0c1a2b) — the word was not there — and the LINK half was
   2.40:1 on the light navbar (#eef2f9). Each half failed in the theme the
   other one was drawn for.

   The art is now tuned for the DARK bar: TARE lifted to #3c72c4, so every
   opaque pixel of the mark clears 3:1 on #0c1a2b (worst 3.62:1) and stays
   legible on anything up to white. One filter then takes the whole mark back
   down for a light ground, which restores the deep navy the mark is supposed
   to have there and fixes the LINK half at the same time (worst 4.99:1 on
   --panel, 5.61:1 on white).

   Keyed on the SRC, not on a class, and deliberately: the mark is placed by
   five different call sites in five different files (navbar, the loader
   overlay, the dispatch header, the dispatch home link, fleet-signup) under
   four class names and one inline style, and a sixth would have quietly
   reintroduced the bug. An attribute
   prefix catches `?v=` cache-busts and anything added later.
   tools/scan-logo-contrast.mjs measures both states out of the PNG and fails
   if this rule, or the factor in it, stops matching what it measured. */
body.light img[src^="/shared/TL.png"] {
  filter: brightness(0.6);
}

/* Light mode: accent-filled controls need white text (the accent is deeper than
   the bright dark-mode sky blue, so dark-on-accent reads muddy). */
body.light .primary,
body.light .nav-btn.primary,
body.light .nav-primary,
body.light .pill-active,
body.light .nav-item.active,
body.light .submit-btn,
body.light .btn-primary,
body.light .logout-stay-btn,
/* Accent fills that carry near-black text in dark mode (homepage .btn--accent,
   quarry-setup's numbered .section-num): dark-on-#1a6fd0 is 4.2:1, white is 5. */
body.light .btn--accent,
body.light .section-num,
/* Same family, found by the 2026-09-04 second pass: the bid drawer's "Book"
   button, the myrequests "Go to Your Loads" banner link and the yard map's
   active tab — flat --accent fills with #06182a / #04223b text (3.6 / 3.3). */
body.light .btn-pick,
body.light .moved-btn,
body.light .map-tab.active,
/* Flat --ok / --warn fills that carry near-black text in dark mode. The light
   tokens are deep enough to read as text on white, which makes them too dark
   for black-on-fill — so these get white text too, same as the accent. */
body.light .btn--green,
body.light .bid.best .btn-pick,
body.light .mr-btn-approve,
body.light .dp-btn-pay,
body.light .rp-badge-sel,
body.light .mq-overdue-btn,
body.light .bid-toast-icon {
  color: #ffffff !important;
}

/* nav-primary must keep its accent gradient in light mode — otherwise the
   generic `body.light .nav-btn` paints it white, leaving white-on-white text. */
body.light .nav-primary {
  background: linear-gradient(135deg, var(--accent), var(--accent-strong)) !important;
}

/* Reserve navbar height before JS injects navbar HTML — prevents layout shift */
#navbar-placeholder {
  min-height: 60px;
}

/* Generic panels/cards used across pages */
.card,
.panel,
.order-container,
.order-form,
.settings-container,
.tonnes-calculator,
.load-card,
.completed-card,
.preset-panel,
.calendar-section,
.schedule-card {
  background: var(--card);
  color: var(--text);
  border-color: var(--border);
}

body.light .card,
body.light .panel,
body.light .order-container,
body.light .order-form,
body.light .settings-container,
body.light .tonnes-calculator,
body.light .load-card,
body.light .completed-card,
body.light .preset-panel,
body.light .calendar-section,
body.light .schedule-card {
  background: var(--card);
  color: var(--text);
  border-color: var(--border);
  box-shadow: var(--shadow);
}

h1,
h2,
h3,
h4,
h5,
h6,
label,
strong {
  color: var(--text);
}

.muted,
.eyebrow,
.subhead,
small,
p.muted {
  color: var(--muted);
}

/* ── THE APP-WIDE 44px FLOOR FOR TEXT-ENTRY CONTROLS ────────────────────────
 *
 * Measured live on production at 390×844 across all three roles (walks CA/CB,
 * 17 Sept 2026): form controls rendered ~38px everywhere, against the 44px
 * minimum comfortable touch target (Apple HIG / WCAG 2.5.5 AAA). This rule was
 * already the one place that styles every input in the app and it set no size
 * at all, so each page arrived at ~38 by its own padding and font-size.
 *
 * WHY HERE. It is the only selector that reaches every text-entry control
 * without listing pages, and it needs no page-by-page edit to take effect. An
 * audit of the ten page stylesheets that size controls (56 agents, 17 Sept)
 * found their own rules set padding and font-size but almost never a height,
 * so a floor here lifts them all and their padding still decides the look.
 *
 * WHAT IS DELIBERATELY EXCLUDED, and why each would break:
 *
 *   [type=checkbox], [type=radio]  A 44px checkbox is a CARTOON. These need a
 *     bigger HIT AREA, not a bigger box, and the hit area belongs on the
 *     wrapping <label> — done per page. The pay page's 13×13 PayID/Card radios
 *     are the worst case in the app and are handled at their own rule.
 *   [type=range], [type=color], [type=file]  Native widgets whose own metrics
 *     a min-height distorts rather than enlarges.
 *   [type=hidden]  Has no box; a floor on it is meaningless but harmless —
 *     excluded so the selector states its intent.
 *
 * `box-sizing: border-box` EXPLICITLY, because there is NO global border-box in
 * this app — theme.css's `*` rule sets scrollbar properties only, and about
 * half the page stylesheets declare one while the rest do not. Without it the
 * `1px solid` border below makes these 46px on some pages and 44px on others,
 * and the declared number is not the rendered one.
 *
 * A SELECT NEEDS THE HEIGHT, NOT JUST PADDING: padding on a <select> is
 * honoured inconsistently across engines, so the floor is what actually makes
 * the two line up beside each other in a form row. */
input:not([type='checkbox']):not([type='radio']):not([type='range']):not([type='color']):not([type='file']):not([type='hidden']),
select,
textarea {
  box-sizing: border-box;
  min-height: 44px;
}

/* ── THE APP-WIDE 44px FLOOR FOR THINGS YOU PRESS ───────────────────────────
 *
 * The rule above covers what you TYPE into. This covers what you PRESS, which
 * turned out to be the larger half by a long way: with tools/render-touch-
 * targets.mjs reaching all 66 pages for the first time (17 Sept 2026), 189
 * controls measured under 44px at 390×844, and about 120 of them were plain
 * <button>s sized only by their own padding — tab strips at 33px, admin export
 * buttons at 35px, range pills at 34px, "Add Truck" at 35px.
 *
 * WHY A BARE ELEMENT SELECTOR IS THE RIGHT TOOL, AND WHY IT IS SAFE
 *
 * It is safe in this ONE direction. A floor can only make a control bigger:
 * `min-height` is a clamp, so it wins over a smaller `height` and does nothing
 * to a larger one. Nothing gets smaller because of this rule, which is what
 * makes an app-wide element selector defensible here when it would not be for
 * padding, colour or font.
 *
 * Specificity is doing real work too. At (0,0,1) this loses to any class rule,
 * so a page that has THOUGHT about a control's height keeps its answer — but
 * only if it said `min-height`; `height: 33px` still gets clamped to 44,
 * because min-height and height are different properties and the used value is
 * max(min-height, height). That is the intended behaviour: an explicit small
 * height is exactly the defect being fixed, and the four rules in the app that
 * genuinely need a smaller control say so with their own `min-height` and are
 * left alone.
 *
 * WHAT IS IN THE SELECTOR AND WHY
 *
 *   button, [role='button']   Every real control.
 *   a.primary, a.ghost, a.btn, a.tab-btn   An <a> dressed as a button is a
 *     button to the person tapping it. Only these four classes, not every
 *     anchor: a link inside a sentence must stay in its line box, and 44px on
 *     running prose breaks the paragraph. The harness reports those separately
 *     for exactly that reason.
 *
 * NOT IN THE SELECTOR, deliberately:
 *   a[href] in general — see above.
 *   label:has(input[type=checkbox]) — a checkbox's hit area IS its label and
 *     several are under 20px tall, but a blanket floor on them would stretch
 *     dense table rows and inline consent lines. Handled at each rule instead.
 *
 * A NARROW BUTTON IS STILL A DEFECT. This fixes the block axis only, so a
 * 24×24 icon button becomes a 24×44 sliver. The harness reports width under
 * 44px as its own list; the icon buttons it finds get `min-width` at their own
 * rules, where the layout around them can be seen.
 *
 * WHAT `box-sizing` HERE CHANGES, counted rather than guessed. It is what makes
 * 44 mean 44 — without it a button with `padding: 9px 16px` and a 1px border
 * renders 64px tall, and the floor becomes a redesign. It also changes the
 * rendered size of any button that already declared an explicit width/height
 * PLUS padding or a border and no box-sizing of its own. There are exactly
 * three in the app: .circle-btn (46→44, its declared size), .edit-avatar-btn
 * (34→28) and .edit-name-btn (26→24). All three now measure what their own
 * rule says they are, which is why they were left alone. */
button,
[role='button'],
a.primary,
a.ghost,
a.btn,
a.tab-btn {
  box-sizing: border-box;
  min-height: 44px;
}

input,
select,
textarea {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
}

/* background-COLOR, not the `background` shorthand. The shorthand also sets
   background-image to none — with !important — so in day mode it wiped the
   drawn arrow off every <select> that uses appearance:none (order page, hire,
   weighbridge, Settings): a dropdown with no arrow reads as a text box. Three
   pages had patched around it one at a time with their own !important
   background-image; this is the one rule that caused all of it (Joel's
   Settings recording, 23 Sept 2026). */
body.light input,
body.light select,
body.light textarea {
  background-color: var(--card) !important;
  color: var(--text) !important;
  color-scheme: light !important;
  border-color: var(--border) !important;
}

body.light input::placeholder,
body.light textarea::placeholder {
  color: #a8bcd4 !important;
}

.primary,
.nav-btn.primary {
  background: linear-gradient(135deg, var(--accent), var(--accent-strong));
  color: var(--on-accent, #0a1422);
}

.ghost,
.nav-btn,
.nav-icon {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
}

body.light .ghost,
body.light .nav-btn,
body.light .nav-icon {
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--border);
}

.badge,
.pill,
.chip {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
}

.status-dot {
  background: var(--panel);
  color: var(--text);
}

/* ── Load status badge ──────────────────────────────────────────────────────
   Defined once here because every page that shows one loads theme.css. The
   class comes from statusClass() in /shared/load-status.js and the text from
   statusLabel(); keep the two in step. No text-transform — labels are already
   written in sentence case, and capitalising would render "Pending
   confirmation" as "Pending Confirmation". */
.status-pill {
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--text);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

/* One colour per state, so the state reads at a glance. */
.status-pill.st-open {
  background: rgba(74, 222, 128, 0.15);
  border-color: rgba(74, 222, 128, 0.5);
  color: #c5f6d8;
}

.status-pill.st-assigned,
.status-pill.st-claimed,
.status-pill.st-accepted {
  background: rgba(96, 165, 250, 0.15);
  border-color: rgba(96, 165, 250, 0.5);
  color: #cfe2ff;
}

.status-pill.st-active,
.status-pill.st-in-transit {
  background: rgba(250, 204, 21, 0.15);
  border-color: rgba(250, 204, 21, 0.5);
  color: #fef08a;
}

.status-pill.st-pending-confirmation {
  background: rgba(251, 146, 60, 0.16);
  border-color: rgba(251, 146, 60, 0.55);
  color: #fed7aa;
}

.status-pill.st-completed,
.status-pill.st-delivered {
  background: rgba(45, 212, 191, 0.15);
  border-color: rgba(45, 212, 191, 0.5);
  color: #99f6e4;
}

.status-pill.st-cancelled,
.status-pill.st-expired {
  background: rgba(240, 93, 94, 0.15);
  border-color: rgba(240, 93, 94, 0.5);
  color: #fecdd3;
}

.status-pill.st-parked {
  background: rgba(148, 163, 184, 0.16);
  border-color: rgba(148, 163, 184, 0.45);
  color: #dbe3ee;
}

body.light .status-pill.st-open {
  background: rgba(22, 163, 74, 0.12);
  border-color: rgba(22, 163, 74, 0.5);
  color: #166534;
}

body.light .status-pill.st-assigned,
body.light .status-pill.st-claimed,
body.light .status-pill.st-accepted {
  background: rgba(37, 99, 235, 0.1);
  border-color: rgba(37, 99, 235, 0.4);
  color: #1e40af;
}

body.light .status-pill.st-active,
body.light .status-pill.st-in-transit {
  background: rgba(180, 130, 0, 0.1);
  border-color: rgba(180, 130, 0, 0.45);
  color: #854d0e;
}

body.light .status-pill.st-pending-confirmation {
  background: rgba(234, 88, 12, 0.1);
  border-color: rgba(234, 88, 12, 0.42);
  color: #9a3412;
}

body.light .status-pill.st-completed,
body.light .status-pill.st-delivered {
  background: rgba(5, 150, 105, 0.1);
  border-color: rgba(5, 150, 105, 0.4);
  color: #065f46;
}

body.light .status-pill.st-cancelled,
body.light .status-pill.st-expired {
  background: rgba(220, 38, 38, 0.1);
  border-color: rgba(220, 38, 38, 0.4);
  color: #991b1b;
}

body.light .status-pill.st-parked {
  background: rgba(100, 116, 139, 0.12);
  border-color: rgba(100, 116, 139, 0.4);
  color: #334155;
}

.map-card iframe {
  background: var(--card);
  border: 1px solid var(--border);
}

.back-arrow {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
}

/* ── Global light mode overrides ─────────────────────────────────────────────
   These apply to every page via theme.css so individual pages don't need
   to repeat them. Use !important only where page CSS hardcodes dark colours.
   ────────────────────────────────────────────────────────────────────────── */

body.light .ghost {
  background: var(--card) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}

body.light .back-arrow {
  background: var(--card) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}

/* Custom date picker (cdp) used across multiple pages */
body.light .cdp-trigger,
body.light .cdp-foot-btn,
body.light .cdp-nav {
  background: var(--card) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}

body.light .cdp-cell {
  color: var(--text) !important;
}

body.light .cdp-cell.cdp-past {
  color: var(--border) !important;
}

body.light .cdp-popup {
  background: var(--card) !important;
  border-color: var(--border) !important;
  box-shadow: 0 8px 32px rgba(12, 26, 43, 0.12) !important;
}

/* Checkbox rows / assign blocks used across forms */
body.light .checkbox-row,
body.light .assign-block,
body.light .truck-item,
body.light .preset-item {
  background: var(--panel) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}

/* Modal overlays */
body.light .modal-content,
body.light .modal-box {
  background: var(--card) !important;
  border-color: var(--border) !important;
  color: var(--text) !important;
}

/* Filters / status selects */
body.light .filters select,
body.light .filters input {
  background-color: var(--card) !important;  /* not the shorthand: see the input rule above */
  color-scheme: light !important;
}

/* ── Number inputs: hide the up/down spinner arrows app-wide ──────────────────
   The native spinners look broken/cramped on mobile. Visual only — this does
   not change input behaviour, typing, step, or validation. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}
input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

/* An unresolved suburb is a gap in the record, not a fact about the load —
   amber so it reads as needing attention. Same palette as the pending badge. */
.addr-unset {
  color: #fed7aa;
  background: rgba(251, 146, 60, 0.16);
  border: 1px solid rgba(251, 146, 60, 0.55);
  border-radius: 6px;
  padding: 1px 7px;
  font-weight: 600;
  font-size: 12.5px;
}

body.light .addr-unset {
  color: #9a3412;
  background: rgba(234, 88, 12, 0.1);
  border-color: rgba(234, 88, 12, 0.42);
}

/* Yard-code chip — pairs with shared/material-name.js: yard shorthand like
   "2.1 roadbase" renders as the clean name + this small code tag. */
.yard-code {
  display: inline-block;
  font-family: ui-monospace, monospace;
  font-size: 10.5px;
  color: var(--muted);
  border: 1px dashed var(--border);
  border-radius: 5px;
  padding: 1px 6px;
  margin-left: 6px;
  vertical-align: 1px;
  letter-spacing: 0.02em;
}

/* ── Scrollbars — the stock chrome bar glares on the dark UI ──
   Thin, rounded, track-less; slightly stronger on hover; re-tinted for the
   light theme. Applies everywhere theme.css is loaded, including the inner
   scroll of modals (.popup-box) and chat panes. */
* {
  scrollbar-width: thin;
  scrollbar-color: rgba(155, 176, 211, 0.3) transparent;
}

*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

*::-webkit-scrollbar-track {
  background: transparent;
}

*::-webkit-scrollbar-thumb {
  background-color: rgba(155, 176, 211, 0.3);
  border-radius: 8px;
  /* Transparent edge keeps the thumb off the container's rounded corners. */
  border: 3px solid transparent;
  background-clip: padding-box;
}

*::-webkit-scrollbar-thumb:hover {
  background-color: rgba(155, 176, 211, 0.5);
}

/* BETA-CREDIT LEDGER ROWS.
   shared/wallet-ledger.js renders these and any page may show them, so the
   styling lives with the tokens rather than on one page's stylesheet. The
   figures are tabular so a column of money lines up. */
.wl-balance {
  margin: 0 0 10px;
  font-size: 26px;
  font-weight: 800;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

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

.wl-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13.5px;
}

.wl-row:last-child {
  border-bottom: none;
}

.wl-what {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.wl-desc {
  color: var(--text);
  overflow-wrap: anywhere;
}
.wl-ref { white-space: nowrap; }

.wl-when,
.wl-after {
  color: var(--muted);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
}

.wl-figures {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  white-space: nowrap;
}

.wl-amount {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* "Show all" under a folded ledger (Settings shows five rows, 28 Sept 2026):
   a quiet full-width button, 44px like every other tap target. */
.wl-more {
  display: block;
  width: 100%;
  min-height: 44px;
  margin-top: 8px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: transparent;
  color: var(--accent);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.wl-more:disabled {
  color: var(--muted);
  cursor: default;
}

*::-webkit-scrollbar-corner {
  background: transparent;
}

body.light * {
  scrollbar-color: rgba(60, 80, 110, 0.35) transparent;
}

body.light *::-webkit-scrollbar-thumb {
  background-color: rgba(60, 80, 110, 0.35);
}

body.light *::-webkit-scrollbar-thumb:hover {
  background-color: rgba(60, 80, 110, 0.55);
}

/* ── The gate link: "← Back to the Admin Panel" and "Go to Settings →" ──────
   The platform admin reaches the four fleet-operator pages by URL, and each
   gate carries a way back. Their colour is a THEME decision, not an inline
   one: white on the accent gradient measured 3.44:1 on the pixels, and the
   accent as text on a light card 3.78 (third re-walk of walk CE, 18 Sept
   2026). theme.css's own note says it — accent text on a light panel uses
   --accent-strong (5.57), and white on --accent-strong reads 6.25. */
.tl-gate-link {
  color: var(--accent);
  text-decoration: none;
  font-weight: 700;
}
body.light .tl-gate-link {
  color: var(--accent-strong);
}
.tl-gate-btn {
  background: var(--accent);
  color: var(--on-accent);
  text-decoration: none;
  font-weight: 700;
}
/* The text stays --on-accent (white in light): 6.25 on --accent-strong. */
body.light .tl-gate-btn {
  background: var(--accent-strong);
}

/* No signal (shared/no-signal.js): one amber line under the bar while the
 * phone has no signal, and the same words where a pressed button is waiting
 * for it. Text in --text on a pale amber wash reads in both themes. */
.no-signal-strip,
.kept-note {
  padding: 10px 12px;
  border-radius: 10px;
  background: rgba(245, 166, 35, 0.14);
  border: 1px solid rgba(245, 166, 35, 0.5);
  color: var(--text);
  font-size: 14px;
  line-height: 1.45;
}
.no-signal-strip {
  margin: 8px 16px 0;
  font-weight: 600;
}
.kept-note {
  margin: 10px 0 0;
}
