/* ═══════════════════════════════════════════════════════════════════════════
   LUXURY ISLAMIC WEDDING INVITATION — stylesheet
   Mobile-first (tuned for ~430px), responsive up to desktop.
   Colour tokens below are overwritten at runtime from CONFIG.colors (script.js)
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  /* The invitation is always ivory & gold. Declaring a light scheme stops
     Chrome / Android "auto dark mode" from inverting it for guests whose
     phones are set to dark mode. */
  color-scheme:only light;

  /* palette */
  --ivory:      #F5EFE6;
  --cream:      #EFE7DA;
  --beige:      #E4D8C6;
  --gold:       #B8925A;
  --gold-2:     #C2A15C;
  --gold-soft:  rgba(184,146,90,.28);
  --charcoal:   #3A322B;
  --taupe:      rgba(58,50,43,.13);

  /* type */
  --serif:  "Cormorant Garamond", "Playfair Display", "Iowan Old Style", Georgia, serif;
  --body:   "EB Garamond", "Iowan Old Style", Georgia, serif;
  --script: "Great Vibes", "Parisienne", "Snell Roundhand", cursive;

  /* rhythm */
  --pad: 26px;
  --ease: cubic-bezier(.22,.68,.24,1);
}

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

html,body{ height:100%; margin:0; }

html{ -webkit-text-size-adjust:100%; }

body{
  /* Base tone lives here, behind the atmosphere layer. The screens themselves
     are translucent so the ambient background shows through all seven. */
  background:linear-gradient(180deg,var(--ivory),var(--cream));
  color:var(--charcoal);
  font-family:var(--body);
  font-size:16px;
  line-height:1.6;
  overflow:hidden;                       /* the deck scrolls, not the body */
  /* Cormorant/EB Garamond default to old-style figures; force lining figures
     so every date and the countdown read cleanly. */
  font-variant-numeric:lining-nums;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

button{ font:inherit; color:inherit; border:0; background:none; cursor:pointer; }
a{ color:inherit; text-decoration:none; }
ul{ margin:0; padding:0; list-style:none; }
h1,h2,p{ margin:0; }
svg{ display:block; }

/* ── Paper grain overlay ─────────────────────────────────────────────────── */
.grain{
  position:fixed; inset:0; z-index:60; pointer-events:none;
  opacity:.4; mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.22'/%3E%3C/svg%3E");
}

/* ═══════════════════════════════════════════════════════════════════════════
   AMBIENT ATMOSPHERE — the continuous "3D" background
   A single fixed layer behind the deck. Depth comes from parallax + scale +
   blur rather than WebGL, so it costs almost nothing. Built by
   buildAtmosphere() in script.js; skipped entirely under reduced motion.
   ═══════════════════════════════════════════════════════════════════════════ */
.atmos{
  position:fixed; inset:0; z-index:0;
  pointer-events:none;
  overflow:hidden;
  contain:strict;                 /* isolate it from the rest of the page's layout */
}

/* One parallax band of botanical line-art. Oversized so shifting it never
   exposes an edge. JS writes the transform. */
.atmos__layer{
  position:absolute; inset:-16%;
  will-change:transform;
}
.atmos__layer svg{
  position:absolute;
  width:190px; height:auto;
  transform-origin:50% 50%;
  fill:none; stroke:var(--gold);
  stroke-width:.9; stroke-linecap:round; stroke-linejoin:round;
}

/* ── drifting petals ──────────────────────────────────────────────────────
   Three nested elements so three independent motions compose without any
   JavaScript: fall (outer) × sway (middle) × spin (inner).            */
.atmos__petals{ position:absolute; inset:0; }
.petal{
  position:absolute; top:0;
  width:var(--w,14px);
  opacity:var(--op,.4);
  filter:blur(var(--blur,0px));
  animation:petal-fall var(--dur,20s) linear var(--delay,0s) infinite;
  will-change:transform;
}
.petal__sway{
  display:block;
  animation:petal-sway calc(var(--dur,20s) / 3.5) ease-in-out var(--delay,0s) infinite alternate;
}
.petal__spin{
  display:block;
  transform:scale(var(--s,1));
  animation:petal-spin calc(var(--dur,20s) * 1.6) linear var(--delay,0s) infinite;
}
.petal svg{ width:100%; height:auto; display:block; }
.petal--far  svg{ fill:var(--gold);  }
.petal--mid  svg{ fill:#FBF4E6;      }
.petal--near svg{ fill:var(--gold-2);}

@keyframes petal-fall{
  from{ transform:translate3d(0,-18vh,0); }
  to  { transform:translate3d(0,118vh,0); }
}
@keyframes petal-sway{
  from{ transform:translateX(calc(var(--sway,16px) * -1)); }
  to  { transform:translateX(var(--sway,16px)); }
}
@keyframes petal-spin{
  to{ transform:scale(var(--s,1)) rotate(var(--spin,300deg)); }
}

/* Freeze the whole scene while the tab is in the background */
.is-hidden .atmos *{ animation-play-state:paused !important; }

/* ═══ SCROLL DECK ═══════════════════════════════════════════════════════════ */
.deck{
  position:relative; z-index:1;    /* sits above .atmos */
  height:100vh; height:100dvh;
  overflow-y:scroll; overflow-x:hidden;
  scroll-snap-type:y mandatory;
  scroll-behavior:smooth;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.deck::-webkit-scrollbar{ display:none; }

/* Scrolling stays locked until the envelope is opened */
.deck.is-locked{ overflow:hidden; }

.screen{
  position:relative;
  min-height:100vh; min-height:100dvh;
  scroll-snap-align:start; scroll-snap-stop:always;
  display:flex; align-items:center; justify-content:center;
  padding:calc(env(safe-area-inset-top) + 46px) var(--pad) 108px;
  overflow:hidden;
  isolation:isolate;
  background:transparent;          /* the atmosphere layer shows through */
}

/* Background photo layer.
   HOW TO SWAP A BACKGROUND: put a URL in CONFIG.images.<key> in script.js.
   JS writes it to --bg on the matching section. Empty = CSS gradient only. */
.screen::before{
  content:""; position:absolute; inset:0; z-index:-2;
  background-image:var(--bg,none);
  background-size:cover; background-position:center;
  opacity:var(--bg-opacity,.5);
  filter:blur(var(--bg-blur,2px)) saturate(.86);
  transform:scale(1.06);
}
/* Cream wash so text always stays readable over any photo.
   `--wash` scales the whole veil: it is deliberately light so the atmosphere
   layer reads through, but raise it per-section if you add a busy photo. */
.screen::after{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  opacity:var(--wash,.26);
  background:
    radial-gradient(120% 80% at 50% 0%,   rgba(245,239,230,.55), transparent 60%),
    radial-gradient(120% 90% at 50% 100%, rgba(239,231,218,.85), transparent 62%),
    linear-gradient(180deg, rgba(245,239,230,.72), rgba(239,231,218,.82));
}
/* Sections carrying a photo need the full veil back for legibility */
.screen[style*="--bg"]{ --wash:1; }

.screen__inner{
  position:relative; z-index:2;
  width:100%; max-width:430px;
  display:flex; flex-direction:column; align-items:center;
  text-align:center;
}

/* ── Corner botanicals (SVG injected by JS) ─────────────────────────────── */
.florals{ position:absolute; inset:0; z-index:1; pointer-events:none; will-change:transform; }
.florals svg{
  position:absolute; width:132px; height:auto;
  stroke:var(--gold); fill:none;
  stroke-width:.9; stroke-linecap:round; stroke-linejoin:round;
  opacity:.42;
}
.florals .fl-tl{ top:-4px;    left:-14px;  }
.florals .fl-tr{ top:-4px;    right:-14px; transform:scaleX(-1); }
.florals .fl-bl{ bottom:-4px; left:-14px;  transform:scaleY(-1); }
.florals .fl-br{ bottom:-4px; right:-14px; transform:scale(-1); }
@media (min-width:520px){ .florals svg{ width:178px; } }

/* ═══ TYPE PRIMITIVES ══════════════════════════════════════════════════════ */
.eyebrow{
  font-family:var(--serif);
  font-size:.66rem; font-weight:500;
  letter-spacing:.44em; text-transform:uppercase;
  color:var(--gold);
  margin-bottom:16px;
}
.h-serif{
  font-family:var(--serif);
  font-weight:300; font-size:clamp(1.75rem,7.4vw,2.35rem);
  line-height:1.24; letter-spacing:.012em;
  color:var(--charcoal);
}
.sub{
  font-size:.95rem; font-style:italic;
  color:rgba(58,50,43,.66);
  margin-top:10px;
}

/* thin gold rule with a centre dot */
.rule{ display:block; height:1px; width:120px; margin-inline:auto; background:linear-gradient(90deg,transparent,var(--gold-soft) 18%,var(--gold) 50%,var(--gold-soft) 82%,transparent); position:relative; }
.rule--dot{ margin-top:22px; }
.rule--dot::after{
  content:""; position:absolute; left:50%; top:50%;
  width:4px; height:4px; border-radius:50%; background:var(--gold);
  transform:translate(-50%,-50%);
}
.rule--tiny{ width:46px; margin:8px auto 10px; }

/* divider with heart / diamond */
/* margin-inline:auto matters inside .card, which is not a flex container */
.divider{ display:flex; align-items:center; gap:12px; margin:18px auto 4px; width:min(240px,72%); }
.divider__line{ flex:1; height:1px; background:linear-gradient(90deg,transparent,var(--gold)); }
.divider__line:last-child{ background:linear-gradient(90deg,var(--gold),transparent); }
.divider__heart{ color:var(--gold); font-size:.7rem; line-height:1; transform:translateY(-1px); }
.divider__diamond{ width:6px; height:6px; background:var(--gold); transform:rotate(45deg); }

/* ── embossed / foil accents — CONFIG.effects.emboss, toggled as body.fx-emboss ──
   Text on gold gets a light highlight up-left and a dark shadow down-right;
   the diamond has no text to shadow, so it gets the box-shadow equivalent.
   The eyebrow labels get their own zero-blur version: at .66rem with heavy
   letter-spacing, a blurred shadow just reads as smudged/out-of-focus, so
   these use crisp 1px offsets with no blur radius instead. */
body.fx-emboss .eyebrow {
  text-shadow:
    -0.5px -0.5px 0 rgba(255,255,255,.35),
     0.5px  0.5px 0 rgba(58,50,43,.18);
}
body.fx-emboss .names__amp,
body.fx-emboss .divider__heart{
  text-shadow:
    -1px -1px 0 rgba(255,255,255,.55),
    1px 1.5px 1.5px rgba(58,50,43,.5);
}
body.fx-emboss .divider__diamond{
  box-shadow:
    -1px -1px 0 rgba(255,255,255,.5) inset,
    1px 1px 1.5px rgba(58,50,43,.5);
}

/* ═══ CARDS / GLASS ════════════════════════════════════════════════════════ */
.card{
  width:100%;
  background:linear-gradient(168deg,#FBF7F0,#F2EADD 62%,#EDE3D4);
  border:1px solid var(--gold-soft);
  border-radius:6px;
  padding:44px 26px 46px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.7) inset,
    0 18px 44px -18px rgba(58,50,43,.28),
    0 40px 80px -40px rgba(58,50,43,.34);
  position:relative;
}
/* inner hairline frame */
.card::after{
  content:""; position:absolute; inset:9px; z-index:1;
  border:1px solid rgba(184,146,90,.22); border-radius:3px; pointer-events:none;
}

.glass{
  width:100%;
  background:rgba(255,252,246,.5);
  -webkit-backdrop-filter:blur(16px) saturate(1.15);
  backdrop-filter:blur(16px) saturate(1.15);
  border:1px solid rgba(184,146,90,.3);
  border-radius:20px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.75) inset,
    0 16px 40px -20px rgba(58,50,43,.3);
}

/* ═══ CHEVRON BUTTON ═══════════════════════════════════════════════════════ */
.chev{
  position:absolute; z-index:5;
  left:50%; bottom:calc(env(safe-area-inset-bottom) + 34px);
  transform:translateX(-50%);
  width:46px; height:46px; border-radius:50%;
  border:1px solid var(--gold-soft);
  background:rgba(255,252,246,.55);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  box-shadow:0 8px 22px -12px rgba(58,50,43,.4);
  transition:background .3s var(--ease), border-color .3s var(--ease), transform .3s var(--ease);
  animation:nudge 2.6s var(--ease) infinite;
}
.chev::before{
  content:""; position:absolute; left:50%; top:47%;
  width:10px; height:10px; margin:-6px 0 0 -5px;
  border-right:1.4px solid var(--gold); border-bottom:1.4px solid var(--gold);
  transform:rotate(45deg);
}
.chev--up::before{ transform:rotate(-135deg); top:53%; }
.chev:hover,.chev:focus-visible{ background:rgba(255,252,246,.9); border-color:var(--gold); outline:none; }
.chev:active{ transform:translateX(-50%) scale(.93); }
@keyframes nudge{
  0%,72%,100%{ transform:translateX(-50%) translateY(0); }
  82%{ transform:translateX(-50%) translateY(5px); }
}

/* ═══ MUSIC TOGGLE ═════════════════════════════════════════════════════════ */
.music-toggle{
  position:fixed; z-index:70;
  top:calc(env(safe-area-inset-top) + 16px); right:16px;
  width:42px; height:42px; border-radius:50%;
  display:grid; place-items:center;
  border:1px solid var(--gold-soft);
  background:rgba(255,252,246,.62);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  box-shadow:0 8px 20px -12px rgba(58,50,43,.45);
  animation:fadeIn .8s var(--ease) both;
}
.music-toggle svg{
  width:19px; height:19px;
  fill:none; stroke:var(--gold); stroke-width:1.35;
  stroke-linecap:round; stroke-linejoin:round;
}
.music-toggle .ico-muted,
.music-toggle[aria-pressed="true"] .ico-sound{ display:none; }
.music-toggle[aria-pressed="true"] .ico-muted{ display:block; }
.music-toggle[aria-pressed="true"] svg{ stroke:rgba(58,50,43,.45); }
@keyframes fadeIn{ from{opacity:0} to{opacity:1} }

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 1 — ENVELOPE
   ═══════════════════════════════════════════════════════════════════════════ */
.screen--cover{
  cursor:pointer;
  background:
    radial-gradient(70% 50% at 22% 18%, rgba(253,250,244,.72), transparent 70%),
    radial-gradient(80% 60% at 82% 78%, rgba(241,231,215,.6), transparent 70%),
    linear-gradient(155deg,rgba(248,242,232,.62) 0%,rgba(239,230,215,.58) 46%,rgba(231,219,200,.64) 100%);
}
/* faint satin sheen — very low contrast, reads as woven silk not stripes */
.screen--cover::after{
  opacity:1;
  background:
    repeating-linear-gradient(112deg, rgba(255,255,255,.05) 0 1px, transparent 1px 14px),
    radial-gradient(140% 70% at 78% 12%, rgba(255,255,255,.24), transparent 62%),
    radial-gradient(120% 90% at 50% 112%, rgba(226,213,193,.3), transparent 62%);
}
/* blurred baby's-breath bokeh */
.bloom{
  position:absolute; z-index:0; pointer-events:none;
  border-radius:50%;
  filter:blur(22px);
  opacity:.65;
}
.bloom--a{
  width:230px; height:180px; top:-30px; left:-50px;
  background:
    radial-gradient(circle 12px at 30% 40%, #fffdf8 60%, transparent 62%),
    radial-gradient(circle 9px  at 55% 20%, #fffdf8 60%, transparent 62%),
    radial-gradient(circle 14px at 70% 55%, #fffdf8 60%, transparent 62%),
    radial-gradient(circle 8px  at 22% 72%, #fdf6e9 60%, transparent 62%),
    radial-gradient(circle 11px at 82% 26%, #fdf6e9 60%, transparent 62%);
}
.bloom--b{
  width:260px; height:210px; bottom:-40px; right:-60px;
  background:
    radial-gradient(circle 13px at 40% 30%, #fffdf8 60%, transparent 62%),
    radial-gradient(circle 9px  at 68% 58%, #fffdf8 60%, transparent 62%),
    radial-gradient(circle 15px at 24% 66%, #fdf6e9 60%, transparent 62%),
    radial-gradient(circle 10px at 78% 22%, #fffdf8 60%, transparent 62%),
    radial-gradient(circle 8px  at 55% 82%, #fdf6e9 60%, transparent 62%);
}

.env-stage{
  position:relative;
  perspective:1400px; perspective-origin:50% 0%;
  margin:14px 0 8px;
}
.envelope{
  position:relative;
  width:min(302px,78vw);
  aspect-ratio:3/2;
  transform-style:preserve-3d;
  transition:transform 1.1s var(--ease);
}
.env-shadow{
  position:absolute; left:50%; bottom:-16px;
  width:74%; height:22px; transform:translateX(-50%);
  background:radial-gradient(50% 50% at 50% 50%, rgba(58,50,43,.3), transparent 70%);
  filter:blur(7px);
  transition:opacity .9s var(--ease), transform .9s var(--ease);
}

/* envelope shell */
.env-back{
  position:absolute; inset:0; z-index:1;
  border-radius:4px;
  background:linear-gradient(165deg,#F7F1E6,#EADFCC);
  box-shadow:
    0 2px 0 rgba(255,255,255,.6) inset,
    0 22px 40px -22px rgba(58,50,43,.42);
}

/* clipping slot that hides the card until the flap opens. preserve-3d keeps
   the card's translateZ lift (below) in the same 3D space as .env-stage's
   perspective instead of being flattened. */
.env-slot{ position:absolute; inset:0; z-index:2; overflow:hidden; border-radius:4px; transform-style:preserve-3d; }
.envelope.is-slot-open .env-slot{ overflow:visible; }

/* the invitation card that rises out */
.env-note{
  position:absolute; left:50%; bottom:5%;
  width:84%; height:132%;
  transform:translateX(-50%) translateY(0);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  padding:18px 16px;
  border-radius:3px;
  background:linear-gradient(170deg,#FDFAF3,#F4ECDF 60%,#EFE5D5);
  border:1px solid rgba(184,146,90,.34);
  box-shadow:0 -6px 26px -12px rgba(58,50,43,.4), 0 1px 0 rgba(255,255,255,.8) inset;
  transition:transform 1.15s var(--ease), box-shadow 1.15s var(--ease);
}
.env-note::after{
  content:""; position:absolute; inset:7px;
  border:1px solid rgba(184,146,90,.2); pointer-events:none;
}
.env-note__label{
  font-family:var(--serif); font-size:.56rem; font-weight:500;
  letter-spacing:.3em; text-transform:uppercase; color:var(--gold);
}
/* Sized off the viewport so long names still fit the small enclosed card. */
.env-note__names{
  font-family:var(--script);
  font-size:clamp(.95rem,4.4vw,1.3rem); line-height:1.32;
  color:var(--gold);
  margin:2px 0 6px; max-width:100%;
  text-wrap:balance;
}
.env-note__date{
  font-family:var(--serif); font-size:.6rem;
  letter-spacing:.26em; color:rgba(58,50,43,.6);
}
.envelope.is-out .env-note{
  transform:translateX(-50%) translateY(-42%) translateZ(70px);
  box-shadow:0 -10px 40px -14px rgba(58,50,43,.45), 0 1px 0 rgba(255,255,255,.8) inset;
}

/* pocket front — three folded triangles with a V notch on top */
.env-front{ position:absolute; inset:0; z-index:4; border-radius:4px; overflow:hidden; }
.env-front span{ position:absolute; inset:0; }
.env-front .f-l{
  clip-path:polygon(0 0, 51% 52%, 0 100%);
  background:linear-gradient(96deg,#F6EFE3,#EDE2D0);
}
.env-front .f-r{
  clip-path:polygon(100% 0, 49% 52%, 100% 100%);
  background:linear-gradient(-96deg,#F6EFE3,#E9DDC9);
}
.env-front .f-b{
  clip-path:polygon(0 100%, 50% 50%, 100% 100%);
  background:linear-gradient(0deg,#F4ECDE,#E6DAC5);
}
/* Hairline gold fold lines. A CSS gradient cannot follow these edges (they
   run corner→centre, not corner→corner), so they are drawn as SVG with a
   non-scaling stroke — crisp at any envelope size. */
.env-folds{
  position:absolute; inset:0; width:100%; height:100%;
  fill:none; stroke:rgba(184,146,90,.4);
}
.env-folds path{ stroke-width:1; vector-effect:non-scaling-stroke; }

/* the flap */
.env-flap{
  position:absolute; top:0; left:0; right:0; height:54%;
  z-index:6;
  transform-origin:top center;
  transform:rotateX(0deg);
  transition:transform 1s var(--ease), z-index 0s linear .5s;
  clip-path:polygon(0 0, 100% 0, 50% 100%);
  background:linear-gradient(180deg,#FCF7EF,#F3EADB 62%,#E9DECA);
  filter:drop-shadow(0 5px 7px rgba(58,50,43,.2));
  backface-visibility:visible;
}
.env-flap .env-folds{ stroke:rgba(184,146,90,.45); }
.envelope.is-open .env-flap{
  transform:rotateX(-172deg);
  z-index:0;
  filter:drop-shadow(0 -6px 10px rgba(58,50,43,.12));
}

/* wax seal */
.env-seal{
  position:absolute; left:50%; top:54%; z-index:8;
  width:46px; height:46px; margin:-23px 0 0 -23px;
  border-radius:50%;
  display:grid; place-items:center;
  background:
    radial-gradient(60% 60% at 34% 28%, #DCC086, transparent 60%),
    radial-gradient(90% 90% at 62% 74%, #9C7739, transparent 62%),
    linear-gradient(150deg,#C9A662,#A9813F 58%,#BE9A55);
  box-shadow:
    0 1px 1px rgba(255,255,255,.5) inset,
    0 -2px 4px rgba(0,0,0,.22) inset,
    0 6px 14px -6px rgba(58,50,43,.55);
  transition:transform .55s var(--ease), opacity .55s var(--ease);
}
/* wavy wax edge */
.env-seal::before{
  content:""; position:absolute; inset:-3px; border-radius:50%;
  background:conic-gradient(from 0deg, #C6A25E, #AD8543, #CDAA68, #A87F3E, #C6A25E);
  z-index:-1;
  -webkit-mask:radial-gradient(closest-side, transparent 84%, #000 85%);
  mask:radial-gradient(closest-side, transparent 84%, #000 85%);
  opacity:.9;
}
.env-seal svg{
  width:27px; height:27px;
  fill:none; stroke:rgba(255,250,240,.9);
  stroke-width:1.1; stroke-linecap:round; stroke-linejoin:round;
  transform-origin:50% 50%;
  animation:seal-breathe 3.2s ease-in-out infinite;
}
@keyframes seal-breathe{
  0%,100%{ transform:scale(1); }
  50%{ transform:scale(1.1); }
}
.envelope.is-open .env-seal{ transform:scale(1.22) rotate(-14deg); opacity:0; }
/* the seal presses inward for a beat before it breaks and the flap opens */
.envelope.is-pressing .env-seal{
  transform:scale(.86);
  box-shadow:
    0 1px 1px rgba(255,255,255,.35) inset,
    0 -2px 6px rgba(0,0,0,.4) inset,
    0 2px 6px -4px rgba(58,50,43,.5);
  transition:transform .16s var(--ease), box-shadow .16s var(--ease);
}

/* tap label */
.tap-label{
  font-family:var(--serif);
  font-size:.74rem; font-weight:500;
  letter-spacing:.42em; text-transform:uppercase;
  color:var(--gold);
  margin-top:34px; padding-left:.42em;
  animation:pulse 2.8s ease-in-out infinite;
  transition:opacity .5s var(--ease);
}
@keyframes pulse{ 0%,100%{opacity:.55} 50%{opacity:1} }

/* the prompt retires the moment the envelope is tapped */
.screen--cover.is-opening .tap-label,
.screen--cover.is-opening .rule--dot,
.screen--cover.is-opening .eyebrow{
  opacity:0; animation:none; transition:opacity .45s var(--ease);
}

/* cover fades out once opened */
.screen--cover.is-done .screen__inner{ opacity:0; transform:scale(1.04); transition:opacity .7s var(--ease), transform .7s var(--ease); }
.screen--cover.is-done .chev{ opacity:0; transition:opacity .4s; }

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 2 — NAMES
   ═══════════════════════════════════════════════════════════════════════════ */
.screen--names{
  background:
    radial-gradient(90% 60% at 50% 0%, rgba(251,246,238,.7), transparent 70%),
    linear-gradient(170deg,rgba(245,239,230,.6),rgba(233,223,206,.64));
}
/* room for the card's mouse-tilt to read as real depth, not a flat skew */
.screen--names .screen__inner{ perspective:1000px; }
.card--names{
  padding:52px 24px 54px;
  position:relative;
  transform-style:preserve-3d;
  transition:transform .5s var(--ease), box-shadow .5s var(--ease);
  will-change:transform;
  /* --tilt-shadow is written by setupCardTilt() in script.js; the rest of
     the stack matches the base .card shadow so it still reads correctly
     with the effect switched off (CONFIG.effects.cardTilt = false). */
  box-shadow:
    var(--tilt-shadow, 0 0 0 transparent),
    0 1px 0 rgba(255,255,255,.7) inset,
    0 18px 44px -18px rgba(58,50,43,.28),
    0 40px 80px -40px rgba(58,50,43,.34);
}
.card--names.is-tilting{ transition:transform .06s linear, box-shadow .06s linear; }
/* faint gloss that follows the cursor, layered above the inner hairline frame */
.card--names::before{
  content:""; position:absolute; inset:0; z-index:2;
  border-radius:inherit;
  opacity:0;
  background:radial-gradient(circle at var(--glare-x,50%) var(--glare-y,50%), rgba(255,255,255,.55), transparent 55%);
  transition:opacity .4s var(--ease);
  pointer-events:none;
}
.card--names.is-tilting::before{ opacity:.5; }
.names{
  font-family:var(--serif);
  font-weight:300;
  font-size:clamp(2.1rem,10vw,2.9rem);
  line-height:1.12;
  color:var(--gold);
  letter-spacing:.01em;
  display:flex; flex-direction:column; align-items:center; gap:2px;
}
.names__amp{
  font-size:.56em; font-style:italic; font-weight:400;
  letter-spacing:0;
  color:var(--gold-2); opacity:.85;
  margin:4px 0 2px;
}
.names__date{
  font-family:var(--serif);
  font-size:.86rem; letter-spacing:.3em;
  color:rgba(58,50,43,.7);
  margin-top:14px;
}
.names__tag{
  font-family:var(--serif); font-style:italic;
  font-size:1.16rem; color:var(--charcoal);
  margin-top:12px; opacity:.85;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 3 — DETAILS
   ═══════════════════════════════════════════════════════════════════════════ */
.screen--details{ --bg-opacity:.42; --bg-blur:3px; }
.screen--details{
  background:
    radial-gradient(60% 42% at 50% 26%, rgba(226,190,132,.26), transparent 66%),
    radial-gradient(40% 30% at 18% 74%, rgba(210,168,110,.18), transparent 70%),
    linear-gradient(170deg,rgba(243,236,224,.62),rgba(231,218,198,.66));
}
.details{ width:100%; margin-top:30px; display:flex; flex-direction:column; gap:2px; }
.detail{
  display:flex; align-items:center; gap:16px;
  padding:16px 4px;
  text-align:left;
  border-bottom:1px solid rgba(184,146,90,.2);
}
.detail:last-child{ border-bottom:0; }
.detail__ico{
  flex:0 0 44px; width:44px; height:44px;
  display:grid; place-items:center;
  border:1px solid var(--gold-soft); border-radius:50%;
  background:rgba(255,252,246,.5);
}
.detail__ico svg{
  width:21px; height:21px;
  fill:none; stroke:var(--gold); stroke-width:1.05;
  stroke-linecap:round; stroke-linejoin:round;
}
.detail__txt{ display:flex; flex-direction:column; min-width:0; }
.detail__txt b{
  font-family:var(--serif); font-weight:500;
  font-size:1.14rem; line-height:1.3; color:var(--charcoal);
}
.detail__txt em{
  font-style:normal;
  font-family:var(--body);
  font-size:.64rem; letter-spacing:.24em; text-transform:uppercase;
  color:rgba(58,50,43,.55);
  margin-top:3px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 4 — COUNTDOWN
   ═══════════════════════════════════════════════════════════════════════════ */
.screen--count{
  background:
    radial-gradient(80% 50% at 50% 12%, rgba(251,246,238,.68), transparent 70%),
    linear-gradient(180deg,rgba(245,239,230,.6),rgba(235,225,209,.64));
}
.count{
  margin-top:28px;
  padding:26px 10px 22px;
  display:flex; align-items:stretch; justify-content:center;
}
.count__unit{ flex:1; display:flex; flex-direction:column; align-items:center; gap:6px; min-width:0; }

/* ── split-flap flip digit ──────────────────────────────────────────────
   Two stacked faces inside one 3D container. The back face is pre-rotated
   180deg and hidden by backface-visibility; rotating the container reveals
   it, then script.js snaps the front face to match and resets rotation —
   see setDigit() in setupCountdown(). */
.flip{
  position:relative; display:inline-block;
  font-family:var(--serif); font-weight:400;
  font-size:clamp(1.85rem,9vw,2.5rem); line-height:1;
  color:var(--gold);
  font-variant-numeric:lining-nums tabular-nums;   /* digits don't jump each tick */
  perspective:200px;
  transform-style:preserve-3d;
}
.flip__front,.flip__back{ display:block; backface-visibility:hidden; }
.flip__back{ position:absolute; inset:0; transform:rotateX(180deg); }
/* faint hinge line to read as a split-flap card even mid-flip */
.flip::after{
  content:""; position:absolute; left:-2px; right:-2px; top:50%;
  height:1px; background:rgba(58,50,43,.16); pointer-events:none;
}
.flip.is-flipping{ animation:flip-digit .5s var(--ease); }
@keyframes flip-digit{
  from{ transform:rotateX(0deg); }
  to  { transform:rotateX(-180deg); }
}
.count__l{
  font-size:.56rem; letter-spacing:.2em; text-transform:uppercase;
  color:rgba(58,50,43,.55);
}
.count__sep{
  flex:0 0 1px; width:1px; align-self:center; height:46px;
  background:linear-gradient(180deg,transparent,var(--gold-soft) 30%,var(--gold-soft) 70%,transparent);
}
.count__note{
  font-family:var(--serif); font-size:.72rem;
  letter-spacing:.24em; text-transform:uppercase;
  color:var(--gold);
  margin-top:22px;
}
/* "Today is the day!" state */
.count.is-day{ padding:34px 18px; }
.count__today{
  font-family:var(--serif); font-weight:300;
  font-size:clamp(1.4rem,7vw,1.9rem); line-height:1.3;
  color:var(--gold); text-align:center; width:100%;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 5 — RSVP
   ═══════════════════════════════════════════════════════════════════════════ */
.screen--rsvp{
  background:
    radial-gradient(70% 46% at 50% 8%, rgba(252,248,241,.68), transparent 72%),
    linear-gradient(172deg,rgba(244,237,227,.6),rgba(232,222,205,.64));
}
.rsvp{
  margin-top:26px; padding:18px;
  display:flex; flex-direction:column; gap:12px;
}
.pill{
  position:relative;
  display:flex; align-items:center; justify-content:center;
  width:100%; min-height:56px;
  padding:14px 52px;
  border-radius:999px;
  border:1px solid rgba(184,146,90,.34);
  background:linear-gradient(180deg,#FBF6EE,#F2EADC);
  color:var(--charcoal);
  box-shadow:0 1px 0 rgba(255,255,255,.8) inset, 0 8px 18px -14px rgba(58,50,43,.4);
  transition:background .34s var(--ease), color .34s var(--ease),
             border-color .34s var(--ease), box-shadow .34s var(--ease),
             transform .18s var(--ease);
}
.pill__t{ font-family:var(--serif); font-size:1.06rem; letter-spacing:.02em; }
.pill__m{
  position:absolute; right:12px; top:50%; transform:translateY(-50%);
  width:30px; height:30px; border-radius:50%;
  display:grid; place-items:center;
  border:1px solid rgba(58,50,43,.28);
  transition:border-color .34s var(--ease), background .34s var(--ease);
}
.pill__m svg{
  grid-area:1/1;
  width:15px; height:15px; fill:none;
  stroke:rgba(58,50,43,.6); stroke-width:1.6;
  stroke-linecap:round; stroke-linejoin:round;
  transition:stroke .34s var(--ease);
}
/* unselected shows a dark ✕, selected shows a white ✓ */
.pill .m-tick{ display:none; }
.pill[aria-pressed="true"] .m-tick{ display:block; }
.pill[aria-pressed="true"] .m-cross{ display:none; }
.pill:active{ transform:scale(.985); }
/* CONFIG.effects.liftHover, toggled as body.fx-lift — rises toward the
   viewer on hover, presses back down on press (the :active rule below has
   equal specificity and comes second, so it wins over hover while held). */
body.fx-lift .pill:hover{
  transform:translateY(-5px) translateZ(12px);
  box-shadow:0 1px 0 rgba(255,255,255,.8) inset, 0 22px 40px -16px rgba(58,50,43,.5);
}
body.fx-lift .pill:active{ transform:translateY(-1px) translateZ(2px) scale(.985); }
.pill[aria-pressed="true"]{
  background:linear-gradient(180deg,#463C33,#332C26);
  color:#FDFAF4;
  border-color:rgba(58,50,43,.9);
  box-shadow:0 10px 26px -14px rgba(58,50,43,.7);
}
.pill[aria-pressed="true"] .pill__m{ background:#FDFAF4; border-color:#FDFAF4; }
.pill[aria-pressed="true"] .pill__m svg{ stroke:var(--charcoal); }

.rsvp__msg{
  min-height:1.2em; margin-top:14px;
  font-size:.86rem; font-style:italic; color:var(--gold);
  opacity:0; transform:translateY(4px);
  transition:opacity .4s var(--ease), transform .4s var(--ease);
}
.rsvp__msg.is-on{ opacity:1; transform:none; }

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 6 — VENUE
   ═══════════════════════════════════════════════════════════════════════════ */
.screen--venue{ --bg-opacity:.44; --bg-blur:2.5px; }
.screen--venue{
  background:
    radial-gradient(55% 40% at 50% 18%, rgba(222,186,130,.22), transparent 68%),
    linear-gradient(172deg,rgba(243,236,225,.62),rgba(230,218,198,.66));
}
.venue{ margin-top:24px; padding:16px 16px 20px; }
.venue__map{
  position:relative;
  width:100%; aspect-ratio:16/11;
  /* vh cap keeps Section 6 inside short viewports (small phones / landscape) */
  max-height:min(240px,26vh);
  border-radius:14px; overflow:hidden;
  border:1px solid rgba(184,146,90,.3);
  background:linear-gradient(170deg,#FAF4EA,#F0E6D6);
  box-shadow:0 8px 22px -16px rgba(58,50,43,.5) inset;
}
.venue__map svg,
.venue__map iframe{ width:100%; height:100%; display:block; border:0; }
body.fx-lift .venue__map{
  transform-style:preserve-3d;
  transition:transform .4s var(--ease), box-shadow .4s var(--ease);
}
body.fx-lift .venue__map:hover{
  transform:rotateX(4deg) rotateY(-4deg) translateZ(6px);
  box-shadow:0 8px 22px -16px rgba(58,50,43,.5) inset, 0 16px 30px -18px rgba(58,50,43,.5);
}
body.fx-lift .screen--rsvp .screen__inner,
body.fx-lift .screen--venue .screen__inner{ perspective:800px; }
.venue__name{
  font-family:var(--serif); font-weight:500;
  font-size:1.24rem; color:var(--charcoal);
  margin-top:16px;
}
.venue__addr{
  font-size:.8rem; line-height:1.7;
  letter-spacing:.06em;
  color:rgba(58,50,43,.62);
  margin-top:5px;
}
.btn-dark{
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  margin-top:18px; padding:14px 26px;
  border-radius:999px;
  background:linear-gradient(180deg,#463C33,#332C26);
  color:#FDFAF4;
  font-family:var(--serif); font-size:.95rem;
  letter-spacing:.13em; text-transform:uppercase;
  box-shadow:0 12px 26px -16px rgba(58,50,43,.8);
  transition:transform .2s var(--ease), box-shadow .3s var(--ease);
  cursor:pointer;
}
.btn-dark svg{
  width:17px; height:17px; fill:none;
  stroke:rgba(226,199,150,.95); stroke-width:1.15;
  stroke-linecap:round; stroke-linejoin:round;
}

.btn-dark:active{ transform:scale(.97); }
.btn-dark:hover{ box-shadow:0 16px 30px -16px rgba(58,50,43,.9); }
body.fx-lift .btn-dark:hover{
  transform:translateY(-5px) translateZ(14px);
  box-shadow:0 22px 40px -16px rgba(58,50,43,.9);
}
body.fx-lift .btn-dark:active{ transform:translateY(-1px) translateZ(4px) scale(.97); }

/* Stylized SVG map: the artwork uses currentColor, so this single line
   keeps it in sync with CONFIG.colors.gold. */
.map-art{ color:var(--gold); background:#FAF4EA; }

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 7 — THANK YOU
   ═══════════════════════════════════════════════════════════════════════════ */
.screen--thanks{ --bg-opacity:.5; --bg-blur:2px; }
.screen--thanks{
  background:
    radial-gradient(60% 40% at 50% 76%, rgba(226,190,132,.26), transparent 68%),
    radial-gradient(70% 40% at 50% 6%, rgba(252,248,240,.68), transparent 70%),
    linear-gradient(172deg,rgba(245,239,230,.6),rgba(233,222,204,.64));
}
/* ── Section 7 flourish: a gold bird that draws itself, then glides away ──
   `pathLength="1"` on each path lets one dash rule animate every stroke
   regardless of its true length. Fires off the reveal observer's .is-in. */
.bird-wrap{
  position:absolute; z-index:1; pointer-events:none;
  top:4.5%; right:13%;          /* clear of the fixed music toggle */
  width:min(170px,42vw);
  color:var(--gold);
}
.bird{ width:100%; height:auto; }

/* Outline sketches itself first. `pathLength="1"` normalises the path so one
   dash rule works for any shape — do NOT add vector-effect:non-scaling-stroke
   here, it makes the dash lengths resolve in screen pixels and breaks it. */
.dove__line{
  fill:none; stroke:currentColor; stroke-width:1.6; stroke-linejoin:round;
  stroke-dasharray:1; stroke-dashoffset:1; opacity:.8;
}
/* Fill settles in behind the outline, then the outline retires. */
.dove__fill{ fill:currentColor; opacity:0; }

.screen--thanks.is-in .bird-wrap{
  animation:bird-float 11s ease-in-out 3.6s infinite;
}
.screen--thanks.is-in .dove__line{
  animation:bird-draw 1.5s var(--ease) 1.1s forwards,
            bird-line-out .9s var(--ease) 2.7s forwards;
}
.screen--thanks.is-in .dove__fill{
  animation:bird-fill 1.1s var(--ease) 2.5s forwards;
}
/* the follower trails the lead */
.screen--thanks.is-in .bird__follow-line{ animation-delay:1.5s, 3.05s; }
.screen--thanks.is-in .bird__follow-fill{ animation-delay:2.85s; }

@keyframes bird-draw    { to{ stroke-dashoffset:0; } }
@keyframes bird-line-out{ to{ opacity:0; } }
@keyframes bird-fill    { to{ opacity:var(--o,.6); } }
@keyframes bird-float{
  0%,100%{ transform:translate3d(0,0,0); }
  50%    { transform:translate3d(9px,-11px,0); }
}

/* The doves own the top-right corner on this screen */
.screen--thanks .florals .fl-tr{ display:none; }
/* no room for them on short screens */
@media (max-height:700px){ .bird-wrap{ display:none; } }

/* ── flying birds flock — Sections 1 & 7, injected by addFlock() ──────────
   Two wing strokes flap via rotate around their shared root; the whole bird
   drifts across on one long keyframe with a shallow rise-then-fall arc. */
.flock{ position:absolute; inset:0; z-index:1; pointer-events:none; overflow:hidden; }
.flock-bird{
  position:absolute; left:-10%;
  opacity:.32;
  color:var(--gold);
  animation:flock-fly var(--fdur,26s) linear var(--fdelay,0s) infinite;
  will-change:transform, opacity;
}
.flock-bird--dark{ color:var(--charcoal); --fop:.2; }
.flock-bird svg{
  width:100%; height:auto; display:block;
  fill:none; stroke:currentColor; stroke-width:1.6; stroke-linecap:round;
}
.flock-wing{ transform-origin:30px 11px; animation:wing-flap .5s ease-in-out infinite alternate; }
.flock-wing--r{ animation-direction:alternate-reverse; }
@keyframes wing-flap{
  from{ transform:rotate(0deg); }
  to  { transform:rotate(-20deg); }
}
/* opacity steps read var(--fop) per element, so light/dark birds fade to
   their own resting opacity even though they share one keyframe rule */
@keyframes flock-fly{
  0%  { transform:translate3d(0,6vh,0)     scale(.85); opacity:0; }
  8%  { opacity:var(--fop,.32); }
  50% { transform:translate3d(58vw,-6vh,0) scale(1); }
  92% { opacity:var(--fop,.32); }
  100%{ transform:translate3d(122vw,8vh,0) scale(1.1); opacity:0; }
}

.thanks__body{
  font-family:var(--serif); font-weight:300;
  font-size:clamp(1.1rem,5.2vw,1.34rem); line-height:1.7;
  color:var(--charcoal);
  margin-top:8px;
}
.thanks__body span{ display:block; text-wrap:balance; }
.thanks__body span + span{ margin-top:.5em; }
.thanks__dua{
  font-family:var(--serif); font-style:italic;
  font-size:1.06rem; color:var(--gold);
  margin-top:18px;
}
.thanks__with{
  font-family:var(--serif); font-style:italic;
  font-size:1rem; color:rgba(58,50,43,.6);
  margin-top:26px;
}
.thanks__names{
  font-family:var(--script);
  font-size:clamp(1.9rem,9.4vw,2.9rem); line-height:1.28;
  color:var(--gold);
  margin-top:6px;
  text-wrap:balance;
  text-shadow:0 1px 0 rgba(255,255,255,.6);
}

/* ═══════════════════════════════════════════════════════════════════════════
   REVEAL ANIMATIONS — fade-up + slight scale as each section enters view
   ═══════════════════════════════════════════════════════════════════════════ */
[data-reveal]{
  opacity:0;
  transform:translateY(22px) scale(.982);
  transition:
    opacity .95s var(--ease) calc(var(--d,0) * 1ms),
    transform 1.05s var(--ease) calc(var(--d,0) * 1ms);
  will-change:opacity, transform;
}
.is-in [data-reveal],
[data-reveal].is-in{ opacity:1; transform:none; }

/* ═══ RESPONSIVE ═══════════════════════════════════════════════════════════ */
@media (min-width:600px){
  :root{ --pad:40px; }
  .screen__inner{ max-width:470px; }
  .detail__txt b{ font-size:1.22rem; }
}
@media (min-width:1024px){
  .screen__inner{ max-width:520px; }
  .card--names{ padding:64px 40px 66px; }
}
/* ── Short viewports ─────────────────────────────────────────────────────
   Every screen must fit without inner scrolling, otherwise scroll-snap
   fights the user. Two tiers: small phones, then very short / landscape.  */
@media (max-height:820px){
  .screen{ padding-top:38px; padding-bottom:96px; }
  .card--names{ padding:40px 24px 42px; }
  .count{ margin-top:22px; padding:20px 8px 18px; }
  .details{ margin-top:20px; }
  .detail{ padding:13px 4px; }
  .venue{ margin-top:18px; padding:14px 14px 16px; }
  .btn-dark{ margin-top:14px; padding:12px 24px; }
  .rsvp{ margin-top:20px; }
  .thanks__body{ line-height:1.62; }
  .thanks__dua{ margin-top:14px; }
  .thanks__with{ margin-top:16px; }
  .thanks__names{ font-size:clamp(2.1rem,10.5vw,3rem); }
  .rule--dot{ margin-top:16px; }
}
@media (max-height:700px){
  .screen{ padding-top:28px; padding-bottom:86px; }
  .chev{ bottom:calc(env(safe-area-inset-bottom) + 24px); width:42px; height:42px; }
  .card--names{ padding:30px 20px 32px; }
  .env-stage{ margin:6px 0 2px; }
  .envelope{ width:min(258px,72vw); }
  .tap-label{ margin-top:24px; }
  .details{ margin-top:12px; }
  .detail{ padding:10px 4px; }
  .detail__ico{ flex-basis:38px; width:38px; height:38px; }
  .count{ margin-top:16px; padding:16px 6px 14px; }
  .count__note{ margin-top:14px; }
  .pill{ min-height:50px; padding:11px 50px; }
  .venue{ margin-top:14px; }
  .venue__map{ max-height:20vh; }
  .thanks__dua{ margin-top:12px; }
  .thanks__with{ margin-top:14px; }
  .rule--dot{ margin-top:14px; }
}
/* landscape phones — the last resort so nothing is ever clipped */
@media (max-height:600px){
  .screen{ padding-top:22px; padding-bottom:74px; }
  .chev{ bottom:calc(env(safe-area-inset-bottom) + 16px); width:38px; height:38px; }
  .eyebrow{ margin-bottom:10px; font-size:.6rem; }
  .h-serif{ font-size:clamp(1.4rem,5.4vw,1.82rem); }
  .divider{ margin:12px auto 2px; }
  .sub{ margin-top:6px; font-size:.88rem; }
  .rule--dot{ margin-top:10px; }

  .env-stage{ margin:2px 0 0; }
  .envelope{ width:min(212px,58vw); }
  .tap-label{ margin-top:16px; font-size:.66rem; }

  .card--names{ padding:22px 18px 24px; }
  .names{ font-size:clamp(1.6rem,7vw,2.1rem); }
  .names__date{ margin-top:10px; }
  .names__tag{ font-size:1rem; margin-top:8px; }

  .detail{ padding:8px 4px; }
  .detail__txt b{ font-size:1rem; }
  .flip{ font-size:1.6rem; }

  .rsvp{ margin-top:14px; padding:14px; gap:10px; }
  .pill{ min-height:46px; padding:10px 48px; }
  .pill__t{ font-size:.96rem; }
  .rsvp__msg{ margin-top:10px; }

  .venue__map{ max-height:17vh; }
  .venue__name{ margin-top:10px; font-size:1.1rem; }
  .btn-dark{ margin-top:10px; padding:10px 20px; font-size:.86rem; }

  .thanks__body{ font-size:1rem; line-height:1.5; }
  .thanks__dua{ font-size:.94rem; margin-top:8px; }
  .thanks__with{ margin-top:10px; font-size:.9rem; }
  .thanks__names{ font-size:1.9rem; }
}

/* ═══ ACCESSIBILITY ════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion:reduce){
  *{ animation-duration:.01ms !important; animation-iteration-count:1 !important;
     transition-duration:.01ms !important; scroll-behavior:auto !important; }
  [data-reveal]{ opacity:1 !important; transform:none !important; }
}
:focus-visible{ outline:2px solid var(--gold); outline-offset:3px; border-radius:4px; }
