/* ============================================================================
   GENERATED — DO NOT EDIT THIS FILE.

   Copied from C:\Users\Landon\zoltrak-store\tokens.css by tools/sync.py.
   Edit it THERE and re-run the sync; anything changed here is overwritten
   without warning and, worse, silently disagrees with the store in the
   meantime.
   ============================================================================ */

/* ============================================================================
   ZOLTRAK STORE — tokens.css
   The single source of truth for every colour, size and radius in Zoltrak.

   RULE: the app never invents a colour. If a value is not in here, it does not
   go in a module. This exists because 396 hardcoded literals had to be swept
   out of knull.css and the modules the first time the palette changed — the
   tokens were right and the app still looked wrong, because the tokens were
   not where the colours actually lived.

   STATUS OF EACH BLOCK
     MEASURED    — sampled from a reference with tools/sample.py. Trustworthy.
     PROVISIONAL — read by eye from a screenshot. Replace when a reference for
                   it lands in references/. Do not defend these in an argument.
   ============================================================================ */

:root {
  /* ── SURFACES ─────────────────────────────────── MEASURED ──────────────
     Sampled from references/Zoltrak Theme.png. THE BIG CORRECTION: every
     eyeballed guess was about ten times too light. The reference ground is
     essentially pure black — #000105, lightness 1% — and the cards sit at 3%,
     not the 5–8% that "a card must lift off the ground" reasoning produced.
     The whole board is nearly black and the separation comes from the BORDER,
     not from a fill difference.

     The border is the other correction: it is dark VIOLET (#0c0618, hue 260),
     not a neutral gray. A gray hairline on this ground reads as dirty.       */
  /* ── BLACK AND GREY (2026-08-12) ─────────────────────────────────────────
     Landon's call, off a side-by-side of the real dashboard at four levels of
     darkness. The ramp above was measured off the reference image and was
     right about the LIGHTNESS; it was wrong about one thing, and the
     comparison made it obvious:

       the border was doing nothing.

     #0c0618 is a violet so dark that against #08080b it never drew an edge at
     all. The note above says "the separation comes from the BORDER, not from a
     fill difference" — and there was no border. Every calendar cell, every KPI
     tile, was floating on a flat sheet. That is most of why the board has
     always read as slightly unfinished.

     So: a true black ground, cards a clear step above it, and a NEUTRAL grey
     line that is actually visible. The violet cast comes out of the ramp
     entirely — grey on black reads as clean here, not dirty, because there is
     no longer a violet ground for it to sit against.

     ── "BARELY THERE" (2026-08-13) ────────────────────────────────────────
     Landon's pick, chosen by stepping through 25 of these live on his own
     screen rather than off my screenshots — see modules/surfacelab.js for why
     that mattered. It is a QUIETER ramp than the one above, not a louder one:

       the box sits five points off the page instead of thirteen
       the edge drops from #1f1f1f to #171717

     So the separation comes almost entirely from a hairline, and the cards
     barely lift at all. That is the opposite of what the measured note at the
     top of this block argued for, and it is right anyway: the reference was a
     picture of somebody else's product, and this is his.

     One thing improves for free. Text now sits on #050505 instead of #0d0d0d,
     so every tier in the ramp below gains a little contrast rather than losing
     it. Measured, not assumed: --z-faint goes 4.22:1 -> 4.42:1. Better, and
     still under the 4.5:1 that small text wants, so it stays held where it is
     and the note beside it still applies. */
  --z-ground:     #000000;
  --z-panel:      #050505;   /* was #0d0d0d */
  --z-card:       #050505;   /* was #0d0d0d */
  --z-card-hi:    #050505;   /* was #0d0d0d — cards are flat, see shell.css */
  --z-raised:     #0f0f0f;   /* was #171717 */

  --z-line:       #171717;   /* was #1f1f1f */
  --z-line-soft:  #171717;   /* was #151515 — the lab held these equal */

  /* ── ACCENT ───────────────────────────────────── MEASURED ──────────────
     Hue 263–273, and I had missed it in BOTH directions: #a855f7 (hue 280) was
     too magenta, #8b5cf6 (hue 258) too blue. The real thing sits between them
     and is far more saturated than either.                                  */
  --z-accent-fill: #6b27d6;   /* @1043,352 the price pill's solid fill */
  --z-accent:      #8b30ef;   /* the workhorse, between fill and arc */
  --z-accent-hi:   #a344ff;   /* @955-1052,118-178 win-rate gauge arc */
  --z-accent-glow: #d976ff;   /* @58-128,20-92 logo highlight */
  --z-accent-deep: #3d1080;
  --z-accent-fade: linear-gradient(180deg, #a344ff 0%, #8b30ef 46%, #4c1596 100%);

  /* -- THE Zoltrak purple ------------------------------------------------
     When Landon asks for "purple", this is it and nothing else: dark-toned,
     descending into a black shade at the foot, the same fall the logo Z makes.
     A FLAT purple shipped twice and was rejected twice -- once as too light
     (it read pink) and once as too even (--z-accent, a violet slab). The
     shade is the identity; a single hex cannot carry it.

     Text takes the gradient through background-clip. --z-purple-flat is only
     for what cannot hold a gradient: an SVG fill, a border, a 1px rule. It
     never starts at --z-accent-hi, because that light violet IS the pink. */
  --z-purple: linear-gradient(180deg, #8b30ef 0%, #6b27d6 38%,
              #55199f 72%, #45128c 100%);
  --z-purple-flat: #6b27d6;

  /* ── SEMANTIC ────────────────────────────────────── ADOPTED ────────────
     These are VORTEX's green and red, not this reference's. Landon put the two
     apps side by side, saw they did not match, and chose one house tone across
     everything he builds. The measurements below are kept because they are
     true about the reference image — they are simply no longer what ships.

       measured here   green #0df072 hsl(147,90%,50%)   red #f4252c hsl(358,90%,55%)
       shipping        green #2ee6a8 hsl(160,78%,54%)   red #f2554a hsl(  4,85%,62%)

     Do not "correct" this back by re-sampling the reference. It is a choice.

     The glow is not decoration
     here — it is the thing that has been asked for in every single round, so
     it is a token, not an effect someone can quietly drop.                 */
  /* RE-MEASURED on the reference's thickest glyphs, where antialiasing cannot
     pull the value. The first pass sampled thin text and landed on a green
     18 points under-saturated — hsl(144,72%,45%) against the reference's
     hsl(146,90%,50%) — which is exactly why it read as dull.

       big 24H P&L number   #0edc69  hsl(147, 88%, 46%)   dominant
       +2.48%               #0df072  hsl(147, 90%, 50%)   peak
       watchlist +1.85%     #16ee74  hsl(146, 86%, 51%)   peak
       -$105.32             #f41d28  hsl(357, 91%, 54%)   peak
       watchlist -0.65%     #f32a2f  hsl(359, 89%, 56%)   peak            */
  --z-green:    #2ee6a8;   /* hsl(160, 78%, 54%) — Vortex */
  --z-green-br: #54f0bd;
  --z-red:      #f2554a;   /* hsl(  4, 85%, 62%) — Vortex */
  --z-red-br:   #ff7a70;
  --z-glow-green: 0 0 6px rgba(46,230,168,.55), 0 0 18px rgba(46,230,168,.32);
  --z-glow-red:   0 0 6px rgba(242,85,74,.55), 0 0 18px rgba(242,85,74,.32);

  /* ── TEXT ─────────────────────────────────────── MEASURED ──────────────
     Peaks off the reference. Thin strokes never reach full coverage, so a
     small label's measured peak sits BELOW its true colour — the ramp below
     is the measurements corrected for that, not the raw numbers.           */
  /* The reference's headline numbers measure pure white, but pure white on a
     near-black ground is the one thing Landon keeps calling out — it glares,
     and it flattens the ramp because every other tier is grey. Headline
     numbers sit one step ABOVE body text and nowhere near #fff. */
  --z-num:   #b4b4b4;   /* was #c7c7c7 — one step down, see the note below */
  /* Pulled down too, at Landon's ask: on his screen #e2e4ee was what read as
     "white". It also left the ramp INVERTED — the body tier was brighter than
     the headline-number tier above it, which is my doing from when --z-num came
     off pure white. Order is restored: num > text > muted > dim > faint, with a
     real step between each. Both new values clear 6:1 on the card ground. */
  /* ── THE BLUE CAST IS OUT, THE LIGHTNESS IS UNTOUCHED (2026-08-12) ───────
     Black and grey means grey text, not brighter text. Every value below is
     the SAME luminance as the cool one it replaces, converted straight to
     neutral — so the ramp Landon asked for twice (num > text > muted > dim >
     faint, nothing near #fff, nothing that glares) survives the change
     exactly. Only the hue moved.

     Doing this the obvious way — jumping the top of the ramp to #ffffff to
     match the mock — would have undone both of those corrections in one go. */
  /* ── ONE STEP DARKER (2026-08-13) ────────────────────────────────────────
     Landon's ask, and the top four moved. --z-faint did NOT, because it was
     already at the bottom: it measures 4.22:1 against the card ground, which is
     under the 4.5:1 that small text needs to stay readable, and it carries the
     tiny uppercase labels. Taking the whole ramp down together would have
     pushed it to 3.9:1 and made the smallest writing on every screen the
     hardest thing on it.

     So the ramp compresses from the top rather than sliding as a block. Every
     tier still steps down in order with 16–22 points between them, and the four
     that moved all clear 5:1 on the card.

     ── AND ONE STEP DARKER AGAIN, same day, same reason ──────────────────
     --z-dim is the one that had to be held back this time. A full step would
     have landed it on #7a7a7a, five points off --z-faint — two tiers that far
     apart are the same colour to look at, and the ramp would have lost a rung
     rather than got darker. It stops at #808080 instead, which keeps a real
     14-point gap and still clears 4.9:1.

     Where the room actually is, measured on the card ground: num had 68 points
     left before 4.5:1, text 52, muted 30, dim 12. That is why the top three
     move freely and the bottom two barely move at all. */
  --z-text:  #a4a4a4;   /* was #bababa */
  --z-muted: #8e8e8e;   /* was #a3a3a3 — table headers */
  --z-dim:   #808080;   /* was #909090 */
  --z-faint: #757575;   /* held — already the darkest small text can go */

  /* ── DERIVED ──────────────────────────────────── DERIVED ───────────────
     Not sampled — worked out FROM the measured values above, for the jobs the
     reference does not show a swatch for. They exist so modules stop inventing
     one-off tints: 108 distinct stray colours had accumulated across the app,
     including warm creams and ambers left behind by the old gold theme that no
     token change could ever have reached.

     Ink = the text colour that sits ON a filled accent/green/red chip. It has
     to be near-black, and it has to carry the chip's own hue or it reads as a
     smudge rather than as type. */
  --z-ink-accent: #150429;
  --z-ink-green:  #041512;
  --z-ink-red:    #2a0d0a;

  /* semantic depth — fills, edges and hovers for green/red surfaces */
  --z-green-deep: #0a9e4a;
  --z-green-line: #0b6b33;
  --z-green-dark: #05301a;
  --z-red-deep:   #c1121a;
  --z-red-line:   #7d1218;
  --z-red-dark:   #3d0a0d;

  /* accent depth — between --z-accent-fill and --z-accent-deep */
  --z-accent-soft: #5b4499;

  /* the scrollbar is chrome, not content: neutral, and the only place in the
     app allowed a hueless gray */
  --z-scroll:    #34343d;
  --z-scroll-hi: #4a4a56;

  /* ── TYPE ─────────────────────────────────────── MEASURED ──────────────
     Whole pixels, always. Half-pixel sizes force subpixel positioning and are
     the single most common cause of "it looks blurry" in this app.         */
  --z-h1:    32px;
  --z-big:   28px;
  --z-kpi:   24px;
  --z-stat:  21px;
  --z-title: 17px;
  --z-nav:   15px;
  --z-label: 14px;
  --z-small: 13px;
  --z-th:    12px;   /* uppercase table headers, letter-spaced */
  --z-tiny:  11px;   /* the floor — below this a glow turns glyphs to mush */

  /* ── SHAPE + RHYTHM ───────────────────────────── MEASURED ──────────────  */
  --z-r-card: 14px;
  --z-r-box:  10px;
  --z-r-pill: 999px;
  --z-gap:    12px;   /* between cards */
  --z-pad:    16px;   /* inside a card */
  --z-row:    11px;   /* table row padding, vertical */

  /* ── DEPTH ────────────────────────────────────── PROVISIONAL ───────────  */
  --z-shadow-card: 0 14px 34px -26px #000;
  --z-bloom: radial-gradient(26% 20% at 4% 1%, rgba(139,48,239,.16), transparent 60%);
}

/* ── THINGS THAT ARE NOT COLOURS BUT BREAK THE LOOK IF WRONG ──────────────
   Recorded here because each one cost a round trip:

   · border-color defaults to currentColor. Any border without an explicit
     colour paints in the text ramp — that is where "white outlines" come from.
   · A `.x button { color: inherit }` reset is (0,1,1) and beats `.x-btn { color }`
     at (0,1,0) regardless of source order.
   · Panels positioned on fractional pixels blur everything inside them.
   · line-height:1 inside overflow:hidden clips ascenders and descenders.
   · SVG `stroke="…"` is a presentation attribute and loses to ANY css rule,
     including a host page's reset. Use inline style for chart strokes.      */
