/* ==========================================================================
   The Folio of Chloe & Owain — stylesheet
   ==========================================================================
   COLOUR SCHEME — every colour on the site derives from the three tokens
   below (plus the hairline pair, which is derived from the ink). To try a
   new scheme, change these values and nothing else.

   The accent is currently slate blue. Guidance for future changes:
   - --accent must stay dark enough to read on --paper (aim for a contrast
     ratio of at least 4.5:1) because it is used for small labels.
   - --paper text sits on top of --accent in the closing spread and the
     2027 leaf, so the same contrast requirement applies in reverse.
   ========================================================================== */
:root {
  --paper: #FAFAF8;
  --ink: #111111;
  --accent: #4A6076; /* slate blue — replaces the prototype's espresso brown */

  /* Derived tones — fallback first for older engines, colour-mix after. */
  --hairline: rgba(17, 17, 17, 0.18);
  --hairline: color-mix(in srgb, var(--ink) 18%, transparent);
  --hairline-strong: rgba(17, 17, 17, 0.85);
  --hairline-strong: color-mix(in srgb, var(--ink) 85%, transparent);

  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-utility: "Space Grotesk", "Helvetica Neue", Arial, sans-serif;
  --page-pad: clamp(1.5rem, 5vw, 4rem);
}

/* ============================== BASE ============================== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { overflow-x: clip; scroll-behavior: auto; }
body {
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-utility);
  font-size: 1rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
::selection { background: var(--accent); color: var(--paper); }
a { color: inherit; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--accent); }
a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 1px;
}
.closing a:focus-visible { outline-color: var(--paper); }
/* Links on the slate spread invert to a paper plate on hover — the global
   a:hover accent would vanish against the accent background. The padding
   is balanced by negative margin so the resting layout never shifts. */
.closing a {
  padding: 0.3rem 0.45rem;
  margin: -0.3rem -0.45rem;
  transition: background 0.25s ease, color 0.25s ease;
}
.closing a:hover,
.closing a:active {
  background: var(--paper);
  color: var(--accent);
}
/* The focus ring stays paper in every state: outline-offset puts it outside
   the hover plate, on the accent spread, where paper is the visible choice. */

/* Utility label style — the Space Grotesk voice of the folio */
.u-label {
  font-family: var(--font-utility);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* Masked line-reveal scaffolding. Visible by default; JS offsets the inner line. */
.mask { display: block; overflow: hidden; }
.mask > .reveal-line { display: block; }

/* ============================== MONOGRAM ============================== */
/* The CO mark, copied from the couple's Save-the-Date artwork: crisp Didone
   capitals — a large C with a smaller upright O tucked into its lower right,
   the C's terminal crossing in front of the O's ring. All offsets are in em
   so this one rule scales from leaf-head small to cover large. Local
   Didot/Bodoni stand in wherever the webfont cannot load. */
.monogram-mark {
  display: inline-block;
  font-family: "Bodoni Moda", "Didot", "Bodoni MT", "Bodoni 72", Georgia, serif;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
}
.monogram-mark .monogram-c {
  position: relative;
  z-index: 1;
}
.monogram-mark .monogram-o {
  display: inline-block;
  font-size: 0.8em;
  margin-left: -0.44em;
  transform: translateY(0.24em);
}

/* Fixed site monogram — top left, constant throughout the scroll.
   Painted in paper and blended with "difference" so it reads as ink on the
   paper spreads and as paper on the slate spreads, without any scripting. */
.site-monogram {
  position: fixed;
  top: 1.1rem;
  left: clamp(1.25rem, 4vw, 2.5rem);
  z-index: 160;
  font-size: 1.6rem;
  color: var(--paper);
  mix-blend-mode: difference;
  pointer-events: none;
}
@supports not (mix-blend-mode: difference) {
  .site-monogram { color: var(--ink); mix-blend-mode: normal; }
}

/* ============================== BOOK SCENE ============================== */
.book-stage-wrap { position: relative; }
.book-stage {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 6rem 1.25rem 5rem;
  background: var(--paper);
}
.js-enhanced .book-stage {
  height: 100vh;
  height: 100svh;
  min-height: 0;
  padding: 0 1.25rem;
  overflow: hidden;
}

/* Masthead pinned to the top of the scene — the year readout on the right;
   the fixed monogram owns the left corner. */
.stage-masthead {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  justify-content: flex-end;
  gap: 1rem;
  padding: 1.35rem clamp(1.25rem, 4vw, 2.5rem);
  z-index: 60;
}
.stage-masthead .u-label { font-size: 0.62rem; }
.folio-progress { color: var(--accent); font-variant-numeric: tabular-nums; }

/* The book — static mode: a vertical folio of pages */
.book {
  position: relative;
  width: min(90vw, 560px);
  margin: 0 auto;
  display: grid;
  gap: 3.5rem;
}
.js-enhanced .book {
  width: min(88vw, 56vh, 540px);
  aspect-ratio: 3 / 4;
  display: block;
  margin: 0;
  perspective: 1800px;
}

/* Persistent book frame (spine + fore-edge leaves) — enhanced only */
.book-frame { display: none; }
.js-enhanced .book-frame {
  display: block;
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 50;
}
.js-enhanced .book-frame::before {
  /* spine: an ink bar with a slate sewn thread */
  content: "";
  position: absolute;
  top: -2px; bottom: -2px; left: -12px;
  width: 12px;
  background: var(--ink);
  border-right: 2px solid var(--accent);
}
.js-enhanced .book-frame::after {
  /* fore-edge: stacked page edges */
  content: "";
  position: absolute;
  top: 3px; bottom: -5px; right: -7px;
  width: 7px;
  background:
    repeating-linear-gradient(to right,
      var(--paper) 0 1px, rgba(17, 17, 17, 0.35) 1px 2px);
  background:
    repeating-linear-gradient(to right,
      var(--paper) 0 1px, color-mix(in srgb, var(--ink) 35%, transparent) 1px 2px);
  border-right: 1px solid var(--hairline-strong);
}

/* ---------- Cover ---------- */
.book-cover { position: relative; aspect-ratio: 3 / 4; container-type: inline-size; }
.js-enhanced .book-cover {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
  z-index: 40;
  transform-style: preserve-3d;
  transform-origin: left center;
}
.cover-front, .cover-back { position: absolute; inset: 0; }
.js-enhanced .cover-front, .js-enhanced .cover-back {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.cover-front {
  background:
    repeating-linear-gradient(115deg, rgba(250, 250, 248, 0.025) 0 2px, transparent 2px 5px),
    var(--ink);
  background:
    repeating-linear-gradient(115deg, color-mix(in srgb, var(--paper) 2.5%, transparent) 0 2px, transparent 2px 5px),
    var(--ink);
  color: var(--paper);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4.5cqw;
  padding: 10cqw 8cqw;
  border-left: 5px solid var(--accent);
  box-shadow: 0 30px 70px -30px rgba(17, 17, 17, 0.5);
  box-shadow: 0 30px 70px -30px color-mix(in srgb, var(--ink) 50%, transparent);
}
.cover-kicker { opacity: 0.75; font-size: max(9px, 2.6cqw); letter-spacing: 0.34em; }
.cover-names {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 13.5cqw;
  line-height: 1.02;
  letter-spacing: -0.02em;
}
.cover-names em { font-style: italic; font-weight: 500; }
.cover-rule { width: 12cqw; height: 1px; background: var(--accent); }
.cover-years { font-size: max(9px, 2.8cqw); letter-spacing: 0.3em; color: var(--paper); opacity: 0.85; }
.cover-venue { position: absolute; bottom: 7cqw; left: 0; right: 0; font-size: max(8px, 2.3cqw); letter-spacing: 0.3em; opacity: 0.55; }

/* The opened cover's inner face — the left-hand page while the years turn.
   It carries the monogram, the running theme of the whole day. */
.cover-back { display: none; }
.js-enhanced .cover-back {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5cqw;
  transform: rotateY(180deg);
  background: var(--paper);
  border: 1px solid var(--hairline);
}
.cover-back .monogram-mark { font-size: 16cqw; color: var(--ink); opacity: 0.85; }
.cover-back-label { font-size: max(8px, 2.4cqw); letter-spacing: 0.3em; color: var(--ink); opacity: 0.4; }

/* ---------- Page stack + leaves ---------- */
.page-stack { position: relative; display: grid; gap: 3.5rem; }
.js-enhanced .page-stack {
  position: absolute;
  inset: 0;
  display: block;
  overflow: hidden;
  box-shadow: 0 26px 60px -32px rgba(17, 17, 17, 0.4);
  box-shadow: 0 26px 60px -32px color-mix(in srgb, var(--ink) 40%, transparent);
}
.stack-shade { display: none; }
.js-enhanced .stack-shade {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 30;
  background: var(--ink);
  opacity: 0;
  pointer-events: none;
}
.leaf {
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: var(--paper);
  border: 1px solid var(--hairline);
  container-type: inline-size;
}
.js-enhanced .leaf {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
  border: none;
  /* right-edge shadow so the leaf reads against the page beneath while sliding */
  box-shadow: 14px 0 34px -14px rgba(17, 17, 17, 0.35);
  box-shadow: 14px 0 34px -14px color-mix(in srgb, var(--ink) 35%, transparent);
  border-right: 1px solid var(--hairline-strong);
}
.leaf-inner {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: 6cqw;
}
.leaf-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  font-size: max(9px, 2.7cqw);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  font-weight: 500;
}
.leaf-head .leaf-folio-no { color: var(--accent); }
.leaf-head .monogram-mark { font-size: max(11px, 3.4cqw); text-transform: none; letter-spacing: -0.02em; }
.leaf-year {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 30cqw;
  line-height: 0.82;
  letter-spacing: -0.05em;
  margin: 2.5cqw 0 4cqw;
  white-space: nowrap;
}
.crop-right .leaf-year { text-align: right; margin-right: -11cqw; }
.crop-left  .leaf-year { text-align: left;  margin-left: -11cqw; }

/* Image plate: a thin ink rule framing the photograph of that year */
.plate { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.plate-frame {
  flex: 1;
  border: 1px solid var(--hairline-strong);
  position: relative;
  min-height: 24cqw;
  overflow: hidden;
}
.plate-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Per-photo focal point is set inline so faces survive the crop */
  display: block;
  /* Every plate prints black and white — the couple's call, and it sits
     the mixed-era photography inside one editorial ink palette. */
  filter: grayscale(1);
}
.plate-caption {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 2.4cqw;
  font-size: max(8px, 2.5cqw);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 500;
}
.plate-caption .plate-no { color: var(--accent); }

/* ---------- Front-matter leaves: the preface and the invitation ---------- */
.leaf-centre {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4.5cqw;
}
.leaf-centre .monogram-mark { font-size: 11cqw; color: var(--accent); }
.leaf-kicker { font-size: max(9px, 2.6cqw); letter-spacing: 0.3em; text-transform: uppercase; font-weight: 500; color: var(--accent); }
.leaf-display {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 12.5cqw;
  line-height: 1.04;
  letter-spacing: -0.03em;
}
.leaf-display em { font-style: italic; font-weight: 500; color: var(--accent); }
.leaf-display .display-line { display: block; white-space: nowrap; }
.leaf-sub {
  font-size: max(9px, 2.5cqw);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 500;
  opacity: 0.7;
  max-width: 34ch;
  line-height: 1.9;
}
.leaf-foot {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-size: max(8px, 2.4cqw);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  font-weight: 500;
  opacity: 0.65;
}

/* 2027 destination leaf — slate, the colour of the day itself */
.leaf-2027 { background: var(--accent); color: var(--paper); }
.leaf-2027 .leaf-head { color: var(--paper); }
.leaf-2027 .leaf-head .leaf-folio-no { color: var(--paper); opacity: 0.8; }
.leaf-2027 .leaf-year { color: var(--paper); }
.leaf-2027-meta {
  margin-top: auto;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  font-size: max(9px, 2.6cqw);
  letter-spacing: 0.26em;
  text-transform: uppercase;
  font-weight: 500;
}
.leaf-2027-meta .continue-cue { opacity: 0.85; }

/* ============================== KEEP-SCROLLING PROMPT ============================== */
/* A constant, animated cue that asks the reader to keep going until the very
   last page. Blended like the monogram so it stays legible on every spread.
   JS hides it once the closing spread is on screen. */
.scroll-prompt {
  position: fixed;
  bottom: 1.15rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 140;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  color: var(--paper);
  mix-blend-mode: difference;
  pointer-events: none;
  transition: opacity 0.5s ease, visibility 0.5s ease;
  animation: prompt-bob 2.1s ease-in-out infinite;
}
@supports not (mix-blend-mode: difference) {
  .scroll-prompt { color: var(--ink); mix-blend-mode: normal; }
}
.scroll-prompt.is-hidden { opacity: 0; visibility: hidden; }
.scroll-prompt .u-label {
  font-size: 0.7rem;
  animation: prompt-breathe 2.1s ease-in-out infinite;
}
.scroll-prompt-line {
  width: 2px;
  height: 3rem;
  background: currentColor;
  opacity: 0.3;
  position: relative;
  overflow: hidden;
}
.scroll-prompt-line::after {
  content: "";
  position: absolute;
  left: 0; top: -100%;
  width: 100%; height: 100%;
  background: currentColor;
  animation: cue-drop 2.1s cubic-bezier(0.77, 0, 0.18, 1) infinite;
}
/* The chevron catches the line's pulse as it lands, then settles again. */
.scroll-prompt-chevron {
  width: 0.6rem;
  height: 0.6rem;
  margin-top: -0.35rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  animation: chevron-catch 2.1s cubic-bezier(0.77, 0, 0.18, 1) infinite;
}
@keyframes prompt-bob {
  0%, 100% { transform: translate(-50%, 0); }
  55% { transform: translate(-50%, 4px); }
}
@keyframes prompt-breathe {
  0%, 100% { opacity: 0.7; }
  55% { opacity: 1; }
}
@keyframes cue-drop { 0% { top: -100%; } 55% { top: 0; } 100% { top: 100%; } }
@keyframes chevron-catch {
  0%, 50% { opacity: 0.35; transform: rotate(45deg) translate(0, 0); }
  78% { opacity: 1; transform: rotate(45deg) translate(3px, 3px); }
  100% { opacity: 0.35; transform: rotate(45deg) translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .scroll-prompt,
  .scroll-prompt .u-label,
  .scroll-prompt-line::after,
  .scroll-prompt-chevron { animation: none; }
}

/* ============================== 2027 EDITORIAL ============================== */
.wedding { background: var(--paper); }
.wedding-inner { max-width: 1160px; margin: 0 auto; padding: 0 var(--page-pad); }

.wedding-hero {
  --hero-pad-bottom: clamp(4rem, 9vh, 7rem);
  position: relative;
  padding: clamp(6rem, 16vh, 11rem) 0 var(--hero-pad-bottom);
}
.hero-kicker { color: var(--accent); margin-bottom: clamp(1.2rem, 3vh, 2rem); }
.hero-names {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(3.4rem, 14.5vw, 11.5rem);
  line-height: 0.94;
  letter-spacing: -0.035em;
}
.hero-names em { font-style: italic; font-weight: 500; color: var(--accent); }
.hero-names .reveal-line { white-space: nowrap; }
.hero-date-row {
  margin-top: clamp(1.8rem, 4vh, 3rem);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 2.5rem;
  justify-content: flex-start;
}
/* Above the mobile breakpoint the ink figure stands on the right end of the
   hero rule — the date row keeps clear of it so the buttons stay readable. */
@media (min-width: 761px) {
  .hero-date-row { padding-right: clamp(13rem, 26vw, 25rem); }
}
.hero-date { font-size: clamp(0.85rem, 1.6vw, 1.05rem); font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; }
.hero-ref { font-size: 0.7rem; letter-spacing: 0.24em; text-transform: uppercase; opacity: 0.7; }
.hero-rule { height: 1px; background: var(--ink); margin-top: 1.4rem; }

/* Hero calls to action — the reply card and the questions, both one jump away.
   The R.S.V.P. is the one filled button on the whole opening spread, so it
   stands out without shouting over the rest of the page. */
.hero-cta { display: flex; flex-wrap: wrap; gap: 0.8rem 1rem; }
/* One button spec across the site — the reply card's metrics are canonical */
.cta-button {
  display: inline-block;
  text-decoration: none;
  font-family: var(--font-utility);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  padding: 1.05rem 1.9rem;
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
.cta-button--filled {
  background: var(--accent);
  color: var(--paper);
  border: 1px solid var(--accent);
}
.cta-button--filled:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.cta-button--outline {
  /* Solid paper, not transparent — the button must stay legible when it
     stands in front of the ink figure on narrow screens. */
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--ink);
}
.cta-button--outline:hover { background: var(--ink); color: var(--paper); }

/* Hero figure — the couple drawn in ink, stood on the hero rule */
.hero-figure {
  position: absolute;
  right: clamp(0rem, 4vw, 3rem);
  bottom: var(--hero-pad-bottom);
  height: clamp(300px, 58vh, 560px);
  aspect-ratio: 420 / 690;
  margin: 0;
  z-index: 2;
  pointer-events: none;
  color: var(--ink);
}
.figure-clip { position: absolute; inset: 0; }
.hero-silhouette-svg { display: block; width: 100%; height: 100%; }
.figure-shadow {
  position: absolute;
  left: -8%; right: -8%; bottom: -7px;
  height: 16px;
  background: radial-gradient(ellipse at center, rgba(17, 17, 17, 0.22), transparent 68%);
  background: radial-gradient(ellipse at center, color-mix(in srgb, var(--ink) 22%, transparent), transparent 68%);
}
.figure-credit {
  position: absolute;
  top: 24%;
  right: calc(100% + 0.9rem);
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: 0.58rem;
  letter-spacing: 0.32em;
  color: var(--accent);
  opacity: 0.85;
}

/* Numbered editorial sections */
.section {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(2rem, 5vw, 5rem);
  padding: clamp(3.5rem, 9vh, 6.5rem) 0;
  border-top: 1px solid var(--hairline);
}
.section-head { align-self: start; }
.section-no { color: var(--accent); display: block; margin-bottom: 0.9rem; }
.section-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.1rem, 5.5vw, 4.2rem);
  line-height: 0.98;
  letter-spacing: -0.025em;
}
.section-note { margin-top: 1.1rem; font-size: 0.78rem; letter-spacing: 0.06em; opacity: 0.68; max-width: 26ch; }

/* 01 — Venue */
.venue-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.4rem, 6.5vw, 5rem);
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.venue-name a { text-decoration: none; }
.venue-name a:hover .venue-fill { color: var(--accent); }
.venue-address { margin-top: 1.5rem; font-style: normal; font-size: clamp(0.95rem, 2vw, 1.2rem); line-height: 1.9; letter-spacing: 0.04em; }
.venue-address a { text-decoration: none; display: block; }
.venue-address a:hover .reveal-line { color: var(--accent); }
.venue-postcode { color: var(--accent); font-weight: 700; letter-spacing: 0.14em; }
.venue-name { position: relative; }
.venue-outline {
  position: absolute;
  inset: 0;
  color: transparent;
  -webkit-text-stroke: 1.3px var(--accent);
  opacity: 0;
  pointer-events: none;
}
.venue-fill { position: relative; display: block; transition: color 0.25s ease; }
.postcode-rule { width: clamp(5rem, 10vw, 8rem); height: 2px; background: var(--accent); margin-top: 0.9rem; }
.venue-links { margin-top: 1.3rem; display: flex; flex-wrap: wrap; gap: 0.4rem 1.6rem; }
.venue-links .u-label { font-size: 0.62rem; color: var(--accent); text-decoration: none; }
.venue-links .u-label:hover { color: var(--ink); }

/* 02 — Hours: stat row */
.stat-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1.2rem, 3vw, 2.5rem); }
.stat { position: relative; }
.stat-bar { height: 2px; background: var(--ink); margin-bottom: 1rem; }
.stat-label { font-size: 0.68rem; letter-spacing: 0.22em; text-transform: uppercase; font-weight: 500; color: var(--accent); }
.stat-value {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.7rem, 4.6vw, 3.4rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin-top: 0.5rem;
  white-space: nowrap;
}
.stat-suffix { display: block; font-family: var(--font-utility); font-weight: 500; font-size: 0.7rem; letter-spacing: 0.2em; text-transform: uppercase; margin-top: 0.45rem; opacity: 0.68; }
.stat-time { display: inline-block; font-variant-numeric: tabular-nums; }

/* 03 — Programme: numbered column with the day's timings.
   Labels and times are locked to a single line at every viewport — a line
   that rewraps mid-scroll breaks the masked reveals — so the label type is
   sized against its own container (cqw), never against the viewport. */
.programme { list-style: none; container-type: inline-size; }
.programme-item {
  display: grid;
  grid-template-columns: 3.2rem minmax(0, 1fr) auto;
  grid-template-areas: "no label time";
  align-items: baseline;
  gap: 0.2rem 1rem;
  padding: clamp(0.9rem, 2vh, 1.4rem) 0;
  position: relative;
}
.programme-rule { position: absolute; top: 0; left: 0; right: 0; height: 1px; background: var(--ink); transform-origin: left center; }
.prog-no { grid-area: no; color: var(--accent); font-weight: 700; font-size: 0.8rem; letter-spacing: 0.18em; }
.prog-label {
  grid-area: label;
  font-family: var(--font-display);
  font-weight: 900;
  /* 5cqw keeps "Evening Celebrations" inside its column at any width */
  font-size: clamp(1.25rem, 5cqw, 2.7rem);
  line-height: 1.02;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.prog-time {
  grid-area: time;
  justify-self: end;
  color: var(--accent);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.programme-rule-end { height: 1px; background: var(--ink); margin-top: 0.4rem; }
/* Once the column narrows, the programme re-stacks: number and time share
   the rule line, the label takes a full row so it never leaves one line. */
@media (max-width: 1050px) {
  .programme-item {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "no time"
      "label label";
  }
  .prog-label { font-size: clamp(1.25rem, 6.4cqw, 2.7rem); }
}

/* 03b — The route: a journey line plotted beside the programme (enhanced only) */
.programme-wrap { position: relative; }
.js-enhanced .programme-wrap { padding-left: clamp(3.4rem, 6vw, 5rem); }
.journey-rail { display: none; }
.js-enhanced .journey-rail {
  display: block;
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: clamp(3.4rem, 6vw, 5rem);
  pointer-events: none;
}
.journey-rail svg { display: block; overflow: visible; }
.journey-path-base { fill: none; stroke: var(--ink); stroke-opacity: 0.22; stroke-width: 1; stroke-dasharray: 0.5 6; stroke-linecap: round; }
.journey-path-ink { fill: none; stroke: var(--accent); stroke-width: 1.6; }
.journey-station { fill: var(--paper); stroke: var(--accent); stroke-width: 1.4; transition: fill 0.3s ease; }
.journey-station.is-passed { fill: var(--accent); }
.journey-marker-ring { fill: var(--paper); stroke: var(--accent); stroke-width: 1.6; }
.journey-marker-dot { fill: var(--accent); }
.js-enhanced .prog-no { opacity: 0.35; transition: opacity 0.35s ease; }
.js-enhanced .programme-item.is-reached .prog-no { opacity: 1; }

/* 04 — Accommodation */
.stay-list { list-style: none; }
.stay-item { padding: clamp(1.1rem, 2.6vh, 1.6rem) 0; }
.stay-item:first-child { padding-top: 0; }
.stay-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem clamp(0.8rem, 2vw, 1.4rem); }
.stay-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.5rem, 4vw, 2.6rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  flex-shrink: 0;
  transition: color 0.25s ease, transform 0.25s ease;
}
.stay-item:hover .stay-name { color: var(--accent); transform: translateX(6px); }
.stay-leader {
  flex: 1 1 auto;
  min-width: 2rem;
  height: 3px;
  align-self: center;
  background-image: radial-gradient(circle, var(--ink) 1.1px, transparent 1.4px);
  background-size: 9px 3px;
  background-repeat: repeat-x;
  opacity: 0.5;
}
.stay-place { text-transform: uppercase; letter-spacing: 0.18em; font-size: 0.7rem; font-weight: 500; opacity: 0.7; }
.stay-link { flex: 1 0 100%; text-align: right; color: var(--accent); font-weight: 500; font-size: 0.8rem; letter-spacing: 0.08em; }
/* Group heading inside the list — separates the country-house favourites
   from the Chippenham stays five to ten minutes from the door. */
.stay-group {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  padding: clamp(1.4rem, 3.4vh, 2rem) 0 0.4rem;
}
.stay-group-label { color: var(--accent); font-size: 0.64rem; }
.stay-group-rule { flex: 1; height: 1px; background: var(--hairline); transform-origin: left center; }

/* 05 — Dress code */
.dress-line {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2rem, 6vw, 4.6rem);
  line-height: 1.04;
  letter-spacing: -0.025em;
}
.dress-line em { font-style: italic; font-weight: 500; color: var(--accent); }
.dress-line .reveal-line { white-space: nowrap; }
.dress-note { margin-top: 1.2rem; font-size: 0.72rem; letter-spacing: 0.22em; text-transform: uppercase; font-weight: 500; opacity: 0.68; }
.dress-invert { position: relative; display: inline-block; }
.invert-overlay {
  position: absolute;
  top: -0.08em; bottom: -0.12em; left: -0.1em; right: -0.1em;
  padding: 0.08em 0.1em 0.12em;
  background: var(--ink);
  color: var(--paper);
  white-space: nowrap;
}
.invert-overlay em { color: var(--paper); }

/* 06 — Countdown */
.count-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(1rem, 2.6vw, 2.2rem); }
.count-bar { height: 2px; background: var(--ink); margin-bottom: 1rem; }
.count-value {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.8rem, 5vw, 4rem);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  min-height: 1em;
}
.count-label { margin-bottom: 0.55rem; font-size: 0.66rem; letter-spacing: 0.22em; text-transform: uppercase; font-weight: 500; color: var(--accent); }
.count-meta { margin-top: 1.6rem; font-size: 0.72rem; letter-spacing: 0.08em; opacity: 0.68; }

/* 07 — RSVP: the reply card */
.rsvp-deadline {
  margin-top: 1.3rem;
  color: var(--accent);
  font-weight: 700;
  font-size: 0.66rem;
  border-top: 1px solid var(--hairline);
  padding-top: 1.1rem;
  max-width: 24ch;
  line-height: 2;
}
.rsvp-form { display: grid; gap: clamp(1.7rem, 4.2vh, 2.6rem); }
.rsvp-label { display: block; color: var(--accent); margin-bottom: 0.7rem; }
.rsvp-input {
  width: 100%;
  border: none;
  border-radius: 0;
  background: transparent;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.2rem, 2.6vw, 1.8rem);
  letter-spacing: -0.01em;
  color: var(--ink);
  padding: 0.15rem 0 0.55rem;
}
.rsvp-input:focus { outline: none; }
/* Keyboard focus gets a full outline; pointer focus keeps the quiet rule cue */
.rsvp-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.rsvp-input::placeholder { color: var(--ink); opacity: 0.25; font-style: italic; }
.rsvp-rule { height: 1px; background: var(--ink); transform-origin: left center; }
.rsvp-field:focus-within .rsvp-rule { height: 2px; background: var(--accent); }
.rsvp-choice-set { border: none; margin: 0; padding: 0; }
.rsvp-choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1rem, 3vw, 2rem); margin-top: 0.2rem; }
.rsvp-choice { position: relative; display: block; cursor: pointer; padding: 0.2rem 0 0.9rem; }
.rsvp-choice input { position: absolute; opacity: 0; pointer-events: none; }
.rsvp-choice-text {
  display: block;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.5rem, 3.6vw, 2.4rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  /* Unselected answers stay subordinate to the chosen one but must remain
     readable in the static document — at 0.55 this display-size type holds
     the WCAG large-text contrast threshold; 0.3 did not. */
  opacity: 0.55;
  transition: opacity 0.25s ease, color 0.25s ease;
}
.rsvp-choice-mark {
  display: inline-block;
  margin-top: 0.65rem;
  font-size: 0.6rem;
  color: var(--accent);
  border: 1px solid var(--accent);
  padding: 0.3rem 0.55rem;
  /* 0.9 keeps this small Yes/No text at ≥ 4.5:1 on paper; the checked state
     still reads clearly stronger because it fills with the accent. */
  opacity: 0.9;
  transition: background 0.25s ease, color 0.25s ease, opacity 0.25s ease;
}
.rsvp-choice::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.35s cubic-bezier(0.77, 0, 0.18, 1);
}
.rsvp-choice:hover .rsvp-choice-text { opacity: 0.8; }
.rsvp-choice input:checked ~ .rsvp-choice-text { opacity: 1; color: var(--accent); }
.rsvp-choice input:checked ~ .rsvp-choice-mark { background: var(--accent); color: var(--paper); opacity: 1; }
.rsvp-choice:has(input:checked)::after { transform: scaleX(1); }
.rsvp-choice input:focus-visible ~ .rsvp-choice-text { outline: 2px solid var(--accent); outline-offset: 5px; }
.rsvp-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1.1rem 1.4rem; }
.rsvp-send {
  display: inline-block;
  background: var(--ink);
  color: var(--paper);
  text-decoration: none;
  font-family: var(--font-utility);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  padding: 1.05rem 1.9rem;
  transition: background 0.25s ease;
}
.rsvp-send:hover { background: var(--accent); color: var(--paper); }
.rsvp-calendar {
  display: inline-block;
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--ink);
  cursor: pointer;
  font-family: var(--font-utility);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  padding: 1.05rem 1.9rem;
  transition: background 0.25s ease, color 0.25s ease;
}
.rsvp-calendar:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.rsvp-calendar:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
/* Same [hidden] guard as the form/thanks/opening states: the display value
   above would otherwise defeat the hidden attribute, leaving a dead button
   in the no-JS document (calendar.js reveals it only when scripts run). */
.rsvp-calendar[hidden] { display: none; }
.rsvp-hint { color: var(--accent); min-height: 1.1em; flex: 1 1 14rem; letter-spacing: 0.18em; }
.rsvp-footnote { font-size: 0.72rem; letter-spacing: 0.05em; opacity: 0.7; max-width: 52ch; }

/* The acknowledgement that replaces the reply card once it has been sent.
   The explicit [hidden] rules matter: the class display values would
   otherwise defeat the hidden attribute's user-agent style. */
.rsvp-form[hidden] { display: none; }
.rsvp-thanks[hidden] { display: none; }
.rsvp-thanks {
  display: grid;
  gap: 1.4rem;
  justify-items: start;
  animation: thanks-arrive 0.9s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes thanks-arrive {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) { .rsvp-thanks { animation: none; } }
.rsvp-thanks .monogram-mark { font-size: 2.2rem; color: var(--accent); }
.rsvp-thanks-line {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.5rem, 3.4vw, 2.4rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  max-width: 24ch;
}
.rsvp-thanks-note { font-size: 0.78rem; letter-spacing: 0.05em; opacity: 0.65; max-width: 44ch; }

/* The held state between pressing send and the thank-you: the guest's mail
   app is opening. mailto reports nothing back on any platform, so this
   bridges the hand-off for a moment before the acknowledgement arrives. */
.rsvp-opening[hidden] { display: none; }
.rsvp-opening {
  display: grid;
  gap: 1rem;
  justify-items: start;
  animation: thanks-arrive 0.9s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.rsvp-opening-title {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.3rem, 3vw, 2rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.rsvp-opening-dots span {
  display: inline-block;
  animation: dot-lift 1.3s ease-in-out infinite;
}
.rsvp-opening-dots span:nth-child(2) { animation-delay: 0.18s; }
.rsvp-opening-dots span:nth-child(3) { animation-delay: 0.36s; }
@keyframes dot-lift {
  0%, 60%, 100% { opacity: 0.35; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-0.12em); }
}
.rsvp-opening-note { font-size: 0.78rem; letter-spacing: 0.05em; opacity: 0.65; max-width: 44ch; }
@media (prefers-reduced-motion: reduce) {
  .rsvp-opening { animation: none; }
  .rsvp-opening-dots span { animation: none; }
}

/* ============================== CLOSING SPREAD ============================== */
.closing {
  background: var(--accent);
  color: var(--paper);
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: clamp(5rem, 14vh, 9rem) var(--page-pad);
}
.closing-inner { max-width: 1160px; margin: 0 auto; width: 100%; padding: 0 var(--page-pad); }
.closing .monogram-mark { font-size: 2.4rem; opacity: 0.85; }
.closing-kicker { opacity: 0.8; margin: clamp(1.2rem, 3vh, 2rem) 0 clamp(1.5rem, 4vh, 2.5rem); }
.closing-line {
  font-family: var(--font-display);
  font-weight: 500;
  font-style: italic;
  font-size: clamp(1.55rem, 4.6vw, 3.6rem);
  line-height: 1.18;
  letter-spacing: -0.015em;
}
.closing-rule { height: 1px; background: var(--paper); opacity: 0.7; margin: clamp(2.2rem, 6vh, 3.8rem) 0 1.6rem; transform-origin: left center; }
.closing-names { font-family: var(--font-display); font-weight: 900; font-size: clamp(1.4rem, 3.4vw, 2.4rem); letter-spacing: -0.01em; }
.closing-names em { font-style: italic; font-weight: 500; }
.closing-meta { margin-top: 0.9rem; display: flex; flex-wrap: wrap; gap: 0.4rem 2rem; font-size: 0.68rem; letter-spacing: 0.24em; text-transform: uppercase; font-weight: 500; opacity: 0.8; }

/* ============================== PAGE PILLS ============================== */
/* Fixed doorways to the two hidden page states: the FAQs and the registry.
   Always in reach, never in the way. */
.page-pills {
  position: fixed;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  z-index: 150;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
}
.page-pill {
  padding: 0.7rem 1.15rem;
  background: var(--paper);
  color: var(--accent);
  border: 1px solid var(--accent);
  text-decoration: none;
  font-size: 0.6rem;
  box-shadow: 0 10px 28px -16px rgba(17, 17, 17, 0.45);
  box-shadow: 0 10px 28px -16px color-mix(in srgb, var(--ink) 45%, transparent);
  transition: background 0.25s ease, color 0.25s ease;
}
.page-pill:hover { background: var(--accent); color: var(--paper); }

/* ============================== PAGE STATES — APPENDIX & REGISTRY ============================== */
/* Static documents: plain sections at the end of the page. Enhanced: hidden
   page states that wipe up over the folio when summoned. */
.page-state { background: var(--paper); border-top: 1px solid var(--hairline); }
.js-enhanced .page-state {
  position: fixed;
  inset: 0;
  z-index: 200;
  overflow-y: auto;
  overscroll-behavior: contain;
  visibility: hidden;
  border-top: none;
}
.page-state:focus { outline: none; }
.page-state-open { overflow: hidden; }
.page-state-inner { max-width: 1160px; margin: 0 auto; padding: clamp(3rem, 8vh, 5.5rem) var(--page-pad) clamp(4rem, 10vh, 6.5rem); }
.page-state-masthead {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 1rem;
  padding-bottom: 1.4rem;
  border-bottom: 2px solid var(--ink);
  margin-bottom: clamp(1.6rem, 4vh, 2.6rem);
}
.page-state-kicker { color: var(--accent); margin-bottom: 0.8rem; }
.page-state-title { font-family: var(--font-display); font-weight: 900; font-size: clamp(2rem, 5.5vw, 4rem); letter-spacing: -0.025em; line-height: 1; }
.page-state-close {
  display: none;
  font-family: var(--font-utility);
  font-size: 0.62rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  font-weight: 500;
  background: none;
  border: 1px solid var(--ink);
  color: var(--ink);
  padding: 0.6rem 1rem;
  cursor: pointer;
  transition: background 0.25s ease, color 0.25s ease;
}
.js-enhanced .page-state-close { display: inline-block; }
.page-state-close:hover { background: var(--ink); color: var(--paper); }
.page-state-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.page-state-footnote { margin-top: clamp(2rem, 5vh, 3rem); opacity: 0.55; font-size: 0.58rem; }

/* Appendix — questions & answers */
.faq-list { list-style: none; }
.faq-item {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(1rem, 3vw, 3.5rem);
  padding: clamp(1.3rem, 3vh, 1.9rem) 0;
  border-top: 1px solid var(--hairline);
}
.faq-item:first-child { border-top: none; }
.faq-q-no { display: block; color: var(--accent); margin-bottom: 0.55rem; }
.faq-q { font-family: var(--font-display); font-style: italic; font-weight: 500; font-size: clamp(1.15rem, 2.4vw, 1.65rem); line-height: 1.25; letter-spacing: -0.01em; }
.faq-a { font-size: 0.9rem; line-height: 1.75; letter-spacing: 0.02em; opacity: 0.85; align-self: center; }

/* Registry — gifts */
.registry-body { max-width: 62ch; display: grid; gap: 1.6rem; justify-items: start; }
.registry-line {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.5rem, 3.6vw, 2.6rem);
  line-height: 1.22;
  letter-spacing: -0.01em;
  max-width: 22ch;
}
.registry-note { font-size: 0.9rem; line-height: 1.75; letter-spacing: 0.02em; opacity: 0.85; }
/* The slot where the registry link will live once it exists — one faint
   ruled baseline, waiting in the folio's voice. */
.registry-slot {
  width: 100%;
  max-width: 30rem;
  padding-bottom: 0.8rem;
  border-bottom: 1px solid var(--hairline);
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  font-weight: 500;
  opacity: 0.4;
}
.registry-slot a { opacity: 1; }
.registry-cta {
  display: inline-block;
  background: var(--accent);
  color: var(--paper);
  text-decoration: none;
  font-family: var(--font-utility);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  padding: 1.05rem 1.9rem;
  transition: background 0.25s ease;
}
.registry-cta:hover { background: var(--ink); }

/* ============================== RESPONSIVE — THE POCKET FOLIO ============================== */
/* On a phone the editorial re-sets like the folio's own leaves: the numbered
   section heads keep the running left-aligned grid (the design's spine), the
   plates inside them become centred ceremonial moments with one display-scale
   moment per spread, functional matter turns into compact ruled rows, and the
   fixed furniture retires once the book is put down (classes applied by
   js/scroll-prompt.js at this width only). Everything here is scoped to
   760px so desktop and tablet stay exactly as they are. */
@media (max-width: 760px) {
  .section { grid-template-columns: minmax(0, 1fr); gap: 1.8rem; }
  .stage-masthead { padding: 1.1rem 1.25rem; }
  .stage-masthead .u-label { font-size: 0.55rem; letter-spacing: 0.16em; }
  .site-monogram {
    font-size: 1.3rem;
    top: 0.95rem;
    transition: opacity 0.5s ease, visibility 0.5s ease;
  }
  .monogram-parked .site-monogram { opacity: 0; visibility: hidden; }

  /* Hero — the pocket frontispiece: names, the couple standing on the rule,
     then the details and both doors beneath it. Centred, and budgeted so the
     R.S.V.P. button lands inside the first screen. */
  .wedding-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding-top: clamp(4.2rem, 10vh, 6rem);
  }
  .hero-kicker { order: 1; }
  .hero-names { order: 2; }
  .hero-figure {
    order: 3;
    /* Relative, not static: the clip and shadow inside are absolutely
       positioned against the figure and must not escape to the hero. */
    position: relative;
    right: auto;
    bottom: auto;
    height: clamp(200px, 34vh, 330px);
    margin-top: clamp(1.2rem, 3vh, 2rem);
    opacity: 1;
  }
  .hero-rule { order: 4; align-self: stretch; margin-top: 0; }
  .hero-date-row {
    order: 5;
    align-self: stretch;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1.5rem;
  }
  .hero-date { font-size: min(0.85rem, 3.6vw); white-space: nowrap; }
  .hero-cta {
    align-self: stretch;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.7rem;
    margin-top: 0.5rem;
  }
  .hero-cta .cta-button { text-align: center; padding: 1.05rem 0.5rem; }
  .figure-credit { display: none; }

  /* No. 01 — the venue plate is the spread's big centred moment. */
  #sectionVenue .section-body { text-align: center; }
  .venue-name { font-size: min(4.6rem, 16vw); }
  .postcode-rule { margin-left: auto; margin-right: auto; }
  /* Row gap must exceed the links' hit-area overhang (0.55rem) so the two
     targets never overlap when the links wrap onto two rows. */
  .venue-links { justify-content: center; gap: 1rem 1.4rem; }
  .venue-links .u-label { padding: 1.1rem 0.3rem; margin: -0.55rem 0; }

  /* No. 02 — compact ruled stats that keep their big-number identity:
     rule, label, then the display-size time with its suffix run beside it. */
  .stat-grid { grid-template-columns: minmax(0, 1fr); gap: 1.4rem; }
  .stat-bar { margin-bottom: 0.75rem; }
  .stat-value {
    display: flex;
    align-items: baseline;
    gap: 0.9rem;
    font-size: 2.1rem;
    margin-top: 0.4rem;
  }
  .stat-suffix { margin-top: 0; }

  /* No. 03 — the programme already reads well; the rail just narrows. */
  .js-enhanced .programme-wrap { padding-left: 2.6rem; }
  .js-enhanced .journey-rail { width: 2.6rem; }

  /* No. 04 — the contents-page anatomy returns: name, dot leader, place on
     one line, the link beneath. Names are container-fitted so the leader
     always points at something, down to 320px. */
  .stay-list { container-type: inline-size; }
  .stay-item { padding: 1rem 0; }
  .stay-name { font-size: clamp(1.05rem, 5.6cqw, 1.5rem); }
  .stay-place { font-size: 0.6rem; letter-spacing: 0.12em; }
  .stay-link { text-align: left; padding: 0.55rem 0 0.2rem; }

  /* No. 05 — the dress plate, centred. */
  #sectionDress .section-body { text-align: center; }
  .dress-line { font-size: min(3.2rem, 11vw); }

  /* No. 06 — the countdown leads with one display-scale figure, echoing the
     folio's cropped year numerals: days huge, the running clock beneath it
     as a small ruled sub-row. */
  .count-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.3rem 0.9rem; }
  .count-unit:first-child { grid-column: 1 / -1; }
  .count-value { font-size: clamp(1.5rem, 6.4vw, 2.4rem); }
  .count-unit:first-child .count-value { font-size: min(7.5rem, 24vw); line-height: 0.9; }
  .count-label { font-size: 0.6rem; letter-spacing: 0.18em; }

  /* No. 07 — the reply card: full-width actions; nothing may clip. The
     hint's 14rem flex-basis is a sensible width in the desktop row but
     becomes 224px of empty height in this column — collapse it (it still
     grows when a validation message appears). The due-date footnote sits
     as its own ruled caption straight after the buttons. */
  .rsvp-choices { gap: 1rem; }
  .rsvp-actions { flex-direction: column; align-items: stretch; }
  .rsvp-send, .rsvp-calendar { width: 100%; text-align: center; }
  .rsvp-actions .rsvp-hint { flex: 0 0 auto; min-height: 0; }
  .rsvp-footnote {
    border-top: 1px solid var(--hairline);
    padding-top: 1.1rem;
  }

  /* Closing — a centred colophon. The stanza is sized against its longest
     authored line (~15.5em) so re-worded lines shrink instead of clipping
     behind overflow-x: clip; the venue line is fitted the same way. */
  .closing-inner { padding: 0; text-align: center; }
  .closing-line { font-size: min(1.55rem, calc((100vw - 2 * var(--page-pad)) / 15.5)); }
  .closing-line .reveal-line { white-space: nowrap; }
  .closing-rule { margin-left: auto; margin-right: auto; }
  .closing-names { font-size: min(1.4rem, calc((100vw - 2 * var(--page-pad)) / 13)); }
  .closing-meta { flex-direction: column; align-items: center; gap: 0.55rem; }
  .closing-meta span {
    font-size: min(0.68rem, calc((100vw - 2 * var(--page-pad)) / 32));
    letter-spacing: 0.14em;
    white-space: nowrap;
  }
  /* With the pills parked here, these two links are the doorway on this
     spread — dressed as proper doors, with full-size tap targets. */
  .closing-meta a {
    border: 1px solid rgba(250, 250, 248, 0.65);
    border: 1px solid color-mix(in srgb, var(--paper) 65%, transparent);
    padding: 1rem 1.3rem;
    margin: 0.35rem 0 0;
    text-decoration: none;
  }

  /* Fixed furniture — the pills sit in one compact row reading just "FAQs"
     and "Gifts" (the prefixes stay in the accessible name), and the whole
     rail parks over the closing, where its duplicates live. The fade class
     goes on the wrapper: GSAP owns the pills' own inline opacity. */
  .page-pills {
    right: 0.9rem;
    bottom: 0.9rem;
    flex-direction: row;
    gap: 0.5rem;
    transition: opacity 0.45s ease, visibility 0.45s ease;
  }
  .pills-parked .page-pills { opacity: 0; visibility: hidden; pointer-events: none; }
  .page-pill {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    font-size: 0.58rem;
    padding: 0 1.05rem;
  }
  .pill-prefix {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  /* A shorter cue on phones — less height, no chance of grazing the book. */
  .scroll-prompt { bottom: 0.9rem; gap: 0.4rem; }
  .scroll-prompt .u-label { font-size: 0.6rem; }
  .scroll-prompt-line { height: 2rem; }

  /* Appendix & Registry as phone pages: the masthead rides sticky so Close
     is always in reach on the long FAQ (enhanced overlays only — the static
     document scrolls as one page). */
  .js-enhanced .page-state-masthead {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--paper);
    padding-top: 1rem;
  }
  .page-state-close { padding: 1rem 1.15rem; }
  .faq-item { grid-template-columns: minmax(0, 1fr); gap: 0.7rem; }
  .faq-a { align-self: start; }
}

/* Below ~360px the reply-card answer stacks to one column — "Regretfully
   Declines" must never clip off the page. */
@media (max-width: 359px) {
  .rsvp-choices { grid-template-columns: minmax(0, 1fr); }
}
