/* ==========================================================================
   Ever After Bloom — Anushka & Shivam
   Colours, fonts and spacing all come from the custom properties below.
   Everything after them is plain hand-written CSS, in page order.
   ========================================================================== */

:root {
  /* Watercolour palette. oklch keeps the washes even across hues. */
  --blush:     oklch(90% .045 8);
  --peach:     oklch(90% .07 55);
  --lavender:  oklch(87% .05 300);
  --cream:     oklch(97.2% .017 85);
  --ivory:     oklch(98.5% .01 90);
  --olive:     oklch(48% .055 120);
  --sage:      oklch(75% .045 135);
  --gold:      oklch(79% .11 85);
  --gold-deep: oklch(63% .11 78);
  --sandstone: oklch(79% .06 70);
  --skyblue:   oklch(90% .035 240);
  --rose:      oklch(65% .16 5);

  /* Ink */
  --primary:    oklch(42% .06 40);   /* headings and strong text */
  --on-primary: oklch(98.5% .01 90); /* text on a primary fill */
  --muted:      oklch(52% .03 60);   /* body copy */
  --foreground: oklch(32% .035 60);

  --gradient-gold: linear-gradient(100deg, var(--gold-deep) 0%, oklch(92% .09 92) 45%, var(--gold-deep) 100%);
  --shadow-plate: 0 24px 60px -28px color-mix(in oklab, var(--gold-deep) 40%, transparent);

  --font-display: "Marcellus", ui-serif, Georgia, serif;
  --font-sans:    "Karla", ui-sans-serif, system-ui, sans-serif;
  --font-script:  "Cormorant Garamond", ui-serif, Georgia, serif;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ivory);
  color: var(--foreground);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: .01em;
}
p { margin: 0; }

/* height:auto matters: every <img> here carries width/height attributes for
   layout stability, and those act as presentation hints. Without this, giving
   one a CSS width leaves the attribute height in place and stretches it. */
img { display: block; max-width: 100%; height: auto; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { text-decoration: none; color: inherit; }

/* Several things below are laid out with flex or grid, which would otherwise
   win over the browser's own [hidden] rule and leave them on screen. */
[hidden] { display: none !important; }

.page { position: relative; width: 100%; overflow-x: hidden; }

/* Lucide-style line icons. */
.icon {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon--sm { width: 15px; height: 15px; }
.icon--heart { width: 11px; height: 11px; fill: var(--rose); stroke: var(--rose); }

/* --------------------------------------------------------------------------
   Shared surfaces
   -------------------------------------------------------------------------- */

/* A card of painted paper. */
.plate {
  background: color-mix(in oklab, oklch(99% .008 90) 88%, var(--cream));
  border: 1px solid color-mix(in oklab, var(--gold) 40%, transparent);
  box-shadow: var(--shadow-plate);
}

/* The same card, but frosted so the scene shows through. */
.glass-plate {
  background: color-mix(in oklab, var(--ivory) 42%, transparent);
  backdrop-filter: blur(18px) saturate(135%);
  -webkit-backdrop-filter: blur(18px) saturate(135%);
  border: 1px solid color-mix(in oklab, var(--gold) 45%, transparent);
  box-shadow: var(--shadow-plate);
}

/* A faint mottling, so a plate reads as paper rather than a flat fill. */
.paper-grain { position: relative; }
.paper-grain::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .5;
  mix-blend-mode: multiply;
  background-image:
    radial-gradient(circle at 20% 30%, color-mix(in oklab, var(--sandstone) 12%, transparent), transparent 60%),
    radial-gradient(circle at 80% 70%, color-mix(in oklab, var(--blush) 14%, transparent), transparent 55%);
}

/* Gold lettering with a highlight that sweeps across it. */
.gold-text {
  background: var(--gradient-gold);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.shimmer { animation: shimmer-sweep 7s linear infinite; }

@keyframes shimmer-sweep {
  from { background-position: 200% 0; }
  to   { background-position: -60% 0; }
}

/* --------------------------------------------------------------------------
   Scroll reveal — elements fade up as they enter the viewport.
   reveal.js adds .is-in; an inline transition-delay staggers a group.
   -------------------------------------------------------------------------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .9s cubic-bezier(.22, 1, .36, 1), transform .9s cubic-bezier(.22, 1, .36, 1);
}
[data-reveal="short"] { transform: translateY(14px); }
[data-reveal].is-in { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   1. The envelope
   -------------------------------------------------------------------------- */

.envelope {
  position: fixed;
  inset: 0;
  z-index: 100;
  overflow: hidden;
  background: var(--ivory);
  transition: opacity 1.2s cubic-bezier(.22, 1, .36, 1);
}
.envelope.is-leaving { opacity: 0; pointer-events: none; }

.envelope__film,
.envelope__seal {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.envelope__film {
  object-fit: cover;
  opacity: 0;
  transition: opacity .5s ease-out;
}
.envelope.is-playing .envelope__film { opacity: 1; }

.envelope__seal {
  padding: 0;
  opacity: 0;
  transform: scale(1.04);
  transition: opacity 1.1s cubic-bezier(.22, 1, .36, 1), transform 1.1s cubic-bezier(.22, 1, .36, 1);
}
.envelope__seal.is-ready { opacity: 1; transform: none; }
.envelope__seal img { width: 100%; height: 100%; object-fit: cover; }

/* Once the film is running the seal fades out over it. */
.envelope.is-playing .envelope__seal {
  opacity: 0;
  transform: scale(1.02);
  pointer-events: none;
  transition-duration: .5s;
}

/* The pulse of light over the wax seal. */
.envelope__glow {
  position: absolute;
  top: 46%;
  left: 50%;
  width: 6rem;
  height: 6rem;
  margin: -3rem 0 0 -3rem;
  border-radius: 9999px;
  filter: blur(40px);
  pointer-events: none;
  background: radial-gradient(circle, color-mix(in oklab, var(--gold) 55%, transparent), transparent 70%);
  animation: seal-glow 2.8s ease-in-out infinite;
}
@keyframes seal-glow {
  0%, 100% { opacity: .35; transform: scale(.9); }
  50%      { opacity: .8;  transform: scale(1.15); }
}

.envelope__skip {
  position: absolute;
  right: 1.25rem;
  bottom: 1.5rem;
  z-index: 10;
  padding: .5rem 1rem;
  border-radius: 9999px;
  background: color-mix(in oklab, var(--ivory) 70%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-size: .6rem;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--primary);
}

/* The song toggle. Fixed bottom-right for the whole visit; sits under the
   envelope (z-index 100) and the lightbox (50) so both still cover it. */
.music-toggle {
  position: fixed;
  right: 1.25rem;
  bottom: 1.5rem;
  z-index: 40;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 9999px;
  background: color-mix(in oklab, var(--ivory) 78%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid color-mix(in oklab, var(--gold) 55%, transparent);
  box-shadow: var(--shadow-plate);
  color: var(--gold-deep);
  transition: background .2s ease, color .2s ease, transform .2s cubic-bezier(.22, 1, .36, 1);
}
.music-toggle:hover  { background: var(--ivory); transform: translateY(-2px); }
.music-toggle:active { transform: translateY(0) scale(.94); }

.music-toggle__icon,
.music-toggle__slash { position: relative; z-index: 1; }
.music-toggle__slash {
  position: absolute;
  opacity: 0;
  transition: opacity .2s ease;
}
.music-toggle.is-muted { color: color-mix(in oklab, var(--primary) 55%, transparent); }
.music-toggle.is-muted .music-toggle__slash { opacity: 1; }

/* A slow pulse ring while the song is actually playing. */
.music-toggle__ring {
  position: absolute;
  inset: -7px;
  border-radius: 9999px;
  border: 1px solid color-mix(in oklab, var(--gold) 50%, transparent);
  opacity: 0;
  animation: music-pulse 2.6s ease-out infinite;
}
.music-toggle:not(.is-muted) .music-toggle__ring { opacity: 1; }
@keyframes music-pulse {
  0%   { scale: .85; opacity: .6; }
  100% { scale: 1.3;  opacity: 0; }
}

@media (min-width: 640px) {
  .music-toggle { right: 1.75rem; bottom: 1.75rem; }
}

/* --------------------------------------------------------------------------
   2. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  width: 100%;
  height: 100svh;
  min-height: 620px;
  overflow: hidden;
}

/* The foot of the hero dissolves into the ivory the invitation opens on, so
   the palace mists away instead of stopping at a hard edge. It sits over the
   artwork and lanterns but under the words and the scroll cue. */
.hero::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  z-index: 5;
  height: 32%;
  pointer-events: none;
  background: linear-gradient(180deg,
    transparent 0%,
    color-mix(in oklab, var(--ivory) 18%, transparent) 30%,
    color-mix(in oklab, var(--ivory) 55%, transparent) 60%,
    color-mix(in oklab, var(--ivory) 88%, transparent) 85%,
    var(--ivory) 100%);
}

.hero__bg { position: absolute; inset: 0; transform: scale(1.08); }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; object-position: bottom; }

.hero__wash {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--lavender) 22%, transparent) 0%,
    transparent 34%,
    color-mix(in oklab, var(--cream) 18%, transparent) 78%,
    color-mix(in oklab, var(--ivory) 62%, transparent) 100%);
}

/* Two slow bands of light drifting across the sky. */
.haze { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.haze span {
  position: absolute;
  left: -30%;
  height: 10rem;
  width: 160%;
  border-radius: 9999px;
  filter: blur(48px);
  animation: haze-drift 52s ease-in-out infinite;
}
.haze span:nth-child(1) { top: 12%; background: color-mix(in oklab, var(--ivory) 34%, transparent); }
.haze span:nth-child(2) { top: 28%; background: color-mix(in oklab, var(--ivory) 24%, transparent); animation-duration: 74s; }

@keyframes haze-drift {
  0%, 100% { transform: translateX(-8%); }
  50%      { transform: translateX(18%); }
}

/* Birds crossing the frame. The outer element carries the long glide, the
   inner path the short bob, so the two never fight over one transform. */
.birds { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.birds svg {
  position: absolute;
  width: 1rem;
  fill: none;
  stroke: color-mix(in oklab, var(--primary) 40%, transparent);
  stroke-width: 1.1;
  stroke-linecap: round;
  animation: bird-glide 34s linear infinite, bird-bob 6s ease-in-out infinite;
}
.birds svg:nth-child(1) { top: 26%; }
.birds svg:nth-child(2) { top: 31%; animation-duration: 43s, 6s; animation-delay: 7s, 0s; }
.birds svg:nth-child(3) { top: 36%; animation-duration: 52s, 6s; animation-delay: 14s, 0s; }

@keyframes bird-glide {
  from { left: -10vw; }
  to   { left: 112vw; }
}
@keyframes bird-bob {
  0%, 100% { transform: translateY(0); }
  33%      { transform: translateY(-14px); }
  66%      { transform: translateY(6px); }
}

.hero__bloom {
  position: absolute;
  width: 13rem;
  pointer-events: none;
  animation: bloom-sway 12s ease-in-out infinite;
}
.hero__bloom--left  { top: -1.5rem; left: -4rem; opacity: .9; }
.hero__bloom--right { right: -5rem; bottom: 6rem; width: 12rem; opacity: .85; transform: scaleX(-1); }

@keyframes bloom-sway {
  0%, 100% { rotate: 0deg; }
  33%      { rotate: 1.6deg; }
  66%      { rotate: -1deg; }
}

.hero__content {
  position: relative;
  z-index: 10;
  display: flex;
  height: 100%;
  flex-direction: column;
  align-items: center;
  padding: 13svh 1.5rem 0;
  text-align: center;
}
/* A soft pool of light behind the invocation, names and date, so they stay
   legible where they cross the palace domes on wide screens. */
.hero__content::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(42% 34% at 50% 34%, color-mix(in oklab, var(--ivory) 58%, transparent) 0%, color-mix(in oklab, var(--ivory) 30%, transparent) 50%, transparent 100%);
}

/* The hero types itself in on load; each piece has its own delay. */
.hero__invocation,
.hero__kicker,
.hero__names,
.hero__rule,
.hero__blessing,
.hero__cta {
  opacity: 0;
  animation-fill-mode: forwards;
}
.hero__invocation { animation: rise-in 1.1s ease .05s forwards; }
.hero__kicker   { animation: rise-in 1.1s ease .2s forwards; }
.hero__names    { animation: name-in 1.5s cubic-bezier(.22, 1, .36, 1) .45s forwards; }
.hero__rule     { animation: rule-in 1.2s ease .9s forwards; }
.hero__blessing { animation: fade-in 1.2s ease 1.05s forwards; }
.hero__cta      { animation: rise-in 1s ease 1.3s forwards; }

@keyframes fade-in { to { opacity: 1; } }
@keyframes rise-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
@keyframes name-in {
  from { opacity: 0; transform: translateY(22px); filter: blur(8px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes rule-in {
  from { opacity: 0; transform: scaleX(.4); }
  to   { opacity: 1; transform: scaleX(1); }
}

/* "Shri Ganeshaya Namah" — the invocation that opens the invitation. */
.hero__invocation {
  /* Served from this folder: a mask image must be same-origin (or CORS-enabled,
     which media.shubhweds.in is not), or the browser refuses to draw it. */
  --invocation: url("");
  display: block;
  width: min(7rem, 34vw);
  aspect-ratio: 2172 / 724;
  margin: 0 auto .6rem;
  /* The same dark brown as the couple's names. */
  background: var(--primary);
  -webkit-mask: var(--invocation) center / contain no-repeat;
  mask: var(--invocation) center / contain no-repeat;
  filter: drop-shadow(0 1px 6px rgba(255, 255, 255, .9));
}

.hero__kicker {
  text-shadow: 0 0 6px rgba(255, 255, 255, .95), 0 0 14px rgba(255, 255, 255, .8);
  /* Tracked a little tighter on phones so the whole line fits on one row. */
  font-size: clamp(.56rem, 2.6vw, .62rem);
  letter-spacing: .26em;
  white-space: nowrap;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--primary) 70%, transparent);
}

.hero__names {
  margin-top: 1.5rem;
  font-size: 3rem;
  line-height: .95;
  color: var(--primary);
  text-shadow: 0 2px 18px rgba(255, 255, 255, .55);
}
/* Stacked: bride, ampersand, groom — each on a line of its own. */
.hero__names { display: flex; flex-direction: column; align-items: center; }
.hero__amp {
  margin: .1em 0 .05em;
  line-height: 1;
  color: var(--rose);
  text-shadow: 0 0 8px rgba(255, 255, 255, 1), 0 0 18px rgba(255, 255, 255, .9), 0 0 32px rgba(255, 255, 255, .7);
  font-family: var(--font-script);
  font-style: italic;
  font-weight: 600;
  font-size: .62em;
}

.hero__rule {
  width: 10rem;
  height: 1px;
  margin-top: 1.5rem;
  transform-origin: center;
  background: var(--gradient-gold);
}

/* The wedding date, lettered like "Save the Date": shimmering gold caps.
   A soft white halo (a drop-shadow, since the gold is clipped to the text)
   keeps it legible over the palace. */
.hero__blessing {
  margin-top: 1.25rem;
  font-size: clamp(.78rem, 3.6vw, .95rem);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  white-space: nowrap;
  filter: drop-shadow(0 0 4px rgba(255, 255, 255, 1)) drop-shadow(0 0 12px rgba(255, 255, 255, .85));
}
/* A deeper run of the same gold, so the shimmer never fades out over the
   sandstone behind it. */
.hero__blessing .gold-text {
  background-image: linear-gradient(100deg, oklch(48% .09 65) 0%, var(--gold-deep) 45%, oklch(70% .11 82) 55%, oklch(48% .09 65) 100%);
}

.hero__cta {
  margin-top: 2.25rem;
  padding: .75rem 2rem;
  border-radius: 9999px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .32em;
  text-transform: uppercase;
  transition: transform .2s ease;
}
.hero__cta:hover  { transform: scale(1.04); }
.hero__cta:active { transform: scale(.97); }

.hero__scroll {
  margin: auto 0 2rem;
  color: color-mix(in oklab, var(--primary) 50%, transparent);
  animation: nudge 2.6s ease-in-out infinite;
}
.hero__scroll .icon { width: 22px; height: 22px; }

@keyframes nudge {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(8px); }
}

@media (min-width: 640px) {
  .hero__kicker { font-size: .75rem; letter-spacing: .5em; }
  .hero__names  { font-size: 3.75rem; }
  .hero__blessing { font-size: 1.05rem; letter-spacing: .26em; }
  .hero__bloom--left  { width: 18rem; }
  .hero__bloom--right { width: 16rem; }
  .birds svg { width: 1.25rem; }
}
@media (min-width: 768px) {
  .hero__names { font-size: 4.5rem; }
  .hero__bloom--left  { width: 20rem; }
  .hero__bloom--right { width: 18rem; }
}

/* --------------------------------------------------------------------------
   Rising lanterns and falling petals. Both are built by effects.js because
   each one needs its own drift, size and timing.
   -------------------------------------------------------------------------- */

.lanterns, .petals {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

/* The wrapper climbs; the image inside sways and turns. Splitting them keeps
   three independent motions off a single transform. */
.lantern {
  position: absolute;
  animation: lantern-climb var(--dur) linear infinite;
}
.lantern img {
  width: 100%;
  filter: drop-shadow(0 0 14px color-mix(in oklab, var(--gold) 55%, transparent));
  animation: lantern-sway calc(var(--dur) / 2) ease-in-out infinite,
             lantern-turn 9s ease-in-out infinite;
}

@keyframes lantern-climb {
  from { transform: translateY(0); }
  to   { transform: translateY(calc(var(--climb) * -1vh)); }
}
@keyframes lantern-sway {
  0%, 100% { translate: 0 0; }
  33%      { translate: calc(var(--drift) * 1px) 0; }
  66%      { translate: calc(var(--drift) * -.6px) 0; }
}
@keyframes lantern-turn {
  0%, 100% { rotate: 0deg; }
  33%      { rotate: 3deg; }
  66%      { rotate: -2deg; }
}

.petal {
  position: absolute;
  top: -6%;
  animation: petal-fall var(--dur) linear infinite;
  animation-delay: var(--delay);
}
.petal span {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 60% 40% 55% 45% / 60% 55% 45% 40%;
  background: color-mix(in oklab, var(--hue) 75%, transparent);
  animation: petal-sway calc(var(--dur) / 2.4) ease-in-out infinite,
             petal-turn var(--dur) linear infinite;
  animation-delay: var(--delay);
}

@keyframes petal-fall {
  0%   { transform: translateY(0);     opacity: 0; }
  12%  { opacity: .85; }
  85%  { opacity: .85; }
  100% { transform: translateY(112vh); opacity: 0; }
}
@keyframes petal-sway {
  0%, 100% { translate: 0 0; }
  33%      { translate: calc(var(--sway) * 1px) 0; }
  66%      { translate: calc(var(--sway) * -.7px) 0; }
}
@keyframes petal-turn {
  from { rotate: 0deg; }
  to   { rotate: 380deg; }
}

/* --------------------------------------------------------------------------
   Section shells
   -------------------------------------------------------------------------- */

.band {
  position: relative;
  overflow: hidden;
  padding: 6rem 1.25rem;
}

/* Each band is washed with a different pair of watercolours. */
.band--events::before,
.band--gallery::before,
.band--rsvp::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
}
.band--events::before {
  /* Opens on the same ivory the invitation fades into, then warms. */
  background: linear-gradient(180deg, var(--ivory) 0%, color-mix(in oklab, var(--peach) 26%, var(--ivory)) 14%, var(--cream) 45%, var(--ivory) 100%);
}
.band--gallery::before {
  background: linear-gradient(180deg, var(--ivory) 0%, color-mix(in oklab, var(--blush) 22%, var(--ivory)) 60%, var(--ivory) 100%);
}
/* Warms towards peach, then settles back to the ivory the closing sky rises
   out of, so there is no seam above the countdown. */
.band--rsvp::before {
  background: linear-gradient(180deg, var(--ivory) 0%, color-mix(in oklab, var(--lavender) 24%, var(--ivory)) 40%, color-mix(in oklab, var(--peach) 28%, var(--ivory)) 75%, var(--ivory) 100%);
}

/* The chapters band shows a courtyard photograph through its wash. */
.band__art {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .25;
}
.band__wash {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg,
    var(--ivory) 0%,
    color-mix(in oklab, var(--ivory) 74%, transparent) 30%,
    color-mix(in oklab, var(--ivory) 74%, transparent) 70%,
    var(--ivory) 100%);
}

.wrap { position: relative; margin: 0 auto; max-width: 56rem; }
.wrap--wide   { max-width: 64rem; }
.wrap--narrow { max-width: 48rem; }
.wrap--slim   { max-width: 42rem; }

.head { text-align: center; }
.head__eyebrow {
  font-size: .68rem;
  letter-spacing: .42em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.head__title {
  margin-top: 1rem;
  font-size: 1.875rem;
  line-height: 1.2;
  color: var(--primary);
}
.head__note {
  max-width: 28rem;
  margin: 1rem auto 0;
  font-family: var(--font-script);
  font-style: italic;
  font-size: 1.125rem;
  color: var(--muted);
}

.flourish { display: flex; justify-content: center; margin-top: 2rem; }
.flourish img { width: 10rem; height: auto; opacity: .8; }

@media (min-width: 640px) {
  .head__title { font-size: 2.25rem; }
  .head__note  { font-size: 1.25rem; }
  .flourish img { width: 13rem; }
}
@media (min-width: 768px) {
  .head__title { font-size: 3rem; }
}

/* --------------------------------------------------------------------------
   3. The invitation — watercolour wash, Ganesha card, swaying jhumars
   -------------------------------------------------------------------------- */

.invite {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 9rem .875rem 4rem;
  background: var(--ivory);
}

.invite__bg { position: absolute; inset: 0; z-index: 0; }
.invite__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Lifts the middle so the card reads, and melts the edges into the ivory
   bands above and below. */
.invite__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(85% 70% at 50% 48%, color-mix(in oklab, var(--ivory) 55%, transparent) 0%, transparent 70%),
    linear-gradient(180deg, var(--ivory) 0%, color-mix(in oklab, var(--ivory) 60%, transparent) 6%, transparent 18%, transparent 74%, color-mix(in oklab, var(--ivory) 55%, transparent) 88%, var(--ivory) 100%);
}

.invite__jhumar {
  position: absolute;
  top: -1.5rem;
  left: 50%;
  z-index: 3;
  width: min(32rem, 97%);
  opacity: .94;
  pointer-events: none;
  transform: translateX(-50%);
  transform-origin: top center;
  animation: jhumar-sway 5s ease-in-out infinite;
}
@keyframes jhumar-sway {
  0%, 100% { transform: translateX(-50%) rotate(-1.7deg); }
  50%      { transform: translateX(-50%) rotate(1.7deg); }
}

/* Text sizes are in cqi — hundredths of the card's width — so the wording
   scales with the frame and always stays inside it. */
.invite__card {
  position: relative;
  z-index: 2;
  width: min(27rem, 94vw);
  container-type: inline-size;
  filter: drop-shadow(0 24px 50px color-mix(in oklab, var(--gold-deep) 28%, transparent));
}
/* Taller than the painted card (940 × 1672) so both families' lines fit.
   Like the event fans, only the plain cream middle (source rows 420–1400)
   stretches; the arch with Ganesha and the foot ornament keep their shape.
   Band sizes are in cqi so they follow the card's width. */
.invite__frame {
  display: block;
  width: 100%;
  aspect-ratio: 940 / 1900;
  border-style: solid;
  border-width: calc(420 / 940 * 100cqi) 0 calc(272 / 940 * 100cqi);
  border-image-source: url("");
  border-image-slice: 420 0 272 0 fill;
  border-image-repeat: stretch;
}

.invite__text {
  position: absolute;
  inset: calc(351 / 940 * 100cqi) 0 calc(184 / 940 * 100cqi);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 17%;
  text-align: center;
  text-wrap: balance;
}

.invite__overline {
  font-family: var(--font-script);
  font-style: italic;
  font-size: clamp(.75rem, 3.6cqi, 1rem);
  color: var(--rose);
  margin-bottom: .4rem;
}
.invite__kicker {
  font-family: var(--font-script);
  font-size: clamp(.75rem, 3.4cqi, .95rem);
  line-height: 1.45;
  color: var(--muted);
}

.invite__lotus {
  width: 13cqi;
  margin: 3cqi auto;
}

/* On the smallest phones the card is narrow enough that every line wraps;
   trim the ornaments and the side margins a touch so it all still fits. */
@media (max-width: 359px) {
  .invite__text  { padding: 0 13%; }
  .invite__kicker { line-height: 1.35; }
  .invite__lotus { width: 11cqi; margin: 2cqi auto; }
}

.invite__names { display: flex; flex-direction: column; align-items: center; }
.invite__person { display: flex; flex-direction: column; align-items: center; }
.invite__name {
  font-family: var(--font-script);
  font-style: italic;
  font-weight: 500;
  font-size: 10cqi;
  line-height: 1.05;
  color: var(--primary);
}
.invite__family {
  margin-top: .15rem;
  font-family: var(--font-script);
  font-style: italic;
  font-size: clamp(.72rem, 3.3cqi, .9rem);
  line-height: 1.35;
  color: var(--muted);
}
.invite__family + .invite__family { margin-top: 0; }
.invite__amp {
  margin: 1.5cqi 0;
  font-family: var(--font-script);
  font-style: italic;
  font-size: 6.5cqi;
  line-height: 1;
  color: var(--gold-deep);
}

.invite__date {
  font-family: var(--font-display);
  font-size: clamp(.75rem, 3.5cqi, .95rem);
  letter-spacing: .14em;
  color: var(--primary);
}
.invite__date sup { font-size: .6em; letter-spacing: .04em; }
.invite__time {
  margin-top: .15rem;
  font-family: var(--font-display);
  font-size: clamp(.68rem, 3cqi, .82rem);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--rose);
}
.invite__venue {
  margin-top: .2rem;
  font-family: var(--font-script);
  font-style: italic;
  font-size: clamp(.75rem, 3.5cqi, .95rem);
  color: var(--muted);
}

/* The card fades up through [data-reveal]; once it has, its lines follow. */
.invite__text > * { opacity: 0; }
.invite__card.is-in .invite__text > * { animation: invite-line .8s cubic-bezier(.22, 1, .36, 1) both; }
.invite__card.is-in .invite__overline              { animation-delay: .15s; }
.invite__card.is-in .invite__kicker                { animation-delay: .3s; }
.invite__card.is-in .invite__lotus:nth-of-type(1)  { animation-delay: .4s; }
.invite__card.is-in .invite__names                 { animation-delay: .5s; }
.invite__card.is-in .invite__lotus:nth-of-type(2)  { animation-delay: .62s; }
.invite__card.is-in .invite__meta                  { animation-delay: .76s; }
.invite__card.is-in .map-link                      { animation-delay: .9s; }
@keyframes invite-line {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

@media (min-width: 768px) {
  .invite         { padding: clamp(4rem, 10vh, 6.5rem) .875rem; }
  .invite__card   { width: 28rem; }
  .invite__jhumar { top: -4%; width: 34rem; }
}

/* A small pill that opens the venue in Google Maps. Used on the invitation
   card and the Shaadi fan. */
.map-link {
  display: inline-flex;
  align-items: center;
  gap: .35em;
  margin-top: .6rem;
  padding: .35em .9em;
  border: 1px solid color-mix(in oklab, var(--gold-deep) 55%, transparent);
  border-radius: 999px;
  font-family: var(--font-sans);
  font-size: .62rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--gold-deep);
  background: color-mix(in oklab, var(--ivory) 70%, transparent);
  transition: background .25s ease, color .25s ease;
}
.map-link:hover,
.map-link:focus-visible { background: var(--gold-deep); color: var(--ivory); }
.map-link .icon { width: 1.1em; height: 1.1em; }

/* --------------------------------------------------------------------------
   5. The events
   -------------------------------------------------------------------------- */

/* Painted ornaments hung around the fans. They sit under everything and never
   take the pointer, so they cannot swallow a tap meant for a card. */
.events__decor {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.decor {
  position: absolute;
  opacity: .4;
  filter: drop-shadow(0 10px 20px color-mix(in oklab, var(--gold-deep) 26%, transparent));
  user-select: none;
  -webkit-user-drag: none;
}

/* Anything that hangs sways from its top edge. */
/* The jhoomers' chains melt in from the top, so they seem to hang down from
   the invitation above rather than start on the section's edge. */
.decor--jhoomer {
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 40%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 40%);
}
.decor--jhoomer,
.decor--chandelier,
.decor--nazar {
  transform-origin: top center;
  animation: sway 6.5s ease-in-out infinite;
}

.decor--jhoomer     { top: -8px; width: 6.25rem; }
.decor--jhoomer-l   { left: -30px; }
.decor--jhoomer-r   { right: -30px; animation-duration: 7.2s; animation-delay: .6s; }

.decor--chandelier   { width: 5.75rem; animation-duration: 7s; }
.decor--chandelier-1 { top: 48%; left: -24px; }
.decor--chandelier-2 { top: 46%; right: -24px; animation-duration: 6.2s; animation-delay: .5s; }

.decor--nazar   { width: 3.6rem; animation-duration: 5.6s; }
.decor--nazar-1 { top: 13%; right: -14px; }
.decor--nazar-2 { top: 30%; right: -12px; animation-duration: 6s; animation-delay: .3s; }
.decor--nazar-3 { top: 88%; left: -12px; animation-duration: 5.2s; animation-delay: .7s; }

.decor--peacock { top: 34%; left: -38px; width: 6.5rem; animation: drift 8s ease-in-out infinite; }
.decor--camel   { top: 66%; left: -26px; width: 6.9rem; }
.decor--horse   { top: 78%; right: -30px; width: 6.9rem; }

@keyframes sway {
  0%, 100% { rotate: -1.6deg; }
  50%      { rotate: 1.6deg; }
}
@keyframes drift {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -10px; }
}

.events {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  margin-top: 3rem;
}

.event { display: flex; width: 100%; justify-content: center; }

/* The stage holds the perspective; the panel is what actually swings open,
   hinged on whichever side the fan's handle is drawn. */
/* Taller than the painted fan (1024 × 1535) so the details have room; the
   frame below stretches only its plain middle to make up the difference. */
.event__stage {
  position: relative;
  width: min(24.5rem, 90vw);
  aspect-ratio: 1024 / 1760;
  perspective: 1500px;
  container-type: inline-size;
}
.event--left  .event__stage { perspective-origin: left center; }
.event--right .event__stage { perspective-origin: right center; }

.event__panel {
  position: absolute;
  inset: 0;
  opacity: 0;
  backface-visibility: hidden;
  transition: transform 1.25s cubic-bezier(.2, .9, .25, 1), opacity .55s ease;
}
.event--left .event__panel {
  transform-origin: left center;
  transform: rotateY(-92deg) scale(.98);
}
.event--right .event__panel {
  transform-origin: right center;
  transform: rotateY(92deg) scale(.98);
}
.event.is-open .event__panel { transform: rotateY(0) scale(1); opacity: 1; }

/* The fan is drawn as three bands: the top (lace and crest) and the bottom
   (flowers and pearl tassels) at their true size, and between them a plain
   cream stretch, cut from source rows 460–760, that grows to fill whatever
   height the stage has. Band sizes are in cqw — the stage's width — so they
   keep the artwork's proportions at every screen size. */
.event__frame {
  position: absolute;
  inset: 0;
  border-style: solid;
  border-width: calc(460 / 1024 * 100cqw) 0 calc(775 / 1024 * 100cqw);
  border-image-slice: 460 0 775 0 fill;
  border-image-repeat: stretch;
  filter: drop-shadow(0 18px 36px color-mix(in oklab, var(--gold-deep) 30%, transparent));
}

.event--left  .event__frame { border-image-source: url("/assets/media/fan-left.webp"); }
.event--right .event__frame { border-image-source: url("/assets/media/fan-right.webp"); }

/* The writing area inside the fan's border, held the same distance from the
   painted top and bottom however tall the fan grows. */
.event__body {
  position: absolute;
  inset: calc(107 / 1024 * 100cqw) 13% calc(384 / 1024 * 100cqw);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .6s ease, transform .7s cubic-bezier(.22, 1, .36, 1);
}
.event--left  .event__body { left: 14%; right: 12%; }
.event--right .event__body { left: 12%; right: 14%; }

/* Held back until the fan has most of the way opened. */
.event.is-open .event__body {
  opacity: 1;
  transform: translateY(0);
  transition-delay: .3s;
}

.event__art {
  width: 44%;
  max-width: 9rem;
  aspect-ratio: 1;
  object-fit: contain;
  margin-top: -7%;
  filter: drop-shadow(0 8px 14px color-mix(in oklab, var(--gold-deep) 22%, transparent));
  animation: event-bob 3.8s ease-in-out infinite;
}

@keyframes event-bob {
  0%, 100% { translate: 0 0;    rotate: 0deg; }
  50%      { translate: 0 -6px; rotate: -1.6deg; }
}

.event__name {
  margin-top: .35rem;
  /* Tangerine sets small for its size, so these run well above the old
     Marcellus sizes to read one step larger on the page. */
  font-family: "Tangerine", var(--font-script);
  font-weight: 700;
  font-size: clamp(2.6rem, 10.5vw, 3.25rem);
  line-height: 1;
  color: var(--primary);
}
/* A two-word ceremony name sits a size down so it clears the fan's edges. */
.event__name.event__name--long { font-size: clamp(2.05rem, 8vw, 2.6rem); }

.event__rule {
  width: 2.875rem;
  height: 1px;
  margin: .55rem auto;
  background: linear-gradient(90deg, transparent, var(--gold-deep), transparent);
}

.event__when {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .3rem;
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.event__date { color: var(--olive); }
.event__time { color: var(--rose); letter-spacing: .18em; }
.event__ord {
  margin-left: 1px;
  font-size: .6em;
  line-height: 0;
  letter-spacing: 0;
  text-transform: lowercase;
  color: var(--gold-deep);
}

.event__venue {
  margin-top: .6rem;
  font-family: var(--font-script);
  font-style: italic;
  font-weight: 600;
  font-size: 1.25rem;
  line-height: 1.25;
  text-wrap: balance;
  color: var(--primary);
}

.event__note {
  max-width: 68%;
  text-wrap: balance;
  margin-top: .45rem;
  font-size: .9rem;
  line-height: 1.45;
  color: var(--muted);
}

@media (min-width: 640px) {
  .decor { opacity: .48; }
  .decor--jhoomer     { top: 0; width: 9.375rem; }
  .decor--jhoomer-l   { left: 10px; }
  .decor--jhoomer-r   { right: 10px; }
  .decor--chandelier  { width: 9.375rem; }
  .decor--chandelier-1 { top: 46%; left: 1%; }
  .decor--chandelier-2 { top: 44%; right: 1%; }
  .decor--nazar   { width: 5rem; }
  .decor--nazar-1 { top: 12%; right: 2%; }
  .decor--nazar-2 { top: 28%; right: 2%; }
  .decor--nazar-3 { top: 88%; left: 2%; }
  .decor--peacock { top: 30%; left: 1%; width: 11.25rem; }
  .decor--camel   { top: 64%; left: 1%; width: 10.625rem; }
  .decor--horse   { top: 76%; right: 1%; width: 10.625rem; }

  /* Wide enough for the fans to alternate down the page. */
  .events { gap: 2.5rem; }
  .event { padding: 0 5vw; }
  .event--left  { justify-content: flex-start; }
  .event--right { justify-content: flex-end; }
  .event__stage { width: min(26.25rem, 44vw); }
  .event__name  { font-size: clamp(3rem, 6.8vw, 3.65rem); }
  .event__name.event__name--long { font-size: clamp(2.45rem, 5.2vw, 3rem); }
}

/* --------------------------------------------------------------------------
   6. The album
   -------------------------------------------------------------------------- */

.album { margin-top: 3rem; text-align: center; }

/* The photo sits behind the painted frame, which is drawn over its edges. */
.album__stage {
  position: relative;
  width: min(26.875rem, 88vw);
  margin: 0 auto;
  aspect-ratio: 1086 / 1448;
  cursor: pointer;
}
.album__photo {
  position: absolute;
  top: 8.5%;
  left: 12%;
  width: 76%;
  height: 81%;
  object-fit: cover;
  /* The taller (9:16) photos crop from near the top so faces stay in frame. */
  object-position: 50% 28%;
  transition: opacity .4s ease;
}
.album__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  pointer-events: none;
  filter: drop-shadow(0 16px 34px color-mix(in oklab, var(--gold-deep) 32%, transparent));
}
/* gallery.js swaps the source behind this fade. */
.album__stage.is-fading .album__photo { opacity: 0; }

.album__arrow {
  position: absolute;
  top: 50%;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 9999px;
  transform: translateY(-50%);
  background: color-mix(in oklab, var(--ivory) 88%, transparent);
  border: 1px solid color-mix(in oklab, var(--gold) 55%, transparent);
  box-shadow: var(--shadow-plate);
  color: var(--primary);
  transition: background .2s ease, color .2s ease, transform .2s cubic-bezier(.22, 1, .36, 1);
}
.album__arrow:hover  { background: var(--ivory); color: var(--gold-deep); }
.album__arrow:active { transform: translateY(-50%) scale(.94); }
.album__arrow--prev { left: -6px; }
.album__arrow--next { right: -6px; }

.album__caption {
  margin: 1rem 0 .75rem;
  font-family: var(--font-script);
  font-style: italic;
  font-size: 1.125rem;
  color: var(--gold-deep);
}

.album__dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  margin-bottom: 1.25rem;
}
.album__dot {
  width: .5rem;
  height: .5rem;
  border-radius: 9999px;
  background: color-mix(in oklab, var(--primary) 28%, transparent);
  transition: background .25s ease, transform .25s cubic-bezier(.22, 1, .36, 1);
}
.album__dot.is-active { background: var(--gold-deep); transform: scale(1.4); }

.album__thumbs {
  display: flex;
  justify-content: center;
  gap: .625rem;
  padding: .25rem .125rem;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
}
.album__thumbs::-webkit-scrollbar { display: none; }

.thumb {
  position: relative;
  flex: 0 0 auto;
  width: clamp(3.125rem, 16vw, 4rem);
  aspect-ratio: 1086 / 1448;
  cursor: pointer;
  opacity: .62;
  scroll-snap-align: center;
  transition: opacity .3s cubic-bezier(.22, 1, .36, 1), transform .3s cubic-bezier(.22, 1, .36, 1);
}
.thumb__photo {
  position: absolute;
  top: 8.5%;
  left: 12%;
  width: 76%;
  height: 81%;
  object-fit: cover;
  object-position: 50% 28%;
}
.thumb__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  pointer-events: none;
}
.thumb:hover { opacity: .9; }
.thumb.is-active { opacity: 1; transform: translateY(-2px) scale(1.04); }

.album__couple { display: flex; justify-content: center; margin-top: 3rem; }
.album__couple img { width: 10rem; animation: float 8s ease-in-out infinite; }

/* Uses `translate` rather than `transform`, so nothing here fights a hover
   lift that also wants the transform property. */
@keyframes float {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -4px; }
}

@media (min-width: 560px) {
  .album__arrow { width: 2.75rem; height: 2.75rem; }
  .album__arrow--prev { left: -20px; }
  .album__arrow--next { right: -20px; }
}
@media (min-width: 640px) {
  .album__couple img { width: 13rem; }
}

/* The full-screen viewer. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  background: color-mix(in oklab, var(--primary) 70%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  opacity: 0;
  transition: opacity .3s ease;
}
.lightbox.is-open { opacity: 1; }

.lightbox__inner { max-width: 90vw; text-align: center; }
.lightbox__img {
  max-height: 78vh;
  width: auto;
  border-radius: 1.4rem;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, .35);
  transform: scale(.92);
  opacity: 0;
  transition: transform .5s cubic-bezier(.22, 1, .36, 1), opacity .5s cubic-bezier(.22, 1, .36, 1);
}
.lightbox.is-open .lightbox__img { transform: none; opacity: 1; }

.lightbox__caption {
  margin-top: .875rem;
  font-family: var(--font-script);
  font-style: italic;
  font-size: 1.05rem;
  color: color-mix(in oklab, var(--on-primary) 90%, transparent);
}

.lightbox__close,
.lightbox__step {
  position: absolute;
  color: color-mix(in oklab, var(--on-primary) 90%, transparent);
  opacity: .8;
  transition: opacity .2s ease;
}
.lightbox__close:hover,
.lightbox__step:hover { opacity: 1; }

.lightbox__close { top: 1.5rem; right: 1.5rem; }
.lightbox__close .icon { width: 26px; height: 26px; }

.lightbox__step { top: 50%; transform: translateY(-50%); padding: 0 1rem; }
.lightbox__step .icon { width: 32px; height: 32px; }
.lightbox__step--prev { left: .375rem; }
.lightbox__step--next { right: .375rem; }

/* --------------------------------------------------------------------------
   The pill button — the reply card below and its send-off both use it.
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .75rem 1.5rem;
  border-radius: 9999px;
  font-size: .66rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  transition: transform .2s ease;
}
.btn:hover  { transform: scale(1.03); }
.btn:active { transform: scale(.97); }
.btn--solid { background: var(--primary); color: var(--on-primary); }

/* --------------------------------------------------------------------------
   7. The reply
   -------------------------------------------------------------------------- */

.reply {
  margin-top: 2.5rem;
  padding: 1.75rem 1.5rem;
  border-radius: 1.6rem;
}

.reply__form { display: flex; flex-direction: column; gap: 1rem; }

.field { display: flex; flex-direction: column; gap: .45rem; }

.field label {
  font-size: .6rem;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.field input,
.field textarea {
  width: 100%;
  padding: .7rem .9rem;
  border: 1px solid color-mix(in oklab, var(--gold) 38%, transparent);
  border-radius: .9rem;
  background: color-mix(in oklab, var(--ivory) 70%, transparent);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: .95rem;
  transition: border-color .25s ease, box-shadow .25s ease;
}

.field textarea { resize: vertical; }
.field ::placeholder { color: color-mix(in oklab, var(--muted) 55%, transparent); }

.field input:focus-visible,
.field textarea:focus-visible {
  outline: none;
  border-color: var(--gold-deep);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--gold) 30%, transparent);
}

/* The yes/no toggle — two buttons carrying aria-pressed. */
.choice-pair { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }

.choice {
  padding: .7rem .5rem;
  border: 1px solid color-mix(in oklab, var(--gold) 38%, transparent);
  border-radius: 9999px;
  background: color-mix(in oklab, var(--ivory) 70%, transparent);
  font-size: .62rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  transition: background-color .25s ease, color .25s ease, border-color .25s ease;
}
.choice:hover { border-color: var(--gold-deep); }
.choice[aria-pressed="true"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

.reply__send { justify-content: center; margin-top: .25rem; }
.reply__send:disabled { opacity: .65; cursor: default; transform: none; }

.reply__thanks { text-align: center; padding: 1rem 0 .5rem; }
.reply__heart { width: 1.75rem; height: 1.75rem; margin: 0 auto; }

.reply__title { margin-top: .75rem; font-size: 1.75rem; color: var(--primary); }

.reply__note {
  max-width: 24rem;
  margin: .6rem auto 0;
  font-family: var(--font-script);
  font-style: italic;
  font-size: 1.1rem;
  color: var(--muted);
}

.reply__again {
  margin-top: 1.5rem;
  padding: .7rem 1.5rem;
  border: 1px solid color-mix(in oklab, var(--gold) 45%, transparent);
  border-radius: 9999px;
  font-size: .6rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--muted);
  transition: border-color .25s ease, color .25s ease;
}
.reply__again:hover { border-color: var(--gold-deep); color: var(--primary); }

/* The other ending. "Regretfully no" has no seat to confirm, so the panel
   swaps the heart for a lantern and says something else entirely. */
.reply__lamp {
  width: 2.1rem;
  height: 2.1rem;
  margin: 0 auto;
  color: var(--gold-deep);
  stroke-width: 1.3;
  filter: drop-shadow(0 0 16px color-mix(in oklab, var(--gold) 60%, transparent));
  animation: lamp-drift 6s ease-in-out infinite;
}

@keyframes lamp-drift {
  0%, 100% { transform: translateY(3px) rotate(-2.5deg); }
  50%      { transform: translateY(-4px) rotate(2.5deg); }
}

/* The guest's own name, written in the hand the rest of the card uses. */
.reply__name {
  font-family: var(--font-script);
  font-style: italic;
  font-size: 1.08em; /* Cormorant sits smaller than Marcellus at the same size. */
  color: var(--gold-deep);
}

.reply__actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .9rem;
  margin-top: 1.5rem;
}
.reply__actions .reply__again { margin-top: 0; }

/* Releases the same lantern the send-off does, carrying the guest's name. */
.reply__lantern {
  border: 1px solid color-mix(in oklab, var(--gold) 55%, transparent);
  background: color-mix(in oklab, var(--gold) 18%, transparent);
  color: var(--primary);
  transition: transform .2s ease, background-color .25s ease, border-color .25s ease;
}
.reply__lantern:hover { background: color-mix(in oklab, var(--gold) 30%, transparent); border-color: var(--gold-deep); }
.reply__lantern:disabled { opacity: .7; cursor: default; transform: none; }

@media (min-width: 640px) {
  .reply { padding: 2.25rem 2rem; }
}

/* --------------------------------------------------------------------------
   The countdown — plaques hanging on a painted garland, as in template-5
   -------------------------------------------------------------------------- */

.finale {
  position: relative;
  z-index: 1;
  padding: clamp(5rem, 12vh, 7rem) .875rem 1rem;
  text-align: center;
}

.finale__head { position: relative; z-index: 2; margin-bottom: clamp(.6rem, 2vh, 1.25rem); }
.finale__title {
  font-family: var(--font-script);
  font-weight: 500;
  font-size: clamp(2.1rem, 8vw, 3rem);
  line-height: 1.02;
  color: var(--primary);
  text-shadow: 0 2px 18px rgba(255, 255, 255, .7);
}
.finale__lead { display: block; }
.finale__forever {
  display: block;
  margin-top: .04em;
  font-family: "Tangerine", var(--font-script);
  font-weight: 700;
  font-size: 2em;
  line-height: .86;
  color: var(--gold-deep);
  text-shadow: 0 2px 22px rgba(255, 255, 255, .85), 0 0 26px color-mix(in oklab, var(--gold) 45%, transparent);
}
.finale__rule { display: block; width: min(180px, 48vw); margin: .75rem auto 0; }

.finale__frame {
  position: relative;
  z-index: 2;
  width: min(700px, 97vw);
  margin: .4rem auto 0;
  aspect-ratio: 1672 / 941;
}
/* A warm halo breathing behind the plaques. */
.finale__frame::before {
  content: "";
  position: absolute;
  top: 56%;
  left: 50%;
  z-index: 0;
  width: 84%;
  height: 46%;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse at center, rgba(216, 169, 87, .32), transparent 70%);
  filter: blur(16px);
  animation: finale-halo 4.6s ease-in-out infinite;
}
@keyframes finale-halo {
  0%, 100% { opacity: .5; }
  50%      { opacity: .92; }
}
.finale__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 20px 34px color-mix(in oklab, var(--gold-deep) 30%, transparent));
}
.finale__cells { position: absolute; inset: 0; z-index: 1; }

.cd-cell {
  position: absolute;
  top: 59%;
  width: 19%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .14em;
  transform: translate(-50%, -50%);
}
.cd-cell--1 { left: 17.9%; }
.cd-cell--2 { left: 39.6%; }
.cd-cell--3 { left: 60.4%; }
.cd-cell--4 { left: 81.9%; }

.cd-num {
  font-family: "Cinzel", var(--font-display);
  font-weight: 600;
  font-size: clamp(1.25rem, 5.8vw, 2.6rem);
  line-height: 1;
  letter-spacing: .01em;
  font-variant-numeric: tabular-nums;
  color: var(--rose);
  text-shadow: 0 1px 0 rgba(255, 255, 255, .55);
}
.cd-label {
  font-family: "Cinzel", var(--font-display);
  font-weight: 600;
  font-size: clamp(.44rem, 1.9vw, .68rem);
  line-height: 1;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--rose);
}
.cd-num.is-tick { animation: cd-tick .5s cubic-bezier(.16, 1, .3, 1); }
@keyframes cd-tick {
  0%   { transform: translateY(-34%) scale(1.16); opacity: 0; filter: blur(2px); }
  55%  { opacity: 1; filter: none; }
  100% { transform: none; opacity: 1; }
}

@media (min-width: 768px) {
  .cd-label { letter-spacing: .16em; }
}

/* --------------------------------------------------------------------------
   8. The send-off
   -------------------------------------------------------------------------- */

.farewell { position: relative; z-index: 1; overflow: hidden; padding: 1.5rem 0 3.5rem; }
/* Sits close under the countdown; the shared sky already separates them. */
.farewell .flourish { margin-top: 0; }
/* The send-off's lanterns melt into the shared sky as they rise, instead of
   vanishing on the section's top edge. */
.farewell > .lanterns,
.farewell > .wishes {
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 30%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 30%);
}

/* The countdown and the send-off sit in one wrapper that paints a single
   sunset sky behind both. It rises out of the album's ivory at the top and
   deepens towards lavender at the foot of the page. */
.closing { position: relative; overflow: hidden; }
.closing__sky {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .6;
}
.closing__wash {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    var(--ivory) 0%,
    color-mix(in oklab, var(--ivory) 40%, transparent) 14%,
    color-mix(in oklab, var(--ivory) 18%, transparent) 55%,
    color-mix(in oklab, var(--lavender) 30%, transparent) 100%);
}

/* Three slow clouds of colour, screened over the sky. */
.aurora { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.aurora span {
  position: absolute;
  height: 70%;
  width: 70%;
  border-radius: 9999px;
  filter: blur(90px);
  mix-blend-mode: screen;
  opacity: .55;
  animation: aurora-drift 30s ease-in-out infinite;
}
.aurora span:nth-child(1) { left: -10%; top: 8%;  background: color-mix(in oklab, var(--lavender) 55%, transparent); }
.aurora span:nth-child(2) { left: 16%;  top: 20%; background: color-mix(in oklab, var(--peach) 50%, transparent); animation-duration: 41s; }
.aurora span:nth-child(3) { left: 42%;  top: 32%; background: color-mix(in oklab, var(--skyblue) 48%, transparent); animation-duration: 52s; }

@keyframes aurora-drift {
  0%, 100% { transform: translate(0, 0); }
  33%      { transform: translate(40px, -26px); }
  66%      { transform: translate(-30px, 18px); }
}

.farewell__inner {
  position: relative;
  z-index: 20;
  margin: 0 auto;
  max-width: 36rem;
  padding: 0 1.5rem;
  text-align: center;
}

.farewell__lines {
  margin-top: 2rem;
  font-family: var(--font-script);
  font-style: italic;
  font-size: 1.875rem;
  line-height: 1.4;
  color: var(--primary);
}

.farewell__wish {
  margin-top: 2.5rem;
  padding: .75rem 1.75rem;
  border-radius: 9999px;
  font-size: .64rem;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--primary);
  transition: transform .2s ease;
}
.farewell__wish:hover  { transform: scale(1.04); }
.farewell__wish:active { transform: scale(.95); }

.farewell__signoff {
  margin-top: 3rem;
  font-family: var(--font-display);
  font-size: 1.125rem;
  color: var(--primary);
}
.farewell__families {
  font-family: var(--font-script);
  font-style: italic;
}
.farewell__date {
  margin-top: .75rem;
  line-height: 2;
  font-size: .6rem;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--primary) 60%, transparent);
}
.farewell__made {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  margin-top: 2.5rem;
  font-size: .6rem;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--primary) 55%, transparent);
}
.farewell__credit { margin: .8rem 0 0; font-size: .625rem; letter-spacing: .06em; color: color-mix(in oklab, var(--primary) 52%, transparent); }
.farewell__credit a { color: var(--gold-deep); font-weight: 600; text-decoration: none; }
.farewell__credit a:hover { color: var(--primary); }

/* A lantern released by the button, carrying its blessing up the sky. */
.wishes { position: absolute; inset: 0; pointer-events: none; }
.wish {
  position: absolute;
  bottom: 2.5rem;
  z-index: 10;
  display: flex;
  width: 10rem;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin-left: -5rem;
  animation: wish-rise 7s ease-out forwards;
}
.wish img {
  width: 2.5rem;
  filter: drop-shadow(0 0 18px color-mix(in oklab, var(--gold) 65%, transparent));
}
.wish span {
  margin-top: .5rem;
  font-family: var(--font-script);
  font-style: italic;
  font-size: .875rem;
  color: var(--primary);
}

@keyframes wish-rise {
  0%   { transform: translateY(0) scale(.7); opacity: 0; }
  14%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { transform: translateY(-520px) scale(1); opacity: 0; }
}

@media (min-width: 640px) {
  .farewell__lines { font-size: 2.25rem; }
}

/* --------------------------------------------------------------------------
   Respect a guest's motion preference.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .lanterns, .petals, .birds, .haze, .aurora { display: none; }

  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
