
    :root, .sw-root {
      --sw-bg: #FBFBEF;          /* GJB ivory */
      --sw-ink: #111111;
      --sw-ink-soft: rgba(17,17,17,.66);
      --sw-accent: #111111;
      --sw-font-display: "Bodoni Moda", "Times New Roman", serif;
      --sw-font-body: "Figtree", -apple-system, "Helvetica Neue", Arial, sans-serif;
      --sw-forest: #1E3B32;      /* GJB forest */
    }
    /* Hero copy sits OUTSIDE the animation (fixed, above the stage). The layer spans
       the full width so the headlines can hold the top left corner while the opening
       eyebrow stays centred on the screen above them. */
    .hero-copy-v2 {
      position: fixed;
      /* clears the fixed top nav (81px) so the eyebrow never sits under the links */
      top: clamp(100px, 12vh, 128px);
      left: clamp(22px, 4.5vw, 64px);
      right: clamp(22px, 4.5vw, 64px);
      z-index: 200;
      pointer-events: none;
      color: var(--sw-ink);
      font-family: var(--sw-font-body);
      text-align: left;
    }
    /* the one centred element: the name over the world */
    #copyStart .eyebrow { text-align: center; }
    .hero-copy-v2 .block {
      position: absolute; top: 0; left: 0; right: 0;
      opacity: 0; transition: none; will-change: opacity, transform;
    }
    /* The second beat lands in exactly the same spot as the first: same left edge,
       same baseline, so the two headlines read as one lockup swapping its words.
       The hidden eyebrow in the markup holds the vertical space; no offset here.
       (mount.js rewrites `transform` on these blocks every frame, so any offset
       that is ever needed has to ride the independent `translate` property.) */
    /* Centred over the film, the copy crosses everything from bright sky to near
       black, so each line carries a tight ivory halo that widens into a soft glow.
       It keeps the type legible on any frame without putting a panel behind it. */
    .hero-copy-v2 .eyebrow {
      display: block;
      font-family: var(--sw-font-display);
      font-size: .78rem; letter-spacing: .18em; text-transform: uppercase;
      color: var(--sw-forest); font-weight: 600; margin-bottom: 18px;
      text-shadow: 0 0 3px rgba(251, 251, 239, .96), 0 0 9px rgba(251, 251, 239, .9),
                   0 0 20px rgba(251, 251, 239, .7);
    }
    /* The hero line is the largest type on the page — the section displays sit a
       step below it. Bodoni takes its own optical size here: the body pins opsz
       to 9 for small text, and at 88px that reads as blown-up body copy.
       The halo keeps a tight core so the hairlines stay sharp and spends its
       spread on a low-alpha outer layer, rather than four stacked glows that
       fill in the counters. */
    .hero-copy-v2 h1 {
      font-family: var(--sw-font-display);
      font-weight: 500; letter-spacing: -.015em;
      font-size: clamp(1.97rem, 3.81vw, 3.62rem); line-height: 1.04; margin: 0;
      color: var(--sw-ink);
      /* opsz 9 is the thicker cut of Bodoni: the high optical sizes thin the
         hairlines to a poster weight that breaks up over moving film. */
      font-variation-settings: "opsz" 9;
      /* the break is authored in the markup as a two-line lockup; balance only
         has to hold the rare narrow-viewport re-wrap of a single line */
      text-wrap: balance;
      text-shadow: 0 0 2px rgba(251, 251, 239, .95), 0 0 12px rgba(251, 251, 239, .82),
                   0 0 36px rgba(251, 251, 239, .5);
    }
    .hero-copy-v2 p {
      margin: 16px 0 0; font-size: clamp(1rem, 1.2vw, 1.12rem);
      line-height: 1.55; color: var(--sw-forest);
      max-width: 42ch; text-wrap: pretty;
      text-shadow: 0 0 3px rgba(251, 251, 239, .96), 0 0 9px rgba(251, 251, 239, .9),
                   0 0 20px rgba(251, 251, 239, .7);
    }
    /* The closing line is split into words and characters by mount.js so each letter
       comes up as the tail of the plane clears it. Words stay inline-block so the
       line still wraps between them and never inside one. */
    .hero-copy-v2 p .wd { display: inline-block; }
    .hero-copy-v2 p .ch { display: inline-block; will-change: opacity, transform; }
    /* Scroll anchoring fights the fixed-stage scrub and drifts the page on its own */
    html, body { overflow-anchor: none; }
    /* Hide engine chrome we do not want: brand bar, nav, copy layer gradient */
    .sw-topbar, .sw-copylayer::before, .sw-copy__num, .sw-route { display: none !important; }
    /* The engine seeds 20 drifting dark particles over the film. On this build they
       read as grain/dirt on the footage, not atmosphere. Off. (The engine also gates
       them on `atmosphere`, but it builds and seeds them outside that flag, so the
       config alone does not remove them.) */
    .sw-particles { display: none !important; }

    /* The film starts below the fixed nav rather than running under its blur panel,
       so the ivory band at the top of the page reads as a deliberate frame.
       (Engine CSS is injected at runtime, so this needs !important to win.) */
    .sw-stage { top: 76px !important; }
    @media (max-width: 700px) { .sw-stage { top: 62px !important; } }

    /* ---- Reveal: a turntable head that looks around, then turns human ---- */
    /* The engine sets overflow-x:hidden, which makes html/body a scroll container
       and stops position:sticky pinning to the viewport. `clip` gives the same
       horizontal containment without creating that scroll container. */
    html, body { overflow-x: clip; }
    /* Scoped to the id, not the class: `.reveal` is also the big typographic
       paragraph class in styles.css, and a bare `.reveal` rule was giving that
       paragraph a 340vh height (the empty screen after the s07 line). */
    #reveal { position: relative; background: var(--sw-bg); height: 340vh; }
    .reveal__sticky {
      position: sticky; top: 0; height: 100vh;
      display: flex; flex-direction: column; align-items: center; justify-content: center;
      gap: clamp(14px, 2.6vh, 32px); padding: clamp(20px, 4vh, 56px) clamp(20px, 5vw, 72px);
    }
    /* The measure was 44ch computed at the 16px body size (~350px) while the
       headline inside renders at up to 45px, so a two-line headline broke into
       four with an orphan on the last. Each child now carries its own measure,
       set in its own type size. */
    .reveal__copy { text-align: center; max-width: min(92vw, 46rem); color: var(--sw-ink); font-family: var(--sw-font-body); }
    .reveal__copy .eyebrow {
      display: block; font-family: var(--sw-font-display);
      font-size: .78rem; letter-spacing: .18em; text-transform: uppercase; font-weight: 600; margin-bottom: 16px;
      color: var(--sw-ink-soft);
    }
    .reveal__copy h2 {
      font-family: var(--sw-font-display); font-weight: 500; letter-spacing: -.015em;
      font-size: clamp(1.75rem, 3.1vw, 2.8rem); line-height: 1.08; margin: 0 auto;
      font-variation-settings: "opsz" 9; text-wrap: balance; max-width: 26ch;
    }
    /* "You built the trust first." is the payoff of the whole turntable, so it is
       set a clear step above the other body lines rather than at caption size. */
    .reveal__copy p { margin: 16px auto 0; font-size: clamp(1.18rem, 1.55vw, 1.42rem); line-height: 1.5; color: var(--sw-ink-soft); max-width: 34ch; text-wrap: pretty; }

    /* The stage is a fixed-ratio box. Heads are sized by HEIGHT, never width, so
       they can never outgrow the box when max-height clamps it. */
    .turn {
      position: relative; width: min(100%, 1080px); aspect-ratio: 1080 / 560;
      max-height: 46vh; margin: 0 auto;
    }
    .turn img {
      position: absolute; display: block; width: auto;
      object-fit: contain; will-change: opacity, transform;
    }
    /* The other busts orbit a shallow ellipse behind the lead. JS owns their
       transform; CSS only anchors them to the centre of the stage. */
    .turn .ghost {
      z-index: 1; height: 46%; left: 50%; top: 50%; opacity: 0;
      filter: saturate(.45) blur(2px);
      transform: translate(-50%, -50%);
    }
    /* The head that stays put. Every angle is stacked here and cross-dissolved,
       so the face changes direction without the head moving. */
    .turn .lead {
      z-index: 2; height: 100%; top: 0; left: 50%;
      transform: translateX(-50%); opacity: 0;
    }
    /* The human layer is not cross-faded in. It is unmasked from the base up, so
       the marble appears to turn to flesh rather than dissolve. */
    .turn .lead.is-human {
      z-index: 3; opacity: 1;
      -webkit-mask-image: linear-gradient(to top, #000 -20%, rgba(0,0,0,0) -2%);
      mask-image: linear-gradient(to top, #000 -20%, rgba(0,0,0,0) -2%);
    }
    /* A warm band that rides the wipe line, so the change has an edge you can see. */
    .turn__glow {
      position: absolute; z-index: 4; left: 50%; top: 0;
      height: 13%; pointer-events: none; opacity: 0;
      transform: translate(-50%, -50%);
      background: radial-gradient(ellipse at center,
        rgba(201,168,76,.55) 0%, rgba(201,168,76,.18) 45%, rgba(201,168,76,0) 72%);
      filter: blur(6px);
    }

    /* ---- Salute: the closing beat ---- */
    /* Scoped to #salute, not the bare class. The main page has its own
       .salute figure in the closing section, and this full-height flex rule was
       reaching it and padding it out with half a screen of empty space. */
    #salute {
      position: relative; background: var(--sw-bg);
      min-height: 100vh; display: flex; align-items: center; justify-content: center;
      gap: clamp(24px, 5vw, 80px); padding: clamp(48px, 9vh, 120px) clamp(20px, 5vw, 72px);
      flex-wrap: wrap;
    }
    .salute__copy {
      max-width: 34ch; color: var(--sw-ink); font-family: var(--sw-font-body);
      opacity: 0; transform: translateY(18px); will-change: opacity, transform;
    }
    .salute__copy .eyebrow {
      display: block; font-family: var(--sw-font-display);
      font-size: .78rem; letter-spacing: .18em; text-transform: uppercase; font-weight: 600; margin-bottom: 16px;
      color: var(--sw-ink-soft);
    }
    .salute__copy h2 {
      font-family: var(--sw-font-display); font-weight: 500; letter-spacing: -.015em;
      font-size: clamp(1.95rem, 3.5vw, 3.1rem); line-height: 1.05; margin: 0;
      font-variation-settings: "opsz" 9; text-wrap: balance;
    }
    .salute__copy p { margin: 16px 0 0; font-size: clamp(1rem, 1.15vw, 1.1rem); line-height: 1.55; color: var(--sw-ink-soft); }
    .salute__figure {
      height: min(76vh, 720px); width: auto; display: block;
      opacity: 0; transform: translateY(26px) scale(.985); will-change: opacity, transform;
    }

    @media (max-width: 700px) {
      #reveal { height: 300vh; }
      /* A wide orbit is unreadable on a phone; the ring is pulled in by JS and the
         box goes taller so the lead head keeps its scale. */
      .turn { aspect-ratio: 1080 / 700; max-height: 44vh; }
      .turn .ghost { height: 38%; }
      #salute { flex-direction: column; text-align: center; gap: 28px; }
      .salute__copy { max-width: 32ch; }
      .salute__figure { height: min(58vh, 520px); }
    }
    @media (prefers-reduced-motion: reduce) {
      #reveal { height: auto; }
      .reveal__sticky { position: static; height: auto; }
      .turn .lead.is-human {
        opacity: 1 !important;
        -webkit-mask-image: none !important; mask-image: none !important;
      }
      .turn__glow { display: none; }
      .salute__copy, .salute__figure { opacity: 1 !important; transform: none !important; }
    }
  