/* The v2 layer, part 1: fonts, tokens, base and components (REDESIGN 2026-10-29; the system is saas/DESIGN-v2.md, "The Line Diagram").
   Every page of the new design loads this file first; site.css, app.css add their surfaces (status.css stands alone).
   Rules this file keeps (tests/test_web_motion.py and tests/test_web_contract.py read every stylesheet under web/):
   - only `transform` and `opacity` transition or animate, every duration is a token, nothing loops;
   - one focus ring, never removed; every url reference is a same-origin /static/ path; no imported sheet, no inline style anywhere;
   - colour means status only where it says so; every text and background pair named in DESIGN-v2.md is at least AA. */

/* ==== fonts: Overpass (OFL 1.1, shared/fonts/Overpass-OFL.txt) for every word; the wordmark keeps Archivo 800 at width 125 %
   (brand kit, "The Live Wordmark Rule"), a 5 KB cut of it with only the characters a product name may hold. */
@font-face {
  font-family: "Overpass";
  src: url("/static/shared/fonts/overpass-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  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: "Overpass";
  src: url("/static/shared/fonts/overpass-latin-ext.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Overpass";
  src: url("/static/shared/fonts/overpass-latin-italic.woff2") format("woff2");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0000-00FF, U+2000-206F;
}
@font-face {
  font-family: "Archivo Wordmark";
  src: url("/static/shared/fonts/archivo-wordmark.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
}
/* metric twin of Overpass on Arial, so the swap moves nothing (computed from both fonts' own tables) */
@font-face {
  font-family: "Overpass Fallback";
  src: local("Arial");
  size-adjust: 101.16%;
  ascent-override: 87.29%;
  descent-override: 37.86%;
  line-gap-override: 0%;
}

/* ==== tokens ================================================================================================= */
:root {
  /* the enamel: grounds and ink */
  --paper: #ffffff;          /* page ground of the public site; panels in the app */
  --paper-2: #f1f3f4;        /* one step down: bands, the app ground */
  --paper-3: #e4e8eb;        /* two steps: pressed rows, skeletons, the empty track */
  --ink: #101b23;            /* text: 17.5:1 on paper, 15.7:1 on paper-2 */
  --ink-2: #45545f;          /* secondary text: 7.8:1 on paper, 7.0:1 on paper-2 */
  --ink-3: #5d6b75;          /* captions and axis labels: 5.5:1 on paper */
  --rule: #d5dbdf;           /* row lines inside tables and lists, nowhere else */
  --edge: #6b7b86;           /* the edge of a field or a control: 4.4:1 on paper, 3.9:1 on paper-2 */
  --placeholder: #66757f;    /* 4.8:1 on paper */

  /* the sign field: the navy panel of a station sign (header, rail, footer, the closing band, dialog titles) */
  --sign: #0d2433;
  --sign-2: #173a50;         /* raised on the sign: hover, the current rail item */
  --sign-3: #24506b;         /* a rule on the sign */
  --on-sign: #ffffff;        /* 15.9:1 */
  --on-sign-2: #c2d2dc;      /* 10.3:1 on sign, 7.7:1 on sign-2 */

  /* the lamp: the one accent. On the sign field only (it is 1.6:1 on paper): the primary action on the sign, "you are here" */
  --lamp: #f5c451;           /* 9.8:1 on sign */
  --lamp-soft: #fbe3a2;      /* hover of a lamp control, text selection */
  --on-lamp: #101b23;        /* 10.7:1 */

  --link: #0f5a8f;           /* 7.3:1 on paper */
  --focus: #0b5cad;          /* the ring on light grounds; on the sign the ring is the lamp */

  /* status: always a glyph and a word with the colour, and the colour means nothing else */
  --steady: #19704f;   --steady-bg: #dcefe6;      /* 6.1:1 on paper, 5.1:1 on its tint */
  --regional: #8a5600; --regional-bg: #fbedd0;    /* 6.2:1 / 5.3:1 */
  --down: #b1261c;     --down-bg: #f8dedb;        /* 6.6:1 / 5.2:1; white on down 6.6:1 (the filled "Down" block) */
  --unknown: #536170;  --unknown-bg: #e2e7eb;     /* 5.1:1 on its tint: paused, not monitored, data unavailable */
  --planned: #0f4c7a;  --planned-bg: #dfeaf4;     /* announced maintenance: 7.4:1 on its tint */
  --planned-fill: #5b8db8;                        /* the diamond and the day bar: 3.5:1 on paper */
  --test: #6b3fa0;     --test-bg: #efe6fa;        /* the TEST label and nothing else: 6.1:1 */

  /* type: one family for every word, the system monospace for machine values only */
  --font: "Overpass", "Overpass Fallback", "Segoe UI", system-ui, sans-serif;
  --font-mark: "Archivo Wordmark", "Archivo", "Segoe UI", system-ui, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", Consolas, "SFMono-Regular", monospace;
  --t-xs: 0.8125rem;   /* 13: captions, axis labels, table heads */
  --t-sm: 0.9375rem;   /* 15: hints, secondary lines */
  --t-md: 1.0625rem;   /* 17: running text and controls */
  --t-lg: 1.25rem;     /* 20: lede, card titles */
  --t-xl: 1.5rem;      /* 24: h3 on the site, h2 in the app */
  --t-2xl: 2rem;       /* 32: app page titles */
  --t-3xl: clamp(2.125rem, 4.4vw, 3.5rem);    /* 34-56: section headings of the site */
  --t-display: clamp(2.75rem, 7.2vw, 6.5rem); /* 44-104: the one display line of a page */
  --lh-tight: 0.94;
  --lh-head: 1.06;
  --lh-body: 1.55;
  --lh-read: 1.65;
  --w-text: 400;
  --w-label: 650;
  --w-strong: 760;
  --w-display: 850;
  --track-display: -0.035em;
  --track-head: -0.025em;

  /* space: one closed scale */
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px; --s-10: 128px;

  /* shape: signs are square. Only glyphs and the stops of a line are round */
  --r-0: 0;
  --r-round: 50%;

  /* the line diagram */
  --line-w: 10px;            /* the line on a strip map */
  --line-w-sm: 6px;          /* the line in a list or a table of contents */
  --stop: 30px;              /* a stop's ring */
  --stop-sm: 18px;
  --rule-heavy: 2px;         /* the ink rule under a sign head, a table head, a panel head */

  /* elevation: flat; tone steps separate surfaces. One shadow, for what truly floats (menu, dialog, toast) */
  --lift: 0 18px 40px -18px rgba(13, 36, 51, 0.45), 0 2px 6px rgba(13, 36, 51, 0.08);
  --scrim: rgba(13, 36, 51, 0.55);

  /* layout */
  --wrap: 1312px;
  --gutter: clamp(16px, 4vw, 64px);
  --measure: 35em;          /* about 70 letters of Overpass (its ch is a wide zero, so the measure is in em) */
  --bar-h: 72px;
  --control: 48px;
  --control-sm: 40px;
  color-scheme: light;
}

/* ==== depth, soft shape and lit lamps (APP-WOW 2026-11-02, additive: no existing token changed) =================================
   The app and the public status page lift their panels off a cool canvas with a ring and a soft navy shadow, round their corners a
   little (pressed enamel plates have soft corners), and show a status as a lamp that is lit: the glyph in a brighter lamp colour with
   a halo of its own light, the word beside it in the status ink. A gap in the data is an unlit lamp (no halo). The public site keeps
   its own shapes; the names live here so both layers can share them. Every lamp colour is at least 3:1 on white (WCAG 1.4.11). */
:root {
  --canvas: #eef2f5;          /* the app's ground, a cool fog under white panels: ink-2 6.9:1, ink-3 4.9:1, link 6.5:1 on it */
  --hair: #e3e8ec;            /* a divider inside a panel, quieter than --rule */
  --raise: #f6f8fa;           /* a row under the pointer, a quiet button's hover, a well inside a panel */
  --r-1: 4px;                 /* small marks: tags, region names, bars, kbd */
  --r-2: 6px;                 /* controls: buttons, fields, segmented controls, notices */
  --r-3: 10px;                /* panels and cards */
  --r-4: 14px;                /* large plates: the verdict, dialogs, the overall status sign */
  --r-pill: 999px;            /* status pills */
  --e-1: 0 0 0 1px rgba(13, 36, 51, 0.07), 0 1px 2px rgba(13, 36, 51, 0.06), 0 2px 6px -2px rgba(13, 36, 51, 0.07);
  --e-2: 0 0 0 1px rgba(13, 36, 51, 0.09), 0 8px 16px -8px rgba(13, 36, 51, 0.2), 0 18px 36px -18px rgba(13, 36, 51, 0.24);
  --e-inset: inset 0 1px 2px rgba(13, 36, 51, 0.08);
  /* the lamps: a lit glyph (3:1 or more on white) and its halo */
  --lamp-steady: #1f9d63;   --halo-steady: rgba(31, 157, 99, 0.5);
  --lamp-down: #d8342a;     --halo-down: rgba(216, 52, 42, 0.5);
  --lamp-regional: #b87a00; --halo-regional: rgba(232, 165, 49, 0.6);
  --lamp-planned: #2d7dd2;  --halo-planned: rgba(45, 125, 210, 0.45);
  --halo-lamp: rgba(245, 196, 81, 0.55);
  --wait-delay: 300ms;        /* a wait shorter than this never shows the branded loader (a delay, not a motion: it stays with reduced motion) */
}

/* ==== motion module (v2): the same tokens and numbers as shared/css/base.css and shared/js/motion.js, plus the scene tokens.
   Full is the default; Calm keeps fades and drops movement; Off and the system's reduced motion make everything instant. */
:root {
  --dur-press: 100ms;
  --dur-state: 180ms;
  --dur-enter: 320ms;
  --dur-move: 180ms;
  --dur-scene: 900ms;        /* a once-only scene step: the line drawing in, a stop arriving */
  --dur-shimmer: 1200ms;     /* one pass of the loading shimmer; it runs four times, never more (WCAG 2.2.2) */
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-enter: cubic-bezier(0.05, 0.7, 0.1, 1);
  --ease-exit: cubic-bezier(0.3, 0, 1, 1);
  --move-xs: 2px;
  --move-sm: 4px;
  --move-md: 8px;
  --move-lg: 24px;           /* a section's parts rising as it enters */
  --press-scale: 0.97;
  --enter-scale: 0.98;
  --pop-scale: 0.6;
  --grow-from: 0;
  --busy-delay: 400ms;
  --busy-turn: 800ms;        /* one turn of the busy indicator */
  --stagger: 70ms;
}
:root[data-motion="calm"] {
  --dur-move: 0ms; --dur-scene: 0ms; --dur-shimmer: 0ms;
  --move-xs: 0px; --move-sm: 0px; --move-md: 0px; --move-lg: 0px;
  --press-scale: 1; --enter-scale: 1; --pop-scale: 1; --grow-from: 1;
}
:root[data-motion="off"] {
  --dur-press: 0ms; --dur-state: 0ms; --dur-enter: 0ms; --dur-move: 0ms; --dur-scene: 0ms; --dur-shimmer: 0ms; --stagger: 0ms;
  --move-xs: 0px; --move-sm: 0px; --move-md: 0px; --move-lg: 0px;
  --press-scale: 1; --enter-scale: 1; --pop-scale: 1; --grow-from: 1;
}
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion]) {
    --dur-press: 0ms; --dur-state: 0ms; --dur-enter: 0ms; --dur-move: 0ms; --dur-scene: 0ms; --dur-shimmer: 0ms; --stagger: 0ms;
    --move-xs: 0px; --move-sm: 0px; --move-md: 0px; --move-lg: 0px;
    --press-scale: 1; --enter-scale: 1; --pop-scale: 1; --grow-from: 1;
  }
  :root:not([data-motion="full"]) *, :root:not([data-motion="full"]) *::before,
  :root:not([data-motion="full"]) *::after { transition-duration: 0ms !important; animation-duration: 0ms !important; }
}
@keyframes lx-fade { from { opacity: 0; } }
@keyframes lx-rise { from { opacity: 0; transform: translateY(var(--move-sm)); } }
@keyframes lx-rise-lg { from { opacity: 0; transform: translateY(var(--move-lg)); } }
@keyframes lx-drop { from { opacity: 0; transform: translateY(calc(-1 * var(--move-md))); } }
@keyframes lx-pop { from { opacity: 0; transform: scale(var(--enter-scale)); } }
@keyframes lx-draw { from { transform: scaleX(var(--grow-from)); } }
@keyframes lx-draw-y { from { transform: scaleY(var(--grow-from)); } }
@keyframes lx-stop { from { opacity: 0; transform: scale(var(--pop-scale)); } }
@keyframes lx-flip { from { opacity: 0; transform: perspective(400px) rotateX(-70deg); } }
@keyframes lx-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }


/* ==== shared components on v2 pages (W0, 2026-11-02) ===========================================================================
   Ask Beam (shared/css/beam.css, loaded by site/js/beam-boot.js after the page has painted) is one stylesheet for the old pages and
   the v2 pages. It reads the token names of base.css; on a v2 page they are the v2 values here, so its launcher and panel are square,
   on the sign field and in Overpass, and nothing in beam.css has to know which system the page is in. The keyframes it names exist
   here under the same names with the same frames as base.css. A page loads base.css or this file, never both: with both, these
   names would give every base.css component on that page the v2 values (square corners, v2 sizes). */
:root {
  --space-1: var(--s-1); --space-2: var(--s-2); --space-3: var(--s-3); --space-4: var(--s-4); --space-5: var(--s-5);
  --text-xs: var(--t-xs); --text-sm: var(--t-sm); --text-md: var(--t-md); --text-lg: var(--t-lg);
  --surface: var(--paper); --fog: var(--paper-2); --rule-strong: var(--edge); --control-edge: var(--edge);
  --night: var(--sign); --night-2: var(--sign-2); --night-3: var(--sign-3); --on-night: var(--on-sign); --on-night-2: var(--on-sign-2);
  --radius-control: 0; --radius-card: 0; --radius-lg: 0;
  --control-h: 44px; --control-h-sm: var(--control-sm);
  --shadow-card: var(--lift); --shadow-lift: var(--lift);   /* the launcher floats: the one shadow */
}
/* (APP-V2, 2026-11-02, additive) the rest of the names the app's shared component sheet reads (app/css/activation.css, which the
   landing band loads on either system, like beam.css): the two larger steps of space and type, and the old small radius (square here) */
:root {
  --space-6: var(--s-6); --space-7: var(--s-7);
  --text-xl: var(--t-xl); --text-2xl: var(--t-2xl);
  --radius: 0;
}
@keyframes mi-rise { from { opacity: 0; transform: translateY(var(--move-sm)); } }
@keyframes mi-rise-md { from { opacity: 0; transform: translateY(var(--move-md)); } }
@keyframes mi-spin { to { transform: rotate(1turn); } }
@keyframes mi-fade { from { opacity: 0; } }   /* (APP-V2, additive) the same frames as base.css's */

/* ==== base ==================================================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: calc(var(--bar-h) + var(--s-4)); }
body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--font); font-size: var(--t-md); line-height: var(--lh-body);
  font-weight: var(--w-text); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-synthesis-weight: none;
  scrollbar-color: var(--edge) var(--paper-2); }
img, svg, video { display: block; max-width: 100%; height: auto; }
svg { height: auto; }
h1, h2, h3, h4 { margin: 0; font-weight: var(--w-strong); line-height: var(--lh-head); text-wrap: balance; }
h1 { font-size: var(--t-display); font-weight: var(--w-display); line-height: var(--lh-tight); letter-spacing: var(--track-display); }
h2 { font-size: var(--t-3xl); font-weight: var(--w-display); letter-spacing: var(--track-head); }
h3 { font-size: var(--t-xl); letter-spacing: -0.01em; }
h4 { font-size: var(--t-lg); }
p, li, dd, figcaption { text-wrap: pretty; }
p { margin: 0; }
p + p { margin-top: var(--s-4); }
ul, ol { margin: 0; padding: 0; }
figure, blockquote { margin: 0; }
a { color: var(--link); text-decoration-line: underline; text-decoration-thickness: 1px; text-underline-offset: 0.22em; }
a:hover { text-decoration-thickness: 2px; }
strong, b { font-weight: var(--w-strong); }
code, kbd, samp, pre { font-family: var(--mono); font-size: 0.9em; }
time, .num, td, th, .tabular { font-variant-numeric: tabular-nums; }
hr { border: 0; height: var(--rule-heavy); background: var(--ink); margin: var(--s-7) 0; }
::selection { background: var(--lamp-soft); color: var(--ink); }
::placeholder { color: var(--placeholder); opacity: 1; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.on-sign :focus-visible { outline-color: var(--lamp); }
[hidden] { display: none !important; }

.wrap { width: min(var(--wrap), 100% - 2 * var(--gutter)); margin-inline: auto; }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.skip-link { position: absolute; left: var(--s-4); top: calc(-1 * var(--s-9)); z-index: 100; padding: var(--s-3) var(--s-4); background: var(--lamp);
  color: var(--on-lamp); font-weight: var(--w-strong); text-decoration: none; }
.skip-link:focus-visible { top: var(--s-3); outline-color: var(--ink); }
.on-sign { background: var(--sign); color: var(--on-sign); }
.on-sign a:not(.btn) { color: var(--on-sign); }
.lede { font-size: var(--t-lg); line-height: 1.45; max-width: 23em; }
.note { color: var(--ink-2); font-size: var(--t-sm); }
.on-sign .note { color: var(--on-sign-2); }
.fine { color: var(--ink-3); font-size: var(--t-xs); }

/* ==== the wordmark: the inline mark (the page placeholder for it, filled by render_page) and the name as live text ==== */
.wordmark { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; color: inherit; text-decoration: none;
  font-family: var(--font-mark); font-weight: 800; font-stretch: 125%; font-size: 1.1875rem; letter-spacing: 0.01em; line-height: 1; }
.wordmark:hover { text-decoration: none; }
.wordmark svg { flex: none; }

/* ==== icons: one set, 24 grid, 2 px stroke (the app's own drawn set, shared/img/v2/icons.svg) ==== */
.icon { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.icon-sm { width: 16px; height: 16px; }
.glyph { width: 15px; height: 15px; flex: none; }

/* ==== buttons: square, flat, one fill; 48 px (40 small); colour changes at once, the press dips ==== */
.btn { position: relative; display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2); min-height: var(--control);
  padding: 2px 22px 0; border: 0; border-radius: var(--r-0); font: inherit; font-weight: var(--w-strong); font-size: var(--t-md);
  line-height: 1.1; text-decoration: none; text-align: center; cursor: pointer; white-space: nowrap; background: var(--ink); color: var(--paper);
  transition: transform var(--dur-press) var(--ease-standard); }
@supports (text-box: trim-both cap alphabetic) { .btn { padding-top: 0; text-box: trim-both cap alphabetic; } }
.btn:hover { background: #24343f; text-decoration: none; }
.btn:active:not([disabled]):not([aria-disabled="true"]) { transform: scale(var(--press-scale)); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }
.btn-sm { min-height: var(--control-sm); padding-inline: 16px; font-size: var(--t-sm); }
.btn-lamp { background: var(--lamp); color: var(--on-lamp); }
.btn-lamp:hover { background: var(--lamp-soft); }
.btn-line { background: var(--paper); color: var(--ink); box-shadow: inset 0 0 0 var(--rule-heavy) var(--ink); }
.btn-line:hover { background: var(--paper-2); }
.btn-sign-line { background: transparent; color: var(--on-sign); box-shadow: inset 0 0 0 var(--rule-heavy) var(--on-sign-2); }
.btn-sign-line:hover { background: var(--sign-2); }
.btn-danger { background: var(--down); color: #fff; }
.btn-danger:hover { background: #8f1d15; }
.btn-quiet { background: transparent; color: var(--link); padding-inline: 4px; text-decoration: underline; text-underline-offset: 0.22em; }
.btn-quiet:hover { background: transparent; text-decoration-thickness: 2px; }
.btn .icon { margin-left: -4px; }
/* busy: the label fades and a static bar shows under it, so the button keeps its size; the bar fills once (no loop) */
.btn-label { transition: opacity var(--dur-state) var(--ease-standard); }
.btn.is-busy { cursor: progress; }
.btn.is-busy .btn-label { opacity: 0.35; transition-delay: var(--busy-delay); }
.btn.is-busy::after { content: ""; position: absolute; left: 12px; right: 12px; bottom: 8px; height: 3px; background: currentColor;
  transform-origin: left; animation: lx-draw var(--dur-scene) var(--ease-standard) var(--busy-delay) both; }
.link-arrow { display: inline-flex; align-items: center; gap: 6px; font-weight: var(--w-label); }
.link-arrow svg { transition: transform var(--dur-move) var(--ease-standard); }
.link-arrow:hover svg { transform: translateX(var(--move-sm)); }

/* ==== fields ==== */
.field { display: grid; gap: 6px; }
.field > label, .label { font-weight: var(--w-label); }
.input, .select, .textarea { width: 100%; min-height: var(--control); padding: 0 14px; border: var(--rule-heavy) solid var(--edge); border-radius: var(--r-0);
  background: var(--paper); color: var(--ink); font: inherit; }
.textarea { padding-block: 12px; min-height: 120px; resize: vertical; line-height: var(--lh-body); }
.select { appearance: none; padding-right: 40px; background-image: url("/static/shared/img/v2/chevron.svg"); background-repeat: no-repeat;
  background-position: right 12px center; background-size: 16px; }
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-2); }
.input:focus-visible, .select:focus-visible, .textarea:focus-visible { border-color: var(--focus); }
.hint { color: var(--ink-2); font-size: var(--t-sm); }
.field.has-error .input, .input[aria-invalid="true"] { border-color: var(--down); }
.field-error { display: flex; gap: 6px; align-items: flex-start; color: var(--down); font-weight: var(--w-label); font-size: var(--t-sm); }
.field-error:not([hidden]) { animation: lx-rise var(--dur-state) var(--ease-standard) both; }
.joined { display: flex; }
.joined .input { border-right: 0; }
.joined .btn { flex: none; }
.check-row { display: flex; align-items: flex-start; gap: 10px; min-height: 44px; padding-top: 10px; }
.check-row input { width: 20px; height: 20px; margin: 1px 0 0; accent-color: var(--ink); }

/* switch: a square track and a square thumb that slides (transform) */
.switch { display: inline-flex; align-items: center; gap: var(--s-3); min-height: 44px; padding: 0; border: 0; background: none; font: inherit; color: inherit;
  cursor: pointer; font-weight: var(--w-label); }
.switch-track { position: relative; width: 52px; height: 28px; flex: none; background: var(--paper-3); box-shadow: inset 0 0 0 var(--rule-heavy) var(--edge); }
.switch-thumb { position: absolute; top: 4px; left: 4px; width: 20px; height: 20px; background: var(--ink-2); transition: transform var(--dur-move) var(--ease-standard); }
.switch[aria-checked="true"] .switch-track { background: var(--ink); box-shadow: none; }
.switch[aria-checked="true"] .switch-thumb { transform: translateX(24px); background: var(--paper); }

/* segmented control: square segments, one ink block slides under the chosen one */
.seg { position: relative; display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; padding: 4px; background: var(--paper-2);
  box-shadow: inset 0 0 0 var(--rule-heavy) var(--ink); }
.seg-opt { position: relative; z-index: 1; min-height: var(--control-sm); padding: 2px 18px 0; border: 0; background: none; font: inherit; font-weight: var(--w-label);
  color: var(--ink); cursor: pointer; }
.seg-opt[aria-checked="true"], .seg-opt[aria-pressed="true"] { color: var(--paper); }
.seg-ink { position: absolute; top: 4px; bottom: 4px; left: 4px; width: calc((100% - 8px) / var(--seg-n, 2)); background: var(--ink);
  transform: translateX(calc(100% * var(--seg-i, 0))); transition: transform var(--dur-move) var(--ease-standard); }

/* tabs: words on a heavy rule; the ink bar slides to the current one */
.tabs { position: relative; display: flex; gap: var(--s-1); overflow-x: auto; scrollbar-width: none; box-shadow: inset 0 calc(-1 * var(--rule-heavy)) 0 var(--rule); }
.tab { position: relative; flex: none; min-height: 48px; padding: 2px 16px 0; border: 0; background: none; font: inherit; font-weight: var(--w-label); color: var(--ink-2);
  cursor: pointer; }
.tab:hover { color: var(--ink); }
.tab[aria-selected="true"] { color: var(--ink); }
.tab-ink { position: absolute; left: 0; bottom: 0; height: 4px; width: 1px; background: var(--ink); transform-origin: left;
  transition: transform var(--dur-move) var(--ease-standard); }
.tabpanel:not([hidden]) { animation: lx-fade var(--dur-state) var(--ease-standard) both; }

/* ==== status ==== */
.st { display: inline-flex; align-items: center; gap: 7px; font-weight: var(--w-label); }
.st .glyph { width: 15px; height: 15px; }
.st-steady { color: var(--steady); }
.st-regional { color: var(--regional); }
.st-down { color: var(--down); }
.st-unknown { color: var(--unknown); }
.st-planned { color: var(--planned); }
/* the service block: a status as a filled sign, as on a line status board */
.svc { display: inline-flex; align-items: center; gap: 8px; min-height: 36px; padding: 2px 12px 0; font-weight: var(--w-strong); font-size: var(--t-sm); }
.svc .glyph { width: 14px; height: 14px; margin-top: -2px; }
.svc-steady { color: var(--steady); background: var(--steady-bg); }
.svc-regional { color: var(--regional); background: var(--regional-bg); }
.svc-down { color: #fff; background: var(--down); }
.svc-unknown { color: var(--unknown); background: var(--unknown-bg); }
.svc-planned { color: var(--planned); background: var(--planned-bg); }
.svc.is-new { animation: lx-flip var(--dur-enter) var(--ease-enter) both; }
.badge-test { display: inline-flex; align-items: center; min-height: 24px; padding: 2px 8px 0; background: var(--test-bg); color: var(--test);
  font-size: var(--t-xs); font-weight: var(--w-strong); }
/* a tag is a label, never a control: filled, small, no border (a bordered box reads as a button) */
.tag { display: inline-flex; align-items: center; gap: 6px; min-height: 24px; padding: 2px 8px 0; font-size: var(--t-xs); font-weight: var(--w-strong);
  background: var(--paper-3); color: var(--ink-2); }
.tag-built { color: var(--steady); background: var(--steady-bg); }
.tag-planned { color: var(--ink-2); background: var(--paper-3); }
.on-sign .tag, .screen-bar .tag { background: var(--sign-2); color: var(--on-sign-2); }
.count { display: inline-flex; align-items: center; justify-content: center; min-width: 26px; height: 22px; padding: 2px 6px 0; background: var(--ink);
  color: var(--paper); font-size: var(--t-xs); font-weight: var(--w-strong); }

/* ==== notices: a tinted plate with a glyph and a title; never a coloured stripe on one side ==== */
.notice { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; padding: 16px 18px 14px; background: var(--paper-2); }
.notice > .glyph { grid-row: span 2; margin-top: 3px; width: 18px; height: 18px; }
.notice-title { font-weight: var(--w-strong); }
.notice p:not(.notice-title) { color: var(--ink-2); }
/* an information notice is neutral: blue, green, amber-brown and red are status colours */
.notice-info { background: var(--paper); box-shadow: inset 0 0 0 var(--rule-heavy) var(--ink); }
.notice-info > .glyph, .notice-info > .icon { color: var(--ink); }
.notice > .icon { grid-row: span 2; margin-top: 2px; }
.notice-ok { background: var(--steady-bg); }
.notice-ok > .glyph { color: var(--steady); }
.notice-warn { background: var(--regional-bg); }
.notice-warn > .glyph { color: var(--regional); }
.notice-error { background: var(--down-bg); }
.notice-error > .glyph { color: var(--down); }
.notice .actions { grid-column: 2; margin-top: 8px; display: flex; gap: 8px; flex-wrap: wrap; }

/* ==== panels and tables ==== */
.panel { background: var(--paper); }
.panel-head { display: flex; align-items: center; gap: var(--s-3); min-height: 56px; padding: 10px 18px 8px; box-shadow: inset 0 calc(-1 * var(--rule-heavy)) 0 var(--ink); }
.panel-head h2, .panel-head h3 { font-size: var(--t-lg); font-weight: var(--w-strong); letter-spacing: 0; }
.panel-body { padding: 18px; }
.table-wrap { overflow-x: auto; max-width: 100%; }
.table { width: 100%; border-collapse: collapse; background: var(--paper); font-size: var(--t-md); }
.table caption { text-align: left; padding: 0 0 var(--s-3); font-weight: var(--w-strong); font-size: var(--t-lg); }
.table th { text-align: left; vertical-align: bottom; padding: 12px 16px 8px; font-size: var(--t-xs); font-weight: var(--w-strong); color: var(--ink-2);
  border-bottom: var(--rule-heavy) solid var(--ink); }
.table td { padding: 14px 16px 12px; border-bottom: 1px solid var(--rule); vertical-align: top; }
.table tbody th { font-size: var(--t-md); color: var(--ink); font-weight: var(--w-label); border-bottom: 1px solid var(--rule); vertical-align: top; text-align: left; }
.table .r { text-align: right; }
.table tr.is-flagged td { background: #fdf5f4; }

/* ==== disclosure and FAQ: a plus that turns into a minus ==== */
.faq { border-top: var(--rule-heavy) solid var(--ink); }
.faq details { border-bottom: 1px solid var(--rule); }
.faq summary { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); min-height: 64px; padding: 14px 0 10px; cursor: pointer;
  list-style: none; font-weight: var(--w-strong); font-size: var(--t-lg); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: ""; flex: none; width: 18px; height: 18px; background: url("/static/shared/img/v2/plus.svg") center / contain no-repeat;
  transition: transform var(--dur-move) var(--ease-standard); }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq .faq-a { padding: 0 0 var(--s-5); max-width: var(--measure); color: var(--ink); }
.faq details[open] .faq-a { animation: lx-rise var(--dur-state) var(--ease-standard) both; }
.more summary { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; font-weight: var(--w-label); color: var(--link); list-style: none; }
.more summary::-webkit-details-marker { display: none; }
.more summary::before { content: ""; width: 14px; height: 14px; background: url("/static/shared/img/v2/chevron.svg") center / contain no-repeat;
  transform: rotate(-90deg); transition: transform var(--dur-move) var(--ease-standard); }
.more[open] summary::before { transform: none; }

/* ==== breadcrumbs ==== */
.crumbs { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; padding-top: var(--s-6); font-size: var(--t-sm); color: var(--ink-2); }
.crumbs li + li::before { content: "/"; margin-right: 6px; color: var(--ink-3); }
.crumbs a { color: var(--ink-2); }

/* ==== code ==== */
.code { position: relative; margin: var(--s-5) 0; background: var(--paper-2); }
.code pre { margin: 0; padding: 18px 20px; overflow-x: auto; font-size: 0.875rem; line-height: 1.6; tab-size: 2; }
.code-head { display: flex; align-items: center; justify-content: space-between; min-height: 44px; padding: 4px 8px 0 20px; font-size: var(--t-xs);
  font-weight: var(--w-strong); color: var(--ink-2); box-shadow: inset 0 -1px 0 var(--rule); }
.copy-btn { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 2px 10px 0; border: 0; background: none; font: inherit;
  font-weight: var(--w-label); color: var(--link); cursor: pointer; }
.copy-btn:hover { background: var(--paper-3); }
:not(pre) > code { padding: 1px 5px; background: var(--paper-2); font-size: 0.875em; overflow-wrap: anywhere; }
kbd { display: inline-block; min-width: 22px; padding: 1px 6px; text-align: center; background: var(--paper); box-shadow: inset 0 0 0 1px var(--edge), 0 2px 0 var(--edge); font-size: 0.8em; }

/* ==== overlays: dialog, drawer, menu, toast, tooltip. A sign band titles each; the one shadow ==== */
.dialog { width: min(560px, 100% - 32px); padding: 0; border: var(--rule-heavy) solid var(--ink); background: var(--paper); color: var(--ink); box-shadow: var(--lift); }
.dialog::backdrop { background: var(--scrim); }
.dialog[open] { animation: lx-pop var(--dur-enter) var(--ease-enter) both; }
.dialog-head, .drawer-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); min-height: 56px; padding: 6px 8px 4px 20px;
  background: var(--sign); color: var(--on-sign); }
.dialog-head h2, .drawer-head h2 { font-size: var(--t-lg); font-weight: var(--w-strong); letter-spacing: 0; }
.dialog-body { padding: 20px; }
.dialog-foot { display: flex; justify-content: flex-end; gap: var(--s-2); padding: 0 20px 20px; flex-wrap: wrap; }
.close-btn { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border: 0; background: none; color: inherit; cursor: pointer; }
.close-btn:hover { background: var(--sign-2); }
.drawer { position: fixed; inset: 0 0 0 auto; width: min(440px, 100%); height: 100%; max-height: none; margin: 0; padding: 0; border: 0; background: var(--paper);
  color: var(--ink); box-shadow: var(--lift); }
.drawer::backdrop { background: var(--scrim); }
.drawer[open] { animation: lx-drawer var(--dur-enter) var(--ease-enter) both; }
@keyframes lx-drawer { from { opacity: 0; transform: translateX(var(--move-lg)); } }
.drawer-body { padding: 20px; overflow-y: auto; height: calc(100% - 56px); }
.toasts { position: fixed; z-index: 90; right: var(--s-4); bottom: var(--s-4); left: auto; height: 0; display: flex; flex-direction: column; justify-content: flex-end;
  align-items: flex-end; gap: var(--s-2); }
.toast { display: flex; align-items: center; gap: var(--s-3); max-width: min(420px, calc(100vw - 32px)); padding: 12px 8px 10px 16px; background: var(--sign);
  color: var(--on-sign); box-shadow: var(--lift); animation: lx-rise var(--dur-enter) var(--ease-enter) both; }
.toast .lamp-dot { width: 10px; height: 10px; flex: none; border-radius: var(--r-round); background: var(--lamp); }
.toast-close { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; margin-left: auto; border: 0; background: none;
  color: var(--on-sign); cursor: pointer; }
.toast-close:hover { background: var(--sign-2); }
.tooltip { position: absolute; z-index: 80; max-width: 260px; padding: 8px 10px 6px; background: var(--ink); color: var(--paper); font-size: var(--t-xs);
  font-weight: var(--w-label); pointer-events: none; animation: lx-rise var(--dur-state) var(--ease-standard) both; }

/* ==== empty, loading and error states ==== */
.state-empty { display: grid; justify-items: start; gap: var(--s-3); padding: var(--s-7) var(--s-6); background: var(--paper); }
.state-empty h3 { font-size: var(--t-xl); }
.state-empty p { color: var(--ink-2); max-width: 26em; }
.terminus { display: flex; align-items: center; width: 200px; margin-bottom: var(--s-2); }
.terminus::before { content: ""; flex: 1; height: var(--line-w-sm); background: var(--paper-3); }
.terminus::after { content: ""; width: 22px; height: 22px; border: 5px solid var(--ink); border-radius: var(--r-round); background: var(--paper); }
.skeleton { position: relative; overflow: hidden; display: block; height: 14px; background: var(--paper-3); }
.skeleton + .skeleton { margin-top: 10px; }
.skeleton.w-60 { width: 60%; }
.skeleton.w-40 { width: 40%; }
.skeleton::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.7), transparent);
  transform: translateX(-100%); }
:root[data-motion="full"] .skeleton::after { animation: lx-shimmer var(--dur-shimmer) var(--ease-standard) 4; }

/* ==== the line diagram: the system's signature ==========================================================================
   A line with stops, read left to right (or top to bottom on a phone). Each stop draws the stretch of line that leaves it, in the
   colour of what the site was doing on that stretch: ink = up as usual, regional = one region failing, down = both regions agree,
   dashed slate = no data. The stop's shape is its meaning and the words under it say it, so colour is never alone:
   change = hollow square, regional = half ring, down = interchange ring, alert (not down) = ink interchange ring, closed = filled dot,
   planned = diamond. Markup: <ol class="line"> of <li class="stop stop-KIND" data-next="down|regional|gap|none">. */
.line { --n: 4; --line-top: 56px; position: relative; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); list-style: none; margin: 0; padding: 0; }
.stop { position: relative; padding-right: var(--s-5); }
.stop::before { content: ""; position: absolute; z-index: 0; left: calc(var(--stop) / 2); width: 100%; top: calc(var(--line-top) + (var(--stop) - var(--line-w)) / 2);
  height: var(--line-w); background: var(--ink); transform-origin: left; }
.stop:last-child::before { width: calc(100% - var(--stop) / 2); }
.stop[data-next="regional"]::before { background: var(--regional); }
.stop[data-next="down"]::before { background: var(--down); }
.stop[data-next="gap"]::before { background: repeating-linear-gradient(90deg, var(--unknown) 0 14px, transparent 14px 22px); }
.stop[data-next="none"]::before { display: none; }
.stop-time { display: block; height: var(--line-top); font-weight: var(--w-strong); color: var(--ink-2); font-size: var(--t-sm); }
.stop-mark { position: relative; z-index: 1; display: block; width: var(--stop); height: var(--stop); border: 6px solid var(--ink); border-radius: var(--r-round);
  background: var(--ground, var(--paper)); }
.stop-change .stop-mark { border-radius: var(--r-0); transform: scale(0.86); }
.stop-regional .stop-mark { border-color: var(--regional); background: linear-gradient(90deg, var(--ground, var(--paper)) 50%, var(--regional) 50%); }
.stop-down .stop-mark { width: 42px; height: 42px; margin: -6px 0 0 -6px; border-color: var(--down); box-shadow: 0 0 0 5px var(--ground, var(--paper)), 0 0 0 11px var(--down); }
.stop-alert .stop-mark { width: 42px; height: 42px; margin: -6px 0 0 -6px; border-color: var(--ink); box-shadow: 0 0 0 5px var(--ground, var(--paper)), 0 0 0 11px var(--ink); }
.stop-closed .stop-mark { border-color: var(--steady); background: var(--steady); }
.stop-planned .stop-mark { border-color: var(--planned-fill); border-radius: var(--r-0); transform: rotate(45deg) scale(0.78); }
.stop-title { margin-top: 22px; font-size: var(--t-lg); font-weight: var(--w-strong); line-height: 1.2; }
.stop-text { margin-top: 4px; color: var(--ink-2); max-width: 14em; }
.stop-down .stop-title { color: var(--down); }
.band-fog, .strip { --ground: var(--paper-2); }
.here { position: absolute; z-index: 2; left: -8px; top: -34px; display: inline-flex; align-items: center; gap: 8px; padding: 5px 10px 3px; background: var(--sign);
  color: var(--on-sign); font-size: var(--t-xs); font-weight: var(--w-strong); white-space: nowrap; }
.here::before { content: ""; width: 9px; height: 9px; border-radius: var(--r-round); background: var(--lamp); box-shadow: 0 0 0 4px rgba(245, 196, 81, 0.25); }
/* the vertical line: phones, the incident page, the sign-up journey */
.line-v { --n: 1; grid-template-columns: minmax(0, 1fr); gap: var(--s-5); padding-left: 60px; }
.line-v .stop { padding-right: 0; min-height: 56px; }
.line-v .stop::before { left: calc(-31px - var(--line-w) / 2); top: 11px; width: var(--line-w); height: calc(100% + var(--s-5)); transform-origin: top; }
.line-v .stop:last-child::before { display: none; }
.line-v .stop[data-next="gap"]::before { background: repeating-linear-gradient(180deg, var(--unknown) 0 14px, transparent 14px 22px); }
.line-v .stop-time { height: auto; }
.line-v .stop-mark { position: absolute; left: -46px; top: -4px; }
.line-v .stop-down .stop-mark, .line-v .stop-alert .stop-mark { left: -52px; top: -10px; margin: 0; }
.line-v .stop-title { margin-top: 2px; }
.line-v .here { position: relative; left: 0; top: 0; margin-bottom: 8px; }
/* the scene: drawn once, stop by stop (Calm keeps the fades and drops the travel; Off and reduced motion show the end at once) */
.line.is-drawn .stop::before { animation: lx-draw var(--dur-scene) var(--ease-enter) both; animation-delay: calc(var(--stagger) * (var(--i, 0) * 3 + 1)); }
.line-v.is-drawn .stop::before { animation-name: lx-draw-y; }
.line.is-drawn .stop-mark { animation: lx-stop var(--dur-enter) var(--ease-enter) both; animation-delay: calc(var(--stagger) * var(--i, 0) * 3); }
.line.is-drawn .stop-time, .line.is-drawn .stop-title, .line.is-drawn .stop-text { animation: lx-rise var(--dur-enter) var(--ease-enter) both;
  animation-delay: calc(var(--stagger) * (var(--i, 0) * 3 + 1)); }
.line.is-drawn .here { animation: lx-drop var(--dur-enter) var(--ease-enter) both; animation-delay: calc(var(--stagger) * 9); }
.line > .stop:nth-child(1) { --i: 0; } .line > .stop:nth-child(2) { --i: 1; } .line > .stop:nth-child(3) { --i: 2; }
.line > .stop:nth-child(4) { --i: 3; } .line > .stop:nth-child(5) { --i: 4; } .line > .stop:nth-child(6) { --i: 5; }
/* a journey that fills as it is read: each stretch turns from pale to ink once its stop has been passed */
.line-fill .stop::before { background: var(--paper-3); }
.line-fill .stop::after { content: ""; position: absolute; z-index: 0; left: calc(-31px - var(--line-w) / 2); top: 11px; width: var(--line-w); height: calc(100% + var(--s-5));
  background: var(--ink); transform: scaleY(var(--fill, 1)); transform-origin: top; transition: transform var(--dur-scene) var(--ease-standard); }
.line-fill .stop:last-child::after { display: none; }
.js .line-fill.is-armed .stop:not(.is-passed) { --fill: 0; }

/* two tracks: what each region saw, one square per check (the last 24 by default) */
.tracks { display: grid; gap: 4px; min-width: 0; }
.track { display: grid; grid-template-columns: 34px repeat(var(--checks, 24), minmax(0, 1fr)); gap: 2px; align-items: center; font-size: var(--t-xs);
  font-weight: var(--w-strong); color: var(--ink-2); }
.track i { display: block; height: 10px; background: var(--steady); }
.track i.x { background: var(--down); }
.track i.n { background: repeating-linear-gradient(135deg, var(--unknown) 0 2px, transparent 2px 4px); }
.track i.m { background: var(--planned-fill); }

/* review fixes (design review, 2026-10-29) */
.close-btn, .toast-close { font: inherit; }
.copy-btn { min-height: 40px; }
@media (pointer: coarse) { .copy-btn { min-height: 44px; } }
.input:disabled, .select:disabled, .textarea:disabled { background: var(--paper-2); color: var(--ink-2); border-color: var(--rule); cursor: not-allowed; }
@media (pointer: coarse) { .btn-sm, .seg-opt, .scenario { min-height: 44px; } }
