/* ============================================================
   Sai Hemanth & Mahita — Custom Wedding Website
   Intro (tap to ring the bell) · Hero (living video) · Invite
   (arch mandap · Ganesha shine · line-by-line reveal)
   Palette + calligraphy drawn from the printed blush/gold card.
   ============================================================ */

:root {
  --blush:       #f6ddd4;   /* soft peach — card field           */
  --blush-soft:  #f9e7dd;
  --cream:       #f5ead3;   /* arch interior cream               */
  --cream-soft:  #faf2e0;
  --gold:        #c49a54;   /* calligraphy + accents             */
  --gold-deep:   #a9803a;
  --gold-soft:   #e0b56a;   /* halo / shine highlights           */
  --maroon:      #9c3a37;   /* body copy                         */
  --maroon-deep: #7f2b29;
  --rose:        #c4748c;
  --rose-deep:   #a83d5b;   /* venue accent                      */
  --ink:         #5a3730;

  /* invite-only palette — richer + warmer so it reads distinctly from hero */
  --inv-gold:    #9a5f14;   /* couple names — deep antique gold  */
  --inv-brown:   #4c2f20;   /* host names — warm espresso        */
  --inv-sepia:   #5f3c28;   /* invitation body copy              */
  --inv-rose:    #a8466a;   /* "with" / daughter accents         */
  --inv-plum:    #6d2a45;   /* closing line                      */

  --font-script:  "Pinyon Script", "Great Vibes", cursive;
  --font-hero:    "Tangerine", "Pinyon Script", cursive;   /* hero couple names */
  --font-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --font-caps:    "Cinzel", "Marcellus", Georgia, serif;
  --font-label:   "Marcellus", "Cormorant Garamond", Georgia, serif;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* ============================================================
   MONOGRAM SHINE  —  the light sweep across the H&M mark
   Same technique as .ganesha-shine: the gradient is masked by the
   logo art itself, so the highlight is clipped to the gold
   letterforms and never spills into the transparent canvas around
   them. Used by both marks (the bloom hand-off and the footer);
   each sets its own animation timing.
   ============================================================ */
.logo-shine {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  /* keep the ?v= in step with the <img src> in index.html — the mask and the
     art it lights must be the same file revision */
  -webkit-mask: url(assets/logo/logo.webp?v=2) center / contain no-repeat;
          mask: url(assets/logo/logo.webp?v=2) center / contain no-repeat;
  background: linear-gradient(115deg,
    transparent 34%,
    rgba(255, 246, 214, 0.55) 45%,
    rgba(255, 255, 255, 0.98) 50%,
    rgba(255, 246, 214, 0.55) 55%,
    transparent 66%);
  background-size: 260% 100%;
  background-repeat: no-repeat;
  background-position: 175% 0;
  opacity: 0;
}
@keyframes logoShine {
  0%        { background-position: 175% 0; opacity: 0; }
  14%       { opacity: 1; }
  52%       { opacity: 1; }
  70%, 100% { background-position: -85% 0; opacity: 0; }
}

/* ============================================================
   THE AMPERSAND  —  one flourish for the whole page
   Every "&" on the site is the hero's: Tangerine (the couple-name
   face), regular weight, deep gold. This block owns the FAMILY,
   WEIGHT and COLOUR; the per-section rules further down may only
   set SIZE and position, because each one sits in type of a
   different scale. Adding a new "&" anywhere = add it here.
   NOTE: Tangerine sits far smaller on its em than Pinyon or
   Cormorant, so every size below is scaled up to compensate.
   ============================================================ */
.couple-name .cn-amp,
.invite-amp,
.events-title .events-amp,
.ev-name i,
.blessings-amp,
.rsvp-amp {
  font-family: var(--font-hero);
  font-style: normal;
  font-weight: 400;
  color: var(--gold-deep);
  letter-spacing: 0;
}

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  background: var(--blush);
  color: var(--ink);
  font-family: var(--font-display);
  overscroll-behavior-x: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img, video { display: block; }


/* ============================================================
   INTRO  —  tap to ring the bell
   ============================================================ */
.intro-screen {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  overflow: hidden;
  background: #241016;
  cursor: pointer;
  opacity: 1;
  transform: scale(1);
  transition: opacity 1300ms ease, filter 1300ms ease, transform 1700ms ease;
}
.intro-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #241016;
}
/* very light veil — just a whisper of shade so the prompt reads; the text
   itself carries a soft shadow for legibility over the bright rangoli */
.intro-veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(36,16,22,0.08) 0%, transparent 26%, transparent 66%, rgba(36,16,22,0.22) 100%);
}
.intro-screen.is-fading {
  opacity: 0;
  filter: blur(16px);
  transform: scale(1.04);
  pointer-events: none;
}

/* soft, localized shade behind the prompt only — lifts the text while the
   overall scene stays bright (no heavy full-width gradient) */
/* seated in the clear space below the bell and above the muggu (rangoli) */
.intro-prompt {
  position: absolute;
  left: 50%;
  bottom: 37dvh;
  z-index: 2;
  display: grid;
  justify-items: center;
  text-align: center;
  transform: translateX(-50%);
  animation: introPromptIn 1200ms var(--ease-out) both 200ms;
}
@keyframes introPromptIn {
  from { opacity: 0; transform: translateX(-50%) translateY(18px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}
/* the tap makes the prompt vanish at once (overrides the entrance animation) */
.intro-prompt.is-hidden {
  animation: none;
  opacity: 0;
  transform: translateX(-50%) translateY(-8px);
  transition: opacity 400ms ease, transform 400ms ease;
  pointer-events: none;
}

.intro-line {
  font-family: var(--font-caps);
  font-size: clamp(1.15rem, 5.4vw, 1.5rem);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-indent: 0.14em;
  color: var(--maroon-deep);
  text-shadow: 0 1px 1px rgba(253,246,234,0.9), 0 2px 12px rgba(253,246,234,0.85), 0 0 26px rgba(253,246,234,0.7);
}


/* ── ivory / blush bloom hand-off to the hero ── */
.ivory-dissolve {
  position: fixed;
  inset: 0;
  z-index: 49;
  display: grid;
  place-items: center;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(circle at 50% 46%, #fdf6ea 0%, #f8ecda 38%, #f4ddd0 70%, #efd2c4 100%);
}
.ivory-dissolve::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: radial-gradient(circle at 50% 42%, rgba(196,154,84,0.22), transparent 58%);
  mix-blend-mode: screen;
}

/* ── the H&M monogram riding the bloom out into the hero ──
   The mark swells to full, holds, then scales past the viewer and clears —
   so the invitation opens THROUGH it rather than cutting to the hero.
   Sits above the ::after gold wash (which is mix-blend-mode: screen and
   would otherwise wash the gold letterforms out).

   TIMING (one clock — keep all four in step):
     · markBloom + ivoryDissolve both run 3800ms
     · the mark is fully legible from 16% to 64% of that = 610ms–2430ms,
       a ~1.8s hold, so the monogram reads as a moment rather than a flash
     · .logo-shine sweeps inside that window (see below)
     · script.js BLOOM_MS must equal 3800 — it is what tears the overlay down
   Lengthening the bloom means the hero would otherwise stagger its names in
   behind an opaque wash, so script.js also holds `.is-animated` back by
   HERO_STAGGER_DELAY_MS; the two numbers are a pair. */
/* The art is a SQUARE 1:1 crest whose ink fills 85% of its canvas, where the
   old wordmark was 3:2 and filled 49% — so the same width now draws a mark
   roughly 1.7× larger and as tall as it is wide. Sized to sit comfortably
   inside the shortest phone viewport with room to swell: 58vw on a 390px
   screen is a 226px box, ~193px of visible crest, centred by `place-items` on
   a full-viewport overlay so nothing can clip it. */
.dissolve-mark {
  position: relative;
  z-index: 2;
  display: block;
  width: min(58vw, 272px);
  opacity: 0;
  transform: scale(0.55);
}
.dissolve-mark img { display: block; width: 100%; height: auto; }
.ivory-dissolve.is-active .dissolve-mark {
  animation: markBloom 3800ms var(--ease-out) forwards;
}
/* the mark arrives early and then simply HOLDS at full size for most of the
   bloom — the drift from scale(1) to scale(1.04) across that hold is what
   keeps a long pause feeling alive rather than frozen */
@keyframes markBloom {
  0%   { opacity: 0;    transform: scale(0.5)  rotate(-3deg); filter: blur(6px); }
  16%  { opacity: 0.98; transform: scale(1)    rotate(0deg);  filter: blur(0); }
  64%  { opacity: 0.96; transform: scale(1.04) rotate(0deg);  filter: blur(0); }
  78%  { opacity: 0.9;  transform: scale(1.12) rotate(0.5deg); filter: blur(0); }
  100% { opacity: 0;    transform: scale(2.6)  rotate(2deg);  filter: blur(7px); }
}
/* one unhurried sweep, seated wholly inside the window where the mark is
   legible (16%–64% of the 3800ms bloom = 610–2430ms): 800ms → 2300ms */
.ivory-dissolve.is-active .logo-shine {
  animation: logoShine 1500ms ease-in-out 800ms 1 both;
}
.ivory-dissolve.is-active { animation: ivoryDissolve 3800ms cubic-bezier(0.4, 0, 0.2, 1) forwards; }
@keyframes ivoryDissolve {
  0%   { opacity: 0; transform: scale(1.05); filter: blur(8px); }
  18%  { opacity: 1; transform: scale(1);    filter: blur(0); }
  72%  { opacity: 1; transform: scale(1);    filter: blur(0); }
  100% { opacity: 0; transform: scale(1.07); filter: blur(5px); }
}


/* ============================================================
   HERO  —  living background video + couple names
   ============================================================ */
.hero-screen {
  position: relative;
  width: 100%;
  min-height: 100svh;
  overflow: hidden;
  background: var(--cream);
  isolation: isolate;
}
.hero-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.hero-content {
  position: relative;
  z-index: 2;
  display: grid;
  align-content: start;
  justify-items: center;
  width: min(94vw, 500px);
  min-height: 100svh;
  margin: 0 auto;
  padding: 20dvh 12px 12dvh;
  text-align: center;
}

.couple-name .cn-first,
.couple-name .cn-amp,
.couple-name .cn-second,
.wedding-date,
.wedding-venue { opacity: 0; }

.couple-name {
  display: grid;
  gap: clamp(10px, 2.6vh, 26px);
  margin: 0;
  color: var(--maroon-deep);
  font-family: var(--font-hero);
  font-weight: 700;
  line-height: 0.9;
}
.couple-name .cn-first,
.couple-name .cn-second {
  display: block;
  white-space: nowrap;
  font-size: clamp(2.6rem, 13.5vw, 4.6rem);
  letter-spacing: 0.02em;
  opacity: 0;
  transform: translateY(24px);
  text-shadow: 0 2px 26px rgba(253,246,234,0.7), 0 1px 3px rgba(90,40,30,0.28);
}
/* family / weight / colour come from the shared ampersand rule at the top */
.couple-name .cn-amp {
  display: block;
  font-size: clamp(2.2rem, 10vw, 3.4rem);
  line-height: 0.6;
  text-shadow: 0 1px 14px rgba(253,246,234,0.85), 0 0 22px rgba(196,154,84,0.5);
  opacity: 0;
  transform: translateY(12px);
}

.wedding-date,
.wedding-venue {
  margin: 0;
  transform: translateY(16px);
  text-shadow: 0 1px 10px rgba(253,246,234,0.75), 0 1px 3px rgba(90,40,30,0.22);
}
/* date — gold, structured caps */
.wedding-date {
  margin-top: 14px;
  color: var(--gold-deep);
  font-family: var(--font-caps);
  font-size: clamp(0.98rem, 4.4vw, 1.28rem);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-indent: 0.16em;
}
.wedding-date sup { font-size: 0.56em; vertical-align: super; }
/* venue — deep rose, flowing italic (a clearly different treatment) */
.wedding-venue {
  margin-top: 10px;
  color: var(--rose-deep);
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(0.92rem, 3.9vw, 1.08rem);
  font-weight: 600;
  letter-spacing: 0.05em;
}

/* elegant staggered fade-in once the intro hands off (.is-animated):
   groom name → ampersand → bride name → date → venue */
.hero-screen.is-animated .couple-name .cn-first   { animation: heroFadeUp 1500ms var(--ease-out) forwards 300ms; }
.hero-screen.is-animated .couple-name .cn-amp     { animation: heroFadeUp 1300ms var(--ease-out) forwards 1250ms; }
.hero-screen.is-animated .couple-name .cn-second  { animation: heroFadeUp 1500ms var(--ease-out) forwards 1650ms; }
.hero-screen.is-animated .wedding-date            { animation: heroFade 1300ms var(--ease-out) forwards 2900ms; }
.hero-screen.is-animated .wedding-venue           { animation: heroFade 1300ms var(--ease-out) forwards 3250ms; }

@keyframes heroFadeUp {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes heroFade {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── scroll cue ────────────────────────────────────────────────
   The hero backdrop is a bright ivory palace, so the old rose cue washed
   straight into it. It is now deep maroon at a larger size, with the whole
   mark bobbing down the page and the chevrons cascading after it — the
   movement is what catches the eye, so no disc or frame is needed behind it.
   NOTE: .scroll-cue itself is centred with translateX(-50%) and carries the
   entrance transition, so every looping animation lives on a CHILD element —
   nothing may overwrite that centring transform.
   ────────────────────────────────────────────────────────────── */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: max(5dvh, 28px);
  z-index: 3;
  display: grid;
  justify-items: center;
  gap: 10px;
  text-decoration: none;
  opacity: 0;
  transform: translateX(-50%) translateY(8px);
  transition: opacity 1000ms ease 4200ms, transform 1000ms ease 4200ms;
}
.hero-screen.is-animated .scroll-cue { opacity: 1; transform: translateX(-50%); }
.scroll-cue-label {
  position: relative;
  color: var(--maroon-deep);
  font-family: var(--font-caps);
  font-size: clamp(0.8rem, 3.4vw, 0.92rem);
  font-weight: 700;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  text-transform: uppercase;
  text-shadow:
    0 1px 2px rgba(253,246,234,1),
    0 0 10px rgba(253,246,234,0.98),
    0 0 22px rgba(253,246,234,0.85);
}
/* The gold gleam travelling across the word.
   It is a GHOST COPY of the text laid exactly over the real one, rather
   than a gradient on the label itself: clipping a gradient to .scroll-cue-label
   would need `color: transparent`, which would take the ivory halo above with
   it and leave the word unreadable on the bright palace. The real text keeps
   its colour and shadow; this layer only adds light.
   Every font metric (family, size, weight, letter-spacing, text-indent,
   text-transform) is inherited, so the ghost lands on the letters — but
   text-shadow inherits too and MUST be cleared, or the halo would paint
   under the transparent fill as an ivory smudge.
   Keep `content` in sync with the markup if the word ever changes. */
.scroll-cue-label::after {
  content: "Scroll";
  position: absolute;
  inset: 0;
  pointer-events: none;
  text-shadow: none;
  color: transparent;
  -webkit-text-fill-color: transparent;
  background-image: linear-gradient(115deg,
    transparent 38%,
    rgba(255, 240, 200, 0.55) 46%,
    rgba(255, 255, 255, 0.98) 50%,
    rgba(255, 240, 200, 0.55) 54%,
    transparent 62%);
  background-size: 260% 100%;
  background-repeat: no-repeat;
  background-position: 175% 0;
  -webkit-background-clip: text;
          background-clip: text;
  animation: scrollShine 3200ms ease-in-out infinite;
}
@keyframes scrollShine {
  0%        { background-position: 175% 0; }
  55%, 100% { background-position: -85% 0; }
}

/* the chevron stack — larger, and the whole group drifts down the page on a
   slow loop so the cue reads as motion rather than a static mark */
.scroll-arrows {
  display: grid;
  justify-items: center;
  height: 30px;
  animation: scrollCueDrift 2600ms ease-in-out infinite;
}
@keyframes scrollCueDrift {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(8px); }
}
.scroll-arrows i {
  display: block;
  width: 16px; height: 16px;
  margin-top: -7px;
  border-right: 3px solid var(--maroon-deep);
  border-bottom: 3px solid var(--maroon-deep);
  filter:
    drop-shadow(0 1px 1px rgba(253,246,234,1))
    drop-shadow(0 0 5px rgba(253,246,234,0.95));
  transform: rotate(45deg);
  opacity: 0;
  /* the chevrons are drawn with borders, so a clipped gradient cannot reach
     them — the gleam is a colour pulse on the stroke instead, on the same
     3200ms clock as the label so the light reads as one sweep continuing
     down the mark. The per-chevron delay below staggers both animations,
     which is what makes the gleam travel down the stack. */
  animation:
    chevronDrop 1700ms ease-in-out infinite,
    chevronGleam 3200ms ease-in-out infinite;
}
.scroll-arrows i:nth-child(2) { animation-delay: 180ms; }
.scroll-arrows i:nth-child(3) { animation-delay: 360ms; }
@keyframes chevronGleam {
  0%, 58%, 100% { border-color: var(--maroon-deep); }
  68%           { border-color: #edc984; }
  80%           { border-color: var(--maroon-deep); }
}
@keyframes chevronDrop {
  0%   { opacity: 0; transform: translateY(-5px) rotate(45deg); }
  50%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(7px) rotate(45deg); }
}
.scroll-cue:active .scroll-arrows { transform: scale(0.94); }


/* ============================================================
   INVITE  —  arch mandap · Ganesha shine · line-by-line text
   ============================================================ */
/* the arch panel is over-wide and clipped, so on a phone it covers the section
   entirely — but from tablet up its sides fall inside the viewport and this
   backdrop shows. The re-cut artwork is a pale mint-and-ivory arch (it was
   peach), so the fill follows it across; a blush field either side of a mint
   panel reads as a seam. */
.invite-screen {
  position: relative;
  width: 100%;
  min-height: 100svh;
  overflow: hidden;
  background:
    radial-gradient(ellipse 90% 50% at 50% 0%, rgba(196,154,84,0.10), transparent 62%),
    linear-gradient(180deg, #eef3ec 0%, #e6efe9 44%, var(--cream-soft) 100%);
  isolation: isolate;
}

/* the arch artwork is a portrait 941×1672 panel — fill the viewport height so
   there is no blush band between the hero and the invitation; the extra width
   overflows equally beyond the viewport and is clipped, keeping the arch + text
   dead-centred (absolute centring is reliable for an over-wide element) */
.invite-card {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  height: 100svh;
  aspect-ratio: 941 / 1672;
}
.invite-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}

/* ── Lord Ganesha — seated inside the arch peak ── */
.invite-ganesha {
  position: absolute;
  top: 6.5%;
  left: 50%;
  z-index: 3;
  width: 25%;
  aspect-ratio: 1 / 1;
  transform: translateX(-50%) translateY(14px);
  opacity: 0;
  filter: blur(8px);
  transition: opacity 1100ms ease, transform 1100ms var(--ease-out), filter 1100ms ease;
}
.invite-screen.is-revealed .invite-ganesha {
  opacity: 1;
  filter: blur(0);
  transform: translateX(-50%) translateY(0);
}
.invite-ganesha img {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
/* warm radial halo behind the deity — gentle breathing glow */
.ganesha-glow {
  position: absolute;
  inset: -22%;
  z-index: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(224,178,96,0.55) 0%, rgba(224,178,96,0.20) 42%, transparent 70%);
  opacity: 0;
}
.invite-screen.is-revealed .ganesha-glow { animation: ganeshaGlow 3.8s ease-in-out infinite 900ms; }
@keyframes ganeshaGlow {
  0%, 100% { opacity: 0.5; transform: scale(0.92); }
  50%      { opacity: 1;   transform: scale(1.06); }
}
/* light-sweep shine clipped to the deity's golden outline (mask = the webp) */
.ganesha-shine {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  -webkit-mask: url(assets/invite/lord_Ganesha.webp) center / contain no-repeat;
          mask: url(assets/invite/lord_Ganesha.webp) center / contain no-repeat;
  background: linear-gradient(115deg,
    transparent 34%,
    rgba(255,246,214,0.55) 45%,
    rgba(255,255,255,0.95) 50%,
    rgba(255,246,214,0.55) 55%,
    transparent 66%);
  background-size: 260% 100%;
  background-repeat: no-repeat;
  opacity: 0;
}
.invite-screen.is-revealed .ganesha-shine { animation: ganeshaShine 4.2s ease-in-out infinite 1600ms; }
@keyframes ganeshaShine {
  0%       { background-position: 175% 0; opacity: 0; }
  12%      { opacity: 1; }
  46%      { opacity: 1; }
  60%, 100%{ background-position: -85% 0; opacity: 0; }
}

/* ── invitation text, seated inside the clear arch interior ── */
.invite-inner {
  position: absolute;
  top: 21.5%;
  left: 16%;
  right: 16%;
  bottom: 9%;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: clamp(5px, 1.35vh, 12px);
  text-align: center;
  color: var(--maroon);
}

.reveal-line {
  opacity: 0;
  transform: translateY(26px);
  filter: blur(8px);
  transition:
    opacity 1000ms var(--ease-out),
    transform 1000ms var(--ease-out),
    filter 1000ms var(--ease-out);
}
.invite-screen.is-revealed .invite-inner .reveal-line {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(1) { transition-delay: 200ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(2) { transition-delay: 340ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(3) { transition-delay: 500ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(4) { transition-delay: 660ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(5) { transition-delay: 800ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(6) { transition-delay: 940ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(7) { transition-delay: 1080ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(8) { transition-delay: 1220ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(9)  { transition-delay: 1360ms; }
.invite-screen.is-revealed .invite-inner .reveal-line:nth-child(10) { transition-delay: 1500ms; }

.invite-blessing {
  margin: 0;
  color: var(--gold-deep);
  font-family: var(--font-caps);
  font-size: clamp(0.6rem, 2.6vw, 0.76rem);
  font-weight: 500;
  letter-spacing: 0.08em;
  line-height: 1.5;
}

/* hosts + daughter blocks — each name on its own line with a gold ampersand */
.invite-hosts, .invite-daughter { margin: 0; }
.invite-host-name {
  margin: 0;
  color: var(--inv-brown);
  font-family: var(--font-display);
  font-size: clamp(0.88rem, 3.9vw, 1.06rem);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.32;
  text-wrap: balance;
}
.invite-amp {
  margin: 0;
  font-size: clamp(1.5rem, 6vw, 1.85rem);
  line-height: 0.72;
}
.invite-daughter-label {
  margin: 0 0 2px;
  color: var(--inv-rose);
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(0.76rem, 3.2vw, 0.92rem);
  line-height: 1.3;
}

.invite-lead {
  margin: 0;
  color: var(--inv-sepia);
  font-family: var(--font-display);
  font-size: clamp(0.78rem, 3.4vw, 0.94rem);
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1.52;
  text-wrap: balance;
}

.invite-person { margin: 0; width: 100%; }
.invite-couple {
  margin: 0;
  white-space: nowrap;
  color: var(--inv-gold);
  font-family: var(--font-hero);
  font-size: clamp(2.7rem, 13vw, 4rem);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: 0.01em;
}

.invite-with { margin: 0; }
.invite-with span {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(0.98rem, 4.1vw, 1.18rem);
  color: var(--inv-rose);
  letter-spacing: 0.03em;
}

.invite-closing {
  margin: 2px 0 0;
  color: var(--inv-plum);
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(0.78rem, 3.3vw, 0.94rem);
  font-weight: 500;
  line-height: 1.5;
  text-wrap: balance;
}


/* ============================================================
   EVENTS  —  layered watercolour cards (bg · hanging · subject · fg)

   Each stage is a 941×1672 frame. The three cut-out layers carry their
   own transparent padding, so every one is placed from its MEASURED
   alpha bounding box (noted per rule) — that is what makes the toran
   meet the top rail and the prop trays sit flat on the card floor.

   Stage geometry: height = width × 1.7768. For a layer sized to W% of
   the stage width, its height as a share of the STAGE height is
       H% = W% × (artH / artW) ÷ 1.7768
   ============================================================ */
.events-screen {
  position: relative;
  padding: clamp(54px, 9vw, 100px) 16px clamp(60px, 10vw, 108px);
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(196, 154, 84, 0.10), transparent 62%),
    linear-gradient(180deg, var(--cream-soft) 0%, var(--blush-soft) 46%, var(--blush) 100%);
}

/* ── section header ── */
.events-head {
  max-width: 640px;
  margin: 0 auto clamp(34px, 6vw, 58px);
  text-align: center;
}
.events-kicker,
.events-title,
.events-divider {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 900ms var(--ease-out), transform 900ms var(--ease-out);
}
.events-screen.is-revealed .events-kicker  { opacity: 1; transform: none; transition-delay: 60ms; }
.events-screen.is-revealed .events-title   { opacity: 1; transform: none; transition-delay: 200ms; }
.events-screen.is-revealed .events-divider { opacity: 1; transform: none; transition-delay: 360ms; }

.events-kicker {
  margin: 0 0 12px;
  color: var(--gold-deep);
  font-family: var(--font-label);
  font-size: clamp(11px, 3vw, 14px);
  letter-spacing: 0.32em;
  text-indent: 0.32em;
  text-transform: uppercase;
}
.events-title {
  margin: 0;
  color: var(--maroon-deep);
  font-family: var(--font-caps);
  font-weight: 600;
  font-size: clamp(27px, 7.2vw, 44px);
  letter-spacing: 0.05em;
  line-height: 1.12;
}
/* at 1.1em this read as a smudge between two heavy Cinzel words — Tangerine
   needs the size to register as the flourish it is meant to be */
.events-title .events-amp {
  font-size: 1.9em;
  line-height: 0;
  vertical-align: -0.08em;
}
.events-divider {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 16px;
}
.events-divider span {
  display: block;
  width: clamp(40px, 14vw, 82px);
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
}
.events-divider i {
  width: 7px;
  height: 7px;
  transform: rotate(45deg);
  background: var(--gold);
  box-shadow: 0 0 0 3px rgba(196, 154, 84, 0.18);
}

/* ── card shell ── */
.events-list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(40px, 7vw, 76px);
}
.ev-card {
  width: 100%;
  max-width: 440px;
  opacity: 0;
  transform: translateY(48px);
  transition:
    opacity 900ms ease,
    transform 1000ms var(--ease-out);
}
.ev-card.is-in { opacity: 1; transform: translateY(0); }

.ev-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 941 / 1672;
  overflow: hidden;
  border-radius: 14px;
  border: 1px solid rgba(196, 154, 84, 0.5);
  background: var(--cream-soft);
  box-shadow:
    0 22px 52px -18px rgba(90, 45, 30, 0.45),
    inset 0 0 0 1px rgba(253, 243, 223, 0.35),
    inset 0 0 70px rgba(95, 71, 51, 0.08);
}
/* themed fill behind transparent edges / while the art streams in */
.ev-card--pellikoduku .ev-stage { background: linear-gradient(168deg, #e9f2ee 0%, #d8e8e2 100%); }
.ev-card--mehendi     .ev-stage { background: linear-gradient(168deg, #f2f2e2 0%, #dfe7cf 100%); }
.ev-card--wedding     .ev-stage { background: linear-gradient(168deg, #faf1e0 0%, #f0e1c8 100%); }
.ev-card--reception   .ev-stage { background: linear-gradient(168deg, #4a1436 0%, #8d3a52 55%, #52163a 100%); }

.ev-layer {
  position: absolute;
  display: block;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
.ev-bg {
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
/* ── CENTRING RULE (do not reintroduce translateX) ─────────────────
   Every cut-out layer is centred by LAYOUT — inset left/right + auto inline
   margins — never by transform. A percentage translateX resolves against the
   element's own box, and iOS Safari bakes that resolved value into the
   running float animation; because these are lazy images, the box is still
   unknown at that moment, so the layer paints off-centre and only snaps back
   after a full relayout (lock/unlock the phone). Layout centring is
   recomputed by the engine, so it cannot go stale. Every <img> also carries
   width/height attributes, so the aspect ratio is known before decode and
   there is no zero-width window at all.
   Layers whose artwork is off-centre inside its own canvas get a static
   `left` instead (see the per-card geometry) — still no transform.
   ================================================================== */

/* the figures stand on the card floor, centred on the stage */
.ev-subject {
  left: 0;
  right: 0;
  margin-inline: auto;
  width: auto;
  height: auto;
  z-index: 2;
  transform-origin: 50% 100%;
  filter: drop-shadow(0 12px 18px rgba(90, 45, 30, 0.26));
  animation: evSubjectFloat 5.8s ease-in-out infinite;
}
/* props: a FULL-BLEED band across the foot of the card and the FRONT-MOST
   layer, so the figures' feet tuck in behind it.
   The artwork already runs edge-to-edge and (bar the wedding file) flush to
   the bottom of its own canvas, so the layer is simply pinned left:0/right:0
   at width:100% with height:auto — no cover-crop, no distortion, identical
   on every phone. --fg-b compensates a file whose art stops short of its
   canvas bottom (see the per-card geometry).
   The float is seated 9px LOW and only ever rises back to flush, so the band
   can never lift off the bottom edge and open a gap. */
.ev-fg {
  left: 0;
  right: 0;
  width: 100%;
  height: auto;
  bottom: calc(var(--fg-b, 0%) - 9px);
  z-index: 7;
  transform-origin: 50% 100%;
  filter: drop-shadow(0 -6px 16px rgba(90, 45, 30, 0.18));
  animation: evFgFloat 6.6s ease-in-out infinite;
}
/* the toran hangs from the top rail and swings from its own hinge */
.ev-hang {
  height: auto;
  z-index: 4;
  transform-origin: 50% 0%;
  filter: drop-shadow(0 10px 16px rgba(90, 45, 30, 0.20));
  animation: evHangSway 7.2s ease-in-out infinite;
}

/* the floats carry NO horizontal component — centring is layout's job. This is
   what makes the layers land identically on iOS and Android, first paint. */
@keyframes evSubjectFloat {
  0%, 100% { transform: translateY(0)     rotate(-0.5deg); }
  50%      { transform: translateY(-14px) rotate(0.5deg); }
}
/* the prop band breathes straight up and back down — no rotation, which on a
   full-bleed layer would swing its bottom corners off the card */
@keyframes evFgFloat {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-9px); }
}
@keyframes evHangSway {
  0%, 100% { transform: rotate(-0.75deg); }
  50%      { transform: rotate(0.75deg); }
}

/* one-shot gold light sweep across the card as it arrives */
.ev-shine {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(112deg,
    transparent 34%,
    rgba(255, 246, 214, 0.30) 46%,
    rgba(255, 255, 255, 0.55) 50%,
    rgba(255, 246, 214, 0.30) 54%,
    transparent 66%);
  background-size: 260% 100%;
  background-repeat: no-repeat;
  background-position: 175% 0;
}
.ev-card.is-in .ev-shine { animation: evShine 1900ms ease-out 500ms 1; }
@keyframes evShine {
  0%        { background-position: 175% 0;  opacity: 0; }
  18%       { opacity: 1; }
  70%       { opacity: 1; }
  100%      { background-position: -85% 0;  opacity: 0; }
}


/* ============================================================
   PER-CARD LAYER GEOMETRY

   Reading order down every card:  hang → text → subject → fg.
   EVERY layer is anchored with left:50% + translateX(-50%) — no left/right
   edge anchors and no --sdx nudges — so nothing can drift to one side on a
   narrow phone. Vertical placement is derived from each layer's MEASURED
   alpha box, in % of the stage, which renders identically on Android + iOS.

   For a layer sized to W% of the stage width:
       elemH% = W% × (artH / artW) ÷ 1.7768
   and an alpha edge at f (0–1 of the art) lands at
       abs% = (100 − bottom% − elemH%) + f × elemH%
   ============================================================ */

/* Alpha boxes below are MEASURED (scripts run over the webp alpha channel),
   not estimated. `left` on the fixed-width layers = 50 − (0.5 + c)·W, where c
   is how far the artwork's own centre sits from its canvas centre — that is
   what puts the PAINTING on the card's centre line rather than the file.

   The prop bands are all full-bleed now, so the FIGURES are seated deliberately
   INTO them: each subject's foot line is carried 9–13% of its own height below
   the point where the props become a solid mass, so the group stands amongst
   the offerings instead of on top of them. Depth, not a sticker. */

/* ── 1 · Pellikoduku ────────────────────────────────────────
   hang    1024×1536, alpha x ctr -0.15%, y 19.73–82.68%
           → 100%w = 84.42%h; top -21% → the flower rail tucks 4% under the
           card's top edge and the strands lift to ~49%, clearing the heading
   subject 1122×1402, alpha x ctr +0.45%, y 13.84–88.87%
           → 44.5%h, foot 11.05% → figures 50.6–84.0%  (63% of the card wide)
   fg      1440×2560 (stage ratio), alpha y 68.2–100%, edge to edge
           → 100%w, flush to the bottom; solid from 79.3%
   feet 84.0% vs solid 79.3% → 14% of the group tucked behind the props.
   This card carries the most type (two day blocks), so the heading stays at
   9% — above that it runs into the toran's flower rail — and the rule and
   day gap are tightened so the type clears the group's heads.             */
.ev-card--pellikoduku .ev-hang    { width: 100%; left: 0.15%; top: -21%; }
.ev-card--pellikoduku .ev-subject { height: 41%; bottom: 10.5%; }
.ev-card--pellikoduku .ev-info    { top: 9%; width: 84%; }
/* two long words — held clear of the toran strands that frame this card.
   The title now reads over THREE lines (name · ampersand · name), which costs
   roughly a line of card height, so the group is taken from 44.5% to 41% and
   the type block is tightened to match: figures 54.5–84.9%, still landing
   with the same 13% of the group tucked behind the props at 79.3%. */
.ev-card--pellikoduku .ev-name    { font-size: clamp(18px, 5.5vw, 26px); }
.ev-card--pellikoduku .ev-name i  { font-size: 2.4em; }
.ev-card--pellikoduku .ev-rule    { margin: 6px 0 8px; }
.ev-card--pellikoduku .ev-days    { gap: clamp(6px, 1.5vw, 9px); }
.ev-card--pellikoduku .ev-daysep  { margin: 1px 0; }

/* ── 2 · Ring Ceremony · Mehendi ────────────────────────────
   hang    1536×1024, alpha x ctr -1.11%, y 7.03–74.32%
           → 100%w = 37.52%h; top -2.94% → rail flush, lanterns to ~25%
   subject 1536×2304, alpha x ctr  0.00%, y 16.41–82.07%  (re-cut art — the
           ring-ceremony pose, at 1.5× the resolution of the 1024×1536 file it
           replaces. Same 2:3 canvas and an alpha box within 0.5% of the old
           one, so the height/foot pair below is unchanged and the painting
           still lands where it did.)
           → 63%h, foot 4.6% → couple 42.7–84.1%  (74% of the card wide)
   fg      1440×2560 (stage ratio), alpha y 75.8–100%, edge to edge
           → 100%w, flush to the bottom; solid from 80.1%
   feet 84.0% vs solid 80.1% → 9% of the couple behind the leaf bed.       */
.ev-card--mehendi .ev-hang    { width: 100%; left: 1.11%; top: -2.94%; }
.ev-card--mehendi .ev-subject { height: 63%; bottom: 4.6%; }
.ev-card--mehendi .ev-info    { top: 9%; }
/* this couple is painted in the same pale sage and cream as the backdrop
   behind them, so on a phone they wash into it. A deeper contact shadow plus
   a touch of contrast pulls them off the wall without altering the artwork. */
.ev-card--mehendi .ev-subject {
  filter:
    drop-shadow(0 14px 20px rgba(58, 74, 40, 0.34))
    drop-shadow(0 2px 5px rgba(58, 74, 40, 0.26))
    contrast(1.05) saturate(1.06);
}

/* ── 3 · Wedding Sumuhurtam ─────────────────────────────────
   hang    1024×1536, alpha x ctr -0.29%, y 11.98–44.34%
           → 100%w = 84.42%h; top -10.41% → rail flush, bells to ~27%
   subject 1086×1448, alpha x ctr +1.01%, y 10.77–91.92%  (re-cut art — the
           seated mangalsutra moment; a wider canvas with far less transparent
           padding than the 1024×1536 file it replaces, so the height/bottom
           pair is re-derived rather than inherited)
           → 56.6%h, foot 9.03% → couple 40.5–86.4%  (74% of the card wide)
           i.e. the PAINTING lands exactly where the old one did; feeding the
           old 66%/2.76% to this file would have thrown the couple to 91.9%,
           a quarter of them buried in the homam.
   fg      1024×1536, alpha y 45.05–89.06% — art stops 10.94% of the file
           short of its own bottom, so --fg-b: -9.24% of the stage carries it
           down flush → the homam reads 62.9–100%, solid mass from 82.7%
   feet 86.4% vs solid 82.7% → 8% of the couple behind the homam plate, with
   the flame itself crossing in front of them exactly as it would in life.
   x centre is off by +1.01% of the file = 0.8% of the card — inside the
   eye's tolerance, so layout centring still stands (no `left` override).   */
.ev-card--wedding .ev-hang    { width: 100%; left: 0.29%; top: -10.41%; }
.ev-card--wedding .ev-subject { height: 56.6%; bottom: 9.03%; }
.ev-card--wedding .ev-fg      { --fg-b: -9.24%; }
.ev-card--wedding .ev-info    { top: 8%; }

/* ── 4 · Reception ──────────────────────────────────────────
   hang    1024×1536, alpha x ctr  0.00%, y 5.27–41.93%
           → 100%w = 84.42%h; top -4.75% → rail flush, lanterns to ~31%
   subject 1024×1536, alpha x ctr +1.86%, y 7.94–95.96%
           → 52%h, foot 10.9% → couple 41.2–87.0%  (61% of the card wide)
   fg      1440×2560 (stage ratio), alpha y 73.1–100%, edge to edge
           → 100%w, flush to the bottom; solid from 80.1%, and at dead
           centre — where the couple stands — the florals start at 81.7%
   feet 87.0% vs 81.7% → 11% of the couple behind the flowers.             */
.ev-card--reception .ev-hang    { width: 100%; left: 0; top: -4.75%; }
.ev-card--reception .ev-subject { height: 52%; bottom: 10.9%; }
/* Seated lower than the other cards so the heading clears the garland's flower
   band instead of starting hard against it. The room for it is bought, not
   found: at top:10% the block ran 10.1–36.16% against a couple whose topmost
   ink is at 40.96%, and pushing it down alone would have walked the venue line
   into the groom's head. Tightening this card's rule margins (below) shortens
   the block from 26.06% to 24.95%, which is what lets the whole thing come
   down 2.6% and still leave 3.3% — 24px, measured — of clear card between the
   venue line and the figures.
   These three values are a set: raise `top` or loosen `.ev-rule` and the text
   walks into the figures. The couple's own geometry is deliberately untouched
   (moving it would change the foot line's overlap with the prop band). */
.ev-card--reception .ev-info    { top: 12.6%; }
.ev-card--reception .ev-rule    { margin: 9px 0 10px; }


/* ============================================================
   EVENT TEXT  —  sits in the open band under the toran
   ============================================================ */
.ev-info {
  position: absolute;
  left: 50%;
  width: 90%;
  z-index: 6;
  transform: translateX(-50%);
  text-align: center;
  pointer-events: none;
}
/* a breath of the card's own light behind the type, so it lifts off the
   painting without ever reading as a panel */
.ev-info::before {
  content: "";
  position: absolute;
  inset: -30px -14% -32px;
  z-index: -1;
  pointer-events: none;
}
.ev-info--ink::before {
  background: radial-gradient(112% 100% at 50% 40%, rgba(253, 246, 234, 0.62), rgba(253, 246, 234, 0) 72%);
}
.ev-info--light::before {
  background: radial-gradient(112% 100% at 50% 40%, rgba(38, 8, 26, 0.45), rgba(38, 8, 26, 0) 74%);
}

/* line-by-line arrival, matching the invitation's reveal language */
.ev-line {
  opacity: 0;
  transform: translateY(20px);
  filter: blur(7px);
  transition:
    opacity 900ms var(--ease-out),
    transform 900ms var(--ease-out),
    filter 900ms var(--ease-out);
}
.ev-card.is-in .ev-line { opacity: 1; transform: translateY(0); filter: blur(0); }
.ev-card.is-in .ev-line:nth-child(1) { transition-delay: 260ms; }
.ev-card.is-in .ev-line:nth-child(2) { transition-delay: 400ms; }
.ev-card.is-in .ev-line:nth-child(3) { transition-delay: 540ms; }
.ev-card.is-in .ev-line:nth-child(4) { transition-delay: 680ms; }
/* the day blocks are nested one level deeper (2 = the hairline on the
   two-day card, 3 = its second day block) */
.ev-card.is-in .ev-days .ev-line:nth-child(1) { transition-delay: 700ms; }
.ev-card.is-in .ev-days .ev-line:nth-child(2) { transition-delay: 840ms; }
.ev-card.is-in .ev-days .ev-line:nth-child(3) { transition-delay: 960ms; }

.ev-name {
  margin: 0;
  font-family: var(--font-caps);
  font-weight: 600;
  font-size: clamp(21px, 6.4vw, 31px);
  letter-spacing: 0.05em;
  line-height: 1.18;
  text-wrap: balance;
}
/* the calligraphic ampersand — a gold flourish, not a running character */
.ev-name i {
  font-size: 2.1em;
  line-height: 0;
  vertical-align: -0.12em;
  padding-left: 0.06em;
}
/* stacked variant — two names reading down the card with the calligraphic
   ampersand centred on its own line between them. The flourish gets its own
   row (so it needs the inline rule's line-height:0 and baseline nudge undone)
   and is flanked by short gold hairlines, which turn it from a stray
   character into a deliberate ornament. */
.ev-name--stack {
  display: grid;
  justify-items: center;
  gap: 0;
}
/* the ampersand is a small, hairline glyph — at the inline size it disappeared
   entirely against this pale card. On its own row it is set large and tight
   (line-height well under 1, so the size costs almost no card height) and
   flanked by gold hairlines, which reads as an ornament dividing the two
   names rather than a stray character. */
.ev-name--stack i {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.34em;
  width: 100%;
  font-size: 2.6em;
  line-height: 0.62;
  vertical-align: baseline;
  padding-left: 0;
  text-shadow: 0 1px 2px rgba(253, 246, 234, 0.95);
}
.ev-name--stack i::before,
.ev-name--stack i::after {
  content: "";
  flex: none;
  width: clamp(26px, 9vw, 48px);
  height: 1px;
  background: linear-gradient(90deg, transparent, currentColor, transparent);
  opacity: 0.75;
}

.ev-sub {
  margin: 7px 0 0;
  font-family: var(--font-label);
  font-size: clamp(10.5px, 2.9vw, 13px);
  letter-spacing: 0.22em;
  text-indent: 0.22em;
  text-transform: uppercase;
}
.ev-rule {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 13px 0 14px;
}
.ev-rule span {
  display: block;
  width: clamp(26px, 9vw, 48px);
  height: 1px;
  background: currentColor;
  opacity: 0.55;
}
.ev-rule i {
  width: 6px;
  height: 6px;
  transform: rotate(45deg);
  background: currentColor;
  opacity: 0.85;
}

.ev-days { display: grid; gap: clamp(9px, 2.4vw, 14px); }
.ev-day  { display: grid; gap: 3px; }

/* a hairline between two day blocks — without it the second date reads as
   another line of the first one's schedule */
.ev-daysep {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
}
.ev-daysep span {
  display: block;
  width: clamp(20px, 7vw, 38px);
  height: 1px;
  background: linear-gradient(90deg, transparent, currentColor, transparent);
  opacity: 0.6;
}
.ev-daysep i {
  width: 4px;
  height: 4px;
  transform: rotate(45deg);
  background: currentColor;
  opacity: 0.75;
}

.ev-date {
  margin: 0 0 2px;
  font-family: var(--font-caps);
  font-weight: 600;
  font-size: clamp(15px, 4.3vw, 20px);
  letter-spacing: 0.09em;
  text-indent: 0.09em;
}
.ev-date sup { font-size: 0.56em; vertical-align: super; letter-spacing: 0; }

/* label · diamond · time — the diamond is dropped when the row is time-only */
.ev-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(12.5px, 3.5vw, 15px);
  line-height: 1.35;
}
.ev-slot span { font-style: italic; font-weight: 500; letter-spacing: 0.02em; }
.ev-slot i {
  flex: none;
  width: 4px;
  height: 4px;
  transform: rotate(45deg);
  background: currentColor;
  opacity: 0.6;
}
.ev-slot b {
  font-family: var(--font-caps);
  font-weight: 600;
  font-size: 0.97em;
  letter-spacing: 0.06em;
}
.ev-slot--solo b { font-size: clamp(14px, 4vw, 18px); letter-spacing: 0.08em; }

.ev-note {
  margin: 5px 0 0;
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(11.5px, 3.2vw, 13.5px);
  letter-spacing: 0.02em;
  opacity: 0.92;
}

/* ── venue · a drawn map pin, tappable straight through to Maps ──
   .ev-info is pointer-events:none so the painting stays inert — the venue
   link opts itself back in. The pin is a slim teardrop with the card's own
   diamond — the motif already carried by .ev-rule and .events-divider — cut
   clean through it, so each card's artwork shows through the hole. It takes
   its colour from the venue text it belongs to (currentColor, no separate
   .ev-pin colour), so the mark and the name always read as one unit. */
.ev-venue {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 7px auto 0;
  pointer-events: auto;
  color: inherit;
  text-decoration: none;
  transition: transform 220ms var(--ease-out), filter 220ms ease;
}
.ev-venue:active { transform: scale(0.97); }
@media (hover: hover) {
  .ev-venue:hover { transform: translateY(-1px); filter: brightness(1.08); }
}

.ev-pin {
  position: relative;
  flex: none;
  display: block;
  width: clamp(12px, 3.1vw, 14px);
  animation: evPinBob 3.6s ease-in-out infinite;
}
.ev-pin-svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  filter: drop-shadow(0 1px 1.5px rgba(90, 45, 30, 0.22));
}
.ev-pin-body { fill: currentColor; }
@keyframes evPinBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2px); }
}

.ev-venue-txt {
  display: grid;
  gap: 1px;
  text-align: left;
}
.ev-venue-txt b {
  font-family: var(--font-caps);
  font-weight: 600;
  font-size: clamp(12px, 3.4vw, 14.5px);
  letter-spacing: 0.05em;
  line-height: 1.2;
}
.ev-venue-txt i {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(10.5px, 2.9vw, 12.5px);
  letter-spacing: 0.02em;
  line-height: 1.25;
  opacity: 0.9;
}


/* ============================================================
   PER-CARD COLOUR THEMES  —  read off each backdrop
   ============================================================ */

/* 1 · Pellikoduku — pale aqua-mint arch, cream field, gold pillars.
   This is the palest backdrop of the four AND the busiest, with the toran's
   cream-and-gold strands falling right through the type band, so the original
   mid-tone teal/gold washed into it. Every colour here is taken a shade or
   two deeper — temple teal for the names, kumkum maroon for the dates,
   burnished gold for the trim — and each carries a tighter ivory halo so the
   letterforms cut cleanly through the flowers behind them. Same three
   colours as before, just at the weight this artwork needs. */
.ev-card--pellikoduku .ev-name  {
  color: #06393a;
  text-shadow: 0 1px 2px rgba(253, 246, 234, 0.98), 0 0 12px rgba(253, 246, 234, 0.85);
}
/* the ampersand keeps the site-wide gold — only the rules around it deepen */
.ev-card--pellikoduku .ev-rule  { color: #9a6a12; }
.ev-card--pellikoduku .ev-date  {
  color: #6b1f2e;
  text-shadow: 0 1px 2px rgba(253, 246, 234, 0.98), 0 0 10px rgba(253, 246, 234, 0.8);
}
.ev-card--pellikoduku .ev-daysep { color: #9a6a12; }
.ev-card--pellikoduku .ev-slot  {
  color: #17443d;
  text-shadow: 0 1px 2px rgba(253, 246, 234, 0.95);
}
.ev-card--pellikoduku .ev-slot b{ color: #7a4a0f; }
.ev-card--pellikoduku .ev-venue {
  color: #123b34;
  text-shadow: 0 1px 2px rgba(253, 246, 234, 0.98), 0 0 10px rgba(253, 246, 234, 0.8);
}
/* the city line runs at 0.9 opacity everywhere else; on this backdrop that
   was the first thing to disappear, so it holds full strength here */
.ev-card--pellikoduku .ev-venue-txt i { opacity: 1; }
/* a deeper pool of the card's own ivory light under the whole type block —
   the type stops fighting the toran without ever reading as a panel */
.ev-card--pellikoduku .ev-info::before {
  inset: -34px -18% -38px;
  background:
    radial-gradient(96% 74% at 50% 44%, rgba(253, 248, 238, 0.92), rgba(253, 248, 238, 0) 76%),
    radial-gradient(130% 106% at 50% 40%, rgba(253, 246, 234, 0.6), rgba(253, 246, 234, 0) 72%);
}

/* 2 · Mehendi — sage-green wash, cream field, blush blossoms.
   Deep leaf green for the title, dusty rose for the subtitle so it picks
   up the flowers, plum for the date. */
.ev-card--mehendi .ev-name  { color: #2f5430; text-shadow: 0 1px 2px rgba(253, 246, 234, 0.85); }
.ev-card--mehendi .ev-sub   { color: #ad5a72; }
.ev-card--mehendi .ev-rule  { color: #b98c3f; }
.ev-card--mehendi .ev-date  { color: #6d2a45; text-shadow: 0 1px 2px rgba(253, 246, 234, 0.8); }
.ev-card--mehendi .ev-slot  { color: #4a6238; }
.ev-card--mehendi .ev-slot b{ color: #8a5a1c; }
.ev-card--mehendi .ev-note  { color: #8a4a5e; }
.ev-card--mehendi .ev-venue { color: #3f5a2f; text-shadow: 0 1px 2px rgba(253, 246, 234, 0.85); }

/* 3 · Wedding — ivory parchment, gold border, crimson floral crest.
   Kumkum red title with marigold-gold trim; terracotta date. */
.ev-card--wedding .ev-name  { color: #8d1e24; text-shadow: 0 1px 2px rgba(253, 246, 234, 0.85); }
.ev-card--wedding .ev-sub   { color: #a97521; }
.ev-card--wedding .ev-rule  { color: #c08a2c; }
.ev-card--wedding .ev-date  { color: #6d2b1e; text-shadow: 0 1px 2px rgba(253, 246, 234, 0.8); }
.ev-card--wedding .ev-slot  { color: #7a3a2a; }
.ev-card--wedding .ev-slot b{ color: #8d1e24; }
.ev-card--wedding .ev-venue { color: #6d2b1e; text-shadow: 0 1px 2px rgba(253, 246, 234, 0.85); }

/* 4 · Reception — plum-to-rose gradient with gold rules: the one dark
   card, so the type inverts to warm ivory and champagne, each carrying
   a soft shadow to hold contrast over the lit centre of the backdrop. */
.ev-card--reception .ev-name {
  color: #fdf1de;
  text-shadow: 0 2px 12px rgba(40, 8, 26, 0.72), 0 0 26px rgba(40, 8, 26, 0.4);
}
.ev-card--reception .ev-sub  { color: #eac996; text-shadow: 0 1px 8px rgba(40, 8, 26, 0.7); }
.ev-card--reception .ev-rule { color: #dcb977; }
.ev-card--reception .ev-date { color: #f8e6c8; text-shadow: 0 2px 10px rgba(40, 8, 26, 0.76); }
.ev-card--reception .ev-slot { color: #f0d6b4; text-shadow: 0 1px 8px rgba(40, 8, 26, 0.7); }
.ev-card--reception .ev-slot b { color: #fdf1de; }
.ev-card--reception .ev-venue  { color: #f8e6c8; text-shadow: 0 2px 10px rgba(40, 8, 26, 0.76); }
/* on the one dark card a warm shadow is invisible — the outline needs its own
   pool of plum shade to hold, the same way the type does */
.ev-card--reception .ev-pin-svg { filter: drop-shadow(0 1px 6px rgba(40, 8, 26, 0.75)); }

/* ── the plum wash behind this card's type, pulled in ──
   The shared .ev-info--light::before hangs 32px BELOW the text block. That was
   harmless while the type sat at top:10%, but the block now sits 2.6% lower
   (see the geometry above) and at that depth the old wash reached ~42% of the
   stage — onto the groom's head at 40.96% — reading as a grey bruise across
   the couple. The bottom edge is cut to 8px so the shade stops at 38.76%,
   2.2% clear of the figures (both measured), and
   the gradient is both tighter (104%/92% at 70% falloff) and lighter (0.34)
   so it fades out inside its own box rather than at the edge. The type keeps
   its own text-shadows, which are doing most of the legibility work here. */
.ev-card--reception .ev-info::before {
  inset: -22px -10% -8px;
  background: radial-gradient(104% 92% at 50% 42%, rgba(38, 8, 26, 0.34), rgba(38, 8, 26, 0) 70%);
}

/* ── reception venue — the one card whose city is SHORTER than its venue ──
   Everywhere else the second venue line is the longer of the two ("Whisper
   Valley, Jubilee Hills, Hyderabad" under "JRC Convention"), so the default
   left-aligned stack reads as a tidy block. Here it is "Guntur" under "V
   Convention": left-aligned, the city sat hard against the venue name's first
   letter with a wide gap to its right, so the line looked shoved off to one
   side while the date and time above it were dead-centre.
   Both lines are centred instead, and the pin is lifted OUT of the flow to
   hang in the margin beside the venue name — so the name, the city, the time
   and the date all share one centre axis (measured: all four within 1px) and
   the pin still reads as the mark belonging to the line it sits on.
   `display: contents` dissolves the .ev-venue-txt wrapper so its two lines
   become rows of .ev-venue's own grid; the wrapper carries no role, so there
   is nothing for it to strip from the accessibility tree.
   Scoped to this card only — the other three are correct as they are.        */
.ev-card--reception .ev-venue {
  position: relative;
  display: grid;
  justify-content: center;
  justify-items: center;
  row-gap: 1px;
}
.ev-card--reception .ev-venue-txt { display: contents; }
.ev-card--reception .ev-venue-txt b,
.ev-card--reception .ev-venue-txt i { text-align: center; }
/* right:100% seats the pin just outside the block's left edge, keeping the
   same 6px gap the flex layout gave it. The venue name is short and the type
   block is 90% of the card, so there is no risk of it reaching the edge. */
.ev-card--reception .ev-pin {
  position: absolute;
  right: 100%;
  top: 0.14em;
  margin-right: 6px;
}


/* ── very narrow phones (≤360px) ────────────────────────────
   The card art is sized in % of the stage, but the type is clamped in px —
   below ~360px every clamp bottoms out, so the text block claims a bigger
   share of a smaller card and starts to reach the figures' heads. Trim the
   type a notch (and the tallest card's group with it) so the three bands —
   text, figures, props — stay separated right down to a 320px screen. */
@media (max-width: 360px) {
  .ev-name        { font-size: 19px; }
  .ev-sub         { font-size: 10px; }
  .ev-rule        { margin: 10px 0 11px; }
  .ev-date        { font-size: 14px; }
  .ev-slot        { font-size: 11.5px; }
  .ev-slot--solo b{ font-size: 13px; }
  .ev-venue-txt b { font-size: 11.5px; }
  .ev-venue-txt i { font-size: 10px; }
  .ev-note        { font-size: 10.5px; }

  /* the two-day card is the tightest of the four — and its title now runs to
     three lines, so the group comes down again to keep the bands apart */
  .ev-card--pellikoduku .ev-name    { font-size: 16.5px; }
  .ev-card--pellikoduku .ev-rule    { margin: 6px 0 7px; }
  .ev-card--pellikoduku .ev-days    { gap: 7px; }
  .ev-card--pellikoduku .ev-subject { height: 39.5%; bottom: 11%; }  /* feet still ~84.6% */
}


/* ============================================================
   LOVE & BLESSINGS  —  painted frame · petal shower · name groups
   The frame is the same portrait 941×1672 artwork treatment used by the
   invitation: sized to the viewport height and centred, so the gold border
   keeps its proportions and only the outer margins clip.
   ============================================================ */
.blessings-screen {
  position: relative;
  width: 100%;
  min-height: 100svh;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(180deg, var(--blush) 0%, var(--blush-soft) 46%, var(--cream-soft) 100%);
}

/* the frame must cover the WHOLE section, not a fixed 100svh — once the real
   name lists go in, the content grows past one viewport and a fixed-height
   card would leave a bare blush band below it */
.blessings-card {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}
.blessings-bg {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.35s ease, transform 2.1s var(--ease-out);
  scale: 1.02;
}
.blessings-screen.is-visible .blessings-bg { opacity: 1; scale: 1; }

/* a breath of ivory light through the middle so the type always lifts */
.blessings-wash {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(ellipse 74% 42% at 50% 34%, rgba(253, 246, 234, 0.5), transparent 72%),
    linear-gradient(to bottom, rgba(253, 246, 234, 0.16), rgba(253, 246, 234, 0) 58%);
}

/* ── petal shower (over the frame, under the type) ── */
.blessings-petals {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
}
.blessings-petal {
  position: absolute;
  top: 0;
  left: var(--p-left, 50%);
  width: var(--p-size, 24px);
  animation: bpSway var(--p-sway-dur, 3.2s) ease-in-out var(--p-delay, 0s) infinite alternate;
  will-change: transform;
}
.blessings-petal img {
  display: block;
  width: 100%;
  height: auto;
  opacity: 0;
  transform-origin: 50% 20%;
  animation: bpFall var(--p-fall-dur, 7s) ease-in var(--p-delay, 0s) infinite;
  will-change: transform, opacity;
}
@keyframes bpSway {
  0%   { transform: translateX(0); }
  28%  { transform: translateX(var(--p-sway, 22px)); }
  52%  { transform: translateX(calc(var(--p-sway, 22px) * -0.35)); }
  74%  { transform: translateX(var(--p-sway, 22px)); }
  100% { transform: translateX(calc(var(--p-sway, 22px) * 0.55)); }
}
@keyframes bpFall {
  0%  { transform: translateY(-80px) rotate(var(--p-r0, -20deg)) scale(0.55); opacity: 0; }
  5%  { opacity: var(--p-op, 0.62);  transform: translateY(4vh) rotate(calc(var(--p-r0, -20deg) + 18deg)) scale(1); }
  92% { opacity: var(--p-op, 0.62); }
  100%{ transform: translateY(var(--fall-h, 200vh)) rotate(var(--p-r1, 230deg)) scale(0.88); opacity: 0; }
}

/* ── content ── */
/* centred in the frame's clear middle — the painted florals live in the four
   corners, and centring keeps the block composed whether the name lists run
   to one line or ten */
.blessings-content {
  position: relative;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: min(80vw, 380px);
  min-height: 100svh;
  margin: 0 auto;
  padding: clamp(84px, 15vh, 150px) 0 clamp(84px, 14vh, 140px);
  text-align: center;
  text-shadow: 0 1px 10px rgba(253, 246, 234, 0.55);
}

.blessings-reveal {
  opacity: 0;
  transform: translateY(26px) scale(0.965);
  filter: blur(8px);
  transition:
    opacity 1.1s ease var(--blessings-delay, 0ms),
    transform 1.25s var(--ease-out) var(--blessings-delay, 0ms),
    filter 1.1s ease var(--blessings-delay, 0ms);
}
.blessings-screen.is-visible .blessings-reveal {
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: blur(0);
}

.blessings-kicker {
  margin: 0 0 10px;
  color: var(--gold-deep);
  font-family: var(--font-label);
  font-size: clamp(11px, 3vw, 14px);
  letter-spacing: 0.32em;
  text-indent: 0.32em;
  text-transform: uppercase;
}
/* same calligraphy as the couple's names in the hero (--font-hero, 700) —
   "Love & Blessings", "RSVP" and "Forever" are all set in it, so the four
   display moments on the page read as one hand. Tangerine sits much smaller
   on its em than Pinyon did, so every size here is scaled up to match. */
.blessings-heading {
  margin: 0;
  color: var(--maroon-deep);
  font-family: var(--font-hero);
  font-weight: 700;
  font-size: clamp(3rem, 13.5vw, 4.4rem);
  line-height: 0.95;
}
/* the heading is Tangerine 700; the ampersand drops to the shared 400 weight */
.blessings-amp { font-size: 1.05em; }

.blessings-divider {
  position: relative;
  width: clamp(70px, 22vw, 120px);
  height: 1px;
  margin: clamp(12px, 2vh, 18px) auto clamp(18px, 2.8vh, 26px);
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
}
.blessings-divider::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 6px;
  height: 6px;
  background: var(--gold);
  transform: translate(-50%, -50%) rotate(45deg);
}

.blessings-group { width: 100%; margin: 0 0 clamp(14px, 2.4vh, 22px); }
.blessings-group:last-child { margin-bottom: 0; }

.blessings-relation {
  margin: 0 0 6px;
  color: var(--rose-deep);
  font-family: var(--font-caps);
  font-size: clamp(10.5px, 2.7vw, 12.5px);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-transform: uppercase;
}
.blessings-names {
  max-width: 30em;
  margin: 0 auto;
  color: var(--inv-brown);
  font-family: var(--font-display);
  font-size: clamp(0.88rem, 3.6vw, 1.04rem);
  font-weight: 600;
  line-height: 1.5;
}
.blessings-names .bl-sep {
  margin: 0 0.45em;
  color: var(--gold-deep);
  font-weight: 400;
  opacity: 0.72;
}
/* obvious, easy to find — swap these out when the real names arrive */
.blessings-names .bl-placeholder {
  font-style: italic;
  font-weight: 500;
  opacity: 0.5;
}


/* ============================================================
   RSVP  —  contact card (WhatsApp + Call)
   Structure follows arpit-weds-gunjan; the palette is this card's own.
   This section is the bridge between two different palettes, so it is pinned
   at BOTH ends: it starts on --cream-soft, where Love & Blessings finishes,
   and lands on #ece8cf, sampled off the top edge of the countdown's painted
   sage frame (bg.webp) as it appears after its cover-crop. It used to end on
   --blush, a warm pink — against the sage frame below that read as a hard
   seam, which is what made the countdown look dropped in from another card.
   If either neighbour's palette changes, re-sample and re-pin both stops.
   ============================================================ */
.rsvp-screen {
  position: relative;
  width: 100%;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(180deg,
    var(--cream-soft) 0%,
    #f5f1de 54%,
    #ece8cf 100%);
  color: var(--maroon-deep);
}
.rsvp-inner {
  position: relative;
  z-index: 1;
  width: min(88%, 400px);
  margin: 0 auto;
  padding: clamp(58px, 9vh, 96px) 0 clamp(58px, 9vh, 96px);
  text-align: center;
}
.rsvp-title {
  margin: 0 0 12px;
  color: var(--maroon-deep);
  font-family: var(--font-hero);
  font-size: clamp(3.8rem, 16vw, 5.4rem);
  font-weight: 700;
  line-height: 0.9;
  text-shadow: 0 2px 16px rgba(253, 246, 234, 0.7);
  transform-origin: center bottom;
}
.rsvp-sub {
  margin: 0 0 clamp(26px, 4vh, 40px);
  color: var(--inv-sepia);
  font-family: var(--font-display);
  font-size: clamp(0.98rem, 4.1vw, 1.14rem);
  font-style: italic;
  font-weight: 500;
  line-height: 1.6;
}
.rsvp-contacts { display: grid; gap: 10px; text-align: left; }
/* square corners — the house rule; the gold hairline is the whole frame */
.rsvp-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border: 1px solid rgba(196, 154, 84, 0.55);
  background: rgba(253, 246, 234, 0.72);
  box-shadow: 0 10px 26px -14px rgba(90, 45, 30, 0.4);
}
.rsvp-info { display: grid; gap: 3px; flex: 1; min-width: 0; }
.rsvp-name {
  font-family: var(--font-caps);
  font-size: clamp(0.8rem, 3.2vw, 0.9rem);
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--inv-brown);
}
.rsvp-phone {
  font-family: var(--font-caps);
  font-size: clamp(0.9rem, 3.7vw, 1.02rem);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--maroon-deep);
}
/* a caps label, so the flourish is sized up to sit level with the capitals */
.rsvp-amp { font-size: 1.7em; line-height: 0; vertical-align: -0.1em; }
.rsvp-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
/* the two action buttons are the one place a circle is right — they read as
   phone affordances, not as decoration */
.rsvp-btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  flex-shrink: 0;
  transition: transform 220ms var(--ease-out), box-shadow 220ms ease, background 220ms ease;
}
.rsvp-btn:active { transform: scale(0.88); }
.rsvp-btn:hover, .rsvp-btn:focus-visible { transform: translateY(-2px); outline: none; }
.rsvp-btn--wa {
  background: #3f7a45;
  color: #fff;
  box-shadow: 0 4px 14px rgba(63, 122, 69, 0.4), 0 0 0 1px rgba(63, 122, 69, 0.22);
}
.rsvp-btn--wa:hover, .rsvp-btn--wa:focus-visible {
  background: #4a8c50;
  box-shadow: 0 6px 20px rgba(63, 122, 69, 0.54), 0 0 0 1px rgba(63, 122, 69, 0.34);
}
.rsvp-btn--call {
  background: #a83d5b;
  color: #fff;
  box-shadow: 0 4px 14px rgba(168, 61, 91, 0.4), 0 0 0 1px rgba(168, 61, 91, 0.22);
}
.rsvp-btn--call:hover, .rsvp-btn--call:focus-visible {
  background: #bd4869;
  box-shadow: 0 6px 20px rgba(168, 61, 91, 0.54), 0 0 0 1px rgba(168, 61, 91, 0.34);
}

.rsvp-line { opacity: 0; filter: blur(12px); }
.rsvp-contacts .rsvp-card {
  transform: translateX(36px);
  transition:
    opacity 1000ms var(--ease-out),
    transform 1000ms var(--ease-out),
    filter 1000ms var(--ease-out);
}
.rsvp-line:not(.rsvp-card) {
  transform: translateY(32px);
  transition:
    opacity 1200ms var(--ease-out),
    transform 1200ms var(--ease-out),
    filter 1000ms var(--ease-out);
}
.rsvp-screen.is-revealed .rsvp-line { opacity: 1; filter: blur(0); }
.rsvp-screen.is-revealed .rsvp-line:not(.rsvp-card) { transform: translateY(0); }
.rsvp-screen.is-revealed .rsvp-contacts .rsvp-card { transform: translateX(0); }
.rsvp-screen.is-revealed .rsvp-title { animation: rsvpTitleIn 1.5s var(--ease-out) 80ms both; }
.rsvp-screen.is-revealed .rsvp-sub               { transition-delay: 280ms; }
.rsvp-screen.is-revealed .rsvp-card:nth-child(1) { transition-delay: 420ms; }
.rsvp-screen.is-revealed .rsvp-card:nth-child(2) { transition-delay: 530ms; }
.rsvp-screen.is-revealed .rsvp-card:nth-child(3) { transition-delay: 640ms; }
@keyframes rsvpTitleIn {
  from { opacity: 0; transform: scale(0.68) translateY(28px); filter: blur(22px); }
  40%  { opacity: 1; filter: blur(0); }
  to   { opacity: 1; transform: scale(1) translateY(0); filter: blur(0); }
}


/* ============================================================
   COUNTDOWN + FOOTER  (structure from arpit-weds-gunjan)
   Live timer to the Sumuhurtam. The number cards are drawn in CSS —
   an ivory panel, a gold hairline and the same rotated diamond already
   carried by .ev-rule / .events-divider / .blessings-divider — so the
   section needs no artwork of its own.
   ============================================================ */
.countdown-section {
  --cd-gold: #a9803a;
  --cd-gold-soft: #c49a54;
  --cd-ink: #5a3730;

  position: relative;
  width: 100%;
  min-height: 100svh;
  overflow: hidden;
  /* Sampled straight off bg.webp's own edges (top #ece8cf → bottom #e8e2c6),
     so this only ever shows as an exact continuation of the painted frame:
     behind its cover-crop, while it streams in, or if the file 404s. It is NOT
     the old blush wash — a warm pink field under sage-green art read as a seam. */
  background: linear-gradient(180deg, #ece8cf 0%, #f2eeda 48%, #e8e2c6 100%);
  color: var(--cd-ink);
}
.countdown-section::before,
.countdown-frame,
.countdown-bg,
.countdown-particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* ── the painted frame ──
   Same treatment as .blessings-card: the portrait 941×1672 panel covers the
   WHOLE section (not a fixed 100svh), so the footer below the countdown grid
   still sits on art rather than on a bare band. object-fit:cover keeps the
   frame's proportions and clips the outer margins evenly, exactly as the
   invitation and Love & Blessings art do.
   z-index 0 and first in the tree, so it paints OVER the gold speck dusting
   in ::before — which is deliberate: the specks would read as grain on a
   watercolour wash, but they remain as the texture if the image ever fails
   (the onerror handler hides this layer). */
.countdown-frame { z-index: 0; overflow: hidden; }
.countdown-frame-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.35s ease, transform 2.1s var(--ease-out);
  scale: 1.02;
}
.countdown-section.is-visible .countdown-frame-img { opacity: 1; scale: 1; }

/* a faint dusting of gold specks — the same trick as the reference, in gold */
.countdown-section::before {
  content: "";
  z-index: 0;
  background:
    radial-gradient(circle at 20% 18%, rgba(196, 154, 84, 0.10) 0 1px, transparent 1.5px),
    radial-gradient(circle at 78% 30%, rgba(168, 61, 91, 0.07) 0 1px, transparent 1.5px),
    radial-gradient(circle at 46% 76%, rgba(127, 43, 41, 0.06) 0 1px, transparent 1.5px);
  background-size: 24px 24px, 31px 31px, 36px 36px;
  opacity: 0.55;
}
.countdown-bg {
  z-index: 1;
  background:
    linear-gradient(115deg, rgba(255, 255, 255, 0.2), transparent 28%, rgba(196, 154, 84, 0.05) 54%, transparent 78%);
  opacity: 0;
  transition: opacity 1.2s ease;
}
.countdown-section.is-visible .countdown-bg { opacity: 1; }

.countdown-particles { z-index: 2; overflow: hidden; }
.countdown-particles span {
  position: absolute;
  width: var(--dust-size, 5px);
  height: var(--dust-size, 5px);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 240, 205, 0.96), rgba(196, 154, 84, 0.5) 55%, transparent 74%);
  box-shadow: 0 0 10px rgba(196, 154, 84, 0.42);
  opacity: 0;
  animation: countdownDust var(--dust-duration, 9s) ease-in-out var(--dust-delay, 0s) infinite;
}
.countdown-particles span:nth-child(1) { --dust-size: 5px; --dust-duration: 8.5s; --dust-delay: -1s; left: 13%; top: 24%; }
.countdown-particles span:nth-child(2) { --dust-size: 4px; --dust-duration: 10s;  --dust-delay: -5s; left: 78%; top: 18%; }
.countdown-particles span:nth-child(3) { --dust-size: 6px; --dust-duration: 11s;  --dust-delay: -3s; left: 86%; top: 55%; }
.countdown-particles span:nth-child(4) { --dust-size: 4px; --dust-duration: 9.5s; --dust-delay: -7s; left: 20%; top: 66%; }
.countdown-particles span:nth-child(5) { --dust-size: 5px; --dust-duration: 12s;  --dust-delay: -2s; left: 62%; top: 78%; }
.countdown-particles span:nth-child(6) { --dust-size: 3px; --dust-duration: 8s;   --dust-delay: -4s; left: 42%; top: 13%; }
@keyframes countdownDust {
  0%, 100% { opacity: 0;    transform: translateY(0)     scale(0.8); }
  16%      { opacity: 0.85; }
  50%      { opacity: 0.95; transform: translateY(-26px) scale(1.05); }
  84%      { opacity: 0.6; }
}

/* ── watercolour butterflies — 6-frame flap sprites flying the full section ──
   Each sprite sheet is six frames laid out horizontally, so the "flap" is a
   background-position walk with steps(6) and the flight path is a separate,
   much slower animation on the same element. --bratio is the per-FRAME aspect
   (sheet height ÷ (sheet width ÷ 6)), which is what keeps the wings from
   stretching. Paused until the section is in view, so nothing animates
   off-screen. */
.countdown-butterflies {
  position: absolute;
  inset: 0;
  z-index: 6;
  overflow: hidden;
  pointer-events: none;
}
.cd-butterfly {
  position: absolute;
  left: 0; top: 0;
  width: var(--bw, 44px);
  height: calc(var(--bw, 44px) * var(--bratio, 1.177));
  background-repeat: no-repeat;
  background-size: 600% 100%;
  background-position: 0% 0;
  opacity: 0;
  filter: drop-shadow(0 5px 7px rgba(90, 45, 30, 0.28)) drop-shadow(0 0 1.5px rgba(90, 45, 30, 0.26));
  will-change: transform, opacity, background-position, left, top;
}
.cd-butterfly--one {
  --bw: clamp(34px, 11vw, 60px);
  --bratio: 1.177;
  --bop: 0.95;
  background-image: url('assets/countdown/butterfly.webp');
  animation:
    cdFlap 900ms steps(6, jump-none) infinite,
    cdFlyOne 21s linear -3s infinite;
}
.cd-butterfly--two {
  --bw: clamp(28px, 9vw, 50px);
  --bratio: 2;
  --bop: 0.86;
  background-image: url('assets/countdown/butterfly_2.webp');
  animation:
    cdFlap 1080ms steps(6, jump-none) infinite,
    cdFlyTwo 26s linear -11s infinite;
}
.countdown-section:not(.is-visible) .cd-butterfly { animation-play-state: paused; }

@keyframes cdFlap { to { background-position: 100% 0; } }

@keyframes cdFlyOne {
  0%   { left: -12%; top: 84%; transform: translateY(0)    rotate(-4deg); opacity: 0; }
  7%   { opacity: var(--bop, 0.9); }
  24%  { left: 22%;  top: 62%; transform: translateY(-7px) rotate(5deg); }
  42%  { left: 44%;  top: 46%; transform: translateY(6px)  rotate(-4deg); }
  60%  { left: 63%;  top: 31%; transform: translateY(-8px) rotate(4deg); }
  78%  { left: 83%;  top: 19%; transform: translateY(5px)  rotate(-3deg); }
  93%  { opacity: var(--bop, 0.9); }
  100% { left: 113%; top: 9%;  transform: translateY(-4px) rotate(3deg); opacity: 0; }
}
@keyframes cdFlyTwo {
  0%   { left: 113%; top: 13%; transform: translateY(0)    rotate(4deg); opacity: 0; }
  7%   { opacity: var(--bop, 0.85); }
  24%  { left: 80%;  top: 29%; transform: translateY(8px)  rotate(-4deg); }
  42%  { left: 58%;  top: 45%; transform: translateY(-5px) rotate(3deg); }
  60%  { left: 37%;  top: 60%; transform: translateY(9px)  rotate(-4deg); }
  78%  { left: 17%;  top: 75%; transform: translateY(-4px) rotate(3deg); }
  93%  { opacity: var(--bop, 0.85); }
  100% { left: -12%; top: 87%; transform: translateY(5px)  rotate(-2deg); opacity: 0; }
}

.countdown-content {
  position: relative;
  z-index: 4;
  min-height: 100svh;
  width: min(90vw, 380px);
  margin: 0 auto;
  /* The top pad is deliberately shallow: this content runs a little taller than
     100svh, so .wedding-footer's `margin-top: auto` yields NO free space (an
     auto margin only distributes slack that exists). Lifting the eyebrow /
     "Forever" / grid group up here is what buys the room that the footer's own
     padding-top then spends as breathing space above the monogram. */
  padding:
    calc(env(safe-area-inset-top, 0px) + clamp(28px, 4.4vh, 50px))
    0
    calc(env(safe-area-inset-bottom, 0px) + clamp(28px, 4.6vh, 44px));
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.countdown-reveal {
  opacity: 0;
  transform: translateY(16px);
  filter: blur(5px);
  transition:
    opacity 0.95s ease var(--countdown-delay, 0ms),
    transform 1.05s var(--ease-out) var(--countdown-delay, 0ms),
    filter 0.95s ease var(--countdown-delay, 0ms);
}
.countdown-section.is-visible .countdown-reveal { opacity: 1; transform: translateY(0); filter: blur(0); }

.countdown-eyebrow {
  margin: 0 0 clamp(6px, 1.1vh, 10px);
  color: var(--cd-gold);
  font-family: var(--font-label);
  font-size: clamp(12px, 3.2vw, 15px);
  font-weight: 400;
  letter-spacing: 0.28em;
  text-transform: uppercase;
}
.countdown-eyebrow span.cd-space { width: 0.6em; }
.countdown-eyebrow span {
  display: inline-block;
  opacity: 0;
  transform: translateY(10px);
  filter: blur(3px);
  transition:
    opacity 0.62s ease calc(var(--countdown-delay, 0ms) + var(--letter-delay, 0ms)),
    transform 0.72s var(--ease-out) calc(var(--countdown-delay, 0ms) + var(--letter-delay, 0ms)),
    filter 0.62s ease calc(var(--countdown-delay, 0ms) + var(--letter-delay, 0ms));
}
.countdown-section.is-visible .countdown-eyebrow span { opacity: 1; transform: translateY(0); filter: blur(0); }

/* the word wipes on left-to-right, as if written */
.countdown-names {
  position: relative;
  margin: 0;
  color: var(--maroon-deep);
  font-family: var(--font-hero);
  font-size: clamp(74px, 20vw, 106px);
  line-height: 0.9;
  font-weight: 700;
  text-shadow: 0 2px 16px rgba(253, 246, 234, 0.7);
  clip-path: inset(0 100% 0 0);
}
.countdown-names::before {
  content: "";
  position: absolute;
  inset: -28% -18%;
  z-index: -1;
  background: radial-gradient(ellipse, rgba(196, 154, 84, 0.24), transparent 70%);
  animation: countdownNameGlow 4.8s ease-in-out infinite;
}
@keyframes countdownNameGlow {
  0%, 100% { opacity: 0.55; transform: scale(0.95); }
  50%      { opacity: 1;    transform: scale(1.05); }
}
.countdown-section.is-visible .countdown-names {
  animation: countdownInkReveal 1.55s var(--ease-out) 460ms forwards;
}
@keyframes countdownInkReveal {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

.countdown-divider {
  position: relative;
  width: clamp(86px, 24vw, 126px);
  height: clamp(18px, 3vh, 24px);
  margin: clamp(12px, 2vh, 18px) auto clamp(14px, 2.4vh, 22px);
  background:
    radial-gradient(circle at 50% 50%, rgba(196, 154, 84, 0.7) 0 2.4px, transparent 2.9px),
    radial-gradient(circle at 43% 50%, rgba(196, 154, 84, 0.4) 0 1.5px, transparent 1.9px),
    radial-gradient(circle at 57% 50%, rgba(196, 154, 84, 0.4) 0 1.5px, transparent 1.9px);
}
.countdown-divider::before,
.countdown-divider::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 0;
  height: 1px;
  background: linear-gradient(to right, transparent, rgba(196, 154, 84, 0.7));
  transition: width 0.95s var(--ease-out) var(--countdown-delay, 0ms);
}
.countdown-divider::before { right: 50%; }
.countdown-divider::after  { left: 50%; transform: scaleX(-1); }
.countdown-section.is-visible .countdown-divider::before,
.countdown-section.is-visible .countdown-divider::after { width: 44%; }

.countdown-grid {
  width: min(78vw, 320px);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(10px, 2.4vw, 14px);
  margin-bottom: clamp(18px, 3vh, 26px);
}
/* the gold cusped cartouche (block.webp) is the frame — no border or fill of
   our own, so the art's transparent corners let the blush wash through */
.countdown-card {
  position: relative;
  aspect-ratio: 0.75;
  display: grid;
  place-items: center;
  isolation: isolate;
  filter: drop-shadow(0 12px 18px rgba(90, 45, 30, 0.16));
  transform-origin: center;
}
.countdown-card-frame {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0.96;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
.countdown-card-content {
  position: relative;
  z-index: 1;
  display: flex;
  min-width: 72%;
  min-height: 58%;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  transform: translateY(1px);
  text-shadow: 0 1px 10px rgba(253, 246, 234, 0.62);
}
.countdown-number {
  color: var(--maroon-deep);
  font-family: var(--font-caps);
  font-size: clamp(31px, 9.5vw, 46px);
  line-height: 0.92;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: transform 0.35s ease, color 0.35s ease, text-shadow 0.35s ease;
}
.countdown-label {
  margin-top: clamp(7px, 1.4vh, 11px);
  color: var(--cd-gold);
  font-family: var(--font-label);
  font-size: clamp(9.5px, 2.6vw, 12px);
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-transform: uppercase;
}
/* each tick lifts its own number — the seconds card beats once a second */
.countdown-card.is-changing .countdown-number {
  color: var(--gold-deep);
  transform: translateY(-3px) scale(1.04);
  text-shadow: 0 0 16px rgba(224, 181, 106, 0.55);
}

.wedding-footer {
  margin-top: auto;
  /* the real gap between the countdown grid and the monogram — `margin-top:
     auto` above cannot supply it (see .countdown-content), so it is paid for
     here out of the shallower top pad */
  padding-top: clamp(26px, 4.6vh, 46px);
  width: 100%;
  color: var(--inv-sepia);
  font-family: var(--font-display);
}
.wedding-footer p { margin: 0; }

/* ── the crest closing the page, above the couple's names ──
   MEASURED off the alpha channel of logo.webp (1254×1254):
     canvas   SQUARE, 1:1 — so canvas height = width, and a padding of P% of
              the canvas is P/100 × width. That matters because percentage
              margins resolve against the container's WIDTH, so a square
              canvas is the one case where the height-derived figures track.
     ink      x 7.18–92.34%  ·  y 7.18–97.45%
     ink is 85.2% of the canvas width (the old wordmark's was 49%), so this
     rule needs a much SMALLER --fl-w than before to draw a slightly LARGER
     mark: at 46vw the visible crest lands ~163 × 173px.
     ink centre x 49.76% — dead centre, within a quarter of a percent. The
     `right:` nudge that used to re-centre the old off-centre wordmark is gone;
     re-adding one would push this crest off true.

   Padding to reclaim, in width units:
     top    7.18% → 0.0718 × width, taken IN FULL, so the air above the crest
            is exactly .wedding-footer's padding-top and nothing else
     bottom 2.55% → 0.0255 × width ≈ 5px, and NOT clawed back. This is the
            reverse of the old art: there is less built-in padding than the
            names need, so the margin below is POSITIVE — it adds ~11px to the
            5px already there for a ~16px gap. Making it negative (as the old
            3:2 numbers did) is what would drag the names into the crest.
   --fl-lift raises the crest without moving the names: the same length is
   taken off the top margin and handed to the bottom one, so the box rises but
   its bottom edge — which the names sit under — stays put. It trades POSITION,
   not padding, so it works no matter how tight the artwork's own margins are,
   and it costs no section height (the two margins cancel).
   Why it is needed: left at zero the ladder ran 85px of air above the crest
   and 17px below it, so the mark drifted away from the grid it closes and
   crowded the name stack under it. At 0.13 the gaps read 59px / 43px.
   `position: relative` must stay — .logo-shine is absolutely positioned
   against this box. It must not become a transform: .countdown-reveal
   animates transform on this same element. */
.footer-logo {
  --fl-w: clamp(168px, 46vw, 212px);
  --fl-lift: calc(var(--fl-w) * 0.13);
  position: relative;
  display: block;
  width: var(--fl-w);
  /* auto side margins are REQUIRED: this is a block box with an explicit
     width, and the text-align:center it inherits from .countdown-content only
     centres inline content — without these it sits flush left. */
  margin-left: auto;
  margin-right: auto;
  margin-top: calc(var(--fl-w) * -0.0718 - var(--fl-lift));
  margin-bottom: calc(var(--fl-w) * 0.058 + var(--fl-lift));
  /* Two shadows, not one: the tight 1px pass gives the crest's fine gold
     linework — the ring, the dotted arc, the leaf sprays — a contour, and the
     soft pass lifts the whole mark off the page. The painted frame behind it
     is pale cream, close enough in value to the gold (and to the crest's blush
     flowers) that without the tight pass the mark thins into a watermark. */
  filter:
    drop-shadow(0 1px 1px rgba(122, 88, 38, 0.34))
    drop-shadow(0 6px 14px rgba(150, 110, 54, 0.26));
}
.footer-logo img { display: block; width: 100%; height: auto; }
.countdown-section.is-visible .footer-logo .logo-shine {
  animation: logoShine 4.4s ease-in-out 2.2s infinite;
}

.footer-names {
  color: var(--maroon-deep);
  font-family: var(--font-hero);
  font-size: clamp(34px, 10vw, 52px);
  font-weight: 700;
  line-height: 1;
}
.footer-date,
.footer-venue {
  font-size: clamp(11.5px, 3vw, 14px);
  line-height: 1.34;
  letter-spacing: 0.12em;
}
.footer-date {
  margin-top: clamp(11px, 1.9vh, 16px) !important;
  color: var(--gold-deep);
  font-family: var(--font-caps);
  font-weight: 600;
  text-transform: uppercase;
  text-wrap: balance;
}
.footer-date sup { font-size: 0.6em; vertical-align: super; letter-spacing: 0; }
.footer-venue { margin-top: 8px !important; color: var(--inv-sepia); }
/* the couple's hashtag — the loudest line in the footer after their names.
   Cormorant, NOT the Cinzel used by the date above it: Cinzel is a caps-only
   face, so it would flatten "#HMForever" to "#HMFOREVER" and lose the casing
   the couple chose. */
.footer-hashtag {
  margin-top: clamp(17px, 2.8vh, 25px) !important;
  color: var(--rose-deep);
  font-family: var(--font-display);
  font-size: clamp(16px, 4.8vw, 21px);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-indent: 0.1em;
  text-shadow: 0 1px 10px rgba(253, 246, 234, 0.7);
}
.footer-credit {
  margin-top: clamp(18px, 2.9vh, 26px) !important;
  color: rgba(95, 60, 40, 0.8);
  font-size: clamp(11px, 3vw, 13px);
  letter-spacing: 0.08em;
}
.footer-credit a {
  color: var(--gold-deep);
  font-weight: 600;
  text-decoration: none;
  transition: color 0.25s ease, text-shadow 0.25s ease;
}
.footer-credit a:hover, .footer-credit a:focus-visible {
  color: #c08a2c;
  text-shadow: 0 0 12px rgba(224, 181, 106, 0.35);
}


/* ============================================================
   BACKGROUND MUSIC TOGGLE  (fixed bottom-right)
   ============================================================ */
.music-btn {
  position: fixed;
  right: clamp(14px, 4vw, 22px);
  bottom: clamp(14px, 4vw, 22px);
  z-index: 45;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(220, 180, 120, 0.7);
  border-radius: 999px;
  background: linear-gradient(180deg, #b3873c 0%, #7f2b29 100%);
  color: #fdf3df;
  cursor: pointer;
  box-shadow: 0 8px 22px rgba(90, 45, 30, 0.36), inset 0 0 0 1px rgba(253, 243, 223, 0.14);
  transition: transform 0.2s ease, box-shadow 0.25s ease, opacity 0.4s ease;
  animation: musicBtnIn 0.5s ease both;
}
.music-btn[hidden] { display: none; }
.music-btn:hover { transform: translateY(-2px); box-shadow: 0 12px 28px rgba(90, 45, 30, 0.46), inset 0 0 0 1px rgba(253, 243, 223, 0.14); }
.music-btn:active { transform: scale(0.95); }
@keyframes musicBtnIn {
  from { opacity: 0; transform: translateY(12px) scale(0.85); }
  to   { opacity: 1; transform: none; }
}
.music-disc {
  position: absolute;
  inset: 7px;
  border-radius: 999px;
  background: repeating-radial-gradient(circle at 50% 50%, rgba(253,243,223,0.14) 0 1.5px, transparent 1.5px 4px);
  opacity: 0.5;
  animation: musicSpin 6s linear infinite;
}
.music-btn.is-muted .music-disc { animation-play-state: paused; opacity: 0.28; }
@keyframes musicSpin { to { transform: rotate(360deg); } }
.music-ico { position: relative; width: 21px; height: 21px; }
.music-ico--off { display: none; }
.music-btn.is-muted .music-ico--on  { display: none; }
.music-btn.is-muted .music-ico--off { display: block; }


/* ============================================================
   REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .music-disc { animation: none !important; }
  /* the monogram still appears in the bloom, it just does not swell or gleam */
  .logo-shine { animation: none !important; display: none; }
  .dissolve-mark { transform: none; }
  .ivory-dissolve.is-active .dissolve-mark {
    animation: none !important;
    opacity: 0.95;
  }
  /* the mark holds still here, so the long 3800ms bloom would read as a dead
     pause rather than a moment — this path keeps its original shorter clock.
     script.js matches it (BLOOM_REDUCED_MS) when it tears the overlay down. */
  .ivory-dissolve.is-active { animation-duration: 2000ms !important; }
  .invite-ganesha, .ganesha-glow, .ganesha-shine { animation: none !important; }
  .hero-screen.is-animated .couple-name .cn-first,
  .hero-screen.is-animated .couple-name .cn-amp,
  .hero-screen.is-animated .couple-name .cn-second,
  .hero-screen.is-animated .wedding-date,
  .hero-screen.is-animated .wedding-venue { animation: none; opacity: 1; filter: none; transform: none; }
  .scroll-arrows   { animation: none !important; transform: none; }
  /* no drift, no gleam — and the stroke must be restored by hand, since the
     colour otherwise only exists inside the cancelled keyframes */
  .scroll-arrows i { animation: none !important; opacity: 0.7; border-color: var(--maroon-deep); }
  .scroll-cue-label::after { display: none; }
  .invite-ganesha, .invite-screen.is-revealed .invite-inner .reveal-line { transition: opacity 600ms ease; transform: none; filter: none; }
  .ganesha-glow, .ganesha-shine { animation: none !important; }
  .invite-screen.is-revealed .ganesha-glow { opacity: 0.7; }

  /* events — layers hold still; the type still fades in, without drift */
  /* layers hold still — centring is layout, so nothing to restore here */
  .ev-subject, .ev-fg, .ev-hang, .ev-shine { animation: none !important; }
  .ev-subject, .ev-hang, .ev-fg { transform: none; }
  /* the band is normally seated 9px low to absorb its float — with no float,
     it sits exactly flush with the bottom of the card */
  .ev-fg { bottom: var(--fg-b, 0%); }
  .ev-shine   { display: none; }
  .ev-pin { animation: none !important; }
  .ev-card { transition: opacity 600ms ease; transform: none; }
  .ev-card.is-in .ev-line,
  .events-screen.is-revealed .events-kicker,
  .events-screen.is-revealed .events-title,
  .events-screen.is-revealed .events-divider { transition: opacity 600ms ease; transform: none; filter: none; }

  /* blessings — no petals at all, and the type simply fades in */
  .blessings-petals { display: none; }
  .blessings-bg { transition: opacity 600ms ease; scale: 1; }
  .blessings-screen.is-visible .blessings-reveal { transition: opacity 600ms ease; }
  .blessings-reveal { transform: none; filter: none; }

  /* rsvp — the cards simply fade in where they sit */
  .rsvp-line, .rsvp-contacts .rsvp-card, .rsvp-line:not(.rsvp-card) {
    transform: none;
    filter: none;
    transition: opacity 600ms ease;
  }
  .rsvp-screen.is-revealed .rsvp-title { animation: none; opacity: 1; transform: none; filter: none; }

  /* countdown — no dust, no butterflies, no glow, no ink wipe; numbers tick.
     The painted frame still fades up, it just does not drift in (same as
     .blessings-bg above). */
  .countdown-frame-img { transition: opacity 600ms ease; scale: 1; }
  .countdown-particles { display: none; }
  .countdown-butterflies { display: none; }
  .countdown-names {
    clip-path: none;
    animation: none !important;
  }
  .countdown-names::before { animation: none !important; opacity: 0.6; transform: none; }
  .countdown-section.is-visible .countdown-names { animation: none !important; }
  .countdown-reveal,
  .countdown-eyebrow span {
    transform: none;
    filter: none;
    transition: opacity 600ms ease;
  }
  .countdown-card.is-changing .countdown-number { transform: none; text-shadow: none; }
}
