html, body { margin: 0; background: #08060B; }
  /* One horizontal margin for the whole page: the nav and every section align to it. */
  :root { --page-gutter: 8vw; }
  #gl { position: fixed; inset: 0; width: 100vw; height: 100vh; display: block; z-index: 0; pointer-events: none; }
  /* no-WebGL poster: the finished planet, drawn in CSS so it needs no asset */
  #poster {
    position: fixed; inset: 0; z-index: 0; display: none; pointer-events: none;
    background:
      radial-gradient(circle 20vmin at 68% 62%, rgba(28,162,112,.55), rgba(255,210,122,.30) 48%, rgba(24,14,38,.85) 72%, transparent 78%),
      radial-gradient(circle 34vmin at 68% 62%, rgba(255,210,122,.10), transparent 70%),
      #08060B;
  }
  #poster[data-on="true"] { display: block; }
  .vignette {
    position: fixed; inset: 0; z-index: 2; pointer-events: none;
    background: radial-gradient(ellipse 80% 80% at 42% 50%, transparent 24%, rgba(8,6,11,.60) 76%, rgba(8,6,11,.90) 100%);
  }
  /* The nav sits ON the sections rather than over a slab of its own: nothing but blur, so the
     field, artwork and particles stay visible through it. The design system's .cds-nav carries a
     near-opaque background by default, which is what was hiding them — this overrides it. */
  .cds-nav-transparent {
    background: transparent; border-bottom-color: transparent;
    -webkit-backdrop-filter: none; backdrop-filter: none;
    transition: background var(--dur-slow) var(--ease-divine),
                border-color var(--dur-slow) var(--ease-divine),
                -webkit-backdrop-filter var(--dur-slow) var(--ease-divine),
                backdrop-filter var(--dur-slow) var(--ease-divine);
  }
  .cds-nav-transparent[data-scrolled="true"] {
    /* a heavy blur with only a whisper of tint — enough to hold the type, not enough to mask */
    background: rgba(8, 6, 11, 0.16);
    -webkit-backdrop-filter: blur(20px) saturate(130%);
    backdrop-filter: blur(20px) saturate(130%);
    border-bottom-color: var(--line-hairline);
  }
  .nav-fixed {
    position: fixed; top: 0; left: 0; right: 0; z-index: 40;
    padding-left: var(--page-gutter); padding-right: var(--page-gutter);
  }
  #hero {
    position: relative; z-index: 3; min-height: 100vh;
    display: flex; flex-direction: column; align-items: flex-start;
    padding: calc(66px + var(--space-7)) var(--page-gutter) var(--space-6);
    box-sizing: border-box;
  }
  .hero-copy { position: relative; margin: auto 0; max-width: 46ch; }
  .hero-kicker {
    font-family: var(--font-mono); font-size: var(--text-kicker); letter-spacing: var(--tracking-kicker);
    text-transform: uppercase; color: var(--text-emerald); margin: 0 0 var(--space-4);
  }
  .hero-title {
    font-family: var(--font-display); font-weight: 500; font-size: clamp(30px, 3.5vw, 58px);
    line-height: 1.06; letter-spacing: var(--tracking-display); margin: 0 0 var(--space-5);
    color: var(--text-primary); text-shadow: 0 2px 48px rgba(8,6,11,.8);
  }
  .hero-title span { display: block; white-space: nowrap; }
  .hero-title em { font-style: normal; color: var(--gold); text-shadow: 0 0 34px rgba(255,210,122,.4); }
  .hero-sub { color: var(--text-secondary); font-size: var(--text-body-lg); margin: 0 0 var(--space-6); max-width: 40ch; }
  .hero-actions { display: flex; gap: var(--space-3); flex-wrap: wrap; }
  @media (max-height: 700px) {
    .hero-title { font-size: clamp(26px, 2.9vw, 42px); }
    .hero-sub { font-size: var(--text-body); margin-bottom: var(--space-5); }
  }
  /* ---- second section: the refusal ---- */
  /* transparent, so the live galaxy field shows through and parallaxes behind it */
  .chapter {
    position: relative; z-index: 5; overflow: hidden;
    background: transparent;
    padding: var(--space-10) var(--page-gutter) var(--space-9);
  }
  /* scrim: a soft pool of void behind the copy only */
  .chapter::before {
    content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background: radial-gradient(ellipse 54% 46% at 50% 50%, rgba(8, 6, 11, 0.52), rgba(8, 6, 11, 0.26) 60%, transparent 84%);
  }
  .chapter-inner {
    position: relative; z-index: 2; max-width: var(--content-max); margin: 0 auto;
    display: flex; justify-content: center;
  }
  .chapter-copy { max-width: 100%; text-align: center; }
  .chapter-title {
    font-family: var(--font-display); font-weight: 500; font-size: clamp(30px, 3.9vw, 60px);
    line-height: 1.04; letter-spacing: var(--tracking-display);
    color: var(--text-primary); margin: 0 0 var(--space-5); text-wrap: pretty;
    text-shadow: 0 2px 40px rgba(8, 6, 11, 0.9);
  }
  .chapter-title em { font-style: normal; color: var(--text-violet); }
  .chapter-title span { display: block; }   /* block gives the two lines; no nowrap, so a narrow container wraps instead of clipping */
  .chapter-body {
    color: var(--text-secondary); font-size: var(--text-body-lg);
    max-width: 46ch; margin: 0 auto var(--space-6);
    text-shadow: 0 1px 24px rgba(8, 6, 11, 0.95);
  }
  .chapter-body span { display: block; }
  .chapter-body-focus { color: var(--text-primary); margin-top: var(--space-4); }
  .chapter-actions {
    display: flex; align-items: center; justify-content: center; gap: var(--space-5);
    border-top: 1px solid var(--line-hairline); padding-top: var(--space-6);
  }
  .chapter-cta {
    display: inline-flex; align-items: center; height: 46px; padding: 0 var(--space-5);
    border: 1px solid var(--line-gilded); border-radius: var(--radius-pill);
    font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase;
    color: var(--gold); text-decoration: none;
    transition: background var(--dur-fast) var(--ease-divine), border-color var(--dur-fast) var(--ease-divine);
  }
  .chapter-cta:hover { background: rgba(255, 210, 122, 0.08); border-color: var(--line-gilded-strong); text-decoration: none; }
  .chapter-cta:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
  .chapter-link {
    font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.12em;
    color: var(--text-muted); text-decoration: none;
  }
  .chapter-link:hover { color: var(--gold); text-decoration: none; }
  /* ---- ninth section: the walk-in. Six painted stations, scrubbed by the section's own scroll
     position. Ported from the standalone study WITHOUT its Lenis + ScrollTrigger + second canvas:
     this page already owns a scroll-driven render loop, and two scroll systems fight over the same
     wheel events. The plates are DOM, so they cost no extra WebGL context. ---------- */
  .halls { z-index: 6; }
  .halls {
    position: relative; z-index: 5;
    /* five viewports of travel, so the walk reads as slow rather than a lurch */
    height: 500vh;
    background: transparent;
  }
  .halls-stage {
    position: sticky; top: 0; height: 100vh; overflow: hidden;
    /* opaque void, so the page's own galaxy field behind cannot bleed into this section */
    background: var(--surface-0);
  }
  /* LAYER 0 — void + starfield + atmosphere, in a canvas scoped to this stage. The page's main
     canvas is fixed and owns sections 1-8; a section-local context is what keeps the two from
     competing for the same frame. */
  .halls-air {
    position: absolute; inset: 0; z-index: 0;
    display: block; width: 100%; height: 100%; pointer-events: none;
  }
  /* LAYER 3 — foreground cut-outs, pinned to the stage's bottom edge and parallaxing faster than
     the plates, which is what places them nearest the lens */
  .halls-fg {
    position: absolute; left: 0; right: 0; bottom: 0;
    z-index: 7; pointer-events: none; will-change: transform;
  }
  #hf-steps {
    left: -4%; right: -4%; height: min(34vh, 380px);
    background: url("../../assets/fg-steps.webp") center bottom / 108% auto no-repeat;
  }
  .halls-fg-col { width: min(28vw, 320px); height: min(48vh, 520px); }
  #hf-col-left {
    left: -2%; right: auto;
    background: url("../../assets/fg-broken-column.webp") left bottom / auto 100% no-repeat;
  }
  #hf-col-right {
    right: -2%; left: auto;
    background: url("../../assets/fg-broken-column.webp") left bottom / auto 100% no-repeat;
  }
  #hf-mist {
    height: 30vh;
    background: url("../../assets/fg-mist.webp") center bottom / cover no-repeat;
    /* the plate carries a black field rather than alpha: screen drops the black, keeps the glow */
    mix-blend-mode: screen; opacity: 0.9;
  }
  .halls-plate {
    position: absolute; inset: 0;
    opacity: 0; pointer-events: none;
    will-change: opacity, transform;
    /* the vanishing point every plate shares, so a dissolve never shifts the receding point */
    transform-origin: 56% 50%;
  }
  .halls-plate img {
    display: block; width: 100%; height: 100%;
    object-fit: cover; object-position: center;
  }
  /* The facade is a whole object, not a room: contain, so the pediment and both outer columns stay
     in frame. Bottom-anchored and pushed right, which leaves the upper-left near-black for the
     heading. It also starts at its own origin so the push-in begins from a fitted view, never
     already inside it. */
  #hp-facade img {
    object-fit: contain;
    /* The plate is ~3:1 in a ~1.7:1 frame, so contain fits by WIDTH — any scale above 1 can only
       grow its height by pushing the outer columns off frame. Height therefore comes from
       anchoring the fitted band to the floor, never from scale, so the whole colonnade stays. */
    object-position: 50% 100%;
    transform: scale(1);
    transform-origin: 50% 96%;
  }
  /* stacked in scroll order: each station covers the one before it, so a dissolve never opens a
     hole to the void — two semi-transparent plates over black composite to 75%, not 100% */
  #hp-facade { z-index: 1; opacity: 1; transform-origin: 50% 92%; }
  #hp-int-b  { z-index: 2; }
  #hp-int-c  { z-index: 3; }
  /* both rooms recede to the same screen point as the facade's doorway, so a crossfade never
     shifts what the eye is tracking */
  #hp-int-b, #hp-int-c { transform-origin: 56% 50%; }
  .halls-bloom {
    position: absolute; inset: 0; z-index: 8;
    opacity: 0; pointer-events: none;
    /* covers the frame at rest, so only its opacity ever changes — a scaled gradient reads as a
       panel sliding in, which is exactly what it must not do */
    background: radial-gradient(circle at 56% 46%, #FFFFFF 0%, #FFF6E2 34%, var(--gold) 74%, #FFE7B4 100%);
    will-change: opacity;
  }
  /* ---- tenth section: the constellation sky. It mounts UNDER section 9's white bloom, so the
     flash is the bridge between them rather than a cut. ---- */
  /* Taller than the viewport with a sticky stage inside, exactly as .halls is built: at 100vh this
     section was the LAST one, so its top never rose above 0 and any window needing more than full
     coverage was unreachable — the white sheet could never burn off and the copy never revealed. */
  .sky {
    position: relative; z-index: 4;   /* below .halls, so section nine paints over it */
    background: var(--surface-0);
    height: 200vh;
    /* One viewport of shared pinned space for the in-place swap with section nine, plus one
       viewport of its own — so the sky is fully revealed within about a normal scroll rather than
       holding the page for multiple screen-heights. */
    margin-top: -100vh;
  }
  .sky-stage {
    position: sticky; top: 0; height: 100vh; overflow: hidden;
    display: flex; align-items: flex-start;
    padding: calc(66px + var(--space-8)) var(--page-gutter) var(--space-8);
    box-sizing: border-box;
  }
  /* the live scene: fixed inside the section, behind the white sheet and the copy */
  .sky-canvas {
    position: absolute; inset: 0; z-index: 0;
    width: 100%; height: 100%; display: block; pointer-events: none;
  }
  .sky-inner {
    position: relative; z-index: 4; max-width: var(--content-max); margin: 0 auto; width: 100%;
    /* copy left, the Keepers right — the copy column takes a floor so the figures can never
       squeeze the headline; the artwork can crop, the type cannot */
    display: grid; grid-template-columns: minmax(min(420px, 100%), 0.86fr) minmax(0, 1fr);
    align-items: center; gap: var(--space-6);
  }
  .sky-art {
    position: relative;
    /* stays inside the container: the artwork fills its grid track and no more, so it never
       breaks the section's gutter while still reading as the section's hero asset */
    width: 100%;
    will-change: transform, opacity;
  }
  .sky-art img {
    /* mirrored, so the burning arrow points inward toward the copy rather than off the frame */
    transform: scaleX(-1);
    display: block; width: 100%; height: auto;
    /* The supplied plate had a transparency checkerboard baked into its pixels with no alpha at
       all, so it read as a bright grey-checkered box on the void. It is keyed here — bright AND
       low-chroma, on soft ramps so the gold and emerald rim survive — and the vignette then only
       has to dissolve the cloaks' outer edge rather than hide a rectangle. */
    -webkit-mask-image: radial-gradient(ellipse 82% 86% at 50% 48%, #000 54%, rgba(0,0,0,0.55) 82%, transparent 100%);
    mask-image: radial-gradient(ellipse 82% 86% at 50% 48%, #000 54%, rgba(0,0,0,0.55) 82%, transparent 100%);
    /* No emerald glow: a 70px drop-shadow in #1CA270 wrapped the whole silhouette in green and
       read as a coloured background behind a plate that is in fact transparent. Only the dark
       shadow remains, which seats the figures on the void without tinting it. */
    filter: drop-shadow(0 24px 60px rgba(8, 6, 11, 0.9));
  }
  @media (max-width: 900px) {
    .sky-inner { grid-template-columns: 1fr; }
    .sky-art { width: 100%; max-width: 600px; margin: 0 auto; }
  }
  .sky-copy { max-width: min(640px, 76vw); will-change: transform, opacity; }
  .sky-title {
    font-family: var(--font-display); font-weight: 500; font-size: clamp(28px, 2.6vw, 40px);
    line-height: 1.04; letter-spacing: var(--tracking-display);
    color: var(--text-primary); margin: 0 0 var(--space-5);
    text-shadow: 0 2px 40px rgba(8, 6, 11, 0.92);
    /* two authored lines now: 14.4em clears the longer of them with room to spare */
    max-width: 14.4em;
  }
  .sky-title span { display: block; }
  .sky-body strong { color: var(--text-primary); font-weight: 700; }
  .sky-title em { font-style: normal; color: var(--gold); }
  .sky-body {
    color: var(--text-secondary); font-size: var(--text-body-lg);
    max-width: 42ch; margin: 0 0 var(--space-6);
    text-shadow: 0 1px 24px rgba(8, 6, 11, 0.95);
  }
  .sky-actions { display: flex; align-items: center; gap: var(--space-5); }

  .halls-copy {
    position: absolute; z-index: 9;
    /* upper-left, where the contained facade leaves the field near-black */
    left: var(--page-gutter); top: calc(66px + var(--space-8));
    max-width: min(680px, 76vw);
    will-change: transform, opacity;
  }
  /* the reveal: the heading arrives word by word, then the subline, then the CTA — all in place,
     rising a few pixels only, so nothing slides across the frame */
  .halls-copy > .halls-body,
  .halls-copy > .halls-actions {
    opacity: 0; transform: translate3d(0, 16px, 0);
    transition: opacity 620ms var(--ease-divine), transform 620ms var(--ease-divine);
  }
  .halls-copy > .halls-actions { transform: translate3d(0, 16px, 0) scale(0.96); }
  .halls-title i {
    display: inline-block; font-style: normal;
    opacity: 0; transform: translate3d(0, 14px, 0);
    transition: opacity 700ms var(--ease-divine), transform 700ms var(--ease-divine);
    transition-delay: var(--wd, 0ms);
  }
  .halls-copy[data-in="true"] .halls-title i { opacity: 1; transform: none; }
  .halls-copy[data-in="true"] > .halls-body,
  .halls-copy[data-in="true"] > .halls-actions { opacity: 1; transform: none; }
  .halls-copy[data-in="true"] > .halls-body { transition-delay: 940ms; }
  .halls-copy[data-in="true"] > .halls-actions { transition-delay: 1180ms; }
  .halls-title {
    font-family: var(--font-display); font-weight: 500; font-size: clamp(28px, 2.6vw, 40px);
    line-height: 1.04; letter-spacing: var(--tracking-display);
    color: var(--text-primary); margin: 0 0 var(--space-4);
    text-shadow: 0 2px 40px rgba(8, 6, 11, 0.9);
    max-width: 11.4em;
  }
  .halls-title span { display: block; }
  .halls-title em { font-style: normal; color: var(--gold); }
  .halls-body {
    color: var(--text-secondary); font-size: var(--text-body-lg);
    max-width: 40ch; margin: 0 0 var(--space-5);
    text-shadow: 0 1px 24px rgba(8, 6, 11, 0.95);
  }
  .halls-actions { display: flex; align-items: center; gap: var(--space-5); }
  /* The facade fills the lower ~56% of the stage, so the copy must live inside the top 44%. On a
     full-height viewport it already does; on a short one it would run down onto the lit pediment,
     so it tightens instead of overlapping — the temple never rises into the type. */
  @media (max-height: 820px) {
    .halls-copy { top: calc(66px + var(--space-4)); max-width: min(560px, 74vw); }
    .halls-title { font-size: clamp(24px, 2.2vw, 32px); margin-bottom: var(--space-3); }
    .halls-body { font-size: var(--text-body); margin-bottom: var(--space-4); max-width: 36ch; }
  }

  /* ---- eighth section: the breath. Full-bleed footage, copy low and centred. ---- */
  .breathe {
    position: relative; z-index: 5; overflow: hidden;
    background: transparent;
    min-height: 100vh; display: flex; align-items: center;
    padding: calc(66px + var(--space-8)) var(--page-gutter) var(--space-8);
    box-sizing: border-box;
  }
  .breathe-inner {
    position: relative; z-index: 1; max-width: var(--content-max); margin: 0 auto; width: 100%;
    /* copy left, asset right. The copy column takes a real floor so the asset can never squeeze
       the headline — the asset can crop, the type cannot. */
    display: grid; grid-template-columns: minmax(min(420px, 100%), 0.62fr) minmax(0, 1fr);
    align-items: center; gap: var(--space-7);
  }
  .breathe-copy { max-width: 100%; text-align: left; will-change: transform, opacity; }
  /* The footage is a contained asset now, not a background: its edges are its own, so it needs a
     frame rather than a seam blend. Circular, matching the forge asset in section 6, so the two
     read as one family. */
  .breathe-asset {
    /* the break has to be IN the width: with width:100% the used width resolves against the grid
       track and a negative margin adds nothing. The left shift is a separate translate, so it
       moves the asset without changing how wide it is. */
    position: relative; width: calc(100% + var(--page-gutter) * 4.2);
    margin-left: -200px;
    /* The fade lives HERE, on a wrapper no scale touches — that is what makes it render at all. No
       overflow clip either: nothing inside is scaled now, so there is nothing to crop, and the
       halo's blur can bleed past the rim as it is meant to. */
    -webkit-mask-image: radial-gradient(circle closest-side at 50% 50%, #000 30%, rgba(0,0,0,0.72) 56%, rgba(0,0,0,0.22) 78%, transparent 92%);
    mask-image: radial-gradient(circle closest-side at 50% 50%, #000 30%, rgba(0,0,0,0.72) 56%, rgba(0,0,0,0.22) 78%, transparent 92%);
    /* breaks the gutter harder than the third section's art, since this column is the narrower of
       the two — it is what keeps the asset reading as the section's subject */
    margin-right: calc(var(--page-gutter) * -1.9);
    will-change: transform, opacity;
  }
  /* section 7's bleed, unchanged: a blurred copy behind the sharp one, extending past its edges, so
     the footage dissolves outward instead of fading to nothing at a rim */
  .breathe-asset .asset-halo {
    position: absolute; inset: -12% -9%;
    z-index: -1; pointer-events: none;
  }
  .breathe-asset .asset-halo video {
    width: 100%; height: 100%; object-fit: cover;
    filter: blur(26px) saturate(112%);
    opacity: 0.44;
    -webkit-mask-image: radial-gradient(circle closest-side at 50% 50%, #000 10%, rgba(0,0,0,0.38) 44%, transparent 80%);
    mask-image: radial-gradient(circle closest-side at 50% 50%, #000 10%, rgba(0,0,0,0.38) 44%, transparent 80%);
  }
  .breathe-asset { isolation: isolate; }
  .breathe-asset > video { position: relative; z-index: 1; }
  .breathe-asset video {
    /* height: auto — the box takes the clip's own height, exactly as section 7's plate does, so
       nothing is cropped and the circle's radius is half that height. */
    display: block; width: 100%; height: auto;
    filter: drop-shadow(0 0 70px rgba(28, 162, 112, 0.18));
  }
  @media (max-width: 900px) {
    .breathe-inner { grid-template-columns: 1fr; }
    .breathe-asset { width: 100%; max-width: 620px; margin: 0 auto; }
  }
  .breathe-title {
    /* a smaller clamp than the single-column sections use: this headline shares its row with the
       asset, so it has roughly 60% of the content width rather than all of it */
    font-family: var(--font-display); font-weight: 500; font-size: clamp(26px, 2.0vw, 30px);
    line-height: 1.04; letter-spacing: var(--tracking-display);
    color: var(--text-primary); margin: 0 0 var(--space-5);
    text-shadow: 0 2px 40px rgba(8, 6, 11, 0.95);
    /* 14.8em against a measured 14.54em requirement, in em so the cap tracks the type itself */
    max-width: 14.8em;
  }
  .breathe-title span { display: block; }
  .breathe-title em { font-style: normal; color: var(--gold); }
  .breathe-body {
    color: var(--text-secondary); font-size: var(--text-body-lg);
    max-width: 46ch; margin: 0 0 var(--space-6);
    text-shadow: 0 1px 24px rgba(8, 6, 11, 0.95);
  }
  .breathe-body strong { color: var(--text-primary); font-weight: 700; }
  .breathe-actions { display: flex; align-items: center; gap: var(--space-5); }
  @media (max-width: 900px) {
    .breathe-title { font-size: clamp(28px, 6.4vw, 40px); }
  }

  /* ---- sixth section: the faces. The same terrain, re-lit in nebula purple and jade. ---- */
  .faces {
    position: relative; z-index: 5; overflow: hidden;
    background: transparent;
    /* min-height, not height: the forge below the copy makes this section taller than a
       viewport, and a fixed height would crop it against overflow:hidden */
    min-height: 100vh; display: flex; align-items: flex-start;
    padding: calc(66px + var(--space-9)) var(--page-gutter) var(--space-8);
    box-sizing: border-box;
  }
  .faces-inner {
    position: relative; z-index: 1; max-width: var(--content-max); margin: 0 auto; width: 100%;
    display: flex; justify-content: center;
  }
  .faces-copy { max-width: 100%; text-align: center; will-change: transform, opacity; }
  .faces-title {
    font-family: var(--font-display); font-weight: 500; font-size: clamp(30px, 3.9vw, 60px);
    line-height: 1.04; letter-spacing: var(--tracking-display);
    color: var(--text-primary); margin: 0 auto var(--space-5);
    text-shadow: 0 2px 40px rgba(8, 6, 11, 0.9);
    /* 15em, measured against the headline's actual 14.35em rather than estimated — the previous
       13.4em was ~7% short, so the single authored line wrapped at every viewport. `em` resolves
       against the title's own font-size, so the measure tracks the clamp. */
    max-width: 15em;
  }
  .faces-body {
    color: var(--text-secondary); font-size: var(--text-body-lg);
    max-width: 44ch; margin: 0 auto var(--space-6);
    text-shadow: 0 1px 24px rgba(8, 6, 11, 0.95);
  }
  .faces-body strong { color: var(--text-primary); font-weight: 700; }
  .faces-actions { display: flex; align-items: center; justify-content: center; gap: var(--space-5); }

  .faces-forge {
    position: relative; isolation: isolate; width: 100%; max-width: 780px;
    margin: var(--space-7) auto 0;
    will-change: transform, opacity;
  }
  /* The footage does not loop cleanly — its first and last frames differ visibly. Rather than
     re-cutting the file, two copies play half a cycle apart and crossfade: whenever one reaches
     its seam the other is mid-shot, so the join is never on screen. They are stacked, hence the
     absolute positioning, with the first in flow to give the box its height. */
  .faces-forge video {
    display: block; width: 100%; height: auto;
    grid-area: 1 / 1;
    /* ONE mask, and it reaches full transparency INSIDE the frame on every side. Multiple mask
       layers composite as a union by default — so my per-edge gradients were adding opacity back
       rather than subtracting it, and `mask-composite` support is inconsistent enough that it
       could not be relied on to intersect them. `circle closest-side` measures against the
       SHORTER axis, so the mask stays genuinely round on a 16:9 plate and still closes inside
       the frame on every side — no straight edge or corner can survive. */
    -webkit-mask-image: radial-gradient(circle closest-side at 50% 48%, #000 14%, rgba(0,0,0,0.55) 46%, rgba(0,0,0,0.10) 72%, transparent 88%);
    mask-image: radial-gradient(circle closest-side at 50% 48%, #000 14%, rgba(0,0,0,0.55) 46%, rgba(0,0,0,0.10) 72%, transparent 88%);
    filter: drop-shadow(0 0 70px rgba(28, 162, 112, 0.20));
  }
  /* A second, blurred copy of the same frame sits behind the sharp one and bleeds past its edges,
     so the boundary reads as the footage dissolving into the field rather than fading to nothing. */
  .faces-forge .forge-alt { position: absolute; inset: 0; }
  /* The rock and the mask ride the same track across the video: raw stone in from the left,
     nothing at the anvil, a finished face out to the right. Both are absolutely positioned so
     they overlay the footage without affecting its box. */
  .forge-travel {
    position: absolute; top: 46%; left: 0; z-index: 2;
    width: 15%; aspect-ratio: 1 / 1;
    margin-top: -7.5%;
    pointer-events: none; opacity: 0;
    will-change: transform, opacity;
  }
  .forge-travel img { display: block; width: 100%; height: 100%; object-fit: contain; }
  /* every face shares one slot; the cycle promotes one at a time */
  #forgeMask img { position: absolute; inset: 0; opacity: 0; }
  #forgeMask img.is-current { opacity: 1; }
  #forgeMask img { filter: drop-shadow(0 0 26px rgba(255, 210, 122, 0.45)); }
  .faces-forge .forge-bleed {
    position: absolute; inset: -12% -9%;
    z-index: -1; pointer-events: none;
  }
  .faces-forge .forge-bleed video {
    width: 100%; height: 100%; object-fit: cover;
    /* The blur is what fills the gap the sharp layer's mask opens up, so the footage reads as
       dissolving outward rather than being cut to an ellipse. Its own mask closes inside its box
       too — a blurred rectangle still has a rectangle's boundary. */
    filter: blur(42px) saturate(118%);
    opacity: 0.62;
    -webkit-mask-image: radial-gradient(circle closest-side at 50% 48%, #000 10%, rgba(0,0,0,0.38) 44%, transparent 80%);
    mask-image: radial-gradient(circle closest-side at 50% 48%, #000 10%, rgba(0,0,0,0.38) 44%, transparent 80%);
  }
  @media (max-width: 900px) {
    .faces-title { font-size: clamp(28px, 6.4vw, 40px); }
  }

  /* ---- fifth section: the well. Copy sits top-left; the field carries deeper still. ---- */
  .well {
    position: relative; z-index: 5; overflow: hidden;
    background: transparent;
    /* The garden is 126% of the section's width, so at its 1672x941 aspect it stands
       126 x 56.28 = 71% of that width tall. The section reserves exactly that below the copy,
       otherwise the artwork is taller than the frame and overflow:hidden crops its temple. */
    /* The copy sits at the top of the frame. Position is a real length here, never a negative
       calc: padding cannot go below 0, so `- 400px` silently clamped and the last nudge moved
       122px instead of 200 — the property had no travel left. */
    min-height: 100vh; display: flex; align-items: flex-start;
    /* 8vw horizontal, the shared gutter: the nav, the hero copy and section two all sit at that
       edge (97px at 1210). This section was on --space-6 (32px), so its copy started 65px left
       of every other section's. The vertical values are this section's own. */
    padding: 0 8vw var(--space-8);
    box-sizing: border-box;
  }
  /* The garden spans the section edge to edge. Absolute positioning resolves against the
     padding BOX, so left:0/right:0 clears the section's own gutters without fighting them —
     no negative margins, and nothing to re-tune when the gutter changes. */
  .well-scene {
    /* Full bleed, edge to edge. The box may be any shape: the shader cover-fits the plate to it,
       so the artwork crops rather than deforming. (object-fit stopped applying when this became a
       shader-mapped quad — the fit lives in coverFit()/uFit now.) */
    /* Overscan below the fold, so the element can absorb its own upward parallax. At
       bottom:0/height:100% any negative Y lifts the artwork's edge off the section and the
       field shows through as a hard-cut void strip — the very seam this section is meant not
       to have. 10% covers the full -7% of travel with margin to spare. */
    /* Wider than the section on both sides, as the old plate was: the artwork's own transparent
       margins fall outside the frame so its terrain reaches both corners, and the extra scale
       makes the temple and falls read at the size they did before. Overscan below the fold too,
       so the element can absorb its own upward parallax without lifting its edge off the
       section and exposing the field beneath as a hard-cut strip. */
    /* Pushed right and flush to the right edge: the overhang now sits entirely on the LEFT,
       where the artwork's own transparent margin is, so nothing is cropped and no gutter shows
       on the right. Overscan below the fold stays, so the element absorbs its own upward
       parallax without lifting its edge off the section and exposing the field beneath. */
    /* Shifted 400px further right, past the section's own edge. The whole overhang lives on the
       LEFT, where the artwork's transparent margin is, so nothing is cropped. Overscan below the
       fold stays, so the element absorbs its own upward parallax without lifting its edge off
       the section and exposing the field beneath. */
    /* Pushed right until the artwork's own terrain meets the right edge, then dropped 200px so it
       sits lower in the frame. The whole overhang lives on the LEFT, where the artwork's
       transparent margin is, so nothing is cropped. The below-fold overscan absorbs both the
       200px drop and the upward parallax — without it the element's bottom edge lifts off the
       section and the field shows through as a hard-cut strip. */
    /* Shifted right and widened toward full bleed: the plate starts inside the container's left
       edge and runs past the section's right gutter, so its terrain crosses almost the whole
       frame. The below-fold overscan absorbs the 200px drop and the upward parallax — without it
       the element's bottom edge lifts off the section and the field shows through as a strip. */
    /* 20% larger, extended leftward so the terrain reaches the section's bottom-left corner
       instead of leaving it empty. Width runs 50% -> -58% grown by 20% (129.6% of the section)
       with the extra taken off the LEFT, and the height grows to match so the aspect holds. */
    position: absolute; left: 24.4%; right: -54%; bottom: calc(-10% - 200px); height: calc(149% + 240px); z-index: 0;
    pointer-events: none; will-change: transform;
  }
  /* The plate is no longer an <img>: it is rendered in the page's own WebGL scene as a
     depth-displaced surface, so it holds real parallax. This box survives only as the
     registration rect the 3D plane measures itself against, and as the host for the
     foreground blur band below — its CSS transform still carries the scroll parallax. */
  /* Whatever runs past the bottom of the frame goes soft rather than being sliced: a
     depth-of-field band, strongest at the very edge, so the foreground falls out of focus
     the way a real lens would render it. */
  .well-scene::after {
    content: ''; position: absolute; inset: auto 0 0; height: 22%;
    -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
    -webkit-mask-image: linear-gradient(180deg, transparent, #000 78%);
    mask-image: linear-gradient(180deg, transparent, #000 78%);
    pointer-events: none;
  }
  .well-inner {
    /* Same container as the other sections (--content-max, 1200px, centred) rather than this
       section's own wider 1460px box — so the copy's left edge lines up with section two's. */
    position: relative; z-index: 1; max-width: var(--content-max); margin: 0 auto; width: 100%;
    display: flex; justify-content: flex-start;
  }
  /* The container no longer sets the headline's measure — the headline does, in `em`, below.
     A `ch` cap here resolves against the inherited 16px body font, so it stays a fixed pixel
     width while the title's clamp(…vw…) grows: widening it only moves the breakpoint. */
  .well-copy { max-width: 100%; will-change: transform, opacity; }
  .well-title {
    font-family: var(--font-display); font-weight: 500; font-size: clamp(30px, 3.9vw, 60px);
    line-height: 1.04; letter-spacing: var(--tracking-display);
    color: var(--text-primary); margin: 0 0 var(--space-5);
    text-shadow: 0 2px 40px rgba(8, 6, 11, 0.9);
  }
  /* 14em > the 13.503em the longest authored line needs, and `em` here resolves against the
     title's own font-size, so the two lines hold at every value of the clamp. */
  .well-title { max-width: 14em; }
  .well-title span { display: block; }
  .well-title em { font-style: normal; color: var(--gold); }
  .well-body {
    color: var(--text-secondary); font-size: var(--text-body-lg);
    max-width: 46ch; margin: 0 0 var(--space-6);
    text-shadow: 0 1px 24px rgba(8, 6, 11, 0.95);
  }
  .well-body strong { color: var(--text-primary); font-weight: 700; }
  .well-actions { display: flex; align-items: center; gap: var(--space-5); }
  @media (max-width: 900px) {
    .well-title { font-size: clamp(28px, 6.4vw, 40px); }
  }

  /* ---- fourth section: the naming. Same field, carried one layer deeper. ---- */
  .naming {
    position: relative; z-index: 5; overflow: hidden;
    background: transparent;
    /* the copy sits low in the frame; the stage above it holds the visual */
    min-height: 100vh; display: flex; align-items: stretch;
    padding: calc(66px + var(--space-7)) var(--space-6) var(--space-9);
    box-sizing: border-box;
  }
  .naming-inner {
    position: relative; max-width: min(1460px, 100%); margin: 0 auto; width: 100%;
    display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
    gap: var(--space-6);
  }
  /* the stage the WebGL waves register to — it owns the space, the canvas just fills it */
  .naming-stage { flex: 1 1 auto; width: 100%; min-height: 32vh; }
  .naming-copy { max-width: min(88ch, 100%); text-align: center; will-change: transform, opacity; }
  .naming-title {
    font-family: var(--font-display); font-weight: 500; font-size: clamp(30px, 3.9vw, 60px);
    line-height: 1.04; letter-spacing: var(--tracking-display);
    color: var(--text-primary); margin: 0 0 var(--space-5);
    text-shadow: 0 2px 40px rgba(8, 6, 11, 0.9);
  }
  /* 15.2em > the 14.669em the longest authored line needs; centred, since this section is. */
  .chapter-title { max-width: 15.2em; margin-inline: auto; }
  /* the spans give the two lines; no nowrap, so a narrow viewport wraps rather than clips */
  .naming-title span { display: block; }
  /* the name carries both lights: the divine gold and the current's jade */
  .grad-gold-jade {
    background-image: linear-gradient(96deg, var(--gold-600) 0%, var(--gold) 34%, var(--emerald-300) 78%, var(--emerald) 100%);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
  /* gold alone, for the line that closes the thought */
  .grad-gold {
    background-image: linear-gradient(96deg, var(--gold-700) 0%, var(--gold) 40%, var(--gold-200) 100%);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
  .naming-body {
    color: var(--text-secondary); font-size: var(--text-body-lg);
    max-width: min(80ch, 100%); margin: 0 auto var(--space-6);
    text-shadow: 0 1px 24px rgba(8, 6, 11, 0.95);
  }
  .naming-body span { display: block; }
  .naming-body em { font-style: italic; color: var(--text-primary); }
  .naming-body strong { color: var(--text-primary); font-weight: 700; }
  .naming-actions {
    display: flex; align-items: center; justify-content: center; gap: var(--space-5);
    border-top: 1px solid var(--line-hairline); padding-top: var(--space-6);
  }
  @media (max-width: 900px) {
    .naming-title { font-size: clamp(28px, 6.4vw, 40px); }
  }

  /* ---- third section: the arrival. Colour returns to the field here. ---- */
  .genesis {
    position: relative; z-index: 5; overflow: hidden;
    background: transparent;
    min-height: 100vh; display: flex; align-items: center;
    padding: calc(66px + var(--space-7)) var(--page-gutter) var(--space-8);
    box-sizing: border-box;
  }
  .genesis-inner {
    position: relative; margin: 0 auto; width: 100%;
    /* wider than the standard measure: this section is the arrival, and the artwork carries it */
    max-width: min(1460px, 100%);
    /* The copy column gets a floor in real pixels so the artwork cannot squeeze it: 0.68fr of a
       764px row left it at 207px, far under the headline's own measure. The art column takes
       whatever remains — it can crop, the type cannot. */
    display: grid; grid-template-columns: minmax(min(440px, 100%), 1fr) minmax(0, 1.05fr);
    align-items: center; gap: var(--space-5);
  }
  .genesis-copy { max-width: 100%; text-align: left; }
  .genesis-art {
    position: relative; justify-self: end; width: 100%; max-width: 980px;
    margin-right: calc(var(--page-gutter) * -0.55);   /* breaks the gutter, like the hero's world */
    will-change: transform, opacity;
  }
  .genesis-art img {
    display: block; width: 100%; height: auto;
    /* never taller than the section can show — it clips its own overflow */
    max-height: 60vh; object-fit: contain; object-position: center right;
    /* the figure is lit from within — let the void take its edges rather than boxing it */
    filter: drop-shadow(0 0 60px rgba(255, 210, 122, 0.20)) drop-shadow(0 24px 60px rgba(8, 6, 11, 0.85));
  }
  .genesis-title {
    font-family: var(--font-display); font-weight: 500; font-size: clamp(30px, 3.9vw, 60px);
    line-height: 1.04; letter-spacing: var(--tracking-display);
    color: var(--text-primary); margin: 0 0 var(--space-5);
    text-shadow: 0 2px 40px rgba(8, 6, 11, 0.9);
  }
  /* 10.4em > the 9.64em the longest authored line needs, and `em` resolves against the title's
     own font-size — so the two authored lines hold at every value of the clamp. A `ch` cap on the
     container resolves against the inherited 16px body font instead: a fixed width that cannot
     track the type as it grows. Same fix as .well-title and .chapter-title. */
  .genesis-title { max-width: 10.4em; }
  .genesis-title span { display: block; }
  /* the name carries the whole palette: gold through starlight into nebula violet */
  .genesis-name {
    background-image: linear-gradient(96deg, var(--gold-600) 4%, var(--gold) 26%, var(--starlight) 52%, var(--text-violet) 82%, var(--neutral-500) 100%);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
  .genesis-body {
    color: var(--text-secondary); font-size: var(--text-body-lg);
    max-width: 44ch; margin: 0 0 var(--space-6);
    text-shadow: 0 1px 24px rgba(8, 6, 11, 0.95);
  }
  .genesis-body strong { color: var(--text-primary); font-weight: 700; }
  .genesis-body-focus { display: block; color: var(--text-primary); margin-top: var(--space-4); }
  .genesis-actions {
    display: flex; align-items: center; gap: var(--space-5);
    border-top: 1px solid var(--line-hairline); padding-top: var(--space-6);
  }
  @media (max-width: 900px) {
    .genesis-title { font-size: clamp(30px, 6.8vw, 44px); }
    .genesis-inner { grid-template-columns: 1fr; gap: var(--space-6); }
    .genesis-copy { max-width: 100%; }
    .genesis-art { justify-self: center; max-width: 620px; order: -1; margin-right: 0; }
  }
  @media (max-width: 900px) {
    .chapter-title { font-size: clamp(28px, 6.4vw, 40px); }
  }
