/* DOTVOID — the shared sheet: tokens + chrome. Every page links this after the fonts and BEFORE its own inline
   <style>, so a page override wins on equal specificity. The chrome rules here were lifted verbatim from the landing
   (index.html), which is the source of truth; only the values the design audit names were changed
   (DESIGN-AUDIT.md: A1–A7, D29, E34; token definitions C16–C19; pass 2 applied B8–B15, C16–C19, D21–D28, D30, D31, E33). Page-specific chrome deltas stay in each page and
   say why. Intro-revealed opacity (the landing's frame/menu/sound fading in) is a PAGE concern, not set here. */

/* ===================== FALLBACK FACE (TYPE-AUDIT 24) =====================
   'Archivo Fallback' sits second in every Archivo stack: until the webfont lands, local Arial (or a metric twin) is
   resized per weight so a line sets to Archivo's width, and its ascent/descent are overridden to Archivo's 0.878 / 0.210 em,
   so a slow font load doesn't reflow nowrap labels or shift the line box. size-adjust = Archivo ÷ Arial advance width,
   measured with canvas measureText on a mixed + uppercase label string at 16px; the overrides are divided by size-adjust
   because the browser scales them by it. 500 sets on Arial regular, 600–900 on Arial Bold. */
@font-face { font-family:'Archivo Fallback'; font-weight:400; src:local('Arial'), local('ArialMT'), local('Helvetica Neue'), local('Liberation Sans'); size-adjust:97.9%; ascent-override:89.68%; descent-override:21.45%; line-gap-override:0%; }
@font-face { font-family:'Archivo Fallback'; font-weight:500; src:local('Arial'), local('ArialMT'), local('Helvetica Neue'), local('Liberation Sans'); size-adjust:98.7%; ascent-override:88.96%; descent-override:21.28%; line-gap-override:0%; }
@font-face { font-family:'Archivo Fallback'; font-weight:600; src:local('Arial Bold'), local('Arial-BoldMT'), local('Helvetica Neue Bold'), local('Liberation Sans Bold'); size-adjust:96.8%; ascent-override:90.70%; descent-override:21.69%; line-gap-override:0%; }
@font-face { font-family:'Archivo Fallback'; font-weight:700; src:local('Arial Bold'), local('Arial-BoldMT'), local('Helvetica Neue Bold'), local('Liberation Sans Bold'); size-adjust:99.3%; ascent-override:88.42%; descent-override:21.15%; line-gap-override:0%; }
@font-face { font-family:'Archivo Fallback'; font-weight:800; src:local('Arial Bold'), local('Arial-BoldMT'), local('Helvetica Neue Bold'), local('Liberation Sans Bold'); size-adjust:102.6%; ascent-override:85.58%; descent-override:20.47%; line-gap-override:0%; }
@font-face { font-family:'Archivo Fallback'; font-weight:900; src:local('Arial Bold'), local('Arial-BoldMT'), local('Helvetica Neue Bold'), local('Liberation Sans Bold'); size-adjust:107.5%; ascent-override:81.67%; descent-override:19.53%; line-gap-override:0%; }

/* ===================== TOKENS ===================== */
:root {
  /* void + type */
  --void:#060607; --text:#e8e9ea;
  --grey:#797d84;                                  /* lightened from #6b6f76 to clear WCAG AA (≈4.9:1 on the void) */
  --grey-2:#b0b4ba;                                /* the long-form tint (notes body) */
  /* chrome geometry — steps down at 1024 / 680 (below) */
  --frame:26px; --margin:48px;
  /* hairlines: three jobs */
  --line:rgba(255,255,255,.16);                    /* rest */
  --line-mark:rgba(255,255,255,.5);                /* corner marks, brackets */
  --line-hot:rgba(255,255,255,.85);                /* hover / active on boxes, buttons, chips */
  /* fills */
  --ghost:rgba(255,255,255,.06); --well:rgba(255,255,255,.02);
  /* the one hover glow */
  --glow:0 0 50px -8px rgba(255,255,255,.23);
  /* the accent pair: hit .8, echo .65 */
  --cy:#00eaff; --mg:#ff005a;
  --cy-hit:rgba(0,234,255,.8); --cy-echo:rgba(0,234,255,.65);
  --mg-hit:rgba(255,0,90,.8);  --mg-echo:rgba(255,0,90,.65);
  --cy-idle:rgba(0,234,255,.55); --mg-idle:rgba(255,0,90,.55);   /* the idle whisper (skull jolt, figure flick): an ambient tic, never a hit */
  /* label tracking: three tiers, nothing else. Labels are 10px / 700 / uppercase (section eyebrows 11px).
     (vars, not .lbl classes: the pages already use .lbl for the eyebrow text span and the fan's SVG labels) */
  --tr-lbl:.3em;                                   /* system labels, buttons, footers */
  --tr-eye:.4em;                                   /* eyebrows, plabels */
  --tr-num:.2em;                                   /* numerals, coordinates, readouts */
  /* surfaces — everything derives from the void */
  --s-chip:rgba(6,6,7,.85); --s-panel:rgba(6,6,7,.92); --s-card:rgba(6,6,7,.97);
  --s-drawer:rgba(8,9,11,.96);                     /* the drawer keeps the landing's exact tone (re-toning it is out of scope) */
  /* type scale steps (TYPE-AUDIT 4): prose + the 10px label grow one step on large screens */
  --body-size:16px; --lbl-size:10px;
}
@media (max-width:1024px){ :root { --frame:20px; --margin:36px; } }
@media (max-width:680px){ :root { --frame:14px; --margin:22px; } }
@media (min-width:1600px){ :root { --body-size:17px; --lbl-size:11px; } }
/* ===================== THE SYSTEM (2026-11-02) =====================
   Every spacing, size, weight, tracking, line-height, radius, duration, easing, colour and z-index on the site references a
   token below. A literal value in a page's CSS is a bug. Values that are a component's own geometry (a 12×14 hex cell, a
   7px diamond, a 4px bar) are component tokens, also here. Add a step before you add a one-off. */
:root {
  /* ---- spacing: a 2px grid in three bands. micro = inside a component, block = between elements, section = between blocks.
          Everything snaps to a step: 5→6, 7→6/8, 9→10, 11→12, 13→12/14, 15→14/16, 18→20, 22→24, 26→28, 30→28, 36→34, 44→46,
          60→64, 90→96, 120→128. */
  --sp-0:4px;  --sp-1:6px;  --sp-2:8px;  --sp-3:10px; --sp-4:12px; --sp-5:14px; --sp-6:16px;     /* micro */
  --sp-7:20px; --sp-8:24px; --sp-9:28px; --sp-10:34px; --sp-11:40px; --sp-12:46px;             /* block */
  --sp-13:56px; --sp-14:64px; --sp-15:96px; --sp-16:128px;                                     /* section */
  --hair:1px; --hair-2:2px;                                                                     /* lines and the two-step's throw */
  /* ---- radius: the site is square. The focus ring softens by one pixel; only the cursor dot and ring are round. */
  --r-0:0; --r-focus:1px; --r-round:50%;
  /* ---- weights */
  --w-regular:400; --w-medium:500; --w-semi:600; --w-bold:700; --w-heavy:800; --w-black:900;
  /* ---- type sizes (fixed steps; display heads keep their clamp() because each is sized to its own stage) */
  --fs-lbl:var(--lbl-size);   /* 10 → 11 at ≥1600 */
  --fs-eye:11px;              /* section eyebrows */
  --fs-micro:12px;            /* brackets, captions, coordinates */
  --fs-small:14px;            /* meta, small prose, marks */
  --fs-ui:15px;               /* handles, names, the wordmark in a crumb */
  --fs-body:var(--body-size); /* 16 → 17 at ≥1600 */
  --fs-lead:18px;             /* standfirsts */
  /* ---- tracking (the three label tiers are above: --tr-lbl .3em, --tr-eye .4em, --tr-num .2em) */
  --tr-display:-0.03em; --tr-brand:-0.05em; --tr-tight:-0.02em;                               /* heads · brand/ghost numerals · handles, names */
  --tr-tab:.14em; --tr-cap:.08em; --tr-soft:.04em;                                            /* the cursor chip · caption heads · italic asides */
  /* ---- line-height */
  --lh-brand:.86; --lh-tight:1; --lh-display:1.04; --lh-snug:1.1; --lh-ui:1.4; --lh-prose:1.6;
  /* ---- motion: durations */
  --t-tick:.12s;    /* key repeats, caret hops, micro state */
  --t-flick:.24s;   /* the two-step glitch */
  --t-color:.3s;    /* colour, opacity */
  --t-move:.35s;    /* transforms, widths */
  --t-settle:.5s;   /* a value finding its place (the damage strip's drain, POST flick) */
  --t-reveal:.6s;   /* small reveals, 8px rise */
  --t-lead:.8s;     /* lead reveals, 12px rise, clip wipes */
  --t-blink:.9s;    /* carets, the EQ bars */
  --t-scan:1.2s;    /* scan lines, the dash march */
  --t-breath:3.2s;  /* breathing cells, the now-node pulse */
  /* ---- motion: staggers */
  --stagger:70ms; --stagger-cell:40ms; --stagger-row:90ms; --stagger-card:.16s;
  /* ---- motion: easings */
  --e-move:cubic-bezier(.7,0,.2,1);      /* every transform */
  --e-over:cubic-bezier(.34,1.56,.64,1); /* overshoot: cells landing */
  --e-snap:cubic-bezier(.2,.8,.2,1);     /* the fan's snap */
  --e-color:ease;                        /* colour, opacity */
  --e-loop:ease-in-out;                  /* breathing loops */
  --e-linear:linear;                     /* marches, scans */
  --e-step:steps(2,end);                 /* the two-step */
  --e-hold:steps(1,end);                 /* blinks, flatlines */
  /* ---- colour: the active white and the shades (the rest of the palette is above) */
  --hot:#fff;                                                    /* active, hover, invert */
  --dim:rgba(255,255,255,.55);                                   /* quiet text on dark media, the lightbox mark */
  --shade:rgba(0,0,0,.16); --shade-2:rgba(0,0,0,.32);            /* the only drop shadows */
  --clear:rgba(255,255,255,0);                                   /* transparent white for gradients and stroke fades */
  /* ---- component geometry */
  --hex-w:12px; --hex-h:14px;      /* a hex cell (meters, badges) */
  --hex-sm-w:6px; --hex-sm-h:7px;  /* a signal cell */
  --node:9px; --node-solid:7px;    /* hollow node · solid accent diamond */
  --mark:14px; --cmk:12px;         /* frame corner mark · card bracket */
  --bar:4px;                       /* the damage bar's track */
  --menu:46px;                     /* the menu button's box */
  --drawer:420px;                  /* the drawer's width (min() against 84vw on phones): room for "My Projects" at 38px on one line beside the arrow slot */
  --stroke:1.5px;                  /* outlined type (the VOID in the wordmark, ghost numerals) */
  --hex-ring:1.8px 1.5px;          /* a hex cell's ring: the inset of its void core */
  --hex-pitch-x:38.11px; --hex-pitch-y:66px;   /* the field's lattice period (R 22: √3·R across, 3·R down): the hex mask tile and the resting dot lattice share it */
  --tap:40px;                      /* the minimum hit area */
  /* ---- z ladder */
  --z-under:-1; --z-base:0; --z-raise:1; --z-raise-2:2; --z-frame:19; --z-content:20; --z-net:25; --z-net-hi:30;
  --z-grain:35; --z-veil:37; --z-marks:38; --z-loader:40; --z-chrome:50; --z-scrim:51; --z-drawer:52; --z-menu:55;
  --z-lightbox:56; --z-flash:58; --z-cursor:59; --z-cursor-dot:60; --z-skip:100;
}

/* no horizontal page scroll, ever (TYPE-AUDIT 23): clip, not hidden — clip makes no scroll container, so scrollTo can't
   slide the page sideways. html takes clip alone (a 'hidden' fallback on the root would stop body's overflow propagating
   and turn body into its own scroller where clip is unsupported); body keeps hidden as the fallback. */
html { overflow-x:clip; }
body { overflow-x:hidden; overflow-x:clip; }

/* ===================== Z LADDER (chrome) =====================
   frame 19 · veils 37 · corner marks 38 · home/sound/vol 50 · scrim 51 · drawer 52 · menu 55 · cursor ring 59 · dot 60 */

/* ===================== CURSOR — dot + ring (behaviour: chrome.js) ===================== */
body { cursor:none; }
@media (hover:hover) and (pointer:fine) and (min-width:681px){ a, button, [role=button], label, summary { cursor:none; } }
#cursor { position:fixed; left:0; top:0; width:var(--node-solid); height:var(--node-solid); border:var(--hair) solid var(--line-hot); border-radius:var(--r-round); z-index:var(--z-cursor-dot); pointer-events:none; transform:translate(-50%,-50%); mix-blend-mode:difference; }
#cursor-ring { position:fixed; top:0; left:0; width:var(--tap); height:var(--tap); z-index:var(--z-cursor); pointer-events:none; transform:translate(-50%,-50%); mix-blend-mode:difference; will-change:transform; }
/* no fine pointer (touch): chrome.js sets .dv-nocursor — the OS cursor comes back and the body never draws */
html.dv-nocursor body { cursor:auto; }
html.dv-nocursor #cursor, html.dv-nocursor #cursor-ring { display:none; }

/* ===================== FRAME SET ===================== */
.frame { position:fixed; z-index:var(--z-frame); background:var(--line); }
.frame.t { top:var(--frame); left:var(--frame); right:var(--frame); height:var(--hair); }
.frame.b { bottom:var(--frame); left:var(--frame); right:var(--frame); height:var(--hair); }
.frame.l { top:var(--frame); bottom:var(--frame); left:var(--frame); width:var(--hair); }
.frame.r { top:var(--frame); bottom:var(--frame); right:var(--frame); width:var(--hair); }
.corner-mark { position:fixed; z-index:var(--z-marks); width:var(--mark); height:var(--mark); }
.corner-mark.tl { top:var(--frame); left:var(--frame); border-top:var(--hair) solid var(--line-mark); border-left:var(--hair) solid var(--line-mark); }
.corner-mark.tr { top:var(--frame); right:var(--frame); border-top:var(--hair) solid var(--line-mark); border-right:var(--hair) solid var(--line-mark); }
.corner-mark.bl { bottom:var(--frame); left:var(--frame); border-bottom:var(--hair) solid var(--line-mark); border-left:var(--hair) solid var(--line-mark); }
.corner-mark.br { bottom:var(--frame); right:var(--frame); border-bottom:var(--hair) solid var(--line-mark); border-right:var(--hair) solid var(--line-mark); }
/* frame furniture — the double-rule inset + registration ticks of a technical drawing sheet.
   .frame2 is kept as a target only (the landing's intro fades it; the old port dots are now ghost stations drawn by light) */
.frame2 { position:fixed; inset:var(--frame); border:none; background:none; pointer-events:none; z-index:var(--z-frame); }
/* seam traces — one short offset hairline per edge at asymmetric stations, ends dissolving into the void; they breathe on offset cycles */
.ftick { position:fixed; pointer-events:none; z-index:var(--z-frame); animation:seamBreathe 9s var(--e-loop) infinite; /* idle period, non-harmonic */ }
.ftick.t { top:calc(var(--frame) + var(--sp-0)); left:38%; width:var(--sp-15); height:var(--hair); background:linear-gradient(90deg,var(--clear),var(--line) 25%,var(--line) 75%,var(--clear)); }
.ftick.b { bottom:calc(var(--frame) + var(--sp-0)); left:58%; width:var(--sp-15); height:var(--hair); background:linear-gradient(90deg,var(--clear),var(--line) 25%,var(--line) 75%,var(--clear)); animation-delay:-3s; /* idle period, non-harmonic */ }
.ftick.l { left:calc(var(--frame) + var(--sp-0)); top:62%; width:var(--hair); height:var(--sp-15); background:linear-gradient(180deg,var(--clear),var(--line) 25%,var(--line) 75%,var(--clear)); animation-delay:-6s; /* idle period, non-harmonic */ }
.ftick.r { right:calc(var(--frame) + var(--sp-0)); top:26%; width:var(--hair); height:var(--sp-15); background:linear-gradient(180deg,var(--clear),var(--line) 25%,var(--line) 75%,var(--clear)); animation-delay:-4.5s; /* idle period, non-harmonic */ }
@keyframes seamBreathe { 0%,100%{ filter:brightness(0.7); } 50%{ filter:brightness(1.6); } }
/* corner pads — LOOPED GLITCH: hard-cut RGB-split jitter bursts walking the corners clockwise.
   steps(1,end) = poses cut, never tween — the site's stepped-glitch signature at registration scale. */
@keyframes cornerGlitch {
  0%,86%,100% { transform:none; filter:none; }
  88% { transform:translate(var(--hair-2),-1px); filter:drop-shadow(calc(-1 * var(--hair-2)) 0 var(--cy-hit)) drop-shadow(var(--hair-2) 0 var(--mg-hit)); }
  90% { transform:translate(calc(-1 * var(--hair-2)),1px); filter:drop-shadow(var(--hair-2) 0 var(--cy-echo)) drop-shadow(calc(-1 * var(--hair-2)) 0 var(--mg-echo)); }
  92% { transform:translate(1px,0) scale(1.08); filter:drop-shadow(0 0 4px var(--line-hot)); }
  94% { transform:none; filter:none; }
}
.corner-mark { animation:cornerGlitch calc(var(--t-breath) * 2) var(--e-hold) infinite; }
.corner-mark.tr { animation-delay:calc(var(--t-breath) * .5); } .corner-mark.br { animation-delay:var(--t-breath); } .corner-mark.bl { animation-delay:calc(var(--t-breath) * 1.5); }
@media (prefers-reduced-motion:reduce){ .ftick, .corner-mark { animation:none; } }

/* ===================== TOP BAR — home + menu share one baseline + the same margin grid line ===================== */
.home { position:fixed; top:var(--margin); left:var(--margin); z-index:var(--z-chrome); height:var(--menu); display:flex; align-items:center; font-size:var(--fs-ui); font-weight:var(--w-heavy); letter-spacing:var(--tr-tight); color:var(--hot); text-decoration:none; pointer-events:auto; cursor:none; }
/* hover = INVERSION: DOT dissolves to a contour while VOID fills solid — substance and absence trade places
   (the brand's thesis, performed by the wordmark). Colour/stroke crossfade only. */
.home .d { color:var(--hot); -webkit-text-stroke:var(--hair) var(--clear); transition:color var(--t-color) var(--e-color), -webkit-text-stroke-color var(--t-color) var(--e-color); }
.home .v { color:transparent; -webkit-text-stroke:var(--hair) var(--line-hot); transition:color var(--t-color) var(--e-color), -webkit-text-stroke-color var(--t-color) var(--e-color); }
.home:hover .d, .home:focus-visible .d { color:transparent; -webkit-text-stroke-color:var(--line-hot); }
.home:hover .v, .home:focus-visible .v { color:var(--hot); -webkit-text-stroke-color:var(--clear); }
.menu-btn { position:fixed; top:var(--margin); right:var(--margin); z-index:var(--z-menu); width:var(--menu); height:var(--menu); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-1); cursor:none; pointer-events:auto; }
.menu-btn span { width:var(--sp-8); height:var(--hair-2); background:var(--hot); transition:transform var(--t-move) var(--e-color), opacity var(--t-color) var(--e-color); }
.menu-btn.open span:nth-child(1){ transform:translateY(var(--sp-2)) rotate(45deg); }
.menu-btn.open span:nth-child(2){ opacity:0; }
.menu-btn.open span:nth-child(3){ transform:translateY(calc(-1 * var(--sp-2))) rotate(-45deg); }
.menu-btn:focus-visible, .home:focus-visible, .panel a:focus-visible, .sound-toggle:focus-visible { outline:var(--hair-2) solid var(--hot); outline-offset:var(--sp-0); border-radius:var(--r-focus); }

/* ===================== DRAWER (behaviour: chrome.js) ===================== */
.panel { position:fixed; top:0; right:0; height:100%; width:min(var(--drawer),84vw); background:var(--s-drawer); border-left:var(--hair) solid var(--line); z-index:var(--z-drawer); transform:translateX(100%); transition:transform var(--t-reveal) var(--e-move); display:flex; flex-direction:column; justify-content:center; padding:var(--sp-13); overflow:hidden; }
.panel[inert] { pointer-events:none; }                 /* closed drawer: inert removes it from tab order + a11y tree (modern browsers) */
.panel.open { transform:translateX(0); }
/* SCRIM + STAMP — when the drawer opens it takes the room: the page behind dims and blurs to the drawer's own tone
   (z 51, just under the drawer), and the wordmark stamps into the dimmed field once, so the drawer is the only
   thing left in focus. Clicking the scrim closes the drawer (the document click-outside handler). */
#scrim { position:fixed; inset:0; z-index:var(--z-scrim); background:var(--s-panel); opacity:0; pointer-events:none; transition:opacity var(--t-settle) var(--e-color); }
#scrim.on { opacity:1; pointer-events:auto; cursor:none; }
#scrim.out { opacity:0; pointer-events:none; transition:opacity var(--t-settle) var(--e-color) var(--t-color); }   /* on close the field holds for a beat while the stamp leaves, then lifts */
/* the stamp is the drawer's nameplate: hex · DOTVOID · leader → node at the drawer's edge, one axis, level with the links */
#scrim .stamp { position:absolute; top:50%; right:min(var(--drawer),84vw); transform:translateY(-50%); display:flex; align-items:center; gap:clamp(var(--sp-5),1.4vw,var(--sp-8)); pointer-events:none; }
#scrim .hx { width:clamp(var(--sp-8),2.6vw,var(--sp-11)); height:auto; fill:none; stroke:var(--line-hot); stroke-width:var(--hair-2); opacity:0; transform-origin:50% 50%; }   /* the mark: the one hex path + the dot, always on */
#scrim .hx circle { fill:var(--line-hot); stroke:none; }
#scrim .wm { font-size:clamp(40px,6.4vw,96px); font-weight:var(--w-black); letter-spacing:var(--tr-brand); line-height:var(--lh-brand); color:var(--hot); opacity:0; will-change:transform,clip-path; }
#scrim .wm .v { color:transparent; -webkit-text-stroke:var(--stroke) var(--line-hot); }
#scrim .lead { position:relative; display:block; width:clamp(72px,9vw,160px); height:var(--hair); background:var(--line-mark); transform:scaleX(0); transform-origin:100% 50%; }   /* grows out of the drawer toward the name */
#scrim .lead .lnode { position:absolute; right:calc(-1 * var(--sp-0)); top:calc(-1 * var(--node-solid) / 2); width:var(--node-solid); height:var(--node-solid); background:var(--hot); transform:rotate(45deg); }   /* the path-node diamond, at the drawer's edge */
/* OPEN — hex spins in, wordmark unclips from the centre with one split frame, rule draws out; then the hex breathes */
#scrim.on .hx { animation:stHex var(--t-settle) var(--e-move) var(--t-color) both, ctHex 2.2s var(--e-loop) var(--t-blink) infinite; /* idle period, non-harmonic */ }
#scrim.on .wm { animation:stWm var(--t-settle) var(--e-move) var(--t-move) both; }
#scrim.on .lead { animation:stRule var(--t-settle) var(--e-move) var(--t-tick) both; }   /* the drawer reaches out first, then the name arrives on the line */
@keyframes stHex { 0%{ opacity:0; transform:rotate(-150deg) scale(.2); } 100%{ opacity:1; transform:rotate(0) scale(1); } }
@keyframes stWm { 0%{ opacity:0; transform:scale(.92); clip-path:inset(0 50% 0 50%); } 45%{ opacity:1; } 62%{ text-shadow:var(--hair-2) 0 var(--cy-hit), calc(-1 * var(--hair-2)) 0 var(--mg-hit); } 72%{ text-shadow:none; } 100%{ opacity:1; transform:none; clip-path:inset(0 0 0 0); } }
@keyframes stRule { 0%{ transform:scaleX(0); } 100%{ transform:scaleX(1); } }
/* CLOSE — the jazz: a jolt and split, the wordmark collapses to a hairline and snaps shut, the hex spins out, the rule retracts */
#scrim.out .wm { animation:stWmOut var(--t-move) var(--e-move) both; }
#scrim.out .hx { animation:stHexOut var(--t-move) var(--e-move) var(--t-tick) both; }
#scrim.out .lead { animation:stRuleOut var(--t-color) var(--e-move) var(--t-color) both; }   /* the line retracts into the drawer after the name has collapsed */
@keyframes stWmOut { 0%{ opacity:1; transform:none; clip-path:inset(0 0 0 0); } 18%{ transform:translateX(3px); text-shadow:-3px 0 var(--cy-hit), 3px 0 var(--mg-hit); } 36%{ transform:translateX(calc(-1 * var(--hair-2))); text-shadow:var(--hair-2) 0 var(--cy-echo), calc(-1 * var(--hair-2)) 0 var(--mg-echo); } 60%{ opacity:1; text-shadow:none; transform:scaleY(.08); clip-path:inset(0 0 0 0); } 100%{ opacity:0; transform:scaleY(.08); clip-path:inset(0 50% 0 50%); } }
@keyframes stHexOut { 0%{ opacity:1; transform:rotate(0) scale(1); } 100%{ opacity:0; transform:rotate(150deg) scale(.2); } }
@keyframes stRuleOut { 0%{ transform:scaleX(1); } 100%{ transform:scaleX(0); } }
/* THE BREATH — a sixth of a turn that ends where it started: 6-fold symmetry makes 60° seamless, so the resting pose is always pointy-top
   (the stamp's hex, the landing's chips and fan indices all breathe on it) */
@keyframes ctHex { 0%{ transform:rotate(0) scale(1); opacity:.7; } 50%{ transform:rotate(30deg) scale(1.12); opacity:1; } 100%{ transform:rotate(60deg) scale(1); opacity:.7; } }
@media (prefers-reduced-motion:reduce){ #scrim, #scrim.out { transition:none; } #scrim .hx, #scrim .wm, #scrim .lead { animation:none !important; } #scrim.on .hx, #scrim.on .wm { opacity:1; } #scrim.on .lead { transform:scaleX(1); } }
/* DRAWER LINKS — arrive one after another once the drawer has landed (translate, not transform: the hover shift keeps its transform) */
.panel .plinks a { opacity:0; translate:var(--sp-9) 0; transition:opacity var(--t-settle) var(--e-move), translate var(--t-settle) var(--e-move), color var(--t-color), transform var(--t-move) var(--e-move); }   /* closing: all three ease out together while the drawer slides */
.panel.open .plinks a { opacity:1; translate:0 0; transition-delay:calc(var(--i,0) * var(--stagger) + var(--t-color)), calc(var(--i,0) * var(--stagger) + var(--t-color)), 0s, 0s; }
@media (prefers-reduced-motion:reduce){ .panel .plinks a { opacity:1; translate:0 0; transition:none !important; } }
#panel-hex { position:absolute; inset:0; width:100%; height:100%; z-index:var(--z-base); pointer-events:none; }
.panel .plabel, .panel .plinks, .panel .foot { position:relative; z-index:var(--z-raise); }
.panel .plabel { font-size:var(--fs-lbl); font-weight:var(--w-bold); letter-spacing:var(--tr-eye); text-transform:uppercase; color:var(--grey); margin-bottom:var(--sp-10); }
.panel a { display:flex; align-items:baseline; gap:var(--sp-4); font-size:clamp(30px,7vw,38px); font-weight:var(--w-heavy); letter-spacing:var(--tr-tight); color:var(--text); text-decoration:none; padding:var(--sp-6) var(--sp-10) var(--sp-6) 0; border-bottom:var(--hair) solid var(--line); cursor:none; position:relative; will-change:transform; transition:color var(--t-color), transform var(--t-move) var(--e-move); }
/* the arrow is absolute (TYPE-AUDIT 25): out of the flex line, so it never pushes a long name onto another line; the link's 34px right
   padding keeps text out from under it. Centred by the translate property, so the hover slide + navArr bob still animate transform. */
.panel a .idx { font-size:var(--fs-eye); font-weight:var(--w-semi); color:var(--grey); transition:color var(--t-color); }
.panel a .arr { position:absolute; right:0; top:50%; translate:0 -50%; opacity:0; transform:translateX(calc(-1 * var(--sp-3))); transition:opacity var(--t-move), transform var(--t-move) var(--e-move); font-weight:var(--w-regular); }
.panel a:hover { color:var(--hot); transform:translateX(var(--sp-6)); }
.panel a:hover .idx { color:var(--hot); }
.panel a:hover .arr { opacity:1; transform:translateX(0); }
/* keyboard focus: mirror the hover affordance + a visible monochrome outline (cursor:none left keyboard users with no indicator) */
.panel a:focus-visible { color:var(--hot); transform:translateX(var(--sp-6)); }
.panel a:focus-visible .idx { color:var(--hot); }
.panel a:focus-visible .arr { opacity:1; transform:translateX(0); }
/* nav buttons — richer hover: a left accent bar grows in, a one-shot RGB glitch flick (the site's signature), the arrow keeps a gentle pulse. All compositor-cheap, one item hovered at a time. */
.plinks a { position:relative; }
.plinks a::before { content:''; position:absolute; left:calc(-1 * var(--sp-6)); top:50%; width:var(--hair-2); height:54%; background:var(--hot); transform:translateY(-50%) scaleY(0); transform-origin:center; transition:transform var(--t-move) var(--e-move); }
.plinks a:hover::before, .plinks a:focus-visible::before { transform:translateY(-50%) scaleY(1); }
.plinks a:hover, .plinks a:focus-visible { animation:navGlitch var(--t-flick) var(--e-step); }
.plinks a:hover .arr, .plinks a:focus-visible .arr { animation:navArr var(--t-lead) var(--e-loop) infinite var(--t-move); }
@keyframes navGlitch { 0%{ text-shadow:none; } 20%{ text-shadow:var(--hair-2) 0 var(--cy-hit),calc(-1 * var(--hair-2)) 0 var(--mg-hit); } 45%{ text-shadow:calc(-1 * var(--hair-2)) 0 var(--cy-echo),var(--hair-2) 0 var(--mg-echo); } 70%,100%{ text-shadow:none; } }
@keyframes navArr { 0%,100%{ transform:translateX(0); } 50%{ transform:translateX(6px); } }
@media (prefers-reduced-motion:reduce){ .plinks a:hover, .plinks a:focus-visible, .plinks a:hover .arr, .plinks a:focus-visible .arr { animation:none !important; } }
/* "you are here" — the drawer marks the section under the reading line */
.plinks a.here .idx { color:var(--hot); }
.plinks a.here::after { content:''; position:absolute; left:calc(-1 * var(--sp-2)); top:50%; width:var(--sp-0); height:var(--sp-0); margin-top:calc(-1 * var(--hair-2)); border-radius:var(--r-round); background:var(--hot); }
.panel .foot { margin-top:var(--sp-11); font-size:var(--fs-lbl); font-weight:var(--w-bold); letter-spacing:var(--tr-lbl); color:var(--grey); text-transform:uppercase; }

/* ===================== SOUND TOGGLE + VOLUME — bottom-left grid line ===================== */
/* the bottom-left bar: SOUND · vol as one flex row on the margin grid line — nothing hard-offset (TYPE-AUDIT 1) */
.bar-bl { position:fixed; left:var(--margin); bottom:var(--margin); z-index:var(--z-chrome); display:flex; align-items:center; gap:var(--sp-8); pointer-events:none; }
.bar-bl > * { pointer-events:auto; }
.sound-toggle { display:flex; align-items:center; gap:var(--sp-3); background:none; border:0; padding:var(--sp-5) 0; margin-block:calc(-1 * var(--sp-5)); font-family:inherit; font-size:var(--fs-lbl); font-weight:var(--w-bold); letter-spacing:var(--tr-lbl); text-transform:uppercase; color:var(--grey); cursor:none; pointer-events:auto; transition:color var(--t-color) var(--e-color), transform var(--t-move) var(--e-move); }
.sound-toggle.on { color:var(--hot); }   /* padding-block 14 / margin-block -14: a 40px hit area, the glyphs and the bar layout unmoved (TYPE-AUDIT 8) */
@media (hover:hover) and (pointer:fine){ .sound-toggle:hover { color:var(--hot); transform:translateX(var(--sp-3)); } }
.sbars { display:flex; align-items:flex-end; gap:var(--hair-2); height:var(--sp-4); }
.sbars i { width:var(--hair-2); height:var(--sp-0); background:currentColor; display:block; }
.sound-toggle.on .sbars i { animation:eq var(--t-blink) var(--e-loop) infinite; }
.sound-toggle.on .sbars i:nth-child(2){ animation-delay:calc(var(--stagger) * 2); }
.sound-toggle.on .sbars i:nth-child(3){ animation-delay:calc(var(--stagger) * 4); }
.sound-toggle.on .sbars i:nth-child(4){ animation-delay:calc(var(--stagger) * 6); }
/* dormant-state beacon — a DIM slow breath (a cue, not a spotlight: the brand keeps the stage; the twitch
   below carries the invitation). Animates color/text-shadow ONLY — a page intro may own opacity. */
.sound-toggle:not(.on) { animation:cueGlow var(--t-breath) var(--e-loop) infinite; }
@keyframes cueGlow { 0%,100%{ color:var(--grey); text-shadow:none; } 50%{ color:var(--text); text-shadow:0 0 var(--sp-1) var(--line); } }
/* the bars twitch in their sleep — every ~8s a tiny ripple, like sound trapped in there trying to get out */
.sound-toggle:not(.on) .sbars i { animation:barTwitch 8s var(--e-loop) infinite; /* idle period, non-harmonic */ }
.sound-toggle:not(.on) .sbars i:nth-child(2){ animation-delay:var(--stagger-row); }
.sound-toggle:not(.on) .sbars i:nth-child(3){ animation-delay:calc(var(--stagger-row) * 2); }
.sound-toggle:not(.on) .sbars i:nth-child(4){ animation-delay:calc(var(--stagger-row) * 3); }
@keyframes barTwitch { 0%,91%,100%{ height:4px; } 93%{ height:9px; } 95%{ height:5px; } 97%{ height:7px; } }
/* blueprint status suffix — SOUND · DORMANT / · LIVE, driven purely by the .on class, zero JS */
.au-st { font-size:var(--fs-lbl); font-weight:var(--w-bold); letter-spacing:var(--tr-lbl); color:var(--grey); opacity:0.75; }
.au-st::after { content:'· DORMANT'; }
.sound-toggle.on .au-st::after { content:'· LIVE'; }
@media (prefers-reduced-motion:reduce){ .sound-toggle:not(.on){ animation:none; } .sound-toggle:not(.on) .sbars i{ animation:none; } }
@keyframes eq { 0%,100%{height:3px} 50%{height:12px} }
/* volume flyout — beside SOUND in .bar-bl; native range input for full keyboard/AT support. Relative: the panel anchors to it */
.vol { position:relative; }
.vol-btn { width:var(--sp-9); height:var(--sp-9); display:flex; align-items:center; justify-content:center; background:none; border:0; padding:0; cursor:none; color:var(--grey); }
.vol-btn svg { width:var(--sp-3); height:var(--sp-1); fill:none; stroke:currentColor; stroke-width:var(--hair); transition:transform var(--t-color) var(--e-color), stroke var(--t-color); }
.vol-btn:hover, .vol-btn[aria-expanded="true"] { color:var(--hot); }
.vol-btn[aria-expanded="true"] svg { transform:rotate(180deg); }
.vol-panel { position:absolute; left:50%; bottom:var(--sp-10); transform:translateX(-50%); padding:var(--sp-5); background:var(--s-panel); border:var(--hair) solid var(--line); }
.vol-panel[hidden] { display:none; }
.vol-range { -webkit-appearance:none; appearance:none; display:block; width:var(--sp-16); height:var(--hair-2); background:var(--line); cursor:none; }
.vol-range:focus-visible { outline:var(--hair-2) solid var(--hot); outline-offset:var(--sp-1); }
.vol-range::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:var(--node-solid); height:var(--node-solid); background:var(--hot); border-radius:var(--r-0); transform:rotate(45deg); }   /* diamond thumb — the site's node marker */
.vol-range::-moz-range-thumb { width:var(--node-solid); height:var(--node-solid); background:var(--hot); border:0; border-radius:var(--r-0); transform:rotate(45deg); }

/* ===================== BUTTON — the one box button (was the sound gate's .sg-btn) ===================== */
.btn { display:inline-flex; align-items:center; gap:var(--sp-3); background:none; border:var(--hair) solid var(--line); padding:var(--sp-4) var(--sp-8); font-family:inherit; font-size:var(--fs-eye); font-weight:var(--w-bold); letter-spacing:var(--tr-lbl); text-transform:uppercase; color:var(--grey); text-decoration:none; cursor:none; transition:color var(--t-color), border-color var(--t-color), letter-spacing var(--t-color); }
.btn:hover, .btn:focus-visible { color:var(--hot); border-color:var(--line-hot); letter-spacing:calc(var(--tr-lbl) + var(--tr-soft)); outline:none; }
.btn.compact { padding:var(--sp-3) var(--sp-4); }

/* ===================== REGISTRATION LINE — the system label + the one footer ===================== */
.reg { font-size:var(--fs-lbl); font-weight:var(--w-bold); letter-spacing:var(--tr-lbl); text-transform:uppercase; color:var(--grey); font-variant-numeric:tabular-nums; }
.reg-foot { display:flex; justify-content:space-between; flex-wrap:wrap; gap:var(--sp-2) var(--sp-6); }
.reg-foot > .reg { opacity:1; }   /* quiet by size + tracking, not by fading: ≈4.9:1 (TYPE-AUDIT 9) */

/* ===================== EYEBROW — number · label · rule ("01 — THE PATH": index fades up, hairline rule draws across on reveal) ===================== */
.eyebrow { font-size:var(--fs-eye); font-weight:var(--w-bold); letter-spacing:var(--tr-eye); text-transform:uppercase; color:var(--grey); margin-bottom:var(--sp-12); display:flex; align-items:center; gap:var(--sp-5); }
.eyebrow .ex { color:var(--hot); font-variant-numeric:tabular-nums; opacity:0; transform:translateY(var(--sp-2)); transition:opacity var(--t-reveal) var(--e-color), transform var(--t-reveal) var(--e-move); }
.eyebrow .exline { flex:1; height:var(--hair); background:var(--line); transform:scaleX(0); transform-origin:left; transition:transform var(--t-lead) var(--e-move) var(--t-tick); }
.eyebrow.drawn .ex { opacity:1; transform:none; }
.eyebrow.drawn .exline { transform:scaleX(1); }

/* ===================== VEILS — void under the chrome (TYPE-AUDIT 1) =====================
   A fixed fade behind the bottom bar and under the header so scrolled content never sits UNDER the chrome. Scroll-gated
   (body.scrolled, chrome.js): the first screen is untouched. z 37 = over content + grain, under the marks (38) and bar (50). */
.veil-b, .veil-t { position:fixed; left:0; right:0; z-index:var(--z-veil); pointer-events:none; opacity:0; transition:opacity var(--t-move) var(--e-color); }
.veil-b { bottom:0; height:var(--sp-15); background:linear-gradient(to bottom, var(--clear), var(--void) 70%); }
.veil-t { top:0; height:var(--sp-13); background:linear-gradient(to top, var(--clear), var(--void) 70%); }
body.scrolled .veil-b, body.scrolled .veil-t { opacity:1; }

/* ===================== PHONE (680) — chrome only ===================== */
@media (max-width:680px){
  body { cursor:auto; } #cursor, #cursor-ring { display:none; }
  #scrim .stamp { display:none; }               /* the drawer is 84vw on phones — no field left to stamp; scrim + drawer switch together here */
  .panel { padding:var(--sp-10); }
  .bar-bl { bottom:var(--sp-9); flex-direction:column-reverse; align-items:flex-start; gap:var(--sp-5); }   /* vol stacked above SOUND on small screens */
  .vol-panel { left:0; transform:none; }        /* edge-anchored — centring on the near-edge button pushed the panel off-screen */
  .reg-foot { flex-direction:column; gap:var(--sp-1); } .reg-foot .tail { display:none; }   /* two lines, each on one line: the em-dash tail drops (TYPE-AUDIT 6) */
  .eyebrow { margin-bottom:var(--sp-9); }               /* 46 is a desktop breath (TYPE-AUDIT 21) */
}
