/* =========================================================
   Jonathan & Anna-Maria — Wedding Invitation
   Theme: glowing garden — coral, magenta, peach & eucalyptus
   ========================================================= */

:root {
  /* palette */
  --cream: #fff6ee;
  --ivory: #fffaf3;
  --paper: #fdf3e8;
  --blush: #fbe3da;
  --blush-2: #f7d2c3;
  --peach: #ffc9a8;
  --peach-2: #ffb088;
  --coral: #ff7a4f;
  --coral-2: #f25f2a;
  --magenta: #e6276b;
  --hot-pink: #d81f5c;
  --deep-rose: #b0124b;
  --eucalyptus: #7c8f6a;
  --olive: #4a5839;
  --gold: #c8a55c;
  --gold-2: #b08940;
  --ink: #2a1418;
  --ink-soft: #5b3b3f;

  /* type */
  --serif: "Cormorant Garamond", "Playfair Display", Georgia, serif;
  --script: "Pinyon Script", "Allura", cursive;
  --sans: "Manrope", "Inter", system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;

  /* phone */
  --phone-w: 390px;
  --phone-h: 844px;
  --phone-radius: 44px;
  --phone-bezel: 12px;

  /* welcome-page envelope — zoom factor
     -------------------------------------------------
     Controls how big the envelope images (flap + body) appear on
     the welcome screen. The value is the rendered WIDTH of each
     image, expressed as a percentage of the phone-frame width.

       100%  → images match the phone width exactly (original)
       130%  → images are 30% larger and overflow both sides
                (clipped by the phone frame, gives a zoomed-in look)
       150%  → even more zoomed-in
       80%   → smaller, with breathing room on both sides

     Both images scale equally so they stay locked together as one
     graphic. */
  --envelope-scale: 130%;

  /* welcome-page envelope FLAP — vertical offset
     -------------------------------------------------
     Controls the vertical position of the TOP image (the flap +
     wax seal) within the phone frame.

     The flap is anchored at 50% of the phone height by default.
     This variable adds an extra nudge on top of that:

       0px      → wax seal centered on the phone (default 50%)
       -200px   → flap pinned near the very top of the phone (current)
       -300px   → flap pushed even higher (its top edge starts going
                  off-screen above)
       100px    → flap shifted down 100px from center

     Negative values move UP, positive values move DOWN.
     Accepts any CSS length: px, %, rem, vh, calc(...) etc. */
  --envelope-flap-offset: -170px;

  /* welcome-page envelope BODY — vertical offset
     -------------------------------------------------
     Controls the vertical position of the BOTTOM image (the envelope
     body) within the phone frame. ONLY the body moves with this — the
     flap and wax stay put, controlled by --envelope-flap-offset.

     The body's top edge is anchored at 20% of the phone height by
     default. This variable adds an extra nudge on top of that:

       0px      → body's top edge sits at 20% of the phone (default)
       -200px   → body lifted 200px upward (current)
       -300px   → body pushed even higher (top edge runs off-screen)
       100px    → body shifted down 100px from its default

     Negative values move UP, positive values move DOWN.
     Accepts any CSS length: px, %, rem, vh, calc(...) etc. */
  --envelope-body-offset: -250px;

  /* welcome-page wax color
     -------------------------------------------------
     The deep burgundy red of the wax seal on the envelope flap.
     Used by the "Tap To Open!" cue (text + arrow) so it visually
     ties to the wax above it. Tweak freely to match the actual
     wax tone in the rendered image. */
  --wax: #7e1320;

  /* welcome-page wax button — rendered size
     -------------------------------------------------
     Width AND height of the invisible round wax-seal button. Shared
     between `.welcome-btn` (which uses it as its width/height) and
     `.welcome-hint` (which uses half of it to compute the gap from
     the button's bottom edge), so the "Tap To Open!" cue always
     stays a fixed 50 px below the bottom of the wax — even if the
     button size is tweaked here. */
  --welcome-btn-size: clamp(110px, 30%, 150px);

  /* welcome-page hint — gap from wax button
     -------------------------------------------------
     Vertical distance, in CSS pixels, between the BOTTOM edge of the
     wax button and the TOP of the "Tap To Open!" cue (arrow + label).
     Held constant regardless of button size or screen size. */
  --welcome-hint-gap: 50px;
}

/* ---------- reset ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  padding: 0;
  /* CONSTANT 100svh — same reasoning as `.phone` and the snap
     sections. Locking html/body to the small-viewport height
     prevents iOS Safari from re-centering the phone (via the body's
     grid-place-items) every time the URL bar collapses, which would
     otherwise shift every snap target by a few pixels. */
  height: 100svh;
  overflow: hidden;
  font-family: var(--sans);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
body {
  /* Page itself never scrolls — every scroll gesture lands on the
     inner .phone-screen, which scrolls through the sections. */
  overflow: hidden;
  background: radial-gradient(
      120% 80% at 50% 0%,
      #fff5e8 0%,
      #fde4d6 35%,
      #fbcfd1 65%,
      #f4b6c0 100%
    ),
    var(--cream);
  background-attachment: fixed;
  display: grid;
  place-items: center;
}
img {
  display: block;
  max-width: 100%;
  user-select: none;
  -webkit-user-drag: none;
}
button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: 0;
  background: transparent;
}

/* ---------- decorative desktop backdrop ---------- */
.desk-backdrop {
  position: fixed;
  inset: 0;
  pointer-events: none;
  display: none;
  overflow: hidden;
  z-index: 0;
}
.desk-glow {
  position: absolute;
  inset: -10%;
  background:
    radial-gradient(40% 30% at 20% 20%, rgba(255, 169, 120, 0.55), transparent 70%),
    radial-gradient(35% 30% at 85% 30%, rgba(230, 39, 107, 0.45), transparent 70%),
    radial-gradient(45% 35% at 70% 85%, rgba(255, 200, 150, 0.55), transparent 70%),
    radial-gradient(35% 30% at 15% 85%, rgba(124, 143, 106, 0.35), transparent 70%);
  filter: blur(40px);
}
.desk-petals {
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle at 8% 18%, rgba(230, 39, 107, 0.25) 0 6px, transparent 7px),
    radial-gradient(circle at 92% 25%, rgba(242, 95, 42, 0.25) 0 5px, transparent 6px),
    radial-gradient(circle at 12% 78%, rgba(255, 176, 136, 0.3) 0 7px, transparent 8px),
    radial-gradient(circle at 88% 80%, rgba(124, 143, 106, 0.25) 0 5px, transparent 6px);
}
@media (min-width: 768px) {
  .desk-backdrop {
    display: block;
  }
}

/* ---------- the phone frame ---------- */
.phone {
  position: relative;
  width: 100vw;
  /* `100svh` = small viewport height, COMPUTED ONCE as if the URL
     bar were always visible. It does NOT change when iOS Safari's
     URL bar collapses or expands, which means the snap targets
     inside this frame are mathematically constant. */
  height: 100svh;
  overflow: hidden;
  background: var(--cream);
  z-index: 1;
}
.phone-notch,
.phone-bottom {
  display: none;
}

/* lock to phone size on tablets and up */
@media (min-width: 768px) {
  .phone {
    width: var(--phone-w);
    height: min(var(--phone-h), 92vh);
    border-radius: var(--phone-radius);
    border: var(--phone-bezel) solid #1a0d10;
    box-shadow:
      0 0 0 2px #3a2125 inset,
      0 30px 80px -20px rgba(120, 20, 50, 0.45),
      0 60px 120px -30px rgba(255, 120, 90, 0.35);
    overflow: hidden;
  }
  .phone-notch {
    display: block;
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    width: 110px;
    height: 28px;
    background: #0a0507;
    border-radius: 999px;
    z-index: 50;
  }
  .phone-bottom {
    display: block;
    position: absolute;
    bottom: 8px;
    left: 50%;
    transform: translateX(-50%);
    width: 130px;
    height: 4px;
    background: #ffffff66;
    border-radius: 999px;
    z-index: 50;
  }
}

.phone-screen {
  position: relative;
  /* Sit ABOVE the .bg-stack (z 5) so the scrolling text is always
     painted on top of the fixed photo, regardless of the stacking
     context iOS Safari creates around scroll containers. */
  z-index: 10;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  scroll-behavior: auto;
  -webkit-overflow-scrolling: touch;
  /* Kill the rubber-band bounce at the very first and very last
     sections on iOS Safari. `none` (vs. `contain`) disables the
     overscroll INSIDE this scroller, so the boundary feels as locked
     as every snap point in between. */
  overscroll-behavior-y: none;
  /* Tell the browser this scroller only handles vertical pans —
     keeps horizontal swipes from being intercepted as a "back"
     gesture or stealing focus from the snap. */
  touch-action: pan-y;
  /* Transparent so the .bg-stack shows through. The dark fallback
     colour now lives on .bg-stack itself. */
  background: transparent;
  scrollbar-width: none;
  /* Per-section snap. Both the phone and the snap-section are sized
     in `100svh` — a CONSTANT, not a dynamic viewport unit — so iOS
     Safari's URL-bar dynamics can't move snap targets mid-scroll. */
  scroll-snap-type: y mandatory;
}
.phone-screen::-webkit-scrollbar {
  display: none;
}

/* =========================================================
   COVER · the welcome page is a soft warm backdrop with a
   self-contained envelope OBJECT centered on it (all four
   edges of the envelope visible, with a drop-shadow under
   it like a card resting on a surface). Tapping the wax
   seal triggers the opening animation: seal breaks →
   flap rotates open → cover fades to reveal the website.

   Animation timeline (ms from click):
     0     wax seal "breaks" (scale up + fade)
     350   flap begins rotating up (0.95s ease)
     1100  whole cover begins fading out
     1600  cover fully hidden, invitation visible
   ========================================================= */
.cover {
  position: absolute;
  inset: 0;
  /* The envelope graphics MUST sit above every other layer (logo at
     z 50, mute fab at z 50, topbar at z 40, etc.) so the flap and
     body always paint on top while the opening animation plays. */
  z-index: 999999;
  /* No fill — the cover is now transparent so the invitation /
     hero photo behind it is visible right from the welcome screen.
     Only the envelope graphics (flap + body + wax) and the click
     hotspot sit on top of the live page. */
  background: transparent;
  display: grid;
  place-items: center;
  isolation: isolate;
  overflow: hidden;
  /* perspective gives the flap real depth as it rotates open. */
  perspective: 1200px;
  -webkit-perspective: 1200px;
  /* Choreography:
       0–2000ms   → flap rotates up around its top hinge
       1000–2200ms → envelope body slides smoothly out the bottom
                     (overlaps with the tail-end of the flap lift)
       2200ms     → cover removed from the layout
     The cover itself stays fully transparent throughout; only the
     visibility flag flips at the end so the click target releases. */
  transition: visibility 0s linear 2.2s;
}
.cover.is-open {
  pointer-events: none;
  visibility: hidden;
}

/* Envelope flap with wax-seal monogram.
   --------------------------------------------------------------------
   The flap and the body (.cover-envelope-body) each have their own
   independent vertical offset variable so you can move one without
   touching the other:

     · flap (this rule) → wax position = 50% + --envelope-flap-offset
     · body             → top edge   = 20% + --envelope-body-offset

   Source-image geometry: in welcome-top.png (1024×568) the wax-seal
   center sits at roughly 50% horizontally and ~83% vertically — that's
   where the −83% translation comes from. */
.cover-envelope {
  position: absolute;
  top: calc(50% + var(--envelope-flap-offset));
  left: 50%;
  transform: translate(-50%, -83%);
  width: var(--envelope-scale);
  max-width: none;
  height: auto;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  z-index: 2;
  filter: drop-shadow(0 10px 22px rgba(120, 20, 30, 0.18));
  /* Pivot for the envelope-opening animation. The hinge sits at the
     TOP edge of the flap — that's the wide edge of the triangle, where
     a real envelope flap attaches to the body. From there the flap
     swings UP and BACK like a real envelope being opened (the wax-end
     at the bottom of the flap travels FROM bottom TO top of the
     screen). */
  transform-origin: 50% 0%;
  -webkit-transform-origin: 50% 0%;
  transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  /* Slow, cinematic easing — eases in gently, glides through the
     middle, and settles softly. cubic-bezier(0.4, 0, 0.2, 1) is the
     classic Material "standard" curve; the long 2-second duration
     gives the flap a real, deliberate "lifting" feel. */
  transition: transform 2s cubic-bezier(0.4, 0, 0.2, 1);
}
/* When the cover is opened (seal tapped), flip the flap upward 180° —
   the flap pivots at its TOP hinge so the wax-end at the bottom rises
   up TOWARD the viewer (positive rotateX makes the bottom of the
   element travel out of the screen toward the camera), exposing the
   envelope body underneath. The translate(-50%, -83%) is repeated so
   the original positioning is preserved through the animation. */
.cover.is-open .cover-envelope {
  transform: translate(-50%, -83%) rotateX(180deg);
}

/* Envelope body — sits behind the flap so the wax seal stays on top.
   Top edge is anchored at 20% of the phone frame, then nudged up or
   down ONLY by --envelope-body-offset. This variable affects the
   body and nothing else — change it freely without disturbing the
   flap.

   Once the flap finishes flipping (2 s after the click), this body
   slides smoothly out the bottom of the phone frame — see the
   .cover.is-open rule below. */
.cover-envelope-body {
  position: absolute;
  top: calc(20% + var(--envelope-body-offset));
  left: 50%;
  transform: translate(-50%, 0);
  width: var(--envelope-scale);
  max-width: none;
  height: auto;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  z-index: 1;
  /* Slide animation — kicks in 1 s after the click (overlapping with
     the second half of the flap lift) and drops the body downward
     over 1.2 s with a soft ease-in-out. `will-change` hints the
     browser to GPU-accelerate the slide for a buttery-smooth motion. */
  transition: transform 1.2s cubic-bezier(0.4, 0, 0.2, 1) 1s;
  will-change: transform;
}
/* When the cover is opened, after the flap has finished its lift the
   envelope body glides downward out of the phone frame, revealing the
   invitation behind it. translateY(120%) is relative to the body's
   own height (~89% of the cover) — more than enough to clear the
   bottom of the frame on every screen size. */
.cover.is-open .cover-envelope-body {
  transform: translate(-50%, 120%);
}

/* Wax-seal welcome button — an invisible round hotspot pinned exactly
   over the seal in the rendered envelope image. Tapping it fades the
   cover away and reveals the invitation behind. The seal is provided
   visually by .cover-envelope; this button supplies only the click
   target, focus ring and a soft press animation. Follows the same
   --envelope-flap-offset as .cover-envelope so it always tracks the
   wax. */
.welcome-btn {
  position: absolute;
  top: calc(50% + var(--envelope-flap-offset));
  left: 50%;
  transform: translate(-50%, -50%);
  /* Size shared via --welcome-btn-size so the hint below can compute
     a constant 50 px gap from the button's bottom edge. */
  width: var(--welcome-btn-size);
  height: var(--welcome-btn-size);
  z-index: 3;
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  padding: 0;
  background: transparent;
  border-radius: 50%;
  cursor: pointer;
  transition: transform 0.18s ease, filter 0.18s ease;
}
.welcome-btn:hover {
  transform: translate(-50%, -50%) scale(1.04);
  filter: brightness(1.05);
}
.welcome-btn:active {
  transform: translate(-50%, -50%) scale(0.96);
}
.welcome-btn:focus-visible {
  outline: 2px solid #b0124b;
  outline-offset: 6px;
}

/* =========================================================
   "Tap To Open!" cue
   -------------------------------------------------
   A decorative call-to-action that lives BELOW the wax seal:
     - a curved hand-drawn-looking SVG arrow points up at the wax
     - a "Tap To Open!" label in the script font sits beneath it
   The whole block is anchored to the same flap offset variable as
   the wax button, so it always tracks the seal as the user tweaks
   --envelope-flap-offset. It bobs gently to draw the eye, and
   fades out the instant the cover starts opening.
   ========================================================= */
.welcome-hint {
  position: absolute;
  /* Vertical anchor — pinned exactly --welcome-hint-gap (50 px) below
     the BOTTOM edge of the wax button, regardless of how the button
     is sized.

       button center  = 50% + var(--envelope-flap-offset)
       button bottom  = button center + var(--welcome-btn-size) / 2
       hint top       = button bottom + var(--welcome-hint-gap)

     Keeping the hint anchored to the button's bottom (instead of a
     hard-coded 100px below the button's center) means the gap stays
     visually constant as the button or screen size changes. */
  top: calc(
    50%
    + var(--envelope-flap-offset)
    + (var(--welcome-btn-size) / 2)
    + var(--welcome-hint-gap)
  );
  /* Horizontal anchor — bulletproof centering. By spanning the full
     width of the cover and shrinking the block to its own content
     width (`width: max-content`) we side-step any transform-based
     centering quirks (on iOS Safari, in particular, an `infinite`
     keyframed transform can leave the element briefly at its base
     `none` transform during the first paint, which used to pull
     the hint to the left by 50% of its width). */
  left: 0;
  right: 0;
  margin-inline: auto;
  width: max-content;
  max-width: min(90vw, 320px);
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  pointer-events: none;
  user-select: none;
  color: var(--wax);
  text-align: center;
  opacity: 1;
  transition: opacity 0.35s ease;
  /* Gentle vertical bob — no more horizontal translate, so this
     animation only affects the Y axis. */
  animation: welcome-hint-bob 1.7s ease-in-out infinite;
}

.welcome-hint-arrow {
  /* The arrow is supplied as a pre-colored PNG. Its canvas (272×610)
     is wider than the visible arrow drawing — the arrowhead sits at
     roughly 42 % from the left of the canvas, and the loopy tail
     extends further left still. Shifting the image ~7 % to the right
     brings the arrowhead's sharp tip into the true horizontal centre
     of the hint block (and therefore the screen), so both the arrow
     and the "Tap To Open!" label below it read as centred. */
  width: 52px;
  height: auto;
  display: block;
  transform: translateX(7%);
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
  /* A soft wax shadow underneath so the arrow lifts off the
     background photo, mirroring the glow on the text below it. */
  filter: drop-shadow(0 2px 6px rgba(126, 19, 32, 0.3));
}

.welcome-hint-text {
  /* Same script as the "Jonathan & Anna‑Maria" hero signature so
     the welcome cue feels typographically tied to the invitation
     itself. Allura first, with Pinyon Script as the system fallback. */
  font-family: "Allura", var(--script);
  font-size: 36px;
  line-height: 1;
  letter-spacing: 0.4px;
  color: var(--wax);
  /* Tiny cream stroke + soft wax glow so the script reads on any
     background and feels hand-inked rather than printed. */
  text-shadow:
    0 1px 0 rgba(255, 246, 238, 0.95),
    0 2px 12px rgba(126, 19, 32, 0.32);
  white-space: nowrap;
}

@keyframes welcome-hint-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}

/* The cue disappears the moment the wax is tapped — the bob keeps
   running but opacity fades, so it slips away gracefully while the
   envelope animation begins. */
.cover.is-open .welcome-hint {
  opacity: 0;
}

/* Formal addressees, pinned to the BOTTOM of the cover screen on a
   single fixed line in the same wax-red as the logo. NOT inside
   .welcome-hint, so the bob animation and the tap-fade don't apply
   to it. The line just sits there, motionless, until the .cover
   itself goes visibility:hidden at the end of the envelope-open
   animation — at which point the whole cover (this line included)
   is no longer in the layout.

   Filled in by script.js from the Sheet's Title / First Name /
   Last Name columns. Stays hidden until there's something to show. */
.cover-names {
  position: absolute;
  /* Anchor to the bottom edge of the cover, lifted just enough to
     clear the iPhone home indicator (env-safe-area). On Android /
     desktop, the env() returns 0 and we get a clean ~22px gap. */
  bottom: calc(env(safe-area-inset-bottom, 0px) + 22px);
  /* Bullet-proof horizontal centering — span the whole cover and
     shrink the block to its own content width via margin auto. */
  left: 0;
  right: 0;
  margin: 0 auto;
  width: max-content;
  max-width: 92vw;
  z-index: 4;

  /* Logo gold — matches the metallic accents on the wedding logo. */
  color: var(--gold);
  /* Upright Cormorant in small-caps with generous tracking — the
     classic engraved-stationery look. The italic & glyph from the
     previous pass had that swirly cursive shape; the upright form
     is a clean, balanced ampersand that reads as "& on a card". */
  font-family: var(--serif);
  font-style: normal;
  font-weight: 700;
  font-variant-caps: all-small-caps;
  text-transform: lowercase;
  font-size: clamp(13px, 3.4vw, 15.5px);
  line-height: 1.2;
  letter-spacing: 0.22em;
  text-align: center;
  white-space: nowrap;

  /* Soft cream halo + faint warm glow so the line lifts off whatever
     background photo is behind the cover. */
  text-shadow:
    0 1px 0 rgba(255, 246, 238, 0.85),
    0 2px 10px rgba(176, 137, 64, 0.30);

  /* Bound to the envelope body's slide. The body runs:
       transform: translate(-50%, 120%);
       transition: transform 1.2s cubic-bezier(0.4, 0, 0.2, 1) 1s;
     We mirror the same easing + duration + 1s delay here so the names
     ride down WITH the body image instead of staying behind. The
     translateY(110vh) overshoot guarantees the names clear the bottom
     edge of the screen at the same moment the body does, on every
     phone size. */
  transform: translateY(0);
  transition: transform 1.2s cubic-bezier(0.4, 0, 0.2, 1) 1s;
  will-change: transform;
  pointer-events: none;
  user-select: none;
}
.cover.is-open .cover-names {
  transform: translateY(110vh);
}
.cover-names[hidden],
.cover-names:empty { display: none; }

/* ---------------------------------------------------------------
   LOCKED COVER · shown when the URL has no guest code, the code is
   malformed, or the database has no row for it. The seal button,
   the "Tap To Open!" hint and the formal-name line all collapse out
   of the layout, and a centred bordo message takes their place. The
   envelope graphics stay visible behind so the page still reads as
   a wedding invitation, just one the visitor isn't recognised on.
   --------------------------------------------------------------- */
.cover.is-locked .welcome-btn,
.cover.is-locked .welcome-hint,
.cover.is-locked .cover-names {
  display: none !important;
}
.cover-locked {
  position: absolute;
  /* Dead-centre on the screen — both axes. The translate(-50%, -50%)
     pulls the block back by half its own size from a top:50% / left:50%
     anchor, so the message sits centred regardless of how tall it
     wraps to on narrow phones. */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: max-content;
  max-width: min(92vw, 360px);
  z-index: 4;
  text-align: center;
  padding: 0 16px;
  pointer-events: none;
  user-select: none;
  /* No animation, no transition — the message is final. */
}
.cover-locked[hidden] { display: none; }
.cover-locked-title {
  margin: 0 0 8px;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 600;
  font-size: clamp(20px, 5.6vw, 24px);
  line-height: 1.2;
  color: var(--wax);
  text-shadow:
    0 1px 0 rgba(255, 246, 238, 0.7),
    0 2px 14px rgba(126, 19, 32, 0.32);
}
.cover-locked-body {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(14px, 4vw, 16px);
  line-height: 1.45;
  color: var(--wax);
  max-width: 32ch;
  margin-inline: auto;
  text-shadow:
    0 1px 0 rgba(255, 246, 238, 0.55),
    0 2px 12px rgba(126, 19, 32, 0.28);
}

@media (prefers-reduced-motion: reduce) {
  .welcome-hint {
    animation: none;
    transform: none;
  }
}


/* =========================================================
   INVITATION
   ========================================================= */
.invite {
  position: relative;
  z-index: 10;
  padding: 0;
  /* Sections inside size themselves explicitly (100svh each), so
     .invite doesn't need to declare a height — it just stretches to
     fit its child sections vertically. */
  /* Transparent — the actual visual is the .bg-stack sitting underneath
     at z 5 (anchored to the phone viewport so it never scrolls). */
  background: transparent;
  opacity: 0;
  /* Snaps to visible the moment the user taps the wax — the cover's
     cream backdrop also disappears instantly, so the invitation page
     reads as instantly there while the flap/body animations play on
     top of it. */
  transition: opacity 0s linear 0s;
}
.invite.is-visible {
  opacity: 1;
}

/* topbar */
.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  background: linear-gradient(180deg, rgba(255, 246, 238, 0.92) 0%, rgba(255, 246, 238, 0.6) 80%, transparent 100%);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.topbar-monogram {
  font-family: var(--serif);
  font-style: italic;
  color: var(--deep-rose);
  font-size: 18px;
  letter-spacing: 0.04em;
}
.topbar-monogram em {
  font-family: var(--script);
  font-style: normal;
  margin: 0 2px;
  color: var(--coral);
}
.music-toggle {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--deep-rose);
  background: linear-gradient(135deg, #ffffff 0%, #fff5ec 100%);
  border: 1px solid rgba(176, 18, 75, 0.15);
  box-shadow:
    0 6px 12px -6px rgba(160, 30, 60, 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
}
.music-toggle svg { width: 18px; height: 18px; }
.music-toggle[aria-pressed="true"] {
  color: #fff;
  background: linear-gradient(135deg, var(--magenta), var(--coral));
}
.music-toggle[aria-pressed="true"]::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1px solid rgba(230, 39, 107, 0.4);
  animation: ringPulse 1.6s ease-out infinite;
  pointer-events: none;
}
@keyframes ringPulse {
  0% { transform: scale(0.9); opacity: 1; }
  100% { transform: scale(1.6); opacity: 0; }
}

/* HERO */
.hero {
  position: relative;
  margin: 0 16px 36px;
  border-radius: 28px;
  overflow: hidden;
  background: var(--ivory);
  box-shadow:
    0 30px 60px -30px rgba(160, 30, 60, 0.45),
    0 1px 0 rgba(255, 255, 255, 0.9) inset;
  isolation: isolate;
}
.hero-photo {
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
}
.hero-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 25%;
  transform: scale(1.04);
  transition: transform 0.9s ease;
}
.hero:hover .hero-photo img { transform: scale(1.08); }
.hero-veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(255, 246, 238, 0) 35%, rgba(255, 246, 238, 0.55) 75%, var(--ivory) 100%),
    radial-gradient(80% 60% at 50% 0%, rgba(230, 39, 107, 0.25), transparent 70%);
}
.hero-content {
  position: relative;
  margin-top: -120px;
  padding: 0 24px 28px;
  text-align: center;
  z-index: 2;
}
.hero-kicker {
  text-transform: uppercase;
  letter-spacing: 0.36em;
  font-size: 10px;
  margin: 0 0 8px;
  color: var(--deep-rose);
  font-weight: 600;
}
.hero-names {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 500;
  margin: 0;
  font-size: 40px;
  line-height: 1.05;
  color: var(--deep-rose);
  letter-spacing: 0.01em;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.hero-names .hero-amp {
  display: inline-flex;
  width: 60px;
  height: 18px;
  color: var(--coral);
}
.hero-names .hero-amp svg { width: 100%; height: 100%; }
.hero-date {
  font-family: var(--sans);
  margin: 12px 0 14px;
  letter-spacing: 0.4em;
  font-size: 11px;
  color: var(--ink-soft);
  text-transform: uppercase;
}
.hero-personal {
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  color: var(--ink);
  margin: 0;
  line-height: 1.5;
  max-width: 280px;
  margin-inline: auto;
}

.hero-corner {
  position: absolute;
  width: 130px;
  height: 130px;
  pointer-events: none;
  opacity: 0.85;
  z-index: 3;
  filter: drop-shadow(0 6px 12px rgba(160, 30, 60, 0.18));
}
.hero-corner-tl {
  top: -8px;
  left: -16px;
  transform: rotate(-10deg);
}
.hero-corner-br {
  bottom: -16px;
  right: -16px;
  transform: rotate(170deg);
}

/* generic block */
.block {
  position: relative;
  margin: 0 22px 44px;
  text-align: center;
}
.block-script {
  font-family: var(--script);
  font-size: 32px;
  color: var(--magenta);
  margin: 0;
  line-height: 1;
}
.block-title {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 500;
  font-size: 26px;
  margin: 6px 0 12px;
  color: var(--deep-rose);
  line-height: 1.15;
}
.block-lede {
  font-family: var(--serif);
  font-size: 15px;
  color: var(--ink-soft);
  line-height: 1.6;
  margin: 0 0 20px;
}
.block-lede strong { color: var(--deep-rose); font-weight: 600; }

/* ornament */
.ornament {
  display: grid;
  place-items: center;
  margin: 6px 0 28px;
  color: var(--coral);
}
.ornament svg { width: 200px; height: auto; }

/* SAVE THE DATE */
.date-card {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  gap: 16px;
  text-align: left;
  padding: 22px;
  border-radius: 24px;
  background:
    linear-gradient(180deg, #ffffff 0%, #fff7ee 100%);
  border: 1px solid rgba(176, 18, 75, 0.12);
  box-shadow: 0 18px 40px -20px rgba(160, 30, 60, 0.35);
  margin: 0 0 18px;
}
.date-day {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.dd-num {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 600;
  font-size: 64px;
  line-height: 0.95;
  background: linear-gradient(180deg, var(--magenta), var(--coral));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.dd-label {
  font-family: var(--serif);
  font-style: italic;
  font-size: 16px;
  color: var(--deep-rose);
  margin-top: 2px;
}
.dd-year {
  font-family: var(--sans);
  letter-spacing: 0.32em;
  font-size: 11px;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-top: 4px;
}
.date-divider {
  width: 1px;
  height: 80px;
  background: linear-gradient(180deg, transparent 0%, rgba(176, 18, 75, 0.35) 50%, transparent 100%);
}
.date-meta {
  font-family: var(--serif);
  color: var(--ink);
  font-size: 16px;
  line-height: 1.55;
}
.date-meta p { margin: 0; }
.date-meta p + p { color: var(--ink-soft); font-style: italic; }

.countdown {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  list-style: none;
  padding: 0;
  margin: 0;
}
.countdown li {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 247, 238, 0.9) 100%);
  border: 1px solid rgba(176, 18, 75, 0.12);
  border-radius: 14px;
  padding: 12px 4px;
  display: grid;
  gap: 2px;
  box-shadow: 0 8px 16px -10px rgba(160, 30, 60, 0.3);
}
.countdown strong {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 600;
  font-size: 26px;
  color: var(--deep-rose);
  display: block;
  line-height: 1;
}
.countdown span {
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 9px;
  color: var(--ink-soft);
}

/* OUR STORY */
.story-photo {
  margin-top: 6px;
  border-radius: 22px;
  overflow: hidden;
  box-shadow: 0 24px 40px -20px rgba(160, 30, 60, 0.4);
  aspect-ratio: 4 / 5;
}
.story-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
}

/* DETAILS */
.event-card {
  text-align: center;
  background:
    linear-gradient(180deg, #ffffff 0%, #fff7ee 100%);
  border: 1px solid rgba(176, 18, 75, 0.12);
  border-radius: 22px;
  padding: 22px 18px;
  margin-bottom: 16px;
  box-shadow: 0 18px 36px -20px rgba(160, 30, 60, 0.35);
  position: relative;
  overflow: hidden;
}
.event-card::before {
  content: "";
  position: absolute;
  inset: -1px -1px auto -1px;
  height: 60%;
  background: radial-gradient(60% 80% at 50% 0%, rgba(255, 200, 168, 0.55), transparent 70%);
  pointer-events: none;
}
.event-card-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--coral);
  margin-bottom: 8px;
}
.event-card-head svg { width: 22px; height: 22px; }
.event-card-head h4 {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 500;
  font-size: 22px;
  margin: 0;
  color: var(--deep-rose);
}
.event-time {
  font-family: var(--serif);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.06em;
  margin: 4px 0 6px;
  color: var(--ink);
}
.event-venue {
  font-family: var(--serif);
  font-style: italic;
  font-size: 16px;
  margin: 0;
  color: var(--ink);
}
.event-addr {
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 4px 0 14px;
}
.ghost-btn {
  display: inline-block;
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--deep-rose);
  text-decoration: none;
  border: 1px solid rgba(176, 18, 75, 0.3);
  background: rgba(255, 255, 255, 0.6);
  transition: background 0.2s ease, color 0.2s ease;
}
.ghost-btn:hover {
  background: var(--deep-rose);
  color: #fff;
}

/* DRESS / SWATCHES */
.swatches {
  list-style: none;
  padding: 0;
  margin: 4px 0 0;
  display: flex;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
}
.swatches li {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--c, #ccc);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.6) inset,
    0 0 0 2px rgba(176, 18, 75, 0.08),
    0 6px 12px -6px rgba(160, 30, 60, 0.3);
}

/* GALLERY */
.gal-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: 110px;
  gap: 8px;
}
.gal-grid figure {
  margin: 0;
  border-radius: 18px;
  overflow: hidden;
  background: var(--blush);
  box-shadow: 0 14px 28px -16px rgba(160, 30, 60, 0.35);
}
.gal-grid figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.gal-1 { grid-row: span 2; }
.gal-3 { grid-row: span 2; }
.gal-6 { grid-row: span 2; }
.gal-8 { grid-row: span 2; }

/* RSVP */
.rsvp-form {
  display: grid;
  gap: 14px;
  text-align: left;
  background: linear-gradient(180deg, #ffffff 0%, #fff7ee 100%);
  padding: 22px;
  border-radius: 22px;
  border: 1px solid rgba(176, 18, 75, 0.12);
  box-shadow: 0 18px 40px -20px rgba(160, 30, 60, 0.35);
}
.field {
  display: grid;
  gap: 6px;
}
.field > span {
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--deep-rose);
  font-weight: 600;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.field-hint {
  font-style: italic;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
  font-weight: 500;
  font-family: var(--serif);
  font-size: 13px;
}
.field input,
.field textarea {
  font-family: var(--sans);
  font-size: 15px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid rgba(176, 18, 75, 0.18);
  background: #fffaf3;
  color: var(--ink);
  outline: none;
  transition: border-color 0.2s, box-shadow 0.2s;
  width: 100%;
}
.field input:focus,
.field textarea:focus {
  border-color: var(--magenta);
  box-shadow: 0 0 0 3px rgba(230, 39, 107, 0.15);
}
.field-group {
  border: 0;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 8px;
}
.field-group legend {
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--deep-rose);
  font-weight: 600;
  margin-bottom: 4px;
}
.radio-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.pill-radio {
  position: relative;
  display: block;
  text-align: center;
  cursor: pointer;
}
.pill-radio input {
  position: absolute;
  opacity: 0;
  inset: 0;
}
.pill-radio span {
  display: block;
  padding: 12px 8px;
  border-radius: 12px;
  font-size: 13px;
  font-family: var(--serif);
  font-style: italic;
  background: #fffaf3;
  border: 1px solid rgba(176, 18, 75, 0.18);
  color: var(--ink);
  transition: all 0.2s ease;
}
.pill-radio input:checked + span {
  color: #fff;
  background: linear-gradient(135deg, var(--magenta), var(--coral));
  border-color: transparent;
  box-shadow: 0 8px 18px -8px rgba(230, 39, 107, 0.6);
}
.stepper {
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  background: #fffaf3;
  border: 1px solid rgba(176, 18, 75, 0.18);
  border-radius: 12px;
  overflow: hidden;
}
.stepper input {
  border: 0;
  background: transparent;
  text-align: center;
  font-size: 18px;
  font-family: var(--serif);
  color: var(--ink);
  font-weight: 600;
  -moz-appearance: textfield;
}
.stepper input::-webkit-outer-spin-button,
.stepper input::-webkit-inner-spin-button {
  -webkit-appearance: none;
}
.step-btn {
  font-size: 22px;
  color: var(--deep-rose);
  display: grid;
  place-items: center;
  background: transparent;
  border-right: 1px solid rgba(176, 18, 75, 0.12);
}
.step-btn:last-child {
  border-right: 0;
  border-left: 1px solid rgba(176, 18, 75, 0.12);
}
.step-btn:hover {
  background: rgba(230, 39, 107, 0.08);
}

.primary-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  font-family: var(--sans);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, var(--magenta) 0%, var(--coral) 100%);
  border: 0;
  box-shadow:
    0 14px 28px -10px rgba(230, 39, 107, 0.55),
    inset 0 1px 0 rgba(255, 255, 255, 0.3);
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  text-decoration: none;
}
.primary-btn:hover {
  transform: translateY(-1px);
  box-shadow:
    0 18px 32px -10px rgba(230, 39, 107, 0.7),
    inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.primary-btn svg { width: 16px; height: 16px; }

/* GIFT */
.gift {
  text-align: center;
  display: grid;
  justify-items: center;
  gap: 0;
}

/* CLOSING */
.closing {
  text-align: center;
  margin: 16px 22px 0;
  padding: 32px 18px;
  border-radius: 24px;
  background:
    radial-gradient(80% 70% at 50% 0%, rgba(255, 200, 168, 0.5), transparent 70%),
    linear-gradient(180deg, #ffffff 0%, #fff7ee 100%);
  border: 1px solid rgba(176, 18, 75, 0.1);
  box-shadow: 0 18px 36px -20px rgba(160, 30, 60, 0.3);
}
.closing-script {
  font-family: var(--script);
  color: var(--magenta);
  font-size: 30px;
  margin: 0;
  line-height: 1;
}
.closing-line {
  font-family: var(--serif);
  font-style: italic;
  font-size: 22px;
  color: var(--deep-rose);
  margin: 8px 0 14px;
  font-weight: 500;
}
.closing-sign {
  font-family: var(--serif);
  font-style: italic;
  font-size: 18px;
  color: var(--ink);
  margin: 0;
}
.closing-sign .sig-amp {
  font-family: var(--script);
  font-style: normal;
  color: var(--coral);
  margin: 0 6px;
  font-size: 1.1em;
}

/* reveal animation */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.reveal.in-view {
  opacity: 1;
  transform: translateY(0);
}

/* small-screen polish */
@media (max-width: 380px) {
  .hero-names { font-size: 36px; }
  .block-title { font-size: 22px; }
  .dd-num { font-size: 56px; }
}

/* =========================================================
   SECTIONS · The invitation interior.

   A vertical stack of full-viewport sections that snap one at
   a time as the guest swipes. Each section, the phone frame,
   and html/body are ALL locked to a constant `100svh`, so iOS
   Safari's URL-bar dynamics can't drift the snap targets — a
   flick lands on the next section instantly, no settle.

   Each section contains ONLY scrollable content:
     <.sec-content> — text & controls

   The photo + its dark gradient veil live together inside each
   <.bg-slide> in the fixed <.bg-stack>, so they crossfade as one
   unit between sections without sliding behind the text.

   The IntersectionObserver in script.js sets `.in-view` on each
   section and `.is-active` on its matching .bg-slide.
   ========================================================= */
.snap-section {
  position: relative;
  width: 100%;
  /* CONSTANT 100svh — same value as `.phone` above — so each
     section's snap target is at exactly i × 100svh. iOS can't
     move it. Each guest swipe → instant snap, no settle. */
  height: 100svh;
  min-height: 100svh;
  /* Become a snap target — the page locks onto the top of the
     next section as soon as the guest's flick crosses it. */
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  isolation: isolate;
}

/* ---------- background stage ----------
   The .bg-stack lives OUTSIDE the scroll container so it stays anchored
   to the phone viewport. Each .bg-slide is a stacked layer holding one
   section's photo; only the matching section's slide is set .is-active
   (driven by IntersectionObserver in script.js), which crossfades it in
   while the others fade out. Result: the photos never scroll — they
   change between sections with a soft fade. */
.bg-stack {
  position: absolute;
  inset: 0;
  z-index: 5;            /* above .phone bg, below .invite content (z 10) */
  overflow: hidden;
  pointer-events: none;
  background: #0d0608;   /* fallback before any slide loads */
}
.bg-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  /* Quick, decisive crossfade between section photos as the guest
     scrolls past the IntersectionObserver threshold. */
  transition: opacity 0.45s ease;
  will-change: opacity;
}
.bg-slide.is-active {
  opacity: 1;
}
.bg-slide img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: 50% 35%;
  user-select: none;
  -webkit-user-drag: none;
}

/* Per-section background-position tuning (where the faces sit). */
.bg-slide[data-sec="hero"]        img { object-position: 50% 50%; }
.bg-slide[data-sec="save"]        img { object-position: 45% 38%; }
.bg-slide[data-sec="story"]       img { object-position: 50% 30%; }
.bg-slide[data-sec="celebration"] img { object-position: 60% 28%; }
.bg-slide[data-sec="dress"]       img { object-position: 45% 28%; }
.bg-slide[data-sec="rsvp"]        img { object-position: 50% 55%; }
.bg-slide[data-sec="closing"]     img { object-position: 55% 38%; }

/* ---------- overlay veils ----------
   Every section has a strong dark veil + an extra darkening band
   under the text so the white editorial type ALWAYS reads, regardless
   of what's behind it (light dresses, white shirts, sunlight, etc.). */
.sec-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* hero / bottom-aligned text: heavy bottom darkening + uniform veil */
  background:
    linear-gradient(
      180deg,
      rgba(20, 5, 15, 0.30) 0%,
      rgba(20, 5, 15, 0.20) 30%,
      rgba(20, 5, 15, 0.65) 65%,
      rgba(0, 0, 0, 0.92) 100%
    );
}
.sec-overlay--center {
  /* center-aligned text — uniform 55% veil + radial darkening behind text */
  background:
    radial-gradient(ellipse 80% 60% at 50% 50%,
      rgba(0, 0, 0, 0.45) 0%,
      rgba(0, 0, 0, 0.05) 75%),
    linear-gradient(180deg,
      rgba(20, 5, 15, 0.55) 0%,
      rgba(20, 5, 15, 0.55) 50%,
      rgba(20, 5, 15, 0.65) 100%);
}
.sec-overlay--strong {
  /* form sections — strongest veil for input legibility */
  background:
    radial-gradient(ellipse 80% 65% at 50% 50%,
      rgba(0, 0, 0, 0.35) 0%,
      rgba(0, 0, 0, 0.05) 80%),
    linear-gradient(180deg,
      rgba(20, 5, 15, 0.72) 0%,
      rgba(20, 5, 15, 0.66) 50%,
      rgba(20, 5, 15, 0.88) 100%);
}
.sec-overlay--hero {
  /* hero — text sits ABOVE their heads in the leafy upper portion.
     Top is heavily darkened so white type pops on the bokeh; the
     middle/lower band is left clear so the couple's faces glow. */
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0.82) 0%,
    rgba(0, 0, 0, 0.62) 18%,
    rgba(20, 5, 15, 0.32) 38%,
    rgba(20, 5, 15, 0.06) 60%,
    rgba(20, 5, 15, 0.06) 80%,
    rgba(20, 5, 15, 0.42) 100%
  );
}

/* ---------- content frame ---------- */
.sec-content {
  position: relative;
  z-index: 2;
  width: 100%;
  padding:
    calc(28px + env(safe-area-inset-top))
    28px
    calc(34px + env(safe-area-inset-bottom));
  color: #fff8ef;
  text-align: center;
  font-family: var(--serif);
  /* Heavy multi-layer text shadow so any text stays readable on
     ANY photo behind it — including light dresses or white shirts. */
  text-shadow:
    0 2px 16px rgba(0, 0, 0, 0.7),
    0 0 6px  rgba(0, 0, 0, 0.55),
    0 1px 2px rgba(0, 0, 0, 0.6);
  /* No entrance animation — the text is fully solid the instant the
     section is visible, so a snap feels INSTANT, with no fade-in
     adding visible "settle" time after every flick. */
}
.sec-content--bottom { margin-top: auto; }
.sec-content--center { margin: auto 0; }
.sec-content--top    { margin-bottom: auto; }

/* Hero text sits in the leafy upper portion above their heads — pushed
   down from the very top of the screen so it floats a little lower over
   the bokeh band rather than hugging the notch. */
.sec-hero .sec-content--top {
  padding-top: calc(110px + env(safe-area-inset-top));
}

/* (`.in-view` no longer drives content opacity — text is always solid.
   The only thing the class still controls is the scroll-hint fade and
   the staggered palette-swatch entrance.) */

/* ---------- typography primitives ---------- */
.sec-kicker {
  font-family: var(--sans);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.85);
  margin: 0 0 16px;
  line-height: 1;
}

.sec-script {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(28px, 7.4vw, 38px);
  line-height: 1.18;
  color: #fff8ef;
  margin: 0 0 18px;
  letter-spacing: 0.005em;
}

.sec-lede {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(15px, 4.2vw, 17.5px);
  line-height: 1.55;
  margin: 0 auto 18px;
  max-width: 32ch;
  color: rgba(255, 244, 232, 0.94);
}
.sec-lede--small { font-size: 13.5px; line-height: 1.5; }
.sec-lede strong {
  color: #ffd0a0;
  font-weight: 500;
  font-style: normal;
  font-family: var(--sans);
  letter-spacing: 0.04em;
}

/* Personal salutation that lives between the kicker and the .sec-script
   line in the RSVP section. Filled in by script.js from the Sheet
   (e.g. "Dear Roy & Andrea,"). The element starts hidden and is only
   shown once a guest match is found, so the empty state never paints.
   Styled as a soft, warm letter-opener — italic serif, a hair smaller
   than the .sec-script line that follows it. */
.sec-greeting {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(17px, 4.8vw, 20px);
  line-height: 1.3;
  letter-spacing: 0.01em;
  /* Logo gold — matches the cover-names line and the metallic accents
     on the wedding logo, so the personal greeting feels tied to the
     brand colour palette rather than the generic cream-on-photo type. */
  color: var(--gold);
  /* Subtle warm glow keeps the gold legible on the dark RSVP photo. */
  text-shadow:
    0 1px 0 rgba(0, 0, 0, 0.18),
    0 2px 14px rgba(176, 137, 64, 0.28);
  margin: 0 0 10px;
}
.sec-greeting[hidden] { display: none; }

.sec-quote {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(15px, 4vw, 17px);
  line-height: 1.55;
  color: rgba(255, 244, 232, 0.92);
  margin: 14px auto 4px;
  max-width: 32ch;
  position: relative;
}
.sec-quote cite {
  display: block;
  margin-top: 10px;
  font-style: normal;
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.65);
}
.sec-quote--small { font-size: 14px; }

/* ---------- §1 hero ---------- */
.sec-display-date {
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: 0.45em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.88);
  margin: 14px 0 22px;
}
.sec-display-date--quiet {
  color: rgba(255, 244, 232, 0.6);
  font-size: 10px;
  letter-spacing: 0.4em;
  margin: 22px 0 0;
}

/* Sits at the very bottom of the hero (outside .sec-content so it stays
   anchored to the section even when the text is at the top). */
.scroll-hint {
  position: absolute;
  left: 50%;
  bottom: calc(22px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  opacity: 0;
  transition: opacity 0.8s ease 0.6s;
}
.snap-section.in-view .scroll-hint {
  opacity: 1;
}
.scroll-hint .sh-line {
  width: 1px;
  height: 28px;
  background: rgba(255, 244, 232, 0.85);
  transform-origin: top;
  animation: shPulse 1.8s ease-in-out infinite;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.5);
}
.scroll-hint .sh-text {
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.38em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.85);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
}
@keyframes shPulse {
  0%, 100% { transform: scaleY(0.3); opacity: 0.4; }
  50%      { transform: scaleY(1);   opacity: 1; }
}

/* ---------- §2 save the date ---------- */
.sec-bigdate {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 6px 0 4px;
  font-family: var(--serif);
  color: #fff8ef;
}
.sec-bigdate .bd-day {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: 0.45em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.7);
  margin-bottom: 6px;
}
.sec-bigdate .bd-num {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(72px, 22vw, 108px);
  line-height: 0.86;
  color: #fff8ef;
  text-shadow:
    0 4px 28px rgba(0, 0, 0, 0.75),
    0 0 12px rgba(0, 0, 0, 0.55),
    0 2px 4px rgba(0, 0, 0, 0.7);
}
.sec-bigdate .bd-mo {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(20px, 5.4vw, 26px);
  margin-top: 4px;
  color: rgba(255, 244, 232, 0.95);
}
.sec-bigdate .bd-year {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: 0.5em;
  text-transform: uppercase;
  margin-top: 6px;
  color: rgba(255, 244, 232, 0.7);
}

.sec-sub {
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: 0.36em;
  text-transform: uppercase;
  margin: 16px 0 22px;
  color: rgba(255, 244, 232, 0.78);
}

/* Countdown — frosted-glass tiles. */
.snap-section .countdown {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin: 4px auto 0;
  padding: 0;
  list-style: none;
  max-width: 360px;
}
.snap-section .countdown li {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: rgba(255, 244, 232, 0.08);
  border: 1px solid rgba(255, 244, 232, 0.18);
  border-radius: 12px;
  padding: 11px 4px 9px;
}
.snap-section .countdown li strong {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 500;
  font-size: 26px;
  line-height: 1;
  color: #fff8ef;
  letter-spacing: 0.005em;
  margin-bottom: 4px;
  font-variant-numeric: tabular-nums;
}
.snap-section .countdown li span {
  font-family: var(--sans);
  font-size: 9.5px;
  letter-spacing: 0.36em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.7);
}

/* ---------- §4 celebration ---------- */
.event-grid {
  display: grid;
  gap: 14px;
  margin: 10px auto 0;
  max-width: 360px;
}
/* Three-stop timeline (bride's home → church → reception) — slightly
   tighter rhythm than the two-tile layout so all three frosted cards
   fit comfortably on a phone viewport without overflowing. */
.event-grid--three {
  gap: 9px;
  margin-top: 6px;
}
.event-tile {
  display: block;
  /* Solid-ish cream card with a touch of warmth — strong enough to
     give the bordeaux text the contrast of a printed invitation,
     so the bordeaux + gold typography sits cleanly on top of the
     photo without any blur on the layer behind. */
  background: rgba(255, 250, 240, 0.88);
  border: 1px solid rgba(167, 138, 77, 0.4);
  border-radius: 14px;
  padding: 16px 18px 14px;
  text-align: center;
  text-decoration: none;
  color: var(--bordeaux);
  box-shadow:
    0 8px 22px rgba(122, 22, 38, 0.10),
    0 2px 6px rgba(122, 22, 38, 0.06),
    inset 0 1px 0 rgba(255, 255, 255, 0.6);
  -webkit-tap-highlight-color: transparent;
  transition:
    transform 0.35s cubic-bezier(0.2, 0.8, 0.2, 1),
    box-shadow 0.35s ease,
    border-color 0.35s ease,
    background 0.35s ease;
}
/* Three-tile variant: a hair tighter so each card still feels
   generous but three of them stack cleanly inside one section. */
.event-grid--three .event-tile {
  padding: 12px 16px 11px;
}
.event-tile:hover,
.event-tile:focus-visible {
  transform: translateY(-1px);
  outline: none;
}
.event-tile:active {
  transform: translateY(0);
}
.event-tile .et-label {
  font-family: var(--sans);
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--bordeaux);
  text-shadow: none;
  margin: 0 0 6px;
}
.event-grid--three .et-label {
  font-size: 9.5px;
  letter-spacing: 0.4em;
  margin: 0 0 4px;
}
.event-tile .et-time {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 500;
  font-size: 26px;
  line-height: 1;
  color: #a78a4d;
  margin: 0 0 8px;
  text-shadow: none;
}
.event-grid--three .et-time {
  font-size: 23px;
  margin: 0 0 5px;
}
.event-tile .et-venue {
  font-family: var(--serif);
  font-size: 16px;
  line-height: 1.25;
  color: var(--bordeaux-deep);
  text-shadow: none;
  margin: 0 0 4px;
}
.event-grid--three .et-venue {
  font-size: 15px;
  margin: 0 0 2px;
}
.event-tile .et-addr {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  color: rgba(122, 22, 38, 0.78);
  text-shadow: none;
  margin: 0;
}
.event-grid--three .et-addr {
  font-size: 10px;
  letter-spacing: 0.22em;
  margin: 0 0 8px;
}
/* "View on map" caption — sits inside each tile, separated from the
   address by a thin bordeaux hairline. Gold to echo the logo + the
   hero/closing date, so it reads as an interactive accent rather
   than another body line. */
.event-tile .et-map {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 6px;
  padding-top: 7px;
  font-family: var(--sans);
  font-weight: 500;
  font-size: 9px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: #a78a4d;
  text-shadow: none;
  border-top: 1px solid rgba(122, 22, 38, 0.18);
  min-width: 60%;
  transition: color 0.3s ease, letter-spacing 0.3s ease;
}
.event-tile .et-map-icon {
  width: 11px;
  height: 11px;
  flex: 0 0 auto;
  color: #a78a4d;
  filter: drop-shadow(0 1px 2px rgba(167, 138, 77, 0.25));
}
.event-tile:hover,
.event-tile:focus-visible {
  background: rgba(255, 252, 245, 0.96);
  border-color: rgba(167, 138, 77, 0.7);
  box-shadow:
    0 12px 28px rgba(122, 22, 38, 0.16),
    0 3px 8px rgba(122, 22, 38, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 0.7);
}
.event-tile:hover .et-map,
.event-tile:focus-visible .et-map {
  color: var(--bordeaux-deep);
  letter-spacing: 0.36em;
}
.event-tile:hover .et-map-icon,
.event-tile:focus-visible .et-map-icon {
  color: var(--bordeaux-deep);
}
.event-divider {
  height: 1px;
  background: linear-gradient(90deg,
    transparent,
    rgba(255, 244, 232, 0.4),
    transparent);
}
.event-grid--three .event-divider {
  width: 36%;
  margin: 0 auto;
}

/* ---------- §5 dress code ---------- */
.palette {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
}
.palette li {
  width: 22px;
  height: 38px;
  border-radius: 99px;
  background: var(--c, #fff);
  box-shadow:
    0 6px 14px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.3);
  transform: translateY(0);
  transition: transform 0.4s ease;
}
.snap-section.in-view .palette li {
  animation: paletteRise 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
}
.palette li:nth-child(1) { animation-delay: 0.10s; }
.palette li:nth-child(2) { animation-delay: 0.18s; }
.palette li:nth-child(3) { animation-delay: 0.26s; }
.palette li:nth-child(4) { animation-delay: 0.34s; }
.palette li:nth-child(5) { animation-delay: 0.42s; }
.palette li:nth-child(6) { animation-delay: 0.50s; }
.palette li:nth-child(7) { animation-delay: 0.58s; }
@keyframes paletteRise {
  0%   { opacity: 0; transform: translateY(14px) scale(0.85); }
  100% { opacity: 1; transform: translateY(0)    scale(1); }
}

/* ---------- §6 RSVP form ---------- */
.sec-form {
  margin: 18px auto 0;
  max-width: 360px;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.sec-form .field {
  display: flex;
  flex-direction: column;
  gap: 7px;
  font-family: var(--sans);
  color: rgba(255, 244, 232, 0.92);
}
.sec-form .field > span {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 10.5px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.78);
}
.sec-form .field > span em {
  font-style: normal;
  font-size: 9.5px;
  letter-spacing: 0.18em;
  color: rgba(255, 244, 232, 0.5);
}
.sec-form input[type="text"],
.sec-form input[type="number"],
.sec-form textarea {
  background: rgba(255, 244, 232, 0.10);
  border: 1px solid rgba(255, 244, 232, 0.22);
  color: #fff8ef;
  padding: 11px 13px;
  border-radius: 10px;
  font-family: var(--sans);
  font-size: 14px;
  outline: none;
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.sec-form input::placeholder,
.sec-form textarea::placeholder {
  color: rgba(255, 244, 232, 0.4);
}
.sec-form input:focus,
.sec-form textarea:focus {
  background: rgba(255, 244, 232, 0.16);
  border-color: rgba(255, 208, 160, 0.8);
  box-shadow: 0 0 0 3px rgba(255, 208, 160, 0.18);
}

.sec-form .field-radios {
  display: flex;
  gap: 8px;
  border: 0;
  padding: 0;
  margin: 0;
}
.sec-form .pill {
  flex: 1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 11px 14px;
  background: rgba(255, 244, 232, 0.08);
  border: 1px solid rgba(255, 244, 232, 0.22);
  border-radius: 99px;
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  color: rgba(255, 244, 232, 0.85);
  transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
.sec-form .pill input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.sec-form .pill:has(input:checked) {
  background: rgba(255, 208, 160, 0.22);
  border-color: rgba(255, 208, 160, 0.7);
  color: #ffe6c8;
}

/* Centre the whole "Number attending" field (heading + stepper).
   The wrapper used to be a <label>, which made tapping anywhere
   inside it focus the count input — visually that gave the whole
   container a "clickable" feel even though the input is read-only.
   We now use a <div> + <p>, and kill the iOS tap-highlight on the
   container so only the explicit − / + buttons feel interactive. */
.sec-form .field--center {
  align-items: center;
  text-align: center;
  cursor: default;
  -webkit-tap-highlight-color: transparent;
}
.sec-form .field--center > span,
.sec-form .field--center > .field-heading {
  justify-content: center;
}
/* The "Number attending  max 2" heading — purely informational. We
   strip user-select / pointer-events so a stray tap on the text or
   the empty whitespace inside the centred container doesn't read as
   interactive. The − / + buttons re-enable pointer-events on
   themselves. Visual styling mirrors `.sec-form .field > span` so the
   heading reads as the field's caption (it used to BE that span). */
.sec-form .field-heading {
  margin: 0 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.78);
  user-select: none;
  pointer-events: none;
}
.sec-form .field-heading em {
  font-style: normal;
  font-size: 9.5px;
  letter-spacing: 0.18em;
  color: rgba(255, 244, 232, 0.5);
}
/* When "Sadly, can't" is picked, script.js sets [hidden] on the field. */
.sec-form .field[hidden] { display: none; }

/* Stepper container — adopts the same chrome as the Note textarea
   (same fill, border, radius) so the form reads as one consistent
   set of inputs. The − and + are framed buttons that sit just inside
   the same outer ring; the centre cell shows the count. */
.sec-form .stepper {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  background: rgba(255, 244, 232, 0.10);
  border: 1px solid rgba(255, 244, 232, 0.22);
  border-radius: 10px;
  padding: 5px;
  width: max-content;
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.sec-form .stepper:focus-within {
  background: rgba(255, 244, 232, 0.16);
  border-color: rgba(255, 208, 160, 0.8);
  box-shadow: 0 0 0 3px rgba(255, 208, 160, 0.18);
}

/* The count cell — purely a display, no interaction.
   `pointer-events: none` plus `readonly` + `tabindex="-1"` on the
   element itself means the user can't click into it, type in it,
   or tab to it. The number only changes via the − / + buttons. */
.sec-form .stepper input {
  width: 56px;
  background: transparent;
  border: none;
  text-align: center;
  font-size: 18px;
  font-family: var(--serif);
  font-style: italic;
  color: #fff8ef;
  -moz-appearance: textfield;
  pointer-events: none;
  user-select: none;
  caret-color: transparent;
  cursor: default;
  outline: none;
}
.sec-form .stepper input::-webkit-outer-spin-button,
.sec-form .stepper input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* − / + buttons — bordered to match the Note input's chrome, sized
   square so they read as a true pair of buttons rather than icons. */
.sec-form .step-btn {
  width: 38px;
  height: 38px;
  border-radius: 8px;
  border: 1px solid rgba(255, 244, 232, 0.22);
  background: rgba(255, 244, 232, 0.10);
  color: #fff8ef;
  font-size: 20px;
  font-weight: 500;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.12s ease;
}
.sec-form .step-btn:hover {
  background: rgba(255, 208, 160, 0.22);
  border-color: rgba(255, 208, 160, 0.55);
}
.sec-form .step-btn:active {
  transform: scale(0.95);
}
.sec-form .step-btn:focus-visible {
  outline: none;
  border-color: rgba(255, 208, 160, 0.85);
  box-shadow: 0 0 0 3px rgba(255, 208, 160, 0.22);
}

.sec-form .primary-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(180deg, #d83a73 0%, #9a0e3f 100%);
  color: #fff8ef;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 12.5px;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  padding: 14px 22px;
  border: 0;
  border-radius: 99px;
  cursor: pointer;
  margin-top: 6px;
  box-shadow:
    0 14px 30px -10px rgba(180, 18, 75, 0.65),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.sec-form .primary-btn:hover {
  transform: translateY(-1px);
  box-shadow:
    0 18px 36px -10px rgba(180, 18, 75, 0.75),
    inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
.sec-form .primary-btn:active { transform: translateY(0); }

/* ---------- THANK-YOU PANEL ----------
   Replaces the form (#rsvpFormState) when the guest has already
   replied. Lives inside the same .sec-rsvp section so the kicker and
   "Dear ___," greeting above stay put — the panel just swaps in
   below them. */
.rsvp-thanks {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  margin-top: 8px;
  animation: rsvpThanksIn 0.5s ease both;
}
@keyframes rsvpThanksIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Soft gold check-mark medallion. The ring + stroke pull from the
   same gold + cream palette as the sec-greeting line above so the
   panel feels like an extension of the personalisation, not a new
   surface. */
.rsvp-thanks-mark {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 208, 160, 0.14);
  border: 1px solid rgba(255, 208, 160, 0.55);
  color: var(--gold);
  box-shadow: 0 0 0 4px rgba(255, 208, 160, 0.06),
              0 6px 22px rgba(176, 137, 64, 0.18);
}
.rsvp-thanks-mark svg {
  width: 28px;
  height: 28px;
}

/* Override the section-wide .sec-script margins inside the thank-you
   panel — we want a tighter stack of (mark, title, body, meta) without
   the breathing space the form-state heading needs.

   Both the title and the body use the brand bordo (--wax) — same
   wine-red as the wax seal — so the confirmation feels like an
   official "yes" stamped onto the card, not a chat-bubble. A soft
   cream halo + faint warm glow keeps it legible on the dark RSVP
   photo behind the panel. */
.rsvp-thanks .rsvp-thanks-title.sec-script {
  margin: 0;
  font-size: clamp(22px, 6vw, 28px);
  line-height: 1.18;
  color: var(--wax);
  text-shadow:
    0 1px 0 rgba(255, 246, 238, 0.55),
    0 2px 14px rgba(126, 19, 32, 0.30);
}

.rsvp-thanks-body {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(15px, 4vw, 17px);
  line-height: 1.45;
  color: var(--wax);
  text-shadow:
    0 1px 0 rgba(255, 246, 238, 0.45),
    0 2px 12px rgba(126, 19, 32, 0.25);
  max-width: 28ch;
}

.rsvp-thanks-meta {
  margin: 0;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(255, 244, 232, 0.55);
}
.rsvp-thanks-meta[hidden] { display: none; }

/* When the thank-you panel is showing, the form state should be
   completely out of the layout — [hidden] on the wrapper handles
   that. Belt-and-braces: a CSS rule mirrors it so a missing JS
   toggle still does the right thing. */
.rsvp-state[hidden] { display: none; }

/* ---------- §7 closing ---------- */
.sec-signature {
  margin: 24px 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  font-family: "Allura", var(--script);
  font-size: clamp(36px, 10vw, 50px);
  color: #ffd0a0;
  text-shadow:
    0 0 26px rgba(255, 200, 150, 0.7),
    0 4px 22px rgba(0, 0, 0, 0.8),
    0 1px 3px rgba(0, 0, 0, 0.7);
  line-height: 1;
}
.sec-signature .sig-amp {
  font-size: 1.05em;
  margin: 0 4px;
  opacity: 0.85;
}

/* Hero variant — same elegant script signature, slightly smaller and
   sitting at the very top of the section instead of underneath copy. */
.sec-signature--hero {
  margin: 0 0 6px;
  font-size: clamp(30px, 8.5vw, 42px);
  gap: 14px;
}

/* ---------- safe-area & mobile tweaks ---------- */
@media (max-width: 480px) {
  .sec-content { padding-left: 22px; padding-right: 22px; }
  .sec-bigdate .bd-num { font-size: clamp(80px, 26vw, 110px); }
}

/* =========================================================
   FLOATING MONOGRAM LOGO
   Pinned at the top-center of the phone, above every section.
   Hidden during the welcome cover; fades in once the
   invitation opens.
   ========================================================= */
.site-logo {
  position: absolute;
  top: calc(14px + env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%) translateY(-6px) scale(0.96);
  z-index: 50;
  width: 56px;
  height: auto;
  pointer-events: none;
  user-select: none;
  opacity: 0;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.45));
  transition:
    opacity 0.55s ease,
    transform 0.55s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.site-logo.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0) scale(1);
}

/* =========================================================
   FLOATING MUTE / UNMUTE BUTTON
   Pinned at the bottom-left of the phone, above every section.
   Hidden during the welcome cover; fades in once the
   invitation opens. Styled as a frosted-glass pill that reads
   well over any photo.
   ========================================================= */
.music-fab {
  position: absolute;
  left: 18px;
  bottom: calc(18px + env(safe-area-inset-bottom));
  z-index: 50;
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 244, 232, 0.32);
  background: rgba(20, 5, 15, 0.55);
  -webkit-backdrop-filter: blur(12px) saturate(120%);
          backdrop-filter: blur(12px) saturate(120%);
  color: #fff8ef;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px) scale(0.92);
  transition:
    opacity 0.55s ease,
    transform 0.55s cubic-bezier(0.2, 0.7, 0.2, 1),
    background 0.2s ease,
    border-color 0.2s ease;
  box-shadow:
    0 10px 26px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.music-fab.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0) scale(1);
}
.music-fab:hover {
  background: rgba(20, 5, 15, 0.72);
  border-color: rgba(255, 208, 160, 0.55);
  color: #ffe6c8;
}
.music-fab:active { transform: translateY(0) scale(0.95); }
.music-fab:focus-visible {
  outline: 2px solid rgba(255, 208, 160, 0.7);
  outline-offset: 2px;
}
.music-fab svg {
  width: 22px;
  height: 22px;
  display: block;
}
/* aria-pressed="true"  → music ON  → show speaker-with-waves icon
   aria-pressed="false" → music OFF → show speaker-with-X (muted) */
.music-fab .mf-icon--off { display: none; }
.music-fab[aria-pressed="false"] .mf-icon--on  { display: none; }
.music-fab[aria-pressed="false"] .mf-icon--off { display: block; }
.music-fab[aria-pressed="false"] {
  color: rgba(255, 208, 160, 0.85);
  border-color: rgba(255, 208, 160, 0.45);
}

/* reduced motion */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

/* =========================================================
   LIGHT + BORDEAUX VARIANT  (single override block)
   • Photo veils: white instead of black, so the photos stay
     bright and airy.
   • All section text: bordeaux (the wax-red), with a soft white
     glow so it stays legible over the lightened photos.
   • Form fields, palette swatches, primary button: re-tinted
     to match.
   ========================================================= */
:root {
  --bordeaux:        #7a1626;
  --bordeaux-deep:   #4d0e1a;
  --bordeaux-soft:   #9a213a;
  --veil-cream:      255, 250, 245;
  --veil-white:      255, 255, 255;
}

/* ---------- photo overlays (heavy white veils, like the hero) --- */
.sec-overlay {
  background: linear-gradient(
    180deg,
    rgba(var(--veil-cream), 0.62) 0%,
    rgba(var(--veil-cream), 0.58) 30%,
    rgba(var(--veil-cream), 0.65) 65%,
    rgba(var(--veil-white), 0.78) 100%
  );
}
.sec-overlay--center {
  background:
    radial-gradient(ellipse 80% 60% at 50% 50%,
      rgba(var(--veil-white), 0.55) 0%,
      rgba(var(--veil-white), 0.30) 75%),
    linear-gradient(180deg,
      rgba(var(--veil-cream), 0.62) 0%,
      rgba(var(--veil-cream), 0.60) 50%,
      rgba(var(--veil-cream), 0.70) 100%);
}
.sec-overlay--strong {
  background:
    radial-gradient(ellipse 80% 65% at 50% 50%,
      rgba(var(--veil-white), 0.55) 0%,
      rgba(var(--veil-white), 0.30) 80%),
    linear-gradient(180deg,
      rgba(var(--veil-cream), 0.72) 0%,
      rgba(var(--veil-cream), 0.68) 50%,
      rgba(var(--veil-cream), 0.82) 100%);
}
.sec-overlay--hero {
  background: linear-gradient(
    180deg,
    rgba(var(--veil-white), 0.80) 0%,
    rgba(var(--veil-white), 0.74) 20%,
    rgba(var(--veil-cream), 0.62) 38%,
    rgba(var(--veil-cream), 0.30) 48%,
    rgba(var(--veil-cream), 0.12) 55%,
    rgba(var(--veil-cream), 0.12) 100%
  );
}

.bg-stack { background: #fffaf3; }

/* ---------- text → bordeaux + light glow ---------- */
.sec-content,
.sec-kicker,
.sec-script,
.sec-lede,
.sec-quote,
.sec-quote cite,
.sec-display-names,
.sec-display-names .sdn-name,
.sec-display-date,
.sec-display-date--quiet,
.sec-bigdate,
.sec-bigdate .bd-day,
.sec-bigdate .bd-num,
.sec-bigdate .bd-mo,
.sec-bigdate .bd-year,
.sec-sub,
.sec-signature,
.sec-signature .sig,
.event-tile,
.et-label,
.et-time,
.et-venue,
.et-addr {
  color: var(--bordeaux);
  text-shadow: none;
}

/* ---------- THINNER type across every section ----------
   Matches the hero's airy feel: every text element drops to
   weight 400 and every glyph-stroke is stripped, so the bordeaux
   sits as a delicate fill on the heavily white-veiled photos. */
.sec-kicker,
.sec-lede strong,
.sec-quote cite,
.sec-form .field > span,
.sec-form .field > span em,
.scroll-hint .sh-text,
.sec-script,
.sec-quote,
.sec-lede,
.sec-display-names,
.sec-display-names .sdn-name,
.sec-display-date,
.sec-display-date--quiet,
.sec-bigdate,
.sec-bigdate .bd-day,
.sec-bigdate .bd-num,
.sec-bigdate .bd-mo,
.sec-bigdate .bd-year,
.sec-sub,
.event-tile,
.et-label,
.et-time,
.et-venue,
.et-addr,
.snap-section .countdown li strong,
.snap-section .countdown li span {
  font-weight: 400;
}
.sec-form .primary-btn,
.primary-btn {
  font-weight: 500;
}

/* Strip every glyph stroke we'd added across §2-§7. */
.sec-kicker,
.sec-script,
.sec-lede,
.sec-lede strong,
.sec-quote,
.sec-quote cite,
.sec-sub,
.event-tile,
.et-label,
.et-time,
.et-venue,
.et-addr,
.sec-form .field > span,
.sec-form .field > span em,
.scroll-hint .sh-text,
.sec-display-names .sdn-amp,
.sec-signature .sig-amp,
.sec-display-date,
.sec-display-date--quiet,
.sec-bigdate,
.sec-bigdate .bd-day,
.sec-bigdate .bd-num,
.sec-bigdate .bd-mo,
.sec-bigdate .bd-year,
.snap-section .countdown li strong,
.snap-section .countdown li span {
  -webkit-text-stroke: 0;
          text-stroke: 0;
}

/* Closing signature on §7 — back to plain Allura at its natural
   thin weight, no stroke, just bordeaux fill. */
.sec-closing .sec-signature,
.sec-closing .sec-signature .sig,
.sec-closing .sec-signature .sig-amp {
  font-family: "Allura", var(--script);
  font-style: normal;
  font-weight: 400;
  color: var(--bordeaux);
  -webkit-text-stroke: 0;
          text-stroke: 0;
  opacity: 1;
  text-shadow: none;
}

/* Closing signature width — capped to 95% of the viewport so the
   "Jonathan & Anna-Maria" line never overflows the phone frame.
   We also nudge the font-size down so the natural line width
   lands right around the 95vw target instead of pushing past it. */
.sec-closing .sec-signature {
  width: 95vw;
  max-width: 95vw;
  margin-left: auto;
  margin-right: auto;
  font-size: clamp(26px, 7.4vw, 34px);
  gap: clamp(8px, 2.5vw, 14px);
}

/* Closing headline ("We can't wait to celebrate with you.") —
   tinted in the same logo gold as the date below it, so the two
   lines read as a single warm pairing. */
.sec-closing .sec-script {
  color: #a78a4d;
}

/* The accent glyphs — ampersands, lede strong, signature amp.
   Use a slightly deeper bordeaux so they still feel like accents. */
.sec-display-names .sdn-amp,
.sec-signature .sig-amp,
.sec-lede strong {
  color: var(--bordeaux-deep);
  text-shadow: none;
}

/* Countdown numbers + labels — logo gold */
.snap-section .countdown li strong,
.snap-section .countdown li span {
  color: #a78a4d;
  text-shadow: none;
}

/* Wedding date — gold across the page so it ties to the logo and
   the countdown. Covers the "18 · 07 · 2026" line in the hero and
   the closing, plus every span of the §2 big calendar date. */
.sec-display-date,
.sec-display-date--quiet,
.sec-bigdate,
.sec-bigdate .bd-day,
.sec-bigdate .bd-num,
.sec-bigdate .bd-mo,
.sec-bigdate .bd-year {
  color: #a78a4d;
  text-shadow: none;
}

/* Countdown tile containers — gold border that matches the numbers
   and the logo, with a slightly warmer frosted background. */
.snap-section .countdown li {
  background: rgba(255, 250, 235, 0.55);
  border: 1px solid #a78a4d;
  box-shadow:
    0 4px 14px rgba(167, 138, 77, 0.18),
    inset 0 1px 0 rgba(255, 255, 255, 0.5);
}

/* Scroll-hint */
.scroll-hint .sh-line {
  background: var(--bordeaux);
  box-shadow: none;
}
.scroll-hint .sh-text {
  color: var(--bordeaux);
  text-shadow: none;
}

/* Event divider line in §4 celebration */
.event-divider {
  background: rgba(122, 22, 38, 0.45);
}

/* ---------- form fields ---------- */
.sec-form .field > span,
.sec-form .field > span em {
  color: var(--bordeaux);
  text-shadow: none;
}
.sec-form input[type="text"],
.sec-form input[type="number"],
.sec-form textarea,
.sec-form .stepper input {
  color: var(--bordeaux-deep);
  background: rgba(255, 255, 255, 0.78);
  border-color: rgba(122, 22, 38, 0.35);
}
.sec-form input::placeholder,
.sec-form textarea::placeholder {
  color: rgba(122, 22, 38, 0.45);
}
.sec-form input:focus,
.sec-form textarea:focus {
  border-color: var(--bordeaux);
  background: #fff;
}
.sec-form .pill {
  color: var(--bordeaux);
  background: rgba(255, 255, 255, 0.55);
  border-color: rgba(122, 22, 38, 0.35);
}
.sec-form .pill:has(input:checked) {
  color: #fff;
  background: var(--bordeaux);
  border-color: var(--bordeaux);
}
.sec-form .step-btn {
  color: var(--bordeaux);
  background: rgba(255, 255, 255, 0.55);
  border-color: rgba(122, 22, 38, 0.35);
}
.sec-form .step-btn:hover {
  background: rgba(122, 22, 38, 0.10);
}

/* Primary submit button — bordeaux fill */
.sec-form .primary-btn,
.primary-btn {
  color: #fff8ef;
  background: var(--bordeaux);
  box-shadow:
    0 12px 24px rgba(122, 22, 38, 0.32),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
  text-shadow: none;
}
.sec-form .primary-btn:hover,
.primary-btn:hover {
  background: var(--bordeaux-deep);
}

/* Music FAB — flip its frosted dark pill to a frosted bordeaux pill
   so it reads on the now-bright photos. */
.music-fab {
  background: rgba(122, 22, 38, 0.55);
  border-color: rgba(255, 255, 255, 0.45);
  color: #fff8ef;
  box-shadow:
    0 10px 26px rgba(122, 22, 38, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.music-fab:hover {
  background: rgba(77, 14, 26, 0.75);
  border-color: rgba(255, 255, 255, 0.7);
  color: #fff;
}
.music-fab[aria-pressed="false"] {
  color: rgba(255, 248, 239, 0.85);
  border-color: rgba(255, 255, 255, 0.35);
}

/* Logo drop-shadow — soft red glow instead of dark shadow,
   since the photos are now bright. */
.site-logo {
  filter: drop-shadow(0 2px 6px rgba(122, 22, 38, 0.35));
}

/* §3 STORY — paint the "To love and be loved…" line in logo gold.
   The cite attribution ("— David Viscott") stays bordeaux so the
   author still reads as a quiet, secondary label under the quote. */
.sec-story .sec-quote {
  color: #a78a4d;
  -webkit-text-stroke: 0;
          text-stroke: 0;
}
.sec-story .sec-quote cite {
  color: var(--bordeaux);
  -webkit-text-stroke: 0;
          text-stroke: 0;
}

/* §3 STORY — flat, even white veil across the whole photo.
   Replaces the gradient .sec-overlay with a uniform wash so the
   story page reads as one calm, evenly-shaded backdrop. */
.bg-slide[data-sec="story"] .sec-overlay {
  background: rgba(var(--veil-cream), 0.68);
}

/* Smoother crossfade between section backgrounds.
   Original was 0.45s (snappy), then 1.2s (too slow) — landed on
   0.7s with a soft ease-in-out curve: photos still dissolve into
   each other but keep up with the swipe. */
.bg-slide {
  transition: opacity 0.7s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Slow "breathing" zoom on every background photo. The image grows
   ~6% then shrinks back, drifting toward and away from its centre
   on a 40-second loop — very gentle motion that adds life without
   distracting from the type. */
@keyframes bgBreathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}
.bg-slide img {
  animation: bgBreathe 40s ease-in-out infinite;
  transform-origin: 50% 50%;
  will-change: transform;
}

/* Respect users who've asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .bg-slide img { animation: none; }
}

/* =========================================================
   §1 HERO — local refinements
   • Strip the soft white glow we added on every other section
     (hero text reads on a heavily-veiled photo without it).
   • Reverse the global thinning so hero body copy sits solid
     and confident.
   • Re-confirm every glyph of "Jonathan & Anna-Maria" — including
     the ampersand — is the same bordeaux as the rest of the
     section, no deeper accent.
   ========================================================= */
.sec-hero .sec-content,
.sec-hero .sec-display-date,
.sec-hero .sec-quote,
.sec-hero .sec-quote cite,
.sec-hero .sec-signature,
.sec-hero .sec-signature .sig,
.sec-hero .sec-signature .sig-amp,
.sec-hero .scroll-hint .sh-text {
  text-shadow: none;
}

.sec-hero .sec-display-date,
.sec-hero .sec-quote,
.sec-hero .scroll-hint .sh-text {
  font-weight: 400;
}
.sec-hero .sec-quote cite {
  font-weight: 400;
}

/* Strip the glyph strokes from the hero so the type sits as plain,
   thin Cormorant / Manrope on the heavily-white-veiled photo. */
.sec-hero .sec-quote,
.sec-hero .sec-quote cite,
.sec-hero .scroll-hint .sh-text,
.sec-hero .sec-display-date {
  -webkit-text-stroke: 0;
          text-stroke: 0;
}

/* Hero title — original Allura at its natural thin weight, with
   no stroke at all so the script is delicate again. */
.sec-hero .sec-signature,
.sec-hero .sec-signature .sig,
.sec-hero .sec-signature .sig-amp {
  font-family: "Allura", var(--script);
  font-style: normal;
  font-weight: 400;
  color: var(--bordeaux);
  -webkit-text-stroke: 0;
          text-stroke: 0;
  opacity: 1;
}

/* =========================================================
   PRELOADER · minimal first-load intro — plain white screen,
   centered monogram, thin loading bar under it. Only shown on
   the first visit of each browser session; reloads skip it
   (the head-script toggles `.no-preloader` on <html>).
   ========================================================= */
.preloader {
  position: fixed;
  inset: 0;
  /* Above absolutely everything — even the cover's z-index 999999. */
  z-index: 2147483647;
  display: grid;
  place-items: center;
  background: #ffffff;
  overflow: hidden;
  opacity: 1;
  transition: opacity 0.55s ease, visibility 0s linear 0.55s;
}
.preloader.is-out {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.no-preloader .preloader {
  display: none !important;
}

.preloader-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
}

/* The monogram, sized comfortably for phone screens. */
.preloader-logo {
  width: 140px;
  height: 140px;
  max-width: 45vw;
  max-height: 45vw;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}

/* The bar — a soft neutral track with a slim bordeaux highlight
   sliding across it, indefinitely. */
.preloader-bar {
  position: relative;
  width: 160px;
  height: 2px;
  background: rgba(0, 0, 0, 0.08);
  overflow: hidden;
  border-radius: 2px;
}
.plb-shine {
  position: absolute;
  top: 0;
  left: -40%;
  height: 100%;
  width: 40%;
  background: var(--bordeaux, #7a1626);
  border-radius: 2px;
  animation: pl-shine 1.4s ease-in-out infinite;
}
@keyframes pl-shine {
  0%   { left: -40%; }
  100% { left: 100%; }
}

/* Respect the "reduce motion" OS setting — the bar stops sliding
   and just shows a static segment at the start. */
@media (prefers-reduced-motion: reduce) {
  .plb-shine {
    animation: none;
    left: 0;
  }
}

/* =========================================================
   §6 GIFT REGISTRY · Whish Money card
   ---------------------------------------------------------
   A single centred card that shows the couple's Whish number
   big and readable, with a primary "Send via Whish" CTA and
   a secondary "Copy number" fallback. Tapping the number
   itself also copies, and a green "Copied!" pill replaces
   the hint until it resets.
   ========================================================= */
.whish-card {
  --whish-card-bg: rgba(255, 250, 245, 0.82);
  --whish-card-br: rgba(122, 22, 38, 0.28);

  width: min(360px, 90%);
  margin: 14px auto 0;
  padding: 18px 18px 16px;
  border-radius: 22px;
  background: var(--whish-card-bg);
  border: 1px solid var(--whish-card-br);
  box-shadow:
    0 18px 40px -18px rgba(122, 22, 38, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(8px) saturate(120%);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
  text-align: center;
}

.whish-label {
  margin: 0 0 4px;
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--bordeaux, #7a1626);
  opacity: 0.75;
}

/* The number itself is a real <button> — tap / click copies it
   to the clipboard, so guests never have to read-and-type. The
   whole element is the tap target (not just the text), and it
   has a subtle underline-on-hover cue for discoverability. */
.whish-number {
  display: block;
  width: 100%;
  padding: 10px 12px 12px;
  margin: 0 0 14px;
  background: transparent;
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: all;
}
.whish-number:focus-visible {
  outline: 2px solid var(--bordeaux, #7a1626);
  outline-offset: 4px;
  border-radius: 14px;
}
.whish-number-value {
  display: block;
  font-family: var(--serif);
  font-size: clamp(26px, 7vw, 30px);
  font-weight: 500;
  letter-spacing: 0.08em;
  line-height: 1.1;
  color: var(--bordeaux-deep, #4d0e1a);
  transition: color 0.2s ease;
}
.whish-number:hover .whish-number-value,
.whish-number:active .whish-number-value {
  color: var(--bordeaux, #7a1626);
}

/* "Copied!" confirmation on the secondary button — JS toggles the
   `is-copied` class for 3s after a successful clipboard write,
   swaps the inner label, and we paint the button solid green with
   white text so the feedback is impossible to miss. */
.whish-copy.ghost-btn.is-copied,
.whish-copy.ghost-btn.is-copied:hover,
.whish-copy.ghost-btn.is-copied:focus,
.whish-copy.ghost-btn.is-copied:active {
  background: #4d8a3a;
  border-color: #4d8a3a;
  color: #fff;
}
.whish-copy.ghost-btn.is-copied span {
  color: #fff;
}

/* The two-button row. Stacks on the narrowest phones so the
   primary CTA never squishes into a tiny pill. */
.whish-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: stretch;
}
/* "Send via Whish" — full-width primary, but with NO hover lift,
   shadow change, or active dip. Keep the bordeaux fill flat in
   every interaction state so it reads as a calm, static link. */
.whish-btn.primary-btn,
.whish-btn.primary-btn:hover,
.whish-btn.primary-btn:focus,
.whish-btn.primary-btn:active {
  transform: none;
  box-shadow: none;
}
.whish-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.wb-icon {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

/* "Copy number" — full-width ghost button, but pinned to bordeaux
   text/border at rest (not the global rose) and with no hover or
   active fill change. The only state change is the green
   `.is-copied` flash, which is handled above. */
.whish-copy.ghost-btn,
.whish-copy.ghost-btn:hover,
.whish-copy.ghost-btn:focus,
.whish-copy.ghost-btn:active {
  width: 100%;
  text-align: center;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.6);
  color: var(--bordeaux, #7a1626);
  border-color: rgba(122, 22, 38, 0.35);
  -webkit-tap-highlight-color: transparent;
}

.whish-footnote {
  margin: 14px 0 0;
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  color: var(--bordeaux, #7a1626);
  opacity: 0.6;
}

/* The gift section's background veil — matches the other
   "center overlay" sections for a calm, evenly-lit photo. */
.bg-slide[data-sec="gift"] img { object-position: 50% 35%; }

/* On the gift section, warm the card's border and text so it
   still reads confidently on the cream veil. */
.sec-gift .whish-card {
  --whish-card-bg: rgba(255, 250, 245, 0.9);
  --whish-card-br: rgba(122, 22, 38, 0.32);
}

/* =========================================================
   DESKTOP / TABLET NOTICE
   ---------------------------------------------------------
   The invitation is designed phone-only. On any screen
   that's clearly NOT a phone (a laptop, desktop, or tablet)
   we replace the entire experience with a soft, printed-card
   message asking the guest to reopen the link on their phone.

   Trigger:
     · Wide enough to be a tablet/laptop (≥ 600px)        AND
     · Tall enough that it isn't a phone in landscape (≥ 600px)
   This keeps phones in landscape — which can be 800-900px
   wide — on the mobile experience, while still catching iPad
   Mini (744px wide) and every laptop / desktop.
   ========================================================= */
.desktop-notice {
  display: none;
}

@media (min-width: 600px) and (min-height: 600px) {
  /* Hide the entire phone preview, the preloader, and any
     floating UI that lives outside .phone — the desktop
     notice is the only thing the guest should see. */
  .phone,
  .preloader,
  .site-logo,
  .music-fab {
    display: none !important;
  }

  /* Let the page actually fill (and scroll, on small laptop
     windows) instead of being clamped to the phone-locked
     `100svh` + `overflow: hidden` we use on mobile. */
  html,
  body {
    height: auto;
    min-height: 100vh;
    overflow: auto;
  }

  /* Re-paint the body with the warm wedding palette so the
     desktop notice sits on its own landscape backdrop —
     gentle radial glows + the same cream + blush base used
     elsewhere in the site. */
  body {
    background:
      radial-gradient(50% 40% at 18% 22%,
        rgba(230, 39, 107, 0.10), transparent 70%),
      radial-gradient(45% 40% at 82% 26%,
        rgba(255, 169, 120, 0.16), transparent 70%),
      radial-gradient(55% 40% at 70% 85%,
        rgba(167, 138, 77, 0.13), transparent 70%),
      radial-gradient(45% 40% at 15% 85%,
        rgba(124, 143, 106, 0.10), transparent 70%),
      radial-gradient(120% 80% at 50% 0%,
        #fff5e8 0%, #fde4d6 35%, #fbcfd1 65%, #f4b6c0 100%),
      var(--cream);
    background-attachment: fixed;
    display: grid;
    place-items: center;
    padding: 40px 24px;
  }

  .desktop-notice {
    display: grid;
    place-items: center;
    width: 100%;
    max-width: 640px;
  }
}

/* The card itself — printed-stationery feel, with a thin gold
   hairline above the title and the same Allura signature used
   on the closing section so it reads as part of the same
   visual language as the mobile invitation. */
.dn-card {
  position: relative;
  width: 100%;
  padding: 56px 44px 44px;
  border-radius: 28px;
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, 0.94) 0%,
      rgba(255, 250, 243, 0.94) 100%);
  border: 1px solid rgba(167, 138, 77, 0.28);
  box-shadow:
    0 30px 80px -30px rgba(122, 22, 38, 0.30),
    0 6px 20px -10px rgba(167, 138, 77, 0.20),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
  text-align: center;
  overflow: hidden;
}

/* Delicate gold hairline under the kicker — echoes the gold
   accents on the countdown tiles and the closing date. */
.dn-card::before {
  content: "";
  position: absolute;
  top: 142px;
  left: 50%;
  transform: translateX(-50%);
  width: 64px;
  height: 1px;
  background: linear-gradient(90deg,
    transparent,
    rgba(167, 138, 77, 0.65),
    transparent);
}

.dn-logo {
  display: block;
  width: 86px;
  height: auto;
  margin: 0 auto 22px;
  filter: drop-shadow(0 6px 14px rgba(122, 22, 38, 0.18));
  user-select: none;
  -webkit-user-drag: none;
}

.dn-kicker {
  margin: 0 0 22px;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--bordeaux, #7a1626);
  opacity: 0.72;
}

.dn-title {
  margin: 0 0 18px;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(28px, 3.6vw, 40px);
  line-height: 1.18;
  color: var(--bordeaux, #7a1626);
  letter-spacing: 0.005em;
}

.dn-body {
  margin: 0 auto 28px;
  max-width: 38ch;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(15px, 1.5vw, 17px);
  line-height: 1.6;
  color: rgba(77, 14, 26, 0.78);
}

.dn-phone {
  display: block;
  width: 56px;
  margin: 6px auto 22px;
  color: #a78a4d;
  animation: dn-bob 3s ease-in-out infinite;
}
.dn-phone svg {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 4px 10px rgba(167, 138, 77, 0.30));
}
@keyframes dn-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

.dn-signature {
  margin: 0 0 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: "Allura", var(--script);
  font-style: normal;
  font-weight: 400;
  font-size: clamp(34px, 4vw, 44px);
  line-height: 1;
  color: var(--bordeaux, #7a1626);
}
.dn-signature .sig-amp {
  font-size: 1.05em;
  opacity: 0.85;
  color: #a78a4d;
}

.dn-date {
  margin: 8px 0 0;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.45em;
  text-transform: uppercase;
  color: #a78a4d;
}

@media (prefers-reduced-motion: reduce) {
  .dn-phone { animation: none; }
}
