/* ============================================================================
   INNOVOTE INVENTORY — TOKEN LAYER
   Production CSS custom properties. Nothing in this file references a component.
   Every other stylesheet references only these.

   PORTED VERBATIM from innovote-inventory-design/tokens.css. Two edits, both
   listed here so a reviewer can diff the two files and account for every line:
     1. The font stacks name the self-hosted faces in fonts.css. There is no
        Google Fonts link anywhere in this application — see fonts.css.
     2. `--font-mono` no longer falls through to a system mono. Fira Code is
        self-hosted, so the fallback only exists for the seconds before it
        loads, and a system mono with different digit widths makes a column of
        codes jump when the real face arrives.
   Nothing else changed. The measured contrast ratios below were computed in the
   design pass and are reproduced unaltered.

   Palette is verbatim from https://innovoteglobal.com/brand/ :
     Deep Teal #0B1F1F · Warm Amber #E0A23B · Cream #F6F4EF
     Graphite #232A2A · Secondary Teal #0E5B5B
   Ratio 60/30/10 — ~60% cream+graphite, 30% teal, 10% amber.

   Every contrast ratio in the comments below was computed, not estimated.
   Ratios are WCAG 2.1 relative luminance, rounded to 2dp.

   Two themes ship: [data-theme="day"] (default, cream body — desk, dock, sun)
   and [data-theme="night"] (Deep Teal body — dim aisle, evening shift).
   Justification in DESIGN-DECISIONS.md §4.
   ========================================================================= */

/* ---------------------------------------------------------------------------
   1. RAW PALETTE — brand-literal. Never used directly by components.
      Components use the semantic tokens in §3.
   ------------------------------------------------------------------------ */
:root {
  /* --- The five brand colours, exactly as published --- */
  --brand-deep-teal:   #0B1F1F;
  --brand-amber:       #E0A23B;
  --brand-cream:       #F6F4EF;
  --brand-graphite:    #232A2A;
  --brand-teal:        #0E5B5B;

  /* --- Brand ramps, from 08-identity/colour-system.md --- */
  --teal-900: #06302F;
  --teal-800: #0A4A47;   /* the sanctioned link teal — 9.17:1 on cream */
  --teal-700: #0B4F4F;
  --teal-600: #0E5B5B;   /* Secondary Teal */
  --teal-500: #16998C;   /* large UI + focus rings ONLY — 3.20:1 on cream */
  --teal-400: #5FB3A8;
  --teal-300: #7FCBBF;
  --teal-200: #C9E6E1;
  --teal-100: #EAF5F2;

  --amber-900: #6E4609;  /* text-safe amber — 7.55:1 on amber-050 */
  --amber-800: #7A4E0C;
  --amber-700: #9A6516;  /* 4.50:1 on cream — AA body, ramp-native */
  --amber-600: #B97A1E;
  --amber-500: #E0A23B;  /* Warm Amber */
  --amber-400: #EFC178;
  --amber-300: #F8E4BE;
  --amber-100: #FCF4E3;

  --graphite-900: #161B1B;
  --graphite-800: #232A2A; /* Graphite — 13.30:1 on cream */
  --graphite-600: #4A5453; /*  7.12:1 on cream */
  --graphite-500: #5F6866; /*  5.22:1 on cream — lowest legal muted ink */
  --graphite-400: #8A938F; /*  2.87:1 — DECORATIVE ONLY, never text */
  --graphite-200: #C7CCC9;

  /* Warm neutrals — the cream family */
  --paper:      #FFFFFF;
  --paper-warm: #FDFCFA;
  --sand-100:   #F1EEE6;
  --sand-200:   #E7E2D8;   /* the brand's 1px card border */
  --sand-300:   #D8D2C6;
  --sand-400:   #CFC8BA;
  --stone-100:  #EBE8E0;

  /* Dark frame family — brand's own dark chrome, promoted to a full surface */
  --dk-900: #08191A;
  --dk-850: #0B1F1F;   /* Deep Teal */
  --dk-800: #12302F;
  --dk-700: #163A38;
  --dk-600: #1C4341;
  --dk-line: #27403E;
  --dk-line-2: #33504D;
  --dk-ink-1: #FFFFFF;   /* 17.07:1 on Deep Teal */
  --dk-ink-2: #C9D6D4;   /* 11.42:1 */
  --dk-ink-3: #9FB3B0;   /*  7.76:1 */

  /* --- State hues.
     NOT invented. Promoted from the brand's own EXTENDED palette
     (colour-system.md §2, Food Flavourings fruity spectrum), because the
     core five carry no danger and no hold colour and this app needs both.
     See DESIGN-DECISIONS.md §5. --- */
  --cherry-800: #8F2718;  /* 7.73:1 on cream */
  --cherry-700: #A3301F;  /* 6.37:1 on cream */
  /* Cherry, one step darker than the brand fill. White on it is 5.83:1.
     It exists because white on --cherry-500 is 4.53:1 — a pass by 0.03,
     which is not a margin to put a destructive action behind on a scratched
     phone in daylight. The hue shift is not perceptible beside the brand
     fill, and the brand fill keeps every job it already had. */
  --cherry-600: #B8371F;  /* 5.83:1 with white — destructive buttons */
  --cherry-500: #D2452E;  /* brand "Cherry" — fill only on light */
  --cherry-300: #F0A192;
  --cherry-100: #FDEEEB;
  --cherry-dk:  #3A1A14;  /* night chip fill */

  --grape-800: #553A70;   /* 8.58:1 on cream */
  --grape-700: #5A3F75;   /* 7.95:1 on cream */
  --grape-500: #6B4E8A;   /* brand "Grape" — the quarantine hue */
  --grape-300: #C4AEDB;
  --grape-100: #F2ECF8;
  --grape-dk:  #2A2038;   /* night chip fill */

  --amber-dk: #3A2B12;    /* night chip fill */
}

/* ---------------------------------------------------------------------------
   2. TYPE
      Latin: Manrope 400/500/600/700/800   (brand page, Google Fonts)
      Mono/data: Fira Code 400/500          (brand page — codes, quantities)
      Arabic: Cairo 400/500/600/700/800     (08-identity Brand Manual §Type)
      Manrope has no Arabic coverage; Cairo is the manual's own RTL companion.
      Deviation from the manual's Tajawal-for-body noted in DESIGN-DECISIONS §3.

      Sizes are rem so that a phone with OS text size turned up actually scales.
      No clamp() anywhere: fluid type makes table columns jump between
      viewport widths, which is the opposite of what a data grid needs.
   ------------------------------------------------------------------------ */
:root {
  --font-latin: 'Manrope', system-ui, -apple-system, sans-serif;
  --font-arabic: 'Cairo', 'Noto Sans Arabic', system-ui, sans-serif;
  --font-mono: 'Fira Code', ui-monospace, 'SF Mono', Menlo, monospace;
  /* All three are self-hosted variable faces — see assets/ivg/fonts.css.
     The stacks above are what renders in the ~200 ms before they load. */

  /* Resolved per direction at the root element */
  --font-ui: var(--font-latin);

  /* Scale — 17px body on the phone, not 16. Read at arm's length, standing. */
  --fs-micro:  0.6875rem;  /* 11px — uppercase micro-labels with tracking only */
  --fs-2xs:    0.75rem;    /* 12px — badge text, table meta */
  --fs-xs:     0.8125rem;  /* 13px — captions, helper text */
  --fs-sm:     0.9375rem;  /* 15px — secondary body, dense table cells */
  --fs-md:     1.0625rem;  /* 17px — BODY DEFAULT */
  --fs-lg:     1.25rem;    /* 20px — card titles, list primary */
  --fs-xl:     1.5rem;     /* 24px — screen titles */
  --fs-2xl:    1.875rem;   /* 30px — section headings */
  --fs-3xl:    2.375rem;   /* 38px — page display */

  /* Data display — quantities are the thing people squint at */
  --fs-qty:    1.75rem;    /* 28px — quantity in a row */
  --fs-qty-lg: 2.75rem;    /* 44px — quantity being entered / keypad readout */
  --fs-addr:   1.375rem;   /* 22px — shelf address, read from a metre away */

  --fw-regular: 400;
  --fw-medium:  500;
  --fw-semi:    600;
  --fw-bold:    700;
  --fw-black:   800;

  --lh-tight:  1.15;
  --lh-snug:   1.35;
  --lh-body:   1.55;
  --lh-arabic: 1.85;   /* Brand Manual: "Arabic line-height ~1.85" */

  --tracking-caps: 0.09em;
  --tracking-tight: -0.015em;
}

/* Arabic root swaps the family and opens up the leading. */
:root:lang(ar), [lang="ar"], [dir="rtl"] {
  --font-ui: var(--font-arabic);
  --lh-body: var(--lh-arabic);
  --lh-snug: 1.5;
  --tracking-tight: 0em;   /* never negative-track Arabic */
}

/* ---------------------------------------------------------------------------
   3. SEMANTIC TOKENS — day theme (default)
      Components reference ONLY these.
   ------------------------------------------------------------------------ */
:root,
[data-theme="day"] {
  color-scheme: light;

  /* Surfaces, back to front */
  --surface-app:     var(--brand-cream);   /* the body */
  --surface-card:    var(--paper);
  --surface-sunken:  var(--sand-100);      /* wells, table zebra, keypad bed */
  --surface-raised:  var(--paper);         /* sheets, popovers */
  --surface-chrome:  var(--dk-850);        /* app bar, tab bar — the dark frame */
  --surface-chrome-2:var(--dk-800);
  --surface-inverse: var(--dk-850);

  /* Ink */
  --ink-1: var(--graphite-800);   /* 13.30:1 — primary */
  --ink-2: var(--graphite-600);   /*  7.12:1 — secondary */
  --ink-3: var(--graphite-500);   /*  5.22:1 — muted; the floor for any text */
  --ink-on-chrome:   var(--dk-ink-1);
  --ink-on-chrome-2: var(--dk-ink-2);
  --ink-on-chrome-3: var(--dk-ink-3);
  --ink-link:        var(--teal-800);   /* 9.17:1, ALWAYS underlined */
  --ink-link-hover:  var(--teal-600);

  /* Lines */
  --line-1: var(--sand-200);   /* the brand's card hairline */
  --line-2: var(--sand-300);   /* table rules, stronger dividers */
  --line-3: var(--sand-400);   /* input borders — must be visible in dim light */
  --line-chrome: var(--dk-line);

  /* Brand accents in an app context */
  --accent:          var(--teal-600);
  --accent-ink:      var(--paper);        /* 7.88:1 white on Secondary Teal */
  --accent-quiet:    var(--teal-100);
  --accent-quiet-ink:var(--teal-800);     /* 9.04:1 */
  --accent-strong:   var(--teal-900);

  /* Amber. FILL-ONLY on light — brand colour law. Text on amber is graphite. */
  --amber-fill:      var(--brand-amber);
  --amber-fill-ink:  var(--brand-graphite);  /* 6.55:1. NEVER white — 2.23:1 */
  --amber-quiet:     var(--amber-100);
  --amber-quiet-ink: var(--amber-900);       /* 7.55:1 */
  --amber-text-on-light: var(--amber-700);   /* 4.50:1 — only 15px+ semibold */

  /* Focus. teal-500 is 3.20:1 on cream — fails for TEXT, passes the 3:1
     WCAG 2.2 non-text contrast bar for an indicator. That is the whole
     distinction: a focus ring is not body copy. */
  --focus-ring:  var(--teal-500);
  --focus-halo:  rgba(11, 31, 31, 0.14);
  --focus-width: 3px;
  --focus-offset:2px;

  /* --- STATE TOKENS ---
     Every state ships as a triple: fill / quiet-fill / text-on-quiet,
     plus a glyph and a word in the component layer. Colour is never alone. */

  /* success = posted, in spec, done. Brand teal, not a new green. */
  --st-ok:        var(--teal-600);
  --st-ok-quiet:  var(--teal-100);
  --st-ok-ink:    var(--teal-800);      /* 9.04:1 on quiet */
  --st-ok-on-fill:var(--paper);

  /* warning = expiring, low cover, near a limit */
  --st-warn:        var(--brand-amber);
  --st-warn-quiet:  var(--amber-100);
  --st-warn-ink:    var(--amber-900);   /* 7.55:1 on quiet */
  --st-warn-on-fill:var(--brand-graphite);

  /* danger = expired, blocked, negative, failed */
  --st-bad:        var(--cherry-500);
  --st-bad-quiet:  var(--cherry-100);
  --st-bad-ink:    var(--cherry-800);   /* 7.53:1 on quiet */
  --st-bad-on-fill:var(--paper);        /* 4.53:1 — large/bold text only */
  --st-bad-solid:  var(--cherry-700);   /* 7.00:1 with white — use for buttons */

  /* quarantine = held, awaiting a certificate. Its own hue on purpose. */
  --st-hold:        var(--grape-500);
  --st-hold-quiet:  var(--grape-100);
  --st-hold-ink:    var(--grape-800);   /* 8.15:1 on quiet */
  --st-hold-on-fill:var(--paper);       /* 6.81:1 */
  --st-hold-solid:  var(--grape-700);

  /* neutral = dormant, draft, queued */
  --st-idle:        var(--graphite-500);
  --st-idle-quiet:  var(--stone-100);
  --st-idle-ink:    var(--graphite-600); /* 6.39:1 on quiet */
  --st-idle-on-fill:var(--paper);        /* 7.82:1 on graphite-600 */

  /* UNKNOWN = never counted. Its own tone, and here is why it is not `idle`.
     «ماتعدّش» (never counted) and «ماتحركش» (dormant) were the same pale grey
     chip with the same treatment, told apart by two letters mid-word and a
     12 px glyph. They are not the same kind of fact: a number nobody has ever
     verified is a stock-integrity risk, and a product that has not sold is a
     commercial question. So this one is a FILLED chip rather than a quiet one
     — same family, opposite weight — and it carries a solid bar on a row where
     dormant carries a dotted one. No new hue is invented: grey is still grey,
     and grey is still not a warning. */
  --st-unknown:        var(--graphite-600);
  --st-unknown-quiet:  var(--graphite-600); /* filled, not tinted */
  --st-unknown-ink:    var(--paper);        /* 7.12:1 on graphite-600 */
  --st-unknown-on-fill:var(--paper);

  /* Elevation. Brand: "soft shadows + crisp 1px dividers, not gradients." */
  --elev-0: none;
  --elev-1: 0 1px 2px rgba(11,31,31,.05), 0 2px 8px rgba(11,31,31,.04);
  --elev-2: 0 2px 6px rgba(11,31,31,.07), 0 10px 24px rgba(11,31,31,.07);
  --elev-3: 0 4px 12px rgba(11,31,31,.10), 0 22px 48px rgba(11,31,31,.12);
  --elev-sheet: 0 -6px 28px rgba(11,31,31,.16);

  /* Chart ink — see DESIGN-DECISIONS §6. Ordered for distinguishability
     in monochrome as well as colour, because these get printed. */
  --chart-1: var(--teal-600);
  --chart-2: var(--brand-amber);
  --chart-3: var(--grape-500);
  --chart-4: var(--teal-400);
  --chart-5: var(--cherry-500);
  --chart-6: var(--graphite-600);
  --chart-grid: var(--sand-300);
  --chart-axis: var(--graphite-500);
  --chart-plot: var(--paper);
}

/* ---------------------------------------------------------------------------
   3b. NIGHT THEME
      The brand already owns a dark frame (#0B1F1F header/hero/footer).
      Night theme promotes that frame to the whole surface. It is not a
      generic inverted dark mode; it is the brand's own dark, extended.
   ------------------------------------------------------------------------ */
[data-theme="night"] {
  color-scheme: dark;

  --surface-app:      var(--dk-850);
  --surface-card:     var(--dk-800);
  --surface-sunken:   var(--dk-900);
  --surface-raised:   var(--dk-700);
  --surface-chrome:   var(--dk-900);
  --surface-chrome-2: var(--dk-800);
  --surface-inverse:  var(--brand-cream);

  --ink-1: var(--dk-ink-1);    /* 17.07:1 */
  --ink-2: var(--dk-ink-2);    /* 11.42:1 */
  --ink-3: var(--dk-ink-3);    /*  7.76:1 */
  --ink-on-chrome:   var(--dk-ink-1);
  --ink-on-chrome-2: var(--dk-ink-2);
  --ink-on-chrome-3: var(--dk-ink-3);
  --ink-link:        var(--teal-300);
  --ink-link-hover:  var(--teal-200);

  --line-1: var(--dk-line);
  --line-2: var(--dk-line-2);
  --line-3: #3E5B58;
  --line-chrome: var(--dk-line);

  --accent:           var(--teal-500);
  --accent-ink:       var(--dk-850);
  --accent-quiet:     var(--dk-600);
  --accent-quiet-ink: var(--teal-300);
  --accent-strong:    var(--teal-400);

  /* On dark, amber-as-TEXT is permitted by the brand colour law. */
  --amber-fill:      var(--brand-amber);
  --amber-fill-ink:  var(--brand-graphite);
  --amber-quiet:     var(--amber-dk);
  --amber-quiet-ink: var(--amber-400);       /* 8.19:1 */
  --amber-text-on-light: var(--amber-400);

  --focus-ring: var(--teal-500);            /* 4.85:1 on Deep Teal */
  --focus-halo: rgba(22,153,140,.22);

  --st-ok:        var(--teal-500);
  --st-ok-quiet:  var(--dk-600);
  --st-ok-ink:    var(--teal-300);           /* 7.52:1 */
  --st-ok-on-fill:var(--dk-850);

  --st-warn:        var(--brand-amber);
  --st-warn-quiet:  var(--amber-dk);
  --st-warn-ink:    var(--amber-400);        /* 8.19:1 */
  --st-warn-on-fill:var(--brand-graphite);

  --st-bad:        var(--cherry-500);
  --st-bad-quiet:  var(--cherry-dk);
  --st-bad-ink:    var(--cherry-300);        /* 7.64:1 */
  --st-bad-on-fill:var(--paper);
  /* Was --cherry-500, which is 4.53:1 with white — a pass by 0.03 on the one
     button in the application that cannot be taken back. */
  --st-bad-solid:  var(--cherry-600);        /* 5.83:1 with white */

  --st-hold:        var(--grape-300);
  --st-hold-quiet:  var(--grape-dk);
  --st-hold-ink:    var(--grape-300);        /* 7.65:1 */
  --st-hold-on-fill:var(--dk-850);
  --st-hold-solid:  var(--grape-500);

  --st-idle:        var(--dk-ink-3);
  --st-idle-quiet:  var(--dk-700);
  --st-idle-ink:    var(--dk-ink-2);         /* 8.28:1 */
  --st-idle-on-fill:var(--dk-850);

  /* Filled here too, and the fill is the light one: on a dark surface the
     chip that has to stand out is the pale one. Same relationship to `idle`
     as in day — opposite weight, same family. */
  --st-unknown:        var(--dk-ink-2);
  --st-unknown-quiet:  var(--dk-ink-2);      /* filled, not tinted */
  --st-unknown-ink:    var(--dk-900);        /* 11.86:1 on dk-ink-2 */
  --st-unknown-on-fill:var(--dk-900);

  /* Shadows do not read on a dark surface. Borders carry the elevation. */
  --elev-0: none;
  --elev-1: 0 0 0 1px var(--dk-line);
  --elev-2: 0 0 0 1px var(--dk-line-2), 0 12px 28px rgba(0,0,0,.45);
  --elev-3: 0 0 0 1px var(--dk-line-2), 0 24px 56px rgba(0,0,0,.6);
  --elev-sheet: 0 0 0 1px var(--dk-line-2), 0 -10px 34px rgba(0,0,0,.5);

  --chart-1: var(--teal-300);
  --chart-2: var(--amber-400);
  --chart-3: var(--grape-300);
  --chart-4: var(--teal-500);
  --chart-5: var(--cherry-300);
  --chart-6: var(--dk-ink-3);
  --chart-grid: var(--dk-line);
  --chart-axis: var(--dk-ink-3);
  --chart-plot: var(--dk-800);
}

/* The shared phone gets handed between people; follow the device unless a
   user has chosen. app.js sets data-theme on <html> when they do. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="day"]) {
    color-scheme: dark;
    --surface-app: var(--dk-850);
  }
}

/* ---------------------------------------------------------------------------
   4. SPACE, SIZE, SHAPE
   ------------------------------------------------------------------------ */
:root {
  --sp-1: 0.25rem;   /*  4px */
  --sp-2: 0.5rem;    /*  8px */
  --sp-3: 0.75rem;   /* 12px */
  --sp-4: 1rem;      /* 16px */
  --sp-5: 1.25rem;   /* 20px */
  --sp-6: 1.5rem;    /* 24px */
  --sp-7: 2rem;      /* 32px */
  --sp-8: 2.5rem;    /* 40px */
  --sp-9: 3rem;      /* 48px */
  --sp-10: 4rem;     /* 64px */

  /* Touch. In rem on purpose: when the user turns OS text size up, the
     target grows with the label instead of clipping it. */
  --tap:      3rem;    /* 48px — the floor, everywhere */
  --tap-lg:   3.5rem;  /* 56px — list rows in a task flow */
  --tap-xl:   4rem;    /* 64px — the one primary action per screen */
  --tap-gap:  0.5rem;  /* minimum gap between two adjacent targets */

  /* Radii. Brand marketing uses 16–20px cards; app uses 14 so more rows fit
     on a 360px screen without the corners eating the content. */
  --r-xs:   6px;    /* badges, chips */
  --r-sm:   10px;   /* inputs, keypad keys, segmented controls */
  --r-md:   14px;   /* cards, list groups */
  --r-lg:   20px;   /* sheets, modals */
  --r-pill: 999px;  /* the primary action + filter chips only */

  --border-hair: 1px;
  --border-input: 1.5px;   /* 1px inputs disappear in a dim aisle */
  --border-state: 4px;     /* the inline-start state marker on a row */

  /* Layout */
  --w-content: 1120px;     /* brand's content max-width */
  --w-wide: 1440px;
  --w-prose: 68ch;
  --appbar-h: 3.5rem;
  --tabbar-h: 4rem;
  --actionbar-h: 5rem;

  /* Motion. Warehouse app: short, or none. Nothing decorative animates. */
  --dur-fast: 90ms;
  --dur-base: 160ms;
  --dur-sheet: 220ms;
  --ease: cubic-bezier(.2,.7,.3,1);

  /* Z */
  --z-sticky: 10;
  --z-appbar: 40;
  --z-actionbar: 45;
  --z-sheet: 60;
  --z-modal: 70;
  --z-toast: 80;
  --z-conn: 90;   /* the offline strip sits above everything */
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 0ms; --dur-base: 0ms; --dur-sheet: 0ms; }
}

/* ---------------------------------------------------------------------------
   4b. THREE VIEWS, AND WHY THIS FILE HAS ONLY ONE OF THEM
   ---------------------------------------------------------------------------

   THE OWNER'S SENTENCE: "touchscreen laptop ← one view · normal browser on a
   computer ← another view · phone browser ← another view. Either to be selected
   automatically or user enforced but not fixed."

   Everything above this line is the FIRST of those three and it is the base:
   a rugged Android held at arm's length, in a dim aisle, one-handed, sometimes
   with a glove on. 48/56/64 targets, 17 px body. It is unconditional, it is the
   default in every sense — the view a device gets when nothing matches and the
   view a browser gets when it cannot parse a condition — and NOTHING in this
   release moves it. tools/overflow/phone-unchanged.mjs proves that at zero
   tolerance, box by box, against origin/main.

   The other two live in files of their own:

     public/assets/ivg/view-touch.css   «لابتوب باللمس»  44/48/56, 16 px body
     public/assets/ivg/view-desk.css    «كمبيوتر بالماوس» 32/40/44, 15 px body

   Each states its own numbers ONCE, and each carries the argument for them at
   the top of the file. There is no third place where a density number is
   written, and there is no `@media` in THIS file that changes one.

   WIDTH DECIDES LAYOUT. THE POINTER DECIDES WHICH FAMILY OF DENSITY. AND AMONG
   COARSE POINTERS, THE WIDTH DECIDES WHICH ONE.
   The seven `min-width: 900px` blocks in components.css do the layout half —
   the sidebar appears, the card list becomes a real table, the sheet becomes a
   centred dialog — because a sidebar genuinely needs room and room is a width
   question. Density is the other half, and it is a question about the POINTER,
   because ROOM IS NOT ACCURACY. A mouse is accurate; a finger is not, however
   large the screen it is on. The one place width re-enters is in telling two
   COARSE devices apart: a phone in a hand and a tablet on a table are both
   touched, and the only signal CSS has for the difference is how wide the glass
   is. view-touch.css names that seam, names the device it can get wrong, and
   names what the mistake costs.

   HOW A VIEW IS SWITCHED ON — AND THIS IS THE PART THAT IS NOT CSS.
   A media query cannot be overridden by a preference: that is what a media
   query IS. And a preference applied by JavaScript paints the wrong size first
   and corrects it, which on a task screen means the layout shifts under a thumb
   that has already started moving. So neither does the switching. The SERVER
   does, in the first byte of the response, by choosing what to put in the
   `media` attribute of two `<link>` elements:

     nobody has chosen — the automatic case, and the default:
       <link href="view-touch.css" media="screen and (pointer: coarse) and (min-width: 1024px)">
       <link href="view-desk.css"  media="screen and (((pointer: fine) and (hover: hover)) or (pointer: none))">
       ...and the CSS does the detecting, with no script, on the first ever
       request, with JavaScript switched off, and with nothing to flash.

     this person chose «لابتوب باللمس»:
       <link href="view-touch.css" media="screen">
       ...and no condition is consulted at all, because the person has already
       answered the question the condition exists to guess at.

     this person chose «موبايل»:
       neither link is written. The base above is the view.

   THE FORCED CHOICE ALWAYS WINS, at any width, on any pointer, and it is not a
   specificity race: the two are mutually exclusive by construction, because the
   condition is either on the link or it is not. App\Support\Ui\Screen owns both
   condition strings and is the only place in the application they are written.

   `screen` stays in the media attribute in BOTH cases and is not decoration.
   Without it a count sheet printed from a desk and the same sheet printed from
   a phone would come out at different type sizes, because the print tokens in
   §5 override colour and never touched the scale. One document, one rendering.

   WHY THE FILES ARE SEPARATE AND NOT THREE BLOCKS IN THIS ONE. A block in this
   file can only be gated by an `@media` rule, and an `@media` rule cannot be
   turned OFF by a preference — so a forced view would need every one of its
   forty declarations written a second time under an attribute selector, in two
   places that must never drift. The `media` attribute on a `<link>` is the
   mechanism CSS already has for exactly this: one copy of the numbers, and the
   condition supplied from outside by whoever knows whether there is a
   preference. Tests\Feature\Ui\ViewChoiceTest asserts that the strings the
   server writes are the strings these files document.
   ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
   5. PRINT TOKENS
      Thermal is 1-bit black. Sheets are mono laser. No colour survives
      either path, so print overrides the whole semantic layer to ink/paper.
   ------------------------------------------------------------------------ */
@media print {
  :root, [data-theme="day"], [data-theme="night"] {
    --surface-app: #FFF; --surface-card: #FFF; --surface-sunken: #FFF;
    --surface-raised: #FFF; --surface-chrome: #FFF; --surface-chrome-2: #FFF;
    --ink-1: #000; --ink-2: #000; --ink-3: #333;
    --ink-on-chrome: #000; --ink-on-chrome-2: #000; --ink-on-chrome-3: #333;
    --ink-link: #000;
    --line-1: #000; --line-2: #000; --line-3: #000;
    --elev-0: none; --elev-1: none; --elev-2: none; --elev-3: none;
    --st-ok: #000; --st-warn: #000; --st-bad: #000; --st-hold: #000;
    --st-idle: #666;
    --st-ok-quiet: #FFF; --st-warn-quiet: #FFF; --st-bad-quiet: #FFF;
    --st-hold-quiet: #FFF; --st-idle-quiet: #FFF;
    --st-ok-ink: #000; --st-warn-ink: #000; --st-bad-ink: #000;
    --st-hold-ink: #000; --st-idle-ink: #000;
    /* UNKNOWN WAS MISSING FROM THIS BLOCK ENTIRELY, and it was the one tone
       that did not survive the print path. Every other state flattens to ink on
       paper; `--st-unknown-quiet` is deliberately the SAME value as
       `--st-unknown` on screen (filled, not tinted — see §3), so on a mono laser
       a never-counted badge printed as a mid-grey box with white text and a
       never-counted bin on the shelf map printed as a solid grey square with
       nothing legible in it. It flattens like the others now: white ground,
       black ink, and the glyph and the word carry the state.

       Found by the shelf map, which is simply the first screen to print a
       never-counted cell; the badge has had this defect since the tokens
       landed. */
    --st-unknown: #000; --st-unknown-quiet: #FFF;
    --st-unknown-ink: #000; --st-unknown-on-fill: #000;
    --chart-1:#000; --chart-2:#666; --chart-3:#999; --chart-4:#444;
    --chart-5:#222; --chart-6:#888; --chart-grid:#BBB; --chart-axis:#000;
    --chart-plot:#FFF;
    /* Thermal geometry: 203 dpi = 7.992 dots/mm. 50×30mm = ~400×240 dots. */
    --dot: 0.125mm;          /* 1 printer dot */
    --qr-min: 16mm;          /* v3 QR at 4 dots/module + quiet zone */
    --bar-x: 0.375mm;        /* Code-128 X-dimension = 3 dots */
    --bar-quiet: 3.75mm;     /* 10X quiet zone */
    --hair: 0.5pt;
  }
}
