/* ============================================================
   focus.css — Project One Focus interaction & composition layer
   ------------------------------------------------------------
   Loaded AFTER styles.css. It adds the "focus" design language
   rather than replacing the existing system: brand tokens, the
   type scale and every component in styles.css stay authoritative.

   The organising idea: the logo is concentric gold rings around a
   rising figure, so the site should BEHAVE like something coming
   into focus — rings, blur resolving to sharp, light gathering to
   a point. Every effect here is a variation on that one idea.

   Contract for everything below:
     - transform / opacity / clip-path only in animations
     - all pointer effects are custom-property driven, rAF-throttled
     - every motion has a reduced-motion resting state that is the
       FINAL state, never the initial one
   ============================================================ */

:root {
  /* --- ring geometry -------------------------------------- */
  --ring-w: 1px;
  --ring-c: color-mix(in srgb, var(--accent) 42%, transparent);
  --ring-c-soft: color-mix(in srgb, var(--accent) 16%, transparent);
  --ring-c-faint: color-mix(in srgb, var(--accent) 8%, transparent);

  /* --- motion --------------------------------------------- */
  /* One easing family. Mixing eases is what makes motion feel
     unrelated; these three are the same curve at three speeds. */
  --ease-focus: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-settle: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 220ms;
  --dur-mid: 520ms;
  --dur-slow: 900ms;
  --dur-cine: 1400ms;

  /* --- pointer (set by JS, safe defaults for no-JS) -------- */
  --mx: 50%;
  --my: 40%;
  --px: 0;      /* -1..1 normalised pointer offset */
  --py: 0;
  --vel: 0;     /* scroll velocity, 0..1 */

  /* --- spatial scales ------------------------------------- */
  /* Deliberately several widths, not one max-width. Hierarchy
     comes from things NOT sharing an edge. */
  --w-read: 68ch;
  --w-text: 700px;
  --w-content: 1200px;
  --w-wide: 1500px;
}

/* Grain: one inline SVG turbulence, no tiled JPG. Kept at a very
   low alpha — it exists to stop large gradients banding, and should
   never be consciously visible. */
:root {
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* ============================================================
   REDUCED MOTION — declared once, high in the file.
   Everything below may assume this override exists.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .pof-boot { display: none !important; }

  .reveal-line > span,
  .reveal-mask > *,
  .rise,
  .resolve,
  .hero-cine__note,
  .fade-in {
    transform: none !important;
    opacity: 1 !important;
    filter: none !important;
    clip-path: none !important;
    transition: none !important;
  }

  .focus-ring,
  .hero-cine__rings > * {
    animation: none !important;
    transform: none !important;
  }

  .marquee__track { animation: none !important; transform: none !important; }
  .depth-layer { transform: none !important; }
}

/* ============================================================
   1 — FOCUS RING PRIMITIVES
   A ring is a bordered circle. No SVG, no canvas: a border-radius
   box animates on the compositor and costs nothing.
   ============================================================ */
.focus-ring {
  position: absolute;
  border: var(--ring-w) solid var(--ring-c-soft);
  border-radius: 50%;
  pointer-events: none;
  will-change: transform, opacity;
}
.focus-ring--faint { border-color: var(--ring-c-faint); }
.focus-ring--bright { border-color: var(--ring-c); }

/* A ring that breathes. Amplitude is tiny on purpose — it should
   read as "alive", never as "animated". */
.focus-ring--breathe { animation: ringBreathe 9s var(--ease-io) infinite; }
.focus-ring--breathe.is-slow { animation-duration: 14s; }
@keyframes ringBreathe {
  0%, 100% { transform: scale(1); opacity: 0.85; }
  50%      { transform: scale(1.035); opacity: 1; }
}

/* Ambient rings sit behind content and take scroll velocity. */
.focus-ring--ambient {
  transform: translate3d(0, calc(var(--vel) * -14px), 0);
  transition: transform 600ms var(--ease-settle);
}

/* ============================================================
   2 — SIGNATURE 1: THE SITE COMES INTO FOCUS
   An overlay that never blocks: pointer-events none from the
   first frame, and it removes itself. The page is usable
   immediately — this is choreography, not a loading gate.
   ============================================================ */
.pof-boot {
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;
  background: var(--brand-900);
  animation: bootVeil var(--dur-cine) var(--ease-focus) forwards;
}
.pof-boot__point {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 24px 6px color-mix(in srgb, var(--accent) 55%, transparent);
  animation: bootPoint var(--dur-cine) var(--ease-focus) forwards;
}
.pof-boot__ring {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border: 1px solid var(--accent);
  border-radius: 50%;
  opacity: 0;
  animation: bootRing 1100ms var(--ease-focus) forwards;
}
.pof-boot__ring:nth-child(2) { animation-delay: 120ms; }
.pof-boot__ring:nth-child(3) { animation-delay: 240ms; }
.pof-boot__ring:nth-child(4) { animation-delay: 360ms; }

@keyframes bootVeil {
  0%   { opacity: 1; }
  62%  { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}
@keyframes bootPoint {
  0%   { transform: scale(0.2); opacity: 0; }
  18%  { transform: scale(1); opacity: 1; }
  60%  { transform: scale(1); opacity: 1; }
  100% { transform: scale(26); opacity: 0; }
}
@keyframes bootRing {
  0%   { transform: scale(0.4); opacity: 0; }
  30%  { opacity: 0.9; }
  100% { transform: scale(58); opacity: 0; }
}

/* The interface arrives out of the focus point rather than just
   being there. One short lift, applied to the header and hero only. */
.boot-emerge { animation: bootEmerge 900ms var(--ease-settle) both; }
.boot-emerge--delay { animation-delay: 140ms; }
@keyframes bootEmerge {
  from { opacity: 0; transform: translate3d(0, 14px, 0); filter: blur(6px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

/* ============================================================
   3 — REVEAL SYSTEM
   Masked line reveal. The mask is a real overflow boundary, so the
   text rises from behind an edge instead of fading — fading reads
   as "a web page", rising from a mask reads as "typeset".
   ============================================================ */
.reveal-line { display: block; overflow: hidden; }
.reveal-line > span {
  display: block;
  transform: translate3d(0, 105%, 0);
  transition: transform var(--dur-slow) var(--ease-focus);
  transition-delay: var(--d, 0ms);
}
.is-revealed .reveal-line > span,
.reveal-line.is-revealed > span { transform: none; }

/* Generic entrance for blocks (not headlines). */
.rise {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity var(--dur-mid) var(--ease-focus),
              transform var(--dur-mid) var(--ease-focus);
  transition-delay: var(--d, 0ms);
}
.rise.is-visible { opacity: 1; transform: none; }

/* blur -> sharp. The brand's own idea, so it is used sparingly and
   only on things that are ABOUT resolving. Never on body copy. */
.resolve {
  filter: blur(14px);
  opacity: 0;
  transform: scale(1.04);
  transition: filter var(--dur-slow) var(--ease-focus),
              opacity var(--dur-slow) var(--ease-focus),
              transform var(--dur-slow) var(--ease-focus);
  transition-delay: var(--d, 0ms);
}
.resolve.is-visible { filter: blur(0); opacity: 1; transform: none; }

/* ============================================================
   4 — SIGNATURE 2: CINEMATIC HERO
   Seven stacked layers in one grid cell. Overlap is the point:
   type crosses the image, rings cross both, light sits over all.
   ============================================================ */
.hero-cine {
  position: relative;
  isolation: isolate;
  overflow: clip;
  min-height: clamp(560px, 92svh, 940px);
  display: grid;
  align-items: center;
  background: var(--brand);
  color: var(--text-on-brand);
}

/* L1 — atmosphere */
.hero-cine__atmos {
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    radial-gradient(120% 90% at 62% 18%, color-mix(in srgb, var(--brand) 40%, #2a1a63) 0%, transparent 62%),
    radial-gradient(80% 70% at 18% 88%, color-mix(in srgb, var(--accent) 10%, transparent) 0%, transparent 60%),
    linear-gradient(180deg, var(--brand-900), var(--brand));
}
.hero-cine__atmos::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--grain);
  opacity: 0.035;
  mix-blend-mode: overlay;
}

/* L2 — the rings, the brand made spatial */
.hero-cine__rings {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.hero-cine__rings .focus-ring {
  left: var(--rx, 62%);
  top: var(--ry, 44%);
  width: var(--rs);
  height: var(--rs);
  margin-left: calc(var(--rs) / -2);
  margin-top: calc(var(--rs) / -2);
}

/* L3 — background word. Enormous, nearly invisible, gives scale. */
.hero-cine__ghost {
  position: absolute;
  z-index: 2;
  left: 50%;
  top: 52%;
  transform: translate(-50%, -50%);
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: clamp(7rem, 26vw, 24rem);
  letter-spacing: -0.04em;
  line-height: 0.8;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1px color-mix(in srgb, var(--accent) 14%, transparent);
  pointer-events: none;
  user-select: none;
}

/* L4 — media */
.hero-cine__media {
  position: relative;
  z-index: 3;
  grid-area: 1 / 1;
  justify-self: end;
  align-self: center;
  width: min(48vw, 620px);
  margin-right: max(2rem, calc((100vw - var(--w-wide)) / 2));
  aspect-ratio: 5 / 6;
  border-radius: 260px 260px 22px 22px;   /* an arch, not a rectangle */
  overflow: hidden;
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.65);
}
.hero-cine__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* The photo slot is composed as a real element so a real photograph
   drops in later without recomposing the hero. */
.hero-cine__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(200deg, transparent 40%, color-mix(in srgb, var(--brand-900) 72%, transparent));
}

/* L5 — foreground type, crossing the media */
.hero-cine__type {
  position: relative;
  z-index: 4;
  grid-area: 1 / 1;
  width: min(100% - 3rem, var(--w-wide));
  margin-inline: auto;
  /* Top padding clears the overlaid header; the type column is held to
     ~56% so the headline crosses the media edge without landing on the
     figure itself. Overlap is the composition; collision is a bug. */
  padding-block: clamp(7rem, 14vh, 10rem) clamp(3rem, 8vh, 6rem);
}
@media (min-width: 901px) {
  .hero-cine__type > * { max-width: 56%; }
}
.hero-cine__type .eyebrow { color: var(--accent); }

.hero-cine h1 {
  /* styles.css sets `h1 { color: var(--text) }` (dark ink) for the light
     page theme. Without this the headline renders near-black on the dark
     hero — invisible. Stated explicitly rather than relying on inheritance. */
  color: #fff;
  font-size: clamp(2.6rem, 6.4vw, 6.6rem);
  line-height: 0.94;
  letter-spacing: -0.035em;
  font-weight: 800;
  margin: 0.35em 0 0;
  max-width: 13ch;
  text-wrap: balance;
}
/* The one word that resolves. Used exactly once on the site.
   font-style is pinned because the academic theme italicises <em>-like
   emphasis into Lora serif, which fights the display face. */
.hero-cine h1 .focusword {
  color: var(--accent);
  font-style: normal;
  position: relative;
  display: inline-block;
}
.hero-cine h1 .focusword::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.1em;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--dur-slow) var(--ease-focus) 900ms;
}
.is-revealed .hero-cine h1 .focusword::after { transform: scaleX(1); }

.hero-cine__lead {
  margin-top: 1.5rem;
  max-width: 46ch;
  color: var(--text-on-brand-soft);
  font-size: var(--fs-500);
}

/* L6 — floating callout, glass because it genuinely floats */
.hero-cine__note {
  position: absolute;
  z-index: 5;
  /* Straddles the media's left edge rather than sitting under the type
     column, where it landed on top of the CTA buttons and blocked them.
     Occlusion across the image boundary is the intent; covering a button
     is not. */
  left: clamp(30rem, 47vw, 60rem);
  bottom: clamp(2rem, 9vh, 5.5rem);
  max-width: min(30ch, 34vw);
  /* Revealed by the hero, NOT by IntersectionObserver. It sits on the fold,
     where the observer's -8% bottom margin excludes it and it never fires. */
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition: opacity var(--dur-mid) var(--ease-focus) 900ms,
              transform var(--dur-mid) var(--ease-focus) 900ms;
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.85rem 1.15rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, #fff 14%, transparent);
  background: color-mix(in srgb, var(--brand-900) 55%, transparent);
  backdrop-filter: blur(14px);
  font-size: var(--fs-300);
  color: var(--text-on-brand);
}
.hero-cine.is-revealed .hero-cine__note { opacity: 1; transform: none; }
.hero-cine__note .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 18%, transparent);
  flex: none;
}

/* L7 — pointer light. Atmospheric, not a flashlight. */
.hero-cine__light {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  background: radial-gradient(
    420px circle at var(--mx) var(--my),
    color-mix(in srgb, var(--accent) 9%, transparent) 0%,
    transparent 70%
  );
  opacity: 0;
  transition: opacity var(--dur-mid) var(--ease-focus);
}
.hero-cine:hover .hero-cine__light { opacity: 1; }

/* Depth: each layer takes a slightly different share of the pointer
   offset. Values are deliberately tiny — felt, not seen. */
.depth-layer {
  transform: translate3d(calc(var(--px) * var(--depth, 4px)), calc(var(--py) * var(--depth, 4px)), 0);
  transition: transform 500ms var(--ease-settle);
}

@media (max-width: 900px) {
  /* Mobile drops the overlap entirely — an arch photo behind a
     giant headline is unreadable at 390px. Vertical, calm, legible. */
  .hero-cine {
    min-height: 0;
    padding-block: 6.5rem 3rem;   /* clears the overlaid header */
    grid-template-columns: 1fr;
  }
  /* The media precedes the type in the DOM so it can sit BEHIND it on
     desktop. On mobile that puts a placeholder image above the headline,
     so the reading order is restored with `order`. */
  .hero-cine__media {
    grid-area: auto;
    order: 2;
    justify-self: stretch;
    width: auto;
    margin: 2rem 1.5rem 0;
    aspect-ratio: 4 / 3;
    border-radius: 140px 140px 18px 18px;
  }
  .hero-cine__type { grid-area: auto; order: 1; padding-block: 0; }
  .hero-cine__note { order: 3; }
  .hero-cine__ghost { font-size: 42vw; opacity: 0.5; }
  .hero-cine__note {
    position: static;
    margin: 1.5rem 1.5rem 0;
    max-width: none;
    left: auto;
    display: inline-flex;
    opacity: 1;            /* static flow: no fold-edge reveal needed */
    transform: none;
  }
  .hero-cine h1 { font-size: clamp(2.5rem, 11vw, 4rem); max-width: none; }
}

/* ============================================================
   5 — SCROLL-DRIVEN HERO EXIT
   The hero transforms into the next scene rather than stopping.
   Driven by a --exit variable (0..1) set from scroll position.
   ============================================================ */
.hero-cine__type,
.hero-cine__media,
.hero-cine__ghost {
  will-change: transform, opacity;
}
.hero-cine[data-exit] .hero-cine__type {
  transform: translate3d(0, calc(var(--exit, 0) * -40px), 0) scale(calc(1 - var(--exit, 0) * 0.04));
  opacity: calc(1 - var(--exit, 0) * 0.85);
}
.hero-cine[data-exit] .hero-cine__ghost {
  transform: translate(-50%, -50%) scale(calc(1 + var(--exit, 0) * 0.18));
  opacity: calc(1 - var(--exit, 0) * 0.6);
}
.hero-cine[data-exit] .hero-cine__media {
  transform: translate3d(0, calc(var(--exit, 0) * -26px), 0);
}

/* ============================================================
   6 — POINTER LIGHTING ON DARK SURFACES
   ============================================================ */
.focus-surface {
  position: relative;
  isolation: isolate;
}
.focus-surface .pointer-light {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(
    600px circle at var(--mx) var(--my),
    color-mix(in srgb, var(--accent) 7%, transparent) 0%,
    transparent 68%
  );
  opacity: 0;
  transition: opacity var(--dur-mid) var(--ease-focus);
}
.focus-surface:hover .pointer-light { opacity: 1; }
.focus-surface > *:not(.pointer-light) { position: relative; z-index: 1; }

/* ============================================================
   7 — BUTTONS: fill originates at the cursor
   ============================================================ */
.btn.magnetic {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.btn.magnetic::before {
  content: "";
  position: absolute;
  left: var(--bx, 50%);
  top: var(--by, 50%);
  width: 0;
  height: 0;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.16;
  transform: translate(-50%, -50%);
  transition: width var(--dur-fast) var(--ease-io), height var(--dur-fast) var(--ease-io);
  z-index: -1;
}
.btn.magnetic:hover::before,
.btn.magnetic:focus-visible::before {
  width: 260%;
  height: 600%;
}

/* Arrow links: the line grows, the arrow travels. */
.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 650;
  text-decoration: none;
}
.arrow-link .bar {
  display: inline-block;
  width: 1.4rem;
  height: 1px;
  background: currentColor;
  transition: width var(--dur-fast) var(--ease-focus);
}
.arrow-link:hover .bar,
.arrow-link:focus-visible .bar { width: 2.4rem; }
.arrow-link svg { transition: transform var(--dur-fast) var(--ease-focus); }
.arrow-link:hover svg,
.arrow-link:focus-visible svg { transform: translateX(3px); }

/* ============================================================
   8 — NAVIGATION CAPSULE
   Transparent over the hero, then a floating inset capsule.
   ============================================================ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 90;
  transition: transform var(--dur-mid) var(--ease-focus),
              background-color var(--dur-mid) var(--ease-focus),
              box-shadow var(--dur-mid) var(--ease-focus);
}
/* On a cinematic-hero page the header must sit OVER the hero, not above it.
   styles.css makes it `position: sticky`, so it occupies layout space and
   simply going transparent reveals the white body behind it. Lift it out of
   flow instead, and let the hero own the full viewport. */
body.has-cine-hero .site-header {
  position: absolute;
  /* left/right rather than inset-inline: an absolutely positioned box with
     only `top` set is shrink-to-fit, which collapsed the header at 390px and
     wrapped the wordmark onto three lines over the logo. */
  left: 0;
  right: 0;
  width: 100%;
  top: 0;
  background: transparent;
  border-bottom-color: transparent;
  backdrop-filter: none;
  box-shadow: none;
}
body.has-cine-hero .site-header .nav-link,
body.has-cine-hero .site-header .brand span { color: var(--text-on-brand); }
body.has-cine-hero .site-header .brand small { color: var(--text-on-brand-soft); }

/* Once past the hero it becomes a real floating capsule, fixed to the top. */
body.has-cine-hero .site-header.is-pinned {
  position: fixed;
  animation: hdrDrop var(--dur-mid) var(--ease-focus) both;
}
@keyframes hdrDrop {
  from { transform: translate3d(0, -12px, 0); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
body.has-cine-hero .site-header.is-pinned > .container {
  max-width: 1380px;
  margin-top: 0.7rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, #fff 12%, transparent);
  background: color-mix(in srgb, var(--brand-900) 72%, transparent);
  backdrop-filter: blur(16px) saturate(1.2);
  box-shadow: 0 18px 44px -22px rgba(0, 0, 0, 0.7);
  transition: all var(--dur-mid) var(--ease-focus);
}

/* Mobile wordmark. PRE-EXISTING BUG, not caused by the hero work: .brand has
   no small-screen rule, so at 390px the flex row squeezes the span to ~71px
   and "Project One Focus" wraps onto three lines across the logo. Verified
   identically on about.html with the untouched sticky header.
   The tagline is dropped below 560px only — it repeats the hero eyebrow. */
@media (max-width: 560px) {
  /* No min-width:0 here — combined with nowrap it lets the flex item shrink
     below its own text, which overflows the wordmark across the Menu button
     instead of reflowing. Natural width + a pushed-right toggle is correct. */
  /* flex: 0 0 auto — the anchor must not shrink. With `0 1 auto` the box
     shrank while its nowrap span kept full width, so the text spilled over
     the Menu button rather than the box reserving room for it. */
  .brand { font-size: 0.95rem; flex: 0 0 auto; }
  .brand span { white-space: nowrap; }
  .brand span small { display: none; }
  .nav-toggle { flex: none; margin-left: auto; }
}

/* gold dot that tracks the hovered nav item */
.nav-menu .nav-link { position: relative; }
.nav-menu .nav-link::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0.15rem;
  width: 4px;
  height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--dur-fast) var(--ease-focus),
              transform var(--dur-fast) var(--ease-focus);
}
.nav-menu .nav-link:hover::after,
.nav-menu .nav-link:focus-visible::after,
.nav-menu .nav-link[aria-current="page"]::after {
  opacity: 1;
  transform: none;
}

/* ============================================================
   9 — EDITORIAL SECTION SYSTEM
   Controlled asymmetry on a shared grid. Sections opt in to a
   width; they do not all inherit one container.
   ============================================================ */
.section-editorial {
  --cols: 12;
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  gap: clamp(1rem, 2.4vw, 2rem);
  width: min(100% - 3rem, var(--w-wide));
  margin-inline: auto;
}
.section-editorial > .lead-col { grid-column: 1 / span 6; }
.section-editorial > .side-col { grid-column: 9 / span 4; align-self: end; }
.section-editorial > .full-col { grid-column: 1 / -1; }

@media (max-width: 860px) {
  .section-editorial > .lead-col,
  .section-editorial > .side-col,
  .section-editorial > .full-col { grid-column: 1 / -1; }
}

/* Oversized display word used as a section anchor. */
.display-word {
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: clamp(4rem, 15vw, 14rem);
  line-height: 0.82;
  letter-spacing: -0.045em;
  color: color-mix(in srgb, var(--brand) 7%, transparent);
  pointer-events: none;
  user-select: none;
}
.section-dark .display-word { color: color-mix(in srgb, #fff 6%, transparent); }

.section-dark {
  background: var(--brand);
  color: var(--text-on-brand);
  position: relative;
  overflow: clip;
}
.section-dark h2 { color: #fff; }
.section-dark p { color: var(--text-on-brand-soft); }

/* ============================================================
   10 — MARQUEE
   Slow, editorial, velocity-aware. Duplicated track for a seamless
   loop; aria-hidden on the clone so it is not read twice.
   ============================================================ */
.marquee {
  overflow: hidden;
  border-block: 1px solid var(--line);
  padding-block: clamp(1rem, 2.5vw, 1.8rem);
}
.section-dark .marquee { border-color: color-mix(in srgb, #fff 10%, transparent); }
.marquee__track {
  display: flex;
  gap: 3rem;
  width: max-content;
  animation: marqueeSlide 68s linear infinite;
  animation-play-state: running;
}
.marquee__track > span {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(1.4rem, 4vw, 3.2rem);
  letter-spacing: -0.02em;
  display: inline-flex;
  align-items: center;
  gap: 3rem;
  white-space: nowrap;
  color: color-mix(in srgb, currentColor 55%, transparent);
}
.marquee__track > span::after {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1px solid var(--accent);
}
@keyframes marqueeSlide {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* ============================================================
   11 — UTILITIES
   ============================================================ */
.u-clip { overflow: clip; }
.u-read { max-width: var(--w-read); }
.u-text { max-width: var(--w-text); }
.u-wide { width: min(100% - 3rem, var(--w-wide)); margin-inline: auto; }

/* Occlusion helper: let an element cross its container's edge. */
.u-bleed-r { margin-right: calc((100vw - min(100vw, var(--w-wide))) / -2); }

/* ============================================================
   12 — SIGNATURE 3: PROGRAM STORYTELLING
   ------------------------------------------------------------
   Progressive enhancement, deliberately:
     - DEFAULT (no JS, mobile, reduced motion) = a plain vertical
       stack of four editorial blocks. Everything readable.
     - .is-enhanced (added by JS, desktop only) = a sticky scene
       where panels cross-fade and the media wipes via a ring.
   The default is the accessible one; the sticky version is the
   enhancement, never the other way round.
   ============================================================ */
.program-story { position: relative; }

.program-story__step {
  padding-block: clamp(3rem, 8vh, 6rem);
  border-top: 1px solid var(--line);
}
.program-story__step:first-of-type { border-top: 0; }

.program-num {
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: clamp(2.5rem, 6vw, 5rem);
  line-height: 1;
  letter-spacing: -0.04em;
  color: color-mix(in srgb, var(--brand) 16%, transparent);
}
.section-dark .program-num { color: color-mix(in srgb, #fff 22%, transparent); }

.program-media { margin: 0; border-radius: 20px; overflow: hidden; }
.program-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- enhanced (desktop only) ---------------------------- */
@media (min-width: 981px) {
  .program-story.is-enhanced .program-story__viewport {
    position: sticky;
    top: 0;
    min-height: 100svh;
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: clamp(2rem, 5vw, 5rem);
    width: min(100% - 3rem, var(--w-wide));
    margin-inline: auto;
    overflow: clip;
  }

  .program-story.is-enhanced .program-story__panels {
    position: relative;
    min-height: 24rem;
    padding-left: 5rem;      /* gutter reserved for the 01-04 index */
  }
  /* The index is in normal flow while the steps are absolute, so without
     this they share an origin and print on top of each other. The index
     gets the gutter; the steps start after it. */
  .program-story.is-enhanced .program-index {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    margin: 0;
    z-index: 2;
  }

  .program-story.is-enhanced .program-story__step {
    position: absolute;
    inset: 0 0 0 5rem;
    padding: 0;
    border: 0;
    opacity: 0;
    visibility: hidden;   /* also drops it from the a11y tree and tab order */
    transform: translate3d(0, 22px, 0);
    transition: opacity var(--dur-mid) var(--ease-focus),
                transform var(--dur-mid) var(--ease-focus),
                visibility 0s linear var(--dur-mid);
  }
  .program-story.is-enhanced .program-story__step.is-active {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
  }

  .program-story.is-enhanced .program-story__media {
    position: relative;
    aspect-ratio: 4 / 5;
  }
  /* Circular ring wipe between programs: the brand mark performs the
     transition, so the motion is specific to this organisation. */
  .program-story.is-enhanced .program-media {
    position: absolute;
    inset: 0;
    clip-path: circle(0% at 50% 50%);
    transition: clip-path 900ms var(--ease-focus);
  }
  .program-story.is-enhanced .program-media.is-active {
    clip-path: circle(150% at 50% 50%);
  }
}

/* vertical 01-04 index */
.program-index {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
}
.program-index li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--fs-300);
  color: var(--text-soft);
  transition: color var(--dur-fast) var(--ease-focus);
}
.program-index li::before {
  content: "";
  width: 1.6rem;
  height: 1px;
  background: currentColor;
  opacity: 0.4;
  transition: width var(--dur-mid) var(--ease-focus), opacity var(--dur-mid) var(--ease-focus);
}
.program-index li.is-active { color: var(--accent-700); }
.program-index li.is-active::before { width: 3.2rem; opacity: 1; }
@media (max-width: 980px) { .program-index { display: none; } }

/* ============================================================
   13 — SIGNATURE 4: IMPACT
   Four oversized figures. The one nearest the viewport centre is
   full strength and gains a settling ring; the others recede.
   Center-focus is used on exactly this one section.
   ============================================================ */
.impact-stage { position: relative; }

.impact-item {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(1rem, 4vw, 4rem);
  padding-block: clamp(2.5rem, 7vh, 5rem);
  border-top: 1px solid color-mix(in srgb, #fff 10%, transparent);
  opacity: 0.34;
  transition: opacity var(--dur-mid) var(--ease-focus);
}
.impact-item:first-child { border-top: 0; }
.impact-item.is-focus { opacity: 1; }

.impact-num {
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: clamp(3.5rem, 12vw, 11rem);
  line-height: 0.86;
  letter-spacing: -0.05em;
  color: #fff;
  display: block;
  font-variant-numeric: tabular-nums;  /* a rolling reel must not shift width */
}
.impact-label {
  font-size: var(--fs-500);
  color: var(--text-on-brand-soft);
  margin: 0;
  max-width: 30ch;
}

.impact-item__ring {
  position: absolute;
  left: clamp(2rem, 12vw, 12rem);
  top: 50%;
  width: clamp(9rem, 22vw, 19rem);
  height: clamp(9rem, 22vw, 19rem);
  margin-top: calc(clamp(9rem, 22vw, 19rem) / -2);
  border: 1px solid var(--ring-c);
  border-radius: 50%;
  opacity: 0;
  transform: scale(1.35);
  transition: opacity var(--dur-slow) var(--ease-focus),
              transform var(--dur-slow) var(--ease-settle);
  pointer-events: none;
}
.impact-item.is-focus .impact-item__ring { opacity: 1; transform: scale(1); }

@media (max-width: 760px) {
  .impact-item { grid-template-columns: 1fr; gap: 0.5rem; opacity: 1; }
  .impact-item__ring { display: none; }
}

/* rolling digit reel */
/* Reel geometry must be EXACT: the window height, each cell height and the
   per-digit translate all have to be the same value, or the clip shows a
   sliver of the neighbouring numeral. 1em with line-height 1 keeps the cell
   box and the line box identical; 0.86em did not and digits bled. */
.reel {
  display: inline-flex;
  overflow: hidden;
  vertical-align: bottom;
  height: 1em;
  line-height: 1;
}
.reel__col { display: block; will-change: transform; transition: transform 1100ms var(--ease-settle); }
.reel__col span { display: block; height: 1em; line-height: 1; text-align: center; }

/* ============================================================
   14 — SIGNATURE 5: ABOUT TIMELINE
   A line that draws as you descend; nodes resolve at the focal
   band; the traversed portion turns gold.
   ============================================================ */
.timeline { position: relative; padding-left: clamp(2.5rem, 6vw, 4.5rem); }
.timeline::before,
.timeline::after {
  content: "";
  position: absolute;
  left: clamp(0.75rem, 2vw, 1.4rem);
  top: 0;
  width: 1px;
}
.timeline::before { bottom: 0; background: var(--line); }
.timeline::after {
  height: calc(var(--draw, 0) * 100%);
  background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 30%, transparent));
  transition: height 160ms linear;
}

.timeline__node { position: relative; padding-block: clamp(1.75rem, 5vh, 3.25rem); }
.timeline__node::before {
  content: "";
  position: absolute;
  left: calc(0px - clamp(2.5rem, 6vw, 4.5rem) + clamp(0.75rem, 2vw, 1.4rem) - 5px);
  top: calc(clamp(1.75rem, 5vh, 3.25rem) + 0.5em);
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--bg);
  transition: border-color var(--dur-mid) var(--ease-focus),
              box-shadow var(--dur-mid) var(--ease-focus);
}
.timeline__node.is-reached::before {
  border-color: var(--accent);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 14%, transparent);
}

.timeline__year {
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: clamp(1.6rem, 4vw, 2.6rem);
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--brand);
  margin: 0 0 0.4rem;
}
.timeline__node.is-reached .timeline__year { color: var(--accent-900); }
.timeline__body { max-width: 58ch; margin: 0; color: var(--text-soft); }

/* ============================================================
   15 — SIGNATURE 6: DONATION + FOOTER
   ============================================================ */
.donate-stage {
  position: relative;
  overflow: clip;
  text-align: center;
  padding-block: clamp(4rem, 14vh, 9rem);
}
.donate-stage__rings { position: absolute; inset: 0; pointer-events: none; }
.donate-stage__rings .focus-ring {
  left: 50%;
  top: 50%;
  width: var(--rs);
  height: var(--rs);
  margin-left: calc(var(--rs) / -2);
  margin-top: calc(var(--rs) / -2);
  transform: scale(1.6);   /* start wide, contract inward on entry */
  opacity: 0;
  transition: transform 1200ms var(--ease-settle), opacity 900ms var(--ease-focus);
  transition-delay: var(--d, 0ms);
}
.donate-stage.is-visible .focus-ring { transform: scale(1); opacity: 1; }

.donate-stage__inner { position: relative; z-index: 2; }
.donate-stage h2 {
  font-size: clamp(2rem, 5.5vw, 4.25rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  max-width: 18ch;
  margin-inline: auto;
  color: #fff;
}

/* the CTA radiates: the ring language at button scale */
.donate-cta { position: relative; display: inline-block; }
.donate-cta::before,
.donate-cta::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 100%;
  height: 100%;
  border: 1px solid var(--accent);
  border-radius: 999px;
  transform: translate(-50%, -50%) scale(1);
  opacity: 0;
  pointer-events: none;
  transition: transform 700ms var(--ease-settle), opacity 700ms var(--ease-focus);
}
.donate-cta:hover::before,
.donate-cta:focus-within::before { transform: translate(-50%, -50%) scale(1.35); opacity: 0.55; }
.donate-cta:hover::after,
.donate-cta:focus-within::after { transform: translate(-50%, -50%) scale(1.7); opacity: 0.25; }

/* footer brand moment */
.footer-brand { position: relative; overflow: clip; }
.footer-brand__word {
  display: block;
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: clamp(3rem, 15vw, 13rem);
  line-height: 0.8;
  letter-spacing: -0.05em;
  white-space: nowrap;
  color: color-mix(in srgb, #fff 5%, transparent);
  pointer-events: none;
  user-select: none;
  margin: 0 0 -0.12em;
}

@media (prefers-reduced-motion: reduce) {
  .impact-item { opacity: 1 !important; }
  .impact-item__ring,
  .donate-stage__rings .focus-ring { opacity: 1 !important; transform: none !important; }
  .reel__col { transition: none !important; }
  .program-story.is-enhanced .program-media { clip-path: none !important; }
}
