/* Kunlayathip & Simon — online wedding card
   Follows the printed card: blush ground, one long white panel with rounded ends,
   rose lettering, FF monogram, watercolour peonies. */

:root {
  --bg: #FAE9E9;        /* the card's blush ground */
  --panel: #FFFFFF;
  --tile: #FDF3F2;      /* soft blocks inside the white panel */
  --rose: #BD685E;      /* the card's lettering colour: names, headings */
  --ink: #A8554C;       /* same hue, a step darker so small text stays readable */
  --mono: #C78B85;
  --line: #F1D9D7;
  --coral: #C66F69;
  --shadow: 0 16px 30px -22px rgba(168, 85, 76, .5);
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: #F3DCDC;
  color: var(--ink);
  font: 300 16.5px/1.8 'Prompt', 'Noto Sans Thai', sans-serif;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* One phone-width column, centred on larger screens */
.card {
  position: relative;
  max-width: 480px;
  margin: 0 auto;
  background: var(--bg);
  overflow: clip;
  box-shadow: 0 0 60px rgba(168, 85, 76, .14);
}

/* ───── Cover ───── */
.cover {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  min-height: 100vh;
  min-height: 100svh;
  padding: max(28px, env(safe-area-inset-top)) 14px 64px;
  text-align: center;
  position: relative;
}
/* Cover artwork in layers (tools/build_cover.py): peonies behind the oval, the oval, peonies in front */
.cover-art { position: relative; width: min(100%, 420px); }
.cover-art img { position: absolute; height: auto; }
.cover-art .oval { position: relative; display: block; width: 100%; }
/* Opening: the oval fades in, then the peonies open one after another.
   Those behind the oval grow out from under its edge; those in front unfurl in place. */
.js .cover-art img { opacity: 0; }
.js .cover-art.open .oval { animation: oval-in 1s ease-out both; }
.js .cover-art.open .bloom {
  animation: bloom 2.6s cubic-bezier(.2, .7, .2, 1) both;
  animation-delay: calc(.6s + var(--i) * .2s);
}
@keyframes oval-in { from { opacity: 0; transform: scale(.97); } to { opacity: 1; transform: none; } }
@keyframes bloom {
  from { opacity: 0; transform: scale(.3) rotate(var(--turn, 0deg)); }
  30% { opacity: 1; }
  to { opacity: 1; transform: none; }
}
.guest {
  margin: 0;
  padding: 8px 22px;
  border-radius: 999px;
  background: var(--panel);
  box-shadow: 0 8px 20px -12px rgba(168, 85, 76, .45);
  font-size: 15.5px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.guest strong { font-weight: 500; }
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  margin-left: -20px;
  border-radius: 50%;
  color: var(--rose);
  animation: nudge 2.2s ease-in-out infinite;
}
.scroll-cue svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
@keyframes nudge { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }

/* ───── The white panel with rounded ends, peonies at its shoulders ───── */
.panel-wrap { position: relative; padding: 26px 12px 96px; }
.panel {
  position: relative;
  background: var(--panel);
  border-radius: 260px;          /* larger than half the width, so both ends are full half-circles */
  padding: var(--panel-top) 22px 120px;
  text-align: center;
}
.peony { position: absolute; z-index: 2; height: auto; pointer-events: none; }
.p1 { left: 4px; top: 8px; width: 62px; }
.p2 { right: 6px; top: 40px; width: 72px; }
.p3 { left: 10px; bottom: 74px; width: 72px; }
.p4 { right: 8px; bottom: 108px; width: 74px; }

/* ───── Versus screen ─────
   Lies over the invitation page when it first comes into view: one photo of the couple, cut on a slant
   between them, her half on the left and his on the right. js/app.js adds .go; the VS mark slams in,
   then the two halves slide apart to show the invitation. */
.versus { display: none; }
.js .versus {
  display: block;
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 100vh;
  height: 100svh;
  z-index: 5;                         /* over the panel and its peonies, under the petals and the menu */
  overflow: hidden;
  pointer-events: none;
}
/* The cut runs from 56% across at the top to 36% at the bottom; the photo is pinned at 46% across,
   the gap between the two of them, so the cut passes between their faces on any screen. */
.versus::before { content: ""; position: absolute; inset: 0; z-index: 1; background: #fff; clip-path: polygon(55.2% 0, 56.8% 0, 36.8% 100%, 35.2% 100%); }
.versus .half { position: absolute; inset: 0; }
.versus .half img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 46% 50%; }
.versus .bride { clip-path: polygon(0 0, 55.6% 0, 35.6% 100%, 0 100%); }
.versus .groom { clip-path: polygon(56.4% 0, 100% 0, 100% 100%, 36.4% 100%); }
.versus .tag, .versus .mark { position: absolute; z-index: 2; height: auto; opacity: 0; }
.versus .bride-tag { left: 4%; top: 71%; width: 25%; }
.versus .groom-tag { right: 4%; top: 75%; width: 25%; }
.versus .mark { left: 45%; top: 67%; width: 32%; margin: -12.5% 0 0 -16%; }
/* One three-second run: mark and names arrive, hold, then everything leaves, each half to its own side */
.versus.go { animation: versus-end .01s linear 3s forwards; }
.versus.go::before { animation: versus-seam 3s both; }
.versus.go .mark { animation: versus-mark 3s both; }
.versus.go .bride { animation: versus-left 3s both; }
.versus.go .groom { animation: versus-right 3s both; }
.versus.go .bride-tag { animation: versus-tag-left 3s both; }
.versus.go .groom-tag { animation: versus-tag-right 3s both; }
@keyframes versus-end { to { visibility: hidden; } }
@keyframes versus-seam { 0%, 58% { opacity: 1; } 66%, 100% { opacity: 0; } }
@keyframes versus-mark {
  0% { opacity: 0; transform: scale(2.8) rotate(-18deg); }
  9% { opacity: 1; transform: scale(.9) rotate(4deg); }
  13% { opacity: 1; transform: scale(1.05) rotate(-2deg); }
  17%, 56% { opacity: 1; transform: none; }
  68%, 100% { opacity: 0; transform: scale(1.8) rotate(6deg); }
}
@keyframes versus-left {
  0%, 58% { transform: none; animation-timing-function: cubic-bezier(.6, 0, .85, .3); }
  100% { transform: translate(-106%, -10%); }
}
@keyframes versus-right {
  0%, 58% { transform: none; animation-timing-function: cubic-bezier(.6, 0, .85, .3); }
  100% { transform: translate(106%, 10%); }
}
@keyframes versus-tag-left {
  0%, 6% { opacity: 0; transform: translateX(-70px); }
  16%, 58% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.6, 0, .85, .3); }
  100% { opacity: 1; transform: translate(-106vw, -10vh); }
}
@keyframes versus-tag-right {
  0%, 6% { opacity: 0; transform: translateX(70px); }
  16%, 58% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.6, 0, .85, .3); }
  100% { opacity: 1; transform: translate(106vw, 10vh); }
}

/* ───── Pages inside the panel ─────
   Each section is at least one screen tall with its content in the middle, and scrolling always settles on
   the start of a page, so the next page never shows at the bottom of the screen. A section with more than
   a screenful simply runs longer and scrolls freely inside itself. */
html { scroll-snap-type: y mandatory; }
.cover, .sec { scroll-snap-align: start; }
/* The very end of the card (closing lines, the panel's rounded end and its peonies) is a resting place too */
.foot { scroll-snap-align: end; scroll-margin-bottom: 216px; }   /* 120px panel padding + 96px below the panel */
.sec {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: 44px 0 96px;            /* bottom: room for the menu floating over the page */
}
.sec + .sec { border-top: 1px solid var(--line); }
/* First page: it begins at the panel's rounded top, which sits above the section itself (26px gap + the panel's padding) */
:root { --panel-top: 84px; }
.invite {
  min-height: calc(100vh - 26px - var(--panel-top));
  min-height: calc(100svh - 26px - var(--panel-top));
  padding-top: 0;
  scroll-margin-top: calc(26px + var(--panel-top));
}
/* Last page: it runs on through the closing lines and the panel's rounded end, about 320px below the section */
#location { min-height: calc(100vh - 320px); min-height: calc(100svh - 320px); padding-bottom: 54px; }
.title {
  margin: 0;
  font: 400 29px/1.2 'Gilda Display', serif;
  letter-spacing: .06em;
  color: var(--rose);
}
.sub { margin: 4px 0 0; font-size: 15.5px; }
.note { margin: 14px auto 0; max-width: 32ch; font-size: 15px; }
.tile { border-radius: 20px; background: var(--tile); }

/* Invitation */
.mono { display: block; width: 62px; height: auto; margin: 0 auto 26px; }
.parents {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 6px;
  margin-inline: -14px;
  font-size: clamp(12px, 3.6vw, 15px);
  line-height: 1.7;
}
.parents p { margin: 0; white-space: nowrap; }
.lead { margin: 22px 0 0; font-size: 16px; }
.name {
  margin: 22px 0 0;
  font: 400 clamp(26px, 8vw, 34px)/1.15 'Gilda Display', serif;
  color: var(--rose);
}
.name-th { margin: 4px 0 0; font-size: 16.5px; }
.rings { display: block; width: 56px; height: auto; margin: 20px auto -6px; color: var(--rose); }
.venue { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 32px 0 0; font-size: 17px; font-weight: 400; }
.venue svg { flex: none; width: 20px; height: 25px; color: var(--rose); }

/* Schedule page: the couple walking hand in hand are the top of the page itself, under an arch like the one that
   opens the first page, strong at the top and fading away into the page further down. The heading and the
   schedule sit at the bottom of the page, over the fade. */
#schedule {
  position: relative;
  justify-content: flex-end;
  padding-top: 228px;                 /* the heading never starts higher than this, so it stays clear of their faces */
  border-top: 0;                      /* the arch itself marks the start of the page */
}
#schedule .sec-body { position: relative; }
/* The heading sits where the photo is still faintly there, so it is darker and heavier than on other pages, with a
   white glow behind it. Gilda Display has no bold cut; the stroke thickens the letters instead. */
#schedule .sec-body > .title {
  font-size: 32px;
  color: #8A4039;
  -webkit-text-stroke: .9px currentColor;
  text-shadow: 0 0 14px #fff, 0 0 6px #fff, 0 0 2px #fff;
}
#schedule .sec-body > .sub { font-weight: 500; text-shadow: 0 0 10px #fff, 0 0 4px #fff, 0 0 2px #fff; }
/* The backdrop reaches from the top of the page to a little way into the heading (the page's content is about
   464px tall and sits at the bottom). Its outline is the first page's arch with a soft edge, and its last 200px
   fade out into the page. The photo itself keeps one size and place, faces about 130px from the top, however
   tall the backdrop is.
   The outline is one drawn shape used as a mask: a box as wide as the backdrop whose corners are rounded by half
   its width (so the top is a half-circle), pulled in 9px and then blurred a little, which gives one seamless soft edge
   round the curve and down both sides. Change `radius` (how far in) and `stdDeviation` (how blurred) together. */
.stroll {
  position: absolute;
  top: 12px; left: -22px; right: -22px;         /* out to the panel's own edges, past its 22px padding */
  height: max(316px, calc(100vh - 476px));
  margin: 0;
  overflow: hidden;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25'%3E%3Cfilter id='soft' x='0' y='0' width='100%25' height='100%25'%3E%3CfeMorphology operator='erode' radius='9'/%3E%3CfeGaussianBlur stdDeviation='4.5'/%3E%3C/filter%3E%3Crect width='100%25' height='300%25' rx='50%25' filter='url%28%23soft%29'/%3E%3C/svg%3E") 0 0 / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25'%3E%3Cfilter id='soft' x='0' y='0' width='100%25' height='100%25'%3E%3CfeMorphology operator='erode' radius='9'/%3E%3CfeGaussianBlur stdDeviation='4.5'/%3E%3C/filter%3E%3Crect width='100%25' height='300%25' rx='50%25' filter='url%28%23soft%29'/%3E%3C/svg%3E") 0 0 / 100% 100% no-repeat;
}
/* the fade into the page: the panel's own white laid over the foot of the photo, on the same eased curve */
.stroll::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to top, rgba(255, 255, 255, 1) 8px, rgba(255, 255, 255, 0.93) 46px, rgba(255, 255, 255, 0.75) 84px, rgba(255, 255, 255, 0.5) 116px, rgba(255, 255, 255, 0.25) 149px, rgba(255, 255, 255, 0.08) 179px, rgba(255, 255, 255, 0) 198px); }
@supports (height: 100svh) { .stroll { height: max(316px, calc(100svh - 476px)); } }
.stroll img { position: absolute; top: 0; left: -6%; width: 122%; max-width: none; height: auto; transform: translateY(-29.5%); }

/* Schedule: the dot-and-line from the printed card */
.timeline { list-style: none; margin: 28px auto 0; padding: 0; max-width: 340px; text-align: left; }
.timeline li {
  position: relative;
  display: grid;
  grid-template-columns: 6.6em 20px 1fr;
  align-items: start;
  gap: 8px;
  padding-bottom: 26px;
  font-size: 16px;
  line-height: 1.5;
  scroll-margin-top: 24px;
}
.timeline li:last-child { padding-bottom: 0; }
.timeline time { text-align: right; white-space: nowrap; }
.timeline i { width: 12px; height: 12px; margin: 6px auto 0; border-radius: 50%; background: var(--rose); }
/* line from this dot down to the next one, whatever the row height */
.timeline li:not(:last-child)::before {
  content: "";
  position: absolute;
  left: calc(6.6em + 8px + 9px);
  top: 12px;
  bottom: -12px;
  width: 2px;
  background: var(--rose);
}

/* Calendar */
.cal-card { max-width: 330px; margin: 24px auto 0; padding: 18px 12px 12px; }
.cal-month { margin: 0 0 8px; font: 400 16.5px/1 'Gilda Display', serif; letter-spacing: .2em; color: var(--rose); }
.cal {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  font: 400 15px/1 'Gilda Display', serif;
  font-variant-numeric: lining-nums tabular-nums;
}
.cal span { display: grid; place-items: center; height: 38px; }
.cal .dow-h { height: 28px; font-size: 10.5px; letter-spacing: .06em; }
.cal .on { width: 36px; height: 36px; margin: auto; border-radius: 50%; background: var(--ink); color: #fff; }

/* Countdown */
.countdown { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; max-width: 330px; margin: 14px auto 0; }
.countdown div { display: grid; gap: 2px; padding: 12px 0 8px; border-radius: 14px; background: var(--tile); }
.countdown b { font: 400 29px/1.1 'Gilda Display', serif; font-variant-numeric: lining-nums tabular-nums; color: var(--rose); }
.countdown span { font-size: 12.5px; line-height: 1.4; }

/* Buttons */
.actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 20px; }
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 1 1 140px;
  max-width: 260px;
  padding: 12px 16px;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font: 400 15px/1.35 'Prompt', sans-serif;
  text-decoration: none;
  cursor: pointer;
  transition: background .2s, color .2s;
}
.btn:hover { background: var(--tile); }
.btn.solid { background: var(--ink); color: #fff; }
.btn.solid:hover { background: #8E463E; }

/* RSVP */
.rsvp, .rsvp-done { display: grid; gap: 16px; max-width: 340px; margin: 22px auto 0; padding: 22px 18px; text-align: left; }
.rsvp-who { margin: 0; font-size: 15.5px; text-align: center; }
.rsvp-who strong { font-weight: 500; overflow-wrap: anywhere; }
.field { display: grid; gap: 6px; }
.field label, .rsvp legend, .stepper-row > span { font-size: 15px; font-weight: 400; }
.field input {
  width: 100%;
  padding: 11px 14px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: #fff;
  color: var(--ink);
  font: 300 16px/1.4 'Prompt', sans-serif;
}
.field input:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }
.rsvp fieldset { display: grid; gap: 8px; margin: 0; padding: 0; border: 0; min-width: 0; }
.rsvp legend { padding: 0; margin-bottom: 8px; }
.chips { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.chips label { position: relative; }
.chips input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.chips span {
  display: block;
  padding: 11px 8px;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: #fff;
  font-size: 15.5px;
  text-align: center;
  transition: background .2s, color .2s, border-color .2s;
}
.chips input:checked + span { background: var(--ink); border-color: var(--ink); color: #fff; }
.chips input:focus-visible + span { outline: 2px solid var(--ink); outline-offset: 2px; }
.stepper-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.stepper-row small { display: block; font-size: 12.5px; font-weight: 300; }
.stepper { flex: none; display: inline-flex; align-items: center; border: 1.5px solid var(--line); border-radius: 999px; background: #fff; }
.stepper button { width: 44px; height: 42px; border: 0; background: none; color: var(--ink); font-size: 22px; line-height: 1; cursor: pointer; }
.stepper output { min-width: 30px; font: 400 20px/1 'Gilda Display', serif; font-variant-numeric: lining-nums tabular-nums; text-align: center; }
.rsvp-total { margin: 10px 0 0; font-size: 14.5px; text-align: center; }
.rsvp-nudge { margin: 0; font-size: 14.5px; text-align: center; }
.rsvp-nudge a { color: var(--ink); text-underline-offset: 3px; }
.rsvp .btn, .rsvp-done .btn { flex: none; width: 100%; max-width: none; }
.rsvp .btn[disabled] { opacity: .6; cursor: default; }
.rsvp-msg { margin: -6px 0 0; min-height: 0; font-size: 14.5px; font-weight: 400; text-align: center; }
.rsvp-msg:empty { display: none; }
.rsvp-captcha:empty { display: none; }       /* the captcha takes room only when it shows itself */
.rsvp-test { margin: -4px 0 0; font-size: 12.5px; text-align: center; opacity: .85; }
.rsvp-done { text-align: center; }
.rsvp-done p { margin: 0; }
.rsvp-thanks { font: 400 24px/1.3 'Gilda Display', 'Prompt', serif; color: var(--rose); }

/* RSVP: the couple on their sofa under the form, pointing up at it. The two cut-outs take turns, about half a
   second each, like a two-frame film. */
.cheer { position: relative; width: min(88%, 300px); margin: 8px auto 0; }
.cheer img { display: block; width: 100%; height: auto; animation: cheer-first 1.1s steps(1) infinite; }
.cheer img + img { position: absolute; inset: 0; animation-name: cheer-second; }
@keyframes cheer-first { 0% { opacity: 1; } 50% { opacity: 0; } }
@keyframes cheer-second { 0% { opacity: 0; } 50% { opacity: 1; } }

/* Gift. The couple's thank-you photo leads: a wide slice of an upright photo, with their two subtitles stuck
   on as zigzag-edged stickers (one picture, made by tools/build_stickers.py). The QR sits right under it. */
.still { position: relative; margin: 14px 0 0; border-radius: 18px; overflow: hidden; }
.still > img { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; object-position: 50% 62%; }
.still figcaption { position: absolute; left: 0; right: 0; bottom: 7px; display: flex; justify-content: center; }
.still figcaption img { width: 66%; height: auto; }
#gift .note { margin-top: 12px; max-width: none; font-size: 14.5px; }
/* The QR tile sits above the falling layer (z-index 10), so nothing ever drifts across the QR */
.gift-card { position: relative; z-index: 11; display: grid; justify-items: center; gap: 14px; max-width: 340px; margin: 14px auto 0; padding: 16px 18px 18px; }
.qr { display: block; width: min(210px, 72%); height: auto; padding: 9px; border-radius: 16px; background: #F5E6D2; }
.gift-card .btn { flex: none; width: 100%; max-width: none; }

/* Theme colour: the four dots from the printed card */
/* Theme colours, under the schedule */
.dress { margin-top: 52px; }
.dress .title { font-size: 24px; }
.dots { list-style: none; margin: 22px 0 0; padding: 0; display: flex; justify-content: center; gap: 14px; }
.dots li { display: grid; justify-items: center; gap: 8px; font-size: 13.5px; line-height: 1.3; }
.dots i { width: 52px; height: 52px; border-radius: 50%; background: var(--c); box-shadow: inset 0 0 0 1px rgba(168, 85, 76, .08); }

/* Gallery: a small collage. An arch-topped photo leads, echoing the oval on the cover, with a tall frame,
   a round one, a square and an upturned arch around it. Row height follows the screen, so the collage
   fits on one page. Photos beyond five repeat the pattern, mirrored. */
.gallery {
  --row: 46px;
  container-type: inline-size;       /* lets the arches size their curve from the collage's width */
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: var(--row);
  grid-auto-flow: dense;
  gap: 10px;
  margin-top: 24px;
}
@supports (height: 100svh) {
  .gallery { --row: clamp(34px, calc((100svh - 304px) / 8), 58px); }
}
.gallery > * { border-radius: 22px; background: var(--tile); }
/* An arch needs its curve to be exactly half the frame's width (a bigger value would shrink the square corners too),
   so it is worked out from the columns: 4 of 6 columns for the big arch, 3 of 6 for the upturned one. */
.gallery > :nth-child(5n + 1) { grid-area: span 5 / span 4; border-radius: 105px 105px 22px 22px; border-radius: calc(33.33cqw - 1.7px) calc(33.33cqw - 1.7px) 22px 22px; }
.gallery > :nth-child(5n + 2) { grid-area: span 3 / span 2; }
.gallery > :nth-child(5n + 3) { grid-area: span 2 / span 2; border-radius: 999px; }
.gallery > :nth-child(5n + 4) { grid-area: span 3 / span 3; }
.gallery > :nth-child(5n + 5) { grid-area: span 3 / span 3; border-radius: 22px 22px 78px 78px; border-radius: 22px 22px calc(25cqw - 2.5px) calc(25cqw - 2.5px); }
.gallery > :nth-child(10n + 6) { grid-column: 3 / span 4; }                 /* second group: the arch moves to the right */
/* fewer than five: let the last one fill the row instead of leaving a hole */
.gallery > :only-child, .gallery > :last-child:nth-child(5n + 4) { grid-column: 1 / -1; }
.gallery > :last-child:nth-child(5n + 2) { grid-row: span 5; }
.gallery button { padding: 0; border: 0; overflow: hidden; cursor: zoom-in; }
/* a fine line around the three shaped photos, like a mount */
.gallery button:nth-child(5n + 1), .gallery button:nth-child(5n + 3), .gallery button:nth-child(5n + 5) { box-shadow: 0 0 0 3px var(--panel), 0 0 0 4px #E3BDB9; }
.gallery img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* empty frames shown until real photos are listed in js/app.js */
.gallery .slot {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 4px;
  border: 1.5px dashed #E3BDB9;
  font-size: 13px;
  line-height: 1.3;
}
.gallery .slot svg { width: 26px; height: 26px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }

/* Location */
.map { margin-top: 22px; border-radius: 18px; overflow: hidden; background: var(--tile); aspect-ratio: 4 / 3; }
.map iframe { display: block; width: 100%; height: 100%; border: 0; }

/* Closing, inside the rounded bottom of the panel */
.foot { padding-top: 46px; border-top: 1px solid var(--line); }
.hashtag { margin: 0; font: 400 22px/1.3 'Gilda Display', serif; letter-spacing: .04em; color: var(--coral); }
.sorry { margin: 6px auto 0; font-size: clamp(12.5px, 3.7vw, 14.5px); line-height: 1.6; white-space: nowrap; }

/* Bottom menu */
.nav {
  position: fixed;
  left: 50%;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  z-index: 20;
  display: flex;
  gap: 2px;
  width: min(430px, calc(100% - 20px));
  padding: 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .95);
  box-shadow: 0 0 0 1px var(--line), 0 14px 30px -14px rgba(168, 85, 76, .55);
  transform: translateX(-50%);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: transform .35s ease, opacity .35s ease;
}
/* Tucked away on the cover so the artwork shows in full; slides in on the first scroll */
.nav.tucked { opacity: 0; transform: translate(-50%, 130%); pointer-events: none; }
.nav a {
  flex: 1;
  display: grid;
  justify-items: center;
  gap: 1px;
  padding: 7px 0 5px;
  border-radius: 999px;
  color: var(--ink);
  font-size: clamp(9.5px, 2.8vw, 11px);
  line-height: 1.3;
  text-decoration: none;
  white-space: nowrap;
  transition: background .25s, color .25s;
}
.nav svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.nav a[aria-current="true"] { background: var(--ink); color: #fff; }

/* Photo viewer */
.lightbox { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; padding: 64px 16px; background: rgba(60, 28, 24, .93); }
.lightbox img { max-width: min(92vw, 560px); max-height: 78vh; object-fit: contain; border-radius: 6px; }
.lightbox button { position: absolute; width: 46px; height: 46px; border: 0; border-radius: 50%; background: rgba(255, 255, 255, .14); color: #fff; font-size: 24px; line-height: 1; cursor: pointer; }
#lbClose { top: calc(14px + env(safe-area-inset-top, 0px)); right: 14px; }
#lbPrev { left: 12px; top: 50%; transform: translateY(-50%); }
#lbNext { right: 12px; top: 50%; transform: translateY(-50%); }

/* A light fall of petals, like cherry blossom (added by js/app.js; none with reduced motion) */
.petals { position: fixed; inset: 0; z-index: 10; overflow: hidden; pointer-events: none; }
.petal {
  position: absolute;
  top: -24px;
  left: var(--x);
  width: var(--size);
  height: var(--size);
  opacity: var(--alpha);
  animation: petal-fall var(--fall) linear var(--wait) infinite;
}
.petal svg { display: block; width: 100%; height: 100%; fill: var(--tint); animation: petal-flutter var(--sway) ease-in-out infinite alternate; transition: opacity .5s ease; }
/* On the gift page the petals turn into banknotes, in the colours of Thai notes (.money is set while that page is on screen) */
.petal .note { position: absolute; left: calc(var(--size) * -.6); top: calc(var(--size) * -.09); width: calc(var(--size) * 2.2); height: calc(var(--size) * 1.18); opacity: 0; }
.note rect { fill: var(--note); }
.note rect + rect { fill: none; stroke: #fff; stroke-opacity: .6; stroke-width: .8; }
.note circle { fill: #fff; fill-opacity: .78; }
.note text { fill: var(--note); font: 700 6.2px sans-serif; text-anchor: middle; }
.petals.money .petal { opacity: .95; }
.petals.money .leaf { opacity: 0; }
.petals.money .note { opacity: 1; }
@keyframes petal-fall { to { transform: translate3d(var(--drift), calc(100vh + 48px), 0); } }
/* Tilts stay well short of 90deg: a petal seen edge-on is a hairline that reads as a scratch on the page */
@keyframes petal-flutter {
  from { transform: translateX(-16px) rotate(-35deg) rotateX(28deg) rotateY(-52deg); }
  to { transform: translateX(16px) rotate(55deg) rotateX(-28deg) rotateY(52deg); }
}

/* Short screens (a phone with the browser's bars showing): tighten the first page so the names stay clear of the menu,
   and the schedule page so its heading starts lower, clear of the faces in the photo behind it */
@media (max-height: 720px) {
  :root { --panel-top: 64px; }
  .mono { width: 54px; margin-bottom: 18px; }
  .lead, .name { margin-top: 16px; }
  .rings { margin-top: 14px; }
  .stroll { height: max(316px, calc(100vh - 424px)); }          /* this page's content is about 52px shorter here */
  .venue { margin-top: 20px; }
  .timeline { margin-top: 18px; }
  .timeline li { padding-bottom: 18px; }
  .dress { margin-top: 30px; }
}

@supports (height: 100svh) {
  @media (max-height: 720px) { .stroll { height: max(316px, calc(100svh - 424px)); } }
}

/* Gentle entrance for each page's content (the page itself stays put, so menu links and snapping land exactly);
   everything stays visible if scripts are off */
.js .reveal .sec-body { opacity: 0; transform: translateY(14px); transition: opacity .7s ease, transform .7s ease; }
.js .reveal.in .sec-body { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal .sec-body { opacity: 1; transform: none; transition: none; }
  .js .cover-art img { opacity: 1; animation: none !important; }
  .js .versus { display: none; }
  .cheer img { animation: none; }
  .cheer img + img { display: none; }
  .scroll-cue { animation: none; }
}
