/* Haive — the token system (DK-07 … DK-16).
 *
 * Two layers, and rules can only see the top one:
 *
 *   palette   `--p-<hue>-<step>`  values, named for what they ARE.
 *             Referenced only by the semantic block below.
 *   semantic  `--surface-*`, `--fg-*`, `--border-*`, …  jobs, named for
 *             what they are FOR. The only names any rule may reference.
 *
 * Vision §1.5's root cause was a token called `--color-text-faint`: the
 * name describes an appearance, so nothing in it said "not on 11px
 * type," and it ended up on every piece of 11px type on the platform. A
 * name that states a job carries the rule with it.
 *
 * Palette step convention: step ≈ (100 − CIE L*) × 10, rounded to the
 * nearest 5 — 0 is white, 1000 is black, larger is darker. The step is
 * measured from the value, not chosen for it, so two neighbouring
 * greys can never be given the same name by accident.
 *
 * **The values are not adjustable by eye.** They were chosen against
 * computed floors — 99 pairs across three themes, zero below floor
 * (DetailedDesign.md §3, DK-09). `design/contrast.md` carries the
 * generated table and `cargo xtask design` regenerates and compares it.
 *
 * Every job description lives in `design/tokens.md`.
 */

@layer tokens, base, layout, components, pages;

@layer tokens {
  :root {
    /* ---- palette: values. Referenced only by the semantic block. ---- */

    /* neutral */
    --p-neutral-0:   #ffffff;
    --p-neutral-40:  #f3f4f6;
    --p-neutral-70:  #e9ebef;
    --p-neutral-80:  #e6e8ed;
    --p-neutral-90:  #e4e6eb;
    --p-neutral-160: #ced1d9;
    --p-neutral-285: #a8afbc;
    --p-neutral-300: #a5acb9;
    --p-neutral-390: #8b93a1;
    --p-neutral-395: #8a92a0;
    --p-neutral-445: #7f8592;
    --p-neutral-450: #7d8593;
    --p-neutral-505: #6e7684;
    --p-neutral-555: #636977;
    --p-neutral-570: #5f6675;
    --p-neutral-580: #5c6472;
    --p-neutral-610: #565c6b;
    --p-neutral-720: #3c424e;
    --p-neutral-800: #2b303a;
    --p-neutral-820: #282c36;
    --p-neutral-825: #262a34;
    --p-neutral-830: #252a35;
    --p-neutral-875: #1d2028;
    --p-neutral-885: #1b1f27;
    --p-neutral-910: #171a21;
    --p-neutral-925: #14161c;
    --p-neutral-940: #101318;
    --p-neutral-975: #08090c;

    /* ink — the rail's own ramp. Neutral greys at rail luminance read
       as a void beside a light page; these carry the brand's own hue
       instead. Kept out of `--p-neutral-*` on purpose: nothing in the
       content pane may reach for them, and a separate prefix is how
       that stays checkable.

       `--p-ink-925` is the mark's own background, sampled from it —
       the rail is the largest surface the brand owns, and it should be
       the colour the brand is drawn on rather than an approximation of
       it. The four steps above are derived from that one. */
    --p-ink-925: #191b24;
    --p-ink-875: #22242f;
    --p-ink-825: #2c2f3d;
    --p-ink-820: #363a4c;
    --p-ink-580: #7b8299;

    /* violet — the brand. `--p-violet-305` is the hexagon's own colour,
       sampled from the mark, and it is what the dark theme and the rail
       draw the accent in. It measures 3.74 : 1 on white, which clears
       the 3.00 graphical floor and misses the 4.50 text floor, so the
       light theme cannot use it for a link. `--p-violet-620` is the
       same hue carried down until it clears text on the page (5.77 : 1)
       and `--p-violet-250` carried up until it clears text on the
       darkest panel a dark session has (5.16 : 1). The mark's own
       colour is what the *rail* draws the accent in, where it measures
       4.59 : 1 — see `--rail-accent`. */
    --p-violet-55:  #efecfe;
    --p-violet-305: #896bff;
    --p-violet-250: #a189ff;
    --p-violet-620: #6440dc;
    --p-violet-820: #251c4d;
    --p-violet-945: #100a20;

    /* green */
    --p-green-55:  #e3f4e9;
    --p-green-170: #a9d9bd;
    --p-green-205: #63dc99;
    --p-green-595: #2d6b48;
    --p-green-605: #0f6b37;
    --p-green-810: #12351f;

    /* amber */
    --p-amber-45:  #fdf1dc;
    --p-amber-200: #e5c187;
    --p-amber-205: #edbf58;
    --p-amber-625: #7a4f00;
    --p-amber-630: #6b5417;
    --p-amber-825: #352a0c;

    /* red */
    --p-red-60:  #fbeae9;
    --p-red-220: #eeb3ae;
    --p-red-275: #ff958d;
    --p-red-635: #a81f1a;
    --p-red-720: #6e2f2a;
    --p-red-830: #431f1c;

    /* ---- semantic: jobs. The only names any rule may reference. ---- */

    --surface-page:            var(--p-neutral-40);
    --surface-default:         var(--p-neutral-0);
    --surface-raised:          var(--p-neutral-0);
    --surface-sunken:          var(--p-neutral-70);
    --surface-accent-soft:     var(--p-violet-55);
    --surface-success-soft:    var(--p-green-55);
    --surface-warning-soft:    var(--p-amber-45);
    --surface-danger-soft:     var(--p-red-60);
    --fg-default:              var(--p-neutral-910);
    --fg-muted:                var(--p-neutral-610);
    --fg-subtle:               var(--p-neutral-555);
    --fg-on-accent:            var(--p-neutral-0);
    --accent:                  var(--p-violet-620);
    --success:                 var(--p-green-605);
    --warning:                 var(--p-amber-625);
    --danger:                  var(--p-red-635);
    --border-subtle:           var(--p-neutral-90);
    --border-default:          var(--p-neutral-160);
    --border-control:          var(--p-neutral-445);
    --border-strong:           var(--p-neutral-570);
    --border-status-success:   var(--p-green-170);
    --border-status-warning:   var(--p-amber-200);
    --border-status-danger:    var(--p-red-220);

    /* Light elevation is shadow; `--surface-raised` deliberately equals
       `--surface-default`. Dark elevation is the fill step above, and
       the shadow there is a supporting cue only (DK-10). */
    --shadow-raised:  0 1px 2px rgba(15,18,25,.08), 0 2px 6px rgba(15,18,25,.06);
    --shadow-overlay: 0 8px 28px rgba(15,18,25,.16);

    /* ---- the fixed chrome rail (DK-12) ----
       Deliberately theme-invariant: the rail's job is to read as chrome,
       not as page content, so it does not follow `prefers-color-scheme`.
       All fourteen of its pairs are computed once and hold in both
       themes. Reasons are recorded in `design/tokens.md`. */
    --rail-bg:             var(--p-ink-925);
    --rail-bg-hover:       var(--p-ink-875);
    --rail-bg-active:      var(--p-ink-825);
    --rail-border:         var(--p-ink-820);
    --rail-border-control: var(--p-ink-580);
    --rail-fg:             var(--p-neutral-80);
    --rail-fg-muted:       var(--p-neutral-285);
    --rail-fg-subtle:      var(--p-neutral-395);
    /* The rail draws the accent in the mark's own violet, not in the
       content theme's. The three status dots beside it already work
       this way — "the rail is fixed dark chrome, so its dots carry the
       dark ramp's value in both themes" — and the active-item marker
       was the one row that did not, which is exactly why it used to be
       the tightest row in the whole table (3.03 : 1). It measures
       4.59 : 1 here. `layout.css` re-points `--accent` to this inside
       `.hv-sidebar`, the same mechanism DK-12 already uses for
       `--surface-sunken`. */
    --rail-accent:         var(--p-violet-305);

    /* ---- type (DK-13) ---- */
    --text-xs:  .75rem;
    --text-sm:  .8125rem;
    --text-md:  .875rem;
    --text-lg:  1rem;
    --text-xl:  1.125rem;
    --text-2xl: 1.375rem;
    --text-3xl: 1.75rem;
    /* One step above `--text-3xl`, for a page's own title and nothing
       else. The scale stopped at 1.75rem, which is a *section* heading
       everywhere else in the system, so a page had no size that said
       "this is the page" — every screen opened at the same weight as
       the panel below it and nothing carried the eye. */
    --text-4xl: 2.25rem;
    --weight-regular: 400;
    --weight-medium:  500;
    --weight-bold:    650;
    --leading-ui:    1.4;
    --leading-prose: 1.6;

    /* ---- space (DK-14) ---- */
    --space-1: .25rem;
    --space-2: .5rem;
    --space-3: .75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4rem;

    /* ---- radius (DK-14) ---- */
    --radius-sm:   5px;
    --radius-md:   9px;
    --radius-lg:   14px;
    --radius-full: 999px;

    /* ---- control (DK-14) ---- */
    --control-height:    2rem;
    --control-height-lg: 2.5rem;
    --control-pad-x:     var(--space-3);

    /* ---- motion (DK-14, DK-28) ---- */
    --motion-fast: 120ms;
    --motion-base: 180ms;
    --motion-slow: 260ms;
    /* The one animation: a liveness halo on a rail row whose project is
       building, and on a run's current step. Long enough to read as a
       heartbeat rather than a flicker, and the only duration on the
       platform that is not a transition. */
    --motion-pulse: 1600ms;
    --ease-out:    cubic-bezier(0.2, 0, 0, 1);

    /* ---- border width (DK-14) ---- */
    --border-width:          1px;
    --border-width-emphasis: 2px;

    /* ---- measure, widths and breakpoints (DK-15, DK-24, DK-29) ---- */
    /* The two families `web/vendor/fonts/fonts.css` declares. They lived
       only in `legacy.css` until now, which made T-0403's deletion of
       that file a silent removal of Inter and JetBrains Mono from every
       migrated page (found while building T-0101). Theme-invariant. */
    --font-ui:     'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono:   'JetBrains Mono', ui-monospace, SFMono-Regular, Consolas, monospace;

    --measure:     68ch;
    --content-max: 84rem;
    /* The height a scrolling stream stops growing at — the pipeline's
       build log (T-0303). A bound is what makes `column-reverse` scroll
       to the newest line for free; without one the container never
       scrolls and a `cargo build` log is the whole page. */
    --stream-height: 24rem;
    /* The shell's first grid track (DK-24, T-0201). A geometry token, not
       part of the rail's eight-colour ramp above — it carries the
       `--rail-` prefix because it is the rail's own measurement, and it
       resolves to no colour, so it produces no contrast row. */
    --rail-width:  15rem;
    /* The narrowest a stat tile may be before its row drops a column
       (the console direction's overview and billing). A geometry token
       for the same reason `--stream-height` is one: it is a measured
       bound a layout depends on, not a spacing step — a tile narrower
       than this cannot hold `--text-2xl` digits and its own uppercase
       label on one line each, which is the whole point of the tile. */
    --stat-min:    11rem;
    --bp-compact:  48rem;
    --bp-wide:     90rem;

    color-scheme: light dark;
  }

  /* A theme block re-points the semantic layer and nothing else: no
     component rule, no palette redefinition, never inside
     `@layer components` (DK-11). */
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme='light']) {
      --surface-page:            var(--p-neutral-940);
      --surface-default:         var(--p-neutral-885);
      --surface-raised:          var(--p-neutral-830);
      --surface-sunken:          var(--p-neutral-975);
      --surface-accent-soft:     var(--p-violet-820);
      --surface-success-soft:    var(--p-green-810);
      --surface-warning-soft:    var(--p-amber-825);
      --surface-danger-soft:     var(--p-red-830);
      --fg-default:              var(--p-neutral-70);
      --fg-muted:                var(--p-neutral-300);
      --fg-subtle:               var(--p-neutral-390);
      --fg-on-accent:            var(--p-violet-945);
      --accent:                  var(--p-violet-250);
      --success:                 var(--p-green-205);
      --warning:                 var(--p-amber-205);
      --danger:                  var(--p-red-275);
      --border-subtle:           var(--p-neutral-800);
      --border-default:          var(--p-neutral-720);
      --border-control:          var(--p-neutral-505);
      --border-strong:           var(--p-neutral-450);
      --border-status-success:   var(--p-green-595);
      --border-status-warning:   var(--p-amber-630);
      --border-status-danger:    var(--p-red-720);
      --shadow-raised:  0 1px 2px rgba(0,0,0,.5);
      --shadow-overlay: 0 12px 40px rgba(0,0,0,.6);
    }
  }

  /* The same block again, so an explicit choice wins in both directions
     (DK-11): `[data-theme='dark']` on a light-scheme browser, and
     `[data-theme='light']` — excluded by the `:not()` above — on a dark
     one. It is duplication, and it is the only way to do this without a
     build step (PLATFORM.md §2). Gate check 6 compares the two sets so
     the duplication is held by a machine rather than by memory. */
  :root[data-theme='dark'] {
    --surface-page:            var(--p-neutral-940);
    --surface-default:         var(--p-neutral-885);
    --surface-raised:          var(--p-neutral-830);
    --surface-sunken:          var(--p-neutral-975);
    --surface-accent-soft:     var(--p-violet-820);
    --surface-success-soft:    var(--p-green-810);
    --surface-warning-soft:    var(--p-amber-825);
    --surface-danger-soft:     var(--p-red-830);
    --fg-default:              var(--p-neutral-70);
    --fg-muted:                var(--p-neutral-300);
    --fg-subtle:               var(--p-neutral-390);
    --fg-on-accent:            var(--p-violet-945);
    --accent:                  var(--p-violet-250);
    --success:                 var(--p-green-205);
    --warning:                 var(--p-amber-205);
    --danger:                  var(--p-red-275);
    --border-subtle:           var(--p-neutral-800);
    --border-default:          var(--p-neutral-720);
    --border-control:          var(--p-neutral-505);
    --border-strong:           var(--p-neutral-450);
    --border-status-success:   var(--p-green-595);
    --border-status-warning:   var(--p-amber-630);
    --border-status-danger:    var(--p-red-720);
    --shadow-raised:  0 1px 2px rgba(0,0,0,.5);
    --shadow-overlay: 0 12px 40px rgba(0,0,0,.6);
  }
}
