@charset "UTF-8";

/* ==========================================================================
   Fabien & Lily — Sakura / Blush
   Direction A: cherry blossom branches framing a centred masthead.

   House rules:
     · centred masthead and section headings; running prose stays left-aligned
       inside a centred column, because centred body copy is hard to read
     · Playfair Display for names, Cormorant Garamond for wording,
       Cinzel for letterspaced labels, Montserrat for UI and body
     · deep rose is the accent; gold is reserved for hairlines and ornament
     · the blossom is generated in blossom.js and never overlaps type
   ========================================================================== */

/* --- faces ---------------------------------------------------------------- */

@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/playfair-display-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'Playfair Display';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/playfair-display-italic-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('fonts/cormorant-garamond-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url('fonts/cormorant-garamond-italic-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'Cinzel';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/cinzel-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url('fonts/montserrat-latin.woff2') format('woff2');
}

/* --- tokens --------------------------------------------------------------- */

:root {
  --ground: #fffcfa;
  --ground-2: #fef4f4;
  --ink: #3a2429;
  --muted: #7d5c61;
  --hairline: #ecdcdd;
  --hairline-soft: #f6ebeb;
  --accent: #a8425c;
  --accent-soft: #d2607a;
  --accent-ink: #fffcfa;
  --gold: #b08430;

  --display: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --wording: 'Cormorant Garamond', Georgia, serif;
  --label: 'Cinzel', Georgia, serif;
  --body: 'Montserrat', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --margin: clamp(20px, 6vw, 96px);
  --gutter: 40px;
  --measure: 56ch;
  --page-width: 1180px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ground: #15101a;
    --ground-2: #1b1422;
    --ink: #f7edea;
    --muted: #b69a9c;
    --hairline: #2e2434;
    --hairline-soft: #221a29;
    --accent: #f3b4a2;
    --accent-soft: #ec8e78;
    --accent-ink: #15101a;
    --gold: #e9be7a;
  }
}

:root[data-theme='dark'] {
  --ground: #15101a;
  --ground-2: #1b1422;
  --ink: #f7edea;
  --muted: #b69a9c;
  --hairline: #2e2434;
  --hairline-soft: #221a29;
  --accent: #f3b4a2;
  --accent-soft: #ec8e78;
  --accent-ink: #15101a;
  --gold: #e9be7a;
}

:root[data-theme='light'] {
  --ground: #fffcfa;
  --ground-2: #fef4f4;
  --ink: #3a2429;
  --muted: #7d5c61;
  --hairline: #ecdcdd;
  --hairline-soft: #f6ebeb;
  --accent: #a8425c;
  --accent-soft: #d2607a;
  --accent-ink: #fffcfa;
  --gold: #b08430;
}

/* --- base ---------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: 78px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--body);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  text-wrap: balance;
}

p {
  margin: 0;
  max-width: var(--measure);
}

/* For a paragraph that sits directly beside full-width bordered rows (e.g. a
   .ruled list) — capping it to the reading measure while its neighbours span
   the whole column leaves a visible dead gap on one side. */
.wide {
  max-width: none;
}

/* Same idea for a standalone field: without this, its own underline stops at
   the reading measure while the rows above it reach the full column. Needs
   this specificity to beat .field textarea/.field input's own max-width. */
.field textarea.wide,
.field input.wide {
  max-width: none;
}

ul,
ol {
  margin: 0;
  padding: 0;
}

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

a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid var(--hairline);
}

a:hover,
a:focus-visible {
  border-bottom-color: var(--accent);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

::selection {
  background: var(--accent);
  color: var(--accent-ink);
}

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

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--margin);
  z-index: 20;
  padding: 10px 16px;
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--body);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.skip-link:focus {
  top: 8px;
}

/* An admin previewing the site as a specific household, via /admin's "View site
   as" link. Sticky and high z-index so it stays visible over everything else —
   the whole point is that it must not be mistaken for the real guest experience. */
.preview-banner {
  position: sticky;
  top: 0;
  z-index: 200;
  margin: 0;
  padding: 12px var(--margin);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--body);
  font-size: 13px;
  line-height: 1.5;
  text-align: center;
}

.preview-banner strong {
  font-weight: 600;
}

/* The only way out of a mode that now follows you from page to page, so it has
   to read as a control rather than as part of the sentence. */
.preview-banner a {
  margin-left: 4px;
  padding-bottom: 1px;
  border-bottom: 1px solid currentColor;
  color: inherit;
  white-space: nowrap;
}

/* --- shared type roles --------------------------------------------------- */

.label {
  margin: 0;
  font-family: var(--label);
  font-size: 11px;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
}

.label-ink {
  color: var(--ink);
}

.label-accent {
  color: var(--accent);
}

.num {
  font-variant-numeric: tabular-nums;
}

.lede {
  font-family: var(--wording);
  font-size: 21px;
  font-weight: 400;
  line-height: 1.65;
  max-width: 46ch;
  color: var(--ink);
}

.muted {
  color: var(--muted);
}

.jp {
  font-family: var(--body);
  font-size: 0.34em;
  font-weight: 400;
  letter-spacing: 0.12em;
  color: var(--muted);
}

.label .jp,
.fact-value .jp {
  font-size: 10px;
  letter-spacing: 0.08em;
}

.amp {
  font-family: var(--wording);
  font-style: italic;
  font-weight: 300;
  color: var(--accent-soft);
  padding: 0 0.05em;
}

/* --- sticky rule --------------------------------------------------------- */

.rule {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--ground);
  background: color-mix(in srgb, var(--ground) 90%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.rule-inner {
  display: flex;
  gap: 8px 26px;
  align-items: baseline;
  justify-content: space-between;
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 14px var(--margin);
  border-bottom: 1px solid var(--hairline);
}

.rule-nav {
  display: flex;
  gap: 20px;
  overflow-x: auto;
  scrollbar-width: none;
  list-style: none;
}

.rule-nav::-webkit-scrollbar {
  display: none;
}

.rule-nav a {
  display: block;
  white-space: nowrap;
  border-bottom: 1px solid transparent;
  color: var(--muted);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.rule-nav a:hover,
.rule-nav a[aria-current='true'] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

/* Set apart from the section anchors either side of it — this one leaves the
   page rather than scrolling to it, and only ever shows for an admin. */
.rule-nav-admin,
/* Marks the start of the secondary cluster (Gallery, Gifts, Questions),
   grouping the nav by meaning instead of leaving all 8 links equal weight. */
.rule-nav-divider {
  padding-left: 20px;
  border-left: 1px solid var(--hairline);
}

/* RSVP is the one link on this page with a real task behind it — promoted so
   a guest does not have to scan the full row to find it. */
.rule-nav a.rule-nav-cta {
  padding: 4px 14px;
  border-radius: 20px;
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.rule-nav a.rule-nav-cta:hover {
  color: var(--accent-ink);
  background: var(--ink);
  border-color: var(--ink);
}

.greeting {
  flex: none;
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

/* --- the account menu ----------------------------------------------------
   A <details> in the corner of the nav. The greeting is the summary, so the
   thing a guest already recognises is the thing that opens it. */

.account {
  position: relative;
  flex: none;
}

.account > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  list-style: none;
}

/* Both spellings are needed: WebKit still uses the pseudo-element. */
.account > summary::-webkit-details-marker {
  display: none;
}

.account > summary::marker {
  content: '';
}

.account > summary:hover,
.account[open] > summary {
  color: var(--ink);
}

.account-chevron {
  flex: none;
  transition: transform 0.15s ease;
}

.account[open] .account-chevron {
  transform: rotate(180deg);
}

.account-menu {
  position: absolute;
  top: calc(100% + 14px);
  right: 0;
  z-index: 150;
  display: flex;
  flex-direction: column;
  min-width: 200px;
  background: var(--ground);
  border: 1px solid var(--hairline);
  box-shadow: 0 12px 34px rgba(58, 36, 41, 0.12);
}

.account-item {
  display: block;
  width: 100%;
  padding: 13px 18px;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--hairline-soft);
  color: var(--muted);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-align: left;
  text-transform: uppercase;
  cursor: pointer;
}

.account-menu > form:last-child .account-item,
.account-item:last-child {
  border-bottom: 0;
}

.account-item:hover {
  background: var(--ground-2);
  color: var(--ink);
}

/* Present so the preview shows the guest's real menu, but going nowhere: these
   two would act on the previewing admin's own account. */
.account-item-inert,
.account-item-inert:hover {
  background: none;
  color: var(--muted);
  opacity: 0.5;
  cursor: default;
}

/* Fixed to the viewport corner, above the sticky rule (z-index: 100) — see
   templates/section/nav.php for why it lives outside .rule-inner. */
.theme-toggle {
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 200;
  display: flex;
  padding: 6px;
  background: color-mix(in srgb, var(--ground) 85%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid var(--hairline);
  border-radius: 50%;
  color: var(--muted);
  cursor: pointer;
}

.theme-toggle:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
}

.bulb-rays {
  opacity: 0;
  transition: opacity 0.2s ease;
}

.bulb-glass {
  transition: fill 0.2s ease;
}

/* The room's lights are "on" in light mode — the bulb glows and casts rays;
   in dark mode it is just the plain outline. */
:root[data-theme='light'] .bulb-glass {
  fill: var(--gold);
  fill-opacity: 0.25;
}

:root[data-theme='light'] .bulb-rays {
  opacity: 1;
}

/* --- page shell ---------------------------------------------------------- */

.page {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 0 var(--margin) 120px;
}

/* --- overture: centred, framed by blossom -------------------------------- */

/* Full-bleed: it sits outside .page so the wash reaches both edges of the
   viewport and the branches can frame the whole width, rather than stopping at
   a 1180px band with white either side. No vw units, so a visible scrollbar
   cannot cause sideways scroll. */
.overture {
  position: relative;
  isolation: isolate;
  padding: clamp(52px, 8vw, 104px) 0 clamp(36px, 5vw, 64px);
  overflow: hidden;
  text-align: center;
  background: linear-gradient(172deg, var(--ground) 0%, var(--ground-2) 100%);
}

.overture-inner {
  position: relative;
  z-index: 2;
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 0 var(--margin);
}

/* the two generated layers; both sit under the type */
.overture canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

.overture canvas[data-frame] {
  z-index: 0;
}

.overture canvas[data-petals] {
  z-index: 1;
}

.overture-top,
.overture h1,
.overture-sub,
.facts,
.facts-locked {
  position: relative;
  z-index: 2;
}

.overture-top {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
  text-align: center;
}

.overture h1 {
  font-size: clamp(2.4rem, 7.6vw, 5rem);
  line-height: 1.02;
  letter-spacing: -0.02em;
  margin: clamp(16px, 2.6vw, 26px) auto 0;
  max-width: min(700px, 92%);
  text-align: center;
}

.overture-sub {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
  margin-top: clamp(18px, 2.6vw, 28px);
}

.overture-lede {
  font-family: var(--wording);
  font-size: 21px;
  font-weight: 400;
  line-height: 1.65;
  max-width: 48ch;
  margin: 0 auto;
  text-align: center;
  text-wrap: balance;
  color: var(--ink);
}

/* gold hairline with a lozenge, between the names and the facts */
.overture-sub::before {
  content: '';
  display: block;
  width: 72px;
  height: 1px;
  background: var(--gold);
  opacity: 0.85;
}

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 22px 28px;
  margin-top: clamp(28px, 4vw, 46px);
  padding-top: 22px;
  border-top: 1px solid var(--hairline);
}

.signin-intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 6px;
  width: 100%;
}

.signin-intro .label-accent {
  text-align: center;
  margin: 0 auto;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.signin-subtext {
  font-family: var(--body);
  font-size: 0.95rem;
  font-weight: 300;
  color: var(--ink);
  opacity: 0.9;
  text-align: center;
  margin: 0 auto;
}

.google-signin {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
  text-align: center;
}

.overture + .page > #rsvp {
  margin-top: clamp(40px, 6vw, 72px);
  padding-top: 0;
  border-top: none;
}

.fact {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.fact-value {
  font-family: var(--display);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.45;
}

.fact-value.is-pending {
  font-family: var(--wording);
  font-style: italic;
  font-size: 18px;
  color: var(--accent);
}

/* Provisional dates are already italic and accent-coloured, which a screen
   reader announces neither of — this carries the same meaning in text. */
.fact-qualifier {
  font-family: var(--body);
  font-style: normal;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--muted);
}

/* --- sections: centred heading, left-aligned prose ----------------------- */

.sec {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
  margin-top: clamp(58px, 8vw, 108px);
  padding-top: 26px;
  border-top: 1px solid var(--hairline);
  text-align: center;
}

/* A page that opens with a section rather than the masthead: its rule would sit
   a few pixels under the nav's own, reading as a doubled line rather than a
   divider between two things. */
.page-bare > .sec:first-child {
  margin-top: clamp(34px, 5vw, 60px);
  padding-top: 0;
  border-top: 0;
}

.sec-aside {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
}

.sec-body {
  display: flex;
  flex-direction: column;
  gap: 24px;
  width: 100%;
  max-width: 760px;
  /* Headings and standfirsts stay centred; running copy reverts to the left,
     which is what makes a long travel section readable. */
  text-align: left;
}

.sec-body > h2,
.sec-body > h3,
.sec-body > .lede {
  align-self: center;
  text-align: center;
}

/* Running copy is capped to the reading measure, which is narrower than the
   column it sits in. Left-aligning the BOX as well as the text pooled all of
   that leftover width into one dead column on the right — most visible in a
   prose-only section like Gifts, where nothing else reached the far edge.
   Centring the box splits the same space evenly, so it reads as margin.
   The text inside stays left-aligned: that is what makes long copy readable,
   and it is what the house rule at the top of this file always meant.
   `width: 100%` is load-bearing — a centred flex item shrink-wraps its text
   without it, and paragraphs would lose their shared left edge. */
.sec-body > p {
  width: 100%;
  align-self: center;
}

/* Prose that shares a section with full-width rows keeps the column's left
   edge instead, so the two line up. .wide is already max-width: none, so this
   only has to put the alignment back. */
.sec-body > p.wide {
  align-self: stretch;
}

.sec h2 {
  font-size: clamp(2rem, 4.6vw, 3.2rem);
  line-height: 1.06;
  letter-spacing: -0.02em;
}

.sec h3 {
  font-family: var(--display);
  font-size: 25px;
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.sec h4 {
  font-family: var(--label);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* --- ruled rows ---------------------------------------------------------- */

.rows {
  display: flex;
  flex-direction: column;
}

.row {
  display: grid;
  grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
  gap: 6px 30px;
  padding: 20px 0;
  border-top: 1px solid var(--hairline);
}

.row:last-child {
  border-bottom: 1px solid var(--hairline);
}

.row-term {
  font-family: var(--display);
  font-size: 21px;
  font-weight: 400;
  line-height: 1.3;
}

.row-term-small {
  font-family: var(--label);
  font-size: 11.5px;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding-top: 3px;
}

.row-time {
  font-family: var(--label);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.14em;
  color: var(--accent);
  padding-top: 4px;
}

.row-timed {
  grid-template-columns: minmax(0, 64px) minmax(0, 170px) minmax(0, 1fr);
}

/* --- verdict rows -------------------------------------------------------- */

.verdict {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.verdict-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
}

.verdict-code {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--muted);
}

.verdict-line {
  font-family: var(--wording);
  font-style: italic;
  font-size: 15px;
  line-height: 1.5;
  color: var(--accent);
}

/* --- areas and hotels ---------------------------------------------------- */

.areas {
  display: flex;
  flex-direction: column;
}

.area {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 26px 0;
  border-top: 1px solid var(--hairline);
}

.area:last-child {
  border-bottom: 1px solid var(--hairline);
}

.area-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 6px 18px;
  text-align: center;
}

/* An area is a centred head and a centred paragraph over full-width hotel
   rows. Centring the two of them together is what stops the paragraph — capped
   to the reading measure inside a much wider column — from leaving its unused
   width stacked on one edge. The rows below keep the full width they need for
   a name-and-detail pair to stay legible. */
.area > p {
  width: 100%;
  align-self: center;
}

.view-as-link {
  padding: 6px 14px;
  border: 1px solid var(--hairline);
  color: var(--ink);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-decoration: none;
  text-transform: uppercase;
}

.view-as-link:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* The household currently being previewed. Same control, opposite job. */
.view-as-link-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.view-as-link-active:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--ground);
}

.hotels {
  display: flex;
  flex-direction: column;
  list-style: none;
}

.hotel {
  display: grid;
  grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
  gap: 4px 30px;
  padding: 16px 0;
  border-top: 1px solid var(--hairline-soft);
}

.hotel-name {
  font-family: var(--display);
  font-size: 19px;
  font-weight: 400;
  line-height: 1.3;
}

.hotel-band {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- notes: set off by a single left rule -------------------------------- */

/* A callout is its text plus the accent rule beside it, so the block is capped
   to the reading measure and centred as a unit — rather than stretching the
   full column while the copy inside stops two-thirds of the way across, which
   left the rule stranded on one edge and a void on the other. */
.note {
  width: 100%;
  max-width: calc(var(--measure) + 22px);
  align-self: center;
  margin-inline: auto;
  padding-left: 22px;
  border-left: 1px solid var(--accent);
}

.note p + p {
  margin-top: 10px;
}

/* --- plain lists --------------------------------------------------------- */

.ruled {
  display: flex;
  flex-direction: column;
  list-style: none;
}

.ruled li {
  padding: 14px 0;
  border-top: 1px solid var(--hairline);
}

.ruled li:last-child {
  border-bottom: 1px solid var(--hairline);
}

/* --- gallery ------------------------------------------------------------- */

.gallery {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 4px;
}

.shot {
  position: relative;
  margin: 0;
  min-width: 0;
}

.shot:nth-child(1) { grid-column: span 7; }
.shot:nth-child(2) { grid-column: span 5; }
.shot:nth-child(3) { grid-column: span 4; }
.shot:nth-child(4) { grid-column: span 8; }
.shot:nth-child(5) { grid-column: span 5; }
.shot:nth-child(6) { grid-column: span 7; }

.shot img {
  width: 100%;
}

.shot-placeholder {
  display: flex;
  align-items: flex-end;
  padding: 20px;
  border: 1px solid var(--hairline);
  background: linear-gradient(165deg, var(--ground-2) 0%, var(--hairline-soft) 100%);
}

.shot-placeholder span {
  font-family: var(--wording);
  font-style: italic;
  font-size: 15px;
  line-height: 1.4;
  max-width: 26ch;
  color: var(--ink);
}

/* --- FAQ ---------------------------------------------------------------- */

.faq {
  display: flex;
  flex-direction: column;
}

.qa {
  border-top: 1px solid var(--hairline);
}

.qa:last-child {
  border-bottom: 1px solid var(--hairline);
}

.qa summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 14px;
  align-items: center;
  gap: 22px;
  padding: 20px 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-size: 20px;
  font-weight: 400;
  line-height: 1.35;
}

.qa summary::-webkit-details-marker {
  display: none;
}

.qa summary:hover {
  color: var(--accent);
}

.qa-mark {
  position: relative;
  width: 14px;
  height: 14px;
  flex: none;
}

.qa-mark::before,
.qa-mark::after {
  content: '';
  position: absolute;
  background: var(--accent);
}

.qa-mark::before {
  top: 50%;
  left: 0;
  width: 14px;
  height: 1px;
}

.qa-mark::after {
  top: 0;
  left: 50%;
  width: 1px;
  height: 14px;
  transition: opacity 0.2s ease;
}

.qa[open] .qa-mark::after {
  opacity: 0;
}

.qa-body {
  padding: 0 0 22px;
  max-width: var(--measure);
}

/* --- RSVP -------------------------------------------------------------- */

.rsvp {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* Same shape as .note, same reason. */
.rsvp-state {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  max-width: calc(var(--measure) + 22px);
  align-self: center;
  margin-inline: auto;
  padding-left: 22px;
  border-left: 1px solid var(--accent);
}

.party {
  display: flex;
  flex-direction: column;
}

.person {
  display: grid;
  grid-template-columns: minmax(0, 210px) minmax(0, 1fr);
  gap: 16px 30px;
  padding: 24px 0;
  border-top: 1px solid var(--hairline);
}

.person:last-of-type {
  border-bottom: 1px solid var(--hairline);
}

.person-id {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.person-name {
  font-family: var(--display);
  font-size: 23px;
  font-weight: 400;
  line-height: 1.25;
}

.person-controls {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

.choices {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

.choice {
  position: relative;
}

.choice input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.choice span {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 8px 18px;
  border: 1px solid var(--hairline);
  color: var(--muted);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.choice input:checked + span {
  background: var(--accent-soft);
  border-color: var(--accent-soft);
  color: var(--accent-ink);
}

.choice input:focus-visible + span {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.choice span:hover {
  color: var(--ink);
  border-color: var(--accent);
}

.choice input:checked + span:hover {
  color: var(--accent-ink);
}

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.field textarea,
.field input {
  width: 100%;
  max-width: var(--measure);
  padding: 9px 0;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  color: var(--ink);
  font-family: var(--body);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.6;
  resize: vertical;
}

.field textarea:focus,
.field input:focus {
  outline: none;
  border-bottom-color: var(--accent);
}

.field textarea::placeholder,
.field input::placeholder {
  color: var(--muted);
}

.rsvp-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px 24px;
}

/* Signing in with a code, for guests with no Google account. Centred column. */
.direct-signin {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 100%;
  max-width: 440px;
  align-self: center;
  margin-top: 24px;
  text-align: center;
}

.direct-signin > .label,
.direct-signin > .signin-subtext,
.direct-signin > .muted {
  text-align: center;
  margin-bottom: 10px;
}

.direct-signin-form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
  text-align: center;
}

.direct-signin .field {
  width: 100%;
  align-items: center;
  text-align: center;
}

.direct-signin .field .label {
  text-align: center;
}

.direct-signin .field input {
  text-align: center;
}

.direct-signin + .muted {
  text-align: center;
}

.direct-signin-form .rsvp-actions {
  margin-top: 8px;
  width: 100%;
  justify-content: center;
}

/* A form narrower than the column it sits in — the password page, the sign-in
   box — centres rather than leaving its width on one side. */
.sec-body > form {
  width: 100%;
  align-self: center;
}

.button {
  padding: 15px 34px;
  background: var(--accent);
  color: var(--accent-ink);
  border: 0;
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  cursor: pointer;
}

.button:hover {
  background: var(--ink);
  color: var(--ground);
}

.button[disabled] {
  cursor: default;
  opacity: 0.5;
}

.button-quiet {
  padding: 14px 0;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  color: var(--muted);
}

.button-quiet:hover {
  background: none;
  color: var(--ink);
  border-bottom-color: var(--accent);
}

.rsvp-status {
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}

.rsvp-status[data-tone='saved'] {
  color: var(--accent);
}

.rsvp-status[data-tone='error'] {
  color: var(--ink);
  border-bottom: 1px solid var(--accent);
}

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

.foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: clamp(72px, 10vw, 120px);
  padding-top: 22px;
  border-top: 1px solid var(--hairline);
  text-align: center;
}

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

.table-wrap {
  overflow-x: auto;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.table th {
  padding: 0 20px 10px 0;
  border-bottom: 1px solid var(--ink);
  text-align: left;
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.table td {
  padding: 12px 20px 12px 0;
  border-bottom: 1px solid var(--hairline);
  vertical-align: top;
}

.table td.is-attending {
  color: var(--accent);
}

/* --- admin: Tokyo overlap table ---------------------------------------- */

.tokyo-table th.tokyo-table-day,
.tokyo-table td.tokyo-cell {
  padding: 0;
  width: 26px;
  min-width: 26px;
  text-align: center;
}

.tokyo-table th.tokyo-table-day {
  padding-bottom: 10px;
  font-size: 10px;
  line-height: 1.4;
}

.tokyo-cell {
  height: 100%;
}

.tokyo-cell.is-present {
  background: var(--accent-soft);
}

.tokyo-cell.is-partial {
  background: var(--hairline);
}

.tokyo-table tr.is-dimmed {
  opacity: 0.35;
}

.tally {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 24px 30px;
}

.tally-figure {
  font-family: var(--display);
  font-size: clamp(2.4rem, 5vw, 3.4rem);
  font-weight: 400;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* --- load sequence, masthead only ------------------------------------- */

.rise {
  opacity: 0;
  transform: translateY(13px);
  animation: rise 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}

.rise-1 { animation-delay: 0.05s; }
.rise-2 { animation-delay: 0.18s; }
.rise-3 { animation-delay: 0.32s; }
.rise-4 { animation-delay: 0.46s; }

@keyframes rise {
  to {
    opacity: 1;
    transform: none;
  }
}

/* --- the index of the other pages, on the homepage ----------------------- */

.cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Hairlines rather than gaps: the cards read as one block of the page, the
     way the rows in a section do, instead of six floating tiles. */
  gap: 1px;
  width: 100%;
  background: var(--hairline);
  border: 1px solid var(--hairline);
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* Room on the right for the arrow, so a long blurb never runs under it. */
  padding: 22px 46px 24px 22px;
  background: var(--ground);
  color: var(--ink);
  /* The card's own edge is the grid's hairline, so the underline every other
     link on the site carries would double it. */
  border-bottom: 0;
}

.card:hover {
  background: var(--hairline-soft);
}

.card-title {
  font-family: var(--display);
  font-size: 23px;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.card-blurb {
  color: var(--muted);
  font-size: 14.5px;
  line-height: 1.5;
  text-wrap: pretty;
}

.card-mark {
  position: absolute;
  top: 24px;
  right: 20px;
  color: var(--muted);
  font-size: 15px;
  transition: transform 0.18s ease, color 0.18s ease;
}

.card:hover .card-mark {
  color: var(--accent);
  transform: translateX(3px);
}

@media (prefers-reduced-motion: reduce) {
  .card-mark {
    transition: none;
  }

  .card:hover .card-mark {
    transform: none;
  }
}

/* --- things to do: gallery page ------------------------------------------ */

.tokyo-dates {
  display: flex;
  flex-direction: column;
  margin-top: 16px;
}

.tokyo-dates-row {
  display: grid;
  grid-template-columns: minmax(0, 180px) minmax(0, 1fr) minmax(0, 1fr);
  gap: 6px 24px;
  align-items: end;
  padding: 16px 0;
  border-top: 1px solid var(--hairline);
}

.tokyo-dates-row:last-child {
  border-bottom: 1px solid var(--hairline);
}

.tokyo-dates-name {
  font-family: var(--display);
  font-size: 17px;
  padding-bottom: 9px;
}

/* --- guests' own suggestions ---------------------------------------------- */

/* A column of form fields. Used by the suggestion forms and the password page,
   both of which are plain HTML posts with no JavaScript behind them. */
.stack {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.activity-by {
  margin-top: 6px;
  font-family: var(--label);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

/* The form is folded away behind its own summary: most visits to this page are
   to read the gallery, not to write. */
.suggest > summary {
  display: inline-flex;
  width: auto;
  list-style: none;
  cursor: pointer;
}

/* The one that opens the whole form is alone on its line, so it sits in the
   middle like every other standalone action. The form it reveals goes back to
   left-aligned — fields are read down an edge, not from a centre. */
.sec-body > .suggest {
  text-align: center;
}

.sec-body > .suggest > .suggest-form {
  text-align: left;
}

/* An input is not running copy: capping it to the reading measure left every
   underline stopping short of the column with the same dead strip beside it.
   Inside the two-column grid they are already narrower than that. */
.suggest-form > .field > input,
.suggest-form > .field > textarea {
  max-width: none;
}

.suggest > summary::-webkit-details-marker {
  display: none;
}

.suggest > summary::marker {
  content: '';
}

.suggest-form {
  margin-top: 24px;
  padding: 24px 0 0;
  border-top: 1px solid var(--hairline);
}

.suggest-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px 26px;
}

/* The photo field: what it looks like now beside what to do about it. The
   preview is the same 4:3 the gallery card crops to, so what a guest sees here
   is what the card will show. */
.suggest-photo {
  display: grid;
  grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
  gap: 18px 20px;
  align-items: start;
}

.suggest-photo-preview {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--hairline-soft);
  border: 1px solid var(--hairline);
}

.suggest-photo-controls {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.suggest-photo-controls input[type='file'] {
  max-width: 100%;
  font-family: var(--body);
  font-size: 13px;
  color: var(--muted);
}

/* A .choice on its own, rather than one of a row inside a fieldset. */
.choice-inline {
  display: inline-flex;
  align-self: flex-start;
}

.suggest-list {
  display: flex;
  flex-direction: column;
  margin-top: 18px;
}

.suggest-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px 24px;
  align-items: start;
  padding: 18px 0;
  border-top: 1px solid var(--hairline);
}

.suggest-row:last-child {
  border-bottom: 1px solid var(--hairline);
}

.suggest-row-id {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.suggest-row-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
}

/* An edit form opened from a row belongs to the whole row, not to the narrow
   tools column it was opened from. */
.suggest-row .suggest[open] {
  grid-column: 1 / -1;
}

/* --- your details -------------------------------------------------------- */

/* What we already know, at the top of the page. Deliberately not ticks and
   crosses: an unanswered section is a thing left to do, not a failure. */
.checklist {
  display: flex;
  flex-wrap: wrap;
  gap: 0 40px;
  margin-top: 30px;
  list-style: none;
}

.checklist-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 0 14px 16px;
  border-left: 1px solid var(--hairline);
}

.checklist-item[data-state='done'] {
  border-left-color: var(--accent);
}

.checklist-item[data-state='part'] {
  border-left-color: var(--gold);
}

.checklist-item a {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 0;
}

.checklist-item a:hover {
  color: var(--accent);
}

.checklist-detail {
  font-size: 13px;
  color: var(--muted);
}

.interest-list {
  display: flex;
  flex-direction: column;
  margin-top: 20px;
}

.interest-row {
  display: grid;
  grid-template-columns: minmax(0, 260px) minmax(0, 1fr);
  gap: 10px 30px;
  align-items: center;
  padding: 18px 0;
  border-top: 1px solid var(--hairline);
}

.interest-row:last-child {
  border-bottom: 1px solid var(--hairline);
}

.interest-row-id {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.interest-title {
  font-family: var(--display);
  font-size: 19px;
  line-height: 1.3;
}

/* Names, not answers — smaller than the RSVP's three big choices so a row of
   four people reads as one control rather than four decisions. */
.interest-row .choice span {
  min-height: 38px;
  padding: 6px 14px;
  font-size: 10px;
}

/* Where, above the tag pills. One place at a time, so a select rather than
   another row of toggles — and it stays one line however many cities the list
   grows to. */
.location-filter {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}

.location-filter select {
  /* Browsers size a select from its widest option WITHOUT counting the
     letter-spacing this one adds, so the last letter lands under the arrow.
     The floor covers the longest label the page ships with; a longer place
     name still grows the control past it. */
  min-width: 210px;
  padding: 9px 42px 9px 14px;
  background: var(--ground);
  /* The arrow, inline so there is no request for it and it inherits nothing. */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237d5c61' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 14px 14px;
  border: 1px solid var(--hairline);
  border-radius: 0;
  color: var(--ink);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

/* The arrow is a data URI, so its colour cannot come from a custom property —
   the dark palette needs its own copy. */
:root[data-theme='dark'] .location-filter select {
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b69a9c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* The options themselves are drawn by the OS, which does not inherit the page's
   theme — say it explicitly or a dark-theme guest gets black text on black. */
.location-filter select option {
  background: var(--ground);
  color: var(--ink);
}

.location-filter select:hover {
  border-color: var(--accent);
}

.location-filter select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.tag-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin: 0 0 28px;
  padding: 0;
  border: 0;
}

.tag-filter-option {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border: 1px solid var(--hairline);
  color: var(--muted);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.tag-filter-option input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.tag-filter-option.is-active {
  background: var(--accent-soft);
  border-color: var(--accent-soft);
  color: var(--accent-ink);
}

.activity-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  width: 100%;
}

.activity-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--hairline);
  color: var(--ink);
}

.activity-card img,
.activity-card-placeholder {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--hairline-soft);
}

.activity-card-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
}

.activity-card-body h3 {
  font-family: var(--display);
  font-size: 19px;
  font-weight: 400;
  line-height: 1.3;
}

.activity-card-body p {
  max-width: none;
  font-size: 14px;
  line-height: 1.55;
}

.activity-card-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: auto;
  padding-top: 8px;
}

.activity-tags {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.activity-interest-count {
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}

/* --- things to do: detail page ------------------------------------------- */

.activity-detail-figure {
  margin: 0 0 28px;
}

.activity-detail-figure img {
  display: block;
  width: 100%;
  max-height: 480px;
  object-fit: cover;
  border: 1px solid var(--hairline);
}

.activity-detail-figure figcaption {
  margin-top: 6px;
  font-size: 11px;
  color: var(--muted);
}

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

@media (max-width: 900px) {
  :root {
    --gutter: 20px;
  }

  /* Give the branches a clear band across the top. On a phone the text fills
     the width, so there is nowhere for them to frame from the sides — they
     arch over the masthead instead. */
  .overture {
    padding-top: clamp(104px, 30vw, 168px);
  }

  /* Cormorant at 21px eats most of a phone screen; ease it back. */
  .overture-lede,
  .lede {
    font-size: 18px;
    line-height: 1.6;
  }

  .rule-inner {
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 8px 12px;
    padding: 10px var(--margin);
  }

  .rule-nav {
    flex-wrap: wrap;
    justify-content: center;
    overflow-x: visible;
    gap: 6px 8px;
  }

  .rule-nav::after {
    display: none;
  }

  .rule-nav a {
    padding: 6px 12px;
    border-radius: 20px;
    background: var(--ground-2);
    border: 1px solid var(--hairline);
    font-size: 11px;
    letter-spacing: 0.14em;
    transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
  }

  .rule-nav a:hover {
    color: var(--ink);
    border-color: var(--accent-soft);
    transform: translateY(-1px);
  }

  .rule-nav a[aria-current='true'] {
    color: var(--accent-ink);
    background: var(--accent);
    border-color: var(--accent);
    box-shadow: 0 3px 10px rgba(168, 66, 92, 0.25);
  }

  /* The pill layout has no room for a divider line, so the gap alone does the
     separating job the left border does at full width. */
  .rule-nav-admin,
  .rule-nav-divider {
    padding-left: 12px;
    border-left: 0;
  }

  .greeting {
    font-size: 10px;
  }

  /* The nav wraps and centres at this width, so the greeting is no longer at
     the right edge — hang the menu off its middle instead. */
  .account-menu {
    top: calc(100% + 10px);
    right: 50%;
    transform: translateX(50%);
  }

  .theme-toggle {
    top: 12px;
    right: 12px;
  }

  .sec {
    padding-top: 22px;
  }

  .row,
  .hotel,
  .person,
  .tokyo-dates-row,
  .interest-row,
  .suggest-row,
  .suggest-grid,
  .suggest-photo {
    grid-template-columns: 1fr;
  }

  /* Full width would make the preview the loudest thing on a phone screen. */
  .suggest-photo-preview {
    max-width: 220px;
  }

  .row-timed {
    grid-template-columns: minmax(0, 58px) minmax(0, 1fr);
  }

  .row-timed > :last-child {
    grid-column: 2;
  }

  .gallery {
    grid-template-columns: repeat(2, 1fr);
  }

  .shot:nth-child(n) {
    grid-column: span 1;
  }

  .shot:nth-child(4n + 1) {
    grid-column: span 2;
  }

  .qa summary {
    font-size: 18px;
    gap: 16px;
  }

  .cards,
  .activity-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .gallery {
    grid-template-columns: 1fr;
  }

  .shot:nth-child(n) {
    grid-column: span 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .rise {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

@media print {
  .rule,
  .rsvp-actions,
  .skip-link,
  .overture canvas {
    display: none;
  }

  body {
    background: #fff;
    color: #000;
  }
}
