/* ============================================================
   tokens.css — design system passport (BRIEF §4, canonical)
   Values extracted from docs/reference/index-v5.dc.html.
   Where the reference and BRIEF disagree, BRIEF wins:
   temp −12 (ref default +12), sat 0.7 (ref 0.75),
   tagline right-edge @0.85× (ref centered @1×).
   ============================================================ */

:root {
  /* ---- reference scale unit ----
     The reference is a 1440×860 canvas scaled by
     min(1.15, vw/1440, vh/860). --u reproduces that: N px on
     the canvas = calc(N * var(--u)); the vh term keeps the
     chrome the same size on every page as on the index stage.
     Floor keeps small type legible below ~1080px; mobile gets
     its own pass. */
  --u: clamp(0.75px, min(calc(100vw / 1440), calc(100vh / 860)), 1.15px);

  /* ---- color ---- */
  --ink: #0E1116;
  --paper: #E9E9E4;
  --secondary: #8E9096;
  --numerals: #5E6268;
  --tagline-color: #C6C8C6;
  --meta-strong: #D2D3D0;   /* tile client line */
  --meta-on-image: #A7A9AC; /* metadata set over photos — lifted from --secondary for legibility */
  --rule: #565A60;          /* active-nav underline */
  --rule-lang: #6E7278;     /* active language underline */

  /* ---- living background v2 "field and matter" (BRIEF §4/§4b) ----
     Rebuilt checkpoint by checkpoint after the 18.07 incident; one
     config point for the whole .bgroot stack (base.css). Step 1:
     duotone two-pole field over base INK + vignette, static. */
  --bg-field:
    radial-gradient(120% 95% at 80% 0%, #253243 0%, rgba(37, 50, 67, 0) 60%),
    radial-gradient(110% 90% at 6% 100%, #2f2016 0%, rgba(47, 32, 22, 0) 58%);
  --bg-grad: 1.2;            /* field strength (layer opacity; >1 clamps —
                                tuning direction is downward) */

  /* grain-matter tile (step 4, validated by eye 18.07: 99% black,
     ~1% sparse soft grains, max brightness 118/255): fractalNoise
     0.9 / 2 octaves + feComponentTransfer table 0 0 0 0.62 — the
     lab threshold, but the ceiling is 0.62 instead of clipping to
     white, so sparks cannot exist by construction. STATIC by rule.
     Tiles change only by minimal deltas from eye-validated ones. */
  --bg-material-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20width%3D'240'%20height%3D'240'%3E%3Cfilter%20id%3D'n'%20x%3D'0'%20y%3D'0'%20width%3D'100%25'%20height%3D'100%25'%3E%3CfeTurbulence%20type%3D'fractalNoise'%20baseFrequency%3D'0.9'%20numOctaves%3D'2'%20stitchTiles%3D'stitch'%20seed%3D'11'%2F%3E%3CfeColorMatrix%20type%3D'matrix'%20values%3D'0.33%200.33%200.33%200%200%200.33%200.33%200.33%200%200%200.33%200.33%200.33%200%200%200%200%200%200%201'%2F%3E%3CfeComponentTransfer%3E%3CfeFuncR%20type%3D'table'%20tableValues%3D'0%200%200%200.62'%2F%3E%3CfeFuncG%20type%3D'table'%20tableValues%3D'0%200%200%200.62'%2F%3E%3CfeFuncB%20type%3D'table'%20tableValues%3D'0%200%200%200.62'%2F%3E%3C%2FfeComponentTransfer%3E%3C%2Ffilter%3E%3Crect%20width%3D'240'%20height%3D'240'%20filter%3D'url(%23n)'%2F%3E%3C%2Fsvg%3E");
  --bg-material-op: 0.26;    /* sanctioned ceiling; 0.18 was imperceptible */
  --bg-material-scale: 2.5;  /* grain size: 240px tile → 600px */

  /* engineering dither against banding (step 2): fine full-range
     240px noise at 1:1 — mathematics, not aesthetics; do not
     restyle. Turning it off in devtools must bring the bands back.

     color-interpolation-filters='sRGB' is LOAD-BEARING, not
     decoration. SVG filters default to linearRGB; feTurbulence then
     emits noise centred on linear 0.5, which the browser encodes to
     sRGB ~0.73 for display. Measured on the shipped tile: values
     112..231, mean 186 — noise sitting in the top third of the
     range, not around the middle. Under soft-light a source that
     is almost always > 0.5 almost always LIGHTENS, so the layer
     delivered +2.54/255 of flat lift against only 0.51/255 of
     noise at INK: a 5:1 brightener, which is why reordering it
     (checkpoint 1) changed nothing visible — a uniform lift has no
     contour to break. With sRGB the same turbulence (same seed,
     frequency, octaves — identical grain) lands 42..203 mean 126:
     lift drops to 0.14/255, noise holds at 0.54/255. Spatial
     character unchanged; only the tone mapping is repaired. */
  --bg-dither-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20width%3D'240'%20height%3D'240'%3E%3Cfilter%20id%3D'n'%20x%3D'0'%20y%3D'0'%20width%3D'100%25'%20height%3D'100%25'%20color-interpolation-filters%3D'sRGB'%3E%3CfeTurbulence%20type%3D'fractalNoise'%20baseFrequency%3D'0.9'%20numOctaves%3D'2'%20stitchTiles%3D'stitch'%20seed%3D'4'%2F%3E%3CfeColorMatrix%20type%3D'matrix'%20values%3D'0.33%200.33%200.33%200%200%200.33%200.33%200.33%200%200%200.33%200.33%200.33%200%200%200%200%200%200%201'%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D'240'%20height%3D'240'%20filter%3D'url(%23n)'%2F%3E%3C%2Fsvg%3E");
  --bg-dither-op: 0.165;     /* calibrated on the author's screen */

  --bg-vignette-op: 1;
  --bg-weave: running;       /* paused = stop the gate weave */
  --bg-chroma: running;      /* paused = stop the field breathing */

  /* ---- image grade (at rest; hover = original + scale) ----
     lift 0 · gamma 1 · gain 0.94 · temp −12 · tint 0 · sat 0.7
     Implemented as SVG filter #grade (partial: grade-filter.html). */
  --grade-filter: url(#grade);
  --hover-scale: 1.02;
  --ease-slide: cubic-bezier(0.25, 0, 0.15, 1);

  /* How long the hover zoom takes. 0.70s until 12.09.2026, when four
     rounds of measurement on the author's machine established that
     the zoom's visible stepping is not a rendering fault that can be
     fixed but a consequence of how little the picture actually
     moves — and that the only thing which helps is giving the eye
     less time to resolve the steps. 0.35s is the author's choice:
     the slowest setting that reads acceptably, a faint step still
     visible. NOT settled — see docs/OPEN-ISSUES.md, which holds the
     whole experimental record and what is left to try. */
  --hover-zoom-time: 0.35s;
  --grade-transition: filter 0.6s ease, transform 0.6s var(--ease-slide);

  /* ---- type roles (BRIEF §4: roles are exclusive) ----
     grotesque   = name + nav ONLY
     serif italic = display lines + film titles ONLY
     monospace   = ALL metadata, labels, brackets, footer, switcher */
  --font-serif: "Cormorant", "Cormorant Garamond", Georgia, serif;
  --font-grotesque: "Space Grotesk", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Space Mono", "Courier New", monospace;

  /* ---- header composition (canvas px → ×--u) ---- */
  --name-comp-width: calc(400 * var(--u)); /* SLAVA…GRYSHANIN spread */
  --name-size: calc(18 * var(--u));
  --name-tracking: 0.24em;
  --header-top: calc(30 * var(--u));
  --header-gap: calc(15 * var(--u));
  --tagline-scale: 0.85;                   /* BRIEF §4; ref default 1 */
  --tagline-size: calc(21 * var(--u) * var(--tagline-scale));
  --tagline-tracking: 0.04em;
  --nav-size: max(calc(10.5 * var(--u)), 9px);
  --nav-tracking: 0.18em;
  --nav-gap: calc(24 * var(--u));

  /* ---- metadata / mono scale ---- */
  --meta-size: max(calc(9.5 * var(--u)), 8.5px);
  --meta-tracking: 0.22em;
  --edge-x: calc(40 * var(--u));           /* switcher/footer inset */
  --footer-bottom: calc(22 * var(--u));

  /* ---- roman numeral section anchors ---- */
  --numeral-size: calc(58 * var(--u));
  --numeral-opacity: 0.5;                  /* BRIEF §4 "quiet anchors" */

  /* ---- layout ---- */
  --page-pad: clamp(1.25rem, 4vw, 3rem);
}

/* ============================================================
   Mobile pass (≤768px). Below ~1080px --u sits on its 0.75px
   floor, so canvas math stops scaling; these overrides recompose
   the chrome for portrait phones instead of shrinking it.
   ============================================================ */
@media (max-width: 768px) {
  :root {
    /* mobile grade policy (BRIEF §4): no muted grade below the
       breakpoint — imagery in original color, since the
       rest/hover pairing does not exist on touch. Every consumer
       reads var(--grade-filter), so redefining the token here
       switches the whole site; background material + ink stay
       unchanged. */
    --grade-filter: none;

    --edge-x: 20px;
    /* The air between the MENU / EN FR IT row and the name.
       --header-top is the header's own padding-top, so everything
       below it — name, tagline, and the page — moves with it.

       48px was set when the row was ~13px of chrome. The tap
       targets (base.css, 14.09.2026) made each of the four a ≥44×44
       box starting at y 1, so the row now ENDS at y 46 while the
       name's cap line sat at 53: seven pixels, and the row read as
       stuck to the name. 84px puts the cap at 89 — 43px of clear
       space below the hit boxes, which is the step the author
       asked for. It stays on the 4px grid the rest of this block
       keeps (20 / 44 / 48 / 32). */
    --header-top: 84px;
    --header-gap: 13px;
    --name-size: 19px;       /* reference index-mobile: single centered line */
    --tagline-size: 19px;
    --footer-bottom: 30px;
    --numeral-size: 44px;
  }
}
