/* ════════════════════════════════════════════════════════════════
   Dalel Bacre — high-fashion portfolio
   Reserve direction, elevated. Cormorant Garamond italic display
   + Archivo sans + JetBrains Mono meta. Warm cream + ink.
   ════════════════════════════════════════════════════════════════ */

:root{
  /* palette */
  --cream:        #faf7f1;
  --cream-warm:   #f3ede1;
  --cream-deep:   #ece5d3;
  --ink:          #1a1612;
  --ink-soft:     rgba(26, 22, 18, .72);
  --ink-mute:     rgba(26, 22, 18, .65);   /* was .50 — bumped for WCAG AA on small text */
  --ink-faint:    rgba(26, 22, 18, .22);
  --ink-line:     rgba(26, 22, 18, .14);
  --accent:       #a8553a;
  --accent-warm:  #c97a4f;
  --accent-deep:  #6f3522;
  --paper:        #f6f1e6;

  /* type */
  --serif:        "Cormorant Garamond", "Times New Roman", serif;
  --sans:         "Archivo", ui-sans-serif, system-ui, sans-serif;
  --mono:         "JetBrains Mono", ui-monospace, monospace;

  /* motion */
  --ease-out:     cubic-bezier(.2, .7, .2, 1);
  --ease-in-out:  cubic-bezier(.6, .04, .3, .96);
  --ease-expo:    cubic-bezier(.86, 0, .07, 1);

  /* layout */
  --gutter:       clamp(24px, 4vw, 56px);
  --gutter-wide:  clamp(40px, 8vw, 120px);
  --maxw:         1640px;
}

/* ── Reset + base ──────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { scroll-behavior: auto; }      /* Lenis owns scroll */
body {
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(14px, .9vw + 6px, 16px);
  font-weight: 400;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  /* Body bg smoothly crossfades when the active route changes — keeps
     the brief stage-opacity dip from flashing cream during dark↔light
     route changes (see body[data-route="work"] below). */
  transition: background-color .45s var(--ease-out);
}
body[data-route="work"] { background: #18130f; }
body[data-route="home"] { background: #0a0807; }   /* hero video bg matches */
img, svg, iframe { display: block; max-width: 100%; }
button { appearance: none; background: transparent; border: 0; color: inherit; cursor: pointer; padding: 0; font: inherit; }
a { color: inherit; text-decoration: none; cursor: pointer; }
ol, ul, dl { margin: 0; padding: 0; list-style: none; }
::selection { background: var(--ink); color: var(--cream); }

/* hide custom cursor target on coarse pointers (touch) */
@media (pointer: coarse) {
  .cursor { display: none !important; }
  body { cursor: auto !important; }
}
@media (pointer: fine) {
  body, a, button, [data-route], [data-cursor] { cursor: none; }
}

/* ── Focus-visible (A-M1) ─────────────────────────────────────────
   The custom cursor sets cursor:none site-wide on fine pointers,
   which deprives keyboard users of any visible focus signal — browser
   defaults are otherwise styled away by .nav-links etc. This restores
   a high-contrast focus ring on every keyboard-focused element,
   regardless of widget-specific overrides further down. */
*:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}
.nav.is-dark *:focus-visible,
body[data-route="work"] *:focus-visible,
body[data-route="home"] *:focus-visible {
  outline-color: var(--paper);
}

/* A-H1: skip-link — WCAG 2.4.1 Bypass Blocks. Off-screen until focused,
   then docks to the top-left corner. Sits above every overlay (loader,
   wipe, lightbox scrim) so it's always reachable from the address bar. */
.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink); color: var(--cream);
  padding: 12px 18px; z-index: 9999;
  font-family: var(--sans, sans-serif); text-decoration: none;
  border-radius: 0 0 4px 0;
}
.skip-link:focus { left: 0; }

/* ── Type primitives ──────────────────────────────────────────── */
em, i, .it { font-style: italic; font-weight: 300; font-family: var(--serif); }

.kicker {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink-mute);
  font-weight: 500;
}
.kicker.light { color: rgba(246, 241, 230, .72); }
.micro {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.micro.light { color: rgba(246, 241, 230, .72); }
.mono { font-family: var(--mono); font-size: 11.5px; letter-spacing: .04em; color: var(--ink-soft); }

/* ════════════════════════════════════════════════════════════════
   LOADER
   ════════════════════════════════════════════════════════════════ */
.loader {
  position: fixed; inset: 0; z-index: 1000;
  background: var(--cream);
  display: grid;
  grid-template-rows: 1fr auto;
  transition: opacity .8s var(--ease-out), transform 1.2s var(--ease-expo);
}
body.loader-out .loader {
  transform: translateY(-100%);
}
body:not(.is-loading) .loader { pointer-events: none; }

.loader-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto 1fr auto;
  padding: clamp(20px, 2.5vw, 36px);
  gap: 16px;
  align-items: start;
}
.loader-meta {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.loader-meta-tl { grid-column: 1; grid-row: 1; text-align: left; }
.loader-meta-tr { grid-column: 2; grid-row: 1; text-align: right; }
.loader-meta-bl { grid-column: 1; grid-row: 3; text-align: left; }
.loader-meta-br { grid-column: 2; grid-row: 3; text-align: right; }

.loader-mark {
  grid-column: 1 / -1;
  grid-row: 2;
  align-self: center;
  justify-self: center;
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Solid disc — minimal mark in the center of the loader. Quietly pulses
   while loading so it doesn't read as a static placeholder. */
.loader-mark-svg {
  width: clamp(120px, 14vw, 180px);
  height: auto;
  opacity: 0;
  animation: loaderMarkFadeIn .8s var(--ease-out) .1s forwards,
             loaderMarkPulse 2.8s var(--ease-in-out) .9s infinite;
}
@keyframes loaderMarkFadeIn {
  from { opacity: 0; transform: scale(.92); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes loaderMarkPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .78; transform: scale(.97); }
}

.loader-bar {
  height: 1px;
  background: var(--ink-line);
  position: relative;
}
.loader-bar-fill {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--ink);
  transition: width .1s linear;
}
.loader-count {
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  color: var(--ink);
}

/* ════════════════════════════════════════════════════════════════
   WIPE (deprecated — keep node hidden, transitions handled on .stage)
   ════════════════════════════════════════════════════════════════ */
.wipe { display: none; }

/* Stage-level crossfade for route changes */
.stage { transition: opacity .18s ease; }
.stage.is-leaving { opacity: 0; }

/* ════════════════════════════════════════════════════════════════
   CUSTOM CURSOR
   ════════════════════════════════════════════════════════════════ */
.cursor {
  position: fixed;
  top: 0; left: 0;
  width: 0; height: 0;
  pointer-events: none;
  z-index: 2147483647; /* above all overlays (lightbox z-9999, dialogs) so the custom cursor stays visible */
  mix-blend-mode: difference;
  transform: translate3d(-100px, -100px, 0);
  will-change: transform;
}
.cursor-dot {
  position: absolute;
  top: 50%; left: 50%;
  width: 6px; height: 6px;
  margin: -3px 0 0 -3px;
  background: var(--cream);
  border-radius: 50%;
  transition: transform .25s var(--ease-out), opacity .25s var(--ease-out);
}
.cursor-ring {
  position: absolute;
  top: 50%; left: 50%;
  width: 38px; height: 38px;
  margin: -19px 0 0 -19px;
  border: 1px solid var(--cream);
  border-radius: 50%;
  opacity: .6;
  transition: width .35s var(--ease-out), height .35s var(--ease-out),
              margin .35s var(--ease-out), opacity .35s var(--ease-out),
              border-color .25s ease;
}
body.cursor-hover .cursor-ring {
  width: 56px; height: 56px;
  margin: -28px 0 0 -28px;
  opacity: 1;
}
body.cursor-hover .cursor-dot { transform: scale(.4); }
body.cursor-press .cursor-ring { transform: scale(.82); }

/* Photo lightbox has a near-black backdrop where the difference-blended cursor can
   read the same tone as the bg (invisible). Drop the blend and force a solid light
   cursor while the lightbox is open so it stays clearly visible. */
body.lb-open .cursor { mix-blend-mode: normal; }
body.lb-open .cursor-dot { background: #faf7f1; }
body.lb-open .cursor-ring { border-color: rgba(250, 247, 241, .7); opacity: .75; }

/* ════════════════════════════════════════════════════════════════
   NAV
   ════════════════════════════════════════════════════════════════ */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 80;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  padding: 18px var(--gutter);
  background: rgba(250, 247, 241, .68);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  border-bottom: 1px solid transparent;
  transition: background .4s ease, border-color .4s ease, padding .4s var(--ease-out), color .4s ease;
}
.nav.is-scrolled {
  background: rgba(250, 247, 241, .88);
  border-bottom-color: var(--ink-line);
  padding-top: 12px; padding-bottom: 12px;
}
.nav.is-dark {
  background: rgba(10, 8, 7, .28);
  color: var(--paper);
  border-bottom-color: rgba(246, 241, 230, .12);
}
.nav.is-dark .kicker,
.nav.is-dark .micro { color: rgba(246, 241, 230, .72); }

.nav-brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-family: var(--serif);
  font-size: 22px;
  line-height: 1;
  white-space: nowrap;
  transition: opacity .3s ease;
}
.nav-brand:hover { opacity: .76; }
.brand-mark { display: inline-flex; align-items: center; justify-content: center; }
.brand-word em { font-weight: 400; }
.brand-word { letter-spacing: -.01em; }

.nav-links {
  justify-self: center;
  display: flex;
  gap: clamp(20px, 2.4vw, 36px);
  align-items: center;
}
.nav-links a {
  position: relative;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: inherit;
  opacity: .68;
  padding: 8px 2px;
  transition: opacity .25s ease;
}
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .45s var(--ease-out);
}
.nav-links a:hover { opacity: 1; }
.nav-links a:hover::after { transform: scaleX(1); }
.nav-links a.on { opacity: 1; }
.nav-links a.on::after { transform: scaleX(1); }

.nav-meta {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 18px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.nav.is-dark .nav-meta { color: rgba(246, 241, 230, .72); }
.nav-clock { font-variant-numeric: tabular-nums; }
@media (max-width: 900px) {
  .nav { grid-template-columns: auto 1fr auto; }
  .nav-meta { gap: 10px; }
  .nav-links { justify-self: end; gap: 14px; }
  .nav-links a { font-size: 10px; letter-spacing: .18em; padding: 8px 0; }
  .nav-client { padding: 5px 10px; font-size: 9.5px; }
}

/* ─── Mobile hamburger: collapse the inline nav and show a toggle ─── */
/* On screens where the inline links + client button would crowd or
   overflow (< 720px), hide them and show the hamburger. The overlay
   menu (.mobile-menu) handles navigation in their place. */
.nav-toggle { display: none; }
/* MOBILE-FIX (audit #27): 800px, aligned with the layout breakpoint. At the old
   720px, a 721-800px touch device got every PHONE layout (single-column stages,
   stacked panels) while keeping the DESKTOP nav — 10px letter-spaced links as
   the only navigation. One breakpoint, one nav paradigm. app.js's drawer
   close-on-grow matchMedia moves in lockstep (801px). */
@media (max-width: 800px) {
  .nav {
    grid-template-columns: 1fr auto; gap: 12px;
    /* safe-area (audit #42): with viewport-fit=cover the fixed nav slides under
       the notch in landscape without these. */
    padding: 14px max(18px, env(safe-area-inset-right)) 14px max(18px, env(safe-area-inset-left));
  }
  .nav-links,
  .nav-meta { display: none; }
  .nav-toggle {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-end;
    gap: 5px;
    width: 32px; height: 32px;
    padding: 0;
    background: transparent;
    border: 0;
    cursor: pointer;
    color: inherit;
    z-index: 100;
  }
  .nav-toggle-bar {
    display: block;
    width: 22px; height: 1.5px;
    background: currentColor;
    transition: transform .35s var(--ease-out), opacity .25s ease, width .25s ease;
  }
  .nav-toggle-bar:nth-child(2) { width: 14px; }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) {
    transform: translateY(3.5px) rotate(45deg);
  }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) {
    transform: translateY(-3px) rotate(-45deg);
    width: 22px;
  }
  .nav-brand .brand-word { font-size: 18px; }
}
@media (max-width: 420px) {
  /* hide brand word, keep monogram — works like a fashion mast */
  .nav-brand .brand-word { display: none; }
}

/* ─── Mobile menu overlay (slides in from right) ─── */
/* Fully opaque so the underlying route content can't bleed through.
   backdrop-filter alone produces a translucent blur which is unreliable
   across mobile browsers and even when supported leaves the underlying
   text faintly visible. Solid color is the safe default. */
.mobile-menu {
  position: fixed;
  inset: 0;
  background: #faf7f1;
  z-index: 200;            /* above the nav (80) and any route content */
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: clamp(96px, 14vh, 130px) clamp(28px, 6vw, 60px) clamp(40px, 6vh, 80px);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-8px);
  transition: opacity .35s var(--ease-out), transform .45s var(--ease-out);
  color: var(--ink);
}
.mobile-menu.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
body.mobile-menu-open { overflow: hidden; }

/* Dark route variants — solid dark to match Personal Work palette and
   the dark home hero. */
body[data-route="work"] .mobile-menu,
body[data-route="home"] .mobile-menu {
  background: #18130f;
  color: var(--cream);
}

.mobile-menu-links {
  display: flex;
  flex-direction: column;
  gap: clamp(18px, 3.6vh, 32px);
}
.mobile-menu-links a {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(36px, 8vw, 56px);
  line-height: 1;
  letter-spacing: -.014em;
  color: inherit;
  position: relative;
}
.mobile-menu-links a.on { color: var(--accent); }
.mobile-menu-links a:active { opacity: .6; }

.mobile-menu-meta {
  display: flex;
  flex-direction: column;
  gap: 16px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  border-top: 1px solid currentColor;
  padding-top: clamp(20px, 3vh, 28px);
  opacity: .72;
}
/* Nav social icons (Dalel 2026-08-18): IG + X replaced the email that used to
   repeat here — it already lives on the Contact page. Sized to sit on the
   nav's mono baseline; inherit color so the dark-nav variant just works. */
.nav-social {
  display: flex;
  align-items: center;
  gap: 14px;
}
.nav-social a {
  color: inherit;
  display: inline-flex;
  padding: 4px;             /* widen the hit target past the glyph */
  opacity: .78;
  transition: opacity .18s ease;
}
.nav-social a:hover,
.nav-social a:focus-visible { opacity: 1; }
.nav-social svg { width: 16px; height: 16px; display: block; }
/* Handle text beside each icon (Dalel 2026-08-19). Same mono voice as the rest
   of nav-meta; the <em> is the setSocialLink() hook, so keep it unstyled-italic
   off — it is a data slot, not emphasis. */
.nav-social a { gap: 7px; align-items: center; }
.nav-social .social-handle { white-space: nowrap; }
.nav-social .social-handle em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .06em;
}
.nav-social-mobile { gap: 22px; }
.nav-social-mobile svg { width: 21px; height: 21px; }
.nav-social-mobile .social-handle em { font-size: 12px; }
/* The nav tightens below 900px (gap 10px) — icons alone breathe better there;
   the mobile-menu overlay still shows icon + handle. */
@media (max-width: 900px) {
  .nav .nav-social .social-handle { display: none; }
}
.mobile-menu-actions {
  display: flex;
  gap: 20px;
  align-items: center;
}
.mobile-menu-actions a { color: inherit; padding: 8px 0; }
.mobile-menu-admin { opacity: .55; }
.mobile-menu-admin:active { opacity: 1; }

/* Hide the mobile menu entirely above the hamburger breakpoint */
@media (min-width: 801px) { .mobile-menu { display: none !important; } }

/* ════════════════════════════════════════════════════════════════
   STAGE / ROUTES
   ════════════════════════════════════════════════════════════════ */
.stage { position: relative; }
.route { display: none; }
.route.is-active { display: block; animation: routeIn .35s var(--ease-out); }
@keyframes routeIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* foot — shared across routes */
.foot {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  padding: 22px var(--gutter);
  border-top: 1px solid var(--ink-line);
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.foot .foot-mid { text-align: center; }
.foot > :last-child { text-align: right; }
.foot em { color: var(--ink); }

/* ════════════════════════════════════════════════════════════════
   HOME / HERO
   ════════════════════════════════════════════════════════════════ */
.hero {
  position: relative;
  /* svh (audit hero finding): 100vh is iOS Safari's LARGE viewport, so the
     bottom meta row + scroll cue sat behind the toolbar until first scroll.
     Small-viewport height guarantees the whole hero fits the initial screen. */
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto 1fr auto;
  align-items: start;
  padding: clamp(96px, 12vh, 140px) var(--gutter) clamp(40px, 6vh, 72px);
  overflow: hidden;
  background: var(--cream);
}

/* ── Cinema variant — dark, full-bleed video, light type ── */
.hero-cinema {
  background: #0a0807;
  color: var(--paper);
}
.hero-cinema .hero-bg { display: none; }
.hero-video {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 100vw;
  height: 100vh;
  object-fit: cover;
  border: 0;
  pointer-events: none;
  z-index: 0;
}
.hero-cinema .hero-grain { z-index: 2; }
.hero-cinema .hero-vignette {
  z-index: 2;
  background: radial-gradient(120% 80% at 50% 50%, transparent 35%, rgba(0,0,0,.55) 100%);
}
.hero-cinema .hero-title  { color: var(--paper); }
.hero-cinema .hero-locations { color: rgba(246,241,230,.78); }
.hero-cinema .hero-locations i { color: var(--accent-warm); }
.hero-cinema .hero-meta {
  color: rgba(246,241,230,.78);
  position: relative; z-index: 3;
}
.hero-cinema .hero-meta .kicker,
.hero-cinema .hero-meta .micro { color: rgba(246,241,230,.72); }
.hero-cinema .hero-cycler .kicker { color: rgba(246,241,230,.78); }
.hero-cinema .cycler { color: var(--paper); }
.hero-cinema .hero-stage { z-index: 3; }
.hero-cinema .hero-scroll-hint { color: rgba(246,241,230,.7); z-index: 3; }
.hero-cinema .hero-scroll-hint .hint-line {
  background: linear-gradient(180deg, rgba(246,241,230,.7) 0%, rgba(246,241,230,0) 100%);
}
.hero-cinema .ghost-link {
  color: var(--paper);
  border-color: rgba(246,241,230,.35);
}
.hero-cinema .ghost-link:hover { border-color: var(--paper); }

/* Now-playing caption (replaces "Watch the reel" since reel IS home) */
.hero-now-playing {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: rgba(246,241,230,.78);
}
.hero-now-line {
  display: inline-flex;
  flex-direction: column;
  gap: 4px;
  line-height: 1.3;
}
.hero-now-title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(13px, 1.1vw, 16px);
  letter-spacing: -.005em;
  color: var(--paper);
}
.hero-now-title em { font-style: italic; }

.hero-media {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
}
.hero-bg {
  position: absolute; inset: -8%;
  background:
    radial-gradient(48% 56% at 28% 32%, rgba(201, 122, 79, .26), transparent 70%),
    radial-gradient(40% 48% at 78% 70%, rgba(168, 85, 58, .22), transparent 75%),
    radial-gradient(60% 62% at 50% 100%, rgba(229, 192, 152, .34), transparent 72%),
    linear-gradient(180deg, var(--cream) 0%, var(--cream-deep) 100%);
  filter: blur(46px) saturate(1.06);
  animation: heroDrift 26s var(--ease-in-out) infinite alternate;
}
@keyframes heroDrift {
  0%   { transform: translate(-2%, 1%)  scale(1.02); }
  100% { transform: translate(2%, -1%) scale(1.08); }
}
.hero-grain {
  position: absolute; inset: 0;
  opacity: .12;
  mix-blend-mode: overlay;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="240" height="240"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency=".9" numOctaves="2" stitchTiles="stitch"/></filter><rect width="100%25" height="100%25" filter="url(%23n)" opacity=".75"/></svg>');
  animation: grainShift 1.5s steps(4) infinite;
}
/* MOBILE-FIX (audit #39): the full-viewport mix-blend grain re-composites at
   every step ON TOP of a playing video — battery/thermals on phones for a
   texture that reads identically when static. Coarse pointers keep the grain,
   lose the shimmy. */
@media (pointer: coarse) {
  .hero-grain { animation: none; }
}
@keyframes grainShift {
  0%   { transform: translate(0,0); }
  25%  { transform: translate(-3px,2px); }
  50%  { transform: translate(2px,-2px); }
  75%  { transform: translate(-2px,3px); }
  100% { transform: translate(0,0); }
}
.hero-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(140% 100% at 50% 50%, transparent 50%, rgba(26,22,18,.10) 100%);
}

.hero-meta {
  position: relative; z-index: 2;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
  display: flex;
  flex-direction: column;
  gap: 6px;
  line-height: 1.7;
}
.hero-meta-tl { grid-column: 1; grid-row: 1; }
.hero-meta-tr { grid-column: 2; grid-row: 1; text-align: right; align-items: flex-end; }
.hero-meta-bl { grid-column: 1; grid-row: 3; align-self: end; }
.hero-meta-br { grid-column: 2; grid-row: 3; text-align: right; align-self: end; align-items: flex-end; }

.hero-stage {
  grid-column: 1 / -1;
  grid-row: 2;
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: clamp(20px, 3vh, 36px);
  padding: clamp(20px, 6vh, 80px) 0;
}

.hero-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(76px, 17vw, 256px);
  line-height: .86;
  letter-spacing: -.024em;
  color: var(--ink);
  margin: 0;
  text-align: center;
}
.hero-line {
  display: block;
  overflow: hidden;
}
.hero-line em { font-weight: 300; font-style: italic; display: inline-block; }
.hero-line[data-line="2"] { transform: translateX(.18em); } /* subtle asymmetric offset */
.hero-line .char {
  display: inline-block;
  transform: translateY(110%);
  opacity: 0;
}
body:not(.is-loading) .hero-line .char {
  animation: charRise 1.1s var(--ease-out) forwards;
}
@keyframes charRise {
  to { transform: translateY(0); opacity: 1; }
}

.hero-cycler {
  display: inline-flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
}
.cycler {
  position: relative;
  display: inline-block;
  height: 1.5em;
  overflow: hidden;
  vertical-align: bottom;
  min-width: 28ch;
  text-align: left;
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--ink);
}
.cycler span {
  position: absolute; inset: 0;
  opacity: 0;
  white-space: nowrap;
  animation: cyclerCycle 9s infinite;
}
.cycler span:nth-child(1) { animation-delay: 0s;  opacity: 1; }
.cycler span:nth-child(2) { animation-delay: 3s; }
.cycler span:nth-child(3) { animation-delay: 6s; }
@keyframes cyclerCycle {
  0%, 3%   { opacity: 0; transform: translateY(60%); }
  10%, 28% { opacity: 1; transform: translateY(0); }
  35%, 100%{ opacity: 0; transform: translateY(-60%); }
}

.hero-locations {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink-mute);
  display: inline-flex;
  gap: 14px;
  align-items: baseline;
}
.hero-locations i { font-family: var(--serif); font-style: italic; color: var(--accent); }

/* ghost-link — used in hero meta + outro */
.ghost-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ink);
  padding: 8px 0;
  border-bottom: 1px solid var(--ink-faint);
  transition: border-color .4s ease, transform .4s var(--ease-out), gap .4s var(--ease-out);
}
.ghost-link:hover { border-color: var(--ink); gap: 16px; }
.ghost-link.light { color: var(--paper); border-color: rgba(246, 241, 230, .35); }
.ghost-link.light:hover { border-color: var(--paper); }

.hero-scroll-hint {
  position: absolute;
  bottom: clamp(80px, 12vh, 120px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  z-index: 2;
  color: var(--ink-mute);
}
.hint-line {
  width: 1px; height: 36px;
  background: linear-gradient(180deg, var(--ink-faint) 0%, transparent 100%);
  animation: hintPulse 2.6s var(--ease-in-out) infinite;
  transform-origin: top;
}
@keyframes hintPulse {
  0%, 100% { transform: scaleY(.4); opacity: .4; }
  50%      { transform: scaleY(1);  opacity: 1; }
}

/* ── Section label (used on many sections) ── */
.section-label {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: var(--gutter);
  align-items: baseline;
  padding: clamp(64px, 9vh, 120px) var(--gutter) clamp(28px, 4vh, 48px);
  border-top: 1px solid var(--ink-line);
}
.section-h {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(40px, 6vw, 88px);
  line-height: .98;
  letter-spacing: -.018em;
  margin: 0;
  color: var(--ink);
  max-width: 14ch;
}
@media (max-width: 800px) {
  .section-label { grid-template-columns: 1fr; gap: 14px; }
  .section-h { max-width: 100%; }
}

/* ── Collaborators marquee ── */
.marquee-section { background: var(--cream); }
.marquee {
  position: relative;
  overflow: hidden;
  padding: clamp(20px, 4vh, 48px) 0 clamp(40px, 6vh, 80px);
  mask-image: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
}
.marquee-track {
  display: inline-flex;
  align-items: baseline;
  gap: 0;
  white-space: nowrap;
  animation: marqueeScroll 80s linear infinite;
  will-change: transform;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
.m-item {
  font-family: var(--serif);
  font-size: clamp(48px, 7vw, 112px);
  line-height: 1.05;
  letter-spacing: -.018em;
  color: var(--ink);
  padding: 0 .25em;
}
.m-item em { font-weight: 300; font-style: italic; }
.m-dot {
  font-family: var(--mono);
  font-size: clamp(36px, 5vw, 80px);
  color: var(--accent);
  padding: 0 .15em;
  vertical-align: middle;
}
@keyframes marqueeScroll { to { transform: translateX(-50%); } }

/* ── Pull quote ── */
.quote-section {
  padding: clamp(80px, 12vh, 160px) var(--gutter);
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: var(--gutter);
  align-items: start;
  border-top: 1px solid var(--ink-line);
}
@media (max-width: 800px) { .quote-section { grid-template-columns: 1fr; } }
.pull-quote {
  margin: 0;
  position: relative;
  max-width: 640px;
}
.pull-quote p { max-width: 12ch; }
@media (min-width: 1100px) {
  .pull-quote p { font-size: clamp(56px, 6vw, 96px); }
}
.quote-mark {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(120px, 16vw, 220px);
  line-height: .6;
  color: var(--accent);
  margin-bottom: 8px;
}
.pull-quote p {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(36px, 5vw, 72px);
  line-height: 1.05;
  letter-spacing: -.012em;
  color: var(--ink);
  margin: 0 0 28px;
}
.pull-quote footer {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.pull-quote footer cite { font-style: normal; color: var(--ink); }
.pull-quote footer i { font-family: var(--serif); }

/* ── Outro CTA ── */
.outro {
  padding: clamp(80px, 12vh, 140px) var(--gutter);
  border-top: 1px solid var(--ink-line);
  display: flex;
  flex-direction: column;
  gap: clamp(24px, 4vh, 56px);
}
.outro-row {
  display: flex; justify-content: space-between; align-items: baseline;
}
.outro-cta {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(24px, 4vw, 64px);
  width: 100%;
  padding: clamp(24px, 4vh, 48px) 0;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(72px, 12vw, 184px);
  line-height: .92;
  letter-spacing: -.022em;
  text-align: left;
  color: var(--ink);
  overflow: hidden;
  transition: padding .5s var(--ease-out), background .5s ease;
}
.outro-cta::before {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 0%, rgba(168,85,58,.06) 100%);
  opacity: 0;
  transition: opacity .5s ease;
}
.outro-cta:hover { padding-top: calc(clamp(24px,4vh,48px) + 6px); padding-bottom: calc(clamp(24px,4vh,48px) + 6px); }
.outro-cta:hover::before { opacity: 1; }
.outro-cta-label em { font-weight: 300; }
.outro-cta-arrow {
  display: inline-flex;
  align-items: center;
  transition: transform .5s var(--ease-out);
}
.outro-cta:hover .outro-cta-arrow { transform: translateX(12px); }

/* ════════════════════════════════════════════════════════════════
   REEL — full-bleed dark cinematic page
   ════════════════════════════════════════════════════════════════ */
.reel-full {
  position: relative;
  width: 100%;
  height: 100vh;
  background: #0a0807;
  overflow: hidden;
  color: var(--paper);
}
.reel-iframe {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 100vw;
  height: 56.25vw;
  min-width: 177.78vh;
  min-height: 100vh;
  border: 0;
  pointer-events: none;
}
.reel-grain {
  position: absolute; inset: 0;
  opacity: .16; mix-blend-mode: overlay;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="180" height="180"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency=".9" numOctaves="2" stitchTiles="stitch"/></filter><rect width="100%25" height="100%25" filter="url(%23n)" opacity=".8"/></svg>');
  animation: grainShift 1.4s steps(4) infinite;
  pointer-events: none;
}
.reel-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(120% 80% at 50% 50%, transparent 35%, rgba(0,0,0,.55) 100%);
  pointer-events: none;
}
.reel-overlay {
  position: absolute; inset: 0;
  padding: clamp(96px, 14vh, 140px) var(--gutter) clamp(40px, 6vh, 80px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto 1fr auto;
  gap: 16px;
  z-index: 3;
  color: var(--paper);
}
.reel-tl { grid-column: 1; grid-row: 1; display: flex; flex-direction: column; gap: 6px; }
.reel-br { grid-column: 2; grid-row: 3; justify-self: end; align-self: end; }
.reel-bl { grid-column: 1; grid-row: 3; align-self: end; display: inline-flex; align-items: center; gap: 10px; }
.reel-center {
  grid-column: 1 / -1; grid-row: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: 24px;
}
.reel-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(96px, 17vw, 268px);
  line-height: .86;
  letter-spacing: -.024em;
  color: var(--paper);
  margin: 0;
  text-shadow: 0 4px 40px rgba(0,0,0,.4);
}
.reel-tagline {
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .32em;
  text-transform: uppercase;
  color: rgba(246, 241, 230, .82);
  display: inline-flex;
  gap: 14px;
}
.reel-tagline i { font-family: var(--serif); font-style: italic; color: var(--accent-warm); }
.rec-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #e23a2a;
  box-shadow: 0 0 12px rgba(226,58,42,.7);
  animation: recBlink 1.4s infinite;
}
@keyframes recBlink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

/* ════════════════════════════════════════════════════════════════
   PERSONAL WORK — Commercial split-pane in dark mode
   Structure mirrors Commercial exactly (list on the LEFT, hero on
   the right) so the two routes feel like a matched pair. Only
   difference: a dark palette scoped to .route-work.is-active.
   ════════════════════════════════════════════════════════════════ */

/* Dark-mode token set — scoped to the route so child rules can pick
   them up via var(). Doesn't touch the global --ink/--cream tokens
   (which would resolve to the swapped value on the same selector). */
.route-work.is-active {
  --dm-bg:         #18130f;
  --dm-bg-soft:    #221c17;
  --dm-bg-elev:    #2a221c;
  --dm-fg:         #f3ede1;
  --dm-fg-soft:    rgba(243, 237, 225, .82);
  --dm-fg-mute:    rgba(243, 237, 225, .56);
  --dm-fg-faint:   rgba(243, 237, 225, .22);
  --dm-line:       rgba(243, 237, 225, .12);
  --dm-line-soft:  rgba(243, 237, 225, .06);
  --dm-row-hover:  rgba(243, 237, 225, .04);
  --dm-row-active: rgba(243, 237, 225, .07);
  background: var(--dm-bg);
  color: var(--dm-fg);
}

/* ─── Stage layout — two-column split, mirrors .commercial-stage.
       Left: scrollable project list. Right: panel that swaps to the
       selected project's full detail view (inlineProjectFullHTML)
       directly — no preview-then-expand two-step flow. ─── */
.work-stage {
  display: grid;
  grid-template-columns: clamp(320px, 32vw, 440px) 1fr;
  align-items: stretch;
  height: 100dvh;
  padding: clamp(96px, 12vh, 130px) 0 0;
  box-sizing: border-box;
  overflow: hidden;
}
/* MOBILE-FIX (audit #26): also collapse for SHORT viewports — a landscape phone
   is >800px wide but ~375px tall, and the desktop 100vh split-pane clipped the
   preview panel with no way to scroll. minmax(0,1fr) as on .commercial-stage. */
@media (max-width: 800px), (max-height: 520px) {
  .work-stage {
    grid-template-columns: minmax(0, 1fr);
    height: auto;
    overflow: visible;
  }
}

/* Left panel — project list, scrolls independently of the hero. */
.ws-list {
  border-right: 1px solid var(--dm-line);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* Same condition as the .work-stage collapse above — the border swap is part
   of the stacked layout, and a short-wide viewport (landscape phone) stacks. */
@media (max-width: 800px), (max-height: 520px) {
  .ws-list { border-right: 0; border-bottom: 1px solid var(--dm-line); }
}
.ws-list-head {
  padding: clamp(18px, 2.4vh, 28px) var(--gutter) clamp(14px, 2vh, 22px);
  border-bottom: 1px solid var(--dm-line);
}
.ws-list-head .kicker {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--dm-fg-mute);
}
.ws-list-scroll {
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  scrollbar-width: thin;
}
.ws-list-scroll::-webkit-scrollbar { width: 4px; }
.ws-list-scroll::-webkit-scrollbar-track { background: transparent; }
.ws-list-scroll::-webkit-scrollbar-thumb { background: var(--dm-fg-faint); border-radius: 2px; }

/* Legacy mast — kept so any stray markup still styles cleanly */
.ws-mast {
  padding: clamp(16px, 2.4vh, 28px) 0 clamp(18px, 2.6vh, 30px);
  border-bottom: 1px solid var(--dm-line);
}
.ws-mast .kicker {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--dm-fg-mute);
}

.ws-row {
  width: 100%;
  display: grid;
  grid-template-columns: 50px 1fr 20px;
  align-items: baseline;
  gap: 18px;
  padding: clamp(14px, 1.6vh, 20px) var(--gutter);
  border: 0;
  border-left: 2px solid transparent;
  border-bottom: 1px solid var(--dm-line);
  background: transparent;
  text-align: left;
  text-decoration: none;
  font: inherit;
  color: var(--dm-fg);
  cursor: pointer;
  transition: background .3s ease, border-left-color .3s ease, color .3s ease;
}
.ws-row:hover {
  background: var(--dm-row-hover);
  /* No padding shift on hover — would cause long titles to wrap */
}
.ws-row.is-active {
  border-left-color: var(--accent);
  background: var(--dm-row-active);
}
.ws-num {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .18em;
  color: var(--dm-fg-mute);
}
.ws-name {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(20px, 1.7vw, 26px);
  line-height: 1.1;
  letter-spacing: -.012em;
  color: var(--dm-fg-mute);
  transition: color .3s ease;
  /* Always single line — no wrapping when hover state nudges padding */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.ws-row.is-active .ws-name,
.ws-row:hover .ws-name { color: var(--dm-fg); }
.ws-arr {
  font-family: var(--serif);
  font-style: italic;
  font-size: 16px;
  color: var(--dm-fg-faint);
  opacity: 0;
  text-align: right;
  transition: opacity .3s ease, transform .3s var(--ease-out);
}
.ws-row.is-active .ws-arr,
.ws-row:hover .ws-arr { opacity: 1; transform: translateX(4px); }
.ws-row.is-active .ws-arr { color: var(--accent); }

/* ─── Hero stage (right panel) ─── */
.ws-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: clamp(20px, 3vh, 36px);
  padding: clamp(28px, 4vh, 56px) clamp(40px, 5vw, 80px);
  min-height: 0;
  transition: opacity .42s var(--ease-out);
}
.ws-hero.is-swapping { opacity: 0; }

/* Override the shared .cs-* rules so the media fills more of the panel
   and the title sits comfortably below the media (not pinned to bottom). */
.route-work.is-active .cs-link {
  display: flex; flex-direction: column;
  align-items: center;
  gap: clamp(20px, 2.6vh, 32px);
  text-decoration: none;
  color: inherit;
  width: 100%;
  max-width: 100%;
}

/* Media frame — sized so media + meta + title all fit in the single
   viewport hero panel (100vh minus ~130px nav padding). 60vh leaves
   enough room (~150px) below for the kicker + title + breathing. */
.route-work.is-active .cs-media-wrap {
  max-height: 60vh;
  background: var(--dm-bg-soft);
}
.route-work.is-active .cs-media-wrap[data-aspect="9/16"] { height: 60vh; }
.route-work.is-active .cs-media-wrap[data-aspect="4/5"]  { height: 60vh; }
.route-work.is-active .cs-media-wrap[data-aspect="16/9"] { width: 100%; max-height: 60vh; }
.route-work.is-active .cs-media-wrap[data-aspect="3/4"]  { height: clamp(320px, 64vh, 580px); }
.route-work.is-active .cs-media-wrap[data-aspect="4/3"]  { height: clamp(320px, 64vh, 580px); }

/* Title row sits right below the media — kicker label injected above
   via a ::before pseudo reading from data-meta (set by commercialHeroHTML).
   No HTML wrapper change needed; Commercial keeps its own .cs-name layout. */
.route-work.is-active .cs-name {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: 14px;
  padding: 30px 0 6px;            /* top padding reserves space for the kicker */
  border-bottom: 1px solid transparent;
  transition: border-color .35s ease, gap .35s var(--ease-out);
}
.route-work.is-active .cs-name::before {
  content: attr(data-meta);
  position: absolute;
  top: 0; left: 50%; transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--dm-fg-mute);
  white-space: nowrap;
}
.route-work.is-active .cs-link:hover .cs-name { border-bottom-color: var(--dm-fg); gap: 20px; }
.route-work.is-active .cs-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(28px, 3vw, 44px);
  line-height: 1;
  letter-spacing: -.012em;
  color: var(--dm-fg);
  margin: 0;
}
.route-work.is-active .cs-arrow {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(20px, 2vw, 28px);
  color: var(--dm-fg-mute);
  transition: color .35s ease;
}
.route-work.is-active .cs-link:hover .cs-arrow { color: var(--accent); }

/* Loader pulse + placeholder for projects without media */
.route-work.is-active .cs-loader { background: rgba(243, 237, 225, .55); }
.route-work.is-active .cs-empty { background: var(--dm-bg-soft); color: var(--dm-fg-mute); }
.route-work.is-active .cs-trio-cell { background: var(--dm-bg-soft); }

/* Hide the cs-loader once any media element is in place (covers the case
   where load events fire too early and the loader pulse never clears). */
.route-work.is-active .cs-media-wrap:has(iframe[src]) .cs-loader,
.route-work.is-active .cs-media-wrap:has(video[src]) .cs-loader { opacity: 0; }

/* Legacy: the old Reel/Index work styles below are no longer used. */

/* ── New mast (editorial) ── */
.route-work > .work-mast {
  display: flex; flex-direction: column;
  gap: clamp(12px, 1.8vh, 22px);
  padding: clamp(100px, 14vh, 160px) var(--gutter) clamp(40px, 5vh, 60px);
  border-bottom: 1px solid var(--ink-line);
}
.work-mast-lede {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(18px, 1.4vw, 24px);
  line-height: 1.35;
  color: var(--ink-soft);
  margin: clamp(8px, 1.5vh, 14px) 0 0;
  max-width: 50ch;
}
.work-view-toggle {
  display: flex; align-items: baseline; gap: 10px;
  margin-top: clamp(18px, 2.5vh, 30px);
}
.wvt-btn {
  background: none; border: none; padding: 0;
  font-family: var(--mono);
  font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink-mute);
  cursor: pointer;
  transition: color .25s var(--ease-out);
  position: relative;
}
.wvt-btn:hover { color: var(--ink); }
.wvt-btn.is-active { color: var(--ink); }
.wvt-btn.is-active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -6px;
  height: 1px; background: var(--ink);
}
.wvt-sep { color: var(--ink-faint); font-family: var(--mono); }
.wvt-count {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* ── REEL view ── */
/* Reel uses a 2-column grid with the first item full-width (featured).
   Each item is a small vertical card: video on top, meta below.
   This trades the previous single-column 16:9 (which scrolled forever)
   for an asymmetric editorial grid — denser, easier to scan. */
.work-reel {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(36px, 5vh, 64px) clamp(24px, 3vw, 48px);
  padding: clamp(36px, 5vh, 72px) var(--gutter);
  max-width: 1640px; margin: 0 auto;
}
.work-reel[hidden], .work-index[hidden] { display: none !important; }

.reel-item {
  display: flex; flex-direction: column;
  gap: clamp(12px, 1.5vh, 18px);
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 1.1s var(--ease-out), transform 1.1s var(--ease-out);
}
.reel-item.is-visible { opacity: 1; transform: none; }
/* Choreographed entrance — children stagger their reveals like a count */
.reel-item.is-visible .reel-meta { transition-delay: .15s; }

/* First item is the editorial hero — spans both columns */
.reel-item:first-child { grid-column: 1 / -1; }

@media (max-width: 760px) {
  .work-reel { grid-template-columns: 1fr; }
  .reel-item:first-child { grid-column: auto; }
}

.reel-meta {
  display: flex; flex-direction: column;
  gap: 4px;
  opacity: 0;
  transition: opacity .8s var(--ease-out);
}
.reel-item.is-visible .reel-meta { opacity: 1; }

/* Top row of the meta: project number on the left, kind/year on the right.
   Pulled apart with justify-content: space-between so they bracket the title. */
.reel-meta-row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.reel-num { color: var(--ink-mute); }
.reel-kind { color: var(--ink-mute); }

.reel-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(20px, 1.8vw, 28px);
  line-height: 1.1;
  letter-spacing: -.012em;
  margin: 0;
  color: var(--ink);
}
.reel-title em { font-style: italic; }
.reel-title-sub {
  font-style: italic; font-weight: 300;
  color: var(--ink-mute);
  font-size: .72em;
  margin-left: 2px;
}
.reel-client {
  font-family: var(--sans);
  font-size: clamp(11px, .82vw, 13px);
  line-height: 1.45;
  letter-spacing: .03em;
  color: var(--ink-soft);
  margin: 2px 0 0;
}

/* Featured first item gets a larger title since it has more horizontal room */
.reel-item:first-child .reel-title {
  font-size: clamp(28px, 2.6vw, 44px);
}
.reel-item:first-child .reel-client {
  font-size: clamp(13px, 1vw, 16px);
}

.reel-link {
  display: block;
  position: relative;
  text-decoration: none;
  color: inherit;
  overflow: hidden;
  background: var(--ink);
  aspect-ratio: 16 / 9;
  transition: transform .6s var(--ease-out);
}
@media (max-width: 760px) {
  .reel-link { order: -1; }
}
.reel-link:hover { transform: scale(1.005); }

/* Media inside the link — iframe, video, or img */
.reel-media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
}
.reel-media iframe,
.reel-media video,
.reel-media img {
  width: 100%; height: 100%;
  object-fit: cover;
  border: 0;
  display: block;
}
/* Shield prevents pointer-events on the iframe from blocking the link */
.reel-shield {
  position: absolute; inset: 0;
  pointer-events: auto;
  background: transparent;
}
/* Reveal arrow that pulls in on hover */
.reel-link::after {
  content: "→";
  position: absolute;
  bottom: 14px; right: 18px;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(22px, 2vw, 32px);
  color: var(--cream);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity .35s var(--ease-out), transform .35s var(--ease-out);
  text-shadow: 0 2px 12px rgba(0, 0, 0, .55);
  z-index: 2;
  pointer-events: none;
}
.reel-link:hover::after { opacity: 1; transform: none; }

/* Placeholder when no media exists */
.reel-empty {
  width: 100%; height: 100%;
  background: var(--cream-deep);
  display: grid; place-items: center;
  color: var(--ink-mute);
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(22px, 2vw, 30px);
}

/* ── INDEX view (chronological type-only list) ── */
.work-index {
  list-style: none;
  margin: 0;
  padding: clamp(32px, 5vh, 60px) var(--gutter) clamp(48px, 7vh, 96px);
  max-width: 1640px;
  margin-left: auto; margin-right: auto;
  counter-reset: idx;
}
.idx-row {
  display: grid;
  grid-template-columns: 60px 1fr auto auto 30px;
  gap: clamp(16px, 2vw, 40px);
  align-items: baseline;
  padding: clamp(18px, 2.5vh, 28px) 0;
  border-top: 1px solid var(--ink-line);
  cursor: pointer;
  transition: padding .35s var(--ease-out), color .35s var(--ease-out);
  color: var(--ink);
}
.idx-row:last-child { border-bottom: 1px solid var(--ink-line); }
.idx-row:hover { padding: clamp(22px, 3.2vh, 36px) clamp(8px, 1.5vw, 22px); }
.idx-row:hover .idx-arr { transform: translateX(6px); opacity: 1; }
.idx-num {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.idx-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(22px, 2.4vw, 40px);
  line-height: 1.04;
  letter-spacing: -.012em;
  margin: 0;
}
.idx-title em { font-style: italic; }
.idx-sub {
  font-style: italic; font-weight: 300;
  color: var(--ink-mute);
  font-size: .55em;
  margin-left: 6px;
}
.idx-client {
  font-family: var(--sans);
  font-size: clamp(11px, .85vw, 13px);
  letter-spacing: .04em;
  color: var(--ink-soft);
  text-align: right;
  max-width: 26ch;
  justify-self: end;
}
.idx-meta {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-mute);
  text-align: right;
  white-space: nowrap;
}
.idx-arr {
  font-family: var(--serif); font-style: italic;
  font-size: 18px;
  color: var(--ink);
  opacity: .35;
  transition: transform .35s var(--ease-out), opacity .35s var(--ease-out);
  justify-self: end;
}

@media (max-width: 900px) {
  .idx-row {
    grid-template-columns: 36px 1fr auto;
    gap: 14px;
  }
  .idx-client { display: none; }
}

/* Original .work-mast-grid / .work-mast-filters / .wf-* / .t-* styles
   below remain for backwards compatibility — unused by new layout. */
.work-mast {
  padding: clamp(120px, 18vh, 200px) var(--gutter) clamp(40px, 6vh, 64px);
  border-bottom: 1px solid var(--ink-line);
}
.work-mast-grid {
  display: grid;
  grid-template-columns: 1fr;
  justify-items: start;
  gap: 16px;
  padding-bottom: clamp(28px, 4vh, 48px);
}
.work-mast-grid .kicker { order: 1; }
.work-mast-title         { order: 2; }
.work-mast-grid .micro   { order: 3; }
.work-mast-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(64px, 10vw, 160px);
  line-height: .9;
  letter-spacing: -.022em;
  color: var(--ink);
  margin: 0;
  text-align: left;
}
.work-mast-title em { font-style: italic; }
.work-mast-grid .kicker { align-self: start; }
.work-mast-grid .micro { align-self: end; }

.work-mast-filters {
  display: flex;
  gap: clamp(16px, 2vw, 28px);
  flex-wrap: wrap;
  padding-top: clamp(20px, 3vh, 32px);
  border-top: 1px solid var(--ink-line);
}
.filter {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-mute);
  padding: 8px 0;
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  transition: color .3s ease;
}
.filter span {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--accent);
  vertical-align: super;
}
.filter::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px; background: var(--ink);
  transform: scaleX(0); transform-origin: left;
  transition: transform .4s var(--ease-out);
}
.filter:hover, .filter.on { color: var(--ink); }
.filter:hover::after, .filter.on::after { transform: scaleX(1); }

/* ticker — the index */
.ticker { padding: 0 var(--gutter) clamp(60px, 10vh, 120px); }
.t-row {
  position: relative;
  display: grid;
  grid-template-columns: 64px 1fr clamp(160px, 18vw, 240px) clamp(120px, 14vw, 180px) 24px;
  gap: clamp(16px, 2vw, 32px);
  align-items: baseline;
  padding: clamp(20px, 3vh, 36px) 0;
  border-top: 1px solid var(--ink-line);
  cursor: pointer;
  overflow: hidden;
  transition: padding .5s var(--ease-out);
}
.t-row:last-child { border-bottom: 1px solid var(--ink-line); }
.t-row::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--ink);
  transform: translateY(102%);
  transition: transform .55s var(--ease-expo);
  z-index: 0;
}
.t-row > * { position: relative; z-index: 1; }
.t-row:hover { padding: clamp(28px, 4vh, 52px) 0; }
.t-row:hover::before { transform: translateY(0); }
.t-row:hover .t-num,
.t-row:hover .t-title,
.t-row:hover .t-client,
.t-row:hover .t-meta,
.t-row:hover .t-arr { color: var(--paper); }

.t-num {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .04em;
  color: var(--ink-mute);
  font-variant-numeric: tabular-nums;
  transition: color .55s var(--ease-out);
}
.t-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(24px, 2.8vw, 44px);
  line-height: 1.05;
  letter-spacing: -.012em;
  color: var(--ink);
  transition: color .55s var(--ease-out), transform .55s var(--ease-out);
}
.t-title-sub {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(14px, 1.2vw, 18px);
  color: var(--ink-mute);
  margin-left: 8px;
  letter-spacing: 0;
}
.t-row:hover .t-title { transform: translateX(16px); }
.t-client {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-mute);
  transition: color .55s var(--ease-out);
}
.t-meta {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-mute);
  text-align: right;
  transition: color .55s var(--ease-out);
}
.t-arr {
  font-family: var(--serif);
  font-style: italic;
  font-size: 24px;
  color: var(--ink-mute);
  text-align: right;
  transition: color .55s var(--ease-out), transform .55s var(--ease-out);
}
.t-row:hover .t-arr { transform: translateX(12px); }

.t-row.hidden-by-filter { display: none; }

@media (max-width: 800px) {
  .t-row { grid-template-columns: 40px 1fr 24px; }
  .t-client, .t-meta { display: none; }
  .t-title { font-size: clamp(28px, 8vw, 40px); }
}

.work-cta {
  padding: clamp(60px, 10vh, 120px) var(--gutter);
  display: flex;
  flex-direction: column;
  gap: clamp(20px, 3vh, 32px);
  border-top: 1px solid var(--ink-line);
}

/* ════════════════════════════════════════════════════════════════
   PROJECT — Werewolf Heart case study
   ════════════════════════════════════════════════════════════════ */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  position: absolute;
  top: clamp(80px, 12vh, 110px);
  left: var(--gutter);
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-mute);
  z-index: 5;
  transition: color .3s ease, gap .3s ease;
}
.back-link:hover { color: var(--ink); gap: 16px; }

.pj-mast {
  padding: clamp(140px, 22vh, 220px) var(--gutter) clamp(40px, 6vh, 80px);
  text-align: center;
  position: relative;
}
.pj-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(96px, 16vw, 248px);
  line-height: .9;
  letter-spacing: -.022em;
  margin: 16px 0 28px;
  color: var(--ink);
}
.pj-summary {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(20px, 2.2vw, 26px);
  line-height: 1.45;
  color: var(--ink-soft);
  max-width: 56ch;
  margin: 0 auto 28px;
}
.pj-credit-line {
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.pj-credit-line em { font-style: italic; color: var(--ink); }

.pj-reel {
  margin: 0 auto clamp(60px, 10vh, 120px);
  padding: 0 var(--gutter);
  max-width: 980px;
  border-top: 1px solid var(--ink-line);
  border-bottom: 1px solid var(--ink-line);
  padding-top: 24px;
  padding-bottom: 24px;
}
.pj-reel-inner {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  max-width: 880px;
  margin: 0 auto;
}
.pj-reel-bg {
  position: absolute; inset: 0;
  background:
    radial-gradient(50% 60% at 30% 40%, rgba(108, 60, 38, .55), transparent 70%),
    radial-gradient(45% 60% at 78% 70%, rgba(40, 24, 16, .85), transparent 75%),
    linear-gradient(180deg, #2a1b12 0%, #0d0907 100%);
}
.pj-reel-grain {
  position: absolute; inset: 0;
  opacity: .14;
  mix-blend-mode: overlay;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="180" height="180"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency=".9" numOctaves="2" stitchTiles="stitch"/></filter><rect width="100%25" height="100%25" filter="url(%23n)" opacity=".8"/></svg>');
  animation: grainShift 1.4s steps(4) infinite;
}
.pj-reel-play {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  transition: transform .5s var(--ease-out), opacity .3s ease;
  opacity: .92;
}
.pj-reel-inner:hover .pj-reel-play { transform: translate(-50%, -50%) scale(1.12); opacity: 1; }
.pj-reel-cap {
  position: absolute;
  bottom: 18px; left: 18px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(246, 241, 230, .82);
}

.pj-body {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: clamp(40px, 6vw, 88px);
  padding: 0 var(--gutter) clamp(60px, 10vh, 100px);
  align-items: start;
}
@media (max-width: 900px) { .pj-body { grid-template-columns: 1fr; } }

.festival-list { counter-reset: f; }
.festival-list li {
  counter-increment: f;
  position: relative;
  padding: 14px 0 14px 56px;
  border-top: 1px solid var(--ink-line);
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .03em;
  color: var(--ink-soft);
  line-height: 1.55;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .6s var(--ease-out), transform .6s var(--ease-out);
}
.festival-list li.is-in { opacity: 1; transform: translateY(0); }
.festival-list li::before {
  content: counter(f, decimal-leading-zero);
  position: absolute;
  left: 0; top: 14px;
  font-size: 10.5px;
  color: var(--ink-mute);
  letter-spacing: .1em;
}
.festival-list li:last-child { border-bottom: 1px solid var(--ink-line); }

.pj-body-right {
  position: sticky;
  top: 100px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px clamp(20px, 2vw, 32px);
}
@media (max-width: 900px) { .pj-body-right { position: static; } }
.pj-meta-block .kicker { margin-bottom: 4px; display: block; }
.pj-meta-block p { margin: 0; }

.pj-stills {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(16px, 2vw, 28px);
  padding: 0 var(--gutter) clamp(60px, 10vh, 100px);
}
.pj-still {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  margin: 0;
}
.pj-still-bg {
  position: absolute; inset: 0;
  transition: transform 1.2s var(--ease-out);
}
.pj-still:hover .pj-still-bg { transform: scale(1.05); }
.pj-still-warm .pj-still-bg {
  background:
    radial-gradient(60% 70% at 30% 40%, rgba(212, 158, 110, .9), transparent 75%),
    linear-gradient(180deg, #c9a37b 0%, #6f4a30 100%);
}
.pj-still-dark .pj-still-bg {
  background:
    radial-gradient(50% 70% at 70% 30%, rgba(168, 85, 58, .5), transparent 75%),
    linear-gradient(180deg, #3a2418 0%, #100805 100%);
}
.pj-still figcaption {
  position: absolute;
  bottom: 14px; left: 14px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: rgba(246, 241, 230, .82);
}

.pj-pager {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: clamp(20px, 4vw, 60px);
  align-items: baseline;
  padding: clamp(40px, 6vh, 80px) var(--gutter);
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}
.pj-pager-prev, .pj-pager-next {
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: transform .4s var(--ease-out);
}
.pj-pager-next { align-items: flex-end; text-align: right; }
.pj-pager-prev:hover { transform: translateX(-10px); }
.pj-pager-next:hover { transform: translateX(10px); }
.pj-pager-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(32px, 4vw, 52px);
  line-height: 1;
  color: var(--ink);
}
.pj-pager-count {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .14em;
  color: var(--ink-mute);
  align-self: center;
  font-variant-numeric: tabular-nums;
}

/* ─── Project detail mobile (< 720px) ───
   The desktop type scale was tuned for 1200px+. On a 390px viewport
   pj-title's min-96px font + 140px mast top padding produced a
   wall of empty space + a title that wrapped awkwardly (esp. for
   long names like "YSL Beauté"). Scale everything down + tighten
   the breathing room. */
@media (max-width: 720px) {
  .pj-mast {
    padding: clamp(96px, 14vh, 130px) var(--gutter) clamp(24px, 4vh, 40px);
  }
  .pj-title {
    font-size: clamp(48px, 13vw, 84px);
    line-height: .94;
    margin: 12px 0 16px;
  }
  .pj-sub {
    font-size: clamp(16px, 4.2vw, 20px);
    margin-top: 8px;
  }
  .pj-summary {
    font-size: clamp(16px, 4vw, 19px);
    line-height: 1.5;
    margin-bottom: 18px;
  }
  .pj-reel { padding: 16px 0; }
  .pj-body { padding: clamp(40px, 7vh, 64px) var(--gutter); gap: clamp(24px, 4vh, 36px); }
  .pj-body-left h2.kicker { font-size: 11px; }
  .pj-credit-row {
    display: grid;
    grid-template-columns: minmax(120px, 38%) 1fr;
    gap: 6px 14px;
    padding: 10px 0;
    border-bottom: 1px solid var(--ink-line);
  }
  .pj-meta-block { padding: 10px 0; border-bottom: 1px solid var(--ink-line); }
  .pj-pager { padding: clamp(40px, 6vh, 64px) var(--gutter); gap: 16px; }
  .pj-pager-prev, .pj-pager-next { min-width: 0; }
  .pj-pager-title { font-size: clamp(22px, 6vw, 32px); }
  /* Festival list: prevent long single-line entries from overflowing */
  .festival-list li { font-size: 14px; line-height: 1.45; word-break: break-word; }
}

/* ════════════════════════════════════════════════════════════════
   BIO + CONTACT
   ════════════════════════════════════════════════════════════════ */
/* ════════════════════════════════════════════════════════════════
   ABOUT PAGE — editorial magazine spread
   Full-bleed portrait left, identity statement + prose right,
   brand marquee strip at the very bottom. Fills the viewport when the
   bio is short; grows past it (page scrolls) when the bio is long.
   ════════════════════════════════════════════════════════════════ */
/* Only override the active route — plain .route-bio must stay hidden
   when not active (otherwise it overrides `.route { display: none }`
   and bleeds into other routes like /#project/...).

   NO `max-height` here. It used to be `max-height: 100dvh` to force the
   spread into one screen, which silently CLIPPED any bio longer than the
   ~460-char default this layout was drawn around — the admin-saved bio is
   ~980 chars, so the last ~4 lines vanished on desktop with no scrollbar
   and no ellipsis (mobile was fine; the ≤820px block below already
   relaxed it). `min-height` keeps the full-screen look when the text
   fits; without a max, a longer bio simply extends the page.
   `overflow: hidden` stays — it only guards the horizontal axis now
   (the 360px min photo column can exceed narrow desktop widths); with
   the height content-driven there is nothing left to clip vertically. */
.route-bio.is-active {
  min-height: 100dvh; overflow: hidden;
  display: grid; grid-template-rows: 1fr auto;
  background: var(--cream);
}

.bio-spread {
  display: grid;
  grid-template-columns: minmax(360px, 0.95fr) 1.25fr;
  min-height: 0; /* let inner content govern height */
}

/* Left half — portrait, full-bleed top to bottom */
.bio-spread-photo {
  margin: 0;
  position: relative;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  background: var(--cream-deep);
}
/* Absolutely positioned so the portrait CROPS to whatever height the text
   column needs, instead of dictating it. In flow, `height: 100%` against a
   now-auto-height figure falls back to the file's natural 2:3 ratio (640×960
   → ~933px tall at desktop column width), which would make the portrait —
   not the prose — set the page height. Taking it out of flow restores the
   pre-fix crop: the row is text-driven, the image fills it. */
.bio-spread-photo img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center 30%;
  display: block;
  filter: contrast(1.02) saturate(.96);
}
.bio-spread-photo figcaption {
  position: absolute;
  bottom: 18px; left: 18px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(250, 247, 241, .82);
  text-shadow: 0 1px 4px rgba(0, 0, 0, .55);
}

/* Right half — identity column.
   Layout: eyebrow → name (display) → pull-quote (editorial moment) → prose → meta.
   The pull-quote acts as the visual centerpiece, set in italic display with
   hairline rules above and below — borrowed from press-quote editorial pages. */
.bio-spread-text {
  /* Top padding clears the fixed nav (~69px) — do not drop it below ~76px
     or the eyebrow tucks under the nav bar. */
  padding: clamp(76px, 11vh, 124px) clamp(40px, 6vw, 96px) clamp(20px, 3vh, 40px);
  display: flex; flex-direction: column;
  gap: clamp(14px, 2.4vh, 30px);
  /* `overflow: visible`, not hidden: this column was the second place a
     long bio got cut off (the prose is a flex item, so it shrank and its
     text spilled out of a box that then clipped it). The column now grows
     with its content and the route above grows with it. */
  overflow: visible;
  min-height: 0;
}

.bio-spread-eyebrow {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-mute);
  display: block;
  margin-bottom: clamp(14px, 2.2vh, 24px);
}

.bio-spread-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  /* min(vw, vh): the name is set from viewport WIDTH, so on a wide-but-short
     screen (1366×768, or a half-height window on a big monitor) it used to
     grow to ~100px and push the spread past the fold. Capping it against
     height too keeps the single-screen promise without shrinking it on the
     tall viewports where there is room. */
  font-size: clamp(56px, min(6.4vw, 12vh), 104px);
  line-height: .9;
  letter-spacing: -.024em;
  margin: 0;
  color: var(--ink);
}
.bio-spread-title em { font-style: italic; }

/* Pull-quote — the editorial signature.
   Hairlines above + below set it apart as a "moment". */
.bio-spread-pull {
  margin: 0;
  padding: clamp(10px, 1.8vh, 22px) 0;
  border-top: 1px solid var(--ink-line);
  border-bottom: 1px solid var(--ink-line);
}
.bio-spread-pull p {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  /* Height-capped for the same reason as .bio-spread-title above. */
  font-size: clamp(28px, min(3.4vw, 6.4vh), 54px);
  line-height: 1.05;
  letter-spacing: -.018em;
  color: var(--ink);
}
.bio-spread-pull p em {
  font-style: italic;
  color: var(--accent);
}

.bio-spread-prose {
  /* Was 56ch, which left 200–470px of the column empty at every desktop
     size while the text ran long vertically — the single biggest reason
     the spread overflowed the viewport. A wider measure costs nothing
     horizontally and removes 3–4 lines of height. */
  max-width: 72ch;
}
.bio-spread-prose p {
  font-family: var(--sans);
  font-size: clamp(13px, .92vw, 15px);
  line-height: 1.68;
  margin: 0;
  color: var(--ink-soft);
  /* The bio is admin-written free text, so it can contain a URL or a long
     booking address. Without this, an unbreakable token overflows the
     column and .route-bio's overflow:hidden cuts it off with NO scrollbar —
     the same silent-truncation trap as the max-height bug, just sideways. */
  overflow-wrap: anywhere;
}
/* Blank lines in the admin Bio box become separate <p> blocks (see
   app.js#bioRenderMarkdown). `margin: 0` above zeroed the UA spacing and the
   column's flex `gap` only applies to its own children, not these — so
   paragraphs rendered flush and structure the admin typed simply vanished.
   CLIENT-GUIDE.md tells her a blank line starts a new paragraph; this is
   what makes that true. */
.bio-spread-prose p + p { margin-top: .85em; }
/* `## Heading` is also reachable from the same box; without this it fell
   back to bold UA styling at 1.5em with UA margins — the only element in
   this column with margins, and visibly out of key. */
.bio-spread-prose h2,
.bio-spread-prose h3 {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(16px, 1.2vw, 19px);
  line-height: 1.3;
  color: var(--ink);
  margin: 1em 0 .35em;
}
.bio-spread-prose > :first-child { margin-top: 0; }
.bio-spread-prose p em {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.08em;
  color: var(--ink);
}
.bio-spread-prose p em {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.1em;
  color: var(--ink);
}

.bio-spread-meta {
  margin-top: auto;
  padding-top: 18px;
  border-top: 1px solid var(--ink-line);
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
}
.bio-spread-cv {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink);
  /* MOBILE-FIX (audit #22): was a 112x26 target. Grow the hit area, keep the
     glyphs — the type size is the design, the tap area is the fix. The hover
     underline is text-decoration (NOT border-bottom): a border draws under
     the padding box, which the 13px padding pushed ~13px below the glyphs. */
  padding: 13px 8px;
  margin: -9px -8px;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 3px;
  transition: color .25s var(--ease-out), text-decoration-color .25s var(--ease-out);
}
.bio-spread-cv:hover, .bio-spread-cv:active { color: var(--accent); text-decoration-color: var(--accent); }
.bio-spread-cv-arrow { font-size: 14px; line-height: 1; }
.bio-spread-since {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* Bottom marquee strip — full-width footer of the about page */
.bio-brands {
  border-top: 1px solid var(--ink-line);
  background: var(--cream);
  display: flex; align-items: center; gap: 24px;
  padding: clamp(12px, 1.6vh, 18px) 0;
  overflow: hidden;
}
.bio-brands-label {
  flex-shrink: 0;
  padding-left: clamp(24px, 3vw, 48px);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.bio-brands .marquee {
  flex: 1;
  overflow: hidden;
  /* Reset the base `.marquee` padding (clamp(20px,4vh,48px) top /
     clamp(40px,6vh,80px) bottom, further up this file). That rule is sized
     for the home-page ticker's 112px display type; inherited here it added
     ~79px of empty band above and below a 52px row of names — dead space
     that pushed the bio page past the fold. .bio-brands owns this strip's
     padding. */
  padding: 0;
  mask: linear-gradient(to right, transparent 0, black 5%, black 95%, transparent 100%);
  -webkit-mask: linear-gradient(to right, transparent 0, black 5%, black 95%, transparent 100%);
}
.bio-brands .brand-track {
  display: inline-flex; white-space: nowrap;
  animation: marqueeScroll 70s linear infinite;
}
.bio-brands .bm-item {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(20px, 2vw, 32px);
  line-height: 1.1;
  letter-spacing: -.01em;
  color: var(--ink);
  padding: 0 .35em;
}
/* line-height matters here: the dot's font-size (clamp(22px,2.4vw,40px) from
   the base .bm-dot) is LARGER than the names', and it was inheriting body's
   1.5 — so the separators, not the names, set the height of this whole strip
   (1.5 × 38.4px = 57.6px at 1600px wide, to show 28.8px names). Matching the
   names' 1.1 costs nothing visually — the glyph size is untouched — and takes
   ~15px off a page that has to land in one screen. */
.bio-brands .bm-dot { color: var(--accent); padding: 0 .2em; line-height: 1.1; }

/* ── Short-viewport compaction (desktop layout only) ──────────────
   The spread is meant to land in one screen. Everything in it is sized
   from viewport WIDTH, so a wide-but-short viewport — a 1366×768 laptop,
   or any window that isn't full height on a large monitor — still ran
   past the fold after the fixes above. Two levers, applied only where
   the height is actually tight:

     ≤780px  the prose takes the full column. A short screen has
             horizontal room to spare, and a wider measure is simply
             fewer lines — the cheapest height there is.
     ≤680px  the leading and the bottom padding tighten by a notch.

   This block deliberately does NOT shrink .bm-item: the strip's height is
   set by the .bm-dot separators (see the line-height note on
   .bio-brands .bm-dot), so shrinking the names reclaimed 0px while making
   the dots 1.5× the client names — and, because app.js measures the track
   to decide how many times to repeat it, a height-only resize across this
   breakpoint re-sized the names underneath a fit that had already been
   computed, opening a visible gap in the loop.

   Nothing is ever clipped: if a viewport is still too short (phones, or
   a very small window) the page just scrolls, exactly as it does now.
   See the `max-height` note on .route-bio.is-active — that clip is what
   used to swallow the end of the bio, and it is not coming back. */
@media (min-width: 821px) and (max-height: 780px) {
  .bio-spread-prose { max-width: 100%; }
}
@media (min-width: 821px) and (max-height: 680px) {
  .bio-spread-prose p { line-height: 1.58; }
  .bio-spread-text { padding-bottom: clamp(12px, 2vh, 24px); }
}

/* Stack on narrow screens — drops the single-viewport constraint
   because portrait + text won't fit side by side comfortably.
   IMPORTANT: target .route-bio.is-active so we override the
   is-active rule's max-height/overflow constraints (which have
   higher specificity than plain .route-bio). */
@media (max-width: 820px) {
  .route-bio.is-active {
    min-height: 0;
    max-height: none;
    overflow-y: auto;
    grid-template-rows: auto auto;
  }
  .bio-spread { grid-template-columns: 1fr; }
  .bio-spread-photo { height: 56vh; min-height: 380px; }
  .bio-spread-text { overflow: visible; }   /* let text flow on mobile */
  .bio-spread-text {
    padding: clamp(36px, 6vh, 56px) clamp(24px, 5vw, 48px) clamp(24px, 4vh, 36px);
    gap: 20px;
  }
  .bio-spread-title { font-size: clamp(54px, 13vw, 96px); }
  .bio-spread-lede { font-size: clamp(17px, 3.5vw, 22px); }
  .bio-spread-meta { flex-direction: column; align-items: flex-start; gap: 12px; }
  .bio-brands {
    flex-direction: column; align-items: flex-start; gap: 6px;
    padding: 14px clamp(24px, 5vw, 48px);
  }
  .bio-brands-label { padding-left: 0; }
  .bio-brands .marquee { width: 100%; }
}

.bio-mast {
  padding: clamp(140px, 22vh, 220px) var(--gutter) clamp(60px, 10vh, 120px);
  border-bottom: 1px solid var(--ink-line);
}
.bio-mast .kicker { display: block; margin-bottom: clamp(20px, 3vh, 36px); }
.bio-mast-title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(40px, 5.4vw, 88px);
  line-height: 1.08;
  letter-spacing: -.012em;
  color: var(--ink);
  margin: 0;
  max-width: 22ch;
}
.bio-mast-title em { font-style: italic; }

.bio-body {
  display: grid;
  grid-template-columns: 0.85fr 1.4fr;
  gap: clamp(40px, 6vw, 96px);
  padding: clamp(60px, 10vh, 120px) var(--gutter);
  align-items: start;
  border-bottom: 1px solid var(--ink-line);
}
@media (max-width: 900px) { .bio-body { grid-template-columns: 1fr; } }

.bio-portrait { position: sticky; top: 100px; }
@media (max-width: 900px) { .bio-portrait { position: static; } }
.portrait-frame {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
}
.portrait-bg {
  position: absolute; inset: 0;
  background:
    radial-gradient(55% 65% at 38% 35%, rgba(232, 200, 165, .9), transparent 75%),
    radial-gradient(45% 55% at 65% 80%, rgba(168, 85, 58, .42), transparent 75%),
    linear-gradient(180deg, #e3cca8 0%, #8c5e3f 100%);
  transition: transform 1.4s var(--ease-out);
}
.portrait-frame:hover .portrait-bg { transform: scale(1.04); }
.portrait-frame figcaption {
  position: absolute;
  bottom: 14px; left: 14px;
  color: rgba(246, 241, 230, .88);
}

.bio-prose p {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(19px, 1.4vw, 24px);
  line-height: 1.5;
  color: var(--ink);
  margin: 0 0 22px;
  max-width: 56ch;
}
.bio-prose p em { font-style: italic; }
.bio-prose p:first-child::first-letter {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  float: left;
  font-size: clamp(64px, 8vw, 96px);
  line-height: .85;
  margin: 4px 12px -4px 0;
  color: var(--accent);
}

.cv-link {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: 22px;
  padding: 12px 0;
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--ink-faint);
  transition: gap .35s var(--ease-out), border-color .35s ease;
}
.cv-link:hover { gap: 18px; border-color: var(--ink); }
.cv-arrow {
  font-family: var(--serif);
  font-size: 16px;
  color: var(--accent);
}

/* Trajectory */
.bio-trajectory { background: var(--cream); }
.traj-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(40px, 6vw, 96px);
  padding: 0 var(--gutter) clamp(80px, 12vh, 140px);
}
@media (max-width: 800px) { .traj-grid { grid-template-columns: 1fr; gap: 48px; } }
.traj-col h3 { margin: 0 0 16px; }
.traj-list {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 12px clamp(16px, 2vw, 28px);
  align-items: baseline;
}
.traj-list dt {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink);
  font-weight: 500;
  padding: 12px 0;
  border-top: 1px solid var(--ink-line);
}
.traj-list dd {
  margin: 0;
  font-family: var(--sans);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-soft);
  padding: 12px 0;
  border-top: 1px solid var(--ink-line);
}
.traj-list dd em { font-style: italic; font-family: var(--serif); font-size: 16px; color: var(--ink); }

/* Funds */
.bio-funds {
  border-top: 1px solid var(--ink-line);
  background: var(--cream-warm);
}
.funds-list { padding: 0 var(--gutter) clamp(80px, 12vh, 140px); }
.funds-list li {
  display: grid;
  grid-template-columns: 320px 1fr 100px;
  gap: clamp(20px, 3vw, 40px);
  align-items: baseline;
  padding: clamp(20px, 3vh, 32px) 0;
  border-top: 1px solid var(--ink-line);
  transition: padding .4s var(--ease-out), background .4s ease;
}
.funds-list li:last-child { border-bottom: 1px solid var(--ink-line); }
.funds-list li:hover { padding: clamp(28px, 4vh, 42px) clamp(8px, 1vw, 16px); background: rgba(168, 85, 58, .04); }
.funds-year {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .1em;
  color: var(--ink);
}
.funds-h {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(20px, 2vw, 28px);
  line-height: 1.25;
  color: var(--ink);
}
.funds-h em { font-style: italic; }
.funds-tag {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent);
  text-align: right;
}
@media (max-width: 800px) {
  .funds-list li { grid-template-columns: 1fr; gap: 8px; }
  .funds-tag { text-align: left; }
}

/* Contact */
.contact {
  background: var(--cream);
  border-top: 1px solid var(--ink-line);
}
.contact-h {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(30px, 4.4vw, 60px);
  line-height: 1.04;
  letter-spacing: -.018em;
  color: var(--ink);
  margin: 0;
  max-width: 16ch;
}
.contact-h em { font-style: italic; }

.contact-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  padding: 0 var(--gutter) clamp(40px, 6vh, 60px);
  border-top: 1px solid var(--ink-line);
}
@media (max-width: 800px) { .contact-grid { grid-template-columns: 1fr; } }

.contact-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(32px, 5vh, 56px) clamp(16px, 2vw, 28px);
  border-right: 1px solid var(--ink-line);
  transition: background .4s ease, transform .4s var(--ease-out);
  position: relative;
}
.contact-card:last-child { border-right: 0; }
.contact-card::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 0; background: var(--ink);
  transition: height .45s var(--ease-out);
}
.contact-card:hover { background: rgba(168, 85, 58, .04); }
.contact-card:hover .contact-handle em { color: var(--accent); }
.contact-handle {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(24px, 2.6vw, 36px);
  line-height: 1.05;
  letter-spacing: -.012em;
  color: var(--ink);
  transition: color .35s ease;
}
.contact-card .micro { color: var(--ink-mute); margin-top: auto; }
@media (max-width: 900px) {
  .contact-card { border-right: 0; border-bottom: 1px solid var(--ink-line); }
  .contact-card:last-child { border-bottom: 0; }
}

.contact-sign {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: var(--gutter);
  padding: clamp(40px, 6vh, 80px) var(--gutter) clamp(60px, 10vh, 100px);
  border-top: 1px solid var(--ink-line);
}
.contact-sign-body {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(20px, 2vw, 26px);
  line-height: 1.45;
  color: var(--ink-soft);
  max-width: 48ch;
  margin: 0;
}
@media (max-width: 800px) { .contact-sign { grid-template-columns: 1fr; } }

/* Bio coda */
.bio-coda {
  padding: clamp(80px, 14vh, 200px) var(--gutter);
  border-top: 1px solid var(--ink-line);
  text-align: center;
}
.coda-line {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(80px, 14vw, 224px);
  line-height: .88;
  letter-spacing: -.024em;
  color: var(--ink);
  margin: 0 0 24px;
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 clamp(20px, 3vw, 48px);
}
.coda-line span:nth-child(2) em { color: var(--accent); }

/* ════════════════════════════════════════════════════════════════
   BIO — meta strip, collaborators network
   ════════════════════════════════════════════════════════════════ */
.bio-mast-meta {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(20px, 2vw, 36px);
  margin-top: clamp(40px, 6vh, 80px);
  padding-top: clamp(28px, 4vh, 48px);
  border-top: 1px solid var(--ink-line);
}
.bio-mast-meta > div { display: flex; flex-direction: column; gap: 6px; }
.bio-mast-meta-val {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(18px, 1.6vw, 24px);
  line-height: 1.1;
  color: var(--ink);
}
@media (max-width: 800px) {
  .bio-mast-meta { grid-template-columns: 1fr 1fr; gap: 24px; }
}

.bio-collaborators {
  background: var(--cream-warm);
  border-top: 1px solid var(--ink-line);
  border-bottom: 1px solid var(--ink-line);
}
.collab-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  padding: 0;
  border-top: 1px solid var(--ink-line);
}
@media (max-width: 800px) { .collab-grid { grid-template-columns: 1fr; } }
.collab-col {
  padding: clamp(32px, 4vh, 48px) var(--gutter);
  border-right: 1px solid var(--ink-line);
  border-bottom: 1px solid var(--ink-line);
}
.collab-col:nth-child(2n) { border-right: 0; }
@media (max-width: 800px) { .collab-col { border-right: 0; } }
.collab-col h3 { margin: 0 0 14px; }
.collab-list {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(16px, 1.5vw, 22px);
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0;
}
.collab-list em {
  font-style: italic;
  color: var(--ink);
  font-weight: 400;
}

/* ════════════════════════════════════════════════════════════════
   CONTACT — representation, inquiry form
   ════════════════════════════════════════════════════════════════ */
.contact-rep {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  padding: 0 var(--gutter);
  border-top: 1px solid var(--ink-line);
}
@media (max-width: 800px) { .contact-rep { grid-template-columns: 1fr; } }
.contact-rep-block {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: clamp(40px, 6vh, 72px) clamp(20px, 3vw, 48px) clamp(40px, 6vh, 72px) 0;
  border-right: 1px solid var(--ink-line);
}
.contact-rep-block:last-child { border-right: 0; padding-left: clamp(20px, 3vw, 48px); padding-right: 0; }
@media (max-width: 800px) {
  .contact-rep-block { border-right: 0; border-bottom: 1px solid var(--ink-line); padding: 32px 0; }
  .contact-rep-block:last-child { border-bottom: 0; padding-left: 0; }
}
.contact-rep-h {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(36px, 4.5vw, 64px);
  line-height: 1;
  letter-spacing: -.014em;
  color: var(--ink);
}
.contact-rep-link {
  font-family: var(--mono);
  font-size: clamp(14px, 1.2vw, 18px);
  letter-spacing: .04em;
  color: var(--ink);
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 6px;
  align-self: flex-start;
  transition: border-color .35s ease, color .35s ease;
}
.contact-rep-link:hover { border-color: var(--accent); color: var(--accent); }
.contact-rep-block .micro { color: var(--ink-mute); }

.contact-form-wrap {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: var(--gutter);
  padding: clamp(60px, 9vh, 110px) var(--gutter);
  border-top: 1px solid var(--ink-line);
  background: var(--cream-warm);
}
@media (max-width: 800px) { .contact-form-wrap { grid-template-columns: 1fr; } }
.contact-form-side .kicker { display: block; margin-bottom: 14px; }
.contact-form-h {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(40px, 5vw, 72px);
  line-height: .98;
  letter-spacing: -.014em;
  color: var(--ink);
  margin: 0 0 20px;
}
.contact-form-note {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(16px, 1.4vw, 20px);
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: 28ch;
  margin: 0;
}

.contact-form { display: flex; flex-direction: column; gap: 28px; }
.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px;
}
@media (max-width: 600px) { .form-row { grid-template-columns: 1fr; } }
.contact-form label,
.contact-form .form-block {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.contact-form .kicker { color: var(--ink); }
/* A-M2: persistent field labels — same visual cadence as the old
   kicker spans but with a class that names them as labels so a future
   restyle can target labels without affecting other kickers. */
.contact-form .field-label {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink);
  font-weight: 500;
}
.contact-form input,
.contact-form select,
.contact-form textarea {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--ink-faint);
  padding: 10px 0 12px;
  font-family: var(--serif);
  font-size: clamp(18px, 1.5vw, 22px);
  color: var(--ink);
  width: 100%;
  resize: vertical;
  font-weight: 400;
  letter-spacing: -.005em;
  border-radius: 0;
  transition: border-color .3s ease;
}
.contact-form input::placeholder,
.contact-form textarea::placeholder {
  color: var(--ink-mute);
  font-style: italic;
  font-weight: 400;
}
.contact-form input:focus,
.contact-form select:focus,
.contact-form textarea:focus {
  outline: 0;
  border-bottom-color: var(--ink);
}
.contact-form select {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="8" viewBox="0 0 12 8"><path d="M1 1 L6 6 L11 1" fill="none" stroke="%231a1612" stroke-width="1.4" /></svg>');
  background-repeat: no-repeat;
  background-position: right 4px center;
  padding-right: 24px;
  cursor: pointer;
}

.form-actions {
  display: flex;
  align-items: baseline;
  gap: 28px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.form-submit {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  background: var(--ink);
  color: var(--cream);
  padding: 16px 28px;
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .24em;
  text-transform: uppercase;
  transition: background .35s ease, transform .35s var(--ease-out), gap .35s var(--ease-out);
  font-weight: 500;
}
.form-submit em { font-family: var(--serif); font-style: italic; font-size: 14px; font-weight: 300; letter-spacing: 0; text-transform: none; }
.form-submit:hover {
  background: var(--accent);
  gap: 22px;
}
.form-submit-arr { font-family: var(--serif); font-size: 18px; }
.form-success {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(15px, 1.3vw, 18px);
  color: var(--accent);
  line-height: 1.4;
}
.form-success em { color: var(--ink); font-weight: 500; }

.contact-form.is-sent .form-submit {
  background: var(--accent);
  pointer-events: none;
  opacity: .85;
}
.contact-form.is-sent .form-submit em::before { content: "✓ "; }

/* ════════════════════════════════════════════════════════════════
   PROJECT — case study extensions
   ════════════════════════════════════════════════════════════════ */
.pj-title em { font-style: italic; }
.pj-sub {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(20px, 2vw, 28px);
  color: var(--ink-mute);
  margin-top: 12px;
  letter-spacing: 0;
}

.pj-reel-video .pj-reel-inner { background: #0a0807; }
.pj-reel-iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.pj-reel-video .pj-reel-cap { z-index: 2; }

/* Tone backgrounds for placeholder reels (when no YouTube video) */
.pj-tone-darker {
  background:
    radial-gradient(50% 60% at 30% 40%, rgba(108, 60, 38, .55), transparent 70%),
    linear-gradient(180deg, #2a1b12 0%, #0d0907 100%);
}
.pj-tone-dark {
  background:
    radial-gradient(60% 70% at 70% 30%, rgba(70, 38, 24, .55), transparent 70%),
    linear-gradient(180deg, #3a2418 0%, #100805 100%);
}
.pj-tone-sepia {
  background:
    radial-gradient(60% 60% at 30% 40%, rgba(180, 108, 60, .6), transparent 70%),
    linear-gradient(180deg, #6f4a30 0%, #2a1c12 100%);
}
.pj-tone-ash {
  background:
    radial-gradient(50% 60% at 40% 40%, rgba(180, 175, 165, .5), transparent 75%),
    linear-gradient(180deg, #5a554d 0%, #1f1c18 100%);
}
.pj-tone-warm {
  background:
    radial-gradient(55% 65% at 35% 40%, rgba(214, 160, 110, .6), transparent 75%),
    linear-gradient(180deg, #9c6c46 0%, #3a2418 100%);
}
.pj-tone-bone {
  background:
    radial-gradient(60% 70% at 45% 40%, rgba(232, 220, 195, .6), transparent 75%),
    linear-gradient(180deg, #b8a888 0%, #4a3e2a 100%);
}
.pj-tone-cool {
  background:
    radial-gradient(55% 65% at 35% 40%, rgba(170, 175, 175, .5), transparent 75%),
    linear-gradient(180deg, #58605c 0%, #1c1e1c 100%);
}

/* ════════════════════════════════════════════════════════════════
   PERSONAL WORK — Featured films panel (YouTube embeds)
   ════════════════════════════════════════════════════════════════ */
.work-films {
  padding: clamp(40px, 6vh, 64px) var(--gutter) clamp(40px, 6vh, 80px);
  border-bottom: 1px solid var(--ink-line);
}
.wf-head {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-bottom: clamp(28px, 4vh, 48px);
}
.wf-h {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(32px, 4.4vw, 64px);
  line-height: 1;
  letter-spacing: -.014em;
  color: var(--ink);
  margin: 0;
  max-width: 22ch;
}
.wf-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.6vw, 24px);
}
@media (max-width: 900px) { .wf-grid { grid-template-columns: 1fr; } }

.wf-card {
  display: flex;
  flex-direction: column;
  gap: 18px;
  background: var(--cream);
  text-decoration: none;
  color: inherit;
  transition: transform .35s var(--ease-out);
}
.wf-card:hover { transform: translateY(-3px); }
.wf-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #0a0807;
}
.wf-frame iframe {
  position: absolute;
  top: 50%; left: 50%;
  width: 100%;
  height: 100%;
  border: 0;
  pointer-events: none;
}
.wf-frame-yt iframe { transform: translate(-50%, -50%) scale(1.4); }
.wf-frame-vm iframe { inset: 0; top: auto; left: auto; transform: none; }
.wf-shield {
  /* Transparent layer above the iframe to block YouTube UI hover triggers */
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(180deg, rgba(0,0,0,.05) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 70%, rgba(0,0,0,.18) 100%);
}
.wf-meta {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 4px;
}
.wf-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(24px, 2.6vw, 36px);
  line-height: 1.05;
  letter-spacing: -.012em;
  color: var(--ink);
  margin: 0;
}
.wf-sub {
  font-size: .55em;
  color: var(--ink-mute);
  font-style: italic;
}
.wf-client {
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin: 0;
}

/* ════════════════════════════════════════════════════════════════
   COMMERCIAL — fixed hero + horizontal slider, single viewport
   ════════════════════════════════════════════════════════════════ */
.commercial-stage {
  display: grid;
  grid-template-columns: clamp(320px, 32vw, 440px) 1fr;
  align-items: stretch;
  height: 100dvh;           /* fixed so inner panels can scroll independently;
                               dvh tracks mobile browser chrome (audit #26) */
  padding: clamp(96px, 12vh, 130px) 0 0;
  box-sizing: border-box;
  overflow: hidden;
}
/* Collapse for narrow OR short viewports — landscape phones are >800px wide
   but ~375px tall and clipped the desktop split-pane (audit #26). */
@media (max-width: 800px), (max-height: 520px) {
  .commercial-stage {
    /* minmax(0, 1fr), NOT 1fr. A bare `1fr` track is min-content-floored, so the
       project list (a flex column whose rows carry a 50px/1fr/20px grid) pushed
       the single column out to ~446px inside a 375px viewport and the whole page
       scrolled sideways. minmax(0, …) lets the track shrink past min-content. */
    grid-template-columns: minmax(0, 1fr);
    height: auto;
    overflow: visible;
  }
}

/* ─── Vertical list of projects (left panel) ─── */
.cm-list {
  border-right: 1px solid var(--ink-line);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* Same condition as the .commercial-stage collapse — see .ws-list. */
@media (max-width: 800px), (max-height: 520px) {
  .cm-list { border-right: 0; border-bottom: 1px solid var(--ink-line); }
}
.cm-list-head {
  padding: clamp(18px, 2.4vh, 28px) var(--gutter) clamp(14px, 2vh, 22px);
  border-bottom: 1px solid var(--ink-line);
}
.cm-list-head .kicker {
  font-size: 10.5px;
}
.cm-list-scroll {
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  scrollbar-width: thin;
}
.cm-list-scroll::-webkit-scrollbar { width: 4px; }
.cm-list-scroll::-webkit-scrollbar-track { background: transparent; }
.cm-list-scroll::-webkit-scrollbar-thumb { background: var(--ink-faint); border-radius: 2px; }

.cm-row {
  width: 100%;
  display: grid;
  grid-template-columns: 50px 1fr 20px;
  align-items: baseline;
  gap: 18px;
  padding: clamp(14px, 1.6vh, 20px) var(--gutter);
  border: 0;
  border-left: 2px solid transparent;
  border-bottom: 1px solid var(--ink-line);
  background: transparent;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background .3s ease, border-left-color .3s ease, padding .3s var(--ease-out);
}
.cm-row:hover {
  background: rgba(168, 85, 58, .03);
  /* No padding shift on hover — the 8px nudge was triggering 2-line
     wraps on borderline-long titles like "Rouge Fashion Book". */
}
.cm-row.is-active {
  border-left-color: var(--accent);
  background: var(--cream-warm);
}
.cm-num {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .16em;
  color: var(--ink-mute);
  align-self: center;
}
.cm-name {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(22px, 1.8vw, 30px);
  line-height: 1.05;
  letter-spacing: -.012em;
  color: var(--ink-mute);
  transition: color .3s ease, transform .3s var(--ease-out);
  /* Always single line — no wrapping when hover shifts padding */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.cm-row.is-active .cm-name,
.cm-row:hover .cm-name { color: var(--ink); }
.cm-arr {
  font-family: var(--serif);
  font-style: italic;
  font-size: 16px;
  color: var(--ink-faint);
  align-self: center;
  opacity: 0;
  transition: opacity .3s ease, transform .3s var(--ease-out);
}
.cm-row.is-active .cm-arr,
.cm-row:hover .cm-arr { opacity: 1; transform: translateX(4px); }
.cm-row.is-active .cm-arr { color: var(--accent); }

/* ─── Stage: the hero that swaps when a list item is selected ─── */
.cs {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: clamp(14px, 2vh, 22px);
  padding: clamp(28px, 5vh, 70px) clamp(28px, 4vw, 72px);
  min-height: 0;
  transition: opacity .42s var(--ease-out);
}
.cs.is-swapping { opacity: 0; }

/* ─── Inline project panel ─────────────────────────────────────
   The hero panel has two states:
   - default: simple preview (video + title) — uses .cs centered flex
   - .ip-expanded: full detail — overrides to block + scroll
   Clicking the preview transitions to expanded; clicking the close
   button (←) returns to preview.
   Older .ip-stage class kept for backwards compatibility. */
.ip-stage,
.cs.ip-expanded {
  display: block !important;
  align-items: stretch !important;
  justify-content: flex-start !important;
  padding: 0 !important;
  overflow-y: auto;
  scrollbar-width: thin;
  scroll-behavior: smooth;
}
.ip-stage::-webkit-scrollbar,
.cs.ip-expanded::-webkit-scrollbar { width: 6px; }
.ip-stage::-webkit-scrollbar-track,
.cs.ip-expanded::-webkit-scrollbar-track { background: transparent; }
.ip-stage::-webkit-scrollbar-thumb,
.cs.ip-expanded::-webkit-scrollbar-thumb { background: rgba(26,22,18,.18); border-radius: 3px; }
.route-work.is-active .ip-stage::-webkit-scrollbar-thumb,
.route-work.is-active .cs.ip-expanded::-webkit-scrollbar-thumb { background: rgba(243,237,225,.22); }

/* Hint the preview is clickable — subtle cursor + slight title lift on hover */
.cs:not(.ip-expanded) .cs-link { cursor: pointer; }
.cs:not(.ip-expanded) .cs-link:hover .cs-arrow {
  transform: translateX(3px);
}
.cs-arrow { transition: transform .35s var(--ease-out); }

.inline-project {
  display: flex;
  flex-direction: column;
  gap: clamp(20px, 3vh, 36px);
  padding: clamp(28px, 4vh, 56px) clamp(28px, 4vw, 72px) clamp(56px, 7vh, 96px);
  max-width: 900px;
  margin: 0 auto;
}

.ip-media {
  position: relative;
  width: 100%;
  background: transparent;
  border-radius: 2px;
  overflow: hidden;
}
.ip-media-16x9 { aspect-ratio: 16 / 9; }
/* Vertical hero — give it real presence in the detail view. 560px wide ×
   994px tall still fits comfortably in the desktop panel + scrolls
   naturally on mobile. Centered horizontally. */
.ip-media-9x16 { aspect-ratio: 9 / 16; max-width: 560px; margin-left: auto; margin-right: auto; }
.ip-media-4x5  { aspect-ratio: 4 / 5;  max-width: 640px; margin-left: auto; margin-right: auto; }

/* Local clip videos — no forced aspect ratio. The wrapper centers the
   video and constrains its max dimensions, but the video renders at its
   NATIVE resolution and aspect ratio. No letterboxing, no cropping, no
   upscaling. Whatever the source file is, that's what you see. */
.ip-media-clip {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  background: transparent;
  margin-left: auto;
  margin-right: auto;
  /* overflow: visible so the height tracks the video's natural size */
  overflow: visible;
}
.ip-video-natural {
  /* Override the absolute / 100% / 100% rule below */
  position: relative !important;
  inset: auto !important;
  width: auto !important;
  height: auto !important;
  max-width: 100%;
  max-height: 78vh;
  display: block;
  object-fit: contain;
  background: transparent;
}
.ip-empty {
  aspect-ratio: 16 / 9;
  display: grid; place-items: center;
  background: var(--ink-line);
  color: var(--ink-mute);
  font-family: var(--serif); font-style: italic;
}
.ip-iframe, .ip-video, .ip-still {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
  display: block;
  opacity: 0;
  transition: opacity .35s var(--ease-out);
}
/* Show the entire video frame in detail — no cropping. object-fit:contain
   would letterbox a 16:9 source into the 9:16 wrapper, but our clipVideos
   are filmed vertically so they match the wrapper. Use cover as a safety
   net for off-spec clips. Background fills the gutter cleanly. */
.ip-video { object-fit: contain; background: #0a0807; }
.ip-still { object-fit: cover; }
.ip-iframe.is-ready, .ip-video, .ip-still { opacity: 1; }

/* On dark Personal Work route, invert spinner colors when inside ip-media */
.route-work.is-active .ip-media .media-spinner {
  border-color: rgba(243,237,225,.18);
  border-top-color: rgba(243,237,225,.85);
}

/* Iframe scroll-shield — sits transparent over Vimeo/YouTube iframes so
   that a two-finger trackpad scroll over the media doesn't get swallowed
   by the iframe's content window. The browser scrolls the nearest
   scrollable ancestor (the hero panel) instead. Click dismisses the
   shield so the player UI becomes interactive. No visible label — the
   shield is invisible by design; users discover it through the natural
   click-to-play affordance of the embedded player. */
.ip-media-shield {
  position: absolute;
  inset: 0;
  z-index: 5;
  margin: 0; padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
}

.ip-head { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.ip-head .kicker {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.route-work.is-active .ip-head .kicker { color: rgba(243,237,225,.62); }
.ip-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(36px, 5vw, 64px);
  line-height: .96;
  letter-spacing: -.014em;
  margin: 0;
}
.ip-title em { font-style: italic; }
.ip-sub {
  display: block;
  font-style: italic;
  font-size: clamp(16px, 2vw, 22px);
  color: var(--ink-mute);
  margin-top: 6px;
}
.route-work.is-active .ip-sub { color: rgba(243,237,225,.6); }

.ip-summary {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(17px, 1.7vw, 21px);
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: 62ch;
  margin: 0;
}
.route-work.is-active .ip-summary { color: rgba(243,237,225,.8); }

.ip-credits {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 36px;
  padding-top: clamp(16px, 2vh, 24px);
  border-top: 1px solid var(--ink-line);
}
.route-work.is-active .ip-credits { border-top-color: rgba(243,237,225,.16); }
.ip-credit { display: flex; flex-direction: column; gap: 4px; }
.ip-credit .kicker {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.route-work.is-active .ip-credit .kicker { color: rgba(243,237,225,.58); }
.ip-credit > span:nth-child(2) {
  font-family: var(--body);
  font-size: 14.5px;
  color: var(--ink-soft);
}
.route-work.is-active .ip-credit > span:nth-child(2) { color: rgba(243,237,225,.84); }

.ip-section { display: flex; flex-direction: column; gap: 12px; }
.ip-section .kicker {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.route-work.is-active .ip-section .kicker { color: rgba(243,237,225,.58); }
.ip-fest-list {
  list-style: decimal-leading-zero;
  padding-left: 1.4em;
  margin: 0;
  display: flex; flex-direction: column; gap: 6px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 15.5px;
  color: var(--ink-soft);
}
.route-work.is-active .ip-fest-list { color: rgba(243,237,225,.82); }
.ip-fest-list li::marker {
  font-family: var(--mono);
  font-style: normal;
  font-size: 11px;
  color: var(--ink-mute);
}

.ip-gallery { display: flex; flex-direction: column; gap: 18px; }
.ip-gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;                      /* generous breathing room between thumbs */
}
.ip-gallery-thumb {
  margin: 0;
  aspect-ratio: 4 / 5;            /* default — overridden per project below */
  overflow: hidden;
  background: var(--ink-line);
  border-radius: 2px;
}
/* Thumb aspect matches the hero media for the project. YSL has 9:16 clips,
   so its 24 stills are cropped 9:16 vertical to match. Projects with a
   16:9 reel get 16:9 thumbs. Still-only projects keep 4:5 editorial. */
.ip-gallery-grid[data-aspect="9/16"] .ip-gallery-thumb { aspect-ratio: 9 / 16; }
.ip-gallery-grid[data-aspect="16/9"] .ip-gallery-thumb { aspect-ratio: 16 / 9; }
.ip-gallery-grid[data-aspect="4/5"]  .ip-gallery-thumb { aspect-ratio: 4 / 5; }

/* When thumbs are tall (9:16), drop to 4 per row so they don't dominate. */
.ip-gallery-grid[data-aspect="9/16"] { grid-template-columns: repeat(4, 1fr); }
.ip-gallery-thumb img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .5s var(--ease-out);
}
.ip-gallery-thumb:hover img { transform: scale(1.04); }

/* ── Fragments — masonry wall of loose photos/clips (no titles) ───────────── */
.fragments-wrap {
  padding: clamp(80px, 12vh, 140px) var(--gutter) clamp(48px, 8vh, 96px);
  max-width: 1600px;
  margin: 0 auto;
}
.fragments-head { margin: 0 0 clamp(24px, 4vh, 48px); }
.fragments-title {
  font-family: var(--serif);
  font-weight: 300; font-style: italic;
  font-size: clamp(34px, 6vw, 72px);
  line-height: 1; letter-spacing: -.02em;
  margin: 0; color: var(--ink);
}
.fragments-empty, .fragments-loading { color: var(--ink-mute); }
.fragments-grid { column-count: 3; column-gap: 18px; }
.fragment {
  margin: 0 0 18px;
  break-inside: avoid;
  overflow: hidden;
  background: var(--ink-line);
  border-radius: 2px;
  display: block;
  /* Mobile audit #25: with 265 cells the wall is ~92k px tall — let the engine
     skip layout/paint for far-offscreen tiles. Each cell already carries an
     explicit aspect-ratio (server-probed dimensions), so the intrinsic-size
     hint only covers the pre-src placeholder moment and scrollbar stability. */
  content-visibility: auto;
  contain-intrinsic-size: auto 320px;
}
.fragment img, .fragment video { width: 100%; height: auto; display: block; }
/* Clips have no server-probed dimensions, so reserve a 4/5 placeholder box before
   metadata loads (prevents 0-height tiles + masonry reflow). object-fit:cover keeps
   the cell filled; JS overrides the figure's aspect-ratio with the clip's REAL ratio
   on loadedmetadata, so once loaded it shows uncropped. */
.fragment-clip { aspect-ratio: 4 / 5; }
.fragment-clip video { height: 100%; object-fit: cover; }
.fragment-photo { cursor: none; }
.fragment-photo img { transition: transform .5s var(--ease-out); }
.fragment-photo:hover img { transform: scale(1.03); }
@media (max-width: 1024px) { .fragments-grid { column-count: 2; } }
@media (max-width: 560px) {
  .fragments-grid { column-count: 1; column-gap: 12px; }
  .fragment { margin-bottom: 12px; }
}

/* Scroll hand-off travels WITH the stacked stage (union condition matches the
   stage collapse), not with the width-only typography tweaks below: when the
   stage is height:auto the expanded panel must give its scroll to the route,
   or a short-wide viewport keeps a nested scroll context inside the stack. */
@media (max-width: 800px), (max-height: 520px) {
  .ip-stage,
  .cs.ip-expanded { overflow-y: visible; }   /* parent route scrolls instead */
}

/* Mobile (single column) — gallery stays 2-col (3-col for vertical),
   type scales down */
@media (max-width: 800px) {
  .inline-project { padding: clamp(20px, 3vh, 32px) var(--gutter) clamp(40px, 6vh, 64px); gap: clamp(18px, 3vh, 28px); }
  .ip-credits { grid-template-columns: 1fr; gap: 12px; }
  .ip-gallery-grid { grid-template-columns: repeat(2, 1fr); gap: 14px; }
  .ip-gallery-grid[data-aspect="9/16"] { grid-template-columns: repeat(3, 1fr); gap: 10px; }
  .ip-title { font-size: clamp(32px, 8vw, 48px); }
  .ip-summary { font-size: clamp(16px, 4vw, 19px); }
}

.cs-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(14px, 2vh, 22px);
  text-decoration: none;
  color: inherit;
  width: 100%;
  max-width: 100%;
}
.cs-name {
  display: inline-flex;
  align-items: baseline;
  gap: 14px;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  transition: border-color .35s ease, gap .35s var(--ease-out);
}
.cs-link:hover .cs-name { border-bottom-color: var(--ink); gap: 20px; }
.cs-link:hover .cs-arrow { color: var(--accent); }
.cs-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(28px, 3vw, 44px);
  line-height: 1;
  letter-spacing: -.012em;
  color: var(--ink);
  margin: 0;
}
.cs-arrow {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(20px, 2vw, 28px);
  color: var(--ink-mute);
  transition: color .35s ease;
}

/* Wrapper is sized in PROPORTION to the source media so there are no dark
   letterbox bars at all. Vertical clip → portrait wrapper centered in the
   column. Wide iframe → 16:9 wrapper. The cream page background shows on
   either side when the wrapper is narrower than its column. */
.cs-media-wrap {
  position: relative;
  overflow: hidden;
  background: transparent;
  max-height: 64vh;
  width: auto;
  margin: 0 auto;
}
.cs-media-wrap[data-aspect="16/9"] {
  aspect-ratio: 16 / 9;
  width: 100%;
}
.cs-media-wrap[data-aspect="9/16"] {
  aspect-ratio: 9 / 16;
  height: 64vh;
}
.cs-media-wrap[data-aspect="4/5"] {
  aspect-ratio: 4 / 5;
  height: 64vh;
}
/* 3:4 portrait is the unified preview frame for every project on
   /#commercial + /#work — the "Godmode" look. Sized by height with
   a clamp so it fills the hero panel without overflowing. */
.cs-media-wrap[data-aspect="3/4"] {
  aspect-ratio: 3 / 4;
  height: clamp(360px, 70vh, 640px);
}
/* (kept for any cached HTML during transition — same numbers as 3/4) */
.cs-media-wrap[data-aspect="4/3"] {
  aspect-ratio: 3 / 4;
  height: clamp(360px, 70vh, 640px);
}

/* Phones: every variant above is sized by HEIGHT (64vh / a vh clamp) and derives
   its width from aspect-ratio. On a tall narrow screen that derived width can
   exceed the viewport — a 3/4 frame at the 64vh cap computes to 520 × 0.75 =
   390px against a 375px screen, and 4/5 is worse — so the page scrolled
   sideways. Flip the constraint: let width drive and height follow, which keeps
   each ratio exact instead of capping width alone and squashing the frame. */
@media (max-width: 800px) {
  .cs-media-wrap {
    max-width: 100%;
  }
  .cs-media-wrap[data-aspect="9/16"],
  .cs-media-wrap[data-aspect="4/5"],
  .cs-media-wrap[data-aspect="3/4"],
  .cs-media-wrap[data-aspect="4/3"] {
    width: 100%;
    height: auto;
    max-height: none;
  }
}

/* Trio preview (used by Commercial → YSL Beauté): vertical 9:16 cells
   side-by-side. Default is 3 cells; .cs-trio--4 swaps to 4 cells for the
   sandwich layout (photo · clip · clip · photo). */
.cs-trio {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  height: 64vh;
  margin: 0 auto;
}
.cs-trio.cs-trio--4 { grid-template-columns: repeat(4, 1fr); }
.cs-trio-cell {
  position: relative;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  background: var(--cream-deep);
  height: 100%;
}
.cs-trio-cell video,
.cs-trio-cell img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
@media (max-width: 720px) {
  .cs-trio { gap: 6px; height: 48vh; }
  .cs-trio.cs-trio--4 { grid-template-columns: repeat(4, 1fr); }
}

/* Iframes fill their wrapper at the source's native aspect. The wrapper
   itself adapts to the source (data-aspect="16/9" for Vimeo/YouTube,
   "9/16" only for local portrait clip files), so the iframe doesn't
   need to be scaled to fit. A tiny zoom (1.08) clips YouTube's
   bottom-right "Watch on YouTube" badge without cropping subjects. */
iframe.cs-media-el {
  transform: scale(1.08);
  transform-origin: center;
}
/* When the wrapper is 9:16 but the iframe is a 16:9 embed (rare —
   only if a clip's only source is a Vimeo/YouTube), bump the scale
   slightly more so the wider video fills the narrower box. */
.cs-media-wrap[data-aspect="9/16"] iframe.cs-media-el {
  transform: scale(1.85);
}
/* 3:4 portrait wrapper holding a 16:9 source: give the iframe its natural
   16:9 aspect at full height, centered horizontally, and let the wrapper's
   overflow:hidden crop the sides. Need max-width: none to override the
   global `iframe { max-width: 100% }` reset that would otherwise clamp
   the iframe to the wrapper's narrower width and prevent it from
   spilling outward. */
.cs-media-wrap[data-aspect="3/4"] iframe.cs-media-el,
.cs-media-wrap[data-aspect="4/3"] iframe.cs-media-el {
  position: absolute;
  inset: auto;            /* clear the base rule's inset:0 first… */
  top: 0;                 /* …then re-apply only the values we want */
  left: 50%;
  right: auto;
  bottom: auto;
  height: 100%;
  width: auto;
  max-width: none;
  aspect-ratio: 16 / 9;
  transform: translateX(-50%);
}

/* Native media fills the 9:16 wrapper, cropping sides for 16:9 sources
   and showing fully for already-9:16 clipVideos */
video.cs-media-el,
img.cs-media-el {
  object-fit: cover;
}

/* (legacy flank classes — kept inert in case any cached HTML uses them) */
.cs-media-wrap.is-flanked .cs-flank,
.cs-flank-l, .cs-flank-r { display: none; }
.cs-media-wrap.is-flanked .cs-flank--retired {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50%;
  margin: 0;
  overflow: hidden;
  z-index: 0;
  pointer-events: none;
}
/* Soft cream fade at the OUTER edge of each flank — the photos dissolve into
   the page background instead of cutting off hard. Inner edges stay solid where
   they meet the centered video. */
.cs-media-wrap.is-flanked .cs-flank-l {
  left: 0;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.4) 25%, #000 75%);
          mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.4) 25%, #000 75%);
}
.cs-media-wrap.is-flanked .cs-flank-r {
  right: 0;
  -webkit-mask-image: linear-gradient(to left, transparent 0%, rgba(0,0,0,.4) 25%, #000 75%);
          mask-image: linear-gradient(to left, transparent 0%, rgba(0,0,0,.4) 25%, #000 75%);
}
.cs-media-wrap.is-flanked .cs-flank img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.85;
  filter: blur(6px) saturate(1.15);
  transform: scale(1.15);
  animation: csFlankDrift 22s var(--ease-in-out) infinite alternate;
}
.cs-media-wrap.is-flanked .cs-flank-r img {
  animation-delay: -11s;     /* offset so the two sides never move in sync */
}
@keyframes csFlankDrift {
  0%   { transform: scale(1.15) translate(-1.5%,  1%); }
  100% { transform: scale(1.18) translate( 1.5%, -1%); }
}

/* Center the actual playing video over the flanked backdrop. We override
   object-fit: contain so the video remains its natural aspect (vertical),
   sized to the height of the box. */
.cs-media-wrap.is-flanked video.cs-media-el,
.cs-media-wrap.is-flanked img.cs-media-el {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: auto;
  height: 100%;
  max-width: 100%;
  object-fit: contain;
}

/* Triptych: side stills frame a centered vertical video.
   Center keeps a 9/16 aspect (matching IG vertical clips). Sides fill
   whatever remains in the 16/9 outer frame, eliminating the dead
   letterbox space and turning it into composition. */
.cs-media-wrap.is-triptych {
  background: transparent;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
  overflow: hidden;
}
.cs-side {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--cream-deep);
}
.cs-side img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.6s var(--ease-out);
}
.cs-media-wrap.is-triptych:hover .cs-side-left  img { transform: scale(1.02); }
.cs-media-wrap.is-triptych:hover .cs-side-right img { transform: scale(1.02); }
.cs-center {
  position: relative;
  height: 100%;
  aspect-ratio: 9 / 16;    /* portrait — matches typical IG clip */
  background: #0a0807;
  overflow: hidden;
}
/* Stills-only triptych: relax center aspect for editorial photos */
.is-still-triptych .cs-center {
  aspect-ratio: 4 / 5;
}
.is-still-triptych .cs-center .cs-media-el {
  /* stills inherit object-fit:cover from .cs-center .cs-media-el */
}

/* ─── Per-project tone backdrops ─── */
.cs-tone-warm   { background: radial-gradient(60% 70% at 35% 40%, rgba(168, 85, 58, .55), transparent 70%), linear-gradient(180deg, #2a1810 0%, #0a0807 100%); }
.cs-tone-darker { background: radial-gradient(60% 70% at 35% 40%, rgba(86, 62, 42, .35), transparent 75%),  linear-gradient(180deg, #1e1a16 0%, #0a0807 100%); }
.cs-tone-dark   { background: linear-gradient(180deg, #1c1814 0%, #0a0807 100%); }
.cs-tone-sepia  { background: radial-gradient(60% 70% at 40% 40%, rgba(180, 108, 60, .35), transparent 70%), linear-gradient(180deg, #2c1f15 0%, #0a0807 100%); }
.cs-tone-ash    { background: linear-gradient(180deg, #44403a 0%, #1f1c18 100%); }
.cs-tone-bone   { background: linear-gradient(180deg, #c9bea0 0%, #6e604a 100%); }
.cs-tone-cool   { background: linear-gradient(180deg, #2a2d2f 0%, #0a0a0c 100%); }

/* ─── Stack-left: 2 stills stacked left | video | 1 still right ─── */
.is-stack-l {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
}
.cs-stack {
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: 0;
  overflow: hidden;
}
.cs-stack-cell {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--cream-deep);
}
.cs-stack-cell img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 1.6s var(--ease-out);
}
.is-stack-l:hover .cs-stack-cell img,
.is-stack-r:hover .cs-stack-cell img { transform: scale(1.02); }

/* ─── Stack-right: 1 still left | video | 2 stills stacked right ─── */
.is-stack-r {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
}

/* ─── Bleed: full-bleed backdrop still + video floating centered ─── */
.is-bleed {
  position: relative;
  display: block;
}
.cs-bleed-bg {
  position: absolute;
  inset: 0;
  margin: 0;
  overflow: hidden;
}
.cs-bleed-bg img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  filter: brightness(.55) saturate(1.05);
  transform: scale(1.04);
  transition: transform 12s linear, filter .8s ease;
}
.is-bleed:hover .cs-bleed-bg img { transform: scale(1.10); }
.cs-bleed-scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(50% 70% at 50% 50%, rgba(0,0,0,.15), rgba(0,0,0,.55) 100%),
    linear-gradient(180deg, rgba(0,0,0,.2) 0%, rgba(0,0,0,.5) 100%);
  z-index: 1;
}
.cs-bleed-center {
  position: relative;
  z-index: 2;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.cs-bleed-center .cs-media-el {
  position: relative;
  inset: auto;
  height: 100%;
  width: auto;
  aspect-ratio: 9 / 16;
  max-height: 100%;
  max-width: 100%;
  object-fit: cover;
  box-shadow: 0 30px 80px rgba(0,0,0,.5);
  opacity: 0;
  transition: opacity .55s var(--ease-out) .05s;
}
.cs-bleed-center .cs-media-el.is-ready { opacity: 1; }
.cs-center .cs-media-el {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;        /* center is now matched to source aspect */
  border: 0;
  opacity: 0;
  transition: opacity .55s var(--ease-out) .05s;
}
.cs-center .cs-media-el.is-ready { opacity: 1; }
.cs-center .cs-loader {
  /* re-anchor the loader inside the center column */
  bottom: 14px;
  left: 50%;
}

/* Poster image sits behind the media element. Visible only while the
   iframe/video is still loading — fades out as soon as the media is ready,
   so it doesn't bleed through the letterbox bars of vertical videos. */
.cs-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  opacity: 1;
  transition: opacity .55s var(--ease-out);
  filter: brightness(.92) saturate(1.05);
}
.cs-media-wrap:has(.cs-media-el.is-ready) .cs-poster {
  opacity: 0;
}
.cs-poster-empty {
  background:
    radial-gradient(50% 60% at 35% 40%, rgba(212, 175, 140, .35), transparent 75%),
    linear-gradient(180deg, #2a2018 0%, #0a0807 100%);
}

/* Subtle pulse while loading — visible behind/around the poster */
/* Circular spinner — shown while media is loading inside .cs-media-wrap
   and .pj-reel-inner. Reused via .media-spinner so other contexts can
   reuse it. */
.cs-loader,
.media-spinner {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 2px solid rgba(246, 241, 230, .18);
  border-top-color: rgba(246, 241, 230, .85);
  z-index: 3;
  pointer-events: none;
  animation: mediaSpinnerSpin 0.9s linear infinite;
  opacity: 0;
  transition: opacity .25s ease;
}
.cs-media-wrap:has(.cs-media-el:not(.is-ready)) .cs-loader,
.pj-reel:has(.pj-reel-iframe.is-loading) .media-spinner,
.pj-reel:has(.pj-reel-iframe:not(.is-ready)) .media-spinner {
  opacity: 1;
}
@keyframes mediaSpinnerSpin {
  to { transform: translate(-50%, -50%) rotate(360deg); }
}
/* On cream backgrounds (default Commercial), invert the spinner colors */
.commercial-stage .cs-loader {
  border-color: rgba(26, 22, 18, .18);
  border-top-color: rgba(26, 22, 18, .85);
}
/* csLoaderPulse keyframes removed — replaced by mediaSpinnerSpin above */

/* The actual playing media — starts invisible, fades in when ready */
.cs-media-el {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  z-index: 1;
  opacity: 0;
  transition: opacity .55s var(--ease-out) .05s;
}
.cs-media-el.is-ready {
  opacity: 1;
}
/* Iframes can't object-fit — Vimeo / YouTube handle their own internal letterbox */
iframe.cs-media-el {
  /* nothing — fills the box, service handles letterbox */
}
/* Native video / image: contain so heads aren't cropped on vertical clips */
video.cs-media-el,
img.cs-media-el {
  object-fit: contain;
}
.cs-media-wrap .cs-yt {
  /* push YouTube UI off-frame */
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) scale(1.4);
  inset: auto;
  pointer-events: none;
}
.cs-shield {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: transparent;
}
.cs-empty {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background:
    radial-gradient(60% 70% at 40% 40%, rgba(212, 175, 140, .35), transparent 75%),
    var(--cream-warm);
}
.cs-empty span {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(24px, 3vw, 48px);
  color: var(--ink-mute);
}

.cs-meta {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.cs-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(32px, 4.2vw, 68px);
  line-height: 1;
  letter-spacing: -.014em;
  color: var(--ink);
  margin: 0;
}
.cs-sub {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: .55em;
  color: var(--ink-mute);
  margin-left: 4px;
  letter-spacing: 0;
}
.cs-client {
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-mute);
  line-height: 1.6;
  margin: 0;
  max-width: 36ch;
}
.cs-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  align-self: flex-start;
  margin-top: 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--ink-faint);
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink);
  transition: border-color .35s ease, gap .35s var(--ease-out);
}
.cs-cta:hover { border-color: var(--ink); gap: 16px; }
.cs-cta span:last-child { font-family: var(--serif); font-size: 14px; }

/* ─── Slider rail at the bottom ─── */
.cc-nav {
  position: relative;
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  gap: 8px;
  padding: clamp(14px, 2.4vh, 28px) var(--gutter) clamp(28px, 4vh, 48px);
  border-top: 1px solid var(--ink-line);
}
.cc-arrow {
  background: transparent;
  border: 1px solid var(--ink-line);
  width: 44px; height: 44px;
  font: 16px/1 serif;
  color: var(--ink);
  cursor: pointer;
  transition: background .25s ease, border-color .25s ease, color .25s ease;
}
.cc-arrow:hover { background: var(--ink); color: var(--cream); border-color: var(--ink); }
.cc-arrow-prev { justify-self: end; }
.cc-arrow-next { justify-self: start; }

.cc-slider {
  display: flex;
  align-items: center;
  gap: 4px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding: 12px 0;
}
.cc-slider::-webkit-scrollbar { display: none; }

/* Text-only cards — italic brand names, dot separators between */
.cc-card {
  flex: 0 0 auto;
  scroll-snap-align: center;
  background: transparent;
  border: 0;
  padding: 8px 6px;
  font: inherit;
  cursor: pointer;
  color: inherit;
  opacity: .42;
  transition: opacity .35s ease, transform .35s var(--ease-out);
  white-space: nowrap;
}
.cc-card:hover { opacity: .8; }
.cc-card.is-active {
  opacity: 1;
}
.cc-name {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(28px, 3.4vw, 56px);
  line-height: 1;
  letter-spacing: -.012em;
  color: var(--ink);
  position: relative;
  display: inline-block;
  padding-bottom: 6px;
}
.cc-card.is-active .cc-name::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--accent);
}
.cc-sep {
  font-family: var(--mono);
  font-size: clamp(20px, 2vw, 32px);
  color: var(--ink-faint);
  align-self: center;
  padding: 0 4px;
  user-select: none;
}

.cc-progress {
  position: absolute;
  bottom: 0;
  left: var(--gutter);
  right: var(--gutter);
  height: 1px;
  background: var(--ink-line);
}
.cc-progress-bar {
  display: block;
  height: 100%;
  width: 0;
  background: var(--ink);
  transition: width .4s var(--ease-out);
}

@media (max-width: 600px) {
  .cc-arrow { display: none; }
  .cc-nav { grid-template-columns: 1fr; padding-bottom: 20px; }
}

/* Hide all the OLD ticker styles cleanly */
.ct-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  grid-auto-flow: dense;
  gap: 0;
  padding: 0 var(--gutter);
  list-style: none;
  margin: 0;
  border-top: 1px solid var(--ink-line);
}
.ct-row {
  display: contents;
}

/* Card */
.ct-head {
  display: grid;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 1fr auto;
  gap: 14px;
  padding: clamp(24px, 3.4vh, 44px) clamp(20px, 2vw, 28px);
  border-right: 1px solid var(--ink-line);
  border-bottom: 1px solid var(--ink-line);
  background: transparent;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
  min-height: clamp(140px, 18vh, 200px);
  transition: background .35s ease;
}
.ct-head:hover { background: rgba(168, 85, 58, .035); }
.ct-row.is-open .ct-head { background: var(--cream-warm); }

.ct-meta {
  grid-column: 1 / -1;
  grid-row: 1;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.ct-title {
  grid-column: 1;
  grid-row: 2;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(26px, 2.4vw, 38px);
  line-height: 1.04;
  letter-spacing: -.012em;
  color: var(--ink);
  align-self: start;
  transition: transform .4s var(--ease-out);
}
.ct-head:hover .ct-title { transform: translateX(4px); }
.ct-sub {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: .55em;
  color: var(--ink-mute);
  margin-left: 4px;
  letter-spacing: 0;
}
.ct-client {
  grid-column: 1 / -1;
  grid-row: 3;
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
  line-height: 1.5;
}
.ct-arr {
  grid-column: 2;
  grid-row: 2;
  align-self: start;
  font-family: var(--mono);
  font-size: 20px;
  font-weight: 300;
  color: var(--ink-mute);
  transition: transform .35s var(--ease-out), color .35s ease;
}
.ct-row.is-open .ct-arr { transform: rotate(45deg); color: var(--accent); }

/* Removes right border on last column at each viewport */
@media (min-width: 900px) {
  .ct-list { grid-template-columns: repeat(3, 1fr); }
  .ct-head:nth-child(3n) { border-right: 0; }
}
@media (min-width: 600px) and (max-width: 899px) {
  .ct-list { grid-template-columns: repeat(2, 1fr); }
  .ct-head:nth-child(2n) { border-right: 0; }
}
@media (max-width: 599px) {
  .ct-list { grid-template-columns: 1fr; }
  .ct-head { border-right: 0; }
}

/* Expandable panel — spans full grid width below the row of cards */
.ct-panel[hidden] { display: none !important; }
.ct-panel {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: clamp(28px, 4vw, 56px);
  align-items: start;
  padding: clamp(28px, 4vh, 56px) clamp(20px, 2vw, 32px);
  background: var(--cream-warm);
  border-bottom: 1px solid var(--ink-line);
  opacity: 0;
  animation: ctPanelIn .45s var(--ease-out) forwards;
}
@keyframes ctPanelIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (max-width: 800px) {
  .ct-panel { grid-template-columns: 1fr; gap: 20px; padding: 24px 16px; }
}
@media (max-width: 800px) {
  .ct-panel { grid-template-columns: 1fr; gap: 18px; }
}

.ct-media {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--cream-deep);
}
.ct-media iframe,
.ct-media video,
.ct-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
}
.ct-media-yt iframe {
  /* push YouTube UI off-frame */
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) scale(1.4);
  inset: auto;
  pointer-events: none;
}
.ct-media-vm iframe { pointer-events: none; }
.ct-shield {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: transparent;
}
.ct-media-empty {
  display: flex; align-items: center; justify-content: center;
  background:
    radial-gradient(60% 70% at 40% 40%, rgba(212, 175, 140, .35), transparent 75%),
    var(--cream-warm);
}
.ct-media-empty span {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(20px, 2.4vw, 36px);
  color: var(--ink-mute);
}

.ct-text {
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding-top: 8px;
}
.ct-summary {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(15px, 1.2vw, 18px);
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0;
}
.ct-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  align-self: flex-start;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--ink-faint);
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink);
  transition: border-color .35s ease, gap .35s var(--ease-out);
}
.ct-cta:hover { border-color: var(--ink); gap: 16px; }
.ct-cta span:last-child { font-family: var(--serif); font-size: 14px; }

/* ════════════════════════════════════════════════════════════════
   PROJECT — stills & clips gallery
   ════════════════════════════════════════════════════════════════ */
.pj-gallery {
  padding: 0 var(--gutter) clamp(60px, 10vh, 100px);
  border-top: 1px solid var(--ink-line);
  padding-top: clamp(40px, 6vh, 64px);
}
.pj-gallery-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding-bottom: clamp(20px, 3vh, 36px);
}
.pj-gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: clamp(10px, 1.2vw, 18px);
}
.pj-gallery-item {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--cream-warm);
  cursor: none;
}
.pj-gallery-item img,
.pj-gallery-item video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.2s var(--ease-out);
}
.pj-gallery-item:hover img,
.pj-gallery-item:hover video { transform: scale(1.03); }
.pj-gallery-item figcaption {
  position: absolute;
  bottom: 10px; left: 10px;
  background: rgba(250, 247, 241, .92);
  padding: 4px 8px;
  z-index: 2;
}
.pj-gallery-video::after {
  content: '▶';
  position: absolute;
  top: 12px; right: 12px;
  color: rgba(250, 247, 241, .9);
  background: rgba(0, 0, 0, .55);
  width: 28px; height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  pointer-events: none;
  z-index: 2;
}
@media (max-width: 600px) {
  .pj-gallery-grid { grid-template-columns: repeat(2, 1fr); }
}

.pj-credits-flat {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px clamp(24px, 3vw, 48px);
  margin-top: 14px;
}
@media (max-width: 600px) { .pj-credits-flat { grid-template-columns: 1fr; } }
.pj-credit-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 0;
  border-top: 1px solid var(--ink-line);
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(18px, 1.5vw, 22px);
  color: var(--ink);
  line-height: 1.35;
}

/* ════════════════════════════════════════════════════════════════
   HOME image grid (editorial campaigns)
   ════════════════════════════════════════════════════════════════ */
.img-grid-section {
  padding: clamp(72px, 12vh, 140px) var(--gutter) clamp(80px, 12vh, 140px);
  background: var(--cream);
  border-top: 1px solid var(--ink-line);
}
.img-grid-head {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding-bottom: clamp(36px, 5vh, 60px);
  border-bottom: 1px solid var(--ink-line);
  margin-bottom: clamp(36px, 5vh, 60px);
}
.img-grid-h {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(40px, 5.4vw, 80px);
  line-height: 1;
  letter-spacing: -.014em;
  color: var(--ink);
  margin: 0;
  max-width: 18ch;
}
.img-grid-h em { font-style: italic; }

.img-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: 80px;
  gap: clamp(12px, 1.4vw, 22px);
}
@media (max-width: 800px) {
  .img-grid { grid-template-columns: repeat(6, 1fr); grid-auto-rows: 60px; }
}
.ig-cell {
  position: relative;
  margin: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.ig-frame {
  position: relative;
  flex: 1;
  overflow: hidden;
  background:
    radial-gradient(55% 65% at 35% 35%, rgba(212, 175, 140, .55), transparent 70%),
    linear-gradient(180deg, var(--cream-deep) 0%, var(--cream-warm) 100%);
}
.ig-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.3s var(--ease-out), filter .8s ease;
}
.ig-cell:hover .ig-frame img { transform: scale(1.04); }
.ig-cell.ig-empty .ig-frame {
  background:
    radial-gradient(55% 65% at 35% 35%, rgba(212, 175, 140, .55), transparent 70%),
    linear-gradient(180deg, var(--cream-deep) 0%, var(--cream-warm) 100%);
}
.ig-cell.ig-empty .ig-frame::before {
  content: "Image · pending";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(26, 22, 18, .42);
}
.ig-cell figcaption {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 0 0;
  border-top: 1px solid var(--ink-line);
  margin-top: 10px;
}
.ig-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(15px, 1.2vw, 19px);
  color: var(--ink);
  letter-spacing: -.005em;
}
.ig-caption {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* Mosaic pattern — each cell spans a curated col/row range */
.ig-cell-1 { grid-column: span 7; grid-row: span 5; }
.ig-cell-2 { grid-column: span 5; grid-row: span 5; }
.ig-cell-3 { grid-column: span 4; grid-row: span 6; }
.ig-cell-4 { grid-column: span 4; grid-row: span 4; }
.ig-cell-5 { grid-column: span 4; grid-row: span 5; }
.ig-cell-6 { grid-column: span 6; grid-row: span 4; }
@media (max-width: 800px) {
  .ig-cell-1, .ig-cell-2, .ig-cell-3, .ig-cell-4, .ig-cell-5, .ig-cell-6 {
    grid-column: span 6; grid-row: span 5;
  }
  .img-grid > .ig-cell:nth-child(odd) { grid-row: span 4; }
}

.img-grid-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  padding-top: clamp(36px, 5vh, 56px);
  margin-top: clamp(36px, 5vh, 56px);
  border-top: 1px solid var(--ink-line);
}
.img-grid-foot .ghost-link { color: var(--ink); }

/* ════════════════════════════════════════════════════════════════
   BRAND BAR (under bio intro)
   ════════════════════════════════════════════════════════════════ */
.brand-bar {
  background: var(--cream);
  border-top: 1px solid var(--ink-line);
  border-bottom: 1px solid var(--ink-line);
  padding: clamp(28px, 4vh, 48px) 0;
}
.brand-track {
  animation: marqueeScroll 60s linear infinite;
}
.bm-item {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(28px, 3.4vw, 56px);
  line-height: 1.1;
  letter-spacing: -.012em;
  color: var(--ink);
  padding: 0 .25em;
  white-space: nowrap;
}
.bm-dot {
  font-family: var(--mono);
  font-size: clamp(22px, 2.4vw, 40px);
  color: var(--accent);
  padding: 0 .2em;
  vertical-align: middle;
}

/* ════════════════════════════════════════════════════════════════
   BIO — new section layout (replaces old .bio-trajectory / .bio-funds)
   ════════════════════════════════════════════════════════════════ */
.bio-intro {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(20px, 2vw, 28px);
  line-height: 1.4;
  color: var(--ink);
  margin: 0;
  max-width: 56ch;
}

.bio-section {
  padding: clamp(60px, 9vh, 100px) var(--gutter);
  border-top: 1px solid var(--ink-line);
}
.bio-section-warm { background: var(--cream-warm); }

.bio-section .section-label {
  display: grid;
  grid-template-columns: 1fr;
  border-top: 0;
  padding: 0 0 clamp(28px, 4vh, 48px);
  gap: 14px;
}
.section-h-line {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(36px, 5vw, 72px);
  line-height: 1.02;
  letter-spacing: -.014em;
  color: var(--ink);
  margin: 0;
  max-width: 100%;
}
.section-h-line em { font-style: italic; }
/* Forced single-line variant for the "must render on one line" headings */
.section-h-line.one-line {
  white-space: nowrap;
  font-size: clamp(28px, 4vw, 60px);
}
@media (max-width: 800px) {
  .section-h-line.one-line { white-space: normal; }
}

.bio-h {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin: 28px 0 14px;
  font-weight: 500;
}

.bio-prose-wide {
  max-width: 72ch;
}
.bio-prose-wide p {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(17px, 1.3vw, 22px);
  line-height: 1.55;
  color: var(--ink);
  margin: 0 0 18px;
}
.bio-prose-wide p em { font-style: italic; }

/* Movement Coaching credits list */
.bio-credit-list {
  display: grid;
  gap: 0;
}
.bc-row {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: clamp(20px, 3vw, 48px);
  padding: clamp(18px, 2.4vh, 28px) 0;
  border-top: 1px solid var(--ink-line);
  align-items: baseline;
}
.bc-row:last-child { border-bottom: 1px solid var(--ink-line); }
.bc-name {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(20px, 2.2vw, 30px);
  color: var(--ink);
  letter-spacing: -.008em;
}
.bc-meta {
  font-family: var(--sans);
  font-size: clamp(13px, 1.05vw, 16px);
  line-height: 1.5;
  color: var(--ink-soft);
}
.bc-meta em {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.08em;
  color: var(--ink);
}
@media (max-width: 700px) {
  .bc-row { grid-template-columns: 1fr; gap: 4px; }
}

/* Short films list (Movement Director, short films) */
.film-list { display: grid; gap: 0; }
.film-list li {
  display: grid;
  grid-template-columns: 1fr 2fr auto;
  gap: clamp(16px, 2vw, 32px);
  padding: clamp(18px, 2.4vh, 28px) 0;
  border-top: 1px solid var(--ink-line);
  align-items: baseline;
}
.film-list li:last-child { border-bottom: 1px solid var(--ink-line); }
.film-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(22px, 2.4vw, 34px);
  color: var(--ink);
}
.film-meta {
  font-family: var(--sans);
  font-size: clamp(13px, 1.05vw, 16px);
  color: var(--ink-soft);
  line-height: 1.5;
}
.film-year {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
  letter-spacing: .08em;
}
@media (max-width: 700px) {
  .film-list li { grid-template-columns: 1fr; gap: 4px; }
  .film-year { font-size: 11px; }
}

/* Trajectory list (year/body) */
.trajectory-list { display: grid; gap: 0; }
.trajectory-list li {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: clamp(20px, 3vw, 48px);
  padding: clamp(18px, 2.4vh, 28px) 0;
  border-top: 1px solid var(--ink-line);
  align-items: baseline;
}
.trajectory-list li:last-child { border-bottom: 1px solid var(--ink-line); }
.tj-year {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .06em;
  color: var(--ink);
}
.tj-body {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(16px, 1.3vw, 20px);
  line-height: 1.5;
  color: var(--ink-soft);
}
.tj-body em { font-style: italic; color: var(--ink); }
@media (max-width: 700px) {
  .trajectory-list li { grid-template-columns: 1fr; gap: 4px; }
}

/* Portrait img variant — uses real image when available, falls back to gradient */
.portrait-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.4s var(--ease-out);
}
.portrait-frame:hover .portrait-img { transform: scale(1.04); }

/* ════════════════════════════════════════════════════════════════
   CONTACT (own route)
   ════════════════════════════════════════════════════════════════ */
.contact-mast {
  padding: clamp(56px, 9vh, 96px) var(--gutter) clamp(24px, 4vh, 48px);
  border-bottom: 1px solid var(--ink-line);
}
.contact-mast .kicker { display: block; margin-bottom: clamp(18px, 3vh, 36px); }

/* (the .nav-mail block lived here — retired 2026-08-18 with the element:
   the nav now shows IG/X icons instead of repeating the Contact email) */

/* Client login — quiet right-aligned button, distinct from the email */
.nav-client {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  padding: 6px 12px;
  border: 1px solid var(--ink-line);
  border-radius: 999px;
  transition: background .25s var(--ease-out), color .25s var(--ease-out), border-color .25s var(--ease-out);
}
.nav-client:hover {
  background: var(--ink);
  color: var(--cream);
  border-color: var(--ink);
}
.nav-client span { font-size: 12px; line-height: 1; }
.nav.is-dark .nav-client {
  color: var(--cream);
  border-color: rgba(246, 241, 230, .32);
}
.nav.is-dark .nav-client:hover {
  background: var(--cream);
  color: var(--ink);
  border-color: var(--cream);
}

/* Admin sign-in — semi-hidden. Just a 6px dot in the corner that expands
   to reveal the word "Admin" on hover. Discoverable for Dalel, invisible
   noise for visitors. */
.nav-admin {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-mute);
  padding: 4px 0;
  max-width: 14px;        /* collapsed: shows only the dot */
  overflow: hidden;
  white-space: nowrap;
  opacity: .55;
  transition: max-width .35s var(--ease-out), opacity .25s ease, color .25s ease;
}
.nav-admin:hover,
.nav-admin:focus-visible {
  max-width: 80px;        /* expanded: shows the word "Admin" */
  opacity: 1;
  color: var(--ink);
}
.nav-admin-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 6px;
}
.nav-admin-text { opacity: 0; transition: opacity .25s ease .1s; }
.nav-admin:hover .nav-admin-text,
.nav-admin:focus-visible .nav-admin-text { opacity: 1; }
.nav.is-dark .nav-admin { color: rgba(246, 241, 230, .45); }
.nav.is-dark .nav-admin:hover,
.nav.is-dark .nav-admin:focus-visible { color: var(--cream); }
@media (max-width: 900px) { .nav-admin { display: none; } }


/* Suppress old route-bio embedded contact styles within new contact route */
.route-contact .contact-rep,
.route-contact .contact-form-wrap,
.route-contact .contact-grid { border-top: 1px solid var(--ink-line); }
.route-contact .contact-grid { border-bottom: 1px solid var(--ink-line); }

/* Masthead removed + "compact the whole page" — scoped overrides that tighten the
   contact route so it sits close to one screen. Base rules unchanged; reversible. */
.route-contact .contact-rep {
  border-top: 0;
  padding-top: clamp(76px, 9vh, 100px); /* clears the fixed nav (~69px) + a small gap */
}
.route-contact .contact-rep-block {
  padding-top: clamp(18px, 2.5vh, 28px);
  padding-bottom: clamp(18px, 2.5vh, 28px);
  gap: 8px;
}
.route-contact .contact-rep-h { font-size: clamp(26px, 3vw, 42px); }
.route-contact .contact-form-wrap {
  padding-top: clamp(24px, 4vh, 44px);
  padding-bottom: clamp(24px, 4vh, 44px);
}
.route-contact .contact-form-h { font-size: clamp(26px, 3.2vw, 44px); margin-bottom: 10px; }
.route-contact .contact-form { gap: 16px; }
.route-contact .form-row { gap: 18px; }
.route-contact .contact-form input,
.route-contact .contact-form select,
.route-contact .contact-form textarea { padding-top: 7px; padding-bottom: 9px; }
.route-contact .contact-grid {
  grid-template-columns: repeat(4, 1fr); /* 2 IG + Twitter + CV in one row */
  padding-bottom: clamp(20px, 3vh, 36px);
}
.route-contact .contact-card {
  padding-top: clamp(18px, 3vh, 30px);
  padding-bottom: clamp(18px, 3vh, 30px);
}
.route-contact .contact-handle { font-size: clamp(18px, 1.9vw, 26px); }
.route-contact .foot { padding-top: 14px; padding-bottom: 14px; }

/* ── Contact polish pass (4-lens design review): tighten the form, balance the
   lone heading, sharpen interaction states. Scoped to .route-contact; reversible. ── */

/* Message box: cap height so it stops being a tall empty void (resize still works). */
.route-contact .contact-form textarea { min-height: 3.5em; max-height: 7em; line-height: 1.45; }

/* Pull the lone "Contact" heading + the form to the panel edges, cap the form to an
   editorial measure, and centre the heading against the form's height (fills the void). */
.route-contact .contact-form-wrap {
  grid-template-columns: minmax(200px, 240px) minmax(0, 580px);
  justify-content: space-between;
  align-items: center;
}
.route-contact .contact-form { max-width: 580px; }

/* Type hierarchy: make "Contact" the apex; step the rep names down a touch. */
.route-contact .contact-form-h { font-size: clamp(30px, 3.4vw, 46px); letter-spacing: -.02em; }
.route-contact .contact-rep-h  { font-size: clamp(24px, 2.6vw, 38px); }

/* Unify the field labels onto the page's mono "small-caps" language (was sans, over-tracked). */
.route-contact .contact-form .field-label {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .14em;
  color: var(--ink-mute);
  font-weight: 400;
}

/* Bring the brand terracotta into the form's focus state + tie the active field to its label. */
.route-contact .contact-form input:focus,
.route-contact .contact-form select:focus,
.route-contact .contact-form textarea:focus {
  border-bottom-color: var(--accent);
  box-shadow: 0 1px 0 0 var(--accent);
}
.route-contact .contact-form label:focus-within .field-label,
.route-contact .contact-form .form-block:focus-within .field-label { color: var(--accent); }

/* Finish the social-card hover underline — the ::after bar was built but never triggered. */
.route-contact .contact-card:hover::after,
.route-contact .contact-card:focus-visible::after { height: 3px; background: var(--accent); }

/* "Send inquiry": use the transform already in its transition + add press/focus states. */
.route-contact .form-submit:hover { transform: translateY(-2px); }
.route-contact .form-submit:active { transform: translateY(0); }
.route-contact .form-submit:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.route-contact .form-submit-arr { transition: transform .35s var(--ease-out); }
.route-contact .form-submit:hover .form-submit-arr { transform: translateX(3px); }

/* Rep emails (the primary CTAs): thicken the underline on hover, padding-compensated. */
.route-contact .contact-rep-link { transition: border-color .35s ease, color .35s ease, padding-bottom .35s var(--ease-out); }
.route-contact .contact-rep-link:hover { border-bottom-width: 2px; padding-bottom: 5px; }

/* ════════════════════════════════════════════════════════════════════════
   CONTACT — Direction C ("Centered Plate"), from the Claude Design handoff
   (Dalel Contact.html). Centered "Get in touch." plate → two coordinate
   columns → editorial framed form → centered IG/X/CV row → colophon. Scoped
   to .route-contact; supersedes the older contact rules above (now unused).
   ════════════════════════════════════════════════════════════════════════ */
.route-contact { background: var(--cream); }
.route-contact .c-center {
  max-width: 1000px; margin: 0 auto;
  padding: clamp(78px, 10vh, 104px) var(--gutter) 24px;
  text-align: center; display: flex; flex-direction: column; align-items: center;
}
.route-contact .c-center > .kicker {
  font-family: var(--sans); font-size: 10.5px; letter-spacing: .24em;
  text-transform: uppercase; color: var(--ink-mute); font-weight: 400;
}
.route-contact .c-title {
  font-family: var(--serif); font-style: italic; font-weight: 300;
  font-size: clamp(40px, 6vw, 68px); line-height: 1; letter-spacing: -.015em;
  color: var(--ink); margin: 12px 0 0; white-space: nowrap;
}
.route-contact .c-lede {
  font-family: var(--serif); font-size: clamp(17px, 1.6vw, 20px); line-height: 1.42;
  color: rgba(26,22,18,.82); max-width: 56ch; margin: 16px 0 0;
}
.route-contact .c-coords {
  display: flex; gap: clamp(32px, 5vw, 60px); margin: 18px 0 0; padding: 16px 0; width: 100%;
  border-top: 1px solid var(--ink-line); border-bottom: 1px solid var(--ink-line);
}
.route-contact .coord { flex: 1; text-align: center; }
.route-contact .coord .kicker {
  font-family: var(--sans); font-size: 10px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--ink-mute); font-weight: 400;
}
.route-contact .coord-name {
  font-family: var(--serif); font-style: italic; font-weight: 300;
  font-size: clamp(26px, 2.6vw, 31px); line-height: 1.05; letter-spacing: -.01em;
  color: var(--ink); margin: 7px 0 6px;
}
.route-contact .coord-mail {
  font-family: var(--mono); font-size: 12px; letter-spacing: .02em; color: var(--ink);
  text-decoration: none; display: inline-block;
  /* MOBILE-FIX (audit #21): these are THE booking links and rendered as 18px-tall
     targets. Padding + negative margin grows the hit area to ~44px without
     moving a pixel of the visual layout. */
  padding: 13px 10px; margin: -13px -10px;
}
.route-contact .coord-mail:hover { color: var(--accent); }
.route-contact .coord-tags {
  font-family: var(--sans); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-mute); margin-top: 10px; line-height: 1.6;
}
/* MOBILE-FIX (audit #38): these two carry INFORMATION (what each contact is
   for; since-when) — on a 375px screen 10px uppercase was decoration-legible
   only. Decorative kickers keep the editorial 10px scale; content doesn't. */
@media (max-width: 800px) {
  .route-contact .coord-tags { font-size: 11.5px; letter-spacing: .12em; }
  .bio-spread-since { font-size: 11.5px; }
}
.route-contact .vline { width: 1px; align-self: stretch; background: var(--ink-line); }

/* Editorial form — open (borderless) variant inside the centered plate. */
.route-contact .c-formwrap { width: 100%; max-width: 760px; margin: 16px auto 0; text-align: left; }
.route-contact .form.open { background: transparent; border: 0; padding: 0; }
.route-contact .form-head {
  display: flex; align-items: baseline; justify-content: center; gap: 18px;
  padding-bottom: 14px; border-bottom: 1px solid var(--ink-line);
}
.route-contact .form-head .kicker {
  font-family: var(--sans); font-size: 10.5px; letter-spacing: .24em;
  text-transform: uppercase; color: var(--ink-mute); font-weight: 400;
}
.route-contact .form-idx { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; color: var(--ink-mute); }
.route-contact .frow {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 3vw, 38px);
  padding: 11px 0;
}
.route-contact .frow.single { grid-template-columns: 1fr; }
.route-contact .fcell { display: flex; flex-direction: column; gap: 9px; }
.route-contact .fcell label {
  font-family: var(--sans); font-size: 10px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--ink-mute); font-weight: 400;
}
.route-contact .fcell input,
.route-contact .fcell textarea,
.route-contact .fselect select {
  font-family: var(--serif); font-size: 19px; font-weight: 400; color: var(--ink);
  background: transparent; border: 0; border-bottom: 1px solid var(--ink-line);
  padding: 0 0 9px; outline: none; width: 100%; resize: none; border-radius: 0;
}
.route-contact .fcell textarea { height: 48px; line-height: 1.4; }
.route-contact .fcell input::placeholder,
.route-contact .fcell textarea::placeholder { color: rgba(26,22,18,.32); }
.route-contact .fcell input:focus,
.route-contact .fcell textarea:focus,
.route-contact .fselect select:focus { border-bottom-color: var(--accent); }
.route-contact .fselect { position: relative; }
.route-contact .fselect select { appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 24px; }
.route-contact .fselect .fcaret {
  position: absolute; right: 0; top: 0; font-family: var(--serif); font-size: 20px;
  color: var(--ink-mute); pointer-events: none;
}
.route-contact .form-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding-top: 18px; flex-wrap: wrap;
}
.route-contact .form-note { font-family: var(--mono); font-size: 10px; letter-spacing: .08em; color: var(--ink-mute); }
.route-contact .btn-send {
  font-family: var(--serif); font-style: italic; font-weight: 400; font-size: 19px;
  color: var(--paper); background: var(--ink); border: 0; cursor: pointer;
  padding: 15px 30px; display: inline-flex; align-items: center; gap: 14px; letter-spacing: .01em;
  transition: background .3s ease, transform .25s var(--ease-out);
}
.route-contact .btn-send em { font-style: italic; }
.route-contact .btn-send:hover { background: #2c251d; transform: translateY(-1px); }
.route-contact .btn-send .arr { font-family: var(--sans); font-style: normal; }
.route-contact .btn-send:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* MOBILE-FIX (audit #20): the route override shrank the ONLY submission
   feedback the visitor gets to 10.5px muted mono — on a phone, whether the
   booking inquiry actually sent was borderline illegible. Keep the editorial
   register but at readable sizes; errors use the accent so they can't be
   mistaken for décor. */
.route-contact .form-success,
.route-contact .form-error { font-family: var(--mono); font-size: 13px; letter-spacing: .04em; color: var(--ink-mute); }
.route-contact .form-error { color: var(--accent); }
.route-contact .form-success em,
.route-contact .form-error em { font-family: var(--serif); font-style: italic; font-size: 15px; color: var(--ink); }
.route-contact .form-error a { color: var(--accent); display: inline-block; padding: 12px 4px; margin: -12px -4px; }

/* Centered social / CV footer. */
.route-contact .social-row { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid var(--ink-line); }
.route-contact .social-row.centered .social-cell { text-align: center; }
.route-contact .social-cell {
  padding: 16px clamp(20px, 3vw, 48px); border-right: 1px solid var(--ink-line);
  text-decoration: none; color: var(--ink); display: block; transition: background .35s ease;
}
.route-contact .social-cell:last-child { border-right: 0; }
.route-contact .social-cell:hover { background: rgba(168,85,58,.05); }
.route-contact .social-cell .kicker {
  font-family: var(--sans); font-size: 9.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ink-mute); font-weight: 400;
}
.route-contact .social-handle {
  font-family: var(--serif); font-style: italic; font-weight: 300;
  font-size: clamp(18px, 1.8vw, 22px); line-height: 1.1; margin: 6px 0; letter-spacing: -.01em;
  transition: color .35s ease;
}
.route-contact .social-cell:hover .social-handle { color: var(--accent); }
.route-contact .social-tag { font-family: var(--sans); font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-mute); }

/* Colophon. */
.route-contact .colophon {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px clamp(24px, 4vw, 56px); border-top: 1px solid var(--ink-line);
  font-family: var(--mono); font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-mute);
}
.route-contact .colophon a { color: inherit; text-decoration: none; }
.route-contact .colophon a:hover { color: var(--accent); }
.route-contact .colophon em { font-family: var(--serif); font-style: italic; font-size: 14px; color: var(--ink); text-transform: none; letter-spacing: 0; }

/* Narrow screens: stack the coordinate columns + form rows. */
@media (max-width: 720px) {
  .route-contact .c-coords { flex-direction: column; gap: 0; }
  .route-contact .c-coords .vline { display: none; }
  .route-contact .coord { padding: 18px 0; border-bottom: 1px solid var(--ink-line); }
  .route-contact .coord:last-of-type { border-bottom: 0; }
  .route-contact .frow { grid-template-columns: 1fr; gap: 14px; }
  .route-contact .c-title { white-space: normal; }
  .route-contact .social-row { grid-template-columns: 1fr 1fr; }
  .route-contact .social-cell:nth-child(2) { border-right: 0; }
  .route-contact .colophon { flex-direction: column; gap: 8px; text-align: center; }
}

/* Form error state */
.form-error {
  font-family: var(--sans);
  font-size: 13px;
  color: var(--accent-deep);
  line-height: 1.4;
}
.form-error a { border-bottom: 1px solid currentColor; }

/* ════════════════════════════════════════════════════════════════
   REVEAL — scroll-driven entrance for marked elements
   ════════════════════════════════════════════════════════════════ */
[data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .9s var(--ease-out), transform .9s var(--ease-out);
}
[data-reveal].is-in {
  opacity: 1;
  transform: translateY(0);
}
[data-reveal][data-reveal="slow"] {
  transition-duration: 1.4s;
}

/* The hero title is fully visible from the start — the loader covers it
   while loading, so when the loader curtain lifts the title is already
   in place (no second "pop in" animation chasing the loader's exit). */

/* ── PHOTO LIGHTBOX (project detail panels) ─────────────────── */
.inline-project .ip-still,
.inline-project .ip-gallery-thumb img { cursor: none; }

body.lb-open { overflow: hidden; }

.lightbox {
  position: fixed; inset: 0; z-index: 9999;
  background: rgba(0, 0, 0, .94);
  display: grid; place-items: center;
  padding: 24px;
  animation: lb-fade-in .18s ease-out;
  /* Keep the OS cursor hidden — the custom cursor now renders above this overlay
     (its z-index was raised; see .cursor) so it's visible against the dark backdrop. */
  cursor: none;
}
@keyframes lb-fade-in { from { opacity: 0; } to { opacity: 1; } }

.lightbox .lb-stage {
  margin: 0;
  display: flex; flex-direction: column; align-items: center;
  gap: 14px;
  max-width: 96vw;
}
.lightbox .lb-img {
  display: block;
  max-width: 100%;
  /* dvh (audit #41): the body is scroll-locked while the lightbox is open, so
     iOS never collapses its toolbar — with 100vh the bottom of portrait images
     (and the caption) sat under the toolbar, unreachable. dvh tracks the real
     visible viewport; the vh line stays as the no-dvh fallback. */
  max-height: calc(100vh - 96px);
  max-height: calc(100dvh - 96px);
  width: auto; height: auto;
  object-fit: contain;
  transition: opacity .18s ease;
  box-shadow: 0 24px 80px rgba(0, 0, 0, .55);
  cursor: none;
}
/* In-flight frame dim (audit #23) — JS toggles while the next image loads. */
.lightbox .lb-img.is-loading {
  opacity: .35;
}
.lightbox .lb-caption {
  color: #faf7f1;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  opacity: .7;
  text-align: center;
}
.lightbox .lb-close,
.lightbox .lb-nav {
  position: absolute;
  background: transparent;
  border: 0;
  cursor: none;
  color: #faf7f1;
  font-family: 'Archivo', system-ui, sans-serif;
  font-weight: 300;
  opacity: .8;
  transition: opacity .15s ease, background-color .15s ease;
  display: grid; place-items: center;
  border-radius: 50%;
}
.lightbox .lb-close:hover,
.lightbox .lb-nav:hover { opacity: 1; background: rgba(255, 255, 255, .08); }

.lightbox .lb-close {
  top: 14px; right: 18px;
  width: 44px; height: 44px;
  font-size: 32px; line-height: 1;
}
.lightbox .lb-nav {
  top: 50%; transform: translateY(-50%);
  width: 56px; height: 56px;
  font-size: 24px;
}
.lightbox .lb-prev { left: 14px; }
.lightbox .lb-next { right: 14px; }

@media (max-width: 640px) {
  /* safe-area padding (audit #42) so the close/nav controls clear the notch
     and home indicator once viewport-fit=cover is active. */
  .lightbox {
    padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right))
             max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  }
  .lightbox .lb-img { max-height: calc(100vh - 110px); max-height: calc(100dvh - 110px); }
  .lightbox .lb-nav { width: 44px; height: 44px; font-size: 20px; }
  .lightbox .lb-prev { left: 6px; }
  .lightbox .lb-next { right: 6px; }
  .lightbox .lb-close { top: 8px; right: 10px; }
}

/* ════════════════════════════════════════════════════════════════
   REDUCED MOTION (A-L3)
   The site relies heavily on always-on decorative animation:
   the hero reel autoplays, the brand strips marquee, the kinetic
   hero title rises into place, the cycler swaps every 3s, the
   csFlankDrift parallax drifts the case-study flanks, etc. None
   of that is essential to navigating the content. Honour
   `prefers-reduced-motion: reduce` by collapsing every animation
   and transition to a no-op, freezing the marquees at their start
   position, and swapping the hero reel for a static poster image.
   ════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  /* Universal animation/transition kill — collapses any decorative
     motion (heroDrift, grainShift, charRise, cyclerCycle, hintPulse,
     marqueeScroll, csFlankDrift, recBlink, lb-fade-in, etc.) so the
     final keyframe paints once and stays. */
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Marquees translate by -50% over their full duration. With the
     duration collapsed they'd land at the end keyframe, hiding half
     the duplicated track. Pin them at the start instead. */
  .marquee-track,
  .brand-track,
  .bio-brands .brand-track {
    transform: none !important;
  }
  /* Hero reel: CSS cannot pause a <video>, so we hide the video
     element and paint its poster as a static background on the
     hero-media wrapper. The poster file matches the one declared in
     the `poster=` attribute of the markup so the visual stays
     consistent for reduced-motion users. */
  .hero-cinema .hero-video { display: none !important; }
  .hero-cinema .hero-media {
    background-image: url('site-images/hero-poster.webp');
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
  }
}

