/*
 * CabinetWorks Pro — Design Tokens
 * Single source of truth for all spacing, typography, radius, elevation,
 * motion, and z-index values used across the shell and future page templates.
 *
 * RULES:
 *   - The app's TWO-theme colour palette (light default + dark) lives at the
 *     BOTTOM of this file so any standalone page can render in the app's
 *     themes with a single <link> (no per-page hardcoded hex). The main SPA
 *     also carries an identical copy inline in app.css; keep the two in sync.
 *   - No component layout rules here — that is shell.css and future page CSs.
 *   - Every --sp-* value maps directly to Section 2 of the Master UI Blueprint.
 *   - All --dur-snap consumers MUST NOT use transition on any element whose
 *     text content changes as a result of user input (numbers, prices, verdicts).
 *   - @media prefers-reduced-motion overrides all --dur-* to 0ms.
 */

:root {

  /* ------------------------------------------------------------------ */
  /* FONT FAMILIES                                                        */
  /* ------------------------------------------------------------------ */
  --ff-ui:   "Inter", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --ff-mono: "JetBrains Mono", "Cascadia Code", "Courier New", monospace;

  /* ------------------------------------------------------------------ */
  /* FONT WEIGHTS                                                         */
  /* ------------------------------------------------------------------ */
  --fw-regular:  400;
  --fw-medium:   500;
  --fw-semibold: 600;
  --fw-bold:     700;

  /* ------------------------------------------------------------------ */
  /* FONT SIZES                                                           */
  /* ------------------------------------------------------------------ */
  --fs-sm:   0.75rem;    /* 12px — dim-callout, monospace-cutlist */
  --fs-base: 1rem;       /* 16px — body, body-dim, numeric-dim    */
  --fs-lg:   1.0625rem;  /* 17px — section-h3, numeric-field      */
  --fs-xl:   1.25rem;    /* 20px — section-h2                     */
  --fs-2xl:  1.5rem;     /* 24px — page-h1                        */

  /* ------------------------------------------------------------------ */
  /* COMPOSITE TYPOGRAPHY ROLES                                          */
  /* (convenience shorthands — use individual properties in components) */
  /* ------------------------------------------------------------------ */
  --type-page-h1:        var(--fw-bold)     var(--fs-2xl)/1.25 var(--ff-ui);
  --type-section-h2:     var(--fw-semibold) var(--fs-xl)/1.3   var(--ff-ui);
  --type-section-h3:     var(--fw-semibold) var(--fs-lg)/1.35  var(--ff-ui);
  --type-body:           var(--fw-regular)  var(--fs-base)/1.5 var(--ff-ui);
  --type-body-dim:       var(--fw-regular)  var(--fs-base)/1.5 var(--ff-ui);
  --type-numeric-field:  var(--fw-medium)   var(--fs-lg)/1     var(--ff-mono);
  --type-numeric-dim:    var(--fw-medium)   var(--fs-base)/1   var(--ff-mono);
  --type-dim-callout:    var(--fw-bold)     var(--fs-sm)/1     var(--ff-mono);
  --type-mono-cutlist:   var(--fw-regular)  var(--fs-sm)/1.6   var(--ff-mono);

  /* ------------------------------------------------------------------ */
  /* SPACING SCALE                                                        */
  /* 4px base unit. Exact values per Blueprint Section 2.               */
  /* ------------------------------------------------------------------ */
  --sp-0:   0px;   /* Reset                                    */
  --sp-1:   4px;   /* Icon internal pad, chip tight gap        */
  --sp-2:   8px;   /* Base unit, inline label gap              */
  --sp-3:  12px;   /* Chip row outer padding                   */
  --sp-4:  16px;   /* Form field gap                           */
  --sp-5:  20px;   /* Button internal horizontal pad           */
  --sp-6:  24px;   /* Card body pad                            */
  --sp-7:  32px;   /* Section divider                          */
  --sp-8:  40px;   /* Panel top/bottom pad                     */
  --sp-9:  48px;   /* Toolbar height minimum                   */
  --sp-10: 56px;   /* Top bar height / sidebar collapsed width */
  --sp-11: 64px;   /* Modal footer height                      */
  --sp-12: 96px;   /* Page hero zone                           */

  /* Semantic aliases so callsites are self-documenting */
  --sp-form-gap:  var(--sp-4);   /* 16px gap between form fields    */
  --sp-card-pad:  var(--sp-6);   /* 24px card body padding          */
  --sp-section:   var(--sp-7);   /* 32px section divider            */

  /* PR-CABINET-REDESIGN (2026-06-28): property-row + list-row rhythm */
  --sp-row:   10px;              /* property-row vertical pad (8↔12 gap) */
  --stripe-w: 3px;               /* category accent rail on list rows    */
  --row-h:    44px;              /* min-height floor for property rows    */

  /* ------------------------------------------------------------------ */
  /* CORNER RADIUS                                                        */
  /* ------------------------------------------------------------------ */
  --radius-xs: 3px;                /* Tags, status pills, badges      */
  --radius-sm: 6px;                /* Inputs, selects, small cards    */
  --radius-md: 10px;               /* Cards, panels, drawers          */
  --radius-lg: 16px;               /* Modals, bottom sheets           */
  --radius:    var(--radius-md);   /* End-user knob maps here (Phase D) */

  /* ------------------------------------------------------------------ */
  /* ELEVATION / SHADOW                                                   */
  /* ------------------------------------------------------------------ */
  --shadow-card:       0 1px 3px  rgba(0,0,0,.18), 0 1px 2px  rgba(0,0,0,.12);
  --shadow-card-hover: 0 4px 12px rgba(0,0,0,.22), 0 2px 4px  rgba(0,0,0,.12);
  --shadow-popover:    0 8px 24px rgba(0,0,0,.28), 0 2px 6px  rgba(0,0,0,.14);
  --shadow-modal:      0 20px 60px rgba(0,0,0,.45), 0 8px 20px rgba(0,0,0,.20);

  /* ------------------------------------------------------------------ */
  /* MOTION                                                               */
  /* CRITICAL: --dur-snap MUST be applied to every element whose text   */
  /* content is a dimension, price, compat verdict, or cutlist number.  */
  /* Never use CSS transition on those elements.                        */
  /* ------------------------------------------------------------------ */
  --dur-snap:     0ms;    /* Numbers, prices, verdicts — instant     */
  --dur-quick:    80ms;   /* Hover, focus ring, button press         */
  --dur-panel:   120ms;   /* Bundle reveal, step transition          */
  --dur-chrome:  150ms;   /* Sidebar expand/collapse, drawer, tabs   */
  --dur-standard:200ms;   /* Panel open, card lift, 3D selection     */
  --dur-slow:    320ms;   /* Major view transition, modal entrance   */
  --ease-out:     cubic-bezier(0.0, 0.0, 0.2, 1);
  --ease-in-out:  cubic-bezier(0.4, 0.0, 0.2, 1);
  /* Apple Pro spring curves — master prompt §9.1 */
  --spring-snappy: cubic-bezier(0.2, 0.8, 0.2, 1.0);  /* overshoot settle */
  --spring-gentle: cubic-bezier(0.25, 0.1, 0.25, 1.0); /* soft float, 3D */

  /* ------------------------------------------------------------------ */
  /* Z-INDEX NAMED LAYERS                                                 */
  /* Rationale: every z-index in the codebase must reference one of     */
  /* these tokens. sentinel grep rule flags any raw z-index value above */
  /* 99 that is not a token reference.                                  */
  /* ------------------------------------------------------------------ */
  --z-base:      0;   /* Normal flow                          */
  --z-sticky:   10;   /* Sticky table headers, step bar       */
  --z-sidebar:  20;   /* Left sidebar                         */
  --z-topbar:   30;   /* Top bar                              */
  --z-statusbar:30;   /* Status bar (same layer as topbar)    */
  --z-popover:  40;   /* Tooltips, dropdowns                  */
  --z-drawer:   50;   /* Settings drawer, right panels        */
  --z-modal:    60;   /* Dialogs                              */
  --z-toast:    70;   /* Toast notifications                  */
  --z-boot:     80;   /* Boot overlay (WASM loading)          */

  /* ------------------------------------------------------------------ */
  /* THEME-STABLE COLOR EXCEPTIONS                                       */
  /* PR-UI-4 (2026-04-27).                                               */
  /*                                                                     */
  /* Per the file rule at the top of this file ("No colour tokens here  */
  /* — colour lives in the :root[data-theme] blocks already in           */
  /* index.html"), color tokens normally live in the per-theme blocks.   */
  /*                                                                     */
  /* The toast tokens below are EXPLICIT EXCEPTIONS because the toast    */
  /* UI must remain legible across EVERY theme. The original code at    */
  /* index.html:1859-1862 documents a prior incident where letting      */
  /* toasts use var(--txt) / var(--sf) produced white-on-white in a    */
  /* light palette. They were hardcoded at #1A1A1A / #2A2A2A / #F5F5F5  */
  /* to fix that. We promote those constants to named tokens so the     */
  /* contract is mechanically reachable from grep + visible in the      */
  /* design-token inventory, while keeping the across-theme stability.  */
  /* ------------------------------------------------------------------ */
  --toast-bg:  #1A1A1A;
  --toast-bdr: #2A2A2A;
  --toast-fg:  #F5F5F5;

  /* ------------------------------------------------------------------ */
  /* LIBRARY-HUB CATEGORY ACCENT TOKENS                                  */
  /* PR-LIB-COLOR-TOKENS (2026-05-25).                                   */
  /*                                                                     */
  /* Same theme-stable exception rationale as the toast tokens above.    */
  /* These nine swatches encode "what kind of woodshop thing is this"    */
  /* (door bronze, cabinet sand, sheet wood, finish teal, etc.) and      */
  /* MUST stay recognisable across every palette swap — a cabinet card   */
  /* shouldn't suddenly turn green in the Dark theme. The values are     */
  /* the same hex that previously lived inline in shell.css's            */
  /* .lib-hub-card[data-accent=...] rules; promoting them to tokens     */
  /* enforces a single source of truth and makes the design-token        */
  /* inventory complete.                                                 */
  /* ------------------------------------------------------------------ */
  --acc-cabinet:   #c89968;   /* warm sand — cabinet bodies              */
  --acc-door:      #8b6f47;   /* door bronze — door styles               */
  --acc-sheet:     #a78865;   /* sheet goods — plywood / MDF             */
  --acc-finish:    #5b8c8c;   /* teal — paint / stain / finish           */
  --acc-drawer:    #b08968;   /* drawer wood — drawer boxes              */
  --acc-lumber:    #7a5a3a;   /* rough lumber — solid stock              */
  --acc-profile:   #6b7280;   /* slate profile — edge / sticking         */
  --acc-hardware:  #4b5563;   /* steel — hinges / slides / pulls         */
  --acc-inventory: #4a7c59;   /* stock green — on-hand counts            */
  --acc-library:   #b8956a;   /* library surface — honey tan stripe/badge */
  --acc-library-deep: #8a7642; /* deeper olive — library badge ink        */

  /* ------------------------------------------------------------------ */
  /* SHADOW SCALE TOKENS                                                 */
  /* PR-LIB-COLOR-TOKENS (2026-05-25).                                   */
  /*                                                                     */
  /* Shadows are theme-stable (raw rgba black with varying opacity)      */
  /* and consumed everywhere — promoted to a numbered scale so authors   */
  /* never write a one-off rgba(0,0,0,...) for a shadow. Six steps cover */
  /* the entire app from subtle resting (--shadow-1) to modal lifts      */
  /* (--shadow-6). The inset variant gives interactive controls a 1px    */
  /* top highlight; the glow-* variants tint a shadow with the active    */
  /* status colors so a focused button can pulse with --acc / --ok /     */
  /* --warn / --no without re-introducing raw rgba values.               */
  /* ------------------------------------------------------------------ */
  --shadow-1:      0 1px 2px rgba(0,0,0,.10);                            /* tight resting          */
  --shadow-2:      0 2px 4px rgba(0,0,0,.15);                            /* card resting           */
  --shadow-3:      0 4px 12px rgba(0,0,0,.22), 0 2px 4px rgba(0,0,0,.12); /* card hover lift       */
  --shadow-4:      0 8px 24px rgba(0,0,0,.28), 0 2px 6px rgba(0,0,0,.14); /* popover / dropdown    */
  --shadow-5:      0 12px 40px rgba(0,0,0,.36);                          /* drawer / sheet         */
  --shadow-6:      0 20px 60px rgba(0,0,0,.45), 0 8px 20px rgba(0,0,0,.20); /* modal               */
  --shadow-inset:  inset 0 1px 0 rgba(255,255,255,.06);                  /* subtle top highlight   */
  --shadow-glow-acc:  0 0 12px color-mix(in srgb, var(--acc)  35%, transparent);
  --shadow-glow-ok:   0 0 12px color-mix(in srgb, var(--ok)   35%, transparent);
  --shadow-glow-warn: 0 0 12px color-mix(in srgb, var(--warn) 35%, transparent);
  --shadow-glow-no:   0 0 12px color-mix(in srgb, var(--no)   35%, transparent);

  /* Scrim — drawer / sidebar / sheet backdrop. Always dark (light themes
     also want a darkening overlay; brightening with white would look like
     a fog rather than a dim). Theme-stable like toast tokens. */
  --scrim:           rgba(0,0,0,.40);
  --scrim-strong:    rgba(0,0,0,.55);

  /* Subtle white-bevel highlight on dark surfaces. Theme-stable. */
  --hairline-white:  rgba(255,255,255,.04);

  /* Named composite shadows for the hub hero cards + KPI press effects.
     These tint the dark base shadow with the active --acc so a theme swap
     re-tints the hero glow without re-writing the rule. Living in tokens
     keeps the rgba(0,0,0,...) base alpha values inside the palette file
     where the strict-token rule allows them. */
  --shadow-hero-rest:
      0 1px 2px rgba(0,0,0,0.08),
      0 4px 12px color-mix(in srgb, var(--acc) 5%, rgba(0,0,0,0.06));
  --shadow-hero-hover:
      0 4px 8px rgba(0,0,0,0.12),
      0 16px 32px color-mix(in srgb, var(--acc) 16%, rgba(0,0,0,0.18));
  --shadow-press-acc:
      inset 0 2px 6px color-mix(in srgb, var(--acc) 18%, rgba(0,0,0,0.12)),
      0 0 0 2px color-mix(in srgb, var(--acc) 22%, transparent);

  /* Cf- modern shell state-layer + elevation tokens are NOT here — they're
     scoped to body[data-ui-version="cabforge"] in shell.css since they're
     a per-UI-version palette and shouldn't leak to legacy chrome modes. */
}

/* Reduce motion: override all duration tokens to 0ms.
   Elements that use --dur-snap are already 0ms so this is a no-op for
   them, but it correctly collapses sidebar/drawer/panel animations. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-quick:    0ms;
    --dur-panel:    0ms;
    --dur-chrome:   0ms;
    --dur-standard: 0ms;
    --dur-slow:     0ms;
  }
}

/* ====================================================================== */
/* PR-UI-2 — NUMERIC NO-ANIMATE ENFORCEMENT                                */
/* ====================================================================== */
/* Structural backstop for the rule documented at the top of this file:    */
/* any element whose text content is a dimension, price, count, or status  */
/* verdict MUST carry one of these classes so its value transitions are    */
/* suppressed.                                                             */
/*                                                                         */
/* Why selectors live in tokens.css:                                       */
/*   tokens.css normally contains only custom properties, not selectors.   */
/*   These two are an explicit exception because they enforce the          */
/*   project's most fundamental UI rule (manufacturing accuracy: no fake   */
/*   animated counting between two numeric values that came from Rust).   */
/*   Keeping them here makes the rule mechanically reachable from any     */
/*   page that loads the design system, not just shell.css consumers.    */
/*                                                                         */
/* `tabular-nums` keeps every digit at the same advance width so the      */
/* value snap is positionally stable (no horizontal jitter when 9 → 10).  */
/* `transition: none !important` overrides any inherited rule, including   */
/* a hypothetical future `transition: all` regression elsewhere.          */
.numeric-field,
.numeric-dim {
    transition: none !important;
    font-variant-numeric: tabular-nums;
}

/* ====================================================================== */
/* PR-UI-1 — STATUS-PILL ENTRANCE (master prompt §9.3-D)                   */
/* ====================================================================== */
/* Plays once when JS toggles `.status-pill.is-updated` on a state         */
/* transition. Initial render renders flat — no animation on page load.   */
/* Reduced-motion users get an instant change because the duration token  */
/* (--dur-quick) is zeroed in the reduced-motion block above.            */
@keyframes pill-pop {
  0%   { transform: scale(0.6); opacity: 0; }
  70%  { transform: scale(1.08); }
  100% { transform: scale(1);    opacity: 1; }
}

/* ======================================================================
   PR-MDEV-1 — MULTI-DEVICE FOUNDATION TOKENS (2026-05-23)
   ======================================================================
   Additive, inert-by-default tokens that let the codebase progressively
   adopt fluid typography, fluid spacing, capability-driven density, and
   stable/dynamic viewport heights. None of these tokens are consumed by
   existing rules; opt-in is per component. Adding them here cannot
   regress any existing surface — they only resolve when a callsite
   references them.

   Full plan + research synthesis: docs/MULTI_DEVICE_PLAN.md
   ====================================================================== */

:root {

  /* --------------------------------------------------------------------
     SIZE-CLASS HINT (Material 3 Window Size Classes)
     Re-exposed as CSS custom property so JS can read the active class via
     getComputedStyle. Components key off the breakpoint media queries
     below; this token is for analytics / behavioral branching in JS.
     -------------------------------------------------------------------- */
  --mdev-size-class: compact;

  /* --------------------------------------------------------------------
     TOUCH-TARGET FLOORS (pointer-coarse aware)
     Base = WCAG 2.2 AA enhanced 44px (also Apple HIG 44pt). Coarse
     pointer (phone, shop tablet with gloves) bumps to 64px per FFitts
     finger-precision floor (Bi/Li/Zhai CHI 2013) and Faytech glove-on-
     PCAP guidance (~10-12mm). Office mouse stays compact.
     -------------------------------------------------------------------- */
  --touch-min: 44px;            /* tap target floor */
  --touch-comfortable: 56px;    /* comfortable mid */
  --touch-spacious: 64px;       /* gloved-hand floor */
  --touch-gap-min: 4px;         /* minimum gap between adjacent targets */
  --touch-gap-spacious: 12px;   /* gloved-hand gap */

  /* --------------------------------------------------------------------
     DENSITY MULTIPLIER
     Multiply spacing scale by this token for surfaces that should
     breathe more under coarse pointers. Default 1.0 = no change.
     -------------------------------------------------------------------- */
  --density: 1;

  /* --------------------------------------------------------------------
     FLUID TYPE SCALE (clamp-based, Utopia-style)
     Floor = 320px viewport, ceiling = 1600px viewport. The preferred
     middle uses calc(rem-floor + vw-slope*vw) so type scales smoothly
     across the range without breakpoint discontinuities.

     Test: at 320px viewport, --fs-fluid-base resolves to ~14px;
     at 1600px viewport, ~18px. Body legibility preserved at every step.
     Accessibility note: ceiling values are >= rem floor so browser zoom
     keeps working (WCAG 1.4.4).
     -------------------------------------------------------------------- */
  --fs-fluid-sm:    clamp(0.75rem, 0.70rem + 0.25vw, 0.875rem);  /* 12-14px */
  --fs-fluid-base:  clamp(0.875rem, 0.80rem + 0.375vw, 1.125rem); /* 14-18px */
  --fs-fluid-lg:    clamp(1rem, 0.90rem + 0.50vw, 1.25rem);      /* 16-20px */
  --fs-fluid-xl:    clamp(1.125rem, 1.00rem + 0.625vw, 1.50rem); /* 18-24px */
  --fs-fluid-2xl:   clamp(1.25rem, 1.05rem + 1.00vw, 1.875rem);  /* 20-30px */
  --fs-fluid-3xl:   clamp(1.5rem, 1.20rem + 1.50vw, 2.5rem);     /* 24-40px */

  /* TV-leanback type (24sp+ floor for 10-foot viewing) */
  --fs-tv-body:     clamp(1.5rem, 1.20rem + 1.50vw, 2.25rem);    /* 24-36px */
  --fs-tv-heading:  clamp(2rem, 1.50rem + 2.50vw, 3.5rem);       /* 32-56px */

  /* --------------------------------------------------------------------
     FLUID SPACING (clamp-based)
     Optional micro/macro variants for fluid surfaces. Existing fixed
     --sp-N tokens unchanged.
     -------------------------------------------------------------------- */
  --sp-fluid-card-pad:    clamp(12px, 8px + 1vw, 24px);
  --sp-fluid-section:     clamp(16px, 8px + 2vw, 48px);
  --sp-fluid-page-gutter: clamp(12px, 4px + 2vw, 32px);

  /* --------------------------------------------------------------------
     VIEWPORT HEIGHT ALIASES (svh / dvh / lvh)
     Per Bram.us "Large, Small, Dynamic Viewports" guidance:
       --vh-stable  = svh (does NOT reflow as iOS Safari URL bar slides)
       --vh-dynamic = dvh (reflows with URL bar; intentional full-bleed)
       --vh-large   = lvh (assumes URL bar collapsed)
     Default: stable. Modal sheets and bottom drawers should use
     --vh-stable to avoid keyboard-occlusion + URL-bar-slide jank.
     Fallback to 100vh for browsers without dvh support (pre-2022).
     -------------------------------------------------------------------- */
  --vh-stable:  100vh;     /* SAFE default; overridden below where supported */
  --vh-dynamic: 100vh;
  --vh-large:   100vh;

  /* --------------------------------------------------------------------
     FOCUS RING (prefers-contrast aware)
     -------------------------------------------------------------------- */
  --focus-ring-w: 2px;
  --focus-ring-offset: 2px;
}

/* Modern browsers (Safari 15.4+, Chrome 108+, Firefox 110+) get the
   stable/dynamic/large viewport units. Older browsers fall back to the
   100vh defaults above. @supports is the universally-supported gate. */
@supports (height: 100svh) {
  :root {
    --vh-stable:  100svh;
    --vh-dynamic: 100dvh;
    --vh-large:   100lvh;
  }
}

/* Coarse pointer (phone, shop tablet, glove-encumbered touch):
   bump tap-target floor + gap minimum + density. Office mouse
   surfaces unchanged. */
@media (pointer: coarse) {
  :root {
    --touch-min: 56px;          /* up from 44px */
    --touch-gap-min: 8px;       /* up from 4px */
    --density: 1.15;            /* spacing scale ~15% looser */
  }
}

/* Hybrid devices (iPad + Apple Pencil + Magic Keyboard, Surface):
   if ANY input is fine, treat as office. Falls between the two
   --touch-min values above. */
@media (any-pointer: fine) and (pointer: coarse) {
  :root {
    --touch-min: 48px;
  }
}

/* Material 3 Window Size Classes — expose active class as a token so
   JS can read it via getComputedStyle(...).getPropertyValue. */
@media (min-width: 600px)  { :root { --mdev-size-class: medium;       } }
@media (min-width: 840px)  { :root { --mdev-size-class: expanded;     } }
@media (min-width: 1200px) { :root { --mdev-size-class: large;        } }
@media (min-width: 1600px) { :root { --mdev-size-class: extra-large;  } }

/* High-contrast preference: bump focus ring + border weight tokens.
   Inert until consumers reference the tokens. */
@media (prefers-contrast: more) {
  :root {
    --focus-ring-w: 3px;
    --focus-ring-offset: 3px;
  }
}

/* ======================================================================
   PR-RESPONSIVE-STUDIO (2026-07-30) — UNIVERSAL PHONE TOUCH BASELINE
   ======================================================================
   tokens.css is loaded by EVERY surface — the SPA *and* every standalone
   page (login, wizard, room-editor, job-specs, foreman, floor, ship-scan,
   track, admin/*). The SPA has a richer phone pass in shell.css; the
   standalone pages (which load ONLY tokens.css) had nothing. This is a
   safe, universal touch + reflow baseline so forms/controls are finger-
   usable and nothing overflows a 360px screen. Deliberately minimal — no
   heading/layout opinions that could clash with a page's own design. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
@media (max-width: 599px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
  select, textarea {
    font-size: 16px;      /* >=16px prevents iOS zoom-on-focus */
    min-height: 44px;     /* WCAG 2.5.5 tap floor */
  }
  button, [role="button"], .btn, a.btn { min-height: 44px; }
  img, svg, video, iframe { max-width: 100%; }
}

/* ======================================================================
   COLOUR PALETTE — exactly TWO themes: light (default) + dark. 2026-07-18.
   Kept here (an always-loaded, always-served token file) so EVERY standalone
   page — login, room-editor, job-specs, foreman, ship-scan, cnc-folders,
   export-destinations, setup-onboarding — renders in the same light/dark as
   the main SPA by just loading tokens.css + setting data-theme on <html>.
   These values are byte-identical to app.css :root[data-theme=...] and
   admin-shell.css. Switch with data-theme="light|dark" (a tiny head bootstrap
   reads csp.theme from localStorage). DO NOT add a third theme.
   ====================================================================== */

/* ─── LIGHT (default) — bright drafting-paper engineering canvas ─── */
:root, :root[data-theme="light"] {
    --bg:    #F3F5F8;
    --sf:    #E9EDF2;
    --pn:    #FFFFFF;
    --pn-h:  #F0F3F7;
    --inp:   #FFFFFF;
    --bdr:   #D9DFE7;
    --bdr-h: #AAB3C0;
    --acc:   #2563EB;
    --acc2:  #1D4FD8;
    --acc-ink: #FFFFFF;
    --txt:   #1A222E;
    --dim:   #5A6573;
    --muted: #8C95A0;
    --white: #0D1118;
    --ink:   var(--white);
    --ok:    #0E9D6E;   --ok-ink:   #FFFFFF;
    --warn:  #C77700;   --warn-ink: #FFFFFF;
    --no:    #D33A4B;   --no-ink:   #FFFFFF;
    --lime:  #0E9D6E;   --lime-ink: #FFFFFF;
}

/* ─── DARK — near-black engineering canvas, SAME blueprint-blue accent ─── */
:root[data-theme="dark"] {
    --bg:    #000000;
    --sf:    #000000;
    --pn:    #16181C;
    --pn-h:  #1E2127;
    --inp:   #202327;
    --bdr:   #2F3336;
    --bdr-h: #3E4348;
    --acc:   #4C8DFF;
    --acc2:  #6AA5FF;
    --acc-ink: #05070D;
    --txt:   #E7E9EA;
    --dim:   #9AA3B0;
    --muted: #6B7480;
    --white: #FFFFFF;
    --ink:   var(--txt);
    --ok:    #34D399;   --ok-ink:   #06281D;
    --warn:  #F0B429;   --warn-ink: #2A1E03;
    --no:    #F2566B;   --no-ink:   #2A0810;
    --lime:  #34D399;   --lime-ink: #06281D;
}

/* Theme-stable derived tokens (follow the active theme via use-time var()). */
:root {
    --status-draft:        var(--dim);      --status-draft-ink:     var(--bg);
    --status-scheduled:    var(--warn);     --status-scheduled-ink: var(--warn-ink);
    --status-progress:     var(--acc);      --status-progress-ink:  var(--acc-ink);
    --status-complete:     var(--ok);       --status-complete-ink:  var(--ok-ink);
    --status-alert:        var(--no);       --status-alert-ink:     var(--no-ink);
    --canvas-viewport:       var(--bg);
    --canvas-grid-minor:     var(--pn-h);
    --canvas-grid-major:     var(--bdr);
    --canvas-model-default:  #D1D1D1;
    --canvas-select-fill:    var(--acc);
    --canvas-select-outline: var(--acc2);
    --canvas-dim-text:       var(--txt);
    --canvas-snap:           var(--acc2);
    --canvas-axis-x:         #E06B6B;
    --canvas-axis-y:         #6BC97A;
    --canvas-axis-z:         var(--acc);
}
