/* ============================================================================
   theme-spatial.css  —  "Spatial / Advanced" skin for the CPC x Daikin
   Production Dashboard.
   Created 08-Aug-2026.
   ----------------------------------------------------------------------------
   WHAT THIS FILE IS
   -----------------
   A pure LOOK layer. It adds no behaviour, removes no class, renames no id and
   touches no page logic. It is loaded AFTER styles.css and after each page's
   own <style> block, and EVERY rule is scoped under

       html[data-theme="spatial"]

   so it only ever paints when that attribute is present. The attribute prefix
   also gives every rule a higher specificity than a bare Tailwind CDN utility
   (0,2,1 vs 0,1,0), so the theme wins without needing !important.

   HOW TO SWITCH IT OFF
   --------------------
   Remove data-theme="spatial" from the <html> element (the toggle lives in the
   account menu, and the bootstrap script on each page reads/writes it). The
   site instantly returns to the classic white "Focus" look with zero side
   effects — nothing in this file cascades when the attribute is gone.

   PRINTING
   --------
   The @media print block at the bottom re-points every token back to the
   classic light values, kills all glass / shadow / aurora / animation, hides
   the sidebar + tab bar and resets the body padding. Job cards, delivery notes
   and pallet labels therefore print on white paper exactly as today.
   (delivery-note.js printNote() opens its own popup document with its own
   self-contained CSS and no link to this file — it is untouched by the theme,
   which is exactly what we want.)

   MARKUP CONTRACT FOR THE NEW NAVIGATION      (corrected 08-Aug-2026)
   --------------------------------------
   This file owns the CSS; nav.js owns the markup. What nav.js ACTUALLY emits:

     <nav id="app-sidebar" class="app-sidebar">     (fixed left, desktop only)
       <div class="side-brand">
         <img class="side-logo" src="assets/cpc_logo.svg" alt="">
         <span class="side-word">CPC<span class="side-word-sep"> × </span>Daikin</span>
       </div>
       <div class="side-links">
         <a class="side-link active" href="index.html" aria-current="page">
            <span class="side-ic">🏠</span><span class="side-lbl">Dashboard</span>
         </a>
         …one <a> per DESTINATIONS entry the role may see…
       </div>
       <div class="side-foot">
         <div class="side-user">
           <span class="side-avatar">S</span>
           <div class="side-user-txt">
             <div class="side-email">…</div><div class="side-role">…</div>
           </div>
         </div>
         <button class="side-signout" id="app-side-signout">Sign out</button>
       </div>
     </nav>

     <nav id="app-tabbar" class="app-tabbar">       (fixed bottom, phones only)
       <a class="tab-item active" href="index.html">
          <span class="tab-ic">🏠</span><span class="tab-lbl">Home</span>
       </a>
       …max 5…
     </nav>

   TWO VOCABULARIES ON PURPOSE. The first draft of this file styled only a
   longer .app-sidebar-brand / .app-nav-link / .app-tab-label set that nav.js
   never emitted, so on a live page the brand row, the links, the footer and
   the phone tabs were all unstyled and the un-capped .side-logo rendered at
   223x112px. Every navigation rule now lists BOTH names. Do not delete either
   list: the .app-* names are the documented contract, the .side-* / .tab-*
   names are what ships today, and matching both is what makes a rename on
   either side a non-event.

   Defensive styling: every <a> inside .app-sidebar / .app-tabbar is styled
   even if it carries a different class name, and both .active and
   [aria-current="page"] mark the current page. The body padding shim fires on
   body:has(.app-sidebar) — if :has() is unavailable, nav.js also sets
   data-appnav="on" on <html> and class="has-app-shell has-app-nav" on <body>;
   all four hooks are supported here.

   CONTENTS
   --------
     01 Tokens
     02 Base / aurora background
     03 Tailwind arbitrary-colour + named-utility overrides
     04 Surfaces & cards
     05 Buttons
     06 Inputs & selects
     07 Pills, badges, stage colours
     08 Progress, trackers, rings
     09 Disclosure / collapse
     10 Tables
     11 Account menu (nav.js dropdown)
     12 NEW: sidebar + phone tab bar
     13 Station terminal + driver
     14 Floor board
     15 Material stock
     16 Kanban board
     17 Delivery calendar
     18 Analytics
     19 Job card
     20 Cut programs
     21 Documents / command bar / PDF viewer / print jobs / modals
     22 Toast, offline banner, loading splash, scrollbars
     23 JS-injected inline colour mitigations
     23b Inline colour overrides (the one !important zone) + batch chips
     24 Reduced motion
     25 Print reset
   ============================================================================ */


/* ============================================================================
   01  TOKENS
   Re-pointing the 12 tokens styles.css already uses does ~60% of the re-skin
   for free. Everything else in this file is expressed through these tokens too,
   so the print block only has to re-point the tokens (see section 25).
   ============================================================================ */
html[data-theme="spatial"] {
    color-scheme: dark;

    /* --- the 12 original tokens, re-pointed --- */
    --bg:        #070c18;
    --surface:   rgba(19, 30, 50, 0.72);
    --surface-2: rgba(28, 42, 66, 0.66);
    --ink:       #eaf2fb;
    --ink-2:     #a8c0d8;
    --ink-3:     #7c96b2;
    --line:      rgba(120, 170, 220, 0.16);
    --accent:    #0090d4;
    --accent-2:  #38bdf8;
    --green:     #22c55e;
    --amber:     #f59e0b;
    --red:       #f87171;

    /* --- new spatial tokens --- */
    --bg-2:          #0b1220;
    --glass-border:  rgba(120, 170, 220, 0.16);
    --glass-hi:      rgba(255, 255, 255, 0.06);
    --cyan:          #67e8f9;

    /* Solid (non-translucent) surfaces: modals, sticky headers, dropdowns —
       anywhere a see-through panel would let content bleed through. */
    --surface-solid:   #152134;
    --surface-solid-2: #1b2a43;

    /* Semantic inks — all >= 4.5:1 on their own tint, >= 4.5:1 on --surface. */
    --ink-red:    #fca5a5;
    --ink-amber:  #fcd34d;
    --ink-green:  #4ade80;
    --ink-blue:   #7dd3fc;
    --ink-indigo: #a5b4fc;

    /* Semantic tints — light pastels become low-alpha washes of the same hue,
       so a red warning stays red, an amber caution stays amber, etc. */
    --tint-red:       rgba(248, 113, 113, 0.15);
    --tint-amber:     rgba(245, 158, 11, 0.15);
    --tint-green:     rgba(34, 197, 94, 0.15);
    --tint-blue:      rgba(56, 189, 248, 0.15);
    --tint-indigo:    rgba(129, 140, 248, 0.18);
    --tint-neutral:   rgba(255, 255, 255, 0.06);
    --tint-neutral-2: rgba(255, 255, 255, 0.09);
    /* Recessed / inset well — segmented controls, progress tracks, count pills. */
    --recess:         rgba(3, 7, 15, 0.45);

    /* Semantic hairlines */
    --line-red:    rgba(248, 113, 113, 0.38);
    --line-amber:  rgba(245, 158, 11, 0.38);
    --line-blue:   rgba(56, 189, 248, 0.55);
    --line-green:  rgba(34, 197, 94, 0.38);

    /* Depth + glass */
    --glass-blur: blur(14px) saturate(120%);
    --hi-top:     inset 0 1px 0 rgba(255, 255, 255, 0.07);
    --shadow-1:   0 1px 2px rgba(0, 0, 0, 0.4),  0 18px 40px -26px rgba(0, 0, 0, 0.9);
    --shadow-2:   0 2px 6px rgba(0, 0, 0, 0.45), 0 30px 64px -30px rgba(0, 0, 0, 0.95);
    --shadow-lift:0 3px 10px rgba(0, 0, 0, 0.5), 0 40px 80px -34px rgba(0, 0, 0, 1);

    /* Sidebar / tab bar geometry (single source of truth for the shims). */
    --sidebar-w:      248px;
    --sidebar-w-icon: 72px;
    /* --tabbar-h is ALSO depended on OUTSIDE this file (08-Aug-2026): the
       Android app draws a native floating gear button on top of the WebView,
       and android/app/src/main/res/layout/activity_main.xml keeps it clear of
       the tab bar with layout_marginBottom = --tabbar-h + 16dp. Change this
       value → change that margin too, or the gear covers the last tab. */
    --tabbar-h:       64px;

    background: var(--bg);
}


/* ============================================================================
   02  BASE  +  AURORA BACKGROUND
   Four soft radial blooms in two fixed layers that drift on transform only
   (never on background-position — that would repaint the whole viewport).
   No filter: blur() here on purpose: these layers are full-screen and the site
   runs on wall tablets; soft gradient stops give the same look for free.
   ============================================================================ */
html[data-theme="spatial"] body {
    color: var(--ink);
    background: transparent;   /* the aurora shows through; --bg lives on <html> */
    -webkit-font-smoothing: antialiased;
}

html[data-theme="spatial"] body::before,
html[data-theme="spatial"] body::after {
    content: "";
    position: fixed;
    inset: -25vmax;            /* oversized so the drift never exposes an edge */
    z-index: -1;
    pointer-events: none;
    will-change: transform;
}

/* Layer A — Daikin blue (upper left) + cyan (lower right) */
html[data-theme="spatial"] body::before {
    background:
        radial-gradient(38vmax 32vmax at 22% 12%, rgba(0, 144, 212, 0.30) 0%, rgba(0, 144, 212, 0) 62%),
        radial-gradient(34vmax 30vmax at 84% 82%, rgba(103, 232, 249, 0.16) 0%, rgba(103, 232, 249, 0) 64%);
    animation: spatialDriftA 38s ease-in-out infinite alternate;
}

/* Layer B — deep indigo (upper right) + teal (lower left) */
html[data-theme="spatial"] body::after {
    background:
        radial-gradient(40vmax 34vmax at 78% 8%, rgba(56, 189, 248, 0.18) 0%, rgba(56, 189, 248, 0) 60%),
        radial-gradient(36vmax 34vmax at 12% 88%, rgba(45, 212, 191, 0.13) 0%, rgba(45, 212, 191, 0) 62%);
    animation: spatialDriftB 46s ease-in-out infinite alternate;
}

@keyframes spatialDriftA {
    0%   { transform: translate3d(0, 0, 0)            scale(1); }
    50%  { transform: translate3d(3.5vmax, 2.5vmax, 0) scale(1.06); }
    100% { transform: translate3d(-2.5vmax, 4vmax, 0)  scale(1.02); }
}
@keyframes spatialDriftB {
    0%   { transform: translate3d(0, 0, 0)             scale(1.03); }
    50%  { transform: translate3d(-4vmax, 3vmax, 0)     scale(1); }
    100% { transform: translate3d(3vmax, -3.5vmax, 0)   scale(1.07); }
}

/* Text selection + keyboard focus ring (bumped to accent-2 for contrast). */
html[data-theme="spatial"] ::selection { background: rgba(56, 189, 248, 0.32); color: #ffffff; }
html[data-theme="spatial"] button:focus-visible,
html[data-theme="spatial"] a:focus-visible,
html[data-theme="spatial"] [role="button"]:focus-visible {
    outline: 2px solid var(--accent-2);
    outline-offset: 2px;
}

/* Brand logos. The CPC mark is a red oval with white text (fine on dark); the
   Daikin PNG is dark-blue artwork on transparent, so it gets a small white
   plate to stay legible and on-brand. box-sizing is border-box (Tailwind
   preflight) so the h-9 / h-11 heights do not change. */
html[data-theme="spatial"] img[src*="daikin_logo"] {
    background: rgba(255, 255, 255, 0.94);
    border-radius: 8px;
    padding: 3px 7px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}


/* ============================================================================
   03  TAILWIND OVERRIDES
   All 42 hardcoded arbitrary-hex utilities (710 uses across the 12 pages),
   their hover: variants, plus the named utilities the pages use (bg-white,
   bg-white/85). Every value goes through a token so section 25 can restore the
   classic look for print by re-pointing tokens only.
   ============================================================================ */

/* ---- text: neutrals ---- */
html[data-theme="spatial"] .text-\[\#6e6e73\] { color: var(--ink-3); }   /* 238 */
html[data-theme="spatial"] .text-\[\#0b2740\] { color: var(--ink);   }   /*  87 */
html[data-theme="spatial"] .text-\[\#424245\] { color: var(--ink-2); }   /*  45 */
html[data-theme="spatial"] .text-\[\#86868b\] { color: var(--ink-3); }   /*  20 */
html[data-theme="spatial"] .text-\[\#44607b\] { color: var(--ink-2); }   /*  10 */
html[data-theme="spatial"] .text-\[\#d2d2d7\] { color: rgba(178, 200, 222, 0.62); } /* 1 — the "|" divider */
html[data-theme="spatial"] .text-\[\#c7c7cc\] { color: var(--ink-3); }   /*   1 */

/* ---- text: blue (links / info) ---- */
html[data-theme="spatial"] .text-\[\#0090d4\] { color: var(--accent-2); } /* 38 */
html[data-theme="spatial"] .text-\[\#0067b3\] { color: var(--accent-2); } /*  7 */

/* ---- text: red (danger) ---- */
html[data-theme="spatial"] .text-\[\#c11717\] { color: var(--ink-red); }  /* 26 */

/* ---- text: amber (warning) ---- */
html[data-theme="spatial"] .text-\[\#8a4b00\] { color: var(--ink-amber); } /* 16 */
html[data-theme="spatial"] .text-\[\#b35309\] { color: var(--ink-amber); } /*  3 */
html[data-theme="spatial"] .text-\[\#9a6b00\] { color: var(--ink-amber); } /*  1 */

/* ---- text: green (success) ---- */
html[data-theme="spatial"] .text-\[\#1d8a4e\] { color: var(--ink-green); } /* 12 */
html[data-theme="spatial"] .text-\[\#178045\] { color: var(--ink-green); } /*  4 */
html[data-theme="spatial"] .text-\[\#1d7a44\] { color: var(--ink-green); } /*  1 */
html[data-theme="spatial"] .text-\[\#1a7f37\] { color: var(--ink-green); } /*  1 */

/* ---- text: indigo ---- */
html[data-theme="spatial"] .text-\[\#3a3fbf\] { color: var(--ink-indigo); } /* 4 */

/* ---- backgrounds: neutral ---- */
html[data-theme="spatial"] .bg-\[\#f5f5f7\] { background-color: var(--surface-2); }   /* 20 */
html[data-theme="spatial"] .bg-\[\#eef3f9\] { background-color: var(--surface-2); }   /* 10 */
html[data-theme="spatial"] .bg-\[\#f0f0f2\] { background-color: var(--recess); }      /*  7 — segmented-control track + count pills */
html[data-theme="spatial"] .bg-\[\#eef4fa\] { background-color: var(--tint-neutral-2); } /* 4 */
html[data-theme="spatial"] .bg-\[\#ececef\] { background-color: var(--tint-neutral-2); } /* 1 */
html[data-theme="spatial"] .bg-\[\#e6edf4\] { background-color: var(--surface-2); }   /*  1 */

/* ---- backgrounds: red / amber / green / blue / indigo tints ---- */
html[data-theme="spatial"] .bg-\[\#ffe5e5\] { background-color: var(--tint-red); }    /* 21 */
html[data-theme="spatial"] .bg-\[\#fff4e5\] { background-color: var(--tint-amber); }  /* 16 */
html[data-theme="spatial"] .bg-\[\#fff2dd\] { background-color: var(--tint-amber); }  /*  3 */
html[data-theme="spatial"] .bg-\[\#fff4e0\] { background-color: var(--tint-amber); }  /*  1 */
html[data-theme="spatial"] .bg-\[\#e8f7ee\] { background-color: var(--tint-green); }  /*  5 */
html[data-theme="spatial"] .bg-\[\#e3f7eb\] { background-color: var(--tint-green); }  /*  2 */
html[data-theme="spatial"] .bg-\[\#e6f7ea\] { background-color: var(--tint-green); }  /*  1 */
html[data-theme="spatial"] .bg-\[\#e6f6ec\] { background-color: var(--tint-green); }  /*  1 */
html[data-theme="spatial"] .bg-\[\#e6f4fc\] { background-color: var(--tint-blue); }   /*  8 */
html[data-theme="spatial"] .bg-\[\#eef6fb\] { background-color: var(--tint-blue); }   /*  1 */
html[data-theme="spatial"] .bg-\[\#eef0ff\] { background-color: var(--tint-indigo); } /*  4 */

/* ---- borders ---- */
html[data-theme="spatial"] .border-\[\#e6edf4\] { border-color: var(--glass-border); } /* 56 */
html[data-theme="spatial"] .border-\[\#eef3f9\] { border-color: var(--glass-border); } /*  2 */
html[data-theme="spatial"] .border-\[\#f0f0f2\] { border-color: var(--glass-border); } /*  1 */
html[data-theme="spatial"] .border-\[\#eee\]    { border-color: var(--glass-border); } /*  1 */
html[data-theme="spatial"] .border-\[\#f5d9a8\] { border-color: var(--line-amber); }   /* 14 */
html[data-theme="spatial"] .border-\[\#f3b8b8\] { border-color: var(--line-red); }     /* 12 */
html[data-theme="spatial"] .border-\[\#0090d4\] { border-color: var(--line-blue); }    /*  3 */

/* ---- hover: variants ---- */
html[data-theme="spatial"] .hover\:text-\[\#0b2740\]:hover { color: var(--ink); }
html[data-theme="spatial"] .hover\:bg-\[\#eef4fa\]:hover   { background-color: var(--tint-neutral-2); }
html[data-theme="spatial"] .hover\:bg-\[\#e6f4fc\]:hover   { background-color: var(--tint-blue); }
html[data-theme="spatial"] .hover\:bg-\[\#f5f5f7\]:hover   { background-color: var(--tint-neutral); }
html[data-theme="spatial"] .hover\:bg-\[\#ececef\]:hover   { background-color: var(--tint-neutral-2); }
html[data-theme="spatial"] .hover\:bg-\[\#e6edf4\]:hover   { background-color: var(--tint-neutral-2); }

/* ---- named utilities ---- */
/* bg-white is the modal card / dropdown / raised segmented-control pill and a
   few inline admin rows: it must stay the RAISED surface, one step lighter than
   the recessed track it sits in. */
html[data-theme="spatial"] .bg-white     { background-color: var(--surface-solid-2); }
html[data-theme="spatial"] .bg-white\/85 { background-color: rgba(21, 33, 52, 0.85); }
/* Tailwind's shadow-sm/shadow-2xl are invisible on dark — give them presence. */
html[data-theme="spatial"] .shadow-sm  { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.45), var(--hi-top); }
html[data-theme="spatial"] .shadow-2xl { box-shadow: var(--shadow-lift); }


/* ============================================================================
   04  SURFACES & CARDS
   Frosted glass: translucent fill + 1px glass hairline + inner top highlight +
   layered shadow. backdrop-filter is used only on the LARGE containers; the
   high-count row-level items use a plain translucent fill so a station terminal
   with 40 tiles or a kanban board with 200 cards stays smooth on a tablet.
   Radii are kept at the values styles.css already uses.
   ============================================================================ */
html[data-theme="spatial"] .login-container,
html[data-theme="spatial"] .dashboard-card,
html[data-theme="spatial"] .admin-card,
html[data-theme="spatial"] .kpi-card,
html[data-theme="spatial"] .sor-card,
html[data-theme="spatial"] .stn-card,
html[data-theme="spatial"] .floor-col,
html[data-theme="spatial"] .stat-box,
html[data-theme="spatial"] .kanban-col,
html[data-theme="spatial"] .jobcard {
    background: var(--surface);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border: 1px solid var(--glass-border);
    box-shadow: var(--hi-top), var(--shadow-1);
}

/* Browsers without backdrop-filter get a slightly more opaque fill so the
   aurora never shows through as noise behind text. */
@supports not ((-webkit-backdrop-filter: blur(2px)) or (backdrop-filter: blur(2px))) {
    html[data-theme="spatial"] .login-container,
    html[data-theme="spatial"] .dashboard-card,
    html[data-theme="spatial"] .admin-card,
    html[data-theme="spatial"] .kpi-card,
    html[data-theme="spatial"] .sor-card,
    html[data-theme="spatial"] .stn-card,
    html[data-theme="spatial"] .floor-col,
    html[data-theme="spatial"] .stat-box,
    html[data-theme="spatial"] .kanban-col,
    html[data-theme="spatial"] .jobcard,
    html[data-theme="spatial"] .app-sidebar,
    html[data-theme="spatial"] .app-tabbar,
    html[data-theme="spatial"] .nav-panel { background: #101a2c; }
}

html[data-theme="spatial"] .login-container { box-shadow: var(--hi-top), var(--shadow-2); }

html[data-theme="spatial"] .dashboard-card:hover,
html[data-theme="spatial"] .kpi-card:hover,
html[data-theme="spatial"] .sor-card:hover {
    border-color: rgba(120, 170, 220, 0.26);
    box-shadow: var(--hi-top), var(--shadow-lift);
}

/* KPI live-update flash — cyan on dark instead of the light-theme blue. */
html[data-theme="spatial"] .kpi-label,
html[data-theme="spatial"] .kpi-sub { color: var(--ink-3); }
html[data-theme="spatial"] .kpi-value { color: var(--ink); }
@keyframes spatialKpiFlash {
    0%   { box-shadow: var(--hi-top), 0 0 0 0 rgba(56, 189, 248, 0.5); }
    100% { box-shadow: var(--hi-top), 0 0 0 14px rgba(56, 189, 248, 0); }
}
html[data-theme="spatial"] .kpi-flash { animation: spatialKpiFlash 0.7s ease-out; }

/* Row-level surfaces (no backdrop-filter — these appear in the hundreds). */
html[data-theme="spatial"] .unit-row,
html[data-theme="spatial"] .comp-row,
html[data-theme="spatial"] .admin-row,
html[data-theme="spatial"] .note-card,
html[data-theme="spatial"] .op-row,
html[data-theme="spatial"] .kanban-card,
html[data-theme="spatial"] .deliv-row {
    background: var(--surface-2);
    border: 1px solid var(--glass-border);
    box-shadow: var(--hi-top), 0 1px 2px rgba(0, 0, 0, 0.32);
}
html[data-theme="spatial"] .unit-row:hover,
html[data-theme="spatial"] .admin-row:hover,
html[data-theme="spatial"] .note-card:hover,
html[data-theme="spatial"] .kanban-card:hover {
    background: rgba(38, 56, 86, 0.72);
    border-color: rgba(120, 170, 220, 0.28);
    box-shadow: var(--hi-top), 0 10px 26px -14px rgba(0, 0, 0, 0.9);
}

/* Paint visibility (11-Aug-2026): the generic .unit-row rule above resets all
   borders, so the painted stripe must be re-asserted here (hover too, or the
   stripe would flick off while the pointer is on the row). Chip colours
   re-tinted for the dark glass surfaces. */
html[data-theme="spatial"] .unit-row.painted,
html[data-theme="spatial"] .unit-row.painted:hover { border-left: 4px solid #a78bfa; }
html[data-theme="spatial"] .paint-chip {
    background: rgba(139, 92, 246, 0.18);
    color: #c4b5fd;
    border-color: rgba(167, 139, 250, 0.45);
}
html[data-theme="spatial"] .paint-chip.off {
    background: var(--tint-neutral);
    color: var(--ink-3);
    border-color: var(--glass-border);
}
/* Whole-unit chip stays solid violet + blinking on the dark look too. */
html[data-theme="spatial"] .paint-chip.full {
    background: #7c3aed;
    color: #ffffff;
    border-color: #a78bfa;
}

/* Low-stock board (stock page, 11-Aug-2026): dark-glass re-tints. The fill
   colours (#ef4444 / #f59e0b) are bright enough on both looks and stay as-is;
   only the text and the track need theme-aware colours. */
html[data-theme="spatial"] .low-board-name { color: var(--ink); }
html[data-theme="spatial"] .low-board-name small { color: var(--ink-3); }
html[data-theme="spatial"] .low-board-track { background: var(--tint-neutral); }
html[data-theme="spatial"] .low-board-qty.crit { color: #fca5a5; }
html[data-theme="spatial"] .low-board-qty.warn { color: #fcd34d; }

/* Dirty (unsaved) admin row + low-stock row. */
html[data-theme="spatial"] .admin-row.dirty {
    border-color: var(--line-amber);
    box-shadow: var(--hi-top), 0 0 0 3px rgba(245, 158, 11, 0.16);
}
html[data-theme="spatial"] .admin-row.material-low {
    border-color: var(--line-red);
    background: linear-gradient(0deg, var(--tint-red), var(--tint-red)), var(--surface-2);
}

/* High-urgency note glow — red pulse re-tuned for a dark ground. */
html[data-theme="spatial"] .note-high-alert { border-color: var(--line-red) !important; }
@keyframes spatialNoteHighGlow {
    0%, 100% { box-shadow: var(--hi-top), 0 0 0 0 rgba(248, 113, 113, 0.30); }
    50%      { box-shadow: var(--hi-top), 0 0 0 4px rgba(248, 113, 113, 0.10); }
}
html[data-theme="spatial"] .note-high-alert { animation: spatialNoteHighGlow 1.6s ease-in-out infinite; }

/* Generic helpers that styles.css leaves untinted. */
html[data-theme="spatial"] .lbl { color: var(--ink-3); }


/* ============================================================================
   05  BUTTONS
   ============================================================================ */
/* CONTRAST (fixed 08-Aug-2026): the first draft used a bright #22b6f2 -> #0083cc
   ramp, which put white text at 3.05:1 — below AA for any size. The ramp is now
   darkened so the LIGHTEST stop still clears 4.5:1 against #ffffff, and :hover
   no longer uses filter:brightness() (which pushed it straight back under the
   line); hover/active get their own measured ramps instead.
     #0a75ad on white = 5.05:1   #0059a3 = 7.10:1   (rest)
     #0b7ab5 on white = 4.70:1   #0062b0 = 6.22:1   (hover)
     #095f8f on white = 6.72:1   #004a87 = 8.94:1   (active) */
html[data-theme="spatial"] .btn-primary {
    background: linear-gradient(180deg, #0a75ad, #0059a3);
    color: #ffffff;
    border: 1px solid rgba(120, 200, 245, 0.45);
    box-shadow: var(--hi-top), 0 8px 22px -10px rgba(0, 144, 212, 0.85);
}
html[data-theme="spatial"] .btn-primary:hover {
    background: linear-gradient(180deg, #0b7ab5, #0062b0);
    filter: none;
    border-color: rgba(150, 215, 250, 0.6);
    box-shadow: var(--hi-top), 0 10px 28px -10px rgba(56, 189, 248, 0.9);
}
html[data-theme="spatial"] .btn-primary:active {
    background: linear-gradient(180deg, #095f8f, #004a87);
    box-shadow: var(--hi-top), 0 4px 12px -8px rgba(0, 144, 212, 0.9);
}
html[data-theme="spatial"] .btn-primary:disabled { opacity: 0.42; filter: none; }

html[data-theme="spatial"] .btn-ghost {
    background: var(--surface-2);
    -webkit-backdrop-filter: blur(10px) saturate(120%);
    backdrop-filter: blur(10px) saturate(120%);
    color: var(--ink);
    border: 1px solid var(--glass-border);
    box-shadow: var(--hi-top);
}
html[data-theme="spatial"] .btn-ghost:hover {
    background: rgba(44, 64, 96, 0.78);
    border-color: rgba(120, 170, 220, 0.34);
}
html[data-theme="spatial"] .btn-ghost.notif-on {
    background: var(--tint-green);
    border-color: var(--line-green);
    color: var(--ink-green);
}
html[data-theme="spatial"] .btn-ghost.notif-denied { opacity: 0.5; }
html[data-theme="spatial"] .btn-ghost .ripple { background: rgba(103, 232, 249, 0.30); }

/* List / grid view toggle (admin.html, documents.html) */
html[data-theme="spatial"] .view-toggle { border-color: var(--glass-border); background: var(--recess); }
html[data-theme="spatial"] .view-toggle-btn { background: transparent; color: var(--ink-2); }
html[data-theme="spatial"] .view-toggle-btn + .view-toggle-btn { border-left-color: var(--glass-border); }
html[data-theme="spatial"] .view-toggle-btn:hover { background: var(--tint-neutral); color: var(--ink); }
/* Same white-on-cyan failure as .btn-primary — same measured ramp. */
html[data-theme="spatial"] .view-toggle-btn.active {
    background: linear-gradient(180deg, #0a75ad, #0059a3);
    color: #ffffff;
}


/* ============================================================================
   06  INPUTS & SELECTS
   color-scheme:dark (section 01) already gives native <select> popups, date
   pickers and number spinners a dark UI; these rules do the visible chrome.
   ============================================================================ */
html[data-theme="spatial"] .field,
html[data-theme="spatial"] .admin-input,
html[data-theme="spatial"] .stn-picker,
html[data-theme="spatial"] textarea,
html[data-theme="spatial"] select.field,
html[data-theme="spatial"] select.admin-input {
    background: rgba(6, 12, 24, 0.55);
    border: 1px solid var(--glass-border);
    color: var(--ink);
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.5);
}
html[data-theme="spatial"] .field::placeholder,
html[data-theme="spatial"] .admin-input::placeholder,
html[data-theme="spatial"] textarea::placeholder { color: var(--ink-3); opacity: 1; }

html[data-theme="spatial"] .field:focus,
html[data-theme="spatial"] .admin-input:focus,
html[data-theme="spatial"] textarea:focus {
    background: rgba(10, 20, 36, 0.85);
    border-color: var(--accent-2);
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.5), 0 0 0 4px rgba(56, 189, 248, 0.22);
}

/* Native option list fallback for engines that ignore color-scheme. */
html[data-theme="spatial"] option { background: var(--surface-solid); color: var(--ink); }

/* The file picker's own button is UA chrome — color-scheme does not reach it,
   so documents.html's "Choose file" was a light-grey patch on dark glass.
   ::-webkit-file-upload-button is the older WebView spelling (Android app). */
html[data-theme="spatial"] input[type="file"] { color: var(--ink-2); }
html[data-theme="spatial"] input[type="file"]::file-selector-button {
    margin-right: 10px;
    padding: 6px 12px;
    border: 1px solid var(--glass-border);
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--ink);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    box-shadow: var(--hi-top);
}
html[data-theme="spatial"] input[type="file"]::file-selector-button:hover {
    background: var(--tint-neutral-2);
    border-color: rgba(120, 170, 220, 0.34);
}
html[data-theme="spatial"] input[type="file"]::-webkit-file-upload-button {
    margin-right: 10px;
    padding: 6px 12px;
    border: 1px solid var(--glass-border);
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--ink);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

/* Password "Show/Hide" toggle: 16px tall text button = far below the 44px tap
   target the wall tablets need. Grow the hit box with padding and pull it back
   with an equal negative margin so nothing moves visually. */
html[data-theme="spatial"] #toggle-pw {
    padding: 12px 8px;
    margin: -12px -8px;
    line-height: 1;
}

/* Low-stock threshold input keeps its red warning identity. */
html[data-theme="spatial"] .stock-low-input {
    border-color: var(--line-red) !important;
    color: var(--ink-red);
    background: var(--tint-red);
}


/* ============================================================================
   07  PILLS, BADGES, STAGE COLOURS
   The 9 .stage-* classes are generated at runtime by sor-common.js
   stageClass() — they never appear literally in the HTML/JS, so do NOT let a
   grep-based audit tell you they are dead. Each pill is now a low-alpha wash of
   its own hue with a matching bright ink and a 1px inner ring; every pairing
   measures >= 5.7:1.
   ============================================================================ */
html[data-theme="spatial"] .stage-pill,
html[data-theme="spatial"] .jc-stage {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
}
html[data-theme="spatial"] .stage-pending    { background: rgba(148, 163, 184, 0.16); color: #cbd5e1; box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.30); }
html[data-theme="spatial"] .stage-design     { background: rgba(167, 139, 250, 0.16); color: #c4b5fd; box-shadow: inset 0 0 0 1px rgba(167, 139, 250, 0.32); }
html[data-theme="spatial"] .stage-cutting    { background: rgba(56, 189, 248, 0.16);  color: #38bdf8; box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.32); }
html[data-theme="spatial"] .stage-bending    { background: rgba(45, 212, 191, 0.16);  color: #2dd4bf; box-shadow: inset 0 0 0 1px rgba(45, 212, 191, 0.32); }
html[data-theme="spatial"] .stage-welding    { background: rgba(251, 146, 60, 0.16);  color: #fb923c; box-shadow: inset 0 0 0 1px rgba(251, 146, 60, 0.32); }
html[data-theme="spatial"] .stage-paint      { background: rgba(244, 114, 182, 0.16); color: #f9a8d4; box-shadow: inset 0 0 0 1px rgba(244, 114, 182, 0.32); }
html[data-theme="spatial"] .stage-packing    { background: rgba(251, 191, 36, 0.16);  color: #fbbf24; box-shadow: inset 0 0 0 1px rgba(251, 191, 36, 0.32); }
html[data-theme="spatial"] .stage-dispatched { background: rgba(129, 140, 248, 0.18); color: #a5b4fc; box-shadow: inset 0 0 0 1px rgba(129, 140, 248, 0.34); }
html[data-theme="spatial"] .stage-delivered  { background: rgba(34, 197, 94, 0.16);   color: #22c55e; box-shadow: inset 0 0 0 1px rgba(34, 197, 94, 0.32); }

/* Urgency badges */
html[data-theme="spatial"] .badge-high   { background-color: var(--tint-red);   color: var(--ink-red);   box-shadow: inset 0 0 0 1px var(--line-red); }
html[data-theme="spatial"] .badge-medium { background-color: var(--tint-amber); color: var(--ink-amber); box-shadow: inset 0 0 0 1px var(--line-amber); }
html[data-theme="spatial"] .badge-low    { background-color: var(--tint-blue);  color: var(--ink-blue);  box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.32); }
@keyframes spatialBadgePulse {
    0%, 100% { box-shadow: inset 0 0 0 1px var(--line-red), 0 0 0 0 rgba(248, 113, 113, 0.5); }
    50%      { box-shadow: inset 0 0 0 1px var(--line-red), 0 0 0 6px rgba(248, 113, 113, 0); }
}
html[data-theme="spatial"] .badge-high-pulse { animation: spatialBadgePulse 1.6s ease-in-out infinite; }

/* Quantity pill — was dark navy on white; inverted so it reads on dark glass. */
html[data-theme="spatial"] .qty-pill {
    background: var(--tint-neutral-2);
    color: var(--ink);
    box-shadow: inset 0 0 0 1px var(--glass-border);
}

/* Generic count / meta pills */
html[data-theme="spatial"] .stn-count-pill {
    background: var(--recess);
    border-color: var(--glass-border);
    color: var(--ink);
}
html[data-theme="spatial"] .op-chip {
    background: var(--recess);
    border-color: var(--glass-border);
    color: var(--ink-2);
}
html[data-theme="spatial"] .tag { color: inherit; }

/* Live dot */
html[data-theme="spatial"] .live-dot { background: #34d399; }
@keyframes spatialLivePulse {
    0%   { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55); }
    70%  { box-shadow: 0 0 0 7px rgba(52, 211, 153, 0); }
    100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0); }
}
html[data-theme="spatial"] .live-dot { animation: spatialLivePulse 2s infinite; }


/* ============================================================================
   08  PROGRESS, TRACKERS, RINGS
   ============================================================================ */
html[data-theme="spatial"] .progress-track {
    background: var(--recess);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.55);
}
html[data-theme="spatial"] .progress-fill {
    background: linear-gradient(90deg, #0090d4, #67e8f9);
    box-shadow: 0 0 12px -2px rgba(56, 189, 248, 0.65);
}
html[data-theme="spatial"] .progress-fill.complete { background: linear-gradient(90deg, #16a34a, #4ade80); box-shadow: 0 0 12px -2px rgba(74, 222, 128, 0.6); }
html[data-theme="spatial"] .progress-fill.behind   { background: linear-gradient(90deg, #ea580c, #fbbf24); box-shadow: 0 0 12px -2px rgba(251, 191, 36, 0.6); }
html[data-theme="spatial"] .progress-fill::after {
    background-image: linear-gradient(90deg,
        rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.55) 50%, rgba(255, 255, 255, 0) 100%);
}

/* Batch-segmented bar: the segment track keeps its (JS-set) batch tint but is
   seated in a recessed well so the light pastel does not float. */
html[data-theme="spatial"] .batch-progress-seg {
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35);
}

/* 7-segment component tracker */
html[data-theme="spatial"] .track-seg { background: var(--recess); }
html[data-theme="spatial"] .track-seg.done      { background: var(--accent-2); box-shadow: 0 0 8px -1px rgba(56, 189, 248, 0.7); }
html[data-theme="spatial"] .track-seg.delivered { background: var(--green);    box-shadow: 0 0 8px -1px rgba(34, 197, 94, 0.6); }
html[data-theme="spatial"] .track-labels { color: var(--ink-3); }
html[data-theme="spatial"] .track-labels span.at     { color: var(--accent-2); }
html[data-theme="spatial"] .track-labels span.at-del { color: var(--ink-green); }

/* Celebration + confetti stay as-is (already bright); only the badge gets a
   deeper shadow so it lifts off the dark ground. */
html[data-theme="spatial"] .celebrate-pop {
    background: linear-gradient(180deg, #22c55e, #15803d);
    box-shadow: 0 24px 60px -18px rgba(34, 197, 94, 0.75), var(--hi-top);
}


/* ============================================================================
   09  DISCLOSURE / COLLAPSE
   ============================================================================ */
html[data-theme="spatial"] .completed-divider {
    color: var(--ink-green);
    border-top-color: var(--glass-border);
}
html[data-theme="spatial"] .completed-divider:hover { background: var(--tint-neutral); }
html[data-theme="spatial"] .completed-caret,
html[data-theme="spatial"] .sor-caret,
html[data-theme="spatial"] .unit-caret,
html[data-theme="spatial"] .stock-group-caret { color: var(--ink-3); }
html[data-theme="spatial"] .sor-head:hover,
html[data-theme="spatial"] .admin-sor-head:hover,
html[data-theme="spatial"] .stock-group-head:not([class*="metal-"]):hover { background: var(--tint-neutral); }


/* ============================================================================
   10  TABLES  (job card, analytics scrap/rework, cut programs)
   ============================================================================ */
html[data-theme="spatial"] .jc-table th,
html[data-theme="spatial"] .sr-table th {
    color: var(--ink-3);
    border-bottom-color: var(--glass-border);
}
html[data-theme="spatial"] .jc-table td,
html[data-theme="spatial"] .sr-table td {
    color: var(--ink);
    border-bottom-color: var(--glass-border);
}
html[data-theme="spatial"] .sr-table tbody tr:hover td { background: var(--tint-neutral); }


/* ============================================================================
   11  ACCOUNT MENU (nav.js dropdown — ids #nav-trigger / #nav-panel /
   #nav-signout and the hidden toggle are untouched)
   ============================================================================ */
html[data-theme="spatial"] .nav-trigger {
    background: var(--surface-2);
    -webkit-backdrop-filter: blur(10px) saturate(120%);
    backdrop-filter: blur(10px) saturate(120%);
    border-color: var(--glass-border);
    box-shadow: var(--hi-top);
}
html[data-theme="spatial"] .nav-trigger:hover {
    border-color: rgba(120, 170, 220, 0.34);
    box-shadow: var(--hi-top), 0 6px 18px -8px rgba(0, 0, 0, 0.8);
}
html[data-theme="spatial"] .nav-avatar { background: linear-gradient(135deg, #38bdf8, #0067b3); }
html[data-theme="spatial"] .nav-caret  { color: var(--ink-3); }

html[data-theme="spatial"] .nav-panel {
    background: var(--surface-solid);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border-color: var(--glass-border);
    box-shadow: var(--hi-top), var(--shadow-lift);
}
html[data-theme="spatial"] .nav-panel-head { border-bottom-color: var(--glass-border); }
html[data-theme="spatial"] .nav-email { color: var(--ink); }
html[data-theme="spatial"] .nav-role  { color: var(--ink-3); }
html[data-theme="spatial"] .nav-link  { color: var(--ink); }
html[data-theme="spatial"] .nav-link:hover { background: var(--tint-neutral-2); }
html[data-theme="spatial"] .nav-link.active {
    background: var(--tint-blue);
    color: var(--accent-2);
    box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.28);
}
html[data-theme="spatial"] .nav-dot { color: var(--accent-2); }
html[data-theme="spatial"] .nav-signout {
    color: var(--ink-red);
    border-top-color: var(--glass-border);
}
html[data-theme="spatial"] .nav-signout:hover { background: var(--tint-red); }


/* ============================================================================
   12  NEW NAVIGATION — DESKTOP SIDEBAR + PHONE TAB BAR
   Markup contract is documented in the file header. nav.js builds both from the
   same DESTINATIONS array it already uses for the dropdown, so role visibility
   stays in one place.
   ============================================================================ */

/* ---- 12a  Sidebar ---- */
html[data-theme="spatial"] .app-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 40;
    width: var(--sidebar-w);
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 18px 12px 14px;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--surface);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border-right: 1px solid var(--glass-border);
    box-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.04), 12px 0 40px -28px rgba(0, 0, 0, 1);
    transition: width 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---------------------------------------------------------------------------
   CLASS-NAME CONTRACT (fixed 08-Aug-2026)
   nav.js emits the SHORT vocabulary (.side-brand / .side-logo / .side-word /
   .side-word-sep / .side-links / .side-link / .side-ic / .side-lbl /
   .side-foot / .side-user / .side-avatar / .side-user-txt / .side-email /
   .side-role / .side-signout / .tab-item / .tab-ic / .tab-lbl). The original
   draft of this file only styled the LONG .app-* vocabulary, so on a real page
   nothing below the sidebar box was themed. Every rule from here on lists BOTH
   names — the .app-* names are kept so a future markup change back to them
   still paints, and the .side-* / .tab-* names are what actually ship today.
   --------------------------------------------------------------------------- */
html[data-theme="spatial"] .app-sidebar-brand,
html[data-theme="spatial"] .side-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 8px 14px;
    margin-bottom: 6px;
    border-bottom: 1px solid var(--glass-border);
    min-height: 46px;
}
/* The CPC mark is a 223x112 SVG with no intrinsic cap — without this it eats
   the whole top of the rail. Cap it in BOTH axes and let it letterbox. */
html[data-theme="spatial"] .app-sidebar-brand img,
html[data-theme="spatial"] .app-sidebar-brand svg,
html[data-theme="spatial"] .side-brand img,
html[data-theme="spatial"] .side-brand svg,
html[data-theme="spatial"] .side-logo {
    max-height: 30px;
    max-width: 38px;
    width: auto;
    height: auto;
    object-fit: contain;
    flex: none;
}
html[data-theme="spatial"] .app-sidebar-wordmark,
html[data-theme="spatial"] .side-word {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    min-width: 0;
}
html[data-theme="spatial"] .side-word-sep { color: var(--accent-2); font-weight: 500; }

html[data-theme="spatial"] .app-sidebar-nav,
html[data-theme="spatial"] .side-links {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1 1 auto;
    min-height: 0;
}

/* Styled by tag as well as by class, so a differently-named link class still
   picks the theme up. */
html[data-theme="spatial"] .app-sidebar a,
html[data-theme="spatial"] .app-nav-link,
html[data-theme="spatial"] .side-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 10px 12px;
    border-radius: 12px;
    font-size: 0.88rem;
    font-weight: 500;
    line-height: 1.2;
    color: var(--ink-2);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    transition: background 0.15s ease, color 0.15s ease, transform 0.15s cubic-bezier(0.22, 1, 0.36, 1);
}
html[data-theme="spatial"] .app-sidebar a:hover,
html[data-theme="spatial"] .app-nav-link:hover,
html[data-theme="spatial"] .side-link:hover {
    background: var(--tint-neutral-2);
    color: var(--ink);
    transform: translateX(2px);
}
html[data-theme="spatial"] .app-sidebar a.active,
html[data-theme="spatial"] .app-sidebar a[aria-current="page"],
html[data-theme="spatial"] .app-nav-link.active,
html[data-theme="spatial"] .side-link.active,
html[data-theme="spatial"] .side-link[aria-current="page"] {
    background: linear-gradient(90deg, rgba(56, 189, 248, 0.22), rgba(56, 189, 248, 0.07));
    color: var(--ink);
    font-weight: 650;
    box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.26);
}
/* Accent rail on the active item */
html[data-theme="spatial"] .app-sidebar a.active::before,
html[data-theme="spatial"] .app-sidebar a[aria-current="page"]::before,
html[data-theme="spatial"] .app-nav-link.active::before,
html[data-theme="spatial"] .side-link.active::before,
html[data-theme="spatial"] .side-link[aria-current="page"]::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 60%;
    border-radius: 0 3px 3px 0;
    background: linear-gradient(180deg, var(--cyan), var(--accent-2));
    box-shadow: 0 0 10px rgba(56, 189, 248, 0.8);
}
html[data-theme="spatial"] .app-nav-ic,
html[data-theme="spatial"] .side-ic {
    width: 1.35rem;
    flex: none;
    text-align: center;
    font-size: 1.02rem;
    line-height: 1;
}
html[data-theme="spatial"] .app-nav-label,
html[data-theme="spatial"] .side-lbl {
    overflow: hidden;
    text-overflow: ellipsis;
    transition: opacity 0.18s ease;
}

html[data-theme="spatial"] .app-sidebar-foot,
html[data-theme="spatial"] .side-foot {
    margin-top: auto;
    padding-top: 10px;
    border-top: 1px solid var(--glass-border);
    font-size: 0.7rem;
    color: var(--ink-3);
    white-space: nowrap;
    overflow: hidden;
}

/* ---- 12a-2  Sidebar footer block (nav.js .side-user / .side-signout) -------
   A signed-in identity card + a sign-out button. None of this existed in the
   first draft, so on a live page it rendered as unstyled white-ish text on the
   glass. */
html[data-theme="spatial"] .side-user {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 6px 6px 8px;
    min-width: 0;
}
html[data-theme="spatial"] .side-avatar {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 999px;
    background: linear-gradient(135deg, #38bdf8, #0067b3);
    color: #ffffff;
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1;
    box-shadow: var(--hi-top), 0 2px 6px rgba(0, 0, 0, 0.45);
}
html[data-theme="spatial"] .side-user-txt { min-width: 0; overflow: hidden; }
html[data-theme="spatial"] .side-email {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
html[data-theme="spatial"] .side-role {
    font-size: 0.66rem;
    color: var(--ink-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
html[data-theme="spatial"] .side-signout {
    display: block;
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--glass-border);
    border-radius: 10px;
    background: var(--surface-2);
    color: var(--ink-red);
    font-size: 0.74rem;
    font-weight: 600;
    text-align: center;
    cursor: pointer;
    box-shadow: var(--hi-top);
    transition: background 0.15s ease, border-color 0.15s ease;
}
html[data-theme="spatial"] .side-signout:hover {
    background: var(--tint-red);
    border-color: var(--line-red);
}

/* ---- 12b  Phone tab bar ---- */
html[data-theme="spatial"] .app-tabbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 45;
    display: none;                       /* shown by the <=900px query below */
    align-items: stretch;
    height: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--surface);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border-top: 1px solid var(--glass-border);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 -12px 34px -20px rgba(0, 0, 0, 1);
}
html[data-theme="spatial"] .app-tabbar a,
html[data-theme="spatial"] .app-tab,
html[data-theme="spatial"] .tab-item {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    max-width: 20%;                      /* 5 items max */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 8px 4px;
    color: var(--ink-3);
    text-decoration: none;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    -webkit-tap-highlight-color: transparent;
    transition: color 0.15s ease;
}
html[data-theme="spatial"] .app-tab-ic,
html[data-theme="spatial"] .tab-ic { font-size: 1.22rem; line-height: 1; }
html[data-theme="spatial"] .app-tab-label,
html[data-theme="spatial"] .tab-lbl {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
html[data-theme="spatial"] .app-tabbar a.active,
html[data-theme="spatial"] .app-tabbar a[aria-current="page"],
html[data-theme="spatial"] .app-tab.active,
html[data-theme="spatial"] .tab-item.active,
html[data-theme="spatial"] .tab-item[aria-current="page"] { color: var(--accent-2); }
html[data-theme="spatial"] .app-tabbar a.active::after,
html[data-theme="spatial"] .app-tabbar a[aria-current="page"]::after,
html[data-theme="spatial"] .app-tab.active::after,
html[data-theme="spatial"] .tab-item.active::after,
html[data-theme="spatial"] .tab-item[aria-current="page"]::after {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 28px;
    height: 3px;
    border-radius: 0 0 3px 3px;
    background: linear-gradient(90deg, var(--cyan), var(--accent-2));
    box-shadow: 0 0 10px rgba(56, 189, 248, 0.85);
}
html[data-theme="spatial"] .app-tabbar a:active,
html[data-theme="spatial"] .app-tab:active,
html[data-theme="spatial"] .tab-item:active { background: var(--tint-neutral); }

/* ---- 12c  Body padding shims ----------------------------------------------
   Applied only when the nav actually exists, so the signed-out login screen
   stays centred. FOUR ways in — :has() for modern engines, then the three
   markers nav.js sets on mount (body.has-app-shell, body.has-app-nav and
   html[data-appnav="on"]). All four are listed everywhere the shim appears so
   a rename on either side cannot silently collapse the page under the rail. */
@media (min-width: 900px) {
    html[data-theme="spatial"] body:has(.app-sidebar),
    html[data-theme="spatial"][data-appnav="on"] body,
    html[data-theme="spatial"] body.has-app-nav,
    html[data-theme="spatial"] body.has-app-shell {
        padding-left: var(--sidebar-w);
    }
    /* Keep the toast centred over the CONTENT, not the whole viewport. */
    html[data-theme="spatial"] body:has(.app-sidebar) > #toast,
    html[data-theme="spatial"][data-appnav="on"] body > #toast,
    html[data-theme="spatial"] body.has-app-nav > #toast,
    html[data-theme="spatial"] body.has-app-shell > #toast {
        left: calc(50% + (var(--sidebar-w) / 2));
    }
    /* nav.js writes #offline-banner with inline `left:0`, so it slid UNDER the
       fixed sidebar. Inline beats the cascade — !important is the only lever. */
    html[data-theme="spatial"] body:has(.app-sidebar) #offline-banner,
    html[data-theme="spatial"][data-appnav="on"] body #offline-banner,
    html[data-theme="spatial"] body.has-app-nav #offline-banner,
    html[data-theme="spatial"] body.has-app-shell #offline-banner {
        left: var(--sidebar-w) !important;
    }
}

/* Tablet / small laptop: sidebar collapses to icons.
   1024x768 wall tablets live in this band, so the label list MUST name the
   real nav.js classes (.side-lbl / .side-word / .side-word-sep / .side-foot)
   as well as the .app-* ones — with only the .app-* names the rail kept its
   full-width labels inside a 72px box and the text was shredded. */
@media (min-width: 900px) and (max-width: 1199.98px) {
    html[data-theme="spatial"] .app-sidebar { width: var(--sidebar-w-icon); padding-left: 10px; padding-right: 10px; }
    html[data-theme="spatial"] .app-sidebar .app-nav-label,
    html[data-theme="spatial"] .app-sidebar .side-lbl,
    html[data-theme="spatial"] .app-sidebar-wordmark,
    html[data-theme="spatial"] .side-word,
    html[data-theme="spatial"] .side-word-sep,
    html[data-theme="spatial"] .app-sidebar-foot,
    html[data-theme="spatial"] .side-foot { display: none; }
    html[data-theme="spatial"] .app-sidebar a,
    html[data-theme="spatial"] .app-nav-link,
    html[data-theme="spatial"] .side-link { justify-content: center; padding: 12px 6px; gap: 0; }
    html[data-theme="spatial"] .app-sidebar a:hover,
    html[data-theme="spatial"] .app-nav-link:hover,
    html[data-theme="spatial"] .side-link:hover { transform: none; }
    html[data-theme="spatial"] .app-sidebar-brand,
    html[data-theme="spatial"] .side-brand { justify-content: center; padding-left: 0; padding-right: 0; gap: 0; }

    html[data-theme="spatial"] body:has(.app-sidebar),
    html[data-theme="spatial"][data-appnav="on"] body,
    html[data-theme="spatial"] body.has-app-nav,
    html[data-theme="spatial"] body.has-app-shell { padding-left: var(--sidebar-w-icon); }
    html[data-theme="spatial"] body:has(.app-sidebar) > #toast,
    html[data-theme="spatial"][data-appnav="on"] body > #toast,
    html[data-theme="spatial"] body.has-app-nav > #toast,
    html[data-theme="spatial"] body.has-app-shell > #toast { left: calc(50% + (var(--sidebar-w-icon) / 2)); }
    html[data-theme="spatial"] body:has(.app-sidebar) #offline-banner,
    html[data-theme="spatial"][data-appnav="on"] body #offline-banner,
    html[data-theme="spatial"] body.has-app-nav #offline-banner,
    html[data-theme="spatial"] body.has-app-shell #offline-banner { left: var(--sidebar-w-icon) !important; }
}

/* Phone: sidebar gone, tab bar in. */
@media (max-width: 899.98px) {
    html[data-theme="spatial"] .app-sidebar { display: none; }
    html[data-theme="spatial"] .app-tabbar  { display: flex; }

    html[data-theme="spatial"] body:has(.app-tabbar),
    html[data-theme="spatial"][data-appnav="on"] body,
    html[data-theme="spatial"] body.has-app-nav,
    html[data-theme="spatial"] body.has-app-shell {
        padding-left: 0;
        padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
    }
    /* Lift the toast above the tab bar so it is never hidden by it. */
    html[data-theme="spatial"] body:has(.app-tabbar) > #toast,
    html[data-theme="spatial"][data-appnav="on"] body > #toast,
    html[data-theme="spatial"] body.has-app-nav > #toast,
    html[data-theme="spatial"] body.has-app-shell > #toast {
        left: 50%;
        bottom: calc(24px + var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
    }
    html[data-theme="spatial"] #offline-banner { left: 0 !important; }
}


/* ============================================================================
   13  STATION TERMINAL (station.html/.js) + DRIVER (driver.html/.js)
   Same classes on both pages; documents.js reuses .stn-grid / .stn-empty /
   .stn-count-pill. Wall-tablet legibility is the priority here.
   ============================================================================ */
html[data-theme="spatial"] .stn-badge {
    background: linear-gradient(135deg, #38bdf8, #0067b3);
    box-shadow: 0 4px 16px -4px rgba(56, 189, 248, 0.6), var(--hi-top);
}
html[data-theme="spatial"] .stn-badge .dot { background: #6ee7b7; box-shadow: 0 0 0 3px rgba(110, 231, 183, 0.28); }

html[data-theme="spatial"] .stn-card {
    border-left: 6px solid var(--accent-2);
    box-shadow: var(--hi-top), -8px 0 24px -18px rgba(56, 189, 248, 0.7), var(--shadow-1);
}
html[data-theme="spatial"] .stn-card.busy { opacity: 0.42; }
html[data-theme="spatial"] .stn-sor   { color: var(--ink-3); }
html[data-theme="spatial"] .stn-part  { color: var(--ink); }
html[data-theme="spatial"] .stn-part small { color: var(--ink-2); }
html[data-theme="spatial"] .stn-facts { color: var(--ink-2); }
html[data-theme="spatial"] .stn-fact  { background: var(--recess); color: var(--ink-2); }
html[data-theme="spatial"] .stn-fact.wait-old {
    background: var(--tint-amber);
    color: var(--ink-amber);
    box-shadow: inset 0 0 0 1px var(--line-amber);
}
html[data-theme="spatial"] .stn-done {
    background: linear-gradient(135deg, #22c55e, #15803d);
    box-shadow: 0 6px 20px -6px rgba(34, 197, 94, 0.6), var(--hi-top);
}
html[data-theme="spatial"] .stn-unitdone {
    background: var(--recess);
    border: 1px dashed var(--glass-border);
    color: var(--ink);
}
html[data-theme="spatial"] .stn-unitdone:hover { background: var(--tint-neutral-2); }
html[data-theme="spatial"] .stn-empty { color: var(--ink-3); }


/* ============================================================================
   14  MANAGER FLOOR BOARD (floor.html/.js)
   ============================================================================ */
html[data-theme="spatial"] .floor-hero {
    background:
        radial-gradient(120% 160% at 12% 0%, rgba(56, 189, 248, 0.26) 0%, rgba(56, 189, 248, 0) 58%),
        linear-gradient(135deg, #0d1b30, #10293f);
    color: var(--ink);
    border: 1px solid var(--glass-border);
    box-shadow: var(--hi-top), var(--shadow-2);
}
html[data-theme="spatial"] .floor-hero .lbl,
html[data-theme="spatial"] .floor-updated { color: #8fc3e6; }
html[data-theme="spatial"] .floor-hero .big small { color: var(--ink-2); }
html[data-theme="spatial"] .floor-hero.calm .big { color: #6ee7b7; }
html[data-theme="spatial"] .floor-hero.hot  .big { color: #fdba74; }

html[data-theme="spatial"] .floor-col { border-top: 5px solid var(--accent-2); }
html[data-theme="spatial"] .floor-col.hot {
    border-top-color: #fb923c;
    box-shadow: var(--hi-top), 0 0 0 2px rgba(251, 146, 60, 0.26), var(--shadow-1);
}
html[data-theme="spatial"] .floor-col .stage { color: var(--ink); }
html[data-theme="spatial"] .floor-col .stage .tag {
    background: var(--tint-amber);
    color: var(--ink-amber);
    box-shadow: inset 0 0 0 1px var(--line-amber);
}
html[data-theme="spatial"] .floor-wip { color: var(--ink); }
html[data-theme="spatial"] .floor-wip small { color: var(--ink-3); }
html[data-theme="spatial"] .floor-sub { color: var(--ink-2); }
html[data-theme="spatial"] .floor-sub b { color: var(--ink); }
html[data-theme="spatial"] .floor-age.old { color: #fdba74; }
html[data-theme="spatial"] .floor-empty-col { color: var(--ink-3); }

html[data-theme="spatial"] .op-avatar { background: linear-gradient(135deg, #38bdf8, #0067b3); }
html[data-theme="spatial"] .op-name  { color: var(--ink); }
html[data-theme="spatial"] .op-total { color: var(--ink); }
html[data-theme="spatial"] .op-total small { color: var(--ink-3); }


/* ============================================================================
   15  MATERIAL STOCK (stock.html/.js, stock-common.js class names)
   The metal tabs keep their brushed-metal identity (different hue + brush angle
   per material = the operator's visual cue) but are re-mixed as NIGHT metal so
   they sit on dark glass instead of glaring. The name/sub colours flip to the
   light inks to keep contrast.
   ============================================================================ */
html[data-theme="spatial"] .metal-gi {
    background:
        repeating-linear-gradient(122deg, rgba(255, 255, 255, 0.09) 0 1px, rgba(0, 0, 0, 0.20) 1px 4px),
        linear-gradient(135deg, #2b3a4b 0%, #40566b 48%, #33475a 56%, #26333f 100%);
}
html[data-theme="spatial"] .metal-ms {
    background:
        repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, rgba(0, 0, 0, 0.30) 1px 3px),
        linear-gradient(135deg, #232b33 0%, #3c4750 50%, #262f37 100%);
}
html[data-theme="spatial"] .metal-ss304 {
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.10) 0 1px, rgba(0, 0, 0, 0.20) 1px 3px),
        linear-gradient(135deg, #37454f 0%, #4d5f6b 50%, #3b4a55 100%);
}
html[data-theme="spatial"] .metal-ss316 {
    background:
        repeating-linear-gradient(80deg, rgba(255, 255, 255, 0.09) 0 1px, rgba(0, 0, 0, 0.24) 1px 4px),
        linear-gradient(135deg, #24384e 0%, #35577b 50%, #2a4462 100%);
}
html[data-theme="spatial"] .metal-alu {
    background:
        repeating-linear-gradient(105deg, rgba(255, 255, 255, 0.10) 0 1px, rgba(0, 0, 0, 0.18) 1px 5px),
        linear-gradient(135deg, #333c44 0%, #4a545c 45%, #3a444c 60%, #2d363d 100%);
}
html[data-theme="spatial"] .metal-default { background: linear-gradient(135deg, #2a3646, #1e2836); }

html[data-theme="spatial"] .stock-group-head[class*="metal-"] {
    box-shadow: var(--hi-top), 0 1px 2px rgba(0, 0, 0, 0.45);
}
html[data-theme="spatial"] .stock-group-head[class*="metal-"]:hover { filter: brightness(1.16); }
html[data-theme="spatial"] .stock-group-head .mat-name { color: var(--ink); }
html[data-theme="spatial"] .stock-group-head .mat-sub  { color: var(--ink-2); }
html[data-theme="spatial"] .stock-group-head.mat-dark .mat-name { color: #ffffff; }
html[data-theme="spatial"] .stock-group-head.mat-dark .mat-sub  { color: rgba(255, 255, 255, 0.84); }
html[data-theme="spatial"] .stock-group-head.mat-dark .stock-group-caret { color: rgba(255, 255, 255, 0.82); }
/* CONTRAST: the caret inherited --ink-3 (#7c96b2) and sat on a NIGHT brushed
   metal head, measuring ~2.4:1. Every metal head gets the bright caret, not
   just the ones stock.js happens to tag .mat-dark. */
html[data-theme="spatial"] .stock-group-head[class*="metal-"] .stock-group-caret { color: rgba(255, 255, 255, 0.82); }
html[data-theme="spatial"] .mat-name { color: var(--ink); }
html[data-theme="spatial"] .mat-sub  { color: var(--ink-2); }
html[data-theme="spatial"] .mat-swatch {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16), 0 1px 3px rgba(0, 0, 0, 0.6);
}

/* −/+ quantity stepper */
html[data-theme="spatial"] .qty-btn {
    background: var(--recess);
    border-color: var(--glass-border);
    color: var(--accent-2);
}
html[data-theme="spatial"] .qty-btn:hover  { background: var(--tint-blue); }
html[data-theme="spatial"] .qty-btn:active { background: rgba(56, 189, 248, 0.28); }


/* ============================================================================
   16  KANBAN BOARD (kanban.html <style> + kanban.js)
   ============================================================================ */
html[data-theme="spatial"] .kanban-col { background: var(--surface-2); }
html[data-theme="spatial"] .kanban-col.drop-hint {
    border-color: var(--accent-2);
    background: linear-gradient(0deg, var(--tint-blue), var(--tint-blue)), var(--surface-2);
    box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.28), var(--shadow-1);
}
html[data-theme="spatial"] .kanban-col.drop-blocked {
    border-color: var(--line-red);
    background: linear-gradient(0deg, var(--tint-red), var(--tint-red)), var(--surface-2);
}
html[data-theme="spatial"] .kanban-col-head  { border-bottom-color: var(--glass-border); }
html[data-theme="spatial"] .kanban-col-title { color: var(--ink); }
html[data-theme="spatial"] .kanban-col-count { color: var(--ink-2); background: var(--recess); }
html[data-theme="spatial"] .kanban-card.dragging { opacity: 0.4; }
html[data-theme="spatial"] .kanban-card.open {
    border-color: rgba(56, 189, 248, 0.34);
    box-shadow: var(--hi-top), 0 0 0 1px rgba(56, 189, 248, 0.22), var(--shadow-1);
}
html[data-theme="spatial"] .kanban-sor       { color: var(--ink); }
html[data-theme="spatial"] .kanban-unit      { color: var(--ink-2); }
html[data-theme="spatial"] .kanban-qty       { color: var(--ink-3); }
html[data-theme="spatial"] .kanban-card-desc { color: var(--ink-3); }
html[data-theme="spatial"] .kanban-move      { border-top-color: var(--glass-border); }
html[data-theme="spatial"] .kanban-move button {
    background: var(--recess);
    border-color: var(--glass-border);
    color: var(--ink);
}
html[data-theme="spatial"] .kanban-move button:hover:not(:disabled) { background: var(--tint-neutral-2); }
html[data-theme="spatial"] .kanban-move button:disabled { opacity: 0.3; }
html[data-theme="spatial"] .kanban-empty { color: var(--ink-3); }


/* ============================================================================
   17  DELIVERY CALENDAR (delivery-calendar.html <style> + .js)
   ============================================================================ */
html[data-theme="spatial"] .cal-dow { color: var(--ink-3); }
html[data-theme="spatial"] .cal-cell {
    background: var(--surface-2);
    border-color: var(--glass-border);
    box-shadow: var(--hi-top);
}
html[data-theme="spatial"] .cal-cell.empty { background: transparent; border: none; box-shadow: none; }
html[data-theme="spatial"] .cal-cell.is-weekend { background: rgba(10, 18, 32, 0.55); }
html[data-theme="spatial"] .cal-cell.has-due:hover {
    border-color: var(--accent-2);
    box-shadow: var(--hi-top), 0 6px 18px -10px rgba(56, 189, 248, 0.8);
}
html[data-theme="spatial"] .cal-cell.is-today {
    border-color: var(--accent-2);
    box-shadow: inset 0 0 0 1px var(--accent-2), 0 0 16px -6px rgba(56, 189, 248, 0.7);
}
/* is-selected must be tellable apart from is-today at a glance (both used to be
   "cyan edge"): today = thin ring only, selected = filled cyan wash + 2px ring. */
html[data-theme="spatial"] .cal-cell.is-selected {
    border-color: var(--accent-2);
    background: linear-gradient(0deg, rgba(56, 189, 248, 0.22), rgba(56, 189, 248, 0.22)), var(--surface-2);
    box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.55), var(--shadow-1);
}
html[data-theme="spatial"] .cal-cell.is-today.is-selected {
    background: linear-gradient(0deg, rgba(56, 189, 248, 0.28), rgba(56, 189, 248, 0.28)), var(--surface-2);
    box-shadow: inset 0 0 0 1px var(--accent-2), 0 0 0 2px rgba(56, 189, 248, 0.55), var(--shadow-1);
}
html[data-theme="spatial"] .cal-daynum { color: var(--ink); }
html[data-theme="spatial"] .cal-cell.is-weekend .cal-daynum { color: var(--ink-3); }
html[data-theme="spatial"] .cal-badge {
    background: var(--accent-2);
    color: #05243a;                  /* dark ink on a bright chip = 9.4:1 */
    box-shadow: 0 0 12px -3px rgba(56, 189, 248, 0.9);
}
/* Sticky day header must be OPAQUE or the rows scroll through it. */
html[data-theme="spatial"] .day-group-head {
    color: var(--ink);
    background: var(--bg-2);
    box-shadow: 0 6px 12px -10px rgba(0, 0, 0, 1);
}
html[data-theme="spatial"] .day-group-head .day-count { color: var(--ink-3); }
html[data-theme="spatial"] .day-group.is-selected .day-group-head { color: var(--accent-2); }
/* Section 04 gives every row-surface `border: 1px solid`, which flattened this
   page's 4px batch-colour stripe down to a hairline. Section 17 is later in the
   file, so restoring the width/style here wins without touching section 04. */
html[data-theme="spatial"] .deliv-row {
    border-left-color: rgba(120, 170, 220, 0.4);
    border-left-width: 4px;
    border-left-style: solid;
}
/* delivery-calendar.js writes the stripe as inline `border-left-color:<batch fg>`
   — the paper-grade mid-dark ink, which is nearly invisible once the stripe is
   4px on a dark row. Lift each batch to its light twin (same hue, so batch
   identity is unchanged). .deliv-row is excluded from the section 23b text
   rules on purpose, so this is the only place its batch hex is handled. */
html[data-theme="spatial"] .deliv-row[style*="#0a6cc4"] { border-left-color: #7cc9f0 !important; }
html[data-theme="spatial"] .deliv-row[style*="#b35309"] { border-left-color: #ffc48a !important; }
html[data-theme="spatial"] .deliv-row[style*="#8a3ffc"] { border-left-color: #c4b5fd !important; }
html[data-theme="spatial"] .deliv-row[style*="#1d8a4e"] { border-left-color: #6ee7a8 !important; }
html[data-theme="spatial"] .deliv-row[style*="#c41d7f"] { border-left-color: #f9a8d4 !important; }
html[data-theme="spatial"] .deliv-row[style*="#007a8a"] { border-left-color: #5eead4 !important; }
html[data-theme="spatial"] .deliv-row[style*="#3b4fd6"] { border-left-color: #a5b4fc !important; }
html[data-theme="spatial"] .deliv-row[style*="#b1400a"] { border-left-color: #fdba74 !important; }
html[data-theme="spatial"] .deliv-row .sor-no  { color: var(--ink); }
html[data-theme="spatial"] .deliv-row .unit-no { color: var(--ink-2); }
html[data-theme="spatial"] .deliv-row .cust    { color: var(--ink-3); }


/* ============================================================================
   18  ANALYTICS (analytics.html <style> + analytics.js)
   NOTE: .heat-cell backgrounds/foregrounds are written inline by analytics.js
   (a cream → hot-orange ramp with dark ink). They are left alone on purpose —
   the ramp IS the information, and dark-on-light inside the cell stays legible.
   Only the chrome around them is themed.
   ============================================================================ */
html[data-theme="spatial"] .stat-num   { color: var(--ink); }
html[data-theme="spatial"] .stat-label { color: var(--ink-3); }
html[data-theme="spatial"] .heat-cell {
    border-color: rgba(0, 0, 0, 0.35);
    box-shadow: 0 6px 18px -12px rgba(0, 0, 0, 0.9);
}
html[data-theme="spatial"] .heat-cell.bottleneck { outline-color: #f87171; }
html[data-theme="spatial"] .heat-badge {
    background: #f87171;
    color: #2b0606;
    box-shadow: 0 0 12px -3px rgba(248, 113, 113, 0.9);
}


/* ============================================================================
   19  JOB CARD (job-card.html <style> + job-card.js, unit-docs.js)
   The QR code keeps a WHITE quiet zone on screen and on paper — a scanner
   needs it. Everything else becomes glass on screen and resets in @media print.
   ============================================================================ */
html[data-theme="spatial"] .jc-qr {
    background: #ffffff;
    border-color: rgba(255, 255, 255, 0.5);
    padding: 4px;
}


/* ============================================================================
   20  CUT PROGRAMS (cut-programs.js injects <style id="cutp-style"> at runtime)
   Its rules are plain single-class selectors, so the theme prefix outranks them
   regardless of injection order.
   ============================================================================ */
html[data-theme="spatial"] .cutp-table th {
    background: linear-gradient(180deg, #17324d, #10243a);
    color: var(--ink);
}
html[data-theme="spatial"] .cutp-table td { border-color: var(--glass-border); color: var(--ink); }
html[data-theme="spatial"] .cutp-table tbody tr:nth-child(odd) td { background: rgba(255, 255, 255, 0.035); }
html[data-theme="spatial"] .cutp-mat {
    background: rgba(56, 189, 248, 0.08) !important;   /* beats the module's own !important */
    color: var(--ink);
}
html[data-theme="spatial"] .cutp-mat small { color: var(--ink-2); }
html[data-theme="spatial"] .cutp-odd { color: var(--ink-red); }
html[data-theme="spatial"] .cutp-donerow td { opacity: 0.45; }
html[data-theme="spatial"] .cutp-check { accent-color: var(--green); }
html[data-theme="spatial"] .cutp-tab.active { background: var(--accent); color: #ffffff; }


/* ============================================================================
   21  DOCUMENTS / COMMAND BAR / PDF VIEWER / PRINT JOBS / MODALS
   These modules build their panels from Tailwind utilities (.bg-white,
   .border-[#e6edf4], .shadow-2xl) which section 03 already themed. What is left
   is the glassy lift and the PDF canvas, which must stay white.
   ============================================================================ */
html[data-theme="spatial"] .bg-white.rounded-2xl,
html[data-theme="spatial"] .bg-white.rounded-xl {
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border: 1px solid var(--glass-border);
    box-shadow: var(--hi-top), var(--shadow-lift);
}
/* A rendered PDF page is white paper — never tint it. */
html[data-theme="spatial"] canvas.bg-white {
    background-color: #ffffff;
    box-shadow: 0 10px 34px -14px rgba(0, 0, 0, 1);
}
html[data-theme="spatial"] .cmdbar-row { border-bottom-color: var(--glass-border); }
html[data-theme="spatial"] .cmdbar-row:hover { background: var(--tint-neutral-2); }


/* ============================================================================
   22  TOAST, OFFLINE BANNER, LOADING SPLASH, SCROLLBARS
   ============================================================================ */
html[data-theme="spatial"] #toast {
    background: rgba(24, 38, 60, 0.92);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    color: var(--ink);
    border: 1px solid var(--glass-border);
    box-shadow: var(--hi-top), var(--shadow-lift);
}
html[data-theme="spatial"] #toast.error {
    background: rgba(120, 26, 26, 0.94);
    border-color: var(--line-red);
    color: #ffe4e4;
}

/* nav.js builds #offline-banner with inline styles (amber #f59e0b on #1f2937).
   The colours already read perfectly on a dark page, so they are left as-is —
   but the inline `left:0` slid the strip UNDER the fixed sidebar. The
   left-offset shim lives with the other sidebar geometry in section 12c. */

html[data-theme="spatial"] #app-loading {
    background:
        radial-gradient(130% 78% at 50% 32%, rgba(0, 144, 212, 0.22) 0%, rgba(0, 144, 212, 0) 58%),
        var(--bg);
}
html[data-theme="spatial"] .load-div { color: rgba(168, 192, 216, 0.5); }
html[data-theme="spatial"] .load-bar { background: var(--recess); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.6); }
html[data-theme="spatial"] .load-bar span {
    background: linear-gradient(90deg, #67e8f9, #0090d4);
    box-shadow: 0 0 14px -2px rgba(103, 232, 249, 0.8);
}

html[data-theme="spatial"] .scroll-area::-webkit-scrollbar-thumb { background: rgba(120, 170, 220, 0.28); }
html[data-theme="spatial"] .scroll-area::-webkit-scrollbar-thumb:hover { background: rgba(120, 170, 220, 0.45); }
html[data-theme="spatial"] .scroll-area::-webkit-scrollbar-track { background: transparent; }
html[data-theme="spatial"] .kanban-scroll::-webkit-scrollbar { height: 8px; }
html[data-theme="spatial"] .kanban-scroll::-webkit-scrollbar-thumb { background: rgba(120, 170, 220, 0.28); border-radius: 999px; }


/* ============================================================================
   23  JS-INJECTED INLINE COLOUR MITIGATIONS
   sor-common.js BATCH_COLORS were picked for white paper: the pale .bg is the
   pill fill and the mid-dark .fg is the ink / dot / ring stroke. Inline styles
   beat any class rule, so instead of fighting them we (a) leave the pills alone
   — dark ink on a pale chip is still perfectly legible on dark glass and the
   batch identity is preserved — and (b) lift the few places where a .fg colour
   is drawn DIRECTLY on the dark ground, using a filter (visual only, no logic
   touched).
   ============================================================================ */

/* index.html hardcodes three KPI colours as INLINE styles
   (style="color:#1d8a4e" / "#b35309" / "#0090d4"). Inline beats the cascade, so
   these three ids are the one place the theme genuinely needs !important —
   without it the "in production" figure sits at 3.5:1 on the dark card. */
html[data-theme="spatial"] #kpi-delivered-units { color: var(--ink-green) !important; }
html[data-theme="spatial"] #kpi-inprod-units    { color: var(--ink-amber) !important; }
html[data-theme="spatial"] #kpi-overall-pct     { color: var(--accent-2)  !important; }

/* Batch pill: pale chip, seated with a ring so it does not float. */
html[data-theme="spatial"] .batch-pill,
html[data-theme="spatial"] .stn-batch {
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.28), 0 1px 2px rgba(0, 0, 0, 0.4);
}

/* Mini progress rings (app.js miniRing) — the whole ring + its "B1" caption
   are brightened together so a batch colour meant for white paper reads on
   glass. The wrapper div has no class of its own, hence :has(). */
html[data-theme="spatial"] div:has(> svg > circle[stroke="#e8e8ed"]) {
    filter: brightness(1.45) saturate(1.08);
}
/* Track ring of those SVGs (a presentation attribute — CSS outranks it). */
html[data-theme="spatial"] svg circle[stroke="#e8e8ed"] { stroke: rgba(120, 170, 220, 0.22); }

/* Calendar batch dots are drawn straight on the dark cell. */
html[data-theme="spatial"] .cal-dot { filter: brightness(1.5) saturate(1.1); }

/* .progress-fill carries an inline batch background on multi-batch SORs. */
html[data-theme="spatial"] .progress-fill,
html[data-theme="spatial"] .batch-progress-fill { filter: saturate(1.1) brightness(1.28); }


/* ============================================================================
   23b  INLINE COLOUR OVERRIDES  —  THE ONE PLACE !important IS CORRECT
   ----------------------------------------------------------------------------
   WHY !important HERE AND NOWHERE ELSE
   Ten modules (app.js, admin.js, job-card.js, station.js, stock.js, floor.js,
   driver.js, documents.js, print-jobs.js, unit-docs.js, delivery-note.js,
   analytics.js) write colour as an INLINE style attribute, e.g.
       <span style="color:#c11717">…</span>
   An inline declaration beats EVERY selector in an author stylesheet no matter
   how specific — html[data-theme="spatial"] cannot reach it. The only author
   lever that outranks a normal inline declaration is `!important`. So these
   rules match on the literal hex inside the style attribute and force the
   dark-theme equivalent. Without them the error text (#c11717, 26 sites) is
   near-black on near-black and simply cannot be read.

   Each rule is reset in @media print (section 25) so paper keeps the original
   dark inks — the printed job card / delivery note is unchanged.

   :not(.deliv-row) — delivery-calendar.js puts the batch hex in
   `border-left-color`, not in `color`; the row must not inherit a batch ink.
   ============================================================================ */

/* ---- 23b-1  Foreground-only inline colours -------------------------------- */

/* errors / danger  #c11717 -> light red */
html[data-theme="spatial"] [style*="#c11717"]:not(.deliv-row),
html[data-theme="spatial"] [style*="c11717"]:not(.deliv-row) { color: #ff9a9a !important; }

/* Quick Command warnings  #b1400a -> light amber */
html[data-theme="spatial"] [style*="#b1400a"]:not(.deliv-row) { color: #ffc48a !important; }

/* other warning ambers written inline (analytics rate pill, KPI sub-lines) */
html[data-theme="spatial"] [style*="#b35309"]:not(.deliv-row),
html[data-theme="spatial"] [style*="#8a4b00"]:not(.deliv-row) { color: #ffc48a !important; }

/* Dispatched date  #0067b3 -> light blue */
html[data-theme="spatial"] [style*="#0067b3"]:not(.deliv-row) { color: #7cc9f0 !important; }

/* Delivered tick  #1d8a4e -> light green */
html[data-theme="spatial"] [style*="#1d8a4e"]:not(.deliv-row) { color: #6ee7a8 !important; }

/* muted grey written inline (analytics.js) — 3.7:1 on the dark card */
html[data-theme="spatial"] [style*="color:#6e6e73"]:not(.deliv-row) { color: var(--ink-3) !important; }

/* ---- 23b-2  Light pastel CHIPS written inline ------------------------------
   sor-common.js batchStyle() emits `background:<pastel>;color:<mid-dark>` for
   .batch-pill / .stn-batch / .jc-stage / the admin batch <input>, and
   analytics.js emits the same shape for its scrap/rework .rate-pill. On white
   paper that is right; on dark glass a pale chip glares and floats.
   Each pair becomes a DARK TRANSLUCENT wash of the SAME hue plus the matching
   light ink — so batch 1 is still blue, batch 3 still purple, batch 8 still
   orange. The per-batch distinction is the whole point of the colour, so it is
   preserved exactly; only the light/dark polarity flips.
   Matched on the background hex (unique per batch), so one rule fixes the chip
   wherever it appears. Every ink below measures >= 7:1 on its own wash. */

/* batch 1 + generic info blue  (#e3f2fd / #e6f4fc  +  #0a6cc4 / #0067b3) */
html[data-theme="spatial"] [style*="#e3f2fd"],
html[data-theme="spatial"] [style*="#e6f4fc"] {
    background: rgba(56, 189, 248, 0.16) !important;
    color: #7cc9f0 !important;
    box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.32);
}
/* batch 2 + warning amber  (#fff2dd / #fff4e5  +  #b35309 / #8a4b00) */
html[data-theme="spatial"] [style*="#fff2dd"],
html[data-theme="spatial"] [style*="#fff4e5"] {
    background: rgba(245, 158, 11, 0.16) !important;
    color: #ffc48a !important;
    box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.32);
}
/* batch 3 purple  (#f3e8ff + #8a3ffc) */
html[data-theme="spatial"] [style*="#f3e8ff"] {
    background: rgba(167, 139, 250, 0.18) !important;
    color: #c4b5fd !important;
    box-shadow: inset 0 0 0 1px rgba(167, 139, 250, 0.32);
}
/* batch 4 green  (#e3f7eb + #1d8a4e) */
html[data-theme="spatial"] [style*="#e3f7eb"] {
    background: rgba(34, 197, 94, 0.16) !important;
    color: #6ee7a8 !important;
    box-shadow: inset 0 0 0 1px rgba(34, 197, 94, 0.32);
}
/* batch 5 pink  (#fde7f3 + #c41d7f) */
html[data-theme="spatial"] [style*="#fde7f3"] {
    background: rgba(244, 114, 182, 0.16) !important;
    color: #f9a8d4 !important;
    box-shadow: inset 0 0 0 1px rgba(244, 114, 182, 0.32);
}
/* batch 6 teal  (#e0f7fa + #007a8a) */
html[data-theme="spatial"] [style*="#e0f7fa"] {
    background: rgba(45, 212, 191, 0.16) !important;
    color: #5eead4 !important;
    box-shadow: inset 0 0 0 1px rgba(45, 212, 191, 0.32);
}
/* batch 7 indigo  (#e7ecff + #3b4fd6) */
html[data-theme="spatial"] [style*="#e7ecff"] {
    background: rgba(129, 140, 248, 0.18) !important;
    color: #a5b4fc !important;
    box-shadow: inset 0 0 0 1px rgba(129, 140, 248, 0.34);
}
/* batch 8 orange  (#ffe9d6 + #b1400a) */
html[data-theme="spatial"] [style*="#ffe9d6"] {
    background: rgba(251, 146, 60, 0.16) !important;
    color: #fdba74 !important;
    box-shadow: inset 0 0 0 1px rgba(251, 146, 60, 0.32);
}
/* analytics scrap rate pill  (#ffe5e5 + #c11717) */
html[data-theme="spatial"] [style*="#ffe5e5"] {
    background: rgba(248, 113, 113, 0.16) !important;
    color: #ff9a9a !important;
    box-shadow: inset 0 0 0 1px rgba(248, 113, 113, 0.32);
}

/* The admin batch <input> takes the same inline pair — keep its field chrome. */
html[data-theme="spatial"] input.admin-input[style*="background:#"] {
    border-color: var(--glass-border);
}


/* ============================================================================
   24  REDUCED MOTION
   Extends (does not replace) the two guards already in styles.css, and adds the
   animations they never covered plus everything this theme introduces.
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {
    html[data-theme="spatial"] body::before,
    html[data-theme="spatial"] body::after { animation: none !important; }

    html[data-theme="spatial"] .app-sidebar,
    html[data-theme="spatial"] .app-sidebar a,
    html[data-theme="spatial"] .app-nav-link,
    html[data-theme="spatial"] .side-link,
    html[data-theme="spatial"] .side-signout,
    html[data-theme="spatial"] .app-tabbar a,
    html[data-theme="spatial"] .app-tab,
    html[data-theme="spatial"] .tab-item { transition: none !important; }
    html[data-theme="spatial"] .app-sidebar a:hover,
    html[data-theme="spatial"] .app-nav-link:hover,
    html[data-theme="spatial"] .side-link:hover { transform: none !important; }

    html[data-theme="spatial"] .kpi-flash,
    html[data-theme="spatial"] .badge-high-pulse,
    html[data-theme="spatial"] .note-high-alert,
    html[data-theme="spatial"] .live-dot,
    html[data-theme="spatial"] .progress-fill::after,
    html[data-theme="spatial"] .nav-panel,
    html[data-theme="spatial"] .fade-in,
    html[data-theme="spatial"] .load-logos { animation: none !important; }
    html[data-theme="spatial"] .fade-in { opacity: 1; transform: none; }
    html[data-theme="spatial"] .load-bar span { animation: none !important; left: 29%; }

    html[data-theme="spatial"] .dashboard-card,
    html[data-theme="spatial"] .kpi-card,
    html[data-theme="spatial"] .sor-card,
    html[data-theme="spatial"] .unit-row,
    html[data-theme="spatial"] .note-card,
    html[data-theme="spatial"] .kanban-card,
    html[data-theme="spatial"] .heat-cell { transition: none !important; }
    html[data-theme="spatial"] .dashboard-card:hover,
    html[data-theme="spatial"] .kpi-card:hover,
    html[data-theme="spatial"] .sor-card:hover,
    html[data-theme="spatial"] .unit-row:hover,
    html[data-theme="spatial"] .note-card:hover,
    html[data-theme="spatial"] .heat-cell:hover { transform: none !important; }
}


/* ============================================================================
   25  PRINT RESET  —  BACK TO WHITE PAPER
   Job cards (job-card.html + job-card.js + unit-docs.js), delivery notes and
   pallet labels must come off the printer exactly as they do today.
   Strategy: re-point every token to its classic value (which fixes everything
   expressed through var()), then flatten the handful of literal dark values,
   then hide the new navigation.
   ============================================================================ */
@media print {

    /* ---- tokens back to the classic "Focus" palette ---- */
    html[data-theme="spatial"] {
        color-scheme: light;
        background: #ffffff !important;

        --bg:        #ffffff;
        --bg-2:      #ffffff;
        --surface:   #ffffff;
        --surface-2: #f4f6f9;
        --surface-solid:   #ffffff;
        --surface-solid-2: #ffffff;
        --ink:       #000000;
        --ink-2:     #333333;
        --ink-3:     #555555;
        --line:      #cccccc;
        --glass-border: #cccccc;
        --glass-hi:  transparent;
        --accent:    #0090d4;
        --accent-2:  #0067b3;
        --cyan:      #0090d4;
        --green:     #1d8a4e;
        --amber:     #b35309;
        --red:       #c11717;

        --ink-red:    #c11717;
        --ink-amber:  #8a4b00;
        --ink-green:  #1d8a4e;
        --ink-blue:   #0067b3;
        --ink-indigo: #3a3fbf;

        --tint-red:       #ffe5e5;
        --tint-amber:     #fff4e5;
        --tint-green:     #e8f7ee;
        --tint-blue:      #e6f4fc;
        --tint-indigo:    #eef0ff;
        --tint-neutral:   #f5f5f7;
        --tint-neutral-2: #ececef;
        --recess:         #f0f0f2;

        --line-red:   #f3b8b8;
        --line-amber: #f5d9a8;
        --line-blue:  #0090d4;
        --line-green: #b8e6c9;

        --glass-blur: none;
        --hi-top:     none;
        --shadow-1:   none;
        --shadow-2:   none;
        --shadow-lift:none;

        --sidebar-w: 0px;
        --sidebar-w-icon: 0px;
        --tabbar-h: 0px;
    }

    /* ---- page ground ---- */
    html[data-theme="spatial"] body {
        background: #ffffff !important;
        color: #000000 !important;
        padding-left: 0 !important;
        padding-bottom: 0 !important;
    }
    html[data-theme="spatial"] body::before,
    html[data-theme="spatial"] body::after { display: none !important; content: none !important; }

    /* ---- new navigation never prints ----
       Both vocabularies and both ids, so nothing can leak onto paper if either
       side of the markup contract changes. */
    html[data-theme="spatial"] .app-sidebar,
    html[data-theme="spatial"] .app-tabbar,
    html[data-theme="spatial"] #app-sidebar,
    html[data-theme="spatial"] #app-tabbar,
    html[data-theme="spatial"] .side-brand,
    html[data-theme="spatial"] .side-links,
    html[data-theme="spatial"] .side-link,
    html[data-theme="spatial"] .side-foot,
    html[data-theme="spatial"] .app-sidebar-brand,
    html[data-theme="spatial"] .app-sidebar-nav,
    html[data-theme="spatial"] .app-sidebar-foot,
    html[data-theme="spatial"] .app-nav-link,
    html[data-theme="spatial"] .app-tab,
    html[data-theme="spatial"] .tab-item,
    html[data-theme="spatial"] #offline-banner { display: none !important; }

    /* ---- kill every trace of glass, depth and motion ---- */
    html[data-theme="spatial"] * {
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        box-shadow: none !important;
        text-shadow: none !important;
        animation: none !important;
        transition: none !important;
        filter: none !important;
    }

    /* ---- flatten the literal dark values this file sets ---- */
    html[data-theme="spatial"] .login-container,
    html[data-theme="spatial"] .dashboard-card,
    html[data-theme="spatial"] .admin-card,
    html[data-theme="spatial"] .kpi-card,
    html[data-theme="spatial"] .sor-card,
    html[data-theme="spatial"] .stn-card,
    html[data-theme="spatial"] .floor-col,
    html[data-theme="spatial"] .stat-box,
    html[data-theme="spatial"] .kanban-col,
    html[data-theme="spatial"] .kanban-card,
    html[data-theme="spatial"] .jobcard,
    html[data-theme="spatial"] .unit-row,
    html[data-theme="spatial"] .comp-row,
    html[data-theme="spatial"] .admin-row,
    html[data-theme="spatial"] .note-card,
    html[data-theme="spatial"] .op-row,
    html[data-theme="spatial"] .cal-cell,
    html[data-theme="spatial"] .deliv-row,
    html[data-theme="spatial"] .day-group-head,
    html[data-theme="spatial"] .bg-white,
    html[data-theme="spatial"] .bg-white\/85,
    html[data-theme="spatial"] .floor-hero,
    html[data-theme="spatial"] #toast {
        background: #ffffff !important;
        color: #000000 !important;
        border-color: #cccccc !important;
    }
    /* The floor hero's own children carried light-on-dark inks. */
    html[data-theme="spatial"] .floor-hero .lbl,
    html[data-theme="spatial"] .floor-updated,
    html[data-theme="spatial"] .floor-hero .big,
    html[data-theme="spatial"] .floor-hero .big small,
    html[data-theme="spatial"] .floor-hero.calm .big,
    html[data-theme="spatial"] .floor-hero.hot .big { color: #000000 !important; }

    /* These four printed as WHITE-ON-WHITE (their fill was a dark gradient that
       the flatten pass above never touched, or a bright chip on a bright page). */
    html[data-theme="spatial"] .btn-primary,
    html[data-theme="spatial"] .view-toggle-btn.active,
    html[data-theme="spatial"] .cutp-tab.active {
        background: #ffffff !important;
        background-image: none !important;
        color: #000000 !important;
        border: 1px solid #000000 !important;
    }
    html[data-theme="spatial"] .stn-done,
    html[data-theme="spatial"] .stn-badge {
        background: #ffffff !important;
        background-image: none !important;
        color: #000000 !important;
        border: 1px solid #000000 !important;
    }
    html[data-theme="spatial"] .stn-badge .dot { background: #000000 !important; }
    /* The calendar day chip must stay a solid readable chip on paper. */
    html[data-theme="spatial"] .cal-badge {
        background: #0090d4 !important;
        background-image: none !important;
        color: #ffffff !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    html[data-theme="spatial"] .field,
    html[data-theme="spatial"] .admin-input,
    html[data-theme="spatial"] .stn-picker,
    html[data-theme="spatial"] textarea,
    html[data-theme="spatial"] option,
    html[data-theme="spatial"] .qty-btn,
    html[data-theme="spatial"] .kanban-move button,
    html[data-theme="spatial"] .btn-ghost,
    html[data-theme="spatial"] .stn-unitdone,
    html[data-theme="spatial"] .view-toggle,
    html[data-theme="spatial"] .view-toggle-btn {
        background: #ffffff !important;
        color: #000000 !important;
        border-color: #cccccc !important;
    }

    /* Job card table + QR exactly as the page's own print block expects. */
    html[data-theme="spatial"] .jobcard { background: #ffffff !important; border: none !important; }
    html[data-theme="spatial"] .jc-table th,
    html[data-theme="spatial"] .jc-table td { color: #000000 !important; border-bottom-color: #cccccc !important; }
    html[data-theme="spatial"] .jc-table th { color: #444444 !important; }
    html[data-theme="spatial"] .jc-qr { background: #ffffff !important; border: 1px solid #000000 !important; padding: 0 !important; }
    html[data-theme="spatial"] .jc-stage { background: #f0f0f2 !important; color: #000000 !important; }

    /* Logos print as artwork, not as chips. */
    html[data-theme="spatial"] img[src*="daikin_logo"] {
        background: transparent !important;
        padding: 0 !important;
        border-radius: 0 !important;
    }

    /* Stage pills / badges: light chips with dark ink, like the classic theme. */
    html[data-theme="spatial"] .stage-pending    { background: #ececef !important; color: #6e6e73 !important; }
    html[data-theme="spatial"] .stage-design     { background: #fce7f0 !important; color: #b21e6a !important; }
    html[data-theme="spatial"] .stage-cutting    { background: #e3f2fd !important; color: #0a6cc4 !important; }
    html[data-theme="spatial"] .stage-bending    { background: #e7ecff !important; color: #3b4fd6 !important; }
    html[data-theme="spatial"] .stage-welding    { background: #fff2dd !important; color: #b35309 !important; }
    html[data-theme="spatial"] .stage-paint      { background: #f3e8ff !important; color: #8a3ffc !important; }
    html[data-theme="spatial"] .stage-packing    { background: #e0f7fa !important; color: #007a8a !important; }
    html[data-theme="spatial"] .stage-dispatched { background: #e6f0ff !important; color: #0059c9 !important; }
    html[data-theme="spatial"] .stage-delivered  { background: #e3f7eb !important; color: #1d8a4e !important; }
    html[data-theme="spatial"] .badge-high   { background: #ffe5e5 !important; color: #c11717 !important; }
    html[data-theme="spatial"] .badge-medium { background: #fff2dd !important; color: #b35309 !important; }
    html[data-theme="spatial"] .badge-low    { background: #e3f2fd !important; color: #0a6cc4 !important; }
    html[data-theme="spatial"] .qty-pill     { background: #0b2740 !important; color: #ffffff !important; }

    /* Metals back to bright brushed metal on paper. */
    html[data-theme="spatial"] .metal-gi,
    html[data-theme="spatial"] .metal-ms,
    html[data-theme="spatial"] .metal-ss304,
    html[data-theme="spatial"] .metal-ss316,
    html[data-theme="spatial"] .metal-alu,
    html[data-theme="spatial"] .metal-default { background: #eef1f4 !important; }
    html[data-theme="spatial"] .stock-group-head .mat-name { color: #17293a !important; }
    html[data-theme="spatial"] .stock-group-head .mat-sub  { color: #4a5a6a !important; }

    /* Progress + trackers as flat ink on paper. */
    html[data-theme="spatial"] .progress-track,
    html[data-theme="spatial"] .track-seg { background: #e8e8ed !important; }
    html[data-theme="spatial"] .progress-fill { background: #0090d4 !important; }
    html[data-theme="spatial"] .progress-fill.complete { background: #1d8a4e !important; }
    html[data-theme="spatial"] .track-seg.done { background: #0090d4 !important; }
    html[data-theme="spatial"] .track-seg.delivered { background: #1d8a4e !important; }

    /* Cut-program tables. */
    html[data-theme="spatial"] .cutp-table th { background: #1f4e79 !important; color: #ffffff !important; }
    html[data-theme="spatial"] .cutp-table td { color: #000000 !important; border-color: #d9e2ec !important; }
    html[data-theme="spatial"] .cutp-table tbody tr:nth-child(odd) td { background: #f4f6f8 !important; }
    html[data-theme="spatial"] .cutp-mat { background: #ffffff !important; }

    html[data-theme="spatial"] svg circle[stroke="#e8e8ed"] { stroke: #e8e8ed !important; }

    /* KPI inline colours back to the classic values. */
    html[data-theme="spatial"] #kpi-delivered-units { color: #1d8a4e !important; }
    html[data-theme="spatial"] #kpi-inprod-units    { color: #b35309 !important; }
    html[data-theme="spatial"] #kpi-overall-pct     { color: #0090d4 !important; }

    /* ---- undo section 23b: paper keeps the ORIGINAL dark inks ----
       These mirror section 23b one-for-one. They come later in the file at the
       same specificity and importance, so they win inside @media print, which
       hands each element straight back to its own inline style. */
    html[data-theme="spatial"] [style*="#c11717"]:not(.deliv-row),
    html[data-theme="spatial"] [style*="c11717"]:not(.deliv-row)  { color: #c11717 !important; }
    html[data-theme="spatial"] [style*="#b1400a"]:not(.deliv-row) { color: #b1400a !important; }
    html[data-theme="spatial"] [style*="#b35309"]:not(.deliv-row) { color: #b35309 !important; }
    html[data-theme="spatial"] [style*="#8a4b00"]:not(.deliv-row) { color: #8a4b00 !important; }
    html[data-theme="spatial"] [style*="#0067b3"]:not(.deliv-row) { color: #0067b3 !important; }
    html[data-theme="spatial"] [style*="#1d8a4e"]:not(.deliv-row) { color: #1d8a4e !important; }
    html[data-theme="spatial"] [style*="color:#6e6e73"]:not(.deliv-row) { color: #6e6e73 !important; }

    html[data-theme="spatial"] [style*="#e3f2fd"] { background: #e3f2fd !important; color: #0a6cc4 !important; }
    html[data-theme="spatial"] [style*="#e6f4fc"] { background: #e6f4fc !important; color: #0067b3 !important; }
    html[data-theme="spatial"] [style*="#fff2dd"] { background: #fff2dd !important; color: #b35309 !important; }
    html[data-theme="spatial"] [style*="#fff4e5"] { background: #fff4e5 !important; color: #8a4b00 !important; }
    html[data-theme="spatial"] [style*="#f3e8ff"] { background: #f3e8ff !important; color: #8a3ffc !important; }
    html[data-theme="spatial"] [style*="#e3f7eb"] { background: #e3f7eb !important; color: #1d8a4e !important; }
    html[data-theme="spatial"] [style*="#fde7f3"] { background: #fde7f3 !important; color: #c41d7f !important; }
    html[data-theme="spatial"] [style*="#e0f7fa"] { background: #e0f7fa !important; color: #007a8a !important; }
    html[data-theme="spatial"] [style*="#e7ecff"] { background: #e7ecff !important; color: #3b4fd6 !important; }
    html[data-theme="spatial"] [style*="#ffe9d6"] { background: #ffe9d6 !important; color: #b1400a !important; }
    html[data-theme="spatial"] [style*="#ffe5e5"] { background: #ffe5e5 !important; color: #c11717 !important; }

    /* Delivery-calendar stripe: hand it back to its own inline batch colour. */
    html[data-theme="spatial"] .deliv-row[style*="#0a6cc4"] { border-left-color: #0a6cc4 !important; }
    html[data-theme="spatial"] .deliv-row[style*="#b35309"] { border-left-color: #b35309 !important; }
    html[data-theme="spatial"] .deliv-row[style*="#8a3ffc"] { border-left-color: #8a3ffc !important; }
    html[data-theme="spatial"] .deliv-row[style*="#1d8a4e"] { border-left-color: #1d8a4e !important; }
    html[data-theme="spatial"] .deliv-row[style*="#c41d7f"] { border-left-color: #c41d7f !important; }
    html[data-theme="spatial"] .deliv-row[style*="#007a8a"] { border-left-color: #007a8a !important; }
    html[data-theme="spatial"] .deliv-row[style*="#3b4fd6"] { border-left-color: #3b4fd6 !important; }
    html[data-theme="spatial"] .deliv-row[style*="#b1400a"] { border-left-color: #b1400a !important; }

    /* Sidebar-only chrome that must never survive to paper. */
    html[data-theme="spatial"] .side-signout,
    html[data-theme="spatial"] .side-avatar,
    html[data-theme="spatial"] .side-user { display: none !important; }
}


/* ============================================================================
   26  PALLET TRACEABILITY  (19-Aug-2026)
   The dark-glass twin of the "Pallet traceability" block at the bottom of
   styles.css: the part typeahead + pallet chips on the delivery note, the
   drag-to-pallet target, and the public finder page. styles.css owns the
   geometry (sizes, radii, tap targets); this section only re-tints it, exactly
   like sections 04–22 do for the older components.

   WHY IT SITS BELOW THE PRINT RESET
   Section 25 re-points the tokens inside @media print, and a custom property is
   resolved where it is USED, not where it is declared — so every rule below
   that paints through var(--surface) / var(--tint-*) / var(--ink-*) still comes
   off the printer white, even though it is written after section 25. That is
   also why nothing here hardcodes a dark hex. The interactive chrome itself
   (dropdown, chip row, sticky search) is hidden for print by styles.css, which
   loads in both themes. The CONTENTS list at the top of this file stops at 25 —
   left untouched on purpose (additive-only change).
   ============================================================================ */

/* ---- Part typeahead ---- */
html[data-theme="spatial"] .pt-suggest,
html[data-theme="spatial"] .ta-results {
    background: var(--surface-solid);   /* solid: DN item rows scroll under it */
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border-color: var(--glass-border);
    box-shadow: var(--hi-top), var(--shadow-lift);
}
html[data-theme="spatial"] .pt-suggest-row,
html[data-theme="spatial"] .ta-row { color: var(--ink); }
html[data-theme="spatial"] .pt-suggest-row:hover,
html[data-theme="spatial"] .ta-row:hover { background: var(--tint-neutral-2); }

/* The classic look fills the keyboard row with Daikin blue and white text. On
   dark glass that same fill dulls the ink, so the highlight is carried by a
   doubled blue wash plus a 2px cyan ring while the text stays full --ink: the
   row is unmistakable at arm's length on a wall tablet and still >= 12:1. */
html[data-theme="spatial"] .pt-suggest-row.active,
html[data-theme="spatial"] .ta-row.ta-hi {
    background: linear-gradient(0deg, var(--tint-blue), var(--tint-blue)), var(--surface-2);
    color: var(--ink);
    box-shadow: inset 0 0 0 2px var(--line-blue);
}
html[data-theme="spatial"] .pt-suggest-code,
html[data-theme="spatial"] .ta-code {
    background: var(--recess);
    color: var(--ink);
    box-shadow: inset 0 0 0 1px var(--glass-border);
}
html[data-theme="spatial"] .pt-suggest-row.active .pt-suggest-code,
html[data-theme="spatial"] .ta-row.ta-hi .ta-code {
    background: var(--recess);
    color: var(--ink-blue);
}
html[data-theme="spatial"] .pt-suggest-empty,
html[data-theme="spatial"] .ta-empty { color: var(--ink-3); }

/* ---- Pallet drop target ---- */
html[data-theme="spatial"] .pallet-drop.over,
html[data-theme="spatial"] .dn-pallet-drop.dn-drop-hot {
    background: linear-gradient(0deg, var(--tint-blue), var(--tint-blue)), var(--surface-2);
    box-shadow: inset 0 0 0 2px var(--accent-2),
                0 0 0 4px rgba(56, 189, 248, 0.30),
                0 18px 40px -22px rgba(0, 0, 0, 0.95);
}

/* ---- Quick pallet chips ---- */
html[data-theme="spatial"] .pt-chip,
html[data-theme="spatial"] .dn-chip {
    background: var(--surface-2);
    border-color: var(--glass-border);
    color: var(--ink);
    box-shadow: var(--hi-top);
}
html[data-theme="spatial"] .pt-chip:hover,
html[data-theme="spatial"] .dn-chip:hover {
    background: var(--tint-neutral-2);
    border-color: rgba(120, 170, 220, 0.34);
}
html[data-theme="spatial"] .pt-chip:active,
html[data-theme="spatial"] .dn-chip:active {
    background: linear-gradient(0deg, var(--tint-blue), var(--tint-blue)), var(--surface-2);
    border-color: var(--line-blue);
    color: var(--ink);
}

/* ---- Permanent pallet id ---- */
html[data-theme="spatial"] .pt-pallet-id,
html[data-theme="spatial"] .dn-pal-ids {
    background: var(--recess);
    border-color: var(--glass-border);
    color: var(--ink);
}
/* Public finder page: styled inside find.html itself (token-driven, so it
   follows this theme automatically). The duplicate block that was here used
   class names find.js never emits and is gone -- do not re-add it. */


/* Dark re-tint for the delivery-note-only classes added in styles.css. */
html[data-theme="spatial"] .ta-meta { color: var(--ink-3); }
html[data-theme="spatial"] .ta-act  { color: var(--accent-2); }
html[data-theme="spatial"] .ta-row.ta-hi .ta-act,
html[data-theme="spatial"] .ta-row.ta-hi .ta-meta { color: #fff; }
html[data-theme="spatial"] .ta-row.ta-added .ta-act { color: #6ee7a8; }
html[data-theme="spatial"] .dn-line.dn-dragging { box-shadow: 0 0 0 2px var(--accent-2) inset; }
html[data-theme="spatial"] .dn-grip { color: var(--ink-3); }
html[data-theme="spatial"] .dn-chip.dn-chip-on {
    background: rgba(56,189,248,0.18); border-color: var(--accent-2); color: var(--ink);
}
html[data-theme="spatial"] .dn-chip-hint,
html[data-theme="spatial"] .dn-chip-demo,
html[data-theme="spatial"] .dn-pal-none { color: var(--ink-3); }

/* Extends the section 24 guard for the four transitions styles.css adds above. */
@media (prefers-reduced-motion: reduce) {
    html[data-theme="spatial"] .pt-suggest-row,
    html[data-theme="spatial"] .ta-row,
    html[data-theme="spatial"] .pallet-drop,
    html[data-theme="spatial"] .dn-pallet-drop,
    html[data-theme="spatial"] .pt-chip,
    html[data-theme="spatial"] .dn-chip { transition: none !important; }
    html[data-theme="spatial"] .pallet-drop.over,
    html[data-theme="spatial"] .dn-pallet-drop.dn-drop-hot,
    html[data-theme="spatial"] .pt-chip:active,
    html[data-theme="spatial"] .dn-chip:active { transform: none !important; }
}
