/* MAX, New Year's Eve 2026. The site is the book, opened. */

@font-face {
  font-family: "Six Caps";
  src: url("fonts/six-caps.woff2?v=b7ba99555d") format("woff2");
  font-display: block;
}
@font-face {
  font-family: "Archivo";
  src: url("fonts/archivo.woff2?v=4c98b9d490") format("woff2");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
}
@font-face {
  font-family: "Libre Caslon Text";
  src: url("fonts/libre-caslon-italic.woff2?v=33a3280b9c") format("woff2");
  font-style: italic;
  font-display: swap;
}

:root {
  --table: #050505;          /* what the book sits on (desktop surround) */
  --page: #0b0a0a;           /* matte black page */
  --page-lift: #171414;
  --flash: #fffaf3;          /* flash-white: reserved for what's in focus */
  --text: #f4f0ee;
  --text-dim: #b8aeaa;       /* 8.9:1 on --page */
  /* One red everywhere: oxblood #92140C, flat, no shine (Ben, 2026-11-07). */
  --foil: #92140C;
  --foil-deep: #92140C;
  --edge-red-bright: #92140C;
  --edge-oxblood: #92140C;
  --edge-white: #f4f0ee;

  --display: "Six Caps", "Archivo", sans-serif;
  --sans: "Archivo", system-ui, sans-serif;
  --serif: "Libre Caslon Text", Georgia, serif;

  --gutter: clamp(20px, 6vw, 32px);
  --edge-room: 34px;          /* space reserved for the sideways caption */
  --book: min(100vw, 34rem);
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
/* The hidden attribute always wins over component display rules. */
[hidden] { display: none !important; }

html {
  background: var(--table);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  scrollbar-color: var(--foil-deep) var(--table);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  color: var(--text);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.5;
  font-stretch: 92%;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--foil); color: var(--flash); }
:focus-visible { outline: 2px solid var(--flash); outline-offset: 3px; }

b { font-weight: 800; }
i { font-family: var(--serif); font-style: italic; font-weight: 400; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Display red: flat oxblood, no shine (Ben, 2026-11-07) ---------- */
.foil {
  color: var(--foil);
  padding-block: var(--foil-pad, 0);
}
/* Live foil (foil.js): a WebGL canvas paints the letters; the real text stays
   underneath, invisible, for screen readers, selection and layout. */
.foil--live {
  background: none !important;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.foil-live {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .foil { -webkit-text-fill-color: currentColor; background: none; }
}

/* ---------- Cover ---------- */
.cover {
  position: relative;
  isolation: isolate;
  width: var(--book);
  min-height: 100svh;
  margin-inline: auto;
  padding: max(env(safe-area-inset-top), 18px) var(--gutter) max(env(safe-area-inset-bottom), 22px) calc(var(--gutter) + 10px);
  display: grid;
  grid-template-rows: 1fr auto auto auto auto;
  overflow: hidden;
  background:
    radial-gradient(120% 70% at 30% 34%, #241b19 0%, #141110 45%, var(--page) 80%);
}
/* Max's photo behind MAX, in its own color (Max, 2026-11-07: no black-and-white filter). */
.cover__photo {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  /* Max, 2026-11-07: up a little, so her face just touches MAX’S and more of her hair and arm shows below. */
  transform: translateY(-12%);
  z-index: -4;
}
/* A dark fade only under the lower text, so the photo stays clear up top. */
.cover.has-photo::before {
  content: "";
  position: absolute; inset: 0;
  z-index: -3;
  background: linear-gradient(180deg, rgba(11,10,10,0) 0%, rgba(11,10,10,0) 34%, rgba(11,10,10,.3) 46%, rgba(11,10,10,.62) 58%, rgba(11,10,10,.82) 70%, rgba(11,10,10,1) 86%, rgba(11,10,10,1) 100%);
}
.cover.has-photo { background: var(--page); }
.guest-caption__plate img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cover__confetti {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  z-index: -2;
}
.cover__flash {
  position: absolute; inset: 0; z-index: 3;
  background: var(--flash);
  opacity: 0;
  pointer-events: none;
}
.is-loaded .cover__flash { animation: flash-pop 1300ms cubic-bezier(.12,.8,.2,1) 120ms both; }
@keyframes flash-pop {
  0% { opacity: 0; }
  4% { opacity: .92; }
  100% { opacity: 0; }
}
.cover__spine {
  position: absolute; inset: 0 auto 0 0;
  width: 12px;
  background: linear-gradient(90deg, #050505 0%, #2a2525 55%, #0a0909 100%);
  box-shadow: 3px 0 8px rgba(0,0,0,.55);
}

.cover__title {
  margin: 0;
  align-self: stretch;
  display: grid;
  grid-template-rows: auto 1fr;
  justify-items: start;
  font-weight: 400;
}
.cover__word {
  display: block;
  pointer-events: none;
  /* Max, 2026-11-07: at the top of the photo; plain red, no shine; a little taller
     and narrower than a normal sans, not bold. JS sizes it to fill the page width. */
  font-family: var(--sans);
  font-weight: 500;
  font-stretch: 72%;
  font-size: calc((var(--book) - var(--gutter) * 2 - 10px) / 1.9);
  line-height: 1; /* whole-pixel box; fitInk's margins hug the ink */
  letter-spacing: 0;
  margin-left: -.03em;
  color: var(--foil);
  transform: scaleY(var(--stretch, 1.15));
  transform-origin: top left;
}
.cover__subtitle {
  display: block;
  align-self: start;
  margin-top: 12px;
  font-family: var(--sans);
  font-stretch: 100%;
  font-weight: 800;
  font-size: clamp(1.25rem, 5.6vw, 1.75rem);
  line-height: 1.04;
  letter-spacing: -.02em;
  color: var(--flash);
  text-shadow: 0 2px 3px rgba(11,10,10,.7), 0 1px 18px rgba(11,10,10,.9);
}
.cover__credits {
  margin: 0;
  display: grid;
  gap: 2px;
  font-size: clamp(.95rem, 4.1vw, 1.125rem);
  line-height: 1.2;
  text-shadow: 0 1px 10px rgba(11,10,10,.9);
}
.cover__credits i { font-size: 1.04em; color: var(--text); }

/* What's on, set apart like the sponsor strip at the foot of a flyer:
   one line, "bites by Up Late | custom cocktails | photo booth", then "and more"
   (Ben, 2026-11-07). Everything is in em so the line shrinks to fit narrow phones. */
.cover__lineup {
  list-style: none;
  margin: clamp(22px, 4.5svh, 40px) 0 0;
  padding: 12px 0 13px;
  border-block: 1px solid rgba(244, 240, 238, .22);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  row-gap: .3em;
  font: 700 1rem/1.2 var(--sans);
  font-stretch: 100%;
  color: var(--text);
  text-align: center;
  text-shadow: 0 1px 10px rgba(11,10,10,.9);
}
.cover__lineup li { display: flex; align-items: center; white-space: nowrap; }
.cover__lineup i { font-size: 1.06em; }
.cover__lineup-bites { gap: .45em; }
.cover__lineup-bites img { display: block; width: auto; height: 2.3em; }
.cover__lineup li:nth-child(2)::before,
.cover__lineup li:nth-child(3)::before {
  content: "";
  width: 1px; height: 1.15em;
  margin: 0 .75em;
  background: rgba(244, 240, 238, .6);
}
.cover__lineup-more { flex-basis: 100%; justify-content: center; }
.cover__countdown {
  margin: 12px 0 0;
  text-align: center;
  font-size: clamp(.95rem, 4.1vw, 1.0625rem);
  color: var(--text);
  font-weight: 500;
  text-shadow: 0 1px 10px rgba(11,10,10,.9);
}
.cover__countdown b { font-weight: 800; }

/* RSVP: one centered button, with "Get on the list" set plainly beneath it.
   The whole link (button and line) is the tap target. */
.cover__rsvp {
  position: relative;
  z-index: 2;
  justify-self: center;
  display: grid;
  justify-items: center;
  gap: 9px;
  margin-top: 14px;
  padding: 2px 8px 0;
  color: var(--text);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.cover__rsvp-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 11.5rem;
  height: 56px;
  padding: 0 40px;
  /* Flat red, white text (Max, 2026-11-07: no chrome effect). */
  background: var(--foil);
  color: var(--flash);
  font: 800 1.5rem/1 var(--sans);
  font-stretch: 100%;
  letter-spacing: .04em;
  padding-bottom: 3px; /* optical: lowercase has no caps to fill the top */
  box-shadow: 0 14px 28px -12px rgba(0, 0, 0, .85);
  transition: filter 160ms ease-out, transform 120ms ease-out;
}
.cover__rsvp-note {
  font: 700 1.0625rem/1.2 var(--sans);
  font-stretch: 100%;
  color: var(--text);
  white-space: nowrap;
  text-shadow: 0 1px 10px rgba(11,10,10,.9);
}
@media (hover: hover) { .cover__rsvp:hover .cover__rsvp-button { filter: brightness(1.08); } }
.cover__rsvp:active .cover__rsvp-button { transform: translateY(1px); }
.cover__rsvp:focus-visible { outline: none; }
.cover__rsvp:focus-visible .cover__rsvp-button { outline: 2px solid var(--flash); outline-offset: 3px; }

/* ---------- Pages ---------- */
main { display: block; }

.page {
  position: relative;
  width: var(--book);
  margin-inline: auto;
  padding: clamp(56px, 12vw, 88px) calc(var(--gutter) + var(--edge-room)) clamp(64px, 14vw, 104px) var(--gutter);
  background: var(--page);
  border-top: 5px solid var(--edge);
}
.page--edge-red { --edge: var(--edge-red-bright); }
/* The RSVP page sits on Max's instant photo (Ben, 2026-11-07), darkened for the form. */
.page--rsvp-photo {
  background:
    linear-gradient(rgba(11, 10, 10, .7), rgba(11, 10, 10, .7)),
    url("photos/rsvp-bg.jpg?v=dc767016b0") 50% 0 / cover no-repeat,
    var(--page);
}
/* The Details page sits on the DJ decks, turned sideways so they run down the page
   (Ben, 2026-11-07), darkened enough for the white text. */
.page--details {
  background:
    linear-gradient(rgba(11, 10, 10, .74), rgba(11, 10, 10, .74)),
    url("photos/details-bg.jpg?v=c35b9dc4dc") center / cover no-repeat,
    var(--page);
}
.page--edge-oxblood { --edge: var(--edge-oxblood); }
.page--edge-white { --edge: var(--edge-white); }

.edge-caption {
  position: absolute;
  top: clamp(56px, 12vw, 88px);
  right: calc(var(--gutter) - 6px);
  margin: 0;
  writing-mode: vertical-rl;
  /* Turn every glyph with the line. Left to the browser, some iPhones set the
     apostrophe upright, so "New Year’s Eve" read "New Year - s Eve" (Max's review, 2026-11-07). */
  text-orientation: sideways;
  font-size: .9375rem;
  line-height: 1;
  white-space: nowrap;
  color: var(--text);
}
.edge-caption i { color: var(--text); }

/* Section titles follow the book cover: two rows of condensed foil caps with
   real air between them and a subtitle set in the gap. Rows never wrap. */
.page__h {
  margin: 0 0 26px;
  font-weight: 400;
  font-size: clamp(5.5rem, 31vw, 10rem);
}
.page__row {
  --foil-pad: .14em;
  display: block;
  width: max-content;
  margin: -.14em 0;
  font-family: var(--display);
  line-height: .82;
  letter-spacing: 0;
  text-transform: uppercase;
  white-space: nowrap;
  transform: scaleX(1.22);
  transform-origin: left;
}
.page__sub {
  display: block;
  width: max-content;
  max-width: 100%;
  margin: clamp(14px, 4vw, 22px) 0;
  font-family: var(--sans);
  font-stretch: 100%;
  font-weight: 800;
  font-size: clamp(1.125rem, 5vw, 1.5rem);
  line-height: 1.1;
  letter-spacing: -.015em;
  text-transform: none;
}

.lede {
  margin: 0 0 14px;
  max-width: 30ch;
  font-weight: 700;
  font-stretch: 88%;
  font-size: clamp(1.375rem, 6.1vw, 1.75rem);
  line-height: 1.14;
  letter-spacing: -.012em;
  text-wrap: pretty;
}
.lede--small {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-stretch: 100%;
  font-size: clamp(1.125rem, 4.8vw, 1.3125rem);
  color: var(--text-dim);
}

/* TK: an editor's mark for a fact that isn't confirmed. Never publish one. */
.tk {
  color: var(--flash);
  background: rgba(146, 20, 12, .2);
  box-shadow: inset 0 -1px 0 var(--foil);
  padding: 0 .2em;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  white-space: nowrap;
}

/* ---------- Plates (flash photos on black) ---------- */
.plate { margin: 40px 0 0; }
.plate__img {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: #0f0d0d;
  box-shadow: 0 18px 40px -18px rgba(0,0,0,.9);
}
.plate--tall .plate__img { aspect-ratio: 3 / 4; }
.plate__img img, .plate__img canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.plate figcaption {
  margin-top: 10px;
  font-size: .9375rem;
  line-height: 1.3;
}
.plate-pair {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  margin-top: 44px;
}
.plate-pair .plate { margin: 0; }
.plate-pair .plate:nth-child(2) .plate__img { aspect-ratio: 3 / 2; }

/* ---------- Program ---------- */
.program {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
  gap: 0;
}
.program__item {
  padding: 18px 0 20px;
  border-bottom: 1px solid #2c2726;
}
.program__item:first-child { border-top: 1px solid #2c2726; }
.program__name {
  margin: 0 0 4px;
  font-weight: 900;
  font-stretch: 62%;
  font-size: clamp(2.25rem, 11vw, 3rem);
  line-height: .95;
  letter-spacing: -.01em;
  text-transform: uppercase;
}
/* "BITES BY UP LATE" in the heading face, then the caterer's moon alone (Ben, 2026-11-07). */
.program__moon { display: inline-block; height: .9em; width: auto; margin-left: .12em; vertical-align: -.06em; }
.program__item p {
  margin: 0;
  max-width: 34ch;
  color: var(--text-dim);
  font-size: 1.0625rem;
  line-height: 1.4;
}

/* ---------- When & where ---------- */
.when { display: flex; flex-direction: column; align-items: flex-start; }
.when__date {
  --foil-pad: .14em;
  margin: -.182em 0 calc(30px + .142em);
  --ink-gap: 30px;
  font-family: var(--display);
  font-size: min(calc((var(--book) - var(--gutter) * 2 - var(--edge-room)) / 1.02), 17rem);
  line-height: .8;
  transform: scaleY(1.3);
  transform-origin: top left;
}
.facts { margin: 0; display: grid; gap: 0; }
.facts div {
  display: grid;
  grid-template-columns: 5.2rem 1fr;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid #2c2726;
  align-items: baseline;
}
.facts div:first-child { border-top: 1px solid #2c2726; }
.facts dt {
      color: var(--text-dim);
  font-weight: 500;
  font-size: .9375rem;
}
.facts dd {
  margin: 0;
  font-weight: 700;
  font-size: 1.125rem;
  line-height: 1.3;
}
.map-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: rgba(244, 240, 238, .45);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}


/* ---------- RSVP ---------- */
.page--rsvp { padding-top: calc(clamp(56px, 12vw, 88px) + 56px); padding-bottom: max(140px, 42svh); } /* text a little lower (Max, 2026-11-07); room below so the RSVP jump lands the form at the top */
.rsvp__answer {
  margin: 14px 0 0; padding: 0; border: 0; /* a little lower, off the ticket (Max, 2026-11-07) */
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.choice { position: relative; display: block; cursor: pointer; }
.choice input {
  position: absolute; opacity: 0; inset: 0;
  margin: 0; cursor: pointer;
}
.choice__face {
  display: grid;
  place-items: center;
  min-height: 80px;
  padding: 8px 4px 4px;
  border: 1.5px solid var(--foil);
  background: var(--foil); /* the same oxblood as everything else (Max, 2026-11-07) */
  color: var(--flash);
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-size: clamp(1.375rem, 6.4vw, 1.875rem);
  line-height: .95;
  letter-spacing: -.005em;
  text-transform: none; /* lowercase, as Max wrote it (2026-11-07) */
  text-align: center;
  transition: background-color 180ms ease-out, color 180ms ease-out, border-color 180ms ease-out, transform 120ms ease-out;
}
.choice input:focus-visible + .choice__face { outline: 2px solid var(--flash); outline-offset: 3px; }
/* Max, 2026-11-07: "i’m in" is the oxblood button and stays oxblood with white text when
   picked; "can’t make it" is a white outline on a clear background. A pick fades the
   other choice back; "can’t make it" also gets a heavier white border. */
.choice input[value="no"] + .choice__face { background: transparent; border-color: var(--flash); }
.choice input[value="no"]:checked + .choice__face { box-shadow: inset 0 0 0 3px var(--flash); } /* "i’m in" gets no white outline (Max, 2026-11-07) */
.rsvp__answer:has(input:checked) .choice input:not(:checked) + .choice__face { opacity: .45; }
.rsvp__answer.is-invalid .choice__face { border-color: var(--flash); }

.field { display: grid; gap: 6px; }
.field__label {
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.3;
}
.field__hint {
  margin-top: -2px;
  font-size: .9375rem;
  line-height: 1.35;
  color: var(--text-dim);
}

.field input, .field textarea {
  width: 100%;
  padding: 10px 0 10px;
  border: 0;
  border-bottom: 1.5px solid #5a5150;
  border-radius: 0;
  background: transparent;
  color: var(--flash);
  font: 600 1.25rem/1.35 var(--sans);
  caret-color: var(--foil);
  transition: border-color 160ms ease-out;
}
.field textarea { resize: vertical; min-height: 5.5rem; }
.field input::placeholder, .field textarea::placeholder { color: #9b918e; font-weight: 400; }
.field input:focus, .field textarea:focus { outline: none; border-bottom-color: var(--flash); }
.field input:focus-visible, .field textarea:focus-visible { box-shadow: 0 1.5px 0 var(--flash); }
.field.is-invalid input { border-bottom-color: var(--foil); }

/* The RSVP story: one question per screen, segmented bars like a phone story. */
.story { margin-top: 26px; scroll-margin-top: max(env(safe-area-inset-top), 20px); }
.story__top { margin-bottom: 22px; }
.story__bar {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
.story__bar li { position: relative; height: 3px; background: #3a3332; overflow: hidden; }
.story__bar li::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--text);
  transform: scaleX(0);
  transform-origin: left;
}
.story__bar li.is-done::after { transform: scaleX(1); }
.story__bar li.is-now::after { background: var(--foil); transform: scaleX(1); transition: transform 420ms cubic-bezier(.2,.8,.2,1); }
.story__bar li:not(.is-now):not(.is-done)::after { transition: none; }
.story__nav {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  margin-top: 6px;
}
.story__back, .story__skip {
  min-height: 44px;
  min-width: 44px;
  padding: 0 4px;
  border: 0;
  background: none;
  color: var(--text);
  font: 500 1rem/1.2 var(--sans);
  text-decoration: underline;
  text-decoration-color: rgba(244, 240, 238, .4);
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
  cursor: pointer;
}
.story__count {
  margin: 0;
  font-weight: 600;
  font-size: .875rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.story__draft {
  margin: 0 0 0 auto;
  padding: 3px 8px;
  border: 1px solid #3a3332;
  color: var(--text);
  font: 500 .8125rem/1.3 var(--sans);
}
.story__step {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.story__step > * + * { margin-top: 0; }
/* One stage height for every screen (set by rsvp.js), main button pinned to its foot. */
.story__step { display: flex; flex-direction: column; gap: 20px; min-height: var(--step-h, auto); }
.story__actions {
  margin-top: auto;
  padding-top: 18px;
  border-top: 1px solid var(--rule, #2c2726);
  display: grid;
  gap: 12px;
}
.story__actions .field__error { margin: 0; }
/* Page turn: the old screen drifts away, the new one settles in. --turn is 1 forward, -1 back. */
.story__step.is-leaving { animation: story-out 200ms cubic-bezier(.4, 0, 1, 1) both; pointer-events: none; }
.story__step.is-entering { animation: story-in 340ms cubic-bezier(.16, 1, .3, 1) both; }
@keyframes story-out { to { opacity: 0; transform: translateX(calc(var(--turn, 1) * -14px)); } }
@keyframes story-in { from { opacity: 0; transform: translateX(calc(var(--turn, 1) * 18px)); } }
.choice:active .choice__face { transform: scale(.985); }
/* Things that come and go inside a row fade in place, so nothing reflows under the thumb. */
.story__skip, .story__draft { transition: opacity 180ms ease-out, visibility 0s linear 0s; }
.story__skip.is-gone, .story__draft.is-gone { opacity: 0; visibility: hidden; transition: opacity 160ms ease-out, visibility 0s linear 160ms; }
.field__error:not([hidden]) { animation: note-in 220ms cubic-bezier(.16, 1, .3, 1) both; }
@keyframes note-in { from { opacity: 0; transform: translateY(-4px); } }
.story.is-sending-off { opacity: 0; transition: opacity 220ms ease-out; }
.guest-caption.is-arriving { animation: caption-in 520ms cubic-bezier(.16, 1, .3, 1) both; }
@keyframes caption-in { from { opacity: 0; transform: translateY(12px); } }
.story__q {
  display: block;
  padding: 0;
  margin: 0;
  font-weight: 900;
  font-stretch: 62%;
  font-size: clamp(2.5rem, 12vw, 3.25rem);
  line-height: .95;
  letter-spacing: -.005em;
  text-transform: uppercase;
  color: var(--flash);
  outline: none;
}
.story__q:focus-visible { outline: 2px solid var(--flash); outline-offset: 4px; }

.ticket {
  position: relative;
  margin: 0;
  padding: 16px 18px;
  /* See-through, so Max's outfit shows behind it (Max, 2026-11-07). */
  background: rgba(23, 20, 20, .42);
  border-top: 1.5px dashed #4a4240;
  border-bottom: 1.5px dashed #4a4240;
  -webkit-mask: radial-gradient(circle 9px at 0 50%, #0000 98%, #000) left / 51% 100% no-repeat,
                radial-gradient(circle 9px at 100% 50%, #0000 98%, #000) right / 51% 100% no-repeat;
          mask: radial-gradient(circle 9px at 0 50%, #0000 98%, #000) left / 51% 100% no-repeat,
                radial-gradient(circle 9px at 100% 50%, #0000 98%, #000) right / 51% 100% no-repeat;
}
.ticket div {
  display: grid;
  grid-template-columns: 4.6rem 1fr;
  gap: 10px;
  padding: 5px 0;
  align-items: baseline;
}
.ticket dt { font: 500 .9375rem/1.3 var(--sans); color: var(--text-dim); }
.ticket dd { margin: 0; font-weight: 700; font-size: 1rem; line-height: 1.3; }

.story__next {
  width: 100%;
  min-height: 56px;
  padding: 12px 18px;
  border: 1.5px solid var(--text);
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font: 900 1.25rem/1 var(--sans);
  font-stretch: 70%;
  letter-spacing: .02em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 140ms ease-out, color 140ms ease-out;
}
.story__next:active { transform: translateY(1px); }
.story__pair { display: grid; grid-template-columns: 1fr auto; gap: 14px; align-items: center; }

.field__error {
  margin: 10px 0 0;
  padding: 10px 12px;
  background: rgba(146, 20, 12, .18);
  color: var(--flash);
  font-weight: 600;
  line-height: 1.35;
}
.field input[aria-invalid="true"] { border-bottom-color: var(--foil); }

.story__editing {
  margin: 10px 0 0;
  font-size: .9375rem;
  color: var(--text-dim);
}
.story__cancel {
  display: inline-block;
  margin-top: 0;
  min-height: 44px;
  padding: 0 4px 0 0;
  border: 0;
  background: none;
  color: var(--text-dim);
  font: 500 1rem/1.2 var(--sans);
  text-decoration: underline;
  text-decoration-color: rgba(244, 240, 238, .4);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  cursor: pointer;
}
.preview__note {
  display: block;
  margin-top: 12px;
  font-size: 1.0625rem;
  line-height: 1.4;
  color: var(--text-dim);
}
.preview__note i { font: 600 1em/1 var(--sans); color: var(--text); margin-right: .25em; }
.guest-caption__sent {
  margin: 14px 0 0;
  font-weight: 800;
  font-size: 1.125rem;
  line-height: 1.35;
}
.ticket--return { margin-top: 16px; }

/* Short phones: the ticket, the question and both choices share one screen. */
@media (max-height: 700px) {
  .story__top { margin-bottom: 10px; }
  .story__step { gap: 14px; }
  .story__q { font-size: clamp(2rem, 10vw, 2.5rem); }
  .ticket { padding: 8px 14px; }
  .ticket div { padding: 2px 0; }
  .ticket dd, .ticket dt { font-size: .9375rem; line-height: 1.25; }
  .choice__face { min-height: 64px; }
  .story__next { min-height: 50px; }
}

.story__lede { margin: -8px 0 0; color: var(--text-dim); font-size: 1rem; line-height: 1.4; }
.note { border-top: 1px solid var(--rule, #2c2726); padding-top: 4px; }
.note__toggle {
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-height: 44px;
  padding-top: 10px;
  font-weight: 600;
  font-size: 1.0625rem;
  cursor: pointer;
  list-style: none;
}
.note__toggle::-webkit-details-marker { display: none; }
.note__toggle::before { content: "+"; width: 1ch; font-weight: 500; color: var(--text-dim); }
.note[open] .note__toggle::before { content: "–"; }
.note .field { margin-top: 6px; }
/* Long names and guest lists wrap instead of widening the page. */
.preview, .guest-caption figcaption, .ticket dd, .story__q, .field input { overflow-wrap: anywhere; }
.calendar {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: 14px;
  padding: 0 16px;
  border: 1.5px solid var(--text);
  color: var(--text);
  font: 700 1rem/1 var(--sans);
  text-decoration: none;
}
.preview {
  padding: 18px 0;
  border-top: 1px solid var(--rule, #2c2726);
  border-bottom: 1px solid var(--rule, #2c2726);
  font-size: clamp(1.25rem, 5.6vw, 1.5rem);
  line-height: 1.3;
  text-wrap: pretty;
}

.rsvp__submit {
  width: 100%;
  appearance: none;
  border: 0;
  border-radius: 0;
  min-height: 56px;
  padding: 12px 18px;
  background: var(--foil);
  color: var(--flash);
  font: 900 1.375rem/1 var(--sans);
  font-stretch: 70%;
  letter-spacing: .02em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 14px 28px -12px rgba(0, 0, 0, .85);
  transition: transform 120ms ease-out, filter 160ms ease-out;
}
.rsvp__submit:active { transform: translateY(1px); }
.rsvp__submit[aria-busy="true"] { filter: saturate(.6) brightness(.9); cursor: progress; }
.rsvp__submit[aria-busy="true"] .rsvp__submit-label::after { content: "…"; }

/* The guest's own caption, printed after they RSVP */
.guest-caption { margin: 34px 0 0; outline: none; scroll-margin-top: max(env(safe-area-inset-top), 16px); }
.guest-caption__plate {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: #0f0d0d;
}
.guest-caption__plate canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.guest-caption figcaption {
  margin-top: 12px;
  font-size: clamp(1.25rem, 5.6vw, 1.5rem);
  line-height: 1.3;
  font-weight: 400;
  text-wrap: pretty;
}
.guest-caption__note {
  margin: 12px 0 0;
  font-size: .9375rem;
  line-height: 1.45;
  color: var(--text-dim);
}
.guest-caption__again {
  margin-top: 10px;
  min-height: 44px;
  padding: 0 4px 0 0;
  border: 0;
  background: none;
  color: var(--text-dim);
  font: 500 1rem/1.2 var(--sans);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: rgba(244, 240, 238, .4);
  text-decoration-thickness: 1px;
  cursor: pointer;
}

/* ---------- Back cover ---------- */
.back {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: var(--book);
  margin-inline: auto;
  padding: 64px var(--gutter) max(calc(env(safe-area-inset-bottom) + 110px), 120px);
  background: var(--page);
  border-top: 5px solid var(--edge-oxblood);
  text-align: left;
}
.back__word {
  --foil-pad: .14em;
  margin: -.182em 0 .136em;
  --ink-gap: 0px;
  font-family: var(--display);
  font-size: min(calc((var(--book) - var(--gutter) * 2) / .705 * .62), 14rem);
  line-height: .78;
  transform: scaleY(1.3);
  transform-origin: top left;
}
.back__line {
  margin: 18px 0 0;
  max-width: 26ch;
  font-weight: 500;
  font-size: 1.0625rem;
  line-height: 1.4;
  color: var(--text-dim);
}

/* ---------- Thumb RSVP ---------- */
.thumb {
  position: fixed;
  z-index: 20;
  right: max(16px, calc((100vw - var(--book)) / 2 + 16px));
  bottom: max(calc(env(safe-area-inset-bottom) + 12px), 18px);
  display: grid;
  place-items: center;
  min-width: 112px;
  height: 58px;
  padding: 6px 20px 2px;
  background: var(--foil);
  color: var(--flash);
  font-family: var(--display);
  font-size: 2.75rem;
  line-height: 1;
  letter-spacing: .02em;
  text-decoration: none;
  box-shadow: 0 12px 30px -8px rgba(0,0,0,.8);
  transition: transform 260ms cubic-bezier(.2,.8,.2,1), opacity 200ms ease-out;
}
.thumb.is-hidden { transform: translateY(140%); opacity: 0; pointer-events: none; }
.thumb:focus-visible { outline-offset: 4px; }

/* ---------- Flash + confetti drop (the RSVP moment) ---------- */
.flashbulb {
  position: fixed; inset: 0; z-index: 40;
  background: var(--flash);
  opacity: 0;
  pointer-events: none;
}
.flashbulb.is-firing { animation: flash-pop 1100ms cubic-bezier(.12,.8,.2,1) both; }
.drop {
  position: fixed; inset: 0; z-index: 30;
  width: 100vw; height: 100vh;
  pointer-events: none;
}

@keyframes fade-out { to { opacity: 0; } }
@keyframes fade-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .is-loaded .cover__flash, .flashbulb.is-firing { animation: none; }
  /* Reduced motion: the same page turn as a gentle crossfade, no sliding. */
  .story__step.is-leaving { animation: fade-out 120ms ease-out both; }
  .story__step.is-entering { animation: fade-in 180ms ease-out both; }
  .guest-caption.is-arriving { animation: fade-in 240ms ease-out both; }
  .field__error:not([hidden]) { animation: fade-in 160ms ease-out both; }
  .choice:active .choice__face { transform: none; }
  .story__bar li.is-now::after { transition: none; }
  .thumb, .choice__face { transition: none; }
}

/* ---------- Larger screens: the book sits on the table ---------- */
@media (min-width: 700px) {
  :root { --book: min(34rem, 92vw); }
  body { padding-bottom: 0; }
  .cover { min-height: min(100svh, 60rem); margin-top: 0; }
  .page, .cover, .back { box-shadow: 0 0 0 1px #1c1918, 0 40px 80px -30px #000; }
  .plate-pair { grid-template-columns: 1fr 1fr; align-items: start; }
  .plate-pair .plate:nth-child(2) .plate__img { aspect-ratio: 4 / 5; }
}

/* Hover effects only where a pointer can hover, so taps don't leave them stuck on. */
@media (hover: hover) {
  .map-link:hover { color: var(--flash); }
  .choice:hover .choice__face { filter: brightness(1.12); }
  .story__back:hover, .story__skip:hover { color: var(--flash); }
  .story__next:hover { background: var(--text); color: var(--page); }
  .rsvp__submit:hover { filter: brightness(1.08); }
  .guest-caption__again:hover, .story__cancel:hover { color: var(--flash); }
  .calendar:hover { background: var(--text); color: var(--page); }
}
