/* design-system: page-library v1 | tokens.css */
/* Token sheet for the page library: three tiers, and nothing else.
 *
 * This banner deliberately does not name the file. The fleet linter treats a first line that
 * names tokens.css/base.css as a COPY of the canonical fleet system, which this is not: it is a
 * second vocabulary with its own names. Claim "copy" and the linter correctly demands it match
 * the fleet, and 212 findings follow. See NOTES.md, "A fork, not a copy".

WHY THREE TIERS
Tier 1 is raw value. Tier 2 is a role a product may use. Tier 3 is a component's own
decision. A component may read tier 2 or 3 and never tier 1, which is what stops a page
from picking a specific grey. The build fails on a tier-1 read outside this file.

WHY THE NAMES ARE ROLES, NOT HUES
`--ok` survives a rebrand and `--green-600` does not. The only hue-named tokens here are
tier 1, which nothing outside this file may use.

WHY HEX AND NOT OKLCH
oklch() is the better authoring space and it is Baseline. It is not here yet because the
contrast gate parses hex, and a token layer the gate cannot measure is a token layer the
gate cannot protect. That is a stated trade, not an oversight: see NOTES.md, D3.
*/

:root {
  /* ── tier 1: primitive ─────────────────────────────────────────────────── */
  --gray-0:#ffffff;   --gray-25:#f7f7f8;  --gray-50:#f2f2f4;  --gray-100:#e9e9ed;
  --gray-200:#e6e6e9; --gray-300:#d4d4d8; --gray-400:#a1a1aa; --gray-500:#71717a;
  --gray-600:#52525b; --gray-700:#3f3f46; --gray-900:#18181b; --gray-950:#111114;
  --indigo-50:#eef0ff; --indigo-500:#4f46e5; --indigo-600:#4338ca;
  --green-50:#eaf6ee;  --green-600:#15803d;  --green-200:#cfe7d8;
  --amber-50:#fdf4e7;  --amber-700:#b45309;  --amber-200:#f0dcc0;
  --red-50:#fdecec;    --red-700:#b91c1c;    --red-200:#f2cccc;

  /* The terminal chrome, deliberately outside the theme: a console is dark on a light page and on a
     dark one, so these are primitives that no theme re-points. They live here because a literal in
     components.css is a literal, even when it is the right one. */
  --term-bg:#0c0c0f;   --term-bar:#14141a;   --term-line:#1f1f25;  --term-line2:#23232b;
  --term-lamp:#2e2e38; --term-ink:#d6d6db;   --term-dim:#8b8b96;
  --term-ok:#7ee2a8;   --term-warn:#e2c07e;  --term-alert:#f08c8c; --term-info:#8ab4f8;

  /* type: one ladder, ten steps, roles not ratios */
  /* his verdict 2026-10-22: the 11px mono micro was hard to read, so micro is 12px sans.
     Mono is for values (code, kbd, addresses), never a whole step below --fs-sm. */
  --fs-micro:12px;  --fs-label:12px; --fs-sm:13px;  --fs-base:14px; --fs-prose:16px;
  --fs-h3:18px;     --fs-h2:22px;    --fs-h1:28px;  --fs-display:40px; --fs-hero:52px;
  --lh-tight:1.12;  --lh-body:1.45;  --lh-prose:1.6;
  --tracking-tight:-.02em; --tracking-hero:-.03em;

  /* space: a ladder of eight, 4px base, nothing between */
  --space-1:4px;  --space-2:8px;  --space-3:12px; --space-4:16px;
  --space-5:24px; --space-6:32px; --space-7:48px; --space-8:64px;

  --radius-sm:6px; --radius:10px; --radius-lg:14px; --radius-box:16px; --radius-pill:999px;
  --border:1px;

  /* motion: four durations, three curves */
  --dur-0:.01ms; --dur-1:90ms; --dur-2:150ms; --dur-3:220ms; --dur-4:320ms;
  /* the ladder, not arbitrary z: a raw z-index is how a dropdown ends up under a modal */
  --z-1:1; --z-2:10; --z-3:50; --z-4:100; --z-5:1000;
  --ease-out:cubic-bezier(.2,0,.1,1);
  --ease-in-out:cubic-bezier(.4,0,.2,1);
  --ease-accelerate:cubic-bezier(.4,0,1,1);   /* exits only, never an entrance */

  /* ── tier 2: semantic, light ───────────────────────────────────────────── */
  --bg:var(--gray-0);
  --sunken:#f4f4f5; /* daisy base-200, his light pick 2026-10-22 */
  --raised:var(--gray-0);
  --ink:var(--gray-900);

  --ink2:var(--gray-700);
  --muted:#6b7280; /* daisy's blue-grey, his light pick */
  --line:#e5e5e5; /* daisy base-200 border */
  --line2:var(--gray-300);

  --accent:var(--indigo-500);
  --accent-hover:var(--indigo-600);
  --accent-ink:var(--gray-0);
  --accent-soft:var(--indigo-50);

  --ok:var(--green-600);     --ok-soft:var(--green-50);     --ok-line:var(--green-200);
  --warn:var(--amber-700);   --warn-soft:var(--amber-50);   --warn-line:var(--amber-200);
  --alert:var(--red-700);    --alert-soft:var(--red-50);    --alert-line:var(--red-200);

  --font-sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,Menlo,monospace;

  --scrim:rgba(16,16,20,.5);
  --shadow:0 1px 2px rgba(16,16,20,.05),0 1px 3px rgba(16,16,20,.04);
  --shadow-lg:0 12px 32px rgba(16,16,20,.10),0 2px 8px rgba(16,16,20,.06);
  --shadow-modal:0 24px 64px rgba(0,0,0,.28);
  --ring:0 0 0 2px var(--bg),0 0 0 4px var(--accent);

  --measure:34em;
  --control-h:36px;
  --control-h-sm:28px;
  --row-h:44px;

  /* ── tier 3: component ─────────────────────────────────────────────────── */
  --btn-bg:var(--raised);
  --btn-bg-hover:var(--sunken);
  --btn-line:var(--line2);
  --btn-radius:var(--radius-sm);
  --btn-fs:13.5px;
  --btn-weight:600;   /* 500 was reading as a label, not an action. The original's CTA was 600. */
  --btn-pad:14px;

  --field-line:var(--line2);
  --field-bg:var(--raised);
  --field-radius:var(--radius-sm);

  --card-bg:var(--raised);
  --card-line:var(--line);
  --card-radius:var(--radius-box); /* 16px, his pick 2026-10-22: daisy's card cornering */
  --card-pad:18px;
  --gap-card:var(--space-4);   /* the floor between two cards. 12px reads as one object split in two. */

  --badge-h:22px;
  --badge-radius:var(--radius-pill);
  --badge-fs:11.5px;

  --table-fs:13.5px;
  --table-head-fs:12px;
  --table-cell-pad:13px 12px; /* the 48px rung, his default 2026-10-22; compact 32px lives in the data-density block */
}

/* A theme re-points tier 2 and declares nothing new. A theme that ADDS a token widens the
   vocabulary for every surface and is how a second palette gets in. */
:root[data-theme="dark"] {
  --bg:var(--gray-950);
  --sunken:#17171c;
  --raised:#1d1d23;
  --ink:#f2f2f5;
  --ink2:#d4d4d8;
  --muted:#9b9ba4;
  --line:#30303a;
  --line2:#4d4d5a;

  --accent:#8b8bf5;
  --accent-hover:#a3a3ff;
  --accent-ink:var(--gray-950);
  --accent-soft:#23233a;

  --ok:#6ee7a0;      --ok-soft:#12251a;      --ok-line:#1f4430;
  --warn:#f0b46b;    --warn-soft:#2a1f10;    --warn-line:#4a3618;
  --alert:#f08c8c;   --alert-soft:#2a1416;   --alert-line:#4a2222;

  --scrim:rgba(0,0,0,.62);
  --shadow:0 1px 2px rgba(0,0,0,.4),0 1px 3px rgba(0,0,0,.3);
  --shadow-lg:0 12px 32px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.35);
  --ring:0 0 0 2px var(--bg),0 0 0 4px var(--accent);
}

/* A third theme, carried over from the fleet's warm-paper palette because a consumer already ships
   it and dropping it would be a visible change to a live page rather than a port. It re-points the
   semantic tier only, and it re-points the SANS slot to a serif on purpose: every page using it is
   prose first, so the reading face is the page face. */
:root[data-theme="bakery"] {
  --bg:#f5f4ed; --sunken:#edeae0; --raised:#faf9f5;
  --ink:#141413; --ink2:#3a3936; --muted:#5e5d59;
  --line:#e8e6dc; --line2:#d9d5c7;
  --accent:#a8412a; --accent-hover:#8f351f; --accent-ink:#ffffff; --accent-soft:#f2e6e1;
  --ok:#2f6f33;    --ok-soft:#e2efe4;    --ok-line:#c6ddc9;
  --warn:#8a5300;  --warn-soft:#f6ecd9;  --warn-line:#e0cba8;
  --alert:#b53333; --alert-soft:#f7e9e6; --alert-line:#d9aa9f;
  --font-sans:Georgia,"Iowan Old Style","Times New Roman",serif;
  --shadow:0 1px 2px rgba(60,50,35,.06),0 1px 3px rgba(60,50,35,.05);
}

/* A third dark reading, and the first THEME that exists to make a product distinct rather than to
   suit a surface class. Near-black canvas, white headline, one violet accent. The point of a theme
   is that the components do not change: a page that picks `tape` gets the same button, table and
   badge, in this product's colour. Sameness across a portfolio is a theme problem, not a component
   problem, which is why this is 20 lines and not a second stylesheet. */
:root[data-theme="tape"] {
  color-scheme: dark;
  /* R4 verdict 2026-10-22, final: his picks are shadcn dark and daisy light, so the reference
     palettes are ADOPTED (the falsifier in DECISIONS.md fired). Dark = shadcn neutrals: cards
     separate by border, not fill; the tape identity layer (gradient, glow, accent) is untouched. */
  --bg:#09090b; --sunken:#18181b; --raised:#09090b;
  --ink:#fafafa; --ink2:#f4f4f5; --muted:#a1a1aa;
  --line:#27272a; --line2:#333333;
  --accent:#7c3aed; --accent-hover:#8b5cf6; --accent-ink:#ffffff; --accent-soft:#1e1b2e;
  /* a gradient is a product's face, so it is a token: a theme may set one, components may not
     invent one. Both stops are dark enough for white text at AA, which is checked by hand below. */
  --accent-grad:linear-gradient(96deg,#7c3aed,#3b82f6);
  /* the same ramp as a TEXT fill. Three stops, because two read as a flat wash at 56px: the eye
     needs the violet to arrive, the blue to carry, and the cyan to land. */
  --accent-grad-text:linear-gradient(96deg,#8b5cf6 0%,#3b82f6 52%,#22d3ee 100%);
  /* the page wash. Not decoration: it is what stops a near-black page reading as a void, and it is
     the difference between this design and a flat #0a0a0a. */
  --page-glow:radial-gradient(1000px 520px at 12% -8%,rgba(124,92,255,.20),transparent 60%),
              radial-gradient(900px 430px at 94% 2%,rgba(34,211,238,.12),transparent 55%);
  --ok:#4ade80;    --ok-soft:#0f2318;    --ok-line:#1f4430;
  --warn:#fbbf24;  --warn-soft:#261d09;  --warn-line:#4a3618;
  --alert:#f87171; --alert-soft:#260f0f; --alert-line:#4a2222;
  --scrim:rgba(0,0,0,.68);
}

/* Density is a data attribute on a container, not a second stylesheet: it moves the row
   height and the control height and nothing else. Text size never changes with density. */
[data-density="compact"] {
  --control-h:28px;
  --control-h-sm:24px;
  --row-h:32px;
  --table-cell-pad:6px 10px;
  --card-pad:14px;
  --space-5:18px;
  --space-6:24px;
}
