/* ═══════════════════════════════════════════════════════════════════════════
   Keel — design tokens. THE canonical source. There is no second copy.
   ═══════════════════════════════════════════════════════════════════════════

   Every Keel surface reads these: the report artifact (inlined by render.ts),
   the marketing site, the agents page, and the governance docs. `site/` gets a
   byte-identical copy written by `make site-tokens`; `make design-audit`
   executes a diff and exits non-zero if it has drifted. That check is anchored
   under Keel's own definition — the signal is a diff exit code, not an
   assertion this repo also writes.

   WHY ONE FILE AND NOT FIVE. Systems this size usually split color/type/space
   into separate files behind an @import entry point. Keel cannot: the report
   must open from file:// with zero external requests, so `render.ts` inlines
   this text verbatim into a <style> block. One file is one read. The section
   rules below carry the structure the file split would have carried.

   NAMESPACE. Every token is `--k-*`. Keel's output gets embedded in other
   people's pages and pasted into other people's docs; an unprefixed `--accent`
   would collide and silently restyle someone else's surface.
   ─────────────────────────────────────────────────────────────────────────── */

:root {
  /* ═══ CANVAS ══════════════════════════════════════════════════════════════
     Dark, because Keel is an instrument, not a document. Elevation is
     expressed as a background step plus a hairline — never a shadow. On a
     #07090c canvas a shadow is a smudge: it costs paint and reads as nothing.
     ─────────────────────────────────────────────────────────────────────── */
  --k-bg-0: #07090c;          /* page */
  --k-bg-1: #0c1015;          /* raised: cards, code blocks, table headers */
  --k-bg-2: #11161d;          /* nested / hover */
  --k-bg-3: #171d26;          /* active / selected row */

  --k-line: #1b2027;          /* hairline — the default separator */
  --k-line-strong: #2a323c;   /* emphasis rule, focused input */

  /* ═══ INK ═════════════════════════════════════════════════════════════════
     Four steps. --k-ink-3 is BELOW the 4.5:1 text threshold on --k-bg-0 by
     design; it is for borders, disabled glyphs, and decorative rules. Never
     set body copy in it. The other three clear 4.5:1 on bg-0 and bg-1.
     ─────────────────────────────────────────────────────────────────────── */
  --k-ink-0: #e8edf2;         /* primary text        ~16:1 on bg-0 */
  --k-ink-1: #b6c0cb;         /* secondary text      ~10:1 */
  --k-ink-2: #8b97a5;         /* tertiary / meta      ~6:1 */
  --k-ink-3: #5b6774;         /* NON-TEXT ONLY        ~2.6:1 */

  /* ═══ KEEL'S OWN VOICE ════════════════════════════════════════════════════
     One accent, used surgically: links, the emphasized clause in a headline,
     Keel's own annotations. It is a HUE RESERVED FOR THE NARRATOR — it never
     encodes a verdict, and no verdict color is ever used for chrome. Mixing
     the two is how a tool starts congratulating itself in green.
     ─────────────────────────────────────────────────────────────────────── */
  --k-accent: #7dd3fc;
  --k-accent-hover: #b6e6ff;
  --k-accent-line: rgba(125, 211, 252, 0.30);   /* link underline at rest */
  --k-accent-wash: rgba(125, 211, 252, 0.10);   /* callout fill */

  /* ═══ VERDICTS ════════════════════════════════════════════════════════════
     Exactly four, matching `GroundingClass` in schemas/keel.ts. The schema is
     frozen; so is this list. Adding a fifth swatch here without a schema
     change means someone is inventing a class in CSS.

       anchored          the producer is outside the write boundary
       self_referential  it is inside
       unknown           the fork point could not be traced — FAILS CLOSED
       not_a_check       asserts nothing; excluded from the denominator

     `not_a_check` is deliberately the least attractive swatch in the file. It
     is the one shoppable class — misfiling a real check there shrinks the
     denominator and inflates the score — so it gets inert slate and, per
     `.k-verdict`, a dashed border rather than a solid one. It should never
     look like a place you want your nodes to land.
     ─────────────────────────────────────────────────────────────────────── */
  --k-anchored: #4ade80;
  --k-self-referential: #f87171;
  --k-unknown: #fbbf24;
  --k-not-a-check: #94a3b8;

  /* Tints for chip fills and graph marks. Kept as explicit rgba rather than
     color-mix() so the report renders identically in older embedded viewers
     (email clients, IDE previews) that never see a modern engine. */
  --k-anchored-wash: rgba(74, 222, 128, 0.10);
  --k-self-referential-wash: rgba(248, 113, 113, 0.10);
  --k-unknown-wash: rgba(251, 191, 36, 0.10);
  --k-not-a-check-wash: rgba(148, 163, 184, 0.08);

  /* Confidence smell — an `anchored` verdict asserted with confidence < 0.5.
     Aliased to --k-unknown on purpose: the visual claim is "this is closer to
     unknown than its color suggests". A separate hue would imply a fifth
     class, and there is no fifth class. */
  --k-smell: var(--k-unknown);

  /* ═══ TYPE ════════════════════════════════════════════════════════════════
     NO WEBFONTS. Not a preference — an invariant. The report must open from
     file://, survive being emailed, and issue zero external requests, which
     rules out every hosted face. System stacks are the honest answer; a
     bundled base64 face would add ~80KB to an artifact whose whole argument
     is that it depends on nothing.

     The two families carry a PROVENANCE distinction, and this is the rule
     most worth keeping: MONO IS QUOTED FROM THE WORLD, SANS IS KEEL TALKING.
     Node names, file paths, commands, exit codes, class names, hashes — mono,
     because Keel did not write them. Prose, headings, arguments, and
     annotations — sans, because Keel did. A reader can tell claim from
     evidence at a glance without reading a word.
     ─────────────────────────────────────────────────────────────────────── */
  --k-font-sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI",
                 Inter, system-ui, sans-serif;
  --k-font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo,
                 "Cascadia Mono", Consolas, monospace;

  --k-fs-ratio: clamp(64px, 13vw, 128px);   /* the grounding ratio, and only it */
  --k-fs-display: clamp(30px, 5.2vw, 46px); /* page hero */
  --k-fs-h1: 24px;
  --k-fs-h2: 19px;
  --k-fs-h3: 16px;
  --k-fs-lede: 19px;
  --k-fs-body: 16px;
  --k-fs-ui: 15px;                          /* dense report UI */
  --k-fs-sm: 14px;
  --k-fs-xs: 12.5px;
  --k-fs-micro: 11px;                       /* eyebrows, table headers */

  --k-lh-ratio: 0.9;
  --k-lh-tight: 1.18;
  --k-lh-snug: 1.35;
  --k-lh-body: 1.65;

  /* Three weights. There is no 700: on a near-black canvas heavy strokes
     bloom, and the halation costs more legibility than the emphasis buys. */
  --k-fw-regular: 400;
  --k-fw-medium: 500;
  --k-fw-semibold: 600;

  --k-track-ratio: -0.045em;
  --k-track-display: -0.022em;
  --k-track-tight: -0.01em;
  --k-track-normal: 0;
  --k-track-eyebrow: 0.18em;   /* uppercase section labels */
  --k-track-brand: 0.22em;     /* the wordmark only */

  /* ═══ SPACE ═══════════════════════════════════════════════════════════════
     4px grid. Measures are capped tight: a verdict list read at 1400px wide
     loses the row it started on, and this artifact is read row by row.
     ─────────────────────────────────────────────────────────────────────── */
  --k-space-0: 0;
  --k-space-1: 4px;
  --k-space-2: 8px;
  --k-space-3: 12px;
  --k-space-4: 16px;
  --k-space-5: 20px;
  --k-space-6: 24px;
  --k-space-8: 32px;
  --k-space-10: 40px;
  --k-space-12: 48px;
  --k-space-16: 64px;
  --k-space-20: 80px;
  --k-space-24: 96px;

  --k-measure-read: 760px;     /* prose column — site, docs */
  --k-measure-report: 1080px;  /* report shell: graph + verdict table */
  --k-measure-prose: 62ch;     /* lede / paragraph wrap */

  /* ═══ RADIUS ══════════════════════════════════════════════════════════════
     Small. Keel's surfaces are cells, rows, and records — the vocabulary of a
     ledger. Generous rounding reads as consumer-soft and undersells that the
     numbers on screen are accounting, not a dashboard.
     ─────────────────────────────────────────────────────────────────────── */
  --k-r-xs: 3px;
  --k-r-sm: 4px;
  --k-r-md: 6px;
  --k-r-lg: 8px;
  --k-r-xl: 12px;
  --k-r-pill: 999px;           /* tags and class chips only */

  /* ═══ MOTION ══════════════════════════════════════════════════════════════
     Fast and flat. Instruments settle; they do not perform. No overshoot, no
     bounce, nothing above 200ms. Motion here exists to preserve object
     continuity across a state change, never to draw attention to one.
     ─────────────────────────────────────────────────────────────────────── */
  --k-ease: cubic-bezier(0.2, 0, 0.38, 1);
  --k-dur-fast: 90ms;
  --k-dur-base: 160ms;

  /* ═══ GRAPH MARKS ═════════════════════════════════════════════════════════
     The node graph is one mark per node. SQUARES, not circles: a circle in a
     verification UI reads as a status dot, and a status dot is exactly the
     unaccountable green light Keel exists to criticize. A square reads as a
     cell in a ledger. Sized to stay legible at 200 nodes.
     ─────────────────────────────────────────────────────────────────────── */
  --k-mark: 10px;
  --k-mark-gap: 3px;
  --k-mark-r: 2px;
  --k-mark-stroke: 1.5px;      /* smell ring on an anchored mark */

  /* ═══ FOCUS ═══════════════════════════════════════════════════════════════
     Two-stop ring: a bg-colored inset so the accent never touches the element
     edge, then the accent. Visible on every surface step without a per-context
     override. */
  --k-focus-ring: 0 0 0 2px var(--k-bg-0), 0 0 0 4px var(--k-accent);
}
