/* ============================================================================
   tokens.css — the one type scale, spacing rhythm and radius set for GCS.

   WHY THIS FILE EXISTS
   Measured 2026-07-26 across the five content stylesheets: the palette was
   already identical hex-for-hex (--bg-0 #0A0A0C, --ink-0 #F4EFE4,
   --brass-500 #C9A96E) in desk.css, ledger.css, site.css and build-wizard.css,
   so colour was never the inconsistency. TYPE was. desk.css — the stylesheet
   the paying client's 19-page desk runs on — defined ZERO type tokens and
   emitted 149 literal font-sizes across 23 distinct values on a half-pixel
   ladder (10, 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14, 14.5, 15, 15.5, 16,
   16.5, 17 ...). Nothing could line up on a vertical rhythm because there was
   nothing to line up to, and no author could pick the right size because there
   was no set to pick from. That is the mechanism behind "lack of attention to
   detail": not carelessness, an absent system.

   THE RULE THIS ENFORCES
   Simple enough for a toddler, prestigious enough for the top 1%. A reader
   should perceive HIERARCHY — a handful of deliberate steps — not a continuous
   smear of nearly-equal sizes. Half-pixel neighbours read as blur, never as
   emphasis.

   HOW IT WAS BUILT — and why nothing moves
   ledger.css already carried a decent semantic scale (11 / 13 / 15 / 16 / 17
   plus clamped display sizes) and 64 declarations already consumed it across
   the 53-page operator console. Those names and VALUES are reproduced here
   byte-for-byte, so lifting them into a shared layer moves nothing on the
   admin side. What is new is the handful of steps desk.css genuinely needed
   and ledger.css lacked, each one absorbing a cluster of desk's half-pixel
   literals rather than inventing a size:
       --fs-meta    12.5px  absorbs 12, 12.5     (desk: 25 declarations)
       --fs-dense   14px    absorbs 13.5, 14, 14.5 (desk: 40 declarations)
       --fs-title   19px    absorbs 19, 20, 21    (desk: 11 declarations)
       --fs-section 24px    absorbs 22, 24, 26    (desk: 6 declarations)

   LOAD ORDER
   Linked BEFORE desk.css / ledger.css / site.css in every shell, so a sheet
   can still override a token locally during migration. Once a sheet's literals
   are migrated its duplicate :root type block is deleted, leaving this file
   authoritative. Add a token here; never re-declare one downstream.
   ========================================================================= */

:root{
  /* ---- Colour -----------------------------------------------------------
     Measured 2026-07-27, and the note at the top of this file was WRONG about
     colour. "Already identical hex-for-hex" was true of the six ladder names
     that happen to appear in every sheet; it was not true of the system. The
     product ships 60 distinct hex values across five stylesheets and 118
     hardcoded hex inside rule bodies, and this file — the one place a token is
     supposed to live — declared 43 variables and NOT ONE COLOUR. So "one
     colour system" was a claim with no file behind it: every sheet re-declared
     its own :root and every new rule reached for a literal.

     Nothing here is invented. Every value below is the value the obsidian +
     brass product already renders; they are collected so there is one place to
     read them, one place to change them, and one name per role. The shells
     (desk.css, ledger.css) have had their duplicate :root colour blocks
     deleted in the same change, so this file is now authoritative rather than
     merely first in the cascade.

     PUBLIC PAGES DO NOT MOVE. site.css and black-label.css keep their own
     :root — they load without this file on the marketing pages the owner has
     signed off, and their ladders are the same hexes anyway (--bl-gold-500 and
     --brass-500 are both #C9A96E). Where a shared component may render on
     either family, it uses the fallback chain
     `var(--ink-2, var(--bl-ink-300, #B6AFA3))`, which resolves on both. */

  /* Obsidian ground — tonal bands, never flat pure black. */
  --bg-0: #0A0A0C;   /* base band                    */
  --bg-1: #0E0D10;   /* alternate band               */
  --bg-2: #111014;   /* deep inset wells             */

  /* Paper — documents lying on the desk; warm-tinted, one step up from ground */
  --paper-0: #121115;
  --paper-1: #17151A;
  --paper-2: #1B1820;

  /* Hairlines. --hairline-2 and --hairline-strong are the SAME rule under two
     names because the two shells each coined one; both are kept so neither
     sheet breaks, and they are defined once here instead of twice there. */
  --hairline:        #26232B;
  --hairline-2:      #3B3742;
  --hairline-strong: #3B3742;

  /* Ink — four steps, in descending emphasis. --ink-3 is the contrast floor
     (>= 5:1 on --bg-0); nothing readable may go quieter than it. */
  --ink-0: #F4EFE4;  /* display / the thing you read first */
  --ink-1: #E7E1D5;  /* body                               */
  --ink-2: #B6AFA3;  /* secondary                          */
  --ink-3: #8E8779;  /* tertiary, etched caps, meta        */
  --ink-a04: rgba(244, 239, 228, .04);
  --ink-a07: rgba(244, 239, 228, .07);

  /* Brass — money, active, focus. Never the primary action (see --action). */
  --brass-200: #EDDFB8;
  --brass-300: #DFC791;
  --brass-400: #D2B378;
  --brass-500: #C9A96E;
  --brass-600: #A08149;
  --brass-700: #6F5830;
  --brass-a08: rgba(201, 169, 110, .08);
  --brass-a14: rgba(201, 169, 110, .14);
  --brass-a28: rgba(201, 169, 110, .28);
  --brass-a45: rgba(201, 169, 110, .45);
  --brass-a60: rgba(201, 169, 110, .60);

  /* Semantic states. The hues already exist as --ok / --warn / --danger; the
     longer names are added as aliases so a new rule can say what it MEANS
     ("this is a success") without a reader having to know that "ok" is the
     house word. Both names resolve to the same colour, so nothing moves.

     INFO deliberately has no new hue. The product's notice colour is brass —
     that is what every "we are telling you something" surface already uses —
     so --info points at it rather than importing a blue that appears nowhere
     in the design. Inventing a fifth hue here would be fabricating a system. */
  --ok:     #8CD9AD;
  --warn:   #D9A441;
  --danger: #E0806C;
  --ok-a10:     rgba(140, 217, 173, .10);
  --ok-a35:     rgba(140, 217, 173, .35);
  --warn-a12:   rgba(217, 164, 65, .12);
  --warn-a40:   rgba(217, 164, 65, .40);
  --danger-a12: rgba(224, 128, 108, .12);
  --danger-a40: rgba(224, 128, 108, .40);
  /* The deep end of the success gradient. It existed as a bare #5FBD8A in
     desk.css, which is how a sixth hue gets into a five-hue system without
     anyone deciding to add one. Named, so the next author can see it. */
  --ok-deep: #5FBD8A;
  --success:      var(--ok);
  --success-wash: var(--ok-a10);
  --success-edge: var(--ok-a35);
  --warning:      var(--warn);
  --warning-wash: var(--warn-a12);
  --warning-edge: var(--warn-a40);
  --danger-wash:  var(--danger-a12);
  --danger-edge:  var(--danger-a40);
  --info:      var(--brass-300);
  --info-wash: var(--brass-a08);
  --info-edge: var(--brass-a28);

  /* The one action colour. Ivory on obsidian, never gold — brass is reserved
     for money/active/focus, so the single primary action stays unmistakable. */
  --action:       #F1EDE4;
  --action-hover: #FFFFFF;
  --action-ink:   #14130F;
  --action-top:   #FBF7EE;  /* the light end of the primary button's gradient */
  --btn-ink:      #191307;  /* ink ON a filled primary                        */

  /* Elevation. One key light, upper-left; no coloured shadows. */
  --shadow-lift:  0 2px 4px rgba(0,0,0,.4), 0 18px 40px -22px rgba(0,0,0,.85), 0 48px 90px -60px rgba(0,0,0,.9);
  --shadow-float: 0 4px 10px rgba(0,0,0,.5), 0 30px 60px -30px rgba(0,0,0,.9), 0 70px 120px -70px rgba(0,0,0,.95);
  --edge-top:     inset 0 1px 0 rgba(244,239,228,.06);
  --shadow-1:     rgba(3, 2, 4, .55);
  --shadow-2:     rgba(3, 2, 4, .78);
  --key:          0 40px 90px -50px rgba(0,0,0,.9);
  --lift-doc:     0 1px 0 rgba(255,255,255,.035) inset, 0 24px 48px -28px rgba(0,0,0,.78);
  --lift-menu:    0 24px 60px -20px rgba(0,0,0,.85);
  --scroll-thumb: #2E2B34;
  --focus-ring:   2px solid var(--brass-500);

  /* ---- Type scale -------------------------------------------------------
     Semantic, not numeric: the name says what the text IS, so the right step
     is obvious without consulting a ratio. Eleven steps cover 11px -> display.
     Values in rem against a 16px root; the px comment is the rendered size. */

  /* Carried over from ledger.css unchanged — the operator console already
     consumes these in 64 declarations and must not shift. */
  --fs-cap:       0.6875rem;  /* 11px   — true micro-caps: table heads, eyebrows  */
  --fs-note:      0.8125rem;  /* 13px   — a note UNDER a figure                   */
  --fs-row:       0.9375rem;  /* 15px   — table rows, list rows: read all day     */
  --fs-fine:      0.9375rem;  /* 15px   — explanatory copy (deliberately not 13.5)*/
  --fs-body:      1rem;       /* 16px   — body copy                               */
  --fs-lede:      1.0625rem;  /* 17px   — the one-sentence brief, intro copy      */

  /* New steps: the sizes desk.css was expressing as half-pixel literals. */
  --fs-meta:      0.78125rem; /* 12.5px — meta, timestamps, secondary labels      */
  --fs-dense:     0.875rem;   /* 14px   — dense UI rows; the client desk workhorse*/
  --fs-title:     1.1875rem;  /* 19px   — card and panel titles                   */
  --fs-section:   1.5rem;     /* 24px   — section headings                        */

  /* Fluid display sizes, carried from ledger.css unchanged. */
  --fs-h2-serif:  clamp(1.9rem, 3.3vw, 3rem);
  --fs-outcome:   clamp(1.7rem, 2.7vw, 2.5rem);
  --fs-metric:    clamp(2.3rem, 3.4vw, 3.6rem);
  --fs-metric-lg: clamp(2.8rem, 4vw, 4.2rem);
  --fs-display:   clamp(3.3rem, 7.6vw, 6.9rem);

  /* ---- Line height ------------------------------------------------------
     Tied to role, because a 15px table row and a 15px paragraph want
     different leading and previously each author guessed. */
  --lh-tight:  1.15;  /* headings, metrics                    */
  --lh-snug:   1.35;  /* card titles, dense rows              */
  --lh-normal: 1.55;  /* body copy                            */
  --lh-relaxed:1.65;  /* long-form explanatory prose          */
  --lh-loose:  1.9;   /* airy lists                           */

  /* ---- Optical letterspacing --------------------------------------------
     Small caps need tracking or they read as a smudge. --ls-cap was declared
     ONLY in ledger.css, and 44 operator pages were moved onto desk.css --
     which references it and never declared it. `letter-spacing: var(--ls-cap)`
     with no fallback is an INVALID declaration, so those pages have been
     rendering their small-cap eyebrows with no tracking at all. Same story for
     `transition: color var(--dur) var(--ease-out)` on .linklist: no token, no
     transition. Both are silent because the markup is right and the rule is
     right -- only the variable is missing, which no markup test can see. */
  --ls-cap:  0.16em;
  --ls-etch: 0.19em;
  --measure: 62ch;

  /* ---- Spacing rhythm ---------------------------------------------------
     Measured: desk.css used 33 distinct padding/margin/gap values and
     ledger.css 43 — 3px next to 4px next to 5px, which is what makes cards
     drift a few pixels apart from page to page. This is a 2px-based ladder
     covering the values actually in use, with the odd ones snapped out. */
  --space-1:  2px;
  --space-2:  4px;
  --space-3:  6px;
  --space-4:  8px;
  --space-5:  10px;
  --space-6:  12px;
  --space-7:  14px;
  --space-8:  16px;
  --space-9:  18px;
  --space-10: 20px;
  --space-11: 22px;
  --space-12: 24px;
  --space-14: 28px;
  --space-16: 32px;
  --space-20: 40px;
  --space-24: 48px;

  /* ---- Radius -----------------------------------------------------------
     --r-control / --r-surface are carried from ledger.css unchanged; desk.css
     hardcoded 12px and 14px for the same two roles. */
  --r-control: 8px;
  --r-surface: 12px;
  --r-panel:   16px;  /* floating panels: the assistant widget, drawers */
  --r-pill:    999px;
  --r-btn:     12px;  /* the one primary/secondary button radius, everywhere */

  /* ---- The page title ---------------------------------------------------
     Measured live 2026-07-27 at a 1280px viewport, on the deployed head: the
     product rendered its h1 at FOUR different sizes depending on which page
     you happened to open.
         76.0px / 600  .greet__hi        client desk (19 pages), operator (45)
         64.0px / 600  .pagehead__title  client desk (5 pages),  operator (8)
         46.1px / 500  h1.h-serif        operator console on ledger.css
         42.2px / 500  h1.h-serif        client login and the error pages
     Opening /admin/review and then /admin/operators — two pages of the same
     operator console, one click apart — moved the headline by 30 pixels and
     changed its weight. That is not a detail a buyer can name; it is the
     reason a product reads as assembled rather than designed.

     ONE value now, and it is the 64px step, not the 76px one. Reasons, in the
     owner's own rubric: (1) exactly one obvious primary action per screen —
     a 76px serif "Good morning" is the loudest thing on the desk and competes
     with the button that actually does the work; at 64px the heading still
     opens the page and the action wins. (2) Restraint. 76px at 1280 is a
     magazine cover, not a desk a person works in all day. (3) It costs less
     vertical space, so the first real content sits higher on every page.
     The 46/42px ledger heading rises to meet it, which is what makes the two
     operator shells finally look like one console. */
  --h1-size:   clamp(40px, 5vw, 64px);
  --h1-lh:     .96;
  --h1-weight: 600;
  --h1-track:  .3px;

  /* ---- Motion -----------------------------------------------------------
     One duration set, so nothing animates at a speed another surface chose.
     Rubric point 9 is restraint: these are deliberately short. */
  --ease:        cubic-bezier(.2, .7, .3, 1);
  --ease-out:    cubic-bezier(.2, 0, 0, 1);
  --dur-fast:    120ms;
  --dur-normal:  200ms;
  --dur-slow:    320ms;
  --dur:         160ms;  /* ledger.css's name for the same idea; both resolve */
}

/* Anyone who has asked their OS to stop moving things gets a still interface.
   Previously unhandled: the operator landing surface ran an animating WebGL
   canvas with no fallback at all. */
@media (prefers-reduced-motion: reduce){
  :root{ --dur-fast: 0ms; --dur-normal: 0ms; --dur-slow: 0ms; }
  *, *::before, *::after{
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
