/* ============================================================
   TOKENS — the whole design system starts here.
   Nothing downstream should hardcode a colour, size, or easing.
   ============================================================ */

:root {
  /* ---- surface ------------------------------------------------ */
  --ink: #000000;            /* page ground */
  --paper: #ffffff;          /* primary type */
  --plate: #1a1a1a;          /* preview plate — a dark panel lifted off the ground */
  --plate-alt: #212121;      /* secondary preview plate */

  /* type on ink, by weight of attention */
  --t-primary: rgba(255, 255, 255, 1);
  --t-second: rgba(255, 255, 255, 0.62);
  --t-dim: rgba(255, 255, 255, 0.38);
  --t-faint: rgba(255, 255, 255, 0.22);

  /* type on plate. The plate is dark now, so these follow it — anything
     rendered back onto a plate stays legible without a second set. */
  --p-primary: rgba(255, 255, 255, 0.94);
  --p-second: rgba(255, 255, 255, 0.56);

  /* how far a section recedes in the index while another is hovered.
     Hover only pushes the others back — nothing brightens — so these are
     the entire effect, and they stay readable rather than dropping away. */
  --recede-label: rgba(255, 255, 255, 0.52);   /* rests at full white */
  --recede-text: rgba(255, 255, 255, 0.42);    /* rests at 0.62 */
  --recede-chip: rgba(255, 255, 255, 0.08);    /* rests at 0.09 */

  /* lines + fills */
  --hair: rgba(255, 255, 255, 0.13);
  --hair-soft: rgba(255, 255, 255, 0.10);   /* dividers — the reference's value */
  --chip: rgba(255, 255, 255, 0.09);
  --chip-hi: rgba(255, 255, 255, 0.16);

  /* button — the primary control across the site. Fills are translucent
     so the same token works on the black ground and on a light plate. */
  --btn-bg: rgba(255, 255, 255, 0.10);
  --btn-bg-hover: rgba(255, 255, 255, 0.17);
  --btn-bg-active: rgba(255, 255, 255, 0.23);
  --btn-fg: var(--t-primary);

  /* ---- accent -------------------------------------------------- */
  --accent: #1c1ccc;         /* deep electric blue */
  --accent-deep: #08084a;    /* blob core */
  --live: #35c05a;
  --warn: #e8875f;           /* a refused field — warm, not alarming */

  /* ---- type ---------------------------------------------------- */
  --serif: "Newsreader", "Times New Roman", Times, serif;
  --sans: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: "DM Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Mono carries this system, at two sizes:
     10px  chrome, section labels, chips  — the quiet register
     12px  ledes, row items, captions     — everything you actually read
     Both track at 0.1em, matching the reference. */
  --mono-size: 10px;
  --mono-body: 12px;
  --mono-track: 0.1em;
  --mono-lh: 1.5;            /* 15px on the 10px size */
  --mono-body-lh: 1.3;       /* 15.6px on the 12px size */

  /* Mono has a third job on the blog: it sets the reading matter itself —
     headlines, excerpts, pullquotes — in place of the serif. Those are
     sentence case and run to paragraph length, so the 0.1em label tracking
     is wrong twice over: it is loose enough to break a long line into
     letters, and it stretches a headline past its measure. A monospace face
     is already generously spaced by construction, so display sizes take
     nothing at all and reading sizes take a hair to keep 13px legible. */
  --mono-display-track: 0em;
  --mono-read-track: 0.01em;

  --display: clamp(22px, 1.75vw, 26px);  /* serif plate headline */
  --title: 20px;                          /* column title (sans) */
  --body: 13px;

  /* ---- geometry ------------------------------------------------ */
  /* Measured off haiqu.ai. The container caps at 1600 and centres; three
     equal columns each carry --col-pad, and the text inside caps at --col.
     So content = min(--col, container/3 − 2 × --col-pad), and BOTH views
     use that same figure — the rail is one column wide. */
  --maxw: 1600px;            /* page container ceiling */
  --col: 340px;              /* text measure cap */
  --pad-x: 60px;             /* nav + footer inset */

  /* The gutter absorbs whatever the three columns do not need, so the text
     holds --col all the way down instead of dipping. It tops out at the
     reference's 86px and floors at 20px.
     The reference instead steps 86 → 43 at 1280, which makes its text jump
     255 → 340 as the window NARROWS past that point. Interpolating between
     the same two end points removes that non-monotonic step. */
  --col-pad: clamp(20px, (min(100vw, var(--maxw)) - 3 * var(--col)) / 6, 86px);
  --nav-h: 56px;
  /* The scrim under the fixed nav. Just past the nav itself on an ordinary
     page — enough to keep the chrome legible over anything scrolling under
     it, and no more. The case-studies page overrides it below, where the
     pager sits in its own band beneath the nav and needs covering too. */
  --scrim-h: calc(var(--nav-h) + 4px);
  --col-end: 58px;           /* leaves ~70px of visual space under the last line */
  --footer-pad: 80px;        /* footer rule → site map */
  --radius: 60px;            /* preview plate */
  --plate-pad: clamp(26px, 3.8vw, 60px);
  --radius-btn: 8px;         /* buttons */
  /* contact form — the reference's own measurements */
  --radius-sheet: 28px;      /* the form card */
  --form-pad: 40px;
  --field-h: 42px;
  --radius-field: 10px;
  --field-bg: rgba(255, 255, 255, 0.12);
  --radius-sm: 3px;          /* chips */
  --flash-r: 100px;          /* the cursor flashlight — ~200px across */
  --reticle: 40px;           /* the cursor's corner frame, side to side */
  --btn-h: 26px;
  --btn-pad-x: 10px;

  /* rhythm — every vertical gap is one of these */
  --s1: 4px;
  --s2: 8px;
  --s3: 14px;
  --s4: 22px;
  --s5: 40px;
  --s6: 64px;
  --s7: 96px;

  /* ---- motion -------------------------------------------------- */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);      /* standard out-expo */
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);   /* symmetrical */
  /* the index→read slide: hangs, then accelerates away, as on the reference */
  --ease-in: cubic-bezier(0.6, 0, 0.85, 0.15);
  /* out-expo lands almost all of its distance in the first few frames, which
     is right for a control answering a click. A plate rising into view is not
     answering anything, so it gets an easeOutCubic instead — it keeps moving
     long enough to read as a glide rather than a snap. */
  --ease-soft: cubic-bezier(0.33, 1, 0.68, 1);
  --fast: 180ms;
  --mid: 420ms;
  --slow: 760ms;
  --slide: 640ms;            /* column slide out of the index */
  --reveal: 620ms;           /* a plate arriving under the scroll */
}

/* Only the case-studies page carries a pager, and only it marks the root
   with data-view. The scrim has to reach past the pager's band there. */
:root[data-view] { --scrim-h: calc(var(--nav-h) + 40px); }

/* The gutters step down with the viewport, as on the reference — the type
   scale never changes, only the space around it. */
@media (max-width: 1279px) { :root { --pad-x: 43px; } }
@media (max-width: 768px)  { :root { --pad-x: 20px; } }

@media (prefers-reduced-motion: reduce) {
  :root { --fast: 1ms; --mid: 1ms; --slow: 1ms; --reveal: 1ms; }
}
