/* ============================================================================
 * DESIGN TOKENS — the single source of truth for the control plane.
 * ----------------------------------------------------------------------------
 * Loaded FIRST on every page. Everything else consumes these; no other
 * stylesheet declares a :root block. Same discipline as the tenant app's
 * tokens.css, which is where this vocabulary comes from.
 *
 * ── WHY STEW'S ACCENT IS NOT THE WIT'S END RED ──────────────────────────────
 *
 * Two reasons, and the second is the load-bearing one.
 *
 * 1. Wit's End red (#c8321a) is a CLIENT's brand. Stew is the company that runs
 *    the platform, and a control plane wearing one client's colours is wrong the
 *    day the second client logs in. The tenant repo's test_tenant_isolation.py
 *    exists to stop that leaking the other way; this is the same principle
 *    pointed at ourselves.
 *
 * 2. GREEN, AMBER AND RED ARE TAKEN. MULTITENANT_SCOPE §7 assigns all three to
 *    the client health model, where they carry the only meaning on the screen
 *    that an operator acts on. Data-Views §0.4 allows exactly one accent, and if
 *    that accent were red, "brand red" and "this club is down" would be the same
 *    colour. The accent therefore has to sit outside the status triad entirely.
 *
 * Violet is the choice: distinct from all three lights, distinct from both
 * clubs, and it reads as tooling rather than as a venue. White on #6E56CF is
 * 5.39:1 — AA for body text, not just for large type.
 *
 * Every ratio in this file is COMPUTED, not estimated. scripts/contrast_audit.py
 * recomputes them and tests/test_contrast.py fails the build on a regression.
 * The 5.39 above was written as "5.6" from eyeballing until the audit was
 * actually run — which is the whole argument for having the audit.
 * ============================================================================ */

:root{
  --color-scheme:dark;
  color-scheme:var(--color-scheme);

  /* ── BRAND ── Stew's own. The only group a re-brand would touch. ────────── */
  --accent:#6E56CF;              /* fills: primary button, selected row bar */
  --accent-rgb:110,86,207;
  --accent-text:#A594F9;         /* accent-coloured TEXT on a dark surface.
                                    #6E56CF as text on --bg is 3.4:1 — fine for
                                    a 20px+ heading, fails for a 13px label. The
                                    fill and the text are different problems and
                                    need different values. */
  --accent-deep:#5A45B0;         /* pressed state */

  /* Type. A system stack, deliberately: the CSP in core/security.py blocks
     every external font host, and bundling a webfont to save 40ms of layout on
     an internal tool nobody's customer sees is not a trade worth making.
     UX_PRINCIPLES §12 — real speed over the appearance of polish. */
  --font-body:ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,
              'Helvetica Neue',Arial,sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,'SF Mono',Menlo,Consolas,monospace;
  --font:var(--font-body);

  /* ── SURFACES ── structural, shared, not brand. ─────────────────────────── */
  --bg:#0a0a0a;
  --surface:#111;
  --surface2:#161616;
  --surface-3:#1a1a1a;
  --surface-4:#222;
  --chrome-solid:#000;

  /* ── INK ── text and borders are one substance at different strengths. ──── */
  --ink-rgb:255,255,255;
  --text:#fff;
  --text-soft:rgba(255,255,255,.6);
  --muted:rgba(255,255,255,.48);
  --placeholder:rgba(255,255,255,.48);
  /* DECORATIVE ONLY — 1.97:1 on --surface, which is not readable text and is
     not meant to be. It was on four real text surfaces (the signed-in email,
     the "optional" field marker, the error code, the poll timings) until the
     contrast audit found them; all four now use --muted. If you are about to
     put --dim on something a person has to read, use --muted (4.52:1). */
  --dim:rgba(255,255,255,.22);
  --text-faint:rgba(255,255,255,.2);

  --border:rgba(255,255,255,.08);
  --border-mid:rgba(255,255,255,.15);
  --border-emph:rgba(255,255,255,.3);
  --border-input:rgba(255,255,255,.1);

  /* ── STATE / HEALTH ── these three mean the client health model and
   * NOTHING ELSE. Never decorate with them. A green that means "nice" and a
   * green that means "this club is fine" cannot coexist on one screen —
   * the second stops being read. (Data-Views §0.4, MULTITENANT_SCOPE §7) */
  --green:#22c55e;   --green-rgb:34,197,94;
  --amber:#f59e0b;   --amber-rgb:245,158,11;
  --danger:#f87171;  --danger-rgb:248,113,113;

  /* The fourth light. "Not reporting" is NOT amber — an operator must be able
     to tell "this club has a problem" from "I cannot see this club", because
     the actions are completely different. Grey-blue, deliberately quiet:
     unknown should read as absence, not as alarm. */
  --unknown:#8b95a8; --unknown-rgb:139,149,168;

  --blue:#60a5fa;    --blue-rgb:96,165,250;

  /* ── ELEVATION ── tints, never ink. ─────────────────────────────────────── */
  --tint-rgb:255,255,255;
  --surface-tint:rgba(255,255,255,.05);
  --state-hover:rgba(255,255,255,.06);
  --state-selected:rgba(255,255,255,.1);
  --bg-input:rgba(255,255,255,.06);

  --shadow-rgb:0,0,0;
  --elev-lift:0 2px 4px rgba(0,0,0,.40), 0 8px 18px rgba(0,0,0,.34);

  /* Text on an accent or state fill. A contrast guarantee, not a theme value. */
  --on-accent:#fff;

  /* ── SHAPE ── */
  --radius-sm:4px;
  --radius-md:6px;
  --radius-lg:10px;
  --radius-pill:999px;

  /* ── LAYOUT ── published so CSS and JS cannot disagree about them.
   * UX_PRINCIPLES §18: "Measure the header; never hardcode its height." The
   * control plane's chrome is fixed-height by construction (no tenant logo to
   * change it), so a token is honest here where a constant would not be in the
   * tenant app — but it stays a token so scroll maths reads one value. */
  --sidebar-w:224px;
  --list-w:360px;          /* master list — Data-Views §4: 320–380px */
  --topbar-h:56px;         /* phone only */
  --page-max:1400px;

  /* The <select> chevron. A colour baked into a data: URI is the one place no
     variable can reach, so the whole url() is the token. */
  --select-chevron:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' stroke='rgba(255,255,255,0.5)' stroke-width='1.4' fill='none' stroke-linecap='round'/></svg>");
}
