/* =========================================================
   Longview Studios: shared stylesheet
   Every colour, font family, font size and spacing value is
   defined once here in :root. Breakpoints only re-assign
   tokens or flip flex direction. (CSS does not allow var()
   inside a media query condition, so the two breakpoint
   widths are written once each, in the @media lines below.)
   ========================================================= */

:root {
  /* colour */
  --color-paper: #ffffff;
  --color-paper-deep: #f3f3f3;
  --color-slot: #e6e6e6;
  --color-ink: #0a0a0a;
  --color-ink-soft: #3a3a3a;
  --color-ink-muted: #6b6b6b;
  --color-gold: #6b6b6b;
  --color-line: rgba(0, 0, 0, 0.1);
  --color-line-strong: rgba(0, 0, 0, 0.28);
  --color-glass: rgba(40, 40, 40, 0.16);
  --color-glass-edge: rgba(255, 255, 255, 0.7);
  --color-glass-shadow: rgba(0, 0, 0, 0.08);
  --color-glass-hover: rgba(240, 240, 240, 0.8);
  --color-mockup: #0a0a0a;
  --color-glass-dark: rgba(10, 10, 10, 0.42);
  --color-glass-dark-hover: rgba(10, 10, 10, 0.62);
  --color-glass-hint: rgba(10, 10, 10, 0.2);
  --color-on-dark: #ffffff;
  --color-on-dark-muted: rgba(255, 255, 255, 0.72);
  --color-line-on-dark: rgba(255, 255, 255, 0.22);
  --halo-light: 0 0 6px rgba(255, 255, 255, 0.55);
  --halo-dark: 0 0 6px rgba(0, 0, 0, 0.55);
  --color-gallery-bg: #000000;
  --color-gallery-slot: #1c1c1c;
  --color-gallery-muted: rgba(255, 255, 255, 0.5);
  --color-transparent: transparent;

  /* font families (always quoted) */
  --font-display: "Cormorant Garamond", "Times New Roman", serif;
  --font-ui: "Jost", "Helvetica Neue", "Arial", sans-serif;

  /* font sizes */
  --fs-micro: 10px;
  --fs-ui: 11px;
  --fs-small: 13px;
  --fs-body: 15px;
  --fs-lead: 19px;
  --fs-h3: 24px;
  --fs-h2: clamp(28px, 3.4vw, 40px);
  --fs-h1: clamp(44px, 7vw, 92px);
  --fs-numeral: clamp(64px, 10vw, 140px);

  /* font weights, tracking, leading */
  --fw-light: 300;
  --fw-regular: 400;
  --fw-medium: 500;
  --track-ui: 0.16em;
  --track-tight: -0.01em;
  --track-none: 0;
  --lh-tight: 1.05;
  --lh-snug: 1.3;
  --lh-body: 1.7;

  /* spacing */
  --space-hair: 2px;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 72px;
  --space-9: 112px;
  --gutter: 28px;

  /* sizes */
  --line: 1px;
  --radius: 1px;
  --dot: 7px;
  --dot-idle: 0.3;
  --dot-hover: 0.6;
  --dot-on: 1;
  --nav-h: 66px;
  --logo-w: 264px;
  --logo-h: 26px;
  --fs-nav: 13px;
  --logo-crop-y: 49%;
  --row-h: calc(100svh - var(--nav-h));
  --half: 50%;
  --full: 100%;
  --none: 0;
  --zero: 0px;
  --measure: 620px;
  /* process section: pinned photo and rising step cards */
  /* scroll distance per Commissions step: longer is slower */
  --process-step-h: 95svh;
  --process-step-h-sm: 115svh;
  --process-fade: 0.8s;
  --process-card-w: 520px;
  --photo-mono: grayscale(1) contrast(1.05);
  --clip-filter: none;
  /* About story: the portrait stays in colour and untouched, and the text
     sits straight on it in white. With nothing behind the words, a soft dark
     shadow around each letter keeps them readable on the light backdrop. */
  --story-filter: none;
  --story-halo: 0 0 3px rgba(0, 0, 0, 0.7), 0 2px 18px rgba(0, 0, 0, 0.6), 0 0 42px rgba(0, 0, 0, 0.35);
  /* slow drift: the pinned photo eases in by this much over the section */
  --drift: 0;
  --drift-zoom: 0.08;
  /* the story sentences and step cards: large type that zooms in from a
     distance and, as you keep scrolling, zooms on past the viewer and fades.
     The zoom follows the scroll position (set by LV.zoomStory in site.js). */
  --story-type: clamp(32px, max(5vw, 4.2svh), 72px);
  --story-lh: 1.14;
  /* scroll distance per About sentence: longer is slower */
  --story-step-h: 110svh;
  /* a pause after the last sentence so it stays pinned before the page moves on */
  --story-end-h: 55svh;
  --story-zoom-from: 0.18;
  /* phones: the text sits a little below the middle of the screen, at eye
     level and out of the thumb's way; this extra space above it pushes it down */
  --story-low-sm: 12svh;
  --story-zoom-out: 2.6;
  --story-origin: 50% 50%;
  /* opening reveal: the first photo starts inset as a framed rectangle and
     opens to full screen; the photo inside eases back from a slight zoom */
  --reveal: 1;
  --reveal-x: 24vw;
  --reveal-y: 16svh;
  --reveal-round: 6px;
  --reveal-zoom: 0.14;
  --process-intro-h: 70svh;
  --measure-wide: 1180px;
  --thumb-w: 72px;
  --press-cover-w: 420px;
  /* Press index strip: tall covers in a sideways strip, drawn by WebGL */
  --strip-card-h: 70svh;
  --strip-card-h-sm: 60svh;
  --strip-card-ratio: 0.75;
  --strip-gap: 24px;
  /* the covers sit at the top of the strip, just under the menu, so they follow
     the heading closely instead of floating mid-screen */
  --strip-top: 24px;
  --strip-gap-sm: 16px;
  --strip-title-size: clamp(52px, 5.2vw, 88px);
  --strip-title-tilt: -9deg;
  --strip-draw-dur: 1.5s;
  --font-script: "Mrs Saint Delafield", cursive;
  /* Press publication view: white like the rest of the site; each print's
     edge comes from its shadow */
  --color-pub-bg: var(--color-paper);
  --pub-fade: 0.5s;
  --pub-title-size: clamp(44px, 4.6vw, 80px);
  --pub-title-tilt: -4deg;
  --pub-info-w: 30%;
  --pub-border-flat: 4%;
  --roll-dur: 0.6s;
  --strip-title-shadow: 0 1px 2px rgba(0, 0, 0, 0.45), 0 2px 18px rgba(0, 0, 0, 0.45);
  --tear-w: 25%;
  --tear-w-third: 33.3333%;
  --tear-hover: 0.85;
  --screen-h: 100svh;
  --half-screen-h: 50svh;
  --next-thumb-h: 88px;
  --swipe-dur: 0.55s;
  --swipe-ease: cubic-bezier(0.5, 0, 0.1, 1);
  --label-dur: 0.45s;
  --label-ease: cubic-bezier(0.32, 0.72, 0, 1);
  --label-delay: 0.5s;
  --label-open-w: 480px;
  --label-gap: var(--space-5);
  --drawer-w: 168px;
  --film-base: 300px;
  --film-zoom: 1.08;
  --film-max-h: 78svh;
  --play-size: 64px;
  --play-tri-h: 10px;
  --play-tri-w: 16px;
  --play-nudge: 4px;
  --zero-time: 0s;
  --on: 1;
  --off: 0;
  --z-stage: 1;
  --z-scroll: 5;
  --z-labels: 6;
  --cap-dur: 0.35s;
  /* soft two-layer drop shadow: a wide soft fall plus a tighter contact
     shadow, so the photos sit slightly above the page */
  /* the drop shadows are red, after the red in the shadows of the studio's
     grade: the same hue, deepened so it still reads as red at low opacity */
  --shadow-rgb: 104, 12, 16;
  --photo-shadow: 0 28px 56px -18px rgba(var(--shadow-rgb), 0.55), 0 10px 20px -10px rgba(var(--shadow-rgb), 0.4);
  --thumb-shadow: 0 10px 22px -8px rgba(var(--shadow-rgb), 0.52), 0 3px 8px -3px rgba(var(--shadow-rgb), 0.36);
  --label-shadow: 0 12px 28px -10px rgba(var(--shadow-rgb), 0.6), 0 3px 8px -2px rgba(var(--shadow-rgb), 0.38);
  --hint-gap: 64px;
  --hint-dur: 0.6s;
  --hint-bob: 6px;
  --hint-bob-dur: 1.6s;
  --chevron: 7px;
  --chevron-line: 1.5px;
  --z-gallery: 50;
  --z-lightbox: 60;
  --color-lightbox-bg: #000000;
  --lb-x-size: 28px;
  --lb-nav-size: 52px;
  --lb-nav-size-sm: 40px;
  --lb-chevron: 14px;
  --lb-chevron-sm: 10px;
  --lb-chevron-line: 2px;
  --lb-chevron-nudge: 4px;
  --lb-chevron-nudge-sm: 3px;
  --lb-dur: 0.3s;
  --lb-close-size: 44px;
  --drawer-dur: 0.5s;
  --drawer-ease: cubic-bezier(0.3, 0, 0, 1);
  --slider-h: 80svh;
  --credits-w: 420px;
  --credits-max-h: 60svh;
  --portrait-w: 420px;
  --field-h: 46px;
  --textarea-h: 160px;
  --blur: blur(18px) saturate(160%);
  --blur-hint: blur(4px);
  /* the Commissions step cards: a lighter frost so more of the photo shows through */
  --blur-card: blur(11px) saturate(150%);
  --hint-text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
  --glass-shadow: 0 2px 16px var(--color-glass-shadow);
  /* frosting copied from the reference: blur, slight darkening and a hue
     shift, so the bar takes on a shifted tint of whatever photo is behind */
  --glass-filter: blur(4px) brightness(0.9) hue-rotate(120deg);
  --glass-filter-hover: blur(4px) brightness(0.6) hue-rotate(120deg) contrast(1.2);
  --logo-on-dark: invert(1);
  --logo-on-light: none;
  --logo-on-mixed: invert(1) drop-shadow(0 0 2px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 6px rgba(0, 0, 0, 0.35));
  --text-halo: 0 0 2px rgba(0, 0, 0, 0.85), 0 0 8px rgba(0, 0, 0, 0.4);
  --tone-dur: 0.4s;
  --pill-pad-y: 10px;
  --pill-pad-x: 18px;
  --z-nav: 10;
  --z-label: 2;

  /* image ratios (display only, photos are never cropped) */
  --ratio-landscape: 3 / 2;
  --ratio-landscape-num: 1.5;
  --ratio-portrait: 2 / 3;
  --ratio-film: 16 / 9;
  --ratio-vertical: 9 / 16;
  --ratio-logo: 10 / 1;

  /* motion */
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --dur: 0.35s;
  --turn-open: rotate(45deg);
}

/* tablet */
@media (max-width: 1024px) {
  :root {
    --gutter: 22px;
    --space-8: 56px;
    --space-9: 80px;
    --logo-w: 220px;
    --logo-h: 22px;
    --fs-nav: 12px;
    --portrait-w: 340px;
  }
}

/* mobile */
@media (max-width: 640px) {
  :root {
    --gutter: 16px;
    --fs-body: 15px;
    --fs-lead: 17px;
    --fs-h3: 21px;
    --space-7: 36px;
    --space-8: 44px;
    --space-9: 56px;
    --nav-h: 52px;
    /* as wide as the row allows next to the Menu button, up to 190px */
    --logo-w: clamp(120px, calc(100vw - 184px), 190px);
    --next-thumb-h: 72px;
    --label-gap: var(--space-4);
    --logo-h: calc(var(--logo-w) / 10);
    --portrait-w: 100%;
    --row-h: calc(100svh - var(--nav-h));
  }
}

/* ---------- base ---------- */
* { box-sizing: border-box; margin: var(--none); padding: var(--none); }

html {
  scroll-padding-top: var(--nav-h);
}


body {
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

a { color: inherit; text-decoration: none; }
img { display: block; }
ul { list-style: none; }

.visually-hidden {
  width: var(--line); height: var(--line);
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ---------- shared atoms ---------- */
.radio-dot {
  display: inline-flex;
  width: var(--dot); height: var(--dot);
  border-radius: var(--full);
  background: currentColor;
  transform: scale(var(--dot-idle));
  transition: transform var(--dur) var(--ease);
  flex-shrink: 0;
}
.is-active > .radio-dot,
[aria-current="page"] > .radio-dot,
[aria-pressed="true"] > .radio-dot { transform: scale(var(--dot-on)); }

.glass-pill {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--color-glass);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  border-radius: var(--radius);
  font-size: var(--fs-ui);
  letter-spacing: var(--track-ui);
  text-transform: uppercase;
  font-weight: var(--fw-regular);
  transition: backdrop-filter var(--tone-dur) var(--ease), color var(--tone-dur) var(--ease);
}
.glass-pill:hover { backdrop-filter: var(--glass-filter-hover); -webkit-backdrop-filter: var(--glass-filter-hover); }

.pill-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  white-space: nowrap;
  color: var(--color-ink-soft);
  background: var(--color-transparent);
  border: var(--none);
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
  transition: color var(--dur) var(--ease);
}
.pill-item:hover { color: var(--color-ink); }
.pill-item:hover > .radio-dot { transform: scale(var(--dot-hover)); }
.pill-item[aria-current="page"],
.pill-item[aria-pressed="true"] { color: var(--color-ink); }

.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-ui);
  letter-spacing: var(--track-ui);
  text-transform: uppercase;
  font-weight: var(--fw-regular);
  color: var(--color-gold);
}

.button-primary,
.button-ghost {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-6);
  font-family: var(--font-ui);
  font-size: var(--fs-ui);
  letter-spacing: var(--track-ui);
  text-transform: uppercase;
  font-weight: var(--fw-regular);
  border: var(--line) solid var(--color-ink);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.button-primary { background: var(--color-ink); color: var(--color-paper); }
.button-primary:hover { background: var(--color-ink-soft); }
.button-ghost { background: var(--color-transparent); color: var(--color-ink); }
.button-ghost:hover { background: var(--color-paper-deep); }

/* ---------- navigation component (injected by site.js) ---------- */
.site-nav {
  position: sticky;
  top: var(--zero);
  z-index: var(--z-nav);
  display: flex;
  flex-direction: column;
  padding: var(--zero) var(--gutter);
  /* the nav keeps a fixed height and takes no room in the page; the open
     menu hangs below it over the content instead of pushing it down */
  height: var(--nav-h);
  overflow: visible;
  margin-bottom: calc(var(--nav-h) * -1);
  pointer-events: none;
}
.site-nav a, .site-nav button, .nav-drawer { pointer-events: auto; }
.nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--nav-h);
  gap: var(--space-5);
}
.nav-logo {
  display: flex;
  width: var(--logo-w);
  height: var(--logo-h);
  flex-shrink: 0;
}
.nav-logo img {
  width: var(--full);
  height: var(--full);
  object-fit: cover;
  object-position: center var(--logo-crop-y);
}
.nav-links { display: flex; }
.nav-links .glass-pill { gap: var(--space-5); padding: 12px 22px; font-size: var(--fs-nav); }
.nav-logo-pill { display: flex; padding: var(--pill-pad-y) var(--pill-pad-x); }
.nav-logo img { filter: var(--logo-on-light); transition: filter var(--tone-dur) var(--ease); }

/* automatic tone: site.js measures the photo behind each nav element and
   adds .tone-dark when it is dark. Logo and text turn white; else black. */
.nav-logo-pill.tone-dark .nav-logo img { filter: var(--logo-on-dark); }
/* half light, half dark behind it: white with a soft dark outline reads on both */
.nav-logo-pill.tone-mixed .nav-logo img { filter: var(--logo-on-mixed); }
.tone-mixed .pill-item, .tone-mixed.pill-item { text-shadow: var(--text-halo); }
.tone-dark .pill-item, .tone-dark.pill-item { color: var(--color-on-dark-muted); }
.tone-dark .pill-item:hover, .tone-dark .pill-item[aria-current="page"],
.tone-dark.pill-item:hover, .tone-dark.pill-item[aria-pressed="true"], .tone-dark.pill-item[aria-current="page"] { color: var(--color-on-dark); }
/* menu links: full white or full black, with a soft halo of the opposite
   shade so they stay readable over busy photos */
.nav-drawer .pill-item { color: var(--color-ink); text-shadow: var(--halo-light); }
.nav-drawer .tone-dark.pill-item { color: var(--color-on-dark); text-shadow: var(--halo-dark); border-bottom-color: var(--color-line-on-dark); }
.pill-item { transition: color var(--tone-dur) var(--ease); }
.nav-toggle { display: none; padding: var(--pill-pad-y) var(--pill-pad-x); font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; font-weight: var(--fw-regular); }
.nav-drawer { display: none; }

@media (max-width: 900px) {  /* compact Menu button on phones and tablets */
  .nav-links { display: none; }
  .nav-toggle { display: inline-flex; }
  /* compact panel that drops from the Menu button, right-aligned,
     so most of the page stays visible behind it */
  .site-nav.is-open .nav-drawer {
    display: flex;
    flex-direction: column;
    align-self: flex-end;
    width: var(--drawer-w);
    padding: var(--space-1) var(--space-4);
    background: var(--color-glass);
    backdrop-filter: var(--glass-filter);
    -webkit-backdrop-filter: var(--glass-filter);
    border-radius: var(--radius);
  }
  .nav-drawer .pill-item {
    padding: var(--space-2) var(--zero);
    font-size: var(--fs-ui);
    letter-spacing: var(--track-ui);
    text-transform: uppercase;
    border-bottom: var(--line) solid var(--color-line);
  }
  .nav-drawer .pill-item:last-child { border-bottom: var(--none); }
}

/* ---------- photo slots (shown only while a photo file is missing) ---------- */
.photo {
  display: flex;
  justify-content: center;
  align-items: center;
  max-width: var(--full);
  max-height: var(--full);
}
.photo img {
  max-width: var(--full);
  max-height: var(--full);
  object-fit: contain;
}
.slot-label { display: none; }
.photo.is-missing img { display: none; }
.photo.is-missing {
  background: var(--color-slot);
  flex-direction: column;
  gap: var(--space-1);
  width: var(--full);
}
.photo.is-missing .slot-label {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-3);
  font-size: var(--fs-micro);
  letter-spacing: var(--track-ui);
  text-transform: uppercase;
  color: var(--color-ink-muted);
  text-align: center;
}
.ratio-landscape.is-missing { aspect-ratio: var(--ratio-landscape); }
.ratio-portrait.is-missing { aspect-ratio: var(--ratio-portrait); }
.ratio-film.is-missing { aspect-ratio: var(--ratio-film); }
.ratio-vertical.is-missing { aspect-ratio: var(--ratio-vertical); }

/* ---------- page scaffold ---------- */
.page {
  display: flex;
  flex-direction: column;
  width: var(--full);
  max-width: var(--measure-wide);
  margin: var(--zero) auto;
  padding: var(--nav-h) var(--gutter) var(--space-9);
}
.page-hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-6) var(--zero) var(--space-8);
  border-bottom: var(--line) solid var(--color-line);
}
.page-title {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: var(--fw-light);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-tight);
}
.page-lead {
  max-width: var(--measure);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--color-ink-soft);
}
.section {
  display: flex;
  flex-direction: column;
  gap: var(--space-7);
  padding: var(--space-8) var(--zero);
  border-bottom: var(--line) solid var(--color-line);
}
.section:last-child { border-bottom: var(--none); }
.section-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-6);
}
.section-title {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
  line-height: var(--lh-snug);
}
.section-note {
  max-width: var(--measure);
  font-size: var(--fs-body);
  color: var(--color-ink-soft);
}
.split {
  display: flex;
  gap: var(--space-8);
}
.split > * { flex: 1 1 var(--zero); }
.body-copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: var(--measure);
  color: var(--color-ink-soft);
}

/* a button on its own in a text column keeps its natural width */
.body-copy > .button-primary, .body-copy > .button-ghost { align-self: flex-start; }

@media (max-width: 1024px) {
  .split { gap: var(--space-7); }
  /* tablets too: the heading sits above its note, so it never gets squeezed */
  .section-head { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 640px) {
  .split { flex-direction: column; }
  /* phones: a heading and its note read as one block */
  .section-head { gap: var(--space-3); }
}

/* ---------- WORK: swipe stage ----------
   Exception to the flex-only / no-positioning rule, on this page only:
   the swipe motion needs photos pinned to the screen while an invisible
   scroller underneath drives which project is showing.

   Each photo is in one of four states:
     is-past    slid up off the top of the screen
     is-active  full size
     is-next    small preview in a bottom corner
     is-later   waiting, invisible
   Moving between states animates position and size together. */
html.work-lock, html.work-lock body {
  overflow: hidden; height: var(--full);
  /* the Work page handles every swipe itself: stop the phone from
     scrolling, bouncing or pull-to-refreshing the page around it */
  touch-action: none; overscroll-behavior: none;
}

.work-stage { position: fixed; inset: var(--zero); z-index: var(--z-stage); pointer-events: none; }
.stage-half { position: absolute; top: var(--zero); height: var(--screen-h); width: var(--half); overflow: hidden; }
.stage-left { left: var(--zero); }
.stage-right { left: var(--half); }

.stage-media {
  position: absolute;
  background: var(--color-slot);
  overflow: hidden;
  transition-property: left, right, bottom, width, height, opacity, visibility;
  transition-duration: var(--swipe-dur);
  transition-timing-function: var(--swipe-ease);
}
.stage-media img { width: var(--full); height: var(--full); object-fit: cover; display: block; }
.stage-media .slot-label { display: none; }
.stage-media.is-missing img { display: none; }
.stage-media.is-missing .slot-label {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-1); height: var(--full); padding: var(--space-3);
  font-size: var(--fs-micro); letter-spacing: var(--track-ui); text-transform: uppercase;
  color: var(--color-ink-muted); text-align: center;
}
.stage-media.is-next.is-missing .slot-label, .stage-media.is-later.is-missing .slot-label { display: none; }

/* desktop: halves side by side. Active photo spans the half; height is
   its natural height, capped at the screen, centred vertically. */
.stage-media {
  --active-w: 50vw;
  --active-h: min(var(--screen-h), calc(50vw / var(--r)));
  --thumb-w: calc(var(--next-thumb-h) * var(--r));
}
.stage-media.is-active { width: var(--active-w); height: var(--active-h); bottom: calc((var(--screen-h) - var(--active-h)) / 2); }
.stage-media.is-past   { width: var(--active-w); height: var(--active-h); bottom: var(--full); opacity: var(--off); visibility: hidden; }
.stage-media.is-next   { width: var(--thumb-w); height: var(--next-thumb-h); bottom: var(--gutter); }
.stage-media.is-later  { width: var(--thumb-w); height: var(--next-thumb-h); bottom: calc(var(--next-thumb-h) * -2); opacity: var(--off); visibility: hidden; }
.stage-left .stage-media { left: var(--zero); }
.stage-right .stage-media { right: var(--zero); }
.stage-left .stage-media.is-next, .stage-left .stage-media.is-later { left: var(--gutter); }
.stage-right .stage-media.is-next, .stage-right .stage-media.is-later { right: var(--gutter); }
.stage-media.is-next { z-index: var(--z-label); }

/* captions: all stacked at screen centre, moved by state */
.stage-labels { position: fixed; left: var(--zero); right: var(--zero); top: var(--half-screen-h); height: var(--zero); z-index: var(--z-labels); pointer-events: none; }
.stage-label {
  position: absolute; left: var(--half); top: var(--zero);
  transform: translate(-50%, -50%);
  transition-property: transform, opacity, visibility;
  transition-duration: var(--label-dur);
  transition-timing-function: var(--label-ease);
  pointer-events: auto;
}
/* the collapsed details take back the caption's gap, so the title alone sits dead centre */
.stage-label .label-meta-group { display: flex; gap: var(--label-gap); max-width: var(--zero); margin-left: calc(var(--label-gap) * -1); overflow: hidden; opacity: var(--off); transition: max-width var(--label-dur) var(--label-ease), opacity var(--label-dur) var(--label-ease), margin-left var(--label-dur) var(--label-ease); }
.stage-label.is-active .label-meta-group { max-width: var(--label-open-w); margin-left: var(--zero); opacity: var(--on); transition-delay: var(--label-delay); }
.stage-label.is-next { transform: translate(-50%, calc(var(--half-screen-h) - var(--gutter) - 100%)); }
.stage-label.is-past { transform: translate(-50%, calc(var(--screen-h) * -1)); opacity: var(--off); visibility: hidden; }
.stage-label.is-later { transform: translate(-50%, calc(var(--half-screen-h) - var(--gutter) - 100%)); opacity: var(--off); visibility: hidden; pointer-events: none; }

.label-dark {
  display: flex;
  align-items: center;
  gap: var(--label-gap);
  padding: var(--space-4) var(--space-5);
  background: var(--color-glass-dark);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  color: var(--color-on-dark);
  font-size: var(--fs-ui);
  letter-spacing: var(--track-ui);
  text-transform: uppercase;
  font-weight: var(--fw-regular);
  white-space: nowrap;
  border-radius: var(--radius);
  transition: background var(--dur) var(--ease);
}
.label-dark:hover { background: var(--color-glass-dark-hover); }
/* project titles (Work page) and the gallery title: the same light
   frosted glass as the menu bar, with a soft shadow under the white
   lettering so it stays readable over pale photos */
.label-dark.stage-label, .gallery-top .label-dark {
  background: var(--color-glass);
  backdrop-filter: var(--glass-filter); -webkit-backdrop-filter: var(--glass-filter);
  text-shadow: var(--hint-text-shadow);
  /* soft drop shadow so the glass sits slightly above the photo */
  box-shadow: var(--label-shadow);
}
.label-dark.stage-label:hover, .gallery-top .label-dark:hover {
  background: var(--color-glass);
  backdrop-filter: var(--glass-filter-hover); -webkit-backdrop-filter: var(--glass-filter-hover);
}
.label-dark .label-meta { color: var(--color-on-dark-muted); }

/* the gesture surface: one wheel flick, swipe or arrow key moves one
   project. It catches clicks too, which open the project gallery. */
.work-scroll {
  position: fixed; inset: var(--zero); z-index: var(--z-scroll);
  overflow: hidden; touch-action: none; overscroll-behavior: none;
  cursor: pointer; outline: none; user-select: none;
}
.work-scroll.is-dragging { cursor: grabbing; }

/* depth: the main photos and the next-project thumbnails cast a soft
   shadow. The halves stop clipping so a shadow can fall across the seam. */
.stage-half { overflow: visible; }
.stage-media { box-shadow: var(--photo-shadow); }
.stage-media.is-next, .stage-media.is-later { box-shadow: var(--thumb-shadow); }

/* phones and portrait tablets: stacked. Each active photo is half the
   screen tall and centred; anything wider than the screen is trimmed. */
@media (max-width: 640px), (max-aspect-ratio: 3/4) {
  .stage-half { width: var(--full); left: var(--zero); }
  .stage-media {
    --active-w: calc(var(--half-screen-h) * var(--r));
    --active-h: var(--half-screen-h);
  }
  .stage-left .stage-media.is-active { bottom: var(--half-screen-h); left: calc(50% - var(--active-w) / 2); }
  .stage-right .stage-media.is-active { bottom: var(--zero); right: calc(50% - var(--active-w) / 2); }
  .stage-media.is-past { width: 100vw; height: calc(100vw / var(--r)); bottom: var(--screen-h); }
  .stage-left .stage-media.is-past { left: var(--zero); }
  .stage-right .stage-media.is-past { right: var(--zero); }
  .label-dark { padding: var(--space-3) var(--space-4); }
  /* long titles: never wider than the screen, wrap onto a second line */
  .label-dark {
    max-width: calc(100vw - var(--gutter) * 2);
    flex-wrap: wrap; justify-content: center; row-gap: var(--space-1);
    white-space: normal; text-align: center;
  }
  .label-dark > span, .label-dark > button { white-space: nowrap; }
}

/* first-visit hint: a glass pill just under the centre caption.
   It never catches clicks, so the photos underneath still open. */
.work-hint {
  position: fixed; left: var(--zero); right: var(--zero);
  top: calc(var(--half-screen-h) + var(--hint-gap));
  z-index: var(--z-labels);
  display: flex; justify-content: center;
  pointer-events: none;
  opacity: var(--off); visibility: hidden;
  transition: opacity var(--hint-dur) var(--ease), visibility var(--zero-time) linear var(--hint-dur);
}
.work-hint.is-shown { opacity: var(--on); visibility: visible; transition: opacity var(--hint-dur) var(--ease); }
html.gallery-open .work-hint { visibility: hidden; }
/* lighter than the other labels: a faint tint and soft blur so the photo
   stays visible through it; a small text shadow keeps the words legible */
.hint-pill, .hint-pill:hover {
  gap: var(--space-3);
  background: var(--color-glass-hint);
  backdrop-filter: var(--blur-hint); -webkit-backdrop-filter: var(--blur-hint);
  text-shadow: var(--hint-text-shadow);
}
.hint-arrow { display: flex; animation: hint-bob var(--hint-bob-dur) var(--ease) infinite; }
.hint-chevron {
  display: flex; width: var(--chevron); height: var(--chevron);
  border-style: solid; border-color: var(--color-on-dark);
  border-width: var(--zero) var(--chevron-line) var(--chevron-line) var(--zero);
  transform: rotate(45deg);
}
@keyframes hint-bob {
  0%, 100% { transform: translateY(var(--zero)); }
  50% { transform: translateY(var(--hint-bob)); }
}

@media (prefers-reduced-motion: reduce) {
  .stage-media, .stage-label, .stage-label .label-meta-group { transition-duration: var(--zero-time); transition-delay: var(--zero-time); }
  .hint-arrow { animation: none; }
}

/* ---------- PROJECT GALLERY (Work page) ----------
   Opens over the Work page when a project is clicked. It slides up from
   the bottom, scrolls vertically, keeps the caption pinned on top and the
   Credits button pinned at the foot, and closes from the end zone. */
.gallery {
  position: fixed; inset: var(--zero); z-index: var(--z-gallery);
  touch-action: pan-y;
  background: var(--color-gallery-bg);
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateY(100%);
  visibility: hidden;
  transition: transform var(--drawer-dur) var(--drawer-ease), visibility var(--zero-time) linear var(--drawer-dur);
  scrollbar-width: none;
}
.gallery::-webkit-scrollbar { display: none; }
.gallery.is-open { transform: translateY(var(--zero)); visibility: visible; transition: transform var(--drawer-dur) var(--drawer-ease); }
html.gallery-open .site-nav { visibility: hidden; }

.gallery-inner { display: flex; flex-direction: column; min-height: var(--full); }
.gallery-top {
  position: sticky; top: var(--zero); z-index: var(--z-label);
  display: flex; justify-content: center;
  height: var(--zero); overflow: visible;
}
.gallery-top .label-dark { margin-top: var(--gutter); height: max-content; transition: background var(--dur) var(--ease), transform var(--cap-dur) var(--ease), opacity var(--cap-dur) var(--ease); }
/* the caption slides up out of the way while scrolling down through the
   photos, and comes back on any scroll up */
.gallery.cap-hidden .gallery-top .label-dark { transform: translateY(calc(-100% - var(--gutter) - var(--space-2))); opacity: var(--off); }
.label-tail { display: inline-flex; align-items: center; gap: inherit; white-space: nowrap; }
.gallery-close-x {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-transparent); border: var(--none); color: inherit;
  font: inherit; letter-spacing: inherit; cursor: pointer;
  padding: var(--zero) var(--space-1);
}

.gallery-flow { display: flex; flex-direction: column; }
.g-full { display: flex; }
.g-row { display: flex; }
.g-item { flex: var(--r) 1 var(--zero); min-width: var(--zero); aspect-ratio: var(--r); background: var(--color-gallery-slot); overflow: hidden; display: flex; }
.g-full .g-item { flex: 1 1 var(--full); }
.g-item img { width: var(--full); height: var(--full); object-fit: cover; display: block; }
.g-item { cursor: zoom-in; }
.g-item:focus-visible { outline: var(--line) solid var(--color-on-dark); outline-offset: calc(var(--line) * -2); }
.g-item .slot-label { display: none; }
.g-item.is-missing img { display: none; }
.g-item.is-missing .slot-label {
  display: flex; flex-direction: column; align-items: center; justify-content: center; flex: 1 1 auto;
  gap: var(--space-1); padding: var(--space-3);
  font-size: var(--fs-micro); letter-spacing: var(--track-ui); text-transform: uppercase;
  color: var(--color-gallery-muted); text-align: center;
}

/* sideways slider with counter */
.g-slider { display: flex; flex-direction: column; }
.g-track { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; height: var(--slider-h); }
.g-track::-webkit-scrollbar { display: none; }
.g-track .g-item { flex: 0 0 auto; height: var(--full); scroll-snap-align: start; }
.g-pager {
  display: flex; justify-content: flex-end; height: var(--zero); overflow: visible;
  padding: var(--zero) var(--gutter); z-index: var(--z-label);
}
.g-pager .label-dark { margin-top: calc(var(--gutter) * -1); transform: translateY(-100%); gap: var(--space-3); height: max-content; }
.g-dots { display: flex; gap: var(--space-2); align-items: center; }
.g-dot { display: inline-flex; width: var(--dot); height: var(--dot); border-radius: var(--full); border: var(--line) solid currentColor; }
.g-dot.is-on { background: currentColor; }
.g-count { font-variant-numeric: tabular-nums; }

/* end zone: scrolling into it closes the gallery */
.gallery-end { display: flex; justify-content: center; align-items: center; padding-block: var(--space-8) var(--space-9); flex-shrink: 0; }

/* Credits button and panel, pinned at the foot */
.gallery-foot {
  position: sticky; bottom: var(--zero); z-index: var(--z-label);
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
  height: var(--zero); overflow: visible; justify-content: flex-end;
  padding-bottom: var(--gutter);
  margin-top: auto;
}
.credits-btn { border: var(--none); cursor: pointer; font-family: var(--font-ui); flex-shrink: 0; }
.credits-panel {
  display: none;
  gap: var(--space-7);
  width: var(--credits-w); max-width: calc(100vw - var(--gutter) * 2);
  max-height: var(--credits-max-h); overflow-y: auto;
  padding: var(--space-5);
  background: var(--color-glass-dark);
  backdrop-filter: var(--blur); -webkit-backdrop-filter: var(--blur);
  color: var(--color-on-dark);
  font-size: var(--fs-ui); line-height: var(--lh-snug);
  border-radius: var(--radius);
  flex-shrink: 0;
}
.gallery.credits-open .credits-panel { display: flex; }
.credits-col { display: flex; flex-direction: column; gap: var(--space-3); flex: 1 1 var(--zero); min-width: var(--zero); }
.credits-head { color: var(--color-on-dark-muted); }
.credit { display: flex; flex-direction: column; }
.credit-role { color: var(--color-on-dark); }
.credit-name { color: var(--color-on-dark-muted); }
.credit-name.data-missing { font-style: italic; }

@media (max-width: 640px) {
  .credits-panel { flex-direction: column; gap: var(--space-4); }
}
@media (prefers-reduced-motion: reduce) {
  .gallery, .gallery.is-open { transition-duration: var(--zero-time); }
  .gallery-top .label-dark { transition-duration: var(--zero-time); }
}

/* index-thumb is reused by the Press list */
.index-thumb { display: flex; width: var(--thumb-w); flex-shrink: 0; }

/* stacked on phones and on portrait tablets (taller than 3:4) */
@media (max-width: 640px), (max-aspect-ratio: 3/4) {
  .work-pair { flex-direction: column; }
  .work-half { flex: 0 0 var(--half-screen-h); }
  .work-half-left { align-items: flex-end; }
  .work-half-right { align-items: flex-start; }
  .work-half .photo { width: auto; height: var(--full); max-width: var(--full); max-height: none; }
  .work-half .photo img { width: auto; height: var(--full); max-width: var(--full); max-height: none; }
  .work-label-anchor { width: var(--full); height: var(--zero); }
  .label-dark { padding: var(--space-3) var(--space-4); }
  /* long titles: never wider than the screen, wrap onto a second line */
  .label-dark {
    max-width: calc(100vw - var(--gutter) * 2);
    flex-wrap: wrap; justify-content: center; row-gap: var(--space-1);
    white-space: normal; text-align: center;
  }
  .label-dark > span, .label-dark > button { white-space: nowrap; }
}

/* ---------- COMMISSIONS ---------- */
.tier-list { display: flex; flex-direction: column; border-top: var(--line) solid var(--color-line); }
.tier { border-bottom: var(--line) solid var(--color-line); }
.tier summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-6) var(--zero);
  cursor: pointer;
  list-style: none;
}
.tier summary::-webkit-details-marker { display: none; }
.tier-heading { display: flex; flex-direction: column; gap: var(--space-1); flex: 1 1 var(--zero); }
.tier-name {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-regular);
  line-height: var(--lh-snug);
}
.tier-sub { font-size: var(--fs-small); color: var(--color-ink-muted); }
.tier-tag { font-size: var(--fs-micro); letter-spacing: var(--track-ui); text-transform: uppercase; color: var(--color-gold); white-space: nowrap; }
.tier-sign { font-family: var(--font-display); font-size: var(--fs-h3); color: var(--color-ink-muted); transition: transform var(--dur) var(--ease); }
.tier[open] .tier-sign { transform: var(--turn-open); }
.tier-body { display: flex; gap: var(--space-8); padding: var(--zero) var(--zero) var(--space-7); }
.tier-col { display: flex; flex-direction: column; flex: 1 1 var(--zero); gap: var(--space-3); }

.list-plain { display: flex; flex-direction: column; }
.list-item {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-2) var(--zero);
  border-bottom: var(--line) solid var(--color-line);
  font-size: var(--fs-small);
  color: var(--color-ink-soft);
}
.list-item:last-child { border-bottom: var(--none); }
.list-mark { color: var(--color-gold); flex-shrink: 0; }

.step-row { display: flex; flex-wrap: wrap; gap: var(--space-hair); }
.card-step {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1 1 var(--zero);
  min-width: var(--zero);
  padding: var(--space-5);
  background: var(--color-paper-deep);
}
.card-num { font-family: var(--font-display); font-size: var(--fs-h3); color: var(--color-gold); line-height: var(--lh-tight); }
.card-title { font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; font-weight: var(--fw-medium); color: var(--color-ink); }
.card-body { font-size: var(--fs-small); color: var(--color-ink-soft); }

.terms { display: flex; flex-direction: column; }
.term-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-3) var(--zero);
  border-bottom: var(--line) solid var(--color-line);
  font-size: var(--fs-small);
}
.term-key { color: var(--color-ink-muted); }
.term-val { color: var(--color-ink); text-align: right; }

@media (max-width: 1024px) {
  .step-row .card-step { flex: 1 1 calc(var(--half) - var(--space-hair)); }
}
@media (max-width: 640px) {
  .tier-body { flex-direction: column; gap: var(--space-6); }
  .tier-tag { display: none; }
  .step-row { flex-direction: column; }
}

/* ---------- PROCESS (Commissions: how a commission runs) ----------
   The same on every screen: a behind-the-scenes photo fills the screen and
   stays pinned (sticky, the same exception as the nav) while the step text
   rises over it. Photos sit in one flex row, each pulled back over the one
   before with a negative margin, so they stack without absolute
   positioning; only the current one is visible. The text sits on the
   same frosted dark glass as the title labels. The section clips its
   own height so the pinned photo never spills onto the next section.
   Photos show in black and white through a filter; the files stay colour. */
.process { display: flex; flex-direction: column; overflow-y: clip; }
.process-media {
  position: sticky; top: var(--zero);
  flex: none; width: 100vw; height: 100svh;
  margin-left: calc(50% - 50vw); margin-bottom: -100svh;
  display: flex; overflow: hidden; background: var(--color-ink);
  clip-path: inset(calc(var(--reveal-y) * (1 - var(--reveal))) calc(var(--reveal-x) * (1 - var(--reveal))) round calc(var(--reveal-round) * (1 - var(--reveal))));
}
.process-stack { display: flex; width: var(--full); height: var(--full); transform: scale(calc(1 + var(--reveal-zoom) * (1 - var(--reveal)) + var(--drift-zoom) * var(--drift))); }
.process-intro { min-height: var(--process-intro-h); }
.process-photo {
  flex: 0 0 var(--full); width: var(--full); height: var(--full);
  /* each photo carries its own focus height (--focus-y, set on the img) so
     the crop keeps the model's face in frame */
  object-fit: cover; object-position: 50% var(--focus-y, 50%); display: block;
  filter: var(--photo-mono);
  /* hidden photos are switched off fully after their fade, so the browser
     only keeps the visible photo (and the one fading) in memory */
  /* the outgoing photo stays fully visible underneath until the new one
     has faded in on top, so the change never dips to black */
  opacity: var(--off); visibility: hidden; z-index: var(--z-stage);
  transition: opacity var(--zero-time) linear var(--process-fade), visibility var(--zero-time) linear var(--process-fade);
}
/* the clips are already black and white in the file, so they skip the
   filter and the phone does not recolour every frame */
.process-clip { filter: var(--clip-filter); }
.process-stack > * + * { margin-left: calc(var(--full) * -1); }
.process-photo.is-on { opacity: var(--on); visibility: visible; z-index: var(--z-label); transition: opacity var(--process-fade) var(--ease); }
.process-steps { width: var(--full); display: flex; flex-direction: column; list-style: none; padding: var(--zero); margin: var(--zero); z-index: var(--z-label); }
.process-step { display: flex; align-items: flex-end; min-height: var(--process-step-h); padding-bottom: var(--space-8); }
.process-card {
  display: flex; flex-direction: column; gap: var(--space-3); max-width: var(--process-card-w);
  padding: var(--space-5) var(--space-6);
  background: var(--color-glass-dark);
  backdrop-filter: var(--blur-card); -webkit-backdrop-filter: var(--blur-card);
  border-radius: var(--radius); box-shadow: var(--label-shadow);
  text-shadow: var(--hint-text-shadow);
}
.process-meta { display: flex; align-items: baseline; gap: var(--space-3); }
.process-phase { font-size: var(--fs-micro); letter-spacing: var(--track-ui); text-transform: uppercase; color: var(--color-on-dark-muted); }
.process-card .card-num { font-size: var(--fs-h3); color: var(--color-on-dark); }
.process-card .card-title { font-size: var(--fs-h2); font-family: var(--font-display); font-weight: var(--fw-light); letter-spacing: var(--zero); text-transform: none; line-height: var(--lh-tight); color: var(--color-on-dark); }
.process-card .card-body { font-size: var(--fs-lead); line-height: var(--lh-body); color: var(--color-on-dark); }

/* About story: the portrait and the sentences are both pinned. The
   sentences are stacked in one layer over the photo (each after the first
   pulled back over it with a negative margin) and only the current one is
   shown. The scrolling list underneath holds one empty marker per sentence. */
.story-photo { filter: var(--story-filter); }
.story-lines { display: flex; flex: 0 0 var(--full); width: var(--full); height: var(--full); margin-left: calc(var(--full) * -1); z-index: var(--z-label); }
.story-line {
  flex: 0 0 var(--full); width: var(--full); height: var(--full);
  display: flex; align-items: flex-end; justify-content: center;
  padding: var(--nav-h) var(--gutter) var(--space-8);
}
.story-line + .story-line { margin-left: calc(var(--full) * -1); }
/* the item that zooms: a sentence on About, a glass card on Commissions */
.zoom-item { transform-origin: var(--story-origin); }
.story .story-line > *, .zoom-slot { width: var(--full); max-width: var(--measure-wide); }
/* Commissions: the card keeps its own width, on the left of the page column */
.zoom-slot { display: flex; }
.story-text {
  margin: var(--zero);
  font-family: var(--font-display); font-weight: var(--fw-regular);
  font-size: var(--story-type); line-height: var(--story-lh);
  color: var(--color-on-dark); text-shadow: var(--story-halo);
}
/* the closing quote sits in the middle of the screen, centred */
.story-line-centre { align-items: center; }
.story-quote { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); text-align: center; }
.story-quote .process-phase { margin: var(--zero); color: var(--color-on-dark); text-shadow: var(--story-halo); }
.story-attr { margin: var(--zero); font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; color: var(--color-on-dark); text-shadow: var(--story-halo); }
.story-mark { min-height: var(--story-step-h); }
.story-end { min-height: var(--story-end-h); }
/* the zoom: only once the script is running, so without it the text still
   shows. Each frame the script sets the opacity and scale from the scroll
   position, so there is no timed transition here. */
.zoom.is-live .story-line { visibility: hidden; }
.zoom.is-live .zoom-item { opacity: var(--off); will-change: transform, opacity; }

@media (max-width: 640px) {
  /* phones: a slimmer opening frame, so the photo starts close under the text */
  .process-media { --reveal-x: 6vw; --reveal-y: 3svh; }
  /* on phones the sentences and step cards sit a little below the middle of
     the screen (about 58% down), not at the bottom where the thumb is */
  .story-line { align-items: center; padding-top: calc(var(--nav-h) + var(--story-low-sm)); padding-bottom: var(--space-5); }
  .process-step { min-height: var(--process-step-h-sm); padding-bottom: var(--space-7); }
  .process-card { width: var(--full); padding: var(--space-5); }
  .process-card .card-title { font-size: var(--fs-h3); }
  .process-card .card-body { font-size: var(--fs-body); }
}
@media (prefers-reduced-motion: reduce) {
  .process-photo { transition-duration: var(--zero-time); }
  .process-media { clip-path: none; }
  .process-stack { transform: none; }
}

/* ---------- PRESS ---------- */
/* Press index strip. The section is as tall as the strip is wide; its stage
   is pinned to the screen (sticky, an approved exception like the process
   photo) and the strip slides sideways as the page scrolls. The canvas and
   the strip of links are stacked in the stage with a negative margin. */
.strip { display: flex; flex-direction: column; width: 100vw; margin-left: calc(50% - 50vw); }
.strip-stage { position: sticky; top: var(--zero); height: 100svh; display: flex; overflow: hidden; }
.strip-canvas { flex: 0 0 var(--full); width: var(--full); height: var(--full); display: block; }
.strip-track {
  flex: 0 0 auto; margin-left: calc(var(--full) * -1); z-index: var(--z-label);
  display: flex; align-items: flex-start; gap: var(--strip-gap);
  height: var(--full); padding: calc(var(--nav-h) + var(--strip-top)) var(--gutter) var(--zero);
  will-change: transform;
}
.strip-card {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  height: var(--strip-card-h); width: calc(var(--strip-card-h) * var(--strip-card-ratio));
  transform: translateY(var(--lift, 0px)) rotate(var(--tilt, 0deg));
  overflow: visible; color: var(--color-on-dark);
}
.strip-card:focus-visible { outline: var(--line) solid var(--color-ink); outline-offset: var(--space-2); }
.strip-img { width: var(--full); height: var(--full); object-fit: cover; object-position: 50% 15%; display: block; }
/* with WebGL the canvas draws the covers; the links stay in place, see-through */
.strip.is-gl .strip-img { opacity: var(--off); }
.strip-title {
  margin-left: calc(var(--full) * -1); flex: 0 0 var(--full);
  display: flex; justify-content: center; text-align: center;
  font-family: var(--font-script); font-size: calc(var(--strip-title-size) * var(--title-scale, 1)); line-height: var(--lh-tight);
  color: var(--color-on-dark); text-shadow: var(--strip-title-shadow);
  transform: rotate(var(--strip-title-tilt)); opacity: var(--intro, 1);
  pointer-events: none;
}
/* the title writes itself in from the left once its cover has arrived */
.strip.is-gl .strip-title { clip-path: inset(0 100% 0 0); transition: clip-path var(--strip-draw-dur) var(--ease); }
.strip.is-gl .strip-card.is-drawn .strip-title { clip-path: inset(0 0 0 0); }
@media (max-width: 640px) {
  .strip-card { height: var(--strip-card-h-sm); width: calc(var(--strip-card-h-sm) * var(--strip-card-ratio)); }
  .strip-track { gap: var(--strip-gap-sm); }
}
@media (prefers-reduced-motion: reduce) {
  .strip.is-gl .strip-title { clip-path: none; transition-duration: var(--zero-time); }
}

/* Press publication view: opens over the page like the Work gallery (fixed,
   an approved exception). Canvas, the page images and the text are stacked
   with negative margins; the page images are moved by the script. */
.pub {
  position: fixed; inset: var(--zero); z-index: var(--z-gallery);
  display: flex; overflow: hidden; background: var(--color-pub-bg);
  opacity: var(--off); visibility: hidden;
  transition: opacity var(--pub-fade) var(--ease), visibility var(--zero-time) linear var(--pub-fade);
}
.pub.is-open { opacity: var(--on); visibility: visible; transition: opacity var(--pub-fade) var(--ease); }
.pub-canvas { flex: 0 0 var(--full); width: var(--full); height: var(--full); display: block; }
.pub-pages { flex: 0 0 var(--full); height: var(--full); margin-left: calc(var(--full) * -1); display: flex; align-items: flex-start; }
.pub-slot { flex: 0 0 var(--zero); width: var(--zero); height: var(--zero); overflow: visible; }
.pub-page { display: flex; padding: var(--zero); border: var(--none); background: var(--color-transparent); cursor: zoom-in; transform-origin: 50% 50%; }
.pub-page img { width: var(--full); height: var(--full); object-fit: cover; display: block; }
.pub.is-gl .pub-page img { opacity: var(--off); }
/* without WebGL the pages show as plain prints */
.pub.is-flat .pub-page { background: var(--color-paper); padding: var(--pub-border-flat); box-shadow: var(--photo-shadow); }
.pub-page:focus-visible { outline: var(--line) solid var(--color-ink); outline-offset: var(--space-2); }
.pub-ui {
  flex: 0 0 var(--full); height: var(--full); margin-left: calc(var(--full) * -1);
  display: flex; flex-direction: column; padding: var(--zero) var(--gutter) var(--gutter);
  pointer-events: none; z-index: var(--z-label);
}
.pub-ui button, .pub-ui a, .pub-more { pointer-events: auto; }
.pub-top { display: flex; justify-content: flex-end; padding-top: var(--gutter); }
/* the view's controls are the same frosted pills as the menu */
.pub-close, .pub-edge, .pub-more-toggle { padding: var(--pill-pad-y) var(--pill-pad-x); border: var(--none); cursor: pointer; font-family: var(--font-ui); color: var(--color-ink); }
.pub-info { display: flex; flex-direction: column; gap: var(--space-3); width: var(--pub-info-w); margin-top: var(--space-6); }
.pub-placement { margin: var(--zero); }
.pub-title {
  margin: var(--zero); font-family: var(--font-display); font-weight: var(--fw-light);
  font-size: var(--pub-title-size); line-height: var(--lh-tight);
  transform: rotate(var(--pub-title-tilt)); transform-origin: 0 100%;
}
.pub-mag { margin: var(--zero); font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; color: var(--color-ink-muted); }
.pub-count { margin: var(--zero); display: flex; align-items: baseline; gap: var(--space-5); font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; }
.pub-num { display: flex; align-items: baseline; font-variant-numeric: tabular-nums; }
/* the rolling counter: each digit is a column 0 to 9 that slides into place */
.roll { display: flex; height: 1em; line-height: 1; overflow: hidden; }
.roll-track { display: flex; flex-direction: column; transform: translateY(calc(var(--d, 0) * -1em)); transition: transform var(--roll-dur) var(--ease); }
.roll-track > span { height: 1em; line-height: 1; }
.pub-more { display: flex; flex-direction: column; gap: var(--space-4); }
.pub-more-toggle { display: none; }
.pub-ui .pub-more-toggle { display: none; }
.pub-edges { flex: 1 1 auto; display: flex; justify-content: space-between; align-items: center; }

/* a new magazine: the text fades up */
.pub.is-fresh .pub-info { animation: pub-in var(--pub-fade) var(--ease) both; }
@keyframes pub-in { from { opacity: var(--off); transform: translateY(var(--space-4)); } to { opacity: var(--on); transform: none; } }
@media (max-width: 640px) {
  .pub-info { width: var(--full); margin-top: var(--zero); gap: var(--space-2); }
  .pub-placement { display: none; }
  .pub-title { font-size: var(--fs-h2); transform: none; }
  .pub-ui .pub-more-toggle { display: inline-flex; align-self: flex-start; }
  /* credits and links open as a panel on phones, so the pages keep the room */
  .pub-more { display: none; padding: var(--space-4); background: var(--color-paper); box-shadow: var(--label-shadow); }
  .pub.is-details .pub-more { display: flex; }
}
@media (prefers-reduced-motion: reduce) {
  .pub, .pub.is-open, .roll-track { transition-duration: var(--zero-time); }
  .pub.is-fresh .pub-info { animation: none; }
}
/* text for screen readers only */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* the Press heading sits close above the cover strip */
.press-hero { padding-bottom: var(--space-5); }
.press-count { display: flex; align-items: flex-end; gap: var(--space-5); }
.press-numeral { font-family: var(--font-display); font-size: var(--fs-numeral); font-weight: var(--fw-light); line-height: var(--lh-tight); }
.press-numeral-label { font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; color: var(--color-ink-muted); padding-bottom: var(--space-4); }
.press-list { display: flex; flex-direction: column; border-top: var(--line) solid var(--color-line); }
.press-row {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-4) var(--zero);
  border-bottom: var(--line) solid var(--color-line);
}
.press-row .index-thumb { width: var(--thumb-w); }
.press-title { flex: 2 1 var(--zero); font-family: var(--font-display); font-size: var(--fs-h3); line-height: var(--lh-snug); }
.press-meta { flex: 1 1 var(--zero); font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; color: var(--color-ink-muted); }
.data-missing { color: var(--color-ink-muted); font-style: italic; }

/* a published feature: cover beside its details, then the inside pages */
.press-feature { display: flex; flex-direction: column; gap: var(--space-6); padding: var(--space-7) var(--zero); border-bottom: var(--line) solid var(--color-line); }
.press-feature-top { display: flex; gap: var(--space-7); align-items: flex-end; }
.press-cover { display: flex; flex: 0 0 var(--press-cover-w); max-width: var(--full); }
.press-cover img { width: var(--full); height: auto; display: block; }
.press-detail { display: flex; flex-direction: column; gap: var(--space-4); flex: 1 1 var(--zero); min-width: var(--zero); }
.press-detail .press-title { flex: none; font-size: var(--fs-h2); }
.press-facts { display: flex; flex-direction: column; }
.tear-sheets { display: flex; flex-wrap: wrap; }
.tear-sheet { display: flex; flex: 0 0 var(--tear-w); max-width: var(--tear-w); }
.tear-sheet img { width: var(--full); height: auto; display: block; }
.tear-sheet-third { flex-basis: var(--tear-w-third); max-width: var(--tear-w-third); }
.tear-sheet:hover img { opacity: var(--tear-hover); }
@media (max-width: 640px) {
  .press-row { flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
  .press-title { flex: 1 1 var(--zero); }
  .press-meta { flex: 1 1 var(--full); }
  .press-feature-top { flex-direction: column; align-items: stretch; }
  .press-cover { flex: 1 1 auto; }
  .tear-sheet { flex-basis: var(--half); max-width: var(--half); }
}

/* ---------- MOTION ----------
   Films sit in rows at one shared height; each card's width follows its
   own shape (16:9, 4:3, square), so nothing is cropped or letterboxed. */
.film-grid { display: flex; flex-wrap: wrap; gap: var(--space-6) var(--space-5); }
.card-film { display: flex; flex-direction: column; gap: var(--space-3); flex: var(--film-r) 1 calc(var(--film-r) * var(--film-base)); min-width: var(--zero);
  /* a film left alone on a row never grows taller than most of the screen */
  max-width: calc(var(--film-r) * var(--film-max-h)); }
.film-frame {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: var(--film-r); width: var(--full);
  background-color: var(--color-ink); background-size: cover; background-position: center;
  overflow: hidden;
}
.film-frame iframe { width: var(--full); height: var(--full); border: var(--none); display: block; }
.film-play-mark {
  display: flex; width: var(--play-size); height: var(--play-size); border-radius: var(--full);
  background: var(--color-glass-dark); backdrop-filter: var(--blur); -webkit-backdrop-filter: var(--blur);
  align-items: center; justify-content: center;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.film-frame:hover .film-play-mark { background: var(--color-glass-dark-hover); transform: scale(var(--film-zoom)); }
.film-play-triangle {
  display: flex; width: var(--zero); height: var(--zero); margin-left: var(--play-nudge);
  border-style: solid; border-color: var(--color-transparent) var(--color-transparent) var(--color-transparent) var(--color-on-dark);
  border-width: var(--play-tri-h) var(--zero) var(--play-tri-h) var(--play-tri-w);
}
.film-caption { display: flex; justify-content: space-between; gap: var(--space-4); font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; color: var(--color-ink-muted); }
.film-caption .film-name { color: var(--color-ink); }
@media (max-width: 640px) {
  .film-grid { flex-direction: column; }
  .card-film { flex: none; width: var(--full); }
}

/* ---------- ABOUT ---------- */
.portrait { display: flex; width: var(--portrait-w); flex-shrink: 0; }
.quote {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-8) var(--zero);
  align-items: center;
  text-align: center;
}
.quote-text { max-width: var(--measure); font-family: var(--font-display); font-size: var(--fs-h2); font-weight: var(--fw-light); line-height: var(--lh-snug); }
.quote-attr { font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; color: var(--color-ink-muted); }
.tag-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: var(--line) solid var(--color-line-strong);
  font-size: var(--fs-ui);
  letter-spacing: var(--track-ui);
  text-transform: uppercase;
  color: var(--color-ink-soft);
}

/* ---------- CONTACT (mockup form) ---------- */
.mockup-banner {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border: var(--line) dashed var(--color-mockup);
  color: var(--color-mockup);
  font-size: var(--fs-ui);
  letter-spacing: var(--track-ui);
  text-transform: uppercase;
  font-weight: var(--fw-regular);
}
.form-mockup { display: flex; flex-direction: column; gap: var(--space-5); }
.form-status { padding: var(--space-3) var(--space-4); border: var(--line) solid var(--color-ink); font-size: var(--fs-small); color: var(--color-ink); }
.field-row { display: flex; gap: var(--space-5); }
.field { display: flex; flex-direction: column; gap: var(--space-2); flex: 1 1 var(--zero); }
.field-label { font-size: var(--fs-ui); letter-spacing: var(--track-ui); text-transform: uppercase; font-weight: var(--fw-regular); color: var(--color-ink-soft); }
.field-input {
  height: var(--field-h);
  padding: var(--zero) var(--space-4);
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
  color: var(--color-ink);
  background: var(--color-paper);
  border: var(--line) solid var(--color-line-strong);
  border-radius: var(--radius);
}
.field-input:focus { outline: var(--line) solid var(--color-ink); border-color: var(--color-ink); }
textarea.field-input { height: var(--textarea-h); padding: var(--space-3) var(--space-4); resize: vertical; }
.choice-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.choice {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: var(--line) solid var(--color-line-strong);
  background: var(--color-transparent);
  font-family: var(--font-ui);
  font-size: var(--fs-ui);
  letter-spacing: var(--track-ui);
  text-transform: uppercase;
  color: var(--color-ink-soft);
  cursor: pointer;
}
.choice[aria-pressed="true"] { border-color: var(--color-ink); color: var(--color-ink); }
.form-foot { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; }
.form-note { font-size: var(--fs-small); color: var(--color-ink-muted); }
.contact-aside { display: flex; flex-direction: column; gap: var(--space-6); }
@media (max-width: 640px) {
  .field-row { flex-direction: column; }
  /* phones: every button runs the full width, so pairs match */
  .form-foot .button-primary, .form-foot .button-ghost,
  .body-copy > .button-primary, .body-copy > .button-ghost { width: var(--full); justify-content: center; align-self: stretch; }
}

/* ---------- PHOTO PREVIEW (Work page galleries) ----------
   Fixed over the gallery, like the gallery itself (same exception to the
   positioning rule). Inside it is plain flex: a top row holding the close
   button, the photo filling the space between, and a counter at the foot. */
.lightbox {
  position: fixed; inset: var(--zero); z-index: var(--z-lightbox);
  display: flex; flex-direction: column;
  background: var(--color-lightbox-bg);
  opacity: var(--off); visibility: hidden;
  transition: opacity var(--lb-dur) var(--ease), visibility var(--zero-time) linear var(--lb-dur);
  touch-action: none;
}
.lightbox.is-open { opacity: var(--on); visibility: visible; transition: opacity var(--lb-dur) var(--ease); }
/* the page behind stays still while a preview is open */
html.lb-open { overflow: hidden; }
.lightbox-top { display: flex; justify-content: flex-end; padding: var(--gutter) var(--gutter) var(--space-3); flex-shrink: 0; }
.lightbox-close {
  justify-content: center; width: var(--lb-close-size); height: var(--lb-close-size); padding: var(--zero);
  border: var(--none); cursor: pointer; font-size: var(--lb-x-size); line-height: var(--lh-tight);
}
.lightbox-stage { flex: 1 1 var(--zero); min-height: var(--zero); display: flex; align-items: center; gap: var(--space-4); padding: var(--zero) var(--gutter); cursor: zoom-out; }
.lightbox-frame { flex: 1 1 var(--zero); min-width: var(--zero); height: var(--full); display: flex; align-items: center; justify-content: center; }
.lightbox-img { max-width: var(--full); max-height: var(--full); object-fit: contain; display: block; cursor: default; }
/* previous / next: round frosted buttons either side of the photo,
   each holding a thin chevron drawn with two borders */
.lightbox-nav {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: var(--lb-nav-size); height: var(--lb-nav-size); border-radius: var(--full);
  border: var(--none); cursor: pointer;
  /* same frosted dark glass as the menu bar and the title labels */
  background: var(--color-glass-dark);
  backdrop-filter: var(--blur); -webkit-backdrop-filter: var(--blur);
  transition: background var(--dur) var(--ease);
  z-index: var(--z-label);
}
.lightbox-nav:hover { background: var(--color-glass-dark-hover); }
.lightbox-nav:focus-visible { outline: var(--line) solid var(--color-on-dark); outline-offset: var(--space-1); }
.lb-chevron {
  display: flex; width: var(--lb-chevron); height: var(--lb-chevron);
  border-style: solid; border-color: var(--color-on-dark);
  border-width: var(--lb-chevron-line) var(--lb-chevron-line) var(--zero) var(--zero);
}
.lb-chevron-right { transform: translateX(calc(var(--lb-chevron-nudge) * -1)) rotate(45deg); }
.lb-chevron-left { transform: translateX(var(--lb-chevron-nudge)) rotate(-135deg); }
.lightbox.is-single .lightbox-nav { visibility: hidden; }
@media (max-width: 640px) {
  /* phones: the photo runs edge to edge; the arrows sit over its sides,
     pulled in with negative margins so the photo keeps the full width.
     Over a photo they use the frosted dark glass so they stay readable. */
  .lightbox-stage { gap: var(--zero); padding: var(--zero); }
  .lightbox-nav { width: var(--lb-nav-size-sm); height: var(--lb-nav-size-sm); }
  .nav-prev { margin-left: var(--space-2); margin-right: calc((var(--lb-nav-size-sm) + var(--space-2)) * -1); }
  .nav-next { margin-right: var(--space-2); margin-left: calc((var(--lb-nav-size-sm) + var(--space-2)) * -1); }
  .lb-chevron { width: var(--lb-chevron-sm); height: var(--lb-chevron-sm); }
  /* smaller chevron needs a smaller shift to sit in the optical centre */
  .lb-chevron-right { transform: translateX(calc(var(--lb-chevron-nudge-sm) * -1)) rotate(45deg); }
  .lb-chevron-left { transform: translateX(var(--lb-chevron-nudge-sm)) rotate(-135deg); }
}
.lightbox-foot { display: flex; justify-content: center; padding: var(--space-3) var(--gutter) var(--gutter); flex-shrink: 0; }
.lightbox-count { font-size: var(--fs-ui); letter-spacing: var(--track-ui); color: var(--color-on-dark-muted); }
@media (prefers-reduced-motion: reduce) { .lightbox, .lightbox.is-open { transition-duration: var(--zero-time); } }
