/* Cinematic mode (html.is-cinematic, added by main.js unless reduced motion is preferred).
   Every chapter's stage is pinned full-screen while its track scrolls past. scenes.js
   publishes each chapter's progress as --in (arriving), --t (pinned) and --out (leaving);
   chapters.js adds the hand-off values (--iris, --spin, --d, --flash, --stamp …).
   Scrubbed motion uses the individual `scale` / `translate` properties so it never fights
   the timed `transform` / `opacity` transitions used by the reveals. The dealt envelopes and
   polaroids are the exception: their rules replace `transform` outright (with transitions
   off) and are declared after the reveal rules, which they must stay after. */

/* ───────── Atmosphere ───────── */

.is-cinematic .embers {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* ───────── Tracks & stages ───────── */

.is-cinematic .scene {
  position: relative;
  height: calc(var(--len, 1) * 100vh);
  min-height: 0;
  overflow: visible;
}

.is-cinematic .scene__stage {
  position: fixed;
  inset: 0;
  display: grid;
  align-items: center;
  align-items: safe center;
  justify-items: center;
  overflow: hidden;
  pointer-events: none;
}

.is-cinematic .scene.is-present > .scene__stage { pointer-events: auto; }
.is-cinematic .scene.is-offstage > .scene__stage { opacity: 0 !important; }

.is-cinematic .section {
  width: 100%;
  padding: max(4.5rem, calc(env(safe-area-inset-top) + 2.5rem)) 1.5rem max(3rem, calc(env(safe-area-inset-bottom) + 2rem));
  translate: 0 calc(var(--shift, 0px) * var(--t) * -1);
}

/* Reveals belong to whichever chapter is present, and replay when you scroll back. */
.is-cinematic .is-present [data-reveal] { opacity: 1; transform: none; filter: none; }
.is-cinematic .is-present .split-char { opacity: 1; filter: none; transform: none; }

.is-cinematic .is-measuring > .scene__stage,
.is-cinematic .is-measuring [data-clock],
.is-cinematic .is-measuring .section { scale: none !important; translate: none !important; transform: none !important; }

/* ───────── I. Monogram: inked in, then drawn back into the paper ───────── */

.is-cinematic .hero > .scene__stage {
  display: block;
  opacity: calc(1 - (var(--out) - .6) * 2.5);
}

.is-cinematic .hero__copy {
  opacity: calc(1 - var(--out) * 2.2);
  translate: 0 calc(var(--out) * -14vh);
}

/* ───────── II. Countdown: rolls in out of the haze ───────── */

.is-cinematic [data-scene="countdown"] > .scene__stage {
  opacity: min(calc((var(--in) - .35) / .5), calc(1 - var(--out) / .55));
  scale: calc(.7 + .3 * var(--in) + .9 * var(--out));
}

.is-cinematic .flip-clock[data-reveal] { opacity: 1; transform: none; filter: none; transition: none; }

.flip-clock.is-rolling .flip.is-flipping .flip__flap--top { animation-duration: .07s; }
.flip-clock.is-rolling .flip.is-flipping .flip__flap--bottom { animation-duration: .07s; animation-delay: .07s; }

/* ───────── III. The day: the clock flies in, hands racing forward to eleven ───────── */

.is-cinematic [data-scene="day"] > .scene__stage {
  opacity: calc((var(--in) - .3) / .45);
  scale: calc(.55 + .45 * var(--in));
}

.is-cinematic .day { gap: 1.6rem; }
.is-cinematic .clock { width: min(58vw, 32svh, 300px); }

.is-cinematic .day__clock[data-reveal] {
  opacity: 1;
  transform: none;
  filter: none;
  transition: none;
  scale: var(--clock-scale, 1);
}

.is-cinematic .clock__hand { transition: none; }
.is-cinematic .clock__hand--hour { transform: rotate(calc(330deg - var(--spin, 0) * 120deg)); }
.is-cinematic .clock__hand--minute { transform: rotate(calc(var(--spin, 0) * -1440deg)); }
.is-cinematic .clock__rim { opacity: calc(1 - var(--out) * 1.2); }

.is-cinematic .day__copy {
  opacity: calc(1 - var(--out) * 4);
  translate: 0 calc(var(--out) * 8vh);
}

/* ───────── IV. The place: seen through the clock face, then up to the house ───────── */

.is-cinematic .passage__stage {
  display: block;
  height: auto;
  clip-path: circle(var(--iris, 0px) at var(--iris-x, 50%) var(--iris-y, 50%));
  opacity: calc(1 - (var(--out) - .82) / .18);
}

.is-cinematic .passage.is-open > .passage__stage { clip-path: none; }

/* While the window is still clock-sized, Danson House sits in the middle of the face; the
   view settles back as the window opens, then the camera zooms towards the house. */
.is-cinematic .passage__art {
  --settle: calc(1 - var(--in) * var(--in) * var(--in));
  transform: scale(calc(1 + var(--t) * 1.6 + (1 - var(--in)) * .3));
  transform-origin: var(--focus-x, 50%) var(--focus-y, 64%);
  translate:
    calc((var(--iris-x, 50vw) - var(--focus-x, 50vw)) * var(--settle))
    calc((var(--iris-y, 50vh) - var(--focus-y, 64vh)) * var(--settle));
}

.is-cinematic .passage__hint { opacity: min(calc((var(--in) - .85) / .15), calc(1 - var(--t) * 5)); }

.is-cinematic .passage__copy { pointer-events: none; }
.is-cinematic .passage.is-arrived:not(.is-burning) .passage__copy { pointer-events: auto; }

.is-cinematic .passage__burn {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
}

/* A hair of blur melts the canvas's pixel steps into a soft, smouldering edge. */
.is-cinematic .passage.is-burning .passage__burn { opacity: 1; filter: blur(2.2px); }

/* ───────── V. Still under seal: envelopes dealt out of the fire ───────── */

.is-cinematic [data-scene="sealed"] > .scene__stage {
  opacity: min(calc((var(--in) - .45) / .3), calc(1 - (var(--out) - .32) / .16));
}

.is-cinematic .sealed__glow {
  display: block;
  position: absolute;
  inset: 0;
  background: radial-gradient(55% 40% at 50% 62%, color-mix(in srgb, var(--white) 85%, transparent), transparent 70%);
  opacity: calc((var(--in) - .6) * 2.5);
  animation: candle-flicker 3.2s ease-in-out infinite alternate;
}

@keyframes candle-flicker {
  0% { scale: 1; }
  35% { scale: 1.04; }
  70% { scale: .98; }
  100% { scale: 1.02; }
}

.is-cinematic .sealed__grid { max-width: min(40rem, 37svh); }

@media (min-width: 900px) {
  .is-cinematic .sealed__grid { max-width: min(58rem, 130svh); }
}

.is-cinematic .sealed [data-envelope] {
  --deal: calc(1 - var(--d, 0));
  opacity: calc(var(--d, 0) * 3);
  filter: none;
  transition: none;
  transform:
    translate(calc(var(--dx, 0px) * var(--deal)), calc(var(--dy, 0px) * var(--deal) + var(--deal) * 55vh))
    rotate(calc(var(--rot, 0deg) * var(--deal)));
}

/* ───────── VI. Photos: a flash, then the polaroids develop as they fan out ───────── */

.is-cinematic [data-scene="photos"] > .scene__stage {
  opacity: calc(1 - var(--out) * 1.8);
  scale: calc(1 + var(--out) * .6);
}

.is-cinematic .photos { opacity: calc((var(--in) - .48) / .08); }

.is-cinematic .flash {
  display: block;
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle at 50% 42%, var(--white), color-mix(in srgb, var(--white) 94%, transparent) 45%, color-mix(in srgb, var(--cream) 85%, transparent));
  opacity: var(--flash, 0);
}

.is-cinematic .polaroids { height: clamp(170px, min(48vw, 28svh), 300px); }

.is-cinematic .polaroids[data-reveal] { opacity: 1; transform: none; filter: none; transition: none; }

.is-cinematic .polaroid {
  transition: none;
  transform:
    translate(calc(-50% + var(--x) * var(--fan, 0)), calc(-50% + var(--rise, 0) * 70vh))
    rotate(calc(var(--r) * var(--fan, 0)));
}

.is-cinematic .polaroid::before {
  /* A print develops out of the paper: washed-out white first, then the image comes up. */
  filter: grayscale(1) brightness(calc(1.7 - .7 * var(--dev, 0))) contrast(calc(.35 + .7 * var(--dev, 0)));
}

/* ───────── VII. Finale: the seal stamps down and our names are written ───────── */

.is-cinematic [data-scene="finale"] > .scene__stage { opacity: calc((var(--in) - .3) / .25); }

.is-cinematic .footer .wax--large {
  --lift: calc(1 - var(--stamp, 0));
  scale: calc(1 + var(--lift) * 2.4);
  opacity: calc(var(--stamp, 0) * 5);
  filter: drop-shadow(0 calc(5px + var(--lift) * 34px) calc(6px + var(--lift) * 26px) color-mix(in srgb, var(--ink) 24%, transparent));
}

.is-cinematic .footer__names {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(var(--write, 0) * 130% - 30%), transparent calc(var(--write, 0) * 130%));
  mask-image: linear-gradient(90deg, #000 calc(var(--write, 0) * 130% - 30%), transparent calc(var(--write, 0) * 130%));
}

.is-cinematic .footer__date,
.is-cinematic .footer__link { opacity: calc((var(--write, 0) - .5) * 2); }

.is-cinematic .is-stamped .wax--large::after {
  content: '';
  position: absolute;
  inset: -12%;
  border: 1px solid color-mix(in srgb, var(--sage) 75%, transparent);
  border-radius: 50%;
  animation: seal-ripple 1.4s var(--ease-out) forwards;
}

.is-cinematic .is-stamped .footer__content { animation: seal-thud .45s ease-out; }

@keyframes seal-ripple {
  from { scale: .7; opacity: 1; }
  to { scale: 2.8; opacity: 0; }
}

@keyframes seal-thud {
  0% { translate: 0 0; }
  25% { translate: 0 5px; }
  60% { translate: 0 -1px; }
  100% { translate: 0 0; }
}
