/* Siemreap — self-hosted Khmer body font (replaces Battambang). SIL OFL. */
@font-face {
  font-family: 'Siemreap';
  src: url('/fonts/Siemreap.ttf') format('truetype');
  /* Single-weight font — declare 'normal' so the browser synthesizes bold
     for font-weight:700 text (e.g. the parents' names). */
  font-weight: normal;
  font-display: swap;
}
/* Koulen — heavy display Khmer font used for the parents' names. SIL OFL. */
@font-face {
  font-family: 'Koulen';
  src: url('/fonts/Koulen-khmer.woff2') format('woff2'),
       url('/fonts/Koulen-khmer.ttf') format('truetype');
  font-weight: normal;
  font-display: swap;
}

:root {
  color-scheme: only light;
  /* Matcha green + gold-foil luxury palette.
     Greens: matcha #4F5D4A, sage #66735F.
     Golds: foil #C9A86A, metallic #B8924A, champagne #E6D3AE, body #D9C39A. */
  --gold: #c9a86a;          /* gold foil — names, headings, decor */
  --gold-dark: #b8924a;     /* metallic gold — borders, deeper accents */
  --blue-dark: #d9c39a;     /* MAIN TEXT colour: light champagne gold */
  --pink: #c9a86a;          /* former pink accent → gold foil */
  --bg-pink: #4f5d4a;       /* page / envelope: deep matcha green */
  --sage: #66735f;          /* sage green (inner cards) */
  --sage-dark: #3f4b3b;     /* deep matcha for solid buttons */
  --cream: #e6d3ae;         /* champagne gold highlight */
  /* Content-card background: sage green, slightly translucent. */
  --card-bg: rgba(102, 115, 95, 0.55);
  /* Gold-foil gradient for ornate lettering / accents. */
  --gold-grad: linear-gradient(180deg, #f0e2c0 0%, #e6d3ae 30%, #c9a86a 60%, #b8924a 100%);
  --gold-deep: #a37f37;
  /* Invitation column width — full-bleed (fills the screen on every size). */
  --app-max: 100%;
}

* { box-sizing: border-box; }

/* Remove the grey/blue tap-highlight flash that mobile browsers paint over
   buttons and links when tapped. */
* { -webkit-tap-highlight-color: transparent; }
button, a, [role="button"], input, textarea, select, label {
  -webkit-tap-highlight-color: transparent;
}
button:focus, a:focus, [role="button"]:focus { outline: none; }
button, [role="button"] { -webkit-touch-callout: none; }

/* Fluid type scale: every rem-based font-size on the page grows smoothly
   from phone up to desktop as the viewport widens. A higher floor keeps the
   text prominent on phones (closer to the roomier wide view). */
html {
  font-size: clamp(17.5px, 15.5px + 0.7vw, 19px);
  scroll-behavior: smooth;
}

html, body {
  margin: 0;
  padding: 0;
  /* Body text: ornate Khmer 'Moul' in solid gold foil (Latin falls back to
     Siemreap, which Moul lacks glyphs for). */
  font-family: 'Moul', 'Siemreap', sans-serif;
  /* Light watercolour-sky tone as the page ground (matches the fixed
     backdrop) so tall/wide screens like iPad never show a flat beige gap. */
  background: #e7ece1;
  background-attachment: fixed;
  color: var(--gold);
  overflow-x: hidden;
  color-scheme: only light;
}

/* Keep form controls in the readable font so typing stays easy. */
input, textarea, select {
  font-family: 'Siemreap', sans-serif;
}

/* Some Android browsers (Samsung Internet, in-app WebViews) algorithmically
   force-darken pages that don't appear to have their own dark-mode styling,
   ignoring the `color-scheme: light` opt-out above. Explicitly re-declaring
   the same light colors inside a dark-scheme media query signals that this
   page already handles dark mode intentionally, which stops that automatic
   re-coloring. */
@media (prefers-color-scheme: dark) {
  html, body {
    background: #e7ece1 !important;
    color: var(--gold) !important;
    color-scheme: only light;
  }
  .app-frame { background: #e7ece1 !important; }
  #cover {
    background: url('/images/cover.jpg?v=6') center 42% / cover no-repeat !important;
  }
  .banner-title, .cover-name { color: var(--blue-dark) !important; }
  main#invitation { background: transparent !important; color: var(--gold) !important; }
}

/* Dreamy "enchanted pink fairy garden" backdrop, matching the fairy-door
   reveal: a soft blush-lavender sky melting into a soft green meadow, with
   blurred bokeh blossoms drifting slowly. Sits fixed behind everything;
   .app-frame and #cover are tinted translucent (below) so this shows through. */
.floral-bg {
  position: fixed;
  top: -12%;
  left: -12%;
  right: -12%;
  bottom: -12%;
  z-index: 0;
  pointer-events: none;
  filter: blur(60px);
  opacity: 0.7;
  background:
    radial-gradient(circle at 12% 14%, rgba(201,168,106,0.45) 0%, transparent 40%),
    radial-gradient(circle at 86% 10%, rgba(230,211,174,0.4) 0%, transparent 44%),
    radial-gradient(circle at 82% 84%, rgba(102,115,95,0.9) 0%, transparent 46%),
    radial-gradient(circle at 14% 82%, rgba(79,93,74,0.9) 0%, transparent 46%),
    radial-gradient(circle at 55% 52%, rgba(184,146,74,0.35) 0%, transparent 50%),
    linear-gradient(180deg, #45513f 0%, #4f5d4a 40%, #56634d 70%, #66735f 100%);
  animation: floralDrift 42s ease-in-out infinite alternate;
}

@keyframes floralDrift {
  0% { transform: translate(0, 0) scale(1) rotate(0deg); }
  50% { transform: translate(-1.5%, 2%) scale(1.06) rotate(1.5deg); }
  100% { transform: translate(1.5%, -1.5%) scale(1.04) rotate(-1.5deg); }
}

/* On wider screens (desktop/web) the pink background fills the whole
   browser window; the content itself stays centered and readable via
   the max-width on .cover-inner / .section further down. */
.app-frame {
  min-height: 100vh;
  position: relative;
  /* Center the invitation as a responsive column; full-width on phones,
     capped by --app-max on tablets/desktop, backdrop shows on either side. */
  max-width: var(--app-max);
  margin: 0 auto;
  /* Light watercolour-sky tone (matches the fixed backdrop) so if the fixed
     background ever leaves a gap during mobile scroll, the gap is invisible
     instead of showing the old dark green. */
  background: #e7ece1;
  overflow-x: hidden;
}

.hidden { display: none !important; }

/* "Skip" button on the cover + curtain-reveal screens — jumps to the invitation. */
.skip-btn {
  /* Sits just to the left of the mute button (top-right). */
  position: fixed;
  top: 22px;
  right: 72px;
  z-index: 30;
  padding: 8px 16px;
  border: none;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.85);
  color: #3f2948;
  font-family: 'Siemreap', sans-serif;
  font-size: 0.85rem;
  font-weight: 700;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease;
}
.skip-btn:hover { background: #fff; }
.skip-btn:active { transform: scale(0.94); }
#curtain-stage .skip-btn { z-index: 60; }

/* Reveal skip button: lives outside the zoomed stage, fixed to the viewport
   and above it. Shown only while the reveal (curtain-stage) is visible. */
.reveal-skip {
  display: none;
  z-index: 400;
}
#curtain-stage:not(.hidden) ~ .reveal-skip {
  display: inline-block;
}

/* ---------------- Envelope-opening entrance animation ---------------- */
/* Plays once over the cover page on load, then fades away to reveal it. */
.envelope-stage {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 900px;
  background: var(--bg-pink);
  opacity: 1;
  transition: opacity 0.7s ease, transform 0.8s ease;
}
.envelope-stage.card-out {
  opacity: 0;
  transform: scale(1.1);
  pointer-events: none;
}

.envelope-flip {
  position: relative;
  width: 160px;
  height: 112px;
  transform-style: preserve-3d;
  transition: transform 1.1s cubic-bezier(0.45, 0.15, 0.15, 1);
}
.envelope-stage.flip .envelope-flip {
  transform: rotateY(180deg);
}

.envelope-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  border-radius: 6px;
  background: #ffffff;
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25);
}

.envelope-face-back {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: 10px;
}
.envelope-back-petals {
  font-size: 0.7rem;
  opacity: 0.7;
  letter-spacing: 2px;
}

.envelope-face-front {
  transform: rotateY(180deg);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.envelope-flap {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 58%;
  background: linear-gradient(160deg, #ffffff, #eceae3);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}
.envelope-seal {
  position: relative;
  z-index: 1;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--pink), var(--sage-dark));
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff8ea;
  font-size: 15px;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.envelope-stage.seal-out .envelope-seal {
  opacity: 0;
  transform: scale(0.5);
}

/* ---------------- Cover page ---------------- */
#cover {
  min-height: 100vh;
  /* Content height = the visible area, so the open button is always in view
     and reachable (never hidden behind the mobile browser bar). */
  min-height: 100dvh;
  display: flex;
  align-items: stretch;
  justify-content: center;
  position: relative;
  text-align: center;
  /* Extra bottom space + the phone's safe-area inset so the open button never
     sits under the browser navigation bar / home indicator. */
  padding: 48px 24px calc(56px + env(safe-area-inset-bottom, 0px));
  overflow: hidden;
}
/* The couple photo on a FIXED full-screen layer behind the cover content, so it
   always fills the whole screen (no blank band when the browser bar shows/hides)
   without affecting where the content sits. */
#cover::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  background: url('/images/cover.jpg?v=6') center 42% / cover no-repeat;
}
/* Keep the decorative hearts above the fixed photo (the cover-inner and the
   fixed Skip button already sit above it via their own positioning). */
#cover .floating-hearts { z-index: 1; }

/* Tap-to-open sequence: seal cracks, content fades */
@keyframes sealCrack {
  0% { transform: scale(1); opacity: 1; }
  35% { transform: scale(1.18); opacity: 1; }
  100% { transform: scale(0.4); opacity: 0; }
}

@keyframes coverContentOut {
  0% { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-18px); }
}

#cover.opening .open-circle-btn {
  animation: sealCrack 0.45s ease forwards;
}

/* Petal-burst particles spawned at the open button on tap */
.petal-burst {
  position: fixed;
  z-index: 50;
  pointer-events: none;
  font-size: 1.3rem;
  will-change: transform, opacity;
  animation: petalBurst 0.8s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}

@keyframes petalBurst {
  0% { transform: translate(0, 0) scale(0.5) rotate(0deg); opacity: 1; }
  100% {
    transform: translate(var(--tx), var(--ty)) scale(1.1) rotate(var(--tr));
    opacity: 0;
  }
}

#cover.opening .cover-inner > *:not(.open-circle-btn) {
  animation: coverContentOut 0.5s ease forwards;
}

.floating-hearts {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.heart-particle {
  position: absolute;
  opacity: 0.6;
  animation: floatParticle ease-in-out infinite;
  will-change: transform;
}

@keyframes floatParticle {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-24px) rotate(10deg); }
}

.cover-inner {
  position: relative;
  z-index: 1;
  max-width: 480px;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Push the invitation line, DEAR card and open button down to the bottom of
   the cover; the banner ✦, title and couple names stay pinned at the top. */
.cover-inner > .invite-line {
  margin-top: auto;
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}

.cover-inner > * {
  opacity: 0;
  animation: fadeInUp 0.8s ease forwards;
}
.cover-inner > .banner-title { animation-delay: 0.25s; }
.cover-inner > .cover-names { animation-delay: 0.4s; }
.cover-inner > .invite-line { animation-delay: 0.55s; }
.cover-inner > .guest-card { animation-delay: 0.7s; }
.cover-inner > .open-caption { animation-delay: 0.85s; }
.cover-inner > .open-sub { animation-delay: 0.95s; }

.banner-text {
  color: var(--gold);
  letter-spacing: 4px;
  margin-bottom: 4px;
  animation: fadeInUp 0.8s ease 0.1s forwards, twinkle 2.4s ease-in-out 1.2s infinite;
}

@keyframes twinkle {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

.banner-title {
  font-family: 'Moul', serif;
  font-size: 1.6rem;
  color: var(--blue-dark);
  margin: 0 0 16px;
  /* Dark halo so the light-gold text stays readable over the photo. */
  text-shadow: 0 2px 5px rgba(0, 0, 0, 0.75), 0 0 14px rgba(0, 0, 0, 0.5),
    0 0 2px rgba(0, 0, 0, 0.9);
}

.cover-names {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.cover-name {
  font-family: 'Moul', serif;
  font-size: 1.4rem;
  color: var(--blue-dark);
  text-shadow: 0 2px 5px rgba(0, 0, 0, 0.75), 0 0 14px rgba(0, 0, 0, 0.5),
    0 0 2px rgba(0, 0, 0, 0.9);
}

.heart-divider { font-size: 1.5rem; }

.invite-line {
  color: #fff;
  margin-bottom: 28px;
  letter-spacing: 0.5px;
  text-shadow: 0 2px 5px rgba(0, 0, 0, 0.8), 0 0 12px rgba(0, 0, 0, 0.55),
    0 0 2px rgba(0, 0, 0, 0.9);
}

/* Guest card = the floral cartouche frame; the name sits in its cream band. */
.guest-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 100%;
  max-width: 420px;
  aspect-ratio: 800 / 294;
  margin: -16px auto -10px;
  /* Keep the text within the cream band (y 28–72%). */
  padding: 0 11%;
  background: url('/images/guest-frame.png') center / contain no-repeat;
}

.guest-label {
  letter-spacing: 3px;
  color: #7a5b70;
  font-size: 0.68rem;
  margin: 0;
}

.guest-name {
  /* Playfair for Latin names; 'Siemreap' so a Khmer guest name shapes correctly
     instead of falling back to a broken default (per-glyph font matching). */
  font-family: 'Playfair Display', 'Siemreap', serif;
  font-style: italic;
  font-weight: 600;
  font-size: 1.1rem;
  line-height: 1.2;
  color: #3f2948;
  margin: 0;
}

.open-circle-btn {
  display: flex;
  width: fit-content;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 28px;
  border-radius: 999px;
  border: none;
  cursor: pointer;
  background: var(--sage-dark);
  color: #fffdf8;
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 700;
  margin: 24px auto 0;
  box-shadow: 0 10px 22px rgba(0,0,0,0.22);
  transition: transform 0.2s ease;
  animation: fadeInUp 0.8s ease 0.7s forwards, pulseAttention 1.8s ease-in-out 1.5s infinite;
}
.open-circle-btn:hover { transform: scale(1.06); }

.open-circle-icon {
  font-size: 1.25rem;
  line-height: 1;
}

.open-btn-text {
  line-height: 1;
}

@keyframes pulseAttention {
  0%, 100% { transform: scale(1); box-shadow: 0 10px 22px rgba(0,0,0,0.22); }
  50% { transform: scale(1.04); box-shadow: 0 10px 32px rgba(92,107,72,0.6); }
}

.open-caption {
  margin-top: 16px;
  color: var(--gold-dark);
  font-weight: bold;
}

.open-sub {
  margin-top: 6px;
  letter-spacing: 3px;
  font-size: 0.7rem;
  color: #bfae82;
}

/* -------- Pink fairy-door in a wildflower garden -------- */
.curtain-stage {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: var(--app-max);
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  perspective: 1400px;
  /* Animated forest video backdrop for the reveal screen. A forest still shows
     behind the video while it loads (instead of a flat dark-green slab). */
  background: url('/images/forest-poster.jpg') center center / cover no-repeat;
  transition: opacity 1s ease, transform 1.3s cubic-bezier(0.33, 0, 0.2, 1);
}
/* Opening state: the closed doors start scaled up to fill the whole screen
   (forest hidden), then zoom back to normal size as they swing open. */
.curtain-stage.door-zoom {
  transform: translateX(-50%) scale(1.75);
}
/* Full-bleed forest backdrop behind the curtain reveal. Two <video> children
   crossfade for a seamless, natural-motion loop (no reverse, no jump). The
   wrapper carries the counter-scale + push-in so both videos stay in sync. */
.stage-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.8s ease;
}
.curtain-stage.scene-in .stage-bg { opacity: 1; }
/* Counter-scale by 1/1.75 so the forest shows un-zoomed behind the full-screen
   doors (no push-in zoom — the forest sits still while the video plays). */
.curtain-stage.door-zoom .stage-bg {
  transform: scale(0.5714);
  transform-origin: center center;
}
.stage-bg-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1s ease;
  /* Promote to its own GPU layer for smooth scaling + playback. */
  will-change: opacity;
  backface-visibility: hidden;
}
.stage-bg-video.active { opacity: 1; }
/* The forest video fills the full screen (cover) on every size, including
   desktop. */
.curtain-stage.hidden { display: none; }
.curtain-stage.fade-out { opacity: 0; }

/* Soft blossom clouds framing the top and sides of the garden. The whole
   backdrop scene starts hidden and gently fades in (0.4s) once the doors
   begin to open — before the first couple photo is revealed. */
.garden-frame {
  /* Disabled — the floral-border image is now the reveal backdrop. */
  display: none;
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease-in-out;
  background:
    radial-gradient(ellipse 72% 26% at 50% -6%, #5c6a50 0%, #4f5d4a 42%, transparent 72%),
    radial-gradient(circle at -4% 34%, #57654f 0%, transparent 40%),
    radial-gradient(circle at 104% 34%, #57654f 0%, transparent 40%),
    radial-gradient(circle at 0% 74%, #4f5d4a 0%, transparent 34%),
    radial-gradient(circle at 100% 74%, #4f5d4a 0%, transparent 34%);
}
/* Little scattered gold flecks tucked in the foliage. */
.garden-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 14% 8%, rgba(230,211,174,0.85) 0 4px, transparent 5px),
    radial-gradient(circle at 30% 5%, rgba(201,168,106,0.85) 0 3px, transparent 4px),
    radial-gradient(circle at 68% 6%, rgba(230,211,174,0.85) 0 4px, transparent 5px),
    radial-gradient(circle at 88% 10%, rgba(201,168,106,0.8) 0 3px, transparent 4px),
    radial-gradient(circle at 5% 52%, rgba(184,146,74,0.8) 0 4px, transparent 5px),
    radial-gradient(circle at 96% 56%, rgba(230,211,174,0.8) 0 4px, transparent 5px);
}
/* Backdrop scene visible once the doors start opening. */
.curtain-stage.scene-in .garden-frame { opacity: 1; }

.stage-photo {
  position: absolute;
  z-index: 2;
  /* Centered with a 60px gutter on each side (phones). Divided by 1.75 to
     cancel the door-zoom scale. Capped so it stays a tidy card on wide/desktop
     screens instead of filling the width. On-screen width = this × 1.75, so the
     290px cap ≈ 507px on screen. */
  width: min(calc((100vw - 120px) / 1.75), 290px);
  max-width: none;
  max-height: calc(78vh / 1.75);
  object-fit: cover;
  border-radius: 14px;
  border: 5px solid #e6d3ae;
  box-shadow: 0 0 42px rgba(201,168,106,0.55), 0 0 80px rgba(184,146,74,0.3), 0 22px 45px rgba(20,30,18,0.4);
  opacity: 0;
  transform: translateY(0);
  /* Slow, elegant cross-fade; a gentle vertical Ken Burns pan while shown
     (keeps the 30px side gutters constant, unlike a zoom). */
  transition: opacity 0.9s ease-in-out;
}
.stage-photo.show {
  opacity: 1;
  animation: stagePhotoPan 7s ease-out forwards;
}
@keyframes stagePhotoPan {
  from { transform: translateY(1.4%); }
  to   { transform: translateY(-1.4%); }
}

/* Floating sparkles / fairy dust drifting through the garden. */
.stage-sparkle {
  position: absolute;
  z-index: 3;
  color: #f4ecd6;
  text-shadow: 0 0 8px #e6d3ae, 0 0 16px rgba(201,168,106,0.7);
  pointer-events: none;
  animation: stageTwinkle 2.2s ease-in-out infinite;
}
@keyframes stageTwinkle {
  0%, 100% { opacity: 0; transform: translateY(0) scale(0.4); }
  50% { opacity: 1; transform: translateY(-9px) scale(1); }
}

/* The pink fairy door: two arched leaves that swing open once. */
.curtain {
  position: absolute;
  top: 6%;
  bottom: 4%;
  width: 42%;
  z-index: 5;
  background:
    linear-gradient(90deg, rgba(47,57,45,0.35), transparent 22%, transparent 78%, rgba(47,57,45,0.35)),
    repeating-linear-gradient(90deg, #5a674f 0px, #66735f 13px, #4f5d4a 26px);
  box-shadow: inset 0 0 45px rgba(30,40,28,0.4), 0 12px 30px rgba(20,30,18,0.4);
  backface-visibility: hidden;
  /* Slow, smooth ease-in-out door swing. */
  transition: transform 3.2s cubic-bezier(0.37, 0, 0.63, 1);
}
/* White painted panel trim inside each door leaf. */
.curtain::before {
  content: "";
  position: absolute;
  inset: 12px;
  border: 2px solid rgba(255,255,255,0.75);
  border-radius: 6px;
}
/* Gold flower-knob handle near the centre seam. */
.curtain::after {
  content: "✿";
  position: absolute;
  top: 50%;
  font-size: 14px;
  color: #d9a63e;
  transform: translateY(-50%);
  text-shadow: 0 0 6px rgba(217,166,62,0.7);
}
.curtain-left  { left: 8%;  transform-origin: left center;  border-top-left-radius: 120px 150px; border-right: 2px solid rgba(184,146,74,0.5); }
.curtain-right { right: 8%; transform-origin: right center; border-top-right-radius: 120px 150px; border-left: 2px solid rgba(184,146,74,0.5); }
.curtain-left::after  { right: 8px; }
.curtain-right::after { left: 8px; }
.curtain-stage.open .curtain-left  { transform: rotateY(-118deg); }
.curtain-stage.open .curtain-right { transform: rotateY(118deg); }

/* Butterflies fluttering around the doorway. */
.garden-butterfly {
  position: absolute;
  z-index: 6;
  font-size: 1.5rem;
  filter: drop-shadow(0 0 8px rgba(201,168,106,0.8));
  animation: fairyFloat 4.5s ease-in-out infinite;
}
.garden-butterfly.gb1 { left: 9%; top: 24%; }
.garden-butterfly.gb2 { right: 9%; top: 36%; animation-delay: 1.4s; }
@keyframes fairyFloat {
  0%, 100% { transform: translateY(0) rotate(-8deg); }
  50% { transform: translateY(-18px) rotate(8deg); }
}


@media (prefers-reduced-motion: reduce) {
  .stage-photo, .curtain, .curtain-stage { transition: none; }
}

/* ---------------- Main invitation ---------------- */
main {
  position: relative;
  /* No trailing padding — the footer flower band sits flush at the page bottom. */
  padding-bottom: 0;
}

@keyframes mainFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

main:not(.hidden) {
  animation: mainFadeIn 0.6s ease;
}

.petals-layer {
  position: fixed;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: var(--app-max);
  height: 100%;
  pointer-events: none;
  z-index: 1000;
  overflow: hidden;
}

.petal {
  position: fixed;
  top: -30px;
  pointer-events: none;
  user-select: none;
  animation: petalFall linear infinite;
}

@keyframes petalFall {
  0% { transform: translateY(-30px) rotate(0deg) translateX(0px); opacity: 0.9; }
  25% { transform: translateY(25vh) rotate(90deg) translateX(20px); opacity: 0.7; }
  50% { transform: translateY(50vh) rotate(180deg) translateX(-10px); opacity: 0.5; }
  75% { transform: translateY(75vh) rotate(270deg) translateX(15px); opacity: 0.3; }
  100% { transform: translateY(105vh) rotate(1turn) translateX(0px); opacity: 0; }
}

.bg-music-frame {
  position: absolute;
  width: 1px;
  height: 1px;
  border: 0;
  opacity: 0;
  pointer-events: none;
}

.mute-btn {
  position: fixed;
  top: 16px;
  /* Sit 16px inside the right edge of the centered column (any width). */
  right: max(16px, calc(50vw - var(--app-max) / 2 + 16px));
  /* Above the door-reveal stage (z 300) so it stays usable during the reveal. */
  z-index: 400;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.85);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease;
}
.mute-btn:active { transform: scale(0.92); }

/* ---------------- Section navigation (burger menu) ---------------- */
.nav-toggle {
  position: fixed;
  /* Keep clear of the phone's bottom nav bar / home indicator. */
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  right: 20px;
  z-index: 60;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.85);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  cursor: pointer;
  transition: transform 0.2s ease;
}
.nav-toggle span {
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 2px;
  background: #3f2948;
  transition: transform 0.3s ease, opacity 0.2s ease;
}
.nav-toggle:active { transform: scale(0.92); }
/* Animate to an X when open. */
.nav-toggle.open span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle.open span:nth-child(2) { opacity: 0; }
.nav-toggle.open span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: rgba(40, 44, 36, 0.25);
  -webkit-backdrop-filter: blur(1px);
  backdrop-filter: blur(1px);
}

.nav-menu {
  position: fixed;
  bottom: calc(74px + env(safe-area-inset-bottom, 0px));
  right: 20px;
  z-index: 61;
  width: min(76vw, 280px);
  max-height: 74vh;
  overflow-y: auto;
  background: rgba(255, 252, 246, 0.96);
  border-radius: 16px;
  box-shadow: 0 12px 34px rgba(79, 93, 74, 0.4);
  padding: 8px;
  transform-origin: bottom right;
  transform: scale(0.9);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.2s ease, opacity 0.2s ease;
}
.nav-menu.open {
  transform: scale(1);
  opacity: 1;
  pointer-events: auto;
}
.nav-menu ul { list-style: none; margin: 0; padding: 0; }
.nav-menu a {
  display: block;
  padding: 11px 14px;
  border-radius: 10px;
  color: #3f2948;
  font-family: 'Siemreap', sans-serif;
  font-size: 0.95rem;
  text-decoration: none;
  transition: background 0.15s ease;
}
.nav-menu a:hover, .nav-menu a:active { background: rgba(139, 90, 131, 0.12); }
.nav-menu a + a { border-top: 1px solid rgba(139, 90, 131, 0.14); }

/* ONE couple-photo backdrop (matcha tint) behind the whole invitation, with
   a single ornate gold frame wrapping all sections together. The photo is a
   fixed, column-width layer (reliable on mobile, unlike background-fixed). */
main#invitation { position: relative; }
main#invitation::before {
  content: "";
  position: fixed;
  /* Overscan the viewport (top/bottom extend past the edges) so the mobile
     browser toolbar showing/hiding never uncovers a gap during scroll. */
  top: -8vh;
  bottom: -8vh;
  left: 50%;
  transform: translateX(-50%);
  width: min(100%, var(--app-max));
  z-index: 0;
  pointer-events: none;
  /* Cloudy-sky backdrop (top of the watercolour) behind the whole invitation;
     the meadow/flower bottom of the same scene is shown at the footer. */
  background: url('/images/sky-bg.jpg') center center / cover no-repeat;
}

/* ---- Wedding palette on the watercolour backdrop ----
   Dark, readable text over the light meadow, scoped to #invitation so the
   photo-backed cover page keeps its own light text. An ivory halo lifts the
   text off the busier parts of the scene (trees / flowers). */
#invitation .section {
  text-shadow: 0 0 3px rgba(255, 253, 247, 0.9), 0 1px 2px rgba(255, 253, 247, 0.75);
}
/* Cards on the watercolour — subtle light fill + soft green shadow, no border
   or blur (matches the schedule-day style). Scoped so the cover keeps its own. */
#invitation { --card-bg: rgba(255, 250, 242, 0.22); }
#invitation .hero-date,
#invitation .mini-calendar,
#invitation .countdown-box,
#invitation .venue-card,
#invitation .rsvp-form,
#invitation .contact-row a,
#invitation .gift-qr-card,
#invitation .wish-form {
  border: none;
  box-shadow: 0 8px 34px 6px rgba(79, 93, 74, 0.38);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Text — deep plum */
#invitation .title,
#invitation .section-banner,
#invitation .couple-name,
#invitation .footer-names,
#invitation .parents-name,
#invitation .invite-lead,
#invitation .invite-body,
#invitation .couple-role,
#invitation .thank-you,
#invitation .venue-address-en,
#invitation .schedule-day-label,
#invitation .mini-cal-weekdays span,
#invitation .countdown-box small,
#invitation .evt-line,
#invitation .footer-date {
  color: #3F2948;
}
/* Numbers — deep wine */
#invitation .countdown-box span,
#invitation .mini-cal-grid span,
#invitation .mini-cal-month,
#invitation .evt-strong {
  color: #542C3A;
}
/* Accent — mauve */
#invitation .stars,
#invitation .invite-guest .flourish,
#invitation .footer-love,
#invitation .rsvp-deadline {
  color: #8B5A83;
}
#invitation .schedule-time {
  color: #3F2948;
}

.section {
  position: relative;
  z-index: 1;
  /* Centered, always keeping a 20px gap on the left and right. */
  width: calc(100% - 40px);
  max-width: 640px;
  margin: 0 auto;
  /* Vertical breathing room between sections (room for the card shadows). */
  padding: 22px 0;
  text-align: center;
  text-shadow: 0 1px 10px rgba(0,0,0,0.55);
}

/* Single frame overlay covering all sections: thin gold border + a kbach
   ornament in each of the four outer corners (injected once by script.js). */
/* Fixed ornate frame: the four kbach corners stay pinned to the corners of
   the viewport (within the centered card column) while the content scrolls
   behind them. */
.invite-frame {
  /* Kbach corners removed — hidden here too so cached browsers don't show them. */
  display: none !important;
}
/* Traditional Khmer kbach corner ornament (from the reference invite). */
.frame-corner {
  position: absolute;
  width: clamp(84px, 26vw, 156px);
  height: clamp(84px, 26vw, 156px);
  background: left top / contain no-repeat url('/images/hero-corner.png');
  filter: drop-shadow(0 1px 4px rgba(0,0,0,0.45));
}
.fc-tl { top: 0; left: 0; }
.fc-tr { top: 0; right: 0; transform: scaleX(-1); }
.fc-bl { bottom: 0; left: 0; transform: scaleY(-1); }
.fc-br { bottom: 0; right: 0; transform: scale(-1, -1); }

.stars { color: var(--gold); letter-spacing: 6px; animation: twinkle 2.6s ease-in-out infinite; }

.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.8s ease, transform 0.8s ease;
}
.reveal.in-view { opacity: 1; transform: translateY(0); }

.title {
  font-family: 'Moul', serif;
  color: var(--blue-dark);
  font-size: 1.2rem;
  margin-bottom: 24px;
}

/* Thank-you title: a divider line sits below it. */
.thanks-title {
  padding-bottom: 14px;
  margin-bottom: 18px;
  border-bottom: 1px solid rgba(139, 90, 131, 0.4);
}
/* Thank-you & apology note — same card style as the others. */
.thanks-note {
  max-width: 560px;
  margin: 0 auto;
  background: var(--card-bg);
  padding: 24px;
  border-radius: 16px;
  box-shadow: 0 8px 34px 6px rgba(79, 93, 74, 0.38);
}
.thanks-note p {
  font-family: 'Siemreap', sans-serif;
  font-size: 0.95rem;
  line-height: 1.9;
  color: #3F2948;
  margin: 0 0 16px;
}
.thanks-note p:last-child { margin-bottom: 0; }

.section-banner {
  font-family: 'Moul', serif;
  /* One line: shrink to fit narrow phones, cap at 1.6rem on larger screens. */
  font-size: clamp(1.05rem, 5.2vw, 1.6rem);
  line-height: 1.5;
  white-space: nowrap;
  text-align: center;
  width: fit-content;
  max-width: 100%;
  margin: 8px auto 10px;
}

/* Tighten the gap between the title and the invitation letter, and trim the
   space above the ✦ ✦ ✦ / title at the top. */
.section.hero { padding-top: 16px; padding-bottom: 6px; }
.section.hero + .section { padding-top: 14px; }

.hero-couple {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 16px;
}

.hero-person { text-align: center; }

.hero-role {
  font-size: 0.72rem;
  color: var(--pink);
  letter-spacing: 3px;
  line-height: 1.4;
  margin: 0 0 8px;
}
.hero-name-kh {
  font-family: 'Moul', serif;
  font-size: 1.9rem;
  line-height: 1.55;
  color: var(--blue-dark);
  margin: 0;
}
.hero-name-en {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: 1rem;
  letter-spacing: 1px;
  color: #bfae82;
  margin: 7px 0 0;
}
.amp {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: 3.2rem;
  line-height: 1;
  color: var(--pink);
  margin: 4px 0;
}

.hero-photo-frame {
  position: relative;
  /* Full-bleed within the phone card: break out of the section's 24px
     horizontal padding so the photo spans the full card width. */
  margin-left: -24px;
  margin-right: -24px;
  margin-top: 28px;
  margin-bottom: 24px;
}
.hero-photo {
  display: block;
  width: 100%;
  height: auto;
  will-change: transform;
  /* Softly fade all four edges (top, bottom, left, right) into the page
     background by intersecting a vertical and a horizontal gradient mask. */
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0%, #000 16%, #000 84%, transparent 100%),
    linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to bottom, transparent 0%, #000 16%, #000 84%, transparent 100%),
    linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
  mask-composite: intersect;
}
/* Soft vignette that feathers the photo edges into the blush page so the
   frame blends with the background instead of standing out as white. */
.hero-photo-frame::before {
  content: "";
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 46px 24px var(--bg-pink);
  pointer-events: none;
}

.hero-date {
  display: inline-block;
  background: var(--card-bg);
  padding: 10px 22px;
  border-radius: 999px;
  color: var(--pink);
  font-weight: bold;
  box-shadow: 0 6px 18px rgba(0,0,0,0.08);
}

.mini-calendar {
  margin: 24px auto 0;
  max-width: 260px;
  background: var(--card-bg);
  border: 1px solid rgba(184, 147, 90, 0.35);
  border-radius: 18px;
  padding: 18px 16px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.06);
}

.mini-cal-month {
  font-family: 'Moul', serif;
  font-size: 0.8rem;
  color: var(--gold-dark);
  margin: 0 0 12px;
}

.mini-cal-weekdays,
.mini-cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.mini-cal-weekdays span {
  font-size: 0.7rem;
  color: var(--pink);
  letter-spacing: 0.5px;
}

.mini-cal-grid {
  margin-top: 6px;
  font-size: 0.7rem;
}

.mini-cal-day {
  font-size: 0.7rem;
  color: var(--blue-dark);
  padding: 4px 0;
  border-radius: 50%;
}

.mini-cal-highlight {
  background: var(--pink);
  color: var(--cream);
  font-weight: bold;
  box-shadow: 0 2px 8px rgba(224, 139, 176, 0.5);
}

.flourish {
  color: var(--pink);
  font-size: 0.85em;
  opacity: 0.7;
}

/* ---- Invitation letter (traditional flowing layout) ---- */
.invite-letter {
  max-width: 500px;
  margin: 0 auto;
  /* Inherit the section's soft ivory halo (no dark shadow on the light bg). */
}

/* Parents — 2×2 grid: fathers on the top row, mothers on the bottom row
   (groom's side left, bride's side right) so both mothers line up. */
.parents-block {
  /* Groom side (left) & bride side (right); each column stacks that side's
     listed parents, top-aligned, so a missing parent leaves no gap. */
  display: flex;
  justify-content: space-between;
  align-items: start;
  gap: 18px;
  margin: 0 0 26px;
}
.parent-col {
  display: flex;
  flex-direction: column;
  text-align: left;
}
.parent-col .parents-name { white-space: nowrap; }
.parents-name {
  font-family: 'Koulen', sans-serif;
  /* Koulen is already a heavy display face — use its natural weight. */
  font-weight: normal;
  color: var(--cream);
  font-size: 0.9rem;
  line-height: 1.7;
  margin: 0;
  min-height: 1.7em;
  text-align: left;
}

/* Honorific lead line. */
.invite-lead {
  font-family: 'Moul', serif;
  font-size: 1.0rem;
  line-height: 1.7;
  color: var(--gold);
  margin: 0 0 12px;
}

/* Personalized guest name. */
.invite-guest {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: 1.3rem;
  color: var(--gold);
  margin: 4px 0 18px;
}
.invite-guest .flourish { font-size: 0.85rem; color: var(--gold-dark); }

/* Invitation paragraph. */
.invite-body {
  font-family: 'Siemreap', sans-serif;
  font-size: 0.95rem;
  line-height: 1.95;
  color: var(--blue-dark);
  margin: 0 auto 6px;
  padding: 0;
  text-shadow: 0 0 3px rgb(255 253 247 / 0%), 0 1px 2px rgba(255, 253, 247, 0.75);
}
.invite-body-sub { margin-bottom: 24px; }

/* Couple names — groom (left) & bride (right). */
.couple-block {
  display: grid;
  /* minmax(0,1fr) lets the name columns shrink below their content so a long
     Khmer name wraps instead of pushing the bride column off-screen. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 16px;
  margin: 26px 0 24px;
}
.couple-col { min-width: 0; }

/* P & S monogram centered between the groom & bride name columns. */
.couple-logo {
  flex: 0 0 auto;
  width: auto;
  height: 110px;
  align-self: center;
  opacity: 0.92;
}
@media (max-width: 360px) {
  .couple-logo { height: 92px; }
}

/* Very small phones: pull margins in and shrink names so the two columns
   don't cramp or wrap. */
@media (max-width: 360px) {
  .couple-block { margin-left: 0; margin-right: 0; }
  .parents-name { font-size: 0.85rem; }
  .couple-name { font-size: 1.2rem; }
}
/* Phones (≤480px): the groom | monogram | bride row gets too cramped and a long
   Khmer name (e.g. "នីន ស្រីនុត") wraps or overflows the narrow side column.
   Stack the monogram on its own row with the two names side by side below, so
   each name has a full half-width and sits on one line. (English already does
   this below.) */
@media (max-width: 480px) {
  .couple-block {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "mono mono"
      "groom bride";
    gap: 8px 16px;
    align-items: start;
  }
  .couple-block > :nth-child(1) { grid-area: groom; }
  .couple-block > :nth-child(2) { grid-area: mono; }
  .couple-block > :nth-child(3) { grid-area: bride; }
  .couple-logo { height: 100px; margin: 0 auto 4px; align-self: center; }
  /* #invitation prefix so this beats the base `.couple-name` rule that appears
     later in the stylesheet. */
  #invitation .couple-name { font-size: 1.2rem; }
  .couple-role { margin-bottom: 10px; }
}
/* Very small phones (≤340px): tighten the font so both names still fit. */
@media (max-width: 340px) {
  #invitation .couple-name { font-size: 1.05rem; }
  .couple-logo { height: 92px; }
}
/* English names (e.g. "Nin Sreynuth") are longer than the Khmer, so the 3-column
   row clips them on phones. For English, stack the monogram above the two names
   (each gets a full half-width) on all phone widths. */
@media (max-width: 480px) {
  html[lang="en"] .couple-block {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "mono mono"
      "groom bride";
    gap: 6px 16px;
    align-items: start;
  }
  html[lang="en"] .couple-block > :nth-child(1) { grid-area: groom; }
  html[lang="en"] .couple-block > :nth-child(2) { grid-area: mono; }
  html[lang="en"] .couple-block > :nth-child(3) { grid-area: bride; }
  html[lang="en"] .couple-logo { height: 96px; margin: 0 auto 6px; align-self: center; }
  /* English names ("Nin Sreynuth") are longer than Khmer — size them down on
     phones so they don't dominate the block. */
  html[lang="en"] #invitation .couple-name { font-size: 1rem; }
}
@media (max-width: 340px) {
  html[lang="en"] #invitation .couple-name { font-size: 0.9rem; }
}
.couple-col { text-align: center; }
.couple-role {
  font-family: 'Siemreap', sans-serif;
  font-size: 0.8rem;
  letter-spacing: 2px;
  color: var(--cream);
  margin: 0 0 16px;
}
.couple-name {
  font-family: 'Moul', serif;
  font-size: 1.2rem;
  color: var(--gold);
  margin: 0;
  /* Never split a Khmer name mid-word (e.g. "ស្រីនុត" orphaning "ត" onto the
     next line). keep-all + normal overflow-wrap means it breaks only at the
     space between given and family name, if it must wrap at all. */
  word-break: keep-all;
  overflow-wrap: normal;
  /* Soft ivory lift instead of a dark drop-shadow (was too dark on light bg). */
  filter: drop-shadow(0 1px 2px rgba(255, 253, 247, 0.85));
}

/* Date + closing. */
.invite-date {
  font-family: 'Moul', serif;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--gold);
  margin: 10px 0 10px;
}
/* Event details block at the end of the letter. */
.invite-event {
  margin: 22px auto 0;
  padding: 0;
  text-shadow: 0 0 3px rgb(255 253 247 / 0%), 0 1px 2px rgba(255, 253, 247, 0.75);
}
.invite-event .evt-line { padding: 0; }
.evt-line {
  font-family: 'Siemreap', sans-serif;
  font-size: 0.92rem;
  line-height: 1.9;
  color: var(--blue-dark);
  margin: 0;
}
.evt-strong { font-weight: 700; color: var(--gold); }
.evt-big {
  font-size: 0.95rem;
  text-align: center;
}

/* Countdown */
.countdown {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
}
.countdown-box {
  background: var(--card-bg);
  border: 1px solid rgba(184, 147, 90, 0.35);
  border-radius: 16px;
  padding: 16px 18px;
  min-width: 70px;
  box-shadow: 0 6px 16px rgba(0,0,0,0.08);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.countdown-box:hover {
  transform: translateY(-4px);
  box-shadow: 0 10px 22px rgba(0,0,0,0.14);
}
.countdown-box span {
  display: block;
  font-size: 1.3rem;
  font-weight: bold;
  color: var(--gold-dark);
}
.countdown-box small { color: #bfae82; font-size: 0.7rem; }

/* Schedule */
.schedule-list { text-align: left; }
.schedule-day {
  /* Translucent light fill + soft green shadow. */
  background: rgba(255, 250, 242, 0.22);
  border: none;
  border-radius: 16px;
  padding: 20px;
  margin-bottom: 20px;
  /* Green-toned shadow (matches the watercolour) — larger, soft spread,
     more presence without going darker. */
  box-shadow: 0 8px 34px 6px rgba(79, 93, 74, 0.38);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.schedule-day:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 42px 8px rgba(79, 93, 74, 0.46);
}
.schedule-day-label {
  font-weight: bold;
  color: var(--gold-dark);
  margin-bottom: 12px;
  text-align: center;
  font-size: 0.9rem;
}
.schedule-item {
  display: flex;
  gap: 12px;
  padding: 6px 0;
  border-top: 1px dashed #e5e5e5;
  font-size: 0.9rem;
}
.schedule-item:first-of-type { border-top: none; }
.schedule-item span { font-weight: normal; }
/* Event text (2nd span) uses the Khmer body font. */
.schedule-item span:nth-child(2) { font-family: 'Siemreap', sans-serif; color: #3F2948; }
.schedule-time { min-width: 78px; font-weight: bold; color: #3F2948; font-size: 0.85rem; }

/* Venue */
.venue-card {
  background: var(--card-bg);
  border: 1px solid rgba(184, 147, 90, 0.35);
  border-radius: 16px;
  padding: 24px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.06);
  transition: box-shadow 0.3s ease;
}
.venue-card:hover { box-shadow: 0 10px 24px rgba(0,0,0,0.1); }
#venue-address-kh { font-size: 0.9rem; }
.venue-address-en { color: #bfae82; font-size: 0.9rem; }
.map-embed {
  margin-top: 18px;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 14px rgba(0,0,0,0.1);
}
.map-embed iframe { display: block; }
.venue-card a {
  display: inline-block;
  margin-top: 14px;
  color: var(--gold-dark);
  text-decoration: none;
  font-weight: bold;
  font-size: 0.85rem;
}

/* Gallery — editorial mosaic: rows cycle through a wide hero (1), then a
   pair (2), then a trio (3), repeating. Paginated in pages of 7. */
.gallery {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.gallery-row {
  display: grid;
  gap: 16px;
}
.gallery-row.row-1 { grid-template-columns: 1fr; }
.gallery-row.row-2 { grid-template-columns: 1fr 1fr; }
.gallery-row.row-3 { grid-template-columns: 1fr 1fr 1fr; }

/* Clean photo cards — no frame colour, no caption; just softly rounded
   images with a subtle shadow and hover lift/zoom. */
.gallery-frame {
  position: relative;
  margin: 0;                 /* reset the default <figure> 40px margin */
  width: 100%;               /* fill the grid column so rows have no gaps */
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 8px 20px rgba(0,0,0,0.15);
  cursor: pointer;
  line-height: 0;
  will-change: transform, opacity;
  transition: box-shadow 0.3s ease, transform 0.3s ease;
}
.gallery-frame:hover {
  box-shadow: 0 16px 30px rgba(0,0,0,0.25);
  transform: translateY(-3px);
  z-index: 2;
}
/* Each cell fills a fixed ratio so rows stay tidy regardless of photo size. */
.row-1 .gallery-frame { aspect-ratio: 16 / 10; }
.row-2 .gallery-frame { aspect-ratio: 3 / 4; }
.row-3 .gallery-frame { aspect-ratio: 3 / 4; }
/* Closing hero: double height (a tall full-width finale). */
.row-tall .gallery-frame { aspect-ratio: 4 / 5; }

.gallery-photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 14px;
  background: linear-gradient(135deg, #5a674f, #4f5d4a);
  transition: transform 0.5s ease;
}
.gallery-frame:hover .gallery-photo {
  transform: scale(1.05);
}

/* Placeholder shown for gallery slots whose photo file isn't added yet. */
.gallery-photo-missing { object-fit: cover; }

/* -------- Fullscreen lightbox -------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(30, 18, 24, 0.92);
  backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s ease, visibility 0.4s ease;
}
.lightbox.open {
  opacity: 1;
  visibility: visible;
}

.lightbox-stage {
  position: relative;
  max-width: min(92vw, 900px);
  max-height: 82vh;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.lightbox-img {
  max-width: 100%;
  max-height: 78vh;
  border-radius: 12px;
  border: 4px solid #fffdfa;
  box-shadow: 0 24px 60px rgba(0,0,0,0.55);
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.lightbox.open .lightbox-img { opacity: 1; transform: scale(1); }
/* Brief fade while switching between photos. */
.lightbox-img.swapping { opacity: 0; transform: scale(0.96); }

.lightbox-caption {
  margin: 14px 0 0;
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: 1rem;
  color: #e6d3ae;
  text-align: center;
  text-shadow: 0 1px 6px rgba(0,0,0,0.5);
}

.lightbox-counter {
  margin: 6px 0 0;
  font-size: 0.8rem;
  letter-spacing: 2px;
  color: rgba(255, 238, 244, 0.7);
  text-align: center;
}

.lightbox-close,
.lightbox-nav {
  position: absolute;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  color: #4a2f3a;
  background: rgba(255, 253, 250, 0.9);
  box-shadow: 0 4px 14px rgba(0,0,0,0.35);
  transition: transform 0.2s ease, background 0.2s ease;
}
.lightbox-close:hover,
.lightbox-nav:hover { transform: scale(1.1); background: #fff; }
.lightbox-close:active,
.lightbox-nav:active { transform: scale(0.95); }

.lightbox-close {
  top: -18px;
  right: -18px;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  font-size: 1.5rem;
  line-height: 1;
}

.lightbox-nav {
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  border-radius: 50%;
  font-size: 1.8rem;
  line-height: 1;
  padding-bottom: 4px;
}
.lightbox-nav:hover { transform: translateY(-50%) scale(1.1); }
.lightbox-prev { left: -20px; }
.lightbox-next { right: -20px; }

@media (max-width: 560px) {
  .lightbox-prev { left: 4px; }
  .lightbox-next { right: 4px; }
  .lightbox-close { top: -8px; right: 4px; }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox, .lightbox-img { transition: opacity 0.2s ease; }
  .lightbox-img { transform: none; }
  .lightbox.open .lightbox-img { transform: none; }
}

/* RSVP */
.rsvp-deadline { color: var(--pink); margin-bottom: 20px; font-size: 0.85rem; white-space: pre-line; }
.rsvp-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--card-bg);
  border: 1px solid rgba(184, 147, 90, 0.35);
  padding: 24px;
  border-radius: 16px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.06);
  text-align: left;
  font-size: 0.85rem;
}
.radio-option { display: flex; align-items: center; gap: 8px; }
.rsvp-form input[type="text"],
.rsvp-form .attend-select,
.wish-form input,
.wish-form textarea {
  padding: 12px;
  border: 1px solid #dce7ee;
  border-radius: 10px;
  font-family: inherit;
  width: 100%;
  /* Pin colours so they never flip with the device's dark mode. */
  background: #ffffff;
  color: #3f4b3b;
}

/* Attendance dropdown — same box as the name field, with a custom chevron. */
.rsvp-form .attend-select {
  font-size: 0.7rem; /* Moul, same size as the Guests label */
  color: #8a9482;    /* sage-grey — match the Guests label */
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%238a9482' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px;
  padding-right: 36px;
}
.rsvp-form .attend-select:required:invalid { color: #8a9482; } /* placeholder look */
.rsvp-form .attend-select option { color: #3f4b3b; }
.rsvp-form .attend-select option[value=""] { color: #8a9482; }
.rsvp-form input[type="text"]::placeholder,
.wish-form input::placeholder,
.wish-form textarea::placeholder { color: #8a9482; }

/* Guest-count stepper — a white rounded field matching the name input, with
   round − / + buttons. */
.guest-count-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 10px 7px 14px;
  border: 1px solid #dce7ee;
  border-radius: 10px;
  background: #ffffff;
}
.gc-label {
  font-family: inherit;
  font-size: 0.7rem; /* Moul, same size everywhere */
  color: #8a9482;    /* sage-grey — the reference label colour */
}
.gc-stepper { display: flex; align-items: center; gap: 6px; }
.rsvp-form .gc-btn {
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
  padding: 0;
  border-radius: 50%;
  border: 1px solid #dce7ee;
  background: #f3f7f1;
  color: var(--sage-dark);
  font-size: 1.25rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: none;
  transition: background 0.15s ease, transform 0.15s ease;
}
.rsvp-form .gc-btn:hover { background: #e7efe3; transform: none; box-shadow: none; }
.rsvp-form .gc-btn:active { transform: scale(0.9); }
.gc-input {
  width: 34px;
  text-align: center;
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: 0.7rem; /* Moul, same size as the Guests label */
  color: #8a9482;    /* sage-grey — match the Guests label */
  padding: 0;
  -moz-appearance: textfield;
}
.gc-input::-webkit-outer-spin-button,
.gc-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.rsvp-form button,
.wish-form button {
  background: var(--sage-dark);
  color: #fff;
  border: none;
  padding: 12px;
  border-radius: 999px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.9rem;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.rsvp-form button:hover,
.wish-form button:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 18px rgba(92,107,72,0.4);
}

/* Submit button: compact and centred, not full width. */
.rsvp-form button[type="submit"],
.wish-form button[type="submit"] {
  align-self: center;
  width: auto;
  padding: 12px 48px;
  margin-top: 4px;
}

.contact-row {
  display: flex;
  gap: 16px;
  justify-content: center;
  margin-top: 20px;
  font-size: 0.85rem;
}
.contact-row a {
  color: var(--blue-dark);
  text-decoration: none;
  background: var(--card-bg);
  border: 1px solid rgba(184, 147, 90, 0.35);
  padding: 10px 18px;
  border-radius: 999px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
/* Telegram-blue text + arrow (overrides the global gold !important). */
#invitation .contact-row a { color: #229ED9 !important; }
/* ➢ arrow tilted up-right, like the Telegram send plane. */
.contact-row a::before {
  content: "\27A2";
  display: inline-block;
  transform: rotate(-45deg);
  margin-right: 10px;
  font-size: 1.5em;
  line-height: 1;
  vertical-align: -0.15em;
}

.gift-qr-link {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-top: 16px;
  text-decoration: none;
}
.gift-qr-card {
  background: var(--card-bg);
  border: 1px solid rgba(184, 147, 90, 0.35);
  padding: 16px;
  border-radius: 16px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.08);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.gift-qr-link:hover .gift-qr-card {
  transform: translateY(-4px);
  box-shadow: 0 12px 26px rgba(0,0,0,0.14);
}
.gift-qr { display: block; max-width: 260px; width: 100%; }
.gift-qr-download {
  color: var(--gold-dark);
  font-size: 0.85rem;
  font-weight: bold;
}

#gift-section p { font-size: 0.95rem; }
.wish-form { display: flex; flex-direction: column; gap: 12px; text-align: left; font-size: 0.9rem; background: var(--card-bg); padding: 24px; border-radius: 16px; }

/* Footer */
.footer {
  position: relative;
  z-index: 1;
  text-align: center;
  font-size: 0.9rem;
  /* Big bottom padding leaves room for the flower band below the text, so
     no text sits over the flowers. */
  padding: 48px 24px 300px;
  /* Ivory halo keeps the dark palette text readable on the sky above. */
  text-shadow: 0 0 3px rgba(255, 253, 247, 0.9), 0 1px 2px rgba(255, 253, 247, 0.75);
}
/* Purple flower band along the very bottom of the last page — decorative
   only, sits below the footer text (fades up into the sky backdrop). */
.footer::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 270px;
  z-index: -1;
  pointer-events: none;
  background: url('/images/footer-bg.jpg') center bottom / cover no-repeat;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 90px);
  mask-image: linear-gradient(180deg, transparent 0, #000 90px);
}
.thank-you {
  max-width: 600px;
  margin: 16px auto;
  line-height: 1.8;
  color: #5c7484;
}
.footer-love { color: var(--pink); margin-top: 20px; }
.footer-names { font-family: 'Moul', serif; font-size: 1.1rem; margin: 6px 0; }
.footer-date { color: #bfae82; }
.back-link {
  display: inline-block;
  margin-top: 20px;
  color: var(--gold-dark);
  text-decoration: none;
}

/* More breathing room between the footer's blocks:
   thank-you/names/date → "Contact us" + Telegram buttons → back link. */
.footer .contact-label { margin: 44px 0 14px; font-size: 0.95rem; }
.footer .contact-row { margin-top: 0; }
.footer .back-link { margin-top: 44px; }

@media (max-width: 480px) {
  .gallery { column-count: 2; }
  .banner-title { font-size: 1.3rem; }
  .cover-name { font-size: 1.15rem; }
}

/* ============================================================
   Language toggle (EN / ខ្មែរ) — top-left pill, mirrors the mute
   button on the right. Switches the whole page on click.
   ============================================================ */
.lang-toggle {
  position: fixed;
  top: 16px;
  left: max(16px, calc(50vw - var(--app-max) / 2 + 16px));
  z-index: 21;
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.88);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.lang-toggle button {
  border: none;
  background: transparent;
  color: #5c6b48;
  font-family: inherit;
  font-size: 0.72rem;
  line-height: 1;
  padding: 6px 11px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}
.lang-toggle button.active {
  background: var(--sage-dark);
  color: #fff;
}

