/* ————————————————————————————————
   Βάπτιση Αννέτας — 20.09.2026
   One continuous sheet of invitation paper.
   Colours sampled from the printed card:
   paper #f6f0ea · ink #6b4f38 · rose #daa69f
———————————————————————————————— */
:root {
  --paper: #f6f0ea;
  --ink: #6b4f38;
  --ink-soft: #9a8672;
  /* #DAA69F — the artwork's pink — belongs to the Αννέτα name alone, so the
     name stays the lightest, softest thing on the page. Everything drawn in
     CSS shares one deeper tone of the same rose. The three names remain so
     each use still reads its intent. */
  --rose: #c58e91;
  --rose-deep: #c58e91;
  --rose-ink: #c58e91;
  --hairline: #e3d6c7;
  --serif: "Noto Serif", "Times New Roman", serif;
  --sans: "Noto Serif", "Times New Roman", serif;
  --frame: clamp(34px, 8.5vw, 88px);
  --gutter: clamp(10px, 3vw, 26px);
  /* Type scale lifted 1:1 from the printed card: every size is a multiple of
     the ΒΑΠΤΙΣΗ size, every tracking value measured off the artwork. */
  /* 0.368 = where the moulding's inner line falls inside the corner slice,
     so --panel is the paper actually visible inside the frame. On the card
     ΒΑΠΤΙΣΗ is 0.083 of that panel and the text column is 0.829 of it —
     that ratio is the whole source of the card's white space. */
  --panel: calc(min(100vw, 660px) - 2 * (var(--frame) * 0.368));
  --t: clamp(22px, calc(var(--panel) * 0.083), 52px);
  --fs-eyebrow: calc(var(--t) * 0.4655);
  --fs-mou:     calc(var(--t) * 0.4718);
  --fs-side:    calc(var(--t) * 0.4905);
  --fs-num:     calc(var(--t) * 1.5150);   /* the card's 1.3773, lifted a tenth: the date is the one thing a guest must not miss */
  --fs-month:   calc(var(--t) * 0.5158);
  --fs-church:  calc(var(--t) * 0.3836);
  --fs-role:    calc(var(--t) * 0.3963);
  --fs-name:    calc(var(--t) * 0.3836);
  --fs-gift:    calc(var(--t) * 0.3458);
}

* { box-sizing: border-box; }
h1, h2, h3, p, button, input, a { font-weight: 300; }
html, body { margin: 0; padding: 0; }

/* the single sheet of paper — colour + grain, fixed so it never breaks */
body {
  position: relative;          /* the frame is measured against the page, not the window */
  min-height: 100dvh;
  font-family: var(--sans);
  font-weight: 300;            /* matches the card's stroke: 0.099 vs 0.107 stem/cap */
  color: var(--ink);
  background-color: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* one continuous paper grain over everything — page and artwork alike, so the
   hero can never read as a separate panel */
.grain {
  position: fixed;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background-image: url("/assets/paper-grain.png");
  background-repeat: repeat;
  background-size: 128px 128px;
}

/* A soft oval vignette over the viewport. Its ellipse is deliberately wider
   than the window and its falloff is gentle: at full strength it veiled the
   ribbon tails as they ran out to the frame, so the artwork appeared to stop
   short and leave bare paper beside the side rules. Now the sides stay clear
   and the artwork carries on under the mouldings, while the corners and the
   top and bottom still get their veil. */
.vignette {
  position: fixed;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background: radial-gradient(ellipse 104% 66% at 50% 44%,
    rgba(246, 240, 234, 0)    0%,
    rgba(246, 240, 234, 0)    50%,
    rgba(246, 240, 234, 0.03) 62%,
    rgba(246, 240, 234, 0.07) 72%,
    rgba(246, 240, 234, 0.13) 82%,
    rgba(246, 240, 234, 0.21) 91%,
    rgba(246, 240, 234, 0.28) 100%);
}

/* The invitation's embossed border. It wraps the page itself rather than the
   window: fixed to the viewport, the bottom rule sits over the text and follows
   you down the page, so it never reads as the end of the card. Anchored to the
   document, the sides run the whole height and the bottom rule lands where the
   invitation actually finishes. */
.frame {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  border: var(--frame) solid transparent;
  border-image-source: url("/assets/frame.png");
  border-image-source: image-set(url("/assets/frame.webp") type("image/webp"),
                                 url("/assets/frame.png") type("image/png"));
  border-image-slice: 300;   /* no `fill` — the centre must stay untouched paper */
  border-image-width: var(--frame);
  border-image-repeat: stretch;
}

.page {
  position: relative;
  z-index: 1;
  max-width: min(100vw, 660px);
  margin: 0 auto;
  padding:
    calc(var(--frame) * 0.85 + clamp(10px, 3.5vw, 30px))
    calc(var(--frame) * 0.368 + var(--panel) * 0.0854)
    calc(var(--frame) * 0.85 + clamp(20px, 6vw, 48px));
}

/* ————— type ————— */
.eyebrow {
  font-family: var(--serif);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.196em;
  line-height: 1;
  text-align: center;
  margin: 0 -0.196em 0 0;   /* see .display: hand back the trailing letter-space */
  color: var(--ink);
}
.display {
  font-family: var(--serif);
  /* a lighter cut than the rest: at this size the same weight reads heavier,
     so 200 keeps ΒΑΠΤΙΣΗ as delicate as the lines around it */
  font-weight: 200;
  font-size: var(--t);
  /* Tracked to sit flush with the line above it — the Β starts under the Σ of
     ΣΑΣ and the Η lands under the Η of ΣΤΗ. Solved rather than eyeballed: at
     0.247em the word measured 3.22px narrow, and its seven letters share six
     gaps, so each wanted 0.54px more. */
  letter-spacing: 0.2655em;
  line-height: 1;
  text-align: center;
  /* letter-spacing also lays a gap AFTER the final letter, which centring then
     counts as part of the line and pays for by shifting everything half a gap
     left. The negative right margin gives that gap back, so what is centred is
     the ink. Both lines need it, or matching their widths still leaves them
     misaligned by half the difference in their tracking. */
  margin: calc(var(--t) * 0.030) -0.2655em 0 0;
  color: #5f4634;
}
.eyebrow + .display { margin-top: calc(var(--t) * 0.030); }
.display + .eyebrow { margin: calc(var(--t) * 0.070) -0.176em 0 0; letter-spacing: 0.176em; font-size: var(--fs-mou); }
h2.section-title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--fs-month);
  letter-spacing: 0.10em;    /* matched to the RSVP heading — same rank, same tracking */
  line-height: 1.25;
  text-align: center;
  color: var(--rose-ink);
  margin: 0 0 calc(var(--t) * 0.5);
}

/* ————— hero: the bear floats directly on the paper ————— */
.hero-art {
  position: relative;
  /* full-bleed: break out of the page column without a transform, so the
     parallax on the hero stays free to use transform itself */
  width: 100vw;
  aspect-ratio: 4 / 3;   /* the loop is 1664x1248 */
  margin: calc(var(--t) * 0.55) calc(50% - 50vw) 0;
}
.hero-art .plate,
.hero-art > canvas,
.hero-art > video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.hero-art > video { opacity: 0; pointer-events: none; }  /* green plate: never shown raw */
.hero-art > canvas { z-index: 2; }
.hero-art.gl-on .plate { opacity: 0; }
.hero-art .plate { transition: opacity 0.8s ease; }

.hero-art .ink-name {
  position: absolute;
  left: 28%;
  top: 0.5%;
  width: 44%;
  z-index: 3;
}

/* a word the wave can move: transforms do not apply to inline boxes */
.wv { display: inline-block; }

/* ————— date —————
   The date now tucks up into the artwork's own paper, and the hero paints
   through a positioned canvas (z-index 2). Unpositioned content later in the
   document still loses to that, which sliced the top off the digits — so the
   date claims a layer of its own above it. */
.page section[data-a="date"] {
  position: relative;
  z-index: 4;
}
.date-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--t) * 0.30);
  /* the artwork carries its own paper below the ribbon — the last ink in the
     centre band sits at 95.4% of the frame, so the figure box ends ~0.45t below
     what the eye reads as the bottom edge. Pull that back so the date hangs off
     the ribbon rather than floating in a gap of its own. */
  margin-top: calc(var(--t) * -0.30);
}
.date-side {
  font-family: var(--serif);
  font-size: var(--fs-side);
  letter-spacing: 0.098em;
  line-height: 1;
  white-space: nowrap;
}
.date-num {
  font-family: var(--serif);
  font-size: var(--fs-num);
  line-height: 1;
  color: var(--rose-deep);
  padding: 0 calc(var(--t) * 0.30);
  border-left: 1px solid var(--hairline);
  border-right: 1px solid var(--hairline);
}
.date-month {
  font-family: var(--serif);
  text-align: center;
  font-size: var(--fs-month);
  letter-spacing: 0.063em;
  line-height: 1;
  margin: calc(var(--t) * 0.350) 0 0;
}

.venue {
  text-align: center;
  /* the church line plus its pin runs a shade wider than the column;
     give this block a little more measure rather than shrinking the type */
  margin: calc(var(--t) * 0.641) calc(var(--panel) * -0.03) 0;
  font-family: var(--serif);
  font-size: var(--fs-church);
  line-height: 1.115;
  letter-spacing: 0.069em;
  color: var(--ink);
}
.venue a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--rose);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  transition: color 0.25s ease, text-decoration-color 0.25s ease;
}
.venue a:hover { color: var(--rose-ink); text-decoration-color: var(--rose-ink); }
.venue .pin { display: inline-block; width: 0.85em; height: 0.85em; vertical-align: -0.06em; margin-right: 6px; }
.venue .pin path { fill: var(--rose-deep); }


/* ————— divider ————— */
.divider {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: calc(var(--t) * 0.782) auto calc(var(--t) * 0.667);
}
.divider::before, .divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--hairline);
}
.divider svg { width: 13px; height: 13px; flex: none; }
.divider svg path { fill: var(--rose); }

/* ————— people ————— */
.people { text-align: center; }
.people .role {
  font-family: var(--serif);
  font-size: var(--fs-role);
  letter-spacing: 0.077em;
  line-height: 1;
  color: var(--rose-ink);
  margin: 0 0 calc(var(--t) * 0.144);
}
.people .names + .role { margin-top: calc(var(--t) * 0.540); }
.people .names {
  font-family: var(--serif);
  font-size: var(--fs-name);
  letter-spacing: 0.066em;
  line-height: 1.333;
  margin: 0;
}

.gift-note {
  text-align: center;
  /* At the names' size the hand-placed breaks this block used to carry orphaned
     ΛΙΣΤΑ onto a line of its own. Rather than re-place them for one width, the
     prose wraps and the browser evens the lines; only the list number keeps a
     hard break, since it should always land on its own. Where balance is not
     supported this simply wraps, which still beats a break in the wrong place —
     and with the prose free to wrap, the block no longer needs the sliver of
     extra measure it used to borrow from the column. */
  text-wrap: balance;
  /* more air above than the card had: this is the one block a guest has to act
     on later, and it should read as its own note rather than as a last line of
     the names above it */
  margin: calc(var(--t) * 1.94) 0 0;
  font-family: var(--serif);
  /* Set as the names are set. It was the smallest and palest thing on the page
     and also the only one a guest has to come back to later; rose on this paper
     measures 2.43:1, roughly half what text that size needs, which at 10.5px is
     a legibility problem before it is a noticing one. On the names' ink it
     measures 6.63:1. It reads level with them now rather than under them —
     which is the deliberate choice: the gift mark above it and the space around
     it are what keep it a note rather than a request. */
  font-size: var(--fs-name);
  letter-spacing: 0.066em;
  line-height: 1.333;
  color: var(--ink);
}

/* a quiet gift mark above the note — drawn in the same hairline weight as the
   rules and the pin, so it reads as part of the card rather than an app icon */
.gift-mark {
  display: block;
  /* Set against the cap height of the note it heads, which is what the eye
     actually compares it to. 0.72t was 2.63 cap heights and read as an icon;
     0.40t was 1.46 and disappeared. 0.55t is 2.0 — twice the letters below it,
     which is the proportion a printed ornament heading a paragraph tends to
     take. The inline marks (13px heart, 17px pin) are a different job: they sit
     within a line rather than over a block, so they are not the yardstick. */
  width: calc(var(--t) * 0.55);
  height: calc(var(--t) * 0.55);
  margin: 0 auto calc(var(--t) * 0.34);
  fill: var(--rose);
  opacity: 0.9;
}

/* solid mark inside the button, same weight as the pin and the gift */
.btn-icon {
  width: 1.05em;
  height: 1.05em;
  fill: currentColor;
  vertical-align: -0.16em;
  margin-right: 0.55em;
}

/* ————— the one button ————— */
.actions { text-align: center; margin-top: clamp(32px, 7.5vw, 48px); }
.btn {
  display: inline-block;
  font-family: var(--serif);
  /* a CTA needs a floor: the type scale alone drops it under 10px on a phone */
  font-size: max(13.5px, calc(var(--t) * 0.42));
  font-weight: 400;
  letter-spacing: 0.118em;
  color: #fff;
  background: var(--rose);
  border: 0;
  border-radius: 999px;
  min-height: 48px;
  padding: 15px 32px;
  cursor: pointer;
  text-decoration: none;
  box-shadow: 0 8px 22px rgba(197, 142, 144, 0.3);
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease, opacity 0.2s;
  -webkit-tap-highlight-color: transparent;
}
.btn:hover { transform: translateY(-1px); box-shadow: 0 10px 26px rgba(197, 142, 144, 0.42); }
.btn:active { transform: scale(0.97); }
.btn[disabled] { opacity: 0.55; pointer-events: none; }

/* The church invitation ends with the gift note; the meal is a new chapter.
   The card's rule-and-heart is its one ornament and it is already spent above,
   between the venue and the family — using it again here would say "another
   small pause" when this is the largest break on the page. Space says it
   better, and says it only once. */
.meal-chapter { margin-top: calc(var(--t) * 2.6); }

/* ————— meal ————— */
/* the meal loop, square, sitting on the paper like the hero */
.meal-art-fig {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  margin: 4px 0 0;
  /* the loop is scaled up inside this box, so it has to be clipped to it */
  overflow: hidden;
}
/* Pushed in a little: the bear sat small in a lot of bare paper. Done here
   rather than by re-cropping the file — the loop is 1440px square shown at
   about 510, so there is resolution to spare and no re-encode to pay for, and
   the amount stays a single number to tune. The caption is a sibling and keeps
   its own scale; at 120% the bear's feet reach 82% and the arch's legs 80%,
   both still clear of the band the venue sits in at 85%. */
.meal-art-fig .plate,
.meal-art-fig > canvas {
  transform: scale(1.2);
  transform-origin: 50% 50%;
}
.meal-art-fig .plate,
.meal-art-fig > canvas,
.meal-art-fig > video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.meal-art-fig > video { opacity: 0; pointer-events: none; }
.meal-art-fig > canvas { z-index: 2; }
.meal-art-fig.gl-on .plate { opacity: 0; }
.meal-art-fig .plate { transition: opacity 0.8s ease; }

/* The arch leaves a clear band under the bear — his feet end at 77% and the
   legs of the arch fade by 92% — so the venue sits inside it rather than
   below the picture. */
.meal-caption {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 3.5%;
  z-index: 3;
  text-align: center;
}
.meal-caption .meal-place { margin: 0; }
.meal-caption .venue { margin: 0.25em 0 0; }
.meal-place {
  font-family: var(--serif);
  text-align: center;
  font-size: var(--fs-month);
  letter-spacing: 0.06em;
  line-height: 1.2;
  color: var(--rose-ink);
  margin: calc(var(--t) * 0.5) 0 calc(var(--t) * 0.2);
}
/* inside the arch the venue needs no extra measure — it is already inset */
.meal-caption .venue { margin-inline: 0; }

/* ————— RSVP — a question on the paper, not a form ————— */
.rsvp { text-align: center; margin-top: calc(var(--t) * 1.4); }
.rsvp h3 {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--fs-month);
  letter-spacing: 0.06em;
  line-height: 1.25;
  margin: 0 0 calc(var(--t) * 0.26);
}
.rsvp .deadline {
  font-family: var(--serif);
  font-size: var(--fs-gift);
  letter-spacing: 0.058em;
  line-height: 1.35;
  color: var(--rose-ink);
  margin: 0 0 calc(var(--t) * 1.05);
}

/* the name sits on a ruled line, centred like everything else */
.field { margin: 0 auto; max-width: 22em; }
.field label {
  display: block;
  font-family: var(--serif);
  font-size: calc(var(--t) * 0.27);
  letter-spacing: 0.14em;
  color: var(--ink-soft);
  margin: 0 0 calc(var(--t) * 0.24);
}
.field input {
  width: 100%;
  font-family: var(--serif);
  font-weight: 300;
  /* never below 16px, or iOS zooms the page on focus */
  font-size: max(16px, calc(var(--t) * 0.5));
  letter-spacing: 0.04em;
  text-align: center;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  border-radius: 0;
  padding: 0 0 calc(var(--t) * 0.26);
  outline: none;
  transition: border-color 0.3s ease;
}
.field input::placeholder { color: #d3c5b4; }
.field input:focus { border-bottom-color: var(--rose); }
.field input:focus-visible { outline: none; }

/* the two answers — quiet until chosen, then unmistakable */
.seg {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(var(--t) * 0.32);
  max-width: 22em;
  margin: calc(var(--t) * 0.95) auto 0;
}
.seg button {
  position: relative;
  font-family: var(--serif);
  font-size: max(12.5px, calc(var(--t) * 0.30));
  font-weight: 300;
  letter-spacing: 0.1em;
  min-height: 52px;
  padding: calc(var(--t) * 0.42) calc(var(--t) * 0.2);
  border-radius: 999px;
  border: 1px solid var(--hairline);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  transition: color 0.3s ease, border-color 0.3s ease,
              background-color 0.3s ease, box-shadow 0.35s ease, transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
  -webkit-tap-highlight-color: transparent;
}
.seg button:hover { border-color: var(--rose); color: var(--ink); }
.seg button:active { transform: scale(0.98); }
.seg button.on-yes {
  background: var(--rose);
  border-color: transparent;
  color: #fff;
  box-shadow: 0 10px 24px rgba(197, 142, 144, 0.3);
  transform: translateY(-1px);
}
.seg button.on-no {
  background: transparent;
  border-color: var(--rose-deep);
  color: var(--rose-ink);
}

/* how many — only once they have said yes */
.stepper-wrap {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 0.5s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.4s ease;
}
.stepper-wrap.open { grid-template-rows: 1fr; opacity: 1; }
.stepper-wrap > div { overflow: hidden; }
.stepper {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--t) * 0.75);
  padding-top: calc(var(--t) * 0.85);
}
.stepper button {
  width: calc(var(--t) * 1.45); height: calc(var(--t) * 1.45);
  min-width: 44px; min-height: 44px;
  border-radius: 50%;
  border: 1px solid var(--hairline);
  background: transparent;
  color: var(--rose-ink);
  font-family: var(--serif);
  font-size: calc(var(--t) * 0.62);
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.25s ease, color 0.25s ease, transform 0.18s;
  -webkit-tap-highlight-color: transparent;
}
.stepper button:hover { border-color: var(--rose); color: var(--rose-deep); }
.stepper button:active { transform: scale(0.9); }
.stepper .num {
  font-family: var(--serif);
  font-size: calc(var(--t) * 1.0);
  min-width: calc(var(--t) * 1.3);
  color: var(--rose-deep);
  line-height: 1;
}
.stepper-lbl {
  font-family: var(--serif);
  font-size: calc(var(--t) * 0.26);
  letter-spacing: 0.14em;
  color: var(--ink-soft);
  margin: calc(var(--t) * 0.4) 0 0;
}

/* one primary action; it wakes up when the answer is complete. Bound to the
   button itself, not its surroundings — it now lives inside the sheet. */
#sendBtn {
  margin-top: calc(var(--t) * 1.05);
  opacity: 0.45;
  transition: opacity 0.35s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;
}
#sendBtn.ready { opacity: 1; }

.rsvp-error, .rsvp-again {
  display: none;
  margin: calc(var(--t) * 0.5) auto 0;
  max-width: 24em;
  font-family: var(--serif);
  font-size: var(--fs-gift);
  letter-spacing: 0.05em;
  line-height: 1.45;
}
.rsvp-error { color: #a9636a; }
.rsvp-again { color: var(--ink-soft); }
.rsvp-error.show, .rsvp-again.show { display: block; }

/* thank-you */
.rsvp-success { display: none; flex-direction: column; align-items: center; }
.rsvp.done .form-stack { display: none; }
.rsvp.done .rsvp-success { display: flex; animation: rise 0.8s ease both; }
.rsvp-success .mark { color: var(--rose); font-size: calc(var(--t) * 0.8); line-height: 1; }
.rsvp-success .big {
  font-family: var(--serif);
  font-size: var(--fs-month);
  letter-spacing: 0.06em;
  margin-top: calc(var(--t) * 0.3);
}
.rsvp-success .for-no { display: none; }
.rsvp.declined .rsvp-success .for-yes { display: none; }
.rsvp.declined .rsvp-success .for-no { display: block; }
.rsvp-success p {
  margin: calc(var(--t) * 0.3) 0 0;
  font-family: var(--serif);
  font-size: var(--fs-gift);
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  line-height: 1.55;
}

/* The calendar reads the same on both invitations: a quiet underlined link
   with its mark, never a filled pill. On the meal page it also has to sit
   below the RSVP without competing with it. */
.actions .btn {
  background: none;
  color: var(--rose-ink);
  box-shadow: none;
  min-height: 44px;
  font-size: max(12px, calc(var(--t) * 0.32));
  letter-spacing: 0.14em;
  padding: calc(var(--t) * 0.3) calc(var(--t) * 0.4);
  text-decoration: underline;
  text-decoration-color: var(--rose);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.32em;
}
.actions .btn:hover { transform: none; color: var(--ink); text-decoration-color: var(--ink-soft); }

/* ————— scroll cue —————
   Guests who do not scroll never reach the church details, or on the meal page
   the RSVP itself. A word plus a thread of ink running down a hairline — the
   same vocabulary as the balloon string and the rules elsewhere on the card. */
.scroll-cue {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 7;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--t) * 0.34);
  /* a soft bed of the page's own paper so the cue never sits on top of text.
     Kept on the element itself: a transform here would make any fixed child
     resolve against this box instead of the viewport. */
  padding: calc(var(--t) * 2.4) 0 calc(var(--frame) * 0.5 + clamp(10px, 3vw, 22px));
  background: linear-gradient(to top,
    var(--paper) 26%,
    rgba(246, 240, 234, 0.92) 52%,
    rgba(246, 240, 234, 0.6) 74%,
    rgba(246, 240, 234, 0) 100%);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.9s ease;
}
.scroll-cue.show { opacity: 1; }
.scroll-cue.gone { opacity: 0; }
.scroll-cue span {
  font-family: var(--serif);
  font-weight: 400;         /* one step up from the page: tracked caps this small need the extra stem */
  font-size: max(15px, calc(var(--t) * 0.38));
  letter-spacing: 0.34em;
  text-indent: 0.34em;      /* tracking adds a trailing gap; nudge back to centre */
  color: var(--rose-ink);
  white-space: nowrap;
  /* the cue can land over the artwork, where rose-on-fur all but disappears.
     A halo of the page's own paper keeps it legible without a box or a rule. */
  text-shadow: 0 0 10px var(--paper), 0 0 18px var(--paper);
}
/* The line runs down INTO the word rather than away from it: faint where it
   starts, strongest where it arrives. With the word underneath, a line that
   faded downward pointed at nothing. */
.scroll-cue .track {
  position: relative;
  width: 1px;
  height: calc(var(--t) * 1.9);
  background: linear-gradient(to bottom, rgba(197, 142, 144, 0), rgba(197, 142, 144, 0.7));
  overflow: hidden;
}
.scroll-cue .track::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 48%;
  background: linear-gradient(to bottom, rgba(197,142,144,0), var(--rose-deep), rgba(197,142,144,0));
  animation: cue-run 2.2s cubic-bezier(0.55, 0, 0.35, 1) infinite;
}
/* Contrast alone was not carrying it — the eye catches movement first. Both
   parts drift together, slowly enough to read as breathing rather than nagging. */
.scroll-cue span,
.scroll-cue .track { animation: cue-float 2.8s ease-in-out infinite; }
.scroll-cue .track { animation-name: cue-float; }
@keyframes cue-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(10px); }
}
@keyframes cue-run {
  0%   { transform: translateY(-100%); opacity: 0; }
  30%  { opacity: 1; }
  75%  { opacity: 1; }
  100% { transform: translateY(240%); opacity: 0; }
}

/* ————— the answer sheet —————
   The section asks one question; the details are asked here, once a guest has
   chosen. Cut from the same paper as the page so it reads as a leaf of the
   invitation rather than a dialog box. */
.sheet {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gutter);
}
.sheet[hidden] { display: none; }
.sheet-veil {
  position: absolute;
  inset: 0;
  background: rgba(240, 232, 224, 0.72);
  -webkit-backdrop-filter: blur(3px);
          backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 0.35s ease;
}
.sheet-panel {
  position: relative;
  width: 100%;
  max-width: 25em;
  max-height: 88dvh;
  overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: 3px;
  box-shadow: 0 24px 60px rgba(110, 90, 71, 0.16);
  padding: calc(var(--t) * 1.5) calc(var(--t) * 1.1) calc(var(--t) * 1.25);
  text-align: center;
  opacity: 0;
  /* origin is set per-open to the button that was pressed, so the sheet grows
     out of the answer rather than materialising in the middle of the screen */
  transform: scale(0.62);
  transition: opacity 0.42s ease, transform 0.48s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.sheet.open .sheet-veil { opacity: 1; }
.sheet.open .sheet-panel { opacity: 1; transform: none; }

.sheet-title {
  font-family: var(--serif);
  font-size: var(--fs-month);
  letter-spacing: 0.10em;
  line-height: 1.25;
  color: var(--rose-ink);
  margin: 0 0 calc(var(--t) * 0.95);
}
.sheet-close {
  position: absolute;
  top: calc(var(--t) * 0.18);
  right: calc(var(--t) * 0.18);
  width: 44px;
  height: 44px;
  border: 0;
  background: none;
  color: var(--ink-soft);
  font-family: var(--serif);
  font-size: calc(var(--t) * 0.8);
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.sheet-close:hover { color: var(--ink); }
.sheet .field { max-width: none; }
.sheet .btn { margin-top: calc(var(--t) * 1.05); }

@media (prefers-reduced-motion: reduce) {
  .sheet-veil, .sheet-panel { transition: none; }
}


/* ————— motion system ————— */
.js [data-a] { opacity: 0; }
.js.no-anim [data-a] { opacity: 1; }

/* hearts burst */
.burst { position: fixed; width: 20px; height: 20px; pointer-events: none; z-index: 90; animation: burst 1.45s cubic-bezier(0.16, 0.72, 0.32, 1) forwards; }
.burst svg { width: 100%; height: 100%; display: block; }
/* they used to fade the whole way out, which at a glance looked like nothing
   happened. Now they open quickly, hold, and only let go at the end. */
@keyframes burst {
  0%   { opacity: 0;   transform: translate(0, 0) scale(0.35) rotate(0); }
  12%  { opacity: 1;   transform: translate(calc(var(--dx) * 0.18), calc(var(--dy) * 0.18)) scale(1.05) rotate(calc(var(--rot) * 0.2)); }
  68%  { opacity: 1; }
  100% { opacity: 0;   transform: translate(var(--dx), var(--dy)) scale(1.3) rotate(var(--rot)); }
}
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

.toast {
  position: fixed;
  left: 50%; bottom: 26px;
  transform: translateX(-50%) translateY(16px);
  background: #5f4634; color: #fff;
  padding: 12px 22px; border-radius: 999px;
  font-size: 14px; opacity: 0; pointer-events: none;
  transition: opacity 0.35s ease, transform 0.35s ease;
  max-width: 88vw; text-align: center; z-index: 99;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .hero-art > video { display: none; }
  .scroll-cue .track::after { animation: none; opacity: 0.85; transform: translateY(60%); }
  .stepper-wrap { transition: none; }
  .burst { display: none; }
}
