/* ============================================================================
   Cortex DS v4 — tokens
   The panel world. Supersedes the v3 warm-paper elevated-card language.

   Locked direction: projects/cortex/design/lane.md (vault).
   Load AFTER the v3 manifest to override it, or instead of it. Same --cx-*
   names by design, so a surface migrates without renaming anything.

   THE ONE RULE THAT ORGANISES THIS FILE — three layers, different owners:

     HOUSE   constant across every client instance. Type, spacing, radius,
             density, motion, elevation, chart ink. Never themed.
     CLIENT  one accent ramp + the mark. This is the ONLY thing a client
             instance overrides. Everything below reads --cx-accent-*.
     MEANING semantic hues. Reserved, never the accent, never a chart series.

   Strip the client layer and every surface must still work. That is the test.
   ========================================================================= */

:root {
  /* ── HOUSE · ground and surfaces ─────────────────────────────────────────
     A TINTED ground, not white. Panels float on it as rounded cards separated
     by radius and ground-contrast — a hairline, almost no shadow. Depth is
     NOT lift. (v3 was the opposite: white cards lifting on warm shadows.) */
  --cx-ground:        #f5f2ef;  /* app canvas — panels sit on this */
  --cx-panel:         #ffffff;  /* panel fill */
  --cx-panel-sunken:  #fbf9f7;  /* inset wells inside a panel */
  --cx-line:          #e6e1dc;  /* panel edge */
  --cx-line-2:        #f0ece8;  /* divider inside a panel — softer than the edge */
  --cx-line-strong:   #d6cfc7;  /* hover edge, focus outline base */

  /* ── HOUSE · ink ─────────────────────────────────────────────────────── */
  --cx-ink:    #1c1b1a;  /* primary */
  --cx-ink-2:  #5d5952;  /* body-dim, secondary */
  --cx-ink-3:  #736e66;  /* metadata, captions, placeholders — 5.06:1 on panel, 4.54 on ground, MEASURED 2026-08-26 (was #8d887f at 3.52) */
  --cx-ink-on-accent: #ffffff;
  --cx-ink-on-vivid:  #ffffff;  /* text on a call-site-supplied VIVID fill (vendor
                                   monograms, the rail stack). Defined once and not
                                   re-declared under dark on purpose: a saturated
                                   brand fill is the same colour in both themes, so
                                   the ink on it is too. The call site owns the
                                   fill and its contrast. */

  /* ── CHROME · the accent ramp — SHIPS AS INK ─────────────────────────────
     THE ONLY LAYER A CLIENT INSTANCE OVERRIDES. Five steps.

     The shipped ramp is INK, not a hue. This is the house default: the demo,
     the marketing surface, and the brand. Chrome is ink; state is carried by
     weight and darkness, and a primary action is an ink pill. Colour is spent
     on OBJECTS instead — see the object palette below — so when colour does
     appear it means something. Doctrine and every measurement behind it:
     projects/cortex/design/base-layer.md (the ethanhunt vault).

     The wine ramp is NOT gone. It is themes/candid.css, which overrides these
     same five steps in both modes, and any client theme does the same. Load a
     theme and the accent lane is back, unchanged. Load nothing and you get
     the house.

     Measured 2026-08-29 against every gate this file sets:
       white on base 17.2:1   quiet on wash 10.9:1   focus vs panel 17.2:1
     A client accent MUST still clear 4.5:1 white-on-base before it ships. */
  --cx-accent:        #1c1b1a;  /* = --cx-ink. Ink pills, ink rails, ink focus. */
  --cx-accent-hover:  #3a3733;  /* LIFTS, not darkens — the base is already near-black */
  --cx-accent-bright: #b8b2a9;  /* mix input only; no component paints it directly */
  --cx-accent-wash:   #f6f4f1;  /* faint tint — active nav, selected row.
       NOT free to be darker. Six semantic hues legitimately sit ON this wash (a selected
       doc row shows "Verified" in canon), and at #efebe6 canon measured 4.35:1, ok 4.48,
       warn 4.48, info 4.47, working 4.40 — all under AA. Check 9 caught two of them; the
       other four are simply not exercised in the gallery. At #f6f4f1 every one clears
       (worst 4.58:1) and the wash still separates from panel at 1.098 — MORE than the wine
       wash's 1.06, because that one read by HUE, not by luminance. Take the hue away and a
       tint alone cannot carry selection: the inset ink bar and the weight do, which is the
       doctrine working rather than a compromise. Measured 2026-08-29. */
  --cx-accent-quiet:  #35312d;  /* chrome-coloured TEXT on wash (AA, 10.9:1) */

  /* ── MEANING · reserved, never the accent ────────────────────────────────
     Canon teal marks VERIFIED TRUTH and is the most load-bearing colour in the
     product. It is RESERVED: a client whose own brand is teal still gets a
     non-teal chrome accent — the semantic wins over the brand. Status is ALWAYS mark + word —
     never colour alone — so these survive greyscale and forced-colors. */
  --cx-canon:      #35786f;  --cx-canon-wash: #e9f2f0;  /* verified / promoted */
  --cx-working:    #656d7a;  --cx-working-wash:#eef0f2; /* draft, unverified */
  --cx-ok:         #2d794d;  --cx-ok-wash:    #e7f0e9;
  --cx-warn:       #8a6508;  --cx-warn-wash:  #faf3e0;
  --cx-error:      #b23f34;  --cx-error-wash: #fdeeec;
  --cx-info:       #3b6ea5;  --cx-info-wash:  #e8eef6;

  /* ── HOUSE · machine output ──────────────────────────────────────────────
     DERIVED from the accent, so AI never becomes a fourth voice. A client
     instance sets these from its own ramp; it does not invent a hue.

     This was briefly given its own pink (2026-08-29) on the argument that ink
     chrome leaves AI silent. REVERTED the same day: --cx-ai-ink paints more
     than twenty surfaces — row dots, doc field labels, match diffs, proposed
     states, the reading header — so a hue here is not a voice, it is a rash.
     The owner's read on seeing it rendered: "pink is everywhere."

     The silence was never the problem it looked like. Machine output is
     identified the way every state in this package is identified — by mark
     plus word, never by colour alone. Under home it reads ink; under a client
     theme it reads that client's quiet step. Both are correct. */
  --cx-ai:      var(--cx-accent-wash);
  /* DERIVED, not a literal. This was #eed3da — a rose hand-picked against the candid
     accent — while --cx-ai above and --cx-ai-ink below both read the ramp. So under any
     client accent that is not rose, every machine-output surface painted a PINK border
     around a differently-coloured fill: measured 2026-08-29 under a violet client,
     background rgb(244,242,250) with border rgb(238,211,218), on nine rules and ten
     elements in the gallery alone. The block's own heading says these are derived so AI
     never becomes a fourth voice; one of the three was not.
     The mix reproduces the old value to within 4 RGB units (#f2d4db against #eed3da), so
     the house theme does not move on a 1px hairline. Owner-ruled 2026-08-29.
     Only drawn when the block is drawn at all — see .cx-reading--bare. */
  --cx-ai-line: color-mix(in oklab, var(--cx-accent-bright) 35%, var(--cx-accent-wash));
  --cx-ai-ink:  var(--cx-accent-quiet);

  /* ── HOUSE · the object palette — NEVER themed, NEVER an encoding ────────
     Four members, taken unchanged from the motion library's chart-icons-best,
     whose ink measures dE 1.0 from --cx-ink. They land on OBJECTS ONLY: motion,
     glyphs, illustration marks. Never a ground, never a chrome surface.

     THE RULE THAT MAKES THEM SAFE: a member may only fill a shape that ink
     already encloses. Seven of the ten source hues fall below 3:1 on the light
     ground, and that is fine inside an ink outline because the ink carries the
     form — it is not fine on open ground. Solving them to stand alone was
     tried and REJECTED: it turns orange into #962a00, pink into magenta, and
     collapses yellow and amber to dE 2.6 apart. The palette cannot be made to
     stand alone without ceasing to be the palette.

     NEVER AN ENCODING. Colour that means something stays where it is: two
     chart series and the reserved semantics. Colour that decorates may be
     polychrome. Without this line the object palette becomes a series palette
     and the CVD validation below is lost.

     The pack's TEAL is deliberately absent: dE 5.1 from --cx-canon, and the
     semantic outranks the palette. Same values in both modes — all four clear
     3:1 on the dark ground, and on light they sit inside ink.

     EACH FAMILY HAS TWO VALUES, added 2026-08-30. The first pass took one hue per
     family and that was incomplete: the pack uses a base AND a variant in every
     one of them, and an asset carrying both would have had both collapse onto a
     single token — flattening its own shading. Found when four picks for the
     loading slot were checked and all four turned out to use #eb3100 alongside
     #f24c00. These are SHADES WITHIN a family, never separate members: solved as
     categories they sit dE 2.6 and 2.0 apart and are not distinguishable, which
     is exactly why they are a light and a dark face of one thing rather than two.

     --cx-obj-blue IS THE SKY, #4bb3fd, and the deeper #3098fc is its variant —
     that way round because the sky blue is 26 shapes across 9 of 22 files where
     the deep one is 5 across 5. The first pass had it backwards, picked for
     standalone contrast rather than for the register. Note this is NOT
     --cx-series-1, and the two must not be conflated: a chart LINE has no outline
     to carry it and needs 3:1 on its own, which the sky blue misses at 2.29 and
     #2d92f2 makes. Different jobs, different gates, different tokens. */
  /* ── HOUSE · the categorical ramp — part-to-whole, NOT series ────────────
     Owner-ruled 2026-08-30: "3-hue is ok, but greys also welcome; combo?" Yes,
     and the combo is what the pack itself does. Its Stacked Bar carries grey,
     white AND ink alongside its three hues — four of its six values are neutral.
     Neutrals lead, hues mark what matters.

     WHY THREE AND NOT TWO. The two-series ceiling was computed for SERIES in the
     dark band and it still stands there. A pie is part-to-whole, a different
     problem with a different gate, and three hues clear it: orange, blue and
     yellow separate at worst 20.6 under CVD against a floor of 15.

     WHY NOT FOUR. Pink fails the set — 13.7 against blue under protanopia, 10.9
     against yellow under tritanopia. Green fails harder and every green in the
     library fails differently; the one authored mint that cleared the gates
     collapsed to 11.3 once the blue was corrected to the pack's sky. So the
     fourth slot is a NEUTRAL by measurement, not by restraint.

     A categorical fill is not required to stand alone on the light panel — the
     set relies on a panel-coloured separator and a direct label, which is why
     yellow at 1.56:1 is legal here and would not be as a mark. */
  --cx-cat-1: var(--cx-obj-orange);
  --cx-cat-2: var(--cx-obj-blue);
  --cx-cat-3: var(--cx-obj-yellow);
  --cx-cat-4: var(--cx-ink-3);      /* the ramp continues in NEUTRALS, never a fourth hue */
  --cx-cat-5: var(--cx-line);

  --cx-obj-orange: #f24c00;  --cx-obj-orange-deep: #eb3100;
  --cx-obj-blue:   #4bb3fd;  --cx-obj-blue-deep:   #3098fc;
  --cx-obj-yellow: #ffc738;  --cx-obj-yellow-deep: #ffb122;
  --cx-obj-pink:   #f28ba8;  --cx-obj-pink-deep:   #eb6b8b;

  /* ── HOUSE · chart ink — NEVER themed, NEVER client-specific ─────────────
     TWO SERIES IS THE CEILING, and it is a computed result, not a preference.
     Validated with the six checks (lightness band, chroma floor, CVD
     separation, normal-vision floor, contrast). Three hues FAIL the dark
     band L 0.48–0.67 against orange at the 15 ΔE normal-vision floor —
     purple, violet, rose, green and cyan were all tried.
     Beyond two series: FACET into small multiples. Never add a hue.
     Never use a semantic colour as a series. */
  /* RE-PICKED into the object palette's family, 2026-08-29, and re-validated rather than
     assumed. With the outline gone a fill has to stand alone, so the gates are: >=3:1 on
     panel AND on panel-sunken, >=15 dE CVD separation, >=15 dE normal vision, >=8 dE from
     every reserved meaning. The result is almost exactly the pack's own pair — orange moved
     0.5 from #f24c00, blue 2.1 from #3098fc — and it clears by a wide margin:
       normal vision dE 36.3   CVD worst dE 29.5 (deuter 30.9 · protan 29.5 · tritan 36.8)
       contrast light  orange 3.54/3.37   blue 3.23/3.07
       contrast dark   orange 4.76/5.01   blue 5.62/5.92
     Yellow and pink CANNOT be chart fills on light (1.56:1 and 2.32:1 on panel). That costs
     nothing — the ceiling is two series and it has not moved. */
  --cx-series-1: #2d92f2;
  --cx-series-2: #f34f0b;

  /* ── HOUSE · type ────────────────────────────────────────────────────────
     One working face everywhere. NO MONO IN THE DATA SURFACE — all four
     corpus references refuse it; figures use tabular numerals instead.
     Mono survives for machine strings only (IDs, paths, raw payloads).
     The display face is the house nod and is permitted on HOME ONLY. */
  --cx-font:         Figtree, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --cx-font-display: "Bricolage Grotesque", var(--cx-font);   /* Home wordmark ONLY */
  --cx-font-figure:  "Departure Mono", ui-monospace, monospace;  /* DISPLAY FIGURES ONLY — the hero figure and tile values; never rows, labels or charts */
  --cx-font-mono:    ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --cx-display: 60px;  /* Home wordmark — the one moment of scale */
  --cx-h1:      25px;
  --cx-h2:      18px;
  --cx-h3:      14.5px;
  --cx-body:    13.5px;
  --cx-sm:      12px;
  --cx-xs:      10.5px;  /* uppercase eyebrows */

  --cx-w-regular: 400;
  --cx-w-medium:  500;
  --cx-w-semi:    600;
  --cx-w-bold:    700;

  --cx-lh-display: 1.02;
  --cx-lh-tight:   1.25;
  --cx-lh-snug:    1.4;
  --cx-lh-normal:  1.55;

  --cx-tr-display: -.035em;
  --cx-tr-heading: -.015em;
  --cx-tr-normal:  0;
  --cx-tr-wide:    .09em;   /* xs uppercase eyebrows */

  /* ── HOUSE · spacing, 4-based ────────────────────────────────────────── */
  --cx-s1: 4px;   --cx-s2: 8px;   --cx-s3: 12px;  --cx-s4: 16px;
  --cx-s5: 24px;  --cx-s6: 32px;  --cx-s7: 48px;  --cx-s8: 64px;

  /* ── HOUSE · radius. The panel world is generously rounded. ───────────── */
  --cx-radius-sm:    6px;   /* quiet buttons, chips-in-cell */
  --cx-radius-md:    9px;   /* inputs, rail items */
  --cx-radius-lg:    12px;  /* cards inside a panel, reading cards */
  --cx-radius-panel: 16px;  /* the panel itself */
  --cx-radius-modal: 18px;
  /* 999px. NOT the default for a container any more (owner ruling 2026-09-02): buttons take
     --cx-radius-md and every state chip takes --cx-radius-sm. This is now reserved for things
     that are actually ROUND — a stage-mark ring, the companion launcher, today's ring on a
     calendar numeral, and the person mark, where round-against-square is a stated semantic. */
  --cx-radius-pill:  999px;

  /* ── HOUSE · density. Authored, never a user setting. ─────────────────── */
  --cx-row-comfortable: 44px;
  --cx-row-compact:     32px;
  --cx-row: var(--cx-row-comfortable);

  /* ── HOUSE · elevation. The panel world is nearly flat. ──────────────────
     Separation is ground-contrast + radius + hairline. Shadow appears only
     where something genuinely floats ABOVE the plane: popover, panel, modal. */
  --cx-shadow-none:    none;
  --cx-shadow-hover:   0 4px 14px rgb(28 27 26 / .07);
  --cx-shadow-popover: 0 4px 14px rgb(28 27 26 / .09), 0 1px 2px rgb(28 27 26 / .05);
  --cx-shadow-modal:   0 24px 60px rgb(28 27 26 / .22);
  --cx-shadow-card:    0 .5px .5px rgb(28 27 26 / .10), 0 0 0 .5px rgb(28 27 26 / .04); /* the chart card — the one shadowed component (register ruling 2026-08-28) */

  /* A focus indicator must clear 3:1 against what it sits on (WCAG 2.1 SC 1.4.11).
     The 30%-alpha accent measured 1.58:1 on --cx-panel, 1.54:1 on --cx-accent-wash
     (a focused CURRENT scope option) and 1.80:1 dark. Solid accent behind a 1px panel
     halo keeps the same 3px footprint and costs no layout. Measured 2026-08-29. */
  --cx-focus-ring: 0 0 0 1px var(--cx-panel), 0 0 0 3px var(--cx-accent);

  --cx-scrim: rgb(28 27 26 / .28);      /* modal scrim — a BLUR, not a dim */
  --cx-scrim-blur: 3px;

  /* ── HOUSE · motion. Calm and quick. Never bounce, never overshoot. ───── */
  /* ── HOUSE · motion slot default size; a slot overrides it inline. ────────── */
  --cx-motion-w: 96px;
  /* the face a slot's shaded/lit cube faces mix from; a slot re-routes it (components.css) */
  --cx-motion-face: var(--cx-accent);
  --cx-spark-y: 0;      /* a dot-field sparkline cell's value, 0..1 — set inline per cell, never themed */
  --cx-bar-v: 0;        /* a bar's value, 0..1 of the plot — set inline per bar, never themed */
  --cx-bar-t: -1;       /* a bar's own target, 0..1; below 0 means none — set inline per bar */
  --cx-bar-v2: 0;       /* a stacked bar's second segment, 0..1 — set inline */
  --cx-bars-t: 0;       /* a bar plot's SHARED target, 0..1 — set on .cx-bars--shared */

  /* ── HOUSE · chart geometry. Not re-declared under dark — geometry is theme-free. ── */
  /* THE REGISTER, owner-ruled 2026-08-29. Chart marks are drawn in the peg's register:
     near-square corners, flat colour, NO outline. The outline was considered and dropped —
     it reads on a 96px glyph with six bars and becomes noise on a twenty-bar plot.
     THIS RETIRES D4 (the anchored-end rule, ruled the same day). D4 existed because a
     fully pilled bar detaches from its own axis and starts reading as a dot; at 2px there
     is no capsule left to detach, so the anchored/free distinction has nothing to carry.
     Both ends are square, one value for the whole family. */
  --cx-chart-radius:    4px;   /* a TRACK or frame: the container, rounded all round */
  /* THE TIP. D4 RETURNS, owner-ruled 2026-08-30, with a bigger free end than it ever had:
     "the rounded corners can go up to 8px, but only at the tip of the bar. the bottom of
     the bar should be flat like it's coming from the base of the chart."

     D4 was ruled on 2026-08-29, retired hours later when the register pass took the family
     square, and is now restored — the same rule, at 8px instead of a pill. Its original
     reasoning was always right: a value has an ANCHORED end that must meet its own baseline
     flat, and a FREE end that may be capped. Squaring both ends satisfied consistency and
     lost the anchoring; a pill on both lost the baseline. This is the third position and
     the correct one. Ranked bars anchor left, columns anchor bottom, gauges anchor left. */
  --cx-chart-tip:       8px;
  /* THE REGISTER'S OUTLINE. Owner-ruled 2026-08-30 after the no-outline pass lost the
     drawn quality he was after: "I like the comic-ness of them."

     PROPORTION, STATED HONESTLY. The pack's own stroke is 1.17% of its canvas — measured,
     148 strokes, median. Its bars are ~100px inside a 512px frame, so its outline lands
     near 1px. The DS's bars are 24-44px on their short side, where 1.17% is under half a
     pixel and cannot be drawn. So 1px here is roughly 2.5x the pack's proportion: this
     reads BOLDER than the peg does, and that is a deliberate consequence of our shapes
     being smaller, not a match. Sub-pixel was tried and is unreliable across displays.

     THE INK DOES NOT INVERT. An outline sits ON the fills, so the number that matters is
     outline-vs-fill, and the fills are bright in BOTH modes:
       #1c1b1a vs orange 4.76  vs blue 7.51  vs yellow 11.04   — identical light and dark
       #f2f0ec vs orange 3.18  vs blue 2.01  vs yellow  1.37   — and 14.79:1 on the ground
     Inverting made the line blaze against the dark ground while nearly vanishing against
     the fills it exists to draw. Declared once, on purpose, and NOT re-declared under
     [data-theme="dark"] — same reasoning as --cx-ink-on-vivid above. */
  --cx-chart-outline:     1px;
  --cx-chart-outline-ink: #1c1b1a;
  --cx-chart-stroke:    2px;    /* series line */
  --cx-chart-stroke-sm: 1.5px;  /* sparkline, small-multiple cell — the house glyph weight */
  --cx-chart-hair:      1px;    /* baseline, target, since-marker, any gridline */
  --cx-chart-dot:       4px;    /* end-dot radius */
  --cx-chart-ring:      2px;    /* panel-coloured ring on a dot */

  --cx-dur-fast: 120ms;
  --cx-dur:      140ms;
  --cx-dur-slow: 240ms;
  --cx-ease:        cubic-bezier(.2, 0, 0, 1);
  --cx-ease-in-out: cubic-bezier(.4, 0, .2, 1);
}

/* ============================================================================
   DARK — selected, never an automatic flip.
   Chart steps are re-picked for the dark band (L 0.48–0.67) and re-validated;
   the light steps FAIL it. Accent lifts so white-on-accent inverts to ink.
   ========================================================================= */
[data-theme="dark"] {
  --cx-ground:        #141312;
  --cx-panel:         #1e1d1c;
  --cx-panel-sunken:  #191817;
  --cx-line:          #302e2c;
  --cx-line-2:        #262423;
  --cx-line-strong:   #423f3c;

  --cx-ink:    #f2f0ec;
  --cx-ink-2:  #a8a29a;
  --cx-ink-3:  #8a847b;  /* 4.54:1 on panel, MEASURED 2026-08-26 (was #7d776f at 3.80) */
  --cx-ink-on-accent: #1c1b1a;   /* INVERTS — dark ink on the lifted accent */

  --cx-accent:        #f2f0ec;   /* = --cx-ink dark. 15.1:1 with --cx-ink-on-accent. */
  --cx-accent-hover:  #ffffff;
  --cx-accent-bright: #6b655d;
  --cx-accent-wash:   #2a2826;
  --cx-accent-quiet:  #e8e4de;   /* 11.6:1 on wash */

  --cx-canon:      #4fa89c;  --cx-canon-wash:  #1c2f2d;   /* 5.47:1 */
  --cx-working:    #98a0ad;  --cx-working-wash:#24262a;
  --cx-ok:         #56b07a;  --cx-ok-wash:     #1a2b21;
  --cx-warn:       #d1a13c;  --cx-warn-wash:   #33291a;
  --cx-error:      #e08379;  --cx-error-wash:  #33211f;
  --cx-info:       #7aa8db;  --cx-info-wash:   #1c2733;

  --cx-ai-line: color-mix(in oklab, var(--cx-accent-bright) 12%, var(--cx-accent-wash));

  --cx-series-1: #3598f9;
  --cx-series-2: #f34f0b;   /* the orange needs no dark step — it clears both bands */

  --cx-shadow-hover:   0 4px 14px rgb(0 0 0 / .45);
  --cx-shadow-popover: 0 4px 14px rgb(0 0 0 / .5), 0 1px 2px rgb(0 0 0 / .4);
  --cx-shadow-modal:   0 24px 60px rgb(0 0 0 / .65);
  --cx-shadow-card:    0 .5px .5px rgb(0 0 0 / .5), 0 0 0 .5px rgb(255 255 255 / .06);
  --cx-scrim: rgb(0 0 0 / .5);
}

[data-density="compact"] { --cx-row: var(--cx-row-compact); }

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