/* ═══════════════════════════════════════════════════════════
   Aziz — portfolio
   Editorial monochrome + blueprint cobalt
   ═══════════════════════════════════════════════════════════ */

/* ── tokens ───────────────────────────────────────────────── */
/*
   Backgrounds and text are the ictech.com.my palette, both schemes.

   --ink is ALWAYS the ground and --paper is ALWAYS the text, whichever theme
   is active. Every rule in this file dims text with
   color-mix(in oklab, var(--paper) N%, var(--ink)), so the entire stylesheet
   inverts correctly from these two values alone. Only the handful of colours
   that must not flip — crimson, and the white that sits on it — are fixed.
*/
:root{
  --accent:     #e11d26;   /* crimson — display type, fills, borders */
  --accent-deep:#a8141b;   /* fills that carry light text */
  --on-accent:  #ffffff;   /* fixed: text on a crimson fill, either theme */

  --text-1: var(--paper);
  /* body copy sat at 64% and read as grey rather than text. 80% keeps the
     hierarchy against --text-1 while staying comfortably readable. */
  --text-2: color-mix(in oklab, var(--paper) 80%, var(--ink));
  --text-3: color-mix(in oklab, var(--paper) 52%, var(--ink));
  --rule:   color-mix(in oklab, var(--paper) 16%, var(--ink));

  /* type */
  --serif: "Instrument Serif", "Iowan Old Style", Georgia, serif;
  --sans:  "Urbanist", "Helvetica Neue", Helvetica, sans-serif;
  --mono:  "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --fs-display: clamp(3.4rem, 13vw, 13.5rem);
  --fs-h2:      clamp(2.75rem, 8vw, 8rem);
  --fs-h3:      clamp(1.35rem, 2.2vw, 2rem);
  --fs-lede:    clamp(1.05rem, 1.35vw, 1.4rem);
  --fs-body:    clamp(1.05rem, 0.98rem + 0.36vw, 1.1875rem);
  --fs-micro:   clamp(0.68rem, 0.64rem + 0.16vw, 0.775rem);

  /* motion */
  --e-out-expo:  cubic-bezier(0.16, 1, 0.3, 1);
  --e-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --e-in-out:    cubic-bezier(0.87, 0, 0.13, 1);
  --d-fast: 220ms;
  --d-norm: 460ms;
  --d-slow: 900ms;

  /* Radii and the interaction curve are ictech's own tokens. The soft curve
     overshoots very slightly, which is what gives their cards that settled,
     springy feel on hover. Reveals keep the expo curve — a long entrance
     wants to decelerate, not bounce. */
  --e-soft: cubic-bezier(0.23, 0.65, 0.74, 1.09);

  /* layout
     ictech's stylesheet runs a 62.5% root, so its 2rem/1rem radii are 20px
     and 10px, not 32/16. These are the true pixel values.
     Their content sits in a centred 8-of-12 column, roughly two thirds of the
     viewport, so --max tracks the viewport instead of pinning to 1680. */
  --radius:   20px;      /* large panels */
  --radius-s: 10px;      /* cards */
  --radius-xs: 6px;      /* chips and tags */
  --pad: clamp(1.25rem, 4.5vw, 5.5rem);
  --max: clamp(1000px, 70vw, 1560px);
}

/* ── themes ───────────────────────────────────────────────── */
/* Dark is the default, and what the composition was drawn for. */
:root,
:root[data-theme="dark"]{
  color-scheme: dark;
  --ink:        #141414;   /* ictech base, dark */
  --ink-2:      #242424;   /* raised surface */
  --ink-3:      #000000;   /* deepest — signature section, footer */
  --paper:      #f4f1ea;   /* warm off-white — easier on the eye than the
                              cool blue-white on a near-black ground */
  --accent-lit: #ff5a52;   /* crimson lifted, for small text on black */
  --fw-base: 300;          /* light text on black bloats; 300 compensates */
  --fw-med:  500;
}

/* The light values appear twice on purpose: once for visitors whose system
   asks for light and who have not chosen, once for an explicit choice.
   CSS cannot share one declaration block between a media query and a
   selector, and duplicating five lines beats an indirection nobody can read. */
@media (prefers-color-scheme: light){
  :root:not([data-theme="dark"]){
    color-scheme: light;
    --ink:        #fcfcfc;
    --ink-2:      #ffffff;
    --ink-3:      #eef1f6;
    --paper:      #151617;
    --accent-lit: #c4141c;   /* crimson darkened, to clear AA on white */
    --fw-base: 400;
    --fw-med:  600;
  }
}
:root[data-theme="light"]{
  color-scheme: light;
  --ink:        #fcfcfc;
  --ink-2:      #ffffff;
  --ink-3:      #eef1f6;
  --paper:      #151617;
  --accent-lit: #c4141c;
  --fw-base: 400;
  --fw-med:  600;
}

/* ── reset ────────────────────────────────────────────────── */
*,*::before,*::after{ box-sizing:border-box; }
/* A class selector beats the UA sheet, so .menu{display:flex} was overriding
   the hidden attribute. The closed menu stayed laid out at opacity 0, a
   full-screen fixed overlay swallowing every tap on mobile. */
[hidden]{ display:none !important; }
html{ -webkit-text-size-adjust:100%; }
body,h1,h2,h3,p,ul,ol,dl,dd,figure{ margin:0; padding:0; }
ul,ol{ list-style:none; }
img,svg{ display:block; max-width:100%; }
a{ color:inherit; text-decoration:none; }

html{ background:var(--ink); }
body{
  background:var(--ink);
  color:var(--text-1);
  font-family:var(--sans);
  font-size:var(--fs-body);
  line-height:1.62;
  font-weight:var(--fw-base, 400);
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

::selection{ background:var(--accent); color:var(--on-accent); }

:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:4px;
  border-radius:1px;
}

.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

.skip{
  position:fixed; top:-100px; left:var(--pad); z-index:200;
  background:var(--accent); color:var(--on-accent);
  padding:.75rem 1.25rem; font-family:var(--mono); font-size:.75rem;
  transition:top var(--d-fast) var(--e-out-quart);
}
.skip:focus{ top:1rem; }

/* shared ─ section numbers */
.sec-num{
  display:block;
  font-family:var(--mono);
  font-size:var(--fs-micro);
  letter-spacing:.16em;
  color:var(--accent-lit);
}
.sec-num.inv{ color:var(--accent-lit); }

/* shared ─ container */
/*
   The nav, the contact block and the footer paint their own full-bleed
   background, so they cannot take max-width + auto margins the way the content
   sections do — that would narrow the background too.

   Instead the inline padding grows to whatever centres a --max-wide column.
   On a wide screen that lands their content on exactly the same left edge as
   every other section; on a narrow one the max() falls back to --pad. Written
   against 100% rather than 100vw so a visible scrollbar cannot skew it.
*/
.hero,.about,.work,.path,.stack,.system{
  padding-inline:var(--pad);
}
.nav,.contact,.foot{
  /* The content sections are centred to --max AND carry --pad inside that, so
     their text starts at ((100% - max) / 2) + pad. Match both terms or these
     land a full --pad to the left of everything else. */
  padding-inline:max(var(--pad), calc((100% - var(--max)) / 2 + var(--pad)));
}

/* ═══════════════════════════════════════════════════════════
   custom cursor  (opt-in — user requested)
   ═══════════════════════════════════════════════════════════ */
.cursor{ position:fixed; inset:0; pointer-events:none; z-index:300; display:none; }
@media (hover:hover) and (pointer:fine){ .cursor{ display:block; } }

.cursor__dot,.cursor__ring{
  position:absolute; top:0; left:0;
  border-radius:50%;
  will-change:transform;
}
.cursor__dot{
  width:6px; height:6px; margin:-3px 0 0 -3px;
  background:var(--accent-lit);
}
.cursor__ring{
  width:36px; height:36px; margin:-18px 0 0 -18px;
  border:1px solid color-mix(in oklab, var(--accent-lit) 50%, transparent);
  transition:width var(--d-fast) var(--e-out-expo),
             height var(--d-fast) var(--e-out-expo),
             margin var(--d-fast) var(--e-out-expo),
             background var(--d-fast) var(--e-out-expo),
             border-color var(--d-fast) var(--e-out-expo);
}
body.is-hovering .cursor__ring{
  width:62px; height:62px; margin:-31px 0 0 -31px;
  background:color-mix(in oklab, var(--accent) 14%, transparent);
  border-color:var(--accent-lit);
}
body.on-dark .cursor__dot{ background:var(--accent-lit); }
body.on-dark .cursor__ring{ border-color:color-mix(in oklab, var(--accent-lit) 55%, transparent); }

/* ═══════════════════════════════════════════════════════════
   loader
   ═══════════════════════════════════════════════════════════ */
html:not(.js) .loader{ display:none; }
.loader{
  position:fixed; inset:0; z-index:250;
  background:var(--ink-3); color:var(--paper);
  display:flex; flex-direction:column; justify-content:flex-end;
  padding:var(--pad);
  transition:transform 1s var(--e-in-out);
}
.loader.done{ transform:translate3d(0,-101%,0); }
.loader__inner{
  display:flex; align-items:baseline; justify-content:space-between;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase;
  margin-bottom:1.25rem;
}
.loader__count{
  font-family:var(--serif); font-size:clamp(4rem,14vw,12rem);
  line-height:.8; letter-spacing:-0.03em; text-transform:none;
}
.loader__bar{ height:1px; background:color-mix(in oklab, var(--paper) 22%, transparent); }
.loader__bar i{ display:block; height:100%; width:0; background:var(--accent-lit); }

body.loading{ overflow:hidden; }

/* ═══════════════════════════════════════════════════════════
   nav
   ═══════════════════════════════════════════════════════════ */
.nav{
  position:fixed; top:0; left:0; right:0; z-index:100;
  display:flex; align-items:center; justify-content:space-between;
  gap:2rem;
  height:74px;
  mix-blend-mode:normal;
  transition:transform var(--d-norm) var(--e-out-quart),
             background var(--d-norm) linear,
             color var(--d-norm) linear;
}
.nav::after{
  content:""; position:absolute; inset:0; z-index:-1;
  background:color-mix(in oklab, var(--ink) 78%, transparent);
  backdrop-filter:blur(14px);
  opacity:0; transition:opacity var(--d-norm) var(--e-out-quart);
}
.nav.stuck::after{ opacity:1; }
.nav.hide{ transform:translate3d(0,-100%,0); }

.nav__mark{ display:flex; align-items:baseline; gap:.5rem; }
.nav__mark-glyph{
  font-family:var(--serif); font-size:1.6rem; line-height:1;
  color:var(--accent);
}
.nav__mark-text{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.2em; text-transform:uppercase;
}

.nav__links{ display:flex; gap:clamp(1rem,2.4vw,2.6rem); }
.nav__links a{
  position:relative;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.1em; text-transform:uppercase;
  color:var(--text-2);
  transition:color var(--d-fast) var(--e-out-quart);
}
.nav__links a em{ font-style:normal; color:var(--accent-lit); margin-right:.35em; }
.nav__links a::after{
  content:""; position:absolute; left:0; right:0; bottom:-6px;
  height:1px; background:currentColor;
  transform:scaleX(0); transform-origin:0 50%;
  transition:transform var(--d-norm) var(--e-out-expo);
}
.nav__links a:hover{ color:var(--text-1); }
.nav__links a:hover::after{ transform:scaleX(1); }

.nav__status{
  display:flex; align-items:center; gap:.55rem;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.1em; text-transform:uppercase; color:var(--text-2);
  white-space:nowrap;
}
.nav__end{ display:flex; align-items:center; gap:clamp(1rem,2vw,1.75rem); }

/* theme toggle */
.theme{
  display:flex; align-items:center; gap:.6rem;
  background:none; border:0; padding:0;
  cursor:pointer; color:var(--text-2);
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase;
  transition:color var(--d-fast) var(--e-out-quart);
}
.theme:hover{ color:var(--text-1); }
.theme__track{
  position:relative; display:block;
  width:34px; height:18px; border-radius:999px;
  border:1px solid var(--rule);
  background:var(--ink-2);
  transition:border-color var(--d-norm) var(--e-out-quart);
}
.theme__knob{
  position:absolute; top:50%; left:3px;
  width:10px; height:10px; margin-top:-5px;
  border-radius:50%;
  background:var(--accent);
  transition:transform var(--d-norm) var(--e-out-expo);
}
.theme[aria-pressed="true"] .theme__knob{ transform:translate3d(15px,0,0); }
.theme:hover .theme__track{ border-color:var(--accent); }
.theme__label{ min-width:3.2em; text-align:left; }

@media (max-width:640px){ .theme__label{ display:none; } }

.nav__status .dot{
  width:6px; height:6px; border-radius:50%; background:var(--accent);
  animation:pulse 2.6s var(--e-in-out) infinite;
}
@keyframes pulse{
  0%,100%{ opacity:1; transform:scale(1); }
  50%    { opacity:.35; transform:scale(.7); }
}

/* ── mobile menu ──────────────────────────────────────────── */
/* The inline links are hidden below 900px, so the burger and this panel are
   the only navigation a phone gets. They must stay in lockstep with the
   breakpoint above or the site loses its nav entirely. */
.burger{
  display:none;
  background:none; border:0; padding:.4rem; margin:-.4rem;
  cursor:pointer; color:var(--text-1);
  line-height:0;
}
.burger__box{ display:block; width:26px; }
.burger__box i{
  display:block; height:1.5px; border-radius:2px;
  background:currentColor;
  transition:transform var(--d-norm) var(--e-out-expo),
             width var(--d-norm) var(--e-out-expo),
             opacity var(--d-fast) linear;
}
.burger__box i:first-child{ width:26px; }
.burger__box i:last-child{ width:17px; margin-top:6px; }
.burger[aria-expanded="true"] .burger__box i:first-child{ transform:translateY(3.75px) rotate(45deg); }
.burger[aria-expanded="true"] .burger__box i:last-child{ width:26px; transform:translateY(-3.75px) rotate(-45deg); }

.menu{
  position:fixed; inset:0; z-index:150;
  background:var(--ink);
  display:flex; flex-direction:column; justify-content:center;
  gap:clamp(2rem,7vh,4rem);
  padding:calc(var(--pad) + 4.5rem) var(--pad) var(--pad);
  /* Visible is the resting state, and the fade is a one-shot animation rather
     than a transition from opacity:0. If animation never runs — a throttled
     tab, a compositor that is not painting, prefers-reduced-motion — the menu
     is simply there. Starting at 0 and depending on a transition to undo it
     risks a laid-out, invisible overlay that still swallows taps. */
  opacity:1;
}
.menu.open{ animation:menuIn var(--d-norm) var(--e-out-quart); }
@keyframes menuIn{ from{ opacity:0; } to{ opacity:1; } }
.menu__links{ display:flex; flex-direction:column; gap:clamp(.6rem,2.2vh,1.1rem); }
.menu__links a{
  font-family:var(--serif);
  font-size:clamp(2.1rem,10vw,3.2rem);
  line-height:1.06; letter-spacing:-0.02em;
  color:var(--text-1);
  display:flex; align-items:baseline; gap:.7rem;
}
.menu__links a em{
  font-family:var(--mono); font-style:normal;
  font-size:var(--fs-micro); color:var(--accent-lit);
}
.menu__links a:active{ color:var(--accent-lit); }
.menu__foot{
  display:flex; flex-direction:column; gap:.5rem;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.08em; color:var(--text-3);
  border-top:1px solid var(--rule); padding-top:1.5rem;
}
.menu__foot a{ color:var(--text-2); }
.menu__install{
  align-self:flex-start; margin-top:.6rem;
  font-family:var(--mono); font-size:var(--fs-micro); letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--on-accent); background:var(--accent-deep);
  border:0; border-radius:var(--radius-xs);
  padding:.7rem 1.1rem;
  cursor:pointer;
}

body.menu-open{ overflow:hidden; }

@media (max-width:900px){
  .nav__links{ display:none; }
  .burger{ display:block; }

  /* Touch targets. These controls were 18-22px tall, which is roughly half
     what a fingertip reliably hits. The hit area grows with padding and is
     pulled back with negative margin, so nothing moves visually. */
  .nav__status,
  .theme,
  .burger{
    min-height:44px;
    display:flex; align-items:center;
  }
  .burger{ justify-content:flex-end; min-width:44px; padding:0; margin:0; }
  .nav__end{ gap:clamp(.75rem,3vw,1.25rem); }
}

@media (min-width:901px){
  .menu{ display:none !important; }
}

/* ═══════════════════════════════════════════════════════════
   hero
   ═══════════════════════════════════════════════════════════ */
.hero{
  position:relative;
  /* the ghost word and the portrait are meant to bleed; clip them here so
     they never widen the document */
  overflow:hidden;
  min-height:100svh;
  display:flex; flex-direction:column; justify-content:flex-end;
  padding-top:clamp(6rem,13vh,10rem); padding-bottom:clamp(2rem,5vh,4rem);
  max-width:var(--max); margin-inline:auto;
}

/* blueprint rules — the only decorative layer, deliberately faint */
.hero__rules{
  position:absolute; inset:0 var(--pad);
  display:grid; grid-template-columns:repeat(5,1fr);
  pointer-events:none;
}
.hero__rules i{ border-left:1px solid var(--rule); }
.hero__rules i:first-child{ border-left:0; }

/* the oversized word behind the hero — pure atmosphere, never read */
.hero__ghost{
  position:absolute;
  top:13vh; left:37%;
  font-family:var(--serif);
  font-size:clamp(5rem,18vw,19rem);
  line-height:.72;
  letter-spacing:-0.04em;
  color:var(--accent);
  opacity:.10;
  pointer-events:none;
  user-select:none;
  white-space:nowrap;
  z-index:0;
}
/* lift the text above the backdrop layers — but the ghost, the rules and the
   portrait are backdrop themselves, so they must keep their own positioning */
.hero > *:not(.hero__ghost):not(.hero__rules):not(.hero__portrait){
  position:relative; z-index:1;
}

/* portrait — sits between the ghost word and the headline */
.hero__portrait{
  position:absolute;
  right:1%; top:7vh;
  /* an explicit width: deriving it from the image's intrinsic ratio lets the
     figure fall back into normal flow and shove the headline down */
  width:clamp(280px, 33vw, 500px);
  height:auto;
  z-index:0;
  margin:0;
  pointer-events:none;
}
.hero__portrait img{
  width:100%; height:auto;
  object-fit:contain; object-position:bottom center;
  /* graded toward the palette, then feathered so the cut never shows */
  filter:grayscale(.2) contrast(1.06) brightness(.96);
  -webkit-mask-image:linear-gradient(to bottom, #000 62%, transparent 99%);
          mask-image:linear-gradient(to bottom, #000 62%, transparent 99%);
}
@media (max-width:1100px){
  .hero__portrait{ height:52vh; right:-4%; opacity:.55; }
}
/* On a phone the portrait was dropped entirely, to stop it colliding with the
   headline. It sits in the free band between the nav and the eyebrow instead,
   top-right, with the text layered above it so nothing can be obscured. */
@media (max-width:820px){
  .hero__portrait{
    display:block;
    top:4.25rem; right:var(--pad); left:auto;
    width:min(36vw,142px);
    height:auto;
    opacity:.92;
    z-index:0;
  }
  .hero__eyebrow{ max-width:min(56%, 200px); }
}

/* credibility band */
.marks{
  border-bottom:1px solid var(--rule);
  background:var(--ink);
}
.marks ul{
  max-width:var(--max); margin-inline:auto;
  padding-inline:var(--pad);
  display:grid; grid-template-columns:repeat(3,1fr);
}
.marks li{
  padding-block:clamp(2rem,5vh,3.5rem);
  padding-inline:clamp(1rem,2.5vw,2.5rem);
  border-left:1px solid var(--rule);
}
.marks li:first-child{ border-left:0; padding-left:0; }
.marks b{
  display:block;
  font-family:var(--serif); font-weight:400;
  font-size:clamp(2.75rem,6vw,5.5rem); line-height:.85;
  letter-spacing:-0.03em;
  color:var(--accent);
}
.marks span{
  display:block; margin-top:.75rem;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--text-3);
}
@media (max-width:900px){
  .hero__ghost{ left:auto; right:-14vw; top:9vh; opacity:.08; }
}
@media (max-width:640px){
  .marks ul{ grid-template-columns:1fr; }
  .marks li{ border-left:0; padding-left:0; border-top:1px solid var(--rule); }
  .marks li:first-child{ border-top:0; }
}

.hero__eyebrow{
  display:flex; flex-wrap:wrap; gap:.7rem;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.18em; text-transform:uppercase; color:var(--text-2);
  margin-bottom:clamp(1.25rem,3vh,2.25rem);
}
.hero__eyebrow .sep{ color:var(--accent-lit); }

.hero__title{
  font-family:var(--serif);
  font-size:var(--fs-display);
  line-height:.84;
  letter-spacing:-0.035em;
  font-weight:400;
  margin-bottom:clamp(1.5rem,5vh,3.5rem);
}
.hero__title .line{ display:block; overflow:hidden; padding-bottom:.06em; }
.hero__title .word{ display:block; will-change:transform; }
.hero__title .accent{ color:var(--accent); font-style:italic; }
/* optical: pull the italic line back onto the left margin */
.hero__title .accent{ margin-left:-0.04em; }

.hero__foot{
  display:grid;
  grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
  gap:clamp(1.5rem,4vw,5rem);
  align-items:end;
  border-top:1px solid var(--rule);
  padding-top:1.6rem;
}
.hero__lede{
  font-size:var(--fs-lede);
  line-height:1.5;
  max-width:44ch;
  color:var(--text-2);
  text-wrap:pretty;
}
.hero__meta{
  display:flex; flex-wrap:wrap; gap:clamp(1.25rem,3vw,3rem);
  justify-content:flex-end;
}
.hero__meta dt{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase; color:var(--text-3);
  margin-bottom:.3rem;
}
.hero__meta dd{ font-size:.9rem; }
#clock{ font-family:var(--mono); font-variant-numeric:tabular-nums; }

.hero__scroll{
  position:absolute; right:var(--pad); bottom:calc(clamp(2rem,5vh,4rem) + 11rem);
  display:flex; align-items:center; gap:.7rem;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.18em; text-transform:uppercase; color:var(--text-3);
  writing-mode:vertical-rl;
}
.hero__scroll i{
  display:block; width:1px; height:64px; background:var(--rule);
  position:relative; overflow:hidden;
}
.hero__scroll i::after{
  content:""; position:absolute; inset:0; background:var(--accent);
  animation:trace 2.4s var(--e-in-out) infinite;
}
@keyframes trace{
  0%   { transform:translateY(-100%); }
  55%  { transform:translateY(0); }
  100% { transform:translateY(100%); }
}

@media (max-width:820px){
  .hero__foot{ grid-template-columns:1fr; }
  .hero__meta{ justify-content:flex-start; }
  .hero__scroll{ display:none; }
  .hero__rules{ grid-template-columns:repeat(3,1fr); }
}

/* ── page-load choreography ───────────────────────────────── */
html.js .load{ opacity:0; transform:translate3d(0,26px,0); }
html.js .hero__title .word{ transform:translate3d(0,110%,0); }

body.ready .load{
  animation:loadIn .9s var(--e-out-expo) forwards;
}
body.ready .hero__title .word{
  animation:wordIn 1.15s var(--e-out-expo) forwards;
}
@keyframes loadIn{ to{ opacity:1; transform:translate3d(0,0,0); } }
@keyframes wordIn{ to{ transform:translate3d(0,0,0); } }

body.ready [data-load="1"]{ animation-delay:.05s; }
body.ready [data-load="2"]{ animation-delay:.18s; }
body.ready [data-load="3"]{ animation-delay:.28s; }
body.ready [data-load="4"]{ animation-delay:.38s; }
body.ready [data-load="5"]{ animation-delay:.62s; }
body.ready [data-load="6"]{ animation-delay:.72s; }
body.ready [data-load="7"]{ animation-delay:.86s; }
body.ready .nav{ animation:loadIn .8s var(--e-out-expo) .55s backwards; }

/* ═══════════════════════════════════════════════════════════
   ticker
   ═══════════════════════════════════════════════════════════ */
.ticker{
  border-block:1px solid var(--rule);
  padding-block:1rem;
  overflow:hidden;
  background:var(--ink-2);
}
.ticker__track{
  display:flex; align-items:center; gap:2.25rem;
  width:max-content;
  animation:marquee 46s linear infinite;
}
.ticker__track span{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.18em; text-transform:uppercase; white-space:nowrap;
  color:var(--text-2);
}
.ticker__track i{ color:var(--accent-lit); font-style:normal; font-size:.6rem; }
@keyframes marquee{ to{ transform:translate3d(-50%,0,0); } }

/* ═══════════════════════════════════════════════════════════
   about
   ═══════════════════════════════════════════════════════════ */
.about{
  max-width:var(--max); margin-inline:auto;
  padding-block:clamp(6rem,16vh,13rem);
}
.about .sec-num{ margin-bottom:clamp(2.5rem,6vh,4.5rem); }

.statement{
  font-family:var(--serif);
  font-size:clamp(1.9rem,5.2vw,4.6rem);
  line-height:1.06;
  letter-spacing:-0.025em;
  /* deliberate asymmetry: pushed off the left margin, bleeding right */
  margin-left:clamp(0rem,8vw,10rem);
  max-width:22ch;
  text-wrap:balance;
}
.statement span{ display:block; overflow:hidden; }
.statement em{ color:var(--accent); font-style:italic; }

.about__cols{
  display:grid; grid-template-columns:repeat(3,1fr);
  gap:clamp(1.75rem,3.5vw,4rem);
  margin-top:clamp(4rem,11vh,9rem);
  border-top:1px solid var(--rule);
  padding-top:2rem;
}
.about__col h3{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase;
  font-weight:500; color:var(--accent-lit);
  margin-bottom:1rem;
}
.about__col p{ color:var(--text-2); max-width:34ch; text-wrap:pretty; }

@media (max-width:820px){
  .about__cols{ grid-template-columns:1fr; gap:2.25rem; }
  .statement{ margin-left:0; max-width:none; }
}

/* ═══════════════════════════════════════════════════════════
   02 — the delivery lifecycle
   ═══════════════════════════════════════════════════════════
   This was a sticky, scroll-assembled SVG diagram. Its labels were unreadable
   on a phone and, part-drawn, its bare connectors read as stray marks with no
   meaning attached. The six stages carry the idea on their own, so the drawing
   and the 280vh of pinned scroll it needed are gone.
*/
.system{
  position:relative;
  background:var(--ink-3);
  color:var(--paper);
  padding-block:clamp(5rem,14vh,10rem);
}
.system__inner{
  max-width:var(--max); margin-inline:auto;
  display:grid;
  grid-template-columns:minmax(300px,34%) minmax(0,1fr);
  gap:clamp(2rem,5vw,5rem);
  align-items:start;
}
.system__head .sec-num{ margin-bottom:1.5rem; }
.system__title{
  font-family:var(--serif);
  /* capped so the longest word in the heading fits the column */
  font-size:clamp(2.1rem,3.6vw,3.9rem);
  line-height:.94; letter-spacing:-0.03em; font-weight:400;
  text-wrap:balance;
  margin-bottom:1.25rem;
}
.system__title em{ color:var(--accent-lit); font-style:italic; }
.system__note{
  font-size:.95rem; line-height:1.6; max-width:38ch;
  color:color-mix(in oklab, var(--paper) 58%, var(--ink));
}

.system__legend{
  display:grid; grid-template-columns:repeat(2,1fr);
  gap:clamp(1.5rem,3vw,2.5rem) clamp(1.5rem,3vw,3rem);
}
.system__legend li{
  position:relative;
  padding-top:1.6rem;
  font-family:var(--mono); font-size:var(--fs-micro); line-height:1.5;
  letter-spacing:.02em;
  color:color-mix(in oklab, var(--paper) 34%, var(--ink));
  transition:color var(--d-norm) var(--e-out-quart);
}
/* the node */
.system__legend li::before{
  content:""; position:absolute; left:0; top:0; z-index:1;
  width:7px; height:7px; border-radius:50%;
  background:color-mix(in oklab, var(--paper) 26%, var(--ink));
  transition:background var(--d-norm) var(--e-out-quart),
             box-shadow var(--d-norm) var(--e-out-quart);
}
/* no connecting wire: the stages now wrap across rows */

.system__legend li em{
  display:block; font-style:normal; margin-bottom:.4rem;
  color:color-mix(in oklab, var(--paper) 22%, var(--ink));
  transition:color var(--d-norm) var(--e-out-quart);
}
.system__legend li.on{ color:var(--paper); }
.system__legend li.on em{ color:var(--accent-lit); }
.system__legend li.on::before{
  background:var(--accent);
  box-shadow:0 0 0 4px color-mix(in oklab, var(--accent) 18%, transparent);
}

@media (max-width:1000px){
  .system__head{ grid-column:1; grid-row:1; }
  /* wrapped onto several rows the wire would run off the end, so drop it */
  .system__legend{ grid-row:3; grid-template-columns:repeat(3,1fr); }
  .system__legend li::after{ display:none; }
  .system__title{ margin-bottom:.75rem; }
  .system__note{ max-width:46ch; }
}
@media (max-width:640px){
  /* The legend used to be hidden here, back when it was a six-across row with
     no room on a phone. It now carries the whole section on small screens, so
     hiding it left nothing behind but a heading. */
}

/* ═══════════════════════════════════════════════════════════
   work
   ═══════════════════════════════════════════════════════════ */
.work{
  max-width:var(--max); margin-inline:auto;
  padding-block:clamp(6rem,16vh,13rem);
}
.work__head{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:2rem; align-items:end;
  margin-bottom:clamp(3rem,8vh,6rem);
}
.work__head .sec-num{ grid-column:1; margin-bottom:1.5rem; }
.work__title{
  grid-column:1;
  font-family:var(--serif); font-weight:400;
  font-size:var(--fs-h2); line-height:.88; letter-spacing:-0.035em;
}
.work__title em{ color:var(--accent); font-style:italic; }
.work__note{
  grid-column:2; justify-self:end; text-align:right;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.12em; text-transform:uppercase; color:var(--text-3);
}

/* ── case studies ─────────────────────────────────────────── */
.case{
  display:grid;
  grid-template-columns:5.5rem minmax(0,1.05fr) minmax(0,0.95fr);
  gap:clamp(1.5rem,3vw,4.5rem);
  align-items:start;
  padding-block:clamp(3.5rem,9vh,7rem);
  border-top:1px solid var(--rule);
}
.case:last-of-type{ border-bottom:1px solid var(--rule); }

/* the imagery alternates sides; the numbering rail never moves */
.case__main{ grid-column:2; }
.shot       { grid-column:3; }
.case--flip{ grid-template-columns:5.5rem minmax(0,0.95fr) minmax(0,1.05fr); }
.case--flip .case__main{ grid-column:3; }
.case--flip .shot       { grid-column:2; }

.case__aside{ grid-column:1; }
.case__num{
  display:block;
  font-family:var(--serif); font-size:clamp(2.5rem,4.5vw,4.25rem);
  line-height:.8; letter-spacing:-0.03em; color:var(--accent);
}
.case__year{
  display:block; margin-top:.75rem;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase; color:var(--text-3);
}

.case__kicker{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.14em; text-transform:uppercase; color:var(--text-3);
  margin-bottom:1rem;
}
.case__title{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(2.4rem,5.5vw,5rem); line-height:.9; letter-spacing:-0.035em;
  margin-bottom:1rem;
}
.case__lede{
  font-size:var(--fs-lede); line-height:1.5; color:var(--text-2);
  max-width:42ch; text-wrap:pretty;
  margin-bottom:clamp(1.75rem,4vh,2.75rem);
}

.case__cols{
  display:grid; grid-template-columns:repeat(2,1fr);
  gap:clamp(1.25rem,2.5vw,2.5rem);
  margin-bottom:clamp(1.75rem,4vh,2.5rem);
}
.case__cols h4{
  font-family:var(--mono); font-size:var(--fs-micro); font-weight:500;
  letter-spacing:.14em; text-transform:uppercase; color:var(--accent-lit);
  padding-bottom:.7rem; margin-bottom:.85rem;
  border-bottom:1px solid var(--rule);
}
.case__cols p{ font-size:1rem; line-height:1.62; color:var(--text-2); text-wrap:pretty; }

.case__metrics{
  display:flex; flex-wrap:wrap; gap:clamp(1.25rem,3vw,2.75rem);
  padding-block:1.25rem;
  border-top:1px solid var(--rule);
  border-bottom:1px solid var(--rule);
  margin-bottom:1.5rem;
}
.case__metrics b{
  display:block;
  font-family:var(--serif); font-weight:400;
  font-size:clamp(1.4rem,2.2vw,2rem); line-height:1; letter-spacing:-0.02em;
  color:var(--accent);
}
.case__metrics span{
  display:block; margin-top:.35rem;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.08em; color:var(--text-3);
}

.case__tags{ display:flex; flex-wrap:wrap; gap:.4rem; margin-bottom:1.75rem; }
.case__tags li{
  font-family:var(--mono); font-size:.66rem;
  letter-spacing:.08em; text-transform:uppercase;
  border:1px solid var(--rule); border-radius:var(--radius-xs);
  padding:.35rem .75rem; color:var(--text-2);
  transition:border-color var(--d-norm) var(--e-soft),
             color var(--d-norm) var(--e-soft);
}
.case:hover .case__tags li{
  border-color:color-mix(in oklab, var(--accent) 60%, var(--ink));
  color:var(--text-1);
}

.case__link{
  display:inline-flex; align-items:center; gap:.75rem;
  font-family:var(--mono); font-size:.8rem; letter-spacing:.04em;
  padding-bottom:.4rem;
  border-bottom:1px solid var(--accent-lit);
  color:var(--accent-lit);
  min-height:44px;                 /* fingertip-sized on touch */
  will-change:transform;
}
.case__arrow{ transition:transform var(--d-norm) var(--e-out-expo); }
.case__link:hover .case__arrow{ transform:translate3d(3px,-3px,0); }

/* ── screenshot frame ─────────────────────────────────────── */
.shot{
  position:relative;              /* anchors the rail arrows */
  border:1px solid var(--rule);
  border-radius:var(--radius);    /* large panel */
  background:var(--ink-2);
  overflow:hidden;
}
.shot__chrome{
  display:flex; align-items:center; gap:.4rem;
  padding:.7rem .85rem;
  border-bottom:1px solid var(--rule);
  background:var(--ink);
}
.shot__chrome i{
  width:8px; height:8px; border-radius:50%;
  background:color-mix(in oklab, var(--paper) 20%, var(--ink));
}
.shot__url{
  margin-left:.6rem;
  font-family:var(--mono); font-size:.66rem; letter-spacing:.06em;
  color:var(--text-3);
}
/* a snapping rail, so a case can carry several screenshots */
.shot__rail{
  display:flex;
  aspect-ratio:16 / 10;             /* reserved — keeps CLS at zero */
  overflow-x:auto;
  overscroll-behavior-x:contain;    /* do not chain to the page scroll */
  scroll-snap-type:x mandatory;
  scroll-behavior:smooth;
  scrollbar-width:none;
  -ms-overflow-style:none;
  background:
    repeating-linear-gradient(45deg,
      transparent 0 10px,
      color-mix(in oklab, var(--paper) 5%, transparent) 10px 20px);
}
.shot__rail::-webkit-scrollbar{ display:none; }
.shot__rail:focus-visible{ outline:2px solid var(--accent); outline-offset:-3px; }
.shot__rail img{
  flex:0 0 100%;
  width:100%; height:100%;
  object-fit:cover; object-position:top center;
  scroll-snap-align:center;
  scroll-snap-stop:always;
}

/* how many, and which one — the frame should say so */
.shot__count{
  margin-left:auto;
  font-family:var(--mono); font-size:.66rem; letter-spacing:.1em;
  color:var(--text-3);
  font-variant-numeric:tabular-nums;
}

/* arrows are the affordance: always on for touch, on hover for pointers */
.shot__nav{
  position:absolute; top:calc(50% + 1.5rem);
  z-index:2;
  width:38px; height:38px;
  display:grid; place-items:center;
  transform:translateY(-50%);
  border:1px solid var(--rule);
  border-radius:50%;
  background:color-mix(in oklab, var(--ink) 76%, transparent);
  backdrop-filter:blur(6px);
  color:var(--text-1);
  font-family:var(--sans); font-size:1.2rem; line-height:1;
  cursor:pointer;
  opacity:0;
  transition:opacity var(--d-norm) var(--e-out-quart),
             background var(--d-fast) var(--e-out-quart),
             border-color var(--d-fast) var(--e-out-quart),
             color var(--d-fast) var(--e-out-quart);
}
.shot__nav--prev{ left:.75rem; }
.shot__nav--next{ right:.75rem; }
.shot:hover .shot__nav,
.shot__nav:focus-visible{ opacity:1; }
.shot__nav:hover{
  background:var(--accent); border-color:var(--accent); color:var(--on-accent);
}
.shot__nav[disabled]{ opacity:0 !important; pointer-events:none; }
@media (hover:none){ .shot__nav{ opacity:1; } }

/* Bigger hit area on touch. This has to sit AFTER the base .shot__nav rule:
   a media query adds no specificity, so placed earlier the 38px base simply
   won. Keyed on width as well as pointer, because hover:none is not reliably
   reported under device emulation. */
@media (hover:none), (max-width:900px){
  .shot__nav{ width:46px; height:46px; font-size:1.35rem; }
  .shot__nav--prev{ left:.5rem; }
  .shot__nav--next{ right:.5rem; }
}

.shot__empty{
  position:absolute; top:50%; left:50%;
  transform:translate(-50%,-50%);
  width:min(88%, 36ch);
  font-family:var(--mono); font-size:var(--fs-micro); line-height:1.7;
  letter-spacing:.06em; text-align:center; color:var(--text-3);
}
.shot.has-shots .shot__empty{ display:none; }
.shot__empty code{
  font-family:var(--mono);
  color:var(--accent-lit);
  border-bottom:1px solid color-mix(in oklab, var(--accent-lit) 45%, var(--ink));
}

@media (max-width:1100px){
  .case{ grid-template-columns:4rem minmax(0,1fr); }
  .case__main,.case--flip .case__main{ grid-column:2; }
  .shot,.case--flip .shot{ grid-column:2; margin-top:2rem; }
  .case__lede{ max-width:52ch; }
}
@media (max-width:640px){
  .case{ grid-template-columns:1fr; }
  .case__aside{
    grid-column:1;
    display:flex; align-items:baseline; gap:1rem;
  }
  .case__year{ margin-top:0; }
  .case__main,.case--flip .case__main,.shot,.case--flip .shot{ grid-column:1; }
  .case__cols{ grid-template-columns:1fr; gap:1.5rem; }
}

@media (max-width:900px){
  .work__head{ grid-template-columns:1fr; }
  .work__note{ grid-column:1; justify-self:start; text-align:left; }
}

/* ═══════════════════════════════════════════════════════════
   path
   ═══════════════════════════════════════════════════════════ */
.path{
  max-width:var(--max); margin-inline:auto;
  padding-block:clamp(5rem,13vh,10rem);
  border-top:1px solid var(--rule);
}
.path__head{ margin-bottom:clamp(2.5rem,6vh,5rem); }
.path__head .sec-num{ margin-bottom:1.5rem; }
.path__title{
  font-family:var(--serif); font-weight:400;
  font-size:var(--fs-h2); line-height:.9; letter-spacing:-0.035em;
}
.path__title em{ color:var(--accent); font-style:italic; }

.path__list li{
  display:grid;
  grid-template-columns:minmax(0,12rem) minmax(0,1fr);
  gap:clamp(1rem,3vw,4rem);
  padding-block:clamp(1.75rem,3.5vh,2.5rem);
  border-top:1px solid var(--rule);
  /* offset into the right two-thirds — asymmetric on purpose */
  margin-left:auto;
  width:min(100%, 62rem);
}
.path__when{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.14em; color:var(--accent-lit);
  padding-top:.4rem;
}
.path__list h3{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(1.3rem,2vw,1.85rem); line-height:1.1;
  letter-spacing:-0.02em; margin-bottom:.15rem;
}
.path__where{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.1em; text-transform:uppercase;
  color:var(--text-3); margin-bottom:.85rem;
}
.path__list p:last-child{ color:var(--text-2); max-width:52ch; text-wrap:pretty; }

@media (max-width:700px){
  .path__list li{ grid-template-columns:1fr; gap:.85rem; }
}

/* ═══════════════════════════════════════════════════════════
   stack
   ═══════════════════════════════════════════════════════════ */
.stack{
  max-width:var(--max); margin-inline:auto;
  padding-block:clamp(5rem,13vh,10rem);
  border-top:1px solid var(--rule);
}
.stack__head{ margin-bottom:clamp(2.5rem,6vh,5rem); }
.stack__head .sec-num{ margin-bottom:1.5rem; }
.stack__title{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(2.25rem,5.5vw,5rem); line-height:.9; letter-spacing:-0.035em;
}
.stack__title em{ color:var(--accent); font-style:italic; }

.stack__note{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; color:var(--accent-lit);
  margin-top:1.25rem;
}

/* ── tool cards ─────────────────────────────────────────────── */
.tools{
  display:grid;
  /* twelve tools divide evenly into four, so the last row is never ragged */
  grid-template-columns:repeat(4,1fr);
  gap:clamp(.6rem,1.2vw,1rem);
  margin-bottom:clamp(3rem,8vh,6rem);
}
.tool{
  display:flex; flex-direction:column; align-items:center;
  gap:clamp(1rem,2vh,1.5rem);
  padding:clamp(1.5rem,3.2vw,2.5rem) 1rem;
  border:1px solid var(--rule);
  border-radius:var(--radius-s);
  overflow:hidden;                 /* nothing escapes a card onto its label */
  background:var(--ink-2);
  transition:border-color var(--d-norm) var(--e-out-quart),
             background var(--d-norm) var(--e-out-quart),
             transform var(--d-norm) var(--e-soft);
}
/* The mark box is definite in BOTH axes and the image fills it with
   object-fit:contain. A percentage max-height does not resolve against a grid
   track, so the previous rule left only the width cap binding and any squarish
   logo rendered at 96px inside a 58px box, spilling onto the label. */
/* Absolute inset, not a grid item. A percentage height on a grid item does not
   reliably resolve, so tall logos fell back to their intrinsic ratio: Java came
   out 193px in a 62px box and covered its own label. Offsets make the size
   definite, and object-fit letterboxes the artwork inside it. */
.tool__mark{
  position:relative;
  width:clamp(76px,7vw,104px);
  height:clamp(44px,4.8vw,62px);
}
.tool__mark img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:contain;
  /* dimmed until you look at it, so the grid reads as one texture */
  filter:grayscale(.35) brightness(.92);
  transition:transform var(--d-norm) var(--e-out-expo),
             filter var(--d-norm) var(--e-out-quart);
}
.tool__name{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.12em; text-transform:uppercase;
  color:var(--text-3);
  text-align:center;
  transition:color var(--d-norm) var(--e-out-quart);
}
.tool:hover{
  border-color:color-mix(in oklab, var(--accent) 65%, var(--ink));
  background:color-mix(in oklab, var(--accent) 7%, var(--ink-2));
  transform:translate3d(0,-4px,0);
}
.tool:hover .tool__mark img{ transform:scale(1.09); filter:none; }
.tool:hover .tool__name{ color:var(--paper); }

@media (max-width:1000px){ .tools{ grid-template-columns:repeat(3,1fr); } }
@media (max-width:620px){  .tools{ grid-template-columns:repeat(2,1fr); } }

.stack__grid{
  /* three capability groups, so name the tracks rather than letting auto-fit
     leave collapsed ones behind */
  display:grid; grid-template-columns:repeat(3,1fr);
  gap:clamp(1rem,1.6vw,1.5rem);
}
.stack__group{
  border:1px solid var(--rule);
  border-radius:var(--radius-s);
  background:var(--ink-2);
  padding:clamp(1.5rem,2.6vw,2rem);
}
.stack__group h3{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase; font-weight:500;
  color:var(--accent-lit);
  padding-bottom:.85rem; margin-bottom:1.1rem;
  border-bottom:1px solid var(--rule);
}
.stack__group li{
  font-size:1rem; color:var(--text-2);
  padding-block:.3rem;
  transition:color var(--d-fast) var(--e-out-quart), transform var(--d-fast) var(--e-out-quart);
}
.stack__group li:hover{ color:var(--text-1); transform:translate3d(4px,0,0); }

@media (max-width:900px){ .stack__grid{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:520px){ .stack__grid{ grid-template-columns:1fr; } }

/* ═══════════════════════════════════════════════════════════
   contact
   ═══════════════════════════════════════════════════════════ */
.contact{
  background:var(--ink-2); color:var(--paper);
  padding-block:clamp(6rem,18vh,14rem);
}
.contact > *{ max-width:var(--max); margin-inline:auto; }
.contact__eyebrow{
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase;
  color:color-mix(in oklab, var(--paper) 55%, var(--ink));
  margin-block:1.5rem clamp(2rem,5vh,3.5rem);
}
.contact__title{
  font-family:var(--serif); font-weight:400;
  font-size:var(--fs-h2); line-height:.88; letter-spacing:-0.035em;
  margin-bottom:clamp(2.5rem,6vh,4.5rem);
}
.contact__title .line{ display:block; overflow:hidden; padding-bottom:.06em; }
.contact__title em{ color:var(--accent-lit); font-style:italic; }

.cta{
  display:inline-flex; align-items:center; gap:1.25rem;
  border:1px solid color-mix(in oklab, var(--paper) 26%, transparent);
  border-radius:999px;
  padding:1.05rem 1.75rem;
  font-family:var(--mono); font-size:.85rem; letter-spacing:.04em;
  position:relative; overflow:hidden;
  will-change:transform;
  transition:border-color var(--d-norm) var(--e-out-quart),
             color var(--d-norm) var(--e-out-quart);
}
.cta::before{
  content:""; position:absolute; inset:0; z-index:-1;
  background:var(--accent-deep);
  transform:translate3d(0,101%,0);
  transition:transform var(--d-norm) var(--e-out-expo);
}
.cta:hover{ border-color:var(--accent-deep); color:var(--on-accent); }
.cta:hover::before{ transform:translate3d(0,0,0); }
.cta__icon{ transition:transform var(--d-norm) var(--e-out-expo); }
.cta:hover .cta__icon{ transform:translate3d(6px,0,0); }

.contact__links{
  display:flex; flex-wrap:wrap; gap:clamp(1.25rem,3vw,2.75rem);
  margin-top:clamp(2.5rem,6vh,4rem);
  padding-top:1.5rem;
  border-top:1px solid color-mix(in oklab, var(--paper) 14%, transparent);
}
.contact__links a{
  position:relative;
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.16em; text-transform:uppercase;
  color:color-mix(in oklab, var(--paper) 62%, var(--ink));
  transition:color var(--d-fast) var(--e-out-quart);
  display:inline-block; will-change:transform;
}
.contact__links a::after{
  content:""; position:absolute; left:0; right:0; bottom:-5px; height:1px;
  background:var(--accent-lit);
  transform:scaleX(0); transform-origin:0 50%;
  transition:transform var(--d-norm) var(--e-out-expo);
}
.contact__links a:hover{ color:var(--paper); }
.contact__links a:hover::after{ transform:scaleX(1); }

/* ═══════════════════════════════════════════════════════════
   footer
   ═══════════════════════════════════════════════════════════ */
.foot{
  background:var(--ink-3); color:color-mix(in oklab, var(--paper) 45%, var(--ink));
  display:flex; flex-wrap:wrap; gap:1rem; justify-content:space-between;
  padding-block:2rem;
  border-top:1px solid color-mix(in oklab, var(--paper) 12%, transparent);
  font-family:var(--mono); font-size:var(--fs-micro);
  letter-spacing:.1em; text-transform:uppercase;
}
.foot a{ display:inline-block; will-change:transform; transition:color var(--d-fast) var(--e-out-quart); }
.foot a:hover{ color:var(--accent-lit); }

/* ═══════════════════════════════════════════════════════════
   scrubbed character reveal
   ═══════════════════════════════════════════════════════════ */
/* Characters start dim and resolve with scroll position. No transition here
   on purpose: opacity is written every frame from scroll, so a transition
   would lag behind the pointer instead of tracking it. */
html.js [data-scrub] .ch{ opacity:.18; }
/*
   Plain inline, never inline-block. An inline-block is an atomic inline box and
   the browser may break a line between any two of them, so splitting a heading
   into per-character inline-blocks let it break mid-word: "From require /
   ment". Inline spans add no break opportunity, so normal word wrapping
   survives. Only opacity is animated here, so nothing needs a block box.
*/

@media (prefers-reduced-motion:reduce){
  [data-scrub] .ch{ opacity:1 !important; }
}

/* ═══════════════════════════════════════════════════════════
   scroll reveals
   ═══════════════════════════════════════════════════════════ */
html.js [data-reveal]{
  opacity:0; transform:translate3d(0,36px,0);
  transition:opacity .8s var(--e-out-quart), transform 1s var(--e-out-expo);
  transition-delay:var(--rd,0ms);
  will-change:transform,opacity;
}
html.js [data-reveal].on{ opacity:1; transform:translate3d(0,0,0); }

[data-reveal-line]{ display:block; }
html.js [data-reveal-line]{
  transform:translate3d(0,105%,0);
  transition:transform 1s var(--e-out-expo);
  transition-delay:var(--rd,0ms);
  will-change:transform;
}
html.js [data-reveal-line].on{ transform:translate3d(0,0,0); }

/* ═══════════════════════════════════════════════════════════
   reduced motion — everything still readable, nothing moves
   ═══════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  .load,[data-reveal]{ opacity:1 !important; transform:none !important; }
  [data-reveal-line],.hero__title .word{ transform:none !important; }
  .system__stats{ opacity:1 !important; transform:none !important; }
  .cursor{ display:none !important; }
  .ticker__track{ animation:none; }
  .loader{ display:none; }
}

/* ── touch targets in the contact block and footer ─────────── */
@media (max-width:900px){
  .contact__links a,
  .foot a{
    display:inline-flex; align-items:center;
    min-height:44px;
  }
  .contact__links{ gap:.25rem 1.5rem; }
}

/* ── the lifecycle on small screens ────────────────────────── */
/*
   The SVG scales to about a third on a phone, which puts its labels at 5.6px
   and its annotations at 3.5px. Unreadable. What survives is a few red
   connectors and an arc floating in black, which reads as decoration with no
   meaning attached.

   So the drawing is dropped below 820px and the same six stages are carried by
   the legend instead, turned into a proper vertical stepped list. Same content,
   legible, and less work for the device.
*/
@media (max-width:820px){

  .system__legend{
    grid-template-columns:1fr;
    gap:0;
    padding-top:.5rem;
  }
  .system__legend li{
    position:relative;
    padding:0 0 1.5rem 1.9rem;
    font-size:.9rem; line-height:1.5;
  }
  .system__legend li:last-child{ padding-bottom:0; }

  /* the node sits on a spine running down the left */
  .system__legend li::before{ top:.3rem; left:0; width:9px; height:9px; }
  .system__legend li::after{
    display:block;
    left:4px; right:auto; top:1.1rem; bottom:0;
    width:1px; height:auto;
  }
  .system__legend li:last-child::after{ display:none; }

  .system__legend li em{
    display:block; margin-bottom:.15rem;
    font-size:var(--fs-micro); letter-spacing:.14em;
  }
}
