/* ═══════════════════════════════════════════════════════════
   Sue is 60 — Let's Celebrate
   Palette + type pulled from the printed invitation:
   hot pink on blush, checkerboard frame, pink foil.
   The invitation arrives inside an envelope; everything below
   the fold is the page it opens onto.
   ═══════════════════════════════════════════════════════════ */

/* ── fonts ─────────────────────────────────────────────── */
@font-face{font-family:'EB Garamond';src:url(../fonts/eb-garamond-400-normal.woff2)format('woff2');font-weight:400;font-display:swap}
@font-face{font-family:'EB Garamond';src:url(../fonts/eb-garamond-600-normal.woff2)format('woff2');font-weight:600;font-display:swap}
@font-face{font-family:'EB Garamond';src:url(../fonts/eb-garamond-700-normal.woff2)format('woff2');font-weight:700;font-display:swap}
@font-face{font-family:'EB Garamond';src:url(../fonts/eb-garamond-400-italic.woff2)format('woff2');font-weight:400;font-style:italic;font-display:swap}
@font-face{font-family:'Great Vibes';src:url(../fonts/great-vibes-400-normal.woff2)format('woff2');font-weight:400;font-display:swap}
/* the card is the printed artwork now, so the only survivor of its type is
   Playfair, setting the two digits on the wax seal */
@font-face{font-family:'Playfair Display';src:url(../fonts/playfair-display-900-normal.woff2)format('woff2');font-weight:900;font-display:swap}

/* ── tokens ────────────────────────────────────────────── */
:root{
  /* --pink and --pink-soft are sampled straight out of the printed card
     (assets/img/invitation.png): its checkerboard is exactly these two. The
     rest of the palette is built from them, so the page and the artwork are
     the same pink rather than two that nearly match. */
  --pink:      #da3c8b;   /* the card's hot pink */
  --pink-soft: #efc7ce;   /* the light square of its checkerboard */
  --pink-hot:  #f0509d;   /* a lift, for hover states */
  --pink-deep: #a01d62;   /* small type: 5.9:1 on the page ground */
  /* white on --pink is 4.2:1, just under AA for the buttons' small caps, so
     solid fills that carry white text use this a shade deeper instead */
  --pink-ink:  #cc2f7e;
  --pink-line: rgba(218,60,139,.3);

  /* the page ground: tints of the card's own light pink */
  --blush:   #f8e2e6;
  --blush-2: #efc7ce;
  --blush-3: #fdf3f5;
  --paper:   #fffbfc;   /* envelope stock */

  --ink:      #4a1128;  /* deep plum body copy */
  --ink-soft: #8a5364;
  --ink-fine: #87596a;  /* hints and fine print — dark enough to pass on blush */

  /* the site is set in Garamond; the invitation card re-declares these
     three below so it keeps the typography of the printed original */
  --serif:  'EB Garamond', Garamond, 'Adobe Garamond Pro', Georgia, serif;
  --sans:   'EB Garamond', Garamond, 'Adobe Garamond Pro', Georgia, serif;
  --script: 'Great Vibes', 'Snell Roundhand', cursive;

  --wrap: 1080px;
  --ease: cubic-bezier(.22,.68,.24,1);
  --ease-out: cubic-bezier(.16,.84,.34,1);

  /* The card is laid out at this width both inside the envelope and at
     rest in the hero, so the hand-off between them is a pure transform
     with nothing to reflow. Change it here and both follow. */
  --card-w: min(90vw, 480px);
  --env-w:  min(93vw, calc(var(--card-w) * 1.26));
  --env-h:  calc(var(--env-w) * .68);
}

/* ── base ──────────────────────────────────────────────── */
*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;background-color:var(--blush)}
body{
  margin:0;
  color:var(--ink);
  font:400 18px/1.62 var(--sans);
  letter-spacing:.012em;
  overflow-x:hidden;
  min-height:100svh;
  /* Safari reads the body's background-COLOR (gradients are skipped) to tint
     the iOS toolbars, so the solid base has to be there under the wash */
  background-color:var(--blush);
  background-image:
    radial-gradient(130% 80% at 50% 0%, var(--blush-3) 0%, var(--blush) 44%, var(--blush-2) 100%);
  background-attachment:fixed;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}
body.is-locked{overflow:hidden}
img{max-width:100%;display:block}
/* `display:grid` on .field/.form/.sent would otherwise beat the UA's [hidden] rule */
[hidden]{display:none !important}
h1,h2,h3{margin:0;font-weight:700;line-height:1.06}
p{margin:0}
a{color:inherit}
:focus-visible{outline:2px solid var(--pink);outline-offset:3px;border-radius:3px}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ═══ iOS toolbar tinting ═══
   Safari reads a thin strip at the very top and bottom of the viewport to
   colour its toolbars, and skips gradients — so with only the page's wash up
   there the bars fall back to white. These give it a solid colour to find,
   matching the two ends of that wash.

   Ported from the McKenna save-the-date, with two changes.

   They sit above the envelope overlay rather than at z-index 0 — the overlay
   covers both edges, which is why the bars were white on the first screen and
   pink on every screen after it.

   And they are ONLY on the envelope screen. Once it lifts, the body's own
   solid background-color is what iOS reads, so the bars were already right
   there without any help — and the bottom strip actively hurt: `body` sets
   background-attachment:fixed, which iOS ignores, so on a scrolling page the
   wash is sized to the whole document and the viewport's bottom edge is far
   lighter than --blush-2. The strip stopped matching and read as a bar across
   the bottom of the page. The overlay has no such problem: it is
   position:fixed, so its wash really is viewport-sized.

   Only ~4px of each is ever on screen; the rest is deliberately off-viewport,
   which is where Safari looks. */
.tint{
  position:fixed;left:0;width:100%;min-height:12px;
  z-index:200;pointer-events:none;display:none;
}
.tint--top   {top:-8px;    background-color:var(--blush-3)}
.tint--bottom{bottom:-8px; background-color:var(--blush-2)}
@supports (-webkit-touch-callout:none){
  /* :not(.is-opened) keeps them to the envelope screen; requiring .js keeps
     them off the plain page a visitor without it gets, which never has the
     overlay either */
  @media (max-width:767px){ .js:not(.is-opened) .tint{display:block} }
}

/* ═══ pink foil type ═══
   Silver foil reads as printing on a dark ground and vanishes on blush, so the
   whole page uses the card's pink now. The gradient only ever runs darker than
   --pink, never lighter, so the sweep can't dip below contrast mid-animation. */
.foil{
  background:linear-gradient(100deg,
    var(--pink) 0%, var(--pink-deep) 24%, var(--pink) 46%,
    var(--pink-deep) 70%, var(--pink) 100%);
  background-size:250% 100%;
  -webkit-background-clip:text;background-clip:text;
  color:transparent;
  animation:foil 11s linear infinite;
}
@keyframes foil{to{background-position:-250% 0}}


/* ═══════════════════════════════════════════════════════════
   THE ENVELOPE
   Three beats: the stamped front turns over, the seal breaks and
   the flap opens, the card rises out and settles into the page.
   ═══════════════════════════════════════════════════════════ */

/* Driven entirely by JS, so it only paints for visitors who have it —
   otherwise someone without it would be staring at a screen they can't open. */
.opener{display:none}
.js .opener{
  display:flex;
  position:fixed;inset:0;z-index:100;
  padding:max(20px,env(safe-area-inset-top)) 16px max(20px,env(safe-area-inset-bottom));
  /* deliberately the same ground as <body>: the envelope screen and the page
     it opens onto have to sample identically at the edges (see .tint), and it
     also means nothing shifts underfoot when the overlay lifts */
  background-color:var(--blush);
  background-image:
    radial-gradient(130% 80% at 50% 0%, var(--blush-3) 0%, var(--blush) 44%, var(--blush-2) 100%);
}
.opener > *{margin:auto}
.opener.is-gone{display:none}

.scene{
  display:flex;flex-direction:column;align-items:center;
  perspective:1800px;              /* drives the turn-over */
}

/* ── the turn-over (two faces) ── */
.flipper{
  position:relative;
  width:var(--env-w);height:var(--env-h);
  transform-style:preserve-3d;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.face{position:absolute;inset:0;backface-visibility:hidden;-webkit-backface-visibility:hidden}
.face--back{transform:rotateY(180deg)}

/* Backface culling alone is not enough: both faces hold composited children,
   and once a face is promoted to its own layer WebKit stops culling it — the
   stamped front stays painted over the back for the whole turn. So the swap is
   written out: envelope.js toggles .show-back as rotateY crosses 90deg, where
   the envelope is edge-on and the change can't be seen. Hidden two ways
   because a promoted layer may honour only one of them. */
.flipper:not(.show-back) .face--back{visibility:hidden;opacity:0}
.flipper.show-back        .face--front{visibility:hidden;opacity:0}

/* once the turn is done JS flattens back to plain 2D, so the flap gets its own
   perspective and ordinary z-index stacking */
.flipper.is-flat{transform-style:flat}
.flipper.is-flat .face--back{transform:none}
.flipper.is-flat .face{backface-visibility:visible}

/* cast shadow under the whole envelope */
.flipper::after{
  content:'';position:absolute;left:5%;right:5%;bottom:-16px;height:28px;
  background:radial-gradient(50% 50% at 50% 50%, rgba(120,20,70,.28), transparent 70%);
  filter:blur(10px);z-index:-1;
}

/* ── face 1: the addressed front ── */
.ef{
  position:absolute;inset:0;
  border-radius:4px;
  background:linear-gradient(158deg, #fffbfc 0%, #fdeff5 58%, #fbe4ee 100%);
  box-shadow:
    0 2px 6px rgba(120,20,70,.08),
    0 16px 38px -14px rgba(120,20,70,.26),
    inset 0 0 0 1px rgba(218,60,139,.22),
    inset 0 1px 0 rgba(255,255,255,.7);
  padding:6%;
  display:grid;
  /* fixed fractions rather than auto: an auto track sized around the stamps'
     percentage width squeezes the return address down to two characters */
  grid-template-columns:1fr 46%;
  grid-template-rows:auto 1fr;
  gap:4%;
  overflow:hidden;
}
.ef__post{
  grid-column:2;grid-row:1;
  display:flex;align-items:flex-start;gap:5%;
  width:100%;
}
.stamps{flex:0 0 56%;display:grid;grid-template-columns:1fr 1fr;gap:6%}
.stamp{display:block}
.stamp__svg{width:100%;height:auto;display:block;filter:drop-shadow(0 1px 1.5px rgba(120,20,70,.2))}
.stamp--1{transform:rotate(-2.5deg)}
.stamp--2{transform:rotate(2deg)}
.postmark{flex:1;color:var(--pink-deep);opacity:.5;transform:rotate(-7deg);margin-top:7%}
.postmark__svg{width:100%;height:auto;display:block}

/* the addressed block, centred on the envelope like a handwritten panel */
.ef__addr{
  grid-column:1 / -1;grid-row:2;
  align-self:center;text-align:center;
  padding-bottom:2%;
}
.ef__script{
  font-family:var(--script);color:var(--pink);
  font-size:clamp(1.4rem,5.1vw,2.2rem);line-height:1.1;white-space:nowrap;
}
.ef__rule{
  display:block;width:clamp(60px,22%,110px);height:1px;margin:clamp(9px,2.4vw,15px) auto;
  background:linear-gradient(90deg,transparent,var(--pink-line),transparent);
}
.ef__fine{
  font-size:clamp(7.5px,1.9vw,10px);letter-spacing:.28em;text-transform:lowercase;
  color:var(--ink-fine);
}

/* ── face 2: the back that opens ──
   COMPOSITING NOTE: every panel below carries will-change:transform on
   purpose. .card-slot and .env__flap need their own layers because they
   animate; once any sibling is promoted the un-promoted ones can be painted
   out of z-index order by the compositor — the card flashes in front of the
   envelope mid-animation. Promote any panel added here too. */
.envelope{
  position:absolute;inset:0;
  perspective:1400px;perspective-origin:50% 30%;
  will-change:transform,opacity;
}
.env__back{
  position:absolute;inset:0;will-change:transform;z-index:1;overflow:hidden;
  border-radius:4px;
  background:linear-gradient(158deg, #fffbfc 0%, #fdeef4 60%, #fae1eb 100%);
  box-shadow:
    0 2px 6px rgba(120,20,70,.08),
    0 16px 38px -14px rgba(120,20,70,.26),
    inset 0 0 0 1px rgba(218,60,139,.22),
    inset 0 1px 0 rgba(255,255,255,.6);
}
.env__lining{
  position:absolute;left:0;right:0;top:0;height:62%;
  will-change:transform;z-index:2;opacity:0;
  background:
    repeating-conic-gradient(var(--pink) 0% 25%,var(--pink-soft) 0% 50%) 0 0/22px 22px;
  clip-path:polygon(0 0, 100% 0, 50% 100%);
  border-radius:4px 4px 0 0;
}
.env__front{
  position:absolute;inset:0;will-change:transform;z-index:6;
  border-radius:4px;
  background:linear-gradient(172deg, #fffafc 0%, #fdeef4 60%, #f9dfe9 100%);
  clip-path:polygon(0 0, 50% 46%, 100% 0, 100% 100%, 0 100%);
  box-shadow:0 -1px 0 rgba(255,255,255,.5) inset;
}
.env__front::before{
  content:'';position:absolute;inset:0;
  background:
    linear-gradient(to bottom right, transparent calc(50% - .5px), rgba(218,60,139,.24) 50%, transparent calc(50% + .5px)),
    linear-gradient(to bottom left,  transparent calc(50% - .5px), rgba(218,60,139,.24) 50%, transparent calc(50% + .5px));
  clip-path:polygon(0 0, 50% 46%, 100% 0, 100% 100%, 0 100%);
}
.env__flap{
  position:absolute;left:0;right:0;top:0;height:62%;
  background:linear-gradient(178deg, #fffbfc 0%, #fbe6ef 92%);
  clip-path:polygon(0 0, 100% 0, 50% 100%);
  transform-origin:top center;transform:rotateX(0deg);
  backface-visibility:visible;border-radius:4px 4px 0 0;
  z-index:8;will-change:transform;
}
.env__flap::after{
  content:'';position:absolute;inset:0;
  background:linear-gradient(180deg, rgba(218,60,139,.12) 0%, transparent 26%);
  clip-path:polygon(0 0, 100% 0, 50% 100%);
}
/* "Shhhh…" printed across the flap */
.env__script{
  position:absolute;top:15%;left:0;right:0;text-align:center;
  font-family:var(--script);color:var(--pink);
  font-size:clamp(18px,5.4vw,30px);line-height:1;
  opacity:.9;
}

/* ── the wax seal ── */
.seal{
  position:absolute;left:50%;top:58%;
  width:clamp(50px,14%,64px);aspect-ratio:1;
  transform:translate(-50%,-50%);
  will-change:transform,opacity;z-index:9;
  border:0;padding:0;background:none;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.seal__face{
  position:absolute;inset:0;display:grid;place-items:center;border-radius:50%;
  background:radial-gradient(68% 68% at 34% 28%, #ff7ec0 0%, var(--pink) 50%, #8e0d4f 100%);
  box-shadow:
    0 3px 9px rgba(120,20,70,.34),
    inset 0 0 0 1px rgba(255,255,255,.3),
    inset 0 0 0 4px rgba(255,255,255,.18);
  transition:transform .35s var(--ease-out);
}
.seal:hover .seal__face{transform:scale(1.05)}
.seal:focus-visible .seal__face{outline:2px solid var(--pink-deep);outline-offset:4px}
.seal__mono{
  font-family:'Playfair Display','Didot',Georgia,serif;font-weight:900;
  font-size:clamp(16px,4.2vw,21px);letter-spacing:.01em;color:#fff9fc;line-height:1;
}

/* ── the cue under the envelope ── */
.cue{
  margin-top:30px;
  font-size:10.5px;letter-spacing:.34em;text-transform:uppercase;
  color:var(--pink-deep);opacity:.85;
  animation:breathe 2.9s ease-in-out infinite;
}
@keyframes breathe{
  0%,100%{opacity:.42;transform:translateY(0)}
  50%    {opacity:.95;transform:translateY(-2px)}
}
/* ── the card while it is inside the envelope ── */
.card-slot{
  position:absolute;left:50%;top:50%;
  width:var(--card-w);
  /* it lies on its side inside the landscape envelope and stands up during the
     final settle — envelope.js owns this transform from load onward */
  transform:translate(-50%,-50%) rotate(90deg) scale(.3);
  transform-origin:50% 50%;
  z-index:4;will-change:transform;pointer-events:none;
}
/* lifted out of the envelope for the final flight, so it stops being stacked
   under the front panel; envelope.js drives it in viewport coordinates */
.card-slot.is-out{
  position:fixed;left:0;top:0;
  z-index:120;
}


/* ═══ buttons ═══ */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.5em;
  font:600 .84rem/1 var(--sans);letter-spacing:.19em;text-transform:uppercase;
  padding:1.06em 2.1em;border-radius:999px;border:1px solid transparent;
  /* <button> would otherwise take the UA's grey button background */
  background:transparent;-webkit-appearance:none;appearance:none;
  cursor:pointer;text-decoration:none;white-space:nowrap;
  transition:transform .25s var(--ease),box-shadow .25s var(--ease),
             background-color .25s,color .25s,border-color .25s;
}
.btn--primary{background:var(--pink-ink);color:#fff;box-shadow:0 8px 22px rgba(218,60,139,.3)}
.btn--primary:hover{background:var(--pink-deep);transform:translateY(-2px);box-shadow:0 12px 28px rgba(218,60,139,.42)}
.btn--ghost{border-color:rgba(160,29,98,.38);color:var(--pink-deep);background:rgba(255,255,255,.5)}
.btn--ghost:hover{border-color:var(--pink);color:var(--pink);background:#fff;transform:translateY(-2px)}
.btn--wide{width:100%}
.btn:active{transform:translateY(0)}
.linkish{background:none;border:0;color:var(--ink-soft);font:400 .95rem var(--sans);
  cursor:pointer;padding:6px;text-decoration:underline;text-underline-offset:3px}
.linkish:hover{color:var(--pink-deep)}

/* ═══ top bar ═══ */
.topbar{
  position:fixed;top:0;left:0;right:0;z-index:60;
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:14px clamp(16px,4vw,34px);
  transform:translateY(-100%);transition:transform .45s var(--ease),background-color .45s,backdrop-filter .45s;
}
.topbar.is-stuck{
  transform:none;background:rgba(253,238,244,.86);backdrop-filter:blur(14px);
  border-bottom:1px solid var(--pink-line);
}
.topbar__mark{font-family:var(--serif);font-size:1.02rem;letter-spacing:.05em;text-decoration:none;color:var(--pink-deep)}
.topbar__nav{display:flex;align-items:center;gap:clamp(10px,2.4vw,26px)}
.topbar__nav a{font-size:.76rem;letter-spacing:.17em;text-transform:uppercase;text-decoration:none;color:var(--ink-soft);transition:color .2s}
.topbar__nav a:hover{color:var(--pink)}
.topbar__cta{color:#fff !important;background:var(--pink-ink);padding:.72em 1.3em;border-radius:999px}
.topbar__cta:hover{background:var(--pink-deep)}

/* ═══ layout ═══ */
main{position:relative;z-index:1}
.section{
  max-width:var(--wrap);margin-inline:auto;
  padding:clamp(72px,12vw,132px) clamp(20px,5vw,40px);
}
.eyebrow{font-size:.74rem;letter-spacing:.32em;text-transform:uppercase;color:var(--pink);text-align:center}
.section__title{
  font-family:var(--serif);text-align:center;color:var(--pink-deep);
  font-size:clamp(1.8rem,4.6vw,2.5rem);letter-spacing:.02em;margin-top:.42em;
}
.section__title--big{font-size:clamp(2.6rem,8.5vw,4.6rem);margin-bottom:clamp(38px,7vw,64px)}

/* ═══ hero ═══ */
.hero{
  position:relative;
  display:flex;flex-direction:column;align-items:center;
  padding:clamp(44px,8vh,88px) clamp(18px,5vw,40px) 0;
  min-height:100svh;
}
/* the card is laid out at --card-w in both places, so the hand-off out of the
   envelope is a pure transform with nothing to reflow */
.card-home{width:var(--card-w);margin-inline:auto}
.card{position:relative;width:100%}
.card--invite{
  /* the invitation is the printed artwork itself — the frame, the checkerboard
     and every word are in the image, so nothing is drawn around it but a
     shadow to lift it off the page */
  background:transparent;
  box-shadow:0 18px 46px -14px rgba(120,20,70,.34),0 46px 90px -40px rgba(120,20,70,.4);
}
.invite{width:100%;height:auto;display:block}

/* The words of the invitation, for anyone whose browser is reading the page
   rather than showing it. Hidden the same way as .sr — until the image fails,
   when they become the invitation. */
.invite__text{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.card--invite.is-missing .invite__text{
  position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;
  display:grid;gap:.8em;text-align:center;
  background:#fff;border:14px solid var(--pink);
  padding:clamp(30px,6vw,52px) clamp(20px,5vw,38px);
  color:var(--pink-deep);
}
.card--invite.is-missing h1{
  font-family:var(--serif);font-size:clamp(2rem,7vw,2.8rem);color:var(--pink);
  line-height:1.1;
}
.card--invite.is-missing strong{color:var(--pink)}

.hero__actions{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;
  margin-top:clamp(30px,6vw,44px)}

/* checkerboard rules, echoing the card's border. Two rows deep, not one: a
   single row of squares reads as a dashed line, because the light square is
   almost the page ground. */
.checker{
  width:100%;height:48px;margin-top:clamp(56px,10vw,96px);
  background:repeating-conic-gradient(var(--pink) 0% 25%,var(--pink-soft) 0% 50%) 0 0/48px 48px;
}
.checker--thin{height:28px;margin:0 0 clamp(34px,6vw,54px);background-size:28px 28px}

/* ═══ timeline ═══ */
.timeline{list-style:none;margin:0 auto;padding:0;max-width:640px;position:relative}
.timeline::before{
  content:'';position:absolute;left:11px;top:14px;bottom:14px;width:1px;
  background:linear-gradient(rgba(218,60,139,0),rgba(218,60,139,.5) 12%,rgba(218,60,139,.5) 88%,rgba(218,60,139,0));
}
.tl{position:relative;padding:0 0 clamp(34px,6vw,48px) clamp(38px,8vw,58px)}
.tl:last-child{padding-bottom:0}
.tl__mark{
  position:absolute;left:0;top:6px;width:23px;height:23px;border-radius:50%;
  background:radial-gradient(circle at 34% 30%,#fff,var(--pink-soft) 46%,var(--pink) 100%);
  /* the ring is the page ground: it masks the rule running behind the dot */
  box-shadow:0 0 0 4px var(--blush),0 3px 10px -3px rgba(218,60,139,.6);
}
.tl--star .tl__mark{
  background:radial-gradient(circle at 34% 30%,#fff,var(--pink-hot) 46%,var(--pink-deep) 100%);
  box-shadow:0 0 0 4px var(--blush),0 0 0 8px rgba(218,60,139,.22);
  animation:pulse 2.4s ease-in-out infinite;
}
@keyframes pulse{
  0%,100%{box-shadow:0 0 0 4px var(--blush),0 0 0 7px rgba(218,60,139,.18)}
  50%    {box-shadow:0 0 0 4px var(--blush),0 0 0 12px rgba(218,60,139,.05)}
}
.tl__time{font-family:var(--serif);font-weight:700;font-size:clamp(1.5rem,5vw,2rem);line-height:1}
.tl__time em{font-style:normal;font-size:.5em;letter-spacing:.16em;text-transform:uppercase}
.tl__what{font-family:var(--sans);font-weight:600;font-size:1.16rem;letter-spacing:.15em;
  text-transform:uppercase;color:var(--pink-deep);margin:.55em 0 .34em}
.tl__note{color:var(--ink-soft);max-width:44ch}
.tl__note strong{color:var(--pink);font-weight:600}
.tl--star .tl__what{color:var(--pink)}

/* ═══ rsvp ═══ */
.rsvp{max-width:560px;margin-inline:auto}
.form{display:grid;gap:clamp(18px,3.4vw,24px)}
.field{display:grid;gap:.5em;border:0;padding:0;margin:0;min-width:0}
.field label,.field legend{font-size:.74rem;letter-spacing:.22em;text-transform:uppercase;color:var(--ink-soft);padding:0}
.req{color:var(--pink);margin-left:.35em}
.field input[type=text],.field input[type=number],.field textarea{
  width:100%;padding:.92em 1.1em;border-radius:12px;
  border:1px solid rgba(160,29,98,.26);background:rgba(255,255,255,.78);
  color:var(--ink);font:400 1.05rem var(--sans);
  transition:border-color .2s,box-shadow .2s,background-color .2s;
}
.field textarea{resize:vertical;min-height:5.2em}
.field input::placeholder,.field textarea::placeholder{color:var(--ink-fine)}
.field input:focus,.field textarea:focus{
  outline:none;background:#fff;border-color:var(--pink);box-shadow:0 0 0 3px rgba(218,60,139,.16)}
.field.has-err input,.field.has-err textarea{border-color:#d81b4a}
.hint{font-size:.82rem;color:var(--ink-fine)}
.err{font-size:.82rem;color:#c4143f;display:none}
.field.has-err .err{display:block}

.choices{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.choice{cursor:pointer}
.choice input{position:absolute;opacity:0;width:0;height:0}
.choice__box{
  display:grid;gap:.24em;padding:1.05em 1em;border-radius:12px;text-align:center;
  border:1px solid rgba(160,29,98,.26);background:rgba(255,255,255,.78);
  transition:border-color .2s,background-color .2s,transform .2s var(--ease);
}
.choice__box strong{font-weight:600;font-size:1.06rem;letter-spacing:.1em;text-transform:uppercase;color:var(--pink-deep)}
.choice__box small{font-size:.78rem;color:var(--ink-fine)}
.choice:hover .choice__box{border-color:var(--pink);transform:translateY(-2px)}
.choice input:checked+.choice__box{
  border-color:var(--pink);background:rgba(218,60,139,.1);box-shadow:0 6px 20px -10px rgba(218,60,139,.6)}
.choice input:focus-visible+.choice__box{outline:2px solid var(--pink);outline-offset:3px}
.form__fine{font-size:.84rem;color:var(--ink-fine);text-align:center}
.form__fine strong{color:var(--ink-soft);font-weight:600}

.sent{display:grid;justify-items:center;gap:16px;text-align:center;
  padding:clamp(26px,5vw,38px);border-radius:18px;
  border:1px solid var(--pink-line);background:rgba(255,255,255,.72);
  box-shadow:0 14px 40px -22px rgba(120,20,70,.5);
  animation:rise .6s var(--ease) both}
@keyframes rise{from{opacity:0;transform:translateY(20px)}}
.sent__title{font-family:var(--serif);font-size:clamp(1.5rem,5vw,2rem);color:var(--pink-deep)}
.sent__copy{color:var(--ink-soft);max-width:34ch}
.sent__copy a{color:var(--pink)}
.sent__msg{
  width:100%;margin:0;padding:1.1em 1.2em;border-radius:12px;text-align:left;
  background:rgba(250,221,231,.5);border:1px solid var(--pink-line);
  font:400 .95rem/1.6 var(--sans);color:var(--ink);
  white-space:pre-wrap;word-break:break-word;max-height:15em;overflow:auto;
}
.sent__actions{display:flex;flex-wrap:wrap;gap:10px;justify-content:center}

.secret-strip{
  margin:clamp(46px,8vw,72px) auto 0;max-width:640px;text-align:center;
  font-size:.76rem;letter-spacing:.24em;text-transform:uppercase;color:var(--pink-deep);
  padding:1.2em;border-top:1px solid var(--pink-line);border-bottom:1px solid var(--pink-line);
}
.secret-strip span{opacity:.6;margin:0 .8em}

/* ═══ footer ═══ */
.foot{position:relative;z-index:1;text-align:center;padding:0 clamp(20px,5vw,40px) clamp(46px,8vw,72px)}
.foot__line{font-family:var(--serif);font-style:italic;font-size:clamp(1.9rem,6vw,2.6rem);color:var(--pink)}
.foot__sub{font-size:.82rem;letter-spacing:.14em;color:var(--ink-soft);margin-top:1em}
.foot__sub--dim{color:var(--ink-fine);letter-spacing:.1em;margin-top:.5em}

/* ═══ toast ═══ */
.toast{
  position:fixed;left:50%;bottom:clamp(26px,6vw,44px);z-index:90;
  transform:translate(-50%,14px);opacity:0;pointer-events:none;
  padding:.85em 1.5em;border-radius:999px;
  background:var(--pink-deep);color:#fff;
  box-shadow:0 12px 34px -12px rgba(120,20,70,.7);
  font-size:.84rem;letter-spacing:.1em;
  transition:opacity .3s,transform .3s var(--ease);
}
.toast.is-up{opacity:1;transform:translate(-50%,0)}

/* ═══ scroll reveal ═══ */
[data-reveal]{opacity:0;transform:translateY(24px);
  transition:opacity .85s var(--ease),transform .85s var(--ease)}
[data-reveal].is-in{opacity:1;transform:none}

/* ═══ confetti (RSVP celebration) ═══ */
.confetti{position:fixed;inset:0;z-index:95;pointer-events:none;overflow:hidden}
.confetti i{position:absolute;top:-14px;width:8px;height:14px;border-radius:1px;
  animation:fall linear forwards}
@keyframes fall{to{transform:translateY(108vh) rotate(720deg);opacity:0}}

/* ═══ responsive ═══ */
@media (max-width:820px){
  .topbar__nav a:not(.topbar__cta){display:none}
}
@media (max-width:560px){
  body{font-size:17px}
  .choices{grid-template-columns:1fr}
  .sent__actions .btn{width:100%}
}
/* the envelope has to clear the cue on short screens */
@media (max-height:720px){
  :root{--card-w:min(80vw,380px)}
  .cue{margin-top:20px}
}

/* ═══ motion & print ═══ */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important}
  [data-reveal]{opacity:1;transform:none}
  .cue{animation:none;opacity:.85}
  .foil{color:var(--pink);background:none;-webkit-background-clip:border-box;background-clip:border-box}
}
@media print{
  .opener,.topbar,.toast,.hero__actions,.form,.sent{display:none !important}
  body{background:#fff;color:#000}
}
