/* =========================================================
   Adam & Emirjeta — Wedding Site
   Palette: ivory, charcoal, sage, dusty gold
   ========================================================= */

:root {
  --ivory: #faf7f2;
  --cream: #f3ede2;
  --sand:  #e8dfce;
  --charcoal: #2c2a26;
  --ink: #1b1a17;
  --sage: #6b7a5a;
  --sage-dark: #4f5c41;
  --gold: #b08a4a;
  --muted: #6e6a62;
  --shadow: 0 10px 30px rgba(28, 27, 23, 0.08);
  --shadow-lg: 0 20px 60px rgba(28, 27, 23, 0.18);
  --radius: 4px;
  --serif: "Cormorant Garamond", "Times New Roman", serif;
  --sans:  "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --nav-h: 64px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

/* =========================================================
   Loader — covers everything until the hero image is ready
   ========================================================= */

body.is-loading { overflow: hidden; }

/* SPA navigation transitions — softens the content swap between pages and
   between in-page sections. #spa-main fades out, the bg-stage cross-fades to
   the destination photo, then the new content fades back in. The two halves
   use different curves so the fade-in feels lighter and lands gently. */
#spa-main {
  opacity: 1;
  transition: opacity 520ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
#spa-main.spa-fade-out {
  opacity: 0;
  transition: opacity 360ms cubic-bezier(0.4, 0, 0.6, 1);
}
body.spa-loading { cursor: progress; }

/* Pre-flight auth check (inline script in index.html head) added this class
   when localStorage already has a session token — pre-hide the loader so it
   never paints for returning visitors. setupGate clears the class on auth
   failure (and the loader becomes visible again). */
html.has-token .loader {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
html.has-token body.is-loading { overflow: auto; }

.loader {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--ivory);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.7s ease, visibility 0.7s ease;
}
.loader.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.loader-inner {
  text-align: center;
  animation: loaderFloat 3s ease-in-out infinite alternate;
}

.gate-portrait {
  width: clamp(86px, 14vw, 116px);
  height: clamp(86px, 14vw, 116px);
  margin: 0 auto 1.25rem;
  border-radius: 50%;
  overflow: hidden;
  box-shadow:
    0 0 0 1px rgba(196, 161, 92, 0.55),
    0 0 0 4px rgba(196, 161, 92, 0.18),
    0 6px 18px rgba(20, 17, 14, 0.35);
}
.gate-portrait img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.loader-monogram {
  font-family: var(--serif);
  font-size: clamp(2.4rem, 6vw, 3.6rem);
  letter-spacing: 0.25em;
  color: var(--ink);
  font-weight: 400;
  line-height: 1;
}
.loader-monogram .amp {
  color: var(--gold);
  font-style: italic;
  font-size: 0.9em;
  margin: 0 0.05em;
}

.loader-shimmer {
  width: 180px;
  height: 1px;
  margin: 1.75rem auto 1.25rem;
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--sand) 20%,
    var(--sage) 50%,
    var(--sand) 80%,
    transparent 100%
  );
  background-size: 200% 100%;
  animation: loaderShimmer 1.8s ease-in-out infinite;
}

/* Gate (password entry) — built on top of the loader styles */
.gate-eyebrow {
  margin: 1rem 0 0;
  font-family: var(--sans);
  text-transform: uppercase;
  letter-spacing: 0.35em;
  font-size: 0.7rem;
  font-weight: 500;
  color: var(--muted);
}

.gate-prompt {
  margin: 0 0 1.25rem;
  font-family: var(--serif);
  font-size: 1.15rem;
  color: var(--charcoal);
  font-style: italic;
  max-width: 32ch;
  margin-left: auto;
  margin-right: auto;
}

/* Hide the gate prompt + form during the initial loader window;
   script.js adds `gate-ready` to body once it's decided auth is needed. */
.gate-prompt,
.gate-form,
.gate-error {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.55s ease 0.15s, transform 0.55s ease 0.15s;
  pointer-events: none;
}
body.gate-ready .gate-prompt,
body.gate-ready .gate-form,
body.gate-ready .gate-error {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.gate-form {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
  max-width: 420px;
  margin: 0 auto;
}

.gate-input {
  flex: 1 1 220px;
  min-width: 0;
  padding: 0.85rem 1rem;
  font-family: var(--sans);
  font-size: 0.95rem;
  letter-spacing: 0.05em;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--sand);
  border-radius: var(--radius);
  outline: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.gate-input::placeholder {
  color: var(--muted);
  letter-spacing: 0.1em;
}
.gate-input:focus {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(176, 138, 74, 0.15);
}
.gate-input[aria-invalid="true"] {
  border-color: #b85a4a;
  box-shadow: 0 0 0 3px rgba(184, 90, 74, 0.12);
}

.gate-submit {
  padding: 0.85rem 1.6rem;
  font-family: var(--sans);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.25em;
  font-weight: 500;
  color: var(--ivory);
  background: var(--ink);
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background .2s ease, color .2s ease, transform .1s ease;
}
.gate-submit:hover { background: var(--gold); border-color: var(--gold); }
.gate-submit:active { transform: translateY(1px); }

.gate-error {
  margin: 1rem auto 0;
  max-width: 38ch;
  color: #a04a3a;
  font-size: 0.85rem;
  font-style: italic;
}

@keyframes loaderFloat {
  0%   { transform: translateY(0); }
  100% { transform: translateY(-6px); }
}
@keyframes loaderShimmer {
  0%   { background-position:  150% 0; }
  100% { background-position: -150% 0; }
}

body {
  margin: 0;
  font-family: var(--sans);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.7;
  color: var(--ivory);
  background: #14110e;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* =========================================================
   Fixed mountain background stage — cross-fades between photos
   ========================================================= */

.bg-stage {
  position: fixed;
  inset: 0;
  z-index: -10;
  background: #14110e;
  overflow: hidden;
  pointer-events: none;
}
.bg-layer {
  position: absolute;
  inset: 0;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  opacity: 0;
  /* Slow, gentle cross-fade so scrolling between sections feels like a
     painted scene drifting in rather than a snap-cut. */
  transition: opacity 1.1s ease-in-out;
  will-change: opacity;
  /* Boost saturation harder to make the wildflower/peony colors pop —
     brightness compensates for the dark tint layer above. */
  filter: brightness(1.18) saturate(1.35) contrast(1.05);
}
.bg-layer.is-active { opacity: 1; }

/* Constant dark wash that anchors every page at the same brightness. Living
   on .bg-stage (outside #spa-main) means it stays put during SPA fade
   transitions — without it, fading the content briefly revealed the bright
   underlying photo and produced a "flash" effect on click navigation. */
.bg-stage-tint {
  position: absolute;
  inset: 0;
  /* Lighter wash so the saturated photos can breathe. Still enough darkness
     to keep ivory text on the hero / section headings readable. */
  background: rgba(20, 17, 14, 0.32);
  pointer-events: none;
}

img { display: block; max-width: 100%; height: auto; }

a { color: var(--sage-dark); text-decoration: none; transition: color .2s ease; }
a:hover { color: var(--gold); }

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 400;
  color: var(--ink);
  letter-spacing: 0.5px;
  line-height: 1.2;
  margin: 0 0 0.5em;
}

h2 { font-size: clamp(2rem, 4vw, 3rem); }
h3 { font-size: 1.5rem; }

p { margin: 0 0 1em; }
.muted { color: var(--muted); font-size: 0.95em; }

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.25em;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--sage-dark);
  margin: 0 0 1em;
}
.eyebrow.light { color: var(--sand); }

.lede { font-size: 1.1rem; color: #4a4842; }
.lede.light { color: rgba(255,255,255,0.85); }

.center { text-align: center; }

/* =========================================================
   Layout
   ========================================================= */

.container {
  width: min(1140px, 92%);
  margin: 0 auto;
}
.container.narrow { max-width: 760px; }

.section {
  padding: clamp(4rem, 8vw, 7rem) 0;
  position: relative;
  color: var(--ivory);
}
/* RSVP-style dim: slight extra wash on top of the global dark tint. Lives
   inside #spa-main so it does fade during transitions, but the underlying
   tint keeps the brightness consistent — no flash. */
.section-dark { background: rgba(0, 0, 0, 0.22); }
.section-dark h2 { color: var(--ivory); }

/* Headings inside the translucent dark sections */
.section h2, .section h3 { color: var(--ivory); }
.section .lede { color: rgba(250, 247, 242, 0.85); }
.section .muted { color: rgba(250, 247, 242, 0.65); }
.section .eyebrow { color: #d4b888; }

/* Cards: frosted dark glass so the mountain shows through */
.section .card {
  background: rgba(60, 38, 50, 0.55);
  color: var(--ivory);
  /* Subtle blur — small radius (4px) keeps the compute cost low so Chrome
     is less likely to defer it during bg cross-fades. translateZ(0)
     promotes the card to its own composite layer, which keeps the filter
     sampled and rendered independently of any animation behind it. */
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transform: translateZ(0);
  will-change: backdrop-filter;
  border: 1px solid rgba(212, 184, 136, 0.18);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}
.section .card h2,
.section .card h3 { color: var(--ivory); }
.section .card .lede,
.section .card p { color: rgba(250, 247, 242, 0.88); }
.section .card .muted { color: rgba(250, 247, 242, 0.6); }
.section .card .eyebrow { color: #d4b888; }
.section .card a { color: #d4b888; }
.section .card a:hover { color: var(--ivory); }
.section .card .card-link { color: #d4b888; }
.section .card .card-link:hover { color: var(--ivory); }

/* Info blocks: same frosted glass treatment, keep the warm side accent */
.section .info-block {
  background: rgba(60, 38, 50, 0.55);
  color: var(--ivory);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transform: translateZ(0);
  will-change: backdrop-filter;
  border-left: 3px solid #d4b888;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}
.section .info-block h3 { color: var(--ivory); }
.section .info-block p,
.section .info-block li { color: rgba(250, 247, 242, 0.88); }
.section .info-block .muted { color: rgba(250, 247, 242, 0.6); }
.section .info-block a { color: #d4b888; }
.section .info-block a:hover { color: var(--ivory); }

/* Timeline lives inside .section but defines its own card styling — see the
   .timeline rules later in this file. No global overrides needed here. */

/* FAQ styling is fully defined in its own block later in this file (the
   list is wrapped in a single dark card with row dividers). No global
   per-section overrides needed here. */

/* Btn-outline across all sections — warm gold on dark glass */
.section .btn-outline,
.section .card .btn-outline,
.section .info-block .btn-outline {
  border-color: #d4b888;
  color: #d4b888;
  background: transparent;
}
.section .btn-outline:hover,
.section .card .btn-outline:hover,
.section .info-block .btn-outline:hover {
  background: #d4b888;
  color: var(--ink);
}

.section-head { margin-bottom: 3rem; }
.section-head h2 { margin-bottom: 0.5rem; }

/* =========================================================
   Navigation
   ========================================================= */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--nav-h);
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 clamp(1rem, 4vw, 2.5rem);
  background: rgba(250, 247, 242, 0);
  backdrop-filter: blur(0);
  border-bottom: 1px solid transparent;
  /* Default = the "leaving white" direction: fast snap back to transparent
     (e.g., clicking the brand to return to the hero). The slow direction is
     defined per-state below so going from transparent → white still eases in
     gently. */
  transition:
    background .3s ease,
    backdrop-filter .3s ease,
    box-shadow .3s ease,
    border-bottom-color .3s ease;
}
.nav.scrolled {
  background: rgba(250, 247, 242, 0.95);
  backdrop-filter: blur(10px);
  box-shadow: 0 2px 20px rgba(0,0,0,0.05);
  border-bottom-color: var(--sand);
  transition:
    background .55s ease,
    backdrop-filter .55s ease,
    box-shadow .55s ease,
    border-bottom-color .55s ease;
}
/* Force the white-nav look during SPA navigation so sub-page → home doesn't
   flash through the transparent-hero nav style while content is swapping. */
body.spa-loading .nav {
  background: rgba(250, 247, 242, 0.96);
  backdrop-filter: blur(10px);
  box-shadow: 0 2px 20px rgba(0,0,0,0.05);
  border-bottom-color: var(--sand);
  transition:
    background .55s ease,
    backdrop-filter .55s ease,
    box-shadow .55s ease,
    border-bottom-color .55s ease;
}
body.spa-loading .nav-brand,
body.spa-loading .nav-menu a,
body.spa-loading .nav-signout,
body.spa-loading .lang-btn {
  color: var(--ink);
  transition: color .5s ease;
}
body.spa-loading .lang-btn { transition: background .2s ease, color .5s ease; }
body.spa-loading .nav-signout { transition: opacity .3s ease, color .5s ease; }
body.spa-loading .nav-toggle span {
  background: var(--ink);
  transition: background .5s ease, transform .3s ease, opacity .3s ease;
}

.nav-brand {
  font-family: var(--serif);
  font-size: 1.5rem;
  letter-spacing: 0.2em;
  color: var(--ivory);
  /* Fast going back to ivory (leaving white nav); slow going to ink is set
     per-state below so the ease-in still feels gentle. */
  transition: color .3s ease;
}
.nav-brand .amp {
  color: var(--gold);
  font-style: italic;
  margin: 0 0.05em;
}
.nav.scrolled .nav-brand { color: var(--ink); transition: color .5s ease; }
.nav.scrolled .nav-brand .amp { color: var(--gold); }

.nav-menu {
  display: flex;
  gap: 2rem;
  list-style: none;
  margin: 0; padding: 0;
  align-items: center;
}
.nav-menu a {
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ivory);
  font-weight: 400;
  transition: color .3s ease;
}
.nav.scrolled .nav-menu a { color: var(--ink); transition: color .5s ease; }
.nav-menu a:hover { color: var(--gold); }

/* Active page highlight — gold text wins across every nav state (transparent
   hero, scrolled white, sub-page white, mid-SPA-loading). Specificity tied
   with the per-state color rules, so each variant needs its own selector. */
.nav-menu a.active,
.nav.scrolled .nav-menu a.active,
.explore-body .nav-menu a.active,
body.spa-loading .nav-menu a.active { color: var(--gold); }

.nav-menu a.nav-cta {
  background: var(--gold);
  color: var(--ink);
  border: 1px solid var(--gold);
  padding: 0.5rem 1.1rem;
  border-radius: var(--radius);
  transition: background .25s ease, color .25s ease, border-color .25s ease;
}
.nav-menu a.nav-cta:hover {
  background: transparent;
  color: var(--gold);
  border-color: var(--gold);
}
/* Active CTA (e.g., RSVP link while on /rsvp.html) — inverted pill so the
   "you are here" treatment matches the hover affordance and the gold text-
   active rule above doesn't render gold-on-gold (invisible). */
.nav-menu a.nav-cta.active,
.nav.scrolled .nav-menu a.nav-cta.active,
.explore-body .nav-menu a.nav-cta.active,
body.spa-loading .nav-menu a.nav-cta.active {
  background: transparent;
  color: var(--gold);
  border-color: var(--gold);
}
.nav.scrolled .nav-menu a.nav-cta { color: var(--ink); }
.nav.scrolled .nav-menu a.nav-cta:hover { color: var(--gold); }

.nav-signout-item { display: flex; align-items: center; }

/* Language switcher — small EN | SQ | PL toggle in the nav */
.nav-lang-item { display: flex; align-items: center; }
.lang-switcher {
  display: inline-flex;
  gap: 0;
  /* Always use the gold border so it stands out over both hero and scrolled-white nav */
  border: 1px solid var(--gold);
  border-radius: var(--radius);
  /* Clip the per-button flag backgrounds to the switcher's rounded corners. */
  overflow: hidden;
  transition: box-shadow .25s ease;
}
.lang-switcher:hover { box-shadow: 0 0 0 2px rgba(176, 138, 74, 0.15); }
/* Each button is now a flag chip — no letters, just the country flag. The
   button's `title` attribute and the switcher's aria-label keep screen
   readers informed. Inactive flags are desaturated so the active flag
   reads as the selected one in full color, with a gold ring around it. */
.lang-btn {
  position: relative;
  background: transparent;
  border: 0;
  padding: 0;
  width: 36px;
  height: 22px;
  cursor: pointer;
  border-right: 1px solid rgba(176, 138, 74, 0.5);
  overflow: hidden;
  transition: outline-color .25s ease;
}
.lang-btn:last-child { border-right: 0; }
.lang-btn > span { display: none; }
.lang-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  /* Inactive flags are muted; full saturation reads as the active one. */
  filter: saturate(0.55) brightness(0.92);
  transition: filter .3s ease;
  pointer-events: none;
}
.lang-btn[data-lang="en"]::before { background-image: url("/img/flag-us.svg"); }
.lang-btn[data-lang="sq"]::before { background-image: url("/img/flag-al.svg"); }
.lang-btn[data-lang="pl"]::before { background-image: url("/img/flag-pl.svg"); }
.lang-btn:hover::before { filter: saturate(0.85) brightness(0.98); }
.lang-btn.is-active::before { filter: saturate(1) brightness(1); }
/* Active state: gold ring drawn inside the button on top of the flag.
   `outline` paints above content (including the ::before flag) so the
   ring is always visible; `outline-offset: -2px` keeps it inset. */
.lang-btn.is-active {
  outline: 2px solid var(--gold);
  outline-offset: -2px;
}
.nav-signout {
  background: none;
  border: 0;
  padding: 0.4rem 0.2rem;
  font-family: var(--sans);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ivory);
  opacity: 0.7;
  cursor: pointer;
  transition: opacity .3s ease, color .3s ease;
}
.nav.scrolled .nav-signout { color: var(--ink); transition: color .5s ease; }
.nav-signout:hover { opacity: 1; color: var(--gold); }
.nav.scrolled .nav-signout:hover { color: var(--gold); }

.nav-toggle {
  display: none;
  background: none;
  border: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  cursor: pointer;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
}
.nav-toggle span {
  display: block;
  width: 26px;
  height: 1.5px;
  background: var(--ivory);
  transition: background .3s ease, transform .3s ease, opacity .3s ease;
}
.nav.scrolled .nav-toggle span { background: var(--ink); transition: background .5s ease, transform .3s ease, opacity .3s ease; }

@media (max-width: 820px) {
  .nav-toggle { display: flex; }
  .nav-menu {
    position: absolute;
    top: var(--nav-h);
    left: 0; right: 0;
    flex-direction: column;
    background: var(--ivory);
    padding: 1.5rem 0;
    gap: 1rem;
    transform: translateY(-120%);
    transition: transform .35s ease;
    box-shadow: 0 10px 30px rgba(0,0,0,0.08);
  }
  .nav-menu.open { transform: translateY(0); }
  .nav-menu a { color: var(--ink); }
}

/* =========================================================
   Hero
   ========================================================= */

.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--ivory);
  background: transparent;
  padding: var(--nav-h) 1rem 4rem;
  overflow: hidden;
  isolation: isolate;
}

/* Vignette over the fixed bg-stage for legibility of the hero text */
/* Vignette is intentionally a no-op now. It used to overlay extra darkness
   inside the hero element specifically, but the hero scrolls with the page
   while the bg-stage-tint is position:fixed — the mismatch produced a hard
   "line" at the hero/welcome boundary as the user scrolled. The element
   stays in the HTML in case we want to bring back a localised effect
   later. */
.hero-vignette {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.hero-content {
  max-width: 900px;
  width: 100%;
  /* Two-layer shadow: tight inner pass for crisp legibility against bright
     photo zones, wider ambient pass for the "halo" feel. Replaces the
     hero-vignette which used to provide the darkening (it scrolled with
     the page and created a visible line at the hero/welcome boundary). */
  text-shadow:
    0 1px 3px rgba(0, 0, 0, 0.7),
    0 2px 24px rgba(0, 0, 0, 0.55);
}

.hero-eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.4em;
  font-size: 0.85rem;
  font-weight: 400;
  margin-bottom: 1.5rem;
  color: #fff;
}

.hero-names {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2.8rem, 8vw, 6rem);
  line-height: 1.05;
  margin: 0 0 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  align-items: center;
  color: #fff;
  text-shadow:
    0 2px 16px rgba(0,0,0,0.55),
    0 1px 3px rgba(0,0,0,0.6);
}
.hero-names .amp {
  font-style: italic;
  color: #e6c483;
  font-size: 0.7em;
  font-weight: 300;
}

.hero-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  font-size: 0.9rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  margin-bottom: 2rem;
}
.hero-meta .dot { opacity: 0.6; }

.hero-countdown {
  display: flex;
  justify-content: center;
  gap: clamp(0.75rem, 3vw, 2rem);
  margin: 2rem 0;
  flex-wrap: wrap;
}
.hero-countdown .unit {
  min-width: 70px;
}
.hero-countdown .num {
  display: block;
  font-family: var(--serif);
  font-size: clamp(1.8rem, 4vw, 2.5rem);
  font-weight: 400;
  line-height: 1;
}
.hero-countdown .label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  opacity: 0.8;
}

.hero-scroll {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  width: 24px;
  height: 40px;
  border: 1px solid rgba(255,255,255,0.6);
  border-radius: 12px;
  display: flex;
  justify-content: center;
  padding-top: 8px;
}
.hero-scroll span {
  width: 2px;
  height: 8px;
  background: rgba(255,255,255,0.8);
  border-radius: 1px;
  animation: scrollDot 1.8s infinite;
}
@keyframes scrollDot {
  0% { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(12px); opacity: 0; }
}

/* =========================================================
   Cards & grids
   ========================================================= */

.grid-2, .grid-3 {
  display: grid;
  gap: 2rem;
}
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* ---------- Our Story gallery ----------
   Gallery-wall / "stack of prints" feel: 3-col grid with a wide hero tile
   in row 2. Each photo gets its own rotation, two-axis offset, scale, and
   resting z-index, so the row reads as a scattered handful of prints —
   some overlap their neighbors at the corners, none sit perfectly square.
   Hovered tile straightens, scales way up, and lifts above the rest. */
.story-gallery {
  display: grid;
  /* 4 cols × 2 rows = 8 tiles exactly. Photos read smaller because each
     cell is narrower; overlap then comes from the per-tile translates. */
  grid-template-columns: repeat(4, 1fr);
  /* No grid gap — overlap is driven entirely by per-tile translate. */
  gap: 0;
}
.story-photo {
  position: relative;
  margin: 0;
  /* Don't stretch to fill the grid row — when one tile in a row is hovered,
     its padding animates to 0, which makes its img (width:100% + aspect-ratio
     3/4) ~5px taller intrinsically and grows the row. With default
     align-self:stretch, the other tiles in the row would grow too — their
     img would stay its computed size and the leftover row space would
     appear as empty padding below the img (re-introducing the polaroid
     look on the non-hovered tiles). align-self:start pins each tile to
     its own intrinsic height so its neighbors don't get dragged along. */
  align-self: start;
  /* Photo-frame style: each tile is a small ivory mat with uniform
     padding on all sides, a gold outline + inner gold matting line, and a
     soft warm drop shadow. The frame stays distinct enough that adjacent
     prints read as separate tiles even when their corners overlap. On
     hover the padding animates to 0 so the photo fills the card edge-to-edge.
     Aspect-ratio is set on the FIGURE (not the img) so the tile's outer
     dimensions are fixed regardless of padding — when padding shrinks
     on hover, only the img inside grows; the row height never changes,
     so other rows don't shift. */
  aspect-ratio: 3 / 4;
  padding: 7px;
  background:
    linear-gradient(180deg, var(--ivory) 0%, #f6efe1 100%);
  overflow: hidden;
  border-radius: 8px;
  box-shadow:
    0 0 0 2px rgba(176, 138, 74, 0.85),
    0 6px 14px rgba(58, 42, 18, 0.3);
  /* `--rot` / `--tx` / `--ty` / `--s` / `--zr` are set per-tile below.
     Function order (scale → translate → rotate) matches the reveal entry
     and visible states so transitions interpolate cleanly. */
  --rot: 0deg;
  --tx: 0px;
  --ty: 0px;
  --s: 0.8;
  --zr: 1;
  transform: scale(var(--s)) translate(var(--tx), var(--ty)) rotate(var(--rot));
  transform-origin: center center;
  z-index: var(--zr);
  transition:
    transform .6s cubic-bezier(.22,1.08,.36,1),
    box-shadow .6s ease,
    padding .55s cubic-bezier(.22,1.08,.36,1),
    z-index 0s linear .6s;
  cursor: zoom-in;
}
.story-photo img {
  display: block;
  width: 100%;
  /* Fill the figure's content area exactly — height comes from the figure's
     aspect-ratio + the figure's width, not from img's own aspect-ratio. */
  height: 100%;
  object-fit: cover;
  /* Inner corner radius is sized so the photo's curve is roughly concentric
     with the figure's outer radius (8px) minus the 7px padding. */
  border-radius: 5px;
  transition: transform 1s ease;
}

/* Per-tile rotation + offset + scale + resting z.
   Each tile picks a neighbor to lean into; translates are sized to clear
   the empty margin on both sides (~25-30px per side at scale ~0.85 in a
   ~350px cell), so corners physically overlap by ~15-30px. zr varies so
   the stacking pattern reads as "tossed prints", not painted in HTML order.
   The wide hero (#5) stays calmest — the focal anchor of the row. */
/* Row 1 (tiles 1–4) and Row 2 (tiles 5–8). Translates lean each tile toward
   a neighbor with alternating signs so adjacent pairs collide horizontally,
   and the rows reach toward each other vertically. Magnitudes are sized to
   exceed the empty margin around each scaled-down tile (~45px per side at
   scale 0.7 in a ~300px cell) so corners physically overlap by 30-50px. */
.story-photo:nth-child(1) { --rot: -5deg;  --tx:  75px; --ty:  55px; --s: 0.72; --zr: 2; }
.story-photo:nth-child(2) { --rot:  4deg;  --tx: -60px; --ty: -45px; --s: 0.70; --zr: 3; }
.story-photo:nth-child(3) { --rot: -3deg;  --tx:  70px; --ty:  58px; --s: 0.74; --zr: 2; }
.story-photo:nth-child(4) { --rot:  5deg;  --tx: -65px; --ty: -48px; --s: 0.71; --zr: 4; }
.story-photo:nth-child(5) { --rot:  3deg;  --tx:  65px; --ty: -55px; --s: 0.72; --zr: 3; }
.story-photo:nth-child(6) { --rot: -4deg;  --tx: -60px; --ty:  55px; --s: 0.74; --zr: 4; }
.story-photo:nth-child(7) { --rot:  6deg;  --tx:  75px; --ty: -50px; --s: 0.71; --zr: 2; }
.story-photo:nth-child(8) { --rot: -3deg;  --tx: -65px; --ty:  60px; --s: 0.73; --zr: 3; }

/* Hover zoom is desktop-only. Gated on `hover: hover` so touch devices never
   trigger it (a tap on mobile would otherwise "stick" the hover state), and
   on min-width so narrow laptop windows match the mobile/tablet behavior. */
@media (hover: hover) and (min-width: 821px) {
  .story-photo:hover {
    /* Straighten the tilt and pop much larger than the resting scale. */
    transform: scale(1.4) translate(0, 0) rotate(0deg);
    /* Photo fills the entire card edge-to-edge on hover — no polaroid
       strip showing at the bottom. */
    padding: 0;
    box-shadow:
      0 0 0 2px rgba(176, 138, 74, 0.85),
      0 30px 60px rgba(20, 17, 14, 0.42),
      0 12px 22px rgba(58, 42, 18, 0.32);
    z-index: 10;
    /* Snap z-index up immediately on hover-in so the lifted tile clears its
       neighbors; the delay only applies on hover-out (above) to let the
       transform settle before the stacking context drops back. */
    transition:
      transform .6s cubic-bezier(.22,1.08,.36,1),
      box-shadow .6s ease,
      padding .55s cubic-bezier(.22,1.08,.36,1),
      z-index 0s linear 0s;
  }
  .story-photo:hover img { transform: scale(1.05); }
}

/* The wide-tile class is preserved for narrower viewports (tablet falls
   back to a 2-col grid where the wide span makes sense). On the 4-col
   desktop grid it behaves like every other tile. */
.story-photo-wide img { object-fit: cover; }

/* Wrapper exists so the nav arrows can be positioned over the gallery in
   carousel mode. On desktop the wrapper is layout-neutral and the arrows
   are hidden. */
.story-gallery-wrap { position: relative; }
.story-nav { display: none; }

@media (max-width: 820px) {
  .story-gallery { grid-template-columns: repeat(2, 1fr); gap: 1rem; }
  .story-photo-wide { grid-column: span 1; }
  /* Reset the gallery-wall tilts on tablet — they're sized for the 4-col
     desktop layout and feel exaggerated at this width. */
  .story-photo { --rot: 0deg; --tx: 0px; --ty: 0px; --s: 0.94; }
}

/* Mobile: convert the grid into a one-photo-at-a-time swipe carousel with
   side arrows. CSS scroll-snap gives free touch swipe; the JS in script.js
   wires the buttons to scroll-by-one. */
@media (max-width: 500px) {
  .story-gallery {
    display: flex;
    grid-template-columns: none;
    gap: 0;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
    -ms-overflow-style: none;
    /* Bleed slightly past the container so the snapped photo can fill the
       full screen width without padding clipping it. */
    margin: 0 calc(-1 * clamp(1rem, 4vw, 2rem));
    padding: 0 clamp(1rem, 4vw, 2rem);
  }
  .story-gallery::-webkit-scrollbar { display: none; }

  .story-photo {
    flex: 0 0 100%;
    margin-right: 1rem;
    scroll-snap-align: center;
    transform: none;
    cursor: default;
  }
  .story-photo:last-child { margin-right: 0; }
  .story-photo:hover {
    transform: none;
    box-shadow: var(--shadow);
    z-index: auto;
  }
  .story-photo:hover img { transform: none; }
  .story-photo-wide { grid-column: auto; }

  /* Skip the fly-in animation on mobile — the carousel scrolls horizontally
     within the gallery, so vertical-scroll intersect logic doesn't apply
     and any leftover transform would fight the scroll-snap. */
  .story-photo.reveal,
  .story-photo.reveal:nth-child(odd),
  .story-photo.reveal:nth-child(even),
  .story-photo.reveal.visible {
    opacity: 1;
    transform: none;
    transition: none;
  }

  /* Side arrows. Stay vertically centred on the visible photo so they read
     as carousel controls regardless of which slide is on screen. */
  .story-nav {
    display: flex;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: rgba(250, 247, 242, 0.94);
    border: 1px solid var(--sand);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
    align-items: center;
    justify-content: center;
    color: var(--ink);
    font-family: var(--serif);
    font-size: 1.6rem;
    line-height: 1;
    padding-bottom: 3px; /* optical centre for the chevron glyph */
    cursor: pointer;
    z-index: 10;
    transition: opacity .2s ease, background .2s ease;
    -webkit-tap-highlight-color: transparent;
  }
  .story-nav:hover { background: var(--ivory); }
  .story-nav:active { background: var(--sand); }
  .story-nav:disabled { opacity: 0.35; cursor: default; }
  .story-nav-prev { left: 6px; }
  .story-nav-next { right: 6px; }
}

/* =========================================================
   Story gallery scroll-in animation — overrides the generic .reveal so
   each photo flies in from its own side with a staggered delay. Tiles
   alternate left/right entry with a slight rotation so the section feels
   alive as the user scrolls into it.
   ========================================================= */
.story-photo.reveal {
  opacity: 0;
  transform: scale(0.78) translate(0, 60px) rotate(0deg);
  /* Entry transition: smooth ease for the scroll-in. Hover-out also falls
     back to this curve (acceptable — hover-out as a smooth ease feels fine).
     The z-index delay equals the transform duration so the lifted hover
     tile drops its stacking context AFTER its transform settles back. */
  transition:
    opacity .9s cubic-bezier(0.22, 0.61, 0.36, 1),
    transform .9s cubic-bezier(0.22, 0.61, 0.36, 1),
    box-shadow .9s ease,
    z-index 0s linear .9s;
  will-change: transform, opacity;
}
.story-photo.reveal:nth-child(odd) {
  transform: scale(0.78) translate(-40px, 60px) rotate(-3deg);
}
.story-photo.reveal:nth-child(even) {
  transform: scale(0.78) translate(40px, 60px) rotate(3deg);
}
.story-photo.reveal.visible {
  opacity: 1;
  /* Settle into the per-tile gallery-wall position. Function order
     (scale → translate → rotate) matches the FROM state above for clean
     interpolation. All four vars come from the per-tile rules on
     .story-photo:nth-child(N). */
  transform: scale(var(--s)) translate(var(--tx), var(--ty)) rotate(var(--rot));
}
/* Hover after the photo has revealed — re-specified at higher specificity
   so it wins against the .reveal.visible transform. Same hover/desktop gate
   as the base rule so mobile and narrow laptop windows don't trigger it. */
@media (hover: hover) and (min-width: 821px) {
  .story-photo.reveal.visible:hover {
    /* Straighten the tilt and pop dramatically larger. */
    transform: scale(1.4) translate(0, 0) rotate(0deg);
    /* Photo fills the entire card edge-to-edge on hover — no polaroid
       strip showing at the bottom. */
    padding: 0;
    z-index: 10;
    box-shadow:
      0 0 0 2px rgba(176, 138, 74, 0.85),
      0 30px 60px rgba(20, 17, 14, 0.42),
      0 12px 22px rgba(58, 42, 18, 0.32);
    /* Hover-in uses a springier, snappier curve. Hover-out reverts to the
       .reveal smooth ease (above) — and z-index drops after that settles. */
    transition:
      transform .55s cubic-bezier(.22, 1.08, .36, 1),
      box-shadow .35s ease,
      padding .55s cubic-bezier(.22, 1.08, .36, 1),
      z-index 0s linear 0s;
  }
}

/* Cascade the entries row-by-row so the section reveals in a wave rather
   than all at once. */
.story-photo.reveal:nth-child(1) { transition-delay: 0ms; }
.story-photo.reveal:nth-child(2) { transition-delay: 90ms; }
.story-photo.reveal:nth-child(3) { transition-delay: 180ms; }
.story-photo.reveal:nth-child(4) { transition-delay: 0ms; }
.story-photo.reveal:nth-child(5) { transition-delay: 120ms; }
.story-photo.reveal:nth-child(6) { transition-delay: 0ms; }
.story-photo.reveal:nth-child(7) { transition-delay: 90ms; }
.story-photo.reveal:nth-child(8) { transition-delay: 180ms; }

.card {
  background: var(--ivory);
  border: 1px solid rgba(0,0,0,0.04);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform .35s ease, box-shadow .35s ease;
  display: flex;
  flex-direction: column;
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
}
.card img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}
.card-body {
  padding: 1.75rem;
  flex: 1;
  display: flex;
  flex-direction: column;
}
.card-body h3 { margin-bottom: 0.6rem; }
.card-body .eyebrow { margin-bottom: 0.5rem; }
.card-link {
  margin-top: auto;
  font-size: 0.85rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  font-weight: 500;
}

/* =========================================================
   Buttons
   ========================================================= */

.btn {
  display: inline-block;
  padding: 0.7rem 1.6rem;
  font-size: 0.8rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 500;
  border-radius: var(--radius);
  cursor: pointer;
  transition: all .25s ease;
  margin-top: 0.5rem;
}
.btn-outline {
  border: 1px solid var(--sage-dark);
  color: var(--sage-dark);
  background: transparent;
}
.btn-outline:hover {
  background: var(--sage-dark);
  color: var(--ivory);
}
.btn-gold {
  background: var(--gold);
  color: var(--ink);
  border: 1px solid var(--gold);
  text-decoration: none;
}
.btn-gold:hover {
  background: transparent;
  color: var(--gold);
}
.explore-cta-row { margin-top: 1.5rem; }

/* ----- /explore.html standalone page ----- */
.explore-body { background: var(--ivory); color: var(--ink); }

/* Sub-pages share the home page's bg-stage filter and tint — every page now
   reads at the same brightness. */

/* Sub-page header text on dark bg → light */
.explore-body .explore-header h1 { color: var(--ivory); }
.explore-body .explore-header .lede { color: rgba(250, 247, 242, 0.85); }
.explore-body .explore-header .eyebrow { color: #d4b888; }
.explore-body .explore-back-link { color: rgba(250, 247, 242, 0.75); }
.explore-body .explore-back-link:hover { color: var(--gold); }

/* Sub-pages keep the nav on a solid ivory pane at all times so it matches
   the main page's scrolled state — consistent across every route. */
.explore-body .nav {
  background: rgba(250, 247, 242, 0.96);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--sand);
  box-shadow: 0 2px 20px rgba(0,0,0,0.05);
  transition:
    background .55s ease,
    backdrop-filter .55s ease,
    box-shadow .55s ease,
    border-bottom-color .55s ease;
}
.explore-body .nav-brand,
.explore-body .nav-menu a,
.explore-body .nav-signout,
.explore-body .lang-btn {
  color: var(--ink);
  transition: color .5s ease;
}
.explore-body .lang-btn { transition: background .2s ease, color .5s ease; }
.explore-body .nav-signout { transition: opacity .3s ease, color .5s ease; }
.explore-body .nav-toggle span {
  background: var(--ink);
  transition: background .5s ease, transform .3s ease, opacity .3s ease;
}

/* Hover states for the always-white sub-page nav, plus the scrolled-white
   state on the main page — match the gold accent the dark nav uses on hover.
   Needs explicit selectors because `.explore-body .nav-menu a` / `.lang-btn`
   etc. share specificity with the base hover rules and would otherwise win
   the cascade and clobber the hover color. */
.explore-body .nav-menu a:hover,
.nav.scrolled .nav-menu a:hover,
.explore-body .nav-brand:hover,
.nav.scrolled .nav-brand:hover,
.explore-body .nav-signout:hover,
.nav.scrolled .nav-signout:hover,
.explore-body .lang-btn:hover,
.nav.scrolled .lang-btn:hover { color: var(--gold); }
.explore-body .lang-btn:hover,
.nav.scrolled .lang-btn:hover { background: rgba(176, 138, 74, 0.12); }
.explore-body .nav-menu a.nav-cta:hover,
.nav.scrolled .nav-menu a.nav-cta:hover {
  background: transparent;
  color: var(--gold);
  border-color: var(--gold);
}

/* Sub-page sections + cards inherit the home page's styling — only text-color
   shims live here since base .section sets these for home already. */

/* Solid-style nav for pages without a dark hero behind */
.nav.nav-solid {
  background: rgba(250, 247, 242, 0.96);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--sand);
  box-shadow: 0 2px 20px rgba(0,0,0,0.04);
}
.nav.nav-solid .nav-brand { color: var(--ink); }
.nav.nav-solid .nav-menu a { color: var(--ink); }
.nav.nav-solid .nav-menu a.active { color: var(--gold); }
.nav.nav-solid .nav-toggle span { background: var(--ink); }

.explore-header {
  padding: calc(var(--nav-h) + 3rem) 0 1.5rem;
  text-align: center;
}
.explore-header h1 {
  font-family: var(--serif);
  font-size: clamp(2.2rem, 5vw, 3.4rem);
  font-weight: 500;
  color: var(--ink);
  margin: 0.4rem 0 1rem;
}
.explore-header .lede { color: var(--charcoal); }
.explore-header .eyebrow { color: var(--muted); }
.explore-back-link {
  display: inline-block;
  margin-top: 0.6rem;
  font-size: 0.75rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--sage-dark);
  text-decoration: none;
}
.explore-back-link:hover { color: var(--gold); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1rem;
}

/* =========================================================
   Info blocks (travel / accommodations)
   ========================================================= */

.info-block {
  background: #fff;
  border-left: 3px solid var(--sage);
  padding: 2rem clamp(1.5rem, 3vw, 2.5rem);
  margin-top: 2rem;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.info-block h3 { margin-top: 0; }

.bullets {
  padding-left: 1.2rem;
  margin: 0 0 1rem;
}
.bullets li { margin-bottom: 0.5rem; }

/* =========================================================
   Timeline
   ========================================================= */

.timeline {
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: 760px;
  margin-left: auto;
  margin-right: auto;
}

/* One frosted card per day — the day header sits at the top of the card and
   all of that day's events stack inside, separated by thin dividers. */
.timeline > li {
  list-style: none;
  margin-bottom: 1.5rem;
  padding: 1.6rem 1.75rem 1.6rem;
  background: rgba(60, 38, 50, 0.55);
  color: var(--ivory);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transform: translateZ(0);
  will-change: backdrop-filter;
  border: 1px solid rgba(212, 184, 136, 0.18);
  border-radius: var(--radius);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}
.timeline > li:last-child { margin-bottom: 0; }

/* Day header at the top of each card — centred chapter-break style with
   a gold rule on each side. Italic gold subtitle for the wedding day. */
.timeline-section-head {
  display: flex;
  align-items: center;
  flex-direction: column;
  gap: 0.2rem;
  margin: 0 0 1.35rem;
  padding: 0 0 1.2rem;
  border-bottom: 1px solid rgba(212, 184, 136, 0.2);
  text-align: center;
}
.timeline-section-head h3 {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin: 0;
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.45rem, 2.8vw, 1.9rem);
  color: var(--ivory);
  letter-spacing: 0.05em;
}
.timeline-section-head h3::before,
.timeline-section-head h3::after {
  content: "";
  width: clamp(36px, 6vw, 72px);
  height: 1px;
  background: linear-gradient(90deg,
    rgba(212, 184, 136, 0) 0%,
    rgba(212, 184, 136, 0.55) 50%,
    rgba(212, 184, 136, 0) 100%);
}
.timeline-section-head span {
  display: block;
  margin: 0;
  padding: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(0.9rem, 1.5vw, 1.02rem);
  letter-spacing: 0.05em;
  text-transform: none;
  color: #d4b888;
  background: transparent;
  border: none;
}

/* The day's events list — no chrome, just rows separated by thin gold rules. */
.timeline-day-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.timeline-day-list > li {
  display: flex;
  gap: 1.5rem;
  align-items: flex-start;
  padding: 0;
  background: transparent;
  border: none;
  box-shadow: none;
}
.timeline-day-list > li + li {
  margin-top: 1.1rem;
  padding-top: 1.1rem;
  border-top: 1px solid rgba(212, 184, 136, 0.15);
}

/* Time column on the left of each event row. */
.timeline-date {
  width: 92px;
  flex-shrink: 0;
  padding-right: 1.25rem;
  border-right: 1px solid rgba(212, 184, 136, 0.18);
  text-align: right;
  display: flex;
  align-items: flex-start;
}
.timeline-date .num {
  display: block;
  font-family: var(--serif);
  font-size: 1.15rem;
  line-height: 1.2;
  color: var(--ivory);
  font-weight: 500;
}

/* Event body — the right side of each row, no chrome. */
.timeline-body {
  flex: 1;
  padding: 0;
  background: transparent;
  border: none;
  box-shadow: none;
  backdrop-filter: none;
  color: var(--ivory);
}
.timeline-body h4 {
  margin: 0 0 0.25rem;
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.05rem, 2vw, 1.2rem);
  line-height: 1.3;
  color: var(--ivory);
}
.timeline-body .time {
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #d4b888;
  margin: 0 0 0.6rem;
  font-weight: 500;
}
.timeline-body p {
  line-height: 1.55;
  color: rgba(250, 247, 242, 0.92);
  margin: 0 0 0.6rem;
}
.timeline-body p:last-child { margin-bottom: 0; }
.timeline-body .muted {
  margin-top: 0.5rem;
  font-size: 0.85rem;
  font-style: italic;
  color: rgba(250, 247, 242, 0.65);
}

/* Mobile: tighten card padding, stack each event row vertically. */
@media (max-width: 540px) {
  .timeline > li {
    padding: 1.25rem 1.1rem;
    margin-bottom: 1rem;
  }
  .timeline-section-head {
    margin: 0 0 1rem;
    padding-bottom: 0.95rem;
  }
  .timeline-section-head h3 {
    font-size: 1.15rem;
    gap: 0.7rem;
  }
  .timeline-section-head h3::before,
  .timeline-section-head h3::after { width: 24px; }
  .timeline-section-head span { font-size: 0.85rem; }

  .timeline-day-list > li { flex-direction: column; gap: 0.45rem; }
  .timeline-day-list > li + li { margin-top: 1rem; padding-top: 1rem; }
  .timeline-date {
    width: auto;
    text-align: left;
    border-right: none;
    padding-right: 0;
    padding-bottom: 0;
  }
  .timeline-date .num { font-size: 1rem; }
}

/* =========================================================
   FAQ (details/summary)
   ========================================================= */

/* The whole FAQ list is wrapped in a single dark card so the text reads
   on top of the photo. Each <details> is a row inside the card, separated
   by a thin gold divider. Matches the schedule day-card pattern. */
.faq {
  background: rgba(60, 38, 50, 0.55);
  color: var(--ivory);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transform: translateZ(0);
  will-change: backdrop-filter;
  border: 1px solid rgba(212, 184, 136, 0.18);
  border-radius: var(--radius);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
  padding: 0.4rem 1.75rem;
}
.faq details {
  border-bottom: 1px solid rgba(212, 184, 136, 0.18);
  padding: 1.25rem 0;
}
.faq details:last-child {
  border-bottom: none;
}
.faq summary {
  list-style: none;
  cursor: pointer;
  font-family: var(--serif);
  font-size: 1.25rem;
  color: var(--ivory);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  font-family: var(--sans);
  font-weight: 300;
  font-size: 1.5rem;
  color: #d4b888;
  transition: transform .3s ease;
  line-height: 1;
}
.faq details[open] summary::after {
  transform: rotate(45deg);
}
.faq details p {
  margin-top: 0.9rem;
  margin-bottom: 0;
  line-height: 1.55;
  color: rgba(250, 247, 242, 0.92);
}

@media (max-width: 540px) {
  .faq { padding: 0.25rem 1.15rem; }
  .faq summary { font-size: 1.1rem; }
}

/* =========================================================
   RSVP form (inside the dark RSVP section)
   ========================================================= */

.rsvp-form {
  margin-top: 1rem;
}

/* Inline flash banner shown after a partial RSVP submit */
.rsvp-flash {
  margin: 0 0 1rem;
  padding: 0.85rem 1.1rem;
  background: rgba(212, 184, 136, 0.12);
  border: 1px solid rgba(212, 184, 136, 0.45);
  border-left: 3px solid #d4b888;
  border-radius: var(--radius);
  color: var(--ivory);
  font-family: var(--sans);
  font-size: 0.9rem;
  line-height: 1.45;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.35s ease, transform 0.35s ease;
}
.rsvp-flash.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.rsvp-members {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-bottom: 2rem;
}

.rsvp-member {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1rem 1.25rem;
  background: rgba(60, 38, 50, 0.62);
  border: 1px solid rgba(212, 184, 136, 0.18);
  border-radius: var(--radius);
  flex-wrap: wrap;
}

.rsvp-member-info {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  min-width: 0;
}
.rsvp-member-name {
  font-family: var(--serif);
  font-size: 1.25rem;
  color: var(--ivory);
  font-weight: 400;
}
.rsvp-member-type {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: rgba(250, 247, 242, 0.5);
}

.rsvp-choices {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.rsvp-radio {
  position: relative;
  cursor: pointer;
}
.rsvp-radio input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.rsvp-radio span {
  display: inline-block;
  padding: 0.65rem 1.2rem;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 500;
  color: rgba(250, 247, 242, 0.78);
  background: transparent;
  border: 1px solid rgba(212, 184, 136, 0.35);
  border-radius: var(--radius);
  transition: background .2s ease, color .2s ease, border-color .2s ease;
  white-space: nowrap;
}
.rsvp-radio:hover span {
  border-color: #d4b888;
  color: var(--ivory);
}
.rsvp-radio input:checked + span {
  background: #d4b888;
  border-color: #d4b888;
  color: var(--ink);
}
.rsvp-radio input:focus-visible + span {
  box-shadow: 0 0 0 3px rgba(212, 184, 136, 0.25);
}

/* "You" badge for the magic-link-authed member */
.rsvp-current-badge {
  width: 100%;
  margin: 0 0 0.4rem;
  font-family: var(--sans);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.28em;
  color: #d4b888;
  font-weight: 600;
}
.rsvp-member.is-current {
  border-color: rgba(212, 184, 136, 0.55);
  box-shadow: 0 0 0 1px rgba(212, 184, 136, 0.2);
}

/* Email field + plus-one section live below the main row */
.rsvp-member .rsvp-field { margin-bottom: 0; }

.rsvp-email-field,
.rsvp-plus-one {
  width: 100%;
  margin-top: 0.7rem;
}

.rsvp-field-label {
  display: block;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(250, 247, 242, 0.65);
  font-weight: 500;
  margin-bottom: 0.35rem;
}
.rsvp-field-hint {
  text-transform: none;
  letter-spacing: 0.02em;
  color: rgba(250, 247, 242, 0.4);
  font-size: 0.7rem;
  font-style: italic;
  font-weight: 400;
}

.rsvp-email-field input[type="email"],
.rsvp-plus-one input[type="text"] {
  width: 100%;
  padding: 0.7rem 0.9rem;
  font-family: var(--sans);
  font-size: 0.92rem;
  color: var(--ivory);
  background: rgba(20, 17, 14, 0.55);
  border: 1px solid rgba(212, 184, 136, 0.25);
  border-radius: var(--radius);
  outline: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.rsvp-email-field input::placeholder,
.rsvp-plus-one input[type="text"]::placeholder {
  color: rgba(250, 247, 242, 0.4);
  font-style: italic;
}
.rsvp-email-field input:focus,
.rsvp-plus-one input[type="text"]:focus {
  border-color: #d4b888;
  box-shadow: 0 0 0 3px rgba(212, 184, 136, 0.15);
}

.rsvp-plus-one {
  padding: 0.9rem 1rem;
  background: rgba(212, 184, 136, 0.06);
  border-left: 2px solid rgba(212, 184, 136, 0.45);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.rsvp-plus-one-label {
  margin: 0 0 0.7rem;
  font-family: var(--sans);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #d4b888;
  font-weight: 600;
}
.rsvp-plus-one .rsvp-field { margin-bottom: 0.65rem; }
.rsvp-plus-one-choices { margin-top: 0.3rem; }

/* Scoped plus-one view — hide host-only fields, slim the layout */
body.rsvp-scoped #rsvpForm > .rsvp-field { display: none; }
.rsvp-scoped-note {
  width: 100%;
  margin: 0 0 0.6rem;
  font-family: var(--serif);
  font-size: 1rem;
  font-style: italic;
  color: rgba(250, 247, 242, 0.85);
}
.rsvp-scoped-note strong {
  font-weight: 500;
  color: #d4b888;
}
.rsvp-member.is-scoped {
  flex-direction: column;
  align-items: flex-start;
  gap: 0.8rem;
}

/* The "everything else we should know" block — dietary, songs, notes —
   lives in its own contained card so the form has the same visual rhythm
   as the rest of the site (member rows are sub-cards above, this is the
   supporting-info card below). */
.rsvp-extras {
  margin-top: 1.25rem;
  margin-bottom: 1.5rem;
  padding: 1.5rem 1.75rem 1.25rem;
  background: rgba(60, 38, 50, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transform: translateZ(0);
  will-change: backdrop-filter;
  border: 1px solid rgba(212, 184, 136, 0.18);
  border-radius: var(--radius);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}

.rsvp-field {
  margin-bottom: 1.25rem;
}
.rsvp-field:last-child { margin-bottom: 0; }
.rsvp-field label {
  display: block;
  margin-bottom: 0.4rem;
  font-family: var(--serif);
  font-size: 1rem;
  letter-spacing: 0.01em;
  color: var(--ivory);
  font-weight: 500;
  text-transform: none;
}
.rsvp-field textarea {
  width: 100%;
  padding: 0.85rem 1rem;
  font-family: var(--sans);
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ivory);
  background: rgba(20, 17, 14, 0.45);
  border: 1px solid rgba(212, 184, 136, 0.22);
  border-radius: var(--radius);
  resize: vertical;
  outline: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.rsvp-field textarea::placeholder {
  color: rgba(250, 247, 242, 0.45);
  font-style: italic;
}
.rsvp-field textarea:focus {
  border-color: #d4b888;
  box-shadow: 0 0 0 3px rgba(212, 184, 136, 0.15);
}

.rsvp-submit {
  display: inline-block;
  padding: 0.95rem 2.5rem;
  font-family: var(--sans);
  font-size: 0.8rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--ink);
  background: #d4b888;
  border: 1px solid #d4b888;
  border-radius: var(--radius);
  cursor: pointer;
  margin-top: 0.5rem;
  transition: background .2s ease, transform .1s ease;
}
.rsvp-submit:hover { background: var(--ivory); border-color: var(--ivory); }
.rsvp-submit:active { transform: translateY(1px); }

.rsvp-success {
  text-align: center;
  padding: 2rem 1rem;
}
.rsvp-success h3 {
  color: var(--ivory);
  margin-bottom: 0.75rem;
}

/* =========================================================
   Footer
   ========================================================= */

.footer {
  background: var(--ink);
  color: var(--sand);
  padding: 3rem 0;
  text-align: center;
}
.footer-names {
  font-family: var(--serif);
  font-size: 1.6rem;
  color: var(--ivory);
  margin: 0 0 0.4rem;
  letter-spacing: 0.1em;
}
.footer-names .amp {
  color: var(--gold);
  font-style: italic;
  margin: 0 0.05em;
}
.footer-cta {
  margin: 1.2rem 0 0;
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
}
.footer-cta a {
  color: var(--gold);
  padding: 0.55rem 1.2rem;
  border: 1px solid rgba(212, 184, 136, 0.55);
  border-radius: 999px;
  transition: background .25s ease, color .25s ease, border-color .25s ease;
}
.footer-cta a:hover {
  background: var(--gold);
  color: var(--ink);
  border-color: var(--gold);
}

.footer-date {
  font-size: 0.8rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  margin: 0;
  opacity: 0.7;
}

/* =========================================================
   Reveal on scroll
   ========================================================= */

.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .8s ease, transform .8s ease;
}
.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  /* Override story-photo reveal so it lands at the resting state without
     animating — keeps the scale(0.92) "small print" look but skips the
     stagger/rotate/slide for users who asked for reduced motion. */
  .story-photo.reveal,
  .story-photo.reveal:nth-child(odd),
  .story-photo.reveal:nth-child(even),
  .story-photo.reveal.visible {
    opacity: 1;
    transform: scale(0.92);
    transition: none;
  }
  .hero-scroll span,
  .bg-layer,
  .loader-inner,
  .loader-shimmer,
  .loader-text .dot { animation: none; }
  .bg-layer { transition: none; }
  #spa-main,
  #spa-main.spa-fade-out { transition: none; opacity: 1; }
  .hero-sky-b { opacity: 0.5; }
  .loader-text .dot { opacity: 0.6; }
}
