/* ==========================================================================
   IN-V-LOCK — the ONE token sheet + the enterprise layer.   (KALLEN-16, 2026-10-07)
   TIER: P5 SOFT / ENTERPRISE  (p5-ui §0; Pinko 2026-10-05: "softly apply p5 doctrine
   and ui guidance but make it bespoke to our design concepts").
   Design doc: docs/design/enterprise-p5-2026-10-07.md

   HOW IT IS WIRED: every HTML page links this file LAST in <head>, so at equal
   specificity it wins over the page's own <style>. The shared chrome that injects its
   own CSS at run time (desknav.js, bottombar.js, home.js, feedback.js) reads these
   tokens through var(--ivl-*, fallback). Change a colour HERE, nowhere else.

   THE FIVE RULES this sheet enforces
   1. Red has exactly TWO jobs (Pinko 10-07 "red main button"):
      a. the PRIMARY action - one solid brand-red plate, white label, no icon, no edge;
      b. ALERT / INFO - and alert never looks like (a): a destructive button is an
         OUTLINE (dark fill, red edge, warning glyph); an alert panel or banner carries
         the red HAZARD EDGE; the NEW MAKER flag carries the glyph + hazard edge.
      Never a heading, a wordmark, a border for looks. tools/kallen16_ui_capture.py
      audits every rendered red pixel-owner against those roles.
   2. One primary action per screen = the BRAND RED plate. Selection (tabs, chips, the
      IN|OUT switch) and the nav-bar scan plate = the CHALK plate. Focus = GOLD ring.
   3. Hard edges: 3px radius, no blur shadows.
   4. Type discipline: page title = the house display (900 italic caps); everything
      below it upright. Body 16px on a phone.
   5. Calm, decisive motion: 0ms selection, <=200ms ease-out, nothing loops on a
      work screen, all of it off under prefers-reduced-motion.
   ========================================================================== */
/* KALLEN 2026-10-11 (couchwave-simplify): the roles below are now the ONLY colours the pages
   use - tools/kallen_cw_tokenize.py rewrote ~2,700 hard-coded page colours (660 distinct hex)
   onto them. Two themes, one set of names (Couchwave's lesson: a theme is DATA, the page only
   reads tokens): :root = DARK (the shipped look, the default); [data-theme=light] = LIGHT, a
   soft Frost-spirit white. /theme.js picks one before first paint. Gates:
   tools/kallen16_contrast_gate.js (token pairs, BOTH themes) and
   tools/kallen_cw_render_gate.py (rendered text vs the colour behind it, BOTH themes). */
:root{
  color-scheme:dark;
  /* surfaces */
  /* WII 2026-10-21: the spec's NIGHT VARIANT (§1) - the Wii menu has no dark mode, so a dark phone
     keeps the whole motion + shape layer on these surfaces. was #0B0B0D / #15161A / #1E2026 / #2A2D35 */
  --ivl-bg:#14151B;
  --ivl-surface:#1E2029;
  --ivl-surface-2:#252833;
  --ivl-surface-3:#2E3240;     /* raised: chips, hover, a field on a card */
  --ivl-edge:#2E3038;          /* dividers - decorative, no contrast duty */
  --ivl-edge-strong:#6B6F7A;   /* control boundaries - 3:1 (WCAG 1.4.11) */
  /* text */
  --ivl-text:#ECEEF2;
  --ivl-text-2:#B4BAC4;
  --ivl-text-3:#9AA1AD;        /* the quietest words that still pass 4.5:1 on a raised field */
  /* PRIMARY ACTION = brand red (Pinko GEASS 2026-10-07 14:38, review Choice 1: "red main button") */
  --ivl-primary:#E60012;
  --ivl-primary-hover:#C4000F;   /* hover goes DARKER: white on #FF1A2B is 3.86:1 and fails AA */
  --ivl-on-primary:#FFFFFF;
  /* selection + nav plate stay neutral - the P5 white plate */
  --ivl-select:#ECEEF2;
  --ivl-on-select:#14151B;
  --ivl-focus:#34BEED;         /* WII 10-21: the soft-blue focus halo (--wii-blue) replaces P5 gold. Blue = focus ONLY */
  --ivl-focus-halo:rgba(52,190,237,.30);
  --ivl-gold:#ECEEF2;          /* WII repair 10-21: was P5 gold #FFCC00. The colour law allows ONE accent (blue = focus),
                                 so words the pages write in --gold are plain strong text (--wii-grey-700 role) */
  --ivl-wash:rgba(52,190,237,.12);   /* --wii-blue-wash: a row under the pointer / finger */
  /* status families: fill + on-fill, -text (the word IS the status), -ink (body words inside a
     tinted panel), -panel (tinted card), -edge (its border). Colour is never alone. */
  --ivl-alert:#E60012;         /* P5 red. Fills + edges only. */
  --ivl-on-alert:#FFFFFF;
  --ivl-alert-text:#FF5A64;    /* red as TEXT on dark (plain #E60012 is 4.09:1 - fails AA) */
  --ivl-alert-ink:#FFD6D9;
  --ivl-alert-panel:#2A0709;
  --ivl-alert-edge:#E60012;
  --ivl-on-alert-panel:var(--ivl-alert-ink);
  /* ALERT must not read as PRIMARY: destructive button = outline on the panel colour */
  --ivl-danger-fill:#2A0709;
  --ivl-danger-fill-hover:#3A0A0E;
  --ivl-on-danger:#FFD6D9;
  --ivl-danger-edge:#E60012;
  --ivl-hazard:repeating-linear-gradient(-45deg,#E60012 0 5px,#0B0B0D 5px 10px);
  --ivl-hazard-w:6px;
  --ivl-ok:#1F7A47;
  --ivl-on-ok:#FFFFFF;
  --ivl-ok-text:#4FD18B;
  --ivl-ok-ink:#C6F5D6;
  --ivl-ok-panel:#0F2A1A;
  --ivl-ok-edge:#2F8A4C;
  --ivl-warn:#F2A93B;
  --ivl-on-warn:#0B0B0D;
  --ivl-warn-text:#F2B85B;
  --ivl-warn-ink:#FFE3A8;
  --ivl-warn-panel:#2A2008;
  --ivl-warn-edge:#B8860B;
  --ivl-info:#2563C9;
  --ivl-on-info:#FFFFFF;
  --ivl-info-text:#8FB8FF;     /* "typed by a person" - the existing blue role */
  --ivl-info-ink:#CFE0FF;
  --ivl-info-panel:#10203A;
  --ivl-info-edge:#4F8DF0;
  /* type */
  /* WII 10-21: M PLUS 1p for labels + body, M PLUS Rounded 1c for titles + numbers (free, OFL, in the
     spirit of the Wii's rounded type - no Nintendo fonts). Self-hosted latin subsets in /fonts/. */
  --ivl-font:"M PLUS 1p","Segoe UI",system-ui,-apple-system,Roboto,sans-serif;
  --ivl-font-display:"M PLUS Rounded 1c","M PLUS 1p","Segoe UI",system-ui,sans-serif;
  --ivl-mono:ui-monospace,"Cascadia Mono",Consolas,monospace;
  --ivl-fs-xs:12px; --ivl-fs-sm:14px; --ivl-fs-md:16px; --ivl-fs-lg:18px; --ivl-fs-xl:22px; --ivl-fs-2xl:28px;
  /* space (4px grid) */
  --ivl-s1:4px; --ivl-s2:8px; --ivl-s3:12px; --ivl-s4:16px; --ivl-s5:24px; --ivl-s6:32px;
  /* edges */
  /* WII 10-21: no sharp corners anywhere (was 3px hard edges). Rows + fields 12, tiles + cards 16,
     dialogs + sheets 22, buttons + chips full pill. */
  --ivl-r:12px; --ivl-r-tile:16px; --ivl-r-dialog:22px; --ivl-r-pill:999px;
  /* soft, never black-heavy shadows (night variant: a rim highlight + a dark drop).
     SPEC EXCEPTION (WII repair 10-21, recorded): spec section 2 says shadow hue is slate and never rgba(0,0,0) above .12.
     That table is for the LIGHT stage. On the night stage (#14151B) a .12 drop is invisible, so the night drops
     run .22-.55 - but in slate-black rgba(6,8,14), never pure black. */
  --ivl-sh-rest:inset 0 1px 0 rgba(255,255,255,.06),0 1px 2px rgba(6,8,14,.30),0 3px 10px rgba(6,8,14,.22);
  --ivl-sh-hover:inset 0 1px 0 rgba(255,255,255,.08),0 10px 24px rgba(6,8,14,.40),0 0 0 2px var(--ivl-focus),0 0 0 6px var(--ivl-focus-halo);
  --ivl-sh-press:inset 0 1px 3px rgba(6,8,14,.40);
  --ivl-sh-dialog:0 24px 60px rgba(6,8,14,.55),0 0 0 1px rgba(255,255,255,.10);
  --ivl-scrim:rgba(10,11,15,.55);
  --ivl-rim:rgba(255,255,255,.12);   /* a tile's 1px outer rim (decorative; the shadow carries the edge) */
  --ivl-stripe:rgba(255,255,255,.018);
  /* MOTION - THE ONE DIAL. Every duration, delay, distance and curve the app moves with is here.
     v3 WII ENTERPRISE (2026-10-21). Pinko via GEASS 17:08, verbatim: "fix up invlock ... so it's super
     clean and bouncy like wii menu". Spec: WII-FEEL SPEC v1 §3.3, the ENTERPRISE tier - same vocabulary
     as the Wii menu, quieter: ONE soft swell (<=2% of the move, exactly one turn) and settle, never a
     wobble; pops <= 220ms, panels/pages <= 280ms, scan confirmation instant, input never waits, no idle
     breathing. The 10-11 "no overshoot wobble" ruling is read as banning WOBBLE (several swings / a big
     overshoot), not one small swell; tools/kallen_cw_motion_gate.js M5 now measures peak + turns and a
     wobbly or FULL-tier (5%) curve still fails (known-bad arms).
     was v2 (10-11): Couchwave pace, no overshoot, pops 300ms, panels 360ms. */
  --motion-dur-press:60ms;     /* a finger going down: the control dips (instant-feeling) */
  --motion-dur-release:180ms;  /* letting go: the soft spring back */
  --motion-dur-hover:160ms;    /* pointer arrives on a tile / button: the soft pop */
  --motion-dur-select:160ms;   /* a selection plate / the bottom-bar indicator gliding */
  --motion-dur-fade:180ms;     /* a scrim, an alert, a quiet arrival; also hover-out (no bounce on the way out) */
  --motion-dur-tick:120ms;     /* the ONE motion a scan confirmation may carry: a one-shot tick, words already painted */
  --motion-dur-toast:220ms;
  --motion-dur-row:220ms;      /* one row / tile of an arrival cascade */
  --motion-dur-pop:220ms;      /* a pop-up / menu / card / the location pop and the search pop */
  --motion-dur-exit:140ms;     /* a pop-up leaving: quicker and calmer than arriving, never bouncy */
  --motion-dur-panel:280ms;    /* a sheet or drawer sliding in, a panel switching */
  --motion-dur-page:280ms;     /* one page sliding into the next (Home / Ammo / Scan / Map / Tasks) */
  --motion-stagger-step:18ms;  /* rows / tiles arrive 18ms apart... */
  --motion-stagger-max:126ms;  /* ...and items past the 8th share the 8th's delay (7 x 18) */
  /* the only loops allowed: status cues that mean something (period ceiling 1600ms, off under reduced motion) */
  --motion-loop-cue:1100ms;    /* low light: tap the torch */
  --motion-loop-wait:1200ms;   /* POS waiting dots */
  --motion-loop-ping:1600ms;   /* map: you are here */
  --motion-ease-out:cubic-bezier(.22,1,.36,1);    /* --wii-ease-out: hover-out, fades, rows that only wash. 0 overshoot */
  --motion-ease-pop:cubic-bezier(.25,1.25,.4,1);  /* --wii-ease-soft: the ENTERPRISE pop. 2.0% swell, 1 turn */
  --motion-ease-slide:cubic-bezier(.33,1.2,.55,1);/* --wii-ease-slide: pages, sheets, panels. 1.25% swell, 1 turn */
  --motion-ease-in:cubic-bezier(.4,0,1,1);        /* --wii-ease-in: exits only */
  --motion-ease-std:cubic-bezier(.4,0,.2,1);      /* both ends soft: the scrim */
  --motion-pop-scale:.94;      /* a pop-up / dialog starts at 94% */
  --motion-zoom-scale:.94;     /* the location card pops in from 94%... */
  --motion-zoom-from:.45;      /* ...at 45% opacity: the bay name is legible from the first frame */
  --motion-press-scale:.97;    /* a pressed tile / button dips to 97% */
  --motion-hover-scale:1.02;   /* a tile / button under the pointer settles at 102%... */
  /* WII repair 10-21: THE SWELL IS IN THE KEYFRAMES, not in the curve. A curve's overshoot is a % of the
     move, and on a .03-.06 move 2% of it is sub-pixel (critic: location pop peaked 1.0012, hover 1.0204 vs
     1.02 - nobody could see a bounce). Each one-turn swell below is an ABSOLUTE rendered scale, ceiling 1.026
     (ENTERPRISE, read as rendered scale). Gate: tools/wii_swell_gate.py samples the RENDERED rect. */
  --motion-hover-peak:1.026;   /* ...after swelling once to 102.6% (1 -> 1.026 at 55% -> 1.02, 160ms) */
  --motion-pop-peak:1.012;     /* a pop-up / the location card: .94 -> 1.012 -> 1 over 220ms */
  --motion-release-peak:1.012; /* a finger letting go (the phone's bounce): .97 -> 1.012 -> 1 over 180ms */
  --motion-arrive-peak:1.008;  /* a tile arriving in a cascade: .96 -> 1.008 -> 1 */
  --motion-peak-at:55%;        /* (documentation: every swell peaks at 55% of its run) */
  --motion-ease-settle:cubic-bezier(.45,0,.55,1); /* the way down from a swell: soft both ends, 0 overshoot */
  --motion-arrive-scale:.96;   /* a tile arriving in a cascade starts at 96% */
  --motion-lift-scale:1.02;    /* (legacy name) = hover scale */
  --motion-rise:12px;          /* how far a sheet / a tile rises in */
  --motion-slide:96px;         /* how far a page / panel slides sideways when you change tabs */
  --motion-exit-drop:16px;     /* how far a closing sheet drops away */
  /* legacy names (10-07), now read from the dial */
  --ivl-dur-select:var(--motion-dur-select); --ivl-dur-fast:var(--motion-dur-press); --ivl-dur-base:var(--motion-dur-fade); --ivl-dur-max:var(--motion-dur-pop);
  --ivl-ease-out:var(--motion-ease-out);
  /* density: comfortable on touch (44), compact under a mouse (36) */
  --ivl-hit:44px;

  /* MAP + RACK DRAWINGS (KALLEN 2026-10-11, P6). The plan, the rack plan, the mini map and the 3D
     walk paint through these. Dark values are the drawings' own colours, except where the 10-11 gate
     found a line or label under its WCAG floor on the dark plan (marked *). Geometry never reads a
     token: tools/kallen_cw_map_gate.py proves every shape is where it was, pixel for pixel. */
  --ivl-map-floor:#141a22;      --ivl-map-wall:#7d8aa0;       --ivl-map-room:#1c2531;
  --ivl-map-room-edge:#66748e;  /* * was #46536a, 1.99:1 */  --ivl-map-room-label:#8592a8;  /* * was #5f6f88, 3.03:1 */
  --ivl-map-notch:#4a5568;      --ivl-map-hatch:#4a6fa5;      --ivl-map-amber:#c9a227;
  --ivl-map-dash:#6b7b95;       --ivl-map-demise-fill:#b06a2c; --ivl-map-demise:#e08b3a;
  --ivl-map-door:#2fa8d6;       --ivl-map-run:#5b6b85;  /* * was #33415a, 1.70:1 */  --ivl-map-run-na:#a8844a;  /* * was #8a6a3a, 3.50:1 */
  --ivl-map-mark:#ffffff;       --ivl-map-chip:#ffffff;       --ivl-map-chip-edge:#ffffff;
  --ivl-map-stg:#d6a02f;        --ivl-map-compass:#9ab0cc;
  --ivl-map-bound:#243447;      --ivl-map-sel:#1f5f8f;        --ivl-map-mine:#2a6f2d;  /* * was #2f7d32, label 4.39:1 */
  --ivl-map-bound-edge:#6b86a8; --ivl-map-unbound-edge:#6a7488;  /* * was #5a6478, 2.94:1 */
  --ivl-map-mine-edge:#7fd67f;  --ivl-map-sel-edge:#69b7ff;
  --ivl-map-bay-text:#e8eef7;   --ivl-map-unbound-text:#8b96a8;
  --ivl-map-hit-fill:#5a3d00;   --ivl-map-hit:#ffd23f;        --ivl-map-label:#ffffff;  --ivl-map-halo:#0b0b0d;
  --ivl-map-mini-floor:#121418; --ivl-map-mini-wall:#666d7c;  /* * was #5b6170, 2.98:1 */  --ivl-map-mini-room:#191c22; --ivl-map-mini-room-edge:#30343d;
  --ivl-map-mini-bay:#1f2a36;   --ivl-map-mini-bay-edge:#3c4a5a;
  --ivl-map-sky-top:#0d1219;    --ivl-map-sky-bottom:#161d27; --ivl-map-floor3d:#10151d;
  --ivl-map-3d-wall:#7d8aa0;    --ivl-map-3d-room:#46536a;    --ivl-map-3d-overhead:#39445a; --ivl-map-3d-demise:#e08b3a;
  --ivl-map-3d-door:#2fa8d6;    --ivl-map-3d-zone:#c9a227;    --ivl-map-3d-clear:#4a6fa5;    --ivl-map-3d-fixture:#8fa3c0;
  --ivl-map-3d-equip:#9a7bd0;   --ivl-map-3d-other:#6b7b95;   --ivl-map-3d-label:#10151c;

  /* LEGACY ALIASES - every page's own --red/--gold now resolve to the roles above */
  --red:var(--ivl-alert);
  --gold:var(--ivl-gold);   /* WII 10-21: was var(--ivl-focus). Pages use --gold as TEXT (links, tags); focus went
                              soft-blue, a ring colour that is 3:1, not 4.5:1 - so the words keep their old gold */
}
/* LIGHT - SOFT tier in the Frost spirit (Couchwave 17abd55): bright cool white, silver edges,
   the SELECTION plate is a slate pane with white words. Red keeps both jobs (primary + alert)
   and nothing else. Every pair is gated (kallen16_contrast_gate.js --theme light). */
:root[data-theme=light]{
  color-scheme:light;
  /* WII 10-21 (spec §1): airy white tiles on a pale-grey stage, slate text, soft-blue focus only.
     was #F3F5F8 / #FFFFFF / #EEF1F5 / #E3E8EE, text #1E232A / #4C5562 / #5A6370 */
  --ivl-bg:#F3F4F6;            /* --wii-stage */
  --ivl-surface:#FFFFFF;       /* --wii-white */
  --ivl-surface-2:#FFFFFF;     /* cards are white tiles on the stage (rim + soft shadow carry the edge) */
  --ivl-surface-3:#EEF1F4;     /* --wii-grey-100: chips, pressed fill, a field on a card */
  --ivl-edge:#DFE3E8;          /* --wii-grey-150 */
  --ivl-edge-strong:#7A8390;   /* control boundaries keep 3:1 (WCAG 1.4.11) */
  --ivl-text:#262B33;          /* --wii-grey-900 */
  --ivl-text-2:#4F5763;        /* --wii-grey-600 */
  --ivl-text-3:#5D6571;        /* --wii-grey-450: the quietest words, >=4.5:1 on the stage */
  --ivl-primary:#E60012;
  --ivl-primary-hover:#C4000F;
  --ivl-on-primary:#FFFFFF;
  --ivl-select:#3C424B;        /* --wii-grey-700: the selected pill. Calm slate, not a second accent */
  --ivl-on-select:#FFFFFF;
  --ivl-focus:#1A86BA;         /* the focus RING stroke: --wii-blue-ring darkened until it clears 3:1 on the stage too */
  --ivl-focus-halo:rgba(52,190,237,.28);   /* --wii-blue halo around it (no text duty) */
  --ivl-gold:#3C424B;                      /* WII repair 10-21: --wii-grey-700 (was #855800 P5 gold) - strong labels, not an accent */
  --ivl-wash:rgba(52,190,237,.12);         /* --wii-blue-wash */
  --ivl-sh-rest:inset 0 1px 0 rgba(255,255,255,.9),0 1px 2px rgba(70,80,95,.10),0 3px 8px rgba(90,100,115,.12);
  --ivl-sh-hover:inset 0 1px 0 rgba(255,255,255,.95),0 10px 24px rgba(70,80,95,.20),0 0 0 2px var(--ivl-focus),0 0 0 6px var(--ivl-focus-halo);
  --ivl-sh-press:inset 0 1px 2px rgba(70,80,95,.18),0 1px 2px rgba(70,80,95,.14);
  --ivl-sh-dialog:0 24px 60px rgba(60,70,85,.28),0 0 0 1px rgba(120,130,145,.18);
  --ivl-scrim:rgba(236,239,243,.62);
  --ivl-rim:#C9CFD7;                 /* --wii-grey-200 tile rim */
  --ivl-stripe:rgba(120,130,145,.05);
  --ivl-alert:#E60012;
  --ivl-on-alert:#FFFFFF;
  --ivl-alert-text:#B0000E;
  --ivl-alert-ink:#7A0A12;
  --ivl-alert-panel:#FDECEE;
  --ivl-alert-edge:#D0101E;
  --ivl-danger-fill:#FDECEE;
  --ivl-danger-fill-hover:#F9DCE0;
  --ivl-on-danger:#7A0A12;
  --ivl-danger-edge:#D0101E;
  --ivl-hazard:repeating-linear-gradient(-45deg,#E60012 0 5px,#FFFFFF 5px 10px);
  --ivl-ok:#1F7A47;
  --ivl-on-ok:#FFFFFF;
  --ivl-ok-text:#17693A;
  --ivl-ok-ink:#14532D;
  --ivl-ok-panel:#E6F4EB;
  --ivl-ok-edge:#3E9A5E;
  --ivl-warn:#F2A93B;
  --ivl-on-warn:#1E232A;
  --ivl-warn-text:#855400;
  --ivl-warn-ink:#5E3D00;
  --ivl-warn-panel:#FFF3DC;
  --ivl-warn-edge:#B8860B;
  --ivl-info:#2563C9;
  --ivl-on-info:#FFFFFF;
  --ivl-info-text:#1D56B0;
  --ivl-info-ink:#1E3A6B;
  --ivl-info-panel:#E9F0FC;
  --ivl-info-edge:#4F7FD0;
  /* map + rack drawings, light: a pale floor, slate walls, the states darkened until their words and
     edges clear WCAG on white (gate: tools/kallen_cw_map_gate.py) */
  --ivl-map-floor:#EEF2F6;      --ivl-map-wall:#4E5A6B;       --ivl-map-room:#DFE5EC;
  --ivl-map-room-edge:#6E7A8C;  --ivl-map-room-label:#485366;
  --ivl-map-notch:#7C8696;      --ivl-map-hatch:#3A66A8;      --ivl-map-amber:#8A6400;
  --ivl-map-dash:#5C6878;       --ivl-map-demise-fill:#C06A24; --ivl-map-demise:#A3520F;
  --ivl-map-door:#1A78A0;       --ivl-map-run:#5D6B80;        --ivl-map-run-na:#7A5A2C;
  --ivl-map-mark:#1E232A;       --ivl-map-chip:#FFFFFF;       --ivl-map-chip-edge:#4E5A6B;
  --ivl-map-stg:#8F6200;        --ivl-map-compass:#485366;
  --ivl-map-bound:#52657F;      --ivl-map-sel:#1f5f8f;        --ivl-map-mine:#2a6f2d;
  --ivl-map-bound-edge:#2F4560; --ivl-map-unbound-edge:#6E7888;
  --ivl-map-mine-edge:#1F6B2A;  --ivl-map-sel-edge:#1A5A9A;
  --ivl-map-bay-text:#F4F7FB;   --ivl-map-unbound-text:#5A6474;
  --ivl-map-hit-fill:#FFE7A3;   --ivl-map-hit:#8A6400;        --ivl-map-label:#1E232A;  --ivl-map-halo:#FFFFFF;
  --ivl-map-mini-floor:#EEF2F6; --ivl-map-mini-wall:#5B6676;  --ivl-map-mini-room:#DFE5EC; --ivl-map-mini-room-edge:#8A95A5;
  --ivl-map-mini-bay:#D3DCE7;   --ivl-map-mini-bay-edge:#6E7A8C;
  --ivl-map-sky-top:#F7F9FB;    --ivl-map-sky-bottom:#E6EBF1; --ivl-map-floor3d:#DCE2E9;
  --ivl-map-3d-wall:#5B6676;    --ivl-map-3d-room:#8A95A5;    --ivl-map-3d-overhead:#A3ADBA; --ivl-map-3d-demise:#C06A24;
  --ivl-map-3d-door:#1A78A0;    --ivl-map-3d-zone:#9A7000;    --ivl-map-3d-clear:#3A66A8;    --ivl-map-3d-fixture:#6F7F98;
  --ivl-map-3d-equip:#7B5CB8;   --ivl-map-3d-other:#6B7686;   --ivl-map-3d-label:#10151c;
}

/* ---- 4. type -------------------------------------------------------------- */
/* WII 10-21: self-hosted latin subsets (SIL OFL 1.1, Google Fonts), precached by /quick-sw.js so a dead
   aisle keeps the same letters. Anything outside latin falls through to the system face. */
/* WII repair 10-21: STAY LIGHT (spec section 2: 300 display, 500 labels, 700 only the primary button; heavy black type
   is P5). The bold faces are declared for the RANGE 600-1000, so a page that still asks for 800 or 900 gets the 700
   cut - never black, never a faux-bold smear - without touching a single page file. The 800 cut is no longer shipped.
   METRICS: M PLUS's own 'normal' line box is 1.485em (hhea 1075/320 + 90 gap) against Segoe UI's 1.33em, so every
   page that leaves line-height at normal grew ~12% taller (MORE lost a row). The overrides set the same 1.33em box
   the pages were laid out with: ascent 104% + descent 29%, no gap. */
@font-face{font-family:"M PLUS 1p";font-style:normal;font-weight:400;font-display:swap;ascent-override:104%;descent-override:29%;line-gap-override:0%;src:url(/fonts/mplus1p-400.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"M PLUS 1p";font-style:normal;font-weight:500;font-display:swap;ascent-override:104%;descent-override:29%;line-gap-override:0%;src:url(/fonts/mplus1p-500.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"M PLUS 1p";font-style:normal;font-weight:600 1000;font-display:swap;ascent-override:104%;descent-override:29%;line-gap-override:0%;src:url(/fonts/mplus1p-700.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"M PLUS Rounded 1c";font-style:normal;font-weight:300;font-display:swap;ascent-override:104%;descent-override:29%;line-gap-override:0%;src:url(/fonts/mplusrounded1c-300.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"M PLUS Rounded 1c";font-style:normal;font-weight:400 500;font-display:swap;ascent-override:104%;descent-override:29%;line-gap-override:0%;src:url(/fonts/mplusrounded1c-500.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"M PLUS Rounded 1c";font-style:normal;font-weight:600 1000;font-display:swap;ascent-override:104%;descent-override:29%;line-gap-override:0%;src:url(/fonts/mplusrounded1c-700.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
h2,h3,h4{font-style:normal}
/* titles + numbers: the rounded display face, light-to-medium weight (heavy black italic is P5, not Wii) */
html:not(#ivl) :is(h1,h2,.ovhead h2,.panelhead,.big,.num,.count){font-family:var(--ivl-font-display);font-style:normal}
html:not(#ivl) :is(h1,h2){font-weight:500;letter-spacing:-.005em}
/* display numbers (a big stat on its own line) run at 300; a bay code read at arm's length keeps 500 */
html:not(#ivl) :is(div.big,.count){font-weight:300}
html:not(#ivl) .loc .big{font-weight:500}
html:not(#ivl) :is(button,.btn,a.btn,a.b-red,.b-red,a.b-ghost,.b-ghost){font-family:var(--ivl-font-display);font-weight:500;letter-spacing:.01em}
/* 700 is the PRIMARY button's alone (and the bar's SCAN word) */
html:not(#ivl) :is(.b-red,a.b-red,button.b-red,.btn.go,button.go,button[data-role=primary],a[data-role=primary]):not([data-tone=alert]):not([data-tab]):not([role=tab]){font-weight:700}
/* the bold cap: labels and emphasis are 600 (= the 700 cut, see the faces above), never 800/900 black */
html:not(#ivl) :is(b,strong,.t,h3,h4,#menu a b,.job,.goal,.lab,.hlab,.wkhead,.grp,.st,.mhead){font-weight:600}
/* BODY TYPE (critic: "M PLUS 1p never renders" - every page's own body stack won over html{font-family}).
   The roots every page styles get the house face at id weight; /theme.js re-points the remaining page and
   injected rules that name a SANS stack (system-ui, Inter, Segoe UI...) and leaves every monospace code alone. */
html:not(#ivl) :is(body,input,select,textarea,td,th,label,p,li,.card):not(.mono):not([class*=mono]):not(code):not(.type input):not(.mapfind input){font-family:var(--ivl-font)}
@media (max-width:700px){ html,body{font-size:var(--ivl-fs-md)} }

/* ---- 1+2. colour roles ---------------------------------------------------- */
/* section headings were red decoration -> chalk */
.card h2,.card h3,h2,h3{color:var(--ivl-text)}
/* (a) PRIMARY - the one "do it" per screen: solid brand-red plate, white label.
   A page declares an extra primary with data-role="primary" (scan: TAP THE MAP, GO). */
.b-red,a.b-red,button.b-red,.btn.go,button.go,button[data-role=primary],a[data-role=primary]{background:var(--ivl-primary);border-color:var(--ivl-primary);color:var(--ivl-on-primary)}
.b-red:hover,.btn.go:hover,[data-role=primary]:hover{background:var(--ivl-primary-hover);filter:none}
/* .b-red used as a SELECTED TAB (tasks) is selection, not action -> chalk plate */
[data-tab].b-red,[role=tab].b-red{background:var(--ivl-select);border-color:var(--ivl-select);color:var(--ivl-on-select)}
/* (b) DESTRUCTIVE - declared only. Outline + warning glyph, so it can never be
   mistaken for the solid red primary sitting next to it. */
[data-tone=alert].b-red,.b-red[data-tone=alert],button[data-tone=alert],a[data-tone=alert],.btn.red{background:var(--ivl-danger-fill);border:2px solid var(--ivl-danger-edge);color:var(--ivl-on-danger)}
[data-tone=alert].b-red:hover,button[data-tone=alert]:hover,a[data-tone=alert]:hover,.btn.red:hover{background:var(--ivl-danger-fill-hover);filter:none}
button[data-tone=alert]::before,a[data-tone=alert]::before,.btn.red::before{content:"\26A0\FE0E";margin-right:.45em;font-style:normal;color:var(--ivl-danger-edge)}
/* panels and banners that carry an alert: red HAZARD EDGE down the left */
div[data-tone=alert],section[data-tone=alert],details[data-tone=alert]{border-color:var(--ivl-alert);background-image:var(--ivl-hazard);background-size:var(--ivl-hazard-w) 100%;background-repeat:no-repeat;background-position:left top}
#posBanner[data-tone=alert]{background-image:var(--ivl-hazard);background-size:var(--ivl-hazard-w) 100%;background-repeat:no-repeat;background-position:left top;padding-left:calc(var(--ivl-hazard-w) + 10px)!important}
/* NEW MAKER - ruled loud: glyph on the flag, hazard edge on the card */
.flagtag.nm::before{content:"\26A0\FE0E";margin-right:.35em}
.card.nm{background-image:var(--ivl-hazard);background-size:var(--ivl-hazard-w) 100%;background-repeat:no-repeat;background-position:left top}
/* #proto: on the home page it is a computed warning (data-tone=alert, stays red);
   on tasks/review/weekly it is only the who-am-I / page-title strip -> neutral bar */
#proto:not([data-tone=alert]){background:var(--ivl-surface)!important;color:var(--ivl-text);border-bottom:1px solid var(--ivl-edge-strong)}
#proto:not([data-tone=alert]) b{background:transparent;color:var(--ivl-text);padding-left:0;clip-path:none}
/* focus: gold, never red */
:focus-visible{outline:2px solid var(--ivl-focus)!important;outline-offset:2px}
input:focus,select:focus,textarea:focus{border-color:var(--ivl-focus)!important;outline:2px solid var(--ivl-focus)!important;outline-offset:1px;box-shadow:none!important}
/* control boundaries meet 3:1 */
input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{border-color:var(--ivl-edge-strong)}
input::placeholder,textarea::placeholder{color:var(--ivl-text-2);opacity:1}
/* the wordmark: one colour, the product name */
.ivl-word{font-family:var(--ivl-font-display);font-weight:700;font-style:normal;letter-spacing:.01em;text-transform:uppercase;color:var(--ivl-text)}   /* WII 10-21: rounded upright (was 900 italic); repair: 700 (was 800) */
.ivl-word em,.ivl-word i,.ivl-word span{color:inherit!important;font-style:inherit}
.ivl-tenant{color:var(--ivl-text-2);font-weight:600;font-style:normal;text-transform:none;letter-spacing:0}
/* ---- WII repair 10-21: ONE ACCENT. The Wii is ~90% white and grey with blue only where the focus is (spec
   anti-pattern 3). Red keeps its two ruled jobs (primary + alert), green keeps STOP/START and a located bay,
   amber is kept ONLY for a real warning (overdue, low light, held on phone, an override). The amber the
   10-11 tokenizer left on DECORATION - the old P5 gold - goes neutral here, at id weight, no page file touched. */
html:not(#ivl) #mAdmin a{color:var(--ivl-text)!important}
html:not(#ivl) .loc.amber{background:var(--ivl-surface)!important;border:1px solid var(--ivl-rim)!important;box-shadow:var(--ivl-sh-rest)!important}
html:not(#ivl) .loc.amber .big{color:var(--ivl-text)!important}
html:not(#ivl) .truckchip{border:1px solid var(--ivl-rim)!important;font-weight:600!important}
html:not(#ivl) .truckchip.on{background:var(--ivl-select)!important;color:var(--ivl-on-select)!important;border-color:var(--ivl-select)!important}
html:not(#ivl) .pkbtn.pk-empty{border-color:var(--ivl-rim)!important;color:var(--ivl-text)!important}
html:not(#ivl) .pkbtn.pk-empty .zdot{background:var(--ivl-surface-3)!important}
html:not(#ivl) .seg button[aria-pressed="true"]{background:var(--ivl-select)!important;color:var(--ivl-on-select)!important;border-color:var(--ivl-select)!important}
/* a due date is information, not a warning; LATE keeps the alert red */
html:not(#ivl) :is(#homeDash .row:not(.late) .dt,.weekbox .due,.weekbox .trow:not(.late) .dt,.due.today){color:var(--ivl-text-2)!important}
html:not(#ivl) .dlmini .pill.today{border-color:var(--ivl-rim)!important;color:var(--ivl-text-2)!important}
html:not(#ivl) .weekbox .grp{color:var(--ivl-text-2)!important}
html:not(#ivl) .weekbox.pool .wkhead{color:var(--ivl-text-2)!important}
/* borders the pages drew in --gold (now a text grey) take the tile rim */
html:not(#ivl) :is(.t-admin,.temp,.notoken,.done .say,.kchip.k-packout_conflict){border-color:var(--ivl-rim)!important}

/* ---- 3. WII SHAPE (2026-10-21): rounded, soft, airy - replaces "hard edges, no glow" ---------------
   Pinko via GEASS 10-21 17:08: "super clean and bouncy like wii menu". Spec §2: no sharp corners
   anywhere, no skew. The old page-level glows are still cleared (the reset below, now at :where()
   weight) and the ONLY shadows left are the soft Wii set, given to tiles, buttons and pop-ups by
   the rules after it. `html:not(#ivl)` = id weight, so these beat every page <style> without
   touching one page file. */
/* WII repair 10-21: NO BLANKET RADIUS. The first pass forced 12px on every element, so a row whose only border is a
   bottom DIVIDER drew it as a curved "smile" (critic: MORE rows, home rows, the tasks dividers). The 3px force from
   10-07 is gone too, so each page's own radius stands, and the Wii radii come only from the ROLE lists below:
   fields 12, tiles/cards 16, dialogs 22, single-line controls a pill. Divider rows are square, always. */
html:not(#ivl) :is(input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea){border-radius:var(--ivl-r)!important}
:where(body *:not(svg):not(svg *)):not(.lit):not([class*=lit]):not(.ivl-keep-shadow){box-shadow:none!important}
/* full-width bars stay square (a rounded bar edge-to-edge reads as a mistake) */
html:not(#ivl) :is(#tabbar,#proto,nav.dnav,header,#hsb-demo-banner,.demo-banner,.hsb-demo,#posBanner,.ivl-flat){border-radius:0!important}
/* tiles + cards: 16px, white body, soft cool shadow, 1px rim (the rim is the card's own border) */
html:not(#ivl) :is(.card,#homeDash .hsec>.card,.tile,.hcard,section.panel,details.card,.weekbox){border-radius:var(--ivl-r-tile)!important;box-shadow:var(--ivl-sh-rest)!important}
/* ONE rim for every tile (critic: the week-goal box drew darker than its sibling cards - it had the rim, they kept
   the page's --ivl-edge). A card that carries a status (data-tone, the NEW MAKER hazard) keeps its own edge. */
html:not(#ivl) :is(.card,.tile,.hcard,section.panel,details.card):not([data-tone]):not(.nm){border-color:var(--ivl-rim)!important}
html:not(#ivl) .weekbox{border:1px solid var(--ivl-rim)!important}
/* divider rows are SQUARE (a rounded row with a bottom border curls its divider up at both ends) */
html:not(#ivl) :is(hr,#menu a,#menu button,#menu .mhead,.ovbody>.gh,.hsec .card>*,.card>li,.weekbox .trow,#homeDash .row){border-radius:0!important}
/* spec section 2: "add a step of space rather than a divider line" - the home + week-box rows breathe instead */
html:not(#ivl) :is(#homeDash .card>.row,#homeDash .weekbox .trow,.weekbox .trow){border:0!important;background:transparent!important}
html:not(#ivl) #homeDash .card>.row{padding:12px 14px}
html:not(#ivl) :is(#homeDash .weekbox .trow,.weekbox .trow){padding:8px 0}
/* buttons, chips, toggles, badges: full pill */
/* ...but only SINGLE-LINE controls (critic: a 90px week chip, a 116px condition card, a task header, the MORE rows and
   the "Found: ... tap to use" line all became capsules with words on the curve). [role=button] is not a pill: it is
   mostly a tappable block. A control that holds a block, a line break or a sub-line is a TILE (16px) instead. */
html:not(#ivl) :is(button,.btn,a.btn,a.b-red,a.b-ghost,.b-red,.b-ghost,.chip,.flagtag,.pill,.badge,input[type=submit],input[type=button]){border-radius:var(--ivl-r-pill)!important}
html:not(#ivl) :is(button,.btn,a.btn,.chip,[role=button]):is(.cond,.thead,.hsbfl,.mini,.pkbtn,.big,.ivl-tall,:has(> div,> br,> p,> ul,> table,> small[style*=block],> .sub,> .n + .t)){border-radius:var(--ivl-r-tile)!important}
html:not(#ivl) .hsbfl{border-radius:var(--ivl-r)!important}
html:not(#ivl) :is(button,.btn,a.btn,a.b-red,a.b-ghost,.b-red,.b-ghost,input[type=submit]):not(#tabbar *):not(#menu *):not([data-tab]):not([role=tab]):not(:disabled){box-shadow:var(--ivl-sh-rest)!important}
/* a tab strip / segmented control: the strip is a pill too, its buttons sit flat inside it */
html:not(#ivl) :is([data-tab],[role=tab]){box-shadow:none!important}
/* pop-ups: 22px, the soft dialog shadow; a bottom sheet rounds its top corners only */
html:not(#ivl) :is([role=dialog],[role=menu],[data-hsb-modal],.upcsheet,#fbWrap,#menu){border-radius:var(--ivl-r-dialog)!important;box-shadow:var(--ivl-sh-dialog)!important}
html:not(#ivl) :is(.sheet,#sheet){border-radius:var(--ivl-r-dialog) var(--ivl-r-dialog) 0 0!important;box-shadow:var(--ivl-sh-dialog)!important}
/* the bar's SCAN plate is a round button (the one Wii-round control on the screen) */
html:not(#ivl) #tabbar button.mid .ic{border-radius:50%!important}
/* the scrim behind a pop-up: Wii frosted wash instead of a dark curtain */
html:not(#ivl) #dim:not(.hide){background:var(--ivl-scrim)!important;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
/* the stage: a faint horizontal stripe under everything, STATIC (the drift is FULL tier only - spec §3.4) */
html:not(#ivl) body{background-image:repeating-linear-gradient(180deg,var(--ivl-stripe) 0 2px,transparent 2px 6px)}   /* scrolls with the page: a FIXED background repaints the whole page under the live camera every frame */
/* rows never scale: under the pointer / finger they take the blue wash and a 4px inset bar */
html:not(#ivl) :is(#menu a,#menu button,.fres,.ovbody>.gh){transition:background-color var(--motion-dur-fade) var(--motion-ease-out),box-shadow var(--motion-dur-fade) var(--motion-ease-out)}
@media (hover:hover){
  html:not(#ivl) :is(#menu a,#menu button,.fres,.ovbody>.gh):hover{background-color:var(--ivl-wash)!important;box-shadow:inset 4px 0 0 var(--ivl-focus)!important}
}
html:not(#ivl) :is(#menu a,#menu button,.fres,.ovbody>.gh):active{background-color:var(--ivl-wash)!important;box-shadow:inset 4px 0 0 var(--ivl-focus)!important}
/* focus: ONE soft-blue ring + halo (was P5 gold). Inputs get the same ring. */
html:not(#ivl) :focus-visible{outline:2px solid var(--ivl-focus)!important;outline-offset:2px;box-shadow:0 0 0 6px var(--ivl-focus-halo)!important}
html:not(#ivl) :is(input,select,textarea):focus{box-shadow:0 0 0 5px var(--ivl-focus-halo)!important}

/* ---- touch targets (density: comfortable on touch) ------------------------ */
@media (pointer:coarse),(max-width:700px){
  button,.btn,a.b-red,a.b-ghost,a.btn,[role=button],summary,
  input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=range]),select,textarea{min-height:var(--ivl-hit)!important}
  button,[role=button]{min-width:var(--ivl-hit)!important}
  .smallnote a{display:inline-flex;align-items:center;min-height:var(--ivl-hit)}
  a.b-red,a.b-ghost,a.btn,summary{display:inline-flex;align-items:center}
  label:has(> input[type=checkbox]),label:has(> input[type=radio]){display:inline-flex;align-items:center;min-height:var(--ivl-hit);min-width:var(--ivl-hit);gap:8px}
  /* a standalone link (its own line, not inside a sentence) is a control */
  a.ivl-link,a.back{display:inline-flex;align-items:center;min-height:var(--ivl-hit)}
  /* rows of inputs wrap instead of crushing a field to 39px */
  .row{flex-wrap:wrap}
  .row>input,.row>select{flex:1 1 140px!important;min-width:0}
}

/* ---- P3 (KALLEN 2026-10-11, Pinko "all lulul lets do it"): SCAN IS THE APP'S PRIMARY ACTION ----
   Home's red SCAN plate is gone, so the bar's SCAN carries the job alone and must win a glance on
   every page: the biggest control on the screen (drawn 56px, rising ~10px out of the bar), the brand-red
   primary plate (red's job #1), and its word in full weight. While the camera runs it is the green
   STOP plate, as before. `html` in front out-ranks the copy bottombar.js injects after this sheet. */
html #tabbar button.mid .ic{background:var(--ivl-primary);color:var(--ivl-on-primary);border:3px solid var(--ivl-bg);
  box-shadow:none;scale:1.4;transform-origin:50% 60%}
/* SIZE WITHOUT MOVING ANYTHING: the plate keeps the old 40px layout box (so the bar is exactly as tall
   as before and nothing above it moves) and is DRAWN 1.4x = 56px with `scale`, which takes no layout.
   It rises ~10px above the bar - a 30px lift covered the middle of whatever sat just above the bar
   (seen on the 10-11 after-captures, Settings drawer foot), and a taller box made the whole bar taller. */
html #tabbar button.mid .lb{color:var(--ivl-text);font-size:11px;font-weight:900;letter-spacing:.1em}
html #tabbar button.mid.live .ic{background:var(--ivl-ok);color:var(--ivl-on-ok)}
html #tabbar button.mid:active .ic{background:var(--ivl-primary-hover)}
html #tabbar button.mid.live:active .ic{background:var(--ivl-ok)}

/* ---- P4 (KALLEN 2026-10-11): ONE BAR PER SCREEN. A page that has the desk bar (>= 1100px) does not
   also show the phone's bottom bar - the board mounts both, and each owns its own width. */
@media (min-width:1100px){
  body:has(> nav.dnav) #tabbar{display:none}
  body:has(> nav.dnav) .hsb-barclear{padding-bottom:0!important}
}

/* ---- 8. THE HUB (WII repair 2026-10-21) - home.js builds it at the top of HOME --------------------------------
   Spec section 2: white 4:3 tiles on an even grid, the label UNDER the tile, 2 columns on a phone and 4 on a desk,
   paged sideways (swipe, or the dots) - never an endless scroll. 16px tile radius, 1px rim, the soft rest shadow,
   the inset top highlight. The art is one slate line icon (the colour law: no accent on a tile). Not the Wii's own
   4x3 page / Disc slot / clock bar (originality ruling). */
#homeHub{margin:2px 0 14px}
#homeHub .ivl-pages{display:flex;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;scrollbar-width:none;
  overscroll-behavior-x:contain;margin:-8px -12px 0}   /* room for the swell + the 8px focus halo: overflow clips */
#homeHub .ivl-pages::-webkit-scrollbar{display:none}
#homeHub .ivl-page{flex:0 0 100%;box-sizing:border-box;padding:12px 12px 6px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:14px 12px;align-content:start;scroll-snap-align:start;scroll-snap-stop:always}
@media (min-width:700px){ #homeHub .ivl-page{grid-template-columns:repeat(4,minmax(0,1fr))} }
html:not(#ivl) #homeHub a.ivl-tile{display:flex;flex-direction:column;gap:7px;text-decoration:none;color:var(--ivl-text);
  border-radius:var(--ivl-r-tile)!important;-webkit-tap-highlight-color:transparent;outline-offset:3px}
html:not(#ivl) #homeHub .ivl-face{position:relative;display:grid;place-items:center;aspect-ratio:4/3;
  background:linear-gradient(160deg,var(--ivl-surface),var(--ivl-surface-3));border:1px solid var(--ivl-rim);
  border-radius:var(--ivl-r-tile)!important;box-shadow:var(--ivl-sh-rest)!important;color:var(--ivl-text-2)}
#homeHub .ivl-face svg{width:42%;height:auto;max-width:56px}
#homeHub .ivl-lab{font:500 14px/1.25 var(--ivl-font);text-align:center;letter-spacing:.01em;color:var(--ivl-text)}
html:not(#ivl) #homeHub .ivl-tile:focus-visible{box-shadow:none!important;outline:0!important}
/* page dots: 44px targets, an 8px dot; the page you are on is the slate dot, a touch bigger (the swell, no width move) */
#homeHub .ivl-dots{display:flex;justify-content:center;margin-top:0}
html:not(#ivl):not(#ivl-a):not(#ivl-b) #homeHub .ivl-dot{width:44px;height:44px;min-width:44px;padding:0;border:0!important;background:transparent!important;
  box-shadow:none!important;display:grid;place-items:center;cursor:pointer}
#homeHub .ivl-dot::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--ivl-edge-strong);opacity:.55;
  transition:scale var(--motion-dur-select) var(--motion-ease-pop),opacity var(--motion-dur-fade) var(--motion-ease-out),background-color var(--motion-dur-fade) var(--motion-ease-out)}
#homeHub .ivl-dot.on::before{background:var(--ivl-text);opacity:1;scale:1.35}

/* ---- P6 (KALLEN 2026-10-11, Pinko "all lulul lets do it"): THE PLAN'S PAINT TABLE ----
   map.js (the 2D plan) and rack.js (TAP THE BAY) write SVG with literal paint attributes. Those
   attributes stay exactly as written - so the GEOMETRY code is untouched - and this table re-points
   each one at a --ivl-map-* token. CSS beats a presentation attribute, so the token wins in both
   themes; a value missing from the table keeps its own colour. Selectors match the attribute VALUE,
   so the same hex can mean different things as a fill and as a stroke. */
svg.ivl-plan [fill="#141a22" i]{fill:var(--ivl-map-floor)}
svg.ivl-plan [stroke="#7d8aa0" i]{stroke:var(--ivl-map-wall)}
svg.ivl-plan [fill="#7d8aa0" i]{fill:var(--ivl-map-wall)}
svg.ivl-plan [fill="#1c2531" i]{fill:var(--ivl-map-room)}
svg.ivl-plan [stroke="#46536a" i]{stroke:var(--ivl-map-room-edge)}
svg.ivl-plan text[fill="#5f6f88" i]{fill:var(--ivl-map-room-label)}
svg.ivl-plan [stroke="#4a5568" i]{stroke:var(--ivl-map-notch)}
svg.ivl-plan [stroke="#4a6fa5" i]{stroke:var(--ivl-map-hatch)}
svg.ivl-plan [fill="#c9a227" i]{fill:var(--ivl-map-amber)}
svg.ivl-plan [stroke="#c9a227" i]{stroke:var(--ivl-map-amber)}
svg.ivl-plan [stroke="#6b7b95" i]{stroke:var(--ivl-map-dash)}
svg.ivl-plan [fill="#b06a2c" i]{fill:var(--ivl-map-demise-fill)}
svg.ivl-plan [stroke="#e08b3a" i]{stroke:var(--ivl-map-demise)}
svg.ivl-plan text[fill="#e08b3a" i]{fill:var(--ivl-map-demise)}
svg.ivl-plan [fill="#2fa8d6" i]{fill:var(--ivl-map-door)}
svg.ivl-plan [stroke="#2fa8d6" i]{stroke:var(--ivl-map-door)}
svg.ivl-plan [stroke="#33415a" i]{stroke:var(--ivl-map-run)}
svg.ivl-plan [stroke="#8a6a3a" i]{stroke:var(--ivl-map-run-na)}
svg.ivl-plan text[fill="#8a6a3a" i]{fill:var(--ivl-map-run-na)}
svg.ivl-plan [stroke="#ffffff" i]{stroke:var(--ivl-map-mark)}
svg.ivl-plan rect[fill="#ffffff" i]:not([stroke]){fill:var(--ivl-map-chip);stroke:var(--ivl-map-chip-edge);stroke-width:2}
svg.ivl-plan [fill="#d6a02f" i]{fill:var(--ivl-map-stg)}
svg.ivl-plan [fill="#9ab0cc" i]{fill:var(--ivl-map-compass)}
svg.ivl-plan [stroke="#9ab0cc" i]{stroke:var(--ivl-map-compass)}
svg.ivl-plan [fill="#243447" i]{fill:var(--ivl-map-bound)}
svg.ivl-plan [fill="#1f5f8f" i]{fill:var(--ivl-map-sel)}
svg.ivl-plan [fill="#2f7d32" i]{fill:var(--ivl-map-mine)}
svg.ivl-plan [stroke="#6b86a8" i]{stroke:var(--ivl-map-bound-edge)}
svg.ivl-plan [stroke="#5a6478" i]{stroke:var(--ivl-map-unbound-edge)}
svg.ivl-plan [stroke="#7fd67f" i]{stroke:var(--ivl-map-mine-edge)}
svg.ivl-plan [stroke="#69b7ff" i]{stroke:var(--ivl-map-sel-edge)}
svg.ivl-plan text[fill="#e8eef7" i]{fill:var(--ivl-map-bay-text)}
svg.ivl-plan text[fill="#8b96a8" i]{fill:var(--ivl-map-unbound-text)}

/* ---- 6. house font everywhere ------------------------------------------------
   KALLEN 2026-10-11: a page whose body says font-family:inherit (rulings) fell through to the
   browser's serif. The root names the house stack once; pages that set their own keep it. */
html{font-family:var(--ivl-font)}

/* ---- 7. words over a live camera stay in the dark roles, in both themes ---------
   The tags, hints and torch over the video sit on a PICTURE, not on the page, so a light theme
   must not turn them dark-on-dark. Same names, dark values, scoped to the camera boxes. */
:root[data-theme=light] :is(.cam,#camWrap,#camWrap0){color-scheme:dark;
  --ivl-bg:#0B0B0D;--ivl-surface:#15161A;--ivl-surface-2:#1E2026;--ivl-surface-3:#2A2D35;--ivl-edge:#2E3038;
  --ivl-text:#F2F2F0;--ivl-text-2:#A8ADB7;--ivl-text-3:#8C929D;
  --ivl-warn-text:#F2B85B;--ivl-warn-ink:#FFE3A8;--ivl-warn-panel:#2A2008;
  --ivl-ok-text:#4FD18B;--ivl-ok-ink:#C6F5D6;--ivl-ok-panel:#0F2A1A;
  --ivl-alert-text:#FF5A64;--ivl-alert-ink:#FFD6D9;--ivl-alert-panel:#2A0709;
  --ivl-info-text:#8FB8FF;--ivl-info-ink:#CFE0FF;--ivl-info-panel:#10203A}

/* ---- 5. MOTION v2 - Couchwave smoothness, enterprise rails (Pinko 2026-10-11) ---------------
   "Like the pop and feel of couchwave ... location pop and search pop throughout the app that
   smoothness like a wii menu, but please be mindful that it is enterprise software."
   Engine: this sheet (entrances, press, lift, page slides) + /motion.js (exits as ghosts that
   cannot be tapped, the row cascades, panel switches by tab direction, the bar indicator).
   THE LAWS (tools/kallen_cw_motion_gate.js + kallen_cw_motion_live.py check them):
   1. Every duration / delay / distance / curve is a --motion-* token (the dial above).
   2. Only opacity, scale and translate animate - compositor only, smooth on a throttled phone.
   3. NOTHING WAITS FOR MOTION. A pop-up is tappable on frame 1; a closing pop-up is a GHOST
      (pointer-events:none, inert) so whatever is under it takes the next tap; page slides run
      with pointer-events:none on the transition layer.
   4. A scan CONFIRMATION is never held back: the words are painted before the flourish, the
      post-scan sheet is at full opacity on frame 1, the location card from 45% opacity.
   5. fill BACKWARDS only: when a motion ends nothing is left on the element.
   6. WII 10-21: ONE soft swell, never a wobble - pops ride --motion-ease-pop (2% peak, one turn),
      pages / sheets ride --motion-ease-slide (1.25%); exits and hover-out never bounce. Alerts and
      refusals (role=alertdialog, data-tone=alert) only fade. A scan confirmation gets at most the
      120ms --motion-dur-tick, words painted first. (was: "No overshoot, no bounce", 10-11)
   7. Dense work surfaces (tables, counts) do not animate.
   8. prefers-reduced-motion: every --motion-* is 0ms, every animation and transition is off,
      /motion.js does nothing, page slides are off. The app works identically. */
/* WII repair 10-21: every swell is a keyframe at an ABSOLUTE scale (peak at 55%), up on the ease-out and down on the
   settle curve - so each one rises past 1 and settles exactly once (one turn), and it is big enough to SEE. */
@keyframes ivl-pop{0%{opacity:0;scale:var(--motion-pop-scale);animation-timing-function:var(--motion-ease-out)}
  55%{opacity:1;scale:var(--motion-pop-peak);animation-timing-function:var(--motion-ease-settle)}100%{opacity:1;scale:1}}
@keyframes ivl-hover-swell{0%{scale:1;animation-timing-function:var(--motion-ease-out)}
  55%{scale:var(--motion-hover-peak);animation-timing-function:var(--motion-ease-settle)}100%{scale:var(--motion-hover-scale)}}
@keyframes ivl-release{0%{scale:var(--motion-press-scale);animation-timing-function:var(--motion-ease-out)}
  55%{scale:var(--motion-release-peak);animation-timing-function:var(--motion-ease-settle)}}
@keyframes ivl-rise{from{opacity:0;translate:0 var(--motion-rise)}}
@keyframes ivl-sheet-in{from{opacity:.4;translate:0 calc(var(--motion-rise) * 6)}}
@keyframes ivl-drawer-in{from{opacity:.3;translate:0 calc(var(--motion-rise) * 2);scale:.98}}
@keyframes ivl-fade{from{opacity:0}}
@keyframes ivl-settle{from{translate:0 var(--motion-rise)}}
@keyframes ivl-zoom{0%{opacity:var(--motion-zoom-from);scale:var(--motion-zoom-scale);animation-timing-function:var(--motion-ease-out)}
  55%{opacity:1;scale:var(--motion-pop-peak);animation-timing-function:var(--motion-ease-settle)}100%{opacity:1;scale:1}}
@keyframes ivl-glide{from{opacity:0;translate:calc(var(--motion-rise) * -1) 0}}
@keyframes ivl-expand{from{opacity:0;scale:.82 1}}
@keyframes ivl-lift{0%{scale:var(--motion-pop-scale);animation-timing-function:var(--motion-ease-out)}
  55%{scale:var(--motion-pop-peak);animation-timing-function:var(--motion-ease-settle)}100%{scale:1}}
@keyframes ivl-vt-in-fwd{from{opacity:0;translate:var(--motion-slide) 0}}
@keyframes ivl-vt-out-fwd{to{opacity:0;translate:calc(var(--motion-slide) * -.5) 0}}
@keyframes ivl-vt-in-back{from{opacity:0;translate:calc(var(--motion-slide) * -1) 0}}
@keyframes ivl-vt-out-back{to{opacity:0;translate:calc(var(--motion-slide) * .5) 0}}
@keyframes ivl-vt-in-up{from{opacity:0;translate:0 var(--motion-rise);scale:.985}}
@keyframes ivl-vt-out-up{to{opacity:0;scale:.985}}

/* pop-ups, menus, the feedback panel: the Wii pop (they open by losing .hide or by being appended;
   an animation starts on both, so nothing about how any of them opens changed) */
:is([role=dialog],[role=menu],[data-hsb-modal],.upcsheet,#fbWrap):not(.hide){
  animation:ivl-pop var(--motion-dur-pop) var(--motion-ease-pop) backwards;transform-origin:50% 0}
#menu:not(.hide){transform-origin:calc(100% - 24px) 0}
/* full-height panels (home, ammo, map, settings, fix) rise in; /motion.js turns a tab-to-tab
   switch into a sideways slide in the bar's direction */
.ovwrap:not(.hide){animation:ivl-drawer-in var(--motion-dur-panel) var(--motion-ease-slide) backwards}
/* SEARCH POP: the panel comes in, the search field EXPANDS across, results cascade (/motion.js) */
#findWrap:not(.hide){animation:ivl-fade var(--motion-dur-fade) var(--motion-ease-out) backwards}
#findWrap:not(.hide) .ovhead{animation:ivl-expand var(--motion-dur-pop) var(--motion-ease-pop) backwards;transform-origin:0 50%}
/* bottom sheets slide up from the bar; the POST-SCAN sheet is a confirmation, so it never fades */
.sheet:not(.hide){animation:ivl-sheet-in var(--motion-dur-panel) var(--motion-ease-slide) backwards}
/* WII ENTERPRISE: the post-scan sheet IS the scan confirmation - full opacity on frame 1, one 120ms tick */
#sheet:not(.hide){animation:ivl-settle var(--motion-dur-tick) var(--motion-ease-out) backwards}
/* the scrim behind a pop-up fades in (and, as a ghost, out) */
#dim:not(.hide){animation:ivl-fade var(--motion-dur-fade) var(--motion-ease-out) backwards}
/* alerts and refusals never pop or bounce - they fade */
:is([role=alertdialog],[data-tone=alert]):not(.hide){animation:ivl-fade var(--motion-dur-fade) var(--motion-ease-out) backwards}
/* selection takes its plate with a small lift: tabs, chips */
:is([data-tab].b-red,[role=tab][aria-selected=true],[aria-pressed=true]):not(#menu *){
  animation:ivl-lift var(--motion-dur-select) var(--motion-ease-pop) backwards}

/* PRESS / HOVER / RELEASE - WII ENTERPRISE (spec 3.3), repaired 10-21 so the swell can be SEEN:
   * HOVER (pointer devices): the control swells ONCE to 102.6% and settles at 102% (ivl-hover-swell, 160ms). The
     scale transition is switched off while it runs, because a running transition out-ranks an animation.
   * PRESS: a finger / button going down dips it to 97% in 60ms (!important, so it wins over the hover state).
   * RELEASE (touch + pen - the phone's only bounce): /theme.js adds .ivl-m-release on pointerup and the control
     springs .97 -> 101.2% -> 100% in 180ms. The press rule steps aside for it: Chrome HOLDS :active ~150ms after a
     quick tap, and the !important dip would otherwise eat the whole bounce (measured: tools/wii_swell_gate.py). A mouse release goes straight back to the hover state.
   * Leaving hover eases out with NO bounce. Rows never scale (they wash, see 3). Wide bars and tab pills never
     scale either (a 1100px bar growing 22px reads as a jump): they take the halo only. Every one is
     interruptible - a new tap retargets mid-flight, nothing is ever blocked. */
:is(button,a.b-red,a.b-ghost,a.btn,[role=button],.chip,.ivl-tile){transition:scale var(--motion-dur-release) var(--motion-ease-pop)}
@media (hover:hover){
  :is(button,a.b-red,a.b-ghost,a.btn,[role=button],.chip,.ivl-tile){transition:scale var(--motion-dur-fade) var(--motion-ease-out)}
  :is(button,a.b-red,a.b-ghost,a.btn,[role=button],.chip,.ivl-tile):hover:not(:disabled):not(#tabbar *):not(#menu *):not([data-tab]):not([role=tab]):not(.ivl-wide):not(.hsbfl){
    scale:var(--motion-hover-scale);transition:scale 0s;animation:ivl-hover-swell var(--motion-dur-hover) linear}
  html:not(#ivl) :is([data-tab],[role=tab],.ivl-wide):hover:not(:disabled){box-shadow:0 0 0 2px var(--ivl-focus),0 0 0 6px var(--ivl-focus-halo)!important}
}
:is(button,a.b-red,a.b-ghost,a.btn,[role=button],.chip,.ivl-tile):active:not(:disabled):not(#menu *):not(.hsbfl):not(.ivl-m-release){scale:var(--motion-press-scale)!important;transition:scale var(--motion-dur-press) var(--motion-ease-out)}
.ivl-m-release{animation:ivl-release var(--motion-dur-release) linear!important;transition:scale 0s!important}
/* TILES (home cards, my tasks, the hub tiles): the same swell / dip, plus the soft hover ring; the hover shadow is a
   pseudo-element faded with opacity, so even the shadow is compositor-only */
:is(#homeDash .hsec>.card,#p-mine .card){position:relative;transition:scale var(--motion-dur-release) var(--motion-ease-pop)}
:is(#homeDash .hsec>.card,#p-mine .card)::after,#homeHub .ivl-tile .ivl-face::after{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:0;border-radius:inherit;
  box-shadow:var(--ivl-sh-hover);transition:opacity var(--motion-dur-fade) var(--motion-ease-out)}
@media (hover:hover){
  :is(#homeDash .hsec>.card,#p-mine .card){transition:scale var(--motion-dur-fade) var(--motion-ease-out)}
  :is(#homeDash .hsec>.card,#p-mine .card):hover{scale:var(--motion-hover-scale);z-index:2;transition:scale 0s;animation:ivl-hover-swell var(--motion-dur-hover) linear}
  :is(#homeDash .hsec>.card,#p-mine .card):hover::after,#homeHub .ivl-tile:hover .ivl-face::after{opacity:1}
}
#homeHub .ivl-tile:focus-visible .ivl-face::after{opacity:1}
:is(#homeDash .hsec>.card,#p-mine .card):active:not(.ivl-m-release){scale:var(--motion-press-scale)!important;transition:scale var(--motion-dur-press) var(--motion-ease-out)}

/* the JS-fired one-shots (window.IVLMotion.play(el, kind)) */
.ivl-m-zoom{animation:ivl-zoom var(--motion-dur-pop) var(--motion-ease-pop) backwards}
#locCard.ivl-m-zoom{transform-origin:50% 100%}                        /* the card zooms out of the camera below it */
/* arriving by a page slide: the panel that opens on arrival rides the slide instead of rising twice */
.ivl-arriving .ovwrap:not(.hide){animation:none}
.ivl-m-glide{animation:ivl-glide var(--motion-dur-pop) var(--motion-ease-pop) backwards}
.ivl-m-pop{animation:ivl-pop var(--motion-dur-pop) var(--motion-ease-pop) backwards}
.ivl-m-confirm{animation:ivl-settle var(--motion-dur-tick) var(--motion-ease-out) backwards}   /* a confirmation: the tick, never a pop */
/* a ghost (a closing pop-up, animated out by /motion.js) can never be tapped or read aloud */
.ivl-ghost{pointer-events:none!important;animation:none!important}
/* dense work surfaces never animate */
:is(table,thead,tbody,tr,td,th){animation:none!important}

/* PAGE SLIDES between the five places (cross-document view transitions, Chrome 126+). /theme.js
   marks the direction from the bar's order (Home Ammo Scan Map Tasks): forward slides left, back
   slides right, anything else rises. The bar and its indicator are their own layers, so the bar
   stays put and the indicator GLIDES from the old tab to the new one. The transition layer takes
   no taps: a finger lands on the new page from its first frame. */
@view-transition{navigation:auto}
::view-transition{pointer-events:none}
::view-transition-group(*){animation-duration:var(--motion-dur-page);animation-timing-function:var(--motion-ease-slide)}
::view-transition-old(root){animation:ivl-vt-out-up var(--motion-dur-page) var(--motion-ease-out) both}
::view-transition-new(root){animation:ivl-vt-in-up var(--motion-dur-page) var(--motion-ease-slide) both}
:root[data-navdir=fwd]::view-transition-old(root){animation-name:ivl-vt-out-fwd}
:root[data-navdir=fwd]::view-transition-new(root){animation-name:ivl-vt-in-fwd}
:root[data-navdir=back]::view-transition-old(root){animation-name:ivl-vt-out-back}
:root[data-navdir=back]::view-transition-new(root){animation-name:ivl-vt-in-back}
#tabbar{view-transition-name:ivl-tabbar}
#tabbar .ivl-tabind{view-transition-name:ivl-tabind}
::view-transition-old(ivl-tabbar),::view-transition-new(ivl-tabbar){animation:none}
/* the bar's selection indicator: a slim plate under the lit item that GLIDES between items */
#tabbar .ivl-tabind{position:absolute;left:0;bottom:calc(3px + env(safe-area-inset-bottom));height:3px;width:var(--ivl-tabind-w,40px);
  border-radius:3px;background:var(--ivl-text);opacity:0;pointer-events:none;
  translate:var(--ivl-tabind-x,0px) 0;transition:translate var(--motion-dur-select) var(--motion-ease-pop),opacity var(--motion-dur-fade) var(--motion-ease-out)}
#tabbar .ivl-tabind.on{opacity:1}
/* a page arriving WITHOUT view transitions (older browsers): a quick fade, opacity only */
@supports not (view-transition-name:none){ body{animation:ivl-fade var(--motion-dur-fade) var(--motion-ease-out) backwards} }

@media (prefers-reduced-motion:reduce){
  :root{--motion-dur-press:0ms;--motion-dur-release:0ms;--motion-dur-hover:0ms;--motion-dur-tick:0ms;--motion-dur-select:0ms;--motion-dur-fade:0ms;--motion-dur-toast:0ms;--motion-dur-row:0ms;
        --motion-dur-pop:0ms;--motion-dur-exit:0ms;--motion-dur-panel:0ms;--motion-dur-page:0ms;--motion-stagger-step:0ms;--motion-stagger-max:0ms;
        --motion-loop-cue:0ms;--motion-loop-wait:0ms;--motion-loop-ping:0ms;
        --motion-hover-scale:1;--motion-press-scale:1;--motion-arrive-scale:1;--motion-pop-scale:1;
        --motion-hover-peak:1;--motion-pop-peak:1;--motion-release-peak:1;--motion-arrive-peak:1}
  *,*::before,*::after,.ivl-m-release{animation:none!important;transition:none!important}
  ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none!important}
}
@media (prefers-reduced-motion:reduce){ @view-transition{navigation:none} }

/* ---- PRINT (WII repair 10-21): a receipt, a label or a pick sheet prints square and flat - no rounded corners, no
   shadows, no stripe stage behind the words. */
@media print{
  html:not(#ivl) body *{border-radius:0!important;box-shadow:none!important}
  html:not(#ivl) body{background-image:none!important}
}
