/* =========================================================
   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 drawn envelope ----------
   Same visual language as the arch it grew out of: gold line art tracing
   itself on a dark field. Beats:

     0.2-1.5s  the envelope body draws
     0.7-1.7s  the pocket seams follow
     1.1-2.1s  the flap and its liner
     1.9-2.5s  the wax seal completes the circle
     2.6s      the names fade up
     on open   seal breaks, flap swings back on its fold, the envelope rises
               past the camera, and only then does the field fade. The field
               used to part down the middle instead — see "the opening".

   ⚠ DWELL in js/main.js mirrors these. Clearing earlier cuts the drawing off
   mid-stroke. */
.reveal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: pointer;
}

/* ONE element, not two halves that slide apart. The halves were meant to make
   the field "part rather than fade", but they upstaged the envelope — guests
   watched a curtain open, not an invitation — and the 50.5% overlap never did
   hide the seam: at fractional DPR the two gradients land on different
   subpixels and a hard vertical line shows down the centre of the field. The
   field now just fades, late, so the envelope opening is the whole effect. */
.reveal__ink {
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, #123b35 0%, #0c2a26 55%, #081d1a 100%);
}

.env {
  position: relative;
  z-index: 2;
  width: min(76vw, 460px);
  transition: transform 1s cubic-bezier(.66,0,.2,1), opacity .8s .15s ease;
}
/* An explicit aspect-ratio, not height:auto. The viewBox gives an intrinsic
   ratio in modern engines, but stating it means the box is correct before the
   SVG is parsed and nothing reflows underneath the drawing. */
.env__draw { display: block; width: 100%; aspect-ratio: 320 / 230; overflow: visible; }

.env__ln {
  fill: none;
  stroke: url(#envgold);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 9px rgba(232,200,138,.4));
  animation: envDraw 1.3s cubic-bezier(.4,0,.2,1) forwards;
}
@keyframes envDraw { to { stroke-dashoffset: 0; } }

/* staggered so it reads as one hand drawing, not five things at once */
.env__ln--body   { animation-delay: .2s; }
.env__ln--pocket { animation-delay: .7s; animation-duration: 1s; opacity: .78; }
.env__ln--flap   { animation-delay: 1.1s; animation-duration: 1s; }
.env__ln--liner  { animation-delay: 1.3s; animation-duration: 1s; stroke-width: 1.3; opacity: .7; }
.env__ln--seal   { animation-delay: 1.9s; animation-duration: .6s; stroke-width: 2.6; }

/* The flap hinges on its own top edge. transform-box: fill-box makes the
   percentage origin resolve against the path's bounding box rather than the
   whole SVG viewport, which is what puts the hinge on the fold. */
/* The perspective is INSIDE the transform, not inherited from a parent. A
   `perspective` property on an ancestor is unreliable for SVG children, and
   without any perspective at all rotateX is an orthographic squash — the flap
   flattened and flipped instead of swinging, which is why the field parting
   used to be the only thing the eye caught. */
.env__flapg {
  transform-box: fill-box;
  transform-origin: 50% 0%;
  transform: perspective(900px) rotateX(0deg);
  transition: transform 1s cubic-bezier(.5,0,.2,1), opacity .6s;
}

.reveal__hint {
  position: absolute;
  left: 50%;
  bottom: clamp(40px, 9vh, 92px);
  transform: translateX(-50%);
  z-index: 3;
  text-align: center;
  opacity: 0;
  animation: hintIn .9s 2.6s 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 ENVELOPE opens; the field no longer parts ----
   Read as four beats in strict order. The whole point is that the guest
   watches an envelope being opened, so nothing may move until the seal has
   visibly broken, and the field must outlast the envelope — if it faded first
   the gold line art would be seen floating over the hero photograph. */
body.doors-open .reveal { pointer-events: none; }
body.doors-open .reveal__hint { opacity: 0; transition: opacity .3s; animation: none; }

/* 1 — the wax seal breaks. Nothing else has started yet. */
body.doors-open .env__ln--seal { opacity: 0; transition: opacity .3s; }

/* 2 — the flap swings back on its own fold, toward the viewer. */
body.doors-open .env__flapg {
  transform: perspective(900px) rotateX(-158deg);
  opacity: .3;
  transition: transform .95s .12s cubic-bezier(.5,0,.2,1), opacity .5s .3s;
}

/* 3 — only once it is open does the envelope rise past the camera, as though
       the guest is being taken inside it. */
body.doors-open .env {
  transform: translateY(-6%) scale(2.5);
  opacity: 0;
  transition: transform 1.1s .8s cubic-bezier(.55,0,.25,1),
              opacity .7s 1.05s ease-in;
}

/* 4 — the field goes last. */
body.doors-open .reveal__ink { opacity: 0; transition: opacity .8s .85s ease; }

body.doors-open .reveal {
  visibility: hidden;
  transition: visibility 0s 1.95s;   /* once the envelope and field have gone */
}

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 drawing is the whole effect, so it is removed rather than shortened —
     the envelope simply arrives complete */
  .env__ln { animation: none; stroke-dashoffset: 0 !important; }
  .env, .env__flapg, .reveal__ink { transition: none; }
  .reveal__hint { opacity: 1; animation: none; }
  body.doors-open .reveal { display: none; }
}

/* Lengths below are EXACT, computed by tools/make_envelope_reveal.py from the
   same geometry that generated the paths. They are literals on purpose: the
   alternative is getTotalLength() in JS, which forces a script-driven start —
   and the first version of this used requestAnimationFrame for that, which
   never fires in a background tab, so the entrance froze half-drawn. */
.env__ln--body   { stroke-dasharray: 836.0;   stroke-dashoffset: 836.0; }
.env__ln--pocket { stroke-dasharray: 290.9; stroke-dashoffset: 290.9; }
.env__ln--flap   { stroke-dasharray: 331.7;   stroke-dashoffset: 331.7; }
.env__ln--liner  { stroke-dasharray: 282.0;  stroke-dashoffset: 282.0; }
.env__ln--seal   { stroke-dasharray: 106.8;   stroke-dashoffset: 106.8; }

/* ---------- 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; }
}
