/* =========================================================================
   adamleech.net — styles.css
   Layered, token-driven. Every value traces to tokens.md.
   ========================================================================= */

@layer reset, tokens, base, components, utilities;

/* ---------- @layer reset ---------- */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  html, body, h1, h2, h3, h4, h5, h6, p, ul, ol, li, figure, blockquote, dl, dd {
    margin: 0; padding: 0;
  }
  ul, ol { list-style: none; }
  img, picture, video, iframe, svg { display: block; max-width: 100%; }
  img { height: auto; }
  button { background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: pointer; }
  a { color: inherit; text-decoration: none; }
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; }
  :focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
  :focus:not(:focus-visible) { outline: none; }
  ::selection { background: var(--ink); color: var(--surface); }
}

/* ---------- @layer tokens ---------- */
@layer tokens {
  :root {
    /* Type families. Avenir is a system font on Apple devices (Avenir Next / Avenir);
       falls back to the platform UI sans elsewhere. JetBrains Mono (Google-hosted) is
       kept for small technical labels (plate codes, meta). */
    --font-avenir: "Avenir Next", "Avenir", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, "Helvetica Neue", Arial, sans-serif;
    --font-display: var(--font-avenir);
    --font-ui: var(--font-avenir);
    --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

    /* Type scale (px → rem; clamps only on display steps) */
    --t-display-xl: clamp(3.5rem, 7vw, 5.5rem);
    --t-display-l:  clamp(2.5rem, 5.5vw, 4rem);
    --t-display-m:  clamp(2rem, 4vw, 2.75rem);
    --t-display-s:  1.75rem;
    --t-body-l:     clamp(1.25rem, 1.5vw, 1.375rem);
    --t-body:       1rem;
    --t-body-s:     0.875rem;
    --t-meta:       0.8125rem;
    --t-meta-xs:    0.6875rem;
    --t-mono:       0.8125rem;

    /* Line-heights */
    --lh-display: 0.98;
    --lh-display-tight: 0.95;
    --lh-display-relaxed: 1.15;
    --lh-body: 1.65;
    --lh-tight: 1.4;

    /* Tracking */
    --tr-display-xl: -0.025em;
    --tr-display: -0.018em;
    --tr-body: -0.005em;
    --tr-meta: 0.04em;
    --tr-eyebrow: 0.08em;

    /* Weights */
    --fw-light: 300;
    --fw-regular: 400;
    --fw-medium: 500;
    --fw-bold: 600;

    /* Spacing (8px base) */
    --s-1: 0.25rem;  /* 4 */
    --s-2: 0.5rem;   /* 8 */
    --s-3: 0.75rem;  /* 12 */
    --s-4: 1rem;     /* 16 */
    --s-5: 1.5rem;   /* 24 */
    --s-6: 2rem;     /* 32 */
    --s-7: 3rem;     /* 48 */
    --s-8: 4rem;     /* 64 */
    --s-9: 6rem;     /* 96 */
    --s-10: 9rem;    /* 144 */
    --s-11: 12rem;   /* 192 */

    /* Grid */
    --grid-cols: 4;
    --grid-gutter: 1rem;     /* 16 */
    --page-px: 1.25rem;      /* 20 */
    --page-max: 100%;
    --prose-max: 65ch;

    /* Aspect ratios */
    --ar-hero: 16 / 9;
    --ar-square: 1 / 1;
    --ar-portrait: 4 / 5;
    --ar-landscape: 3 / 2;
    --ar-video: 16 / 9;

    /* Color — light theme (default) */
    --surface: #F4F2EE;
    --surface-elevated: #FFFCF7;
    --ink: #0A0A0A;
    --ink-strong: #0A0A0A;
    --ink-muted: #5A5A56;
    --ink-quiet: #8A8884;
    --rule: #E8E5DF;
    --rule-strong: #C8C5BE;
    --focus: #0A0A0A;

    /* Motion */
    --dur-fast: 160ms;
    --dur-base: 320ms;
    --dur-slow: 1600ms; /* hero crossfade transition (legacy alias) */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    --ease-hero: cubic-bezier(0.65, 0, 0.35, 1);

    /* Hero rotation cadence */
    --hero-slide-duration: 2.2s;       /* rest/hold on each slide */
    --hero-crossfade-duration: 0.5s;   /* legacy alias */
    /* Hero transition — Marian Goodman curtain reveal (ported from mariangoodman.com).
       A white curtain wipes the old image away and reveals the new one
       right→left; the image itself drifts horizontally; the caption grows. */
    --hero-img-fade: 400ms;            /* image opacity fade in/out */
    --hero-curtain-duration: 700ms;    /* white curtain wipe */
    --hero-drift-duration: 1200ms;     /* image horizontal drift */
    --hero-curtain-ease: cubic-bezier(0.45, 0, 0.27, 1);
    --hero-drift-ease-in: cubic-bezier(0, 0.73, 0.27, 1);   /* incoming settle */
    --hero-drift-ease-out: cubic-bezier(0.45, 0, 0.27, 1);  /* outgoing exit */
    --hero-drift-from: 5%;             /* incoming image starts shifted right */
    --hero-drift-to: -7%;              /* outgoing image drifts left */
    --hero-img-overscan: 1.12;         /* scale so drift never bares an edge */
    --hero-fade-color: var(--surface); /* curtain colour (paper / "white") */
    --hero-caption-scale-from: 0.82;   /* caption grows from this → 1 */
    --hero-caption-rise: 12px;         /* …and rises this far while fading in */

    /* Hero scroll (Victoria Miro sticky hold-fade) */
    --hero-fade-end-opacity: 0.15;
    --hero-fade-end-scale: 0.97;

    /* Scroll reveal (Marian Goodman pattern) — every non-hero image. */
    --reveal-distance: 28px;
    --reveal-duration: 900ms;
    --reveal-ease: var(--ease-out);

    /* Hero scrim — directional, bottom-only */
    --scrim-hero: linear-gradient(
      to top,
      color-mix(in oklab, var(--ink) 42%, transparent) 0%,
      color-mix(in oklab, var(--ink) 18%, transparent) 18%,
      transparent 38%
    );
    --scrim-hero-coverage: 38%;

    /* Caption-on-image token group */
    --caption-on-image-family: var(--font-ui);
    --caption-on-image-weight: 500;
    --caption-on-image-tracking: 0.08em;
    --caption-on-image-size: var(--t-meta);
    --caption-on-image-color: #F4F2EE;
    --caption-on-image-color-quiet: color-mix(in oklab, #F4F2EE 78%, transparent);
    --hero-caption-bottom: var(--s-8);
    --hero-caption-bottom-desktop: var(--s-9);

    /* Borders */
    --rule-weight: 1px;
    --radius: 0;

    /* z-index */
    --z-base: 0;
    --z-hero: 1;
    --z-content: 2;
    --z-hero-overlay: 5;
    --z-hero-caption: 6;
    --z-nav: 100;
    --z-menu: 110;
    --z-skip: 200;

    /* Breakpoints (for reference; @media literal uses below) */
    color-scheme: light;
  }

  /* Tablet */
  @media (min-width: 601px) {
    :root {
      --grid-cols: 8;
      --grid-gutter: 1.25rem;
      --page-px: 2.5rem;
      --page-max: 100%;
    }
  }
  /* Desktop */
  @media (min-width: 1025px) {
    :root {
      --grid-cols: 12;
      --grid-gutter: 1.5rem;
      --page-px: 4rem;
      --page-max: 1440px;
    }
  }
  /* Wide */
  @media (min-width: 1600px) {
    :root {
      --page-px: 6rem;
      --page-max: 1680px;
    }
  }

}

/* ---------- @layer base ---------- */
@layer base {
  html {
    background: var(--surface);
    color: var(--ink);
    /* Clip (not hidden) so the full-bleed 100vw section grounds can't induce a
       horizontal scrollbar on classic-scrollbar platforms, without turning the
       root into a scroll container (which would break the sticky hero). */
    overflow-x: clip;
    font-family: var(--font-ui);
    font-size: 16px;
    line-height: var(--lh-body);
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
  }
  body {
    font-family: var(--font-ui);
    font-size: var(--t-body);
    background: var(--surface);
    color: var(--ink);
    min-height: 100dvh;
  }

  h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    color: var(--ink-strong);
    font-weight: var(--fw-light);
    letter-spacing: var(--tr-display);
    line-height: var(--lh-display);
  }

  p {
    max-width: var(--prose-max);
    color: var(--ink);
  }

  a { color: inherit; }
  a.link-underline {
    background-image: linear-gradient(currentColor, currentColor);
    background-position: 0 100%;
    background-repeat: no-repeat;
    background-size: 0 1px;
    transition: background-size var(--dur-base) var(--ease-out);
    padding-bottom: 2px;
  }
  a.link-underline:hover { background-size: 100% 1px; }

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

/* ---------- @layer components ---------- */
@layer components {

  /* -- Page layout helpers -- */
  .page {
    padding-inline: var(--page-px);
    max-width: var(--page-max);
    margin-inline: auto;
  }
  .page-section {
    padding-block: var(--s-9);
  }
  /* When two page-sections sit back-to-back, the previous section's
     padding-bottom already supplies the breathing room — drop the
     successor's padding-top so the inter-section gap doesn't stack to a
     ~288px dark band (this was visible between the curated grid and the
     pull-quote section once the video card was removed). */
  .page-section + .page-section { padding-top: var(--s-7); }

  /*
    Content under the sticky hero. Establishes a clean opaque ground at a higher
    z-index than --z-hero so sections slide up over the hero on scroll (Victoria
    Miro hold-fade pattern). Every section that follows .hero inherits this stack.

    These sections carry .page, so the element itself is capped at --page-max and
    centred. A surface fill on the element alone would stop at that cap, letting
    the full-width sticky hero peek out on either side (the "black bands" on wide
    viewports). So the paper ground is painted by a full-bleed ::before that spans
    the whole viewport width, while the content stays measured.
  */
  .hero ~ .page-section,
  .hero ~ .site-content {
    position: relative;
    z-index: var(--z-content);
  }
  .hero ~ .page-section::before,
  .hero ~ .site-content::before {
    content: "";
    position: absolute;
    inset-block: 0;
    left: 50%;
    width: 100vw;
    transform: translateX(-50%);
    background: var(--surface);
    z-index: -1;
  }
  @media (min-width: 1025px) {
    .page-section { padding-block: var(--s-10); }
    .page-section + .page-section { padding-top: var(--s-7); }
  }

  .grid-12 {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--grid-gutter);
  }

  /* -- Skip link -- */
  .skip-link {
    position: fixed;
    top: -3rem; left: var(--page-px);
    z-index: var(--z-skip);
    background: var(--ink); color: var(--surface);
    padding: var(--s-3) var(--s-4);
    font: var(--fw-medium) var(--t-meta)/1 var(--font-ui);
    letter-spacing: var(--tr-meta); text-transform: uppercase;
    transition: top var(--dur-fast) var(--ease-out);
  }
  .skip-link:focus-visible {
    top: var(--s-3);
    outline-offset: 2px;
  }

  /* -- Header / Nav -- */
  .site-header {
    position: sticky; top: 0;
    z-index: var(--z-nav);
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-bottom: var(--rule-weight) solid transparent;
    transition: background-color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
  }
  .site-header[data-scrolled="true"] {
    background: color-mix(in srgb, var(--surface-elevated) 96%, transparent);
    border-bottom-color: var(--rule);
  }
  .site-header__inner {
    display: flex;
    align-items: center;
    gap: var(--s-5);
    padding: clamp(12px, 1.4vw, 18px) var(--page-px);
    max-width: var(--page-max);
    margin-inline: auto;
  }
  .site-header__wordmark {
    font-family: var(--font-display);
    font-style: normal;
    font-size: clamp(1.1875rem, 1.7vw, 1.5rem);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ink-strong);
    flex-shrink: 0;
    line-height: 1;
  }
  .site-header__nav {
    display: none;
    align-items: center;
    margin-inline-start: auto;
  }
  @media (min-width: 1025px) {
    .site-header__nav { display: flex; }
  }
  .site-header__nav a {
    font-family: var(--font-ui);
    font-size: clamp(0.6875rem, 0.76vw, 0.75rem);
    font-weight: 500;
    line-height: 1;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink);
    position: relative;
    padding: var(--s-3) clamp(var(--s-4), 1.4vw, var(--s-5));
  }
  .site-header__nav a + a::before {
    content: "·";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translate(-50%, -56%);
    font-size: 0.875rem;
    letter-spacing: 0;
    color: var(--ink-quiet);
    line-height: 1;
    pointer-events: none;
  }
  .site-header__nav a::after {
    content: "";
    position: absolute;
    left: clamp(var(--s-4), 1.4vw, var(--s-5));
    right: clamp(var(--s-4), 1.4vw, var(--s-5));
    bottom: calc(var(--s-3) - 4px);
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--dur-base) var(--ease-out);
  }
  .site-header__nav a:hover::after,
  .site-header__nav a[aria-current="page"]::after { transform: scaleX(1); }
  .site-header__nav a[aria-current="page"] { color: var(--ink-strong); }

  .site-header__actions {
    display: flex;
    align-items: center;
    gap: var(--s-4);
    margin-inline-start: auto;
  }
  @media (min-width: 1025px) {
    .site-header__actions { margin-inline-start: 0; }
  }
  .site-header__menu-trigger {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
    font-family: var(--font-ui);
    font-size: clamp(0.6875rem, 0.76vw, 0.75rem);
    font-weight: 500;
    line-height: 1;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink);
    padding: var(--s-2) 0;
  }
  @media (min-width: 1025px) {
    .site-header__menu-trigger { display: none; }
  }
  .site-header__menu-trigger svg { width: 18px; height: 18px; stroke: currentColor; }

  /* -- Mobile menu (native <dialog>) -- */
  .mobile-menu {
    border: 0;
    padding: 0;
    margin: 0;
    width: 100vw;
    height: 100dvh;
    max-width: none;
    max-height: none;
    background: var(--surface);
    color: var(--ink);
  }
  .mobile-menu::backdrop { background: rgba(0,0,0,0.4); }
  .mobile-menu__inner {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: var(--s-5) var(--page-px) var(--s-9);
  }
  .mobile-menu__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-block: var(--s-3);
    border-bottom: 1px solid var(--rule);
    margin-bottom: var(--s-8);
  }
  .mobile-menu__close {
    font: var(--fw-medium) var(--t-meta)/1 var(--font-ui);
    letter-spacing: var(--tr-meta);
    text-transform: uppercase;
  }
  .mobile-menu__nav {
    display: flex;
    flex-direction: column;
    gap: var(--s-5);
  }
  .mobile-menu__nav a {
    font-family: var(--font-display);
    font-size: var(--t-display-m);
    font-weight: var(--fw-light);
    letter-spacing: var(--tr-display);
    color: var(--ink-strong);
  }

  /* -- Hero (sticky hold-fade + cross-fade rotation + scrimmed caption) -- */
  .hero {
    position: sticky;
    top: 0;
    /* Subtract the sticky-header height so the pager and caption sit inside
       the visible viewport at scrollY = 0. --header-h is published by JS. */
    height: calc(100svh - var(--header-h, 0px));
    z-index: var(--z-hero);
    overflow: hidden;
    background: var(--ink);
  }
  /* Bottom-only directional scrim (above image, below caption) */
  .hero::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--scrim-hero-coverage);
    background: var(--scrim-hero);
    z-index: var(--z-hero-overlay);
    pointer-events: none;
  }
  /* Stacking context. Scroll hold-fade applies scale + opacity HERE; the
     per-frame curtain/drift run inside, so the two never fight. The paper
     background is the colour the old image fades to. */
  .hero__frames {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: var(--hero-fade-color);
    will-change: opacity, transform;
    transform-origin: center center;
  }

  /* -- Marian Goodman curtain reveal -----------------------------------------
     Each frame is a stacked, full-bleed layer. Hidden frames sit at opacity 0.
     - is-active   : the resting/incoming slide (curtain retracted, image at 0)
     - is-entering : the incoming start state — applied for one frame with no
                     transition (curtain covers, image pre-shifted), then
                     removed so it animates to is-active
     - is-leaving  : the outgoing slide (curtain grows from the right, image
                     drifts left + fades to the paper colour)
     ------------------------------------------------------------------------- */
  .hero__frame {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    z-index: 1;
    overflow: hidden;
    pointer-events: none;
  }
  .hero__frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    /* Overscan so the horizontal drift never bares a paper edge. */
    transform: translateX(0) scale(var(--hero-img-overscan));
    will-change: transform;
  }
  /* The white "curtain". A paper panel over the image; its width animates to
     wipe (out) or reveal (in), always sweeping right→left. */
  .hero__frame::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    width: 100%;
    background: var(--hero-fade-color);
    opacity: 0;
    pointer-events: none;
  }

  /* Resting / incoming slide. */
  .hero__frame.is-active {
    opacity: 1;
    z-index: 3;
    pointer-events: auto;
    transition: opacity var(--hero-img-fade) ease-in-out;
  }
  .hero__frame.is-active img {
    transform: translateX(0) scale(var(--hero-img-overscan));
    transition: transform var(--hero-drift-duration) var(--hero-drift-ease-in);
  }
  .hero__frame.is-active::after {
    /* Curtain retracts to the left edge → reveals image from the right. */
    width: 0;
    left: 0;
    right: auto;
    opacity: 1;
    transition:
      width var(--hero-curtain-duration) var(--hero-curtain-ease),
      opacity var(--hero-img-fade) ease-in-out;
  }

  /* Incoming start state — no transition, so the switch to is-active animates. */
  .hero__frame.is-entering img {
    transform: translateX(var(--hero-drift-from)) scale(var(--hero-img-overscan));
    transition: none;
  }
  .hero__frame.is-entering::after {
    width: 100%;
    left: 0;
    right: auto;
    opacity: 1;
    transition: none;
  }

  /* Outgoing slide. */
  .hero__frame.is-leaving {
    opacity: 1;
    z-index: 2;
    pointer-events: none;
  }
  .hero__frame.is-leaving img {
    transform: translateX(var(--hero-drift-to)) scale(var(--hero-img-overscan));
    opacity: 0;
    transition:
      transform var(--hero-drift-duration) var(--hero-drift-ease-out),
      opacity var(--hero-img-fade) ease-in-out;
  }
  .hero__frame.is-leaving::after {
    /* Curtain grows from the right edge → wipes old image to paper, right→left. */
    width: 100%;
    left: auto;
    right: 0;
    opacity: 1;
    transition: width var(--hero-curtain-duration) var(--hero-curtain-ease);
  }

  /* Per-slide caption — fades in AND scales up (MG's growing title). */
  .hero__frame .hero__caption {
    position: absolute;
    /* Pull left so the padded text still lines up with --page-px */
    left: calc(var(--page-px) - var(--s-4));
    right: auto;
    bottom: var(--hero-caption-bottom);
    z-index: var(--z-hero-caption);
    display: grid;
    gap: var(--s-2);
    width: fit-content;
    max-width: min(720px, calc(100% - var(--page-px) * 2));
    margin: 0;
    /* Faint white wash for legibility — sharp on the left, rounded on the right */
    padding: var(--s-3) var(--s-6) var(--s-3) var(--s-4);
    background: rgba(255, 255, 255, 0.06);
    border-radius: 0 999px 999px 0;
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    opacity: 0;
    transform: translate3d(0, var(--hero-caption-rise), 0) scale(var(--hero-caption-scale-from));
    transform-origin: left bottom;
    pointer-events: none;
  }
  .hero__frame.is-active .hero__caption {
    opacity: 1;
    transform: translate3d(0, 0, 0) scale(1);
    pointer-events: auto;
    /* Appears as the reveal settles (delayed past the curtain wipe). */
    transition:
      opacity var(--hero-drift-duration) var(--hero-drift-ease-in) var(--hero-curtain-duration),
      transform var(--hero-drift-duration) var(--hero-drift-ease-in) var(--hero-curtain-duration);
  }
  .hero__frame.is-leaving .hero__caption {
    opacity: 0;
    transition: opacity 200ms ease-in-out;
  }
  /* Bright/high-contrast slides — darker pill + localised scrim for legibility */
  .hero__frame.is-bright .hero__caption {
    background: rgba(0, 0, 0, 0.42);
    -webkit-backdrop-filter: blur(10px) saturate(1.05);
    backdrop-filter: blur(10px) saturate(1.05);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  }
  .hero__frame.is-bright::before {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 70%;
    height: 55%;
    background: radial-gradient(
      ellipse at left bottom,
      rgba(0, 0, 0, 0.55) 0%,
      rgba(0, 0, 0, 0.25) 35%,
      transparent 70%
    );
    z-index: 1;
    pointer-events: none;
  }
  @media (min-width: 1025px) {
    .hero__frame .hero__caption {
      bottom: var(--hero-caption-bottom-desktop);
    }
  }
  /* Caption-on-image typography (uniform across lines) */
  .hero__caption-line {
    font-family: var(--caption-on-image-family);
    font-weight: var(--caption-on-image-weight);
    font-size: var(--caption-on-image-size);
    letter-spacing: var(--caption-on-image-tracking);
    text-transform: uppercase;
    color: var(--caption-on-image-color);
    line-height: 1.4;
    display: block;
    margin: 0;
    max-width: none;
  }
  .hero__caption-line--quiet {
    color: var(--caption-on-image-color-quiet);
  }
  /* Legacy caption hooks retained for backwards compatibility — restyled to the new system */
  .hero__eyebrow {
    font-family: var(--caption-on-image-family);
    font-weight: var(--caption-on-image-weight);
    font-size: var(--caption-on-image-size);
    letter-spacing: var(--caption-on-image-tracking);
    text-transform: uppercase;
    color: var(--caption-on-image-color);
    line-height: 1.4;
  }
  .hero__title {
    /* Reduced from display-xl to caption-on-image — no oversized hero headline (anti-pattern). */
    font-family: var(--caption-on-image-family);
    font-weight: var(--caption-on-image-weight);
    font-size: var(--caption-on-image-size);
    letter-spacing: var(--caption-on-image-tracking);
    text-transform: uppercase;
    color: var(--caption-on-image-color);
    line-height: 1.4;
  }
  .hero__sub {
    font-family: var(--caption-on-image-family);
    font-style: normal;
    font-weight: var(--caption-on-image-weight);
    font-size: var(--caption-on-image-size);
    letter-spacing: var(--caption-on-image-tracking);
    text-transform: uppercase;
    color: var(--caption-on-image-color-quiet);
    line-height: 1.4;
    max-width: 60ch;
  }

  /* -- Hero dot pager (hl-projects.com pattern) -- */
  .hero__pager {
    position: absolute;
    left: 0;
    right: 0;
    bottom: var(--s-4);
    z-index: var(--z-hero-caption);
    display: flex;
    justify-content: center;
    align-items: center;
    gap: var(--s-3);
    padding: var(--s-2) var(--page-px);
    pointer-events: none;
    will-change: opacity;
  }
  @media (min-width: 1025px) {
    .hero__pager { bottom: var(--s-5); }
  }
  .hero__pager-dot {
    pointer-events: auto;
    appearance: none;
    background: transparent;
    border: 0;
    padding: 8px;
    margin: 0;
    cursor: pointer;
    line-height: 0;
    border-radius: 999px;
    -webkit-tap-highlight-color: transparent;
  }
  .hero__pager-dot-fill {
    display: block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--caption-on-image-color-quiet);
    /* Subtle dark halo so the dot stays legible on lighter-toned slides. */
    box-shadow: 0 0 0 1px color-mix(in oklab, var(--ink) 35%, transparent);
    opacity: 0.65;
    transition:
      opacity var(--dur-base) var(--ease-out),
      background-color var(--dur-base) var(--ease-out),
      transform var(--dur-base) var(--ease-out);
  }
  .hero__pager-dot:hover .hero__pager-dot-fill,
  .hero__pager-dot:focus-visible .hero__pager-dot-fill {
    opacity: 1;
  }
  .hero__pager-dot[aria-current="true"] .hero__pager-dot-fill {
    opacity: 1;
    background: var(--caption-on-image-color);
    transform: scale(1.25);
  }
  .hero__pager-dot:focus-visible {
    outline: 2px solid var(--caption-on-image-color);
    outline-offset: 2px;
  }

  /* -- Eyebrow (reusable section label) -- */
  .eyebrow {
    display: block;
    font: var(--fw-medium) var(--t-meta-xs)/1 var(--font-ui);
    letter-spacing: var(--tr-eyebrow);
    text-transform: uppercase;
    color: var(--ink-muted);
    padding-bottom: var(--s-3);
    border-bottom: 1px solid var(--rule);
    margin-bottom: var(--s-6);
  }

  /* -- Page title block (used on inner pages) -- */
  .page-title {
    padding-block: var(--s-9) var(--s-8);
  }
  @media (min-width: 1025px) {
    .page-title {
      padding-block: var(--s-10) var(--s-9);
      display: grid;
      grid-template-columns: repeat(var(--grid-cols), 1fr);
      column-gap: var(--grid-gutter);
    }
    .page-title__inner {
      grid-column: 1 / span 9;
    }
  }
  .page-title__head {
    font-family: var(--font-display);
    font-size: var(--t-display-l);
    font-weight: var(--fw-light);
    letter-spacing: var(--tr-display);
    line-height: var(--lh-display);
    color: var(--ink-strong);
  }
  .page-title__lead {
    margin-top: var(--s-5);
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--t-body-l);
    font-weight: var(--fw-light);
    color: var(--ink);
    max-width: 60ch;
  }

  /* -- Section opener -- */
  .section-opener {
    display: grid;
    gap: var(--s-3);
    margin-bottom: var(--s-8);
  }
  @media (min-width: 1025px) {
    .section-opener {
      grid-template-columns: repeat(var(--grid-cols), 1fr);
      column-gap: var(--grid-gutter);
      align-items: end;
    }
    .section-opener__title { grid-column: 1 / span 9; }
    .section-opener__aside { grid-column: 10 / -1; text-align: right; }
  }
  .section-opener__title :is(h1, h2) {
    font-size: var(--t-display-l);
    line-height: var(--lh-display);
    color: var(--ink-strong);
  }
  .section-opener__aside {
    font: var(--fw-regular) var(--t-body-s)/1.5 var(--font-ui);
    color: var(--ink-muted);
  }

  /* -- Work card -- */
  .work-card {
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
  }
  .work-card__figure {
    margin: 0;
    background: var(--surface-elevated);
    overflow: hidden;
  }
  .work-card__figure[data-ar="square"] { aspect-ratio: var(--ar-square); }
  .work-card__figure[data-ar="portrait"] { aspect-ratio: var(--ar-portrait); }
  .work-card__figure[data-ar="landscape"] { aspect-ratio: var(--ar-landscape); }
  .work-card__figure[data-ar="video"] { aspect-ratio: var(--ar-video); }
  .work-card__figure[data-ar="video-v1"] { aspect-ratio: 738 / 540; }
  .work-card__figure[data-ar="video-v2"] { aspect-ratio: 720 / 540; }
  .work-card__figure img {
    width: 100%; height: 100%;
    object-fit: cover; object-position: center;
    transition: opacity var(--dur-base) var(--ease-out);
  }
  /* <picture> wrappers must fill their sized parent so the inner img's
     width/height:100% resolves against the frame, not a shrink-wrapped box. */
  .hero__frame picture,
  .work-card__figure picture { display: block; width: 100%; height: 100%; }

  /* Editorial paintings render at their true proportions — no slot crop.
     The intrinsic width/height on each <img> reserves correct space (no CLS).
     Video figures keep their fixed-ratio poster frame (handled above). */
  .work-grid[data-layout="editorial"] .work-card__figure:not([data-lazy-video]) {
    aspect-ratio: auto;
  }
  .work-grid[data-layout="editorial"] .work-card__figure:not([data-lazy-video]) picture,
  .work-grid[data-layout="editorial"] .work-card__figure:not([data-lazy-video]) img {
    height: auto;
  }

  /* -- Video work-card (lazy autoplay, silent loop) -- */
  .work-card__link {
    display: block;
    color: inherit;
    text-decoration: none;
  }
  .work-card__figure[data-lazy-video] { position: relative; }
  .work-card__video {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover; object-position: center;
    opacity: 0;
    transition: opacity 240ms var(--ease-out);
    pointer-events: none;
  }
  .work-card__figure[data-playing="true"] .work-card__video { opacity: 1; }
  @media (prefers-reduced-motion: reduce) {
    .work-card__video { display: none; }
  }
  .work-card__caption {
    display: block;
    padding-top: var(--s-1);
  }
  .work-card__plate {
    display: block;
    font: var(--fw-regular) var(--t-mono)/1 var(--font-mono);
    color: var(--ink-quiet);
    letter-spacing: 0.02em;
    margin-bottom: var(--s-2);
    font-variant-numeric: tabular-nums oldstyle-nums;
  }
  h3.work-card__line {
    font-family: var(--font-ui);
    font-weight: var(--fw-regular);
    font-size: var(--t-body-s);
    line-height: 1.55;
    letter-spacing: 0;
    color: var(--ink-muted);
    max-width: 56ch;
    margin: 0;
    text-wrap: pretty;
  }
  .work-card__line .work-card__title {
    display: inline;
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.0625rem;
    font-weight: var(--fw-regular);
    letter-spacing: -0.005em;
    line-height: 1.3;
    color: var(--ink-strong);
    font-variant-numeric: oldstyle-nums;
  }
  /* Legacy caption hooks — preserved for backwards-compat on other pages */
  .work-card__meta {
    font: var(--fw-regular) var(--t-body-s)/1.5 var(--font-ui);
    color: var(--ink-muted);
    max-width: 50ch;
  }
  .work-card__meta-line + .work-card__meta-line { margin-top: 2px; }

  /* -- Work grid: editorial (home curated scroll) -- */
  .work-grid {
    display: grid;
    gap: var(--s-7) var(--grid-gutter);
  }
  .work-grid[data-layout="editorial"] {
    grid-template-columns: 1fr;
  }
  @media (min-width: 601px) {
    .work-grid[data-layout="editorial"] {
      grid-template-columns: repeat(6, 1fr);
      row-gap: var(--s-9);
    }
  }
  @media (min-width: 1025px) {
    .work-grid[data-layout="editorial"] {
      grid-template-columns: repeat(12, 1fr);
      row-gap: var(--s-10);
    }
  }

  /* Editorial cell placements — one work per row, alternating left/right anchors */
  .cell-lg-l,
  .cell-lg-r,
  .cell-sq-l,
  .cell-sq-r,
  .cell-portrait-l,
  .cell-portrait-r,
  .cell-full { grid-column: 1 / -1; }

  @media (min-width: 601px) {
    .cell-lg-l       { grid-column: 1 / span 5; }
    .cell-lg-r       { grid-column: 2 / span 5; }
    .cell-sq-l       { grid-column: 1 / span 4; }
    .cell-sq-r       { grid-column: 3 / span 4; }
    .cell-portrait-l { grid-column: 1 / span 3; }
    .cell-portrait-r { grid-column: 4 / span 3; }
  }
  @media (min-width: 1025px) {
    .cell-lg-l       { grid-column: 1 / span 8; }
    .cell-lg-r       { grid-column: 5 / span 8; }
    .cell-sq-l       { grid-column: 1 / span 6; }
    .cell-sq-r       { grid-column: 7 / span 6; }
    .cell-portrait-l { grid-column: 1 / span 5; }
    .cell-portrait-r { grid-column: 8 / span 5; }
  }

  /* -- Work grid: index (paintings page) -- */
  .work-grid[data-layout="index"] {
    grid-template-columns: 1fr;
    row-gap: var(--s-8);
  }
  @media (min-width: 1025px) {
    .work-grid[data-layout="index"] {
      grid-template-columns: 1fr 1fr;
      column-gap: var(--s-7);
      row-gap: var(--s-10);
    }
    .work-grid[data-layout="index"] .work-card:nth-child(odd) { padding-right: var(--s-5); border-right: 1px solid var(--rule); }
    .work-grid[data-layout="index"] .work-card:nth-child(even) { padding-left: var(--s-5); }
  }

  /* -- Parallax targets -- */
  .parallax {
    will-change: transform;
  }

  /* -- Exhibition list (CV + Exhibitions page) -- */
  .exhibition-list {
    border-top: 1px solid var(--rule);
  }
  .exhibition-row {
    display: grid;
    gap: var(--s-2);
    padding-block: var(--s-5);
    border-bottom: 1px solid var(--rule);
    transition: background-color var(--dur-fast) var(--ease-out);
  }
  .exhibition-row:hover { background: var(--surface-elevated); }
  @media (min-width: 1025px) {
    .exhibition-row {
      grid-template-columns: 6rem 1fr;
      gap: var(--s-7);
      padding-block: var(--s-6);
    }
  }
  .exhibition-row__year {
    font: var(--fw-regular) var(--t-mono)/1.4 var(--font-mono);
    color: var(--ink-muted);
    letter-spacing: 0;
  }
  .exhibition-row__title {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.125rem;
    font-weight: var(--fw-regular);
    line-height: 1.35;
    color: var(--ink-strong);
    margin-bottom: var(--s-1);
  }
  .exhibition-row__venue {
    font: var(--fw-regular) var(--t-body-s)/1.55 var(--font-ui);
    color: var(--ink-muted);
  }

  .exhibition-group + .exhibition-group { margin-top: var(--s-9); }
  .exhibition-group__head {
    font: var(--fw-medium) var(--t-meta)/1 var(--font-ui);
    letter-spacing: var(--tr-meta);
    text-transform: uppercase;
    color: var(--ink);
    margin-bottom: var(--s-4);
  }

  /* -- Video embed -- */
  .video-embed {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
  }
  .video-embed__frame {
    aspect-ratio: var(--ar-video);
    background: var(--ink);
    overflow: hidden;
    position: relative;
  }
  .video-embed__frame iframe,
  .video-embed__frame img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    object-fit: cover;
  }
  .video-embed__caption {
    display: grid;
    gap: var(--s-2);
  }
  .video-embed__title {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.25rem;
    font-weight: var(--fw-regular);
    color: var(--ink-strong);
    letter-spacing: -0.005em;
  }
  .video-embed__meta {
    font: var(--fw-regular) var(--t-body-s)/1.55 var(--font-ui);
    color: var(--ink-muted);
  }
  .video-embed__link {
    font: var(--fw-medium) var(--t-meta)/1 var(--font-ui);
    letter-spacing: var(--tr-meta);
    text-transform: uppercase;
    color: var(--ink);
    margin-top: var(--s-2);
    align-self: start;
  }

  /* -- CV section (hanging head pattern) -- */
  .cv-section {
    padding-block: var(--s-8);
    border-top: 1px solid var(--rule);
  }
  .cv-section:first-of-type { border-top: 0; padding-top: 0; }
  @media (min-width: 1025px) {
    .cv-section {
      display: grid;
      grid-template-columns: repeat(var(--grid-cols), 1fr);
      column-gap: var(--grid-gutter);
    }
    .cv-section__head { grid-column: 1 / span 3; }
    .cv-section__body { grid-column: 4 / -1; max-width: 65ch; }
  }
  .cv-section__head {
    font-family: var(--font-display);
    font-size: var(--t-display-m);
    font-weight: var(--fw-light);
    letter-spacing: var(--tr-display);
    line-height: var(--lh-display);
    color: var(--ink-strong);
    margin-bottom: var(--s-5);
  }
  .cv-section__body p { margin-bottom: var(--s-4); }
  .cv-section__body p:last-child { margin-bottom: 0; }
  .cv-section__body ul:not(.exhibition-list) {
    display: grid;
    gap: var(--s-3);
  }
  .cv-section__body ul:not(.exhibition-list) li {
    font: var(--fw-regular) var(--t-body)/1.55 var(--font-ui);
    color: var(--ink);
    padding-left: var(--s-4);
    position: relative;
  }
  .cv-section__body ul:not(.exhibition-list) li::before {
    content: "";
    position: absolute;
    left: 0; top: 0.8em;
    width: 8px; height: 1px;
    background: var(--ink-muted);
  }

  /* -- Prose -- */
  .prose {
    max-width: var(--prose-max);
  }
  .prose p + p { margin-top: var(--s-4); }
  .prose p { font-size: var(--t-body); line-height: var(--lh-body); }
  .prose__lead {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--t-body-l);
    font-weight: var(--fw-light);
    line-height: 1.45;
    color: var(--ink-strong);
    margin-bottom: var(--s-6);
  }

  /* -- Wall text (artist statement, museum-style) -- */
  .wall-text {
    display: grid;
    gap: var(--s-7);
    grid-template-columns: 1fr;
  }
  @media (min-width: 1025px) {
    .wall-text {
      grid-template-columns: repeat(var(--grid-cols), 1fr);
      column-gap: var(--grid-gutter);
      align-items: start;
    }
    .wall-text__meta { grid-column: 1 / span 3; }
    .wall-text__body { grid-column: 5 / span 7; }
  }
  .wall-text__meta dl {
    display: grid;
    gap: var(--s-3);
    border-top: 1px solid var(--ink);
    padding-top: var(--s-4);
  }
  .wall-text__meta div {
    display: grid;
    grid-template-columns: 6rem 1fr;
    gap: var(--s-4);
    align-items: baseline;
  }
  .wall-text__meta dt {
    font: var(--fw-medium) var(--t-meta-xs)/1.4 var(--font-ui);
    letter-spacing: var(--tr-eyebrow);
    text-transform: uppercase;
    color: var(--ink-quiet);
    margin: 0;
  }
  .wall-text__meta dd {
    margin: 0;
    font: var(--fw-regular) var(--t-body-s)/1.5 var(--font-ui);
    color: var(--ink);
  }
  .wall-text__title {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: var(--fw-light);
    font-size: clamp(1.625rem, 2.4vw, 2.125rem);
    letter-spacing: -0.012em;
    line-height: 1.15;
    margin-bottom: var(--s-6);
    color: var(--ink-strong);
  }
  .wall-text__lead {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--t-body-l);
    font-weight: var(--fw-light);
    line-height: 1.45;
    color: var(--ink-strong);
    margin-bottom: var(--s-5);
    max-width: 56ch;
    text-wrap: pretty;
  }
  .wall-text__body p:not(.wall-text__lead) {
    font-size: var(--t-body);
    line-height: var(--lh-body);
    color: var(--ink);
    max-width: 56ch;
    text-wrap: pretty;
  }
  .wall-text__body p:not(.wall-text__lead) + p { margin-top: var(--s-4); }

  /* -- Quote / pull line -- */
  .pull {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--t-display-s);
    font-weight: var(--fw-light);
    line-height: 1.35;
    color: var(--ink-strong);
    max-width: 32ch;
    letter-spacing: -0.012em;
  }

  /* -- Contact-specific -- */
  .contact-grid {
    display: grid;
    gap: var(--s-8);
    grid-template-columns: 1fr;
  }
  @media (min-width: 1025px) {
    .contact-grid {
      grid-template-columns: 1fr 1fr;
      gap: var(--s-10);
    }
  }
  .contact-block h3 {
    font-family: var(--font-display);
    font-size: var(--t-display-s);
    font-weight: var(--fw-light);
    margin-bottom: var(--s-4);
    color: var(--ink-strong);
  }
  .contact-block dl {
    display: grid;
    grid-template-columns: 8rem 1fr;
    row-gap: var(--s-3);
    column-gap: var(--s-4);
  }
  .contact-block dt {
    font: var(--fw-medium) var(--t-meta)/1.4 var(--font-ui);
    letter-spacing: var(--tr-meta);
    text-transform: uppercase;
    color: var(--ink-muted);
    padding-top: 3px;
  }
  .contact-block dd {
    margin: 0;
    font: var(--fw-regular) var(--t-body)/1.55 var(--font-ui);
    color: var(--ink);
  }

  /* -- Footer -- */
  .site-footer {
    /* The preceding .page-section already supplies bottom padding (--s-10),
       so the footer doesn't need an additional margin-top — that stacked
       ~144px on top of the section padding and the footer's own top padding,
       which left the bottom of the page feeling empty. */
    padding-block: var(--s-7) var(--s-7);
    border-top: 1px solid var(--rule);
    background: var(--surface);
  }
  .site-footer__inner {
    padding-inline: var(--page-px);
    max-width: var(--page-max);
    margin-inline: auto;
    display: grid;
    gap: var(--s-7);
    grid-template-columns: 1fr;
  }
  @media (min-width: 601px) {
    .site-footer__inner {
      grid-template-columns: 1fr 1fr;
    }
  }
  @media (min-width: 1025px) {
    .site-footer__inner {
      grid-template-columns: repeat(4, 1fr);
      column-gap: var(--grid-gutter);
    }
  }
  .site-footer__col h4 {
    font: var(--fw-medium) var(--t-meta-xs)/1 var(--font-ui);
    letter-spacing: var(--tr-eyebrow);
    text-transform: uppercase;
    color: var(--ink-muted);
    margin-bottom: var(--s-4);
  }
  .site-footer__col p,
  .site-footer__col a {
    font: var(--fw-regular) var(--t-body-s)/1.55 var(--font-ui);
    color: var(--ink);
    display: block;
  }
  .site-footer__col p + p,
  .site-footer__col a + a,
  .site-footer__col p + a,
  .site-footer__col a + p { margin-top: var(--s-2); }
  .site-footer__credit {
    color: var(--ink-quiet) !important;
    font-variant-numeric: oldstyle-nums;
  }
  .site-footer__credit .site-footer__studio {
    display: inline;
    font-family: var(--font-display);
    font-style: italic;
    color: var(--ink) !important;
    background-image: linear-gradient(currentColor, currentColor);
    background-position: 0 100%;
    background-repeat: no-repeat;
    background-size: 0 1px;
    transition: background-size var(--dur-base) var(--ease-out);
    padding-bottom: 1px;
  }
  .site-footer__credit .site-footer__studio:hover { background-size: 100% 1px; }

  /* -- External link arrow -- */
  .ext::after {
    content: " \2197";
    display: inline-block;
    margin-left: 2px;
    font-size: 0.85em;
    transition: transform var(--dur-base) var(--ease-out);
  }
  .ext:hover::after { transform: translate(2px, -2px); }

  /* ---- Video index (editorial alternating scroll) ----
     The video archive reads as a large-format editorial scroll rather than a
     contact sheet: each poster occupies the better part of the grid and is
     anchored alternately left / right with generous whitespace between rows —
     the same `data-layout="editorial"` rhythm as the homepage curated works.
     Posters 06–10 are designed colour title-cards (title baked in); 01–05 are
     photographic stills. Anchor side is driven by :nth-child, so markup stays
     a flat list. */
  .video-grid {
    list-style: none;
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-8);
    margin-top: var(--s-7);
  }
  @media (min-width: 601px) {
    .video-grid {
      grid-template-columns: repeat(6, 1fr);
      column-gap: var(--grid-gutter);
      row-gap: var(--s-9);
    }
    /* odd → left-anchored, even → right-anchored (one column of inset) */
    .video-grid__item { grid-column: 1 / span 5; }
    .video-grid__item:nth-child(even) { grid-column: 2 / span 5; }
  }
  @media (min-width: 1025px) {
    .video-grid {
      grid-template-columns: repeat(12, 1fr);
      row-gap: var(--s-10);
    }
    .video-grid__item { grid-column: 1 / span 7; }
    .video-grid__item:nth-child(even) { grid-column: 6 / span 7; }
  }

  .video-tile { display: block; }
  .video-tile__poster {
    position: relative;
    display: block;
    aspect-ratio: var(--ar-video);
    overflow: hidden;
    background: var(--rule);
  }
  .video-tile__poster picture { display: block; width: 100%; height: 100%; }
  .video-tile__poster img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
    /* deliberately slow, unhurried pan — no motion token sits at this duration */
    transition: transform 600ms var(--ease-out);
  }
  /* subtler than the old contact-sheet (1.03) — large frames need less travel */
  .video-tile:hover .video-tile__poster img,
  .video-tile:focus-visible .video-tile__poster img { transform: scale(1.02); }

  .video-tile__play {
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%) scale(.92);
    width: 56px; height: 56px; border-radius: 50%;
    background: color-mix(in srgb, var(--surface) 90%, transparent);
    display: grid; place-items: center;
    opacity: .85;
    transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
  }
  .video-tile__play::before {
    content: ""; width: 0; height: 0;
    border-left: 15px solid var(--ink);
    border-top: 9px solid transparent;
    border-bottom: 9px solid transparent;
    margin-left: 3px;
  }
  .video-tile:hover .video-tile__play,
  .video-tile:focus-visible .video-tile__play { opacity: 1; transform: translate(-50%, -50%) scale(1); }

  .video-tile__caption {
    display: flex; gap: var(--s-4);
    margin-top: var(--s-4);
    padding-top: var(--s-3);
    border-top: 1px solid var(--rule);
    align-items: baseline;
  }
  .video-tile__num {
    font-family: var(--font-mono);
    font-size: var(--t-mono);
    color: var(--ink-quiet);
    flex-shrink: 0;
  }
  .video-tile__title {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: var(--fw-regular);
    font-size: var(--t-display-s);
    line-height: 1.15;
    letter-spacing: var(--tr-body);
    color: var(--ink-strong);
  }

  @media (prefers-reduced-motion: reduce) {
    .video-tile__poster img, .video-tile__play { transition: none; }
    .video-tile:hover .video-tile__poster img { transform: none; }
    .video-tile__play { transform: translate(-50%, -50%); }
  }

  /* ---- Video feature (dedicated pages: /speech-bubble, /do-you-love-me) ----
     A focused single-video page. Poster facade fills a native-AR stage; the
     Vimeo iframe is injected in-place on click by initVideoFeature(). Per-video
     aspect ratios follow the same instance-rule pattern as .work-card video AR. */
  .video-feature__stage {
    position: relative;
    margin-inline: auto;
    max-width: min(1000px, 100%);
    background: #000;
    overflow: hidden;
  }
  .video-feature__stage[data-ar="4-3"]           { aspect-ratio: 4 / 3; }
  .video-feature__stage[data-ar="do-you-love-me"] { aspect-ratio: 1280 / 937; }

  .video-feature__facade { position: absolute; inset: 0; display: block; }
  .video-feature__facade picture { display: block; width: 100%; height: 100%; }
  .video-feature__facade img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
    transition: transform 600ms var(--ease-out); /* deliberately slow pan — no motion token at this duration */
  }
  .video-feature__facade:hover img,
  .video-feature__facade:focus-visible img { transform: scale(1.02); /* larger stage — subtler than .video-tile's 1.03 */ }

  .video-feature__stage iframe {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    border: 0;
  }

  .video-feature__play {
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%) scale(.92);
    width: 72px; height: 72px; border-radius: 50%;
    background: color-mix(in srgb, var(--surface) 90%, transparent);
    display: grid; place-items: center;
    opacity: .9;
    transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
  }
  .video-feature__play::before {
    content: ""; width: 0; height: 0;
    border-left: 19px solid var(--ink);
    border-top: 12px solid transparent;
    border-bottom: 12px solid transparent;
    margin-left: 4px;
  }
  .video-feature__facade:hover .video-feature__play,
  .video-feature__facade:focus-visible .video-feature__play {
    opacity: 1; transform: translate(-50%, -50%) scale(1);
  }

  .video-feature__meta {
    margin-top: var(--s-5);
    margin-inline: auto;
    max-width: min(1000px, 100%);
    font: var(--fw-regular) var(--t-mono)/1 var(--font-mono);
    letter-spacing: 0.02em;
    color: var(--ink-quiet);
  }
  .video-feature__desc {
    margin-top: var(--s-5);
    margin-inline: auto;
  }
  .video-feature__nav {
    margin-top: var(--s-7);
    margin-inline: auto;
    max-width: min(1000px, 100%);
    font: var(--fw-regular) var(--t-body-s)/1.5 var(--font-ui);
  }

  @media (prefers-reduced-motion: reduce) {
    .video-feature__facade img,
    .video-feature__play { transition: none; }
    .video-feature__facade:hover img { transform: none; }
    .video-feature__play { transform: translate(-50%, -50%); }
  }

  /* ---- Video lightbox ---- */
  .video-lightbox {
    width: min(1100px, 92vw);
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--surface);
    overflow: visible;
  }
  .video-lightbox::backdrop {
    background: color-mix(in srgb, var(--ink) 88%, transparent);
    backdrop-filter: blur(2px);
  }
  .video-lightbox__stage {
    position: relative;
    aspect-ratio: var(--ar-video);
    background: #000;
    box-shadow: 0 30px 80px rgba(0, 0, 0, .5);
  }
  .video-lightbox__frame, .video-lightbox__stage iframe {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    border: 0;
  }
  .video-lightbox__title {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: var(--fw-regular);
    font-size: var(--t-display-s);
    margin-bottom: var(--s-3);
    color: var(--surface);
  }
  .video-lightbox__close {
    position: absolute; top: -44px; right: 0;
    font-family: var(--font-mono);
    font-size: var(--t-meta);
    letter-spacing: var(--tr-meta);
    text-transform: uppercase;
    color: var(--surface);
    opacity: .8;
    transition: opacity var(--dur-base) var(--ease-out);
  }
  .video-lightbox__close:hover { opacity: 1; }
  .video-lightbox__nav {
    position: absolute; top: 50%; transform: translateY(-50%);
    width: 48px; height: 48px;
    display: grid; place-items: center;
    background: color-mix(in srgb, var(--surface) 14%, transparent);
    color: var(--surface);
    font-size: 1.5rem; line-height: 1;
    opacity: .75;
    transition: opacity var(--dur-base) var(--ease-out);
  }
  .video-lightbox__nav:hover { opacity: 1; }
  .video-lightbox__nav[data-dir="prev"] { left: -64px; }
  .video-lightbox__nav[data-dir="next"] { right: -64px; }
  /* Arrows sit outside the stage only when the viewport can clear them:
     the dialog caps at 1100px, each arrow needs 64px beyond it, so below
     1100 + 2×64 = 1228px we tuck them just inside the player instead. */
  @media (max-width: 1228px) {
    .video-lightbox__nav[data-dir="prev"] { left: 6px; }
    .video-lightbox__nav[data-dir="next"] { right: 6px; }
  }
  @media (prefers-reduced-motion: reduce) {
    .video-lightbox__nav, .video-lightbox__close { transition: none; }
  }
}

/* ---------- @layer utilities ---------- */
@layer utilities {
  .sr-only {
    position: absolute !important;
    width: 1px !important; height: 1px !important;
    padding: 0 !important; margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0,0,0,0) !important;
    white-space: nowrap !important;
    border: 0 !important;
  }
  .hide-mobile { display: none; }
  @media (min-width: 1025px) { .hide-mobile { display: initial; } }
  .hide-desktop { display: initial; }
  @media (min-width: 1025px) { .hide-desktop { display: none; } }

  .mt-section { margin-top: var(--s-9); }
  .mt-page { margin-top: var(--s-10); }

  /* ---------- Scroll reveal (Marian Goodman pattern) ----------
     Every non-hero image is tagged with [data-reveal]. The element sits
     opacity:0 + translated 28px below its final position until an
     IntersectionObserver flips on .is-revealed, at which point it slowly
     rises and fades into place. Lives on the <img> so it does not collide
     with [data-parallax] on the wrapping figure. */
  [data-reveal] {
    opacity: 0;
    transform: translate3d(0, var(--reveal-distance), 0);
    transition:
      opacity var(--reveal-duration) var(--reveal-ease),
      transform var(--reveal-duration) var(--reveal-ease);
    will-change: opacity, transform;
  }
  [data-reveal].is-revealed {
    opacity: 1;
    transform: translate3d(0, 0, 0);
    will-change: auto;
  }

  /* ---------- Card reveal (Selected Works) ----------
     Whole-card lift + fade with a left-to-right row stagger driven by
     --reveal-index (set in script.js from each card's row position).
     Symmetric: cards park 40px below the viewport (default / "below" state)
     when waiting to enter from beneath, and park 40px above ("above" state)
     after the user has scrolled past them. Either way, re-entry animates
     them back to (opacity 1, translateY 0) — so scrolling down lifts them
     up into place, and scrolling back up drops them down into place. */
  [data-card-reveal] {
    opacity: 0;
    transform: translate3d(0, 40px, 0);
    transition:
      opacity 800ms cubic-bezier(0.22, 1, 0.36, 1),
      transform 800ms cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: calc(var(--reveal-index, 0) * 120ms);
    will-change: opacity, transform;
  }
  [data-card-reveal][data-card-state="above"] {
    transform: translate3d(0, -40px, 0);
  }
  [data-card-reveal][data-card-state="visible"] {
    opacity: 1;
    transform: translate3d(0, 0, 0);
    will-change: auto;
  }
}

/* ---------- Reduced motion: blanket override (NOT in a layer; must win) ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Drop sticky positioning and skip the opacity/scale animation on the hero. */
  .hero {
    position: relative !important;
    height: auto !important;
  }
  .hero__frames {
    height: clamp(560px, 92dvh, 880px) !important;
    transform: none !important;
    opacity: 1 !important;
  }
  .hero__frames img {
    transform: none !important;
    opacity: 1 !important;
  }
  .hero__frame .hero__caption {
    opacity: 1 !important;
    transition: none !important;
  }
  .hero__pager {
    opacity: 1 !important;
  }
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  [data-card-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    transition-delay: 0ms !important;
  }
  .hero__pager-dot-fill {
    transition: none !important;
  }
  .parallax { transform: none !important; }
}
