/* ==========================================================================
   design-system.css — DESIGN TOKENS ONLY
   --------------------------------------------------------------------------
   The "Night Service" token system (DESIGN-LESSONS R01), dual-slot from day
   one: :root carries the dark (default) theme; [data-theme="light"] carries
   the derived light overrides. Do not add component styles here.

   This file is the ONLY place in the codebase where a raw COLOUR literal may
   appear — that rule is absolute, and a test enforces it. Every other rule, in
   components.css and layout.css, reaches its colours through var(). That is
   what makes a restyle a values-only change: edit this block and the whole app
   restyles without touching a single template or component rule.

   Sizes are tokenised wherever a token is meaningful, but the rule there is
   weaker on purpose: a media-query breakpoint CANNOT be a custom property (CSS
   does not resolve var() in @media conditions), and one-off measures like a
   60ch line length are layout facts rather than design decisions. So layout.css
   carries a few raw lengths, by design and not by neglect.

   THEME EXPOSURE IS DORMANT. :root = dark is the only active theme. The
   [data-theme="light"] slot exists so that setting that attribute works once
   exposure is decided at the G1-a freeze — there is NO toggle and NO auto-switch
   media query here, and base.html carries no data-theme attribute
   (so the app renders dark by default). P1-08 gates audit both themes.
   ========================================================================== */

/* Mulish — self-hosted (SIL OFL, static 400/600, woff2). D117 supersedes R01's
   Figtree choice: BRAND-GUIDELINES.md:69/80/122 (brand corpus) mandates Mulish
   as the primary typeface at 400/600 — "never use fonts outside Brush Up
   (accent) + Mulish (everything)". Figtree's assets are removed (dead once this
   swap ships — D117 leaves removal vs retain to the implementer; removed, since
   a kept-but-unreferenced font file is just repo weight with no future caller).
   Avenir Next remains the someday-licensed target if a webfont licence is ever
   bought: swap these two src files and change "Mulish" to "Avenir Next" in
   --font-body below — still the one-token change R01 built this seam for.
   NEVER a CDN link (repo doctrine). */
@font-face {
  font-family: "Mulish";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/mulish-400.woff2") format("woff2");
}
@font-face {
  font-family: "Mulish";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/mulish-600.woff2") format("woff2");
}

:root {
  color-scheme: dark;

  /* --- Colour — Night Service (DESIGN-LESSONS R01). Ratios vs bg #0C0B0A / surface #181613. */
  --color-bg: #0C0B0A;
  --color-surface: #181613;
  --color-line: #2B2823;            /* decorative hairline (low-contrast by design) */
  --color-ink: #F4F1EB;             /* headings/strongest — 17.44 / 16.02 (AAA) */
  --color-body: #C9C4BB;            /* body copy — 11.33 / 10.40 */
  --color-muted: #8A857F;           /* captions/labels — 5.38 / 4.94 (AA floor) */
  --color-accent: #EE312C;          /* Flame Red — BRAND LAW: accent/large-UI only, never body text (4.79 / 4.39 UI floor) */
  --color-accent-text: #F2716D;     /* SMALL red text/labels on dark — 6.89 / 6.33 (raw Flame fails AA at label sizes) */
  --color-done: #4C9A6A;            /* completed/done-state (checks, done pills) — 5.75 / 5.28. Keeps red = "urgent" */
  --color-focus-ring: #F2716D;      /* :focus-visible outline — 6.89 / 6.33 (clears 3:1 on bg & surface) */

  /* Feedback banners — ink on its own bg (existing rules border in the ink colour, so the edge is always visible). */
  --color-success-bg: #14231A;  --color-success-ink: #7FCBA0;   /* 8.52 */
  --color-error-bg:   #2A1513;  --color-error-ink:   #F2716D;   /* 6.06 */
  --color-warning-bg: #2A2211;  --color-warning-ink: #E3B368;   /* 8.17 */

  /* --- Elevation (quiet — R01 "brand volume quiet"). rgba() legal here only.
     D116 ruling 3: a black shadow on a #0C0B0A page is ~invisible (critic C4)
     — kept for the light theme (where it DOES read) and for any residual dark
     use, but dark elevation now comes from --color-raised (surface TINT, see
     below), not these. --overlay-press is the touch/:active fill-darken scrim
     for filled controls (.btn-primary/.btn-fab) — a translucent black overlay
     reads as "pressed" on ink fill in EITHER theme (dark ink is near-white, so
     the overlay visibly dims it; light ink is near-black, so it adds a subtle
     extra press without needing a second literal per theme). */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 6px 20px rgba(0, 0, 0, 0.6);
  --overlay-press: rgba(0, 0, 0, 0.18);

  /* --- Space (8px-family grid — unchanged) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 16px;
  --space-4: 24px;
  --space-5: 40px;

  /* --- Shape (D116 ruling 4 — supersedes R01's "cards 16 / buttons 14 /
     inputs 12; soft": uniform 12-16px rounding everywhere was the #1
     AI-template tell, critic A1, "no crisp/square element anywhere").
     New grammar, four tiers by INTENT, not by component family:
       4px  structural containers — cards, panels, composer, banners/toast/flagbar
       6px  controls/tables — form fields, data-table rows/head (crisp-leaning,
            slightly softer than pure structural so a field still reads tappable)
       8px  buttons — "drops from 14", deliberately NOT eliminated: the one
            control allowed to stay a little soft
       999px true pills only — chips, toggles, avatar, FAB, PIN keys (unchanged)
     A pill is never confused with "just a very round button" any more — the
     ramp has real air between each step instead of one soft cluster. */
  --radius: 4px;                    /* generic structural (banner/toast/flagbar) — same tier as --radius-card */
  --radius-input: 6px;
  --radius-button: 8px;
  --radius-card: 4px;
  --radius-pill: 999px;
  --border-width: 1px;

  /* --- Type (Mulish 400/600 — D117 supersedes R01's Figtree; brand fallback
     stack per BRAND-GUIDELINES.md:82) */
  --font-body: "Mulish", -apple-system, "Segoe UI", Montserrat, Arial, sans-serif;
  --font-size-caption: 12px;
  --font-size-small: 14px;
  --font-size-body: 16px;
  --font-size-lg: 20px;
  --font-size-heading: 24px;
  --font-size-display: 32px;
  --line-height-body: 1.5;
  --line-height-tight: 1.25;
  --weight-normal: 400;             /* keep — only 400/600 are shipped; do NOT add a 500 token */
  --weight-bold: 600;

  /* --- Touch targets (CLAUDE.md house floor — RULES, do not lower) */
  --touch-target-primary: 36px;
  --touch-target-row: 32px;
  --touch-target-compact: 28px;

  /* --- Navigation (P1-04 refine) — staff bottom tab-bar height. A floor-facing
     nav stacks a ~22px icon over a caption label and must breathe / stay tappable
     on the move; the 36px primary tap-min is a control floor, not a nav height.
     Theme-independent (a size), so it lives in :root only. */
  --nav-height: 56px;

  /* --- Focus */
  --focus-ring-width: 2px;

  /* --- Layout */
  --content-max-width: 960px;

  /* --- Motion (R01: quiet 200ms) */
  --transition-quick: 200ms ease;

  /* --- Component-level tokens (P1-04, retuned D116 ruling 1/3) ---
     --color-hover was #201D19 — only +7.1/255 luma past surface (#181613),
     below the just-noticeable-difference floor (critic D-anchor: "invisible on
     a phone in daylight"). Retuned to clear the ruling's >=10-12/255 floor with
     real margin: surface Y=22.2 -> hover Y=36.9 (delta +14.7). ink 13.63:1 /
     body 8.85:1 on it (AAA, both comfortably re-verified against the NEW
     value — DL08 precedent: a retune is a new pairing, not the old one). muted
     is 4.20:1 on it — CLEARS 3:1 (non-text/large-text) but NOT 4.5 (small-text
     AA): the arithmetic that gets a visible hover step on this warm-neutral
     palette does not leave room for small muted captions to stay AA-normal on
     it too (would need a hue shift the palette doesn't want). Every component
     whose hover paints --color-muted caption text (thread-list-row preview/
     timestamp, table-row--dim) gets a hover-scoped override to --color-body
     instead (components.css) — never rely on --color-muted staying legible
     on this token.
     --color-raised is NEW: a third elevation tier above --color-surface for
     genuinely LIFTED tiles (card/stat-tile/modal/drawer/edit-card/side-panel)
     — depth via surface TINT, since shadow does not read on #0C0B0A (critic
     C4). surface Y=22.2 -> raised Y=34.8 (delta +12.6, clears the floor). ink
     13.98:1 / body 9.08:1 on it (AAA). muted is 4.31:1 — same non-text-only
     scoping as --color-hover above; components riding --color-raised at REST
     (not just on hover) have had their own --color-muted captions bumped to
     --color-body permanently (.stat-tile__label, .feed-card__timestamp).
     --color-line-strong is NEW: a border token brighter than the decorative
     --color-line hairline, for hover border-brightens (ruling 1's "OR" path)
     and any border that needs to clear 3:1 non-text on its own. Deliberately
     set to --color-muted's exact value (already proven >=4.3:1 non-text vs
     bg/surface/raised/hover in this theme) rather than a new hue — reused as a
     STRUCTURAL border here, never as text (DL15: a token's certification is
     scoped to the job it was measured for; muted's job was captions, this is a
     second, independently-true job for the identical value, not an assumption
     carried over). */
  --color-hover: #2A241C;
  --color-raised: #282219;
  --color-line-strong: #8A857F;
  --color-disabled-bg: #181613;     /* disabled control fill (= surface); label stays --color-muted 4.94 on it (disabled text is WCAG-exempt) */
  --color-overlay: rgba(0, 0, 0, 0.6);       /* modal/drawer scrim (dark). rgba legal only here. */
  --color-skeleton: #201D19;         /* loading-placeholder base (dark) — decorative, carries no text */

  /* --- Comms — own-message-bubble tokens (P1-05, R01 "light-inverted own bubble") ---
     "Mine" inverts the surface so a person's own words read distinctly — dark
     theme's own bubble is LIGHT, never Flame. AA-verified foreground-on-fill
     (DL08 — this is exactly the pairing class DL08 warns a token-value test
     cannot see; verified here as its own explicit component pairing). */
  --color-bubble-mine-bg: #F4F1EB;    /* = --color-ink's value; own bubble is light-inverted on dark (R01) */
  --color-bubble-mine-text: #181613;  /* = --color-surface's value; dark text on the light bubble — 16.02:1 (AAA) */
}

/* Light slot — DERIVED from the brand light palette (BRAND-GUIDELINES.md: Ink,
   White, Warm Paper, Mid Grey, Flame Red), re-derived AA pairings, not an
   inversion of the dark set (R01). DORMANT: no toggle, no auto-switch media query
   here — exposure is decided at G1-a. Ratios vs bg #FAF7F2 / surface #FFFFFF.
   --color-accent is intentionally NOT overridden: Flame Red #EE312C is identical
   in both themes (brand law). */
[data-theme="light"] {
  color-scheme: light;

  --color-bg: #FAF7F2;              /* Warm Paper */
  --color-surface: #FFFFFF;         /* White — cards lift off the warm page */
  --color-line: #E7E2D9;            /* decorative hairline */
  --color-ink: #141414;            /* brand Ink — 17.24 / 18.42 (AAA) */
  --color-body: #33312D;           /* 12.15 / 12.98 */
  --color-muted: #6B6B6B;          /* brand Mid Grey — 4.99 (AA, thin margin: recheck if ever on a darker panel) */
  --color-accent-text: #C21F1B;    /* SMALL red text on light — 5.61 / 5.99 (Flame fails 4.5 as small text: 3.84 / 4.11) */
  --color-done: #2E7D4F;           /* 4.72 / 5.05 */
  --color-focus-ring: #EE312C;     /* Flame clears 3:1 on light bg & surface (3.84 / 4.11) */

  --color-success-bg: #E6F4EC;  --color-success-ink: #1E6B41;   /* 5.72 */
  --color-error-bg:   #FCE9E8;  --color-error-ink:   #B4231F;   /* 5.61 */
  --color-warning-bg: #FBF0DA;  --color-warning-ink: #8A5A00;   /* 5.24 */

  --shadow-sm: 0 1px 2px rgba(20, 20, 20, 0.08);
  --shadow-md: 0 8px 24px rgba(20, 20, 20, 0.12);
  /* Same literal as :root, restated explicitly (not left to inherit) — DL04's
     dual-slot rule (Codex round 1): a black press-scrim reads as "pressed" on
     an ink fill regardless of theme, so the VALUE doesn't change between
     slots, but the slot must still declare it, not rely on cascade. */
  --overlay-press: rgba(0, 0, 0, 0.18);

  /* --- Component-level tokens (P1-04; D116 ruling 1/3 re-verification) ---
     --color-hover UNCHANGED: surface is #FFFFFF (max luma 255) on light, so the
     existing hover step (Y 255 -> 236.6, delta -18.4/255) already clears the
     >=10-12 floor with margin — there is no dark-theme-style "+7 invisible
     tint" problem here, so no retune is needed; re-verified, not re-derived.
     --color-raised = --color-surface (#FFFFFF) on light BY DESIGN — ruling 3:
     "the light theme keeps soft shadows" as its lift mechanism (they DO read
     on a warm-paper bg, critic report), so there is no tint tier to add; a
     raised component still gets --shadow-md, same as before. */
  --color-hover: #F1ECE4;           /* ink 15.67 / body 11.04 / muted 4.53 on it (AA, thin margin) */
  --color-raised: #FFFFFF;
  --color-line-strong: #6B6B6B;     /* = --color-muted's value, reused as a structural border (see dark-slot comment) — 4.99 vs bg, clears 3:1 non-text with margin */
  --color-disabled-bg: #EFEBE4;     /* label --color-muted 5.33 on it */
  --color-overlay: rgba(20, 20, 20, 0.4);    /* scrim (light) */
  --color-skeleton: #F1ECE4;         /* loading-placeholder base (light) */

  /* --- Comms — own-message-bubble tokens (P1-05) — the inversion: light theme's
     own bubble is DARK, so "mine" always reads as a deliberate inversion of the
     theme, never as an accidental colour. No Flame on a bubble (D108). */
  --color-bubble-mine-bg: #141414;    /* = brand Ink; own bubble is dark-inverted on light */
  --color-bubble-mine-text: #FAF7F2;  /* = --color-bg's value (Warm Paper); light text on the dark bubble — 17.24:1 (AAA) */
}
