/* ═══════════════════════════════════════════════════════════════════
   CASTLE SOIREE · Princess Birthday Invitation — styles.css
   ───────────────────────────────────────────────────────────────────
   HOUSE UX: natural scrolling. Sections are full-viewport "scenes"
   stacked in normal document flow — no app shell, no wheel/touch
   hijacking. A fixed header (desktop section pills · mobile burger
   sheet), a floating dock and a scroll-spy are added by main.js; all
   of that chrome is sized from the --header-h / --dock-h tokens so
   nothing ever drifts.

   Conventions:
     · Geometry flows from tokens: --header-h locks the header height;
       the cover cap and every anchor offset derive from it.
     · Cover type scales on --su, a fluid unit that FREEZES once the
       viewport's smaller edge passes ~650px (~700px-tall phones stop
       growing), so mid-size phones never lose cover content.
     · Without JS the document reads as a plain stacked page; the dock,
       burger, pills and progress bar simply don't appear.
     · prefers-reduced-motion and @media print are supported. Print
       restores everything the empty-state audit visually hid
       (.is-empty / .fit-hidden).
   ═══════════════════════════════════════════════════════════════════ */

/* ── Design tokens ─────────────────────────────────────────────── */
:root {
  --blush:      #fff6fa;
  --blush-2:    #fde9f3;
  --blush-3:    #f9d8e9;
  --rose:       #e0537d;
  --rose-deep:  #c0446e;
  --plum:       #6d3a57;
  --plum-ink:   #55304a;
  --gold:       #c99a41;
  --gold-deep:  #a97c2e;
  --gold-light: #f3dd9a;
  --cream:      #fffdf8;
  --card:       rgba(255, 253, 248, 0.88);
  --line:       rgba(201, 154, 65, 0.35);
  --line-soft:  rgba(201, 154, 65, 0.22);
  --shadow-soft: 0 10px 30px -12px rgba(192, 68, 110, 0.35);
  --shadow-gold: 0 8px 22px -8px rgba(169, 124, 46, 0.55);

  --font-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --font-script:  'Great Vibes', 'Segoe Script', 'Brush Script MT', cursive;
  --font-body:    'Quicksand', 'Avenir Next', 'Segoe UI', system-ui, sans-serif;

  --ease-spring: cubic-bezier(0.22, 1, 0.36, 1);

  /* Geometry tokens — the header height is LOCKED here and enforced on
     the real header below; the cover cap and anchor offsets derive
     from it. */
  --header-h: calc(54px + env(safe-area-inset-top, 0px));
  --dock-h: 58px;

  /* Cover sizing unit: fluid with the viewport's smaller edge but
     FROZEN once that edge passes ~650px, so mid-size phones, tall
     phones and desktops stop scaling and never lose cover content. */
  --su: min(1vmin, 6.5px);

  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
}

/* ── Reset & base ──────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth; /* anchor jumps glide; reduced-motion turns it off */
  /* Anchor/deep-link jumps land their target just below the fixed header.
     Derived ONLY from --header-h; no scroll-margin on .panel, or the two
     would add up and overshoot. */
  scroll-padding-top: calc(var(--header-h) + 10px);
}

body {
  margin: 0;
  padding-top: var(--header-h); /* clear the fixed header */
  background: var(--blush-2);
  color: var(--plum-ink);
  font-family: var(--font-body);
  font-weight: 500;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden; /* §nothing-cut-off: never a sideways scroll */
}
html:not(.js) body { padding-top: 0; }

::selection { background: rgba(224, 83, 125, 0.25); }

img, svg { display: block; max-width: 100%; }

button { font: inherit; cursor: pointer; }

:focus-visible {
  outline: 3px solid rgba(224, 83, 125, 0.55);
  outline-offset: 2px;
  border-radius: 6px;
}

.svg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

[hidden] { display: none !important; } /* keep the hidden attr reliable */

/* Empty-state audit utility: visually hidden only — kept in the DOM and
   restored in print (see @media print at the end). */
.is-empty { display: none !important; }

/* Cover-fit trim utility: decorations hidden by initCoverFit() so the
   cover always fits one screen. Nothing is removed from the DOM; print
   restores every trimmed layer. */
.fit-hidden { display: none !important; }

.skip-link {
  position: fixed;
  top: calc(-60px + var(--safe-t));
  left: 12px;
  z-index: 300;
  padding: 10px 16px;
  background: var(--plum);
  color: var(--blush);
  font-size: 12px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  border-radius: 0 0 10px 10px;
  text-decoration: none;
  transition: top 0.2s var(--ease-spring);
}
.skip-link:focus { top: var(--safe-t); }

/* Custom scrollbars wherever a region may internally scroll — on-palette:
   a slim rose/gold bar. (Firefox uses the scrollbar-color shorthand.) */
.mobile-menu__scroller,
.panel--cover,
.dock {
  scrollbar-width: thin;
  scrollbar-color: rgba(224, 83, 125, 0.45) transparent;
}
.mobile-menu__scroller::-webkit-scrollbar,
.panel--cover::-webkit-scrollbar,
.dock::-webkit-scrollbar { width: 8px; height: 8px; }
.mobile-menu__scroller::-webkit-scrollbar-track,
.panel--cover::-webkit-scrollbar-track,
.dock::-webkit-scrollbar-track { background: transparent; }
.mobile-menu__scroller::-webkit-scrollbar-thumb,
.panel--cover::-webkit-scrollbar-thumb,
.dock::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, rgba(224, 83, 125, 0.5), rgba(201, 154, 65, 0.5));
  border-radius: 8px;
  border: 2px solid transparent;
  background-clip: padding-box;
}

/* ═══════════════════════════════════════════════════════════════════
   SCENES — every section is its own full-viewport "scene" in normal
   flow. Tall content simply grows; the whole page scrolls natively.
   ═══════════════════════════════════════════════════════════════════ */
.panel {
  position: relative;
  display: flex;
  flex-direction: column;
  /* Every section is a full-viewport "scene": taller ones simply grow;
     shorter ones breathe across the whole viewport, and late sections
     can always scroll far enough to land exactly below the header. */
  min-height: calc(100vh - var(--header-h));
  min-height: calc(100dvh - var(--header-h));
}
.sheet {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 620px;
  margin: auto; /* vertical centre when slack; flows when tight */
  padding:
    clamp(20px, calc(var(--su) * 5), 40px)
    22px
    clamp(30px, calc(var(--su) * 6), 48px);
  display: flex;
  flex-direction: column;
  align-items: center;
}
.sheet::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: 1.5px solid var(--line);
  border-radius: 18px;
  pointer-events: none;
}

.panel--letter,
.panel--details,
.panel--memories {
  background:
    radial-gradient(120% 60% at 50% -8%, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0) 55%),
    linear-gradient(180deg, var(--blush), var(--blush-2) 60%, var(--blush-3));
}
.panel--rsvp {
  background:
    radial-gradient(120% 60% at 50% -8%, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0) 55%),
    linear-gradient(180deg, var(--blush), var(--blush-2) 60%, var(--blush-3));
}
.panel--guestbook {
  background:
    radial-gradient(120% 60% at 50% -8%, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0) 55%),
    linear-gradient(180deg, var(--blush-3), var(--blush-2) 55%, var(--blush));
}
.panel--free {
  background:
    radial-gradient(120% 60% at 50% -8%, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0) 55%),
    linear-gradient(180deg, var(--blush), var(--blush-2) 60%, var(--blush-3));
}

/* ── Sparkles ──────────────────────────────────────────────────── */
.sparkle-field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.sparkle {
  position: absolute;
  color: rgba(224, 83, 125, 0.55);
  animation: twinkle 2.8s var(--ease-spring) infinite;
  will-change: opacity, transform;
}
@keyframes twinkle {
  0%, 100% { opacity: 0.15; transform: scale(0.7) rotate(0deg); }
  50%      { opacity: 0.9;  transform: scale(1.15) rotate(22deg); }
}

/* ── Shared type bits ──────────────────────────────────────────── */
.eyebrow {
  margin: 0;
  font-size: clamp(0.66rem, calc(var(--su) * 2.05), 0.82rem);
  font-weight: 700;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.crown { width: clamp(54px, 9vw, 74px); height: auto; margin: 0 auto 6px; filter: drop-shadow(0 4px 8px rgba(169, 124, 46, 0.35)); }
.crown--sm { width: 46px; margin-bottom: 4px; }

.name {
  display: inline-block;
  font-family: var(--font-script);
  font-weight: 400;
  background: linear-gradient(160deg, #f7e7b3 0%, #e0bb6d 40%, #b9862f 78%, #efd690 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 3px 0 rgba(169, 124, 46, 0.28));
  overflow-wrap: anywhere;
}

.sheet__head { text-align: center; margin-bottom: 18px; }
.sheet__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5.4vw, 2rem);
  font-weight: 700;
  color: var(--plum);
}
.sheet__title:focus { outline: none; }
.sheet__sub {
  margin: 8px 0 0;
  font-size: clamp(0.82rem, 2.6vw, 0.94rem);
  color: var(--plum);
}

/* ═══════════════ SCENE 1 · COVER = exactly one screen ═══════════════
   Capped below the header, vertically centred, fully visible at load.
   Internal scroll is a last-resort valve only (initCoverFit trims
   decorations first — documented order in main.js). */
.panel--cover {
  background:
    radial-gradient(90% 50% at 50% 112%, rgba(243, 221, 154, 0.5), rgba(243, 221, 154, 0) 60%),
    linear-gradient(180deg, #ffeaf4 0%, #fde0ee 42%, #f7c9de 78%, #f2b9d3 100%);
  min-height: calc(100vh - var(--header-h));
  min-height: calc(100dvh - var(--header-h));
  max-height: calc(100vh - var(--header-h));
  max-height: calc(100dvh - var(--header-h));
  overflow-y: auto;   /* safety valve for extreme viewports / huge names */
  overflow-x: hidden;
}

.cover {
  position: relative;
  z-index: 1;
  width: 100%;
  margin: auto; /* keeps the composition centred when the valve scrolls */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(12px, calc(var(--su) * 3), 26px) 20px;
}

.castle {
  width: clamp(200px, calc(var(--su) * 66), 330px);
  height: auto;
  filter: drop-shadow(0 10px 22px rgba(192, 68, 110, 0.28));
  margin-top: -6px;
}

/* ── Optional photo backdrops (cover & farewell) ────────────────
   A soft, blurred photo sits behind the scene, tinted by a rose
   gradient overlay so the castle / names / text stay readable. The
   negative z-index keeps it above the scene gradient but below every
   piece of content (.cover and .closing are the stacking contexts).
   Removing the wrapper restores the classic gradient. */
.cover-photo,
.closing-photo {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.cover-photo__img,
.closing-photo__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(10px) saturate(0.92);
  transform: scale(1.08); /* keep the blur from showing edge fringing */
}
.cover-photo__overlay,
.closing-photo__overlay {
  position: absolute;
  inset: 0;
}
.cover-photo__overlay {
  background:
    radial-gradient(120% 90% at 50% 16%, rgba(255, 246, 250, 0.72), rgba(255, 246, 250, 0) 48%),
    linear-gradient(180deg, rgba(255, 234, 244, 0.76), rgba(247, 201, 222, 0.82) 58%, rgba(242, 185, 211, 0.9));
}
.closing-photo__overlay {
  background:
    radial-gradient(120% 90% at 50% 24%, rgba(255, 246, 250, 0.8), rgba(255, 246, 250, 0) 48%),
    linear-gradient(180deg, rgba(255, 246, 250, 0.8), rgba(249, 216, 233, 0.85) 55%, rgba(249, 216, 233, 0.9));
}
/* Backdrop photos open full size too (click-only; JS wires it). */
html.js:not(.lb-off) .photo-bg .js-cover-img { pointer-events: auto; cursor: zoom-in; }
html.lb-off .photo-bg .js-cover-img { pointer-events: none; }

/* Portrait slot — gold-ringed photo medallion. A <button> so tapping
   it opens the photo full size in the viewer (main.js); the crown
   monogram is the empty-state fallback: it stays hidden while a photo
   (<img>) is present and shows when the image is removed or fails to
   load (then the button stops being clickable). */
.portrait {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  padding: 5px;
  width: clamp(88px, calc(var(--su) * 25), 118px);
  aspect-ratio: 1;
  border-radius: 50%;
  margin-top: -26px;
  z-index: 2;
  background: linear-gradient(160deg, var(--gold-light), var(--gold-deep));
  box-shadow: var(--shadow-gold), 0 0 0 4px rgba(255, 255, 255, 0.55);
  display: grid;
  place-items: center;
  cursor: zoom-in;
}
.portrait > * { grid-area: 1 / 1; }
.portrait--empty {
  background:
    radial-gradient(circle at 35% 28%, rgba(255, 255, 255, 0.95), rgba(255, 255, 255, 0) 55%),
    linear-gradient(160deg, var(--gold-light), var(--gold) 70%, var(--gold-deep));
  cursor: default;
}
html.lb-off .portrait { cursor: default; }
/* Zoom badge — a quiet hint that the portrait can be tapped to view
   it full size; hidden in the monogram (empty) state and when the
   lightbox feature is off (html.lb-off). */
.portrait__zoom {
  justify-self: end;
  align-self: end;
  width: 26px;
  height: 26px;
  margin: 0 7px 7px 0;
  border-radius: 50%;
  background: rgba(255, 253, 248, 0.92);
  color: var(--gold-deep);
  display: grid;
  place-items: center;
  box-shadow: var(--shadow-gold);
  opacity: 0;
  transition: opacity 0.2s;
  pointer-events: none;
}
.portrait__zoom svg { width: 14px; height: 14px; }
.portrait:not(.portrait--empty):hover .portrait__zoom,
.portrait:not(.portrait--empty):focus-visible .portrait__zoom { opacity: 1; }
html.lb-off .portrait__zoom { display: none; }
.portrait__crown {
  width: 44%;
  height: auto;
  display: none;
}
.portrait__hint {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  display: none;
}
.portrait--empty .portrait__crown,
.portrait--empty .portrait__hint { display: block; }
/* When a photo fills the medallion */
.portrait__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  border: 3px solid var(--blush);
}

.cover__copy { margin-top: clamp(8px, calc(var(--su) * 2.4), 20px); }

.cover__title { margin: 6px 0 0; line-height: 1.06; }
.cover__title .name { font-size: clamp(2.7rem, calc(var(--su) * 14.5), 5.2rem); line-height: 1.05; }
.cover__title .name--second { font-size: clamp(1.8rem, calc(var(--su) * 9), 3.2rem); }

.cover__sub {
  margin: 10px 0 0;
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(0.9rem, calc(var(--su) * 3), 1.1rem);
  color: var(--plum);
}
.cover__sub .age {
  font-family: var(--font-script);
  font-style: normal;
  font-size: 1.5em;
  color: var(--rose-deep);
}

.cover__date {
  margin: 12px 0 0;
  font-size: clamp(0.78rem, calc(var(--su) * 2.7), 0.96rem);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold-deep);
  background: rgba(255, 253, 248, 0.7);
  border: 1px solid var(--line);
  border-radius: 999px;
  display: inline-block;
  padding: 7px 18px;
}

.cover__hint {
  margin: clamp(12px, calc(var(--su) * 2.6), 22px) 0 0;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: rgba(109, 58, 87, 0.65);
  animation: hint-bob 2.8s ease-in-out infinite;
}
@keyframes hint-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(4px); }
}

/* Last-resort squeeze when even the trimmed cover spills a few pixels:
   shave breathing room instead of letting content clip. */
.cover-squeeze .cover { padding-top: 6px; padding-bottom: 6px; }
.cover-squeeze .cover__copy { margin-top: 4px; }

/* ── Buttons ───────────────────────────────────────────────────── */
.btn-gold {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  border: 0;
  border-radius: 999px;
  padding: 14px 30px;
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 60%, var(--gold-deep));
  color: #fff;
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  box-shadow: var(--shadow-gold);
  transition: transform 0.18s var(--ease-spring), box-shadow 0.18s;
}
.btn-gold:hover { transform: translateY(-2px); box-shadow: 0 12px 26px -8px rgba(169, 124, 46, 0.7); }
.btn-gold:active { transform: translateY(0); }
.btn-gold:disabled { opacity: 0.65; cursor: default; transform: none; }
.btn-gold__star { width: 15px; height: 15px; fill: currentColor; }

.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  padding: 12px 26px;
  background: rgba(255, 253, 248, 0.75);
  color: var(--plum);
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  transition: border-color 0.18s, color 0.18s, transform 0.18s var(--ease-spring);
}
.btn-ghost:hover { border-color: var(--rose); color: var(--rose-deep); transform: translateY(-2px); }

/* ── Scene 2 · The letter ──────────────────────────────────────── */
.letter {
  width: 100%;
  max-width: 520px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: clamp(20px, 5vw, 30px);
  box-shadow: var(--shadow-soft);
  font-size: clamp(0.92rem, 2.8vw, 1.02rem);
}
.letter p { margin: 0 0 14px; color: var(--plum-ink); }
.letter p:last-of-type { margin-bottom: 0; }

.letter__dropcap {
  float: left;
  font-family: var(--font-display);
  font-size: 3.3em;
  line-height: 0.85;
  padding: 4px 10px 0 0;
  background: linear-gradient(160deg, var(--gold-light), var(--gold-deep));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.letter__names {
  font-family: var(--font-script);
  font-style: normal;
  font-size: 1.35em;
  color: var(--rose-deep);
}

.letter__date strong { color: var(--rose-deep); font-weight: 700; }

.letter__sig {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  text-align: center;
}
.letter__sig-name {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 0.9rem;
  color: var(--plum);
}
.letter__sig-script {
  font-family: var(--font-script);
  font-size: clamp(1.5rem, 5vw, 1.9rem);
  color: var(--rose-deep);
}

.letter__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 22px;
}

/* ── Scene 3 · Details ─────────────────────────────────────────── */
.countdown { text-align: center; margin-bottom: 20px; width: 100%; }
.countdown__label {
  margin: 0 0 10px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.countdown__chips {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  max-width: 400px;
  margin: 0 auto;
}
.chip {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 10px 4px 9px;
  box-shadow: var(--shadow-soft);
}
.chip__num {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 5vw, 1.7rem);
  font-weight: 700;
  color: var(--rose-deep);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.chip__label {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(109, 58, 87, 0.7);
}

.facts {
  width: 100%;
  max-width: 520px;
  margin: 0 0 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.fact {
  display: flex;
  gap: 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: var(--shadow-soft);
}
.fact__icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(243, 221, 154, 0.5);
  border: 1px solid var(--line-soft);
  display: grid;
  place-items: center;
  color: var(--gold-deep);
}
.fact__icon svg { width: 22px; height: 22px; }
.fact dd { margin: 0; }
.fact__label {
  margin: 0;
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.fact__value {
  margin: 3px 0 0;
  font-weight: 600;
  color: var(--plum);
  overflow-wrap: anywhere;
}
/* Value lines are block segments so emptied ones vanish cleanly
   without leaving stray commas or line breaks behind. */
.fact__line { display: block; }
.fact__note {
  margin: 5px 0 0;
  font-size: 0.8rem;
  font-style: italic;
  color: rgba(109, 58, 87, 0.75);
}

/* Add to Calendar (.ics export lives in main.js) */
.calendar-cta { text-align: center; margin: 0 0 22px; }
.cal-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 24px;
  border: 1.5px solid var(--gold);
  border-radius: 999px;
  background: rgba(255, 253, 248, 0.85);
  color: var(--plum);
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  box-shadow: var(--shadow-gold);
  transition: transform 0.18s var(--ease-spring), background-color 0.2s, color 0.2s, box-shadow 0.2s;
}
.cal-btn svg { width: 17px; height: 17px; }
.cal-btn:hover {
  background: var(--plum);
  color: var(--blush);
  transform: translateY(-2px);
  box-shadow: 0 14px 30px -14px rgba(109, 58, 87, 0.7);
}
.cal-btn:disabled { filter: grayscale(0.6); cursor: default; transform: none; }
.cal-hint {
  margin: 8px 0 0;
  font-size: 0.74rem;
  letter-spacing: 0.05em;
  color: rgba(109, 58, 87, 0.75);
}

.timeline {
  width: 100%;
  max-width: 520px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 20px 20px 8px;
  box-shadow: var(--shadow-soft);
}
.timeline__title {
  margin: 0 0 14px;
  text-align: center;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--plum);
}
.timeline__list { list-style: none; margin: 0; padding: 0; }
.timeline__item {
  display: flex;
  gap: 14px;
  padding: 0 0 14px;
  position: relative;
}
.timeline__item::before {
  content: "";
  position: absolute;
  left: 44px;
  top: 26px;
  bottom: 0;
  width: 2px;
  background: linear-gradient(180deg, var(--gold-light), var(--line-soft));
}
.timeline__item:last-child::before { display: none; }
.timeline__time {
  flex: 0 0 auto;
  min-width: 44px;
  height: 26px;
  display: grid;
  place-items: center;
  padding: 0 10px;
  white-space: nowrap;
  border-radius: 999px;
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 70%, var(--gold-deep));
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.timeline__text { font-size: 0.88rem; color: var(--plum-ink); }
.timeline__text strong { color: var(--plum); }

.sheet__cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  text-align: center;
  margin-top: 24px;
}

/* ── Optional party banner / flyer (Royal Plan scene) ──────────
   A framed image slot for an existing party poster/flyer. Clicking
   it opens the image full size; an optional data-link adds an
   "open the party page" button under the banner. */
.banner-wrap {
  width: 100%;
  max-width: 520px;
  margin-bottom: 22px;
  text-align: center;
}
.banner { margin: 0; }
.banner__btn {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 18px;
  overflow: hidden;
  background: var(--card);
  box-shadow: var(--shadow-soft);
  aspect-ratio: 2 / 1;
  cursor: zoom-in;
  transition: transform 0.2s var(--ease-spring), box-shadow 0.2s;
}
.banner__btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 30px -12px rgba(192, 68, 110, 0.45);
}
.banner__btn:active { transform: translateY(0); }
html.lb-off .banner__btn { cursor: default; }
.banner__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.banner__zoom {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: rgba(255, 253, 248, 0.92);
  color: var(--gold-deep);
  display: grid;
  place-items: center;
  box-shadow: var(--shadow-gold);
  opacity: 0;
  transition: opacity 0.2s;
}
.banner__zoom svg { width: 18px; height: 18px; }
.banner__btn:hover .banner__zoom,
.banner__btn:focus-visible .banner__zoom { opacity: 1; }
html.lb-off .banner__zoom { display: none; }
.banner__caption {
  margin-top: 8px;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 0.82rem;
  color: var(--plum);
  opacity: 0.85;
}
.banner__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--rose-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.banner__link:hover { color: var(--plum); }

/* ── Scene 4 · Gallery (photo showcase) ─────────────────────── */
.gallery {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  max-width: 520px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}
@media (min-width: 820px) {
  .gallery { grid-template-columns: repeat(3, 1fr); max-width: 620px; }
}
.gallery__item { margin: 0; }
.gallery__btn {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 16px;
  overflow: hidden;
  background: var(--card);
  box-shadow: var(--shadow-soft);
  aspect-ratio: 4 / 3;
  cursor: zoom-in;
  transition: transform 0.2s var(--ease-spring), box-shadow 0.2s;
}
.gallery__btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 30px -12px rgba(192, 68, 110, 0.45);
}
.gallery__btn:active { transform: translateY(0); }
html.lb-off .gallery__btn { cursor: default; }
.gallery__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.gallery__caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 26px 12px 9px;
  background: linear-gradient(180deg, rgba(85, 48, 74, 0), rgba(85, 48, 74, 0.78));
  color: var(--blush);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-align: left;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
}

/* ── Scene 5 · Party film (optional video scene) ───────────────
   The card shows a poster with a gold play button; clicking it
   opens the player full size in the zoomable viewer (built by
   main.js) — or plays inline when the lightbox feature is off.
   The whole scene hides itself when no video URL is set. */
.video-card {
  position: relative;
  display: block;
  width: 100%;
  max-width: 520px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 18px;
  overflow: hidden;
  background: var(--card);
  box-shadow: var(--shadow-soft);
  aspect-ratio: 16 / 9;
  transition: transform 0.2s var(--ease-spring), box-shadow 0.2s;
}
.video-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 30px -12px rgba(192, 68, 110, 0.45);
}
.video-card:active { transform: translateY(0); }
.video-card__poster {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.video-card__shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(85, 48, 74, 0.04), rgba(85, 48, 74, 0.42));
  pointer-events: none;
}
.video-card__play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: clamp(58px, 16vw, 74px);
  height: clamp(58px, 16vw, 74px);
  border-radius: 50%;
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 60%, var(--gold-deep));
  color: #fff;
  display: grid;
  place-items: center;
  box-shadow: var(--shadow-gold), 0 0 0 6px rgba(255, 253, 248, 0.35);
  transition: transform 0.2s var(--ease-spring);
}
.video-card__play svg { width: 28px; height: 28px; margin-left: 4px; }
.video-card:hover .video-card__play { transform: translate(-50%, -50%) scale(1.08); }
.video-card__label {
  position: absolute;
  left: 50%;
  bottom: 14px;
  transform: translateX(-50%);
  white-space: nowrap;
  color: var(--blush);
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  background: rgba(85, 48, 74, 0.55);
  border: 1px solid rgba(255, 253, 248, 0.4);
  border-radius: 999px;
  padding: 7px 16px;
}
/* Inline player used when MEDIA_LIGHTBOX = false swaps the poster. */
.video-card.is-playing { aspect-ratio: 16 / 9; }
.video-card iframe,
.video-card video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  background: #000;
}

/* ── Scene 6 · RSVP form ───────────────────────────────────────── */
.rsvp-form { width: 100%; max-width: 480px; }

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 15px;
}
.field label,
.field legend {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--plum);
}
.field legend { padding: 0; }
.field .opt { font-weight: 500; font-style: normal; opacity: 0.62; font-size: 0.88em; }

.form-control {
  width: 100%;
  padding: 12px 14px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--cream);
  color: var(--plum-ink);
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 500;
  transition: border-color 0.2s, box-shadow 0.2s;
  appearance: none;
  -webkit-appearance: none;
}
.form-control::placeholder { color: rgba(109, 58, 87, 0.4); }
.form-control:focus {
  outline: none;
  border-color: var(--rose);
  box-shadow: 0 0 0 4px rgba(224, 83, 125, 0.14);
}
textarea.form-control { resize: vertical; min-height: 76px; }

select.form-control {
  background-image:
    linear-gradient(45deg, transparent 50%, var(--gold-deep) 50%),
    linear-gradient(135deg, var(--gold-deep) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
  padding-right: 36px;
}

.error {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  color: #d63a6b;
  margin-top: 2px;
}

.field--attending { gap: 8px; }
.attend-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.attend-option input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}
.attend-option__face {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px 10px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  color: var(--plum);
  font-size: 0.84rem;
  text-align: center;
  transition: transform 0.18s var(--ease-spring), border-color 0.18s, box-shadow 0.18s, background 0.18s, color 0.18s;
}
.attend-option__face svg { width: 26px; height: 26px; }
.attend-option input:checked + .attend-option__face {
  border-color: transparent;
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 70%, var(--gold-deep));
  color: #fff;
  box-shadow: var(--shadow-gold);
  transform: translateY(-1px);
}
.attend-option input:focus-visible + .attend-option__face {
  outline: 3px solid rgba(224, 83, 125, 0.55);
  outline-offset: 2px;
}
.attend-option input:focus-visible:not(:checked) + .attend-option__face { border-color: var(--rose); }

.rsvp-form.is-declined .js-attending-fields {
  opacity: 0.45;
  transition: opacity 0.25s;
}

.rsvp-actions { margin-top: 6px; text-align: center; }

.loading {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 14px;
  font-size: 0.84rem;
  color: var(--plum);
}
.loading__spinner {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2.5px solid rgba(201, 154, 65, 0.3);
  border-top-color: var(--gold-deep);
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.sheet__foot-note {
  margin: 22px 0 0;
  font-size: 0.76rem;
  text-align: center;
  color: rgba(109, 58, 87, 0.75);
  max-width: 380px;
}

/* ── Scene 7 · Guestbook (platform-injected markup) ────────────── */
.guestbook-body { width: 100%; max-width: 480px; }

.guestbook-form { display: flex; flex-direction: column; gap: 14px; }

#guestbookForm {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: var(--shadow-soft);
}
#guestbookForm .form-group { display: flex; flex-direction: column; gap: 6px; }
#guestbookForm label { font-size: 0.8rem; font-weight: 700; letter-spacing: 0.04em; color: var(--plum); }
#guestbookForm .form-control {
  padding: 11px 13px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--cream);
  color: var(--plum-ink);
  font-family: var(--font-body);
  font-size: 0.95rem;
}
#guestbookForm textarea.form-control { min-height: 84px; resize: vertical; }
#guestbookForm .error { display: block; font-size: 0.78rem; font-weight: 600; color: #d63a6b; margin-top: 2px; }
.guestbook-chapta { min-height: 0; }

#guestbookForm button[type="submit"] {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  align-self: center;
  margin: 8px auto 0;
  border: 0;
  border-radius: 999px;
  padding: 13px 30px;
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 60%, var(--gold-deep));
  color: #fff;
  font-size: 0.92rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  box-shadow: var(--shadow-gold);
  transition: transform 0.18s var(--ease-spring);
}
#guestbookForm button[type="submit"]:hover { transform: translateY(-2px); }
/* The platform's injected markup uses utility classes this template does
   not ship — centre them so the injected form matches the RSVP design. */
#guestbookForm .d-flex { display: flex; justify-content: center; }
#guestbookForm .btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 0;
  border-radius: 999px;
  padding: 13px 30px;
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 60%, var(--gold-deep));
  color: #fff;
  font-size: 0.92rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  box-shadow: var(--shadow-gold);
}

.loading-guestbook { text-align: center; font-size: 0.84rem; color: var(--plum); }

.guestbook-wrap {
  margin-top: 18px !important;
  border-top: 1px solid var(--line-soft) !important;
  padding-top: 18px !important;
}
/* Platform-injected guestbook message list container (id comments-container,
   class guestbook-list) - ensure it never renders unstyled. */
#comments-container.guestbook-wrap,
#comments-container.guestbook-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 480px;
  margin-left: auto;
  margin-right: auto;
}
.guestbook-entry {
  background: var(--card);
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--gold);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 10px;
}
.guestbook-entry h5 { margin: 0 0 4px; font-family: var(--font-display); font-size: 0.95rem; color: var(--plum); }
.guestbook-entry p { margin: 0 0 6px; font-size: 0.88rem; }
.guestbook-entry small { font-size: 0.72rem; color: rgba(109, 58, 87, 0.6); }

.more-guestbook-wrap { text-align: center; margin-top: 4px; }
#load-more {
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--plum);
  font-weight: 700;
  font-size: 0.85rem;
  padding: 10px 26px;
}
#load-more:hover { border-color: var(--rose); color: var(--rose-deep); }

/* ── Scene 8 · Free page (optional) ─────────────────────────────
   Repeatable free blocks: each block = title + free text + optional
   photo. The platform clones .free-block per host entry; when the
   host has added no blocks (or toggles the Free Page section off)
   the whole section is removed and its nav entries disappear with it.
   The .free-media figure collapses via :empty/:not(:has(img)) when a
   block has no photo, so a text-only block reads cleanly. */
.free-blocks {
  display: grid;
  gap: clamp(26px, 5vmin, 40px);
  width: 100%;
  margin-top: 4px;
}
.free-block { margin: 0; text-align: center; }
.free-title {
  margin: 0 0 clamp(12px, 2.6vmin, 18px);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.15rem, 4.4vw, 1.5rem);
  line-height: 1.25;
  color: var(--plum);
  overflow-wrap: anywhere;
}
.free-title:focus { outline: none; }
.free-media {
  margin: 0 auto clamp(14px, 3vmin, 20px);
  max-width: 560px;
}
.free-media:empty, .free-media:not(:has(img)) { display: none; }   /* text-only block: no photo, no gap */
.free-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  padding: 5px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: var(--shadow-soft);
  cursor: zoom-in;
}
html.lb-off .free-media img { cursor: default; }
.free-media { position: relative; }
.free-media::after {
  content: "";
  position: absolute;
  top: 14px; right: 14px;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: rgba(255, 253, 248, 0.94)
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2355304a' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5L21 21'/%3E%3Cpath d='M10.5 8v5M8 10.5h5'/%3E%3C/svg%3E")
    center / 16px no-repeat;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-gold);
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity 0.2s, transform 0.2s;
  pointer-events: none;
}
.free-media:hover::after,
.free-media:focus-within::after { opacity: 1; transform: none; }
html.lb-off .free-media::after { display: none; }
.free-content {
  margin: 0 auto;
  max-width: 34em;
  text-align: left;
  font-size: 0.95rem;
  line-height: 1.75;
  color: var(--plum-ink);
  white-space: pre-line;
  overflow-wrap: anywhere;
}

/* ── Scene 9 · Farewell ────────────────────────────────────────── */
.panel--closing {
  background:
    radial-gradient(100% 60% at 50% 115%, rgba(243, 221, 154, 0.55), rgba(243, 221, 154, 0) 62%),
    linear-gradient(180deg, var(--blush), var(--blush-2) 50%, var(--blush-3));
}
.closing {
  position: relative;
  z-index: 1;
  width: 100%;
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* Bottom room reserved for the floating dock — the "Back to the
     cover" button must never sit underneath it. */
  padding: clamp(20px, calc(var(--su) * 5), 40px) 22px calc(clamp(30px, calc(var(--su) * 6), 48px) + var(--dock-h) + var(--safe-b));
}
body:not(.has-dock) .closing { padding-bottom: clamp(30px, calc(var(--su) * 6), 48px); }
.closing__heart {
  width: 34px;
  height: 34px;
  color: var(--rose);
  margin-bottom: 10px;
}
.closing__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 6vw, 2.2rem);
  font-weight: 700;
  color: var(--plum);
}
.closing__script {
  margin: 16px 0 0;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 0.95rem;
  color: var(--plum);
}
.closing__sig {
  margin: 4px 0 0;
  font-family: var(--font-script);
  font-size: clamp(1.7rem, 6.5vw, 2.2rem);
  color: var(--rose-deep);
}
.closing__note {
  max-width: 420px;
  margin-top: 22px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 14px 20px;
  box-shadow: var(--shadow-soft);
  font-size: 0.88rem;
  color: var(--plum-ink);
}
.closing__note p { margin: 0; }
.closing__tag {
  margin: 18px 0 0;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.closing .btn-ghost { margin-top: 22px; }

/* ── Footer brand placeholder ───────────────────────────────────
   An empty slot the platform fills with the site/brand mark; leave
   the element in place. */
.footer-brand {
  margin-top: 28px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(109, 58, 87, 0.55);
  text-align: center;
}

/* ── Powered-by brand strip — plain flow at the document's end ──
   The platform swaps the literal Kundangi token inside .link-footer
   for its brand name at render; the cockpit's Free Powered By field
   can override the whole line. It is not part of the free page and
   stays visible even when the free page is hidden. */
.powered-by {
  text-align: center;
  padding: 18px 18px calc(24px + var(--safe-b));
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(109, 58, 87, 0.55);
}
.powered-by .link-footer { color: var(--gold-deep); }
/* Reserve room for the floating dock, so end-of-page content is never
   covered by fixed chrome (§nothing-cut-off). */
body.has-dock .powered-by { padding-bottom: calc(var(--dock-h) + 48px + var(--safe-b)); }

/* ═══════════════════════════════════════════════════════════════════
   FIXED HEADER — brand · desktop pills · print · burger · progress.
   Height LOCKED to --header-h (token above); safe-area included in it.
   All JS chrome inside is gated behind html.js.
   ═══════════════════════════════════════════════════════════════════ */
.app-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 90;
  display: none; /* JS chrome only — a no-JS visitor gets a clean document */
  align-items: center;
  gap: 14px;
  height: var(--header-h);            /* LOCKED to the token … */
  padding: var(--safe-t) clamp(14px, 3vw, 28px) 0; /* … safe area included */
  border-bottom: 1px solid transparent;
  transition: background-color 0.3s var(--ease-spring), border-color 0.3s var(--ease-spring), box-shadow 0.3s var(--ease-spring);
}
html.js .app-header { display: flex; }
.app-header.is-scrolled {
  background: rgba(255, 246, 250, 0.88);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom-color: var(--line-soft);
  box-shadow: 0 12px 30px -22px rgba(109, 58, 87, 0.55);
}
.head-brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}
.head-crown { width: 30px; height: auto; flex: none; filter: drop-shadow(0 2px 4px rgba(169, 124, 46, 0.35)); }
.head-title {
  font-family: var(--font-script);
  font-size: 21px;
  line-height: 1;
  color: var(--plum);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Desktop section pills — built by main.js from the live DOM */
.topnav { display: none; }

.head-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
}
.head-btn {
  display: none;
  align-items: center; gap: 6px;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--plum);
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em;
  padding: 6px 13px; cursor: pointer;
  transition: background-color 0.2s var(--ease-spring), color 0.2s var(--ease-spring);
}
html.js .head-btn { display: inline-flex; }
.head-btn svg { width: 15px; height: 15px; }
.head-btn:hover { background: var(--plum); color: var(--blush); }

/* Burger — mobile JS chrome only (hidden without JS, hidden on desktop) */
.nav-burger {
  display: none;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 4px;
  width: 42px; height: 38px;
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(255, 253, 248, 0.7);
  color: var(--plum);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.burger-bar {
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform 0.3s var(--ease-spring), opacity 0.3s;
}
html.js .nav-burger { display: inline-flex; }
.nav-burger[aria-expanded="true"] .burger-bar:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-burger[aria-expanded="true"] .burger-bar:nth-child(2) { opacity: 0; }
.nav-burger[aria-expanded="true"] .burger-bar:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Scroll progress — a whisper-thin gold line filling along the header's
   bottom edge as guests read. JS chrome: never shown without JS. */
.scroll-progress {
  display: none;
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  transform-origin: left center;
  transform: scaleX(0);
  background: linear-gradient(90deg, var(--gold), var(--rose) 70%, var(--rose-deep));
  pointer-events: none;
}
html.js .scroll-progress { display: block; }

/* Desktop nav pills (≥820px): labelled buttons, active follows the spy */
@media (min-width: 820px) {
  html.js .topnav {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .topnav::-webkit-scrollbar { display: none; }
  html.js .nav-burger { display: none; }
  .head-btn span { display: inline; }
}
@media (max-width: 520px) {
  .head-btn span { display: none; } /* icon-only print button on phones */
  .head-title { display: none; }   /* the crown carries the brand */
}
.nav-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 13px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--plum);
  font-family: var(--font-body);
  font-size: 11px; font-weight: 700; line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.2s var(--ease-spring), color 0.2s var(--ease-spring);
}
.nav-pill svg { width: 14px; height: 14px; flex: none; }
.nav-pill:hover { color: var(--rose-deep); background: rgba(243, 221, 154, 0.55); }
.nav-pill.is-active {
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 60%, var(--gold-deep));
  color: #fff;
  box-shadow: var(--shadow-gold);
}
.nav-pill:focus-visible { outline-offset: 2px; }

/* ═══════════════ Mobile menu: slide-down sheet over a dimmed backdrop ══ */
.menu-backdrop {
  display: none; /* JS chrome only */
  position: fixed;
  inset: 0;
  z-index: 95;
  background: rgba(85, 48, 74, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.28s var(--ease-spring);
}
html.js .menu-backdrop { display: block; }
.menu-backdrop.is-open { opacity: 1; pointer-events: auto; }

.mobile-menu {
  display: none; /* JS chrome only */
  position: fixed;
  top: var(--header-h);
  left: 0; right: 0;
  z-index: 96;
  background: var(--cream);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 30px 50px -28px rgba(109, 58, 87, 0.55);
  transform: translateY(-12px);
  opacity: 0;
  transition: transform 0.28s var(--ease-spring), opacity 0.28s var(--ease-spring);
}
html.js .mobile-menu { display: block; }
.mobile-menu.is-open { transform: translateY(0); opacity: 1; }
.mobile-menu__scroller {
  max-height: min(62vh, 440px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 10px clamp(14px, 4vw, 24px) calc(14px + var(--safe-b));
}
.mobile-menu__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.menu-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 13px 14px;
  border: 1px solid transparent;
  border-radius: 12px;
  background: transparent;
  color: var(--plum-ink);
  font-family: var(--font-body);
  font-size: 14px; font-weight: 600; line-height: 1.2;
  letter-spacing: 0.04em;
  text-align: left;
  cursor: pointer;
  transition: background-color 0.18s var(--ease-spring), border-color 0.18s var(--ease-spring), color 0.18s var(--ease-spring);
}
.menu-row svg { width: 17px; height: 17px; flex: none; color: var(--gold-deep); }
.menu-row .menu-num {
  margin-left: auto;
  font-size: 10px; font-weight: 700; letter-spacing: 0.18em;
  color: rgba(109, 58, 87, 0.65);
}
.menu-row:hover { background: rgba(243, 221, 154, 0.4); border-color: var(--line-soft); }
.menu-row.is-current {
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 60%, var(--gold-deep));
  color: #fff;
}
.menu-row.is-current svg { color: #fff; }
.menu-row.is-current .menu-num { color: rgba(255, 253, 248, 0.8); }

/* ═══════════════════════════════════════════════════════════════════
   DOCK — floating gold-trimmed pill with icon shortcuts; built by
   main.js from the sections that exist, so deleted sections lose their
   entry. Horizontally scrollable (styled scrollbar) if labels don't
   fit; must fit within 390px viewports.
   ═══════════════════════════════════════════════════════════════════ */
.dock {
  position: fixed;
  left: 50%;
  bottom: calc(12px + var(--safe-b));
  transform: translateX(-50%);
  z-index: 85;
  display: none; /* built & shown by main.js only */
  align-items: stretch;
  gap: 2px;
  max-width: calc(100vw - 20px);
  padding: 6px 8px;
  background: rgba(255, 253, 248, 0.94);
  border: 1px solid var(--line);
  border-radius: 18px;
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: 0 22px 44px -22px rgba(192, 68, 110, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.65);
  overflow-x: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
body.has-dock .dock { display: flex; }
.dock button {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-width: 52px;
  height: 46px;
  padding: 5px 7px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--plum);
  cursor: pointer;
  transition: color 0.22s var(--ease-spring), background-color 0.22s var(--ease-spring), transform 0.22s var(--ease-spring);
  -webkit-tap-highlight-color: transparent;
}
.dock button svg { width: 19px; height: 19px; flex: none; }
.dock button:hover { color: var(--rose-deep); background: rgba(243, 221, 154, 0.55); }
.dock button:active { transform: scale(0.94); }
.dock button.is-current {
  color: #fff;
  background: linear-gradient(160deg, var(--gold-light), var(--gold) 60%, var(--gold-deep));
  box-shadow: var(--shadow-gold);
}
.dock__label {
  font-family: var(--font-body);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════
   TOAST — quiet confirmations (Add to Calendar, …)
   ═══════════════════════════════════════════════════════════════════ */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(84px + var(--safe-b));
  transform: translateX(-50%) translateY(14px);
  z-index: 150;
  padding: 11px 20px;
  border-radius: 999px;
  background: var(--plum);
  color: var(--blush);
  font-size: 12px; font-weight: 700; letter-spacing: 0.08em;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s var(--ease-spring), transform 0.25s var(--ease-spring);
  max-width: calc(100vw - 32px);
  text-align: center;
}
.toast.is-show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ═══════════════════════════════════════════════════════════════════
   LIGHTBOX — click-to-open originals with zoom & pan.
   Every content photo AND the film open here: images zoom (wheel, pinch,
   double-tap, ± buttons) and pan while zoomed; videos play as an embed or
   native player with an "open original" link. Closes via Escape /
   backdrop / ×. Markup is built by main.js only when clickable media
   exists. html.lb-off (window.MEDIA_LIGHTBOX = false) disables the whole
   feature — media renders inline only.
   ═══════════════════════════════════════════════════════════════════ */
.lightbox {
  position: fixed; inset: 0;
  z-index: 200;
  display: flex;
  align-items: center; justify-content: center;
  padding: calc(16px + var(--safe-t)) 16px calc(16px + var(--safe-b));
  background: rgba(49, 22, 38, 0.93);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
.lightbox[hidden] { display: none; }
body.lb-open { overflow: hidden; } /* lock the document behind the open lightbox */

.lightbox-stage {
  position: relative;
  width: 100%;
  max-width: 960px;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  animation: lb-zoom-in 0.28s var(--ease-spring);
}
@keyframes lb-zoom-in {
  from { transform: scale(0.94); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}
.lightbox-frame {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 100%;
  touch-action: none;
  overflow: hidden;
  border-radius: 10px;
}
.lightbox-img {
  display: block;
  max-width: 100%;
  max-height: 68vh; max-height: 68dvh;
  width: auto; height: auto;
  border: 6px solid var(--cream);
  border-radius: 10px;
  background: var(--blush-2); /* mat while loading / if the file is missing */
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.75);
  cursor: zoom-in;
  user-select: none;
  -webkit-user-select: none;
  will-change: transform;
  transition: transform 0.18s var(--ease-spring);
}
.lightbox-frame.is-zoomed .lightbox-img { cursor: grab; }
.lightbox-frame.is-zoomed .lightbox-img:active { cursor: grabbing; }
.lightbox-frame.is-panning .lightbox-img { transition: none; }
.lightbox-video {
  width: min(880px, 92vw);
  aspect-ratio: 16 / 9;
  max-height: 68vh; max-height: 68dvh;
}
.lightbox-video iframe,
.lightbox-video video {
  width: 100%; height: 100%;
  border: 0;
  border-radius: 10px;
  background: #000;
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.85);
}
.lightbox-caption {
  margin: 0;
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1rem, 3.4vw, 1.15rem);
  color: #ffeaf4;
  text-align: center;
  overflow-wrap: anywhere;
}
.lightbox-counter {
  margin: 0;
  font-size: 10px; font-weight: 700; letter-spacing: 0.26em;
  color: rgba(255, 234, 244, 0.6);
}

.lb-btn {
  position: absolute;
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(243, 221, 154, 0.5);
  background: rgba(255, 253, 248, 0.94);
  color: var(--rose-deep);
  cursor: pointer;
  box-shadow: 0 10px 24px -12px rgba(0, 0, 0, 0.6);
  transition: transform 0.2s var(--ease-spring), background-color 0.2s;
}
.lb-btn:hover { transform: scale(1.06); background: #fff; }
.lb-close { top: calc(12px + var(--safe-t)); right: calc(12px + var(--safe-r)); font-size: 24px; line-height: 1; }
.lb-prev { left: 10px; top: 50%; transform: translateY(-50%); }
.lb-next { right: 10px; top: 50%; transform: translateY(-50%); }
.lb-prev:hover, .lb-next:hover { transform: translateY(-50%) scale(1.06); }

/* Zoom tools + "open original" link (images) */
.lightbox-tools {
  position: absolute;
  left: calc(12px + var(--safe-l));
  bottom: calc(12px + var(--safe-b));
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 8px;
}
.lightbox-tools[hidden] { display: none; }
.lb-tool {
  min-width: 42px; height: 42px;
  padding: 0 8px;
  border-radius: 999px;
  border: 1px solid rgba(243, 221, 154, 0.5);
  background: rgba(255, 253, 248, 0.94);
  color: var(--rose-deep);
  font: 700 12px/1 var(--font-body);
  letter-spacing: 0.04em;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  transition: transform 0.2s var(--ease-spring), background-color 0.2s;
}
.lb-tool svg { width: 17px; height: 17px; }
.lb-tool:hover { transform: scale(1.05); background: #fff; }
.lb-tool[disabled] { opacity: 0.4; cursor: default; }
.lb-original {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 42px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid rgba(243, 221, 154, 0.5);
  background: rgba(255, 253, 248, 0.94);
  color: var(--rose-deep);
  font: 700 11px/1 var(--font-body);
  letter-spacing: 0.1em; text-transform: uppercase;
  text-decoration: none;
}
.lb-original:hover { background: #fff; }
.lightbox-original-row {
  position: absolute;
  right: calc(12px + var(--safe-r));
  bottom: calc(12px + var(--safe-b));
  z-index: 3;
}
.lightbox-original-row[hidden] { display: none; }

.lightbox :focus-visible { outline: 2px solid var(--gold-light); outline-offset: 3px; }

/* Narrow screens: prev/next drop below the photo so they never cover it. */
@media (max-width: 520px) {
  .lightbox { padding-left: 10px; padding-right: 10px; }
  .lightbox-img { max-height: 56vh; max-height: 56dvh; }
  .lightbox-video { width: 94vw; max-height: 56vh; max-height: 56dvh; }
  .lb-prev, .lb-next { position: static; transform: none; width: 42px; height: 42px; }
  .lb-prev:hover, .lb-next:hover { transform: scale(1.06); }
  .lightbox-stage { gap: 10px; justify-content: center; }
  .lightbox-tools { left: 8px; bottom: calc(8px + var(--safe-b)); }
  .lightbox-original-row { right: 8px; bottom: calc(8px + var(--safe-b)); }
}

/* ── Motion preferences ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .sparkle-field { display: none; }
  .cover__hint { animation: none; }
  html { scroll-behavior: auto; }
}

/* ── Print — the full stacked invitation, everything restored ──── */
@media print {
  @page { margin: 12mm; }
  html { scroll-padding-top: 0; }
  body { padding-top: 0; background: #fff; color: #222; }
  .app-header, .dock, .mobile-menu, .menu-backdrop, .scroll-progress,
  .js-print, .powered-by, .toast, .skip-link, .cover__hint,
  .sparkle-field, .letter__actions, .sheet__cta, .calendar-cta,
  .portrait__zoom, .banner__zoom, .free-media::after { display: none !important; }
  .panel {
    min-height: 0;
    break-before: page;
    page-break-before: always;
  }
  .panel--cover { break-before: auto; page-break-before: auto; max-height: none; overflow: visible; }
  .closing { padding-bottom: 24px; }
  .sheet { margin: 0 auto; }
  .sheet::before { border-color: #caa; }
  .lightbox { display: none !important; }
  /* Playing media can't print — the poster prints instead. */
  .video-card iframe, .video-card video { display: none !important; }
  /* The empty-state audit and the cover-fit trim only ever VISUALLY hid
     things: print restores everything … except live counters that would
     be meaningless on paper. */
  .is-empty, .fit-hidden { display: revert !important; }
  .js-countdown { display: none !important; }
  * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  a { color: inherit; }
}

/* ── Small screens ─────────────────────────────────────────────── */
@media (max-width: 520px) {
  .gallery { grid-template-columns: repeat(2, 1fr); }
}
