/* The "Industry" design system — brand fonts and the token layer, for all three pages.
 *
 * This file exists because there were three copies of it. The dashboard carried 95
 * tokens, live.html 44 and break.html 36, and only 35 were identical: the body font was
 * --font on one page and --sans on the other two, neither of the smaller pages ever
 * adopted --space-* or --r-*, and live.html had already started papering over that with
 * `padding:var(--space-6, 20px)` — a fallback for a token that did not exist on it.
 *
 * The copies were not just redundant, they DISAGREED, and the disagreement reached the
 * screen: clock.js draws one dial on all three pages and read a different --empty on
 * each. That is the bug class this file removes.
 *
 * ── The architecture (unchanged, and the reason a re-skin is cheap) ─────────────────
 *   1. PRIMITIVES (--color-*, --space-*) are the design system verbatim: two OKLCH-
 *      derived ramps plus a spacing scale.
 *   2. The SEMANTIC layer (--bg, --text, --accent, --border, --r-*) keeps the names
 *      every rule and every JS var() call already reads, re-pointed at the primitives.
 *      Re-skinning is then a matter of moving the mapping, not of rewriting several
 *      hundred call sites.
 *
 * Dark is the same ramps REVERSED rather than a second palette, so --accent stays
 * var(--color-accent-700) in both themes and only the ~20 tokens that cannot be
 * expressed as a reversal are restated.
 *
 * ── Where the three copies disagreed, and what was chosen ───────────────────────────
 * Three tokens genuinely differed. They resolve in different directions, because they
 * are different jobs:
 *
 *   --empty      the unfilled track of a dial. dashboard var(--color-neutral-200);
 *                live/break #DEDEE0 / #2A2C2E. Takes the DASHBOARD's value: the dial is
 *                one instrument shared by three pages, and #2A2C2E sits ~1.2:1 against
 *                the board's own surface — a scale you cannot see is not a scale.
 *   --surface-2  a hover, tooltip and input fill. dashboard #424244 in dark;
 *                live/break #2A2B2D. Takes LIVE's value: this wants a subtle lift off
 *                --surface, and #424244 (the reversed 200 step) reads as a border
 *                weight, not a surface.
 *   --amber      dashboard #8A5A18 / #E0A951 (a real amber); live/break steel. Takes the
 *                DASHBOARD's value, so the name means one thing. The two consumers that
 *                wanted steel now say so directly and are pixel-identical: live's
 *                `.status.past .dot` reads --warn, and break's --warn reads the accent
 *                step rather than routing through --amber.
 *
 * --navy and --da-blue were dropped: neither had a single consumer anywhere.
 */

/* ── Brand fonts ──────────────────────────────────────────────────────────────
   Self-hosted rather than linked from Google, so no page makes a third-party request at
   runtime, all three render identically on a locked-down office network, and the app
   works with no internet at all when run locally. Open Sans is the variable file, which
   covers 400–700 in 48 KB. Barlow is static weights: Google serves no variable Barlow,
   and the latin subsets are ~22 KB each. A face is only fetched when something on the
   page actually uses it, so carrying all six here costs the smaller pages nothing. */
@font-face { font-family:'Open Sans'; src:url('/assets/fonts/open-sans-var.woff2') format('woff2');
  font-weight:400 700; font-style:normal; font-display:swap; }
@font-face { font-family:'Barlow Condensed'; src:url('/assets/fonts/barlow-condensed-600.woff2') format('woff2');
  font-weight:600; font-style:normal; font-display:swap; }
@font-face { font-family:'Barlow'; src:url('/assets/fonts/barlow-400.woff2') format('woff2');
  font-weight:400; font-style:normal; font-display:swap; }
@font-face { font-family:'Barlow'; src:url('/assets/fonts/barlow-500.woff2') format('woff2');
  font-weight:500; font-style:normal; font-display:swap; }
@font-face { font-family:'Barlow'; src:url('/assets/fonts/barlow-600.woff2') format('woff2');
  font-weight:600; font-style:normal; font-display:swap; }
@font-face { font-family:'Barlow'; src:url('/assets/fonts/barlow-700.woff2') format('woff2');
  font-weight:700; font-style:normal; font-display:swap; }

/* ── Light: the base ───────────────────────────────────────────────────────── */
:root {
  color-scheme: light;
  /* — design-system primitives — */
  --color-bg:#F2F2F3; --color-surface:#E9E9EA; --color-text:#1D1F20;
  --color-accent:#5980A6;
  --color-divider:rgba(29,31,32,.16);
  --color-neutral-100:#F5F5F8; --color-neutral-200:#E7E7EA; --color-neutral-300:#D4D4D7;
  --color-neutral-400:#B7B7BA; --color-neutral-500:#98989B; --color-neutral-600:#7A7A7D;
  --color-neutral-700:#5D5D60; --color-neutral-800:#424244; --color-neutral-900:#2B2B2D;
  --color-accent-100:#EEF6FF; --color-accent-200:#D6EBFF; --color-accent-300:#B5D9FD;
  --color-accent-400:#94BCE3; --color-accent-500:#749DC4; --color-accent-600:#597EA3;
  --color-accent-700:#416180; --color-accent-800:#2C455D; --color-accent-900:#1D2D3D;
  /* — semantic layer — */
  --bg:var(--color-bg); --surface:var(--color-surface); --surface-2:var(--color-neutral-200);
  /* --empty is the unfilled track of a dial: the scale its spokes are read against.
     Measured, all three previous values were effectively invisible on the card —
     dashboard #E7E7EA on #E9E9EA is 1.02:1, live/break #DEDEE0 is 1.11:1, and in dark
     live/break #2A2C2E is 1.20:1. The 300 step is the same ramp position in both themes
     and is the best of them on both grounds (1.21 light, 2.24 dark). Still short of the
     3:1 a meaningful graphic wants — that is the palette's job in the re-skin, and there
     is now a measurement in test/tokens.browser.js that will not let it slip further. */
  --border:var(--color-divider); --border-2:rgba(29,31,32,.30); --empty:var(--color-neutral-300);
  --text:var(--color-text); --text-2:var(--color-neutral-700); --muted:#67676A;
  --neutral:var(--color-neutral-500);
  --away:#6E6E72;   /* recorded away time on the hour dial, as on the Live Board */
  /* The silence ramp. Both the board and the dashboard colour one record by how long
     somebody had been quiet, so the two must not each keep their own idea of what that
     looks like — a gap that reads steel on the wall and gold on the dashboard is the
     same drift as a spoke meaning two different things. */
  --calm:var(--color-accent-300); --warn:var(--color-accent-600); --alert:#8C3A2B; --justified:#4E7D4E; --away-break:#3E7D78; --away-other:#6E5FA0;
  --accent:var(--color-accent-700); --accent-hover:var(--color-accent-800);
  --accent-solid:var(--color-accent-700); --on-accent:var(--color-bg);
  --sky:var(--color-accent); --sky-ink:var(--color-accent-700);
  /* Status and series go mono — the ramp, not a traffic light. Ordering, ink fields and
     written state labels carry the urgency instead. */
  --green:var(--color-accent-700); --green-fill:var(--color-accent-500);
  --todo:var(--color-accent-800); --new:var(--color-neutral-500);
  /* Two series stacked in one bar have to be told apart at a glance, so they sit WELL
     APART on the ramp — steps 700 and 300 — rather than on neighbouring steps.
     Deliberately not the literal ends: 100 and 900 would vanish into the page ground and
     the text ink respectively. Because the ramp is redefined per theme, one definition
     here reads correctly in both: each series keeps its role and the pair keeps its
     distance. */
  --series-a:var(--color-accent-700); --series-b:var(--color-accent-300);
  /* The one surviving alert hue: a desaturated brick that reads as a technical warning
     stamp rather than a sweet. Always paired with words. */
  --red:#8C3A2B;   --red-fill:#A8503E;
  --amber:#8A5A18;
  --owner:var(--color-accent-800); --status-waiting:var(--color-accent-300);
  /* The one permitted full field: steel as ground, type reversed to paper. Not a ramp
     step, because a reversed ramp would flip it to a white slab on the dark ground — the
     field has to stay STEEL in both themes, only trading which side of the ground it
     sits on. */
  --ink-field:var(--color-accent-900); --on-ink:var(--color-bg);
  --logo-ink:#006098;                  /* DETROIT, brand navy on paper */
  --hover:rgba(29,31,32,.055); --hover-strong:rgba(29,31,32,.11);
  /* The wash behind the rail's current section. Carried as its own token because it is
     the accent at an alpha, and a reversed ramp cannot express "the same accent,
     fainter" — the dark ground needs its own value. */
  --rail-lit:rgba(89,128,166,.15);
  --band:rgba(29,31,32,.035); --zebra:rgba(29,31,32,.025);
  /* The ruled ground. A tool that is entirely tables and charts sits better on
     graph paper than on a slab, and it is the blueprint idea the retired
     registration marks used to carry — once, at the page level, instead of
     crosshairs on every figure. Faint enough to read as texture: a ruling you can
     actually measure against competes with the charts drawn on top of it.
     Only the dashboard and its sign-in overlay wear it today. */
  --grid-line:rgba(29,31,32,.05); --grid-size:32px;
  --hatch:rgba(29,31,32,.42);
  --scrim:rgba(43,43,45,.50); --shadow-modal:0 12px 32px rgba(43,43,45,.22);
  /* What a card-shaped surface is filled with, and what sits under it. Both are the
     wireframe's answer — nothing and nothing — but they are tokens rather than literals
     so the four rules that draw a card (.card, .tile, .login-card, the board's .agent)
     can be filled from one place instead of four. --shadow-card had always been a token
     nobody read; --surface-card is new and starts at the value those rules already had.
     Changing them is the whole of the visual re-skin: a filled card on a near-black
     ground needs an edge, and this app has borders rather than elevation. */
  --surface-card:var(--surface);
  --shadow-card:none;
  --owner-tint:rgba(44,69,93,.10); --red-tint:rgba(140,58,43,.12); --todo-tint:rgba(65,97,128,.12);
  --green-tint:var(--color-accent-100);
  /* SVG alphas: light backgrounds need more ink for the same perceived weight. */
  --chart-area-alpha:.16; --density-min:.12; --density-max:.62; --arc-alpha:.22;
  --tick-major:.75; --tick-minor:.4;
}

/* ── Dark: the same ramps, reversed ───────────────────────────────────────────
   An explicit choice wins everywhere. The dashboard picks the theme in a pre-paint
   inline script; live.html and break.html follow the OS through the media query below.
   Both routes land on the same values. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --away:#C9C9CE;   /* reversed, so the band stays findable on the dark ground */
  --calm:var(--color-accent-300); --warn:var(--color-accent-400); --alert:#E9917F; --justified:#9CC79C; --away-break:#7FB8B2; --away-other:#A89BD4;
  /* The same technical ground with the lights off: a near-black steel-tinted paper, and
     every ramp reversed so each step keeps its role. */
  --color-bg:#0E1011; --color-surface:#191B1D; --color-text:#ECEDED;
  --color-accent:#94BCE3;
  --color-divider:rgba(236,237,237,.18);
  --color-neutral-100:#2B2B2D; --color-neutral-200:#424244; --color-neutral-300:#5D5D60;
  --color-neutral-400:#7A7A7D; --color-neutral-500:#98989B; --color-neutral-600:#B7B7BA;
  --color-neutral-700:#D4D4D7; --color-neutral-800:#E7E7EA; --color-neutral-900:#F5F5F8;
  --color-accent-100:#1D2D3D; --color-accent-200:#2C455D; --color-accent-300:#416180;
  --color-accent-400:#597EA3; --color-accent-500:#749DC4; --color-accent-600:#94BCE3;
  --color-accent-700:#B5D9FD; --color-accent-800:#D6EBFF; --color-accent-900:#EEF6FF;
  --border-2:rgba(236,237,237,.34);
  /* A subtle lift off --surface, not a step of the reversed ramp: this is the fill under
     a hover, a tooltip and a form input, and the 200 step reads as a border weight. */
  --surface-2:#2A2B2D;
  /* A steel panel lifted off the ground, rather than the reversed ramp's paper. */
  --ink-field:#24384C; --on-ink:var(--color-text);
  --logo-ink:#F2EFE8;                  /* DETROIT reversed, as the dark logo ships */
  --muted:#8E9195;
  --red:#E9917F;   --red-fill:#C4614C;
  --amber:#E0A951;
  --hover:rgba(255,255,255,.055); --hover-strong:rgba(255,255,255,.11);
  --rail-lit:rgba(148,188,227,.16);
  --band:rgba(255,255,255,.03); --zebra:rgba(255,255,255,.022);
  --grid-line:rgba(236,237,237,.045);
  --hatch:rgba(236,237,237,.42);
  --scrim:rgba(0,0,0,.62); --shadow-modal:0 12px 32px rgba(0,0,0,.55);
  --owner-tint:rgba(214,235,255,.10); --red-tint:rgba(233,145,127,.14); --todo-tint:rgba(181,217,253,.12);
  --chart-area-alpha:.12; --density-min:.14; --density-max:.5; --arc-alpha:.2;
  --tick-major:.9; --tick-minor:.5;
}

/* Follow the OS when nothing has been chosen. The dashboard does not need this — its
   pre-paint script sets data-theme before first paint, which is what stops the flash —
   but live.html and break.html have always relied on it, so it lives here now instead of
   being spelled out twice. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --away:#C9C9CE;
    --calm:var(--color-accent-300); --warn:var(--color-accent-400); --alert:#E9917F; --justified:#9CC79C; --away-break:#7FB8B2; --away-other:#A89BD4;
    --color-bg:#0E1011; --color-surface:#191B1D; --color-text:#ECEDED;
    --color-accent:#94BCE3;
    --color-divider:rgba(236,237,237,.18);
    --color-neutral-100:#2B2B2D; --color-neutral-200:#424244; --color-neutral-300:#5D5D60;
    --color-neutral-400:#7A7A7D; --color-neutral-500:#98989B; --color-neutral-600:#B7B7BA;
    --color-neutral-700:#D4D4D7; --color-neutral-800:#E7E7EA; --color-neutral-900:#F5F5F8;
    --color-accent-100:#1D2D3D; --color-accent-200:#2C455D; --color-accent-300:#416180;
    --color-accent-400:#597EA3; --color-accent-500:#749DC4; --color-accent-600:#94BCE3;
    --color-accent-700:#B5D9FD; --color-accent-800:#D6EBFF; --color-accent-900:#EEF6FF;
    --border-2:rgba(236,237,237,.34);
    --surface-2:#2A2B2D;
    --ink-field:#24384C; --on-ink:var(--color-text);
    --logo-ink:#F2EFE8;
    --muted:#8E9195;
    --red:#E9917F;   --red-fill:#C4614C;
    --amber:#E0A951;
    --hover:rgba(255,255,255,.055); --hover-strong:rgba(255,255,255,.11);
    --rail-lit:rgba(148,188,227,.16);
    --band:rgba(255,255,255,.03); --zebra:rgba(255,255,255,.022);
    --grid-line:rgba(236,237,237,.045);
    --hatch:rgba(236,237,237,.42);
    --scrim:rgba(0,0,0,.62); --shadow-modal:0 12px 32px rgba(0,0,0,.55);
    --owner-tint:rgba(214,235,255,.10); --red-tint:rgba(233,145,127,.14); --todo-tint:rgba(181,217,253,.12);
    --chart-area-alpha:.12; --density-min:.14; --density-max:.5; --arc-alpha:.2;
    --tick-major:.9; --tick-minor:.5;
  }
}

/* ── Geometry and type ────────────────────────────────────────────────────────
   Theme-independent, so stated once outside both blocks. */
:root {
  /* The scale every rule that draws a shape reads. It was flattened to 0 — the wireframe
     look — and the sentence "one edit squares the whole app" was aspirational until the
     rules were made to read it. They do now, so this is that one edit, in reverse.

     Four steps by weight: sm for focus rings and small chips, md for buttons and the
     segmented control, lg for cards and tiles, xl for modals and the sign-in card.
     --r-pill stays a real pill for count badges. */
  --r-sm:6px; --r-md:10px; --r-lg:14px; --r-xl:18px; --r-pill:9999px;
  /* Motion. Three durations by weight and one stagger, the way the radii are four steps
     by weight: dur-1 for a hover, a knob, a caret; dur-2 for a state change or a popup;
     dur-3 for an entrance or a draw-in. Every rule that moves reads one of these — the
     app used to carry ten literal durations and eight curves scattered across three
     inline stylesheets, and the reduced-motion opt-out had to be remembered per rule.

     The tempo is deliberately quick: this is a tool people open thirty times a day, and
     a reveal that takes longer than a glance reads as the page being slow, not as
     polish. Under 600ms end to end, including the last item of a staggered list. */
  --dur-1:120ms; --dur-2:200ms; --dur-3:420ms; --stagger:40ms;
  --ease-out:cubic-bezier(.2,.7,.2,1);
  --ease-in-out:cubic-bezier(.45,0,.2,1);
  /* The system's spacing scale (density 0.85). */
  --space-1:3.4px; --space-2:6.8px; --space-3:10.2px;
  --space-4:13.6px; --space-6:20.4px; --space-8:27.2px;
  /* Barlow Condensed headings over Barlow body, per the system. Open Sans is kept as the
     first fallback so a failed font load degrades to the face the dashboard used before
     rather than to a system grotesque. Mono is kept only where it earns its place: ids,
     timestamps, payloads, the webhook URL.

     --sans is an alias, not a second stack: live.html and break.html spelled the body
     font that way and their rules still read it. One value, two names, so neither page
     had to be rewritten to be hoisted. */
  --font:'Barlow','Open Sans',system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
  --sans:var(--font);
  --head:'Barlow Condensed','Barlow','Open Sans',system-ui,'Segoe UI',Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,'SF Mono',Menlo,Consolas,monospace;
}

/* Reduced motion as ONE token override rather than a media block per rule. Anything
   that reads a duration goes instant here, so a rule that forgets its own opt-out is
   still covered — which is how five rules were left animating under the preference
   before this existed. The two ambient loops (the route loader's ball, the on-break
   pulse) are the exception: an infinite animation at 0ms is not "off", so those keep
   an explicit animation:none beside their own rule. */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-1:0ms; --dur-2:0ms; --dur-3:0ms; --stagger:0ms; }
}
