/* ===== Custom fonts — served locally so they render for every visitor ===== */
/* The Seasons (TrueType) */
@font-face { font-family: 'The Seasons'; font-style: normal; font-weight: 300; font-display: swap; src: url('/fonts/theseasons-light.ttf') format('truetype'); }
@font-face { font-family: 'The Seasons'; font-style: italic; font-weight: 300; font-display: swap; src: url('/fonts/theseasons-lightitalic.ttf') format('truetype'); }
@font-face { font-family: 'The Seasons'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/theseasons-regular.ttf') format('truetype'); }
@font-face { font-family: 'The Seasons'; font-style: italic; font-weight: 400; font-display: swap; src: url('/fonts/theseasons-italic.ttf') format('truetype'); }
@font-face { font-family: 'The Seasons'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/theseasons-bold.ttf') format('truetype'); }
@font-face { font-family: 'The Seasons'; font-style: italic; font-weight: 700; font-display: swap; src: url('/fonts/theseasons-bolditalic.ttf') format('truetype'); }
/* Ovo — free for commercial use */
@font-face { font-family: 'Ovo'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/ovo-regular.ttf') format('truetype'); }
/* New Icon Script — free for personal use (installed but currently unused) */
@font-face { font-family: 'New Icon Script'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/new-icon-script-regular.otf') format('opentype'); }

:root {
  --cream: #faf6f0;
  --paper: #fffdf9;
  --ink: #765e4d;
  --muted: #8a8178;
  --gold: #b08d57;
  --gold-soft: #c9b18a;
  --line: #e6ddd0;
  --sage: #6e7a63;
  --danger: #a4553e;
  /* Ovo is the base font for everything except the couple's names. */
  --serif: 'Ovo', Georgia, 'Times New Roman', serif;
  --sans: 'Ovo', Georgia, 'Helvetica Neue', Arial, sans-serif;
  /* The Seasons is used ONLY for the couple's names (uppercase, no variants). */
  --name: 'The Seasons', Georgia, serif;
  --shadow: 0 10px 30px rgba(90, 70, 40, 0.08);

  /* ============================================================
     ===== EDIT WEB HEADER FONT SIZE HERE =====
     ONE knob standardises every header to the same size: "programme",
     "frequently asked questions", "dress code", "after party", and the story
     "date and time" / "location" headers (they all read var(--header-size)).
     Change this single number to resize them all together.
       • BIGGER value = larger headers   • SMALLER value = smaller headers
     Controls the WEB (desktop) layout only. Phones use their own value —
     search "MOBILE TITLE FONT SIZE" further down. The RSVP "dear …" greeting
     and thank-you line are intentionally NOT on this knob (they are single
     no-wrap lines that could overflow if enlarged too far). */
  --header-size: 2.0rem;

  /* ============================================================
     ===== EDIT WEB SIDE PADDING HERE =====
     The left/right gutter of the programme + FAQ sections, as a % of the
     viewport width (so it stays proportional at every screen size).
       • BIGGER number  = more padding = narrower columns pulled toward centre
       • SMALLER number = less padding = wider columns
     This knob controls the WEB (desktop) layout only. Phones are pinned to a
     comfortable value separately — search "MOBILE SIDE PADDING" further down —
     so raising this never crowds the phone layout.
     ============================================================ */
  --side-pad: 8vw;

  /* ============================================================
     ===== EDIT BODY FONT SIZE HERE =====
     The main body text size, shared by: the programme list (times + labels),
     the "dress code" / "after party" paragraphs, and the FAQ answers.
       • BIGGER value = larger body text   • SMALLER value = smaller body text
     Applies to both desktop and phone (the mobile body rule reads this too).
     ============================================================ */
  --body-size: 1.15rem;

  /* Distance from the top of a content section to its header — shared by the
     programme and FAQ so their headers sit at exactly the same height. */
  --section-top: clamp(2.5rem, 6vw, 4.5rem);

  /* FAQ centre gap (between its two columns). Reused to size the programme's
     right column so "dress code / after party" line up with the FAQ 04 column. */
  --faq-col-gap: clamp(2rem, 6vw, 4.5rem);
}

* { box-sizing: border-box; }

/* Hide the page scrollbar site-wide (scrolling still works, wheel/touch/keys). */
html, body { scrollbar-width: none; -ms-overflow-style: none; }
html::-webkit-scrollbar, body::-webkit-scrollbar { width: 0; height: 0; display: none; }

body {
  margin: 0;
  font-family: var(--sans);
  color: var(--ink);
  background: #fdf8f5; /* soft warm white behind the content sections */
  line-height: 1.6;
  font-weight: 400; /* Ovo ships a single weight */
}

a { color: var(--gold); }

.script,
.section-title,
.names,
.admin-title,
.card h3 {
  font-family: var(--serif);
}

/* ---------- shared decorative bits ---------- */

.divider {
  color: var(--gold-soft);
  font-size: 1.4rem;
  margin: 1.2rem 0;
  letter-spacing: 0.5rem;
}
.divider.small { font-size: 1rem; margin: 0.6rem 0 1.6rem; }

.monogram {
  font-family: var(--serif);
  font-size: 2.4rem;
  letter-spacing: 0.15rem;
  color: var(--gold);
}
.monogram span { color: var(--gold-soft); font-style: italic; }
.monogram.small { font-size: 1.4rem; }

.amp { color: var(--gold-soft); font-style: italic; }

.btn {
  display: inline-block;
  font-family: var(--sans);
  font-weight: 400;
  letter-spacing: 0.12rem;
  text-transform: uppercase;
  font-size: 0.8rem;
  background: var(--gold);
  color: #fff;
  border: none;
  padding: 0.85rem 2rem;
  border-radius: 2px;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.2s, transform 0.1s;
}
.btn:hover { background: #9a7a48; }
.btn:active { transform: translateY(1px); }
.btn.ghost { background: transparent; color: var(--gold); border: 1px solid var(--gold-soft); }
.btn.tiny { padding: 0.4rem 0.8rem; font-size: 0.68rem; }
.btn.danger { background: transparent; color: var(--danger); border: 1px solid #d9b7ab; }
.btn.danger:hover { background: var(--danger); color: #fff; }

/* ---------- landing / not-found ---------- */

.landing-body { display: flex; min-height: 100vh; align-items: center; justify-content: center; }
/* Landing (no-invite) rides higher instead of vertically centred */
.landing-body.landing-invite { align-items: flex-start; }
.landing-invite .landing { padding-top: clamp(4rem, 11vh, 7.5rem); }
.landing {
  text-align: center;
  max-width: 540px;
  padding: 3rem 1.5rem;
}
.landing .script { font-size: clamp(2.5rem, 7vw, 4rem); margin: 1rem 0 0.3rem; font-weight: 500; }
.tagline { font-size: 1.1rem; color: var(--muted); letter-spacing: 0.1rem; }
.date-line { font-family: var(--serif); font-size: 1.3rem; letter-spacing: 0.06rem; }
.hint { color: var(--muted); font-size: 0.95rem; margin-top: 1.5rem; }

/* No-invite landing — matches the invitation aesthetic (intro-bg + scrim,
   The Seasons names, Ovo body, wax seal). */
.landing-invite {
  position: relative;
  color: #fdf8f5;
  background-color: #23252b;
  background-image:
    linear-gradient(rgba(28, 20, 24, 0.55), rgba(28, 20, 24, 0.66)),
    var(--img-intro, none),
    linear-gradient(180deg, #cdd4dc 0%, #8f99a4 45%, #5c6570 100%);
  background-size: cover;
  background-position: center;
}
.landing-invite .landing { color: #fdf8f5; max-width: 640px; }
.li-eyebrow { font-family: var(--sans); text-transform: lowercase; letter-spacing: normal; font-size: 0.9rem; color: var(--wax); opacity: 0.9; margin: 0 0 1rem; }
.li-names { font-family: var(--name); font-weight: 400; font-style: normal; text-transform: uppercase; letter-spacing: normal; font-size: clamp(1.7rem, 6.4vw, 3.6rem); line-height: 1.1; white-space: nowrap; margin: 0 0 1.1rem; }
.li-date { font-family: var(--sans); letter-spacing: normal; font-size: clamp(0.95rem, 2.4vw, 1.2rem); margin: 0 0 0.3rem; }
.li-loc { font-family: var(--serif); font-size: 1rem; color: #efe7df; margin: 0 0 1.8rem; }
/* Static closed envelope (with its wax seal) as the centrepiece */
.li-envelope { position: relative; width: clamp(230px, 42vw, 360px); aspect-ratio: 2000 / 1442; margin: 0.4rem auto 0.9rem; }
.li-env-img { position: absolute; left: 0; top: 0; width: 100%; height: auto; user-select: none; -webkit-user-drag: none; }
.li-seal { position: absolute; left: 50%; top: 58%; transform: translate(-50%, -50%); width: 30%; height: auto; filter: drop-shadow(0 5px 10px rgba(0,0,0,0.4)); }
.li-hint { font-family: var(--sans); text-transform: lowercase; letter-spacing: normal; font-size: 0.92rem; line-height: 1.6; color: #e6d9cf; opacity: 0.9; max-width: 42ch; margin: 0 auto; }

/* ============================================================
   REDESIGN — burgundy envelope invitation
   ------------------------------------------------------------
   Drop-in image assets: every ".slot" below has a --img variable
   with an on-brand gradient placeholder behind it. To use a real
   photo, drop the file at the path shown and (if the name differs)
   update the matching --img variable here. When --img resolves to a
   real file it paints on top of the placeholder automatically.
   ============================================================ */
:root {
  --burgundy: #701d2d;
  --burgundy-dk: #521018;
  --burgundy-lt: #8a2a38;
  --wax: #ece3d6;
  --wax-sh: #cdbfa8;

  /* Image slots — set these to url('/img/xxx.jpg') when assets are ready */
  --img-intro:     url('/img/intro-bg.png');       /* spans stage + story */
  --img-floral:    url('/img/floral-bg.jpg');      /* (unused now)       */
  --img-card:      url('/img/card-portrait.jpg');  /* invitation photo   */
  --img-story:     url('/img/story.jpg');          /* (unused now)       */
  --img-programme: url('/img/programme.jpg');      /* programme photo    */
  --img-faq:       url('/img/faq.jpg');            /* faq photo          */
}

/* placeholder tints so empty slots look deliberate, not broken */
.slot { background-repeat: no-repeat; background-position: center; background-size: cover; }

/* Sections fade + rise into view as you scroll (JS adds .reveal, then .in) */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.9s ease, transform 0.9s ease; }
.reveal.in { opacity: 1; transform: none; }

.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 1.6rem;
  transform: translateX(-50%);
  z-index: 3;
  color: var(--wax);
  font-size: 1.5rem;
  line-height: 1;
  text-decoration: none;
  opacity: 0.85;
  animation: cue-bob 1.9s ease-in-out infinite;
}
.scroll-cue[hidden] { display: none; }
.scroll-cue:hover { opacity: 1; }
@keyframes cue-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50% { transform: translate(-50%, 8px); }
}

/* ---------- landscape "please rotate" notice ---------- */
/* Hidden by default; shown only on touch phones held in landscape (short height).
   The pointer:coarse + max-height gate keeps it off desktops, laptops, and
   tablets — it fires only on actual phones turned sideways. */
.rotate-notice { display: none; }
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  /* Freeze the page behind the overlay so it can't be scrolled in landscape —
     but ONLY on the pages that actually show the overlay (invite + landing).
     The admin page has no overlay and must stay usable/scrollable in landscape. */
  html:has(.rotate-notice), .invite-body, .landing-body { overflow: hidden; height: 100%; }
  .rotate-notice {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 9999;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 1.5rem;
    background: #23252b;
    color: #fdf8f5;
  }
  .rotate-notice .rn-icon {
    display: block;
    font-size: 2.4rem;
    margin: 0 0 0.9rem;
    animation: rn-tip 2.2s ease-in-out infinite;
  }
  .rotate-notice p {
    margin: 0;
    font-family: var(--serif);
    text-transform: lowercase;
    font-size: 1.1rem;
    letter-spacing: 0.02rem;
    line-height: 1.5;
    max-width: 22ch;
  }
}
@keyframes rn-tip {
  0%, 100% { transform: rotate(0deg); }
  50%      { transform: rotate(-90deg); }
}
@media (prefers-reduced-motion: reduce) {
  .rotate-notice .rn-icon { animation: none; }
}

/* ---------- 1+2. envelope stage (image assets) ---------- */

/* Page stays locked on the envelope until the seal is clicked (JS toggles) */
html.intro-locked, html.intro-locked body { overflow: hidden; height: 100%; }

/* One photo (intro-bg) sits behind BOTH the envelope stage and Our Story */
.intro {
  position: relative;
  background-color: #23252b;
  background-image:
    var(--img-intro, none),
    linear-gradient(180deg, #cdd4dc 0%, #8f99a4 45%, #5c6570 100%);
  background-size: cover;
  background-position: center top;
}

.stage {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3rem 1.5rem;
  overflow: hidden;
  background: transparent; /* let the .intro photo show through */
}

/* Container is sized to the CLOSED envelope (2000x1442). The taller open
   frames (square) are bottom-anchored, so they overflow upward as the card
   rises. Width capped by 66vh so the open state always fits the viewport. */
.envelope {
  position: relative;
  width: min(92vw, 86vh, 780px);
  aspect-ratio: 2000 / 1442;
  transition: transform 0.8s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* on open, slide down so the taller open frame is centred / fully visible */
.envelope.is-opening { transform: translateY(18%); }
.env-img {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: auto;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
  transition: opacity 0.6s ease;
}
.env-closed { z-index: 2; opacity: 1; }
.env-start  { z-index: 3; opacity: 0; }
.env-final  { z-index: 4; opacity: 0; }

.env-caption {
  position: absolute;
  left: 0; right: 0; top: 20%;
  text-align: center;
  color: var(--wax);
  z-index: 5;
  pointer-events: none;
  transition: opacity 0.4s ease;
}
.env-love { font-family: var(--sans); text-transform: lowercase; letter-spacing: 0.12rem; font-size: 0.9rem; opacity: 0.9; margin: 0 0 0.4rem; }
.env-names { font-family: var(--name); font-weight: 400; font-style: normal; font-size: clamp(1.2rem, 3.2vw, 1.8rem); letter-spacing: 0.14rem; text-transform: uppercase; margin: 0; white-space: nowrap; }

/* wax seal button (image asset) */
.seal {
  position: absolute;
  left: 50%; top: 60%;
  transform: translate(-50%, -50%);
  /* ===== EDIT SEAL SIZE HERE =====
     The middle value (30%) is the knob = seal width as a % of the envelope.
     Bigger % → bigger seal. (84px / 220px are just the min / max clamps.) */
  width: clamp(84px, 30%, 220px);
  aspect-ratio: 1;
  border: none;
  background: none;
  padding: 0;
  z-index: 6;
  cursor: pointer;
  filter: drop-shadow(0 5px 10px rgba(0,0,0,0.45));
  transition: transform 0.25s ease, opacity 0.5s ease;
}
.seal img { width: 100%; height: 100%; display: block; }
.seal:hover { transform: translate(-50%, -50%) scale(1.06); }
.seal:active { transform: translate(-50%, -50%) scale(0.96); }

/* opening sequence: JS adds .is-opening, then .is-open a beat later */
.envelope.is-opening .env-closed { opacity: 0; }
.envelope.is-opening .env-start  { opacity: 1; }
.envelope.is-open    .env-start  { opacity: 0; }
.envelope.is-open    .env-final  { opacity: 1; }
.envelope.is-opening .seal,
.envelope.is-opening .env-caption { opacity: 0; pointer-events: none; }

/* sits on the lower body of the closed envelope (child of .envelope) */
.open-hint {
  position: absolute;
  left: 0; right: 0; bottom: 9%;
  text-align: center;
  color: var(--wax);
  font-family: var(--sans);
  text-transform: lowercase;
  letter-spacing: 0.12rem;
  /* ===== EDIT "OPEN THE INVITATION" HORIZONTAL OFFSET HERE =====
     Positive value nudges the text RIGHT, negative nudges it LEFT.
     (Compensates the letter-spacing + the slightly off-centre envelope art.) */
  text-indent: 0.6rem;
  font-size: clamp(0.78rem, 1.7vw, 0.95rem);
  opacity: 0.82;
  z-index: 5;
  animation: hint-bob 2.4s ease-in-out infinite;
  transition: opacity 0.4s ease;
}
.open-hint.gone { opacity: 0; pointer-events: none; animation: none; }

/* "RSVP HERE" box on the open envelope's lower pocket (child of .envelope).
   Hidden until the card is fully open, then it fades in. Clicking it unlocks
   the page and scrolls down (see rsvp.js). */
.env-rsvp {
  position: absolute;
  left: 50%;
  /* ===== EDIT "RSVP HERE" VERTICAL POSITION HERE =====
     Bigger % → higher up the envelope. */
  bottom: 8%;
  transform: translateX(-50%) translateY(8px);
  z-index: 6;
  font-family: var(--sans);
  text-transform: uppercase;
  letter-spacing: 0.22rem;
  text-indent: 0.22rem; /* offsets the trailing letter-spacing so text sits centered */
  font-size: clamp(0.72rem, 1.6vw, 0.92rem);
  color: #fdf8f5;
  background: transparent;
  border: 1px solid #fdf8f5;
  padding: 0.72rem 1.7rem;
  border-radius: 2px;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s ease 0.35s, transform 0.5s ease 0.35s,
              background 0.2s ease, color 0.2s ease;
}
.envelope.is-open .env-rsvp {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
.env-rsvp:hover { background: #fdf8f5; color: var(--burgundy); }
.env-rsvp:active { transform: translateX(-50%) translateY(1px); }
/* Y-only bob — the full-width hint must NOT reuse cue-bob's translate(-50%) */
@keyframes hint-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(6px); }
}

/* ---------- 3. our story (full-bleed) ---------- */

.story-hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  /* ===== EDIT GAP BETWEEN STORY TEXT AND DATE/LOCATION HERE =====
     Bigger value pushes date/time + location further down the photo. */
  gap: clamp(3rem, 12vh, 7rem);
  /* top value raised to lower the whole block toward the horizon */
  padding: clamp(5rem, 14vh, 8.5rem) clamp(1.5rem, 6vw, 5rem) clamp(2.5rem, 6vw, 4.5rem);
  color: #f3efe9;
  text-align: center;
  /* transparent to the .intro photo; scrim darkens for white-text legibility.
     Starts at 0 opacity so it blends seamlessly from the stage above (no seam),
     then ramps in behind the names and again at the bottom (date/location). */
  background: linear-gradient(rgba(28,32,42,0) 0%, rgba(28,32,42,0.28) 35%, rgba(28,32,42,0.26) 100%);
}
.story-top { max-width: 1200px; margin: 0 auto; }
.story-names { font-family: var(--name); font-weight: 400; font-style: normal; font-size: clamp(2rem, 6vw, 3.4rem); letter-spacing: 0.06rem; text-transform: uppercase; margin: 0 0 0.8rem; }
/* ===== EDIT STORY PARAGRAPH WIDTH HERE (higher ch = longer lines / fewer rows) ===== */
.story-prose { font-family: var(--serif); font-size: var(--body-size); line-height: 1.5; max-width: 100ch; margin: 0 auto; }
.story-meta { display: flex; justify-content: space-between; gap: 2rem; max-width: 1000px; margin: 0 auto; width: 100%; }
.story-block h3 { font-family: var(--serif); font-weight: 400; text-transform: lowercase; font-size: 1.8rem; margin: 0 0 0.1rem; }
.story-block p { margin: 0.1rem 0; font-size: var(--body-size); }

/* Mobile-only scrollytelling for Our Story — hidden on desktop (shown in the mobile media query). */
.story-scrolly { display: none; }

/* ---------- shared section headings ---------- */

.block-title { font-family: var(--serif); font-weight: 400; text-transform: lowercase; font-size: var(--header-size); color: var(--burgundy); margin: 0 0 1.6rem; }
.block-title.sm { font-size: clamp(1.2rem, 3vw, 1.5rem); margin: 0 0 0.4rem; }
.block-title.center { text-align: center; }

.section { max-width: 1080px; margin: 0 auto; padding: clamp(3rem, 8vw, 5.5rem) clamp(1.5rem, 6vw, 4rem); }

/* ---------- 4. programme ---------- */

/* Full-width section. The keychain lives inside the RIGHT column: its photo
   frame sits directly above the dress-code / after-party notes (frame-left
   aligned to the notes), the ribbon rises above into the top padding, and its
   tail overflows to the right (clipped at the viewport by overflow:hidden).
   --kcw is the keychain's rendered width; every offset is derived from it via
   the asset's frame insets (frame bottom-left corner 0.2407w, bottom ~0.89h;
   aspect h = 0.437w) so the piece scales as one unit. */
.programme { position: relative; overflow: hidden; max-width: none; margin: 0; --kcw: clamp(760px, 70.3vw, 1550px); padding: var(--section-top) 0 clamp(3rem, 8vw, 6.5rem); }
.prog-inner {
  position: relative; z-index: 1;
  /* Two equal columns with the same centre gap as the FAQ, so all four columns
     across both sections are the same width and "dress code / after party" line
     up with the FAQ 04 column. */
  display: grid; grid-template-columns: 0.86fr 1fr; gap: clamp(3.5rem, 5.63vw, 7.4rem);
  align-items: start; width: min(84vw, 1680px); margin-inline: auto;
  padding: 0;
}
/* Nudge the whole left column down and right so it sits lower and more inset. */
.prog-left { padding-top: clamp(3rem, 6.5vw, 9rem); padding-left: clamp(2.5rem, 7.2vw, 9.5rem); }
.timeline { list-style: none; padding: 0; margin: 1.5rem 0 0; max-width: 100%; }
.tl-item { display: grid; grid-template-columns: 8.5rem 1fr; gap: 1rem; padding: clamp(1.3rem, 1.75vw, 2.5rem) 0; align-items: baseline; border-bottom: 1pt solid #b2ac99; }
.tl-time { font-family: var(--serif); font-size: var(--body-size); color: var(--ink); }
.tl-label { font-family: var(--serif); font-size: var(--body-size); color: var(--ink); }
.prog-right { position: relative; }
/* Keychain anchored by its frame's BOTTOM-LEFT corner (asset x-frac 0.2407),
   which lands exactly on the column's left edge = the "dress code" left. Image
   top sits at the section top so the ribbon stays flush. Tail spills right. */
.prog-keychain {
  position: absolute;
  left: calc(-0.234 * var(--kcw));
  top: calc(-1 * var(--section-top));
  width: var(--kcw);
  height: auto; z-index: 0; pointer-events: none;
}
/* Push the dress code / after party below the frame's bottom (0.89h * 0.437 aspect). */
.prog-right { padding-top: calc(0.389 * var(--kcw) - var(--section-top) + 2.5rem); }
/* ===== EDIT GAP BETWEEN DRESS CODE AND AFTER PARTY HERE ===== */
/* Indent the notes slightly right of the keychain's bottom-left corner. */
.prog-note { margin-bottom: 1.5rem; margin-left: clamp(0.8rem, 1.5vw, 1.8rem); }
.prog-note:last-child { margin-bottom: 0; }
/* header-to-text gap matches the story "location" block (0.1rem) */
.prog-note .block-title.sm { margin-bottom: 0.1rem; font-size: var(--header-size); }
.prog-note p { margin: 0; color: var(--ink); font-family: var(--serif); font-size: var(--body-size); line-height: 1.55; }
/* Programme "programme" heading scales with the section so it fills wide screens. */
.prog-left .block-title { font-size: var(--header-size); }

/* ---------- 5. faq (full-bleed banner + two-column questions) ---------- */

.faq { max-width: 100%; margin: 0; padding: 0; }
.faq-banner { width: 100%; overflow: hidden; }
.faq-banner img { display: block; width: 100%; height: 56vh; object-fit: cover; object-position: center 62%; }
.faq-body { max-width: none; margin: 0; padding: var(--section-top) var(--side-pad); }
/* Two columns, filled top-to-bottom then across (matches the mockup). */
.faq-list { list-style: none; padding: 0; margin: 1.6rem 0 0; columns: 2; column-gap: var(--faq-col-gap); }
.faq-item { display: grid; grid-template-columns: 2.6rem 1fr; gap: 0.8rem; margin: 0 0 1.8rem; break-inside: avoid; -webkit-column-break-inside: avoid; }
.faq-num { font-family: var(--serif); font-size: 1.35rem; color: var(--ink); }
.faq-q { font-family: var(--serif); font-weight: 400; font-size: 1.35rem; color: var(--ink); margin: 0 0 0.35rem; }
.faq-a { margin: 0; font-size: var(--body-size); color: var(--muted); line-height: 1.55; }
/* Force the split: items 01–03 in the left column, 04–05 in the right. */
.faq-item:nth-child(3) { break-after: column; -webkit-column-break-after: always; }
/* The second sentence of the directions answer sits on its own line with a
   slightly larger gap than a normal wrapped line. */
.faq-a-next { display: block; margin-top: 0.55em; }
.map-link { color: var(--gold); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }

/* ---------- map modal (embedded Google Map) ---------- */
html.modal-open { overflow: hidden; }
.map-modal { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; padding: clamp(1rem, 4vw, 2.5rem); }
.map-modal[hidden] { display: none; }
.map-modal-backdrop { position: absolute; inset: 0; background: rgba(40, 28, 22, 0.55); backdrop-filter: blur(2px); }
.map-modal-card { position: relative; z-index: 1; width: min(760px, 100%); background: var(--paper); border-radius: 6px; box-shadow: var(--shadow); padding: 1.1rem; }
.map-modal-close { position: absolute; top: 0.35rem; right: 0.6rem; background: none; border: none; font-size: 1.9rem; line-height: 1; color: var(--muted); cursor: pointer; padding: 0.2rem 0.4rem; }
.map-modal-close:hover { color: var(--ink); }
.map-modal-embed { position: relative; width: 100%; aspect-ratio: 16 / 10; border-radius: 4px; overflow: hidden; background: var(--cream); }
.map-modal-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.map-modal-addr { margin: 0.9rem 0 0.2rem; text-align: center; font-family: var(--serif); color: var(--ink); font-size: 0.98rem; line-height: 1.5; }

/* ---------- rsvp (kept functional) ---------- */

.section.rsvp { max-width: 620px; text-align: center; padding-top: clamp(1rem, 2.3vw, 2rem); }
.rsvp-intro { font-family: var(--serif); font-weight: 400; font-size: clamp(1.45rem, 3.2vw, 2rem); line-height: 1.3; color: var(--burgundy); text-transform: lowercase; text-align: center; margin: 0 0 1rem; }
/* Greeting ("Dear ___,") in the script font on its own line above. */
.rsvp-greeting { display: block; font-family: 'New Icon Script', var(--serif); text-transform: none; font-size: 1.5em; line-height: 1.05; margin-bottom: 0.15rem; white-space: nowrap; }
/* Second line keeps the standard serif title font. */
.rsvp-line2 { display: block; }
.countdown { font-family: var(--serif); font-size: var(--body-size); color: var(--ink); line-height: 1.45; margin: 1.9rem 0 0.2rem; }
/* Put the time on its own clean line (was wrapping awkwardly). */
.cd-time { display: block; }

/* names helper still used by landing.ejs */
.names { font-family: var(--name); font-style: normal; text-transform: uppercase; display: flex; flex-direction: column; align-items: center; gap: 0.05rem; margin: 0.5rem 0; line-height: 1.02; }
.names .nm { font-size: clamp(2.4rem, 7.5vw, 4.4rem); font-weight: 400; white-space: nowrap; }
.names .amp-line { font-size: clamp(1.3rem, 3.5vw, 2rem); color: var(--gold-soft); font-style: italic; margin: 0.15rem 0; }

@media (prefers-reduced-motion: reduce) {
  .scroll-cue, .open-hint, .ss-cue { animation: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .env-img { transition: none; }
}

/* ---------- redesign responsive ---------- */
@media (max-width: 760px) {
  /* Programme returns to a simple stacked layout; keychain becomes a normal
     inline image at the top (no bleed / absolute positioning). */
  .programme { overflow: hidden; padding-top: var(--section-top); } /* clip the oversized keychain at the screen edges; top gap == FAQ + after-party gaps */
  /* Match the FAQ's gutter (var(--side-pad)) and drop the desktop centred-block
     width, so "programme" lines up with "frequently asked questions" on phones. */
  .prog-inner { grid-template-columns: 1fr; width: auto; margin: 0; padding: 0 var(--side-pad); }
  /* Remove the desktop down/right nudge on phones (it was pushing the heading in). */
  .prog-left { padding: 0; }
  /* Keychain much bigger, bleeding past both edges; the image is centred so the
     photo frame (centre of the asset) stays in the middle of the screen. */
  .prog-keychain { position: relative; left: 50%; top: auto; transform: translateX(-47%); display: block; width: 176vw; max-width: none; margin: 0.5rem 0 1.5rem; }
  .prog-right { padding-top: 0; min-width: 0; } /* keep the grid track at viewport width so the oversized keychain can centre + bleed */
  /* Left-aligned and full width on phones: the dotted line reaches the right edge
     so the empty gap on the left and right (the section side padding) is equal. */
  .timeline { max-width: none; margin-left: 0; margin-right: 0; }
  .faq-list { columns: auto; }           /* single column of questions on phones (auto disables multicol cleanly) */
  .faq-banner img { height: 30vh; }      /* shorter banner on phones (fixed % of viewport height) */
  .story-meta { flex-direction: column; gap: 1.4rem; text-align: center; }
  /* On phones this line must wrap instead of overflowing the screen.
     Drop the max-content centering (only needed to keep it one line on desktop).
     NOTE: .done-msg gets the same treatment lower down, after its base rule,
     because that rule is defined later in the file and would otherwise win. */
  .rsvp-intro {
    white-space: normal;
    width: auto;
    left: auto;
    transform: none;
    max-width: 100%;
  }

  /* ===== MOBILE FONT STANDARDISATION — match the "date and time"/"location" block ===== */
  /* ===== MOBILE TITLE FONT SIZE ===== (pinned; the web title knob above does not
     affect phones). Section titles (programme / FAQ / "dear …" / RSVP response)
     match .ss-h (≈23.2px). Change this number to resize phone titles. */
  :root { --header-size: 1.45rem; }
  /* ===== MOBILE BODY FONT SIZE ===== (pinned; the web body knob above does not
     affect phones). Everything programme-and-below (timeline lines, dress code
     body, FAQ answers, countdown, RSVP venue + form) matches the story
     "date and time" / "location" body (.ss-t ≈ 0.95rem / 15.2px). */
  :root { --body-size: 0.95rem; }
  /* Shared section breathing room on phones — drives all three standardised gaps:
     above "programme", after "after party", and above "frequently asked questions".
     Raised above the desktop min so the gap before the FAQ photo reads generously. */
  :root { --section-top: 3.5rem; }
  /* ===== MOBILE SIDE PADDING ===== (pinned; the web knob above does not affect
     phones). Change this number to adjust the phone gutters independently. */
  :root { --side-pad: 9vw; }
  /* Main body text across every section + the form matches .ss-t (0.95rem / 15.2px). */
  .tl-time, .tl-label, .prog-note p, .faq-a, .countdown, .cd-time,
  .rsvp-form .text-input, .rsvp-form textarea.text-input,
  .rsvp .rsvp-venue { font-size: var(--body-size); }
  /* "dress code" matches the section headers ("programme"/"faq") on phones — it
     falls back to the desktop rule (var(--header-size) = 1.45rem here). The FAQ
     questions + numeration keep their own in-between size. */
  .faq-q, .faq-num { font-size: 1.2rem; }
}

/* ---------- mobile (phone) tuning — MOBILE ONLY ---------- */
@media (max-width: 640px) {
  /* 1. Much bigger envelope, centred by .stage's flexbox; sides spill past the
        viewport and get clipped by .stage overflow:hidden (no page scroll).
        flex: 0 0 auto stops the flexbox from shrinking it back to fit. */
  .envelope { width: 135vw; flex: 0 0 auto; }
  /* The stage BOX must be a full 100vh (not svh) so its bottom edge lands on the
     same photo row (200vh photo -> row 100vh) where the pinned scrolly's crop
     begins — that's what makes the shared photo continuous across the seam.
     To still center the envelope inside the VISIBLE area (svh, excluding the
     address bar), pad the bottom by exactly the address-bar height (100vh-100svh);
     where svh isn't supported this collapses to 0 and centres in 100vh. */
  .stage { min-height: 100vh; padding: 1rem 0 calc(100vh - 100svh); }

  /* 2. "open the invitation": tighter kerning, smaller, truly centred. */
  .open-hint {
    letter-spacing: 0.02rem;
    text-indent: 0;           /* was compensating the wide kerning */
    font-size: 0.7rem;
  }

  /* 3. RSVP button a little bigger — but far less than the envelope grew. */
  .env-rsvp {
    font-size: 1rem;
    letter-spacing: 0.18rem;
    text-indent: 0.18rem;
    padding: 0.85rem 2.1rem;
  }

  /* 4. Our Story becomes the pinned scrollytelling section below; hide the
        desktop story block. Give the envelope stage its own copy of the photo
        (top/sky crop) so hiding .story-hero doesn't reframe the shared background. */
  .story-hero { display: none; }
  .stage {
    /* NO scrim — this is the TOP half of one continuous photo. The photo is scaled
       to 200vh tall and top-aligned, so the stage (100vh box) shows rows [0..100vh];
       the pin below shows [100vh..200vh]. No darkening anywhere = no seam shadow.
       vh (not dvh) keeps the scale stable while the address bar shows/hides. */
    background-image:
      var(--img-intro, none),
      linear-gradient(180deg, #cdd4dc 0%, #8f99a4 45%, #5c6570 100%);
    background-size: auto 200vh, cover;
    background-position: center top, center top;
    background-repeat: no-repeat, no-repeat;
  }

  /* ----- pinned story crossfade: the title + couple photo pin in place while the
           page scrolls through a tall section; each text (prose 1, prose 2,
           date/time, location) gets ~one screen of scroll and crossfades to the
           next. It's plain page scroll, so you can move up/down freely and scroll
           straight out of either end. Opacity is driven by rsvp.js. ----- */
  .story-scrolly {
    display: block;
    position: relative;
    /* Tall so each of the 4 texts gets ~one screen of scroll (one swipe ≈ one
       text). ~100vh per step — tune this number to pace the story faster/slower. */
    height: 400vh;
    background: #23252b;
  }
  .ss-pin {
    position: sticky; top: 0;
    /* vh (large viewport, fixed) not dvh — a dvh height changes with the address
       bar during scroll, which rescales the photo and shifts the layout. */
    height: 100vh;
    overflow: hidden;
    color: #fdf8f5;
    /* NO scrim — this is the BOTTOM half of the same continuous photo (200vh tall,
       bottom-aligned -> shows rows [100vh..200vh], continuing from the stage
       above). Legibility is handled by text-shadow on the text itself. */
    background-image:
      var(--img-intro, none),
      linear-gradient(180deg, #5c6570, #23252b);
    background-size: auto 200vh, cover;
    background-position: center bottom, center;
    background-repeat: no-repeat;
  }
  /* Title pins above the texts; pointer-events off so it never blocks scrolling. */
  .ss-names {
    position: absolute; top: 1.6rem; left: 0; right: 0; z-index: 3;
    pointer-events: none; text-align: center; margin: 0;
    font-family: var(--name); font-weight: 400; font-style: normal;
    text-transform: uppercase; letter-spacing: normal;
    font-size: clamp(1.7rem, 6.4vw, 3.6rem); line-height: 1.1;
  }
  /* The four texts are stacked in the same spot; only one shows at a time and they
     crossfade as you scroll (opacity set by rsvp.js). */
  .ss-box { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
  .ss-panel {
    position: absolute; inset: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
    gap: 0.15rem; margin: 0; padding: 5.5rem 1.4rem 0; text-align: center;
    opacity: 0; will-change: opacity;
  }
  .ss-panel.is-active { opacity: 1; }   /* first card, until rsvp.js takes over */
  .ss-copy { font-family: var(--serif); font-size: 0.85rem; line-height: 1.55; max-width: 30rem; margin: 0; }
  .ss-panel .ss-h { font-family: var(--serif); font-size: 1.45rem; margin-bottom: 0.2rem; }
  .ss-panel .ss-t { font-size: 0.95rem; }
  /* chevron cue right below the text (Y-only bob so it stays centred) */
  .ss-cue {
    margin-top: 0.7rem; font-size: 1.4rem; line-height: 1; color: #fdf8f5; opacity: 0.75;
    pointer-events: none; animation: hint-bob 2s ease-in-out infinite;
  }

  /* Even vertical rhythm down the programme column on phones: the gap
     image->dress code, dress code->after party, and after party->next image
     are all made equal. The last two gaps are driven by margins (below), so
     zero the section paddings that otherwise pad the after-party->FAQ seam. */
  .prog-photo { margin-bottom: 2.2rem; }              /* image -> dress code   */
  .prog-note { margin-bottom: 2.2rem; }               /* dress code -> after party */
  /* after party -> FAQ banner: match the section-top breathing room so it equals
     the gap above "programme" and the gap above "frequently asked questions". */
  .prog-note:last-child { margin-bottom: var(--section-top); }
  .programme { padding-bottom: 0; }
  .faq { padding-top: 0; }

}

/* ---------- rsvp form ---------- */

.rsvp-form { max-width: 520px; margin: 1.5rem auto 0; text-align: left; }
.rsvp-form[hidden] { display: none; }
/* Send RSVP: brown (matches the form text) and centred in the form. */
.rsvp-form .btn { background: var(--ink); display: block; width: fit-content; margin: 0.5rem auto 0; }
.rsvp-form .btn:hover { background: #5f4c3e; }
.thanks-note { text-align: center; color: var(--sage); }

.rsvp-done { text-align: center; padding: 1.5rem 0 0.5rem; }
.rsvp-done[hidden] { display: none; }
.done-msg { font-size: clamp(1.45rem, 3.2vw, 2rem); color: var(--ink); text-transform: lowercase; white-space: nowrap; width: max-content; position: relative; left: 50%; transform: translateX(-50%); margin: 0 0 2.3rem; line-height: 1.3; }
/* Phones: let the confirmation line wrap (placed after the base rule so it wins) */
@media (max-width: 760px) {
  .done-msg { white-space: normal; width: auto; left: auto; transform: none; max-width: 100%; }
}
/* Second half of the RSVP title / confirmation line: inline on desktop (one
   line), forced onto its own line on phones. */
.mob-line2 { display: inline; }
@media (max-width: 640px) {
  .mob-line2 { display: block; }
}
/* Venue reminder under the date/time in the RSVP zone. */
.rsvp-venue { margin: 0.15rem 0 3rem; font-family: var(--serif); color: var(--ink); font-size: var(--body-size); line-height: 1.45; }
.rsvp-venue span { display: block; }
/* Address opens the map modal, but looks like plain text (no colour/underline). */
.venue-link { display: block; color: inherit; text-decoration: none; cursor: pointer; }

/* Add-to-calendar: three provider buttons. */
.cal-links { text-align: center; margin: 0 0 3.2rem; }
.cal-links[hidden] { display: none; }
.cal-label { display: block; font-family: var(--sans); text-transform: lowercase; letter-spacing: 0.03rem; font-size: 0.95rem; color: var(--burgundy); margin-bottom: 0.55rem; }
.cal-btns { display: inline-flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; }
.cal-btn { display: inline-block; font-family: var(--sans); font-size: 0.85rem; letter-spacing: 0.03rem; color: var(--burgundy); border: 1px solid var(--burgundy); border-radius: 999px; padding: 0.4rem 1.05rem; text-decoration: none; transition: background 0.15s, color 0.15s; }
.cal-btn:hover { background: var(--burgundy); color: #fdf8f5; }
/* Match the Send-RSVP-to-footer distance in the form state (the empty status
   line there sits below the button) so the done state ends the same way. */
#edit-rsvp { font-size: 0.72rem; margin-bottom: 49px; }
/* Desktop shows the full question; phones swap to the short label. The mobile
   override sits right after this base rule so cascade order lets it win. */
.edit-short { display: none; }
@media (max-width: 640px) {
  .edit-full { display: none; }
  .edit-short { display: inline; }
}
.field { border: none; padding: 0; margin: 0 0 1.8rem; }
.field legend {
  font-family: var(--serif);
  font-size: 1.25rem;
  color: var(--ink);
  margin-bottom: 0.7rem;
  padding: 0;
}
.radio, .check { display: flex; align-items: center; gap: 0.6rem; padding: 0.35rem 0; cursor: pointer; }
.checks { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.2rem 1rem; margin-bottom: 0.8rem; }
.radio input, .check input { accent-color: var(--ink); width: 1.05rem; height: 1.05rem; }

.text-input {
  width: 100%;
  font-family: var(--sans);
  font-size: 1rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--paper);
  color: var(--ink);
  margin-top: 0.4rem;
}
.text-input:focus { outline: none; border-color: var(--gold-soft); box-shadow: 0 0 0 3px rgba(201,177,138,0.2); }

.rsvp-status { margin-top: 1rem; font-family: var(--serif); font-size: 1.15rem; min-height: 1.4rem; }
.rsvp-status.success { color: var(--sage); }
.rsvp-status.error { color: var(--danger); }
.rsvp-status.sending { color: var(--muted); }

/* ---------- footer ---------- */

.site-footer { text-align: center; padding: clamp(1rem, 2.4vw, 1.5rem) 1.5rem; background: var(--burgundy); position: relative; }
/* ===== EDIT FOOTER SEAL SIZE HERE (middle value = seal width) ===== */
/* Negative top margin lifts the seal above the footer's top edge so it looks
   like it's "sealing" the footer. Make it MORE negative to pop it up further. */
.footer-seal { width: clamp(63px, 8.4vw, 105px); height: auto; display: block; margin: -4.6rem auto 0; position: relative; z-index: 2; }
/* Phones: the -4.6rem pull is sized for the 105px desktop seal and yanks the
   smaller 63px mobile seal entirely off the footer. Pull up ~half its height so
   it still pokes above the edge. Placed AFTER the base rule so the margin
   shorthand above doesn't reset our margin-top (cascade order, not specificity). */
@media (max-width: 640px) {
  .footer-seal { margin-top: -3.0rem; }
}
.footer-date { margin: 0; font-family: var(--sans); color: var(--wax); letter-spacing: 0.25rem; font-size: clamp(0.85rem, 2vw, 1.05rem); }

/* ---------- admin ---------- */

/* Match the invitation's palette. Base accents (stat numbers, links, icons, the
   small table Save button) use brown via the retinted gold token; prominent
   buttons and section headers use maroon. Invite pages use a different body
   class, so they keep their own gold. */
.admin-body { background: var(--cream); --gold: #765e4d; --gold-soft: #a98a6f; }

/* Section headers + page title in maroon. */
.admin-body .admin-title,
.admin-body .panel h2,
.admin-body .sum-h,
.admin-body .modal-box h3 { color: var(--burgundy); }

/* Big buttons in maroon: solid ones fill, ghost ones outline. The tiny table
   buttons (Save/Delete/Copy) are excluded and keep their own styling. */
.admin-body .btn:not(.tiny):not(.ghost):not(.ci-voice) { background: var(--burgundy); color: #fff; }
.admin-body .btn:not(.tiny):not(.ghost):not(.ci-voice):hover { background: var(--burgundy-dk); }
.admin-body .btn.ghost { color: var(--burgundy); border-color: var(--burgundy); }
.admin-body .btn.ghost:hover { background: var(--burgundy); color: #fff; }
/* Style the file input's "Choose Files" button like a ghost .btn (e.g. Add row). */
.admin-body input[type="file"] { font-family: var(--sans); font-size: 0.85rem; color: var(--muted); }
.admin-body input[type="file"]::file-selector-button {
  font-family: var(--sans); font-weight: 400; letter-spacing: 0.12rem; text-transform: uppercase;
  font-size: 0.8rem; background: transparent; color: var(--burgundy); border: 1px solid var(--burgundy);
  padding: 0.85rem 2rem; border-radius: 2px; cursor: pointer; margin-right: 0.9rem;
  transition: background 0.2s, color 0.2s;
}
.admin-body input[type="file"]::file-selector-button:hover { background: var(--burgundy); color: #fff; }

/* Small solid table button (Save) stays brown with a darker-brown hover, and
   gets a transparent 1px border so its box height matches the outlined Delete
   button beside it — that's what lines up their top/bottom edges. */
.admin-body .btn.tiny:not(.danger):not(.invite-btn) { border: 1px solid transparent; }
.admin-body .btn.tiny:not(.ghost):not(.danger):not(.invite-btn):hover { background: #5f4c3e; }

/* Copy invite is now a compact emoji icon (no button chrome). */
.admin-body .invite-btn { background: none; border: none; box-shadow: none; min-width: 0; padding: 0.2rem 0.4rem; font-size: 1.15rem; line-height: 1; color: inherit; }
.admin-body .invite-btn:hover { background: none; }
.admin-body .invite-btn.copied { background: none; color: var(--sage); }

/* Clickable guest name in the Responses table (opens the edit modal). */
.admin-body .resp-name { background: none; border: none; padding: 0; font: inherit; color: var(--burgundy); cursor: pointer; text-decoration: none; }
.admin-body .resp-name:hover { color: var(--burgundy-dk); }

/* Larger modal for the edit form. */
.modal-box-lg { max-width: 520px; max-height: 85vh; overflow-y: auto; text-align: left; }
.edit-form .field { margin-bottom: 1.2rem; }
/* +1 details: the guest name sits directly above the dietary checkboxes with no
   gap — add one so it matches the spacing below the checkboxes. Adjacent-sibling
   selector targets only checks that follow an input (not the main dietary list,
   which follows its legend). */
.edit-form .text-input + .checks { margin-top: 1.2rem; }
.edit-actions { display: flex; gap: 0.8rem; margin-top: 0.5rem; }

/* Display-name column button (emoji) + its modal form. */
.disp-btn { background: none; border: none; cursor: pointer; font-size: 1.1rem; line-height: 1; padding: 0.2rem 0.4rem; border-radius: 3px; }
.disp-form { display: flex; flex-direction: column; gap: 0.4rem; align-items: stretch; }

/* Programme editor. */
.programme-form { display: flex; flex-direction: column; gap: 0.6rem; align-items: flex-start; }
.prog-rows { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; max-width: 560px; }
.prog-row { display: flex; gap: 0.5rem; align-items: center; }
.prog-row .text-input { margin-top: 0; }
.prog-time { flex: 0 0 9rem; }
.prog-label { flex: 1; min-width: 0; }
.prog-del { flex: 0 0 auto; align-self: stretch; }
.prog-start-check { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.85rem; color: var(--ink); white-space: nowrap; cursor: pointer; }
.prog-start-check input { cursor: pointer; }
.prog-rows { max-width: 640px; }
.prog-actions { display: flex; gap: 0.8rem; margin-top: 0.4rem; }

/* Note emoji button in the guest table. */
.note-cell-btn { background: none; border: none; cursor: pointer; font-size: 1.05rem; line-height: 1; padding: 0.2rem 0.35rem; border-radius: 3px; }
.note-cell-btn.has-note { background: radial-gradient(circle at center, rgba(242,199,74,0.7) 0%, rgba(242,199,74,0.28) 45%, rgba(242,199,74,0) 72%); }

/* Custom Start/End programme picker. */
.pp-field { display: inline-flex; flex-direction: column; gap: 0.2rem; }
.pp-name { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08rem; color: var(--muted); }
/* Prog modal: Start and End side by side, with generous space above (from the
   explanation) and below (to the buttons). */
.pp-row { display: flex; gap: 1.75rem; margin: 1.5rem 0 1.7rem; flex-wrap: wrap; }
.pp-row .pp-field { align-items: flex-start; }
.prog-picker { position: relative; display: inline-block; }
.pp-toggle { position: relative; font-family: var(--sans); font-size: 0.9rem; color: var(--ink); background: var(--paper); border: 1px solid var(--line); border-radius: 3px; padding: 0.45rem 1.7rem 0.45rem 0.7rem; cursor: pointer; min-width: 6.5rem; text-align: left; }
.pp-toggle::after { content: '▾'; position: absolute; right: 0.6rem; top: 50%; transform: translateY(-50%); color: var(--muted); font-size: 0.7rem; pointer-events: none; }
.prog-picker.open .pp-toggle { border-color: var(--burgundy-lt); }
.pp-menu { list-style: none; margin: 0.25rem 0 0; padding: 0.25rem; position: absolute; top: 100%; left: 0; z-index: 30; min-width: 100%; width: max-content; max-width: 20rem; background: var(--paper); border: 1px solid var(--line); border-radius: 4px; box-shadow: var(--shadow); text-align: left; }
.pp-menu[hidden] { display: none; }
.pp-opt { padding: 0.4rem 0.6rem; font-size: 0.88rem; color: var(--ink); border-radius: 3px; cursor: pointer; white-space: nowrap; }
.pp-opt:hover { background: #efe6d8; }

/* Email-all-guests panel. */
.email-form { display: flex; flex-direction: column; gap: 0.8rem; align-items: flex-start; max-width: 560px; }
.email-form .text-input { width: 100%; margin-top: 0; }
.email-check { display: flex; align-items: flex-start; gap: 0.5rem; font-size: 0.9rem; color: var(--ink); }
.email-check input { margin-top: 0.2rem; }
.email-images { display: flex; flex-direction: column; gap: 0.35rem; width: 100%; }
.email-images-label { font-size: 0.85rem; color: var(--muted); }
.email-images input[type="file"] { font-size: 0.85rem; }
.email-tip { font-size: 0.8rem; margin: 0.1rem 0 0.3rem; }
.email-check code, .email-tip code { background: #f0e7d7; padding: 0.05rem 0.35rem; border-radius: 3px; font-size: 0.85em; }
.email-warn { color: var(--danger); }
.email-result { font-family: var(--serif); margin: 0 0 0.9rem; font-size: 1.05rem; }
.email-result.ok { color: var(--sage); }
.email-result.err { color: var(--danger); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; pointer-events: none; }

/* ---------- admin: phone tuning ---------- */
@media (max-width: 640px) {
  /* Title + hamburger on one line; the links drop into a dropdown panel. */
  .admin-header { flex-wrap: nowrap; gap: 0.6rem; }
  .admin-body .admin-title { font-size: 1.35rem; }
  .admin-body .admin-nav { position: relative; flex: 0 0 auto; }
  /* Plain three-line hamburger (no box). */
  .admin-body .nav-toggle { display: inline-flex; flex-direction: column; justify-content: center; align-items: center;
    gap: 5px; box-sizing: border-box; width: 34px; height: 34px; padding: 0; cursor: pointer;
    background: transparent; border: none; }
  .admin-body .nav-toggle span { display: block; width: 22px; height: 2px; border-radius: 2px; background: var(--burgundy); }
  .admin-body .nav-links { display: none; position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
    flex-direction: column; align-items: stretch; gap: 0; min-width: 190px;
    background: var(--paper); border: 1px solid var(--line); border-radius: 10px; padding: 0.25rem 0.5rem;
    box-shadow: 0 10px 28px rgba(0,0,0,0.14); }
  .admin-body .admin-nav.open .nav-links { display: flex; }
  .nav-arrow { display: none; }
  /* Menu items: plain rows with faint dividers between them. */
  .admin-body .admin-nav .nav-links .btn { border: none; background: transparent; color: var(--burgundy);
    border-radius: 0; height: 40px; width: 100%; justify-content: flex-start;
    padding: 0 0.6rem; font-size: 0.72rem; letter-spacing: 0.04rem; }
  .admin-body .admin-nav .nav-links .btn:hover { background: rgba(112,29,45,0.06); color: var(--burgundy); }
  .admin-body .admin-nav .nav-links > *:not(:first-child) { border-top: 1px solid var(--line); }
  .admin-body .nav-links form .btn { width: 100%; }
  /* "Download Excel" -> "Excel" to save space in the responses header. */
  .admin-body .dl-word { display: none; }
}
.admin-login { max-width: 380px; margin: 12vh auto; text-align: center; padding: 2rem; }
.admin-title { font-size: 2rem; font-weight: 500; margin: 0.5rem 0 1.5rem; }
.login-form { display: flex; flex-direction: column; gap: 1rem; }
.login-form input { padding: 0.8rem 1rem; border: 1px solid var(--line); border-radius: 3px; font-size: 1rem; }
.form-error { color: var(--danger); }

.admin-wrap { max-width: 1300px; margin: 0 auto; padding: 2rem 1.5rem 5rem; }
.admin-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
.admin-header .admin-title { margin: 0; }

.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 2rem; }
.stat { background: var(--paper); border: 1px solid var(--line); border-radius: 4px; padding: 1.2rem; text-align: center; box-shadow: var(--shadow); }
.stat .num { display: block; font-family: var(--serif); font-size: 2.2rem; color: var(--gold); line-height: 1; }
.stat .lbl { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.12rem; color: var(--muted); }

.panel { background: var(--paper); border: 1px solid var(--line); border-radius: 6px; padding: 1.5rem; margin-bottom: 1.5rem; box-shadow: var(--shadow); }
.panel h2 { font-family: var(--serif); font-weight: 500; font-size: 1.5rem; margin: 0 0 1rem; }
.muted { color: var(--muted); }

/* flex-end so the Side select + Start/End picker boxes bottom-align (the pickers
   carry a label above their box). */
.inline-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 1rem; }
.inline-form input[type="text"] { flex: 1; min-width: 200px; padding: 0.6rem 0.8rem; border: 1px solid var(--line); border-radius: 3px; font-size: 1rem; font-family: var(--sans); color: var(--ink); background: var(--paper); }
.inline-form input[type="text"]::placeholder { color: var(--muted); }
.inline-form input[type="text"]:focus { outline: none; border-color: var(--burgundy-lt); box-shadow: 0 0 0 3px rgba(112,29,45,0.12); }

.table-scroll { overflow-x: auto; }
.guest-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.guest-table th { text-align: left; font-weight: 400; text-transform: uppercase; letter-spacing: 0.08rem; font-size: 0.72rem; color: var(--muted); border-bottom: 1px solid var(--line); padding: 0.6rem 0.7rem; }
.guest-table td { border-bottom: 1px solid var(--line); padding: 0.6rem 0.7rem; vertical-align: middle; }
.guest-table td.center { text-align: center; }
.name-input { width: 100%; min-width: 160px; padding: 0.4rem 0.6rem; border: 1px solid var(--line); border-radius: 3px; font-size: 0.92rem; font-family: var(--sans); color: var(--ink); background: var(--paper); }
.name-input:focus { outline: none; border-color: var(--burgundy-lt); box-shadow: 0 0 0 3px rgba(112,29,45,0.12); }
.msg-cell { max-width: 220px; }
.small-txt { font-size: 0.78rem; white-space: nowrap; }

.link-cell { display: flex; gap: 0.4rem; align-items: center; }
.link-input {
  width: 11rem;
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  font-family: var(--sans);
  font-size: 0.82rem;
  color: var(--ink);
  background: var(--paper);
  cursor: pointer;
  user-select: none;
  transition: border-color 0.15s, background 0.15s;
}
.link-input:hover { border-color: var(--gold-soft); }
.link-input.copied { border-color: var(--sage); background: #eef2e8; color: var(--sage); }

.side-text { white-space: nowrap; font-size: 1.1rem; color: var(--ink); text-align: center; }

/* Responses: filter bar, sortable headers, stacked dietary */
.panel-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-bottom: 0.5rem; }
.panel-head h2 { margin: 0; }

.filters { display: flex; flex-wrap: wrap; gap: 1rem; margin: 0.5rem 0 1.2rem; }
.filters label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08rem; color: var(--muted); }
.filters select,
.filters .filter-search { box-sizing: border-box; height: 34px; padding: 0 0.6rem; border: 1px solid var(--line); border-radius: 3px; font-family: var(--sans); font-size: 0.9rem; background: var(--paper); color: var(--ink); }
.filters .filter-search { min-width: 11rem; }

th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.sortable:hover { color: var(--gold); }
th.sortable::after { content: '\2195'; opacity: 0.35; margin-left: 0.3rem; font-size: 0.8em; }
th.sortable.sort-asc::after { content: '\2191'; opacity: 1; }
th.sortable.sort-desc::after { content: '\2193'; opacity: 1; }

.diet-line { white-space: nowrap; }
.diet-note { font-style: italic; color: var(--muted); font-size: 0.85rem; margin-top: 0.15rem; }

/* Wide enough to contain "Copy invite" so the swap to "Copied!" never resizes it. */
.copy-btn { min-width: 7rem; text-align: center; white-space: nowrap; }
.copy-btn.copied { background: var(--sage); }

.side-select {
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  font-family: var(--sans);
  font-size: 1rem;
  background: var(--paper);
  color: var(--ink);
}
/* In "Add a guest", the Side dropdown + Start picker match the name input height. */
.inline-form .pp-toggle { padding: 0.6rem 1.7rem 0.6rem 0.8rem; font-size: 1rem; }

/* Summary panel */
.summary-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.6rem; }
.summary-grid-3 { grid-template-columns: repeat(3, 1fr); }
.sum-card { text-align: center; background: #fbf8f2; border: 1px solid var(--line); border-radius: 4px; padding: 1rem 0.5rem; }
.sum-num { display: block; font-family: var(--serif); font-size: 1.9rem; color: var(--gold); line-height: 1; }
.sum-lbl { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1rem; color: var(--muted); }
.summary-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; }
.sum-h { font-family: var(--serif); font-weight: 500; font-size: 1.15rem; margin: 0.5rem 0 0.6rem; color: var(--ink); }
.sum-list { list-style: none; padding: 0; margin: 0; }
.sum-list li { display: flex; justify-content: space-between; gap: 1rem; padding: 0.35rem 0; border-bottom: 1px dotted var(--line); font-size: 0.92rem; }
.sum-list li b { font-family: var(--serif); color: var(--gold); font-weight: 500; }
.sum-notes { margin: 0.3rem 0 0; padding-left: 1.1rem; color: var(--ink); font-size: 0.92rem; }
.sum-notes li { padding: 0.15rem 0; }

/* Keep the cell as a real table-cell (not flex) so the base vertical-align:middle
   centres the buttons within the row — a flex td sizes to its content and sits at
   the top of taller rows, throwing the Save/Delete off. Lay the two forms out
   inline instead. */
.actions { text-align: center; white-space: nowrap; }
.actions form { display: inline-block; margin: 0; vertical-align: middle; }
.actions form + form { margin-left: 0.4rem; }

.pill { display: inline-block; padding: 0.2rem 0.7rem; border-radius: 999px; font-size: 0.72rem; letter-spacing: 0.05rem; white-space: nowrap; }
.pill.yes { background: #e5ecdd; color: var(--sage); }
.pill.no { background: #f2e0da; color: var(--danger); }
.pill.pending { background: #efe8db; color: var(--muted); }
/* Pending pill is a button (click to fill in the guest's RSVP for them) but must
   match the plain span pills exactly, so reset the button chrome. */
button.pill.fill-rsvp { -webkit-appearance: none; appearance: none; border: none; margin: 0; font-family: inherit; line-height: inherit; cursor: pointer; transition: background 0.15s, color 0.15s; }
button.pill.fill-rsvp:hover { background: var(--burgundy); color: #fff; }

/* Message icon + modal */
.msg-btn { background: none; border: none; cursor: pointer; font-size: 1.15rem; color: var(--gold); padding: 0.2rem 0.45rem; border-radius: 3px; line-height: 1; }
.msg-btn:hover { background: #f0e7d7; }

.modal { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 50; padding: 1rem; }
.modal[hidden] { display: none; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(51, 48, 43, 0.45); }
.modal-box { position: relative; z-index: 1; background: var(--paper); border-radius: 6px; padding: 2rem; max-width: 460px; width: 100%; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25); }
.modal-box h3 { font-family: var(--serif); font-weight: 500; font-size: 1.3rem; margin: 0 0 0.8rem; color: var(--gold); }
.modal-box p { margin: 0; white-space: pre-wrap; line-height: 1.6; color: var(--ink); }
.modal-close { position: absolute; top: 0.4rem; right: 0.8rem; background: none; border: none; font-size: 1.7rem; line-height: 1; color: var(--muted); cursor: pointer; }
.modal-close:hover { color: var(--ink); }

/* Settings subsections */
.settings-hint { font-size: 0.85rem; margin-top: 0; }
.settings-hint code { background: #f0e7d7; padding: 0.05rem 0.35rem; border-radius: 3px; font-size: 0.85em; }
.message-form { display: flex; flex-direction: column; gap: 0.8rem; align-items: flex-start; }
.rsvp-labels-form { display: flex; flex-direction: column; gap: 0.9rem; align-items: flex-start; max-width: 420px; }
.rsvp-labels-form .stacked-label { display: flex; flex-direction: column; gap: 0.3rem; width: 100%; }
.rsvp-labels-form .stacked-label span { font-size: 0.85rem; color: var(--muted); letter-spacing: 0.03rem; }
.msg-template { width: 100%; font-family: var(--sans); line-height: 1.5; resize: vertical; }
.dietary-list { list-style: none; padding: 0; margin: 0 0 1rem; display: flex; flex-wrap: wrap; gap: 0.6rem; }
.dietary-list li { margin: 0; }
.dietary-chip-form { margin: 0; }
.dietary-chip {
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: #fbf8f2; border: 1px solid var(--line); border-radius: 999px;
  padding: 0.35rem 0.95rem; font-family: var(--sans); font-size: 0.9rem; color: var(--ink);
  cursor: pointer; transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.dietary-chip .chip-x { opacity: 0; width: 0; overflow: hidden; font-size: 1.05rem; line-height: 1; transition: opacity 0.15s; }
.dietary-chip:hover { background: var(--danger); border-color: var(--danger); color: #fff; }
.dietary-chip:hover .chip-x { opacity: 1; width: auto; }
.dietary-add { margin-top: 0.5rem; }

/* Relatives view (second password): a small gold star after the admin title. */
.role-star { color: var(--gold); }

/* ---------- day-of check-in ---------- */
/* Reception: searchable attendee list with check-in buttons. */
.checkin-wrap { max-width: 720px; }
/* Only two header buttons here, so keep them together on one line like /admin. */
.checkin-wrap .admin-nav { flex-wrap: nowrap; }
/* Arrival stats: arrived count, percentage, and the next programme item. */
.ci-stats { display: grid; grid-template-columns: 1fr 1fr 1.6fr; gap: 0.75rem; margin: 0 0 1.4rem; }
.ci-stat { background: #fff; border: 1px solid var(--line); border-radius: 10px; padding: 0.8rem 0.9rem;
  display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.ci-stat-num { font-family: var(--serif); font-size: 1.7rem; line-height: 1; color: var(--burgundy); }
.ci-stat-lbl { font-size: 0.75rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
.ci-next { background: var(--burgundy); border-color: var(--burgundy); color: #fdf6ef; }
.ci-next-eyebrow { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.12em; opacity: 0.8; }
.ci-next-label { font-family: var(--serif); font-size: 1.15rem; line-height: 1.15; }
.ci-next-sub { font-size: 0.8rem; opacity: 0.88; }
@media (max-width: 560px) {
  .ci-stats { grid-template-columns: 1fr 1fr; }
  .ci-next { grid-column: 1 / -1; flex-direction: row; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
  .ci-next-eyebrow { order: 0; }
  .ci-next-label { order: 1; }
  .ci-next-sub { order: 2; margin-left: auto; }
}
.checkin-search { display: flex; gap: 0.6rem; align-items: stretch; margin-bottom: 0.4rem; }
.checkin-search .text-input { flex: 1; margin-top: 0; }
/* Circular voice button: stretches to the search box's height, kept square by
   aspect-ratio, transparent fill with just the maroon outline. */
.ci-voice { flex: 0 0 auto; width: 42px; height: 42px;
  padding: 0; border-radius: 50%; background: transparent; border: 1px solid var(--burgundy);
  color: var(--burgundy); font-size: 1.1rem; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; }
.ci-voice:hover { background: rgba(112,29,45,0.07); }
.ci-voice.is-listening { background: var(--burgundy); color: #fff; animation: ciPulse 1.1s ease-in-out infinite; }
@keyframes ciPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(112,29,45,0.4); } 50% { box-shadow: 0 0 0 6px rgba(112,29,45,0); } }
.ci-voice-status { color: var(--muted); font-size: 0.85rem; margin: 0 0 0.6rem; }
.checkin-list { list-style: none; padding: 0; margin: 0.6rem 0 0; }
.ci-row { display: flex; align-items: center; gap: 0.8rem; padding: 0.7rem 0.9rem; border: 1px solid var(--line);
  border-radius: 10px; margin-bottom: 0.5rem; border-left: 4px solid var(--muted); }
.ci-row.side-groom { border-left-color: var(--gold); }
.ci-row.side-bride { border-left-color: var(--burgundy); }
.ci-row.is-plus { border-style: dashed; }
.ci-row.is-in { background: #eef6e6; border-color: #bcd7a8; }
.ci-info { display: flex; flex-direction: column; gap: 0.15rem; margin-right: auto; min-width: 0; }
.ci-name { font-family: var(--serif); font-size: 1.05rem; color: var(--ink); }
/* Dietary / allergies shown inline after the table, for reception to confirm. */
.ci-diet { color: var(--burgundy); font-weight: 600; }
.ci-meta { font-size: 0.8rem; color: var(--muted); }
.ci-row.is-in .ci-meta::after { content: " · arrived"; color: #5f9146; }
.ci-qr { flex: 0 0 auto; }
/* Check-in toggle: an empty ring that fills once the guest has arrived.
   Click to check in, click again to undo. */
.ci-toggle { flex: 0 0 auto; width: 26px; height: 26px; padding: 0; border-radius: 50%;
  border: 2px solid var(--burgundy); background: transparent; cursor: pointer; box-shadow: none;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.08s ease; }
.ci-toggle:hover { background: rgba(112, 29, 45, 0.12); }
.ci-toggle:active { transform: scale(0.9); }
.ci-toggle.is-on { background: var(--burgundy); border-color: var(--burgundy); }
.ci-toggle.is-on:hover { background: var(--burgundy); opacity: 0.85; }
/* QR stays outlined on hover (no fill). */
.admin-body .checkin-list .ci-qr.btn:hover { background: transparent; color: var(--burgundy); }
/* Per-guest QR modal on reception. */
.qr-box { display: flex; flex-direction: column; align-items: center; text-align: center; max-width: 360px; }
.qr-box h3 { margin: 0 0 0.1rem; }
.qr-box .qr-table { font-family: var(--serif); color: var(--burgundy); font-size: 1.1rem; margin: 0.2rem 0 1.5rem; }
.qr-holder { display: block; background: #fff; border: 1px solid var(--line); border-radius: 14px; padding: 1rem; text-decoration: none; cursor: pointer; }
.qr-holder img { display: block; width: clamp(200px, 60vw, 280px); height: auto; aspect-ratio: 1; }
.qr-box .qr-hint { color: var(--muted); font-size: 0.9rem; margin: 1.5rem 0 0; }

/* Welcome display: full-screen, high-contrast, for a tablet by the door. */
.display-body { margin: 0; min-height: 100vh; background: var(--burgundy); color: #fdf6ef;
  display: flex; align-items: center; justify-content: center; text-align: center; padding: 4vmin; }
.display-idle, .display-welcome { width: 100%; max-width: 900px; }
.display-eyebrow { font-family: var(--sans); text-transform: uppercase; letter-spacing: 0.25em;
  font-size: clamp(0.8rem, 2.5vmin, 1.1rem); opacity: 0.8; margin: 0 0 1rem; }
.display-couple { font-family: var(--name, var(--serif)); font-weight: 400; letter-spacing: 0.04em;
  font-size: clamp(2.2rem, 9vmin, 5rem); margin: 0 0 2rem; line-height: 1.1; }
.display-couple span { opacity: 0.7; }
.display-programme h2 { font-family: var(--serif); font-weight: 400; font-size: clamp(1rem, 3vmin, 1.5rem);
  opacity: 0.85; margin: 0 0 0.8rem; }
.display-programme ul { list-style: none; padding: 0; margin: 0 auto; max-width: 540px; }
.display-programme li { display: flex; justify-content: space-between; gap: 1.5rem; padding: 0.4rem 0;
  border-bottom: 1px solid rgba(253,246,239,0.18); font-size: clamp(0.95rem, 2.6vmin, 1.3rem); }
.dp-time { opacity: 0.85; white-space: nowrap; }
.dp-label { text-align: right; }
/* Keep the hidden attribute working even though these sections are flex. */
.display-idle[hidden], .display-welcome[hidden] { display: none; }
/* Welcome overlay: two halves. Left = welcome text, pinned to the bottom.
   Right = hint above a centred QR card. */
.display-welcome { display: flex; flex-direction: row; align-items: stretch;
  gap: 5vmin; width: 100%; max-width: 940px; text-align: left; }
.dw-info { flex: 1 1 50%; min-width: 0; display: flex; flex-direction: column;
  justify-content: flex-end; align-items: flex-start; padding-bottom: 0.5rem; }
.dw-name { font-family: var(--name, var(--serif)); font-weight: 400; font-size: clamp(2.6rem, 11vmin, 7rem);
  margin: 0 0 0.6rem; line-height: 1.05; }
.dw-table { font-family: var(--serif); font-size: clamp(1.4rem, 5vmin, 3rem); margin: 0; }
/* The "see our host" fallback is a sentence, not a table number — keep it small. */
.dw-table.is-pending { font-size: clamp(1rem, 2.6vmin, 1.3rem); opacity: 0.85; }
/* Right half: the QR card is centred; the hint floats just above it. */
.dw-qr-side { flex: 1 1 50%; min-width: 0; display: flex; align-items: center; justify-content: center; }
.dw-qr-wrap { position: relative; display: inline-flex; background: #fdf6ef; color: var(--ink);
  padding: 1.8rem; border-radius: 18px; }
.dw-qr-hint { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%);
  margin-bottom: 1.2rem; font-family: var(--serif); font-size: clamp(1rem, 2.6vmin, 1.4rem);
  color: #fdf6ef; opacity: 0.9; white-space: nowrap; }
.dw-qr { width: clamp(260px, 40vmin, 520px); height: auto; display: block; }
/* Portrait / narrow screens: stack text above the QR and centre everything. */
@media (max-width: 820px) {
  .display-welcome { flex-direction: column; align-items: center; text-align: center;
    gap: 4vmin; min-height: 0; }
  .dw-info { flex: 0 0 auto; align-items: center; justify-content: center; padding-bottom: 0; }
  .dw-qr-side { flex: 0 0 auto; margin-top: 3rem; }
}

/* Guest day page (the QR target): seat map + their table + programme. */
/* Guest day page shares the invite's warm colour scheme: #fdf8f5 paper,
   --ink body text, --burgundy accents, gold map. */
.day-body { background: #fdf8f5; color: var(--ink); margin: 0; }
.day-wrap { max-width: 620px; margin: 0 auto; padding: 2rem 1rem 3rem; }
.day-head { text-align: center; margin-bottom: 1.5rem; }
.day-eyebrow { font-family: var(--sans); text-transform: uppercase; letter-spacing: 0.2em; color: var(--muted); margin: 0 0 0.9rem; font-size: 0.8rem; }
.day-name { font-family: 'New Icon Script', var(--serif); font-weight: 400; text-transform: none; color: var(--burgundy); font-size: clamp(2.6rem, 12vw, 3.8rem); line-height: 1.2; margin: 0; }
.day-seat { text-align: center; background: var(--paper); border: 1px solid var(--line); border-radius: 14px;
  padding: 1.2rem; margin-bottom: 1.8rem; }
.day-seat-cap { font-family: var(--sans); text-transform: uppercase; letter-spacing: 0.15em; color: var(--muted); font-size: 0.75rem; margin: 0; }
.day-seat-table { font-family: var(--serif); color: var(--burgundy); font-size: clamp(1.8rem, 8vw, 2.6rem); margin: 0.3rem 0 0; }
.day-seat-name { color: var(--muted); margin: 0.2rem 0 0; }
.day-seat-pending { color: var(--ink); margin: 0.3rem 0 0; }
.day-h { font-family: var(--serif); font-weight: 400; color: var(--burgundy); text-align: center; font-size: 1.2rem; margin: 0 0 0.8rem; }
.day-map-section { margin-bottom: 2rem; }
/* The floor renders at its natural 720px and is scaled to fit by seating-view.js.
   The wrapper is sized to the scaled square and centred (margin auto); overflow
   is hidden so nothing scrolls inside it. Uniform scale keeps the aspect ratio. */
.day-body .day-floor-scroll { overflow: hidden; margin: 0 auto; touch-action: pan-y; }
.day-body .day-floor { width: 720px; height: 720px; min-width: 0; max-width: none; margin: 0; background: transparent; }
.day-body .table-token { cursor: default; }
/* Read-only token states on the guest map — same palette as the actual seating
   plan (gold tables + pillars), with a light glow + a maroon dot marking the
   guest's own table and their exact seat. */
.table-token.is-other .tt-body { border-color: var(--gold-soft); }
.table-token.is-mine .tt-body { border-color: var(--burgundy); background: transparent; animation: mineGlow 2.6s ease-in-out infinite; }
@keyframes mineGlow {
  0%, 100% { box-shadow: 0 0 14px 4px rgba(207,143,158,0.38); }
  50%      { box-shadow: 0 0 42px 13px rgba(207,143,158,0.62); }
}
.table-token.is-mine .tt-label { color: var(--burgundy); font-weight: 600; }
.tt-seat.is-mine-seat { background: var(--burgundy); border-color: var(--burgundy); width: 13px; height: 13px; }
.day-map-hint { text-align: center; color: var(--muted); font-size: 0.85rem; margin: 0 0 0.7rem; }
.day-prog-list { list-style: none; padding: 0; margin: 0 auto; max-width: 420px; }
.day-prog-list li { display: flex; justify-content: space-between; gap: 1rem; padding: 0.5rem 0; border-bottom: 1px solid var(--line); }
.day-foot { text-align: center; color: var(--muted); font-family: var(--serif); margin-top: 2.5rem; }

/* ---- Dark theme for the guest day page (always on; .day-dark is fixed on the
   day <body>). Deep burgundy background matching the welcome display, white text
   and seat map, with a pale-yellow glow on the guest's own table. Scoped to
   .day-dark so nothing else is affected. */
.day-dark {
  --paper: #701d2d;
  --ink: #fdf6ef;        /* cream-white text, matching the check-in welcome display */
  --muted: #e4d1c8;      /* soft near-white for secondary text */
  --burgundy: #fdf6ef;   /* names & headings render white on the burgundy page */
  --gold: #f0d8a2;
  --gold-soft: #d3a3ad;
  --line: rgba(253, 246, 239, 0.26);
  --shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  color: var(--ink);
}
/* Same deep burgundy as the welcome display (.display-body background). */
.day-dark.day-body { background: #701d2d; }
/* Seat map on dark: white tables, pillars and grid lines on the burgundy floor,
   with a warm gold marker for the guest's own table. */
.day-dark .floor {
  --paper: #fdf6ef;      /* table bodies + seat dots render white */
  --ink: #701d2d;        /* table labels stay dark so they read on the white tables */
  --gold: #fdf6ef;
  --gold-soft: rgba(253, 246, 239, 0.5);
  --burgundy: #fdf6ef;
  background: transparent;   /* no grid lines on the guest day map */
}
.day-dark .floor-decor.fp-stage { background: #fdf6ef; border-color: rgba(253,246,239,0.6); color: #701d2d; }
.day-dark .floor-decor.fp-pillar { background: #fdf6ef; border-color: rgba(253,246,239,0.6); }
.day-dark .floor-decor.fp-aisle { background: rgba(255,255,255,0.06); }
/* The guest's own table: a solid white token set apart by the pale (whiter)
   yellow glow. */
.day-dark .table-token.is-mine .tt-body { background: #fff; border-color: #fff; animation-name: mineGlowDark; animation-duration: 1.6s; }
.day-dark .table-token.is-mine .tt-label { color: #701d2d; }
.day-dark .tt-seat.is-mine-seat { background: #f3d9a0; border-color: #f3d9a0; }
@keyframes mineGlowDark {
  0%, 100% { box-shadow: 0 0 30px 9px rgba(255, 248, 204, 0.5); }
  50%      { box-shadow: 0 0 72px 26px rgba(255, 248, 204, 0.8); }
}
/* "You're seated at" card: a solid white block with the words in the page's
   burgundy, inverting the rest of the dark page. */
.day-dark .day-seat { background: #fdf6ef; border-color: #fdf6ef; }
.day-dark .day-seat-cap,
.day-dark .day-seat-table,
.day-dark .day-seat-pending { color: #701d2d; }
.day-dark .day-seat-name { color: rgba(112, 29, 45, 0.72); }

/* ---------- seating plan ---------- */
.seating-wrap { max-width: 1480px; }
.admin-nav { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; justify-content: flex-end; }
.admin-nav form { margin: 0; display: flex; }
/* Desktop: links lay out inline (contents) and the hamburger is hidden. */
.nav-links { display: contents; }
.nav-toggle { display: none; }
/* Uniform page-nav buttons: same height + centred text whether <a> or <button>. */
.admin-nav .btn { display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box; height: 40px; padding: 0 1.1rem; line-height: 1; white-space: nowrap; }
.seating-note { background: #fbeee0; border: 1px solid var(--gold-soft); color: var(--ink);
  border-radius: 4px; padding: 0.6rem 0.9rem; font-size: 0.9rem; margin: 0 0 1rem; }

.seating-grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 1.5rem; align-items: start; }
.floor-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.8rem; }
.floor-head h2 { margin: 0; }
.floor-tools { display: flex; align-items: center; gap: 0.8rem; }
.save-tag { font-size: 0.8rem; color: var(--muted); min-width: 5.5rem; text-align: right; }
.save-tag.saving { color: var(--gold); }
.save-tag.ok { color: var(--sage); }
.save-tag.err { color: var(--danger); }
.floor-hint { font-size: 0.8rem; color: var(--muted); margin: 0.7rem 0 0; }
.mobile-view-note { display: none; font-size: 0.8rem; color: var(--burgundy); margin: 0.7rem 0 0; }

.floor-scroll { position: relative; overflow: auto; max-width: 720px; margin: 0 auto; }
/* The square banquet hall, held to a sensible size and centred. */
.floor { position: relative; width: 100%; max-width: 720px; min-width: 480px; margin: 0 auto;
  height: 720px; /* 20 grid squares wide x 20 tall (36px each) */
  background:
    repeating-linear-gradient(0deg, transparent 0 35px, rgba(112,29,45,0.06) 35px 36px),
    repeating-linear-gradient(90deg, transparent 0 35px, rgba(112,29,45,0.06) 35px 36px),
    transparent;
  border: 2px solid var(--gold-soft); border-radius: 4px; }

/* Alignment guide lines shown while dragging a table into line with another. */
.snap-guide { position: absolute; pointer-events: none; z-index: 5; background: var(--burgundy); opacity: 0.55; }
.snap-guide-v { top: 0; bottom: 0; width: 1px; margin-left: -0.5px; }
.snap-guide-h { left: 0; right: 0; height: 1px; margin-top: -0.5px; }

.floor-decor { position: absolute; pointer-events: none; color: var(--muted); box-sizing: border-box; }
/* Stage bar across the top, with a runway leading down into the aisle. */
.floor-decor.fp-stage { left: 35%; width: 30%; top: 2.5%; height: 15%; background: #fff;
  border: 1px solid var(--gold-soft); border-radius: 3px; display: flex; align-items: center;
  justify-content: center; text-align: center; font-size: 0.72rem; letter-spacing: 0.02rem; color: #9d7b82; }
.floor-decor.fp-aisle { left: 45%; width: 10%; top: 17.5%; height: 73%; background: rgba(112,29,45,0.05);
  border-left: 1px dashed var(--gold-soft); border-right: 1px dashed var(--gold-soft); }
/* Pillars/poles drawn the same diameter as a round table body (50px). */
.floor-decor.fp-pillar { width: 50px; height: 50px; margin: -25px 0 0 -25px; border-radius: 50%;
  background: #fff; border: 1px solid var(--gold); }

/* Maroon-ish palette for the whole seat map: remap the gold tokens to burgundy
   within the floor, so tables, seat rings and pillars all read maroon (applies
   to both the planner and the guest map). Green "full/filled" status is kept. */
.floor { --gold: #701d2d; --gold-soft: #b3808a; }

/* Table tokens (draggable). The token is a transparent box; .tt-body is the
   visible table, with seat dots (.tt-seat) placed around it. */
.table-token { position: absolute; transform: translate(-50%, -50%); cursor: grab;
  user-select: none; touch-action: none; }
.table-token.dragging { z-index: 6; cursor: grabbing; }
.tt-body { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center; background: var(--paper);
  border: 2px solid var(--burgundy); box-shadow: var(--shadow);
  transition: box-shadow 0.15s, border-color 0.15s, background 0.15s; }
.is-round .tt-body { border-radius: 50%; }
.is-rect .tt-body { border-radius: 9px; }
.table-token:hover .tt-body { box-shadow: 0 6px 16px rgba(112,29,45,0.28); }
.tt-label { font-family: var(--serif); font-size: 0.85rem; line-height: 1; color: var(--ink); }
.is-empty .tt-body { border-color: var(--gold-soft); }
.is-partial .tt-body { border-color: var(--gold); }
.is-full .tt-body { border-color: #5f9146; background: #eef6e6; animation: seatGlow 2.4s ease-in-out infinite; }
@keyframes seatGlow {
  0%, 100% { box-shadow: 0 0 0 3px rgba(95,145,70,0.28), 0 0 12px 2px rgba(95,145,70,0.42); }
  50%      { box-shadow: 0 0 0 3px rgba(95,145,70,0.45), 0 0 22px 6px rgba(95,145,70,0.68); }
}
.tt-seat { position: absolute; transform: translate(-50%, -50%); width: 11px; height: 11px;
  border-radius: 50%; background: var(--paper); border: 1px solid var(--gold-soft);
  box-shadow: 0 1px 2px rgba(0,0,0,0.12); }
.tt-seat.filled { background: #6e8f52; border-color: #4f6a3a; }

/* Hover tooltip */
.floor-tip { position: fixed; z-index: 80; pointer-events: none; background: #3b332c; color: #fdf8f0;
  font-size: 0.78rem; line-height: 1.35; padding: 0.4rem 0.6rem; border-radius: 5px;
  white-space: pre-line; max-width: 220px; box-shadow: 0 6px 18px rgba(0,0,0,0.28); }
.floor-tip[hidden] { display: none; }

/* Sidebar */
.people-panel { position: sticky; top: 1rem; }
.people-panel h2 { margin-bottom: 0.4rem; }
.people-count { font-size: 0.85rem; color: var(--muted); margin: 0 0 0.8rem; }
.people-panel .text-input { width: 100%; margin-bottom: 0.8rem; }
.people-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column;
  gap: 0.4rem; max-height: 13.5rem; overflow-y: auto; }
.people-empty { font-size: 0.85rem; color: var(--sage); margin: 0.5rem 0 0; }
.person-chip { padding: 0.4rem 0.7rem; border-radius: 4px; font-size: 0.9rem; color: var(--ink);
  background: #fbf8f2; border: 1px solid var(--line); border-left-width: 4px; }
.person-chip.is-plus { font-style: italic; }

/* "Who's at a table" browser in the sidebar. */
.table-browse { margin-top: 1.3rem; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.tb-h { font-family: var(--serif); font-weight: 400; color: var(--burgundy); font-size: 1rem; margin: 0 0 0.6rem; }
.table-browse .text-input { width: 100%; margin: 0 0 0.7rem; }
/* Fits ~10 rows without scrolling; only scrolls when a table holds more than 10. */
.tb-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem;
  max-height: 25.5rem; overflow-y: auto; }
.tb-row { display: flex; align-items: center; gap: 0.6rem; padding: 0.4rem 0.6rem; border-radius: 4px;
  font-size: 0.9rem; color: var(--ink); background: #fbf8f2; border: 1px solid var(--line); border-left-width: 4px; }
.tb-row.is-plus { font-style: italic; }
.tb-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-plus { color: var(--muted); font-style: normal; }
.tb-empty { font-size: 0.85rem; color: var(--muted); margin: 0.3rem 0 0; }

/* Live X/Y readout overlaid on the floor's top-left corner (no layout shift, so
   nothing jolts when it appears). Plain text, no background. */
.floor-coord { position: absolute; top: 6px; left: 8px; z-index: 10; margin: 0; pointer-events: none;
  font-family: var(--sans); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.04em; color: var(--burgundy); }

/* Side colour coding (chips + seat dots) */
.side-groom { border-left-color: #5b7aa8; }
.side-bride { border-left-color: #b5657e; }
.side-both { border-left-color: var(--gold); }
.side-unset { border-left-color: var(--muted); }

/* Table detail modal */
.modal-box-lg { max-width: 720px; }
.td-title { font-family: var(--serif); font-weight: 500; font-size: 1.3rem; color: var(--burgundy); margin: 0 0 0.9rem; }
/* Row 1: number (narrow) | name | shape. Row 2: seats (narrow) | rotation. */
.td-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 0.8rem; margin-bottom: 0.9rem; }
.td-c-num { grid-column: span 3; }
.td-c-name { grid-column: span 5; }
.td-c-shape { grid-column: span 4; }
.td-c-seats { grid-column: span 3; }
.td-c-rot { grid-column: span 9; }
.td-field { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.7rem;
  text-transform: uppercase; letter-spacing: 0.06rem; color: var(--muted); }
@media (max-width: 560px) { .td-grid > .td-field { grid-column: 1 / -1; } }
.td-ctl { height: 46px; box-sizing: border-box; width: 100%; border: 1px solid var(--line);
  border-radius: 5px; background: var(--paper); color: var(--ink); font-family: var(--sans);
  font-size: 1rem; padding: 0 0.8rem; }
.td-ctl:focus { outline: none; border-color: var(--burgundy-lt); box-shadow: 0 0 0 3px rgba(112,29,45,0.12); }
select.td-ctl { appearance: none; -webkit-appearance: none; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) 20px, calc(100% - 12px) 20px; background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; }
.stepper.td-ctl { display: flex; align-items: center; justify-content: space-between; padding: 0 0.5rem; }
.rot-ctl { display: flex; align-items: center; gap: 0.6rem; padding: 0 0.7rem; }
.rot-ctl input[type="range"] { flex: 1; min-width: 0; accent-color: var(--burgundy); cursor: pointer; }
#td-rot-val { font-family: var(--serif); font-size: 1rem; min-width: 3ch; text-align: right; color: var(--ink); }
.step-btn { width: 30px; height: 30px; flex: 0 0 auto; border: 1px solid var(--line); border-radius: 5px;
  background: #fbf8f2; cursor: pointer; font-size: 1.1rem; line-height: 1; color: var(--ink); }
.step-btn:hover { background: var(--burgundy); border-color: var(--burgundy); color: #fff; }
#td-seat-count { font-family: var(--serif); font-size: 1.2rem; min-width: 2ch; text-align: center; }

.td-actions { display: flex; align-items: center; gap: 0.7rem; margin-top: 1rem; padding-top: 0.9rem; border-top: 1px solid var(--line); }
.td-fill { font-size: 0.85rem; color: var(--muted); margin-right: auto; }
.td-hint { font-size: 0.8rem; color: var(--muted); margin: 0.3rem 0 0.5rem; }

.seat-stage { overflow-x: auto; display: flex; justify-content: safe center; padding: 0.5rem 0 0.2rem; }
.seat-ring { position: relative; flex: 0 0 auto; margin: 0 auto; }
.ring-body { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center; text-align: center; padding: 0.3rem;
  font-family: var(--serif); color: var(--muted); font-size: 0.9rem; line-height: 1.25;
  border: 1px dashed var(--gold-soft); border-radius: 8px; }
.seat-ring.is-round .ring-body { width: 122px; height: 122px; border-radius: 50%; }
.seat-dot { position: absolute; transform: translate(-50%, -50%); width: 44px; height: 44px;
  border-radius: 50%; border: 2px solid var(--line); background: var(--paper); cursor: pointer;
  padding: 0; display: flex; align-items: center; justify-content: center;
  transition: border-color 0.15s, transform 0.1s; }
.seat-dot:hover { transform: translate(-50%, -50%) scale(1.09); border-color: var(--burgundy); z-index: 2; }
.seat-dot .sd-num { font-size: 0.8rem; color: var(--muted); }
.seat-dot .sd-ini { font-size: 0.8rem; font-weight: 600; color: var(--ink); }
.seat-dot.filled { background: #eef6e6; border-color: #5f9146; }

/* Seat assignment picker (floating popover) */
.seat-picker { position: fixed; z-index: 60; width: 240px; background: var(--paper);
  border: 1px solid var(--line); border-radius: 6px; box-shadow: 0 14px 34px rgba(0,0,0,0.22); padding: 0.6rem; }
.seat-picker[hidden] { display: none; }
.seat-picker .text-input { width: 100%; margin-bottom: 0.5rem; }
.picker-list { list-style: none; margin: 0; padding: 0; max-height: 240px; overflow-y: auto; }
.picker-list li { padding: 0.4rem 0.55rem; border-radius: 3px; font-size: 0.88rem; color: var(--ink);
  cursor: pointer; border-left: 4px solid transparent; }
.picker-list li:hover { background: #f4ede1; }
.picker-remove { color: var(--danger); border-top: 1px solid var(--line); }
.picker-none { color: var(--muted); cursor: default; }
.picker-none:hover { background: none; }

@media (max-width: 820px) {
  .seating-grid { grid-template-columns: 1fr; }
  .people-panel { position: static; }
}

/* Mobile planner: view-only, scaled to fit like the guest map (seating.js scales
   the floor and locks dragging/editing). Hide the editing affordances. */
@media (max-width: 640px) {
  /* min-width:0 stops the grid item from stretching to the 720px floor (which
     made the map blow up to full size when a resize re-ran the fit). */
  .seating-wrap .seating-grid, .seating-wrap .floor-panel { min-width: 0; }
  .seating-wrap .floor-scroll { overflow: hidden; margin: 0 auto; }
  .seating-wrap .floor { min-width: 0; }
  .seating-wrap #add-table { display: none; }
  .seating-wrap .floor-hint { display: none; }
  .seating-wrap .floor-coord { display: none; }
  .seating-wrap .mobile-view-note { display: block; }
}

/* ---------- responsive ---------- */

@media (max-width: 640px) {
  .cards { grid-template-columns: 1fr; }
  .gallery { grid-template-columns: 1fr 1fr; }
  .stats { grid-template-columns: 1fr 1fr; }
  .inline-form { flex-direction: column; align-items: stretch; }
  .summary-grid { grid-template-columns: 1fr 1fr; }
  .summary-cols { grid-template-columns: 1fr; gap: 1rem; }
}

/* ======================================================================
   Day-of media: upload manager, projector screen, coordinator remote.
   ====================================================================== */

/* ---- Media manager (/media-upload) ---- */
.media-intro { color: var(--muted); max-width: 60ch; margin: 0 0 1.4rem; }
.media-forms { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); gap: 1rem; margin-bottom: 1.4rem; }
.media-form { min-width: 0; } /* let columns shrink instead of overflowing the page */
.media-form h2 { margin-top: 0; }
.media-form input[type="file"] { max-width: 100%; }
.media-form form { display: flex; flex-direction: column; gap: 0.7rem; }
.mf-label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.9rem; color: var(--ink); }
.mf-label input[type="text"], .mf-label input[type="number"] { box-sizing: border-box; height: 34px; padding: 0 0.6rem; border: 1px solid var(--line); border-radius: 3px; font: inherit; }
.mf-label input[type="file"] { font-size: 0.85rem; }
.mf-opt { color: var(--muted); font-weight: normal; }
.mf-check { display: flex; align-items: center; gap: 0.4rem; font-size: 0.9rem; color: var(--ink); }
.media-form .btn { align-self: flex-start; margin-top: 0.2rem; }

.media-count { font-size: 0.85rem; color: var(--muted); font-weight: normal; }
.media-empty { color: var(--muted); }
.media-disk { font-size: 0.85rem; color: var(--muted); margin: 0.2rem 0 1rem; }
.media-disk strong { color: var(--ink); }
/* Default background section */
.media-default-hint { color: var(--muted); font-size: 0.9rem; margin: 0 0 0.9rem; }
.media-default-row { display: flex; gap: 1rem; align-items: stretch; flex-wrap: wrap; }
.media-default-preview { flex: 0 0 auto; width: 160px; min-height: 100px; border-radius: 6px; overflow: hidden; background: #000; border: 1px solid var(--line); display: flex; align-items: center; justify-content: center; }
.media-default-preview img { width: 100%; height: 100%; object-fit: cover; }
.mdp-none { color: var(--muted); font-size: 0.8rem; }
.media-default-actions { display: flex; flex-direction: column; gap: 0.7rem; min-width: 0; }
.media-default-actions form { display: flex; flex-direction: column; gap: 0.6rem; align-items: flex-start; }
.media-lib { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.media-lib-row { display: flex; align-items: center; gap: 0.9rem; padding: 0.6rem 0.8rem; border: 1px solid var(--line); border-radius: 6px; }
.ml-badge { flex: 0 0 auto; font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase; padding: 0.2rem 0.5rem; border-radius: 999px; color: #fff; }
.ml-video { background: var(--burgundy); }
.ml-audio { background: var(--gold); }
.ml-slideshow { background: var(--sage); }
.ml-main { display: flex; flex-direction: column; gap: 0.15rem; margin-right: auto; min-width: 0; }
.ml-title { font-family: var(--serif); font-size: 1.05rem; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ml-sub { font-size: 0.82rem; color: var(--muted); }
.ml-preview { flex: 0 0 auto; width: 72px; height: 48px; border-radius: 4px; overflow: hidden; background: #000; display: flex; align-items: center; justify-content: center; }
.ml-preview video, .ml-preview img { width: 100%; height: 100%; object-fit: cover; }
.ml-note { color: var(--gold); font-size: 1.4rem; }

/* ---- Projector screen (/media) ---- */
.media-body { margin: 0; background: #000; min-height: 100vh; overflow: hidden; }
.media-stage { position: fixed; inset: 0; background: #000; }
/* Every stage layer is an absolute, full-screen layer that cross-fades via
   opacity, so switching media — and blacking out to the background — is smooth.
   The default background sits behind everything (z 0); content fades on top. */
.media-video, .media-slides, .media-music, .media-default-bg {
  position: absolute; inset: 0; opacity: 0; transition: opacity 0.6s ease;
}
.media-video.vis, .media-slides.vis, .media-music.vis, .media-default-bg.vis { opacity: 1; }
.media-video { width: 100%; height: 100%; object-fit: contain; background: #000; }
.m-slide { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: #000; opacity: 0; transition: opacity 0.8s ease; }
.m-slide.show { opacity: 1; }
.media-default-bg { width: 100%; height: 100%; object-fit: cover; background: #000; z-index: 0; }
.media-music { z-index: 2; color: #fdf6ef; text-align: center; font-family: var(--serif); padding: 2rem;
  display: flex; flex-direction: column; align-items: center; justify-content: center; }
/* Blackout cover: fades pure black over the whole stage (screen on/off toggle). */
.media-blackout { position: fixed; inset: 0; z-index: 50; background: #000; opacity: 0;
  transition: opacity 0.6s ease; pointer-events: none; }
.media-blackout.vis { opacity: 1; }
.mm-eyebrow { font-size: clamp(1.4rem, 5vmin, 3rem); letter-spacing: 0.04em; margin: 0 0 1rem; }
.mm-eyebrow span { color: var(--gold-soft); }
.mm-title { font-size: clamp(1rem, 3vmin, 1.8rem); color: #e8d8c4; margin: 0 0 2rem; }
.mm-bars { display: flex; justify-content: center; gap: 0.5rem; height: 48px; align-items: flex-end; }
.mm-bars span { width: 8px; background: var(--gold-soft); border-radius: 3px; animation: mmBar 1s ease-in-out infinite; }
.mm-bars span:nth-child(1) { animation-delay: 0s; }
.mm-bars span:nth-child(2) { animation-delay: 0.2s; }
.mm-bars span:nth-child(3) { animation-delay: 0.4s; }
.mm-bars span:nth-child(4) { animation-delay: 0.1s; }
.mm-bars span:nth-child(5) { animation-delay: 0.3s; }
@keyframes mmBar { 0%, 100% { height: 12px; } 50% { height: 46px; } }

.media-start { position: fixed; inset: 0; z-index: 100; background: var(--burgundy); color: #fdf6ef; display: flex; align-items: center; justify-content: center; text-align: center; cursor: pointer; }
.media-start[hidden] { display: none; } /* author display:flex above would otherwise beat the hidden attribute */
/* Flex column so each line (heading, text, button) sizes to its own content and
   is centred as a unit — a nowrap heading never gets squeezed into overflowing. */
.media-start-inner { padding: 2rem; display: flex; flex-direction: column; align-items: center; max-width: 90vw; }
.media-start h1 { font-family: var(--serif); font-size: clamp(1.8rem, 6vmin, 3rem); margin: 0 0 0.8rem; white-space: nowrap; max-width: 100%; }
.media-start p { color: #e8d8c4; line-height: 1.6; margin: 0 0 1.6rem; max-width: 34ch; }
.media-start .btn { background: #fdf6ef; color: var(--burgundy); border-color: #fdf6ef; }

/* ---- Coordinator remote (/media-control) ---- */
.mc-wrap { max-width: 720px; }
.mc-now { position: sticky; top: 0; z-index: 20; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 0.9rem 1rem; margin-bottom: 1rem; display: grid; grid-template-columns: 1fr auto; gap: 0.7rem 1rem; align-items: center; box-shadow: var(--shadow); }
.mc-now-info { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.mc-now-eyebrow { font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.mc-now-title { font-family: var(--serif); font-size: 1.2rem; color: var(--burgundy); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mc-live-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: #e02424; margin-right: 0.5rem; vertical-align: baseline; animation: mcLiveBlink 1.1s steps(1, end) infinite; }
.mc-live-dot[hidden] { display: none; } /* display:inline-block above would otherwise beat the hidden attribute */
@keyframes mcLiveBlink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0.15; } }
@media (prefers-reduced-motion: reduce) { .mc-live-dot { animation: none; } }
.mc-transport { display: flex; gap: 0.5rem; }
/* Fixed widths so buttons never shift as their labels change (Play/Pause,
   Blackout/Screen on). Play/Pause + Stop stay compact; only Blackout is wide
   enough for "Screen on", leaving room for the now-playing title. */
.mc-transport .btn { width: 7.25rem; }
.mc-transport .mc-blackout { width: 9.75rem; }
/* Blackout toggle shows as solid/active while the screen is blacked out.
   Scoped to .admin-body so it beats `.admin-body .btn.ghost`'s burgundy text
   (otherwise the active button is burgundy-on-burgundy and only shows on hover). */
.admin-body .mc-blackout.is-on { background-color: var(--burgundy); border-color: var(--burgundy); color: #fff; }
.admin-body .mc-blackout.is-on:hover { background-color: var(--burgundy-dk); border-color: var(--burgundy-dk); }
.mc-vol { grid-column: 1 / -1; display: flex; align-items: center; gap: 0.7rem; font-size: 0.85rem; color: var(--muted); }
.mc-vol input[type="range"] { flex: 1 1 auto; accent-color: var(--burgundy); }

.mc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.mc-item { display: flex; align-items: center; gap: 0.9rem; padding: 0.7rem 0.9rem; border: 1px solid var(--line); border-radius: 8px; cursor: pointer; background: var(--paper); transition: border-color 0.12s, box-shadow 0.12s; }
.mc-item:hover { border-color: var(--gold-soft); }
.mc-item.is-live { border-color: var(--burgundy); box-shadow: 0 0 0 2px rgba(112, 29, 45, 0.18); }
.mc-thumb { flex: 0 0 auto; width: 84px; height: 56px; border-radius: 5px; overflow: hidden; background: #000; color: var(--gold-soft); display: flex; align-items: center; justify-content: center; font-size: 1.5rem; }
.mc-thumb img, .mc-thumb video { width: 100%; height: 100%; object-fit: cover; }
.mc-item-main { display: flex; flex-direction: column; gap: 0.2rem; margin-right: auto; min-width: 0; }
.mc-item-title { font-family: var(--serif); font-size: 1.1rem; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mc-item-sub { font-size: 0.82rem; color: var(--muted); }
.mc-live-badge { flex: 0 0 auto; display: none; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.08em; color: #fff; background: var(--burgundy); padding: 0.2rem 0.5rem; border-radius: 999px; }
.mc-item.is-live .mc-live-badge { display: inline-block; }

/* Preload control (remote) */
.mc-preload { margin: 0 0 1rem; }
.mc-preload-btn { width: 100%; }
.mc-preload-status { display: flex; flex-direction: column; gap: 0.4rem; margin-top: 0.6rem; }
.mc-preload-text { font-size: 0.85rem; color: var(--burgundy); }
.mc-preload-bar { height: 8px; border-radius: 999px; background: var(--line); overflow: hidden; }
.mc-preload-fill { display: block; height: 100%; width: 0; background: var(--burgundy); border-radius: 999px; transition: width 0.25s ease; }
.mc-preload-hint { font-size: 0.78rem; color: var(--muted); margin: 0.5rem 0 0; line-height: 1.5; }

/* Preload progress toast (projector) — bottom-left, never covers a live slide */

@media (max-width: 640px) {
  .media-forms { grid-template-columns: 1fr; }
  /* Stack the status bar: "Now on screen" on its own line, buttons below. */
  .mc-now { grid-template-columns: 1fr; }
  .mc-now-title { white-space: normal; }
  .mc-transport { justify-content: stretch; }
  .mc-transport .btn { flex: 1 1 0; }
}
