/* =========================================================
   ELEGANT tier — reference build

   Everything Classic has, plus the four unlocks:
     1. falling flowers + a hero entrance animation
     2. a six-picture gallery
     3. the pre-wedding film
     4. the calendar SUBSCRIBE feed and the WhatsApp share card

   Palette is shared with Classic — same door2 artwork, same product. The
   difference a bride sees in a 15-second demo is motion and content, not a
   different colour scheme.
   ========================================================= */
:root {
  --turq:      #20b4b1;
  --turq-deep: #14807f;
  --teal:      #3e8377;
  --teal-ink:  #14403a;   /* small text over the hero — see Classic's note */
  --rose:      #b34766;
  --rose-deep: #8d3350;
  --terra:     #ae8a71;
  --sand:      #eed1b0;
  --cream:     #fbf6ea;
  --cream-2:   #f5ece0;
  --ink:       #3a2b26;
  --ink-soft:  #6d5a52;

  --serif:  "Cormorant Garamond", Georgia, serif;
  --display:"Marcellus", Georgia, serif;
  --script: "Great Vibes", cursive;

  --maxw: 1040px;
  --ease: cubic-bezier(.22,.61,.36,1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }

body {
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.65;
  color: var(--ink);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;   /* petals drift sideways; never let them add a scrollbar */
}

/* width/height attributes stop images collapsing before they load, but they
   map to presentational height declarations that silently override
   aspect-ratio wherever author CSS leaves height unset. The two go together. */
img { max-width: 100%; height: auto; display: block; }

/* ---------- SHARED ---------- */
.section { padding: clamp(56px, 8vw, 96px) 22px; position: relative; }
.section--tint { background: var(--cream-2); }

.script {
  font-family: var(--script);
  font-size: clamp(30px, 4.4vw, 42px);
  color: var(--rose);
  text-align: center;
  line-height: 1.1;
}
/* `margin: … auto …`, never `… 0 …` — the shorthand cancels inherited auto
   centring and the heading silently sits flush left (Issue 15). */
.section__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(24px, 3.4vw, 34px);
  letter-spacing: 2.5px;
  text-transform: uppercase;
  text-align: center;
  color: var(--ink);
  max-width: var(--maxw);
  margin: 6px auto 0;
}
.rule {
  width: 78px; height: 1px;
  background: var(--turq);
  margin: 20px auto 36px;
  position: relative;
}
.rule::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 7px; height: 7px;
  transform: translate(-50%, -50%) rotate(45deg);
  background: var(--rose);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--display);
  font-size: 12px;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--cream);
  background: var(--turq-deep);
  border: 1px solid var(--turq-deep);
  border-radius: 2px;
  padding: 13px 28px;
  cursor: pointer;
  transition: background .25s, border-color .25s, color .25s;
}
.btn:hover { background: var(--teal); border-color: var(--teal); }
.btn:focus-visible { outline: 2px solid var(--rose); outline-offset: 3px; }
.btn--wa { background: #25d366; border-color: #25d366; color: #06301a; }
.btn--wa:hover { background: #1eb257; border-color: #1eb257; color: #fff; }
.btn--ghost { background: transparent; color: var(--turq-deep); border-color: rgba(20,128,127,.5); }
.btn--ghost:hover { background: var(--turq-deep); color: var(--cream); }
.ico { flex-shrink: 0; }

.link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--display);
  font-size: 11px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--turq-deep);
  text-decoration: none;
  border-bottom: 1px solid rgba(20,128,127,.35);
  padding-bottom: 2px;
}
.link:hover { color: var(--rose-deep); border-bottom-color: var(--rose); }
.link:focus-visible { outline: 2px solid var(--rose); outline-offset: 3px; }

[data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}
[data-reveal].is-visible { opacity: 1; transform: none; }

/* ---------- FALLING FLOWERS ----------
   The Elegant fence, and the cheapest thing on the page: CSS shapes, no
   images, no payload. Colours come from the bougainvillea in the door
   artwork so the two read as one scene.

   pointer-events:none matters — an invisible full-height overlay would
   otherwise swallow every click on the page underneath it. */
.petals {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  overflow: hidden;
}
.petal {
  position: absolute;
  top: -8vh;
  /* a bougainvillea bract: papery, wider than tall, one pointed corner */
  border-radius: 60% 8% 60% 8%;
  opacity: 0;
  will-change: transform;
  animation-name: fall;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.petal--a { background: rgba(214,72,130,.72); }
.petal--b { background: rgba(179,71,102,.62); }
.petal--c { background: rgba(232,140,175,.66); }
.petal--d { background: rgba(238,209,176,.58); }

@keyframes fall {
  0%   { opacity: 0;   transform: translate3d(0, 0, 0) rotate(0deg); }
  8%   { opacity: .95; }
  35%  { transform: translate3d(26px, 34vh, 0) rotate(150deg); }
  65%  { transform: translate3d(-18px, 68vh, 0) rotate(280deg); }
  92%  { opacity: .8; }
  100% { opacity: 0;   transform: translate3d(14px, 112vh, 0) rotate(420deg); }
}

/* Motion is the tier's selling point, but never at the cost of someone who
   has asked the OS to stop it. The petals are removed outright rather than
   slowed — js/main.js does not create them either. */
@media (prefers-reduced-motion: reduce) {
  .petals { display: none; }
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
  .hero__eyebrow, .hero__names, .hero__date, .hero__photo { animation: none !important; opacity: 1 !important; transform: none !important; }
}

/* ---------- HERO ---------- */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(40px, 7vh, 80px) 22px clamp(56px, 9vh, 92px);
  overflow: hidden;
  background: var(--cream-2);
}
.hero__bg {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 35%;
  animation: heroZoom 14s var(--ease) forwards;
}
@keyframes heroZoom { from { transform: scale(1.06); } to { transform: scale(1); } }

/* Tuned against measured contrast, not by eye — the same wash the Classic
   build arrived at after tools/check_hero_contrast.py failed it twice. It is
   stronger than this particular image needs, deliberately, so it still holds
   for whatever photograph a client swaps in. */
.hero__wash {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(251,246,234,.86) 0%, rgba(251,246,234,.52) 38%, rgba(251,246,234,.92) 100%),
    radial-gradient(ellipse at 50% 42%, rgba(251,246,234,.94) 0%, rgba(251,246,234,.88) 34%, transparent 72%);
}
.hero__inner { position: relative; z-index: 2; text-align: center; max-width: 640px; }

/* The entrance. Staggered, and `both` fill so nothing flashes before its
   turn. This is what Classic does not get. */
.hero__eyebrow, .hero__names, .hero__date, .hero__photo { animation: riseIn .9s var(--ease) both; }
.hero__eyebrow { animation-delay: .15s; }
.hero__names   { animation-delay: .35s; }
.hero__date    { animation-delay: .6s; }
.hero__photo   { animation-delay: .8s; }
@keyframes riseIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }

.hero__eyebrow {
  font-family: var(--display);
  font-size: clamp(10px, 1.5vw, 12px);
  letter-spacing: 4.5px;
  text-transform: uppercase;
  color: var(--teal-ink);
}
.hero__names {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(40px, 8vw, 74px);
  line-height: 1.05;
  color: var(--ink);
  margin: 12px 0 6px;
}
.hero__names span { font-family: var(--script); font-size: .62em; color: var(--rose); }
.hero__date {
  font-family: var(--display);
  font-size: clamp(11px, 1.7vw, 14px);
  letter-spacing: 4px;
  text-transform: uppercase;
  color: var(--ink);
}
.hero__photo {
  width: clamp(180px, 30vw, 236px);
  margin: clamp(22px, 4vh, 38px) auto 0;
  border-radius: 50% 50% 6px 6px / 32% 32% 6px 6px;
  overflow: hidden;
  border: 3px solid var(--cream);
  box-shadow: 0 18px 44px rgba(58,43,38,.24);
}
.hero__photo img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }

.hero__cue { position: absolute; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 2; }
.hero__cue span {
  display: block; width: 1px; height: 42px;
  background: linear-gradient(var(--teal-ink), transparent);
  animation: cue 2.2s ease-in-out infinite;
}
@keyframes cue { 50% { opacity: .25; transform: translateY(8px); } }

/* ---------- COUNTDOWN ---------- */
.count {
  background: var(--turq-deep);
  color: var(--cream);
  text-align: center;
  padding: clamp(38px, 6vw, 62px) 22px;
  position: relative;
  z-index: 2;
}
.count__grid {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(18px, 5vw, 58px);
  max-width: var(--maxw);
  margin: 0 auto;
}
.count__u { min-width: 68px; }
/* Below ~560px four units no longer fit on one line and wrap 3 + 1 with one
   stranded; an explicit 2x2 is deliberate rather than accidental. */
@media (max-width: 560px) {
  .count__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 22px 12px;
    max-width: 320px;
  }
  .count__u { min-width: 0; }
}
.count__u span {
  display: block;
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(32px, 6vw, 56px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.count__u small {
  display: block;
  font-family: var(--display);
  font-size: 10px;
  letter-spacing: 2.6px;
  text-transform: uppercase;
  opacity: .78;
  margin-top: 7px;
}
.count__note { font-style: italic; font-size: 17px; opacity: .85; margin-top: 22px; }

/* ---------- STORY ---------- */
.story__body { max-width: 620px; margin: 0 auto; text-align: center; }
.story__body p { margin-bottom: 16px; color: var(--ink-soft); }
.story__sign {
  font-family: var(--script);
  font-size: clamp(28px, 4.2vw, 38px);
  color: var(--rose);
  margin-top: 18px !important;
  line-height: 1.1;
}

/* ---------- GALLERY ----------
   Six pictures, shown large. No lightbox — that is the Signature upgrade,
   so these are sized to be worth looking at in place rather than acting as
   thumbnails that invite a click which does nothing. */
.gallery__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(12px, 1.8vw, 20px);
  max-width: var(--maxw);
  margin: 0 auto;
}
@media (max-width: 820px) { .gallery__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .gallery__grid { grid-template-columns: 1fr; } }
.gallery__grid figure {
  min-width: 0;   /* grid items default to min-width:auto and refuse to shrink */
  overflow: hidden;
  border: 1px solid rgba(174,138,113,.28);
  background: var(--cream);
}
.gallery__grid img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  transition: transform .6s var(--ease);
}
.gallery__grid figure:hover img { transform: scale(1.04); }

/* ---------- PRE-WEDDING FILM ---------- */
.film__frame {
  position: relative;
  max-width: 900px;
  margin: 0 auto;
  overflow: hidden;
  border: 1px solid rgba(174,138,113,.34);
  background: #0e2a28;
}
.film__frame img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.film__frame iframe,
.film__frame video { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; background: #0e2a28; }
.film__play {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 78px; height: 78px;
  border-radius: 50%;
  border: 1px solid var(--sand);
  background: rgba(20,128,127,.72);
  color: var(--cream);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background .25s, transform .25s var(--ease);
}
.film__play:hover { background: var(--turq-deep); transform: translate(-50%, -50%) scale(1.06); }
.film__play:focus-visible { outline: 2px solid var(--rose); outline-offset: 4px; }
.film__note {
  text-align: center;
  font-style: italic;
  color: var(--ink-soft);
  font-size: 16px;
  margin-top: 16px;
}
.film__note code {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 14px;
  font-style: normal;
  background: var(--cream-2);
  padding: 2px 6px;
}

/* ---------- EVENTS ---------- */
.events__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2.4vw, 26px);
  max-width: var(--maxw);
  margin: 0 auto;
}
@media (max-width: 860px) { .events__grid { grid-template-columns: 1fr; } }

.event {
  background: var(--cream);
  border: 1px solid rgba(174,138,113,.3);
  border-top: 3px solid var(--accent, var(--turq));
  padding: clamp(22px, 3vw, 30px);
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.event--mehendi { --accent: var(--turq); }
.event--sangeet { --accent: var(--rose); }
.event--wedding { --accent: var(--terra); }

.event__label {
  font-family: var(--display);
  font-size: 10px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--accent);
}
.event__name {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 600;
  font-size: clamp(24px, 3.2vw, 32px);
  line-height: 1.1;
  color: var(--accent);
  margin: 5px 0 8px;
}
.event__when {
  font-family: var(--display);
  font-size: 11.5px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink);
}
.event__desc { margin-top: 10px; color: var(--ink-soft); font-size: 17px; }
.event__dress {
  margin-top: 10px;
  font-size: 15px;
  font-style: italic;
  color: var(--ink-soft);
  padding-top: 10px;
  border-top: 1px dashed rgba(174,138,113,.42);
}
.event__actions {
  margin-top: auto;
  padding-top: 18px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
}

/* ---------- CALENDAR MENUS ---------- */
.cal { position: relative; }
.cal__btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--display);
  font-size: 11px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--cream);
  background: var(--accent, var(--turq));
  border-radius: 2px;
  padding: 9px 15px;
  cursor: pointer;
  list-style: none;
}
.cal__btn::-webkit-details-marker { display: none; }
.cal__btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.cal[open] .cal__btn { filter: brightness(.9); }
.cal__menu {
  position: absolute;
  z-index: 5;
  top: calc(100% + 6px);
  left: 0;
  min-width: 190px;
  background: var(--cream);
  border: 1px solid rgba(174,138,113,.42);
  box-shadow: 0 12px 30px rgba(58,43,38,.16);
}
.cal__opt {
  display: block;
  padding: 11px 15px;
  font-size: 16px;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid rgba(174,138,113,.22);
}
.cal__opt:last-child { border-bottom: 0; }
.cal__opt:hover { background: var(--cream-2); color: var(--turq-deep); }
.cal__opt:focus-visible { outline: 2px solid var(--rose); outline-offset: -2px; }
/* de-emphasised on purpose: a download cannot auto-update, unlike the two above */
.cal__opt--alt { font-size: 14px; color: var(--ink-soft); font-style: italic; }

/* the subscribe menu, centred under the grid */
.events__all { text-align: center; margin-top: clamp(30px, 4vw, 44px); }
.cal--lg { display: inline-block; text-align: left; }
.cal__btn--lg {
  background: var(--turq-deep);
  font-size: 12px;
  padding: 13px 24px;
  letter-spacing: 2.2px;
}
.cal__menu--lg { left: 50%; transform: translateX(-50%); min-width: 240px; }
.events__note {
  max-width: 54ch;
  margin: 18px auto 0;
  font-size: 16px;
  color: var(--ink-soft);
  font-style: italic;
}

/* ---------- VENUE ---------- */
.venue__card {
  max-width: 520px;
  margin: 0 auto;
  text-align: center;
  background: var(--cream);
  border: 1px solid rgba(174,138,113,.32);
  padding: clamp(26px, 4vw, 40px);
}
.venue__card h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(22px, 2.8vw, 28px);
  margin-bottom: 10px;
}
.venue__card p { color: var(--ink-soft); margin-bottom: 10px; }
.venue__note { font-style: italic; }
.venue__card .btn { margin-top: 12px; }

/* ---------- SHARE ---------- */
.share { text-align: center; }
.share__lead { max-width: 56ch; margin: 0 auto 24px; color: var(--ink-soft); }
.share__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px; }
.share__status { min-height: 24px; margin-top: 16px; font-style: italic; color: var(--ink-soft); }

/* ---------- CLOSING ---------- */
.closing {
  background: var(--turq-deep);
  color: var(--cream);
  text-align: center;
  padding: clamp(52px, 8vw, 84px) 22px;
  position: relative;
  z-index: 2;
}
.closing__script { color: var(--sand); }
.closing__line { font-style: italic; margin-top: 10px; opacity: .9; }
.closing__names {
  font-family: var(--serif);
  font-size: clamp(26px, 4vw, 36px);
  letter-spacing: 1px;
  margin-top: 20px;
}
.closing__date {
  font-family: var(--display);
  font-size: 11px;
  letter-spacing: 5px;
  opacity: .72;
  margin-top: 8px;
}
.closing__credit {
  font-family: var(--display);
  font-size: 10.5px;
  letter-spacing: 2px;
  text-transform: uppercase;
  opacity: .62;
  margin-top: 30px;
}
.closing__credit a { color: var(--sand); text-decoration: none; border-bottom: 1px solid rgba(238,209,176,.4); }


/* ---------- MINIMUM TAP TARGET ----------
   WCAG 2.5.5 and the Apple HIG both want 44x44. These controls computed to
   32-42px from padding alone — and Add to Calendar is the most-tapped
   control on a wedding invitation, so it was the smallest thing on the page.

   min-height plus centring raises the hit area without changing how anything
   looks; padding is left alone so nothing gets visually chunkier. */
.btn, .cal__btn, .cal__btn--lg, .link {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* =========================================================
   SIGNATURE additions — door intro + background music
   ========================================================= */

/* ---------- CUSTOM REVEAL — the layered door (bespoke-2) ----------
   Three registered plates; the front one is the door, split down its exact
   centre, and the leaves swing out of the doorway to show the couple standing
   on the threshold.

   Not Signature's door. That one swings a single flat photograph in two halves,
   so the whole picture — lantern, olive tree, wall — tears apart with it. Here
   only the DOOR moves and the scene stays still, which is what a real door
   does. It works because the two source plates are the same 671x1000 render and
   pixel-identical outside the doorway, so the door is exactly their difference.

   Every percentage below is measured by tools/make_door_reveal.py. Do not
   hand-edit them; re-run the script. */
.reveal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: pointer;
}

.reveal--door { background: #f4ece0; }   /* the plate's own wall cream */

/* The sides are filled with a blurred, enlarged copy of the scene itself, so a
   portrait plate on a landscape screen does not sit between two flat bars. Same
   file, so it costs no extra request. `inset: -5%` pushes the blur's soft edge
   off-screen, otherwise the blur radius leaves a pale halo round the viewport. */
.reveal--door::before {
  content: "";
  position: absolute;
  inset: -5%;
  background: url(../assets/door-scene.webp) center / cover no-repeat;
  filter: blur(30px) brightness(.94) saturate(.8);
  z-index: 0;
}

/* CONTAIN, not cover. The plate is 0.671:1 — portrait, and much narrower than a
   landscape screen. Covering such a viewport means scaling to its WIDTH, which
   on a 1707x825 window makes the plate 2544px tall: the arch, the couple and
   the whole point of the reveal end up off-screen, leaving a close-up of door
   panelling. Measured, not guessed — that is exactly what the first attempt did.
   Fitting guarantees the doorway is wholly visible at every viewport, and the
   blurred backdrop above pays for the letterboxing.

   Fit maths: width = height x 0.671, so the width-limited height is
   100vw / 0.671 = 149.031vw; take whichever of that and 100% is smaller.

   The leaves are positioned in percentages of THIS box, which is the whole
   reason they live inside `.dr` rather than in `.reveal` — they stay registered
   to the scene at every size, with no JS and no media queries. */
.dr {
  position: relative;
  z-index: 1;
  flex: none;                       /* never let the flex parent shrink it */
  height: min(100%, 149.031vw);
  aspect-ratio: 671 / 1000;
  transition: transform 2.4s cubic-bezier(.5,0,.2,1);
}
.dr__scene { display: block; width: 100%; height: 100%; object-fit: cover; }

.dr__leaf {
  position: absolute;
  top: 18.9000%;
  height: 69.6000%;
  /* Perspective INSIDE the transform, for the same reason the envelope flap
     needed it: with no perspective at all rotateY is an orthographic squash and
     the door reads as shrinking rather than swinging. */
  transform: perspective(1400px) rotateY(0deg);
  /* --dr-swing is read by the hand-over timing below; keep them in one place so
     the hold on the couple cannot silently vanish when the swing is retuned. */
  --dr-swing: 1.8s;
  transition: transform var(--dr-swing) cubic-bezier(.5,0,.2,1),
              filter    var(--dr-swing) cubic-bezier(.5,0,.2,1);
  backface-visibility: hidden;
  will-change: transform;
}
.dr__leaf img { display: block; width: 100%; height: 100%; }

/* Each leaf hinges on its OUTER edge, like a real pair of doors. */
.dr__leaf--l { left: 26.0805%; width: 23.9940%; transform-origin: left center; }
.dr__leaf--r { left: 50.0745%; width: 23.8450%; transform-origin: right center; }

.reveal__hint {
  position: absolute;
  left: 50%;
  bottom: clamp(40px, 9vh, 92px);
  transform: translateX(-50%);
  z-index: 3;
  text-align: center;
  opacity: 0;
  /* .8s, not the envelope's 2.6s. There is no drawing to wait for here — the
     door is simply present on the first frame — so making the guest wait would
     be dead time. HINT_READY in js/main.js mirrors this: 800 + 900 = 1700ms. */
  animation: hintIn .9s .8s ease forwards;
}
@keyframes hintIn { to { opacity: 1; } }
.reveal__script {
  font-family: var(--script);
  font-size: clamp(30px, 6vw, 52px);
  color: #f6e6c4;
  line-height: 1;
  text-shadow: 0 3px 22px rgba(0,0,0,.6);
}
.reveal__sub {
  font-family: var(--display);
  font-size: 11px;
  letter-spacing: 4.5px;
  text-transform: uppercase;
  color: rgba(246,230,196,.72);
  margin: 8px 0 18px;
}
.reveal__btn {
  font-family: var(--display);
  font-size: 11.5px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: #0c2a26;
  background: #e8c88a;
  border: 1px solid #e8c88a;
  border-radius: 999px;
  padding: 12px 34px;
  min-height: 44px;
  cursor: pointer;
  box-shadow: 0 10px 30px rgba(0,0,0,.4);
}
.reveal__btn:hover { background: #fff4d6; border-color: #fff4d6; }
.reveal__btn:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

/* ---- the opening — the two leaves swing out of the doorway ----
   Three beats. The scene never moves except for a slow push inward, because the
   wall and the olive tree are not attached to the door. */
body.doors-open .reveal { pointer-events: none; }
body.doors-open .reveal__hint { opacity: 0; transition: opacity .3s; animation: none; }

/* 1 — the leaves swing out on their outer hinges, darkening as they turn away
       from the light. The right leaf is 90ms behind: a real pair of doors is
       never pushed by one hand, and moving them in perfect lockstep is the
       single thing that makes a double door read as a cardboard cut-out. */
body.doors-open .dr__leaf--l {
  transform: perspective(1400px) rotateY(-102deg);
  filter: brightness(.62);
}
body.doors-open .dr__leaf--r {
  transform: perspective(1400px) rotateY(102deg);
  filter: brightness(.72);
  transition-delay: .09s, .09s;
}

/* 2 — a slow push toward the doorway, so the reveal has somewhere to go. */
body.doors-open .dr { transform: scale(1.06); }

/* 3 — hold on the couple, THEN hand over to the hero.
       Arithmetic, because getting this wrong is invisible in code and obvious on
       screen: the leaves take 1.8s and the right one starts 0.09s late, so the
       doors are open at 1.89s. The hold is the 0.8s AFTER that, which is the
       only moment the couple is on screen by themselves and the entire payoff of
       the reveal. Fade therefore starts at 2.7s, not before.

       The first version of this delayed by 2.2s against a 2.1s swing, i.e. it
       began dismissing the couple 10ms after they appeared. It read as the door
       opening onto nothing. If the swing above is retuned, retune these two. */
body.doors-open .reveal {
  opacity: 0;
  visibility: hidden;
  transition: opacity .75s 2.7s ease, visibility 0s 3.45s;
}

body.doors-closed { overflow: hidden; }
/* Pauses ANIMATIONS behind the reveal only — it does nothing about downloads,
   which is why the open is gated on image decode in main.js (Issue 5). */
body.doors-closed .hero__eyebrow,
body.doors-closed .hero__names,
body.doors-closed .hero__date,
body.doors-closed .hero__photo,
body.doors-closed .hero__bg { animation-play-state: paused; }
body.doors-closed .petals { display: none; }

@media (prefers-reduced-motion: reduce) {
  /* The swing is the effect, so it goes entirely rather than being shortened.
     The closed door is still shown — it is the thing being knocked on — it just
     snaps out of the way instead of swinging. */
  .dr, .dr__leaf { transition: none; }
  .reveal__hint { opacity: 1; animation: none; }
  body.doors-open .reveal { display: none; }
}

/* ---------- MUSIC CONTROL ---------- */
.music {
  position: fixed;
  right: clamp(12px, 2.5vw, 26px);
  bottom: clamp(12px, 2.5vw, 26px);
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid rgba(20,128,127,.4);
  background: rgba(251,246,234,.94);
  color: var(--turq-deep);
  font-family: var(--display);
  font-size: 10.5px;
  letter-spacing: 2px;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 8px 22px rgba(58,43,38,.18);
  transition: background .25s, color .25s;
}
.music[hidden] { display: none; }
.music:hover { background: var(--turq-deep); color: var(--cream); }
.music:focus-visible { outline: 2px solid var(--rose); outline-offset: 3px; }

/* three bars that animate only while the music is actually playing, so the
   control always shows the true state */
.music__icon { display: inline-flex; align-items: flex-end; gap: 2px; height: 14px; }
.music__icon i {
  display: block;
  width: 3px;
  height: 5px;
  background: currentColor;
  border-radius: 1px;
  transition: height .2s;
}
.music.is-playing .music__icon i { animation: bars .9s ease-in-out infinite; }
.music.is-playing .music__icon i:nth-child(2) { animation-delay: .18s; }
.music.is-playing .music__icon i:nth-child(3) { animation-delay: .36s; }
@keyframes bars { 0%, 100% { height: 4px; } 50% { height: 14px; } }

/* while the film is playing the control shows why it fell silent, rather
   than just appearing broken */
.music.is-ducked { opacity: .55; }

@media (prefers-reduced-motion: reduce) {
  .music.is-playing .music__icon i { animation: none; height: 9px; }
}

/* =========================================================
   BESPOKE modules
     1. personalised guest links
     2. guestbook
     3. live-stream page
   ========================================================= */

/* ---------- 1. PERSONALISED GREETING ---------- */
.hero__greeting {
  font-family: var(--script);
  font-size: clamp(24px, 4vw, 36px);
  line-height: 1.15;
  color: var(--rose);
  margin-bottom: 6px;
}
.hero__greeting[hidden] { display: none; }

/* ---------- 3. LIVE STREAM ---------- */
.live__frame {
  position: relative;
  max-width: 900px;
  margin: 0 auto;
  overflow: hidden;
  border: 1px solid rgba(174,138,113,.34);
  background: #0e2a28;
}
.live__frame img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.live__frame iframe { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; }

.live__badge {
  position: absolute;
  top: 14px; left: 14px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--rose-deep);
  color: var(--cream);
  font-family: var(--display);
  font-size: 10px;
  letter-spacing: 2.4px;
}
.live__badge[hidden] { display: none; }
.live__badge span {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--cream);
  animation: livePulse 1.4s ease-in-out infinite;
}
@keyframes livePulse { 50% { opacity: .25; } }

.live__countdown {
  text-align: center;
  font-family: var(--display);
  font-size: 13px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--turq-deep);
  margin-top: 20px;
}
.live__schedule {
  list-style: none;
  max-width: 460px;
  margin: 22px auto 0;
  padding: 0;
}
.live__schedule li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  padding: 11px 0;
  border-bottom: 1px dashed rgba(174,138,113,.42);
  color: var(--ink-soft);
  font-size: 16px;
}
.live__schedule li:last-child { border-bottom: 0; }
.live__schedule strong { font-family: var(--display); font-weight: 400; color: var(--ink); }
/* the ones actually being streamed carry the accent; the rest read as muted */
.live__schedule li.is-on strong { color: var(--rose-deep); }
.live__schedule li:not(.is-on) { opacity: .58; }
.live__note {
  text-align: center;
  font-style: italic;
  font-size: 15px;
  color: var(--ink-soft);
  margin-top: 18px;
}

/* ---------- 2. GUESTBOOK ---------- */
.guestbook__wall {
  columns: 2 260px;
  column-gap: 18px;
  max-width: var(--maxw);
  margin: 0 auto;
}
.guestbook__wall .wish {
  break-inside: avoid;
  margin: 0 0 16px;
  padding: 18px 20px;
  background: var(--cream-2);
  border-left: 2px solid var(--rose);
  border-radius: 0 2px 2px 0;
}
.guestbook__wall .wish p { font-style: italic; font-size: 16.5px; line-height: 1.55; color: var(--ink); }
.guestbook__wall .wish cite {
  display: block;
  margin-top: 9px;
  font-family: var(--display);
  font-style: normal;
  font-size: 10px;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  color: var(--rose-deep);
}
/* an entry the guest just submitted, shown before moderation */
.guestbook__wall .wish--pending { border-left-color: var(--turq); opacity: .72; }

.guestbook__form {
  max-width: 520px;
  margin: 30px auto 0;
  text-align: left;
}
.guestbook__form[hidden] { display: none; }
.guestbook__lead {
  text-align: center;
  color: var(--ink-soft);
  margin-bottom: 18px;
  font-size: 16px;
}
.field { display: block; margin-bottom: 14px; }
.field span {
  display: block;
  font-family: var(--display);
  font-size: 10px;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 6px;
}
.field input,
.field textarea {
  width: 100%;
  font-family: var(--serif);
  font-size: 17px;
  color: var(--ink);
  background: var(--cream);
  border: 1px solid rgba(174,138,113,.5);
  border-radius: 2px;
  padding: 11px 13px;
  /* 16px+ on the input itself stops iOS Safari zooming the whole page in
     when the field is focused, which then leaves the layout scrolled
     sideways with no obvious way back. */
  min-height: 44px;
}
.field textarea { resize: vertical; min-height: 88px; }
.field input:focus-visible,
.field textarea:focus-visible { outline: 2px solid var(--turq); outline-offset: 1px; }

.guestbook__form .btn { width: 100%; justify-content: center; }
.guestbook__status { min-height: 24px; margin-top: 12px; font-style: italic; color: var(--ink-soft); text-align: center; }
.guestbook__note {
  max-width: 54ch;
  margin: 22px auto 0;
  text-align: center;
  font-size: 15px;
  font-style: italic;
  color: var(--ink-soft);
}
.guestbook__note code {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 13px;
  font-style: normal;
  background: var(--cream-2);
  padding: 2px 6px;
}
@media (max-width: 560px) {
  .guestbook__wall { columns: 1; }
}
