/* MUNDP 2027 — homepage welcome experience.
   A full-screen, scroll-linked animation that opens automatically the
   first time the homepage is opened fresh each browser session — a real
   lightbox experience, not embedded page content — and markets everything
   that changed in the rebuild before releasing into the normal homepage
   underneath. Navigating back to the homepage again later in the same
   session (e.g. the nav logo / "Home") goes straight through, uninterrupted
   — see .mundp-intro-seen below. A "Bored?" button lets visitors replay it
   on demand at any time. Motion is driven by intro.js with a lerped
   (trailing) progress value for a silky, Apple-product-page feel rather
   than a 1:1 scroll bind.

   Structure: .intro-overlay (the lightbox) > .intro-scroll (its own
   scrollable viewport — scrolling THIS, not the page, drives the story) >
   .intro-experience (tall inner content) > .intro-stage (pinned via
   position: sticky inside .intro-scroll).

   Progressive enhancement: without JS, .intro-overlay/.intro-scroll stay in
   normal document flow (see base rules below) so the intro just renders as
   an ordinary tall section at the top of the page, with real anchor links
   to skip past it — nothing here is load-bearing for reaching the site.
   Additive + self-contained: safe to delete this file, intro.js, and the
   markup block in index.html to fully remove the whole feature. */

.intro-overlay {
  position: static;
}

.intro-scroll {
  position: static;
  overflow: visible;
  height: auto;
}

/* JS-enhanced mode: promote to a true full-screen lightbox with its own
   internal scroll container, independent of the page's real scroll
   position (which stays at 0 the whole time, revealed the instant this
   closes). */
.intro-overlay.intro-js {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: #0a1f4d;
  transition: opacity 0.5s ease, visibility 0s linear 0s;
}

.intro-overlay.intro-js .intro-scroll {
  position: absolute;
  inset: 0;
  overflow-y: scroll;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.intro-overlay.intro-js.is-closed {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.5s ease, visibility 0s linear 0.5s;
}

.intro-experience {
  position: relative;
  height: 920vh;
  background: var(--accent-deep, #0a1f4d);
}

.intro-stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  isolation: isolate;
}

/* ---------- backdrop ---------- */
.intro-backdrop {
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 120% at 50% 0%, #12296b 0%, #0a1f4d 55%, #060f28 100%);
}

/* liquid-glass blobs: drift ambiently forever (independent of scroll) while
   continuously shifting hue against the overall journey progress — one
   continuous colour glide rather than a slideshow of fixed murals, so it
   scales cleanly to any number of beats. mix-blend-mode: screen gives the
   soft additive glow typical of "liquid glass" surfaces. */
.intro-blob {
  position: absolute;
  border-radius: 50%;
  mix-blend-mode: screen;
  will-change: transform, filter;
}

.intro-blob--a {
  top: -14%;
  left: -12%;
  width: 62vmax;
  height: 62vmax;
  background: radial-gradient(circle at 30% 30%, rgba(3, 86, 240, 0.6), transparent 70%);
  filter: blur(70px) hue-rotate(calc(var(--intro-progress, 0) * 30deg));
  animation: intro-drift-a 26s ease-in-out infinite;
}

.intro-blob--b {
  bottom: -22%;
  right: -16%;
  width: 70vmax;
  height: 70vmax;
  background: radial-gradient(circle at 60% 60%, rgba(122, 92, 255, 0.5), transparent 70%);
  filter: blur(80px) hue-rotate(calc(var(--intro-progress, 0) * -35deg));
  animation: intro-drift-b 32s ease-in-out infinite;
}

.intro-blob--c {
  top: 28%;
  left: 38%;
  width: 48vmax;
  height: 48vmax;
  background: radial-gradient(circle at 50% 50%, rgba(3, 197, 240, 0.42), transparent 70%);
  filter: blur(60px) hue-rotate(calc(var(--intro-progress, 0) * 40deg));
  animation: intro-drift-c 22s ease-in-out infinite;
}

.intro-blob--d {
  bottom: 6%;
  left: -6%;
  width: 44vmax;
  height: 44vmax;
  background: radial-gradient(circle at 40% 60%, rgba(80, 110, 220, 0.32), transparent 70%);
  filter: blur(65px) hue-rotate(calc(var(--intro-progress, 0) * -25deg));
  animation: intro-drift-d 29s ease-in-out infinite;
}

@keyframes intro-drift-a {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(6%, 8%) scale(1.08); }
}

@keyframes intro-drift-b {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(-8%, -6%) scale(1.1); }
}

@keyframes intro-drift-c {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(5%, -8%) scale(0.94); }
}

@keyframes intro-drift-d {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(7%, -5%) scale(1.06); }
}

/* photo collage: every conference photo supplied, tiled into vertical
   reels of randomly cropped tiles at low opacity over the blue backdrop.
   Each reel (built by intro.js) is taller than the viewport and rolls
   past — alternating direction reel to reel, like adjacent strips of
   film — driven purely by --intro-progress, the same custom property
   everything else in the backdrop already reacts to. */
.intro-collage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-start;
  gap: 2px;
  opacity: 0.3;
  overflow: hidden;
}

.intro-collage-reel {
  position: relative;
  flex: 1 1 0%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  will-change: transform;
  transform: translate3d(0, calc(var(--intro-reel-base, 0px) + var(--intro-progress, 0) * var(--intro-reel-shift, 0px)), 0);
}

.intro-collage-reel img {
  width: 100%;
  height: var(--intro-tile-h, 190px);
  flex: none;
  object-fit: cover;
  display: block;
  filter: saturate(0.85) contrast(1.05);
  transform: scale(var(--intro-tile-scale, 1));
}

.intro-backdrop::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(255, 255, 255, 0.09) 1px, transparent 1px);
  background-size: 26px 26px;
  opacity: 0.5;
  transform: translate3d(calc(var(--intro-progress, 0) * -18px), calc(var(--intro-progress, 0) * -140px), 0);
}

.intro-backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(6, 10, 24, 0) 60%, rgba(6, 10, 24, 0.65) 100%);
}

/* subtle film grain for depth — cheap SVG noise, screened on top at low
   opacity so it reads as texture rather than visible speckling */
.intro-grain {
  position: absolute;
  inset: 0;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- brand mark ---------- */
.intro-mark {
  position: absolute;
  top: 8.5rem;
  left: 50%;
  width: 128px;
  transform: translateX(-50%);
  opacity: 1;
  will-change: transform, opacity;
}

.intro-mark img {
  width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 12px 30px rgba(0, 0, 0, 0.35));
}

/* ---------- skip control ---------- */
.intro-skip {
  position: absolute;
  top: 7rem;
  right: 1.75rem;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  box-sizing: border-box;
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  padding: 0.55rem 1rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.06);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  transition: color 0.25s ease, background-color 0.25s ease, border-color 0.25s ease;
}

.intro-skip:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.4);
}

/* ---------- beats ---------- */
.intro-beats {
  position: relative;
  width: 100%;
  max-width: 720px;
  height: min(64vh, 560px);
  padding: 0 1.75rem;
}

.intro-beat {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  will-change: opacity, transform;
}

/* default (pre-JS / no-JS) state: first beat visible and static */
.intro-beat:first-child {
  position: relative;
  opacity: 1;
}

.intro-experience.intro-js .intro-beat {
  position: absolute;
}

.intro-beat.is-active {
  pointer-events: auto;
}

.intro-eyebrow {
  color: rgba(255, 255, 255, 0.62);
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  margin: 0 0 1.1rem;
}

.intro-heading {
  color: #fff;
  font-size: clamp(2.4rem, 6vw, 4.25rem);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.03em;
  margin: 0 0 1.1rem;
  text-wrap: balance;
}

/* emphasis word: used sparingly on a single word per beat */
.intro-shine {
  color: #fff;
}

.intro-sub {
  color: rgba(255, 255, 255, 0.78);
  font-size: clamp(1rem, 1.6vw, 1.2rem);
  line-height: 1.55;
  letter-spacing: -0.008em;
  max-width: 30em;
  margin: 0 auto;
}

.intro-cta {
  margin-top: 1.75rem;
}

.intro-credit {
  margin: 1.1rem 0 0;
  color: rgba(255, 255, 255, 0.45);
  font-size: 0.8rem;
  letter-spacing: 0.01em;
}

/* continuous word-by-word writing: every word is its own span, and its
   opacity/blur/chromatic fringe is set directly by intro.js on every scroll
   frame — no CSS transition here, so nothing "pops" at a threshold. The
   words themselves ARE the scrollbar, in effect: how far you've scrolled
   through a beat is exactly how much of it has been "written". */
.intro-word {
  display: inline-block;
  transition: none;
}

/* feature peeks & the closing CTA fade in continuously too (driven by
   intro.js from the same per-beat progress that writes the words) rather
   than popping in on a fixed-duration CSS transition — nothing in this
   experience is triggered by crossing a hard threshold except pointer-
   events (is-active, below) and the chip bounce (is-revealed, further
   down), both intentionally binary. */
.intro-experience.intro-js .intro-feature,
.intro-experience.intro-js .intro-cta {
  opacity: 0;
}

/* ---------- feature peeks ---------- */
.intro-feature {
  position: relative;
  margin-top: 1.75rem;
}

/* card-style peeks (ui / forms) get a tiltable inner wrapper — intro.js
   applies a subtle pointer-reactive rotateX/rotateY to this element on fine
   pointers, kept separate from .intro-feature so it never fights the
   entrance transform above. */
.intro-feature-inner {
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
  overflow: hidden;
}

/* a prismatic, rainbow-tinted sheen sweeps across card-style peeks as they
   fade in — a "liquid glass" specular highlight, like light refracting
   through curved glass, driven by the same continuous --sheen custom
   property intro.js sets on .intro-feature-inner (no keyframe animation:
   its position is scroll position, not a timer). */
.intro-feature-inner::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    transparent 14%,
    rgba(10, 31, 77, 0.4) 34%,
    rgba(255, 255, 255, 0.75) 50%,
    rgba(10, 31, 77, 0.4) 66%,
    transparent 86%
  );
  transform: translateX(calc(var(--sheen, -130) * 1%));
  pointer-events: none;
  mix-blend-mode: screen;
}

/* a slow-rotating halo glows behind each glass card — white easing through
   navy, like light raking across curved glass, rather than a literal
   rainbow. The containing block lives one level up so it can extend past
   the card's own clipped edges. */
.intro-feature--ui,
.intro-feature--forms {
  position: relative;
  isolation: isolate;
}

.intro-feature--ui::before,
.intro-feature--forms::before {
  content: "";
  position: absolute;
  inset: -18px;
  z-index: -1;
  border-radius: 26px;
  background: conic-gradient(
    from var(--halo-angle, 0deg),
    #ffffff, #0a1f4d, #ffffff, #0a1f4d, #ffffff
  );
  filter: blur(20px);
  opacity: 0.48;
  animation: intro-halo-spin 9s linear infinite;
}

@keyframes intro-halo-spin {
  to { --halo-angle: 360deg; }
}

@property --halo-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

/* — "a new look, a new feel": a small browser-chrome mock of the redesigned UI — */
.intro-feature--ui .intro-feature-inner {
  width: 260px;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 24px 48px -24px rgba(0, 0, 0, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.intro-mock-chrome {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 10px 12px;
  background: rgba(255, 255, 255, 0.05);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.intro-mock-chrome span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.35);
}

.intro-mock-chrome i {
  flex: 1;
  height: 8px;
  margin-left: 6px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.12);
  font-style: normal;
}

.intro-mock-body {
  padding: 14px;
  text-align: left;
}

.intro-mock-hero {
  height: 46px;
  border-radius: 10px;
  margin-bottom: 10px;
  background: linear-gradient(135deg, rgba(3, 86, 240, 0.55), rgba(150, 110, 255, 0.4));
}

.intro-mock-line {
  height: 7px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.18);
  margin-bottom: 7px;
}

.intro-mock-line--lg { width: 78%; }
.intro-mock-line--sm { width: 52%; margin-bottom: 0; }

.intro-mock-pill {
  width: 64px;
  height: 16px;
  border-radius: 999px;
  margin-top: 10px;
  background: var(--accent, #0356f0);
}

/* — "registration, reimagined": a small form mock — */
.intro-feature--forms .intro-feature-inner {
  width: 240px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 4px;
}

.intro-mock-field {
  height: 15px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.09);
  border: 1px solid rgba(255, 255, 255, 0.14);
}

.intro-mock-field.is-focus {
  border-color: rgba(120, 170, 255, 0.9);
  box-shadow: 0 0 0 3px rgba(3, 86, 240, 0.25);
  background: rgba(255, 255, 255, 0.14);
}

.intro-mock-confirm {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin-top: 4px;
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.75);
}

.intro-mock-confirm img {
  width: 15px;
  height: 15px;
  filter: brightness(0) invert(1);
  opacity: 0.85;
}

/* — chip rows: "smoother, from the first tap", "that's not all", and the
   closing "ready?" peek — plain pill rows, no tilt/sheen (no card surface) — */
.intro-feature--stats,
.intro-feature--highlights,
.intro-feature--next {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  justify-content: center;
  max-width: 30em;
}

.intro-chip {
  padding: 0.45rem 0.95rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}

/* the highlight-reel beat gets its own bouncier, more staggered cascade —
   a springier cubic-bezier than the rest of the copy, since it's meant to
   feel like a flurry of good news rather than a calm reveal */
.intro-experience.intro-js .intro-feature--highlights .intro-chip,
.intro-experience.intro-js .intro-feature--stats .intro-chip {
  opacity: 0;
  transform: translateY(10px) scale(0.85);
  transition:
    opacity 0.5s cubic-bezier(0.34, 1.56, 0.64, 1),
    transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.intro-feature--highlights.is-revealed .intro-chip,
.intro-feature--stats.is-revealed .intro-chip {
  opacity: 1;
  transform: translateY(0) scale(1);
}

.intro-feature--highlights.is-revealed .intro-chip:nth-child(1),
.intro-feature--stats.is-revealed .intro-chip:nth-child(1) { transition-delay: 0.02s; }
.intro-feature--highlights.is-revealed .intro-chip:nth-child(2),
.intro-feature--stats.is-revealed .intro-chip:nth-child(2) { transition-delay: 0.09s; }
.intro-feature--highlights.is-revealed .intro-chip:nth-child(3),
.intro-feature--stats.is-revealed .intro-chip:nth-child(3) { transition-delay: 0.16s; }
.intro-feature--highlights.is-revealed .intro-chip:nth-child(4) { transition-delay: 0.23s; }
.intro-feature--highlights.is-revealed .intro-chip:nth-child(5) { transition-delay: 0.30s; }
.intro-feature--highlights.is-revealed .intro-chip:nth-child(6) { transition-delay: 0.37s; }

/* ---------- progress dots ---------- */
.intro-progress {
  position: absolute;
  right: 2rem;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  z-index: 3;
}

.intro-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
  transition: background-color 0.35s ease, transform 0.35s ease;
}

.intro-dot.is-active {
  background: #ffffff;
  transform: scale(1.7);
  box-shadow: 0 0 8px -1px rgba(255, 255, 255, 0.55);
}

/* ---------- scroll cue ---------- */
.intro-scrollcue {
  position: absolute;
  left: 50%;
  bottom: 2.5rem;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  color: rgba(255, 255, 255, 0.6);
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  z-index: 3;
  transition: opacity 0.4s ease;
}

.intro-scrollcue span {
  width: 1px;
  height: 26px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.85), transparent);
  animation: intro-cue-run 1.8s ease-in-out infinite;
}

@keyframes intro-cue-run {
  0%   { transform: scaleY(0); transform-origin: top; opacity: 0; }
  40%  { transform: scaleY(1); transform-origin: top; opacity: 1; }
  60%  { transform: scaleY(1); transform-origin: bottom; opacity: 1; }
  100% { transform: scaleY(0); transform-origin: bottom; opacity: 0; }
}

/* ---------- small screens ---------- */
@media (max-width: 640px) {
  .intro-mark { width: 88px; top: 6.5rem; }
  .intro-beats { max-width: 92vw; height: min(70vh, 580px); }
  .intro-progress { display: none; }
  .intro-skip { top: 5.5rem; right: 1.25rem; }
  .intro-feature--ui .intro-feature-inner { width: 88vw; max-width: 300px; }
  .intro-feature--forms .intro-feature-inner { width: 84vw; max-width: 280px; }
  .intro-feature--stats,
  .intro-feature--highlights,
  .intro-feature--next { max-width: 92vw; }
}

/* ---------- no-JS fallback ---------- */
.no-js .intro-experience {
  height: auto;
}

.no-js .intro-stage {
  position: static;
  height: auto;
  padding: 7rem 0 5rem;
}

.no-js .intro-mark { position: static; margin: 0 auto 2.5rem; transform: none; }
.no-js .intro-beat { display: none; }
.no-js .intro-beat:first-child { display: flex; }
.no-js .intro-progress,
.no-js .intro-scrollcue,
.no-js .intro-skip { display: none; }
.no-js .intro-blob { animation: none; }

/* ---------- already seen this session ---------- */
/* set on <html> by a tiny synchronous script in <head> (before first paint,
   so there's zero flash) whenever sessionStorage remembers the intro
   already played once this session — e.g. the user clicked the nav logo /
   "Home" after browsing elsewhere on the site. The homepage underneath
   renders immediately, uninterrupted. intro.js still wires up the "Bored?"
   button so the experience can be replayed on demand; openIntro() clears
   this class so the overlay can reappear when asked for. */
.mundp-intro-seen .intro-overlay {
  display: none;
}

/* ---------- "Bored?" replay trigger ---------- */
/* lives on the real homepage, underneath the overlay; hidden until JS has
   actually initialized the experience (nothing to replay otherwise) */
.intro-replay {
  display: none;
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  z-index: 50;
  width: 44px;
  height: 44px;
  box-sizing: border-box;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(10, 20, 55, 0.82);
  color: #fff;
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  cursor: pointer;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 12px 28px -14px rgba(10, 20, 55, 0.55);
  transition: transform 0.28s cubic-bezier(0.22, 0.61, 0.36, 1), background-color 0.25s ease, box-shadow 0.25s ease;
}

.intro-js-ready .intro-replay {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.intro-replay:hover {
  transform: translateY(-2px);
  background: rgba(3, 86, 240, 0.92);
  box-shadow: 0 16px 32px -14px rgba(3, 86, 240, 0.55);
}

.intro-replay:active {
  transform: translateY(0) scale(0.97);
}

@media (max-width: 640px) {
  .intro-replay { right: 1rem; bottom: 1rem; }
}

/* ---------- reduced motion: skip the journey, keep the welcome ---------- */
@media (prefers-reduced-motion: reduce) {
  .intro-experience {
    height: auto;
  }

  .intro-stage {
    position: static;
    height: auto;
    padding: 7rem 0 5rem;
  }

  .intro-mark {
    position: static;
    margin: 0 auto 2.5rem;
    transform: none;
  }

  .intro-beat {
    display: none;
  }

  .intro-beat:first-child {
    display: flex;
    position: relative;
  }

  .intro-progress,
  .intro-scrollcue {
    display: none;
  }

  .intro-blob {
    animation: none;
  }

  .intro-collage {
    display: none;
  }

  .intro-feature--ui::before,
  .intro-feature--forms::before {
    animation: none;
  }

  .intro-backdrop::before {
    transform: none;
  }
}

/* ---------- home hero collage ----------
   Same photo set as the intro overlay's collage above, reused as the
   background for the homepage's normal in-flow hero (#main-content,
   right under the intro). That section isn't a pinned full-screen stage
   like .intro-stage, so it can't reuse --intro-progress — instead
   home-hero-collage.js drives --home-hero-progress off the section's real
   scroll position as it passes through the viewport. Tiles still render
   (statically) under prefers-reduced-motion; only the scroll-driven
   transform is skipped, so the section always has its background. */
#main-content.section-hero {
  position: relative;
  overflow: hidden;
  background-image: none;
}

#main-content .grid-halves-section {
  position: relative;
  z-index: 1;
}

.home-hero-collage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-start;
  gap: 2px;
  overflow: hidden;
}

.home-hero-collage-reel {
  position: relative;
  flex: 1 1 0%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  will-change: transform;
  transform: translate3d(0, calc(var(--home-hero-reel-base, 0px) + var(--home-hero-progress, 0) * var(--home-hero-reel-shift, 0px)), 0);
}

.home-hero-collage-reel img {
  width: 100%;
  height: 190px; /* keep in sync with TILE_H in home-hero-collage.js */
  flex: none;
  object-fit: cover;
  display: block;
  filter: saturate(0.75) contrast(1.05);
}

.home-hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(6, 15, 40, 0.6) 0%, rgba(6, 15, 40, 0.42) 45%, rgba(6, 15, 40, 0.78) 100%);
}

@media (prefers-reduced-motion: reduce) {
  .home-hero-collage-reel {
    transform: none;
  }
}
