/* =====================================================================
   Rakhi & Aravind — animated parallax wedding invitation
   Palette: blush · ivory · rose · antique gold
   ===================================================================== */
:root {
  --cream:   #fbf5ef;
  --blush:   #f6e3e7;
  --blush-2: #f1d2da;
  --rose:    #d98ba0;
  --rose-deep: #a85c72;
  --ink:     #5c3b45;
  --gold:    #c9a24b;
  --gold-lite: #e7cf95;
  --shadow: 24px 40px 80px rgba(120, 70, 85, .28);

  --stage-ar: 1023 / 1537;   /* portrait art aspect ratio */
  --ease: cubic-bezier(.22, 1, .36, 1);
}

* { box-sizing: border-box; }

/* Both are needed: overflow-x on body alone is not honoured reliably on mobile.
   hidden first as the fallback - clip needs Safari 16+ and is dropped below that. */
html { scroll-behavior: smooth; overflow-x: hidden; overflow-x: clip; }

body {
  margin: 0;
  font-family: "Jost", system-ui, sans-serif;
  color: var(--ink);
  background: var(--cream);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

/* ---------------------------------------------------------------- Loader */
#loader {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 22px;
  background: radial-gradient(120% 120% at 50% 30%, #fff 0%, var(--blush) 60%, var(--blush-2) 100%);
  transition: opacity .9s var(--ease), visibility .9s;
}
#loader.hide { opacity: 0; visibility: hidden; }
.loader-monogram {
  font-family: "Great Vibes", cursive;
  font-size: clamp(3rem, 9vw, 5.5rem);
  color: var(--rose-deep);
}
.loader-monogram span { color: var(--gold); margin: 0 .1em; }
.loader-bar {
  width: min(240px, 60vw); height: 2px; background: rgba(168, 92, 114, .2);
  border-radius: 2px; overflow: hidden;
}
.loader-bar i {
  display: block; height: 100%; width: 30%;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
  animation: load 1.1s var(--ease) infinite;
}
@keyframes load { 0% { transform: translateX(-120%);} 100% { transform: translateX(430%);} }
#loader p { font-size: .78rem; letter-spacing: .32em; text-transform: uppercase; color: var(--rose-deep); opacity: .7; }

/* ---------------------------------------------------------- Entry gate */
/* display:none until JS adds .show - if the script fails, nobody is locked out. */
.enter-gate {
  position: fixed; inset: 0; z-index: 1100;
  display: none; place-items: center;
  text-align: center; cursor: pointer;
  background: radial-gradient(125% 125% at 50% 28%, #fffdfb 0%, var(--blush) 58%, var(--blush-2) 100%);
  opacity: 0; transition: opacity .8s var(--ease);
  touch-action: none; overscroll-behavior: contain;
}
/* Stops a swipe or wheel over the gate from scrolling the hero away behind it. */
body.gated { overflow: hidden; }
.enter-gate.show { display: grid; opacity: 1; }
.enter-gate.gone { opacity: 0; pointer-events: none; }
.gate-inner {
  display: flex; flex-direction: column; align-items: center;
  padding: 24px;
  transform: translateY(14px); opacity: 0;
  transition: transform 1s var(--ease) .12s, opacity 1s var(--ease) .12s;
}
.enter-gate.show .gate-inner { transform: none; opacity: 1; }
.enter-gate.gone .gate-inner { transform: translateY(-18px); opacity: 0; transition-delay: 0s; }

.gate-mono {
  font-family: "Great Vibes", cursive; color: var(--gold);
  font-size: clamp(2.6rem, 8vw, 4.4rem); line-height: 1;
}
.gate-pre {
  margin: 18px 0 0; font-family: "Jost", sans-serif;
  font-size: clamp(.56rem, 1.2vw, .66rem);
  letter-spacing: .34em; text-transform: uppercase; color: var(--rose-deep); opacity: .75;
}
.gate-names {
  margin: 8px 0 0; font-family: "Cormorant Garamond", serif; font-weight: 500;
  font-size: clamp(1.9rem, 5.6vw, 3.2rem); color: var(--ink);
}
.gate-orn { display: flex; align-items: center; gap: 12px; margin: 16px 0 0; }
.gate-orn i { width: 44px; height: 1px; background: linear-gradient(90deg, transparent, var(--gold)); }
.gate-orn i:last-child { background: linear-gradient(270deg, transparent, var(--gold)); }
.gate-orn b { color: var(--gold); font-size: .8rem; font-weight: 400; }
.gate-date {
  margin: 14px 0 0; font-family: "Jost", sans-serif;
  font-size: clamp(.62rem, 1.4vw, .74rem);
  letter-spacing: .3em; color: var(--rose-deep);
}
.gate-btn {
  position: relative; margin-top: clamp(28px, 5vh, 44px);
  padding: 15px 40px; cursor: pointer;
  font-family: "Jost", sans-serif; font-size: .72rem;
  letter-spacing: .28em; text-transform: uppercase; color: var(--ink);
  border: 0; border-radius: 40px;
  background: linear-gradient(120deg, var(--gold-lite), var(--gold));
  box-shadow: 0 12px 26px rgba(201,162,75,.4);
  animation: gateBreathe 2.8s ease-in-out infinite;
  transition: box-shadow .4s var(--ease), filter .4s var(--ease);
}
/* Hover reads through light, not transform - the breathing owns transform. */
.gate-btn:hover { box-shadow: 0 20px 40px rgba(201,162,75,.6); filter: brightness(1.07); }
.gate-btn:focus-visible { outline: 2px solid var(--rose-deep); outline-offset: 4px; }
.gate-btn-text { position: relative; z-index: 2; }
/* Light travelling across the gold. */
.gate-btn::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  border-radius: inherit; pointer-events: none;
  background: linear-gradient(105deg, transparent 38%, rgba(255,255,255,.6) 50%, transparent 62%);
  background-size: 260% 100%;
  animation: gateSheen 3.6s var(--ease) infinite;
}
.gate-btn-halo {
  position: absolute; inset: -6px; border-radius: inherit; pointer-events: none;
  border: 1.5px solid rgba(201,162,75,.55);
  animation: gateHalo 2.8s ease-out infinite;
}
/* A second ring half a beat later, so it ripples rather than blinks. */
.gate-btn-halo::after {
  content: ''; position: absolute; inset: -1px;
  border-radius: inherit; border: 1.5px solid rgba(201,162,75,.45);
  animation: gateHalo 2.8s ease-out infinite;
  animation-delay: 1.4s;
}
@keyframes gateHalo {
  0%        { transform: scale(1); opacity: .75; }
  70%, 100% { transform: scale(1.22); opacity: 0; }
}
@keyframes gateBreathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.035); }
}
@keyframes gateSheen {
  0%, 58%  { background-position: 130% 0; }
  100%     { background-position: -40% 0; }
}
.gate-hint {
  margin: 16px 0 0; font-family: "Jost", sans-serif;
  font-size: .58rem; letter-spacing: .24em; text-transform: uppercase;
  color: var(--rose-deep); opacity: .5;
  animation: gateHint 2.8s ease-in-out infinite;
}
@keyframes gateHint {
  0%, 100% { opacity: .4; }
  50%      { opacity: .72; }
}
@media (prefers-reduced-motion: reduce) {
  .gate-btn, .gate-btn::before, .gate-btn-halo, .gate-btn-halo::after,
  .gate-hint { animation: none !important; }
  .gate-btn { transform: none !important; }
  .gate-hint { opacity: .55; }
}

/* ------------------------------------------------------------- Ambient bg */
.ambient { position: fixed; inset: 0; z-index: -2; overflow: hidden; }
.ambient-gradient {
  position: absolute; inset: -10%;
  background:
    radial-gradient(60% 55% at 22% 18%, rgba(246,227,231,.9), transparent 60%),
    radial-gradient(55% 55% at 82% 22%, rgba(241,210,218,.85), transparent 60%),
    radial-gradient(70% 60% at 50% 100%, rgba(233,207,149,.28), transparent 55%),
    linear-gradient(180deg, #fdf8f3, #f7e7ea 55%, #f3dbe1 100%);
}
.ambient-bokeh {
  position: absolute; inset: -12%;
  background-image: url("../assets/florals-back.png");
  background-size: 130% auto; background-position: center 12%;
  background-repeat: no-repeat;
  filter: blur(46px) saturate(1.05);
  opacity: .5; transform: scale(1.1);
  will-change: transform;
}
.ambient-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(120% 100% at 50% 42%, transparent 55%, rgba(120,70,85,.20) 100%);
  mix-blend-mode: multiply;
}

/* --------------------------------------------------------- Overlay: gold sparkles */
#sparkles {
  position: fixed; inset: 0; pointer-events: none; z-index: 39;
}

/* ================================================================= HERO */
.hero {
  position: relative;
  min-height: 100svh;
  overflow: hidden;              /* contains the petal field + foreground bleed */
  display: flex; flex-direction: column; align-items: center;
  padding: clamp(14px, 3vw, 30px);
}

.hero-topbar {
  width: 100%; max-width: 1200px;
  display: flex; align-items: center; justify-content: space-between;
  z-index: 30;
}
.monogram { font-family: "Great Vibes", cursive; font-size: 1.7rem; color: var(--rose-deep); }
.eyebrow {
  font-size: .72rem; letter-spacing: .42em; text-transform: uppercase;
  color: var(--gold); border: 1px solid rgba(201,162,75,.5);
  padding: 8px 16px; border-radius: 40px; backdrop-filter: blur(4px);
}

/* Stage + copy share a centered column */
.stage-wrap {
  position: relative; flex: 1;
  width: 100%; display: flex; align-items: center; justify-content: center;
  perspective: 1300px;               /* camera depth for the 3D scene */
  perspective-origin: 50% 45%;
  margin-top: clamp(6px, 2vh, 22px);
}

/* The layered parallax artwork — a real preserve-3d multiplane.
   Each plane sits at its own translateZ and is counter-scaled (--s) so
   every plane renders at the same size and registers into one painting at
   rest; the JS camera rig (parallax.js) then reveals their depth on move. */
.scene {
  position: relative;
  /* Lifted off centre so the copy crosses the couple lower down. Uses top,
     not transform - parallax.js owns the transform on this element. */
  top: clamp(-58px, -5.5vh, -26px);
  height: min(82vh, 78vw * 1537 / 1023);
  aspect-ratio: var(--stage-ar);
  transform-style: preserve-3d;
  will-change: transform;
}
.scene .layer {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  will-change: transform; backface-visibility: hidden;
  transform: translateZ(var(--z, 0px)) scale(var(--s, 1));
}
.scene .layer img {
  width: 100%; height: 100%; object-fit: contain;
  -webkit-user-drag: none; user-select: none;
}
/* Depth planes + depth-of-field: far planes soften, the couple stays sharp. */
.scene .l-tex   { --z: -200px; --s: 1.200; filter: blur(.8px); }
.scene .l-back  { --z: -110px; --s: 1.128; filter: blur(1.5px); }
.scene .glow    { --z: -60px;  --s: 1.088; }
.scene .couple  { --z: 0px;    --s: 1.040; }
.scene .sheen   { --z: 60px;   --s: 0.992; }
.scene .l-front { --z: 110px;  --s: 0.952; filter: blur(.4px); }
.scene .couple img {
  filter: drop-shadow(0 30px 42px rgba(120, 70, 85, .34));
  /* couple.png is bled to its own edges (bottom alpha 1.0), so without this
     the plate ends on a visible rectangle. Feather it into the page. */
  -webkit-mask-image:
    linear-gradient(90deg, transparent 0, #000 12%, #000 88%, transparent 100%),
    linear-gradient(180deg, #000 76%, transparent 100%);
          mask-image:
    linear-gradient(90deg, transparent 0, #000 12%, #000 88%, transparent 100%),
    linear-gradient(180deg, #000 76%, transparent 100%);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
}
/* soft radiance haloing the couple */
.scene .glow {
  background: radial-gradient(48% 44% at 50% 40%, rgba(255,255,255,.92), rgba(255,247,240,.4) 54%, transparent 72%);
  filter: blur(8px);
}
/* ambient light plane — drifts opposite the camera like light on varnish */
.scene .sheen {
  background: radial-gradient(58% 48% at 50% 32%, rgba(255,250,236,.6), rgba(255,244,224,.18) 55%, transparent 70%);
  mix-blend-mode: soft-light;
}
/* Extreme-foreground floral fragments — "filming through flowers".
   Heavily blurred, semi-transparent, framing the lower/upper corners. */
.fg-frame {
  position: absolute; pointer-events: none;
  will-change: transform;
  transform: translateZ(var(--z)) scale(var(--s));
}
.fg-frame img { width: 100%; filter: blur(11px) saturate(1.08); opacity: .5; }
.fg-l { --z: 230px; --s: .856; width: 88%; left: -44%; bottom: -24%; }
.fg-r { --z: 245px; --s: .844; width: 80%; right: -42%; top: -22%; }
.fg-l img { transform: rotate(22deg); }
.fg-r img { transform: rotate(199deg); }
/* Gold dust motes drifting inside the scene depth (populated by petals.js) */
.dust3d {
  position: absolute; top: 0; left: 0; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,244,214,.95), rgba(231,207,149,.4) 55%, transparent 72%);
  will-change: transform, opacity; pointer-events: none;
}
.scene-scrim {
  position: absolute; left: -6%; right: -6%; bottom: -4%; height: 42%;
  /* Ramps up as the plate fades, then back to nothing - a scrim that ends
     on a flat colour reads as a panel edge against the page. */
  background: linear-gradient(180deg,
    transparent 0,
    rgba(250, 235, 224, .42) 46%,
    rgba(250, 235, 224, .76) 74%,
    rgba(250, 235, 224, .58) 92%,
    rgba(250, 235, 224, 0) 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 17%, #000 83%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 17%, #000 83%, transparent 100%);
  pointer-events: none;
  transform: translateZ(120px) scale(.944);
}

/* 3D petal field — lives INSIDE the scene depth so petals interleave with
   the couple (some pass in front, some behind). Populated by petals.js. */
/* Spans well beyond the art plate so petals fall across the whole hero,
   not just the picture. .hero clips the overhang. */
.petal-field {
  position: absolute; inset: -14% -80%;
  transform-style: preserve-3d;
  pointer-events: none;
}
.petal3d {
  position: absolute; top: 0; left: 0;
  display: block; overflow: visible;
  will-change: transform, opacity;
  -webkit-user-drag: none; user-select: none;
}

/* Names + meta overlaid on the lower art */
.hero-copy {
  position: absolute; left: 50%; bottom: clamp(-2%, 1vh, 4%);
  transform: translateX(-50%);
  width: min(92vw, 640px); text-align: center; z-index: 25;
  pointer-events: none;
}
.pre {
  margin: 0; font-size: clamp(.7rem, 1.6vw, .84rem);
  letter-spacing: .42em; text-transform: uppercase; color: var(--rose-deep);
  opacity: .85;
}
.names {
  font-family: "Great Vibes", cursive; font-weight: 400;
  font-size: clamp(3.4rem, 11vw, 7rem); line-height: .9; margin: .08em 0;
  color: var(--rose-deep);
  display: flex; align-items: center; justify-content: center; gap: .18em;
  text-shadow: 0 2px 30px rgba(255,255,255,.6);
}
.names em {
  font-family: "Cormorant Garamond", serif; font-style: italic;
  font-size: .5em; color: var(--gold);
  background: linear-gradient(120deg, var(--gold-lite), var(--gold), #b98a2f);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
.tagline {
  margin: .1em 0 .5em; font-family: "Cormorant Garamond", serif;
  font-style: italic; font-size: clamp(1.1rem, 2.6vw, 1.5rem); color: var(--ink);
}
.meta {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: .55em;
  font-size: clamp(.74rem, 1.7vw, .92rem); letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink);
}
.meta .dot { color: var(--gold); }
.muhurtam {
  margin: .5em 0 .1em; font-family: "Cormorant Garamond", serif;
  font-size: clamp(1rem, 2.3vw, 1.28rem); letter-spacing: .02em; color: var(--rose-deep);
}
.muhurtam b {
  color: var(--gold); font-weight: 600; font-size: .78em;
  letter-spacing: .16em; text-transform: uppercase; margin-right: .12em;
}
.venue {
  margin: 0; font-size: clamp(.66rem, 1.5vw, .82rem);
  letter-spacing: .2em; text-transform: uppercase; color: var(--ink); opacity: .92;
}

/* Countdown — floral medallions linked by a gold thread */
.countdown {
  position: relative; z-index: 26;
  display: flex; align-items: center; justify-content: center;
  gap: clamp(2px, .8vw, 10px);
  margin: clamp(8px, 1.6vh, 20px) 0 4px;
  perspective: 900px; transform-style: preserve-3d;
}
.cd {
  position: relative;
  width: clamp(84px, 12vw, 124px); aspect-ratio: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  /* Alternating depth keeps the row from reading as a flat strip. */
  transform: translateZ(calc(var(--i, 0) * -6px));
}
.cd-ring {
  position: absolute; inset: 0; border-radius: 50%;
  background:
    radial-gradient(circle at 50% 34%, #fffdfa 0%, #fdf3ec 62%, #f9e7e0 100%);
  border: 1.5px solid rgba(201,162,75,.8);
  box-shadow:
    inset 0 3px 12px rgba(255,255,255,.95),
    inset 0 -6px 16px rgba(214,150,160,.14),
    0 16px 34px rgba(150,90,110,.18),
    0 3px 8px rgba(150,90,110,.08);
}
/* Second hairline + the four compass points of the ring. */
.cd-ring::before {
  content: ''; position: absolute; inset: 5px; border-radius: 50%;
  border: 1px solid rgba(201,162,75,.38);
}
.cd-ring::after {
  content: ''; position: absolute; inset: -5px; border-radius: 50%;
  background:
    radial-gradient(circle 3.5px at 50% 0%, var(--gold) 0 60%, transparent 62%),
    radial-gradient(circle 3.5px at 50% 100%, var(--gold) 0 60%, transparent 62%),
    radial-gradient(circle 3.5px at 0% 50%, var(--gold) 0 60%, transparent 62%),
    radial-gradient(circle 3.5px at 100% 50%, var(--gold) 0 60%, transparent 62%);
}
.cd b {
  position: relative; z-index: 2;
  font-family: "Cormorant Garamond", serif; font-weight: 600;
  font-size: clamp(1.6rem, 4.4vw, 2.5rem); line-height: 1; color: var(--rose-deep);
  font-variant-numeric: tabular-nums;
}
.cd small {
  position: relative; z-index: 2; margin-top: 7px;
  font-size: clamp(.52rem, 1.1vw, .62rem); letter-spacing: .26em;
  text-transform: uppercase; color: var(--gold);
}
/* Watercolour sprigs bracket the row rather than crowding every ring.
   Sheet crops with their bleed stripped - see scripts/10_clean_sprigs.py. */
.cd-sprig-l::after, .cd-sprig-r::after {
  content: ''; position: absolute;
  background-repeat: no-repeat; background-position: center; background-size: contain;
  pointer-events: none; z-index: 3;
}
.cd-sprig-l::after {
  left: -34%; bottom: 4%;
  width: 84%; aspect-ratio: 365/130;
  background-image: url("../assets/ui/sprig_left.png");
}
.cd-sprig-r::after {
  right: -32%; top: 2%;
  width: 96%; aspect-ratio: 250/175;
  background-image: url("../assets/ui/sprig_right.png");
}
/* Gold link with a diamond node between medallions. */
.cd-link {
  position: relative; width: clamp(14px, 2.6vw, 34px); height: 12px; flex: none;
}
.cd-link::before {
  content: ''; position: absolute; top: 50%; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(201,162,75,.85), transparent);
}
.cd-link::after {
  content: ''; position: absolute; top: 50%; left: 50%; width: 7px; height: 7px;
  transform: translate(-50%, -50%) rotate(45deg);
  background: linear-gradient(135deg, var(--gold-lite), var(--gold));
  border-radius: 1px;
}

/* Watercolour divider */
.floral-divider {
  position: relative; z-index: 26;
  width: clamp(150px, 24vw, 240px); aspect-ratio: 355/165;
  margin: clamp(0px, .4vh, 6px) auto 0;
  background: url("../assets/ui/floral_divider.png") no-repeat center/contain;
}

/* Hanging brass lamps */
.lamp {
  position: absolute; top: 0; z-index: 24; pointer-events: none;
  width: clamp(64px, 8vw, 104px);
  opacity: 0; transition: opacity 1.1s var(--ease) .25s;
}
body.ready .lamp { opacity: 1; }
/* Nested pivots so JS parallax, the arrival and each chain link never fight
   over the same transform. Every link rotates about its own joint, one beat
   behind the link above it, so the sway travels down the chain as a wave. */
.lamp-drop { display: block; transform-origin: 50% 0; }
/* -520% of one link clears the full lamp height, so it really starts offstage. */
.lamp-drop { transform: translateY(-520%) rotate(5deg); }
body.ready .lamp-drop { animation: lampDrop 3.8s linear .25s both; }
.chain {
  display: block; width: 100%; aspect-ratio: 133 / 60;
  transform-origin: 50% 0;
  animation: chainSway 6.8s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * -.42s);
}
.lamp-drop > .chain { position: relative; }
.chain .chain { position: absolute; top: 100%; left: 0; }
/* Background lives on the pseudo so each link's shadow covers only its slice. */
.chain::before {
  content: ''; position: absolute; inset: 0;
  background-image: url("../assets/ui/lamp_chain.png");
  background-repeat: no-repeat;
  background-size: 100% 300%;
  background-position: 0 calc(var(--i, 0) * 50%);
  filter: drop-shadow(0 6px 9px rgba(150,90,110,.2));
}
.lamp-body {
  position: absolute; top: 100%; left: 0;
  width: 100%; aspect-ratio: 133 / 119;
  transform-origin: 50% 0;
  animation: bodyLag 6.8s ease-in-out infinite;
  animation-delay: -1.05s;
}
.lamp-body img {
  display: block; width: 100%; height: auto;
  filter: drop-shadow(0 14px 22px rgba(150,90,110,.28))
          drop-shadow(0 4px 14px rgba(255,178,104,.22));
}
/* Warm pool of lamplight around the bowl. */
.lamp-glow {
  position: absolute; left: 48.8%; top: 30.6%;
  width: 190%; aspect-ratio: 1;
  border-radius: 50%; pointer-events: none;
  mix-blend-mode: screen;
  background: radial-gradient(circle,
    rgba(255,222,164,.62) 0%,
    rgba(255,188,112,.34) 24%,
    rgba(255,166,86,.12) 46%,
    rgba(255,160,80,0) 70%);
  animation: lampBreath 5.4s ease-in-out infinite;
}
.lamp-glow::after {
  content: ''; position: absolute; inset: 36%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,238,206,.7), rgba(255,206,140,0) 68%);
  animation: lampFlicker 3.1s ease-in-out infinite;
}
.lamp-l { left: clamp(8px, 4vw, 66px); }
.lamp-r { right: clamp(8px, 4vw, 66px); }
/* Offset every cycle so the pair never reads as a mirrored metronome. */
.lamp-r .lamp-drop  { animation-delay: .62s; }
.lamp-r .chain      { animation-delay: calc(-3.1s + var(--i, 0) * -.42s); }
.lamp-r .lamp-body  { animation-delay: -4.3s; }
.lamp-r .lamp-glow  { animation-delay: -2.7s; }
.lamp-r .lamp-glow::after { animation-delay: -1.4s; }

/* A damped pendulum: gravity on the way down, then sinusoidal easing between
   extremes at a CONSTANT period - only the amplitude decays. Per-keyframe
   timing matters here; one curve across the whole thing reads as robotic. */
@keyframes lampDrop {
  0%   { transform: translateY(-520%) rotate(5deg);
         animation-timing-function: cubic-bezier(.38, 0, .68, .48); }
  27%  { transform: translateY(0) rotate(-4.4deg);
         animation-timing-function: ease-in-out; }
  45%  { transform: translateY(0) rotate(2.8deg);
         animation-timing-function: ease-in-out; }
  64%  { transform: translateY(0) rotate(-1.7deg);
         animation-timing-function: ease-in-out; }
  82%  { transform: translateY(0) rotate(.9deg);
         animation-timing-function: ease-in-out; }
  100% { transform: none; }
}
@keyframes chainSway {
  0%, 100% { transform: rotate(-1.15deg); }
  50%      { transform: rotate(1.15deg); }
}
@keyframes bodyLag {
  0%, 100% { transform: rotate(-1.6deg); }
  50%      { transform: rotate(1.6deg); }
}
@keyframes lampBreath {
  0%, 100% { transform: translate(-50%, -50%) scale(.94); opacity: .5; }
  50%      { transform: translate(-50%, -50%) scale(1.08); opacity: .85; }
}
@keyframes lampFlicker {
  0%, 100% { opacity: .55; }
  38%      { opacity: .95; }
  62%      { opacity: .7; }
}

/* Scroll cue - pinned to the viewport; the hero is taller than the screen,
   so anything in its flow lands below the fold. */
.scroll-cue {
  position: fixed; z-index: 40;
  left: 50%; bottom: clamp(12px, 2.4vh, 26px);
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(6px, .9vh, 11px);
  text-decoration: none;
  opacity: 0;
  transition: opacity .7s var(--ease) .2s, transform .6s var(--ease);
}
body.ready .scroll-cue { opacity: 1; }
/* Out of the way the moment the page starts moving. */
body.scrolled .scroll-cue {
  opacity: 0; pointer-events: none;
  transform: translateX(-50%) translateY(16px);
  transition-delay: 0s;
}
.cue-text {
  font-family: "Jost", sans-serif; font-size: clamp(.58rem, 1.1vw, .7rem);
  letter-spacing: .38em; text-transform: uppercase;
  color: var(--rose-deep); opacity: .85;
  text-shadow: 0 1px 10px rgba(251, 245, 239, .9);
  transition: opacity .5s var(--ease), letter-spacing .5s var(--ease);
}
.cue-chevrons {
  display: flex; flex-direction: column; align-items: center;
  animation: cueBob 3s ease-in-out infinite;
}
.cue-chevrons i {
  width: clamp(19px, 2.2vw, 26px); aspect-ratio: 1;
  border-right: 3px solid var(--gold);
  border-bottom: 3px solid var(--gold);
  border-radius: 0 0 4px 0;
  transform: rotate(45deg);
  filter: drop-shadow(0 2px 6px rgba(255, 255, 255, .85)) drop-shadow(0 1px 3px rgba(201, 162, 75, .5));
  animation: cueChev 2.2s var(--ease) infinite;
}
/* Overlap so the three read as one falling arrow, not a stack. */
.cue-chevrons i + i { margin-top: clamp(-17px, -1.6vw, -13px); }
.cue-chevrons i:nth-child(2) { animation-delay: .17s; }
.cue-chevrons i:nth-child(3) { animation-delay: .34s; }
@keyframes cueChev {
  0%, 100% { opacity: .2; }
  45%      { opacity: 1; }
}
@keyframes cueBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(6px); }
}
.scroll-cue:hover .cue-text { opacity: 1; letter-spacing: .44em; }
.scroll-cue:focus-visible { outline: 2px solid var(--rose-deep); outline-offset: 6px; border-radius: 4px; }

/* Music toggle - bottom left, clear of the centred scroll cue.
   Autoplay is blocked, so this button is the only way music ever starts:
   it carries a label rather than relying on an icon being understood. */
.music-toggle {
  position: fixed; z-index: 45;
  left: clamp(14px, 2.4vw, 28px); bottom: clamp(14px, 2.4vh, 28px);
  display: inline-flex; align-items: center; gap: 10px;
  height: 44px; padding: 0 18px 0 16px;
  border-radius: 40px; cursor: pointer;
  background: linear-gradient(180deg, rgba(255,253,250,.97), rgba(253,241,234,.95));
  border: 1.5px solid rgba(201,162,75,.75);
  box-shadow: 0 10px 26px rgba(150,90,110,.24), inset 0 1px 0 rgba(255,255,255,.9);
  backdrop-filter: blur(6px);
  opacity: 0; transform: translateY(10px);
  transition: opacity .7s var(--ease) .4s, transform .7s var(--ease) .4s,
              box-shadow .4s var(--ease);
}
body.ready .music-toggle { opacity: 1; transform: none; }
.music-toggle:hover { box-shadow: 0 14px 32px rgba(150,90,110,.32); }
.music-toggle:focus-visible { outline: 2px solid var(--rose-deep); outline-offset: 3px; }
.music-label {
  font-family: "Jost", sans-serif; font-size: .6rem;
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--rose-deep); white-space: nowrap;
}
/* A halo until it has been used once, so nobody misses that there is music. */
.music-toggle.idle::after {
  content: ''; position: absolute; inset: -5px;
  border-radius: inherit; pointer-events: none;
  border: 1.5px solid rgba(201,162,75,.65);
  animation: musicPulse 2.6s ease-out infinite;
}
@keyframes musicPulse {
  0%        { transform: scale(1); opacity: .7; }
  70%, 100% { transform: scale(1.18); opacity: 0; }
}

.music-toggle .eq { display: flex; align-items: flex-end; gap: 3px; height: 16px; }
.music-toggle .eq i {
  width: 3px; border-radius: 2px; background: var(--gold);
  height: 6px;
}
/* Bars only dance while it is actually playing. */
.music-toggle.playing .eq i { animation: eqBar 1.1s ease-in-out infinite; }
.music-toggle.playing .eq i:nth-child(2) { animation-delay: .18s; }
.music-toggle.playing .eq i:nth-child(3) { animation-delay: .36s; }
.music-toggle.playing .eq i:nth-child(4) { animation-delay: .54s; }
@keyframes eqBar {
  0%, 100% { height: 5px; }
  50%      { height: 15px; }
}
@media (max-width: 640px) {
  /* The bottom edge is where Safari parks its toolbar and iOS its home
     indicator. The top-right is free here because .eyebrow is hidden. */
  .music-toggle {
    padding: 0; width: 44px; justify-content: center;
    left: auto; bottom: auto;
    right: calc(12px + env(safe-area-inset-right, 0px));
    top: calc(12px + env(safe-area-inset-top, 0px));
  }
  .music-label { display: none; }
}

/* ================================================================ STORY */
main { position: relative; z-index: 5; }

.story {
  max-width: 1080px; margin: 0 auto;
  padding: clamp(28px, 5.5vh, 70px) clamp(20px, 5vw, 40px) clamp(40px, 8vh, 90px);
  text-align: center;
}
.script-accent {
  font-family: "Great Vibes", cursive; font-size: clamp(1.8rem, 5vw, 2.8rem);
  color: var(--rose); margin: 0;
}
.story h2, .rsvp h2 {
  font-family: "Cormorant Garamond", serif; font-weight: 500;
  font-size: clamp(1.7rem, 5vw, 3rem); margin: .1em 0 .5em; color: var(--ink);
}
.lede {
  max-width: 620px; margin: 0 auto; font-size: clamp(1rem, 2.2vw, 1.14rem);
  line-height: 1.9; color: #7a5a63; font-weight: 300;
}

.cards {
  position: relative;
  margin-top: clamp(40px, 7vh, 76px);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(18px, 2.4vw, 30px);
  perspective: 1000px;
}
/* The container is only a trigger — its children carry the motion. */
.cards.reveal { opacity: 1; transform: none; transition: none; }

/* Gold thread linking the three details, drawn from the centre outwards. */
.cards::before {
  content: ''; position: absolute; left: 4%; right: 4%; top: 50%; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(201,162,75,.5) 20%,
              rgba(201,162,75,.5) 80%, transparent);
  transform: scaleX(0); transition: transform 1.7s var(--ease) .3s;
  z-index: 0;
}
.cards.in::before { transform: scaleX(1); }

.card {
  position: relative; z-index: 1; overflow: hidden; isolation: isolate;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(255,255,255,.95), rgba(255,255,255,.55) 60%, rgba(252,238,238,.5)),
    linear-gradient(180deg, rgba(255,255,255,.9), rgba(253,243,240,.72));
  backdrop-filter: blur(10px);
  border: 1px solid rgba(201,162,75,.42); border-radius: 20px;
  padding: clamp(26px, 3.4vw, 36px) clamp(20px, 3vw, 30px) clamp(68px, 9vw, 90px);
  box-shadow:
    0 22px 50px rgba(150,90,110,.16),
    0 6px 14px rgba(150,90,110,.08),
    inset 0 1px 0 rgba(255,255,255,.9);
  opacity: 0;
  transform: translateY(46px) rotateX(12deg) scale(.955);
  transform-origin: 50% 100%;
  filter: blur(6px);
  transition:
    opacity .95s var(--ease), transform 1.15s var(--ease), filter .95s var(--ease),
    box-shadow .5s var(--ease), border-color .5s var(--ease);
  transition-delay: calc(var(--i, 0) * 170ms);
}
.cards.in .card { opacity: 1; transform: none; filter: none; }
.cards.in .card:hover {
  transform: translateY(-10px);
  border-color: rgba(201,162,75,.62);
  box-shadow:
    0 34px 68px rgba(150,90,110,.24),
    0 8px 18px rgba(150,90,110,.1),
    inset 0 1px 0 rgba(255,255,255,.95);
}
/* Watercolour garland along the foot of the card. */
.card::after {
  content: ''; position: absolute; left: 50%; bottom: 14px;
  width: 74%; height: clamp(42px, 5.5vw, 58px); transform: translateX(-50%);
  background: url("../assets/ui/floral_branch_center.png") no-repeat center bottom/contain;
  pointer-events: none;
}

/* Engraved double frame with gold corner brackets. */
.card-frame {
  position: absolute; inset: 10px; border-radius: 13px;
  border: 1px solid rgba(201,162,75,.42); pointer-events: none; z-index: 2;
}
.card-frame::before {
  content: ''; position: absolute; inset: 4px; border-radius: 9px;
  border: 1px solid rgba(201,162,75,.2);
}
/* Light sweeps inside the frame on hover. */
.card-frame::after {
  content: ''; position: absolute; inset: 0; overflow: hidden; border-radius: 12px;
  background: linear-gradient(100deg, transparent 38%, rgba(255,255,255,.7) 50%, transparent 62%);
  background-size: 260% 100%; background-position: 130% 0; background-repeat: no-repeat;
  opacity: 0; transition: background-position 1.1s var(--ease), opacity .45s linear;
}
.cards.in .card:hover .card-frame::after { background-position: -30% 0; opacity: 1; }
.card-frame i {
  position: absolute; width: 15px; height: 15px;
  border: 0 solid var(--gold); opacity: .85;
}
.card-frame i:nth-child(1) { top: -1px; left: -1px; border-top-width: 2px; border-left-width: 2px; border-top-left-radius: 13px; }
.card-frame i:nth-child(2) { top: -1px; right: -1px; border-top-width: 2px; border-right-width: 2px; border-top-right-radius: 13px; }
.card-frame i:nth-child(3) { bottom: -1px; right: -1px; border-bottom-width: 2px; border-right-width: 2px; border-bottom-right-radius: 13px; }
.card-frame i:nth-child(4) { bottom: -1px; left: -1px; border-bottom-width: 2px; border-left-width: 2px; border-bottom-left-radius: 13px; }

.card-index {
  position: absolute; top: 16px; right: 22px; z-index: 3;
  font-family: "Cormorant Garamond", serif; font-size: .82rem;
  letter-spacing: .2em; color: rgba(201,162,75,.62);
}
.card-orn {
  position: relative; z-index: 3;
  display: flex; align-items: center; justify-content: center; gap: 12px; margin-bottom: 18px;
}
.orn-line { width: 30px; height: 1px; background: linear-gradient(90deg, transparent, var(--gold-lite)); }
.orn-line:last-child { background: linear-gradient(90deg, var(--gold-lite), transparent); }
.orn-medal {
  display: grid; place-items: center; width: 46px; height: 46px; border-radius: 50%;
  background: radial-gradient(circle at 50% 35%, #fffdfa, #fdf1ea);
  border: 1.5px solid rgba(201,162,75,.72);
  box-shadow: inset 0 2px 8px rgba(255,255,255,.9), 0 6px 14px rgba(150,90,110,.14);
  font-size: 1.15rem; color: var(--gold); line-height: 1;
  text-shadow: 0 0 12px rgba(201,162,75,.4);
  transition: transform .9s var(--ease), box-shadow .5s var(--ease);
}
.cards.in .card:hover .orn-medal {
  transform: rotate(180deg) scale(1.08);
  box-shadow: inset 0 2px 8px rgba(255,255,255,.95), 0 10px 22px rgba(150,90,110,.2);
}

.card h3 {
  position: relative; z-index: 3;
  font-family: "Jost", sans-serif; font-weight: 400;
  font-size: .74rem; letter-spacing: .34em; text-transform: uppercase;
  margin: 0 0 12px; color: var(--rose-deep);
}
.card-main {
  position: relative; z-index: 3;
  font-family: "Cormorant Garamond", serif; font-weight: 500;
  font-size: clamp(1.5rem, 3.2vw, 2rem); line-height: 1.22;
  margin: 0; color: var(--ink);
}
.card-rule {
  position: relative; z-index: 3;
  display: block; height: 1px; width: 0; margin: 15px auto 13px;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
  transition: width 1.1s var(--ease);
  transition-delay: calc(var(--i, 0) * 170ms + .45s);
}
.cards.in .card .card-rule { width: 60px; }
.cards.in .card:hover .card-rule { width: 100px; transition-delay: 0s; }
.card .muted { position: relative; z-index: 3; margin: 0; color: #9a7b83; font-size: .86rem; letter-spacing: .03em; }
.card-map {
  position: relative; z-index: 3;
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 14px; padding: 8px 16px; border-radius: 30px;
  font-family: "Jost", sans-serif; font-size: .62rem;
  letter-spacing: .2em; text-transform: uppercase; text-decoration: none;
  color: var(--rose-deep);
  border: 1px solid rgba(201,162,75,.5);
  background: rgba(255,255,255,.6);
  transition: background .4s var(--ease), border-color .4s var(--ease), transform .4s var(--ease);
}
.card-map svg { width: 13px; height: 13px; color: var(--gold); }
.card-map:hover {
  background: rgba(255,255,255,.92);
  border-color: rgba(201,162,75,.85);
  transform: translateY(-2px);
}
.card-map:focus-visible { outline: 2px solid var(--rose-deep); outline-offset: 3px; }

/* ====================================================== SAVE THE DATE */
.savedate {
  position: relative;
  padding: clamp(50px, 10vh, 120px) clamp(20px, 5vw, 40px) clamp(50px, 9vh, 110px);
  text-align: center;
}
.sd-head { max-width: 620px; margin: 0 auto; }
.sd-head h2 {
  font-family: "Cormorant Garamond", serif; font-weight: 500;
  font-size: clamp(1.7rem, 5vw, 3rem); margin: .1em 0 .5em; color: var(--ink);
}

.sd-compare {
  --x: 50%;
  position: relative;
  width: min(540px, 92vw); aspect-ratio: 853 / 1280;
  margin: clamp(26px, 4vh, 52px) auto 0;
  border-radius: 18px; overflow: hidden;
  border: 1px solid rgba(201,162,75,.45);
  box-shadow: 0 30px 70px rgba(150,90,110,.22), 0 8px 18px rgba(150,90,110,.1);
  cursor: ew-resize; user-select: none;
  touch-action: pan-y; /* vertical scrolling stays with the page */
}
.sd-pane { position: absolute; inset: 0; }
.sd-pane img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sd-b { clip-path: inset(0 0 0 var(--x)); }
.sd-tag {
  position: absolute; bottom: 14px; z-index: 3;
  font-family: "Jost", sans-serif; font-size: .58rem;
  letter-spacing: .26em; text-transform: uppercase; color: #fff;
  padding: 7px 14px; border-radius: 20px;
  background: rgba(92,59,69,.4); backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.25);
}
.sd-a .sd-tag { left: 14px; }
.sd-b .sd-tag { right: 14px; }

.sd-handle {
  position: absolute; top: 0; bottom: 0; left: var(--x);
  width: 46px; transform: translateX(-50%);
  display: grid; place-items: center;
  background: none; border: 0; padding: 0; cursor: ew-resize; z-index: 4;
}
.sd-handle::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: 50%;
  width: 2px; transform: translateX(-50%);
  background: linear-gradient(180deg, rgba(255,255,255,.25), var(--gold-lite) 30%, var(--gold-lite) 70%, rgba(255,255,255,.25));
  box-shadow: 0 0 14px rgba(201,162,75,.55);
}
.sd-handle i {
  position: relative; width: 46px; height: 46px; border-radius: 50%;
  background: radial-gradient(circle at 50% 35%, #fffdfa, #fdf1ea);
  border: 1.5px solid rgba(201,162,75,.8);
  box-shadow: 0 8px 20px rgba(150,90,110,.3), inset 0 2px 8px rgba(255,255,255,.9);
  transition: transform .5s var(--ease);
}
.sd-compare:hover .sd-handle i { transform: scale(1.08); }
.sd-handle:focus-visible i { outline: 2px solid var(--rose-deep); outline-offset: 3px; }
/* Chevrons drawn with borders so no glyph can go missing. */
.sd-handle i::before, .sd-handle i::after {
  content: ''; position: absolute; top: 50%; margin-top: -5px;
  width: 0; height: 0; border: 5px solid transparent;
}
.sd-handle i::before { left: 8px; border-right-color: var(--gold); }
.sd-handle i::after { right: 8px; border-left-color: var(--gold); }

/* Container is only a trigger; each frame runs its own stagger. */
.sd-strip.reveal { opacity: 1; transform: none; transition: none; }
.sd-strip {
  display: flex; gap: clamp(10px, 1.4vw, 18px);
  margin: clamp(28px, 5vh, 56px) 0 0;
  padding: 6px clamp(20px, 5vw, 40px) 20px;
  overflow-x: auto; scroll-snap-type: x proximity;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.sd-strip::-webkit-scrollbar { display: none; }
.sd-shot {
  flex: none; scroll-snap-align: center; margin: 0;
  height: clamp(170px, 26vh, 270px);
  border-radius: 12px; overflow: hidden;
  border: 1px solid rgba(201,162,75,.34);
  box-shadow: 0 14px 30px rgba(150,90,110,.16);
  opacity: 0; transform: translateY(26px) scale(.96);
  transition: opacity .8s var(--ease), transform .8s var(--ease), box-shadow .45s var(--ease);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.sd-strip.in .sd-shot { opacity: 1; transform: none; }
.sd-strip.in .sd-shot:hover { box-shadow: 0 24px 46px rgba(150,90,110,.28); }
.sd-shot img { display: block; height: 100%; width: auto; }

/* Save-the-date films - two vertical reels, framed like the photographs. */
.sd-films { margin-top: clamp(34px, 6vh, 72px); }
.sd-films.reveal { opacity: 1; transform: none; transition: none; }
.films-label {
  font-family: "Great Vibes", cursive; color: var(--rose);
  font-size: clamp(1.4rem, 3.4vw, 2rem); margin: 0 0 clamp(16px, 2.6vh, 28px);
}
.films-row {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(16px, 3vw, 34px);
}
.film {
  position: relative; margin: 0;
  width: min(520px, 92vw);
  border-radius: 18px; overflow: hidden;
  border: 1px solid rgba(201,162,75,.5);
  box-shadow: 0 26px 60px rgba(150,90,110,.22), 0 6px 16px rgba(150,90,110,.1);
  background: #f6e3e7;
  opacity: 0; transform: translateY(30px) scale(.97);
  transition: opacity .9s var(--ease), transform .9s var(--ease), box-shadow .5s var(--ease);
  transition-delay: calc(var(--i, 0) * 140ms);
}
.sd-films.in .film { opacity: 1; transform: none; }
.sd-films.in .film:hover { box-shadow: 0 34px 74px rgba(150,90,110,.3); }
.film video {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 9; object-fit: cover; background: #f1d2da;
}
.film figcaption {
  position: absolute; left: 14px; bottom: 14px; z-index: 3;
  font-family: "Jost", sans-serif; font-size: .58rem;
  letter-spacing: .26em; text-transform: uppercase; color: #fff;
  padding: 7px 14px; border-radius: 20px;
  background: rgba(92,59,69,.42); backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.25);
  transition: opacity .4s var(--ease);
}
.film-play {
  position: absolute; inset: 0; z-index: 4;
  display: grid; place-items: center;
  background: none; border: 0; cursor: pointer;
  transition: opacity .45s var(--ease);
}
.film-play-ring {
  position: absolute; width: 72px; height: 72px; border-radius: 50%;
  background: radial-gradient(circle at 50% 35%, rgba(255,253,250,.96), rgba(253,241,234,.9));
  border: 1.5px solid rgba(201,162,75,.85);
  box-shadow: 0 8px 24px rgba(92,59,69,.34), inset 0 2px 8px rgba(255,255,255,.9);
  transition: transform .5s var(--ease);
}
.film-play-tri {
  position: relative; width: 0; height: 0; margin-left: 5px;
  border-left: 17px solid var(--rose-deep);
  border-top: 11px solid transparent;
  border-bottom: 11px solid transparent;
}
.film-play:hover .film-play-ring { transform: scale(1.09); }
/* Once it is playing the poster furniture gets out of the way. */
.film.playing .film-play,
.film.playing figcaption { opacity: 0; pointer-events: none; }

/* ================================================================ ALBUM */
.album {
  position: relative;
  max-width: 1240px; margin: 0 auto;
  padding: clamp(30px, 6vh, 70px) clamp(16px, 4vw, 40px) clamp(50px, 9vh, 100px);
  text-align: center;
  /* The reveal bloom (inset -12%, scale 1.25) and the cards' --fx fly-in both
     spill sideways; clip (not hidden) so they never widen the document and
     overflow-y stays visible. hidden is the pre-Safari-16 fallback. */
  overflow-x: hidden;
  overflow-x: clip;
}
.album h2 { font-family: "Cormorant Garamond", serif; font-weight: 500;
  font-size: clamp(1.7rem, 5vw, 3rem); margin: .1em 0 .5em; color: var(--ink); }

/* --- Tabs --- */
.album-tabs {
  position: relative; display: inline-flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(4px, 1.4vw, 14px);
  margin: clamp(18px, 3vh, 34px) 0 clamp(24px, 4vh, 44px);
  padding: 6px; border-radius: 40px;
  background: rgba(255,255,255,.55); backdrop-filter: blur(8px);
  border: 1px solid rgba(201,162,75,.3);
  box-shadow: 0 12px 30px rgba(150,90,110,.12);
}
.album-tabs .tab {
  position: relative; z-index: 2; cursor: pointer;
  font-family: "Jost", sans-serif; font-size: clamp(.66rem, 1.6vw, .78rem);
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--ink); background: none; border: 0;
  padding: 12px clamp(12px, 2.6vw, 26px); border-radius: 30px;
  transition: color .45s var(--ease);
}
.album-tabs .tab.is-active { color: #fff; }
.tab-ink {
  position: absolute; z-index: 1; top: 6px; left: 6px; height: calc(100% - 12px);
  border-radius: 30px; background: linear-gradient(120deg, var(--rose), var(--rose-deep));
  box-shadow: 0 8px 20px rgba(168,92,114,.4);
  transition: transform .6s var(--ease), width .6s var(--ease);
  pointer-events: none;
}

/* --- Grid of 3D photo cards --- */
.album-grid {
  position: relative;
  display: grid; gap: clamp(10px, 1.6vw, 20px);
  /* auto-fit, not auto-fill: empty tracks collapse so a short set stays
     balanced instead of hugging the left edge. */
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  grid-auto-rows: 128px; grid-auto-flow: dense;
  perspective: 1250px; perspective-origin: 50% 45%;
}
/* Warm bloom that blossoms out of the grid centre as the photos land. */
.album-grid::before {
  content: ""; position: absolute; z-index: 3; inset: -12%;
  pointer-events: none; opacity: 0;
  background: radial-gradient(45% 45% at 50% 50%, rgba(255,247,225,.85), rgba(233,207,149,.28) 45%, transparent 72%);
}
.album-grid.revealing::before { animation: gridBloom 1.9s var(--ease) both; }
@keyframes gridBloom {
  0%   { opacity: 0; transform: scale(.6); }
  28%  { opacity: .95; }
  100% { opacity: 0; transform: scale(1.25); }
}

.shot {
  position: relative; grid-row: span 2; overflow: hidden;
  margin: 0;                       /* figure carries a default 40px inline margin */
  border-radius: 16px; cursor: pointer;
  background: var(--blush-2);
  border: 1px solid rgba(201,162,75,.34);
  box-shadow: 0 16px 34px rgba(150,90,110,.16);
  transform-style: preserve-3d;
  will-change: transform, opacity, filter;
  transition: box-shadow .6s var(--ease), border-color .6s var(--ease);
  opacity: 0;                      /* held until the reveal runs */
}
.shot.tall { grid-row: span 3; }
.shot.wide { grid-column: span 2; }

/* Cinematic entrance: each frame flies in from deep space, focus racks from
   soft to sharp, and a clip-wipe unveils it as it settles with a slight
   overshoot. --d/--fx/--rx are set per card by album.js (radial bloom order). */
.album-grid.revealing .shot {
  animation: shotIn 1.35s cubic-bezier(.17, .85, .3, 1.02) both;
  animation-delay: var(--d, 0s);
}
/* Once landed the animation is dropped entirely — a filled animation would
   outrank the inline transforms the hover tilt writes. */
.album-grid.landed .shot { opacity: 1; }
@keyframes shotIn {
  0% {
    opacity: 0;
    transform: translate3d(var(--fx, 0px), var(--fy, 40px), -520px)
               rotateX(var(--rx, 12deg)) rotateY(var(--ry, 0deg)) scale(.9);
    filter: blur(18px) saturate(.45) brightness(1.45);
    clip-path: inset(42% 18% 42% 18% round 16px);
  }
  55% { opacity: 1; filter: blur(2.5px) saturate(.9) brightness(1.12); }
  100% {
    opacity: 1; transform: none; filter: none;
    clip-path: inset(0% 0% 0% 0% round 16px);
  }
}
/* Gold glint that streaks across each frame exactly as it lands. */
.album-grid.revealing .shot .glint {
  animation: glint 1.05s var(--ease) both;
  animation-delay: calc(var(--d, 0s) + .55s);
}
.glint {
  position: absolute; inset: 0; z-index: 2; pointer-events: none; opacity: 0;
  background: linear-gradient(112deg, transparent 34%, rgba(255,250,232,.9) 50%, transparent 66%);
}
@keyframes glint {
  0%   { opacity: 0; transform: translateX(-115%); }
  35%  { opacity: 1; }
  100% { opacity: 0; transform: translateX(115%); }
}

.shot img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.1s var(--ease), filter .7s var(--ease);
  transform: scale(1.02);
}
.shot:hover { box-shadow: 0 30px 60px rgba(150,90,110,.32); border-color: rgba(201,162,75,.8); }
.shot:hover img { transform: scale(1.11); filter: saturate(1.06); }
/* gold sheen sweep on hover */
.shot::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 30%, rgba(255,246,222,.55) 48%, transparent 62%);
  transform: translateX(-120%);
  transition: transform 1.1s var(--ease);
}
.shot:hover::after { transform: translateX(120%); }
/* warm vignette so the grid reads as one composition */
.shot::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, transparent 55%, rgba(92,59,69,.42));
  opacity: 0; transition: opacity .6s var(--ease);
}
.shot:hover::before { opacity: 1; }
.shot .zoom {
  position: absolute; z-index: 2; right: 12px; bottom: 12px;
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255,255,255,.9); color: var(--rose-deep); font-size: 1rem;
  opacity: 0; transform: translateY(10px) scale(.8);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
}
.shot:hover .zoom { opacity: 1; transform: none; }

/* --- Lightbox --- */
.lightbox {
  position: fixed; inset: 0; z-index: 900;
  display: grid; place-items: center;
  background: rgba(58, 30, 40, .82);
  backdrop-filter: blur(14px) saturate(1.1);
  opacity: 0; transition: opacity .5s var(--ease);
}
.lightbox.open { opacity: 1; }
/* `display: grid` would otherwise defeat the hidden attribute and let the
   invisible overlay swallow every click on the page. */
.lightbox[hidden] { display: none; }
.lb-stage { margin: 0; padding: clamp(10px, 3vw, 30px); max-width: 94vw; }
.lb-stage img {
  max-width: min(92vw, 1100px); max-height: 82vh;
  border-radius: 12px; border: 1px solid rgba(231,207,149,.5);
  box-shadow: 0 40px 90px rgba(0,0,0,.5);
  opacity: 0; transform: scale(.9) rotateY(6deg);
  transition: opacity .6s var(--ease), transform .7s var(--ease);
}
.lightbox.open .lb-stage img { opacity: 1; transform: none; }
.lb-cap {
  margin-top: 14px; text-align: center; color: var(--gold-lite);
  font-size: .72rem; letter-spacing: .3em; text-transform: uppercase;
}
.lb-close, .lb-nav {
  position: absolute; z-index: 2; cursor: pointer;
  background: rgba(255,255,255,.12); color: #fff; border: 1px solid rgba(255,255,255,.28);
  backdrop-filter: blur(6px); border-radius: 50%;
  display: grid; place-items: center;
  transition: background .4s var(--ease), transform .4s var(--ease);
}
.lb-close:hover, .lb-nav:hover { background: rgba(255,255,255,.26); transform: scale(1.1); }
.lb-close { top: 18px; right: 18px; width: 46px; height: 46px; font-size: 1.7rem; line-height: 1; }
.lb-nav { top: 50%; margin-top: -28px; width: 56px; height: 56px; font-size: 2rem; line-height: 1; }
.lb-prev { left: clamp(8px, 2vw, 28px); }
.lb-next { right: clamp(8px, 2vw, 28px); }

.quote-band {
  position: relative; overflow: hidden;
  padding: clamp(70px, 16vh, 170px) 20px; text-align: center;
}
.quote-layer {
  position: absolute; inset: -20% -5%;
  background-image: url("../assets/florals-front.png");
  background-size: 60% auto; background-repeat: no-repeat; background-position: 90% 120%;
  opacity: .35; filter: blur(1px); will-change: transform;
}
.quote-band::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(246,227,231,.0), rgba(241,210,218,.5));
}
.quote-band blockquote {
  position: relative; margin: 0 auto; max-width: 760px;
  font-family: "Cormorant Garamond", serif; font-style: italic;
  font-size: clamp(1.5rem, 4.4vw, 2.6rem); line-height: 1.5; color: var(--rose-deep);
}
.quote-band blockquote span { font-family: "Great Vibes", cursive; color: var(--gold); font-size: 1.4em; }

/* RSVP */
.rsvp {
  max-width: 720px; margin: 0 auto;
  padding: clamp(50px, 10vh, 120px) 24px clamp(60px, 12vh, 140px); text-align: center;
}
.btn {
  display: inline-block; margin-top: 22px; padding: 15px 40px;
  font-size: .8rem; letter-spacing: .28em; text-transform: uppercase; text-decoration: none;
  color: var(--ink); border-radius: 40px;
  background: linear-gradient(120deg, var(--gold-lite), var(--gold));
  box-shadow: 0 12px 26px rgba(201,162,75,.4);
  transition: transform .4s var(--ease), box-shadow .4s var(--ease), filter .4s;
}
.btn:hover { transform: translateY(-3px); box-shadow: 0 18px 34px rgba(201,162,75,.55); filter: brightness(1.05); }

/* Venue details + scannable map link */
.rsvp-details {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: clamp(24px, 5vw, 56px);
  margin-top: clamp(30px, 5vh, 54px);
}
.rsvp-where { text-align: center; }
.rsvp-label {
  font-family: "Jost", sans-serif; font-size: .64rem;
  letter-spacing: .34em; text-transform: uppercase; color: var(--gold);
  margin: 0 0 10px;
}
.rsvp-place {
  font-family: "Cormorant Garamond", serif; font-weight: 500;
  font-size: clamp(1.4rem, 3.2vw, 1.9rem); color: var(--ink); margin: 0;
}
.rsvp-addr { margin: 6px 0 0; color: #9a7b83; font-size: .9rem; letter-spacing: .03em; }

.rsvp-qr { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.rsvp-qr img {
  display: block; width: clamp(122px, 15vw, 158px); height: auto;
  padding: 14px; border-radius: 14px;
  background: #fffdfa;
  border: 1px solid rgba(201,162,75,.5);
  box-shadow: 0 16px 34px rgba(150,90,110,.16), inset 0 1px 0 rgba(255,255,255,.9);
}
.rsvp-qr figcaption {
  font-family: "Jost", sans-serif; font-size: .58rem;
  letter-spacing: .26em; text-transform: uppercase; color: var(--gold);
}
/* Kept on phones: guests screenshot it to send to whoever is driving. */
@media (max-width: 700px) {
  .rsvp-qr img { width: 150px; padding: 12px; }
}

/* Footer */
.site-footer {
  text-align: center; padding: 50px 20px 60px; color: var(--rose-deep);
  background: linear-gradient(180deg, transparent, rgba(241,210,218,.55));
}
.fmono { font-family: "Great Vibes", cursive; font-size: 2.2rem; color: var(--gold); }
.site-footer p { margin: 6px 0; letter-spacing: .12em; font-size: .9rem; }
.site-footer .tiny { font-size: .72rem; opacity: .7; letter-spacing: .2em; text-transform: uppercase; }
/* An aside, not a label - uppercase tracking would make it shout. */
.site-footer .quip {
  margin-top: 5px;
  font-style: italic; text-transform: none;
  letter-spacing: .05em; font-size: .76rem; opacity: .6;
}
/* The aside plays better lowercase and italic than in formal caps. */
.site-footer .quip {
  margin-top: 6px; font-family: "Cormorant Garamond", serif;
  font-style: italic; font-size: .86rem;
  letter-spacing: .04em; text-transform: none; opacity: .58;
}

/* --------------------------------------------------------- Reveal states */
.reveal { opacity: 0; transform: translateY(38px); transition: opacity 1s var(--ease), transform 1s var(--ease); }
.reveal.in { opacity: 1; transform: none; }

/* The cue is excluded - floatUp animates transform, which would wipe the
   translateX(-50%) that centres it. It fades in via body.ready instead. */
.pre, .names, .tagline, .meta, .countdown, .hero-topbar {
  opacity: 0; animation: floatUp 1.1s var(--ease) forwards;
}
body.ready .pre        { animation-delay: .15s; }
body.ready .names      { animation-delay: .32s; }
body.ready .tagline    { animation-delay: .5s;  }
body.ready .meta       { animation-delay: .64s; }
body.ready .countdown  { animation-delay: .8s;  }
body.ready .hero-topbar{ animation-delay: .1s;  }
body:not(.ready) .pre, body:not(.ready) .names, body:not(.ready) .tagline,
body:not(.ready) .meta, body:not(.ready) .countdown,
body:not(.ready) .hero-topbar { animation: none; }
@keyframes floatUp { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }

/* ------------------------------------------------------------ Responsive */
@media (max-width: 900px) {
  .names { font-size: clamp(3rem, 9.4vw, 5rem); }
  /* The thread only reads correctly across

/* The cue is excluded - floatUp animates transform, which would wipe the a single row. */
   translateX(-50%) that centres it. It fades in via body.ready instead. */  .cards::before { display: none; }
}
@media (max-width: 780px) {
  .lamp { display: none; }
}
@media (max-width: 640px) {
  .scene { height: min(62vh, 92vw * 1537 / 1023); }
  .eyebrow { display: none; }
  .fg-frame { display: none; }
  .album-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); grid-auto-rows: 96px; }
  .album-tabs .tab { padding: 10px 14px; letter-spacing: .14em; }
  .lb-nav { width: 44px; height: 44px; font-size: }
  .names { font-size: clamp(2.2rem, 11.5vw, 3.1rem); gap: .08em; }
  .tagline { font-size: 1.1rem; }
  .scene-scrim { height: 54%; }
  .countdown { gap: 0; }
  .cd { width: clamp(66px, 19vw, 82px); }
  .cd-link { width: 10px; }
  .cd-sprig-l::after, .cd-sprig-r::after { display: none; }
  .floral-divider { width: clamp(170px, 56vw, 230px); }
  .card { padding-bottom: clamp(66px, 19vw, 84px); }
}

/* --------------------------------------------------- Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .scene, .ambient-bokeh, .quote-layer { animation: none !important; }
  .lamp, .lamp *, .lamp *::before, .lamp *::after { animation: none !important; }
  .lamp { opacity: 1 !important; }
  .lamp-drop, .chain, .lamp-body { transform: none !important; }
  .lamp-glow { transform: translate(-50%, -50%) !important; opacity: .6; }
  .cue-rail i { animation: none !important; opacity: 1; transform: translateY(4px) rotate(45deg); }
  *, *::before, *::after { transition-duration: .001ms !important; }
  .reveal { opacity: 1; transform: none; }
  .card { opacity: 1 !important; transform: none !important; filter: none !important; }
  .sd-shot { opacity: 1 !important; transform: none !important; }
  .card-rule { width: 60px !important; }
  .cards::before { transform: scaleX(1) !important; }
  .shot { animation: none !important; opacity: 1; }
  .glint, .album-grid::before { display: none; }
  .lightbox .lb-stage img { opacity: 1; transform: none; }
}
