:root{
  color-scheme: light;
  /* Gold-foil invitation palette, sampled pixel-by-pixel off the real
     printed cards. The stock is NOT black: it is a diagonal foil sweep
     that runs bright brass at the top-left and bottom-right corners
     (~#A2830E) and falls to a deep warm bronze through the middle
     (~#372301) — never lower than that. The ink/frame gold is #D6CA89.
     The --foil-* trio below are those measured stops; everything that
     should read as invitation stock is built from them. */
  --foil-hi:#A2830E;       /* bright brass corner of the sweep */
  --foil-mid:#503403;      /* the shoulder between corner and valley */
  --foil-low:#372301;      /* deepest bronze in the valley — not black */
  --ivory:#C89B2E;         /* page ground — a real, rich gold now (was the
                              dark foil valley); flat fallback used before
                              body::before's gradient paints, and the
                              ring-match colour for badges that sit ON the
                              gold page (.rsvp-monogram). .wax-seal, which
                              sits on the dark envelope instead, uses a
                              literal dark colour rather than this var. */
  --paper:#1C1201;         /* dark ink used ON gold badges & buttons */
  --paper-edge:#8A6C12;    /* brass edge line on card & envelope stock */
  --ink:#E7D9A0;           /* primary text — real invitation's champagne-gold ink */
  --ink-soft:#C6B083;      /* secondary text, muted tan-gold */
  --gold:#C0982E;          /* accent gold — lines, labels, icons */
  --gold-deep:#82611E;
  --gold-light:#F0DFA0;
  --brass-hi-rgb:183,152,16; /* bright foil-gradient corner (#B79810), sampled from the real cards */
  --frame-gold:#E3C168;    /* brighter than --gold, used only for the card/
                              envelope's own engraved hairlines and corner
                              flourishes — these need to stay crisp even
                              where they cross the gradient's dark valley,
                              which --gold (tuned for the page's lighter
                              backdrop) reads too dim to do */
  --line: rgba(198,152,60,.4);
  --shadow: rgba(0,0,0,.65);
  --glow: rgba(198,162,77,.22);
  /* The page ITSELF is now the gold surface (a real celebration-invitation
     look — think a card laid on gold silk, not gold text on black). The
     envelope/cards stay their own dark foil material (that's the real
     client artwork, untouched) so everything below needs a text/accent
     set for content sitting DIRECTLY on the gold page — --ink/--ink-soft
     stay exactly as they were and still mean "text on a DARK surface"
     (the coach-mark bubble, the confirm badge's paper text, etc.). */
  --ink-dark:#2A1B03;       /* primary text on the gold page — deep espresso */
  /* darkened from #6E4E12 once the gold page itself got deeper/richer —
     that value's own luminance was nearly identical to the new sweep's
     darkest point, which would have made secondary text disappear
     exactly where the gold gets deep */
  /* darkened again along with round 4 of the page background — its
     shadow point (~L56) is deep enough now that the previous #3D2C08
     (~L45) was getting close enough to read poorly against it */
  --ink-dark-soft:#2A1E06;  /* secondary/muted text on the gold page */
  --line-on-gold: rgba(38,26,4,.5); /* dividers sitting directly on the gold page — --line reads as barely-there on gold since it's the same hue family at low opacity */
  /* Envelope width drives the whole reveal's geometry. It is capped against
     viewport HEIGHT too (54svh->62svh), so the card never rises past the
     top of the screen mid-animation on short windows. The outer ceiling
     was 460px — on any normal desktop monitor min(vw,svh) comfortably
     clears that, so it was silently flattening the envelope down to a
     small object adrift in a lot of empty page on wide screens. Raised to
     680px: mobile is untouched (there, vw/svh are already the smaller
     term and never got near 460 to begin with), only wide/tall viewports
     get to actually use the room they have. */
  --env-w: clamp(260px, min(86vw, 62svh), 680px);
}

*{box-sizing:border-box;}
html{ background:var(--ivory); }
body{
  margin:0;
  background:var(--ivory);
  color:var(--ink-dark);
  font-family:'Cormorant Garamond', Georgia, serif;
  -webkit-font-smoothing:antialiased;
  /* NOT overflow-x:hidden here: on iOS Safari, ANY overflow on body/html
     breaks position:sticky in every descendant — which is exactly what
     pins the envelope while it opens. The one thing that could bleed
     horizontally (the giant watermark letters) is clipped on itself
     instead, below. */
  /* the whole page rises into view once on load rather than snapping in
     all at once — a small "curtain lifts" beat before the hero's own
     staggered reveal takes over */
  animation:page-fade-in 1.1s ease both;
}
@keyframes page-fade-in{ from{ opacity:0; } to{ opacity:1; } }
@media (prefers-reduced-motion: reduce){ body{ animation:none; } }

/* The page itself is now a genuinely gold surface — a real celebration-
   event look, like the invitation laid on gold silk, rather than gold
   text/accents on a black page. It's a sweep, not a flat fill, so it
   still reads as a lit material rather than a solid colour swatch: light
   warm gold at the corners, a slightly deeper amber through the middle —
   the deepest point (~#AD8A22) is still unmistakably gold, nothing here
   ever approaches brown-black the way the old dark version did. Painted
   as a FIXED layer so the whole scroll reads as one continuous sheet
   rather than the sweep stretching thin over several screens of
   document height. The envelope/cards keep their OWN dark foil gradient
   unchanged (that's the real client artwork) — they now read as a dark
   object resting on this gold ground, which is the whole effect. */
body::before{
  content:'';
  position:fixed; inset:0;
  z-index:0;
  pointer-events:none;
  /* Fourth pass: round 3 only deepened the MIDDLE of the sweep — at wide
     aspect ratios the visible area is dominated by the bright 0%/100%
     corners, which were still a fairly light mustard (#D4AF37) and read
     as washed-out/plain over the large areas they actually cover. This
     round darkens the WHOLE sweep, corners included, not just the
     shadow point — every stop dropped a full step, so even the
     brightest corner is a deeper, richer gold than before. Corner
     highlight blooms also pulled back (smaller radius, lower opacity) so
     they read as a tight glint rather than washing out a big patch of
     the corner back toward pale. */
  background:
    radial-gradient(68% 48% at 3% -4%, rgba(255,235,185,.35) 0%, rgba(255,235,185,0) 55%),
    radial-gradient(68% 48% at 97% 104%, rgba(255,235,185,.28) 0%, rgba(255,235,185,0) 55%),
    linear-gradient(158deg,
      #9C7A18 0%,
      #7E6212 20%,
      #664E0E 40%,
      #4A390A 50%,
      #664E0E 60%,
      #7E6212 80%,
      #9C7A18 100%);
}
/* bumped up again alongside the darker sweep — the two need to move
   together, since the vignette's whole job is adding shadow ON TOP of
   whatever the sweep itself already is */
body::after{
  content:'';
  position:fixed; inset:0;
  z-index:0;
  pointer-events:none;
  background:radial-gradient(122% 85% at 50% 40%, transparent 60%, rgba(80,56,8,.36) 100%);
}
h1,h2,h3{text-wrap:balance; font-weight:500; margin:0;}
p{margin:0;}
::selection{background:var(--gold-light); color:var(--paper);}

a, button{font-family:inherit;}

/* ---------- watermark ---------- */
.watermark{
  position:fixed; inset:0;
  overflow:hidden;
  display:flex; align-items:center; justify-content:center;
  pointer-events:none;
  z-index:0;
  font-family:'Marcellus', serif;
  font-size:clamp(9rem, 42vw, 26rem);
  /* now a soft IMPRESSION into the gold rather than a light sheen lifted
     off it — the page ground flipped from dark to gold, so the mark
     needs to read as slightly darker/deeper than its surroundings (like
     a blind emboss) instead of lighter */
  color:var(--gold-deep);
  opacity:.16;
  letter-spacing:.02em;
  user-select:none;
}

/* faint grain so the gold ground reads as a lit material, not a flat
   fill — overlay (not screen, which only ever brightens) works both ways
   against a midtone gold, giving the noise some actual texture instead of
   just a uniform light dusting */
.grain{
  position:fixed; inset:0;
  z-index:0;
  pointer-events:none;
  opacity:.05;
  mix-blend-mode:overlay;
  background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="180" height="180"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="2" stitchTiles="stitch"/></filter><rect width="180" height="180" filter="url(%23n)"/></svg>');
  background-size:180px 180px;
}

/* ---------- scroll progress ---------- */
/* a faint, ambient sense of "how far along am I" without adding a nav
   bar or anything the guest has to interpret */
.progress-track{
  position:fixed; top:0; left:0; right:0; height:3px;
  z-index:55;
  /* was a near-invisible gold-tinted line — fine against the old dark
     page, but the exact same hue at low opacity all but disappears
     against a gold page. Needs to read as a groove IN the gold now. */
  background:rgba(64,42,4,.22);
}
.progress-fill{
  height:100%; width:0%;
  background:linear-gradient(90deg, var(--gold-deep), var(--ink-dark));
  transition:width .1s linear;
}

/* ---------- persistent rsvp pill ---------- */
/* the same radial gold-to-deep-gold formula as the wax seal/badges,
   rather than a plain outline — this reads as struck from the same
   material as the rest of the mark instead of a generic web button */
.rsvp-pill{
  position:fixed; top:20px; right:20px; z-index:50;
  background:radial-gradient(circle at 30% 25%, var(--gold-light), var(--gold) 60%, var(--gold-deep) 100%);
  /* a plain --gold-deep border used to be enough separation against a
     dark page; against the new gold page the badge and its background
     are the same material, so the border/shadow are the ONLY thing that
     still reads it as an object sitting on the surface rather than a
     hole cut into it — darkened and thickened accordingly. */
  border:1.5px solid var(--ink-dark);
  color:var(--paper);
  font-family:'Jost', sans-serif;
  font-size:.72rem;
  font-weight:500;
  letter-spacing:.22em;
  padding:.7em 1.3em;
  border-radius:999px;
  cursor:pointer;
  box-shadow:0 8px 18px -6px rgba(42,27,3,.55), inset 0 0 0 1px rgba(255,255,255,.16);
  transition:box-shadow .3s ease, transform .3s ease, filter .3s ease;
}
.rsvp-pill:hover{ filter:brightness(1.1); box-shadow:0 10px 22px -10px var(--shadow), inset 0 0 0 1px rgba(255,255,255,.2); transform:translateY(-1px); }
.rsvp-pill:active{ transform:translateY(0) scale(.96); }
.rsvp-pill:focus-visible{ outline:2px solid var(--frame-gold); outline-offset:3px; }

main{position:relative; z-index:1;}

section{
  position:relative;
  padding:0 20px;
  display:flex;
  flex-direction:column;
  align-items:center;
}

/* ---------- hero ---------- */
.hero{
  min-height:100svh;
  justify-content:center;
  text-align:center;
  z-index:1;
}
.hero-inner{
  max-width:560px;
  transition:opacity .3s ease-out, transform .3s ease-out;
  will-change:opacity, transform;
}
@keyframes rise-in{ from{ opacity:0; transform:translateY(16px); } to{ opacity:1; transform:translateY(0); } }
.hero-inner > *{ animation:rise-in .9s cubic-bezier(.22,.68,0,1.03) both; }
.hero-inner > *:nth-child(1){ animation-delay:.05s; }
.hero-inner > *:nth-child(2){ animation-delay:.16s; }
.hero-inner > *:nth-child(3){ animation-delay:.28s; }
.hero-inner > *:nth-child(4){ animation-delay:.4s; }
.hero-inner > *:nth-child(5){ animation-delay:.5s; }
.hero-inner > *:nth-child(6){ animation-delay:.6s; }
.hero-inner > *:nth-child(7){ animation-delay:.7s; }
.eyebrow{
  font-family:'Jost', sans-serif;
  font-size:.78rem;
  letter-spacing:.32em;
  text-transform:uppercase;
  color:var(--ink-dark-soft);
  margin-bottom:1.4rem;
}
.hero h1{
  font-size:clamp(2.6rem, 8vw, 4.6rem);
  letter-spacing:.02em;
  text-transform:uppercase;
  /* a faint LIGHT emboss now, not a dark drop shadow — the text itself is
     dark ink on a light gold page, so what sells depth here is a hint of
     the page's own highlight catching the letterform's lower edge, the
     way foil-stamping presses a shape rather than printing a flat shadow
     under it */
  text-shadow:0 1px 0 rgba(255,255,255,.4);
}
.hero h1{
  /* a slow band of brighter gold light drifting across the name — the
     same "foil catching the light" idea used on the cards, but on the
     ink itself. Painted as a background clipped to the glyphs rather than
     an animated color so it reads as light moving over one fixed
     material, not the text changing color. Base flipped from light
     champagne to dark espresso now that the page itself is gold — the
     shimmer band (gold-light) is still brighter than its surroundings
     either way. (Used to also target .invite-card .who — that element no
     longer exists now that the cards show the real invitation artwork
     instead of recreated text.) */
  color:var(--ink-dark);
  background-image:linear-gradient(100deg,
    var(--ink-dark) 42%, var(--ink-dark) 46%,
    var(--gold-light) 50%,
    var(--ink-dark) 54%, var(--ink-dark) 100%);
  background-size:280% 100%;
  background-position:160% 0;
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent;
  animation:name-shimmer 7s ease-in-out 2.4s infinite;
}
@keyframes name-shimmer{
  0%, 55%{ background-position:160% 0; }
  85%, 100%{ background-position:-60% 0; }
}
@media (prefers-reduced-motion: reduce){
  .hero h1{ animation:none; background-position:0 0; -webkit-text-fill-color:var(--ink-dark); }
}
.hero .occasion-label{
  margin-top:1.1rem;
  font-family:'Jost', sans-serif;
  font-size:clamp(.85rem, 2vw, 1rem);
  letter-spacing:.4em;
  text-transform:uppercase;
  /* --gold sits well inside the page background's own brightness range
     now, so a label set in it would nearly vanish — needs real ink to
     read as a label rather than dissolve into the gold behind it */
  color:var(--ink-dark);
}
.hero .date-line{
  margin-top:.9rem;
  font-style:italic;
  font-size:clamp(1.05rem,3vw,1.3rem);
  color:var(--ink-dark-soft);
}

/* small line-dot-line ornament used wherever the invitation would
   print a flourish between sections */
.flourish{
  display:flex; align-items:center; justify-content:center;
  gap:.55rem; margin:1.8rem auto;
}
/* --gold read fine as a thin line against the old dark page; against the
   new gold page it's within the background's own tonal range and all but
   disappears, so these lines/dot switch to dark ink instead */
.flourish .fl-line{ width:38px; height:1px; flex:none; }
.flourish .fl-line.l{ background:linear-gradient(90deg, transparent, var(--ink-dark-soft)); }
.flourish .fl-line.r{ background:linear-gradient(90deg, var(--ink-dark-soft), transparent); }
.flourish .fl-dot{
  width:5px; height:5px; background:var(--ink-dark); transform:rotate(45deg); flex:none;
  /* the glow stays gold-toned even though the dot itself is now dark ink —
     a bit of warmth still catching light, just on a darker mark */
  box-shadow:0 0 7px 1px rgba(224,180,80,.5);
}
.flourish.small{ margin:.55rem auto; }
.flourish.small .fl-line{ width:22px; }

.countdown{
  display:flex; align-items:baseline; justify-content:center;
  gap:.5rem; flex-wrap:wrap;
  margin-top:.4rem;
  padding-block:1.1rem;
  border-top:1px solid var(--line-on-gold);
  border-bottom:1px solid var(--line-on-gold);
}
/* each unit as its own small display case rather than bare numbers
   floating in a row — a hairline edge and a dark interior gradient give
   the digits the same "set into the stock" feel as everything else on
   the card, instead of looking like plain webpage text dropped in. The
   interior needed to go from a barely-there tint to genuinely dark once
   the page itself turned gold — these read as small dark plaques resting
   on the gold surface, independent of whatever's behind them, which is
   exactly what keeps the gold numbers inside legible. */
.cd-unit{
  display:flex; flex-direction:column; align-items:center; min-width:3.6rem;
  overflow:hidden; padding:.55rem .3rem .45rem;
  border:1px solid rgba(255,238,196,.2);
  border-radius:7px;
  background:linear-gradient(165deg, #4A3306 0%, #1C1201 100%);
  box-shadow:0 4px 10px -4px rgba(42,27,3,.5);
}
.cd-num{
  display:inline-block;
  font-family:'Jost', sans-serif;
  font-variant-numeric:tabular-nums;
  font-size:clamp(1.6rem,5vw,2.3rem);
  font-weight:500;
  color:var(--gold);
  letter-spacing:.03em;
}
/* a small roll each time this unit's value actually changes — a refined
   stand-in for a mechanical flip-clock digit, not a jarring instant swap */
@keyframes cd-tick{
  0%{ transform:translateY(0); opacity:1; }
  40%{ transform:translateY(-40%); opacity:.35; }
  41%{ transform:translateY(40%); }
  100%{ transform:translateY(0); opacity:1; }
}
.cd-num.tick{ animation:cd-tick .5s cubic-bezier(.4,0,.2,1); }
.cd-label{
  font-family:'Jost', sans-serif;
  font-size:.62rem;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--ink-soft); /* stays as-is: this sits inside the now-dark .cd-unit chip, not on the gold page directly */
  margin-top:.2rem;
}
/* unlike .cd-label, the separator dots sit directly on the gold page
   between chips, so they need the dark-ink treatment, not --ink-soft */
.cd-sep{ color:var(--ink-dark-soft); font-size:1.4rem; align-self:flex-start; margin-top:.3rem; }

/* a real <button> now, not just a decorative cue — reset the browser
   button chrome but keep every visual property it already had */
.scroll-cue{
  -webkit-appearance:none; appearance:none;
  border:none; background:none; padding:0; margin:2.2rem auto 0;
  cursor:pointer;
  /* a <button> shrinks to fit its content's width even as a flex
     container (unlike a plain div) — without the auto side margins
     above, that narrower box just sits flush against the LEFT edge of
     its parent instead of centering, even though text-align:center
     made everything above it (which stayed full-width text) look fine */
  width:fit-content;
  display:flex; flex-direction:column; align-items:center; gap:.75rem;
  font-family:'Jost', sans-serif;
  font-size:.76rem;
  font-weight:500;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--ink-dark-soft);
}
.scroll-cue-icon{
  width:48px; height:48px;
  border-radius:50%;
  border:1.5px solid var(--gold);
  background:var(--paper);
  display:flex; align-items:center; justify-content:center;
  color:var(--gold);
  box-shadow:0 8px 18px -10px var(--shadow);
  animation:cue-bounce 1.8s ease-in-out infinite;
  transition:transform .25s ease, box-shadow .25s ease, background .25s ease;
}
.scroll-cue-icon svg{ width:22px; height:22px; }
@keyframes cue-bounce{
  0%,100%{ transform:translateY(0); }
  50%{ transform:translateY(9px); }
}
/* an obvious, tactile response to hover/press — reassurance for anyone
   unsure whether this round shape is actually clickable */
.scroll-cue:hover .scroll-cue-icon{
  background:var(--gold);
  color:var(--paper);
  box-shadow:0 12px 22px -10px var(--shadow);
  transform:scale(1.08);
}
.scroll-cue:active .scroll-cue-icon{ transform:scale(.96); }
.scroll-cue:focus-visible .scroll-cue-icon{ outline:2px solid var(--gold); outline-offset:3px; }

/* ---------- invitation stage ---------- */
.invite-stage{ min-height:175vh; padding-top:0; z-index:2; }
.stage-inner{
  position:sticky; top:0;
  min-height:100svh;
  width:100%;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:1.6rem;
}
/* soft gold light behind the envelope, like a spotlight, once it opens */
.stage-inner::before{
  content:'';
  position:absolute; top:50%; left:50%;
  width:min(70vmin, 640px); aspect-ratio:1;
  transform:translate(-50%,-50%);
  border-radius:50%;
  background:radial-gradient(circle, var(--gold-light) 0%, transparent 68%);
  opacity:0;
  filter:blur(50px);
  transition:opacity 1.4s ease;
  pointer-events:none;
}
.stage-inner:has(.envelope.is-open)::before{ opacity:.4; }

.envelope-wrap{
  perspective:1800px;
  opacity:0;
  transform:translateY(46px);
  transition:opacity 1s ease, transform 1s cubic-bezier(.22,.68,0,1.03);
  will-change:opacity, transform;
}
.envelope-wrap.is-visible{ opacity:1; transform:translateY(0); }

.envelope{
  position:relative;
  width:var(--env-w);
  aspect-ratio: 5 / 7;
  transform-style:preserve-3d;
  /* held until both cards are out — gliding the envelope (and the pocket
     with it) mid-reveal would drag a card that is still inside it */
  transition:transform 1s cubic-bezier(.22,.61,.24,1) 4.6s;
}
/* The stage centres the ENVELOPE box, but the cards end up floating well
   above it. Once they're out and the shell has dissolved, glide the whole
   assembly down by that difference so the CARDS land dead centre. */
.envelope.is-open{ transform:translateY(calc(var(--env-w) * 0.2)); }

.env-shadow{
  position:absolute; left:50%; bottom:-6%;
  width:74%; height:22px;
  background:radial-gradient(ellipse at center, var(--shadow) 0%, transparent 72%);
  transform:translateX(-50%) scaleX(1);
  filter:blur(2px);
  opacity:.45;
  transition:opacity .7s ease 4.6s, transform 1s ease 4.6s;
  z-index:0;
  pointer-events:none;
}
/* the envelope's own contact shadow hands off to .cards-position::after
   (the cards' shadow) once the cards have fully emerged */
.envelope.is-open .env-shadow{ opacity:0; transform:translateX(-50%) scaleX(1.25); }

.env-back{
  position:absolute; inset:0;
  /* same widened-contrast foil as the cards (see .invite-card), held a
     touch darker overall so the invitations read as lighter stock sliding
     out of it */
  background:linear-gradient(152deg,
    #B8901E 0%,
    #7C5D0D 16%,
    #402E04 32%,
    #170D00 48%,
    #0C0600 58%,
    #1C1201 72%,
    #2E2004 86%,
    #40300A 100%);
  border:1px solid var(--paper-edge);
  border-radius:4px;
  box-shadow:0 24px 50px -18px var(--shadow), inset 0 0 0 1px rgba(255,255,255,.06);
  z-index:1;
  transition:opacity .7s ease 4.6s;
  pointer-events:none;
}
.env-back::before{
  content:'';
  position:absolute; inset:10px;
  border:1px solid var(--line);
  border-radius:2px;
  opacity:.6;
}
/* the empty envelope shell dissolves once its job is done, instead of
   lingering behind the cards as a large blank box. It has to outlast BOTH
   cards coming out — it used to fade at .95s, while card B was still
   inside it, which is why the second card appeared out of thin air. */
.envelope.is-open .env-back{ opacity:0; }

/* The front pocket the cards are drawn out of. Sits above them (z-index 4)
   so the part of a card still inside the envelope is genuinely hidden
   rather than just faded — occlusion is the only thing that makes a card
   read as emerging from somewhere. Brighter than .env-back because this is
   the near face of the envelope, catching more light. */
.env-front{
  position:absolute; left:0; right:0; top:70%; bottom:0;
  background:linear-gradient(160deg,
    #D6AF48 0%,
    #97730F 30%,
    #4A3606 58%,
    #190E00 82%,
    #2E2004 100%);
  border-top:1px solid var(--paper-edge);
  border-radius:0 0 4px 4px;
  /* thrown upward, onto the card, so the card looks tucked behind this
     edge instead of merely overlapped by it, PLUS a crisp bright line
     right on the fold — real paper catches a hard highlight exactly at a
     crease, not a soft blur, which is what actually sells the fold */
  box-shadow:0 -14px 22px -10px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,238,196,.5);
  z-index:4;
  transition:opacity .8s ease 4.6s;
  /* purely visual occlusion, and it sits ABOVE the cards in z-index — once
     it's faded out this was silently still catching clicks/hover meant
     for whatever card happens to sit underneath it on screen */
  pointer-events:none;
}
.envelope.is-open .env-front{ opacity:0; }

/* the flap folds down from the top edge; opening rotates it up & back */
.env-flap{
  position:absolute; top:0; left:0; width:100%; height:42%;
  /* the flap catches the light rather than falling away from it, so its
     sweep runs the opposite direction to the envelope body underneath —
     bright along the top edge, dark down at the point, which also makes
     the seal (sitting right on that point) pop against something dark
     instead of a similarly-bright flap washing it out */
  background:
    radial-gradient(160% 140% at 20% -10%, rgba(255,238,190,.55) 0%, rgba(var(--brass-hi-rgb),0) 46%),
    linear-gradient(200deg, #CFA83E 0%, #7C5D0D 38%, #1B1000 78%, #2E2004 130%);
  clip-path:polygon(0 0, 100% 0, 50% 100%);
  transform-origin:top center;
  transform:rotateX(0deg);
  transition:transform .85s cubic-bezier(.5,.02,.16,1);
  backface-visibility:hidden;
  z-index:3;
  box-shadow:0 1px 0 rgba(255,255,255,.08) inset;
  /* drop-shadow (not box-shadow) follows the clip-path's actual triangular
     silhouette, so this reads as a hard highlight right along the folded
     edge rather than a rectangle poking out past the point */
  filter:drop-shadow(0 1px 0 rgba(255,238,196,.4));
  pointer-events:none;
}
.envelope.is-open .env-flap{ transform:rotateX(-162deg); }

/* 42% is the flap's own height, i.e. the point of the triangle — the seal
   sits on that fold exactly as it did when it was nested inside the flap,
   but as a sibling it escapes the flap's clip-path. z-index clears both
   the flap (3) and the front pocket (4). */
.seal-wrap{
  position:absolute; left:50%; top:42%; width:46px; height:46px;
  transform:translate(-50%,-52%);
  z-index:5;
  transition:opacity .5s ease .1s, transform .5s ease .1s;
  /* REAL bug this uncovered: once faded to opacity 0, this 46x46px box
     was still sitting at z-index 5 — above both settled cards (2/3) —
     and its default pointer-events:auto meant a click or hover landing
     in that small central patch hit this invisible, non-interactive
     wrapper instead of falling through to the card underneath. Found by
     testing a genuine mouse hover (not just eyeballing a screenshot) and
     getting no :hover match; document.elementFromPoint() at the card's
     centre confirmed .seal-wrap was the actual hit target. */
  pointer-events:none;
}
.envelope.is-open .seal-wrap{ opacity:0; transform:translate(-50%,-52%) scale(.7) rotate(-14deg); }
.seal-wrap::after{
  content:'';
  position:absolute; inset:-5px;
  border:1px solid rgba(198,162,77,.35);
  border-radius:50%;
}
.wax-seal{
  width:100%; height:100%; border-radius:50%;
  background:radial-gradient(circle at 32% 30%, var(--gold-light), var(--gold) 55%, var(--gold-deep) 100%);
  border:1px solid var(--gold-deep);
  display:flex; align-items:center; justify-content:center;
  font-size:1.05rem; color:var(--paper);
  /* the ring uses a literal dark colour, NOT var(--ivory) — that token is
     now the page's gold ground, but this seal sits on the dark envelope
     flap, a different surface entirely; its ring has to match THAT. */
  box-shadow:0 6px 14px -6px var(--shadow), inset 0 0 0 3px rgba(255,255,255,.14),
             0 0 0 3px #2C1C01, 0 0 0 4px var(--gold-deep);
}

/* ---------- YN monogram — the site's logo mark ---------- */
/* Tightened into a real interlocking lockup (negative tracking + a thin
   crest hairline between the two letters) rather than plain spaced-out
   "YN" text, reused everywhere the mark appears: both card seals, the
   envelope's wax seal, the watermark and the RSVP badge. */
.yn-mark{
  position:relative;
  font-family:'Marcellus', serif;
  letter-spacing:-.06em;
}
/* .watermark already declares position:fixed (needed to pin it as a true
   full-viewport background layer), but .yn-mark's position:relative has
   the same specificity and sits later in this file, so it was silently
   winning — .watermark rendered as a normal-flow block instead, adding
   its own ~500px of real height at the very top of <body> and shoving
   every section (hero included) down by that much. Two classes beats one,
   so this wins regardless of source order — the fix that actually holds. */
.watermark.yn-mark{ position:fixed; }
.yn-mark::after{
  content:'';
  position:absolute; left:50%; top:50%;
  width:1px; height:.85em;
  background:currentColor;
  opacity:.55;
  transform:translate(-50%,-50%);
}
/* the seal "cracks" the instant the envelope opens, just before it fades
   away with the flap — a small narrative beat, not just a disappearance */
@keyframes seal-crack{
  0%{ transform:scale(1) rotate(0deg); }
  35%{ transform:scale(1.18) rotate(-4deg); }
  60%{ transform:scale(.9) rotate(3deg); }
  100%{ transform:scale(1) rotate(0deg); }
}
.envelope.is-open .wax-seal{ animation:seal-crack .4s ease-out; }

/* ---------- the two invitation cards ---------- */
/* both cards share this box's geometry (inset:0 each), each then applies
   its own offset/rotation transform on top so they fan out like two
   physical cards pulled from the same envelope */
.cards-position{
  position:absolute;
  left:50%; bottom:5%;
  /* matches the real weekday card's own shape (576x960 = 0.6) almost
     exactly — that card fills this box edge to edge, and it's also the
     TALLER of the two real cards, so it sets the height the shorter
     landscape Shabbos card gets centred inside (see .invite-card below). */
  width:86%; aspect-ratio:576/960;
  /* left:50% anchors the BOX's left edge to center — without this
     translateX(-50%) the whole 86%-wide box (and both cards inside it)
     sits shifted a half-width to the right of center instead of centred,
     clipping off the right edge of narrower viewports. */
  transform:translateX(-50%);
  transform-origin:center bottom;
  z-index:2;
  /* A card waiting in the pocket is pushed down far enough that it hangs
     well below the envelope; .env-front hides the middle of it but nothing
     hid the part below the envelope's own bottom edge. This clips exactly
     that, so only what has actually emerged is ever painted. The -5% keeps
     the settled cards' drop shadows from being sliced off, and the whole
     clip is dropped once both cards are out — before .cards-hint, which
     lives below this box and would otherwise be clipped away entirely. */
  clip-path:inset(-200% -200% -5% -200%);
  transition:clip-path 0s linear 5s;
}
.envelope.is-open .cards-position{
  clip-path:inset(-200%);
  animation:float 5.5s ease-in-out 5.4s infinite;
}
@keyframes float{
  0%,100%{ transform:translateX(-50%) translateY(0) rotate(.35deg); }
  50%{ transform:translateX(-50%) translateY(-10px) rotate(-.35deg); }
}
/* grounds the pair once the envelope shell has dissolved */
.cards-position::after{
  content:'';
  position:absolute; left:50%; bottom:-8%;
  width:78%; height:18px;
  transform:translateX(-50%);
  background:radial-gradient(ellipse at center, var(--shadow) 0%, transparent 72%);
  filter:blur(6px);
  opacity:0;
  transition:opacity .8s ease 5.1s;
  z-index:1;
  pointer-events:none;
}
.envelope.is-open .cards-position::after{ opacity:.6; }

.invite-card{
  /* inset:0 + margin:auto (rather than stretching to fill, as it used to)
     lets each card keep ITS OWN real aspect-ratio (set per side below)
     while still centering inside the shared box above — needed because
     the two real cards are genuinely different shapes: forcing the
     landscape Shabbos card into the same tall box as the portrait
     Weekday one made it render as a thin strip with huge empty margins
     top and bottom. width:100% + auto height means only the SHORTER
     (landscape) card ever has margin space to center into; the taller
     one already fills the box edge to edge. */
  position:absolute; inset:0; margin:auto;
  width:100%; height:auto;
  border-radius:3px;
  /* v1 of this gradient sampled the real card's hue correctly but
     compressed everything into a narrow 40-127 luminance band, which is
     why it read as flat brown mud instead of foil. A diagonal sweep this
     rich in real gold foil runs roughly 8-185: a genuine near-black
     shadow, a genuine bright metallic corner, not two shades of the same
     midtone. Widening the range is what actually reads as "foil" rather
     than "brown paper" — the hue barely changed, the CONTRAST did. */
  background:
    /* a small, sharp specular glint at the corner the light hits — real
       foil has a hard hotspot, not just an evenly bright zone */
    linear-gradient(160deg, rgba(255,241,208,.4) 0%, rgba(255,241,208,0) 11%),
    linear-gradient(152deg,
      #E7C468 0%,
      #C29A24 11%,
      #8A6A0F 24%,
      #4E3805 38%,
      #1E1200 52%,
      #0F0800 62%,
      #241704 75%,
      #3B2A08 88%,
      #52400E 100%);
  border:1px solid var(--paper-edge);
  /* the outer drop shadow plus two INSET shadows: a bright 1px rim right
     at the edge (a bevel catching light, like a card under glass) and a
     soft dark ring just inside that (recesses the "mat" the image sits
     in) — this is what turns a bordered box into something that reads as
     a physically framed object instead of a rectangle with a photo in it */
  box-shadow:
    0 30px 60px -20px var(--shadow), 0 0 46px -14px var(--glow),
    inset 0 0 0 1px rgba(255,238,196,.22),
    inset 0 0 26px 4px rgba(0,0,0,.4);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center;
  /* small and uniform now — this used to be sized for the recreated
     text's own margins (6.2%/8%); the real artwork just needs a sliver of
     this box's own foil-gradient "mat" showing around it */
  padding:3%;
  cursor:pointer;
  /* fully opaque even while waiting: the card is hidden by the pocket in
     front of it, not by being transparent. Fading a card in is what made
     the old reveal look like it materialised rather than came out. */
  opacity:1;
  /* tucked down inside the pocket — deep enough that its top edge sits
     below .env-front's top edge, so none of it shows until it moves */
  transform:translate(0,78%) scale(.98) rotate(0deg);
  transition:transform .95s cubic-bezier(.2,.78,.26,1), opacity .6s ease, box-shadow .4s ease;
  will-change:transform, opacity;
}
/* the real cards' own shapes — Shabbos card is landscape, Weekday is
   portrait and matches .cards-position closely already (see above).
   Because it's landscape, card-a's own rendered height is barely 40% of
   .cards-position's height (vs. card-b's ~100%) — the base rule's
   translate(0,78%) tuck is 78% of the CARD'S OWN height, so the same
   percentage moves a much shorter card a much smaller distance in real
   pixels, nowhere near enough to clear .env-front's line (measured:
   pokes out ~90px at every viewport otherwise). Retuned empirically
   against that measurement rather than derived by hand, since padding
   and the shared box's exact proportions both feed into the real number. */
.invite-card.card-a{ aspect-ratio:1488/996; transform:translate(0,145%) scale(.98) rotate(0deg); }
.invite-card.card-b{ aspect-ratio:576/960; transform:translate(0,78%) scale(.965) rotate(0deg); }

/* Step 1 — the card is drawn straight up out of the pocket, square to the
   viewer, and held there for a beat. Step 2 (.is-out below) then only fans
   it sideways into its resting place. Splitting the move in two is what
   reads as being pulled out of something; one continuous tween from inside
   the pocket to the final angled position just looks like the card slid
   diagonally. Both steps are transitions rather than keyframes so a later
   tap can still re-transition the card to .is-front.
   This lands at the SAME height the card rests at, deliberately: an
   .is-rising that overshoots upward makes the card visibly sink back into
   the envelope on the second beat, which reads as it being swallowed
   again rather than settling. */
.invite-card.is-rising{ transform:translate(0,-1%) scale(1.02) rotate(0deg); }
.invite-card.card-a.is-out{ transform:translate(-9%,0) scale(1) rotate(-3deg); z-index:3; }
.invite-card.card-b.is-out{ transform:translate(9%,1%) scale(1) rotate(4deg); z-index:2; }
/* whichever card was tapped last comes forward, dead centre */
.invite-card.is-out.is-front{ transform:translate(0,-1%) scale(1.04) rotate(0deg); z-index:5; }
.invite-card.is-front{
  box-shadow:0 34px 70px -18px var(--shadow), 0 0 60px -10px var(--glow);
}
.invite-card:focus-visible{ outline:2px solid var(--gold); outline-offset:4px; }

/* a single soft gold sheen sweeps across each card the moment IT is
   revealed — relative to its own .is-out, so the two cards' sheens land
   naturally staggered without any extra timing math */
.invite-card::before{
  content:'';
  position:absolute; inset:0;
  z-index:6;
  border-radius:3px;
  background:linear-gradient(115deg, transparent 40%, rgba(240,223,160,.32) 50%, transparent 60%);
  background-size:250% 250%;
  background-position:130% 0;
  pointer-events:none;
  opacity:0;
}
.invite-card.is-rising::before{ animation:sheen 1.3s ease-out .35s 1; }

/* a thin metallic bezel ring traced around the card — a gradient "border"
   painted only into the ring itself (background clipped to the border
   box, masked out where the padding/content box would be), so it reads
   as a distinct frame edge rather than a flat single-colour outline */
.invite-card::after{
  content:'';
  position:absolute; inset:0;
  z-index:7;
  border-radius:3px;
  padding:1.5px;
  background:linear-gradient(155deg, rgba(255,241,208,.85) 0%, rgba(120,90,10,.15) 45%, rgba(120,90,10,.15) 55%, rgba(255,241,208,.65) 100%);
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite:exclude;
  pointer-events:none;
}
@keyframes sheen{
  0%{ background-position:130% 0; opacity:0; }
  15%{ opacity:.8; }
  55%{ opacity:.3; }
  100%{ background-position:-30% 0; opacity:0; }
}
/* once settled, each card still catches a slow ambient glint every so
   often — foil under real light is never perfectly static, and this is
   what keeps the resting cards feeling like metal rather than a printed
   flat image once the reveal itself is long over */
.invite-card.is-out:not(.is-rising)::before{
  animation:sheen-ambient 9s ease-in-out 1s infinite;
}
@keyframes sheen-ambient{
  0%, 40%{ background-position:140% 0; opacity:0; }
  58%{ opacity:.5; }
  76%, 100%{ background-position:-40% 0; opacity:0; }
}
@media (prefers-reduced-motion: reduce){
  .invite-card.is-out:not(.is-rising)::before{ animation:none; }
}

/* a light lift on hover, mouse-driven devices only — a physical card on a
   table responds when you reach for it; nothing here should trigger on
   touch, which already has its own tap-to-front interaction */
@media (hover:hover) and (pointer:fine){
  /* a real "reach for it" zoom, not a light lift — big enough that hovering
     genuinely previews what tapping (which opens the full lightbox) is
     about to do, rotation eased toward 0 so it squares up as it grows
     instead of just getting bigger on a tilt */
  .invite-card.card-a.is-out:hover{ transform:translate(-9%,-22px) scale(1.14) rotate(-1deg); box-shadow:0 46px 90px -20px var(--shadow), 0 0 64px -10px var(--glow); z-index:8; }
  .invite-card.card-b.is-out:hover{ transform:translate(9%,-20px) scale(1.14) rotate(1deg); box-shadow:0 46px 90px -20px var(--shadow), 0 0 64px -10px var(--glow); z-index:8; }
  .invite-card.is-out.is-front:hover{ transform:translate(0,-22px) scale(1.18) rotate(0deg); z-index:8; }
  .invite-card:hover .card-zoom-cue{ opacity:1; transform:translate(-50%,-50%) scale(1); }
}
/* touch devices have no hover to preview with, so the cue sits faintly
   visible from the start instead of appearing only on an interaction that
   can't happen — it's the only advance notice a touch guest gets that
   tapping does something beyond just reordering the cards */
@media (hover:none){
  .card-zoom-cue{ opacity:.85; transform:translate(-50%,-50%) scale(1); }
}
.card-zoom-cue{
  position:absolute; left:50%; top:50%;
  transform:translate(-50%,-50%) scale(.8);
  width:44px; height:44px;
  border-radius:50%;
  background:rgba(15,9,0,.55);
  border:1px solid rgba(255,238,196,.4);
  color:var(--gold-light);
  display:flex; align-items:center; justify-content:center;
  opacity:0;
  pointer-events:none;
  z-index:6;
  backdrop-filter:blur(2px);
  transition:opacity .25s ease, transform .25s ease;
}
.card-zoom-cue svg{ width:20px; height:20px; }

/* ---------- full-screen card zoom ---------- */
/* opened by tapping either card — the real artwork's own printed text
   (bilingual, on the Shabbos card) is genuinely small at on-page card
   size, so this is a reading tool as much as it is a "premium" flourish */
.card-zoom-overlay{
  position:fixed; inset:0;
  z-index:200; /* clears everything: rsvp-pill (50), progress-track (55) */
  display:flex; align-items:center; justify-content:center;
  padding:6vh 5vw;
  background:rgba(8,5,0,.88);
  backdrop-filter:blur(6px);
  opacity:0;
  visibility:hidden;
  transition:opacity .35s ease, visibility 0s linear .35s;
}
.card-zoom-overlay.is-open{
  opacity:1;
  visibility:visible;
  transition:opacity .35s ease, visibility 0s linear 0s;
}
body.zoom-locked{ overflow:hidden; }
.card-zoom-img{
  max-width:100%; max-height:100%;
  width:auto; height:auto;
  object-fit:contain;
  border-radius:4px;
  box-shadow:0 40px 100px -20px rgba(0,0,0,.8), 0 0 0 1px var(--paper-edge);
  transform:scale(.92);
  transition:transform .35s cubic-bezier(.22,.68,0,1.03);
}
.card-zoom-overlay.is-open .card-zoom-img{ transform:scale(1); }
.card-zoom-close{
  position:absolute; top:20px; right:20px; z-index:1;
  width:42px; height:42px;
  border-radius:50%;
  border:1px solid var(--gold-deep);
  background:rgba(15,9,0,.7);
  color:var(--gold-light);
  display:flex; align-items:center; justify-content:center;
  cursor:pointer;
  transition:background .25s ease, transform .25s ease;
}
.card-zoom-close svg{ width:18px; height:18px; }
.card-zoom-close:hover{ background:var(--gold-deep); transform:scale(1.06); }
.card-zoom-close:focus-visible{ outline:2px solid var(--gold); outline-offset:3px; }
@media (prefers-reduced-motion: reduce){
  .card-zoom-overlay, .card-zoom-img{ transition:opacity .01ms linear, visibility 0s linear; }
}

/* The real artwork now IS the card's only child (see index.html) — the
   old nth-child(-n+6) split existed to keep 6 static frame/corner
   elements from fading like the text content that used to follow them.
   Those elements are gone, so this is just a plain single-child reveal:
   fade + rise in once the card is drawn out of the pocket. */
.invite-card > *{ opacity:0; }
.invite-card.is-rising > *{
  animation:rise-in .7s cubic-bezier(.22,.68,0,1.03) .85s both;
}

.card-art{
  width:100%; height:100%;
  /* "contain", never "cover" — the two real cards are different shapes
     (one landscape, one portrait); cover would crop the client's actual
     artwork to fit a box it was never designed for. Contain shows the
     whole card and lets the existing foil-gradient .invite-card
     background act as a mat around it wherever the shapes don't match. */
  object-fit:contain;
  border-radius:2px;
  pointer-events:none; /* clicks still hit .invite-card's own button role */
  filter:drop-shadow(0 10px 22px rgba(0,0,0,.45));
}

/* .seal, .invite-eyebrow, .who, .invite-line, .invite-hosts,
   .invite-rsvp-note, .schedule-item and their small-screen overrides
   below were the recreated-text build of the card face — removed along
   with the matching HTML once the cards switched to the real invitation
   artwork (see .card-art above and index.html). The same coin-badge
   treatment .seal used still lives on, under .wax-seal/.rsvp-monogram. */

/* sits right under the pair (not a separate block far below the whole
   envelope) so it reads as clearly "about this" */
.cards-hint{
  position:absolute; top:100%; left:50%;
  z-index:4; /* above both cards (z-index 2/3) so the peeking back card
                never paints over this text — it has no z-index of its
                own otherwise, so DOM order alone isn't enough here */
  /* top:100% anchors this to .cards-position's box, but the fanned-out
     card B is translated down 3% AND rotated 4deg, so its bottom corner
     hangs below that box by roughly .04 * --env-w. A flat 14px gap put
     this text straight on top of that corner at every screen size, so the
     clearance has to scale with the envelope the same way the overhang
     does — measured to leave ~16px of real daylight from 360px to 1870px. */
  margin-top:calc(14px + var(--env-w) * .075);
  width:max-content; max-width:86vw;
  opacity:0; transform:translateX(-50%) translateY(2px) scale(.92);
  transition:opacity .5s ease, transform .5s cubic-bezier(.22,.68,0,1.03);
}
.cards-hint.ready{ opacity:1; transform:translateX(-50%) translateY(0) scale(1); }
/* an app-onboarding coach mark, not a plain caption: a rounded bubble with
   a small tail pointing up at the cards, so it reads as "here's a gesture
   you haven't tried yet" rather than a caption labelling what's already
   in view */
.hint-bubble{
  position:relative;
  display:flex; align-items:center; justify-content:center; gap:.5rem;
  padding:.65em 1.1em;
  border-radius:999px;
  background:linear-gradient(165deg, #2A1B03, #150C00);
  border:1px solid rgba(255,238,196,.3);
  box-shadow:0 10px 22px -10px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.08), 0 0 0 3px rgba(224,180,80,.08);
  font-family:'Jost', sans-serif; font-size:.68rem; letter-spacing:.14em;
  text-transform:uppercase; color:var(--ink-soft); white-space:nowrap;
  animation:hint-pulse 2.6s ease-in-out infinite;
}
/* the pointer tail — a small square rotated 45°, half-hidden behind the
   bubble's own top edge so only its top-left corner shows as a triangle */
.hint-bubble::before{
  content:'';
  position:absolute; top:-5px; left:50%;
  width:10px; height:10px;
  background:#2A1B03;
  border-left:1px solid rgba(255,238,196,.3);
  border-top:1px solid rgba(255,238,196,.3);
  transform:translateX(-50%) rotate(45deg);
}
@keyframes hint-pulse{
  0%,100%{ box-shadow:0 10px 22px -10px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.08), 0 0 0 3px rgba(224,180,80,.08); }
  50%{ box-shadow:0 10px 22px -10px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.08), 0 0 0 7px rgba(224,180,80,0); }
}
.hint-bubble svg{ width:15px; height:15px; flex:none; color:var(--gold-light); }
@media (prefers-reduced-motion: reduce){ .hint-bubble{ animation:none; } }

/* a second, quieter cue so a guest who isn't interested in tapping the
   cards still knows there is more below, not just a dead end */
.continue-hint{
  display:flex; align-items:center; gap:.5rem;
  font-family:'Jost', sans-serif; font-size:.66rem; letter-spacing:.16em;
  /* unlike .hint-bubble's text, this sits directly on the gold page —
     no dark plaque behind it — so it needs the dark-ink treatment */
  text-transform:uppercase; color:var(--ink-dark-soft);
  opacity:0; transform:translateY(6px);
  transition:opacity .7s ease, transform .7s ease, margin-top .3s ease;
}
/* .cards-position is absolutely positioned INSIDE .envelope and is taller
   than .envelope's own box (needed so the real invitation copy fits — see
   .cards-position above), and .envelope.is-open then also slides the whole
   assembly down by .5*env-w so the cards land centred on screen. Neither
   of those affects the FLEX layout's own reserved height (.envelope-wrap's
   box size only ever reflects .envelope's un-shifted aspect-ratio), so
   without this, the cards' bottom edge visually paints well past where
   flex layout thinks .envelope-wrap ends — straight over this hint's text.
   Pre-open there's nothing to clear, so this only adds the gap once open.
   The flat +24px on top of that clears .cards-hint, which hangs a fixed
   ~7px into this line once the open transition and the float settle —
   that part is constant, not proportional, so it needs a constant term. */
.stage-inner:has(.envelope.is-open) .continue-hint{
  /* the flat term grew from 24px: .cards-hint's plain icon+text row became
     a padded coach-mark bubble (.hint-bubble padding + its pointer tail),
     which measured out taller by almost exactly the amount this needed
     to go up by — re-measured after the redesign rather than guessed. */
  margin-top:calc(var(--env-w) * .2 + 46px);
}
.continue-hint.ready{ opacity:.8; transform:translateY(0); }
.continue-hint svg{ width:14px; height:14px; animation:continue-nudge 2s ease-in-out infinite; }
@keyframes continue-nudge{ 0%,100%{ transform:translateY(0); } 50%{ transform:translateY(4px); } }

/* ---------- rsvp ---------- */
.rsvp{ min-height:100svh; justify-content:center; padding-block:6rem; z-index:3; }
.rsvp-inner{
  width:100%; max-width:480px; text-align:center;
  opacity:0; transform:translateY(28px);
  transition:opacity 1s ease, transform 1s cubic-bezier(.22,.68,0,1.03);
}
.rsvp-inner.is-visible{ opacity:1; transform:translateY(0); }
.rsvp-monogram{
  width:64px; height:64px; border-radius:50%;
  background:radial-gradient(circle at 32% 30%, var(--gold-light), var(--gold) 55%, var(--gold-deep) 100%);
  /* darkened/thickened for the same reason as .rsvp-pill: this badge and
     the page behind it are now the same gold material, so the border is
     the only thing left defining its edge */
  border:1.5px solid var(--ink-dark);
  display:flex; align-items:center; justify-content:center;
  font-size:1.55rem; color:var(--paper);
  box-shadow:0 6px 14px -6px rgba(42,27,3,.5), inset 0 0 0 3px rgba(255,255,255,.14),
             0 0 0 3px var(--ivory), 0 0 0 4px var(--ink-dark);
  margin:0 auto 1rem;
}
.rsvp h2{
  font-size:clamp(1.5rem,4.4vw,2.1rem);
  margin-bottom:1.4rem;
}
.rsvp-email-note{
  font-size:.85rem; color:var(--ink-dark-soft); font-style:italic;
  margin:0 0 2.2rem;
}
.rsvp-email-note a{ color:var(--ink-dark); text-decoration:none; border-bottom:1px solid currentColor; }

form{ display:flex; flex-direction:column; gap:1.3rem; text-align:left; }
.field{ position:relative; opacity:0; }
.rsvp-inner.is-visible .field{
  animation:rise-in .6s cubic-bezier(.22,.68,0,1.03) both;
  animation-delay:calc(.15s + var(--d,0) * .08s);
}
.field label{
  display:block; font-family:'Jost', sans-serif; font-size:.68rem;
  letter-spacing:.18em; text-transform:uppercase; color:var(--ink-dark-soft);
  margin-bottom:.5rem;
}
.field input, .field textarea{
  width:100%; border:none; border-bottom:1px solid var(--line-on-gold);
  background:transparent; font-family:'Cormorant Garamond', serif;
  font-size:1.15rem; color:var(--ink-dark); padding:.4rem 0;
}
.field input:focus, .field textarea:focus, .field input:focus-visible{
  outline:none;
}
.field textarea{ resize:vertical; min-height:3rem; }
.field input::placeholder, .field textarea::placeholder{ color:var(--ink-dark-soft); opacity:.55; }
/* the underline grows out from center on focus, instead of an instant
   swap — dark ink now, so it still shows clearly against the gold page
   once it's fully open (--gold here would repeat the same low-contrast
   problem every other gold-on-gold element on this page had) */
.field::after{
  content:'';
  position:absolute; left:50%; right:50%; bottom:0;
  height:1px; background:var(--ink-dark);
  transition:left .35s cubic-bezier(.4,0,.2,1), right .35s cubic-bezier(.4,0,.2,1);
  pointer-events:none;
}
.field:focus-within::after{ left:0; right:0; }

/* Unchecked state flips to dark ink (a plain gold outline read as almost
   invisible on the gold page); checked state flips the other way, to a
   dark filled pill with gold text — the same "dark plaque on the gold
   surface" language as the countdown chips and the coach-mark bubble, so
   a selected state reads clearly as ITS OWN small object, not just a
   tint change. */
.attend-toggle{ display:flex; gap:.7rem; }
.attend-toggle input{ position:absolute; opacity:0; width:0; height:0; }
.attend-toggle label{
  flex:1; text-align:center;
  font-family:'Jost', sans-serif; font-size:.78rem; letter-spacing:.08em;
  padding:.75em .5em; border:1px solid var(--ink-dark);
  border-radius:999px; color:var(--ink-dark); cursor:pointer;
  transition:background .25s ease, color .25s ease;
}
.attend-toggle input:checked + label{ background:var(--ink-dark); color:var(--gold-light); border-color:var(--ink-dark); }
.attend-toggle input:focus-visible + label{ outline:2px solid var(--ink-dark); outline-offset:2px; }

/* grid-rows 1fr/0fr animates to the content's real height, no max-height
   guess to snap against or leave a gap under */
.conditional-fields{
  display:grid;
  grid-template-rows:1fr;
  opacity:1;
  transition:grid-template-rows .45s cubic-bezier(.4,0,.2,1), opacity .35s ease;
}
.conditional-fields.collapsed{ grid-template-rows:0fr; opacity:0; }
.conditional-fields > .fields-inner{
  overflow:hidden;
  min-height:0;
  display:flex; flex-direction:column; gap:1.3rem;
}

/* same struck-gold treatment as the RSVP pill/seals, for one consistent
   "which things are actionable" material across the whole page — border
   darkened/thickened like the other two for the same reason */
.submit-btn{
  margin-top:.6rem;
  background:radial-gradient(circle at 30% 25%, var(--gold-light), var(--gold) 60%, var(--gold-deep) 100%);
  color:var(--paper);
  border:1.5px solid var(--ink-dark);
  border-radius:999px;
  box-shadow:0 8px 18px -6px rgba(42,27,3,.55), inset 0 0 0 1px rgba(255,255,255,.16);
  padding:1em; font-family:'Jost', sans-serif; font-size:.78rem;
  font-weight:500;
  letter-spacing:.24em; text-transform:uppercase; cursor:pointer;
  opacity:0;
  transition:filter .3s ease, transform .3s ease, box-shadow .3s ease;
}
.rsvp-inner.is-visible .submit-btn{ animation:rise-in .6s cubic-bezier(.22,.68,0,1.03) .58s both; }
.submit-btn:hover{
  filter:brightness(1.1);
  transform:translateY(-2px);
  box-shadow:0 14px 26px -12px rgba(42,27,3,.6), inset 0 0 0 1px rgba(255,255,255,.2);
}
.submit-btn:active:not(:disabled){ transform:translateY(0) scale(.97); }
.submit-btn:focus-visible{ outline:2px solid var(--ink-dark); outline-offset:3px; }
.submit-btn:disabled{ opacity:.65; cursor:default; transform:none; box-shadow:none; }

.form-error{
  font-family:'Jost', sans-serif; font-size:.78rem; letter-spacing:.02em;
  /* deepened from a coral (#E08A75, tuned to pop against a dark page) to
     a burnt terracotta — the coral read as too pale/washed-out against
     the new light gold page to still register as an error */
  color:#8B3A1F; text-align:center; margin-top:-.4rem;
}

#rsvpForm{ transition:opacity .5s ease, transform .5s ease; }
#rsvpForm.gone{ opacity:0; transform:translateY(-14px); pointer-events:none; position:absolute; }

.rsvp-confirm{
  display:flex; flex-direction:column; align-items:center; gap:.5rem;
  opacity:0; transform:translateY(14px);
  transition:opacity .6s ease .1s, transform .6s ease .1s;
}
.rsvp-confirm.shown{ opacity:1; transform:translateY(0); }
.confirm-check{ width:60px; height:60px; margin-bottom:.3rem; }
.confirm-check svg{ width:100%; height:100%; overflow:visible; }
.confirm-check circle{ stroke-dasharray:190; stroke-dashoffset:190; }
.confirm-check path{ stroke-dasharray:45; stroke-dashoffset:45; }
.rsvp-confirm.shown .confirm-check circle{ animation:draw-in .7s ease-out .15s forwards; }
.rsvp-confirm.shown .confirm-check path{ animation:draw-in .45s ease-out .65s forwards; }
@keyframes draw-in{ to{ stroke-dashoffset:0; } }
.confirm-title{ font-size:1.6rem; margin-top:.4rem; }
.rsvp-confirm p.sub{ color:var(--ink-dark-soft); font-style:italic; }

footer{
  position:relative; z-index:3;
  text-align:center; padding:2.5rem 20px 3rem;
  font-family:'Jost', sans-serif; font-size:.65rem; letter-spacing:.15em;
  text-transform:uppercase; color:var(--ink-dark-soft); opacity:.7;
}

@media (prefers-reduced-motion: reduce){
  *{ animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; }
  html{ scroll-behavior:auto; }
}

@media (max-width:420px){
  .rsvp-pill{ top:14px; right:14px; padding:.6em 1em; font-size:.66rem; }
  /* the rest of this block was small-screen tightening for the recreated
     TEXT card content (frame inset, font sizes, schedule spacing) — moot
     now that the card face is a single real image scaled by object-fit,
     which already handles every screen size without per-breakpoint rules. */
}
