/* ============================================================================
   chambers · design tokens
   Single source of truth. The running app imports this file directly.
   Declared in DESIGN.md frontmatter as `tokens-css: static/css/tokens.css`.

   Register:  Hearth  — warm, soft edges, generous leading, unhurried
   Dark:      Flint   — cool ground, clay as the only warm element
   Light:     Slate   — deeper cool ground, clay darkened to hold contrast

   THE ACCENT RULE. `--accent` (aliased `--self`) means *the authenticated
   viewer*: their name, their messages, their actions, and anything addressed
   to them. Nowhere else. It is per-viewer, not per-product — chambers has no
   signature colour. See DESIGN.md § Colour Usage before spending it.

   Theme: dark is the default. `:root[data-theme="light"]` and the
   prefers-color-scheme fallback both switch to Slate. Stamp the attribute on
   <html> before first paint or the theme flashes.

   DEVICE CLASSES. Three genuine design targets, not one desktop layout with
   ad hoc mobile patches. See DESIGN.md § Device Classes and
   DEC-BS-2026-08-13-160000. CSS custom properties can't be read inside a
   media query condition, so these breakpoints are NOT tokens — they are
   literal values, and this comment is their single documented source of
   truth. Every @media rule in this file and in the app's own CSS must use
   these exact numbers, not a nearby approximation:

     phone   : max-width: 719px   — touch-primary, roster-trigger layout
     tablet  : 720px – 1023px     — touch-primary, desktop roster layout
     desktop : min-width: 1024px  — pointer-primary, desktop roster layout

   Touch-primary (phone + tablet) also means --tap-target-min applies to
   every interactive element, not just phone's compact ones.
   ========================================================================= */

/* ─────────────────────────── DARK · Flint (default) ─────────────────────── */
:root {
  color-scheme: dark;

  /* Surface scale — family names mirrored from open-brain */
  --bg:            #131417;   /* the chamber ground */
  --bg-surface:    #1c1e22;   /* roster, top bar, composer, neutral bubbles */
  --bg-chip:       #23262b;   /* the arbiter cue and other neutral chips */

  /* Text scale */
  --text:           #e6e8ec;
  --text-secondary: #99a0a8;
  --text-muted:     #7b828a;

  /* Rules */
  --border: #2b2e34;

  /* Accent — SELF ONLY. See the accent rule above. */
  --accent:         #e08558;
  --accent-surface: #2e2723;  /* your own bubble's tinted ground */
  --accent-border:  #3d322b;  /* your own bubble's hairline */
  --on-accent:      #131417;  /* text/glyphs sitting on --accent (Send) */

  /* Addressed-to-you — a clay-tinted border on an otherwise neutral bubble.
     Deliberately dimmer than --accent-border so "about you" never reads as
     "by you". */
  --accent-border-soft: #37302c;

  /* Semantic — ONE reserved red, genuine failure only.
     Unreachable agents, stopped chains and procedural notices are neutral +
     a text label. They are conditions and correct behaviour, not failures. */
  --fail:         #e2596b;
  --fail-surface: #2b1b1f;
  --fail-border:  #4b2a31;
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #131417; --bg-surface: #1c1e22; --bg-chip: #23262b;
  --text: #e6e8ec; --text-secondary: #99a0a8; --text-muted: #7b828a;
  --border: #2b2e34;
  --accent: #e08558; --accent-surface: #2e2723; --accent-border: #3d322b;
  --on-accent: #131417; --accent-border-soft: #37302c;
  --fail: #e2596b; --fail-surface: #2b1b1f; --fail-border: #4b2a31;
}

/* ─────────────────────────── LIGHT · Slate ──────────────────────────────── */
/* Slate's ground is deliberately deeper than a near-white page: in light,
   message bubbles have to read *lighter* than the ground, and a near-white
   page leaves nowhere to go. */

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --bg: #e4e8ec; --bg-surface: #f4f6f8; --bg-chip: #d8dee4;
    --text: #161a1e; --text-secondary: #525c66; --text-muted: #7d8791;
    --border: #cfd6dd;
    --accent: #b4593a; --accent-surface: #f6ece4; --accent-border: #e3c3ab;
    --on-accent: #f4f6f8;
    --accent-border-soft: #e3c3ab;    /* deliberately IDENTICAL to --accent-border — see note below */
    --fail: #b3384c; --fail-surface: #fbeef0; --fail-border: #eecbd1;
  }
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg: #e4e8ec; --bg-surface: #f4f6f8; --bg-chip: #d8dee4;
  --text: #161a1e; --text-secondary: #525c66; --text-muted: #7d8791;
  --border: #cfd6dd;
  --accent: #b4593a; --accent-surface: #f6ece4; --accent-border: #e3c3ab;
  --on-accent: #f4f6f8;
  --accent-border-soft: #e3c3ab;      /* deliberately IDENTICAL to --accent-border */
  --fail: #b3384c; --fail-surface: #fbeef0; --fail-border: #eecbd1;
}

/* WHY --accent-border-soft COLLAPSES IN LIGHT (settled 2026-08-06).
   In Flint the two borders differ: "addressed to you" is dimmer than "by
   you", and on a dark ground dimmer means closer to the background, which
   reads as quieter. That arithmetic does not transfer. On a light ground,
   lightening a border pushes it into the surface and it disappears, so
   copying Flint's numbers would have produced a border that says nothing.

   The resolution is not a third colour. The "about you / by you" hierarchy
   is already carried by the tinted *background*, which only your own bubble
   has — a stronger and more squint-proof signal than a hairline. So light
   uses one border value and lets the background do the work.

   The token is kept rather than deleted because the markup still needs to
   name the state (.m.tome), and dark still distinguishes. Do not "fix" this
   coincidence by inventing a light-specific value: it was tested against
   three alternatives in design/explorations/2026-08-06_slate-addressed-to-you.html
   and chosen deliberately. */

/* ─────────────────────────── Theme-independent ──────────────────────────── */
:root {
  /* Semantic alias. Prefer --self in chamber markup: it states the rule at
     the point of use, so a stray `color: var(--self)` on an agent's name
     reads as obviously wrong during review. */
  --self:         var(--accent);
  --self-surface: var(--accent-surface);
  --self-border:  var(--accent-border);
  --self-border-soft: var(--accent-border-soft);

  /* ── Type ──────────────────────────────────────────────────────────────
     Hearth is a single-family register. There is no display/body split —
     the softness comes from the rounded face, the leading and the radii,
     not from a second typeface. */
  --font-ui:   ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont,
               "Segoe UI", system-ui, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Scale — nothing below 12px, anywhere. See DESIGN.md § Legibility Floor. */
  --size-chamber:  17px;  /* chamber name in the top bar */
  --size-message:  15px;  /* message body, composer field */
  --size-name:     14px;  /* participant names, Send */
  --size-meta:     12px;  /* speaker line, roster meta, roles, cues, labels */
  --size-mono:     13px;  /* inline code and IDs inside a message */

  --lh-message: 1.65;     /* generous — the register's main carrier */
  --lh-meta:    1.45;

  --track-label:   0.1em;  /* tracked uppercase roster labels */
  --track-chamber: -0.01em;

  --weight-name: 600;

  /* ── Radii ─────────────────────────────────────────────────────────────
     Soft, not walled. Boundaries are tonal before they are ruled. */
  --radius-panel:  16px;  /* the chamber shell */
  --radius-bubble: 12px;  /* message bubbles, composer field, Send */
  --radius-chip:   10px;  /* arbiter cue, tags */
  --radius-row:    12px;  /* roster rows */

  /* ── Spacing — 4px base ────────────────────────────────────────────────── */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* ── Layout ────────────────────────────────────────────────────────────── */
  --roster-width:  220px;
  --message-measure: 64%;   /* max bubble width; the turn boundary needs slack */

  /* ── Touch ─────────────────────────────────────────────────────────────
     44px (Apple HIG minimum; comfortably covers Android's 48dp guidance
     too). Applies to every interactive element on the phone and tablet
     device classes — see DESIGN.md § Device Classes. Desktop is
     pointer-primary and is not held to this floor, though nothing stops a
     control from meeting it anyway.
     A visually small control (a text link, an icon button) should reach
     this via invisible hit-slop on a `::before`, not by growing the label —
     see design/concepts/2026-08-13_chamber-mobile-roster-strip.html for
     the pattern. A control that's meant to read as a tappable chip/button
     can just grow to this size directly. */
  --tap-target-min: 44px;

  /* ── Motion ────────────────────────────────────────────────────────────── */
  --tx-fast: 120ms cubic-bezier(.2,.6,.2,1);
  --tx-base: 180ms cubic-bezier(.2,.6,.2,1);
  --tx-slow: 280ms cubic-bezier(.2,.6,.2,1);
}

@media (prefers-reduced-motion: reduce) {
  :root { --tx-fast: 0ms; --tx-base: 0ms; --tx-slow: 0ms; }
}
