/* The single source of every colour, spacing and typeface in this app.
   No other file may carry a colour literal — tests/contract/test_design_tokens.py
   enforces that, and also checks that every token used somewhere is declared
   here. A `var(--typo)` that resolves to nothing is not an error in CSS: the
   property silently falls back to its initial value, so a padding vanishes or
   a status turns black with nothing anywhere to say why. */
:root {
  /* ── Paper ──────────────────────────────────────────────────────────────
     --paper is the page, --surface is anything raised off it, --sunken is the
     one step below the page: a column header, a hovered row. Three values and
     no more — a ladder of neutral tints is how a background starts competing
     with the four colours that carry a verdict. */
  --paper: #f0f3f8;
  --surface: #ffffff;
  --sunken: #e7ecf4;
  --rule: #cdd3dc;
  /* The rule *inside* a panel: between a header and its body, between two rows
     of one list. Lighter than --rule so the panel's own edge stays the
     strongest line on screen, and the page keeps a hierarchy of boundaries
     instead of one uniform grid. */
  --rule-faint: #e2e7ee;

  /* ── Chrome ─────────────────────────────────────────────────────────────
     The one dark surface in the app: the top bar, and the field the sign-in
     page floats on. It is the cover of the register — it carries identity,
     navigation and the pulse of the queue, and never a figure or a verdict.
     That restriction is what lets it be dark at all: no status colour has to
     stay readable against it, because no status is ever printed on it.
     Anything up there that does carry a status sits on a --surface pill. */
  --chrome: #0f1a2e;
  --chrome-deep: #0a1220;
  --chrome-rule: rgba(255, 255, 255, 0.1);
  --chrome-hover: rgba(255, 255, 255, 0.07);
  /* Text on the chrome. Exempt from the sweep against --paper / --surface —
     neither is ever printed on paper — and declared in the test's
     INVERSE_PAIRS so both are checked against the field they land on:
     15.6:1 and 5.6:1 on --chrome. */
  --on-chrome: #eef2f8;
  --on-chrome-muted: #8593a8;
  /* The accent, lightened for the dark field. --accent itself reaches only
     2.7:1 on --chrome: legible as a shape, not as a mark of state. This is
     the same identity at a luminance the cover can carry — 7.8:1. */
  --accent-on-chrome: #b9a3e8;

  /* ── Ink ────────────────────────────────────────────────────────────────
     Both clear 4.5:1 on --paper and on --surface. */
  --ink: #131f36;
  --muted: #5a6577;

  /* ── Accent ─────────────────────────────────────────────────────────────
     Constrained by spec §13: it may not occupy any status hue, and navy is
     already taken by the ink. Violet sits >100 degrees from every status hue,
     so a decoration can never be mistaken for a signal.
     --accent clears 4.5:1 on both surfaces; --accent-text clears 7:1 and is
     the variant for small or dense text. --on-accent is the inverse pairing
     on paper: white on --accent, 6.5:1. --accent-wash is a background only,
     and holds --accent-text at 7.4:1. */
  --accent: #6d4aad;
  --accent-text: #553a8b;
  --accent-wash: #ede8f7;
  --on-accent: #ffffff;
  /* The expanding ring of the queue pulse. Not a hex, so the contrast checks
     skip it, which is correct: nothing is ever read against it. */
  --accent-halo: rgba(109, 74, 173, 0.4);

  /* ── Status ─────────────────────────────────────────────────────────────
     The four statuses a metric can carry. Named after the vocabulary, never
     after the colour, so a palette change never means renaming a state.
     Each one is used as text, so each one clears 4.5:1 on both surfaces —
     including --status-na. A "no data" the user cannot read is exactly the
     failure this app exists to prevent: absent must look absent, not blank. */
  --status-met: #1f7a4d;
  --status-borderline: #96590a;
  --status-broken: #b3261e;
  --status-na: #5f6a7d;

  /* The washes carry a verdict as a field rather than as a letter: the chip on
     a card, the status cell in the queue. Deliberately *not* named
     `--status-*-wash` — the four statuses are enumerated by that prefix in
     test_design_tokens.py, and a fifth `--status-` token would make the
     enumeration say five. Each is a background only, and each holds its own
     status colour above 4.5:1: 4.62, 4.89, 5.57 and 4.70 in order. */
  --wash-met: #e6f2ea;
  --wash-borderline: #f7eedd;
  --wash-broken: #fbe9e7;
  --wash-na: #ebeef3;

  /* ── Type ───────────────────────────────────────────────────────────────
     Three voices, three jobs. Mono is not a style here: it is what makes two
     figures line up digit under digit so they can be compared by eye.

     Self-hosted, latin subset, declared in fonts.css. The display face is
     used at 1.06rem and above and never below: Cormorant is a high-contrast
     garamond whose hairlines disappear at label size. Everything small — panel
     headers, buttons, chips — is the sans, and a ruled column header takes its
     authority from uppercase and tracking rather than from a serif set too
     small to show it has one. */
  --font-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --font-sans: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* A fixed rem scale, not a fluid one. This is a task surface, read at a desk
     and in the hand at a consistent DPI; a heading that shrinks with the
     viewport buys nothing and costs the vertical rhythm. The ratio is ~1.13,
     tight on purpose: there are many type roles on a register and an
     exaggerated scale turns density into noise. */
  --text-2xs: 0.72rem;
  --text-xs: 0.79rem;
  --text-sm: 0.86rem;
  --text-base: 0.94rem;
  --text-lg: 1.06rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;

  /* Positive tracking on the uppercase micro-labels, where caps need air to
     stay legible; slightly negative on the display face, which sets loose by
     default. Never past -0.04em. */
  --track-caps: 0.08em;
  --track-display: -0.01em;

  /* ── Space ──────────────────────────────────────────────────────────────
     Two steps, and the halves were being written as a bare 4px in fourteen
     places — a scale nobody can change in one edit is not a scale. */
  --space: 8px;
  --space-half: 4px;

  /* Radii. 6px on small controls, 12px on anything that is a panel. A card and
     a chip sharing one radius is how a page stops saying which is which. */
  --radius: 6px;
  --radius-panel: 12px;
  --radius-pill: 999px;

  /* The gap between panels — the whole vertical rhythm of a page, in one
     place, applied by the stack rather than by each panel's own margin. */
  --gap-panel: 16px;
  /* The top bar's floor. A floor and not a height: under 46rem the bar wraps
     its search field onto a second line, and a fixed height would clip it. */
  --topbar-height: 56px;

  /* ── Depth ──────────────────────────────────────────────────────────────
     "Flat at rest, the shadow is a reply": a shadow belongs on what answers a
     gesture — the modal, an open trace — never on an inert card. Neither is a
     hex, so the contrast checks skip them, which is correct: nothing is ever
     read against a shadow. */
  --shadow: rgba(19, 31, 54, 0.18);
  --shadow-deep: rgba(10, 18, 32, 0.35);
  /* The backdrop under the modal. Heavier than the shadow because the page it
     covers is white panels on near-white paper: at the shadow's opacity the
     dialog read as one more panel instead of a layer above them. */
  --overlay: rgba(10, 18, 32, 0.55);

  /* ── Motion ─────────────────────────────────────────────────────────────
     Two durations, one curve. The user is inside a task: a transition long
     enough to watch is a transition in the way. Everything decays from an
     already-visible default — nothing on this screen animates its way in. */
  --ease: cubic-bezier(0.2, 0.8, 0.3, 1);
  --fast: 120ms;
  --base: 180ms;

  /* ── Elevation ──────────────────────────────────────────────────────────
     Two tiers, declared rather than sprinkled: the bar the page scrolls under,
     and the panel that answers a click. */
  --z-chrome: 40;
  --z-reply: 60;
}
