@charset "UTF-8";
/* ============================================================================
   Happy Birthday, Sneha — cinematic stylesheet
   Plain CSS only: no build step, no Tailwind directives, no preprocessor syntax.
   Section order mirrors PRD.md §8.
   Rules:
     · animate transform / opacity only
     · mobile-first; desktop extras behind (min-width:1024px) / (hover:hover)
     · progressive enhancement: everything readable without JS (html has no .js)
     · no user-facing copy lives here (only decorative glyphs)
   ========================================================================= */


/* ============================================================================
   1 · TOKENS
   ========================================================================= */
:root {
  /* ---- palette (PRD §4) ---- */
  --rose:          #e87f9c;
  --rose-deep:     #c4577a;
  --rose-soft:     #f7cdd8;
  --rose-ink:      #a83e60;   /* AA-safe rose for small text on cream */
  --lavender:      #c9b6e4;
  --lavender-soft: #ece5f7;
  --gold:          #d9b166;
  --gold-soft:     #f0dcae;
  --gold-ink:      #8a6420;   /* AA-safe gold for small text on cream */
  --cream:         #fdf8f4;
  --pink-light:    #fdeef3;
  --night:         #12071f;
  --plum:          #2a1140;

  /* ---- ink (all AA or better on their stated background) ---- */
  --ink:        var(--plum);      /* on cream: 14.6:1 */
  --ink-soft:   #4a2a63;          /* on cream:  9.1:1 */
  --ink-mute:   #6b4a80;          /* on cream:  6.8:1 */
  --ink-onDark: var(--cream);     /* on night: 18.5:1 */
  --ink-onDark-soft: #e4d7ef;     /* on night: 15.4:1 */

  /* ---- surfaces ---- */
  --surface:         #ffffff;
  --surface-tint:    var(--pink-light);
  --surface-tint-2:  var(--lavender-soft);
  --hairline:        rgba(42, 17, 64, .10);
  --hairline-strong: rgba(42, 17, 64, .18);
  --hairline-light:  rgba(253, 248, 244, .22);

  /* ---- glass ---- */
  --glass-bg:      rgba(255, 255, 255, .58);
  --glass-bg-dark: rgba(24, 10, 38, .52);
  --glass-brd:     rgba(255, 255, 255, .55);
  --glass-blur:    14px;

  /* ---- radii (rounded-xl scale) ---- */
  --r-xs:   .375rem;
  --r-sm:   .625rem;
  --r-md:   .875rem;
  --r-lg:   1.125rem;
  --r-xl:   1.5rem;
  --r-2xl:  2rem;
  --r-3xl:  2.75rem;
  --r-pill: 999px;

  /* ---- soft layered shadows ---- */
  --sh-1: 0 1px 2px rgba(42, 17, 64, .05),
          0 2px 8px -2px rgba(42, 17, 64, .07);
  --sh-2: 0 1px 2px rgba(42, 17, 64, .05),
          0 6px 14px -4px rgba(42, 17, 64, .10),
          0 14px 32px -12px rgba(42, 17, 64, .14);
  --sh-3: 0 2px 4px rgba(42, 17, 64, .05),
          0 10px 24px -8px rgba(42, 17, 64, .13),
          0 28px 56px -18px rgba(42, 17, 64, .20);
  --sh-4: 0 4px 8px rgba(42, 17, 64, .06),
          0 18px 40px -10px rgba(42, 17, 64, .18),
          0 44px 88px -24px rgba(42, 17, 64, .26);
  --sh-inset: inset 0 1px 0 rgba(255, 255, 255, .65);
  --glow-rose: 0 0 0 1px rgba(232, 127, 156, .30),
               0 6px 18px -6px rgba(196, 87, 122, .50),
               0 0 34px -6px rgba(232, 127, 156, .55);
  --glow-rose-lg: 0 0 0 1px rgba(232, 127, 156, .40),
               0 10px 26px -8px rgba(196, 87, 122, .55),
               0 0 58px -6px rgba(232, 127, 156, .70);
  --glow-gold: 0 0 22px -4px rgba(217, 177, 102, .65),
               0 0 52px -10px rgba(217, 177, 102, .45);

  /* ---- easing ---- */
  --e-out:    cubic-bezier(.16, .84, .44, 1);
  --e-in-out: cubic-bezier(.65, 0, .35, 1);
  --e-soft:   cubic-bezier(.25, .46, .45, .94);
  --e-back:   cubic-bezier(.34, 1.46, .64, 1);

  /* ---- durations (PRD §9: 300–900ms) ---- */
  --t-fast: 220ms;
  --t-mid:  420ms;
  --t-slow: 640ms;
  --t-cine: 900ms;

  /* ---- fonts ---- */
  --ff-display: "Playfair Display", Georgia, "Times New Roman", serif;
  --ff-body:    Poppins, system-ui, -apple-system, "Segoe UI", sans-serif;
  --ff-hand:    "Dancing Script", "Segoe Script", cursive;

  /* ---- fluid type ---- */
  --fs-xs:    clamp(.72rem,  .70rem + .12vw, .8rem);
  --fs-sm:    clamp(.82rem,  .79rem + .18vw, .92rem);
  --fs-base:  clamp(.98rem,  .95rem + .22vw, 1.08rem);
  --fs-md:    clamp(1.05rem, 1.00rem + .35vw, 1.22rem);
  --fs-lg:    clamp(1.15rem, 1.05rem + .60vw, 1.45rem);
  --fs-h3:    clamp(1.08rem, 1.00rem + .50vw, 1.35rem);
  --fs-h2:    clamp(1.65rem, 1.25rem + 2.10vw, 2.70rem);
  --fs-h1:    clamp(2.35rem, 1.30rem + 7.20vw, 5.25rem);
  --fs-name:  clamp(2.60rem, 1.20rem + 9.50vw, 6.25rem);
  --fs-quote: clamp(1.55rem, 1.00rem + 4.40vw, 3.30rem);
  --fs-q:     clamp(1.85rem, 1.05rem + 5.60vw, 3.90rem);
  --fs-hand:  clamp(1.30rem, 1.05rem + 1.40vw, 1.90rem);
  --lh-tight: 1.12;
  --lh-snug:  1.32;
  --lh-body:  1.72;
  --ls-wide:  .18em;

  /* ---- rhythm / spacing ---- */
  --pad-x:  clamp(1.1rem, 5vw, 2.25rem);
  --sec-y:  clamp(3.75rem, 11vw, 8rem);
  --gap:    clamp(1rem, 3.2vw, 1.9rem);
  --gap-sm: clamp(.6rem, 2vw, 1rem);
  --wrap:        72rem;
  --wrap-narrow: 40rem;
  --tap: 44px;               /* minimum tap target (PRD §13) */

  /* ---- layers ---- */
  --z-fx:       60;
  --z-cursor:   65;
  --z-progress: 70;
  --z-secret:   75;
  --z-intro:    90;
  --z-modal:    100;
  --z-lightbox: 110;

  /* ---- reveal transform channels (overridden per component) ---- */
  --rv-x: 0px;
  --rv-y: 22px;
  --rv-s: .985;

  color-scheme: light;
}


/* ============================================================================
   2 · BASE
   ========================================================================= */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

html.js { scroll-padding-top: 2rem; }

body {
  margin: 0;
  min-height: 100%;
  font-family: var(--ff-body);
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--ink);
  background-color: var(--cream);
  background-image:
    radial-gradient(120% 70% at 12% -10%, rgba(247, 205, 216, .40), transparent 62%),
    radial-gradient(110% 65% at 92% 4%, rgba(201, 182, 228, .32), transparent 60%);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  text-rendering: optimizeLegibility;
}

/* scroll lock while the intro / a modal / the lightbox owns the screen */
body.is-locked { overflow: hidden; }

h1, h2, h3, h4, blockquote, figure, figcaption, p, ol, ul, li { margin: 0; }
ol, ul { padding: 0; list-style: none; }

img, svg, canvas, video { display: block; max-width: 100%; }
img { height: auto; }

em { font-style: italic; }
strong { font-weight: 600; }

button, input {
  font: inherit;
  color: inherit;
  margin: 0;
}

button {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  border: 0;
  background: none;
  cursor: pointer;
}

::selection {
  background: var(--rose-soft);
  color: var(--plum);
}

/* --- emoji: app.js wraps every emoji run in .emoji so display type
       (huge Playfair sizes, gradient background-clip:text) can never
       repaint or clip a colour glyph. --- */
.emoji {
  display: inline-block;
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", sans-serif;
  font-size: .72em;
  font-style: normal;
  font-weight: 400;
  line-height: 1;
  vertical-align: baseline;
  /* undo any gradient text-clip inherited from a heading */
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--rose-deep);
  -webkit-text-fill-color: currentColor;
  text-shadow: none;
  animation: none;
}

/* --- focus: always visible, never suppressed (PRD §13) --- */
:focus { outline: none; }

:focus-visible {
  outline: 3px solid var(--rose-deep);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

.intro :focus-visible,
.proposal :focus-visible,
.ending :focus-visible,
.lightbox :focus-visible {
  outline-color: var(--gold-soft);
}

/* app.js toggles the `hidden` attribute — assert it, never fight it */
[hidden] { display: none !important; }


/* ============================================================================
   3 · UTILITIES  (story / section / titles / glass / buttons / reveal)
   ========================================================================= */
.story {
  position: relative;
  display: block;
  isolation: isolate;
}

/* Progressive enhancement: readable by default, cinematic only with JS. */
.js .story {
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-cine) var(--e-soft);
}

.js .story.is-live {
  opacity: 1;
  pointer-events: auto;
}

.section {
  position: relative;
  isolation: isolate;
  overflow-x: clip;
}

.section--pad { padding-block: var(--sec-y); }

.section--tinted {
  background-image: linear-gradient(180deg,
    rgba(253, 248, 244, 0) 0%,
    var(--surface-tint) 14%,
    var(--surface-tint) 86%,
    rgba(253, 248, 244, 0) 100%);
}

.section--quote {
  padding-block: calc(var(--sec-y) * 1.15);
  background-image: radial-gradient(80% 90% at 50% 50%,
    rgba(236, 229, 247, .85), rgba(253, 248, 244, 0) 72%);
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad-x);
}

.wrap--narrow { max-width: var(--wrap-narrow); }

.section__title {
  margin-bottom: clamp(1.5rem, 5vw, 2.75rem);
  font-family: var(--ff-display);
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: var(--lh-snug);
  letter-spacing: -.01em;
  color: var(--ink);
  text-align: center;
  text-wrap: balance;
}

.section__title::after {
  content: "";
  display: block;
  width: 3.25rem;
  height: 2px;
  margin: .85rem auto 0;
  border-radius: var(--r-pill);
  background-image: linear-gradient(90deg, transparent, var(--rose), var(--gold), transparent);
}

.section__hint {
  margin: -.75rem auto clamp(1.5rem, 5vw, 2.5rem);
  max-width: 34rem;
  font-size: var(--fs-sm);
  color: var(--ink-mute);
  text-align: center;
  text-wrap: pretty;
}

/* --- subtle glassmorphism (PRD §4: "very subtle") --- */
.glass {
  background-color: var(--glass-bg);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, .55), rgba(255, 255, 255, .12));
  border: 1px solid var(--glass-brd);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-2), var(--sh-inset);
}

@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .glass {
    background-color: rgba(255, 255, 255, .38);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.35);
    backdrop-filter: blur(var(--glass-blur)) saturate(1.35);
  }
}

/* --- buttons --- */
.btn-soft,
.btn-glow,
.btn-proposal {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: var(--tap);
  padding: .8rem 1.6rem;
  font-family: var(--ff-body);
  font-size: var(--fs-sm);
  font-weight: 500;
  letter-spacing: .06em;
  text-transform: uppercase;
  border-radius: var(--r-pill);
  transition:
    transform var(--t-fast) var(--e-back),
    box-shadow var(--t-mid) var(--e-out),
    opacity var(--t-mid) var(--e-out);
  will-change: transform;
}

.btn-soft {
  color: var(--rose-ink);
  background-color: var(--surface);
  background-image: linear-gradient(170deg, #ffffff, var(--rose-soft));
  box-shadow: var(--sh-2), var(--sh-inset);
}

.btn-soft:hover { box-shadow: var(--sh-3), var(--sh-inset); }
.btn-soft:active { transform: scale(.965); }

.btn-glow {
  padding: .95rem 2.2rem;
  font-size: var(--fs-base);
  letter-spacing: .14em;
  color: #ffffff;
  background-color: var(--rose-deep);
  background-image: linear-gradient(135deg, var(--rose) 0%, var(--rose-deep) 55%, #9d3f5f 100%);
  box-shadow: var(--glow-rose);
}

.btn-glow:hover {
  transform: translateY(-2px) scale(1.02);
  box-shadow: var(--glow-rose-lg);
}

.btn-glow:active { transform: scale(.96); }

/* glow halo */
.btn-glow::before {
  content: "";
  position: absolute;
  inset: -40%;
  z-index: -1;
  border-radius: inherit;
  background-image: radial-gradient(circle at 50% 50%, rgba(232, 127, 156, .70), transparent 62%);
  opacity: .8;
  animation: btn-halo 3.4s var(--e-in-out) infinite;
}

/* Ripple: a pill the same shape as the button, scaled 0.25 -> 1 from the centre.
   Because it never exceeds the button box, the button needs no `overflow:hidden`
   — which is what lets the ::before glow halo below bleed outside and be seen. */
.btn-glow::after,
.btn-proposal::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-image: radial-gradient(circle at 50% 50%,
    rgba(255, 255, 255, .62), rgba(255, 255, 255, 0) 64%);
  opacity: 0;
  transform: scale(.25);
  transform-origin: 50% 50%;
  pointer-events: none;
}

.btn-glow:active::after,
.btn-proposal:active::after { animation: btn-ripple 620ms var(--e-out); }

@keyframes btn-halo {
  0%, 100% { opacity: .55; transform: scale(.94); }
  50%      { opacity: .95; transform: scale(1.06); }
}

@keyframes btn-ripple {
  0%   { opacity: .9; transform: scale(.25); }
  100% { opacity: 0;  transform: scale(1); }
}

/* --- reveal system (one IntersectionObserver in app.js adds .is-in) --- */
.reveal { opacity: 1; }

.js .reveal {
  opacity: 0;
  transform:
    translate3d(var(--rv-x, 0px), var(--rv-y, 22px), 0)
    scale(var(--rv-s, .985))
    rotateX(var(--rx, 0deg))
    rotateY(var(--ry, 0deg));
  transition:
    opacity var(--t-cine) var(--e-soft),
    transform var(--t-cine) var(--e-out);
  transition-delay: var(--d, 0ms);
}

.js .reveal.is-in {
  opacity: 1;
  --rv-x: 0px;
  --rv-y: 0px;
  --rv-s: 1;
}


/* ============================================================================
   4 · SECTION 1 — INTRO / LOADING (night sky)
   ========================================================================= */
.intro {
  display: none;                       /* no-JS: never shown */
  position: fixed;
  inset: 0;
  z-index: var(--z-intro);
  align-items: center;
  justify-content: center;
  padding:
    max(1.5rem, env(safe-area-inset-top)) var(--pad-x)
    max(1.5rem, env(safe-area-inset-bottom));
  color: var(--ink-onDark);
  background-color: var(--night);
  background-image:
    radial-gradient(120% 90% at 50% 118%, rgba(196, 87, 122, .34), transparent 60%),
    radial-gradient(90% 70% at 14% 6%, rgba(201, 182, 228, .22), transparent 62%),
    linear-gradient(180deg, #0b0416 0%, var(--night) 46%, #1d0a2e 100%);
  transition: opacity var(--t-cine) var(--e-soft);
}

.js .intro { display: flex; }

.intro.is-out {
  opacity: 0;
  pointer-events: none;
}

/* canvas star field (painted by app.js) */
.intro__stars {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: .95;
}

/* CSS twinkle layer, so the sky is never empty */
.intro::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(1.5px 1.5px at 18% 24%, rgba(255, 255, 255, .85), transparent 100%),
    radial-gradient(1.5px 1.5px at 72% 14%, rgba(255, 255, 255, .70), transparent 100%),
    radial-gradient(1px 1px at 41% 62%, rgba(240, 220, 174, .80), transparent 100%),
    radial-gradient(1.5px 1.5px at 86% 58%, rgba(255, 255, 255, .62), transparent 100%),
    radial-gradient(1px 1px at 28% 82%, rgba(247, 205, 216, .75), transparent 100%),
    radial-gradient(1px 1px at 62% 88%, rgba(255, 255, 255, .55), transparent 100%);
  opacity: .8;
  animation: twinkle 5.5s var(--e-in-out) infinite;
  pointer-events: none;
}

.intro__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(.85rem, 3vw, 1.35rem);
  width: 100%;
  max-width: 34rem;
  text-align: center;
}

.intro__line {
  min-height: 2.6em;
  font-family: var(--ff-display);
  font-size: clamp(1.5rem, 1.05rem + 3.4vw, 2.6rem);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--ink-onDark);
  text-wrap: balance;
}

.intro__sub {
  min-height: 1.6em;
  font-size: var(--fs-md);
  font-weight: 300;
  color: var(--rose-soft);
  text-wrap: balance;
}

/* typing caret */
.intro__caret {
  display: inline-block;
  width: .06em;
  min-width: 2px;
  height: 1.05em;
  margin-left: .08em;
  vertical-align: -.14em;
  border-radius: 2px;
  background-color: var(--gold);
  animation: caret 1s steps(1, end) infinite;
}

/* The button occupies its box from the first frame — it is revealed with
   visibility/opacity, never display, so the typed lines above never reflow.
   visibility:hidden also keeps it out of the tab order and un-clickable. */
.intro__btn { margin-top: clamp(.5rem, 2.5vw, 1.25rem); }

.js .intro__btn {
  visibility: hidden;
  opacity: 0;
  transform: translate3d(0, 10px, 0) scale(.96);
  transition:
    opacity var(--t-slow) var(--e-out),
    transform var(--t-slow) var(--e-out),
    visibility 0s linear var(--t-slow);
}

.js .intro__btn.is-in {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition-delay: 0s;
}

/* no halo pulse while it is still invisible */
.js .intro__btn:not(.is-in)::before { animation: none; }

@keyframes twinkle {
  0%, 100% { opacity: .55; }
  50%      { opacity: 1; }
}

@keyframes caret {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}


/* ============================================================================
   5 · SECTION 2 — HERO
   ========================================================================= */
.hero {
  display: grid;
  place-items: center;
  min-height: 100svh;
  padding: calc(var(--sec-y) * .8) var(--pad-x) calc(var(--sec-y) * .9);
  text-align: center;
}

/* animated multi-stop gradient */
.hero__bg {
  position: absolute;
  inset: -10% -20%;
  z-index: -2;
  background-image: linear-gradient(118deg,
    var(--pink-light) 0%,
    var(--rose-soft) 22%,
    var(--lavender-soft) 44%,
    var(--gold-soft) 62%,
    var(--rose-soft) 80%,
    var(--lavender) 100%);
  background-size: 320% 320%;
  background-position: 0% 50%;
  opacity: .85;
  animation: hero-drift 22s var(--e-in-out) infinite alternate;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    radial-gradient(70% 55% at 50% 40%, rgba(255, 255, 255, .58), transparent 70%),
    linear-gradient(180deg, transparent 62%, var(--cream) 100%);
  pointer-events: none;
}

/* floating particle layer: CSS bokeh base + .particle children from app.js */
.hero__particles {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.hero__particles::before,
.hero__particles::after {
  content: "";
  position: absolute;
  inset: -20%;
  background-repeat: no-repeat;
  background-image:
    radial-gradient(5px 5px at 12% 78%, rgba(255, 255, 255, .85), transparent 100%),
    radial-gradient(3px 3px at 28% 32%, rgba(232, 127, 156, .70), transparent 100%),
    radial-gradient(4px 4px at 48% 66%, rgba(217, 177, 102, .60), transparent 100%),
    radial-gradient(2px 2px at 66% 22%, rgba(255, 255, 255, .90), transparent 100%),
    radial-gradient(5px 5px at 82% 54%, rgba(201, 182, 228, .75), transparent 100%),
    radial-gradient(3px 3px at 92% 84%, rgba(232, 127, 156, .55), transparent 100%);
  animation: particle-rise 17s linear infinite;
}

.hero__particles::after {
  background-image:
    radial-gradient(3px 3px at 6% 44%, rgba(255, 255, 255, .70), transparent 100%),
    radial-gradient(5px 5px at 36% 88%, rgba(217, 177, 102, .50), transparent 100%),
    radial-gradient(2px 2px at 58% 12%, rgba(232, 127, 156, .60), transparent 100%),
    radial-gradient(4px 4px at 74% 74%, rgba(255, 255, 255, .80), transparent 100%),
    radial-gradient(3px 3px at 96% 30%, rgba(201, 182, 228, .70), transparent 100%);
  animation-duration: 26s;
  animation-delay: -9s;
  opacity: .8;
}

/* individual particles injected by app.js (--x/--y/--s/--o/--dur/--d) */
.hero__particles > .particle,
.hero__particles > span {
  position: absolute;
  top: var(--y, 50%);
  left: var(--x, 50%);
  width: var(--s, 4px);
  height: var(--s, 4px);
  border-radius: 50%;
  background-image: radial-gradient(circle,
    rgba(255, 255, 255, .95), rgba(232, 127, 156, .35) 62%, transparent 100%);
  box-shadow: 0 0 10px -2px rgba(255, 255, 255, .8);
  opacity: var(--o, .72);
  animation: particle-float var(--dur, 12s) var(--e-in-out) infinite alternate;
  animation-delay: var(--d, 0s);
  will-change: transform;
}

.hero__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(.6rem, 2.4vw, 1.1rem);
  max-width: 46rem;
  will-change: transform;
}

.hero__kicker {
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--rose-ink);
}

.hero__kicker::before,
.hero__kicker::after {
  content: "·";
  margin-inline: .6em;
  color: var(--gold-ink);
}

.hero__title {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .05em;
  font-family: var(--ff-display);
  font-weight: 500;
  line-height: var(--lh-tight);
  color: var(--ink);
  text-wrap: balance;
}

.hero__title-line {
  display: block;
  font-size: var(--fs-h1);
  letter-spacing: -.015em;
}

.hero__name {
  display: block;
  font-size: var(--fs-name);
  font-weight: 700;
  font-style: italic;
  letter-spacing: -.02em;
  color: var(--rose-deep);
  background-image: linear-gradient(100deg,
    var(--rose-deep) 0%, var(--rose) 34%, #b8895f 66%, var(--rose-deep) 100%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  animation: sheen 9s var(--e-in-out) infinite alternate;
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero__name { color: transparent; }
}

.hero__sub {
  display: flex;
  flex-direction: column;
  gap: .1em;
  max-width: 30rem;
  font-size: var(--fs-md);
  font-weight: 300;
  line-height: var(--lh-snug);
  color: var(--ink-soft);
}

.hero__sub > span:last-child {
  font-style: italic;
  color: var(--ink-mute);
}

/* hero heart — press & hold easter egg (PRD §15) */
.hero__heart {
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  margin-top: .35rem;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--rose-deep);
  border-radius: 50%;
  filter: drop-shadow(0 4px 10px rgba(196, 87, 122, .35));
  transition: transform var(--t-mid) var(--e-back), filter var(--t-mid) var(--e-out);
  animation: heart-pulse 2.4s var(--e-in-out) infinite;
}

.hero__heart:hover { transform: scale(1.12); }

.hero__heart.is-holding {
  filter: drop-shadow(0 0 18px rgba(232, 127, 156, .9));
  animation: heart-hold 3s var(--e-out) forwards;
}

/* scroll indicator (bounce) */
.scroll-indicator {
  position: absolute;
  bottom: max(1.1rem, env(safe-area-inset-bottom));
  left: 50%;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
  transform: translateX(-50%);
  pointer-events: none;
}

.scroll-indicator__label {
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

.scroll-indicator__dot {
  position: relative;
  display: block;
  width: 1.55rem;
  height: 2.6rem;
  border: 1.5px solid var(--hairline-strong);
  border-radius: var(--r-pill);
}

.scroll-indicator__dot::after {
  content: "";
  position: absolute;
  top: .42rem;
  left: 50%;
  width: .34rem;
  height: .34rem;
  border-radius: 50%;
  background-color: var(--rose-deep);
  transform: translateX(-50%);
  animation: scroll-bounce 1.7s var(--e-in-out) infinite;
}

@keyframes hero-drift {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 32%; }
  100% { background-position: 22% 100%; }
}

@keyframes sheen {
  0%   { background-position: 0% 50%; }
  100% { background-position: 100% 50%; }
}

@keyframes particle-rise {
  0%   { transform: translate3d(0, 6%, 0); }
  100% { transform: translate3d(2%, -32%, 0); }
}

@keyframes particle-float {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  100% { transform: translate3d(6px, -26px, 0) scale(1.35); }
}

@keyframes heart-pulse {
  0%, 100% { transform: scale(1); }
  38%      { transform: scale(1.14); }
  56%      { transform: scale(1.02); }
}

@keyframes heart-hold {
  0%   { transform: scale(1); }
  100% { transform: scale(1.55); }
}

@keyframes scroll-bounce {
  0%   { opacity: 0; transform: translate(-50%, 0); }
  22%  { opacity: 1; }
  78%  { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, 1.35rem); }
}


/* ============================================================================
   6 · SECTION 3 — LONG DISTANCE
   ========================================================================= */
.distance {
  --arc-h: clamp(6.5rem, 30vw, 11rem);
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: end;
  gap: .5rem;
  max-width: 40rem;
  margin: 0 auto clamp(1.75rem, 6vw, 3rem);
  /* the arc's endpoints sit at 81.8% of its own height — park the pins there */
  padding-top: calc(var(--arc-h) * .818 - .4rem);
}

/* soft rose→gold→rose bloom behind the arc */
.distance::after {
  content: "";
  position: absolute;
  top: 8%;
  left: 16%;
  right: 16%;
  height: 62%;
  z-index: 0;
  border-radius: 50%;
  background-image: linear-gradient(90deg,
    rgba(232, 127, 156, .32), rgba(217, 177, 102, .30), rgba(232, 127, 156, .32));
  filter: blur(26px);
  opacity: .85;
  pointer-events: none;
}

/* the path spans x=40..560 of a 600-wide viewBox (6.67%..93.33%), so this inset
   lands its endpoints exactly on the two pins at 25% / 75% of the row */
.distance__svg {
  position: absolute;
  top: 0;
  left: 21%;
  z-index: 1;
  width: 58%;
  height: var(--arc-h);
  overflow: visible;
}

/* index.html is frozen and carries no <defs>/<linearGradient>, so a literal SVG
   gradient stroke is not reachable: the gradient reads as a gold core inside a
   layered rose+gold bloom, sitting on the gradient glow above. */
#distance-path {
  fill: none;
  stroke: var(--gold);
  stroke-width: 2.25;
  stroke-linecap: round;
  filter:
    drop-shadow(0 0 3px rgba(240, 220, 174, .95))
    drop-shadow(0 0 9px rgba(232, 127, 156, .75))
    drop-shadow(0 0 20px rgba(217, 177, 102, .55));
}

/* GSAP animates the geometry; with JS on, the arc starts undrawn. */
.js #distance-path {
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
}

#distance-spark {
  fill: var(--cream);
  filter:
    drop-shadow(0 0 4px rgba(255, 255, 255, .95))
    drop-shadow(0 0 10px rgba(217, 177, 102, .90))
    drop-shadow(0 0 22px rgba(232, 127, 156, .80));
  animation: spark-pulse 1.6s var(--e-in-out) infinite;
}

.distance__node {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
}

.distance__node--a { --rv-x: -22px; }
.distance__node--b { --rv-x: 22px; }

.distance__pin {
  position: relative;
  display: block;
  width: .8rem;
  height: .8rem;
  border-radius: 50%;
  background-image: radial-gradient(circle at 34% 30%, #fff, var(--rose) 52%, var(--rose-deep) 100%);
  box-shadow: 0 0 0 4px rgba(232, 127, 156, .20), 0 4px 10px -3px rgba(196, 87, 122, .55);
}

.distance__pin::after {
  content: "";
  position: absolute;
  inset: -.55rem;
  border: 1px solid rgba(232, 127, 156, .5);
  border-radius: 50%;
  animation: pin-ring 2.8s var(--e-out) infinite;
}

.distance__label {
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: .03em;
  color: var(--ink);
}

.distance__heart {
  position: absolute;
  top: calc(var(--arc-h) * .273);      /* the arc's apex */
  left: 50%;
  z-index: 3;
  font-size: clamp(1.5rem, 6vw, 2.25rem);
  line-height: 1;
  color: var(--rose-deep);
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 12px rgba(232, 127, 156, .75));
  pointer-events: none;
}

.js .distance__heart {
  --rv-y: 10px;
  --rv-s: .6;
  transform:
    translate(-50%, calc(-50% + var(--rv-y, 10px)))
    scale(var(--rv-s, .6));
}

.js .distance__heart.is-in {
  --rv-y: 0px;
  --rv-s: 1;
}

.distance__heart.is-pop { animation: heart-pop 720ms var(--e-back); }

.distance__text {
  display: flex;
  flex-direction: column;
  gap: .25em;
  max-width: 34rem;
  margin-inline: auto;
  font-family: var(--ff-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  color: var(--ink-soft);
  text-align: center;
  text-wrap: balance;
}

.distance__text > span:nth-child(2) { color: var(--ink-mute); }

.distance__text > em {
  margin-top: .45em;
  font-size: 1.12em;
  font-weight: 700;
  font-style: italic;
  color: var(--rose-ink);
}

@keyframes spark-pulse {
  0%, 100% { opacity: .8; }
  50%      { opacity: 1; }
}

@keyframes pin-ring {
  0%   { opacity: .9; transform: scale(.6); }
  70%  { opacity: 0;  transform: scale(1.7); }
  100% { opacity: 0;  transform: scale(1.7); }
}

@keyframes heart-pop {
  0%   { transform: translate(-50%, -50%) scale(1); }
  38%  { transform: translate(-50%, -50%) scale(1.42); }
  100% { transform: translate(-50%, -50%) scale(1); }
}


/* ============================================================================
   7 · SECTION 4 — PHOTO STORY
   ========================================================================= */
.story-frames {
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 9vw, 5rem);
  max-width: 58rem;
  margin-inline: auto;
}

.frame {
  position: relative;
  width: 100%;
  max-width: 30rem;
}

.frame--left {
  --rv-x: -28px;
  align-self: flex-start;
}

.frame--right {
  --rv-x: 28px;
  align-self: flex-end;
}

/* the media box is a <button>: tapping it opens the photo full screen */
.frame__media {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: zoom-in;
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;          /* stable box — placeholder never shifts layout */
  border-radius: var(--r-xl);
  background-color: var(--rose-soft);
  background-image: linear-gradient(150deg, var(--rose-soft), var(--lavender-soft));
  box-shadow: var(--sh-3);
}

.frame__media::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid rgba(255, 255, 255, .45);
  border-radius: inherit;
  box-shadow: inset 0 -60px 70px -50px rgba(42, 17, 64, .40);
  pointer-events: none;
}

.frame__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.001);
  transition: transform var(--t-cine) var(--e-out);
  will-change: transform;
}

.frame:hover .frame__img,
.frame:focus-within .frame__img { transform: scale(1.06); }

/* missing photo → gradient placeholder with a ❤ glyph, identical box */
.frame__media[data-missing="1"] {
  display: grid;
  place-items: center;
  background-image:
    radial-gradient(78% 64% at 28% 18%, rgba(255, 255, 255, .42), transparent 60%),
    linear-gradient(150deg, var(--rose-soft) 0%, var(--lavender) 62%, var(--gold-soft) 100%);
}

.frame__media[data-missing="1"]::before {
  content: "❤";
  font-size: clamp(3rem, 15vw, 4.75rem);
  line-height: 1;
  color: rgba(255, 255, 255, .78);
  text-shadow: 0 6px 18px rgba(196, 87, 122, .35);
  animation: heart-pulse 3.2s var(--e-in-out) infinite;
}

.frame__caption {
  margin-top: 1rem;
  padding-inline: .25rem;
  font-family: var(--ff-display);
  font-size: var(--fs-md);
  font-style: italic;
  line-height: var(--lh-snug);
  color: var(--ink-soft);
  text-wrap: pretty;
}

.frame__caption::before {
  content: "";
  display: inline-block;
  width: 1.4rem;
  height: 1px;
  margin-right: .6rem;
  vertical-align: .35em;
  background-color: var(--gold);
}

.frame--right .frame__caption { text-align: right; }

.frame--right .frame__caption::before {
  float: right;
  margin: .72em 0 0 .6rem;
}


/* ============================================================================
   8 · SECTION 5 — TIMELINE
   ========================================================================= */
.timeline {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 5vw, 2.25rem);
  max-width: 52rem;
  margin-inline: auto;
  padding-left: 2.1rem;
}

/* vertical gradient rail */
.timeline::before {
  content: "";
  position: absolute;
  top: .55rem;
  bottom: .55rem;
  left: .45rem;
  width: 2px;
  border-radius: var(--r-pill);
  background-image: linear-gradient(180deg,
    rgba(232, 127, 156, 0) 0%,
    var(--rose) 8%,
    var(--lavender) 42%,
    var(--gold) 74%,
    rgba(196, 87, 122, 0) 100%);
}

.tl {
  position: relative;
  --rv-x: -18px;
}

.tl__dot {
  position: absolute;
  top: .52em;
  left: -1.65rem;
  display: block;
  width: .7rem;
  height: .7rem;
  border-radius: 50%;
  background-image: radial-gradient(circle at 32% 30%, #fff, var(--rose) 50%, var(--rose-deep) 100%);
  box-shadow: 0 0 0 3px rgba(253, 248, 244, .95), 0 0 0 4px rgba(232, 127, 156, .28);
}

.tl__dot::after {
  content: "";
  position: absolute;
  inset: -.3rem;
  border-radius: 50%;
  background-color: rgba(232, 127, 156, .35);
  animation: dot-pulse 2.6s var(--e-out) infinite;
}

.tl:nth-child(even) .tl__dot::after { animation-delay: .9s; }
.tl:nth-child(3n) .tl__dot::after { animation-delay: 1.6s; }

.tl__label {
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--ink);
}

.tl:last-child .tl__label {
  font-weight: 700;
  color: var(--rose-ink);
}

@keyframes dot-pulse {
  0%   { opacity: .75; transform: scale(.55); }
  70%  { opacity: 0;   transform: scale(1.55); }
  100% { opacity: 0;   transform: scale(1.55); }
}


/* ============================================================================
   9 · SECTION 6 — REASONS I LOVE YOU
   ========================================================================= */
.reasons {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap);
  max-width: 66rem;
  margin-inline: auto;
  perspective: 900px;
}

.card {
  position: relative;
  /* title-only cards: icon and title share one row */
  display: flex;
  align-items: center;
  gap: clamp(.8rem, 3.2vw, 1.05rem);
  padding: clamp(.95rem, 3.4vw, 1.25rem) clamp(1.15rem, 4vw, 1.5rem);
  border: 1px solid var(--glass-brd);
  border-radius: var(--r-lg);
  background-color: rgba(255, 255, 255, .62);
  background-image: linear-gradient(158deg, rgba(255, 255, 255, .70), rgba(247, 205, 216, .28));
  box-shadow: var(--sh-2), var(--sh-inset);
  transform-style: preserve-3d;
  transition:
    opacity var(--t-cine) var(--e-soft),
    transform var(--t-mid) var(--e-out),
    box-shadow var(--t-mid) var(--e-out);
}

@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .card {
    background-color: rgba(255, 255, 255, .42);
    -webkit-backdrop-filter: blur(10px) saturate(1.25);
    backdrop-filter: blur(10px) saturate(1.25);
  }
}

.card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-image: linear-gradient(140deg, rgba(255, 255, 255, .55), transparent 46%);
  opacity: 0;
  transition: opacity var(--t-mid) var(--e-out);
  pointer-events: none;
}

.card:hover { box-shadow: var(--sh-4), var(--sh-inset); }
.card:hover::before { opacity: 1; }
.card:active { transform: scale(.985); }

/* tilt: app.js writes --rx / --ry on pointermove; the shared reveal transform
   already composes rotateX()/rotateY(), so only the timing changes here. */
.js .card[data-tilt].is-in {
  transition:
    opacity var(--t-cine) var(--e-soft),
    transform var(--t-fast) var(--e-out),
    box-shadow var(--t-mid) var(--e-out);
}

.card__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: var(--r-md);
  color: var(--rose-deep);
  background-image: linear-gradient(150deg, #fff, var(--rose-soft));
  box-shadow: 0 4px 12px -6px rgba(196, 87, 122, .55), var(--sh-inset);
  transition: transform var(--t-mid) var(--e-back);
}

.card:hover .card__icon { transform: scale(1.1) rotate(-4deg); }

.card__icon svg,
.card__icon i {
  width: 1.35rem;
  height: 1.35rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
}

/* title only — the card is a single line of type beside its icon */
.card__title {
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--ink);
  text-wrap: balance;
}


/* ============================================================================
   10 · SECTION 7 — QUOTE
   ========================================================================= */
.quote {
  display: flex;
  flex-direction: column;
  gap: .12em;
  max-width: 46rem;
  margin-inline: auto;
  padding-inline: var(--pad-x);
  font-family: var(--ff-display);
  font-size: var(--fs-quote);
  font-weight: 500;
  line-height: 1.22;
  letter-spacing: -.015em;
  color: var(--ink);
  text-align: center;
  text-wrap: balance;
}

.quote::before {
  content: "\201C";
  display: block;
  margin-bottom: -.35em;
  font-size: 2.4em;
  line-height: .8;
  color: var(--rose-soft);
}

.quote::after {
  content: "";
  display: block;
  width: 2.75rem;
  height: 2px;
  margin: .8em auto 0;
  border-radius: var(--r-pill);
  background-image: linear-gradient(90deg, transparent, var(--gold), transparent);
}

.quote__line {
  display: block;
  --rv-y: 16px;
}

.quote__line:nth-child(2) { color: var(--rose-ink); }

.quote__line:last-child {
  margin-top: .3em;
  font-style: italic;
  color: var(--ink-soft);
}

/* ============================================================================
   13 · SECTION 10 — LITTLE MOMENTS (drifting cards)
   ========================================================================= */
.moments {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--gap-sm);
  max-width: 58rem;
  margin-inline: auto;
}

.moment {
  padding: .7rem 1.15rem;
  font-family: var(--ff-display);
  font-size: var(--fs-sm);
  font-style: italic;
  line-height: 1.4;
  color: var(--ink-soft);
  border: 1px solid rgba(255, 255, 255, .6);
  border-radius: var(--r-pill);
  background-color: rgba(255, 255, 255, .6);
  background-image: linear-gradient(150deg, rgba(255, 255, 255, .8), rgba(236, 229, 247, .55));
  box-shadow: var(--sh-2), var(--sh-inset);
  will-change: transform;
}

.moment:nth-child(3n) { color: var(--rose-ink); }

.moment:nth-child(4n+2) {
  background-image: linear-gradient(150deg, rgba(255, 255, 255, .82), rgba(247, 205, 216, .55));
}

.moment:nth-child(5n+3) {
  background-image: linear-gradient(150deg, rgba(255, 255, 255, .82), rgba(240, 220, 174, .45));
}

/* reveal is opacity-only here so the drift animation owns `transform` */
.js .moment {
  --rv-y: 0px;
  --rv-s: 1;
  transform: none;
}

.js .moment.is-in {
  animation: moment-drift var(--dur, 9s) var(--e-in-out) infinite alternate;
  animation-delay: calc(var(--d, 0ms) + 700ms);
}

@keyframes moment-drift {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
  100% {
    transform:
      translate3d(var(--x, 12px), calc(var(--x, 12px) * -.75), 0)
      rotate(.75deg);
  }
}


/* ============================================================================
   14 · SECTION 11 — BIRTHDAY CAKE (pure CSS)
   ========================================================================= */
.cake {
  --cake-w: clamp(9rem, 44vw, 13rem);
  --candle-h: clamp(1.5rem, 6.5vw, 2rem);
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: var(--cake-w);
  margin: calc(var(--candle-h) + 1.75rem) auto clamp(1.25rem, 5vw, 2rem);
  filter: drop-shadow(0 18px 26px rgba(42, 17, 64, .18));
}

/* warm halo once the candles are lit */
.cake::before {
  content: "";
  position: absolute;
  top: calc(var(--candle-h) * -1.35);
  left: 50%;
  z-index: -1;
  width: 190%;
  aspect-ratio: 1;
  border-radius: 50%;
  background-image: radial-gradient(circle, rgba(255, 196, 106, .55), rgba(255, 196, 106, 0) 62%);
  opacity: 0;
  transform: translate(-50%, -20%) scale(.7);
  transition: opacity var(--t-cine) var(--e-soft), transform var(--t-cine) var(--e-out);
  pointer-events: none;
}

.cake[data-lit="true"]::before {
  opacity: 1;
  transform: translate(-50%, -20%) scale(1);
}

.cake[data-blown="true"]::before {
  opacity: 0;
  transform: translate(-50%, -20%) scale(1.25);
}

.cake__candles {
  position: absolute;
  bottom: 100%;
  left: 50%;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  gap: clamp(.35rem, 2.2vw, .65rem);
  transform: translateX(-50%);
}

.candle {
  position: relative;
  display: block;
  width: clamp(.34rem, 1.6vw, .45rem);
  height: var(--candle-h);
  border-radius: .2rem .2rem .1rem .1rem;
  background-image: repeating-linear-gradient(48deg,
    #ffffff 0 .18rem,
    var(--rose) .18rem .36rem);
  box-shadow: 0 2px 5px -2px rgba(42, 17, 64, .45), inset -1px 0 0 rgba(42, 17, 64, .12);
}

.candle:nth-child(even) {
  background-image: repeating-linear-gradient(48deg,
    #ffffff 0 .18rem,
    var(--lavender) .18rem .36rem);
}

.candle__wick {
  position: absolute;
  bottom: 100%;
  left: 50%;
  display: block;
  width: 2px;
  height: .28rem;
  border-radius: 1px;
  background-color: #4a3a3a;
  transform: translateX(-50%);
}

/* smoke wisp after blowing */
.candle__wick::after {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 50%;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background-image: radial-gradient(circle, rgba(220, 214, 226, .8), transparent 70%);
  opacity: 0;
  transform: translateX(-50%);
}

.candle__flame {
  position: absolute;
  bottom: calc(100% + .26rem);
  left: 50%;
  display: block;
  width: .42rem;
  height: .72rem;
  border-radius: 50% 50% 42% 42% / 68% 68% 34% 34%;
  background-image:
    radial-gradient(60% 45% at 50% 74%, #fff7d6 0 32%, rgba(255, 247, 214, 0) 74%),
    linear-gradient(180deg, #fff3bf 0%, #ffbe4d 42%, #ff8a3d 78%, rgba(255, 138, 61, .35) 100%);
  box-shadow: 0 0 8px 2px rgba(255, 176, 74, .75), 0 0 20px 6px rgba(255, 140, 60, .35);
  opacity: 0;
  transform: translate(-50%, 4px) scale(.2);
  transform-origin: 50% 100%;
  transition: opacity var(--t-mid) var(--e-out), transform var(--t-mid) var(--e-back);
  pointer-events: none;
}

.cake[data-lit="true"] .candle__flame {
  opacity: 1;
  animation: flame 780ms var(--e-in-out) infinite alternate;
}

.candle:nth-child(2) .candle__flame { animation-delay: -.16s; }
.candle:nth-child(3) .candle__flame { animation-delay: -.34s; }
.candle:nth-child(4) .candle__flame { animation-delay: -.51s; }
.candle:nth-child(5) .candle__flame { animation-delay: -.68s; }

.cake[data-blown="true"] .candle__flame {
  opacity: 0;
  transform: translate(-50%, -10px) scale(.15);
  animation: none;
}

.cake[data-blown="true"] .candle__wick::after {
  animation: smoke 2.4s var(--e-out) forwards;
}

.cake__top,
.cake__mid,
.cake__base {
  position: relative;
  flex: 0 0 auto;
}

.cake__top {
  width: 60%;
  height: clamp(1.5rem, 6.5vw, 2rem);
  border-radius: .5rem .5rem .2rem .2rem;
  background-image:
    linear-gradient(100deg, rgba(255, 255, 255, .55), transparent 46%),
    linear-gradient(180deg, #fffaf6 0%, var(--rose-soft) 100%);
  box-shadow: inset 0 -.35rem .5rem -.35rem rgba(196, 87, 122, .35);
}

.cake__mid {
  width: 80%;
  height: clamp(1.9rem, 8.5vw, 2.6rem);
  border-radius: .35rem;
  background-image:
    linear-gradient(100deg, rgba(255, 255, 255, .45), transparent 44%),
    linear-gradient(180deg, #fbe3ea 0%, #edb6c6 100%);
  box-shadow: inset 0 -.4rem .55rem -.4rem rgba(196, 87, 122, .38);
}

.cake__base {
  width: 100%;
  height: clamp(2.2rem, 10vw, 3.1rem);
  border-radius: .3rem .3rem .45rem .45rem;
  background-image:
    linear-gradient(100deg, rgba(255, 255, 255, .40), transparent 42%),
    linear-gradient(180deg, #f6cdd8 0%, #dfa1b5 100%);
  box-shadow: inset 0 -.5rem .6rem -.45rem rgba(140, 55, 82, .35);
}

/* frosting drips */
.cake__top::before,
.cake__mid::before,
.cake__base::before {
  content: "";
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: .5rem;
  background-color: #fffaf6;
  background-image: radial-gradient(circle at 50% 0, #fffaf6 46%, rgba(255, 250, 246, 0) 52%);
  background-size: .9rem .5rem;
  background-repeat: repeat-x;
  transform: translateY(-.44rem);
}

.cake__mid::before {
  background-color: #fff3f7;
  background-image: radial-gradient(circle at 50% 0, #fff3f7 46%, rgba(255, 243, 247, 0) 52%);
}

.cake__base::before {
  background-color: #fdeef3;
  background-image: radial-gradient(circle at 50% 0, #fdeef3 46%, rgba(253, 238, 243, 0) 52%);
}

/* sprinkles */
.cake__mid::after,
.cake__base::after {
  content: "";
  position: absolute;
  inset: .6rem .35rem .35rem;
  background-image:
    radial-gradient(2px 2px at 14% 30%, var(--gold) 100%, transparent 100%),
    radial-gradient(2px 2px at 42% 62%, var(--lavender) 100%, transparent 100%),
    radial-gradient(2px 2px at 68% 24%, #ffffff 100%, transparent 100%),
    radial-gradient(2px 2px at 86% 70%, var(--gold-soft) 100%, transparent 100%),
    radial-gradient(2px 2px at 28% 82%, #ffffff 100%, transparent 100%);
  opacity: .85;
  pointer-events: none;
}

.cake__plate {
  width: 122%;
  height: .8rem;
  margin-top: -.1rem;
  border-radius: 50% / 100%;
  background-image: linear-gradient(180deg, #f4ecf7 0%, #d3c4de 62%, #bda9cc 100%);
  box-shadow: 0 6px 14px -8px rgba(42, 17, 64, .55);
}

.cake__message {
  min-height: 2.6em;
  margin-bottom: 1rem;
  font-family: var(--ff-hand);
  font-size: var(--fs-hand);
  line-height: 1.4;
  color: var(--rose-ink);
  text-align: center;
  text-wrap: balance;
}

#cake-btn {
  display: flex;
  margin-inline: auto;
}

#cake-btn.is-done {
  color: var(--gold-ink);
  background-image: linear-gradient(170deg, #fffdf8, var(--gold-soft));
  box-shadow: var(--sh-2), var(--glow-gold);
}

@keyframes flame {
  0%   { transform: translate(-50%, 0)    scale(1)         rotate(-2deg); }
  35%  { transform: translate(-50%, -1px) scale(1.1, 1.18) rotate(2deg); }
  70%  { transform: translate(-50%, 0)    scale(.94, 1.06) rotate(-1deg); }
  100% { transform: translate(-50%, -2px) scale(1.06, 1.14) rotate(1.5deg); }
}

@keyframes smoke {
  0%   { opacity: 0;   transform: translate(-50%, 0) scale(.6); }
  18%  { opacity: .75; }
  100% { opacity: 0;   transform: translate(-50%, -2.2rem) scale(3.4); }
}


/* ============================================================================
   15 · SECTION 12 — THE LETTER
   ========================================================================= */
.paper {
  --rule: 2.15rem;
  position: relative;
  padding: clamp(1.6rem, 6vw, 2.75rem) clamp(1.25rem, 5vw, 2.5rem);
  border-radius: var(--r-sm);
  color: #35205a;
  background-color: #fffdf7;
  background-image:
    linear-gradient(90deg, rgba(232, 127, 156, .22) 0 1px, rgba(232, 127, 156, 0) 1px 100%),
    repeating-linear-gradient(180deg,
      rgba(201, 182, 228, 0) 0 calc(var(--rule) - 1px),
      rgba(201, 182, 228, .38) calc(var(--rule) - 1px) var(--rule)),
    radial-gradient(120% 80% at 8% 4%, rgba(255, 247, 230, .9), transparent 60%),
    radial-gradient(90% 70% at 96% 96%, rgba(247, 205, 216, .35), transparent 62%),
    linear-gradient(180deg, #fffdf7, #fdf6ec);
  background-position:
    clamp(.9rem, 3.6vw, 1.85rem) 0,
    0 clamp(1.6rem, 6vw, 2.75rem),
    0 0,
    0 0,
    0 0;
  box-shadow: var(--sh-3), inset 0 0 0 1px rgba(217, 177, 102, .18);
}

/* soft torn edges */
.paper::before,
.paper::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 9px;
  background-color: var(--cream);
  background-image: radial-gradient(circle at 50% 100%, rgba(253, 248, 244, 0) 5.5px, var(--cream) 6px);
  background-size: 13px 9px;
  background-repeat: repeat-x;
  pointer-events: none;
}

.paper::before { top: 0; }

.paper::after {
  bottom: 0;
  transform: scaleY(-1);
}

.paper__salutation {
  margin-bottom: .9rem;
  font-family: var(--ff-hand);
  font-size: calc(var(--fs-hand) * 1.06);
  line-height: var(--rule);
  color: var(--rose-ink);
}

.paper__body {
  display: flex;
  flex-direction: column;
  font-family: var(--ff-hand);
  font-size: var(--fs-hand);
  font-weight: 500;
  line-height: var(--rule);
  letter-spacing: .004em;
}

.paper__line {
  --rv-y: 12px;
  --rv-s: 1;
  margin-bottom: var(--rule);
  text-wrap: pretty;
}

.paper__line:last-child { margin-bottom: 0; }

.paper__line::first-letter { color: var(--rose-ink); }

.paper__closing {
  margin-top: calc(var(--rule) * 1.2);
  font-family: var(--ff-hand);
  font-size: calc(var(--fs-hand) * 1.25);
  font-weight: 700;
  line-height: 1.3;
  color: var(--rose-deep);
  text-align: right;
  transform: rotate(-1.6deg);
  transform-origin: 100% 50%;
}

#letter-signature::before {
  content: "";
  display: block;
  width: 4.5rem;
  height: 1px;
  margin: 0 0 .35rem auto;
  background-image: linear-gradient(90deg, transparent, var(--gold));
}


/* ============================================================================
   16 · SECTION 13 — OUR FUTURE
   ========================================================================= */
.future {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap-sm);
  max-width: 62rem;
  margin-inline: auto;
}

.dream {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: .85rem;
  padding: clamp(1rem, 3.6vw, 1.35rem) clamp(1.1rem, 4vw, 1.5rem);
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .55);
  border-radius: var(--r-lg);
  background-color: rgba(255, 255, 255, .55);
  background-image: linear-gradient(120deg, rgba(255, 255, 255, .8), rgba(236, 229, 247, .45));
  box-shadow: var(--sh-1), var(--sh-inset);
  transition:
    opacity var(--t-cine) var(--e-soft),
    transform var(--t-mid) var(--e-out),
    box-shadow var(--t-mid) var(--e-out);
}

.dream::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 2px;
  background-image: linear-gradient(90deg, var(--rose), var(--gold));
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-slow) var(--e-out);
}

.dream:hover { box-shadow: var(--sh-3), var(--sh-inset); }
.dream:hover::after { transform: scaleX(1); }

.js .dream:hover {
  transition-duration: var(--t-mid);
  transition-delay: 0s;
}

.dream__idx {
  flex: 0 0 auto;
  font-family: var(--ff-display);
  font-size: clamp(1.5rem, 6vw, 2.1rem);
  font-weight: 700;
  font-style: italic;
  line-height: 1;
  color: var(--gold-ink);
  background-image: linear-gradient(150deg, var(--gold), var(--rose-deep));
  -webkit-background-clip: text;
  background-clip: text;
  opacity: .9;
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .dream__idx { color: transparent; }
}

.dream__title {
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--ink);
}


/* ============================================================================
   17 · SECTION 15 — PROPOSAL (dark, starry, slow)
   ========================================================================= */
.proposal {
  display: grid;
  place-items: center;
  min-height: 100svh;
  padding: calc(var(--sec-y) * 1.1) var(--pad-x);
  color: var(--ink-onDark);
  background-color: var(--night);
  background-image:
    radial-gradient(100% 70% at 50% 112%, rgba(196, 87, 122, .30), transparent 62%),
    radial-gradient(80% 60% at 10% 10%, rgba(201, 182, 228, .18), transparent 62%),
    linear-gradient(180deg, #1a0a2b 0%, var(--night) 44%, #0a0413 100%);
}

.proposal::before,
.proposal::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* CSS star layer (the canvas adds motion on top) */
.proposal::before {
  background-image:
    radial-gradient(1.4px 1.4px at 12% 18%, rgba(255, 255, 255, .80), transparent 100%),
    radial-gradient(1px 1px at 34% 46%, rgba(240, 220, 174, .75), transparent 100%),
    radial-gradient(1.6px 1.6px at 58% 12%, rgba(255, 255, 255, .70), transparent 100%),
    radial-gradient(1px 1px at 76% 62%, rgba(247, 205, 216, .80), transparent 100%),
    radial-gradient(1.3px 1.3px at 90% 28%, rgba(255, 255, 255, .65), transparent 100%),
    radial-gradient(1px 1px at 22% 78%, rgba(255, 255, 255, .55), transparent 100%),
    radial-gradient(1.2px 1.2px at 66% 88%, rgba(240, 220, 174, .60), transparent 100%);
  animation: twinkle 7.5s var(--e-in-out) infinite;
}

/* vignette */
.proposal::after {
  background-image: radial-gradient(72% 60% at 50% 46%, transparent 42%, rgba(6, 2, 12, .62) 100%);
}

.proposal__stars {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  opacity: .9;
}

.proposal__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.5rem, 6vw, 2.75rem);
  width: 100%;
  max-width: 44rem;
  text-align: center;
}

.proposal__buildup {
  display: flex;
  flex-direction: column;
  gap: .55em;
  font-family: var(--ff-display);
  font-size: var(--fs-lg);
  font-style: italic;
  line-height: var(--lh-snug);
  color: var(--ink-onDark-soft);
  text-wrap: balance;
}

.proposal__line { opacity: 1; }

.js .proposal__line {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition:
    opacity var(--t-cine) var(--e-soft),
    transform var(--t-cine) var(--e-out);
}

.js .proposal__line.is-in {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.proposal__question {
  display: flex;
  flex-direction: column;
  gap: .06em;
  font-family: var(--ff-display);
  font-size: var(--fs-q);
  font-weight: 500;
  line-height: 1.14;
  letter-spacing: -.02em;
  color: var(--cream);
  text-wrap: balance;
}

.proposal__q-line {
  display: block;
  opacity: 1;
}

.proposal__q-line:nth-child(2),
.proposal__q-line:nth-child(4) {
  font-style: italic;
  color: var(--rose-soft);
}

.proposal__q-line:last-child {
  margin-top: .18em;
  color: var(--rose);
  text-shadow: 0 0 26px rgba(232, 127, 156, .65);
}

.js .proposal__q-line {
  opacity: 0;
  transform: translate3d(0, 22px, 0) scale(.97);
  transition:
    opacity var(--t-cine) var(--e-soft),
    transform var(--t-cine) var(--e-out);
}

.js .proposal__q-line.is-in {
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1);
}

/* Both the buttons and the thanks line hold their box from the first frame and
   are revealed with visibility/opacity — never display — so the question above
   them never moves. visibility:hidden also keeps the buttons untabbable and
   unclickable until the moment they are offered. */
.proposal__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(.7rem, 3vw, 1.15rem);
}

.js .proposal__actions,
.js .proposal__thanks {
  visibility: hidden;
  opacity: 0;
  transition:
    opacity var(--t-slow) var(--e-out),
    transform var(--t-slow) var(--e-out),
    visibility 0s linear var(--t-slow);
}

.js .proposal__actions { transform: translate3d(0, 14px, 0) scale(.97); }
.js .proposal__thanks  { transform: translate3d(0, 8px, 0); }

.js .proposal__actions.is-in,
.js .proposal__thanks.is-in {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition-delay: 0s;
}

/* no idle pulse while the buttons are still unseen */
.js .proposal__actions:not(.is-in) .btn-proposal.is-pulsing { animation: none; }

.btn-proposal {
  min-width: 9.5rem;
  min-height: 52px;
  padding: 1rem 2rem;
  font-size: var(--fs-base);
  font-weight: 600;
  letter-spacing: .12em;
  color: var(--night);
  background-image: linear-gradient(140deg, #ffffff 0%, var(--rose-soft) 48%, var(--gold-soft) 100%);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .5),
    0 10px 26px -10px rgba(0, 0, 0, .6),
    0 0 34px -8px rgba(247, 205, 216, .6);
}

.btn-proposal:nth-child(2) {
  color: var(--cream);
  background-image: linear-gradient(140deg, var(--rose) 0%, var(--rose-deep) 55%, #7f2f4c 100%);
}

.btn-proposal:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .6),
    0 14px 32px -10px rgba(0, 0, 0, .65),
    0 0 54px -8px rgba(247, 205, 216, .75);
}

.btn-proposal:active { transform: scale(.96); }

.btn-proposal.is-pulsing { animation: proposal-pulse 2.8s var(--e-in-out) infinite; }
.btn-proposal.is-pulsing:nth-child(2) { animation-delay: .45s; }

.proposal__thanks {
  /* one line of its own type, reserved before the text exists */
  min-height: 1.35em;
  font-family: var(--ff-hand);
  font-size: calc(var(--fs-hand) * 1.15);
  line-height: 1.35;
  color: var(--gold-soft);
  text-shadow: 0 0 22px rgba(217, 177, 102, .45);
  text-wrap: balance;
}

@keyframes proposal-pulse {
  0%, 100% { transform: scale(1); }
  46%      { transform: scale(1.045); }
  62%      { transform: scale(1.01); }
}


/* ============================================================================
   18 · SECTION 16 — ENDING
   ========================================================================= */
.ending {
  display: grid;
  place-items: center;
  min-height: 88svh;
  padding: var(--sec-y) var(--pad-x);
  color: var(--ink-onDark);
  background-color: var(--plum);
  background-image:
    radial-gradient(90% 70% at 50% 108%, rgba(232, 127, 156, .40), transparent 62%),
    radial-gradient(70% 55% at 50% 18%, rgba(217, 177, 102, .20), transparent 62%),
    linear-gradient(180deg, #0a0413 0%, #1e0b31 40%, var(--plum) 100%);
  text-align: center;
}

/* Kept out of the layout entirely so no dead space follows the proposal;
   the entrance is an animation (transitions cannot run from display:none). */
.js .ending:not(.is-live) {
  display: none;
}

.js .ending.is-live {
  animation: ending-in var(--t-cine) var(--e-soft) both;
}

@keyframes ending-in {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}

.ending__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.25rem, 5vw, 2rem);
  max-width: 40rem;
}

.ending__title {
  display: flex;
  flex-direction: column;
  gap: .04em;
  font-family: var(--ff-display);
  font-size: var(--fs-h1);
  font-weight: 500;
  line-height: var(--lh-tight);
  letter-spacing: -.02em;
  color: var(--cream);
  text-wrap: balance;
}

.ending__title > span:last-child {
  font-style: italic;
  color: var(--rose-soft);
  text-shadow: 0 0 30px rgba(232, 127, 156, .5);
}

.ending__signoff {
  display: flex;
  flex-direction: column;
  gap: .1em;
  font-family: var(--ff-hand);
  font-size: var(--fs-hand);
  line-height: 1.35;
  color: var(--ink-onDark-soft);
}

.ending__name {
  font-size: 1.5em;
  font-weight: 700;
  color: var(--gold-soft);
  text-shadow: 0 0 24px rgba(217, 177, 102, .45);
}

.ending__inner::after {
  content: "❤";
  font-size: 1.35rem;
  line-height: 1;
  color: var(--rose);
  filter: drop-shadow(0 0 14px rgba(232, 127, 156, .8));
  animation: heart-pulse 3s var(--e-in-out) infinite;
}

/* the finale settles: everything slows right down */
.ending.is-calm .ending__inner::after { animation-duration: 5.5s; }
.ending.is-calm .ending__title > span:last-child { text-shadow: 0 0 44px rgba(232, 127, 156, .65); }


/* ============================================================================
   19 · SECTION 14 — SECRET HEART · MODAL · LIGHTBOX
   ========================================================================= */
.secret-heart {
  position: fixed;
  right: max(.85rem, env(safe-area-inset-right));
  bottom: max(.85rem, env(safe-area-inset-bottom));
  z-index: var(--z-secret);
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  font-size: 1.05rem;
  line-height: 1;
  color: var(--rose-deep);
  border-radius: 50%;
  opacity: .32;
  transform: scale(.9);
  transition:
    opacity var(--t-mid) var(--e-out),
    transform var(--t-mid) var(--e-back);
}

.secret-heart::before {
  content: "";
  position: absolute;
  inset: 4px;
  z-index: -1;
  border-radius: 50%;
  background-color: rgba(255, 255, 255, .22);
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28);
}

.secret-heart.is-in {
  opacity: .45;
  transform: scale(1);
  animation: secret-pulse 4.2s var(--e-in-out) infinite;
}

.secret-heart:hover,
.secret-heart:focus-visible {
  opacity: 1;
  transform: scale(1.14);
}

@keyframes secret-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.1); }
}

/* --- modal --- */
.modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding:
    max(1rem, env(safe-area-inset-top)) var(--pad-x)
    max(1rem, env(safe-area-inset-bottom));
}

.modal__backdrop {
  position: absolute;
  inset: 0;
  background-color: rgba(18, 7, 31, .58);
  -webkit-backdrop-filter: blur(10px) saturate(.9);
  backdrop-filter: blur(10px) saturate(.9);
  cursor: pointer;
}

.modal__panel {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  width: 100%;
  max-width: 26rem;
  padding: clamp(1.5rem, 6vw, 2.25rem) clamp(1.25rem, 5vw, 2rem);
  border-radius: var(--r-2xl);
  /* opaque enough to keep AA text contrast over the dark blurred backdrop */
  background-color: rgba(253, 248, 244, .95);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, .92), rgba(247, 205, 216, .55));
  box-shadow: var(--sh-4);
  text-align: center;
  animation: modal-in var(--t-slow) var(--e-back);
}

.modal__panel::before {
  content: "❤";
  font-size: 1.5rem;
  line-height: 1;
  color: var(--rose);
  filter: drop-shadow(0 0 12px rgba(232, 127, 156, .55));
}

.modal__title {
  font-family: var(--ff-display);
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--ink);
  text-wrap: balance;
}

.modal__body {
  display: flex;
  flex-direction: column;
  gap: .5em;
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  color: var(--ink-soft);
  text-wrap: pretty;
}

.modal__line:last-child {
  font-family: var(--ff-hand);
  font-size: calc(var(--fs-hand) * .95);
  color: var(--rose-ink);
}

.modal__close { margin-top: .35rem; }

@keyframes modal-in {
  0%   { opacity: 0; transform: translate3d(0, 16px, 0) scale(.94); }
  100% { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}

/* --- lightbox --- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-lightbox);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: .25rem;
  padding:
    max(3.25rem, calc(env(safe-area-inset-top) + 3rem)) .35rem
    max(1rem, env(safe-area-inset-bottom));
}

.lightbox__backdrop {
  position: absolute;
  inset: 0;
  background-color: rgba(10, 4, 19, .88);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  cursor: zoom-out;
}

.lightbox__x,
.lightbox__nav {
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  font-family: var(--ff-body);
  line-height: 1;
  color: var(--cream);
  border: 1px solid rgba(253, 248, 244, .28);
  border-radius: 50%;
  background-color: rgba(253, 248, 244, .10);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition:
    transform var(--t-fast) var(--e-back),
    background-color var(--t-fast) var(--e-out);
}

.lightbox__x:hover,
.lightbox__nav:hover {
  transform: scale(1.08);
  background-color: rgba(253, 248, 244, .22);
}

.lightbox__x:active,
.lightbox__nav:active { transform: scale(.94); }

.lightbox__x {
  position: absolute;
  top: max(.85rem, env(safe-area-inset-top));
  right: max(.85rem, env(safe-area-inset-right));
  padding-bottom: .15rem;
  font-size: 1.7rem;
}

.lightbox__nav { font-size: 2rem; }

.lightbox__nav--prev {
  grid-column: 1;
  padding-bottom: .18rem;
}

.lightbox__nav--next {
  grid-column: 3;
  padding-bottom: .18rem;
}

.lightbox__figure {
  position: relative;
  z-index: 1;
  grid-column: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .85rem;
  min-width: 0;
  max-height: 100%;
}

.lightbox__img {
  max-width: 100%;
  max-height: 74svh;
  border-radius: var(--r-md);
  background-color: rgba(253, 248, 244, .06);
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, .8);
  animation: modal-in var(--t-slow) var(--e-out);
}

.lightbox__caption {
  max-width: 34rem;
  font-family: var(--ff-display);
  font-size: var(--fs-sm);
  font-style: italic;
  line-height: var(--lh-snug);
  color: var(--ink-onDark-soft);
  text-align: center;
  text-wrap: pretty;
}


/* ============================================================================
   20 · FX CANVAS · CURSOR GLOW · SCROLL PROGRESS
   ========================================================================= */
.fx-canvas {
  position: fixed;
  inset: 0;
  z-index: var(--z-fx);
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.cursor-glow {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-cursor);
  width: 22rem;
  height: 22rem;
  margin: -11rem 0 0 -11rem;
  border-radius: 50%;
  background-image: radial-gradient(circle,
    rgba(232, 127, 156, .22), rgba(201, 182, 228, .12) 42%, transparent 68%);
  opacity: 0;
  transition: opacity var(--t-slow) var(--e-out);
  will-change: transform;
  pointer-events: none;
}

.cursor-glow.is-active { opacity: 1; }

.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-progress);
  height: 3px;
  background-color: rgba(42, 17, 64, .07);
  pointer-events: none;
}

.scroll-progress > span {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 0 var(--r-pill) var(--r-pill) 0;
  background-image: linear-gradient(90deg, var(--rose), var(--rose-deep) 46%, var(--gold));
  box-shadow: 0 0 12px -2px rgba(232, 127, 156, .8);
  transform: scaleX(0);
  transform-origin: 0 50%;
}


/* ============================================================================
   21 · RESPONSIVE
   ========================================================================= */

/* --- ≥480px --- */
@media (min-width: 480px) {
  .moment { font-size: var(--fs-base); }
}

/* --- ≥640px: tablets --- */
@media (min-width: 640px) {
  .reasons { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .future  { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .lightbox {
    gap: .75rem;
    padding-inline: .75rem;
  }
}

/* --- ≥768px: alternating timeline around a centred rail --- */
@media (min-width: 768px) {
  .timeline { padding-left: 0; }

  .timeline::before {
    left: 50%;
    transform: translateX(-50%);
  }

  .tl {
    width: 50%;
    padding-inline: 2.25rem;
  }

  .tl:nth-child(odd) {
    --rv-x: -30px;
    align-self: flex-start;
    text-align: right;
  }

  .tl:nth-child(even) {
    --rv-x: 30px;
    align-self: flex-end;
    text-align: left;
  }

  .tl:nth-child(odd) .tl__dot {
    left: auto;
    right: -.35rem;
  }

  .tl:nth-child(even) .tl__dot { left: -.35rem; }

  .story-frames { gap: clamp(3rem, 8vw, 6rem); }
  .frame { max-width: 26rem; }
  .distance { max-width: 44rem; }
}

/* --- ≥1024px: desktop extras (mouse parallax, cursor glow, wider spacing) --- */
@media (min-width: 1024px) {
  :root {
    --sec-y: clamp(6rem, 9vw, 9.5rem);
    --gap: 2rem;
  }

  .cursor-glow { display: block; }

  .reasons { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .future  { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  .story-frames {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    gap: clamp(3rem, 6vw, 5.5rem) clamp(2rem, 5vw, 4rem);
  }

  .frame { max-width: none; }
  .frame--left  { grid-column: 1; }
  .frame--right { grid-column: 2; margin-top: 4.5rem; }

  .hero__inner { max-width: 52rem; }
  .paper { --rule: 2.4rem; }

  .lightbox {
    gap: 1.5rem;
    padding-inline: 1.5rem;
  }

  .lightbox__x,
  .lightbox__nav {
    width: 56px;
    height: 56px;
  }
}

@media (min-width: 1280px) {
  .wrap { padding-inline: clamp(2rem, 4vw, 3.5rem); }
}

/* --- touch: swap hover affordances for press feedback (PRD §10) --- */
@media (hover: none) {
  .frame:hover .frame__img { transform: none; }
  .frame__media:active { transform: scale(.985); }

  .card:hover { box-shadow: var(--sh-2), var(--sh-inset); }
  .card:hover .card__icon { transform: none; }

  .btn-glow:hover,
  .btn-proposal:hover { transform: none; }

  .card:active { transform: scale(.98); }
  .moment:active { transform: scale(.96); }
}

@media (hover: hover) and (pointer: fine) {
  .moments .moment {
    transition: transform var(--t-fast) var(--e-back), box-shadow var(--t-mid) var(--e-out);
  }

  .moment:hover { box-shadow: var(--sh-3), var(--sh-inset); }
}

/* --- coarse pointers: bigger tap targets, calmer motion (PRD §11) --- */
@media (pointer: coarse) {
  :root { --tap: 48px; }

  .btn-soft,
  .btn-glow { padding-inline: 1.8rem; }

  .btn-proposal {
    min-width: 11rem;
    min-height: 56px;
  }

  .hero__bg { animation-duration: 34s; }

  .hero__particles::before,
  .hero__particles::after {
    animation-duration: 30s;
    opacity: .55;
  }

  .secret-heart { opacity: .45; }
  .secret-heart.is-in { opacity: .5; }
}

/* --- short viewports: don't let 100svh sections crowd --- */
@media (max-height: 620px) {
  .hero {
    min-height: auto;
    padding-block: calc(var(--sec-y) * 1.1);
  }

  .scroll-indicator {
    position: static;
    transform: none;
    margin-top: 1.5rem;
  }

  .proposal,
  .ending { min-height: auto; }
}


/* ============================================================================
   22 · REDUCED MOTION  (PRD §13)
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  /* every reveal is simply present */
  .js .reveal,
  .js .reveal.is-in,
  .js .proposal__line,
  .js .proposal__q-line,
  .js .paper__line,
  .js .moment,
  .js .moment.is-in,
  .js .distance__heart {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }

  .js .story { opacity: 1; }

  .hero__bg,
  .hero__particles::before,
  .hero__particles::after,
  .hero__particles > .particle,
  .hero__particles > span,
  .hero__name,
  .hero__heart,
  .hero__heart.is-holding,
  .scroll-indicator__dot::after,
  .intro::before,
  .intro__caret,
  .distance__pin::after,
  .distance__heart.is-pop,
  #distance-spark,
  .tl__dot::after,
  .btn-glow::before,
  .btn-glow::after,
  .btn-proposal::after,
  .btn-proposal.is-pulsing,
  .moment,
  .candle__flame,
  .candle__wick::after,
  .frame__media[data-missing="1"]::before,
  .secret-heart.is-in,
  .modal__panel,
  .lightbox__img,
  .proposal::before,
  .ending__inner::after,
  .ending.is-calm .ending__inner::after { animation: none !important; }

  /* keep the arc drawn — GSAP will not animate it */
  .js #distance-path {
    stroke-dasharray: none;
    stroke-dashoffset: 0;
  }

  /* candles still read as lit / blown, just without flicker */
  .cake[data-lit="true"] .candle__flame {
    opacity: 1;
    transform: translate(-50%, 0) scale(1);
  }

  .cake[data-blown="true"] .candle__flame { opacity: 0; }

  .hero__heart,
  .secret-heart,
  .frame__img,
  .card,
  .dream,
  .btn-glow,
  .btn-soft,
  .btn-proposal { transform: none !important; }

  .dream::after { transform: scaleX(1); }
}


/* ============================================================================
   23 · PRINT  (a keepsake, without the theatre)
   ========================================================================= */
@media print {
  .intro,
  .intro__stars,
  .fx-canvas,
  .cursor-glow,
  .scroll-progress,
  .secret-heart,
  .modal,
  .lightbox,
  .hero__bg,
  .hero__particles,
  .hero__heart,
  .scroll-indicator,
  .proposal__stars { display: none !important; }

  html,
  body {
    background: #ffffff !important;
    color: #000000 !important;
  }

  .js .story,
  .js .ending {
    opacity: 1 !important;
    visibility: visible !important;
    pointer-events: auto !important;
  }

  .js .reveal,
  .js .proposal__line,
  .js .proposal__q-line,
  .js .distance__heart {
    opacity: 1 !important;
    transform: none !important;
  }

  .section--pad { padding-block: 1.5rem; }

  .hero,
  .proposal,
  .ending { min-height: auto; }

  .proposal,
  .ending {
    color: #000000 !important;
    background: #ffffff !important;
  }

  .proposal__question,
  .ending__title { color: #000000 !important; }

  .proposal__buildup,
  .proposal__q-line:last-child,
  .proposal__thanks,
  .ending__title > span:last-child,
  .ending__signoff,
  .ending__name,
  .lightbox__caption {
    color: #333333 !important;
    text-shadow: none !important;
  }

  .paper,
  .card,
  .dream,
  .glass,
  .moment {
    border: 1px solid #cccccc !important;
    background: #ffffff !important;
    box-shadow: none !important;
  }

  .frame,
  .card,
  .dream,
  .tl,
  .paper { break-inside: avoid; }
}

/* ============================================================================
   24 · NO-JAVASCRIPT FALLBACK
   Every word of the story lives in config.js, so with scripting off the shells
   are empty. Hide them and say something warm and legible instead.
   ========================================================================= */
html:not(.js) .story,
html:not(.js) .secret-heart,
html:not(.js) .fx-canvas,
html:not(.js) .cursor-glow,
html:not(.js) .scroll-progress { display: none; }

.nojs {
  display: grid;
  place-content: center;
  gap: 1.25rem;
  min-height: 100svh;
  padding: var(--pad-x);
  text-align: center;
  background:
    radial-gradient(80% 60% at 50% 0%, var(--rose-soft), transparent 70%),
    var(--cream);
}

.nojs__title {
  font-family: var(--ff-display);
  font-size: clamp(1.9rem, 8vw, 3rem);
  line-height: 1.15;
  color: var(--plum);
}

.nojs__body {
  max-width: 34ch;
  margin-inline: auto;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--ink-soft);
}

.nojs__sign {
  font-family: var(--ff-hand);
  font-size: 1.5rem;
  color: var(--rose-deep);
}
