/* ============================================
   EDITION8 — site styles
   EDITORIAL MONO — pure white / black, no chroma
   palette: white paper / black ink (Copenhagen editorial)
   type: Fraunces (display) + Geist (UI/body) + Geist Mono (labels)
   ============================================ */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --paper: #FFFFFF;
  --paper-2: #F5F5F4;
  --ink: #0A0A0A;
  --ink-2: #2A2A2A;
  --muted: #6E6E6E;          /* mono label grey — eyebrows, N°08, coords */
  --faint: #9B9B9B;          /* faint grey */
  --rule: rgba(10,10,10,0.13);
  --rule-on-ink: rgba(250,250,250,0.16);
  --scrim: rgba(10,10,10,.6);
  --scrim-strong: rgba(10,10,10,.96);
  --pad: clamp(28px, 5vw, 96px);
  --maxw: 1640px;

  /* === 2026.06 Editorial-Mono token system === */

  /* theme-invariant constants (use sparingly, e.g. video scrims) */
  --paper-dark: #0A0A0A;
  --cream-ink:  #FAFAFA;
  /* accent — REMOVED. The site is strictly monochrome; emphasis is carried
     by the Fraunces italic + weight + whitespace, never colour. Token name
     kept as --rule-red for ABI stability across CSS files (editorial.css /
     menu.css consume it via --ed-red); its VALUE is now pure black so every
     former-indigo accent renders as black ink. Flips to white on dark. */
  --rule-red:   #0A0A0A;
  /* former band gradient — now a flat black fill so the menu columns /
     accents that referenced it read as solid black ink (no chroma). */
  --rule-gradient: linear-gradient(0deg, #0A0A0A 0%, #0A0A0A 100%);

  /* opacity ramps over current type color (--ink) — auto-flip with theme */
  --mute-12: color-mix(in oklab, var(--ink) 12%, transparent);
  --mute-24: color-mix(in oklab, var(--ink) 24%, transparent);
  --mute-40: color-mix(in oklab, var(--ink) 40%, transparent);
  --mute-60: color-mix(in oklab, var(--ink) 60%, transparent);

  /* type scale */
  --display-xl: clamp(4rem, 12vw, 12rem);     /* hero claims */
  --display-lg: clamp(3rem, 8vw, 8rem);       /* section H2 */
  --display-md: clamp(2rem, 4vw, 4rem);       /* card titles */
  --body-lg:    clamp(1.0625rem, 1.2vw, 1.3125rem);
  --mono-kicker-size: 0.75rem;
  --mono-kicker-tracking: 0.08em;

  /* === motion vocabulary — single source of truth (WS2) ===
     The codebase has TWO distinct cinematic ease-out curves; consolidation
     is behavior-preserving, so each keeps its own token (no retiming):
       --ease-cinema  = .2 .7 .2 1   home/archive reveals (19× bare +
                      --works-ease) — the dominant hand-rolled curve.
       --ease-expo    = .16 1 .3 1   editorial/menu/game/services family
                      (was --ed-ease / --e8g-ease / --srv2-ease-cine).
     --ease-spring is the magnetic/overshoot curve (was --srv2-ease-mag).
     Deliberately-unique ease-IN-OUT curves are intentionally NOT aliased:
       .7,0,.18,1 modal sheet · .7,0,.2,1 flow bar · .6,.05,.2,1 logoDrop/drag
       · 0,0,0.2,1 srv decel (Material). They stay as literals/local tokens. */
  --ease-cinema: cubic-bezier(.2, .7, .2, 1);       /* reveals, large moves */
  --ease-expo:   cubic-bezier(0.16, 1, 0.3, 1);     /* editorial reveals */
  --ease-ui:     cubic-bezier(0.4, 0, 0.2, 1);      /* hovers, toggles */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* magnetic accents */

  /* Duration scale — values chosen to equal the durations already most
     used in the code (inventoried), so swaps are behavior-preserving.
     Durations that don't match a step are left as literals on purpose. */
  --dur-1: .2s;   /* micro: 200ms hovers/toggles (most-used ms tier) */
  --dur-2: .35s;  /* short: most-used literal (37×) */
  --dur-3: .5s;   /* medium */
  --dur-4: .7s;   /* long */
  --dur-5: .9s;   /* cinematic reveal */
  --dur-6: 1.2s;  /* extended cinematic move */

  /* legacy aliases — keep the older names working (services/home JS &
     CSS may reference them); values unchanged from prior definitions */
  --dur-micro:    180ms;
  --dur-standard: 420ms;
  --dur-cinema:   900ms;

  /* shared editorial primitives — hoisted from menu.css/editorial.css so
     there is a single source of truth (both files load AFTER styles.css
     on every page). Local --ed-* re-declarations are now redundant. */
  --ed-pad-x: clamp(20px, 4vw, 64px);
  --ed-rule:  1px solid var(--ink);
  --ed-hair:  1px solid var(--mute-24);
  --ed-red:   var(--rule-red);
  --ed-ease:  var(--ease-expo); /* editorial family = 0.16,1,0.3,1 */
  --ed-mono:  'Geist Mono', ui-monospace, monospace;

  /* type families — single source of truth (Editorial Mono) */
  --font-serif: 'Geist', system-ui, sans-serif; /* display / headlines, italic emphasis */
  --font-sans:  'Geist', system-ui, sans-serif;                 /* body / UI / sub */
  --font-mono:  'Geist Mono', ui-monospace, monospace;          /* index labels / eyebrows / N°08 / coords */

  /* grid */
  --gutter: clamp(16px, 2vw, 32px);
  --max-w:  1680px;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-1: 0ms;
    --dur-2: 0ms;
    --dur-3: 0ms;
    --dur-4: 0ms;
    --dur-5: 0ms;
    --dur-6: 0ms;
    --dur-micro: 0ms;
    --dur-standard: 0ms;
    --dur-cinema: 0ms;
  }
}

[data-theme="dark"] {
  /* inverted monochrome — pure inverted black/white, no warmth */
  --paper: #0A0A0A;
  --paper-2: #161616;
  --ink: #FAFAFA;
  --ink-2: #D8D8D8;
  --muted: #9B9B9B;
  --faint: #6E6E6E;
  --rule: rgba(250,250,250,0.14);
  --rule-on-ink: rgba(10,10,10,0.16);
  --scrim: rgba(250,250,250,.6);
  --scrim-strong: rgba(250,250,250,.96);
  /* accent flips to white on dark (kept monochrome) */
  --rule-red: #FAFAFA;
  --rule-gradient: linear-gradient(0deg, #FAFAFA 0%, #FAFAFA 100%);
}

html, body { transition: background-color .45s ease, color .45s ease; }

html { background: var(--paper); }
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(14px, 0.95vw, 17px);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Editorial default: headlines are Fraunces serif (display weight, low
   leading, slightly negative tracking). Components that explicitly set their
   own font-family still win via the cascade; this only governs bare headings.
   Emphasis is the Fraunces ITALIC — never colour. */
h1, h2, h3 {
  font-family: var(--font-serif);
  font-weight: 680;
  line-height: 0.98;
  letter-spacing: -0.012em;
}

a { color: inherit; text-decoration: none; }
button { background: none; border: none; font: inherit; color: inherit; cursor: pointer; }
img { display: block; max-width: 100%; height: auto; }
em { font-style: normal; font-weight: 600; }

::selection { background: var(--ink); color: var(--paper); }

/* ============================================ LENIS smooth-scroll runtime
   Required by Lenis (these rules were never loaded). The html.lenis* classes
   are toggled by the library; data-lenis-prevent opts overlays out of smooth
   scroll so their internal scroll / scroll-lock never leaks into the page. */
html.lenis, html.lenis body { height: auto; }
html.lenis-smooth { scroll-behavior: auto !important; }
html.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
html.lenis-stopped { overflow: hidden; }

/* ============================================ CROSS-PAGE VIEW TRANSITIONS
   Cross-document fade between index/services/archive so navigation reads as
   one continuous move instead of a white flash. Progressive enhancement: a
   silent no-op in browsers without the API, and disabled under reduced motion.
   Only duration/timing are set — the UA default cross-fade keyframes stay. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: .45s;
    animation-timing-function: var(--ease-cinema);
  }
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}

/* PERSISTENT CHROME — name the elements that exist on every page so the UA
   morphs them in place across the cross-document cross-fade instead of
   fading the whole snapshot. Each name must be unique per page; these IDs
   appear once per document, so a stable name keeps the logo / nav rail /
   footer / cursor visually anchored through the navigation. Progressive
   enhancement: browsers without View Transitions simply ignore the property,
   and the @supports guard avoids defining it where it can't apply. */
@supports (view-transition-name: none) {
  #logo      { view-transition-name: e8-logo; }
  #edNavRail { view-transition-name: e8-navrail; }
  .ed-foot   { view-transition-name: e8-footer; }
  /* hold their own position/scale across the swap; the root keeps cross-fading */
  @media (prefers-reduced-motion: no-preference) {
    ::view-transition-group(e8-logo),
    ::view-transition-group(e8-navrail),
    ::view-transition-group(e8-footer) {
      animation-duration: .45s;
      animation-timing-function: var(--ease-cinema);
    }
  }
  @media (prefers-reduced-motion: reduce) {
    ::view-transition-group(e8-logo),
    ::view-transition-group(e8-navrail),
    ::view-transition-group(e8-footer) { animation: none; }
  }
}

/* ============================================ FOCUS-VISIBLE (keyboard a11y)
   One zero-specificity ring (:where) so any component focus style still wins.
   Outline (not box-shadow) so it never triggers layout or scroll shift. */
:where(a, button, [tabindex], input, select, textarea):focus-visible {
  outline: 2px solid var(--rule-red);
  outline-offset: 2px;
  border-radius: 1px;
}
:where(a, button, [tabindex]):focus:not(:focus-visible) { outline: none; }

/* ============================================ SKIP LINK (keyboard a11y)
   Off-screen until focused, then docks top-left. Matches the services/archive
   .srv2-skip pattern (which lives in services.css) but uses site tokens so it
   works on index.html, which doesn't load services.css. */
.e8-skip {
  position: absolute;
  left: -9999px;
  top: 1rem;
  z-index: 200;
  padding: .5rem .9rem;
  background: var(--ink);
  color: var(--paper);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: 0;
}
.e8-skip:focus { left: 1rem; }

/* ============================================ LOGO (top-left mark) */
/* RESTING state is the default and is always visible — its on-screen position
   does NOT depend on any animation. The tall 3-line EDITION8 mark is sized to
   sit cleanly ABOVE the nav-rail's bottom hairline (rail bottom ≈ 81px), so it
   never crosses the header rule. The drop-in is a pure enhancement (below). */
/* screen-reader-only utility (visually hidden, still announced) */
.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;
}

.logo {
  position: fixed; z-index: 95;
  top: auto; bottom: clamp(14px, 2vw, 26px);
  left: clamp(14px, 1.6vw, 24px);     /* far-left gutter — clears section content */
  width: 36px; height: auto;          /* +30% from 28; a corner mark, bottom-left */
  display: block;
  transform-origin: bottom left;
  transition: transform .35s var(--ease-cinema);
  pointer-events: auto;
}
.logo::before { content: none; }      /* no rail hairline to mask at the bottom-left */
/* adaptive contrast over ANY section: invert the black mark to white, then
   difference-blend so it reads dark-on-light and light-on-dark automatically.
   (Logos are exempt from the no-blend media rule.) Over the hero film we switch
   to a clean white invert instead — difference would tint against the colour. */
.logo img {
  width: 100%; height: auto; display: block;
  /* Theme-aware, deterministic logo colour (no mix-blend, which went grey
     over mid-tone backdrops). brightness(0) forces pure black; adding
     invert(1) forces pure white. Logos are exempt from the no-filter rule. */
  filter: brightness(0);
}
[data-theme="dark"] .logo img { filter: brightness(0) invert(1); }
/* Works & Services match the home page's logo scale — the global 36px corner
   mark reads too small on those pages (mobile keeps its own 56px size). */
body[data-page="works-v2"] .logo,
body[data-page="services-v2"] .logo { width: 42px !important; }   /* match home (mobile sets 56px !important otherwise) */

/* ENTER — drop-in intro as a PROGRESSIVE ENHANCEMENT only. Animates transform
   (not layout), starting off-screen and settling to the resting transform. With
   `both` fill it holds the rested pose; if motion is reduced or the tab is
   throttled, the rule simply doesn't apply and the logo shows at rest. */
@media (prefers-reduced-motion: no-preference) {
  .logo[data-state="enter"] {
    animation: logoDrop 1s cubic-bezier(.62,.05,.2,1) both;
    animation-delay: 0.12s;
  }
  @keyframes logoDrop {
    0%   { transform: translateX(-150px) rotate(-9deg); opacity: 0; }
    60%  { transform: translateX(0) rotate(2.5deg);     opacity: 1; }
    100% { transform: translateX(0) rotate(0deg);       opacity: 1; }
  }
}
.logo:hover { transform: rotate(-6deg) scale(1.1); }
.logo:active { transform: rotate(8deg) scale(.95); }
.logo.is-wobble { animation: wobble .6s ease; }
@keyframes wobble {
  0%, 100% { transform: rotate(0); }
  20% { transform: rotate(-12deg) scale(1.15); }
  45% { transform: rotate(10deg)  scale(1.05); }
  70% { transform: rotate(-6deg)  scale(1.08); }
  88% { transform: rotate(3deg)   scale(1.02); }
}

/* ============================================ HEADER */
.hd {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 22px var(--pad);
  font-family: 'Geist Mono', monospace; font-size: 12px; letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--paper);
  color: var(--ink);
  pointer-events: none;
  transition: background-color .45s ease, color .45s ease;
}
.hd > * { pointer-events: auto; }
.hd__brand { visibility: hidden; }
.hd__nav { display: flex; gap: 22px; justify-content: center; }
.hd__nav a {
  display: inline-flex;
  align-items: center;
}
/* CLIP/TRANSLATE MASK (TEXT only — never over media).
   The label is an overflow-hidden window; two stacked copies (regular + bold)
   slide together so the bold weight rises into place on hover instead of a
   flat opacity fade. Both copies carry the live text so the i18n text-node
   walker translates them in lockstep (no EN/TR desync). The bold copy governs
   width, so siblings never shift — same width-reserve guarantee as the old
   ::after ghost, which is now retired. */
.hd__nav-label {
  position: relative;
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  line-height: 1.25;
}
/* The BOLD copy stays in normal flow (opacity 0 until hover) so it governs the
   label's width AND height at the widest weight — siblings never shift, same
   guarantee the old ::after ghost gave. Crucially it holds the LIVE translated
   text node, so width stays correct in TR (no static attr() desync). The
   regular copy is overlaid absolutely on top for the rest state. */
.hd__nav-line {
  display: block;
  transition: transform var(--dur-2) var(--ease-cinema),
              opacity var(--dur-2) var(--ease-cinema);
}
.hd__nav-line:not(.hd__nav-line--bold) {
  position: absolute;
  inset: 0;
  opacity: .9;
}
.hd__nav-line--bold {
  position: relative;
  font-weight: 700;
  opacity: 0;
  transform: translateY(100%);
}
.hd__nav a:hover .hd__nav-line,
.hd__nav a:focus-visible .hd__nav-line {
  transform: translateY(-100%);
  opacity: 0;
}
.hd__nav a:hover .hd__nav-line--bold,
.hd__nav a:focus-visible .hd__nav-line--bold {
  transform: translateY(0);
  opacity: 1;
}
/* active page: hold the bold line up, regular line out (no hover needed) */
.hd__nav a.is-active .hd__nav-line { transform: translateY(-100%); opacity: 0; }
.hd__nav a.is-active .hd__nav-line--bold { transform: translateY(0); opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  /* No slide — instant cross-fade between the regular and bold copies. The
     bold copy STAYS the in-flow width/height reserver (kept from the motion
     path) so the weight change never shifts siblings; only opacity flips, no
     transform, no transition. */
  .hd__nav-line { transition: none; transform: none; }
  .hd__nav-line--bold { transform: none; }
  .hd__nav a:hover .hd__nav-line:not(.hd__nav-line--bold),
  .hd__nav a:focus-visible .hd__nav-line:not(.hd__nav-line--bold),
  .hd__nav a.is-active .hd__nav-line:not(.hd__nav-line--bold) { opacity: 0; }
  .hd__nav a:hover .hd__nav-line--bold,
  .hd__nav a:focus-visible .hd__nav-line--bold,
  .hd__nav a.is-active .hd__nav-line--bold { transform: none; opacity: 1; }
}
.hd__lang { display: flex; gap: 8px; justify-content: flex-end; align-items: center; }
.hd__lang span { opacity: .4; }
.hd__lang-btn { padding: 0; opacity: .5; }
.hd__lang-btn.is-active { opacity: 1; }

/* theme toggle — sun / moon */
.hd__right { display: flex; gap: 22px; justify-content: flex-end; align-items: center; }
.hd__theme {
  display: inline-flex; gap: 8px; align-items: center;
  background: none; border: 0; padding: 0; cursor: pointer;
  color: inherit;
}
/* tactile press for the theme toggle (transform-only, reduced-motion gated) */
@media (prefers-reduced-motion: no-preference) {
  .hd__theme { transition: transform var(--dur-1) var(--ease-spring); }
  .hd__theme:active { transform: scale(.92); }
}
.hd__theme-bit {
  width: 16px; height: 16px;
  display: inline-flex; align-items: center; justify-content: center;
  color: inherit;
  opacity: 1;
  transition: transform .35s var(--ease-cinema);
}
.hd__theme-bit svg { width: 100%; height: 100%; display: block; }
.hd__theme[data-mode="dark"] .hd__theme-bit--dark svg { transform: rotate(-18deg); }
.hd__theme-sep { opacity: .35; font-size: 11px; }
@media (max-width: 700px) {
  .hd__nav { display: none; }
}

/* ============================================ PROGRESS BAR */
.progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 60;
  background: var(--ink);
  transform: scaleX(0); transform-origin: left;
  pointer-events: none;
}

/* PROGRESSIVE scroll-driven enhancement — where the browser supports a
   scroll() timeline, drive the progress bar off the main thread with a CSS
   scroll-linked animation. The script.js scaleX path keeps running as the
   universal fallback; the animated value simply takes visual precedence where
   supported, so this is a no-op everywhere it isn't. Disabled under
   reduced-motion (the bar still reflects position via the JS fallback). */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    @keyframes e8-progress-scrub { from { transform: scaleX(0); } to { transform: scaleX(1); } }
    .progress {
      animation: e8-progress-scrub linear both;
      animation-timeline: scroll(root block);
    }
  }
}

/* ============================================ HERO */
.hero {
  position: relative; min-height: 100vh;
  padding: 120px var(--pad) 40px;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.hero__video {
  position: absolute; top: 0; right: 0; bottom: 0;
  width: 80%; height: 100%;
  z-index: 0; pointer-events: none;
}
.hero__video video {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.hero__overlay {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(to right, var(--paper) 0%, color-mix(in srgb, var(--paper) 55%, transparent) 22%, transparent 50%),
    color-mix(in srgb, var(--paper) 18%, transparent);
}
.hero > .hero__grid,
.hero > .hero__body,
.hero > .hero__bottom { position: relative; z-index: 3; }
.hero__photo {
  position: relative;
  align-self: end;
  aspect-ratio: 4/5;
  overflow: hidden;
  background: var(--paper-2);
}
.hero__photo img {
  width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.02);
  transition: transform 1s var(--ease-cinema);
}
.hero__photo:hover img { transform: scale(1.06); }

.hero__grid {
  display: flex; justify-content: space-between; gap: 24px;
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.05em; text-transform: uppercase;
  opacity: .82;
  margin-bottom: clamp(40px, 8vh, 80px);
  padding-left: 60px; /* leave room for sticky logo */
}
.hero__meta-l, .hero__meta-r {
  display: flex; flex-direction: column; gap: 4px;
}
.hero__meta-r { text-align: right; }
.hero__meta-num { font-weight: 600; }

.hero__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.55fr);
  gap: clamp(24px, 4vw, 60px);
  align-items: end;
  flex: 1;
}

.hero__title {
  font-family: 'Geist', sans-serif;
  font-weight: 700;
  font-size: clamp(28px, 5.5vw, 100px);
  line-height: 0.86;
  letter-spacing: -0.045em;
}
.hero__line { display: block; }
.hero__amp {
  font-style: italic; font-weight: 300;
  margin-left: 20px;
}
.hero em { font-style: italic; font-weight: 300; }
.hero__word { display: inline-block; }

.hero__photo img {
  width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.02);
  transition: transform 1s var(--ease-cinema);
}
.hero__photo:hover img { transform: scale(1.06); }
.hero__photo figcaption {
  position: absolute; left: 16px; bottom: 14px; right: 16px;
  display: flex; justify-content: space-between; gap: 10px;
  color: var(--paper);
  font-family: 'Geist Mono', monospace; font-size: 11px;
  letter-spacing: 0.06em; text-transform: uppercase;
  text-shadow: 0 1px 12px rgba(0,0,0,.45);
}

.hero__lede {
  margin-top: clamp(20px, 3vh, 36px);
  font-size: clamp(15px, 1.2vw, 20px);
  max-width: 36ch;
  opacity: .8;
}

.hero__bottom {
  display: flex; justify-content: space-between; align-items: flex-end;
  margin-top: clamp(40px, 6vh, 60px);
  font-family: 'Geist Mono', monospace; font-size: 12px;
  text-transform: uppercase; letter-spacing: 0.06em;
  opacity: .8;
}
.hero__caption { display: flex; align-items: center; gap: 14px; }

/* reveal helper
   Transition lives on the BASE rule (not only on .is-in) so the engine
   always has it before .is-in is added. When home.js sets an inline
   transform on a revealing card, having the transition pre-armed keeps the
   opacity/transform transitions from sticking "running" and stranding the
   element at opacity 0. will-change is toggled back to auto by a one-shot
   transitionend listener in motion.js so we don't leave layers promoted. */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--dur-5) var(--ease-cinema),
              transform var(--dur-5) var(--ease-cinema);
  will-change: opacity, transform;
}
.reveal.is-in { opacity: 1; transform: none; }
.reveal.is-in[data-d="0"] { transition-delay: 0.05s; }
.reveal.is-in[data-d="1"] { transition-delay: 0.18s; }
.reveal.is-in[data-d="2"] { transition-delay: 0.30s; }
.reveal.is-in[data-d="3"] { transition-delay: 0.42s; }
.reveal.is-in[data-d="4"] { transition-delay: 0.62s; }
.reveal.is-in[data-d="5"] { transition-delay: 0.74s; }
.reveal.is-in[data-d="6"] { transition-delay: 0.86s; }
.reveal.is-in[data-d="7"] { transition-delay: 0.98s; }

/* Index-driven stagger: a single --reveal-i integer on the element drives a
   calc() transition-delay so a flat group reads as one guided sequence.
   Additive — elements without --reveal-i fall back to 0 (no delay). The
   data-d delays above still win where both are present (later cascade). */
.reveal.is-in { transition-delay: calc(var(--reveal-i, 0) * 70ms); }

/* Line-mask CLIP reveal — for big headings only (text/UI, never media).
   Each heading line sits in an overflow:hidden clip (.reveal__line); a single
   inner span (.reveal__inner) holds the whole line and slides
   translateY(110%) → 0 so the type rises out of the mask as one unit (works
   whether the line is a bare text node, an <em>, or both). The wrapper itself
   does NOT fade (the clip does the work), so this layers cleanly with the base
   .reveal opacity on siblings. The italic <em> accent gets a small opacity
   delay so the serif "arrives" a beat after the sans — opacity only, so it
   never fights the single rising transform. */
.reveal--clip { opacity: 1; transform: none; will-change: auto; }
.reveal--clip .reveal__line {
  display: block;
  overflow: hidden;
  /* small vertical breathing room so descenders aren't clipped mid-rise */
  padding-bottom: 0.04em;
  margin-bottom: -0.04em;
}
.reveal--clip .reveal__inner {
  display: inline-block;
  transform: translateY(110%);
  transition: transform var(--dur-5) var(--ease-cinema);
  will-change: transform;
}
.reveal--clip.is-in .reveal__inner { transform: translateY(0); }
.reveal--clip .reveal__inner em {
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease-cinema) 0.18s;
}
.reveal--clip.is-in .reveal__inner em { opacity: 1; }
/* per-line stagger when multiple masked lines share one heading */
.reveal--clip.is-in .reveal__line:nth-child(2) .reveal__inner { transition-delay: 0.10s; }
.reveal--clip.is-in .reveal__line:nth-child(3) .reveal__inner { transition-delay: 0.20s; }
@media (prefers-reduced-motion: reduce) {
  /* clip reveal resolves instantly — no rise, no masked-out text/accent */
  .reveal--clip .reveal__inner { transform: none; transition: none; }
  .reveal--clip .reveal__inner em { opacity: 1; transition: none; }
}

/* PROGRESSIVE scroll-driven reveal — where view() timelines are supported,
   the cheapest reveals resolve off the main thread as they enter the viewport,
   so they no longer depend on the IntersectionObserver firing. Scoped to
   .reveal:not(.is-in) only: the instant the JS/IO path adds .is-in (the
   universal fallback), this selector stops matching and the static
   .reveal.is-in { opacity:1; transform:none } holds — the element ends visible
   either way, and this is a no-op where view() is unsupported. Excludes the
   clip headings (own mask animation) and the moving-column highlight. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    @keyframes e8-reveal-in {
      from { opacity: 0; transform: translateY(16px); }
      to   { opacity: 1; transform: none; }
    }
    /* Exclude reveals that define their own transform/opacity (editorial hero
       + section titles) so this generic rise never fights the hero-card
       parallax or the clip masks. */
    .reveal:not(.is-in):not(.reveal--clip):not(.ed-hero__card):not(.ed-hero__line):not(.ed-hero__caption):not(.ed-hero__since):not(.ed-section__title):not(.ed-manifesto__head) {
      animation: e8-reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 60%;
    }
  }
}

@media (max-width: 800px) {
  .hero__body { grid-template-columns: 1fr; }
  .hero__photo { max-width: 360px; }
  .hero__grid { padding-left: 0; }
}

/* ============================================ LOGO DROP — scroll-driven assembly */
.logodrop {
  --p: 0; --p1: 0; --p2: 0; --p3: 0;
  position: relative;
  height: 280vh;
  background: var(--paper);
  border-block: 1px solid var(--rule);
}
.logodrop__track {
  position: sticky; top: 0; height: 100vh;
  display: grid; place-items: center;
  overflow: hidden;
}
.logodrop__stage {
  position: relative;
  width: min(560px, calc((100vh - 64px) * 0.5625));
  height: min(996px, calc(100vh - 64px));
  aspect-ratio: 9 / 16;
  display: grid;
  background:
    radial-gradient(120% 80% at 50% 0%, color-mix(in oklab, var(--paper) 100%, var(--ink) 0%) 0%, color-mix(in oklab, var(--paper) 88%, var(--ink) 12%) 100%);
  border: 1px solid var(--rule);
  border-radius: 6px;
  overflow: hidden;
}
.logodrop__canvas {
  position: relative;
  display: grid; grid-template-rows: auto 1fr auto;
  height: 100%; width: 100%;
  padding: 28px 24px;
}
.logodrop__kicker {
  font-family: 'Geist Mono', monospace;
  font-size: 11px; letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink); opacity: 0.5;
  z-index: 5;
}
.logodrop__head {
  position: absolute;
  top: 70px; left: 0; right: 0;
  margin: 0;
  text-align: center;
  font-family: 'EB Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(22px, 3.2vh, 36px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  pointer-events: none;
  z-index: 5;
}
.logodrop__head-line {
  display: block;
  position: absolute; top: 0; left: 0; right: 0;
  transition: opacity .5s ease;
}
.logodrop__head-line[data-state="intro"] {
  opacity: clamp(0, calc(1.1 - var(--p) * 6), 1);
}
.logodrop__head-line[data-state="final"] {
  opacity: clamp(0, calc((var(--p) - 0.84) * 8), 1);
  font-style: italic;
}
.logodrop__field {
  position: relative;
  width: 100%; height: 100%;
}
.logodrop__ghost,
.logodrop__piece {
  position: absolute; left: 50%; top: 50%;
  height: 64%; width: auto; aspect-ratio: 980 / 2405;
}
.logodrop__ghost img,
.logodrop__piece img {
  display: block; height: 100%; width: 100%;
  user-select: none;
  filter: brightness(0) saturate(100%);
}
[data-theme="dark"] .logodrop__ghost img,
[data-theme="dark"] .logodrop__piece img {
  filter: brightness(0) saturate(100%) invert(1);
}
.logodrop__ghost {
  transform: translate(-50%, -50%);
  opacity: 0.05;
}
.logodrop__piece[data-piece="1"] img { clip-path: inset(0 0 53% 0); }
.logodrop__piece[data-piece="2"] img { clip-path: inset(47% 0 28% 0); }
.logodrop__piece[data-piece="3"] img { clip-path: inset(72% 0 0 0); }

.logodrop__piece {
  --pp: 0;
  transform: translate(-50%, calc(-50% + (1 - var(--pp)) * -120vh));
  filter: blur(calc((1 - var(--pp)) * 5px));
  opacity: calc(0.08 + var(--pp) * 0.92);
  will-change: transform, filter, opacity;
}
.logodrop__piece[data-piece="1"] { --pp: var(--p1); }
.logodrop__piece[data-piece="2"] { --pp: var(--p2); }
.logodrop__piece[data-piece="3"] { --pp: var(--p3); }

.logodrop__lines {
  position: absolute; inset: 14% 14%;
  display: flex; flex-direction: column; justify-content: space-between;
  pointer-events: none; z-index: 0;
  opacity: clamp(0, calc(0.8 - var(--p) * 1.4), 1);
}
.logodrop__lines span {
  display: block; height: 1px; background: var(--rule);
}
.logodrop__foot {
  position: absolute;
  bottom: 28px; left: 24px; right: 24px;
  display: flex; justify-content: space-between; align-items: end; gap: 16px;
  font-family: 'Geist Mono', monospace;
  font-size: 10px; letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink); opacity: 0.55;
  z-index: 5;
}
.logodrop__count em { font-style: normal; font-weight: 600; opacity: 1; }
.logodrop__hint { text-align: right; opacity: clamp(0, calc(1 - var(--p) * 4), 1); }

@media (max-width: 720px) {
  .logodrop { height: 340vh; }
  .logodrop__stage {
    width: 92vw; height: auto;
    border-radius: 0; border-inline: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .logodrop { height: 100vh; }
  .logodrop__piece {
    transform: translate(-50%, -50%);
    filter: none; opacity: 1;
  }
}

/* legacy (unused) ============================ MARQUEE */
.marquee {
  display: none;
  border-block: 1px solid var(--rule);
  padding: 22px 0;
  overflow: hidden;
  background: var(--paper);
}
.marquee--top { border-top: none; }
.marquee__track {
  display: flex; gap: 36px;
  white-space: nowrap;
  font-family: 'Geist', sans-serif;
  font-size: clamp(28px, 4vw, 64px);
  font-weight: 700; letter-spacing: -0.02em;
  text-transform: lowercase;
  animation: marquee 38s linear infinite;
  width: max-content;
}
.marquee__dot {
  font-size: 0.5em;
  align-self: center;
  opacity: .3;
}
@keyframes marquee {
  to { transform: translateX(-50%); }
}

/* ============================================ INDEX (services accordion → modal) */
.index {
  padding: clamp(80px, 14vh, 160px) var(--pad);
  border-bottom: 1px solid var(--rule);
}
.index__head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 32px; flex-wrap: wrap;
  margin-bottom: clamp(40px, 6vh, 80px);
}
.index__label {
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .6;
}
.index__heading {
  max-width: 36ch; font-size: clamp(16px, 1.4vw, 22px);
  font-weight: 400; line-height: 1.3;
  letter-spacing: -0.01em;
  text-align: right;
}
.index__list { list-style: none; }
.index__row {
  border-bottom: 1px solid var(--rule);
}
.index__list .index__row:last-child { border-bottom: 0; }
.index__head-btn {
  display: grid;
  grid-template-columns: 100px 1fr auto 40px;
  gap: 24px;
  align-items: baseline;
  padding: 26px 0 22px;
  width: 100%;
  text-align: left;
  cursor: pointer;
  transition: padding .5s var(--ease-cinema);
}
.index__row:hover .index__head-btn { padding-left: 24px; padding-right: 24px; }
.index__row:hover .index__arrow { transform: translateX(8px); }
.index__num {
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.04em; opacity: .6;
}
.index__name {
  font-size: clamp(48px, 8vw, 132px);
  font-weight: 700; letter-spacing: -0.045em; line-height: 0.92;
  text-transform: lowercase;
}
.index__name em { font-style: italic; font-weight: 300; }
.index__desc {
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.04em; opacity: .65;
  text-transform: uppercase;
  max-width: 38ch; text-align: right;
}
.index__arrow {
  font-family: 'Geist', sans-serif;
  font-size: 26px;
  transition: transform .5s var(--ease-cinema);
  display: inline-block;
}
.index__row.is-open .index__arrow { transform: rotate(45deg); }

.index__panel {
  display: grid; grid-template-columns: 1.2fr 1fr; gap: 28px 40px;
  padding: 0 0 0 124px;
  max-height: 0;
  opacity: 0;
  transform: translateY(-10px);
  overflow: hidden;
  transition: max-height .7s var(--ease-cinema),
              opacity .5s ease,
              transform .6s var(--ease-cinema),
              padding-bottom .6s ease;
}
.index__row.is-open .index__panel {
  max-height: 600px;
  opacity: 1;
  transform: translateY(0);
  padding-bottom: 32px;
}
.index__copy {
  font-size: clamp(16px, 1.3vw, 22px);
  line-height: 1.45; letter-spacing: -0.005em;
  max-width: 44ch;
  opacity: .85;
}
.index__chips {
  list-style: none;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 8px 16px;
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.04em; text-transform: uppercase;
  align-self: start;
}
.index__chips li { padding: 6px 0; border-top: 1px solid var(--rule); opacity: .85; }
.index__more {
  grid-column: 1 / -1;
  display: inline-flex; align-items: center; gap: 12px;
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 14px 0;
  border-top: 1px solid var(--rule);
  width: fit-content;
  transition: gap .3s ease;
}
.index__more:hover { gap: 22px; }

@media (max-width: 900px) {
  .index__head-btn { grid-template-columns: 60px 1fr 28px; }
  .index__desc { display: none; }
  .index__panel { grid-template-columns: 1fr; padding-left: 80px; }
}

/* ============================================ MODAL POPUP (service detail) */
.modal {
  position: fixed; inset: 0; z-index: 200;
  pointer-events: none;
}
.modal[aria-hidden="false"] { pointer-events: auto; }
.modal__scrim {
  position: absolute; inset: 0;
  background: var(--scrim);
  opacity: 0;
  transition: opacity .5s ease;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.modal[aria-hidden="false"] .modal__scrim { opacity: 1; }
.modal__sheet {
  position: absolute; left: 0; right: 0; top: 0;
  background: var(--paper);
  color: var(--ink);
  padding: clamp(60px, 10vh, 120px) var(--pad) clamp(40px, 6vh, 80px);
  transform: translateY(-105%);
  transition: transform .8s cubic-bezier(.7,0,.18,1);
  max-height: 92vh; overflow-y: auto;
  border-bottom: 1px solid var(--rule);
}
.modal[aria-hidden="false"] .modal__sheet { transform: translateY(0); }
.modal__close {
  position: absolute; top: 22px; right: var(--pad);
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 10px 18px; border: 1px solid var(--ink);
  border-radius: 999px;
}
.modal__close:hover { background: var(--ink); color: var(--paper); }

.modal__inner {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(30px, 5vw, 80px);
  max-width: var(--maxw); margin: 0 auto;
}
.modal__num {
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .6; margin-bottom: 14px; display: block;
}
.modal__title {
  font-size: clamp(56px, 10vw, 168px);
  font-weight: 700; letter-spacing: -0.05em; line-height: 0.86;
  margin-bottom: 28px;
  text-transform: lowercase;
}
.modal__title em { font-style: italic; font-weight: 300; }
.modal__copy {
  font-size: clamp(17px, 1.5vw, 22px);
  line-height: 1.45; letter-spacing: -0.01em;
  max-width: 42ch;
}
.modal__list {
  list-style: none;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 14px 28px;
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.04em; text-transform: uppercase;
  align-self: end;
}
.modal__list li {
  padding-bottom: 12px; border-bottom: 1px solid var(--rule);
  opacity: .8;
}
.modal__cta {
  grid-column: 1 / -1;
  display: inline-flex; align-self: start;
  align-items: center; gap: 18px;
  padding: 22px 36px;
  border: 1px solid var(--ink);
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.06em; text-transform: uppercase;
  border-radius: 999px;
  margin-top: 30px; width: fit-content;
  transition: background .35s, color .35s;
}
.modal__cta:hover { background: var(--ink); color: var(--paper); }
.modal__cta::after { content: "→"; font-size: 16px; }

@media (max-width: 800px) {
  .modal__inner { grid-template-columns: 1fr; }
  .modal__list { grid-template-columns: 1fr; }
}

/* slide-down stagger for modal content */
.modal[aria-hidden="false"] .modal__inner > * {
  opacity: 0; transform: translateY(-20px);
  animation: modalIn .7s var(--ease-cinema) forwards;
}
.modal[aria-hidden="false"] .modal__inner > *:nth-child(1) { animation-delay: .35s; }
.modal[aria-hidden="false"] .modal__inner > *:nth-child(2) { animation-delay: .45s; }
.modal[aria-hidden="false"] .modal__inner > *:nth-child(3) { animation-delay: .55s; }
.modal[aria-hidden="false"] .modal__inner > *:nth-child(4) { animation-delay: .65s; }
@keyframes modalIn {
  to { opacity: 1; transform: translateY(0); }
}

/* ============================================ WORKS */
.works {
  padding: clamp(80px, 14vh, 160px) var(--pad) clamp(60px, 10vh, 120px);
}
.works__head {
  display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 32px;
  margin-bottom: clamp(40px, 6vh, 80px);
  align-items: end;
}
.works__kicker {
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .6;
}
.works__title {
  font-size: clamp(56px, 9vw, 144px);
  font-weight: 700; letter-spacing: -0.045em; line-height: 0.88;
  text-transform: lowercase;
  white-space: nowrap;
}
.works__title em { font-style: italic; font-weight: 300; }
.works__lede {
  font-size: clamp(15px, 1.1vw, 18px);
  max-width: 28ch; opacity: .8;
}

.works__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2vw, 36px);
}
.work {
  cursor: pointer;
  display: flex; flex-direction: column;
  gap: 16px;
  opacity: 0; transform: translateY(40px);
  transition: opacity .9s var(--ease-cinema), transform .9s var(--ease-cinema);
}
.work.is-in { opacity: 1; transform: translateY(0); }

.work__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--paper-2);
}
.work__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.2s var(--ease-cinema), opacity .8s;
}
.work__media--alt {
  position: absolute; inset: 0;
  opacity: 0;
}
.work:hover .work__media img { transform: scale(1.04); }
.work:hover .work__media--alt { opacity: 1; }

.work__playmark {
  position: absolute; left: 22px; bottom: 22px;
  background: rgba(255,255,255,.92);
  color: #0A0A0A;
  padding: 8px 14px;
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  border-radius: 999px;
}

.work__meta {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 16px; flex-wrap: wrap;
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.04em; text-transform: uppercase;
  padding-top: 6px;
}
.work__num { opacity: .5; min-width: 40px; }
.work__client {
  flex: 1;
  font-family: 'Geist', sans-serif;
  font-size: clamp(16px, 1.4vw, 22px);
  font-weight: 600; letter-spacing: -0.02em;
  text-transform: none;
}
.work__type { opacity: .6; }

@media (max-width: 900px) {
  .works__grid { grid-template-columns: 1fr 1fr; }
  .works__head { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
  .works__grid { grid-template-columns: 1fr; }
}

.works__cta {
  display: flex; justify-content: center;
  margin-top: clamp(60px, 10vh, 120px);
}
/* Primary editorial CTA — BLACK fill + paper text (matches _directions .btn).
   The ::before sweep is now PAPER, so on hover the button inverts to a paper
   field with ink text + a hairline ink border showing through. Restrained
   2px radius instead of the old full pill. Monochrome throughout. */
.cta {
  display: inline-flex; align-items: center; gap: 18px;
  padding: 22px 36px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.06em; text-transform: uppercase;
  border-radius: 2px;
  position: relative; overflow: hidden;
  transition: color .4s ease;
}
.cta::before {
  content: ""; position: absolute; inset: 0;
  background: var(--paper);
  transform: translateY(101%);
  transition: transform .5s var(--ease-cinema);
  z-index: -1;
}
.cta:hover { color: var(--ink); }
.cta:hover::before { transform: translateY(0); }
/* tactile press: a quick scale dip on active. transform-only; reduced-motion
   users get no scale (the rule is gated below). */
@media (prefers-reduced-motion: no-preference) {
  .cta { transition: color .4s ease, transform var(--dur-1) var(--ease-spring); }
  .cta:active { transform: scale(.97); }
}

/* ============================================ NUMBERS */
.numbers {
  background: var(--paper); color: var(--ink);
  padding: clamp(80px, 14vh, 160px) var(--pad);
}
.numbers__head { margin-bottom: clamp(40px, 6vh, 80px); }
.numbers__kicker {
  display: block;
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .5;
  margin-bottom: 20px;
}
.numbers__title {
  font-size: clamp(48px, 7vw, 108px);
  font-weight: 700; letter-spacing: -0.045em; line-height: 0.92;
  text-transform: lowercase;
}
.numbers__title em { font-style: italic; font-weight: 300; }
.numbers__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 3vw, 56px);
}
.num {
  display: flex; flex-direction: column; gap: 22px;
  padding-top: 28px;
  border-top: 1px solid var(--rule-on-ink);
}
.num__client {
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.04em; text-transform: uppercase;
  opacity: .7;
}
.num__row {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
}
.num__row > div { display: flex; flex-direction: column; gap: 4px; }
.num__big {
  font-size: clamp(28px, 3.8vw, 60px);
  font-weight: 700; letter-spacing: -0.04em; line-height: 1;
}
.num__lbl {
  font-family: 'Geist Mono', monospace; font-size: 11px;
  letter-spacing: 0.04em; text-transform: uppercase;
  opacity: .55;
}
.num__period {
  font-family: 'Geist Mono', monospace; font-size: 11px;
  letter-spacing: 0.04em; text-transform: uppercase;
  opacity: .45;
  margin-top: auto;
}
@media (max-width: 900px) {
  .numbers__grid { grid-template-columns: 1fr; }
}

/* ============================================ ARCHIVE — uniform 4-col, warp on scroll */
.archive {
  padding: clamp(80px, 14vh, 160px) var(--pad);
  border-bottom: 1px solid var(--rule);
}
.archive__head { margin-bottom: clamp(40px, 6vh, 80px); }
.archive__kicker {
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .6;
}
.archive__title {
  font-size: clamp(48px, 8vw, 124px);
  font-weight: 700; letter-spacing: -0.045em; line-height: 0.92;
  margin-top: 14px;
  text-transform: lowercase;
}
.archive__title em { font-style: italic; font-weight: 300; }
.archive__lede {
  margin-top: 18px; max-width: 42ch; opacity: .75;
  font-size: clamp(15px, 1.1vw, 18px);
}
.archive__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  perspective: 1400px;
}
.ax {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--paper-2);
  cursor: pointer;
  transform-style: preserve-3d;
  transition: transform .25s ease;
  /* warp variables driven by JS */
  --warp-y: 0px;
  --warp-rot: 0deg;
  --warp-skew: 0deg;
  transform: translate3d(0, var(--warp-y), 0) rotate(var(--warp-rot)) skewY(var(--warp-skew));
}
.ax img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1s var(--ease-cinema);
}
.ax:hover img { transform: scale(1.05); }
.ax figcaption {
  position: absolute; left: 12px; bottom: 12px; right: 12px;
  font-family: 'Geist Mono', monospace; font-size: 11px;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--paper);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .4s, transform .4s;
  text-shadow: 0 1px 12px rgba(0,0,0,.4);
}
.ax:hover figcaption { opacity: 1; transform: translateY(0); }

@media (max-width: 1100px) { .archive__grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 700px) { .archive__grid { grid-template-columns: repeat(2, 1fr); } }

/* ============================================ WORKFLOW */
.flow {
  padding: clamp(80px, 14vh, 160px) var(--pad);
  border-bottom: 1px solid var(--rule);
}
.flow__head {
  display: grid; grid-template-columns: 1fr 1fr; gap: 32px;
  align-items: end;
  margin-bottom: clamp(40px, 6vh, 80px);
}
.flow__kicker {
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .6;
}
.flow__title {
  font-size: clamp(48px, 8vw, 132px);
  font-weight: 700; letter-spacing: -0.045em; line-height: 0.88;
  text-transform: lowercase;
}
.flow__title em { font-style: italic; font-weight: 300; }
.flow__steps {
  list-style: none;
  display: grid; gap: 0;
}
.flow__step {
  display: grid;
  grid-template-columns: 140px 1fr 2fr;
  gap: clamp(20px, 3vw, 60px);
  padding: 36px 0;
  border-top: 1px solid var(--rule);
  align-items: start;
  position: relative;
}
.flow__step::before {
  content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 2px;
  background: var(--ink);
  transform: scaleX(0); transform-origin: left;
  transition: transform 1.2s cubic-bezier(.7,0,.2,1);
}
.flow__step.is-in::before { transform: scaleX(1); }
.flow__no {
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.04em; text-transform: uppercase;
  opacity: .55;
}
.flow__step h4 {
  font-size: clamp(22px, 2.3vw, 38px);
  font-weight: 600; letter-spacing: -0.025em; line-height: 1.1;
  text-transform: lowercase;
}
.flow__step p {
  font-size: clamp(15px, 1.1vw, 18px);
  line-height: 1.5; max-width: 56ch;
  opacity: .8;
}
@media (max-width: 800px) {
  .flow__head { grid-template-columns: 1fr; }
  .flow__step { grid-template-columns: 1fr; }
}

/* ============================================ TEAM */
.team {
  padding: clamp(80px, 14vh, 160px) var(--pad);
  border-bottom: 1px solid var(--rule);
}
.team__head { margin-bottom: clamp(40px, 6vh, 80px); }
.team__kicker {
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .6;
}
.team__title {
  font-size: clamp(48px, 8vw, 132px);
  font-weight: 700; letter-spacing: -0.045em; line-height: 0.88;
  margin-top: 14px;
  text-transform: lowercase;
}
.team__title em { font-style: italic; font-weight: 300; }
.team__foot {
  margin-top: 20px; opacity: .65; max-width: 48ch;
  font-size: clamp(14px, 1vw, 16px);
}
.team__grid {
  display: grid; grid-template-columns: repeat(5, 1fr);
  gap: clamp(16px, 2vw, 36px);
  margin-top: 30px;
}
.member {
  display: flex; flex-direction: column; gap: 10px;
  padding-top: 22px; border-top: 1px solid var(--rule);
}
.member__role {
  font-family: 'Geist Mono', monospace; font-size: 11px;
  letter-spacing: 0.04em; text-transform: uppercase;
  opacity: .65;
}
.member__name {
  font-size: clamp(20px, 1.8vw, 30px);
  font-weight: 600; letter-spacing: -0.02em;
}
.member__yrs {
  font-family: 'Geist Mono', monospace; font-size: 12px;
  opacity: .55;
  margin-top: auto;
}
@media (max-width: 1000px) { .team__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .team__grid { grid-template-columns: 1fr; } }

/* ============================================ CONTACT / FOOTER */
.contact {
  background: var(--ink); color: var(--paper);
  padding: clamp(80px, 14vh, 160px) var(--pad) 0;
}
.contact__big { margin-bottom: clamp(60px, 10vh, 120px); }
.contact__kicker {
  display: block;
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .55; margin-bottom: 18px;
}
.contact__title {
  font-size: clamp(72px, 14vw, 264px);
  font-weight: 700; letter-spacing: -0.05em; line-height: 0.86;
  text-transform: lowercase;
}
.contact__title em { font-style: italic; font-weight: 300; }
.contact__title em a { color: inherit; }
.contact__mark {
  display: block;
  width: clamp(140px, 18vw, 300px);
  max-width: 300px;
  margin: 8px auto 28px;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
  will-change: transform;
  transform: translate3d(0,0,0) rotate(0deg);
  transition: transform .35s cubic-bezier(.6,.05,.2,1);
}
.contact__mark.is-dragging {
  cursor: grabbing;
  transition: none;
}
.contact__mark img {
  width: 100%; height: auto; display: block;
  filter: invert(1);
  pointer-events: none;
}
[data-theme="dark"] .contact__mark img { filter: none; }
.contact__mark__hint {
  position: absolute; left: 0; bottom: -28px;
  font-family: 'Geist Mono', monospace;
  font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase;
  opacity: .35;
  pointer-events: none;
}
.contact__sub {
  display: inline-block;
  font-size: clamp(28px, 4vw, 56px);
  font-weight: 500; letter-spacing: -0.02em;
  text-transform: lowercase;
  opacity: .85;
}
.contact__sub em { font-style: italic; font-weight: 300; }

.contact__cols {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 32px;
  padding-bottom: 80px;
  border-bottom: 1px solid var(--rule-on-ink);
}
.contact__col {
  display: flex; flex-direction: column; gap: 10px;
  padding-top: 22px; border-top: 1px solid var(--rule-on-ink);
}
.contact__label {
  font-family: 'Geist Mono', monospace; font-size: 11px;
  letter-spacing: 0.04em; text-transform: uppercase;
  opacity: .55;
}
.contact__line {
  font-size: clamp(16px, 1.2vw, 22px);
  line-height: 1.4;
}
@media (max-width: 800px) { .contact__cols { grid-template-columns: 1fr 1fr; } }

.ft {
  display: flex; justify-content: space-between; align-items: center;
  padding: 30px 0;
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .7;
}
.ft__left { display: flex; gap: 14px; flex-wrap: wrap; }
.ft__right { display: flex; gap: 14px; align-items: center; }
.ft__line { display: inline-block; width: 60px; height: 1px; background: var(--paper); opacity: .4; }

/* ============================================ LIGHTBOX */
.lb {
  position: fixed; inset: 0; z-index: 200;
  background: var(--scrim-strong);
  display: none;
  align-items: center; justify-content: center;
}
.lb.is-on { display: flex; }
.lb__close {
  position: absolute; top: 20px; right: 24px;
  color: var(--paper); font-size: 36px; line-height: 1;
}
.lb__counter {
  position: absolute; top: 24px; left: 24px;
  color: var(--paper);
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .8;
}
.lb__nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 56px; height: 56px;
  color: var(--paper); font-size: 22px;
  border: 1px solid var(--rule-on-ink);
  border-radius: 50%;
}
.lb__nav--prev { left: 24px; }
.lb__nav--next { right: 24px; }
.lb__stage {
  max-width: min(82vw, 1300px);
  max-height: 78vh;
  display: flex; align-items: center; justify-content: center;
}
.lb__stage img {
  max-width: 100%; max-height: 78vh;
  object-fit: contain;
}
.lb__caption {
  position: absolute; bottom: 24px; left: 0; right: 0;
  text-align: center; color: var(--paper);
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: .8;
}

/* ============================================ CHRONOLOGY PAGE specifics */
.chrono {
  padding: 140px var(--pad) 80px;
  min-height: 100vh;
}
.chrono__head { margin-bottom: 60px; }
.chrono__title {
  font-size: clamp(56px, 9vw, 144px);
  font-weight: 700; letter-spacing: -0.045em; line-height: 0.88;
  text-transform: lowercase;
}
.chrono__title em { font-style: italic; font-weight: 300; }
.chrono__list { list-style: none; }
.chrono__item {
  display: grid;
  grid-template-columns: 90px 1fr 2fr 100px;
  gap: clamp(16px, 3vw, 60px);
  align-items: center;
  padding: 22px 0;
  border-bottom: 1px solid var(--rule);
  cursor: pointer;
  transition: padding .4s var(--ease-cinema);
}
.chrono__item:hover { padding-left: 18px; padding-right: 18px; }
.chrono__year {
  font-family: 'Geist Mono', monospace; font-size: 13px;
  letter-spacing: 0.04em; opacity: .6;
}
.chrono__name {
  font-size: clamp(22px, 2.4vw, 38px);
  font-weight: 600; letter-spacing: -0.025em;
}
.chrono__type {
  font-family: 'Geist Mono', monospace; font-size: 12px;
  letter-spacing: 0.04em; text-transform: uppercase;
  opacity: .6;
}
.chrono__cover {
  width: 100px; aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--paper-2);
}
.chrono__cover img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 800px) {
  .chrono__item { grid-template-columns: 60px 1fr 80px; }
  .chrono__type { display: none; }
}
