/* ---- w/css/style.css ---- */
/* ================= THE SMITH WEDDING · MISTY HIGHLANDS (clean white) ================= */

/* ---------- Fonts: self-hosted (SIL OFL, see ../fonts/OFL.txt) ----------
   Each face is a small "core" cut (only the characters the site sets; preloaded in index.html) plus the full
   latin and latin-ext files for anything else, split by unicode-range so a page only fetches what it uses. */
@font-face { font-family: 'Pinyon Script'; font-style: normal; font-weight: 400; font-display: swap; src: url(../fonts/pinyon-script-core-v1.woff2) format('woff2'); unicode-range: U+0000-00A0, U+00A7, U+00A9, U+00AB, U+00B0, U+00B7, U+00BB, U+00D7, U+00E0-00FF, U+2013-2014, U+2018-2019, U+201C-201D, U+2022, U+2026, U+2039-203A; }
@font-face { font-family: 'Pinyon Script'; font-style: normal; font-weight: 400; font-display: swap; src: url(../fonts/pinyon-script-latin-400-normal.woff2) format('woff2'); unicode-range: U+00A1-00A6, U+00A8, U+00AA, U+00AC-00AF, U+00B1-00B6, U+00B8-00BA, U+00BC-00D6, U+00D8-00DF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-2012, U+2015-2017, U+201A-201B, U+201E-2021, U+2023-2025, U+2027-2038, U+203B-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Pinyon Script'; font-style: normal; font-weight: 400; font-display: swap; src: url(../fonts/pinyon-script-latin-ext-400-normal.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Playfair Display'; font-style: normal; font-weight: 400 900; font-display: swap; src: url(../fonts/playfair-display-core-wght-normal-v1.woff2) format('woff2'); unicode-range: U+0000-00A0, U+00A7, U+00A9, U+00AB, U+00B0, U+00B7, U+00BB, U+00D7, U+00E0-00FF, U+2013-2014, U+2018-2019, U+201C-201D, U+2022, U+2026, U+2039-203A; }
@font-face { font-family: 'Playfair Display'; font-style: normal; font-weight: 400 900; font-display: swap; src: url(../fonts/playfair-display-latin-wght-normal.woff2) format('woff2'); unicode-range: U+00A1-00A6, U+00A8, U+00AA, U+00AC-00AF, U+00B1-00B6, U+00B8-00BA, U+00BC-00D6, U+00D8-00DF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-2012, U+2015-2017, U+201A-201B, U+201E-2021, U+2023-2025, U+2027-2038, U+203B-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Playfair Display'; font-style: normal; font-weight: 400 900; font-display: swap; src: url(../fonts/playfair-display-latin-ext-wght-normal.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Playfair Display'; font-style: italic; font-weight: 400 900; font-display: swap; src: url(../fonts/playfair-display-core-wght-italic-v1.woff2) format('woff2'); unicode-range: U+0000-00A0, U+00A7, U+00A9, U+00AB, U+00B0, U+00B7, U+00BB, U+00D7, U+00E0-00FF, U+2013-2014, U+2018-2019, U+201C-201D, U+2022, U+2026, U+2039-203A; }
@font-face { font-family: 'Playfair Display'; font-style: italic; font-weight: 400 900; font-display: swap; src: url(../fonts/playfair-display-latin-wght-italic.woff2) format('woff2'); unicode-range: U+00A1-00A6, U+00A8, U+00AA, U+00AC-00AF, U+00B1-00B6, U+00B8-00BA, U+00BC-00D6, U+00D8-00DF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-2012, U+2015-2017, U+201A-201B, U+201E-2021, U+2023-2025, U+2027-2038, U+203B-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Playfair Display'; font-style: italic; font-weight: 400 900; font-display: swap; src: url(../fonts/playfair-display-latin-ext-wght-italic.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Plus Jakarta Sans'; font-style: normal; font-weight: 200 800; font-display: swap; src: url(../fonts/plus-jakarta-sans-core-wght-normal-v1.woff2) format('woff2'); unicode-range: U+0000-00A0, U+00A7, U+00A9, U+00AB, U+00B0, U+00B7, U+00BB, U+00D7, U+00E0-00FF, U+2013-2014, U+2018-2019, U+201C-201D, U+2022, U+2026, U+2039-203A; }
@font-face { font-family: 'Plus Jakarta Sans'; font-style: normal; font-weight: 200 800; font-display: swap; src: url(../fonts/plus-jakarta-sans-latin-wght-normal.woff2) format('woff2'); unicode-range: U+00A1-00A6, U+00A8, U+00AA, U+00AC-00AF, U+00B1-00B6, U+00B8-00BA, U+00BC-00D6, U+00D8-00DF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-2012, U+2015-2017, U+201A-201B, U+201E-2021, U+2023-2025, U+2027-2038, U+203B-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Plus Jakarta Sans'; font-style: normal; font-weight: 200 800; font-display: swap; src: url(../fonts/plus-jakarta-sans-latin-ext-wght-normal.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

:root {
  --blush: #F0C4CB;
  --dusk-rose: #B48A93;
  --heather: #9E7F8E;
  --sage: #8E9A92;
  --sage-mist: #B9C4BD;
  --slate: #5A6964;
  --stone: #D6CBBE;
  --champagne: #FBEAD6;
  --moonbone: #F2EEE9;

  --bg: #FFFFFF;
  --bg-soft: #FAF8F6;
  --blush-wash: #FCF3F4;
  --sage-wash: #F4F7F5;
  --ink: #2E3532;
  --ink-soft: #626A66;
  --primary: #5A6964;
  --primary-hover: #46534F;
  --accent-text: #7E5F6E;
  --line: #ECE7E2;

  --font-script: 'Pinyon Script', cursive;
  --font-title: 'Playfair Display', Georgia, serif;
  --font-body: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --radius: 16px;
  --radius-sm: 10px;
  --shadow: 0 8px 28px rgba(52, 62, 58, 0.06);
  --shadow-lg: 0 16px 44px rgba(52, 62, 58, 0.12);
  --maxw: 1160px;

  /* engraved ornament (Chappl's one-ink plates, inked in the Misty Highlands palette) */
  --ink-mist: #B9C4BD;
  --ink-sage: #8E9A92;
  --ink-rose: #B48A93;
  --out: cubic-bezier(.22, .61, .36, 1);
  --io: cubic-bezier(.65, 0, .35, 1);
  --pen: cubic-bezier(.45, .05, .55, .95);
  /* fine paper grain for printed photographs (an SVG noise tile, alpha only) */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .2 0 0 0 0 .21 0 0 0 0 .2 0 0 0 .55 -.16'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  --star: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M5 0C5.5 3.5 6.5 4.5 10 5C6.5 5.5 5.5 6.5 5 10C4.5 6.5 3.5 5.5 0 5C3.5 4.5 4.5 3.5 5 0Z'/%3E%3C/svg%3E");
}
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
/* Until app.js has rendered the story (motion.js removes html.ww-hold on app.js's first 'ww:route' with the gate
   down, or when the gate is passed), the chapters are laid out but not shown: what app.js fills in (dates, cards,
   photographs) can therefore never shift visible content. The header and the invitation card (#home: static HTML,
   its photograph included) paint at once. */
html.ww-hold #main > :not(#home), html.ww-hold .site-footer { visibility: hidden; }
html.ww-hold.ww-deep #home { visibility: hidden; }

*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--ink); font-family: var(--font-body); font-size: 17px; line-height: 1.75; -webkit-font-smoothing: antialiased; }
img { max-width: 100%; display: block; }
a { color: var(--accent-text); text-underline-offset: 3px; }
a:hover { color: var(--primary); }
h1, h2, h3, h4 { font-family: var(--font-title); color: var(--primary); line-height: 1.2; margin: 0 0 .5em; font-weight: 400; letter-spacing: .005em; }
h1 { font-size: clamp(2.2rem, 5vw, 3.3rem); }
h2 { font-size: clamp(1.7rem, 3.2vw, 2.25rem); }
h3 { font-size: 1.3rem; }
p { margin: 0 0 1em; }
.skip-link { position: absolute; left: -999px; top: 0; background: var(--primary); color: #fff; padding: .6rem 1rem; z-index: 999; }
.skip-link:focus { left: 1rem; top: 1rem; }
:focus-visible { outline: 3px solid var(--heather); outline-offset: 3px; }

.container { max-width: var(--maxw); margin: 0 auto; padding: 0 1.5rem; }
.section { padding: 5.5rem 1.5rem; }
.container.section { padding-left: 1.5rem; padding-right: 1.5rem; }
.narrow { max-width: 820px; }
.center { text-align: center; }
.mt-1 { margin-top: 1rem; } .mt-2 { margin-top: 2rem; }
.small { font-size: .9rem; } .muted { color: var(--ink-soft); }
.eyebrow { text-transform: uppercase; letter-spacing: .24em; font-size: .74rem; font-weight: 600; color: var(--accent-text); margin-bottom: .8rem; }
.lead { font-size: 1.1rem; color: var(--ink-soft); }
.text-link { font-size: .8rem; font-weight: 600; letter-spacing: .2em; text-transform: uppercase; color: var(--primary); text-decoration: none; border-bottom: 1px solid var(--sage-mist); padding-bottom: .25rem; }
.text-link:hover { color: var(--accent-text); border-color: var(--heather); }

/* ---------- Logo ---------- */
.logo { display: block; color: var(--primary); }
.logo-gate { width: 97px; height: 108px; margin: 0 auto .7rem; }
.logo-footer { width: 66px; height: 74px; margin: 0 auto .6rem; color: var(--sage); }

/* ---------- Icons ---------- */
.ic { display: inline-flex; align-items: center; justify-content: center; color: var(--primary); flex-shrink: 0; line-height: 0; }
.ic svg { width: 1.15em; height: 1.15em; display: block; }
.ic-circle { width: 52px; height: 52px; border-radius: 50%; background: var(--sage-wash); border: 1px solid #E3E9E5; }
.ic-circle svg { width: 22px; height: 22px; }
.ic-circle.ic-sm { width: 38px; height: 38px; }
.ic-circle.ic-sm svg { width: 18px; height: 18px; }
.ic-inline { vertical-align: middle; margin-top: -2px; }
.ic-inline svg { width: 1em; height: 1em; }

/* ---------- Engraved ornament ----------
   Chappl's one-ink engravings used as CSS masks over a background colour, so the palette inks them.
   .orn: four corner flourishes inside a card (four small corner pieces, so nothing sits behind the card's text).
   .orule: hairline, scrolls and a star. All decorative (aria-hidden). */
.orn { position: absolute; inset: 14px; z-index: 0; pointer-events: none; color: var(--ink-rose); opacity: .5; --cs: 58px; }
.orn > span { position: absolute; width: var(--cs); height: var(--cs); background: currentColor; }
.orn > span:nth-child(1) { left: 0; top: 0; -webkit-mask: url(../img/ornament/corner-tl.svg) center / contain no-repeat; mask: url(../img/ornament/corner-tl.svg) center / contain no-repeat; }
.orn > span:nth-child(2) { right: 0; top: 0; -webkit-mask: url(../img/ornament/corner-tr.svg) center / contain no-repeat; mask: url(../img/ornament/corner-tr.svg) center / contain no-repeat; }
.orn > span:nth-child(3) { left: 0; bottom: 0; -webkit-mask: url(../img/ornament/corner-bl.svg) center / contain no-repeat; mask: url(../img/ornament/corner-bl.svg) center / contain no-repeat; }
.orn > span:nth-child(4) { right: 0; bottom: 0; -webkit-mask: url(../img/ornament/corner-br.svg) center / contain no-repeat; mask: url(../img/ornament/corner-br.svg) center / contain no-repeat; }
.orule { display: block; width: min(100%, var(--ow, 220px)); aspect-ratio: 10 / 1; margin: 0 auto; color: var(--ink-rose); background: currentColor;
  -webkit-mask: url(../img/ornament/rule.svg) center / contain no-repeat; mask: url(../img/ornament/rule.svg) center / contain no-repeat; }
/* The J & S monogram (the logo): the mark James chose and supplied as vectors (v19; _work/v19/logo): four outlines,
   used as they are: the stem, the sweeping return, the ribbon and the lower flourish. Large (.lg: the invitation card
   and the footer) it has three stars and a light that passes over it (.lg-shine, a white copy under a moving mask);
   on the invitation card the pen writes it: each part is seen through a mask whose line (.lg-rv) runs along it, in
   their order, and when all are written the whole ink (.lg-all) takes over. Small (#logoMark in the sprite: the
   header, the contents, the update bar) it is the same mark, a little fuller. Without motion everything is simply
   there; the stars and the light stay hidden. */
.lg { position: relative; }
.lg svg { display: block; width: 100%; height: 100%; overflow: visible; }
.lg-part, .lg-all { fill: currentColor; }
.lg-rv { fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 3; }
.lg-star { fill: var(--ink-rose); opacity: 0; transform-box: fill-box; transform-origin: 50% 50%; }
.lg-shine { position: absolute; inset: 0; fill: #fff; opacity: 0; pointer-events: none; }

/* ---------- Buttons ---------- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: .45rem; font-family: var(--font-body); font-weight: 600; font-size: .9rem; letter-spacing: .04em; padding: .85rem 1.6rem; border-radius: 999px; border: 1.5px solid transparent; cursor: pointer; text-decoration: none; transition: all .2s ease; line-height: 1.2; }
.btn-sm { padding: .45rem 1rem; font-size: .85rem; }
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-hover); color: #fff; transform: translateY(-1px); box-shadow: var(--shadow); }
/* outline buttons fill with ink from their foot on hover */
.btn-outline { background: #fff linear-gradient(var(--primary), var(--primary)) no-repeat 50% 100% / 100% 0; color: var(--primary); border-color: var(--sage-mist);
  transition: background-size .45s var(--io), color .3s ease, border-color .3s ease, transform .2s ease, box-shadow .2s ease; }
.btn-outline:hover { background-color: #fff; background-size: 100% 100%; border-color: var(--primary); color: #fff; }
.btn-outline:hover .ic { color: #fff; }
.btn-danger { background: #fff; color: #9B2C2C; border-color: #E2B4B4; }
.btn-danger:hover { background: #9B2C2C; color: #fff; }
.btn[disabled] { opacity: .55; cursor: not-allowed; transform: none; }
.btn-row { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 1.6rem; }

/* ---------- Invitation gate: an invitation card on white paper, the misty ridge low behind it ---------- */
.gate { position: fixed; inset: 0; z-index: 500; display: grid; padding: 1.25rem 1.25rem 4.25rem; overflow-y: auto; overscroll-behavior: contain;
  background: radial-gradient(ellipse 90% 55% at 50% 0%, var(--blush-wash) 0%, rgba(252, 243, 244, 0) 72%), #fff; }
.gate[hidden] { display: none; }
/* the highlands, very faint, along the foot of the screen (decorative) */
.gate-scene { position: absolute; left: 0; right: 0; bottom: 0; height: min(30vh, 260px); min-height: 150px; z-index: 0; pointer-events: none; overflow: hidden; opacity: 0; }
html.ww-deco .gate-scene { opacity: 1; transition: opacity 2s var(--out); }
.gate-scene .gs-ridge { position: absolute; left: 50%; bottom: 34%; width: max(1100px, 115vw); aspect-ratio: 1440 / 136; translate: -50% 0; color: var(--ink-mist); opacity: .55; }
.gate-scene .gs-ground { position: absolute; left: 50%; bottom: 0; width: max(1100px, 115vw); aspect-ratio: 1440 / 118; translate: -50% 0; color: var(--ink-sage); opacity: .24; }
html.ww-deco .gate-scene .gs-ridge { background: currentColor; -webkit-mask: url(../img/ornament/ridge.svg) center / 100% 100% no-repeat; mask: url(../img/ornament/ridge.svg) center / 100% 100% no-repeat; }
html.ww-deco .gate-scene .gs-ground { background: currentColor; -webkit-mask: url(../img/ornament/ground.svg) center / 100% 100% no-repeat; mask: url(../img/ornament/ground.svg) center / 100% 100% no-repeat; }
.gate-scene .gs-mist { position: absolute; left: -10%; right: -10%; bottom: 18%; height: 46%; background: radial-gradient(50% 50% at 50% 50%, rgba(255, 255, 255, .92), rgba(255, 255, 255, 0)); }
.gate-card { position: relative; z-index: 1; margin: auto; background: #fff; border: 1px solid var(--line); border-radius: 18px;
  box-shadow: inset 0 0 0 9px #fff, inset 0 0 0 10px rgba(185, 196, 189, .6), 0 1px 2px rgba(52, 62, 58, .05), 0 22px 54px -18px rgba(52, 62, 58, .22);
  padding: 2.9rem 2.2rem 3.4rem; max-width: 440px; width: 100%; text-align: center; display: flex; flex-direction: column; align-items: center; }
.gate-card > :not(.orn, .gate-seal) { position: relative; z-index: 1; }
.gate-card > .orn { inset: 16px; --cs: 62px; }
.gate-names { font-family: var(--font-script); font-size: 3.6rem; line-height: 1.1; color: var(--accent-text); margin: 0; }
.gate-date { font-family: var(--font-title); font-size: 1.15rem; color: var(--primary); margin: .3rem 0 .2rem; }
.gate-card .orule { --ow: 190px; margin: .5rem auto .3rem; }
.gate-card .label { text-align: center; }
/* codes can hold letters as well as digits (app.js makes the field a text field) */
.gate-input { text-align: center; font-size: 1.5rem; letter-spacing: .22em; max-width: 290px; font-weight: 600; font-variant-numeric: lining-nums tabular-nums; transition: border-color .3s ease, opacity .35s ease; }
.gate-card .label, .gate-card .btn { transition: opacity .35s ease; }
/* the message line is kept, so a message never moves the card; "opening" is a quiet italic, an error a deep rose */
.gate-card .form-msg { min-height: 3em; margin-top: .6rem; font-size: .92rem; line-height: 1.5; display: flex; align-items: center; justify-content: center; max-width: 330px; }
.gate-card .form-msg:not(.error) { font-family: var(--font-title); font-style: italic; font-weight: 400; font-size: 1rem; color: var(--accent-text); }
.gate-card .form-msg.error { color: #8C3A4C; }
.gate-card.is-wrong .gate-input { border-color: #C99AA6; }
/* the wax seal waits just below the card's foot: it hovers while the code is checked and is pressed when it
   opens (motion.css); the form rests meanwhile */
.gate-seal { position: absolute; z-index: 2; left: 50%; bottom: -54px; width: 108px; margin-left: -54px; aspect-ratio: 1; pointer-events: none;
  visibility: hidden; opacity: 0; transition: opacity .3s ease, visibility 0s linear .3s; }
.gate-seal img { display: block; width: 100%; height: 100%; rotate: -6deg; filter: drop-shadow(0 2px 2px rgba(110, 79, 94, .3)); }
.gate-card.is-pending .gate-seal { visibility: visible; opacity: 1; transition: opacity .45s ease; }
.gate-card.is-pending .gate-seal img { opacity: .6; scale: 1.12; rotate: -13deg; filter: drop-shadow(0 14px 12px rgba(110, 79, 94, .2)); }
.gate-card.is-pending .label, .gate-card.is-pending .gate-input, .gate-card.is-pending .btn { opacity: .42; }
body.locked { overflow: hidden; }

/* ---------- Header: the story's header is story.css (.hdr) ---------- */

/* ---------- Hero ---------- */
.hero { max-width: var(--maxw); margin: 0 auto; padding: 4.5rem 1.5rem 4rem; display: grid; grid-template-columns: 1.05fr 1fr; gap: 4rem; align-items: center; min-height: calc(100vh - 64px); }
.hero-names { font-family: var(--font-script); font-weight: 400; color: var(--accent-text); font-size: clamp(4rem, 9vw, 7.2rem); line-height: 1.05; margin: 0; }
.hero-names .amp { color: var(--blush); font-size: .7em; padding: 0 .08em; }
.hero-sub { font-family: var(--font-title); font-style: italic; font-size: 1.35rem; color: var(--ink-soft); margin: .3rem 0 0; }
.hero-date { font-family: var(--font-title); font-size: clamp(1.4rem, 2.6vw, 1.85rem); color: var(--primary); margin: 0 0 .4rem; }
.hero-venue { font-size: .98rem; color: var(--ink-soft); letter-spacing: .02em; }
.arch-wrap { position: relative; z-index: 1; width: 100%; max-width: 480px; border-radius: 260px 260px 18px 18px; box-shadow: 0 2px 4px rgba(52, 62, 58, .05), 0 30px 60px -28px rgba(52, 62, 58, .42); }
.arch.photo-slot { width: 100%; aspect-ratio: 4 / 5.6; border-radius: 260px 260px 18px 18px; }
.arch img { object-position: center 35%; }
/* a fine engraved frame line around the arch, with a star at its crown */
.arch-frame { position: absolute; inset: -13px; border: 1px solid rgba(142, 154, 146, .6); border-radius: 280px 280px 30px 30px; pointer-events: none; }
.arch-frame::before, .arch-frame::after { content: ""; position: absolute; left: 50%; top: 0; translate: -50% -50%; }
.arch-frame::before { width: 26px; height: 12px; background: #fff; }
.arch-frame::after { width: 15px; height: 15px; background: var(--ink-rose); -webkit-mask: var(--star) center / contain no-repeat; mask: var(--star) center / contain no-repeat; }
/* swallows: only drawn when motion is on (motion.css); two wing positions, one shown at a time */
.bird { display: none; position: absolute; left: 0; top: 0; width: 38px; color: var(--primary); }
.bird .bob { display: block; position: relative; aspect-ratio: 8 / 5; }
.bird .w1, .bird .w2 { position: absolute; inset: 0; }
html.ww-deco .bird .w1, html.ww-deco .bird .w2 { background: currentColor; }
html.ww-deco .bird .w1 { -webkit-mask: url(../img/ornament/swallow-1.svg) center / contain no-repeat; mask: url(../img/ornament/swallow-1.svg) center / contain no-repeat; }
html.ww-deco .bird .w2 { -webkit-mask: url(../img/ornament/swallow-2.svg) center / contain no-repeat; mask: url(../img/ornament/swallow-2.svg) center / contain no-repeat; opacity: 0; }

/* the countdown (app.js startCountdown; its columns are styled in s-invite.css) */
.countdown { display: flex; justify-content: center; gap: .7rem; margin-top: 1.8rem; flex-wrap: wrap; }
.cd-done { font-family: var(--font-script); font-size: 3.2rem; color: var(--accent-text); }

/* ---------- Photo slots ---------- */
.photo-slot { position: relative; width: 100%; background: var(--bg-soft); border-radius: var(--radius); overflow: hidden; }
.photo-slot img { width: 100%; height: 100%; object-fit: cover; object-position: center 30%; }
.photo-slot.empty::after { content: "Photo coming soon"; position: absolute; inset: 0; display: grid; place-items: center; font-family: var(--font-title); font-size: 1.1rem; font-style: italic; color: var(--accent-text); }
/* photographs printed into the paper, not laid on it: a fine grain, a soft pressed edge and a hairline bevel */
.photo-slot::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; border-radius: inherit; background: var(--grain);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22), inset 0 1px 3px rgba(40, 46, 43, .2), inset 0 0 44px rgba(40, 46, 43, .09); }
.photo-slot.empty::before { display: none; }

/* ---------- Sections / cards ---------- */
/* the colophon carries a whisper of the toile wallpaper (painted once the page has loaded and it is in view, see motion.js) */
html.ww-deco .site-footer.in::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; background: var(--ink-sage); opacity: .11;
  -webkit-mask: url(../img/ornament/toile-wall.webp) 50% 0 / 600px repeat, linear-gradient(transparent, #000 16%, #000 84%, transparent);
  -webkit-mask-composite: source-in;
  mask: url(../img/ornament/toile-wall.webp) 50% 0 / 600px repeat, linear-gradient(transparent, #000 16%, #000 84%, transparent);
  mask-composite: intersect; }
.card { background: #fff; border-radius: var(--radius); padding: 2.2rem; box-shadow: var(--shadow); border: 1px solid var(--line); }
.card + .card { margin-top: 1.5rem; }
.narrow-card { max-width: 440px; margin: 0 auto; }
/* the couple's dashboard keeps a plain heading (the story's chapters have their own heads, story.css) */
.page-banner { position: relative; overflow: hidden; text-align: center; padding: 4.5rem 1.5rem 5.2rem; background: radial-gradient(ellipse at top, var(--blush-wash) 0%, #FFFFFF 65%); border-bottom: 1px solid var(--line); }
.page-banner > * { position: relative; z-index: 1; }
.page-banner.slim { padding: 2.5rem 1.5rem 1.5rem; }
.page-banner h1 { margin-bottom: .3rem; }

/* ---------- Itinerary ---------- */
.tl-loc { display: flex; align-items: center; gap: .4rem; font-size: .88rem; color: var(--ink-soft); }

/* ---------- Gallery ---------- */
.lightbox { position: fixed; inset: 0; background: rgba(255,255,255,.97); z-index: 100; display: flex; align-items: center; justify-content: center; padding: 2rem; }
.lightbox[hidden] { display: none; }
.lightbox figure { margin: 0; max-width: 90vw; max-height: 88vh; text-align: center; }
.lightbox img { max-width: 90vw; max-height: 82vh; border-radius: 10px; margin: 0 auto; box-shadow: var(--shadow-lg); }
.lightbox figcaption { color: var(--ink-soft); margin-top: .8rem; font-family: var(--font-title); font-size: 1.1rem; }
.lb-close, .lb-nav { position: absolute; background: #fff; color: var(--primary); border: 1px solid var(--line); width: 50px; height: 50px; border-radius: 50%; font-size: 1.9rem; cursor: pointer; line-height: 1; box-shadow: var(--shadow); }
.lb-close { top: 1rem; right: 1rem; }
.lb-nav.prev { left: 1rem; } .lb-nav.next { right: 1rem; }
.lb-close:hover, .lb-nav:hover { background: var(--primary); color: #fff; }

/* ---------- FAQ ---------- */
.faq-list { display: flex; flex-direction: column; gap: .9rem; }
.faq-item { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.faq-item summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 1rem; padding: 1.1rem 1.4rem; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-q { flex: 1; font-family: var(--font-title); font-size: 1.2rem; color: var(--primary); }
.faq-item[open] summary { border-bottom: 1px solid var(--line); background: var(--bg-soft); }
.faq-a { padding: 1.1rem 1.4rem 1.3rem calc(1.4rem + 52px + 1rem); margin: 0; color: var(--ink-soft); }

/* ---------- Forms ---------- */
.label { display: block; font-weight: 600; margin: 1rem 0 .35rem; font-size: .93rem; }
.input, select.input, textarea.input { width: 100%; font: inherit; font-size: 1rem; padding: .75rem 1rem; border: 1px solid #DDD7D1; border-radius: var(--radius-sm); background: #fff; color: var(--ink); }
.input:focus { border-color: var(--primary); outline: none; box-shadow: 0 0 0 3px rgba(90,105,100,.15); }
textarea.input { min-height: 96px; resize: vertical; }
.form-msg { margin-top: .8rem; font-weight: 600; }
.form-msg.error { color: #9B2C2C; }
.notice { display: flex; align-items: center; gap: .7rem; border-radius: var(--radius-sm); padding: 1rem 1.2rem; margin-bottom: 1.5rem; font-weight: 500; }
.notice.warn { background: var(--blush-wash); border: 1px solid #F2D6DA; }
.notice.info { background: var(--sage-wash); border: 1px solid #E3E9E5; }

/* RSVP steps */
.step-nav { display: flex; flex-wrap: wrap; gap: .8rem; justify-content: space-between; margin-top: 1.8rem; padding-top: 1.4rem; border-top: 1px solid var(--line); }

/* ---------- Admin ---------- */
.admin-top { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem; margin-bottom: 1.5rem; }
.admin-tabs { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: 1.5rem; border-bottom: 1px solid var(--line); padding-bottom: .8rem; }
.admin-tab { background: none; border: 0; font: inherit; font-weight: 600; padding: .5rem 1rem; border-radius: 999px; cursor: pointer; color: var(--ink); }
.admin-tab[aria-selected="true"] { background: var(--primary); color: #fff; }
.save-bar { position: sticky; bottom: 0; background: rgba(255,255,255,.97); border-top: 1px solid var(--line); padding: 1rem; margin: 2rem -2.2rem -2.2rem; display: flex; gap: .8rem; justify-content: flex-end; align-items: center; border-radius: 0 0 var(--radius) var(--radius); flex-wrap: wrap; }
.save-bar .dirty { margin-right: auto; font-weight: 600; color: var(--accent-text); font-size: .9rem; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.2rem; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 1.2rem; }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0 1rem; }
.edit-block { border: 1px solid var(--line); border-radius: var(--radius); padding: 1.3rem; margin-top: 1.2rem; background: var(--bg-soft); }
.edit-block h3 { margin: 0; }
.edit-row { background: #fff; border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 1rem; margin-top: .9rem; }
.edit-row-head { display: flex; justify-content: space-between; align-items: center; gap: .5rem; flex-wrap: wrap; }
.icon-btns { display: flex; gap: .3rem; }
.icon-btn { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: .3rem .6rem; cursor: pointer; font: inherit; font-size: .85rem; }
.icon-btn:hover { background: var(--sage-wash); }
.icon-btn.del:hover { background: #F8DADA; }
.inline-check { display: flex; align-items: center; gap: .5rem; margin-top: 1rem; font-weight: 600; font-size: .93rem; }
.inline-check input { width: 18px; height: 18px; accent-color: var(--primary); }
.photo-edit { display: grid; grid-template-columns: 120px 1fr; gap: 1rem; align-items: start; }
.photo-thumb { width: 120px; height: 120px; border-radius: 12px; object-fit: cover; background: var(--bg-soft); }
.thumb-row { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: .6rem; }
.thumb-item { position: relative; width: 110px; }
.thumb-item img { width: 110px; height: 80px; object-fit: cover; border-radius: 10px; background: var(--bg-soft); }
.thumb-item .icon-btn { margin-top: .3rem; width: 100%; }
.file-btn { position: relative; overflow: hidden; }
.file-btn input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
.stat { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 1.2rem; text-align: center; }
.stat b { display: block; font-family: var(--font-title); font-size: 2.2rem; color: var(--primary); line-height: 1.1; font-weight: 500; }
.stat span { font-size: .84rem; font-weight: 600; color: var(--ink-soft); }
.stat.rose b { color: var(--accent-text); }
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius-sm); }
table.data { width: 100%; border-collapse: collapse; font-size: .88rem; background: #fff; }
table.data th, table.data td { padding: .6rem .8rem; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
table.data th { background: var(--bg-soft); font-weight: 700; white-space: nowrap; }
.status { display: inline-block; padding: .15rem .6rem; border-radius: 999px; font-size: .76rem; font-weight: 700; }
.status.yes { background: #E7EDE9; color: #3E4D48; }
.status.no { background: #F6E6EA; color: #6E4F5E; }
.bar { height: 8px; background: var(--bg-soft); border-radius: 999px; overflow: hidden; margin-top: .3rem; }
.bar i { display: block; height: 100%; background: var(--sage); border-radius: 999px; }
.event-stat { padding: .7rem 0; border-bottom: 1px solid var(--line); }
.event-stat div:first-child { display: flex; justify-content: space-between; font-weight: 600; gap: 1rem; }
.menu-count h4 { font-family: var(--font-body); font-size: .74rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--accent-text); margin: 1rem 0 0; }

/* ---------- Footer / toast ---------- */
.site-footer { position: relative; isolation: isolate; text-align: center; padding: 3.5rem 1.5rem; background: var(--bg-soft); color: var(--ink-soft); border-top: 1px solid var(--line); }
.site-footer p { margin: .2rem 0; }
.site-footer .orule { --ow: 170px; margin: .2rem auto .7rem; }
.footer-names { font-family: var(--font-script); font-size: 3rem; color: var(--accent-text); line-height: 1.2; }
.site-footer a { color: var(--primary); }
.toast { position: fixed; left: 50%; bottom: 1.5rem; transform: translate(-50%, 150%); background: var(--ink); color: #fff; padding: .8rem 1.4rem; border-radius: 999px; font-weight: 600; z-index: 600; transition: transform .3s ease; box-shadow: var(--shadow-lg); max-width: 90vw; text-align: center; visibility: hidden; }
.toast.show { transform: translate(-50%, 0); visibility: visible; }
/* above an open modal dialog app.js hosts it inside that dialog: it keeps its own box there (no part of the sheet's column) */
dialog > .toast { flex: none; width: auto; max-width: 90vw; margin: 0; }
/* a toast has nothing to tap: a tap meant for what it covers (a sheet's foot, the save bar) goes through */
.toast { pointer-events: none; }

/* all motion lives in motion.css (inside prefers-reduced-motion: no-preference); with reduced motion every
   element simply rests in its final state */
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }

/* ---------- Responsive ---------- */
@media (max-width: 1100px) {
  .stats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 860px) {
  .hero { grid-template-columns: 1fr; gap: 2.5rem; padding: 2.5rem 1.25rem 3rem; min-height: 0; }
  .arch-wrap { max-width: 330px; }
}
@media (max-width: 800px) {
  body { font-size: 16px; }
  .section { padding: 3.5rem 1rem; }
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .card { padding: 1.4rem; }
  .save-bar { margin: 1.5rem -1.4rem -1.4rem; }
  .photo-edit { grid-template-columns: 1fr; }
  .faq-a { padding-left: 1.4rem; }
}
@media print {
  .site-footer, .hero-cta, .btn, .gate { display: none !important; }
}
/* ---- w/css/motion.css ---- */
/* =====================================================================
   THE SMITH WEDDING · MOTION
   Chappl's ink-and-paper motion language, inked in the Misty Highlands palette.

   Rules of the house
   - Everything here sits inside `screen and (prefers-reduced-motion: no-preference)`: with reduced motion
     (and in print) nothing is hidden and nothing moves; every element rests in its final state.
   - Hidden first frames only apply under html.ww-js (set by w/js/motion.js before first paint), so a page
     without JavaScript is simply there, finished.
   - Only transform / translate / scale / rotate, opacity, filter, clip-path, mask-position and
     stroke-dashoffset animate: nothing here moves layout, so nothing here can cause a layout shift.
   - Words are never kept waiting (they rise within ~1 s); only the art takes its time (the pen, the ink,
     the seal). Nothing blocks reading or input.

   Hooks (classes set by motion.js, story.js)
   html.ww-js          JavaScript is running (first frames may be hidden)
   html.ww-hold        app.js has not shown the story yet, or the gate is up: the chapters are laid out but not
                       shown (style.css) and the home intro waits on its first frame
   html.ww-intro-done  the home intro has played once this visit (or the visit began further down the story)
   html.ww-deco        the page has loaded: the toile (landscapes, swallows, wallpaper) may paint
   .rv / .rv-ink / .rvg  scroll-reveal targets (rise, ink a photograph in, reveal a group); .in = revealed
   .ch-head.rvg.in     a chapter head plays its choreography (on reveal, or on arrival from a jump)
   .ch-knot.is-pulse   a jump has landed on this chapter: its knot pulses once
   [data-ambient].is-off  an ambient loop is off screen or the tab is hidden: it rests
   .arch.photo-slot.inked  the hero photograph is decoded and may be inked into the page
   .gate-card.is-pending / .is-wrong  the server is checking the code / the code was not right
   .gate-ghost         a copy of the gate, playing the exit once the gate has opened
   ===================================================================== */

@property --arc { syntax: '<angle>'; inherits: false; initial-value: 180deg; }

@media screen and (prefers-reduced-motion: no-preference) {

  /* ------------------------------------------------------------------ keyframes */
  @keyframes fade { from { opacity: 0; } }
  @keyframes fade-out { to { opacity: 0; } }
  @keyframes rise { from { opacity: 0; translate: 0 var(--rise, 18px); } }
  @keyframes draw { from { stroke-dashoffset: 1.02; } }
  /* the monogram (.lg): the pen along a part's line, the ink that takes over, the stars and the passing light */
  @keyframes lg-write { from { stroke-dashoffset: 1.08; } }
  @keyframes lg-pen { from { opacity: 0; } }
  @keyframes lg-twinkle { 0% { opacity: 0; transform: scale(.2) rotate(-45deg); } 9% { opacity: 1; transform: none; } 20%, 100% { opacity: 0; transform: scale(.2) rotate(45deg); } }
  @keyframes lg-shine { 0% { opacity: .62; -webkit-mask-position: 100% 0; mask-position: 100% 0; } 17% { opacity: .62; -webkit-mask-position: 0 0; mask-position: 0 0; } 17.01%, 100% { opacity: 0; -webkit-mask-position: 0 0; mask-position: 0 0; } }
  @keyframes lg-twinkle-1 { 0% { opacity: 0; transform: scale(.2) rotate(-45deg); } 45% { opacity: 1; transform: none; } 100% { opacity: 0; transform: scale(.2) rotate(45deg); } }
  @keyframes lg-shine-1 { from { opacity: .62; -webkit-mask-position: 100% 0; mask-position: 100% 0; } to { opacity: .62; -webkit-mask-position: 0 0; mask-position: 0 0; } }
  /* an engraved rule opens from its star outward */
  @keyframes rule-in { from { clip-path: inset(0 50% 0 50%); opacity: .3; } }
  /* a ridge (or any wide plate) opens out from the middle */
  @keyframes spread { from { clip-path: inset(0 50% 0 50%); opacity: .25; } }
  /* script lettering soaks in like ink: a soft wash sweeps left to right as the line comes into focus */
  @keyframes ink-write {
    0% { -webkit-mask-image: linear-gradient(100deg, #000 40%, transparent 60%); mask-image: linear-gradient(100deg, #000 40%, transparent 60%);
         -webkit-mask-size: 300% 100%; mask-size: 300% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 100% 0; mask-position: 100% 0; opacity: 0; filter: blur(6px); translate: 0 .18em; }
    55% { filter: blur(1.2px); opacity: 1; }
    100% { -webkit-mask-image: linear-gradient(100deg, #000 40%, transparent 60%); mask-image: linear-gradient(100deg, #000 40%, transparent 60%);
         -webkit-mask-size: 300% 100%; mask-size: 300% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 0 0; mask-position: 0 0; opacity: 1; filter: blur(0); translate: 0 0; }
  }
  /* a photograph is printed into the paper: the ink rises through it from the foot as it comes into focus */
  @keyframes print-in {
    0% { -webkit-mask-image: linear-gradient(0deg, #000 40%, transparent 60%); mask-image: linear-gradient(0deg, #000 40%, transparent 60%);
         -webkit-mask-size: 100% 300%; mask-size: 100% 300%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 0 0; mask-position: 0 0; filter: blur(8px) saturate(.6); scale: 1.025; }
    60% { filter: blur(1px) saturate(.9); }
    100% { -webkit-mask-image: linear-gradient(0deg, #000 40%, transparent 60%); mask-image: linear-gradient(0deg, #000 40%, transparent 60%);
         -webkit-mask-size: 100% 300%; mask-size: 100% 300%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 0 100%; mask-position: 0 100%; filter: blur(0) saturate(1); scale: 1; }
  }
  /* the frame around the arch is drawn up both sides from its foot and meets at the crown */
  @keyframes arc-draw { from { --arc: 0deg; } }
  /* a wax seal pressed into the paper: from where it hovered it comes down, turning, its lifted shadow tightens
     and goes on contact (the start matches the hover pose of .is-pending in style.css) */
  @keyframes press {
    0% { opacity: .6; scale: 1.12; rotate: -13deg; filter: drop-shadow(0 14px 12px rgba(110, 79, 94, .2)); }
    45% { opacity: 1; scale: 1.06; }
    100% { opacity: 1; scale: 1; rotate: -6deg; translate: 0 0; filter: drop-shadow(0 2px 2px rgba(110, 79, 94, .3)); } }
  @keyframes seal-breathe { from { scale: 1.12; opacity: .5; } to { scale: 1.075; opacity: .72; } }
  @keyframes press-shadow { 0% { opacity: 0; transform: translate(12%, 16%) scale(1.22); } 38% { opacity: 1; transform: translate(7%, 9%) scale(1.1); } 100% { opacity: 0; transform: none; } }
  @keyframes card-out { to { opacity: 0; translate: 0 -18px; scale: .985; } }
  @keyframes nudge { 15% { translate: -7px 0; } 30% { translate: 6px 0; } 45% { translate: -4px 0; } 60% { translate: 3px 0; } 75% { translate: -1px 0; } }
  /* the thread is drawn down into a chapter's knot; a knot pulses when a jump lands on its chapter */
  @keyframes thread-in { from { scale: 1 0; } }
  /* ambient: the mist drifts, swallows glide with their wings beating */
  @keyframes mist { from { translate: -5% 0; } to { translate: 5% 0; } }
  @keyframes fly-x { from { transform: translateX(-70px); } to { transform: translateX(calc(100cqw + 70px)); } }
  @keyframes fly-x-back { from { transform: translateX(calc(100cqw + 70px)); } to { transform: translateX(-70px); } }
  @keyframes fly-y-low { 0% { transform: translateY(0) rotate(0deg); } 25% { transform: translateY(-9px) rotate(2deg); } 50% { transform: translateY(4px) rotate(-3deg); } 75% { transform: translateY(-5px) rotate(2deg); } 100% { transform: translateY(0) rotate(0deg); } }
  @keyframes beat-up { 0%, 49.9% { opacity: 1; } 50%, 100% { opacity: 0; } }
  @keyframes beat-down { 0%, 49.9% { opacity: 0; } 50%, 100% { opacity: 1; } }

  /* ------------------------------------------------------------------ the swallows (drawn only with motion) */
  html.ww-js .bird { display: block; will-change: transform; }
  .bird .w1 { animation: beat-up .46s linear infinite both; }
  .bird .w2 { animation: beat-down .46s linear infinite both; }

  /* the toile wallpaper whispers in once the page has loaded */
  html.ww-deco .site-footer::before { animation: fade 1600ms var(--out) backwards; }

  /* ------------------------------------------------------------------ scroll reveals (classes from motion.js) */
  html.ww-js .rv:not(.in) { opacity: 0; translate: 0 var(--rise, 14px); }
  html.ww-js .rv.in { transition: opacity 800ms var(--out) var(--d, 0ms), translate 900ms var(--out) var(--d, 0ms); }
  html.ww-js .rv-ink:not(.in) { opacity: 0; }
  html.ww-js .rv-ink.in { animation: print-in 1500ms cubic-bezier(.33, 0, .2, 1) var(--d, 0ms) backwards; }
  /* a group plays its own choreography when it comes into view (the footer) */
  html.ww-js .rvg:not(.in) *, html.ww-js .rvg:not(.in) *::before, html.ww-js .rvg:not(.in) *::after { animation-play-state: paused !important; }
  html.ww-js .site-footer.rvg .lg-all { animation: fade 1200ms var(--out) 200ms backwards; }
  html.ww-js .site-footer.rvg .lg-star--a { animation: lg-twinkle-1 1500ms var(--io) 1500ms 1 backwards; }
  html.ww-js .site-footer.rvg .lg-star--b { animation: lg-twinkle-1 1500ms var(--io) 2200ms 1 backwards; }
  html.ww-js .site-footer.rvg .lg-star--c { animation: lg-twinkle-1 1500ms var(--io) 2900ms 1 backwards; }
  @supports ((-webkit-mask-image: linear-gradient(#000, #000)) or (mask-image: linear-gradient(#000, #000))) {
    html.ww-js .site-footer.rvg .lg-shine { -webkit-mask: linear-gradient(105deg, transparent 43%, #000 50%, transparent 57%) 100% 0 / 300% 100% no-repeat; mask: linear-gradient(105deg, transparent 43%, #000 50%, transparent 57%) 100% 0 / 300% 100% no-repeat;
      animation: lg-shine-1 1600ms var(--io) 1400ms 1 backwards; }
  }
  html.ww-js .site-footer.rvg .orule { animation: rule-in 1100ms var(--io) 500ms backwards; }
  html.ww-js .site-footer.rvg .footer-names { padding: .1em .3em; margin: -.1em -.3em; animation: ink-write 1500ms cubic-bezier(.33, 0, .2, 1) 650ms backwards; }
  html.ww-js .site-footer.rvg .footer-names ~ p { animation: fade 900ms var(--out) 1000ms backwards; }

  /* ------------------------------------------------------------------ the chapters (the frame in index.html) */
  /* a chapter head ([data-rv="group"]) plays as it is revealed, or as a jump lands on it: the pen draws the knot's
     circle from the top, where the thread comes in, the numeral fades in, then the eyebrow, the title and the answer
     line rise in turn (until then the .rvg rule above holds each part on its first frame) */
  html.ww-js .ch-head.rvg .ch-knot circle { stroke-dasharray: 1 2; transform-box: fill-box; transform-origin: center; rotate: -90deg; animation: draw 700ms var(--pen) backwards; }
  html.ww-js .ch-head.rvg .ch-knot i { animation: fade 400ms var(--out) 200ms backwards; }
  html.ww-js .ch-head.rvg .ch-eyebrow { animation: rise 700ms var(--out) 100ms backwards; --rise: 10px; }
  html.ww-js .ch-head.rvg .ch-title { animation: rise 800ms var(--out) 160ms backwards; --rise: 14px; }
  html.ww-js .ch-head.rvg .ch-lede { animation: rise 800ms var(--out) 240ms backwards; --rise: 10px; }

  /* ------------------------------------------------------------------ ambient loops rest off screen (motion.js) */
  [data-ambient].is-off, [data-ambient].is-off::before, [data-ambient].is-off::after,
  [data-ambient].is-off *, [data-ambient].is-off *::before, [data-ambient].is-off *::after { animation-play-state: paused !important; }

  /* ------------------------------------------------------------------ the scroll-linked thread (where supported) */
  @supports (animation-timeline: view()) {
    /* the thread is drawn down into each chapter's knot as the chapter comes up the screen (it sits outside the
       head's .rvg group: a paused group would freeze the scrub). Without scroll timelines it is simply drawn. */
    .ch-thread { transform-origin: 50% 0; animation: thread-in linear both; animation-timeline: view(); animation-range: entry 0% entry 100%; }
  }
}
/* ---- w/css/location.css ---- */
/* ================= THE SMITH WEDDING · LOCATION (maps, directions, getting there) =================
   1 The Venue's map: the tabs, the frame, a phone's picture of the map   2 Our Weekend (an event's place)
   3 Navigate ("Navigate to ...?")   4 Full-screen map   5 The map, restyled (site/s/css/map.css + the old map's
   markup, in Misty Highlands)   6 Google Maps (the gate from the road, "How far am I?", the satellite's credit)
   III's own blocks (the plates, the places, getting there, the drive) are vn- in s-venue.css.
   Section 5 is scoped to .loc-map (the frames the maps live in), so it out-ranks map.css (loaded with the
   first map) without !important and never reaches the old site (asetrix.site), which has no .loc-map. The type
   floor holds everywhere here, the old map's markup included: no text under 13px, no target under 44 x 44. */

:root { --loc-panel: clamp(340px, 30vw, 410px); }
.loc-ic { width: 1.1em; height: 1.1em; flex: none; display: inline-block; vertical-align: -0.15em; }

/* ---------- 1. The Venue's map (#map): the two maps' tabs, the frame ---------- */
.loc-sec__head { margin: 0 0 16px; }
.loc-sec__lede { margin: 6px 0 0; max-width: 34em; font-size: 16px; line-height: 1.55; color: var(--ink-soft); }
.loc-tabs { display: inline-flex; gap: 2px; padding: 4px; border-radius: 999px; background: var(--sage-wash); border: 1px solid #E3E9E5; }
.loc-tab {
  appearance: none; -webkit-appearance: none; border: 0; background: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 0 18px; border-radius: 999px;
  font: 600 15px/1.2 var(--font-body); letter-spacing: .01em; color: var(--primary); white-space: nowrap;
  transition: background-color .2s, color .2s, box-shadow .2s; -webkit-tap-highlight-color: transparent;
}
.loc-tab .loc-ic { width: 18px; height: 18px; }
.loc-tab:hover { color: var(--accent-text); }
.loc-tab[aria-selected="true"] { background: var(--primary); color: #fff; box-shadow: 0 6px 14px -8px rgba(46, 53, 50, .6); }
.loc-tab__short { display: none; }
/* III's tabs: a segmented control the column's width; the chosen tab's slate pill slides across (240ms) */
#locTabs { position: relative; isolation: isolate; display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
#locTabs::before {
  content: ""; position: absolute; z-index: -1; top: 4px; bottom: 4px; left: 4px; width: calc(50% - 4px); border-radius: 999px;
  background: var(--primary); box-shadow: 0 6px 14px -8px rgba(46, 53, 50, .6); pointer-events: none; transition: translate 240ms var(--io);
}
#locTabs[data-on="around"]::before { translate: 100% 0; }
#locTabs .loc-tab { padding: 0 10px; transition: color 240ms var(--io); }
#locTabs .loc-tab[aria-selected="true"] { background: none; box-shadow: none; }
@media (max-width: 419.98px) { #locTabs .loc-tab__long { display: none; } #locTabs .loc-tab__short { display: inline; } }
@media (max-width: 339.98px) { #locTabs .loc-ic { display: none; } }

/* the frame: 4:5 on a phone (never taller than the screen leaves), 16:10 on a wide screen, the screen's height on
   a phone held sideways */
.loc-frame {
  position: relative; isolation: isolate; overflow: hidden; overflow: clip;
  aspect-ratio: 4 / 5; min-height: 280px; max-height: calc(100vh - 176px); max-height: calc(100svh - 176px);
  border-radius: 16px; border: 1px solid var(--line); background: #F2EEE9; box-shadow: 0 22px 44px -34px rgba(46, 53, 50, .5);
}
@media (min-width: 900px) { .loc-frame { width: 100%; aspect-ratio: 16 / 10; min-height: 440px; max-height: 640px; } }
@media (orientation: landscape) and (max-height: 520px) {
  .loc-frame { aspect-ratio: auto; min-height: 260px; max-height: none; height: calc(100vh - var(--hdr) - 24px); height: calc(100svh - var(--hdr) - 24px); }
}
.loc-root { position: absolute; inset: 0; z-index: 1; }
/* The light picture before the map, where the map goes: the painting itself as its tiny blurred preview (the map's
   own LQIP, 1 KB: nothing is downloaded for it); beside the side panel on a wide screen */
.loc-ph { position: absolute; inset: 0; display: grid; place-items: center; background: radial-gradient(ellipse at 55% 45%, #F7F4F0 0%, #F2EEE9 72%); }
.loc-ph::before {
  content: ""; position: absolute; inset: 7% 5% 7% calc(var(--loc-panel) + 5%);
  background: url("data:image/webp;base64,UklGRu4CAABXRUJQVlA4WAoAAAAQAAAAJwAAJAAAQUxQSIQBAAABkEPbtqk9+9wb2+5s27ZtO6ls2yqT0pVtp7dtmxc7evi+oI6ICcB/qCitkkE0AIhKmAC6RNMygNaJEUkx4dxXml3lkFgRtZWkIz9u6SaSAI2B/OY8vSXZFzo2QdqbzvFX/9VdSgWJC6LP8nf0fJItARqraIIeZY5JdAqlUZ/+d9adUIIYlQYAnTLFHtpfvGUL6GiigNwdRpUF0IWOdMZxARQiik4BFJ19n/ywevCupyQtyXFQCC1aA8i75iPpDH/rLc/NqQMloRSANC3XPCaNJ7211jvPjekBhdCCLP3WXSFpPQMN7UQghUZohaqXSTrjGegtLzSCEoQXSXGO36xjSEuuy4oUiKpQ2jjPsJYvRgMakTVq0TOkN9xbEEoQXaEC6YO841aNFIhTkP2WcwGWfmlaaMSbAlP59XeWX9oBgpiVFLpL84vnxfpIIYhdUOAwDem4Nj00EqmQbj2t5escSIHEKmAmaR9kE0kQRKH3Mz7IhIQBGkUOjIBCEmokrRJJkn8rVlA4IEQBAAAwBwCdASooACUAPs1Wo0unpKMhqrquqPAZiUG3ILHe4XfLFYGGCZjO/ViJr4LzJRcmru5XToyvlIfQIE8VeNzfDsAA/vyl1H/HYQofgTiNvwJQOgZdXQ4T8usrXn26f4+eR3G7fmTfleWMfIPWWrb8gOrGPCcFLtiA1J9A2nXKL5OjtPJP4QUN929F8P//Bb0H6P6GSdb5Kn9LnM39Yi/pJxcXfZ0RdW7J5XI0/8ldTC4j75QAB68+m6N6oB82QOApLGXefpChXtsmhhJfb4z4UfM4ivkDKncx6yVeHh5UVj7gRkoae6OFiSZR2TKZrkLIpqDl64pF6itw+98jM3Gx/yW8b5+WesHMzH7CKSwEXccqFp9hAU8Uv6Jf//9puHjf/2+x/k7JoT9kh74Tf/+H9mh2wv3Eo8LIMrZ/83E8S+QQAAA=") center / contain no-repeat;
  filter: blur(6px) saturate(.85); opacity: .8;
}
.loc-frame.is-around .loc-ph::before { display: none; }
.loc-ph__label { position: relative; z-index: 1; padding: 8px 18px; border-radius: 999px; background: rgba(255, 255, 255, .94); box-shadow: var(--shadow); font: italic 400 16px/1.2 var(--font-title); color: var(--primary); }
.loc-frame.is-mounted .loc-ph { visibility: hidden; }
@media (min-width: 900px) and (pointer: fine), (min-width: 900px) and (pointer: none), (min-width: 1100.02px) {
  .loc-ph__label { margin-left: var(--loc-panel); }
}
.loc-fail { position: absolute; inset: 0; display: grid; place-content: center; gap: .9rem; padding: 2rem; text-align: center; background: #F2EEE9; color: var(--ink); }
.loc-fail p { margin: 0; max-width: 26rem; }
.loc-fail__act { display: flex; flex-wrap: wrap; justify-content: center; gap: .6rem; }

/* A phone's map (and a tablet's): the painted estate as a picture (estate.js forceStatic) on the frame's paper, the
   whole estate in view; only its pins are live: each opens its place's card, which rises from the frame's foot (it
   stays away until then). Nothing else floats over it but "Open the map" (s-venue.css), which brings the live map
   up full screen. Its credit is the line under the frame (.vn-credit). */
@media (max-width: 899.98px), (pointer: coarse) and (max-width: 1100px) {
  .loc-frame { container-type: size; }
  /* (the preview where the picture will be: the same geometry as .est-static__in below) */
  .loc-ph::before {
    inset: auto; left: 50%; top: calc(50cqh - 29px); translate: -50.5% -52.5%; aspect-ratio: 2048 / 1884;
    width: min((100cqw - 28px) / .75, (100cqh - 86px) * 2048 / 1884 / .71); background-size: 100% 100%;
  }
  .loc-ph__label { margin: 0 0 58px; }
}
@media (orientation: landscape) and (max-height: 520px) {
  .loc-ph::before { top: 50cqh; width: min((100cqw - 24px) / .75, (100cqh - 24px) * 2048 / 1884 / .71); }
  .loc-ph__label { margin: 0; }
}
.loc-frame .est.is-static .est-ctrls, .loc-frame .est.is-static .est-cartouche, .loc-frame .est.is-static .est-credit,
.loc-frame .est.is-static .est-flourish, .loc-frame .est.is-static .est-paper { display: none; }
/* only the key places (the big pins: location.js STATIC_PINS) stand on the picture */
.loc-frame .est.is-static .est-pin:not(.est-pin--l) { display: none; }
.loc-frame .est.is-static .est-static { container-type: size; padding: 0; overflow: hidden; }
/* The estate (75% x 71% of the painting, centred at 50.5% / 52.5%; the painting is estate.js's 2048 x 1884) as
   large as the frame holds it whole, above the room "Open the map" keeps at the foot; it prints in once it has come */
.loc-frame .est.is-static .est-static__in {
  position: absolute; left: 50%; top: calc(50cqh - 29px); translate: -50.5% -52.5%;
  width: min((100cqw - 28px) / .75, (100cqh - 86px) * 2048 / 1884 / .71);
  transition: opacity 400ms var(--out);
}
.loc-frame .est.is-static.is-printing .est-static__in { opacity: 0; }
/* the walk from the lodges to the Great Barn: a rose thread over the painting, drawn by the pen as the picture
   comes into view (location.js); it gives way to a chosen place's own route */
.loc-frame .loc-walk { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; transition: opacity 240ms var(--out); }
.loc-frame .loc-walk path { fill: none; stroke: var(--thread); stroke-width: 6; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 0; }
.loc-frame .est.is-focus .loc-walk { opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
  .loc-frame .loc-walk:not(.is-drawn) path { stroke-dashoffset: 1; }
  .loc-frame .loc-walk.is-drawn path { transition: stroke-dashoffset 1600ms var(--pen); }
}
.loc-frame .est.is-static .est-sheet { transition: opacity 320ms var(--out), translate 320ms var(--e-sheet), visibility 0s; }
.loc-frame .est.is-static .est-sheet.is-anim { transition: transform 360ms var(--e-sheet), opacity 320ms var(--out), translate 320ms var(--e-sheet), visibility 0s; }
.loc-frame .est.is-static:not(.is-focus) .est-sheet {
  visibility: hidden; opacity: 0; translate: 0 18px; pointer-events: none;
  transition: opacity 200ms var(--out), translate 200ms var(--out), visibility 0s linear 200ms;
}
/* In The Venue the page's own "Find your way" heads the map: the estate's panel does not say it again (it opens on
   "Take me there"); full screen, the panel's own head stays */
.loc-frame .est:not(.est--around) .est-head:not(.est-head--spot):not(.est-head--route) > :is(.est-title, .est-lede) { display: none; }
/* the card is short here (the frame is), so its actions show with the sheet half raised: no lede (the rows under
   the map say it), the two actions side by side */
.loc-frame .est.is-static .est-lede { display: none; }
.loc-frame .est.is-static .est-head--spot .est-title { margin-bottom: 0; }
.loc-frame .est.is-static .est-actions { flex-wrap: nowrap; margin-top: 8px; }
.loc-frame .est.is-static .est-actions .btn { flex: 1 1 auto; min-width: 0; padding-inline: 12px; font-size: 15px; white-space: nowrap; }
@media (max-width: 359.98px) { .loc-frame .est.is-static .est-actions .btn .ic { display: none; } }
/* a phone held sideways: the picture fills the frame's height; a chosen place's card is the side panel, the
   picture beside it */
@media (orientation: landscape) and (max-height: 520px) {
  .loc-frame .est.is-static .est-static__in { top: 50cqh; width: min((100cqw - 24px) / .75, (100cqh - 24px) * 2048 / 1884 / .71); }
  .loc-frame .est.is-static.is-focus .est-static__in { left: calc(50% + min(46vw, 360px) / 2); width: min((100cqw - min(46vw, 360px) - 24px) / .75, (100cqh - 24px) * 2048 / 1884 / .71); }
}

/* ---------- 2. Our Weekend: an event's place, the button that navigates there (s-weekend.css draws it under
   #weekend; here only its words for screen readers and its wait) ---------- */
.loc-vh { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.loc-place[aria-busy="true"] { opacity: .6; cursor: progress; }

/* ---------- 3. Navigate (a modal <dialog>: a bottom sheet on phones, a card from 640 px) ---------- */
.loc-dlg {
  width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0;
  background: transparent; color: var(--ink); font-family: var(--font-body); overflow: hidden;
}
.loc-dlg[open] { display: grid; align-items: end; justify-items: center; }
.loc-dlg::backdrop { background: rgba(46, 53, 50, .42); }
.loc-dlg__panel {
  position: relative; width: 100%; max-width: 560px; max-height: calc(100% - 24px); overflow: auto; overscroll-behavior: contain;
  padding: 8px 20px calc(20px + env(safe-area-inset-bottom)); border-radius: 22px 22px 0 0;
  background: #fff; box-shadow: 0 -12px 40px rgba(46, 53, 50, .18); animation: loc-up 320ms var(--e-sheet);
}
@keyframes loc-up { from { transform: translateY(28px); opacity: 0; } to { transform: none; opacity: 1; } }
.loc-dlg__grip { width: 44px; height: 5px; margin: 4px auto 14px; border-radius: 3px; background: var(--sage-mist); }
.loc-dlg__head { display: grid; grid-template-columns: auto 1fr auto; align-items: start; gap: 14px; }
.loc-dlg__badge { width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; background: var(--blush-wash); color: var(--accent-text); }
.loc-dlg__badge .loc-ic { width: 21px; height: 21px; }
.loc-dlg__titles { min-width: 0; }
.loc-dlg__title { margin: 2px 0 4px; font: 400 22px/1.22 var(--font-title); color: var(--primary); text-wrap: balance; }
.loc-dlg__title:focus { outline: none; }
.loc-dlg__sub { margin: 0; font-size: 15px; line-height: 1.45; color: var(--ink-soft); }
.loc-dlg__x {
  appearance: none; cursor: pointer; width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--line); background: #fff; color: var(--primary);
}
.loc-dlg__x:hover { background: var(--sage-wash); }
.loc-dlg__x .loc-ic { width: 18px; height: 18px; }
.loc-dlg__note { margin: 16px 0 0; padding: 12px 14px; border-radius: 12px; background: var(--sage-wash); border: 1px solid #E3E9E5; font-size: 15px; line-height: 1.5; color: var(--ink-soft); }
.loc-dir__list { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 8px; }
.loc-dir__opt {
  appearance: none; cursor: pointer; width: 100%; min-height: 60px; display: grid; grid-template-columns: 44px 1fr auto; align-items: center; gap: 14px;
  padding: 8px 14px 8px 8px; border-radius: 16px; border: 1px solid var(--line); background: #fff;
  color: var(--ink); text-decoration: none; text-align: left; font: 600 16px/1.25 var(--font-body);
  transition: border-color .2s, background-color .2s; -webkit-tap-highlight-color: transparent;
}
.loc-dir__opt:active { background: var(--blush-wash); }
.loc-dir__opt:hover { border-color: var(--sage-mist); background: var(--sage-wash); color: var(--ink); }
.loc-dir__ic { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; background: var(--sage-wash); color: var(--primary); transition: background-color .2s, color .2s; }
.loc-dir__ic .loc-ic { width: 20px; height: 20px; }
.loc-dir__t { min-width: 0; }
.loc-dir__t small { display: block; margin-top: 2px; font-size: 14px; line-height: 1.4; font-weight: 500; color: var(--ink-soft); overflow-wrap: anywhere; }
.loc-dir__go { width: 18px; height: 18px; color: var(--sage); }
.loc-dir__opt.is-done .loc-dir__ic { background: var(--primary); color: #fff; }
.loc-dir__opt.is-primary { border-color: var(--primary); background: var(--primary); color: #fff; }
.loc-dir__opt.is-primary small { color: rgba(255, 255, 255, .85); }
.loc-dir__opt.is-primary .loc-dir__ic { background: rgba(255, 255, 255, .16); color: #fff; }
.loc-dir__opt.is-primary .loc-dir__go { color: #fff; }
.loc-dir__opt.is-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: #fff; }
.loc-dir__opt--quiet { border-style: dashed; }
.loc-dir__group { margin: 18px 2px 8px; font-family: var(--font-body); font-size: 13px; font-weight: 600; letter-spacing: .18em; line-height: 1.4; text-transform: uppercase; color: var(--accent-text); }
.loc-dir__list + .loc-dir__group { margin-top: 20px; }
.loc-dir__status { min-height: 1.5em; margin: 12px 0 0; text-align: center; font-size: 15px; font-weight: 600; color: var(--primary); }
.loc-dlg__cancel {
  appearance: none; cursor: pointer; display: block; width: 100%; min-height: 48px; margin-top: 8px; border-radius: 999px;
  border: 1.5px solid var(--sage-mist); background: #fff; color: var(--primary); font: 600 16px/1.2 var(--font-body); letter-spacing: .02em;
}
.loc-dlg__cancel:hover { background: var(--sage-wash); }
.loc-dlg :focus-visible { outline: 3px solid var(--heather); outline-offset: 2px; }
@media (min-width: 640px) {
  .loc-dlg[open] { align-items: center; }
  .loc-dlg__panel { max-width: 460px; padding: 24px 24px 22px; border-radius: 22px; box-shadow: var(--shadow-lg); animation-name: loc-in; }
  .loc-dlg__grip { display: none; }
}
@keyframes loc-in { from { transform: translateY(10px) scale(.98); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---------- 4. Full-screen map (a modal <dialog>, above the header) ---------- */
html.loc-lock, html.loc-lock body { overflow: hidden; }
.loc-full {
  width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; overflow: hidden;
  background: #F2EEE9; color: var(--ink); font-family: var(--font-body);
}
.loc-full[open] { display: block; }
.loc-full::backdrop { background: rgba(46, 53, 50, .5); }
.loc-full__frame { position: absolute; inset: 0; }
.loc-full__bar { position: absolute; z-index: 20; top: 10px; left: 10px; display: flex; align-items: center; gap: 8px; pointer-events: none; }
.loc-full__bar > * { pointer-events: auto; }
.loc-full__close {
  appearance: none; cursor: pointer; width: 44px; height: 44px; flex: none; border-radius: 50%; display: grid; place-items: center;
  border: 0; background: #fff; color: var(--primary); box-shadow: 0 0 0 1px var(--line), 0 6px 18px -8px rgba(46, 53, 50, .45);
}
.loc-full__close:hover { color: var(--accent-text); }
.loc-full__close .loc-ic { width: 19px; height: 19px; }
.loc-tabs--float { padding: 0; gap: 0; background: rgba(255, 255, 255, .97); border: 0; box-shadow: 0 0 0 1px var(--line), 0 6px 18px -8px rgba(46, 53, 50, .45); }
/* 44 px to the touch; the chosen tab's pill is drawn 3 px inside it */
.loc-tabs--float .loc-tab { border: 3px solid transparent; background-clip: padding-box; padding: 0 16px; font-size: 15px; }
.loc-full :focus-visible { outline: 3px solid var(--heather); outline-offset: 2px; }
.loc-full .loc-expand { display: none; }
.loc-toast {
  position: absolute; z-index: 30; left: 50%; bottom: 1.2rem; transform: translate(-50%, 150%); visibility: hidden; max-width: min(90%, 30rem);
  margin: 0; padding: 12px 20px; border-radius: 999px; background: var(--ink); color: #fff; font-weight: 600; font-size: 15px; text-align: center;
  box-shadow: var(--shadow-lg); transition: transform .3s ease, visibility 0s .3s;
}
.loc-toast.show { transform: translate(-50%, 0); visibility: visible; transition: transform .3s ease; }
@media (min-width: 900px) {
  .loc-full__bar { top: 14px; left: calc(var(--loc-panel) + 14px); }
  .loc-full .est-cartouche { top: 72px; }
  .loc-full .est-arrive-btn { top: 196px; }
  .loc-full .est-arrive-btn.is-on, .loc-full .est.is-cart-off .est-arrive-btn, .loc-full .est.is-cart-clear .est-arrive-btn, .loc-full .est.is-sat .est-arrive-btn { top: 72px; }
}
@media (orientation: landscape) and (max-height: 520px) and (min-width: 640px) and (max-width: 899.98px) { .loc-full__bar { left: calc(min(46vw, 360px) + 10px); } }
@media (max-width: 559.98px) {
  .loc-full .loc-tab__long, .loc-full .loc-tab .loc-ic { display: none; }
  .loc-full .loc-tab__short { display: inline; }
  .loc-tabs--float .loc-tab { padding: 0 14px; }
}
/* the narrowest phones: the map's round buttons stand in a column at the right, clear of the tabs */
@media (max-width: 379.98px) { .loc-full .est-ctrls { flex-direction: column; } }
/* a phone held sideways: the inline map's column of round buttons has the full-screen button too, so "Watch the
   arrival" (a round button under them) moves down a step */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 640px) and (max-width: 899.98px) {
  .loc-frame .est-arrive-btn, .loc-frame .est-arrive-btn.is-on, .loc-frame .est.is-cart-off .est-arrive-btn,
  .loc-frame .est.is-cart-clear .est-arrive-btn, .loc-frame .est.is-sat .est-arrive-btn { top: 166px; }
}

/* ---------- 5. The map, restyled ---------- */
.loc-map [hidden] { display: none !important; }
.loc-map .est {
  --m-card: #fff; --m-heading: var(--primary); --m-text: var(--ink); --m-text-soft: var(--ink-soft); --m-ink-soft: var(--ink-soft);
  --m-thyme: var(--sage); --m-thyme-dark: var(--primary); --m-rose: var(--dusk-rose); --m-rose-dark: var(--accent-text);
  --m-fae: var(--sage-mist); --m-line: var(--line); --m-champ: var(--sage-wash); --m-grain: none;
  color: var(--ink); font-family: var(--font-body); line-height: 1.5;
}
.loc-map .ic { color: currentColor; }
/* the paper's grain and darkened edges belong to the letterpress site: here the painting sits on clean moonbone */
.loc-map .est-paper, .loc-map .est-flourish { display: none; }

/* cartouche: the estate's name on a white card */
.loc-map .est-cartouche {
  -webkit-mask: none; mask: none; filter: none; padding: .45rem 1.1rem .6rem; border-radius: 16px;
  background: rgba(255, 255, 255, .95); box-shadow: 0 0 0 1px var(--line), 0 10px 24px -14px rgba(46, 53, 50, .45);
}
.loc-map .est-cartouche::before { display: none; }
.loc-map .est-cartouche__sprig { color: var(--sage); --bot-accent: var(--dusk-rose); }
.loc-map .est-cartouche__name { color: var(--accent-text); text-shadow: none; font-size: 2.25rem; }
.loc-map .est-cartouche__sub { font: italic 400 14px/1.3 var(--font-title); letter-spacing: 0; text-transform: none; color: var(--ink-soft); }
@media (max-width: 899.98px) { .loc-map .est-cartouche__name { font-size: 2.05rem; } }
/* phones: the page says where the map is; the corner goes to the map's buttons and "Watch the arrival" */
@media (max-width: 767.98px) { .loc-map .est-cartouche { display: none; } }

/* round buttons and the Painted | Satellite switch: white, slate */
.loc-map .est-seg, .loc-map .est-zoom, .loc-map .est-ctrl { background: #fff; color: var(--primary); box-shadow: 0 0 0 1px var(--line), 0 6px 16px -8px rgba(46, 53, 50, .45); }
.loc-map .est-zoom .est-ctrl { background: transparent; box-shadow: none; }
.loc-map .est-zoom .est-ctrl + .est-ctrl { border-top-color: var(--line); }
.loc-map .est-seg button { min-height: 44px; padding: 0 16px; font: 600 14px/1 var(--font-body); color: var(--primary); }
.loc-map .est-seg button[aria-pressed="true"], .loc-map .est-ctrl--layers[aria-pressed="true"] { background: var(--primary); color: #fff; }
.loc-map .est-ctrl:hover, .loc-map .est-seg button:not([aria-pressed="true"]):hover { color: var(--accent-text); }
.loc-map .est-ctrls :focus-visible, .loc-map .est-pin:focus-visible, .loc-map .est-back:focus-visible, .loc-map .est-row:focus-visible,
.loc-map .est-swap:focus-visible, .loc-map .est-grip:focus-visible, .loc-map .est-thumb:focus-visible { outline: 3px solid var(--heather); outline-offset: 2px; }
.loc-map .est .maplibregl-ctrl-attrib { background: rgba(255, 255, 255, .9) !important; color: var(--ink-soft); font: 13px/1.45 var(--font-body); }
.loc-map .est .maplibregl-ctrl-attrib a, .loc-map .est-credit a { color: var(--ink-soft); }
.loc-map .est-credit { background: rgba(255, 255, 255, .92); color: var(--ink-soft); font: 13px/1.45 var(--font-body); }
.loc-map .maplibregl-cooperative-gesture-screen { background: rgba(46, 53, 50, .42); font: 600 1.05rem/1.4 var(--font-body); }

/* pins: slate seals ringed in white (heather when chosen), names on white pills */
.loc-map .est-pin { color: #fff; }
.loc-map .est-pin__seal { background: var(--primary); box-shadow: 0 0 0 2.5px #fff, 0 3px 9px rgba(46, 53, 50, .38); }
.loc-map .est-pin__seal .m-ic { filter: none; stroke-width: 1.7; }
.loc-map .est-pin.is-selected .est-pin__seal { background: var(--accent-text); box-shadow: 0 0 0 3px #fff, 0 0 0 6.5px rgba(240, 196, 203, .95), 0 5px 14px rgba(46, 53, 50, .38); }
.loc-map .est-pin__label {
  font: 500 15px/1.2 var(--font-title); letter-spacing: 0; color: var(--ink);
  padding: 4px 11px 5px; border-radius: 999px; background: rgba(255, 255, 255, .96);
  box-shadow: 0 0 0 1px rgba(90, 105, 100, .16), 0 4px 12px -4px rgba(46, 53, 50, .32);
}
.loc-map .est-pin--l .est-pin__label { font-size: 16px; }
.loc-map .est-pin--sub .est-pin__label { border-radius: 12px; padding-bottom: 6px; }
/* the second line (what happens there): Playfair italic at the type floor, never small caps under it */
.loc-map .est-pin__label small { margin-top: 1px; font: italic 400 13px/1.2 var(--font-title); letter-spacing: 0; text-transform: none; color: var(--accent-text); }
.loc-map .est-pin.is-selected .est-pin__label { color: var(--accent-text); }
/* the canapé lawn stands between the hall and the lodges: its name on one line ("The lawn  CANAPÉS") */
.loc-map .est-pin[data-spot="sporting-horse-lawn"] .est-pin__label { border-radius: 999px; padding-bottom: .31rem; }
.loc-map .est-pin[data-spot="sporting-horse-lawn"] .est-pin__label small { display: inline; margin: 0 0 0 .4em; }
.loc-map .est-pin__lead { background: var(--primary); box-shadow: 0 0 0 1.5px #fff; }
/* a callout standing below its host (the canapé lawn under the Great Barn): its leader runs up to the place */
.loc-map .est-pin.has-lead-up .est-pin__lead { top: auto; bottom: 50%; }
.loc-map .est-pin[data-more]:not([data-more=""])::after { min-width: 24px; height: 24px; padding: 0 6px; top: -4px; right: -6px; background: var(--accent-text); font: 700 13px/1 var(--font-body); box-shadow: 0 0 0 2px #fff, 0 2px 4px rgba(46, 53, 50, .3); }
.loc-map .est.is-sat .est-pin__label { background: #fff; }
.loc-map .around-pin .est-pin__seal { background: var(--primary); box-shadow: 0 0 0 2.5px #fff, 0 3px 9px rgba(46, 53, 50, .38); }
.loc-map .around-pin--home .est-pin__seal { background: var(--accent-text); }
.loc-map .around-pin--stay .est-pin__seal { background: #fff; color: var(--accent-text); box-shadow: 0 0 0 1.5px var(--dusk-rose), 0 0 0 3.5px #fff, 0 3px 8px rgba(46, 53, 50, .3); }
.loc-map .around-pin--poi .est-pin__seal { background: var(--sage); }
.loc-map .around-pin.is-selected .est-pin__seal { background: var(--accent-text); color: #fff; box-shadow: 0 0 0 3px #fff, 0 0 0 6.5px rgba(240, 196, 203, .95), 0 5px 14px rgba(46, 53, 50, .38); }
.loc-map .around-pin--home .est-pin__label { font-size: 17px; color: var(--accent-text); }
.loc-map .around-pin--stay .est-pin__label { font-size: 14px; }
.loc-map .around-pin--poi .est-pin__label { font-size: 14px; color: var(--primary); }
.loc-map .around-letter span { font-size: 13px; color: var(--accent-text); }
.loc-map .around-letter--town span { font: 600 13px/1.1 var(--font-body); letter-spacing: .18em; color: rgba(46, 53, 50, .62); }
.loc-map .around-leaders path { stroke: var(--primary); stroke-opacity: .5; }
.loc-map .around-leaders circle { fill: var(--accent-text); stroke: #fff; }
/* route marks */
.loc-map .est-walker span { background: #fff; color: var(--primary); box-shadow: 0 0 0 2.5px var(--dusk-rose), 0 3px 8px rgba(46, 53, 50, .35); }
.loc-map .est-start { background: #fff; box-shadow: 0 0 0 3px var(--primary), 0 2px 4px rgba(0, 0, 0, .3); }
.loc-map .est-you { background: var(--accent-text); box-shadow: 0 0 0 3px #fff, 0 2px 5px rgba(46, 53, 50, .45); }
.loc-map .est-you::after { border-color: rgba(126, 95, 110, .55); }

/* the sheet (phones) / side panel (wide screens): white */
.loc-map .est-sheet { background: #fff; border-radius: 22px 22px 0 0; box-shadow: 0 -1px 0 var(--line), 0 -14px 34px -16px rgba(46, 53, 50, .32); }
.loc-map .est-sheet::before { display: none; }
.loc-map .est-grip__bar { background: var(--sage-mist); }
.loc-map .est-peek__t { font-family: var(--font-title); font-weight: 400; color: var(--primary); }
.loc-map .est-peek__s { font-size: 14px; line-height: 1.35; color: var(--ink-soft); }
/* the sheet's handle is 44 px to the touch when the sheet is raised (its hit area reaches above the sheet's edge;
   the lowered strip is taller anyway) */
.loc-map .est-grip { position: relative; }
.loc-map .est-sheet:not([data-snap="peek"]) .est-grip::after { content: ""; position: absolute; left: 0; right: 0; top: -21px; height: 44px; }
@media (min-width: 900px) { .loc-map .est-sheet { border-radius: 0; box-shadow: 1px 0 0 var(--line), 14px 0 30px -24px rgba(46, 53, 50, .4); } }
@media (orientation: landscape) and (max-height: 520px) and (min-width: 640px) and (max-width: 899.98px) { .loc-map .est-sheet { border-radius: 0; box-shadow: 1px 0 0 var(--line), 14px 0 30px -24px rgba(46, 53, 50, .4); } }
.loc-map .est-title { font-family: var(--font-title); font-weight: 400; color: var(--primary); text-shadow: none; }
.loc-map .est-title__sub, .loc-map .est-row__sub { color: var(--accent-text); }
.loc-map .est-lede { color: var(--ink-soft); }
.loc-map .est-back { min-height: 44px; color: var(--accent-text); font: 600 15px/1 var(--font-body); border-radius: 999px; }
.loc-map .est-back:hover { background: var(--blush-wash); }
.loc-map .est-group { font-family: var(--font-body); font-size: 13px; font-weight: 600; letter-spacing: .18em; color: var(--accent-text); }
.loc-map .est-group::after { background: var(--line); }
.loc-map .est-list li + li { border-top-color: var(--line); }
.loc-map .est-row { border-radius: 12px; }
.loc-map .est-row:hover { background: var(--sage-wash); }
.loc-map .est-row__art { border-radius: 10px; background: var(--sage-wash); box-shadow: inset 0 0 0 1px #E3E9E5; }
.loc-map .est-row__art--photo { background: none; box-shadow: none; }
.loc-map .est-row__name { font-family: var(--font-title); color: var(--ink); }
.loc-map .est-row__when { font-size: 14px; color: var(--ink-soft); }
.loc-map .est-row__chev { color: var(--sage-mist); }
.loc-map .est-foot { border-top-color: var(--line); font-size: 14px; color: var(--ink-soft); }
.loc-map .est-foot .est-credits { font-size: 13px; line-height: 1.5; }
.loc-map .est-foot .btn--link { padding-left: 0; }
.loc-map .est-offline { font-family: var(--font-title); font-size: 15px; color: var(--primary); }

/* the old map's buttons in the site's own: slate pills, white outlines, quiet links */
.loc-map .btn { font-family: var(--font-body); letter-spacing: .02em; }
.loc-map .btn .ic { width: 1.1rem; height: 1.1rem; flex: none; }
.loc-map .btn--primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.loc-map .btn--primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: #fff; }
.loc-map .btn--ghost { background: #fff; border-color: var(--sage-mist); color: var(--primary); }
.loc-map .btn--ghost:hover { background: var(--primary); border-color: var(--primary); color: #fff; }
.loc-map .btn--link { background: none; border-color: transparent; color: var(--accent-text); padding-inline: .2rem; text-decoration: underline; text-decoration-color: var(--sage-mist); text-underline-offset: 3px; }
.loc-map .btn--link:hover { color: var(--primary); text-decoration-color: currentColor; }
.loc-map .btn--sm { min-height: 44px; padding: .5rem 1rem; font-size: 14px; }
.loc-map .btn--block { display: flex; width: 100%; }
.loc-map .chip {
  display: inline-flex; align-items: center; gap: .4rem; min-height: 44px; padding: 0 16px; border-radius: 999px;
  background: #fff; box-shadow: inset 0 0 0 1px var(--sage-mist); color: var(--primary); font: 600 14px/1.2 var(--font-body); text-decoration: none;
}
.loc-map .around-meta .chip { min-height: 44px; font-size: 14px; }
.loc-map .chip:hover { background: var(--sage-wash); }
.loc-map .chip .m-ic { width: 1rem; height: 1rem; }
.loc-map .chip--soft { background: var(--bg-soft); color: var(--ink-soft); }

/* a place's card */
.loc-map .plate { position: relative; margin: 0; }
.loc-map .plate__frame { display: block; overflow: hidden; border-radius: 14px; background: var(--bg-soft); }
.loc-map .plate__frame picture, .loc-map .plate__img { display: block; width: 100%; height: 100%; }
.loc-map .plate__img { object-fit: cover; }
.loc-map .plate--oval .plate__frame { border-radius: 50%; }
.loc-map .est-plate .plate__frame { aspect-ratio: 3 / 2; }
.loc-map .est-plate .plate__cap { margin-top: .3rem; text-align: center; font-family: var(--font-script); font-size: 2rem; line-height: 1.1; color: var(--accent-text); }
.loc-map .est-row__art--photo .plate { width: 50px; padding: 0; }
.loc-map .est-row__art--photo .plate__frame { aspect-ratio: 1; border-radius: 12px; }
.loc-map .est-thumb { border-radius: 12px; }
.loc-map .est-thumb .plate__frame { border-radius: 10px; }
.loc-map .est-thumb.is-on { box-shadow: 0 0 0 2px var(--primary); }
.loc-map .est-vignette { border-radius: 14px; background: var(--sage-wash); box-shadow: inset 0 0 0 1px #E3E9E5; }
.loc-map .est-vignette::before { display: none; }
.loc-map .vg .vg-l, .loc-map .vg .vg-h { stroke: var(--primary); }
.loc-map .vg .vg-a { stroke: var(--dusk-rose); }
.loc-map .vg .vg-w { fill: #fff; }
.loc-map .vg .vg-g { fill: var(--sage-mist); }
.loc-map .vg .vg-b, .loc-map .vg .vg-flag { fill: var(--blush); }
.loc-map .vg .vg-roof { fill: #E9DEE1; stroke: var(--primary); }
.loc-map .vg .vg-roof--g { fill: var(--sage-mist); }
.loc-map .vg .vg-horse { fill: var(--heather); }
.loc-map .vg .vg-fire { fill: var(--blush); stroke: var(--dusk-rose); }
.loc-map .vg .vg-water { fill: #D6E1DE; }
.loc-map .est-when__list li { border-bottom: 1px solid var(--line); }
.loc-map .est-when__day { font-size: 13px; font-weight: 600; letter-spacing: .14em; color: var(--accent-text); }
.loc-map .est-when__time { font-family: var(--font-title); color: var(--ink-soft); }
.loc-map .est-when__t { color: var(--ink); }
.loc-map .est-desc { color: var(--ink); }
.loc-map .est-note { border-radius: 12px; background: var(--sage-wash); box-shadow: inset 0 0 0 1px #E3E9E5; color: var(--ink-soft); }
.loc-map .est-note .m-ic { color: var(--accent-text); }
.loc-map .est-note--warn { background: var(--blush-wash); box-shadow: inset 0 0 0 1px #F2D6DA; color: var(--accent-text); }
.loc-map .est-small { font-size: 14px; color: var(--ink-soft); }
.loc-map .around-contact a { min-height: 44px; color: var(--accent-text); }
.loc-map .around-contact a:hover { color: var(--primary); }

/* "Take me there" */
.loc-map .est-sum__main { color: var(--ink-soft); }
.loc-map .est-sum__main b { font-family: var(--font-title); font-weight: 400; color: var(--primary); }
.loc-map .est-sum__dist { color: var(--primary); box-shadow: inset 0 0 0 1px var(--sage-mist); }
.loc-map .est-sum__hint { font-family: var(--font-title); color: var(--ink-soft); }
.loc-map .est-field label { font-family: var(--font-body); font-size: 13px; font-weight: 600; letter-spacing: .16em; color: var(--accent-text); }
.loc-map .est-field select {
  font-family: var(--font-body); color: var(--ink); border-radius: 10px; box-shadow: inset 0 0 0 1px #DDD7D1;
  background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 10l5 5 5-5' fill='none' stroke='%235A6964' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right .6rem center / 18px;
}
.loc-map .est-field select:focus-visible { outline: 3px solid var(--heather); outline-offset: 1px; }
.loc-map .est-swap { background: #fff; color: var(--primary); box-shadow: inset 0 0 0 1px var(--line); }
.loc-map .est-swap:hover { color: var(--accent-text); }
.loc-map .est-mode { background: var(--sage-wash); box-shadow: inset 0 0 0 1px #E3E9E5; }
.loc-map .est-mode span { min-height: 44px; font-family: var(--font-body); font-size: 15px; color: var(--primary); }
.loc-map .est-mode input:checked + span { background: var(--primary); color: #fff; }
.loc-map .est-mode input:focus-visible + span { outline: 3px solid var(--heather); }
.loc-map .est-loc { border-radius: 14px; background: var(--sage-wash); box-shadow: inset 0 0 0 1px #E3E9E5; }
.loc-map .est-steps::before { border-left-color: var(--dusk-rose); }
.loc-map .est-step::before { background: #fff; box-shadow: inset 0 0 0 2.5px var(--primary); }
.loc-map .est-step:first-child::before { background: var(--primary); }
.loc-map .est-step--arrive::before { background: var(--accent-text); box-shadow: 0 0 0 2px #fff, 0 0 0 3.5px var(--dusk-rose); }
.loc-map .est-step--arrive { color: var(--primary); }

/* the arrival flight */
.loc-map .est-arrive__cap { font-family: var(--font-title); background: rgba(255, 255, 255, .96); color: var(--primary); box-shadow: 0 0 0 1px var(--line), 0 10px 24px -12px rgba(46, 53, 50, .45); }
.loc-map .est-arrive-btn { min-height: 44px; font: 600 14px/1 var(--font-body); background: #fff; color: var(--primary); box-shadow: 0 0 0 1px var(--line), 0 6px 16px -8px rgba(46, 53, 50, .4); }
.loc-map .est-arrive-btn .m-ic { color: var(--accent-text); }
.loc-map .est-arrive-btn:hover { color: var(--accent-text); }
.loc-map .est-arrive-btn.is-on { background: var(--primary); color: #fff; }
.loc-map .est-arrive-btn.is-on .m-ic { color: #fff; }
.loc-map .est-arrive-btn:focus-visible { outline: 3px solid var(--heather); }
.loc-map .est-arrive-tag span { border-radius: 999px; background: rgba(255, 255, 255, .96); color: var(--primary); box-shadow: 0 0 0 1px var(--line), 0 6px 14px -8px rgba(46, 53, 50, .5); }
.loc-map .est-arrive-tag--key span { color: var(--accent-text); }
.loc-map .est-arrive-tag::after { background: var(--accent-text); box-shadow: 0 0 0 3px #fff; }

/* "Getting to Mistvale", at the top of each map's list */
.loc-map .loc-trip { margin: .2rem 0 .9rem; border-radius: 14px; background: var(--sage-wash); border: 1px solid #E3E9E5; }
.loc-map .loc-trip summary { list-style: none; cursor: pointer; display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: .75rem; min-height: 56px; padding: .6rem .85rem; border-radius: 14px; }
.loc-map .loc-trip summary::-webkit-details-marker { display: none; }
.loc-map .loc-trip summary:focus-visible { outline: 3px solid var(--heather); outline-offset: 2px; }
.loc-map .loc-trip__ic { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; background: #fff; color: var(--primary); box-shadow: inset 0 0 0 1px #E3E9E5; }
.loc-map .loc-trip__ic .loc-ic { width: 1.15rem; height: 1.15rem; }
.loc-map .loc-trip__t { display: grid; gap: .05rem; min-width: 0; }
.loc-map .loc-trip__h { font-family: var(--font-title); font-size: 17px; line-height: 1.25; color: var(--primary); }
.loc-map .loc-trip__l { font-size: 14px; line-height: 1.35; color: var(--ink-soft); }
.loc-map .loc-trip__chev { color: var(--sage); transition: transform .2s; }
.loc-map .loc-trip[open] .loc-trip__chev { transform: rotate(90deg); }
.loc-map .loc-trip__body { padding: 0 .9rem .95rem; font-size: 15px; line-height: 1.55; color: var(--ink); }
.loc-map .loc-trip__body p { margin: 0 0 .75rem; }
.loc-map .loc-trip__body .btn { gap: .45rem; }
.loc-map .loc-trip__body .loc-ic { width: 1.05rem; height: 1.05rem; }

@media (prefers-reduced-motion: reduce) {
  .loc-dlg__panel { animation: none; }
  .loc-tab, .loc-dir__opt, .loc-toast, #locTabs::before { transition: none; }
}
@media print { .loc-sec, .tl-where { display: none !important; } }

/* The map credits, quietly: "© OpenStreetMap" (and "© Esri" with the satellite on) + an (i) that unfolds the rest;
   both 44 px to the touch (the hit area reaches past the pill), the words at the type floor */
.loc-map .m-credits { position: relative; display: flex; align-items: center; gap: 8px; margin: 0 8px 8px 0; padding: 3px 4px 3px 12px;
  border-radius: 999px; background: rgba(255, 255, 255, .94);
  font: 500 13px/1.5 var(--font-body); letter-spacing: .01em; color: var(--ink-soft); box-shadow: 0 1px 4px rgba(46, 53, 50, .14); pointer-events: auto; }
.loc-map .m-credits a { color: inherit; text-decoration: none; }
.loc-map .m-credits a:hover, .loc-map .m-credits a:focus-visible { text-decoration: underline; }
.loc-map .m-credits__osm { position: relative; }
.loc-map .m-credits__osm::after { content: ""; position: absolute; top: -14px; bottom: -14px; left: -10px; right: -6px; }
.loc-map .m-credits__more { position: relative; width: 28px; height: 28px; border-radius: 50%; border: 1px solid rgba(98, 106, 102, .45); background: #fff; color: var(--ink-soft);
  font: italic 600 14px/1 var(--font-title); display: grid; place-items: center; cursor: pointer; padding: 0; }
.loc-map .m-credits__more::after { content: ""; position: absolute; top: -9px; bottom: -9px; left: -9px; right: -9px; border-radius: 50%; }
.loc-map .m-credits__more[aria-expanded="true"] { background: var(--primary); border-color: var(--primary); color: #fff; }
.loc-map .m-credits__all { position: absolute; right: 0; bottom: calc(100% + 10px); width: min(320px, calc(100vw - 48px)); max-height: 50vh; overflow: auto;
  padding: 12px 14px; border-radius: 12px; background: #fff; box-shadow: var(--shadow-lg); border: 1px solid var(--line);
  font: 400 13px/1.5 var(--font-body); color: var(--ink-soft); z-index: 5; }
.loc-map .m-credits__all p { margin: 0 0 6px; }
.loc-map .m-credits__all p:last-child { margin: 0; }
.loc-map .m-credits__all a { text-decoration: underline; }

/* ---------- 6. Google Maps (google.js): the gate from the road, "How far am I?", the satellite's credit, Around photos ---------- */
/* the main gate in Street View: a framed print (the picture keeps Google's own marks in its corners, never covered).
   Its box is there from the first paint and never goes: until the picture comes (and when there is none) the gate
   is drawn in the map's engraving */
.loc-gx { margin: 0 0 1.2rem; }
.loc-gx--dlg { margin: 16px 0 0; }
.loc-sv { margin: 0; }
.loc-sv__frame { position: relative; display: block; aspect-ratio: 16 / 9; overflow: hidden; border-radius: 12px; background: var(--sage-wash);
  box-shadow: 0 0 0 1px var(--line), 0 0 0 5px #fff, 0 0 0 6px var(--line), 0 14px 30px -18px rgba(46, 53, 50, .45); margin: 6px; }
.loc-sv__frame img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .45s ease; }
.loc-sv.is-ready .loc-sv__frame img { opacity: 1; }
.loc-sv__ph { position: absolute; inset: 10% 14%; display: grid; place-items: center; }
.loc-sv__ph .vg { width: 100%; height: 100%; animation: loc-fade .6s var(--out); }
.loc-sv .vg .vg-l, .loc-sv .vg .vg-h { fill: none; stroke: var(--primary); stroke-linecap: round; stroke-linejoin: round; }
.loc-sv .vg .vg-l { stroke-width: 1.5; }
.loc-sv .vg .vg-thin { stroke-width: 1; }
.loc-sv .vg .vg-h { stroke-width: .8; opacity: .7; }
.loc-sv .vg .vg-a { fill: none; stroke: var(--dusk-rose); stroke-width: 1.5; stroke-linecap: round; }
.loc-sv .vg .vg-w { fill: #fff; }
.loc-sv .vg .vg-g { fill: var(--sage-mist); opacity: .85; }
.loc-sv .vg .vg-b { fill: var(--blush); }
.loc-sv.is-ready .loc-sv__ph { visibility: hidden; }
.loc-sv__frame:focus-visible { outline: 3px solid var(--heather); outline-offset: 4px; }
.loc-sv__cap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 2px 16px; margin: 10px 6px 0; }
.loc-sv__t { font: italic 400 16px/1.35 var(--font-title); color: var(--primary); }
/* (Google's attribution: "Google Maps" in a sans at weight 400, 12 px or more) */
.loc-sv__t small { display: block; margin-top: 2px; font: normal 400 13px/1.5 Roboto, var(--font-body); letter-spacing: normal; color: #5E5E5E; }
.loc-sv__open { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; font-size: 15px; font-weight: 600; color: var(--accent-text); }
.loc-sv__open .loc-ic { width: 16px; height: 16px; }
.loc-sv__by[hidden], .loc-sv__open[hidden] { display: none; }
/* "How far am I?": the answer takes the hint's two lines (nothing below moves) */
.loc-far { display: grid; gap: 8px; }
.loc-far__go .loc-ic { width: 20px; height: 20px; }
.loc-far.is-busy .loc-far__go { cursor: progress; }
.loc-far__out { margin: 0; min-height: 3em; font-size: 15px; line-height: 1.5; color: var(--ink-soft); }
.loc-far__main { display: block; font-weight: 600; color: var(--primary); }
.loc-far__hint { display: block; }
.loc-far__meta { display: block; font: 400 13px/1.5 Roboto, var(--font-body); letter-spacing: normal; color: #5E5E5E; }
.loc-far--dlg .loc-far__out { padding: 0 6px; }
/* the satellite's credit (estate.js opts.satellite): "Google Maps" and the imagery's copyright, apart from OpenStreetMap's */
.loc-map .maplibregl-ctrl-bottom-right { max-width: 100%; }
.loc-map .m-credits { max-width: calc(100% - 8px); box-sizing: border-box; }
.loc-map .m-credits__osm, .loc-map .m-credits__more { flex: none; white-space: nowrap; }
.loc-map .m-credits__alt { display: inline-flex; align-items: baseline; gap: 5px; min-width: 0; overflow: hidden; padding-left: 6px; border-left: 1px solid rgba(98, 106, 102, .35); }
.loc-map .m-credits__alt[hidden] { display: none; }
.loc-map .m-credits__gm { font: 400 13px/1.5 Roboto, var(--font-body); letter-spacing: normal; color: #1F1F1F; white-space: nowrap; }
.loc-map .m-credits__cr { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.loc-map .est.is-sat .m-credits { background: rgba(255, 255, 255, .94); }
/* Around Mistvale: a place's photos (around.js opts.placePhotos) over its engraving, with their credits */
.loc-map .around-hp .plate__frame { position: relative; aspect-ratio: 3 / 2; display: grid; place-items: center; background: var(--sage-wash); box-shadow: inset 0 0 0 1px #E3E9E5; }
.loc-map .around-hp .plate__frame .vg { width: 62%; height: auto; }
.loc-map .around-hp.is-loading .plate__frame .vg { opacity: .55; }
.loc-map .around-hp__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; animation: loc-fade .45s ease; }
@keyframes loc-fade { from { opacity: 0; } to { opacity: 1; } }
.loc-map .around-hp__cap { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin-top: .4rem; font: 400 13px/1.5 Roboto, var(--font-body); letter-spacing: normal; color: #5E5E5E; }
.loc-map .around-hp__by { min-width: 0; }
.loc-map .around-hp__by a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.loc-map .around-hp__nav { display: inline-flex; align-items: center; gap: .25rem; flex: none; }
.loc-map .around-hp__n { min-width: 2.6em; text-align: center; }
.loc-map .around-hp__btn { width: 44px; height: 44px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--primary); cursor: pointer; }
.loc-map .around-hp__btn:hover { background: var(--sage-wash); }
.loc-map .around-hp__btn .m-ic { width: 18px; height: 18px; }
.loc-map .around-hp__btn:focus-visible { outline: 3px solid var(--heather); outline-offset: 1px; }
@media (prefers-reduced-motion: reduce) { .loc-sv__frame img { transition: none; } .loc-map .around-hp__img { animation: none; } }
/* ---- w/css/dress.css ---- */
/* ================= THE SMITH WEDDING · V WHAT TO WEAR (#dresscode, WP5) =================
   app.js renderDress() writes #dressCode:
   - .dc-looks    the lookbook comes first and opens on Saturday; the palette follows
   - .dc-palette  "Our palette": the swatch book (.dc-book), silk swatches grouped for the ladies, for the gents,
                  as accents, and white & ivory reserved for the bride. Nothing to tap or copy: every colour is
                  named and on the page at once. The swatches keep a four-across rhythm (--slot) on a white card;
                  larger screens get the same card, larger; from 1100px the book lies open (.dc-book--spread:
                  the ladies and the accents on the left page, the gents and the bride on the right).
   - .dc-looks    the looks: a chip for each day and the lookbook, a [data-snap] carousel of one plate per day
                  (story.js pages it: .is-current, "2 of 3", the arrows); the three side by side from 1100px.
                  A plate is a printed scene: the day in script, the highlands' ridge, the figures in the palette.
   Motion (prefers-reduced-motion: no-preference; each block is a [data-rv="group"], its parts held on their
   first frame until it is revealed): the rows rise; the swatches fan out of a stack, then the light glides over
   the silk once; the plates are printed in and the figures step on as their plate becomes the current one.
   With reduced motion or without JavaScript everything simply rests in its final state. Only opacity,
   transforms, filter and masks animate (no layout shift).
   ================================================================================= */

/* the light gliding over a silk swatch (animated once, see the end of the file) */
@property --dc-sx { syntax: '<percentage>'; inherits: false; initial-value: 34%; }

#dresscode .dc { --sw-gap: 10px; --dc-line: rgba(180, 138, 147, .24); }

/* ------------------------------------------------------------------ the weekend at a glance */

/* ------------------------------------------------------------------ the palette: the swatch book */
#dresscode .dc-palette { margin-top: 44px; }
#dresscode .dc-h { margin: 0; font: 400 24px/1.2 var(--font-title); color: var(--primary); }
#dresscode .dc-palette__sub { margin: 6px 0 0; font: italic 400 16px/1.55 var(--font-title); color: var(--ink-soft); text-wrap: pretty; }
/* a page of white stationery on the blush field, an engraved hairline inside its edge */
#dresscode .dc-book {
  --slot: calc((100cqw - 3 * var(--sw-gap)) / 4);   /* a swatch's width: four across the page */
  position: relative; container-type: inline-size; margin-top: 18px; padding: 26px 16px 24px; border-radius: 14px; background: #fff;
  box-shadow: inset 0 0 0 6px #fff, inset 0 0 0 7px rgba(180, 138, 147, .3), 0 1px 2px rgba(52, 62, 58, .05), 0 24px 44px -28px rgba(52, 62, 58, .32);
}
#dresscode .dc-book > .orn { inset: 11px; --cs: 30px; opacity: .4; }
#dresscode .dc-group { position: relative; z-index: 1; min-width: 0; text-align: center; }
#dresscode .dc-group + .dc-group, #dresscode .dc-pair { margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--line); }
#dresscode .dc-group__title { margin: 0 0 12px; font: 400 30px/1.15 var(--font-script); color: var(--accent-text); white-space: nowrap; }
#dresscode .dc-group__text { max-width: 30em; margin: 12px auto 0; font: italic 400 15px/1.5 var(--font-title); color: var(--ink-soft); text-wrap: balance; }
#dresscode .dc-sws {
  /* a group of one or two keeps wider gaps, so long names never touch */
  --sg: max(var(--sw-gap), calc((4 - var(--n, 4)) * 9px));
  /* --n swatches to a row (four at most); a group of five or more wraps, and its last row is centred like the
     first (five = three, then two): the list is only as wide as one row, so it breaks there */
  display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start;
  gap: 18px var(--sg); margin: 0 auto; padding: 0; list-style: none;
  max-width: calc(var(--n, 1) * var(--slot) + (var(--n, 1) - 1) * var(--sg) + 1px);
}
#dresscode .dc-sw { flex: 0 0 var(--slot); width: var(--slot); display: flex; flex-direction: column; align-items: center; gap: 8px; min-width: 0; }
/* the names may use the gap beside their swatch */
#dresscode .dc-sw__name { width: calc(100% + var(--sg, var(--sw-gap))); font: italic 400 15px/1.25 var(--font-title); color: var(--ink); text-align: center; }
/* accents and the bride share the last row, two swatch places each */
#dresscode .dc-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--sw-gap); align-items: start; }
#dresscode .dc-pair > .dc-group { margin: 0; padding: 0; border: 0; }
/* (its two swatches share half the page: they never wrap, they give a little instead) */
#dresscode .dc-pair .dc-sws { flex-wrap: nowrap; max-width: none; }
#dresscode .dc-pair .dc-sw { flex: 0 1 var(--slot); }
#dresscode .dc-pair > :only-child { grid-column: 1 / -1; }
#dresscode .dc-pair .dc-group__title { font-size: 26px; }

/* a swatch: an arch of silk with a pinked hem, lit from the upper left, with a fine weave, tone-on-tone stitching
   just inside its edge and a soft shadow on the page */
#dresscode .dc-sw__fab { position: relative; display: block; width: 100%; aspect-ratio: 3 / 4;
  filter: drop-shadow(0 10px 12px rgba(52, 62, 58, .1)) drop-shadow(0 2px 3px rgba(52, 62, 58, .1)); }
#dresscode .dc-sw__fab::before, #dresscode .dc-sw__fab::after { content: ""; position: absolute; border-radius: 999px 999px 0 0; pointer-events: none; }
#dresscode .dc-sw__fab::before { inset: 0;
  background:
    radial-gradient(120% 56% at 26% 12%, rgba(255, 255, 255, .44), rgba(255, 255, 255, 0) 64%),
    linear-gradient(102deg, rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, .26) 41%, rgba(255, 255, 255, 0) 50%, rgba(0, 0, 0, .05) 64%, rgba(0, 0, 0, .11) 82%, rgba(0, 0, 0, .04) 100%),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, .07) 0 1px, rgba(255, 255, 255, 0) 1px 3px),
    repeating-linear-gradient(0deg, rgba(0, 0, 0, .035) 0 1px, rgba(0, 0, 0, 0) 1px 3px),
    var(--c, #F2EEE9);
  background-size: 100% 100%, 260% 100%, auto, auto, auto;
  background-position: 0 0, var(--dc-sx) 0, 0 0, 0 0, 0 0;
  -webkit-mask: conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) 50% / 9px 100%;
  mask: conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) 50% / 9px 100%; }
#dresscode .dc-sw__fab::after { inset: 5px 5px 12px; border: 1px dashed rgba(40, 36, 34, .2); border-bottom: 0; mix-blend-mode: multiply; }
/* white & ivory: an empty swatch of ivory silk, kept for the bride */
#dresscode .dc-sw--bride .dc-sw__fab { filter: drop-shadow(0 10px 12px rgba(52, 62, 58, .07)) drop-shadow(0 0 .6px rgba(126, 95, 110, .55)); }
#dresscode .dc-sw--bride .dc-sw__fab::before { --c: #FFFDF8; }
#dresscode .dc-sw--bride .dc-sw__fab::after { border-color: rgba(126, 95, 110, .3); }
#dresscode .dc-sw__mark { position: absolute; inset: 0; z-index: 1; display: grid; place-items: center; padding-top: 14%;
  font: 400 min(20px, calc(var(--slot) * .27)) / 1 var(--font-script); color: var(--accent-text); }
#dresscode .dc-sw--bride .dc-sw__name { white-space: nowrap; }

/* ------------------------------------------------------------------ the looks */
#dresscode .dc-looks { margin-top: 4px; }
#dresscode .dc-looks__head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
#dresscode .dc-looks__t { margin: 0; font: 400 24px/1.2 var(--font-title); color: var(--primary); }
#dresscode .dc-chips { display: flex; gap: 8px; }
#dresscode .dc-chip { justify-content: center; gap: 0; min-width: 58px; padding-inline: 14px; transition: background-color 320ms var(--out), color 320ms var(--out); }
/* a phone says Fri, Sat, Sun (the rest of the word is not shown, nor read) */
#dresscode .dc-chip__more { display: none; }
@media (min-width: 600px) { #dresscode .dc-chip__more { display: inline; } }
/* the chip of the plate in front is filled */
#dresscode .dc-looks:has(#look-fri.is-current) .dc-chip[href="#look-fri"],
#dresscode .dc-looks:has(#look-sat.is-current) .dc-chip[href="#look-sat"],
#dresscode .dc-looks:has(#look-sun.is-current) .dc-chip[href="#look-sun"] { background: var(--primary); color: #fff; }
/* the lookbook: plates 88% wide, the next one peeking (the room above and below keeps the cards' shadows) */
/* (a jump to a look lands its plate where a chapter lands: the wrap's own top is the room above the cards) */
#dresscode .dc-lookwrap { min-width: 0; margin-top: 10px; scroll-margin-top: var(--hdr); }
#dresscode .dc-lookbook { padding-block: 8px 26px; }
#dresscode .dc-look {
  width: min(88%, 440px); display: flex; flex-direction: column; overflow: hidden; border-radius: 12px; background: #fff;
  box-shadow: 0 0 0 1px rgba(180, 138, 147, .14), 0 1px 2px rgba(52, 62, 58, .05), 0 18px 34px -22px rgba(52, 62, 58, .38);
}
#dresscode .dc-copy { flex: 1; padding: 18px 18px 22px; }
#dresscode .dc-eyebrow { margin: 0; font: 600 13px/1.4 var(--font-body); letter-spacing: .18em; text-transform: uppercase; color: var(--accent-text); }
#dresscode .dc-title { margin: 6px 0 0; font: 400 28px/1.15 var(--font-title); color: var(--primary); }
#dresscode .dc-when { margin: 4px 0 0; font: italic 400 16px/1.45 var(--font-title); color: var(--ink-soft); }
#dresscode .dc-text { margin: 14px 0 0; font-size: 16px; line-height: 1.6; color: var(--ink); }
#dresscode .dc-tip { margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line); font-size: 15px; line-height: 1.55; color: var(--ink-soft); }
#dresscode .dc-tip__label { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; font: 600 13px/1.4 var(--font-body); letter-spacing: .18em; text-transform: uppercase; color: var(--primary); }
#dresscode .dc-tip__label::before { content: ""; flex: none; width: 11px; height: 11px; background: var(--ink-rose); -webkit-mask: var(--star) center / contain no-repeat; mask: var(--star) center / contain no-repeat; }
/* the pager under the plates: ‹ 2 of 3 › */
#dresscode .dc-pager { display: flex; align-items: center; justify-content: center; gap: 14px; }
#dresscode .dc-pager [aria-disabled="true"] { opacity: .4; cursor: default; }

/* the plate: a printed scene in a fine frame; the day in script, the highlands' ridge behind, mist at its foot,
   and the figures standing on the ground line. Sized in container units, so it scales as one picture. */
#dresscode .dc-plate { position: relative; isolation: isolate; overflow: hidden; container-type: inline-size; aspect-ratio: 5 / 4;
  background: var(--dc-wash, #FFFFFF); outline: 1px solid rgba(180, 138, 147, .3); outline-offset: -12px; --fh: 64cqw; --foot: 7cqw; }
#dresscode .dc-plate::after { content: ""; position: absolute; z-index: 1; left: 7%; right: 7%; bottom: calc(var(--foot) - 1px); height: 2px; pointer-events: none;
  background: radial-gradient(closest-side, rgba(70, 83, 79, .2), rgba(70, 83, 79, 0)); }
#dresscode .dc-plate__script { position: absolute; z-index: 0; left: 0; right: 0; top: 4.5cqw; text-align: center; white-space: nowrap; pointer-events: none;
  font-family: var(--font-script); font-size: 19cqw; line-height: 1.2; color: var(--accent-text); opacity: .09; }
#dresscode .dc-plate__land { position: absolute; z-index: 0; left: -6%; right: -6%; bottom: var(--land, 24cqw); height: 12cqw; background: var(--ink-mist); opacity: .42;
  -webkit-mask: url(../img/ornament/ridge.svg) center / 100% 100% no-repeat, linear-gradient(#000 35%, transparent 96%); -webkit-mask-composite: source-in;
  mask: url(../img/ornament/ridge.svg) center / 100% 100% no-repeat, linear-gradient(#000 35%, transparent 96%); mask-composite: intersect; }
#dresscode .dc-figs { position: absolute; z-index: 2; left: 0; right: 0; bottom: var(--foot); display: flex; justify-content: center; align-items: flex-end; gap: var(--fg, 2.6cqw); }
#dresscode .dc-fig { position: relative; display: block; }
#dresscode .dc-fig svg { display: block; height: var(--fh); width: auto; margin-bottom: calc(var(--fh) * -.042); }
/* what each guest on the stage wears, in their order (a line steps closer to that guest) */
#dresscode .dc-wearsbox { margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line); }
#dresscode .dc-wears { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 14px; margin: 8px 0 0; padding: 0; list-style: none; counter-reset: dcw;
  font-size: 14.5px; line-height: 1.4; color: var(--ink); }
#dresscode .dc-wears[hidden] { display: none; }
#dresscode .dc-wears li { position: relative; min-width: 0; counter-increment: dcw; text-wrap: pretty; }
#dresscode .dc-wears button { display: block; width: 100%; min-height: 44px; padding: 0 0 0 27px; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
#dresscode .dc-wears button:hover { color: var(--accent-text); }
#dresscode .dc-wears button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 6px; }
#dresscode .dc-wears li::before { content: counter(dcw); position: absolute; left: 0; top: 12px; width: 20px; height: 20px; border-radius: 50%; pointer-events: none;
  background: var(--sage-wash); box-shadow: inset 0 0 0 1px rgba(142, 154, 146, .5); font: 600 13px/20px var(--font-body); text-align: center; color: var(--primary); }
#dresscode .dc-plate--fri { --dc-wash: radial-gradient(90% 72% at 50% 100%, #FBEAD6 0%, rgba(251, 234, 214, .5) 46%, #FFFDFA 82%); }
#dresscode .dc-plate--sun { --dc-wash: radial-gradient(90% 72% at 50% 100%, #E2EAE5 0%, rgba(226, 234, 229, .5) 46%, #FBFCFB 82%); }
/* Saturday: the palette itself, gowns and suits in turn; a phone shows four of them, larger */
#dresscode .dc-plate--sat { --fg: 1.6cqw; --dc-wash: radial-gradient(80% 95% at 50% 100%, #F8E3E6 0%, rgba(248, 227, 230, .45) 50%, #FFFCFC 84%); }
#dresscode .dc-plate--sat .dc-fig:nth-child(n+5) { display: none; }

/* ------------------------------------------------------------------ the smallest phones */
@media (max-width: 359px) {
  #dresscode .dc { --sw-gap: 8px; }
  #dresscode .dc-book { padding-inline: 12px; }
  #dresscode .dc-sw__name { font-size: 14px; }
  #dresscode .dc-group__title { font-size: 28px; }
  /* accents and the bride each get the row */
  #dresscode .dc-pair { grid-template-columns: minmax(0, 1fr); }
  #dresscode .dc-pair > .dc-group + .dc-group { margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--line); }
  #dresscode .dc-chip { min-width: 52px; padding-inline: 12px; }
}

/* ------------------------------------------------------------------ tablets and up */
@media (min-width: 600px) {
  #dresscode .dc { --sw-gap: 14px; }
  /* the swatch card, centred, its swatches as large as a hand's width */
  #dresscode .dc-book { --slot: min(100px, calc((100cqw - 3 * var(--sw-gap)) / 4)); max-width: 600px; margin-inline: auto; padding: 36px 32px 32px; }
  #dresscode .dc-book > .orn { inset: 13px; --cs: 40px; }
  #dresscode .dc-pair { column-gap: 28px; }
  #dresscode .dc-pair .dc-group__title { font-size: 30px; }
  #dresscode .dc-palette__head { text-align: center; }
  #dresscode .dc-palette__sub { max-width: 34em; margin-inline: auto; }
  #dresscode .dc-look { width: min(64%, 440px); }
  /* the three days side by side, parted by hairlines */
}
@media (min-width: 900px) {
  #dresscode .dc-palette { margin-top: 64px; }
  #dresscode .dc-book { max-width: 640px; padding: 40px 40px 36px; }
  #dresscode .dc-looks { margin-top: 8px; }
  #dresscode .dc-looks__t { font-size: 26px; }
}
/* from 1100px the three plates side by side: no carousel */
@media (min-width: 1100px) {
  #dresscode .dc-looks__head { max-width: calc(var(--wide) + 2 * var(--gut)); }
  #dresscode .dc-chips, #dresscode .dc-pager { display: none; }
  #dresscode .dc-lookbook {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; overflow: visible; scroll-snap-type: none;
    max-width: calc(var(--wide) + 2 * var(--gut)); margin-inline: auto;
  }
  #dresscode .dc-look { width: auto; }
  #dresscode .dc-plate--sat .dc-fig:nth-child(n+5) { display: block; }
  #dresscode .dc-plate--sat { --fh: 44cqw; --fg: 0cqw; }
  #dresscode .dc-plate--sat .dc-fig { margin-inline: -1.2cqw; }
  /* nothing to choose beside it: the lookbook's title sits on the page's centre axis, like the palette's */
  #dresscode .dc-looks__head { justify-content: center; }
  #dresscode .dc-lookwrap { margin-top: 14px; }

  /* the swatch book lies open, as wide as the lookbook: two pages about the page's centre axis, parted by the
     book's gutter; the ladies and the accents on the left page, the gents and the bride on the right (a book
     without one of the two keeps its single page) */
  #dresscode .dc-palette { margin-top: 80px; }
  #dresscode .dc-bookcol { max-width: calc(var(--wide) + 2 * var(--gut)); }
  #dresscode .dc-book { margin-top: 26px; }
  #dresscode .dc-book--spread {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 96px; align-items: start;
    max-width: none; padding: 48px 56px 44px;
  }
  #dresscode .dc-book--spread::before { content: ""; position: absolute; top: 48px; bottom: 44px; left: 50%; width: 1px; background: var(--line); }
  #dresscode .dc-book--spread > .dc-pair { display: contents; }
  #dresscode .dc-book--spread .dc-group { margin-top: 0; padding-top: 0; border-top: 0; }
  #dresscode .dc-book--spread .dc-group--accent, #dresscode .dc-book--spread .dc-group--bride { margin-top: 30px; padding-top: 28px; border-top: 1px solid var(--line); }
}

/* ------------------------------------------------------------------ motion (never with reduced motion) */
@media (prefers-reduced-motion: no-preference) {
  /* the swatches fan out of a stack at the middle of their row, each a little more turned than the last */
  @keyframes dc-fan {
    from { translate: calc(((var(--n, 1) - 1) / 2 - var(--i, 0)) * (var(--slot) + var(--sg, var(--sw-gap)))) 4px; rotate: calc(-18deg + var(--i, 0) * 4deg); }
  }
  @keyframes dc-sheen { from { --dc-sx: 100%; } }
  @keyframes dc-up { from { opacity: 0; translate: 0 var(--dc-rise, 14px); } }
  @keyframes dc-fade { from { opacity: 0; } }
  /* the ridge opens out from the middle; the plate is printed in from its foot */
  @keyframes dc-spread { from { clip-path: inset(0 50% 0 50%); opacity: .2; } }
  @keyframes dc-print {
    0% { -webkit-mask-image: linear-gradient(0deg, #000 40%, transparent 60%); mask-image: linear-gradient(0deg, #000 40%, transparent 60%);
         -webkit-mask-size: 100% 300%; mask-size: 100% 300%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 0 0; mask-position: 0 0; filter: blur(6px) saturate(.7); }
    65% { filter: blur(.8px) saturate(.95); }
    100% { -webkit-mask-image: linear-gradient(0deg, #000 40%, transparent 60%); mask-image: linear-gradient(0deg, #000 40%, transparent 60%);
         -webkit-mask-size: 100% 300%; mask-size: 100% 300%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 0 100%; mask-position: 0 100%; filter: blur(0) saturate(1); }
  }

  /* the weekend at a glance: the rows rise in turn */

  /* a group of the palette: the title soaks in, the swatches fan out (60 ms apart), the light glides over the
     silk once, the names and the words rise */
  html.ww-js #dresscode .dc-group.rvg .dc-group__title { animation: dc-fade 1100ms var(--out) calc(var(--d, 0ms) + 60ms) backwards; }
  html.ww-js #dresscode .dc-group.rvg .dc-sw__fab { transform-origin: 50% 100%; animation: dc-fan 700ms var(--out) calc(var(--d, 0ms) + 160ms + var(--i, 0) * 60ms) backwards; }
  html.ww-js #dresscode .dc-group.rvg .dc-sw__fab::before { animation: dc-sheen 2400ms var(--io) calc(var(--d, 0ms) + 760ms + var(--i, 0) * 60ms) backwards; }
  html.ww-js #dresscode .dc-group.rvg .dc-sw__name { animation: dc-up 800ms var(--out) calc(var(--d, 0ms) + 520ms + var(--i, 0) * 60ms) backwards; --dc-rise: 6px; }
  html.ww-js #dresscode .dc-group.rvg .dc-group__text { animation: dc-up 900ms var(--out) calc(var(--d, 0ms) + 640ms) backwards; --dc-rise: 8px; }
  html.ww-js #dresscode .dc-group--bride.rvg .dc-sw__mark { animation: dc-fade 1400ms var(--out) calc(var(--d, 0ms) + 900ms) backwards; }

  /* the lookbook: the plates are printed in, the ridge opens, the day's script soaks in, the words rise */
  html.ww-js #dresscode .dc-lookwrap.rvg .dc-plate { animation: dc-print 1500ms var(--e-ink) backwards; }
  html.ww-js #dresscode .dc-lookwrap.rvg .dc-plate__land { animation: dc-spread 2000ms var(--io) 200ms backwards; }
  html.ww-js #dresscode .dc-lookwrap.rvg .dc-plate__script { animation: dc-fade 1800ms var(--out) 300ms backwards; }
  html.ww-js #dresscode .dc-lookwrap.rvg .dc-copy > * { animation: dc-up 900ms var(--out) 260ms backwards; --dc-rise: 10px; }
  html.ww-js #dresscode .dc-lookwrap.rvg .dc-copy > :nth-child(2) { animation-delay: 330ms; }
  html.ww-js #dresscode .dc-lookwrap.rvg .dc-copy > :nth-child(n+3) { animation-delay: 400ms; }
  /* the figures step onto their plate (90 ms apart) once it is revealed, and again each time it comes to the
     front; a plate to the side rests with its figures faint */
  html.ww-js #dresscode .dc-fig { transition: opacity 600ms var(--out) calc(240ms + var(--n, 0) * 90ms), translate 900ms var(--out) calc(240ms + var(--n, 0) * 90ms); }
  html.ww-js #dresscode .dc-lookwrap.rvg:not(.in) .dc-fig { opacity: 0; translate: 0 16px; transition: none; }
  @media (max-width: 1099px) {
    html.ww-js #dresscode .dc-lookwrap.in .dc-look:not(.is-current) .dc-fig { opacity: .32; translate: 0 10px; transition-delay: 0ms; }
  }
}

/* ------------------------------------------------------------------ print: everything at rest, every plate whole
   (the motion above is not only for screens: nothing may print on its first frame, and no figure faint; story.css
   lays the lookbook out plate after plate; the chips have nothing to choose on paper) */
@media print {
  #dresscode *, #dresscode *::before, #dresscode *::after { animation: none !important; }
  #dresscode .dc-fig { opacity: 1 !important; translate: none !important; transition: none !important; }
  #dresscode .dc-chips { display: none; }
}

/* ------------------------------------------------------------------ the stage (the looks in 3D, atelier-*.js)
   A canvas the figures stand on, the day's name in script, a tab for each day, a number under each figure, and
   (close to one figure) a card with what it wears and, on Saturday, the palette to try on it. app.js adds the
   stage only where WebGL is available; without it the drawn plates stay. */
#dresscode .dc-stage__view { position: relative; height: clamp(410px, 112vw, 480px); }
#dresscode .dc-stage { position: relative; width: min(100% - 2 * var(--gut, 16px), var(--wide, 1100px)); margin: 10px auto 0; border-radius: 18px; overflow: hidden; isolation: isolate;
  background: radial-gradient(90% 34% at 50% 97%, rgba(120, 96, 92, .13), transparent 72%), linear-gradient(#f7ecee, #fcf6f4 50%, #f3e9e4 78%, #efe4de);
  border: 1px solid var(--line); box-shadow: var(--shadow); -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; }
#dresscode .dc-stage[data-day="fri"] { background: radial-gradient(90% 34% at 50% 97%, rgba(96, 70, 60, .16), transparent 72%), linear-gradient(#e9e1ec, #f6ebe6 52%, #f3e2d2 80%, #ecd8c6); }
#dresscode .dc-stage[data-day="sun"] { background: radial-gradient(90% 34% at 50% 97%, rgba(90, 105, 100, .12), transparent 72%), linear-gradient(#eef4f3, #f9f8f4 52%, #f1ede4 80%, #ebe5da); }
#dresscode .dc-stage__wait { position: absolute; inset: 0; margin: 0; display: grid; place-items: center; font: italic 400 15px/1.4 var(--font-body); color: var(--ink-soft); opacity: .75; }
#dresscode .dc-stage__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: pan-y; cursor: grab; }
#dresscode .dc-stage__canvas:active { cursor: grabbing; }
/* (the day in script only where there is room beside the tabs: not on a phone) */
#dresscode .dc-stage__day { display: none; position: absolute; left: 18px; top: 10px; margin: 0; font: 400 44px/1 var(--font-script); color: var(--accent-text); pointer-events: none; }
#dresscode .dc-stage__tabs { position: absolute; right: 10px; top: 10px; display: flex; gap: 6px; }
#dresscode .dc-stage__tab { min-width: 54px; min-height: 44px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--line); background: rgba(255, 255, 255, .86); font: 600 15px/1 var(--font-body); color: var(--accent-text); cursor: pointer; }
#dresscode .dc-stage__tab span { display: none; }
#dresscode .dc-stage__tab.is-on { background: var(--primary); border-color: var(--primary); color: #fff; }
#dresscode .dc-stage__marks { list-style: none; margin: 0; padding: 0; position: absolute; left: 0; top: 0; }
#dresscode .dc-stage__marks li { position: absolute; left: 0; top: 0; transition: opacity 260ms var(--out); }
#dresscode .dc-stage__marks button { position: absolute; left: -22px; top: -6px; width: 44px; height: 44px; display: grid; place-items: center; padding: 0; border: 0; background: none; font: italic 400 16px/1 var(--font-title); color: var(--primary); cursor: pointer; }
#dresscode .dc-stage__marks button::before { content: ''; position: absolute; inset: 8px; z-index: -1; border-radius: 50%; background: rgba(255, 255, 255, .9); border: 1px solid var(--line); }
#dresscode .dc-stage.is-close .dc-stage__marks { pointer-events: none; }
#dresscode .dc-stage__hint { margin: 0; padding: 10px 14px 11px; text-align: center; font: 500 14px/1.35 var(--font-body); color: var(--ink-soft); background: rgba(255, 255, 255, .72); border-top: 1px solid var(--line); }
#dresscode .dc-stage.is-close .dc-stage__hint { display: none; }
#dresscode .dc-stage__card { padding: 8px 8px 6px; background: rgba(255, 255, 255, .94); border-top: 1px solid var(--line); }
#dresscode .dc-stage__card[hidden] { display: none; }
#dresscode .dc-stage__head { display: grid; grid-template-columns: 44px minmax(0, 1fr) 44px; align-items: center; gap: 4px; }
#dresscode .dc-stage__head button { width: 44px; height: 44px; padding: 0 0 3px; border: 1px solid var(--line); border-radius: 50%; background: #fff; font: 400 22px/1 var(--font-body); color: var(--primary); cursor: pointer; }
#dresscode .dc-stage__what { margin: 0; display: flex; align-items: center; justify-content: center; gap: 8px; text-align: center; font: 400 17px/1.25 var(--font-title); color: var(--primary); }
#dresscode .dc-stage__n { flex: none; width: 26px; height: 26px; display: grid; place-items: center; border-radius: 50%; border: 1px solid var(--dusk-rose); font: italic 400 14px/1 var(--font-title); color: var(--accent-text); }
#dresscode .dc-stage__try { font: 500 13px/1.2 var(--font-body); color: var(--ink-soft); }
#dresscode .dc-stage__sws { display: flex; justify-content: center; gap: 0; margin: 2px -4px 0; overflow-x: auto; scrollbar-width: none; }
#dresscode .dc-stage__sws::-webkit-scrollbar { display: none; }
#dresscode .dc-stage__sw { position: relative; flex: 0 0 44px; width: 44px; height: 44px; padding: 0; border: 0; background: none; cursor: pointer; }
#dresscode .dc-stage__sw::before { content: ''; position: absolute; inset: 7px; border-radius: 50%; background: var(--c); box-shadow: inset 0 0 0 1px rgba(46, 53, 50, .14); }
#dresscode .dc-stage__sw.is-on::after { content: ''; position: absolute; inset: 3px; border-radius: 50%; border: 1.5px solid var(--primary); }
#dresscode .dc-stage__nav { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 0 6px 0 10px; }
#dresscode .dc-stage__nav button { min-width: 44px; min-height: 44px; padding: 0 16px; border: 1px solid var(--line); border-radius: 999px; background: #fff; font: 600 15px/1 var(--font-body); color: var(--primary); cursor: pointer; }
#dresscode .dc-stage :is(button):focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
@media (min-width: 600px) {
  #dresscode .dc-stage__view { height: 520px; }
  #dresscode .dc-stage__day { display: block; left: 26px; top: 14px; font-size: 54px; }
  #dresscode .dc-stage__tabs { right: 16px; top: 16px; }
  #dresscode .dc-stage__tab span { display: inline; }
}
@media (min-width: 900px) {
  #dresscode .dc-stage__view { height: 560px; }
  #dresscode .dc-stage__card { position: absolute; left: 30px; top: 50%; width: 330px; transform: translateY(-50%); padding: 14px 14px 10px; border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow); }
  #dresscode .dc-stage__what { font-size: 20px; }
  #dresscode .dc-stage__sws { flex-wrap: wrap; justify-content: center; margin-top: 8px; }
}
/* with the stage, the day cards are words only: their drawn plates are the fallback */
#dresscode .dc-looks--3d .dc-plate, #dresscode .dc-looks--3d .dc-chips { display: none; }
#dresscode .dc-looks--3d .dc-look.is-stage { border-color: var(--dusk-rose); }
/* ---- w/css/gallery.css ---- */
/* =====================================================================
   THE SMITH WEDDING · GALLERY
   The photos on the page (VII, #galleryPreview), the photo viewer (dialog#gv) and, for a big set, the full-screen
   gallery (dialog#gx), built by app.js (renderGallery, galRows, galTrim and the gallery helpers).
   Justified rows: every tile is as wide as its photo's aspect ratio (--ar) times the row height (--rh); flex-grow in
   the same proportion fills each row, so the photos of a row share one height. The pictures carry their width and
   height and every tile its ratio, so nothing moves while they load.
   A small set is a wall (.is-wall): every photo is on the page and app.js galRows gives each tile its own row's
   height as --rh, so the rows break where it chose them. A big set is a preview of whole rows (app.js galTrim works
   them out from the --rh and --gap below, so keep those here); the full gallery's last row keeps its height (the
   ::after filler).
   ===================================================================== */
.gx-preview, .gx-grid { --rh: 128px; --gap: 6px; display: flex; flex-wrap: wrap; gap: var(--gap); }
.gx-preview { --rh: 120px; }
.gx-grid::after { content: ""; flex: 999999 1 0px; }
/* the wall: a last row that would come out far too tall keeps its height and sits in the middle (galRows) */
.gx-preview.is-wall { justify-content: center; }
.gx-tile.is-loose { flex-grow: 0; }
.gx-tile { position: relative; flex: calc(var(--ar) * 1000) 1 calc(var(--ar) * var(--rh)); max-width: 100%; aspect-ratio: var(--ar);
  margin: 0; padding: 0; border: 0; border-radius: 8px; overflow: hidden; background: var(--bg-soft); cursor: zoom-in; -webkit-tap-highlight-color: transparent; }
.gx-tile img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--out, ease), filter .4s ease; }
/* printed into the paper, like the other photographs on the site (the preview's tiles also take .print's grade) */
.gx-tile::after { content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit; background: var(--grain);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22), inset 0 1px 3px rgba(40, 46, 43, .18), inset 0 0 36px rgba(40, 46, 43, .08); }
/* a wall of large colour photographs: on an ordinary (1x) screen the full grain speckles pale skies and white shirts,
   so the wall takes the half grain that sharp screens already get (story.css) */
@media (max-resolution: 1.99dppx) { .gx-tile::after { opacity: .5; } }
@media (hover: hover) { .gx-tile:hover img { transform: scale(1.03); } }   /* (a finger leaves no hover behind) */
.gx-tile:focus-visible { outline: 3px solid var(--heather); outline-offset: 2px; }
.gx-tile:active { scale: .98; }

/* the preview's last photo: darkened, "+284 · See all" (it opens the full gallery) */
.gx-tile.is-more { cursor: pointer; }
.gx-tile.is-more::before { content: ""; position: absolute; inset: 0; z-index: 2; border-radius: inherit; pointer-events: none; background: rgba(21, 24, 23, .58); }
.gx-more { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  padding: 4px; color: #fff; text-align: center; pointer-events: none; text-shadow: 0 1px 6px rgba(0, 0, 0, .35); }
.gx-more b { font: 400 28px/1.05 var(--font-title); font-variant-numeric: lining-nums; }
.gx-more span { font: 600 13px/1.3 var(--font-body); letter-spacing: .14em; text-transform: uppercase; }
.gx-tile.is-more:hover img { transform: none; }

.gx-section { padding-top: 4px; }
.gx-soon { margin: 0; text-align: center; color: var(--ink-soft); }
.gx-cta { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-top: 28px; text-align: center; }
.gx-cta .btn { min-width: min(100%, 280px); }
.gx-cta .btn[hidden] { display: none; }   /* (a wall shows every photo: there is nothing more to see) */
.gx-credit { margin: 0; font: italic 400 15px/1.5 var(--font-title); letter-spacing: .01em; color: var(--ink-soft); }

/* ---------- the full-screen gallery: a sheet (opens rising 24px and fading in, 320 ms) ---------- */
html.gx-lock, html.gx-lock body { overflow: hidden; }
dialog.gx, dialog.gv { position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; color: var(--ink); }
dialog.gx { background: #fff; overflow-y: auto; overscroll-behavior: contain; }
dialog.gx::backdrop, dialog.gv::backdrop { background: rgba(255, 255, 255, .92); }
.gx-bar { position: sticky; top: 0; z-index: 4; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: calc(8px + env(safe-area-inset-top, 0px)) max(var(--gut, 16px), calc(50% - 620px)) 8px; background: rgba(255, 255, 255, .97); border-bottom: 1px solid var(--line); }
.gx-head { min-width: 0; }
.gx-head .eyebrow { margin: 0; font-size: 13px; letter-spacing: .18em; }
.gx-head h2 { margin: 0; font-size: clamp(1.3rem, 5vw, 1.6rem); }
.gx-close { flex: none; display: inline-flex; align-items: center; gap: .35rem; min-height: 44px; padding: .5rem 1rem .5rem .7rem; border: 1px solid var(--line); border-radius: 999px;
  background: #fff; color: var(--primary); font: 600 15px var(--font-body); cursor: pointer; }
.gx-close svg { width: 18px; height: 18px; }
.gx-close:active { background: var(--primary); color: #fff; border-color: var(--primary); }
@media (hover: hover) { .gx-close:hover { background: var(--primary); color: #fff; border-color: var(--primary); } }
.gx-body { max-width: 1240px; margin: 0 auto; padding: .4rem var(--gut, 16px) calc(4rem + env(safe-area-inset-bottom, 0px)); }
.gx-body .gx-grid { margin-top: 1.5rem; }
.gx-end { height: 1px; }

/* ---------- the viewer ---------- */
dialog.gv { background: rgba(255, 255, 255, .98); overflow: hidden; }
.gv-fig { position: absolute; inset: calc(60px + env(safe-area-inset-top, 0px)) 12px calc(64px + env(safe-area-inset-bottom, 0px)); margin: 0; touch-action: pan-y pinch-zoom; }
.gv-fig img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; -webkit-user-select: none; user-select: none; -webkit-user-drag: none; }
.gv-low { filter: blur(2px); }
.gv-img { opacity: 0; transition: opacity .3s ease; }
.gv-img.is-in { opacity: 1; }
.gv-meta { position: absolute; left: 0; right: 0; bottom: calc(18px + env(safe-area-inset-bottom, 0px)); margin: 0; display: flex; justify-content: center; gap: .8rem; font-size: 13px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft); }
.gv-meta #gvCount { font-variant-numeric: tabular-nums; color: var(--primary); font-weight: 600; }
.gv-meta span:empty { display: none; }   /* (no caption: the count stays in the middle) */
.gv-btn { position: absolute; display: grid; place-items: center; width: 46px; height: 46px; padding: 0; border: 1px solid var(--line); border-radius: 50%;
  background: rgba(255, 255, 255, .92); color: var(--primary); font-size: 1.7rem; line-height: 1; cursor: pointer; box-shadow: var(--shadow); }
.gv-btn svg { width: 22px; height: 22px; }
/* pressed, and under a mouse: on a touch screen a tapped button would otherwise stay dark while the guest pages on */
.gv-btn:active { background: var(--primary); color: #fff; }
@media (hover: hover) { .gv-btn:hover { background: var(--primary); color: #fff; } }
.gv-close { top: calc(8px + env(safe-area-inset-top, 0px)); right: 12px; }
.gv-prev, .gv-next { top: 50%; translate: 0 -50%; }
.gv-prev { left: 12px; } .gv-next { right: 12px; }
@media (hover: none) and (max-width: 700px) { .gv-prev, .gv-next { top: auto; bottom: calc(8px + env(safe-area-inset-bottom, 0px)); translate: none; } .gv-meta { bottom: calc(22px + env(safe-area-inset-bottom, 0px)); } }

@media (min-width: 600px) { .gx-preview, .gx-grid { --rh: 180px; --gap: 8px; } }
@media (min-width: 1000px) { .gx-preview, .gx-grid { --rh: 230px; --gap: 10px; } .gv-fig { inset: 64px 76px 64px; } }
/* wide screens: the photos are a wall as wide as the page's other photo rows (the venue's plates, the invitation
   card); app.js works its rows out from this width (galRows; for a big set galTrim shows three whole rows) */
@media screen and (min-width: 1100px) {
  #gallery .gx-section { max-width: calc(1200px + 2 * var(--gut)); }
  #gallery .gx-cta { margin-top: 36px; }
}

/* ---------- motion (VII): the photos print in row by row (motion.js [data-rv="ink"]) 70 ms apart; the full
   gallery opens as a sheet. With reduced motion everything is simply there (style.css stops every animation) ---------- */
@keyframes gx-sheet { from { opacity: 0; translate: 0 24px; } }
@media (prefers-reduced-motion: no-preference) {
  html.ww-js #gallery .gx-tile.rv-ink.in { animation-delay: calc(var(--d, 0ms) * 7 / 9); }
  dialog.gx[open] { animation: gx-sheet 320ms var(--e-sheet, cubic-bezier(.32, .72, 0, 1)) both; }
  .gx-tile { transition: scale 160ms var(--out, ease); }
}
@media (prefers-reduced-motion: reduce) { .gx-tile img, .gv-img { transition: none; } }
/* ---- w/css/pwa.css ---- */
/* ================= THE SMITH WEDDING · OFFLINE (pwa.js) =================
   The update note, the "Offline" note and the map's "saved for offline use" line, in the site's tokens
   (style.css :root). Linked after the other stylesheets. */

/* ---------- "A fresh version of the invitation is ready" ---------- */
.ww-update {
  position: fixed; left: 50%; bottom: calc(1rem + env(safe-area-inset-bottom, 0px)); z-index: 650;
  display: flex; align-items: center; gap: .75rem; width: max-content; max-width: calc(100vw - 32px);
  padding: .55rem .55rem .55rem 1rem; background: #fff; color: var(--ink);
  border: 1px solid var(--line); border-radius: 999px; box-shadow: var(--shadow-lg);
  font-family: var(--font-body); font-size: .9rem; line-height: 1.35;
  transform: translate(-50%, calc(100% + 2rem)); opacity: 0; transition: transform .45s var(--out), opacity .3s ease;
}
.ww-update.is-in { transform: translate(-50%, 0); opacity: 1; }
.ww-update p { margin: 0; }
.ww-update .ww-mark { width: 23px; height: 26px; flex: none; color: var(--sage); }
.ww-update .btn { flex: none; }
.ww-update__x { flex: none; width: 44px; height: 44px; margin: -5px 0; border: 0; border-radius: 50%; background: transparent; color: var(--ink-soft); font-size: 1.35rem; line-height: 1; cursor: pointer; }
.ww-update__x:hover { background: var(--bg-soft); color: var(--primary); }
@media (max-width: 520px) {
  .ww-update { left: 16px; right: 16px; width: auto; max-width: none; transform: translateY(calc(100% + 2rem)); border-radius: var(--radius); }
  .ww-update.is-in { transform: none; }
  .ww-update p { flex: 1; }
}
/* during the weekend the floating Now pill (52px, 12px off the foot) holds the bottom of the screen: the update
   note and the toast sit above it */
html.has-now-pill .ww-update { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
html.has-now-pill .toast { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
/* (coming or going, the note never catches a tap meant for what is under it) */
.ww-update:not(.is-in) { pointer-events: none; }

/* ---------- offline ---------- */
.ww-net {
  position: fixed; left: 50%; top: calc(var(--hdr, 64px) + 10px); z-index: 49; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: .5rem; margin: 0; max-width: calc(100vw - 32px);
  padding: .35rem .9rem; border-radius: 999px; background: rgba(255, 255, 255, .96); border: 1px solid var(--line);
  box-shadow: var(--shadow); color: var(--ink-soft); font-size: 13px; font-weight: 600; letter-spacing: .05em;
  pointer-events: none; white-space: nowrap; transition: top 240ms var(--out);
}
.ww-net[hidden] { display: none; }
/* in II the day rail sticks under the header (s-weekend.css): while it is stuck there, the note sits under it and
   never covers the days (pwa.js watches the rail) */
.ww-net.is-low { top: calc(var(--hdr, 64px) + var(--rail, 44px) + 10px); }
/* a few seconds on, only its dot stays, on the foot of the header (or of the stuck rail), between what is written
   there and the page under it (the words are still there for screen readers) */
.ww-net.is-dot { top: calc(var(--hdr, 64px) - 9px); z-index: 51; width: 18px; height: 18px; padding: 0; gap: 0; justify-content: center; }
.ww-net.is-dot.is-low { top: calc(var(--hdr, 64px) + var(--rail, 44px) - 9px); }
.ww-net.is-dot .ww-net__t { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.ww-net__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dusk-rose); box-shadow: 0 0 0 3px var(--blush-wash); }
.ww-net__sub { font-weight: 400; letter-spacing: .02em; }
@media (max-width: 420px) { .ww-net__sub { display: none; } }
/* what needs the network (Google photos and the like) steps aside while offline */
html.ww-offline [data-online-only] { display: none !important; }

/* ---------- the map: saved for offline use ---------- */
.ww-mapsave {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: .45rem .55rem;
  margin: .9rem auto 0; color: var(--ink-soft); font-size: 13px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; text-align: center;
}
.ww-mapsave[hidden] { display: none; }
.ww-mapsave__ic { width: 18px; height: 18px; flex: none; border-radius: 50%; border: 1px solid var(--sage-mist); background: var(--sage-wash) no-repeat center / 10px
  url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.2 6.3 4.8 8.8 9.8 3.4' fill='none' stroke='%235A6964' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); }
.ww-mapsave.is-saving .ww-mapsave__ic { background-image: none; border-color: var(--sage-mist); border-top-color: var(--slate); animation: ww-spin 1.1s linear infinite; }
.ww-mapsave__bar { display: none; flex-basis: 100%; height: 2px; max-width: 220px; margin: 0 auto; background: var(--line); border-radius: 2px; overflow: hidden; }
.ww-mapsave.is-saving .ww-mapsave__bar { display: block; }
.ww-mapsave__bar > span { display: block; width: 0; height: 100%; background: var(--sage); transition: width .6s var(--out); }
@keyframes ww-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .ww-update { transition: opacity .2s ease; }
  .ww-net { transition: none; }
  .ww-mapsave.is-saving .ww-mapsave__ic { animation: none; }
}
/* ---- w/css/story.css ---- */
/* =====================================================================
   THE SMITH WEDDING · STORY (the one-page invitation)
   The chrome and the shared primitives every chapter builds on (SPEC §4.5): the tokens; the header (monogram,
   running chapter title, Reply, Contents, the thread as its progress line); Contents (the full-screen menu); the
   Now pill; the chapter frame (thread, knot, eyebrow, title, answer line); the fields; the print grade; chips,
   text buttons and the button sizes; the [data-snap] scroller; the admin view; safe areas; reduced motion.
   Linked after style.css and the older sheets, before the chapters' own sheets (s-*.css), which only use
   selectors scoped by their section id or prefix.

   Hooks on <html> (SPEC §4.2; set by motion.js, story.js and app.js)
   on-hero        the invitation card is on screen: no running head, no Reply pill
   rsvp-open      replies are accepted              has-replied   this device has sent a reply
   is-weekend     data-phase="weekend" (also pre / post)
   data-ch        the chapter under the reading line (home, weekend, venue, stay, party, dresscode, gallery, faq, rsvp)
   ink-night      a [data-ink="night"] section is under the header: the header turns charcoal
   toc-open       Contents is open                  has-now-pill  the floating Now pill is shown
   view-admin     the couple's dashboard is shown alone
   ===================================================================== */

/* ------------------------------------------------------------------ tokens */
:root {
  color-scheme: only light;
  /* easing (--out, --io and --pen live in style.css; --ink is a colour there, so the ink easing is --e-ink) */
  --e-ink: cubic-bezier(.33, 0, .2, 1);
  --e-sheet: cubic-bezier(.32, .72, 0, 1);
  /* space, on a 4px base */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;
  /* the gutter (never under a notch: viewport-fit=cover), the reading column and the wide column */
  --gut: max(clamp(16px, 5vw, 24px), env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px));
  --col: 720px;
  --wide: 1100px;
  /* the sticky header (its height includes the status bar's safe area) and the weekend's day rail under it */
  --hdr: calc(56px + env(safe-area-inset-top, 0px));
  --rail: 44px;
  /* the thread, and the one dark band (the night) */
  --thread: #B48A93;
  --thread-night: #CDBBA4;
  --tie: #151817;
  --night-ink: #F2EEE9;
  --night-role: #CDBBA4;
  --night-soft: #B9B2A8;
}
@media (min-width: 900px) { :root { --hdr: calc(64px + env(safe-area-inset-top, 0px)); } }

/* ------------------------------------------------------------------ the page */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: calc(var(--hdr) + 8px); }
body { font-size: 17px; line-height: 1.65; }
/* nothing ever scrolls the page sideways (a .bleed is 100vw wide); clip, not hidden: sticky bars keep working */
#main { overflow-x: clip; }
/* every anchor lands under the header. NB: the browser adds html's scroll-padding-top to this for native anchor
   scrolls and scrollIntoView(); WW.jump() computes its own target from this margin */
[id] { scroll-margin-top: calc(var(--hdr) + 8px); }
/* focus that the page moves to something you cannot press (the skip link's #main, a chapter's h2 after a jump) is
   not a ring around a whole heading; controls always keep theirs */
[tabindex="-1"]:not(a, button, input, select, textarea, summary):focus { outline: none; }
html.toc-open { overflow: hidden; }
/* the primitives' type floor: eyebrows and text links are never under 13px */
.eyebrow { font-size: 13px; letter-spacing: .2em; }
.text-link { font-size: 13px; }
.vh { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }

/* ------------------------------------------------------------------ the header
   [monogram → #home] [running head] [Reply] [Contents], solid white (no blur), a hairline at its foot and the
   thread drawn along it as the reading progress */
.hdr {
  position: sticky; top: 0; z-index: 50;
  display: grid; grid-template-columns: 44px minmax(0, 1fr) auto 44px; grid-template-areas: "mono run pill menu";
  align-items: center; column-gap: 8px;
  height: var(--hdr);
  padding: env(safe-area-inset-top, 0px) max(calc(var(--gut) - 10px), 6px, calc((100% - 1180px) / 2)) 0;
  background: #fff; color: var(--primary);
  transition: background-color 240ms var(--out), color 240ms var(--out);
}
.hdr::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--line); pointer-events: none; transition: background-color 240ms var(--out); }
.hdr-mono { grid-area: mono; width: 44px; height: 44px; display: grid; place-items: center; border-radius: 50%; color: inherit; text-decoration: none; transition: color 240ms var(--out); }
.hdr-mono .logo { width: 36px; height: 40px; color: inherit; }
.hdr-mono:hover { color: var(--accent-text); }

/* the running head: the chapter's numeral and its short title (story.js writes them while it is faded out, so a
   swap is never a layout shift; a tap opens Contents) */
.hdr-run {
  grid-area: run; min-width: 0; display: flex; align-items: baseline; justify-content: center; gap: .45em;
  white-space: nowrap; overflow: hidden; color: inherit; cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent;
  transition: opacity 220ms var(--out), translate 220ms var(--out), visibility 0s;
}
.hdr-run__n { flex: none; font: italic 400 15px/1.2 var(--font-title); color: var(--accent-text); transition: color 240ms var(--out); }
.hdr-run__t { min-width: 0; overflow: hidden; text-overflow: ellipsis; font: 400 16px/1.25 var(--font-title); }
html.on-hero .hdr-run { opacity: 0; visibility: hidden; transition: opacity 220ms var(--out), visibility 0s linear 220ms; }

/* Reply: only while replies are open, before the weekend, off the hero and away from IX (the Now pill takes over
   during the weekend) */
.hdr-pill {
  grid-area: pill; display: none; align-items: center; justify-content: center; min-height: 44px; padding: 0 18px;
  border-radius: 999px; background: var(--primary); color: #fff; text-decoration: none; white-space: nowrap;
  font: 600 15px/1 var(--font-body); letter-spacing: .03em;
  transition: background-color 240ms var(--out), color 240ms var(--out);
}
.hdr-pill:hover { background: var(--primary-hover); color: #fff; }
html.rsvp-open:not(.has-replied):not(.on-hero):not(.view-admin):not(.is-weekend):not([data-phase="post"]):not([data-ch="rsvp"]) .hdr-pill { display: inline-flex; }

/* Contents: two engraved lines */
.hdr-menu {
  grid-area: menu; width: 44px; height: 44px; display: grid; place-content: center; gap: 6px; padding: 0;
  border: 0; border-radius: 50%; background: none; color: inherit; cursor: pointer;
}
.hdr-menu span { display: block; width: 22px; height: 1.5px; border-radius: 1px; background: currentColor; }
.hdr-menu:hover { color: var(--accent-text); }

/* the thread along the header's foot: the reading progress (a scroll timeline where there is one; elsewhere
   story.js sets --p, 0 to 1) */
.hdr-progress {
  position: absolute; z-index: 1; left: 0; right: 0; bottom: 0; height: 1.5px; pointer-events: none;
  background: var(--thread); transform-origin: 0 50%; transform: scaleX(var(--p, 0));
  transition: background-color 240ms var(--out);
}
@keyframes hdr-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .hdr-progress { animation: hdr-progress linear both; animation-timeline: scroll(root block); }
  }
}

/* the inline chapter nav (from 1100px; the running head steps aside, Contents stays) */
.hdr-nav { grid-area: run; display: none; justify-content: center; align-items: center; gap: 2px; min-width: 0; }
.hdr-nav a {
  position: relative; display: inline-flex; align-items: center; min-height: 44px; padding: 0 12px;
  font: 500 15px/1 var(--font-body); letter-spacing: .02em; color: inherit; text-decoration: none; white-space: nowrap;
}
.hdr-nav a::after { content: ""; position: absolute; left: 12px; right: 12px; bottom: 9px; height: 1.5px; background: var(--thread); transform: scaleX(0); transition: transform 320ms var(--e-sheet); }
.hdr-nav a:hover::after { transform: scaleX(.5); }
.hdr-nav a[aria-current]::after { transform: none; }
.hdr-nav a[aria-current] { color: var(--accent-text); }
@media (min-width: 1100px) {
  .hdr-nav { display: flex; }
  .hdr-run { display: none; }
}

/* the dashboard's header: "Couple's dashboard" and the way back (only in html.view-admin) */
.hdr-admin, .hdr-back { display: none; }
.hdr-admin { grid-area: run; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; font: 400 16px/1.25 var(--font-title); }
.hdr-back {
  grid-column: pill / menu; justify-self: end; align-items: center; min-height: 44px; padding: 0 14px;
  border: 1px solid var(--sage-mist); border-radius: 999px; color: var(--primary); text-decoration: none; white-space: nowrap;
  font: 600 15px/1 var(--font-body); letter-spacing: .02em;
}
.hdr-back:hover { border-color: var(--primary); color: var(--primary); }
html.view-admin .hdr-admin { display: block; }
html.view-admin .hdr-back { display: inline-flex; }
html.view-admin .hdr-run, html.view-admin .hdr-nav, html.view-admin .hdr-pill, html.view-admin .hdr-menu, html.view-admin .hdr-progress { display: none; }
@media (max-width: 419px) { html.view-admin .hdr-admin { visibility: hidden; } }

/* the ink switch: over the night band the header turns charcoal, its ink moonbone and its monogram champagne */
html.ink-night .hdr { background-color: #151817; color: var(--night-ink); }
html.ink-night .hdr::after { background-color: rgba(242, 238, 233, .12); }
html.ink-night .hdr-mono, html.ink-night .hdr-run__n { color: var(--thread-night); }
html.ink-night .hdr-pill { background-color: var(--night-ink); color: var(--tie); }
html.ink-night .hdr-progress { background-color: var(--thread-night); }
html.ink-night .hdr-nav a[aria-current] { color: var(--thread-night); }
html.ink-night .hdr-nav a::after { background: var(--thread-night); }

/* ------------------------------------------------------------------ Contents (<dialog id="toc">, showModal())
   Full screen on white paper: the top bar (the monogram, × where the menu button was), the date, "Contents",
   the Now block during the weekend, nine rows strung on the thread (the current knot filled), and the foot */
dialog.toc {
  position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; border: 0;
  padding: 0 var(--gut); background: #fff; color: var(--ink);
  overflow: hidden auto; overscroll-behavior: contain;
}
dialog.toc[open] { display: flex; flex-direction: column; }
dialog.toc::backdrop { background: transparent; }
.toc > * { flex: none; width: 100%; max-width: 560px; margin-inline: auto; }
/* (the top bar lines up with the header: its padding, less the dialog's own; 100% here is the dialog's content) */
.toc-top {
  max-width: none; height: var(--hdr); display: flex; align-items: center; justify-content: space-between;
  width: auto; margin-inline: calc(max(calc(var(--gut) - 10px), 6px, calc((100% - 1180px) / 2 + var(--gut))) - var(--gut));
  padding-top: env(safe-area-inset-top, 0px);
}
.toc-top .logo { width: 36px; height: 40px; margin-left: 8px; color: var(--primary); }
.toc-x {
  width: 44px; height: 44px; display: grid; place-items: center; padding: 0 0 3px; border: 0; border-radius: 50%;
  background: none; color: var(--primary); font: 300 34px/1 var(--font-body); cursor: pointer;
}
.toc-x:hover { color: var(--accent-text); }
.toc-eyebrow { margin: 4px auto 0; text-align: center; font: 600 13px/1.4 var(--font-body); letter-spacing: .2em; text-transform: uppercase; color: var(--accent-text); }
.toc-title { margin: 2px auto 0; text-align: center; font: 400 clamp(1.75rem, 7.6vw, 2.1rem)/1.15 var(--font-title); color: var(--primary); }

/* the Now block (weekend only; story.js renders it from 'ww:live'): .toc-now__eyebrow (.toc-now__dot,
   .toc-now__day) · .toc-now__t (the event) · .toc-now__m (when and where) · .toc-now__go (Navigate) ·
   .toc-now__also (a second event at the same time) · .toc-now__next (up next) */
.toc-now {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 12px; row-gap: 2px;
  margin-top: 16px; padding: 14px 14px 12px 16px; border-radius: 14px;
  background: var(--blush-wash); box-shadow: inset 0 0 0 1px #F1DDE1; text-align: left;
}
.toc-now[hidden] { display: none; }
.toc-now > * { grid-column: 1 / -1; margin: 0; }
.toc-now__eyebrow { margin-bottom: 2px; font: 600 13px/1.4 var(--font-body); letter-spacing: .14em; text-transform: uppercase; color: var(--accent-text); }
.toc-now__dot { display: inline-block; width: 8px; height: 8px; margin-right: 8px; vertical-align: 1px; border-radius: 50%; background: var(--dusk-rose); box-shadow: 0 0 0 4px rgba(180, 138, 147, .2); }
.toc-now .toc-now__t { grid-column: 1; }
.toc-now__t { font: 400 21px/1.2 var(--font-title); color: var(--primary); }
.toc-now__m { font-size: 15px; line-height: 1.45; color: var(--ink-soft); }
.toc-now .toc-now__go { grid-column: 2; grid-row: 2; min-height: 44px; padding: 0 18px; font-size: 15px; }
.toc-now__also { margin-top: 4px; font: italic 400 15px/1.4 var(--font-title); color: var(--accent-text); }
.toc-now__next { margin-top: 8px; padding-top: 8px; border-top: 1px solid #F1DDE1; font-size: 15px; line-height: 1.45; color: var(--ink-soft); }

/* the nine rows on their thread */
.toc-nav { margin-top: 14px; }
.toc-list { position: relative; margin: 0; padding: 0; list-style: none; }
.toc-list::before {
  content: ""; position: absolute; z-index: 0; left: 21.4px; top: 28px; bottom: 28px; width: 1.25px;
  background: var(--thread); transform-origin: 50% 0; pointer-events: none;
}
.toc-list > li { position: relative; }
.toc-row {
  display: grid; grid-template-columns: 44px minmax(0, 1fr); grid-template-rows: auto auto; column-gap: 14px; align-items: center;
  min-height: 56px; padding: 6px 0; color: var(--primary); text-decoration: none; -webkit-tap-highlight-color: transparent;
}
.toc-knot {
  position: relative; z-index: 1; grid-row: 1 / span 2; width: 44px; height: 44px; display: grid; place-items: center;
  border-radius: 50%; background: #fff; box-shadow: inset 0 0 0 1.25px var(--thread);
}
.toc-knot i { font: italic 500 15px/1 var(--font-title); color: var(--accent-text); }
.toc-t { grid-column: 2; align-self: end; font: 400 20px/1.2 var(--font-title); }
.toc-d { grid-column: 2; align-self: start; font: italic 400 15px/1.35 var(--font-title); color: var(--ink-soft); text-wrap: pretty; }
.toc-row:hover .toc-t { color: var(--accent-text); }
.toc-row:active .toc-knot { scale: .94; }
/* the knot of the chapter you are in is pulled tight (filled) */
.toc-row[aria-current] .toc-knot { background: var(--accent-text); box-shadow: 0 0 0 4px rgba(180, 138, 147, .18); }
.toc-row[aria-current] .toc-knot i { color: #fff; }
.toc-row[aria-current] .toc-t { color: var(--accent-text); }

/* the foot: Kindly reply (only while replies are open and none was sent from here) and the calendar, over a
   whisper of the toile */
.toc-foot {
  position: relative; isolation: isolate; margin-top: auto; padding: 22px 0 calc(16px + env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
html:not(.rsvp-open) .toc-reply, html.has-replied .toc-reply { display: none; }
html.ww-deco .toc-foot::before {
  content: ""; position: absolute; z-index: -1; left: 50%; bottom: 0; width: 100vw; height: 210px; translate: -50% 0; pointer-events: none;
  background: var(--ink-sage); opacity: .11;
  -webkit-mask: url(../img/ornament/toile-wall.webp) 50% 100% / 600px repeat, linear-gradient(transparent, #000 65%); -webkit-mask-composite: source-in;
  mask: url(../img/ornament/toile-wall.webp) 50% 100% / 600px repeat, linear-gradient(transparent, #000 65%); mask-composite: intersect;
}

/* opening: the sheet unfolds from the top, the rows rise on their thread and the thread is drawn; closing
   (.is-closing, set by story.js, which closes the dialog when this animation ends): it fades and lifts away */
@keyframes toc-unfold { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0); } }
@keyframes toc-rise { from { opacity: 0; translate: 0 14px; } }
@keyframes toc-thread { from { transform: scaleY(0); } }
@keyframes toc-close { to { opacity: 0; translate: 0 -8px; } }
@media (prefers-reduced-motion: no-preference) {
  dialog.toc[open] { animation: toc-unfold 480ms var(--io) both; }
  dialog.toc.is-closing { animation: toc-close 220ms var(--out) both; pointer-events: none; }
  dialog.toc[open] :is(.toc-eyebrow, .toc-title, .toc-now) { animation: toc-rise 320ms var(--e-sheet) 60ms both; }
  dialog.toc[open] .toc-list > li { animation: toc-rise 320ms var(--e-sheet) calc(120ms + var(--i, 0) * 40ms) both; }
  dialog.toc[open] .toc-list::before { animation: toc-thread 600ms var(--io) 140ms both; }
  dialog.toc[open] .toc-foot { animation: toc-rise 320ms var(--e-sheet) 480ms both; }
}

/* ------------------------------------------------------------------ the Now pill (weekend only)
   Fixed at the foot, under the thumb: "● Now · The Ceremony" and a round slate "Navigate ›" (story.js shows it
   off the hero and hides it over the itinerary's current row, with a dialog open or while typing) */
.now-pill {
  position: fixed; z-index: 60; left: 0; right: 0; bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  width: fit-content; max-width: calc(100% - 2 * var(--gut)); height: 52px; margin-inline: auto;
  display: flex; align-items: center; gap: 10px; padding: 0 6px 0 18px;
  border: 0; border-radius: 999px; background: #fff; color: var(--ink); cursor: pointer;
  box-shadow: 0 0 0 1px var(--line), 0 14px 34px -12px rgba(46, 53, 50, .38), 0 2px 6px rgba(46, 53, 50, .06);
  font: 600 15px/1.2 var(--font-body); text-align: left; -webkit-tap-highlight-color: transparent;
}
.now-pill[hidden] { display: none; }
.now-pill__dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--dusk-rose); box-shadow: 0 0 0 4px rgba(180, 138, 147, .2); }
.now-pill__t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.now-pill__go {
  flex: none; display: inline-flex; align-items: center; gap: 6px; height: 40px; padding: 0 12px 0 16px;
  border-radius: 999px; background: var(--primary); color: #fff; font-size: 15px; letter-spacing: .02em;
}
.now-pill__go::after { content: "›"; font: 400 22px/1 var(--font-title); translate: 0 -1px; }
.now-pill:active { scale: .97; }
/* on the smallest phones the event's name gets the room: "Navigate" becomes a round arrow (the word stays the
   button's accessible name) */
@media (max-width: 359px) {
  .now-pill { gap: 8px; padding-left: 14px; }
  .now-pill__go { position: relative; width: 40px; padding: 0; overflow: hidden; white-space: nowrap; text-indent: 64px; }
  .now-pill__go::after { position: absolute; inset: 0; display: grid; place-items: center; text-indent: 0; translate: 1px -1px; }
}
html.view-admin .now-pill { display: none !important; }
/* the colophon keeps its last lines clear of the pill */
html.has-now-pill .site-footer { padding-bottom: calc(3.5rem + 76px + env(safe-area-inset-bottom, 0px)); }
/* and the focus is never under it: a control that takes the focus in the pill's band is scrolled up above it */
html.has-now-pill { scroll-padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
@keyframes now-pill-in { from { opacity: 0; translate: 0 18px; } }
@media (prefers-reduced-motion: no-preference) {
  .now-pill { animation: now-pill-in 320ms var(--e-sheet) both; transition: scale 160ms var(--out); }
}

/* ------------------------------------------------------------------ the chapter frame
   The thread comes down into the knot that carries the chapter's numeral; then the eyebrow, the title and the
   answer line. Without a scroll timeline every thread is simply drawn (the scrubs are in motion.css). */
.ch { position: relative; padding: 52px 0 56px; }
.ch-thread {
  position: absolute; left: 50%; top: 0; width: 1.25px; height: 53px; margin-left: -.625px; pointer-events: none;
  background: var(--thread); transform-origin: 50% 0;
}
.ch-head {
  position: relative; display: flex; flex-direction: column; align-items: center; text-align: center;
  max-width: calc(var(--col) + 2 * var(--gut)); margin: 0 auto 28px; padding-inline: var(--gut);
}
.ch-knot { position: relative; flex: none; width: 44px; height: 44px; display: grid; place-items: center; color: var(--thread); }
.ch-knot svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.ch-knot circle { fill: none; stroke: currentColor; stroke-width: 1.25; }
.ch-knot i { position: relative; font: italic 500 16px/1 var(--font-title); color: var(--accent-text); }
.ch-eyebrow { margin: 14px 0 0; font: 600 13px/1.4 var(--font-body); letter-spacing: .2em; text-transform: uppercase; color: var(--accent-text); }
.ch-title { margin: 6px 0 0; font: 400 clamp(2rem, 8.4vw, 3rem)/1.12 var(--font-title); letter-spacing: 0; color: var(--primary); text-wrap: balance; }
.ch-lede { max-width: 34em; margin: 12px 0 0; font-size: 17px; line-height: 1.6; color: var(--ink-soft); text-wrap: pretty; }
.ch-lede strong { font-weight: 600; color: var(--ink); }
/* on arrival from a jump the knot gives a small pull */
@keyframes ch-knot-pulse { 50% { scale: 1.15; } }
@media (prefers-reduced-motion: no-preference) {
  .ch-knot.is-pulse { animation: ch-knot-pulse 500ms var(--out); }
}
@media (min-width: 900px) {
  .ch { --ch-pad: clamp(64px, 10vw, 112px); padding-block: var(--ch-pad); }
  .ch-thread { height: calc(var(--ch-pad) + 1px); }
}

/* fields: faint chapter tints whose top and bottom feather out over 72px, so chapters flow into each other */
.ch[data-field] { isolation: isolate; }
.ch[data-field]::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--field) 72px, var(--field) calc(100% - 72px), transparent);
}
.ch[data-field="sage"] { --field: var(--sage-wash); }
.ch[data-field="blush"] { --field: var(--blush-wash); }
.ch[data-field="soft"] { --field: var(--bg-soft); }
.ch[data-field="table"] { --field: var(--moonbone); }

/* ------------------------------------------------------------------ layout */
.ch-col { max-width: calc(var(--col) + 2 * var(--gut)); margin-inline: auto; padding-inline: var(--gut); }
.ch-wide { max-width: calc(var(--wide) + 2 * var(--gut)); margin-inline: auto; padding-inline: var(--gut); }
/* full width from inside any centred column, with no gutter */
.bleed { width: 100vw; max-width: none; margin-inline: calc(50% - 50vw); padding-inline: 0; }

/* ------------------------------------------------------------------ controls */
.btn { min-height: 48px; padding-block: .55rem; font-size: 16px; letter-spacing: .02em; }
.btn-sm { min-height: 44px; padding: .4rem 1.1rem; font-size: 15px; }
.btn-lg { min-height: 52px; padding-inline: 1.75rem; }
.btn-block { display: flex; width: 100%; }
.btn:active:not([disabled]) { scale: .97; }
/* a quiet action in running text or under a block: a 44px tap row, underlined */
.text-btn {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0; border: 0; background: none;
  font: 600 16px/1.3 var(--font-body); letter-spacing: .02em; color: var(--accent-text); cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; text-decoration-color: rgba(126, 95, 110, .45);
}
.text-btn:hover { color: var(--primary); text-decoration-color: currentColor; }
/* a 44px pill on a blush wash (the day's dress, a look, a filter) */
.chip {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px; border: 0; border-radius: 999px;
  background: var(--blush-wash); color: var(--accent-text); font: 600 15px/1.2 var(--font-body); letter-spacing: .01em;
  text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.chip:hover { background: #F8E7EA; color: var(--accent-text); }
.chip:active { scale: .97; }

/* ------------------------------------------------------------------ photographs: the print grade
   a colour photograph printed into the paper: a touch less saturation, the fine grain and a pressed edge */
.print { position: relative; isolation: isolate; }
.print img { filter: saturate(.86) contrast(1.02); }
.print::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; border-radius: inherit; background: var(--grain);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22), inset 0 1px 3px rgba(40, 46, 43, .2), inset 0 0 44px rgba(40, 46, 43, .09);
}
/* on sharp screens the grain is finer than a print's: half as strong, everywhere grain is used */
@media (min-resolution: 2dppx) {
  .print::after, .photo-slot::before, .gx-tile::after { opacity: .5; }
}

/* ------------------------------------------------------------------ [data-snap]: a horizontal scroll-snap list
   (story.js marks the current item .is-current and drives [data-snap-prev] / [data-snap-next] / [data-snap-count]).
   Only a [data-snap-wrap]'s own child is one: the maps' sheet keeps its state in a data-snap of its own (peek, half,
   full) and stays a sheet */
[data-snap-wrap] > [data-snap] {
  display: flex; gap: 12px; margin: 0; padding: 0 var(--gut); list-style: none;
  overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; scroll-padding-inline: var(--gut);
  overscroll-behavior-x: contain; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
[data-snap-wrap] > [data-snap]::-webkit-scrollbar { display: none; }
[data-snap-wrap] > [data-snap] > * { flex: none; scroll-snap-align: start; }
[data-snap-wrap] > [data-snap]:focus-visible { outline-offset: -3px; }
[data-snap-prev], [data-snap-next] {
  width: 44px; height: 44px; display: inline-grid; place-items: center; padding: 0; border: 1px solid var(--line); border-radius: 50%;
  background: #fff; color: var(--primary); font: 400 22px/1 var(--font-title); cursor: pointer;
}
[data-snap-prev]:disabled, [data-snap-next]:disabled,
[data-snap-prev][aria-disabled="true"], [data-snap-next][aria-disabled="true"] { opacity: .4; cursor: default; }
[data-snap-count] { min-width: 4.5em; text-align: center; font: 400 16px/1.2 var(--font-title); font-variant-numeric: lining-nums tabular-nums; color: var(--ink-soft); }

/* ------------------------------------------------------------------ the couple's dashboard (#admin) stands alone */
html.view-admin #main > :not(#page-admin), html.view-admin .site-footer { display: none !important; }

/* ------------------------------------------------------------------ reduced motion: finished and still
   (style.css's global rule stops every animation and transition; the progress line is not drawn at all) */
@media (prefers-reduced-motion: reduce) {
  .hdr-progress { display: none; }
}

@media print {
  .hdr, .toc, .now-pill { display: none !important; }
  .ch[data-field]::before { display: none; }
  /* a pager prints every item, at rest, row after row (a scroller prints only what is in its window) */
  [data-snap-wrap] > [data-snap] { overflow: visible !important; flex-wrap: wrap; row-gap: 16px; scroll-snap-type: none; }
  [data-snap-wrap] > [data-snap] > * { break-inside: avoid; animation: none !important; }
  [data-snap-prev], [data-snap-next], [data-snap-count] { display: none !important; }
}
/* ---- w/css/s-invite.css ---- */
/* THE SMITH WEDDING · I The Invitation: the gate, the invitation card, the letter and the colophon (WP1). Scope: #gate, #home, #welcome, .colophon */
/* =====================================================================
   SPEC v9 §2.3 (1), §2.6 "Gate", "I · The invitation card", "I · A note from us", "Colophon".
   Phones first (320-430 px); two columns from 900px and on phones held sideways.
   - The gate (#gate; #gate-ghost is the copy motion.js plays the exit with): a card on white paper, the names on one
     line, a 52px field, the message line kept, Enter at full width. No toile below 600px. P1 (html.story-vt): the
     card is tied with two rose ribbons and closed with the wax seal, which breaks when the code is right; a View
     Transition then carries the monogram, the names and the date into the header and the hero.
   - The invitation card (#home): the whole invitation on the first phone screen. The arch's height follows the
     screen (it gives way first), the names never wrap, the countdown is four hairline columns of a fixed height,
     one call to action at a time (html classes), and during the weekend the live card (#heroNow) in the
     countdown's place with its height kept.
   - The letter (#welcome): a drop cap, left-aligned reading text, the signature with a small round portrait, the
     weekend and the calendar.
   - The colophon (footer.colophon): the monogram, the rule, the names, the way back to the invitation.
   Motion (inside prefers-reduced-motion: no-preference; with reduced motion everything rests, finished):
   the gate's entrance, wait, nudge, unseal and exit (moved here from motion.css), the home intro (also moved; the
   photograph's first frame is already on the paper, so the LCP never waits), the letter's rise and signature,
   the hero's recede scrub and the thread's bead.
   ===================================================================== */

/* ------------------------------------------------------------------ the gate (look) */
:is(#gate, #gate-ghost) { padding: max(12px, env(safe-area-inset-top, 0px)) 12px max(16px, env(safe-area-inset-bottom, 0px)); }
:is(#gate, #gate-ghost) .gate-card {
  --gate-px: clamp(16px, 5vw, 28px);
  max-width: 440px; padding: 24px var(--gate-px) 22px; border-radius: 16px;
}
:is(#gate, #gate-ghost) .gate-card > .orn { inset: 12px; --cs: 44px; }
:is(#gate, #gate-ghost) .logo-gate { width: 97px; height: 108px; margin: 0 auto 8px; }
@media (max-height: 660px) { :is(#gate, #gate-ghost) .logo-gate { width: 75px; height: 84px; margin-bottom: 6px; } }
:is(#gate, #gate-ghost) .gate-card .eyebrow { margin: 0 0 6px; font-size: 13px; letter-spacing: .2em; line-height: 1.4; }
/* the names on one line, whatever the phone */
:is(#gate, #gate-ghost) .gate-names { font-size: clamp(2.6rem, 13vw, 3.6rem); line-height: 1.12; white-space: nowrap; }
:is(#gate, #gate-ghost) .gate-date { margin: 2px 0 0; font: 400 20px/1.3 var(--font-title); color: var(--primary); }
:is(#gate, #gate-ghost) .gate-card .orule { --ow: 170px; margin: 12px auto 8px; }
:is(#gate, #gate-ghost) .gate-card .label { margin: 12px 0 8px; font: 500 16px/1.4 var(--font-body); color: var(--ink); }
:is(#gate, #gate-ghost) .gate-input {
  max-width: 300px; min-height: 52px; padding: 8px 14px; border-radius: 12px; text-align: center;
  font: 600 22px/1.2 var(--font-body); letter-spacing: .22em; font-variant-numeric: lining-nums tabular-nums;
}
/* the message line is always there (two lines kept), so a message never moves the card */
:is(#gate, #gate-ghost) .gate-card .form-msg { width: 100%; max-width: 300px; min-height: 44px; margin-top: 6px; font-size: 15px; line-height: 1.45; text-align: center; }
:is(#gate, #gate-ghost) .gate-card .form-msg:not(.error) { font-size: 16px; }
:is(#gate, #gate-ghost) .gate-card .btn { width: 100%; max-width: 300px; min-height: 48px; margin-top: 4px; }
/* the wax seal that hovers below the card while the code is checked (today's, without View Transitions) */
:is(#gate, #gate-ghost) .gate-seal { bottom: -40px; width: 80px; margin-left: -40px; }
/* no toile at the foot of a phone: the card is the whole screen */
@media (max-width: 599px) { :is(#gate, #gate-ghost) .gate-scene { display: none; } }
@media (min-width: 600px) {
  :is(#gate, #gate-ghost) { padding: 1.25rem 1.25rem 4.25rem; }
  :is(#gate, #gate-ghost) .gate-card { --gate-px: 2.2rem; padding: 2.9rem var(--gate-px) 3.4rem; border-radius: 18px; }
  :is(#gate, #gate-ghost) .gate-card > .orn { inset: 16px; --cs: 62px; }
  :is(#gate, #gate-ghost) .logo-gate { width: 111px; height: 124px; margin-bottom: 12px; }
  :is(#gate, #gate-ghost) .gate-seal { bottom: -54px; width: 108px; margin-left: -54px; }
}
/* a phone on its side: the card is taller than the screen, so the monogram gives some of its height back */
@media (min-width: 600px) and (max-height: 520px) { :is(#gate, #gate-ghost) .logo-gate { width: 75px; height: 84px; margin-bottom: 8px; } }

/* P1 (html.story-vt): two rose ribbons tie the card, edge to edge, and the wax seal closes them (in the rule's place).
   With reduced motion the seal is there too, already pressed, and the gate simply closes; elsewhere (no View
   Transitions) today's engraved rule, and the seal that hovers below the card's foot while the code is checked */
:is(#gate, #gate-ghost) .gate-tie {
  display: none; position: relative; z-index: 2; align-self: stretch; height: 40px;
  margin: 10px calc(-1 * var(--gate-px) - 1px) 4px; overflow-x: clip; pointer-events: none;
}
html.story-vt :is(#gate, #gate-ghost) .gate-tie { display: block; }
html.story-vt :is(#gate, #gate-ghost) :is(.gate-card > .orule, .gate-seal) { display: none; }
@media (prefers-reduced-motion: reduce) {
  :is(#gate, #gate-ghost) .gate-tie { display: block; }
  :is(#gate, #gate-ghost) :is(.gate-card > .orule, .gate-seal) { display: none; }
}
:is(#gate, #gate-ghost) .gate-ribbon {
  position: absolute; top: 50%; height: 5.5px; margin-top: -2.75px;
  border-top: 1.25px solid var(--dusk-rose); border-bottom: 1.25px solid var(--dusk-rose);
}
:is(#gate, #gate-ghost) .gate-ribbon--l { left: 0; right: 50%; transform-origin: 100% 50%; }
:is(#gate, #gate-ghost) .gate-ribbon--r { left: 50%; right: 0; transform-origin: 0 50%; }
:is(#gate, #gate-ghost) .gate-wax {
  position: absolute; left: 50%; top: 50%; width: 56px; height: 56px; margin: -28px 0 0 -28px; rotate: -6deg;
  filter: drop-shadow(0 2px 2px rgba(110, 79, 94, .3));
}
:is(#gate, #gate-ghost) .gate-wax__half { position: absolute; inset: 0; transform-origin: 50% 100%; background: url(../img/ornament/seal.svg) center / contain no-repeat; }
/* the crack the seal breaks along */
:is(#gate, #gate-ghost) .gate-wax__half--l { clip-path: polygon(0 0, 53% 0, 47% 24%, 55% 47%, 46% 71%, 52% 100%, 0 100%); }
:is(#gate, #gate-ghost) .gate-wax__half--r { clip-path: polygon(53% 0, 100% 0, 100% 100%, 52% 100%, 46% 71%, 55% 47%, 47% 24%); }

/* ------------------------------------------------------------------ I · the invitation card (#home) */
#home {
  /* the arch gives way first on a short screen: 150 to 330px tall, 4:5 */
  --ah: clamp(150px, calc(100svh - 490px), 330px);
  position: relative; display: flex; flex-direction: column; gap: 0;
  max-width: none; min-height: calc(100svh - var(--hdr)); margin: 0; padding: 12px 12px 0;
}
#home .hero-card {
  position: relative; isolation: isolate; flex: 1 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 100%; max-width: 560px; margin: 0 auto; padding: 22px var(--gut) 34px; text-align: center;
  border-radius: 6px; background: radial-gradient(130% 55% at 50% 0%, #FDF6F7 0%, rgba(253, 246, 247, 0) 70%), #fff;
  /* the double inset frame of a printed card */
  box-shadow: inset 0 0 0 1px rgba(185, 196, 189, .55), inset 0 0 0 5px #fff, inset 0 0 0 6px rgba(185, 196, 189, .32);
}
#home .hero-card > .orn { inset: 12px; --cs: 44px; opacity: .45; }
#home .hero-eyebrow { position: relative; z-index: 1; margin: 0 0 14px; font: 600 13px/1.4 var(--font-body); letter-spacing: .2em; text-transform: uppercase; color: var(--accent-text); }

/* the arch: the photograph printed into the paper, a hairline frame drawn around it with a star at its crown */
#home .hero-arch-wrap { position: relative; z-index: 1; padding-top: 8px; }
#home .arch-wrap {
  position: relative; width: calc(var(--ah) * .8); max-width: none; height: var(--ah);
  border-radius: 999px 999px 10px 10px; box-shadow: 0 2px 4px rgba(52, 62, 58, .05), 0 22px 40px -26px rgba(52, 62, 58, .5);
}
#home .arch.photo-slot { width: 100%; height: 100%; aspect-ratio: auto; border-radius: inherit; }
#home .arch.photo-slot picture { display: block; width: 100%; height: 100%; }
#home .arch img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; }
#home .arch-frame { inset: -8px; border-color: rgba(142, 154, 146, .6); border-radius: 999px 999px 16px 16px; }
#home .arch-frame::before { width: 22px; height: 10px; }
#home .arch-frame::after { width: 13px; height: 13px; }

/* the swallows: one on a phone, a pair on a wide screen, behind the arch (decoration: drawn only with motion,
   painted after load; [data-ambient] rests them off screen) */
#home .hero-sky { position: absolute; z-index: 0; left: 6px; right: 6px; top: 6px; height: min(60%, 420px); overflow: hidden; pointer-events: none; container-type: inline-size; border-radius: 4px; }
#home .hero-sky .b2 { display: none; }

/* the words */
#home .hero-words { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; width: 100%; }
#home .hero-names {
  margin: 14px 0 0; font: 400 clamp(2.9rem, 14vw, 5.5rem)/1.02 var(--font-script); letter-spacing: 0;
  color: var(--accent-text); white-space: nowrap;
}
#home .hero-names .hn { display: inline-block; padding: .16em .32em; margin: -.16em -.32em; }
#home .hero-names .amp { display: inline-block; padding: 0 .06em; font-size: .62em; color: var(--heather); }
#home .hero-sub { margin: 2px 0 0; font: italic 400 18px/1.3 var(--font-title); color: var(--ink-soft); }
#home .hero-rule { --ow: 150px; margin: 12px auto 10px; }
#home .hero-date { margin: 0; font: 400 clamp(1.3rem, 6vw, 1.6rem)/1.25 var(--font-title); color: var(--primary); text-wrap: balance; }
#home .hero-venue { margin: 4px 0 0; font-size: clamp(14.5px, 4.6vw, 15px); line-height: 1.45; letter-spacing: 0; color: var(--ink-soft); }

/* the countdown slot: four hairline columns of a fixed height; during the weekend the live card takes its place */
#home .hero-slot { width: 100%; margin-top: 16px; }
#home .countdown { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); width: min(100%, 300px); height: 56px; margin: 0 auto; gap: 0; flex-wrap: nowrap; }
#home .cd-col { display: flex; flex-direction: column; align-items: center; justify-content: center; min-width: 0; }
#home .cd-col + .cd-col { border-left: 1px solid var(--line); }
#home .cd-n { display: inline-block; font: 400 26px/1.1 var(--font-title); font-variant-numeric: lining-nums tabular-nums; color: var(--primary); }
#home .cd-u { font: 600 13px/1.5 var(--font-body); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); }
#home .cd-done { grid-column: 1 / -1; align-self: center; font: 400 2.6rem/56px var(--font-script); color: var(--accent-text); white-space: nowrap; }

/* one call to action at a time: reply (replies open, none sent, before the weekend), the weekend (replied, closed
   or during it), the photographs (after it) */
#home .hero-ctas { display: flex; justify-content: center; width: 100%; margin-top: 18px; }
#home .hero-cta { display: none; width: 100%; max-width: 320px; padding-inline: 16px; gap: .28em; white-space: nowrap; }
html:not([data-phase]) #home .hero-cta--reply,
html[data-phase="pre"].rsvp-open:not(.has-replied) #home .hero-cta--reply,
html[data-phase="pre"]:not(.rsvp-open) #home .hero-cta--weekend,
html[data-phase="pre"].has-replied #home .hero-cta--weekend,
html[data-phase="weekend"] #home .hero-cta--weekend,
html[data-phase="post"] #home .hero-cta--photos { display: inline-flex; }
/* after the weekend the countdown's place reads "Just married!": "are getting married" steps aside */
html[data-phase="post"] #home .hero-sub { display: none; }

/* the thread hangs from the card's foot into knot I */
#home .hero-thread {
  position: absolute; z-index: 2; left: 50%; bottom: 0; width: 1.25px; height: 26px; margin-left: -.625px;
  background: var(--thread); transform-origin: 50% 0; pointer-events: none;
}
#home .hero-thread::after {
  content: ""; position: absolute; left: 50%; top: 0; width: 5px; height: 5px; margin-left: -2.5px; border-radius: 50%;
  background: var(--thread); opacity: 0;
}

/* ------------------------------------------------------------------ the weekend: the live card (#heroNow)
   html.is-weekend is known before the first paint: the arch shrinks, the countdown steps aside and the card is
   there at once with its height kept (a placeholder until the first 'ww:live'; s-invite.js renders it) */
#home .hero-now { display: none; }
html.is-weekend #home { --ah: clamp(120px, 22svh, 200px); }
html.is-weekend #home .hero-eyebrow, html.is-weekend #home .hero-rule, html.is-weekend #home .hero-sky { display: none; }
html.is-weekend #home .hero-sub { margin-bottom: 8px; }
html.is-weekend #home .countdown { display: none; }
/* (from the top: when the live card grows, only what is under it moves) */
html.is-weekend #home .hero-card { justify-content: flex-start; }
html.is-weekend #home .hero-now {
  display: block; width: 100%; max-width: 420px; min-height: 276px; margin: 0 auto; padding: 14px 16px 12px; border-radius: 16px;
  text-align: left; background: linear-gradient(#FCF3F4, #fff 72%);
  box-shadow: inset 0 0 0 1px #F1DDE1, 0 14px 30px -22px rgba(110, 79, 94, .45);
}
/* Monday afternoon, everything done: the countdown's place again, reading "Just married!" */
html.is-weekend #home.hero--quiet .hero-now { display: none; }
html.is-weekend #home.hero--quiet .countdown { display: grid; }
#home .hero-now__eyebrow { display: flex; align-items: center; flex-wrap: wrap; gap: 0 8px; margin: 0; font: 600 13px/1.4 var(--font-body); letter-spacing: .14em; text-transform: uppercase; color: var(--accent-text); }
#home .hero-now__day { font-weight: 500; letter-spacing: .04em; text-transform: none; color: var(--ink-soft); }
#home .hero-now__dot { position: relative; flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--dusk-rose); }
#home .hero-now__dot::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: var(--dusk-rose); opacity: 0; }
#home .hero-now__t { margin: 6px 0 0; font: 400 24px/1.2 var(--font-title); color: var(--primary); text-wrap: balance; }
#home .hero-now__m { margin: 2px 0 0; font-size: 15px; line-height: 1.45; color: var(--ink-soft); }
#home .hero-now__left { display: flex; align-items: center; gap: 10px; margin: 10px 0 0; font: 500 13px/1.3 var(--font-body); color: var(--ink-soft); white-space: nowrap; }
#home .hero-now__bar { flex: 1; height: 2px; border-radius: 2px; background: #F1E4E6; overflow: hidden; }
#home .hero-now__bar i { display: block; height: 100%; background: var(--dusk-rose); transform-origin: 0 50%; transform: scaleX(var(--p, 0)); transition: transform 600ms var(--io); }
#home .hero-now__go { margin-top: 12px; gap: 10px; }
#home .hero-now__go svg { width: 20px; height: 20px; flex: none; }
#home .hero-now__see { margin-top: 6px; }
#home .hero-now__also { margin: 8px 0 0; font: italic 400 15px/1.4 var(--font-title); color: var(--accent-text); }
#home .hero-now__next {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 12px; width: 100%; min-height: 48px;
  margin-top: 10px; padding: 8px 0 0; border: 0; border-top: 1px solid #F1DDE1; background: none; color: inherit; font: inherit;
  text-align: left; text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
#home .hero-now__nl { grid-column: 1; font: 600 13px/1.4 var(--font-body); letter-spacing: .14em; text-transform: uppercase; color: var(--accent-text); }
#home .hero-now__nl [data-k="nrel"] { font-weight: 500; letter-spacing: .04em; text-transform: none; color: var(--ink-soft); }
#home .hero-now__nt { grid-column: 1; font: 400 18px/1.3 var(--font-title); color: var(--primary); }
#home .hero-now__chev { grid-column: 2; grid-row: 1 / span 2; width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; background: var(--primary); color: #fff; }
#home .hero-now__chev svg { width: 16px; height: 16px; }
#home .hero-now__next:hover .hero-now__nt { color: var(--accent-text); }
#home .hero-now__ph { margin: 6px 0 0; font: italic 400 18px/1.4 var(--font-title); color: var(--ink-soft); }

/* ------------------------------------------------------------------ short phones: the eyebrow, then the countdown, give way */
@media (max-width: 899px) and (orientation: portrait) and (max-height: 640px) {
  #home .hero-eyebrow { display: none; }
}
@media (max-width: 899px) and (orientation: portrait) and (max-height: 600px) {
  #home .countdown { display: none; }
}

/* ------------------------------------------------------------------ two columns: phones held sideways, and from 900px
   one card, the arch on the left and the words on the right */
@media (orientation: landscape) and (max-height: 520px) {
  #home { --ah: clamp(150px, calc(100svh - var(--hdr) - 64px), 330px); padding: 8px var(--gut) 0; }
  #home .hero-card {
    display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto auto minmax(0, 1fr);
    grid-template-areas: "arch ." "arch eyebrow" "arch words" "arch ."; column-gap: clamp(24px, 5vw, 48px); align-items: center;
    max-width: 920px; padding: 12px 28px 24px;
  }
  /* a phone held sideways has no height to spare: the eyebrow and the rule step aside */
  #home .hero-eyebrow, #home .hero-rule { display: none; }
  #home .hero-arch-wrap { grid-area: arch; padding: 8px 8px 0; }
  #home .hero-words { grid-area: words; }
  #home .hero-names { margin-top: 0; font-size: clamp(2.6rem, 12svh, 3.6rem); }
  #home .hero-sub { margin-bottom: 8px; }
  #home .hero-slot { margin-top: 12px; }
  #home .hero-ctas { margin-top: 14px; }
  html.is-weekend #home { --ah: clamp(150px, calc(100svh - var(--hdr) - 64px), 330px); }
  html.is-weekend #home .hero-card { grid-template-rows: 0 auto auto minmax(0, 1fr); }
  /* the weekend sideways: the names, then what is happening now (the card names the day and the place) */
  html.is-weekend #home :is(.hero-sub, .hero-date, .hero-venue) { display: none; }
}
@media (orientation: landscape) and (max-height: 380px) {
  #home .hero-sub { display: none; }
}
@media (min-width: 900px) and (min-height: 521px) {
  /* the arch stands as tall as the screen lets it (and never so wide that the words lose their column): the
     photograph is the card's left half, not a stamp in the middle of it */
  #home { --ah: clamp(300px, min(calc(100svh - var(--hdr) - 230px), 44vw), 640px); padding: 24px var(--gut) 0; }
  #home .hero-card {
    display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto auto minmax(0, 1fr);
    grid-template-areas: "arch ." "arch eyebrow" "arch words" "arch ."; column-gap: clamp(40px, 5vw, 72px); align-items: center;
    max-width: 1200px; padding: 40px clamp(40px, 5vw, 72px) 48px;
  }
  #home .hero-card > .orn { inset: 16px; --cs: 58px; }
  #home .hero-eyebrow { grid-area: eyebrow; margin: 0 0 6px; }
  #home .hero-arch-wrap { grid-area: arch; padding: 8px; }
  #home .hero-words { grid-area: words; }
  #home .hero-names { margin-top: 0; font-size: clamp(3.4rem, 6.2vw, 5.5rem); }
  #home .hero-sub { font-size: 21px; }
  #home .hero-rule { --ow: 190px; margin: 16px auto 12px; }
  #home .hero-date { font-size: clamp(1.6rem, 2.4vw, 2rem); }
  #home .hero-venue { font-size: 17px; }
  #home .hero-slot { margin-top: 22px; }
  #home .countdown { width: min(100%, 380px); height: 64px; }
  #home .cd-n { font-size: 30px; }
  #home .hero-ctas { margin-top: 24px; }
  #home .hero-cta { width: auto; max-width: none; padding-inline: 2rem; }
  /* the toile is a wide screen's: the swallows fly as a pair */
  #home .hero-sky { left: 16px; right: 16px; top: 16px; height: 46%; }
  #home .hero-sky .b2 { display: block; }
  html.is-weekend #home { --ah: clamp(260px, calc(100svh - var(--hdr) - 160px), 420px); }
  html.is-weekend #home .hero-eyebrow { display: block; }
}

/* ------------------------------------------------------------------ I · a note from us (#welcome) */
#welcome .letter { max-width: calc(640px + 2 * var(--gut)); text-align: left; }
#welcome .letter-text { margin: 0; font-size: 17px; line-height: 1.7; color: var(--ink); text-wrap: pretty; }
/* a drop cap three lines deep (a floated capital where initial-letter is not known) */
#welcome .letter-text::first-letter {
  -webkit-initial-letter: 3; initial-letter: 3; margin-right: .14em;
  font-family: var(--font-title); font-weight: 400; color: var(--accent-text);
}
@supports not ((initial-letter: 3) or (-webkit-initial-letter: 3)) {
  #welcome .letter-text::first-letter { float: left; margin: .08em .12em 0 0; font-size: 3.55em; line-height: .78; }
}
#welcome .letter-sig { display: flex; align-items: center; gap: 14px; margin-top: 22px; }
#welcome .letter-portrait { flex: none; width: 56px; height: 56px; border-radius: 50%; background: var(--bg-soft); box-shadow: 0 0 0 1px var(--line); }
#welcome .letter-portrait.empty { display: none; }
#welcome .letter-portrait.empty::after { content: none; }
#welcome .letter-portrait img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 28%; filter: grayscale(1) contrast(1.04); }
#welcome .letter-names { margin: 0; padding: .1em .3em; margin-inline: -.3em; font: 400 2.4rem/1.15 var(--font-script); color: var(--accent-text); white-space: nowrap; }
#welcome .glance__foot { margin: 0; padding: 12px 20px 14px; border-top: 1px solid var(--line); }
#welcome .glance__foot .text-btn svg { width: 18px; height: 18px; flex: none; }
/* the essentials at a glance: when, where, stay, wear, reply; each row is the way to its chapter */
#welcome .glance { margin: 30px 0 0; border-radius: 18px; background: #fff; box-shadow: 0 0 0 1px var(--line), 0 16px 36px -24px rgba(60, 72, 66, .4); overflow: hidden; }
#welcome .glance__t { margin: 0; padding: 16px 20px 12px; font: 600 13px/1.4 var(--font-body); letter-spacing: .18em; text-transform: uppercase; color: var(--accent-text); }
#welcome .glance__list { margin: 0; padding: 0; list-style: none; }
#welcome .gl-row { display: grid; grid-template-columns: 64px minmax(0, 1fr) 20px; grid-template-areas: "k v go" "k s go"; column-gap: 12px; align-items: center; min-height: 64px; padding: 12px 16px 12px 20px; border-top: 1px solid var(--line); color: inherit; text-decoration: none; transition: background-color .2s; }
#welcome .gl-k { grid-area: k; align-self: start; padding-top: 4px; font: 600 13px/1.4 var(--font-body); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-soft); }
#welcome .gl-v { grid-area: v; font: 400 18px/1.3 var(--font-title); color: var(--primary); }
#welcome .gl-s { grid-area: s; font-size: 14px; line-height: 1.45; color: var(--ink-soft); }
#welcome .gl-go { grid-area: go; width: 20px; height: 20px; color: var(--accent-text); transition: transform .25s var(--out); }
#welcome .gl-row:active { background: var(--bg-soft); }
@media (hover: hover) { #welcome .gl-row:hover { background: var(--bg-soft); } #welcome .gl-row:hover .gl-go { transform: translateX(3px); } }
#welcome .gl-row:focus-visible { outline: 2px solid var(--primary); outline-offset: -3px; }
@media (min-width: 600px) { #welcome .gl-row { grid-template-columns: 84px minmax(0, 1fr) 20px; padding-inline: 24px 20px; } #welcome .glance__t { padding-inline: 24px; } }
@media print { #welcome .gl-go { display: none; } }
/* a wide screen: the letter on the left, at the height of the card's middle; the essentials beside it on the right,
   so the whole invitation (who, when, where, and the way to each chapter) is one screen */
@media screen and (min-width: 1100px) {
  #welcome .letter {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 500px); grid-template-rows: 1fr auto auto 1fr;
    column-gap: clamp(56px, 6vw, 88px); max-width: calc(var(--wide) + 2 * var(--gut));
  }
  #welcome .letter-text { grid-area: 2 / 1; font-size: 18px; line-height: 1.75; }
  #welcome .letter-sig { grid-area: 3 / 1; margin-top: 26px; }
  #welcome .letter-portrait { width: 64px; height: 64px; }
  #welcome .letter-names { font-size: 2.75rem; }
  #welcome .glance { grid-area: 1 / 2 / 5 / 3; margin: 0; }
}
@media (min-width: 600px) {
  #home .hero-sub { font-size: 20px; }
}

/* ------------------------------------------------------------------ the colophon */
.colophon { padding: 56px var(--gut) calc(40px + env(safe-area-inset-bottom, 0px)); }
.colophon .logo-footer { width: 61px; height: 68px; margin-bottom: 10px; }
.colophon .orule { --ow: 160px; margin: 0 auto 8px; }
.colophon .footer-names { margin: 0; font-size: 3rem; line-height: 1.2; }
.colophon .colophon-date { margin: 0; font: 400 18px/1.4 var(--font-title); color: var(--primary); }
.colophon .colophon-note { max-width: 30em; margin: 10px auto 0; font-size: 15px; line-height: 1.55; color: var(--ink-soft); text-wrap: balance; }
.colophon .colophon-note:empty { display: none; }
.colophon .colophon-back { margin: 22px 0 0; }
.colophon .colophon-back .text-btn svg { width: 18px; height: 18px; flex: none; }
.colophon .colophon-admin { margin: 4px 0 0; }
.colophon .admin-link {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 14px;
  font: 500 15px/1.3 var(--font-body); letter-spacing: .02em; color: var(--ink-soft); text-decoration: none;
}
.colophon .admin-link:hover { color: var(--primary); text-decoration: underline; text-underline-offset: 4px; }

/* =====================================================================
   MOTION (nothing here runs with reduced motion: every element rests in its final state)
   ===================================================================== */
@keyframes inv-print { from { opacity: .3; filter: blur(8px) saturate(.6); scale: 1.025; } 60% { filter: blur(1px) saturate(.9); } }
/* motion.css's ink-write from nothing at all (a signature waiting below the fold is not a faint grey line) */
@keyframes inv-ink {
  0% { -webkit-mask-image: linear-gradient(100deg, #000 40%, transparent 60%); mask-image: linear-gradient(100deg, #000 40%, transparent 60%);
       -webkit-mask-size: 300% 100%; mask-size: 300% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
       -webkit-mask-position: 100% 0; mask-position: 100% 0; opacity: 0; filter: blur(6px); translate: 0 .18em; }
  55% { filter: blur(1.2px); opacity: 1; }
  100% { -webkit-mask-image: linear-gradient(100deg, #000 40%, transparent 60%); mask-image: linear-gradient(100deg, #000 40%, transparent 60%);
         -webkit-mask-size: 300% 100%; mask-size: 300% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 0 0; mask-position: 0 0; opacity: 1; filter: blur(0); translate: 0 0; }
}
@keyframes inv-drop { from { scale: 1 0; } }
@keyframes inv-bead { 0% { opacity: 0; translate: 0 0; } 12% { opacity: 1; } 82% { opacity: 1; } 100% { opacity: 0; translate: 0 var(--bead, 76px); } }
@keyframes inv-halo { from { opacity: .5; scale: 1; } to { opacity: 0; scale: 2.2; } }
@keyframes inv-ribbon { from { transform: scaleX(0); } }
@keyframes inv-stamp { from { opacity: 0; scale: 1.3; rotate: -12deg; } 70% { opacity: 1; scale: .97; } }
@keyframes inv-breathe { from { scale: 1; } to { scale: 1.07; } }
@keyframes inv-wobble { 20% { rotate: -9deg; } 45% { rotate: -3deg; } 70% { rotate: -8deg; } 88% { rotate: -5deg; } }
@keyframes inv-split-l { to { opacity: 0; transform: translateX(-16px) rotate(-10deg); } }
@keyframes inv-split-r { to { opacity: 0; transform: translateX(16px) rotate(10deg); } }
@keyframes inv-retract-l { to { opacity: 0; transform: translateX(-100%); } }
@keyframes inv-retract-r { to { opacity: 0; transform: translateX(100%); } }
@keyframes inv-recede-arch { to { transform: translateY(-16px); } }
@keyframes inv-recede-names { to { transform: translateY(-8px); } }
@keyframes inv-recede-slot { to { opacity: .4; } }

@media screen and (prefers-reduced-motion: no-preference) {

  /* ------------------------------------------------------------------ the invitation gate (entrance) */
  #gate { animation: fade 500ms var(--out) backwards; }
  #gate .gate-card { animation: rise 1000ms var(--out) 40ms backwards; --rise: 24px; }
  #gate .gate-card > .orn { animation: fade 1500ms var(--out) 450ms backwards; }
  /* the monogram is written: the stem comes down, the return sweeps round to the left, the ribbon runs through,
     the flourish closes it (each along its own line, half a second apart); then the whole ink takes over, the
     stars come out, and a light passes over the mark now and then */
  #gate .gate-card .lg-rv { animation: lg-write 1870ms var(--pen) calc(300ms + var(--i) * 510ms) backwards; }
  #gate .gate-card .lg-all { animation: lg-pen 1ms linear 3720ms backwards; }
  #gate .gate-card .lg-star--a { animation: lg-twinkle 7s var(--io) 3900ms infinite backwards; }
  #gate .gate-card .lg-star--b { animation: lg-twinkle 7s var(--io) 4700ms infinite backwards; }
  #gate .gate-card .lg-star--c { animation: lg-twinkle 7s var(--io) 5500ms infinite backwards; }
  @supports ((-webkit-mask-image: linear-gradient(#000, #000)) or (mask-image: linear-gradient(#000, #000))) {
    #gate .gate-card .lg-shine { -webkit-mask: linear-gradient(105deg, transparent 43%, #000 50%, transparent 57%) 100% 0 / 300% 100% no-repeat; mask: linear-gradient(105deg, transparent 43%, #000 50%, transparent 57%) 100% 0 / 300% 100% no-repeat;
      animation: lg-shine 9s var(--io) 3900ms infinite backwards; }
  }
  #gate .gate-card .eyebrow { animation: rise 900ms var(--out) 380ms backwards; --rise: 10px; }
  #gate .gate-names { padding: .14em .3em; margin: -.14em -.3em; animation: ink-write 1600ms var(--e-ink) 520ms backwards; }
  #gate .gate-date { animation: rise 900ms var(--out) 760ms backwards; --rise: 10px; }
  #gate .gate-card .orule { animation: rule-in 1200ms var(--io) 880ms backwards; }
  /* P1: the ribbons are drawn out from the seal's place, then the seal is pressed on */
  #gate .gate-ribbon { animation: inv-ribbon 900ms var(--io) 700ms backwards; }
  #gate .gate-wax { animation: inv-stamp 600ms var(--out) 1100ms backwards; }
  /* the form comes with the card and is ready at once (app.js focuses the field straight away).
     While the server checks the code the seal hovers over the card's foot (or, tied, breathes on the ribbon); a
     code that is not right gives the field a small shake, the seal a wobble, and the message rises in */
  #gate .gate-card.is-pending .gate-seal img { animation: seal-breathe 1.7s var(--io) infinite alternate; }
  #gate .gate-card.is-pending .gate-wax { animation: inv-breathe 850ms var(--io) infinite alternate; }
  #gate .gate-card.is-pending .form-msg { animation: fade 600ms var(--out) backwards; }
  #gate .gate-card.is-wrong .gate-input { animation: nudge 440ms var(--io); }
  #gate .gate-card.is-wrong .gate-wax { animation: inv-wobble 480ms var(--io); }
  #gate .gate-card.is-wrong .form-msg { animation: rise 460ms var(--out); --rise: 6px; }
  /* the highlands come up out of the mist once the page has loaded (html.ww-deco): the ridge opens out */
  html.ww-deco #gate .gate-scene .gs-ridge { animation: spread 2400ms var(--io) backwards; }
  #gate .gate-scene .gs-mist { animation: mist 38s var(--io) -9s infinite alternate; }
  #gate .gate-scene { container-type: inline-size; }
  #gate .b1 { top: 26%; width: 30px; animation: fly-x 34s linear 2.2s infinite backwards; }
  #gate .b1 .bob { animation: fly-y-low 11.3s var(--io) 2.2s infinite; }
  /* P1, the right code: the seal breaks along its crack and the ribbons fall away to the edges (motion.js
     WWMotion.unseal); a View Transition then carries the card into the hero */
  #gate.is-unsealed .gate-wax { animation: none; }
  #gate.is-unsealed .gate-wax__half--l { animation: inv-split-l 520ms var(--io) forwards; }
  #gate.is-unsealed .gate-wax__half--r { animation: inv-split-r 520ms var(--io) forwards; }
  #gate.is-unsealed .gate-ribbon--l { animation: inv-retract-l 600ms var(--io) 60ms forwards; }
  #gate.is-unsealed .gate-ribbon--r { animation: inv-retract-r 600ms var(--io) 60ms forwards; }
  #gate.is-unsealed .gate-card :is(.label, .gate-input, .form-msg, .btn) { opacity: 0; transition: opacity 300ms ease; }

  /* ------------------------------------------------------------------ the gate's exit (a copy plays it: #gate-ghost) */
  #gate-ghost, #gate-ghost *, #gate-ghost *::before, #gate-ghost *::after { animation: none !important; }
  #gate-ghost { pointer-events: none; animation: fade-out 900ms var(--io) 1050ms forwards !important; }
  #gate-ghost .gate-card { animation: card-out 760ms var(--io) 1050ms forwards !important; }
  #gate-ghost .gate-card :is(.label, .gate-input, .form-msg, .btn) { animation: fade-out 280ms ease forwards !important; }
  #gate-ghost .gate-seal { visibility: visible; opacity: 1; transition: none; isolation: isolate; }
  #gate-ghost .gate-seal img { rotate: -6deg; animation: press 820ms var(--out) 170ms backwards !important; }
  #gate-ghost .gate-seal::before {
    content: ""; position: absolute; inset: 6%; z-index: -1; border-radius: 50%; opacity: 0; pointer-events: none;
    background: radial-gradient(closest-side, rgba(110, 79, 94, .32), rgba(110, 79, 94, .12) 60%, rgba(110, 79, 94, 0));
    animation: press-shadow 820ms var(--out) 170ms backwards !important;
  }
  html.ww-js #gate-ghost .bird { display: none; }
  /* tied (html.story-vt, when no View Transition carries the card: a deep link): the seal breaks, then the card goes */
  html.story-vt #gate-ghost .gate-wax__half--l { animation: inv-split-l 520ms var(--io) 160ms forwards !important; }
  html.story-vt #gate-ghost .gate-wax__half--r { animation: inv-split-r 520ms var(--io) 160ms forwards !important; }
  html.story-vt #gate-ghost .gate-ribbon--l { animation: inv-retract-l 600ms var(--io) 220ms forwards !important; }
  html.story-vt #gate-ghost .gate-ribbon--r { animation: inv-retract-r 600ms var(--io) 220ms forwards !important; }

  /* ------------------------------------------------------------------ the home intro (once per visit) */
  /* the arch: the frame is drawn up both sides from its foot and meets at the crown */
  html.ww-js:not(.ww-intro-done) #home .arch-frame {
    -webkit-mask: conic-gradient(from 180deg, #000 var(--arc), transparent 0 calc(360deg - var(--arc)), #000 0);
    mask: conic-gradient(from 180deg, #000 var(--arc), transparent 0 calc(360deg - var(--arc)), #000 0);
    animation: arc-draw 1700ms var(--io) 150ms backwards;
  }
  html.ww-js:not(.ww-intro-done) #home .arch-frame::after { animation: fade 900ms var(--out) 1500ms backwards; }
  /* the photograph is printed into the paper once it is decoded (motion.js inkHero, .inked). Its first frame is
     already there (.3, blurred), never transparent: the largest paint never waits for the intro */
  html.ww-js:not(.ww-intro-done) #home .arch.photo-slot:not(.inked) { opacity: .3; filter: blur(8px) saturate(.6); scale: 1.025; }
  html.ww-js:not(.ww-intro-done) #home .arch.photo-slot.inked { animation: inv-print 1700ms var(--e-ink) backwards; }
  /* the words: the names soak in, the rest rises in turn, the thread drops from the card's foot */
  html.ww-js:not(.ww-intro-done) #home .hero-eyebrow { animation: rise 900ms var(--out) 60ms backwards; --rise: 10px; }
  html.ww-js:not(.ww-intro-done) #home .hero-names .hn-1 { animation: ink-write 1500ms var(--e-ink) 200ms backwards; }
  html.ww-js:not(.ww-intro-done) #home .hero-names .amp { animation: fade 1100ms var(--out) 560ms backwards; }
  html.ww-js:not(.ww-intro-done) #home .hero-names .hn-2 { animation: ink-write 1500ms var(--e-ink) 520ms backwards; }
  html.ww-js:not(.ww-intro-done) #home .hero-sub { animation: rise 900ms var(--out) 760ms backwards; --rise: 10px; }
  html.ww-js:not(.ww-intro-done) #home .hero-rule { animation: rule-in 1100ms var(--io) 860ms backwards; }
  html.ww-js:not(.ww-intro-done) #home .hero-date { animation: rise 900ms var(--out) 900ms backwards; --rise: 10px; }
  html.ww-js:not(.ww-intro-done) #home .hero-venue { animation: rise 900ms var(--out) 980ms backwards; --rise: 10px; }
  html.ww-js:not(.ww-intro-done) #home .hero-slot > * { animation: rise 900ms var(--out) 1060ms backwards; --rise: 12px; }
  html.ww-js:not(.ww-intro-done) #home .hero-ctas { animation: rise 900ms var(--out) 1140ms backwards; --rise: 12px; }
  html.ww-js:not(.ww-intro-done) #home .hero-thread { animation: inv-drop 900ms var(--io) 1300ms backwards; }
  /* P1: a bead slides once down the thread, from the card into knot I */
  html.ww-js:not(.ww-intro-done) #home .hero-thread::after { animation: inv-bead 1300ms var(--io) 2300ms backwards; }
  /* carried in from the gate by the View Transition (P1): the names and the date are already in place */
  #home.hero--carried :is(.hero-names .hn, .hero-names .amp, .hero-date) { animation: none !important; }
  /* while the gate is up (or app.js is deciding), the words wait on their first frame; the photograph does not */
  html.ww-hold #home :not(.arch, .arch *), html.ww-hold #home :not(.arch, .arch *)::before,
  html.ww-hold #home :not(.arch, .arch *)::after { animation-play-state: paused !important; }

  /* the swallows (ambient: one loop in view at most, paused off screen by [data-ambient].is-off) */
  #home .hero-sky .b1 { top: 22%; width: 30px; animation: fly-x 30s linear 2.6s infinite backwards; }
  #home .hero-sky .b1 .bob { animation: fly-y-low 10s var(--io) 2.6s infinite; }
  #home .hero-sky .b2 { top: 40%; width: 24px; animation: fly-x-back 58s linear 9s infinite backwards; }
  #home .hero-sky .b2 .bob { animation: fly-y-low 19.3s var(--io) 9s infinite; }
  #home .hero-sky .b2 .w1, #home .hero-sky .b2 .w2 { scale: -1 1; animation-duration: .38s; animation-delay: -.2s; }
  /* the live card: a soft halo round the dot */
  #home .hero-now__dot::after { animation: inv-halo 1.8s var(--out) infinite; }
  /* press feedback */
  #home .hero-now__next:active .hero-now__chev { scale: .94; }

  /* ------------------------------------------------------------------ the letter: the paragraph rises, then the signature is
     inked in (a [data-rv="group"]: its parts wait until it is revealed) */
  html.ww-js #welcome .letter.rvg .letter-text { animation: rise 800ms var(--out) backwards; --rise: 12px; }
  html.ww-js #welcome .letter.rvg .letter-portrait { animation: fade 900ms var(--out) 85ms backwards; }
  html.ww-js #welcome .letter.rvg .letter-names { animation: inv-ink 1500ms var(--e-ink) 400ms backwards; }
  html.ww-js #welcome .letter.rvg .glance { animation: rise 800ms var(--out) 170ms backwards; --rise: 10px; }

  /* ------------------------------------------------------------------ the hero recedes as it leaves (scroll-linked; on
     wrappers, never on what the intro animates) */
  @supports (animation-timeline: view()) {
    #home .hero-arch-wrap { animation: inv-recede-arch linear both; animation-timeline: view(); animation-range: exit 0% exit 100%; }
    #home .hero-names { animation: inv-recede-names linear both; animation-timeline: view(); animation-range: exit 0% exit 100%; }
    #home .hero-slot { animation: inv-recede-slot linear both; animation-timeline: view(); animation-range: exit 0% exit 100%; }
  }

  /* ------------------------------------------------------------------ P1: the View Transition from the gate into the hero */
  html.story-vt::view-transition-group(invite-mono),
  html.story-vt::view-transition-group(invite-names),
  html.story-vt::view-transition-group(invite-date) { animation-duration: 700ms; animation-timing-function: var(--io); }
  html.story-vt::view-transition-old(root), html.story-vt::view-transition-new(root) { animation-duration: 700ms; }
}

@media print {
  #home { min-height: 0; }
  #home .hero-sky, #home .hero-thread, #home .hero-now { display: none !important; }
}
/* ---- w/css/s-weekend.css ---- */
/* THE SMITH WEDDING · II The Weekend: the day rail, the spine, the four days and the Saturday spread (WP2). Scope: #weekend, wk- */
/* =====================================================================
   The days stacked on one thread. The rail (#wkRail) sticks under the header where the screen is tall enough and
   story.js underlines the day under its line (aria-current). The spine (.wk-spine) runs down the left of the days
   at x = 9px: a faint base, the rose thread drawn at the reading line as you scroll (where scroll timelines exist;
   elsewhere simply drawn), 2px through the wedding day; during the weekend (.wk-days.is-live, s-weekend.js) it is
   filled solid up to now instead. Each event hangs on its bead: past (.is-past) filled sage, now (.is-now) rose with
   a halo, a NOW tag and a rose wash, next (.is-next) "· in 40 min". The wedding day (.wk-day--feature) is a
   full-bleed blush spread with the gazebo engraving, a ghost of its date and its title in Pinyon.
   Places: app.js leaves .tl-loc (the place in words) and .tl-where (location.js puts the Navigate button there and
   hides .tl-loc); both are the same 48px row, so the swap never moves the page.
   ===================================================================== */

/* ------------------------------------------------------------------ the day rail
   (it sticks inside .wk-board, the rail and the days: it lets go once the last day has gone by) */
#weekend .wk-rail {
  position: relative; z-index: 40;
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(64px, 1fr);
  height: var(--rail); padding-inline: max(var(--gut), calc((100% - var(--col)) / 2));
  background: #fff; box-shadow: inset 0 -1px 0 var(--line);
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
}
#weekend .wk-rail::-webkit-scrollbar { display: none; }
#weekend .wk-rail:empty { display: none; }
/* (it sticks only where the screen leaves room for it: not on a phone held sideways) */
@media (min-height: 500px) {
  #weekend .wk-rail { position: sticky; top: var(--hdr); }
}
#weekend .wk-rail a {
  position: relative; display: flex; align-items: center; justify-content: center; gap: 6px; min-height: 44px; padding: 0 4px;
  color: var(--ink-soft); text-decoration: none; white-space: nowrap; -webkit-tap-highlight-color: transparent;
  transition: color 320ms var(--e-sheet);
}
#weekend .wk-rail__w { font: 600 13px/1 var(--font-body); letter-spacing: .14em; text-transform: uppercase; }
#weekend .wk-rail__n { font: 400 17px/1 var(--font-title); font-variant-numeric: lining-nums tabular-nums; }
#weekend .wk-rail a::after {
  content: ""; position: absolute; left: 24%; right: 24%; bottom: 0; height: 2px; border-radius: 1px;
  background: var(--thread); transform: scaleX(0); transition: transform 320ms var(--e-sheet);
}
#weekend .wk-rail a:hover { color: var(--accent-text); }
#weekend .wk-rail a[aria-current] { color: var(--accent-text); }
#weekend .wk-rail a[aria-current]::after { transform: none; }
#weekend .wk-rail a:focus-visible { outline-offset: -4px; }
/* during the weekend: today's day carries a rose dot (s-weekend.js) */
#weekend .wk-rail a.is-today .wk-rail__n::after {
  content: ""; display: inline-block; width: 5px; height: 5px; margin-left: 3px; border-radius: 50%; vertical-align: top;
  background: var(--thread);
}

/* ------------------------------------------------------------------ the days and their spine */
#weekend .wk-days {
  position: relative; isolation: isolate;
  max-width: calc(var(--col) + 2 * var(--gut)); margin: 0 auto; padding: 12px var(--gut) 0;
}
#weekend .wk-day { position: relative; padding-left: 34px; scroll-margin-top: calc(var(--hdr) + 8px); }
#weekend .wk-day + .wk-day { margin-top: 48px; }
/* an event (the Now pill goes to its row) lands under the rail too */
#weekend .wk-ev { scroll-margin-top: calc(var(--hdr) + 16px); }
@media (min-height: 500px) {
  #weekend .wk-day { scroll-margin-top: calc(var(--hdr) + var(--rail) + 8px); }
  #weekend .wk-ev { scroll-margin-top: calc(var(--hdr) + var(--rail) + 16px); }
  /* a control the browser scrolls to as it takes the focus (Shift+Tab) clears the rail as well as the header
     (html's scroll-padding-top already keeps the header's height) */
  #weekend .wk-days :is(a[href], button) { scroll-margin-top: calc(var(--rail) + 8px); }
}

/* the spine: 2px wide at x = 9px of the column; it starts at the first day's ring (--spine-top) and fades out at the
   foot, on its way to the venue */
#weekend .wk-spine {
  position: absolute; z-index: 0; top: var(--spine-top, 34px); bottom: 0; left: calc(var(--gut) + 8px); width: 2px; pointer-events: none;
  -webkit-mask: linear-gradient(#000 calc(100% - 140px), transparent); mask: linear-gradient(#000 calc(100% - 140px), transparent);
}
#weekend .wk-spine::before { content: ""; position: absolute; top: 0; bottom: 0; left: .375px; width: 1.25px; background: rgba(180, 138, 147, .3); }
/* the thread, 1.25px; the wedding day's stretch 2px (--feat-top, --feat-h from s-weekend.js) */
#weekend .wk-spine__draw {
  position: absolute; inset: 0; transform-origin: 50% 0;
  background:
    linear-gradient(var(--thread), var(--thread)) 0 var(--feat-top, 0px) / 2px var(--feat-h, 0px) no-repeat,
    linear-gradient(90deg, transparent .375px, var(--thread) .375px 1.625px, transparent 1.625px);
}
/* during the weekend: filled solid up to now (--now-k of the spine's height) */
#weekend .wk-spine__now { position: absolute; inset: 0; background: var(--thread); transform-origin: 50% 0; transform: scaleY(var(--now-k, 0)); display: none; }
#weekend .wk-days.is-live .wk-spine__now { display: block; }
#weekend .wk-days.is-live .wk-spine__draw { display: none; }

/* ------------------------------------------------------------------ a day's head: its ring on the spine, the date, the title, the dress */
#weekend .wk-head { position: relative; }
#weekend .wk-ring { position: absolute; left: -35px; top: 12px; width: 20px; height: 20px; overflow: visible; }
#weekend .wk-ring circle { fill: #fff; stroke: var(--thread); stroke-width: 1.25; }
#weekend .wk-h {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: 14px;
  margin: 0; font: 400 22px/1.2 var(--font-title); color: var(--primary); letter-spacing: 0;
}
#weekend .wk-num { grid-row: 1 / span 2; font: 400 46px/.9 var(--font-title); color: var(--primary); font-variant-numeric: lining-nums; }
#weekend .wk-label { grid-column: 2; align-self: end; font: 600 13px/1.3 var(--font-body); letter-spacing: .18em; text-transform: uppercase; color: var(--accent-text); }
#weekend .wk-name { grid-column: 2; align-self: start; font: 400 22px/1.2 var(--font-title); color: var(--primary); text-wrap: balance; }
#weekend .wk-wear { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin: 16px 0 0; }
#weekend .wk-dress .ic { color: currentColor; margin: 0; }
#weekend .wk-dress .ic svg { width: 18px; height: 18px; }
#weekend .wk-wear__note { font: italic 400 16px/1.35 var(--font-title); color: var(--ink-soft); }

/* ------------------------------------------------------------------ the events */
#weekend .wk-evs { margin: 4px 0 0; padding: 0; list-style: none; }
#weekend .wk-ev { position: relative; z-index: 0; padding-top: 24px; }
/* the bead on the spine, level with the time */
#weekend .wk-bead {
  position: absolute; z-index: 1; left: -30.5px; top: 29px; width: 11px; height: 11px; border-radius: 50%;
  background: #fff; box-shadow: inset 0 0 0 1.5px var(--thread);
}
#weekend .wk-time { margin: 0; font: 400 16px/1.3 var(--font-title); color: var(--ink-soft); font-variant-numeric: lining-nums tabular-nums; }
#weekend .wk-rel { font-style: italic; color: var(--accent-text); }
#weekend .wk-now { display: none; }
#weekend .wk-title { margin: 2px 0 0; font: 400 21px/1.25 var(--font-title); color: var(--primary); letter-spacing: 0; text-wrap: balance; }
#weekend .wk-desc { max-width: 34em; margin: 4px 0 0; font-size: 16px; line-height: 1.6; color: var(--ink-soft); text-wrap: pretty; }
#weekend .wk-ev--tbc { padding-top: 16px; }

/* the place: a 48px row on a sage wash, the pin, the name (two lines at most) and a round slate arrow; the place in
   words (.tl-loc: before location.js has been, and for a place that is not confirmed) is the same row, unpressable */
#weekend .tl-where { display: block; margin: 12px 0 0; }
#weekend .tl-loc { margin: 12px 0 0; }
#weekend .tl-where[hidden], #weekend .tl-loc[hidden] { display: none; }
#weekend .loc-place, #weekend .tl-loc {
  display: grid; grid-template-columns: 18px minmax(0, 1fr) 32px; align-items: center; gap: 0 10px;
  width: 100%; max-width: 30rem; min-height: 48px; padding: 7px 8px 7px 12px;
  border: 0; border-radius: 12px; background: var(--sage-wash); box-shadow: none; color: var(--ink);
  font: 500 16px/1.35 var(--font-body); letter-spacing: 0; text-align: left;
}
#weekend .tl-loc::after { content: ""; }
#weekend .loc-place { cursor: pointer; transition: background-color 160ms var(--out); -webkit-tap-highlight-color: transparent; }
#weekend .loc-place:hover { background: #EBF1ED; box-shadow: none; }
#weekend .loc-place > .loc-ic, #weekend .tl-loc .ic svg { width: 18px; height: 18px; }
#weekend .loc-place > .loc-ic, #weekend .tl-loc .ic { color: var(--accent-text); }
#weekend .tl-loc .ic { margin: 0; }
/* (two lines on the smallest phones; a name the couple makes longer still shows whole, on a third, never cut) */
#weekend .loc-place__t, #weekend .tl-loc__t { min-width: 0; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; text-wrap: balance; }
/* "Navigate" is the button's name; what shows is the arrow */
#weekend .loc-place__go {
  width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; gap: 0; padding: 0; border-radius: 50%;
  background: var(--primary); color: #fff; font-size: 0; letter-spacing: 0;
}
#weekend .loc-place__go .loc-ic { width: 16px; height: 16px; translate: 1px 0; }
#weekend .loc-place:hover .loc-place__go { background: var(--primary-hover); }
/* the smallest phones: a little less air around the name, so the longest place still takes two lines */
@media (max-width: 359px) {
  #weekend .loc-place, #weekend .tl-loc { grid-template-columns: 16px minmax(0, 1fr) 32px; gap: 0 8px; padding: 6px 6px 6px 10px; }
  #weekend .loc-place > .loc-ic, #weekend .tl-loc .ic svg { width: 16px; height: 16px; }
}
/* pressed: a rose wash, at once */
#weekend .loc-place:active { background-color: #F8E7EA; transition-duration: 0s; }
/* a place the event before it already showed: once is enough (unless this is the one happening now) */
#weekend .wk-ev:not(.is-now) .wk-where--repeat { display: none; }

/* ------------------------------------------------------------------ live: past, now, next */
#weekend .is-past .wk-bead { background: var(--sage); box-shadow: none; }
/* (quieter, and still 4.5:1 on the wedding day's blush paper) */
#weekend .is-past :is(.wk-time, .wk-title, .wk-desc) { color: #666E6A; }
#weekend .is-past :is(.loc-place, .tl-loc) { background: #F7F8F7; }
/* now: a rose wash behind the row (out to the spine), the bead rose with its halo, the NOW tag */
#weekend .wk-ev.is-now::before {
  content: ""; position: absolute; z-index: -1; top: 12px; right: -8px; bottom: -12px; left: -44px; border-radius: 16px;
  background: linear-gradient(90deg, rgba(240, 196, 203, .46), rgba(240, 196, 203, .16));
}
#weekend .is-now .wk-bead { background: var(--thread); box-shadow: 0 0 0 4px rgba(180, 138, 147, .22); }
#weekend .is-now .wk-bead::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: var(--thread); opacity: 0; }
#weekend .is-now .wk-time { color: var(--ink); }
#weekend .is-now .wk-now {
  display: inline-block; margin-left: 10px; padding: 3px 9px 2px; border-radius: 999px; vertical-align: 1px;
  background: var(--accent-text); color: #fff; font: 600 13px/1.15 var(--font-body); letter-spacing: .14em; text-transform: uppercase;
}
#weekend .is-now :is(.loc-place, .tl-loc) { background: #fff; }

/* ------------------------------------------------------------------ the wedding day: a full-bleed blush spread */
#weekend .wk-day--feature { margin-top: 64px; padding-top: 24px; padding-bottom: 32px; }
#weekend .wk-day + .wk-day--feature, #weekend .wk-day--feature + .wk-day { margin-top: 64px; }
#weekend .wk-paper {
  position: absolute; z-index: -2; top: -32px; bottom: -32px; left: 50%; width: 100vw; max-width: var(--wide); translate: -50% 0;
  background: linear-gradient(to bottom, rgba(252, 239, 241, 0), #FCEFF1 72px, #FCEFF1 calc(100% - 72px), rgba(252, 239, 241, 0));
  pointer-events: none;
}
@media (min-width: 1100px) {
  #weekend .wk-paper {
    -webkit-mask: linear-gradient(90deg, transparent, #000 96px, #000 calc(100% - 96px), transparent);
    mask: linear-gradient(90deg, transparent, #000 96px, #000 calc(100% - 96px), transparent);
  }
}
/* the ghost of the date behind the head: only where the column leaves room for it beside the words (a tablet;
   on a phone it would run through the day's title, and from 1100px the date itself stands large in its own column) */
@media (min-width: 768px) and (max-width: 1099.98px) {
  #weekend .wk-day--feature::before {
    content: attr(data-n); content: attr(data-n) / "";
    position: absolute; z-index: -1; top: 118px; right: 0; pointer-events: none; user-select: none;
    font: 400 240px/.8 var(--font-title); letter-spacing: -.02em; color: var(--dusk-rose); opacity: .12;
  }
}
/* the gazebo engraving over the head, centred on the column (not on the indented words); its plate is fetched only
   once the day is about a screen away (.wk-near, s-weekend.js), never with the first screen */
#weekend .wk-gazebo {
  position: relative; left: -17px; display: block; width: 112px; height: 112px; margin: 0 auto 12px;
  background: var(--ink-rose); opacity: .55; visibility: hidden;
}
/* (two layers: the plate, and a wash the reveal slides up through it, from its foot to its lantern; at rest it is all
   ink) */
#weekend .wk-day--feature.wk-near .wk-gazebo {
  visibility: visible;
  -webkit-mask-image: url(../img/ornament/gazebo.svg), linear-gradient(0deg, #000 45%, transparent 55%);
  mask-image: url(../img/ornament/gazebo.svg), linear-gradient(0deg, #000 45%, transparent 55%);
  -webkit-mask-size: contain, 100% 300%; mask-size: contain, 100% 300%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center, 0 100%; mask-position: center, 0 100%; -webkit-mask-composite: source-in; mask-composite: intersect;
}
#weekend .wk-day--feature .wk-ring circle { fill: #FCEFF1; }
/* on the blush paper the chip and the places are white */
#weekend .wk-day--feature .wk-dress { background: #fff; }
#weekend .wk-day--feature .wk-dress:hover { background: #fff; color: var(--primary); }
#weekend .wk-day--feature :is(.loc-place, .tl-loc) { background: #fff; }
#weekend .wk-day--feature .loc-place:hover { background: #fff; box-shadow: inset 0 0 0 1px var(--sage-mist); }
#weekend .wk-day--feature .wk-h { align-items: center; }
#weekend .wk-day--feature .wk-num { grid-row: 1; }
#weekend .wk-day--feature .wk-label { grid-row: 1; align-self: center; }
#weekend .wk-day--feature .wk-name {
  grid-column: 1 / -1; grid-row: 2; margin-top: 4px;
  font: 400 clamp(2.2rem, 10.6vw, 2.75rem)/1.15 var(--font-script); color: var(--accent-text);
}
/* (its ring by its date, under the gazebo: 112px and 12px) */
#weekend .wk-day--feature .wk-ring { top: calc(124px + 10px); }

/* ------------------------------------------------------------------ the end of the chapter */
#weekend .wk-end { margin-top: 40px; text-align: center; }
#weekend .wk-end .text-btn { text-wrap: balance; }

/* ------------------------------------------------------------------ motion (nothing here hides anything without it) */
@keyframes wk-rise { from { opacity: 0; translate: 0 var(--wk-rise, 16px); } }
@keyframes wk-draw { from { stroke-dashoffset: 1.02; } }
@keyframes wk-halo { from { transform: scale(1); opacity: .5; } to { transform: scale(2.2); opacity: 0; } }
@keyframes wk-spine { from { transform: scaleY(0); } }
@keyframes wk-unfold { from { transform: scaleX(.94) translateY(16px); } }
@keyframes wk-ghost { from { opacity: 0; transform: translateY(28px); } }
/* the gazebo comes up out of the paper, from its foot to its lantern (only the wash moves: the plate itself is not
   named here, so a reveal still waiting never fetches it) */
@keyframes wk-gz-up { from { -webkit-mask-position: center, 0 0; mask-position: center, 0 0; opacity: .2; } }
@media (prefers-reduced-motion: no-preference) {
  /* a day's head as it is revealed (motion.js: [data-rv="group"] holds its parts on their first frame until .in):
     the ring is drawn by the pen from the top, the date rises, then the words */
  html.ww-js #weekend .wk-head.rvg .wk-ring circle { stroke-dasharray: 1 2; transform-box: fill-box; transform-origin: center; rotate: -90deg; animation: wk-draw 600ms var(--pen) backwards; }
  html.ww-js #weekend .wk-head.rvg .wk-num { animation: wk-rise 800ms var(--out) backwards; }
  html.ww-js #weekend .wk-head.rvg :is(.wk-label, .wk-name) { animation: wk-rise 800ms var(--out) 120ms backwards; --wk-rise: 10px; }
  html.ww-js #weekend .wk-head.rvg .wk-wear { animation: wk-rise 700ms var(--out) 220ms backwards; --wk-rise: 8px; }
  html.ww-js #weekend .wk-head.rvg .wk-gazebo { animation: wk-gz-up 1600ms var(--io) backwards; }
  /* the ghost of the date surfaces behind the head as it is revealed */
  html.ww-js #weekend .wk-day--feature:has(.wk-head.rvg:not(.in))::before { opacity: 0; }
  html.ww-js #weekend .wk-day--feature:has(.wk-head.rvg.in)::before { animation: wk-ghost 1400ms var(--e-ink) 240ms backwards; }
  /* the events rise 12px in turn (motion.js staggers them 70ms); the place follows its title by 120ms. The row itself
     stays where it is (a jump measures it: the Now pill goes to it); what is in it rises, the bead waits on the spine */
  html.ww-js #weekend .wk-ev.rv:not(.in) { translate: none; }
  html.ww-js #weekend .wk-ev.rv.in { transition-duration: 700ms; }
  html.ww-js #weekend .wk-ev.rv:not(.in) > :not(.wk-bead) { translate: 0 12px; }
  html.ww-js #weekend .wk-ev.rv.in > :not(.wk-bead) { transition: translate 700ms var(--out) var(--d, 0ms); }
  html.ww-js #weekend .wk-ev.rv:not(.in) > :is(.tl-where, .tl-loc) { opacity: 0; }
  html.ww-js #weekend .wk-ev.rv.in > :is(.tl-where, .tl-loc) { transition: opacity 600ms var(--out) calc(var(--d, 0ms) + 120ms), translate 700ms var(--out) calc(var(--d, 0ms) + 120ms); }
  /* now: the bead's halo breathes out (an ambient loop: story.js pauses it off screen) */
  #weekend .is-now .wk-bead::after { animation: wk-halo 1800ms var(--out) infinite; }
  /* the fill follows now along the thread */
  #weekend .wk-spine__now { transition: transform 1200ms var(--io); }
  #weekend .wk-rail a:active { scale: .97; }
}
/* scrubbed by the scroll (where scroll timelines exist): the thread is drawn exactly at the reading line, and the
   wedding day's paper unfolds as it comes up the screen. Elsewhere both are simply there. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* (view(block 0px): the whole screen, not the page's scroll-padding under the header, so the line holds still) */
    #weekend .wk-spine__draw { animation: wk-spine linear both; animation-timeline: view(block 0px); animation-range: cover 50vh cover calc(100% - 50vh); }
    #weekend .wk-paper { animation: wk-unfold linear both; animation-timeline: view(); animation-range: entry 0% entry 60%; }
  }
}

/* ------------------------------------------------------------------ larger screens */
@media (min-width: 900px) {
  #weekend .wk-days { padding-top: 20px; }
  #weekend .wk-day + .wk-day { margin-top: 56px; }
  #weekend .wk-day--feature, #weekend .wk-day + .wk-day--feature, #weekend .wk-day--feature + .wk-day { margin-top: 80px; }
  #weekend .wk-day--feature { padding-bottom: 48px; }
}

/* ------------------------------------------------------------------ a wide screen: the day on the left, its hours on the right
   From 1100px the thread runs down the middle of the page, on the same axis as the chapter's own thread, its numeral
   and its title, and a day opens into two columns either side of it. On the left, set toward the thread, stand the
   weekday (level with the day's ring), the date, the day's name and its dress, and under the wedding day its gazebo;
   they stay in view under the rail while the day's hours go by on the right, the ring riding down the thread with
   them (s-weekend.js measures the thread from where the ring rests, not from where it has been carried to). */
@media screen and (min-width: 1100px) {
  #weekend .wk-days { --wk-gap: 96px; max-width: calc(1200px + 2 * var(--gut)); padding-top: 28px; }
  #weekend .wk-day {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: var(--wk-gap); align-items: start;
    padding-left: 0; scroll-margin-top: calc(var(--hdr) + var(--rail) + 20px);
  }
  #weekend .wk-day + .wk-day { margin-top: 72px; }
  #weekend .wk-day--feature, #weekend .wk-day + .wk-day--feature, #weekend .wk-day--feature + .wk-day { margin-top: 104px; }
  #weekend .wk-day--feature { padding-top: 40px; padding-bottom: 56px; }
  #weekend .wk-spine { left: calc(50% - 1px); }
  /* the head: a small title page, set right */
  #weekend .wk-head { z-index: 2; display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
  #weekend .wk-ring { left: calc(100% + var(--wk-gap) / 2 - 10px); top: -2px; }
  #weekend .wk-day--feature .wk-ring { top: -2px; }
  #weekend .wk-h, #weekend .wk-label, #weekend .wk-num, #weekend .wk-name { display: block; }
  #weekend .wk-num { margin-top: 14px; font-size: 88px; line-height: .95; letter-spacing: -.01em; }
  #weekend .wk-name { margin-top: 14px; font-size: 26px; }
  #weekend .wk-wear { justify-content: flex-end; margin-top: 18px; }
  #weekend .wk-day--feature .wk-num { font-size: 112px; }
  #weekend .wk-day--feature .wk-name { margin-top: 10px; font-size: 3.5rem; white-space: nowrap; }
  #weekend .wk-day--feature .wk-wear { flex-direction: column; align-items: flex-end; gap: 8px; }
  #weekend .wk-gazebo { order: 9; left: 0; width: 136px; height: 136px; margin: 28px 0 0; }
  /* the hours: the first one starts under the ring's line */
  #weekend .wk-evs { margin-top: 14px; }
  #weekend .wk-ev + .wk-ev { padding-top: 32px; }
  #weekend .wk-ev + .wk-ev .wk-bead { top: 37px; }
  #weekend .wk-bead { left: calc(var(--wk-gap) / -2 - 5.5px); }
  #weekend .wk-title { font-size: 23px; }
  #weekend .wk-ev.is-now::before { left: calc(var(--wk-gap) / -2 - 19px); right: -16px; }
  #weekend .wk-ev + .wk-ev.is-now::before { top: 20px; }
  #weekend .wk-paper { max-width: 1280px; }
}
/* (the head stays in view only where the screen is tall enough to hold the tallest one) */
@media screen and (min-width: 1100px) and (min-height: 700px) {
  #weekend .wk-head { position: sticky; top: calc(var(--hdr) + var(--rail) + 20px); }
}

@media print {
  #weekend .wk-rail, #weekend .wk-spine, #weekend .wk-paper, #weekend .wk-gazebo, #weekend .wk-day--feature::before { display: none; }
}
/* ---- w/css/s-venue.css ---- */
/* THE SMITH WEDDING · III The Venue: the plates, the map and the way in (WP3). Scope: #venue, vn- (the map and the Navigate sheet: loc- in location.css)
   - the plates: the gardens printed full bleed at the photo's own ratio, then the Great Barn and its hall as a
     4:5 pair; captions under each (app.js renderVenue; they print in as they come, the lead drifts with the scroll)
   - the way there (.vn-way), far to near: the address, Directions to the main gate and "How far am I?" on a card, then
     the drive as a thread of beads ending at the main gate (#vnGate, its Street View) and one quiet line about the
     drive and the evenings
   - the map (#map), where the drive ends: "Find your way", the two maps' tabs, the frame (location.css) with "Open
     the map" on phones, the map's credit under it, then the weekend's places as 60px rows (location.js renderPlaces)
   - wide screens (1100px): the three plates in one row, and the way there as two columns about the page's axis */

/* ------------------------------------------------------------------ the plates */
#venue .vn-plates { display: grid; gap: 24px; }
#venue .vn-plates[hidden] { display: none; }
#venue .vn-lead, #venue .vn-plate { margin: 0; min-width: 0; }
#venue .vn-photo {
  position: relative; display: block; width: 100%; margin: 0; padding: 0; border: 0; border-radius: 0;
  background: var(--sage-wash); overflow: hidden; overflow: clip; cursor: zoom-in; -webkit-tap-highlight-color: transparent;
}
#venue .vn-photo picture { display: contents; }
#venue .vn-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
#venue .vn-photo:focus-visible { outline: 3px solid var(--heather); outline-offset: 3px; }
#venue .vn-lead .vn-photo { aspect-ratio: 789 / 556; }
#venue .vn-pair {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px; box-sizing: border-box; width: 100%;
  max-width: calc(var(--col) + 2 * var(--gut)); margin: 0 auto; padding: 0 var(--gut);
}
#venue .vn-plate .vn-photo { aspect-ratio: 4 / 5; border-radius: 12px; }
#venue .vn-cap { margin: 10px var(--gut) 0; text-align: center; font: italic 400 15px/1.35 var(--font-title); color: var(--ink-soft); text-wrap: balance; }
#venue .vn-pair .vn-cap { margin: 8px 2px 0; }
/* a phone held sideways: no plate is taller than the screen under the header (the lead becomes a wide view, the
   pair keep their 4:5) */
@media (orientation: landscape) and (max-height: 520px) {
  #venue .vn-lead .vn-photo { max-height: calc(100vh - var(--hdr) - 48px); max-height: calc(100svh - var(--hdr) - 48px); }
  #venue .vn-pair { max-width: calc((100vh - var(--hdr) - 48px) * 1.6 + 12px + 2 * var(--gut)); max-width: calc((100svh - var(--hdr) - 48px) * 1.6 + 12px + 2 * var(--gut)); }
}
@media (min-width: 900px) {
  #venue .vn-plates { gap: 32px; }
  #venue .vn-lead { box-sizing: border-box; width: 100%; max-width: calc(var(--col) + 2 * var(--gut)); margin: 0 auto; padding: 0 var(--gut); }
  #venue .vn-lead .vn-photo { border-radius: 16px; }
  #venue .vn-pair { gap: 20px; }
}

/* ------------------------------------------------------------------ the map */
#venue .vn-map { margin-top: 56px; }
#venue .vn-h3 { margin: 0; font: 400 24px/1.2 var(--font-title); color: var(--primary); text-wrap: balance; }
#venue .vn-frame { margin-top: 14px; }
@media (min-width: 900px) {
  #venue .vn-map { max-width: calc(var(--wide) + 2 * var(--gut)); }
  #venue .vn-map #locTabs { max-width: 440px; }
}
/* "Open the map": a white pill at the foot of a phone's picture of the map (the live map comes up full screen); it
   steps aside while a place's card is up */
#venue .vn-open {
  position: absolute; z-index: 5; left: 50%; bottom: 14px; translate: -50% 0;
  display: none; align-items: center; gap: 8px; min-height: 44px; padding: 0 18px 0 14px; border: 0; border-radius: 999px;
  background: #fff; color: var(--primary); font: 600 15px/1 var(--font-body); letter-spacing: .02em; white-space: nowrap; cursor: pointer;
  box-shadow: 0 0 0 1px var(--sage-mist), 0 10px 24px -12px rgba(46, 53, 50, .55); -webkit-tap-highlight-color: transparent;
  transition: opacity 260ms var(--out), visibility 0s;
}
#venue .vn-open .loc-ic { width: 18px; height: 18px; }
#venue .vn-open:hover { color: var(--accent-text); }
#venue .vn-open:focus-visible { outline: 3px solid var(--heather); outline-offset: 3px; }
#venue .loc-frame.has-pick .vn-open { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 180ms var(--out), visibility 0s linear 180ms; }
/* the map's credit (OpenStreetMap's licence asks for it in view): a caption under a phone's picture of the map; the
   live map carries its own */
#venue .vn-credit { display: none; margin: 10px 4px 0; text-align: center; font-size: 13px; line-height: 1.5; color: var(--ink-soft); text-wrap: balance; }
#venue .vn-credit a { color: inherit; text-underline-offset: 2px; text-decoration-color: rgba(98, 106, 102, .45); }
@media (max-width: 899.98px), (pointer: coarse) and (max-width: 1100px) {
  #venue .vn-open { display: inline-flex; }
  #venue .vn-credit { display: block; }
}
@media (orientation: landscape) and (max-height: 520px) { #venue .vn-open { left: auto; right: 12px; bottom: 12px; translate: none; } }

/* Around Mistvale on a phone: the map's printed picture, cropped to the frame, with its three names on it */
#venue .vn-poster { position: absolute; inset: 0; margin: 0; overflow: hidden; background: #EEF0E8; }
#venue .vn-poster__art { position: absolute; left: 0; top: 50%; width: 100%; aspect-ratio: var(--ar); translate: 0 -50%; }
#venue .vn-poster__art img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
#venue .vn-aname { position: absolute; left: var(--x); top: var(--y); width: 0; height: 0; }
#venue .vn-aname i {
  position: absolute; left: -6px; top: -6px; width: 12px; height: 12px; border-radius: 50%;
  background: var(--primary); box-shadow: 0 0 0 2.5px #fff, 0 2px 6px rgba(46, 53, 50, .4);
}
#venue .vn-aname.is-home i { left: -8px; top: -8px; width: 16px; height: 16px; background: var(--accent-text); box-shadow: 0 0 0 3px #fff, 0 0 0 6px rgba(240, 196, 203, .9), 0 3px 8px rgba(46, 53, 50, .4); }
#venue .vn-aname b {
  position: absolute; left: 0; translate: -50% 0; white-space: nowrap; text-align: center;
  padding: 5px 11px 6px; border-radius: 12px; background: rgba(255, 255, 255, .96);
  box-shadow: 0 0 0 1px rgba(90, 105, 100, .16), 0 4px 12px -4px rgba(46, 53, 50, .32);
  font: 500 15px/1.15 var(--font-title); color: var(--ink);
}
#venue .vn-aname.is-home b { font-size: 16px; color: var(--accent-text); }
#venue .vn-aname b small { display: block; margin-top: 1px; font: italic 400 13px/1.2 var(--font-title); color: var(--accent-text); }
#venue .vn-aname--up b { bottom: 14px; }
#venue .vn-aname--down b { top: 14px; }

/* the weekend's places: hairline rows of 60px, each "Navigate to ...?" (a round slate arrow) */
#venue .vn-places { list-style: none; margin: 24px 0 0; padding: 0; border-top: 1px solid var(--line); }
#venue .vn-places:empty { min-height: 427px; }
#venue .vn-places > li { border-bottom: 1px solid var(--line); }
#venue .vn-place {
  appearance: none; -webkit-appearance: none; width: 100%; height: 60px; margin: 0; padding: 0 2px; border: 0; border-radius: 0;
  display: grid; grid-template-columns: 22px minmax(0, 1fr) 32px; align-items: center; column-gap: 14px;
  background: none; color: var(--ink); text-align: left; font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background-color 160ms var(--out);
}
#venue .vn-place__pin { width: 22px; height: 22px; color: var(--dusk-rose); }
#venue .vn-place__txt { display: grid; min-width: 0; }
#venue .vn-place__t, #venue .vn-place__s { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#venue .vn-place__t { font: 400 18px/1.25 var(--font-title); color: var(--primary); }
#venue .vn-place__s { font-size: 15px; line-height: 1.4; color: var(--ink-soft); }
#venue .vn-place__go { width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; background: var(--primary); color: #fff; transition: background-color 160ms var(--out); }
#venue .vn-place__go .loc-ic { width: 16px; height: 16px; translate: 1px 0; }
#venue .vn-place:hover .vn-place__t { color: var(--accent-text); }
#venue .vn-place:hover .vn-place__go { background: var(--primary-hover); }
/* a press: the row flashes a rose wash (160ms) as the sheet comes up */
#venue .vn-place:active { background: var(--blush-wash); transition-duration: 0s; }
#venue .vn-place:focus-visible { outline: 3px solid var(--heather); outline-offset: -3px; border-radius: 8px; }
#venue .vn-place[aria-busy="true"] { cursor: progress; }
#venue .vn-place[aria-busy="true"] .vn-place__go { opacity: .55; }
@media (min-width: 900px) {
  #venue .vn-places { display: grid; grid-template-columns: 1fr 1fr; column-gap: 40px; border-top: 0; }
  #venue .vn-places:empty { min-height: 244px; }
  #venue .vn-places > li:nth-child(-n + 2) { border-top: 1px solid var(--line); }
}

/* ------------------------------------------------------------------ getting there */
#venue .vn-getting { margin-top: 40px; }
/* arriving: the address, Directions and "How far am I?" on a card, straight after the photographs */
#venue .vn-arrive { margin-top: 36px; }
#venue .vn-arrive__card { padding: 22px 20px 20px; border-radius: 18px; background: #fff; box-shadow: 0 0 0 1px var(--line), 0 14px 34px -22px rgba(60, 72, 66, .35); }
#venue .vn-arrive__card .vn-addr { margin-bottom: 18px; }
@media (min-width: 900px) { #venue .vn-arrive { max-width: calc(560px + 2 * var(--gut)); } #venue .vn-arrive__card { padding: 28px; text-align: center; } }
#venue .vn-addr { margin: 8px 0 20px; font-size: 16px; line-height: 1.55; color: var(--ink-soft); }
#venue .vn-addr strong { font-weight: 600; color: var(--ink); }
#venue .vn-dir { gap: 10px; padding-inline: 16px; white-space: nowrap; }
#venue .vn-dir .loc-ic { width: 20px; height: 20px; }
#venue .loc-far--card { margin-top: 12px; }
#venue .loc-far--card .loc-far__go { gap: 10px; }

/* the drive: a thread of beads (the itinerary's spine, now the road), ending in the main gate's seal. The thread is
   one line from the first bead to the seal (location.js keeps --vn-tail, the seal's bead below its centre) */
#venue .vn-drive { position: relative; margin: 30px 0 0; }
#venue .vn-drive__line { position: absolute; left: 9.4px; top: 10px; bottom: var(--vn-tail, 100%); width: 1.25px; background: var(--thread); transform-origin: 50% 0; pointer-events: none; }
#venue .vn-drive__list { position: relative; list-style: none; margin: 0; padding: 0; }
#venue .vn-bead { position: relative; padding: 0 0 26px 34px; }
#venue .vn-bead::before {
  content: ""; position: absolute; z-index: 1; left: 4px; top: 4px; width: 11px; height: 11px; border-radius: 50%;
  background: #fff; box-shadow: inset 0 0 0 1.5px var(--thread), 0 0 0 3px var(--sage-wash);
}
#venue .vn-bead__k { display: block; font: 600 13px/1.4 var(--font-body); letter-spacing: .18em; text-transform: uppercase; color: var(--accent-text); }
#venue .vn-bead__t { margin: 4px 0 0; font-size: 16px; line-height: 1.6; color: var(--ink-soft); }
/* "The whole drive": the rest of the way, folded (airport, the last stretch, the holiday, tolls, fuel) */
#venue .vn-bead--more::before { top: 18px; }
#venue .vn-more summary {
  display: flex; align-items: center; gap: 10px; min-height: 48px; list-style: none; cursor: pointer;
  font: 600 16px/1.3 var(--font-body); letter-spacing: .02em; color: var(--accent-text); -webkit-tap-highlight-color: transparent;
}
#venue .vn-more summary::-webkit-details-marker { display: none; }
#venue .vn-more summary::after {
  content: ""; flex: none; width: 8px; height: 8px; margin: -3px 0 0 2px; border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
  rotate: 45deg; transition: rotate 240ms var(--io), translate 240ms var(--io);
}
#venue .vn-more[open] summary::after { rotate: -135deg; translate: 0 4px; }
#venue .vn-more summary:hover { color: var(--primary); }
#venue .vn-more summary:focus-visible { outline: 3px solid var(--heather); outline-offset: 2px; border-radius: 6px; }
#venue .vn-more__list { margin: 6px 0 4px; }
#venue .vn-more__list dt { margin: 14px 0 0; font: 600 13px/1.4 var(--font-body); letter-spacing: .18em; text-transform: uppercase; color: var(--accent-text); }
#venue .vn-more__list dt:first-child { margin-top: 2px; }
#venue .vn-more__list dd { margin: 4px 0 0; font-size: 16px; line-height: 1.6; color: var(--ink-soft); }
/* the main gate: the thread's end, a rose seal; its Street View under the words */
#venue .vn-bead--gate { padding-bottom: 0; }
#venue .vn-bead--gate::before { left: 0; top: 0; width: 19px; height: 19px; background: var(--accent-text); box-shadow: 0 0 0 3px #fff, 0 0 0 4.25px var(--thread), 0 0 0 7px var(--sage-wash); }
#venue .vn-bead--gate .vn-bead__k { color: var(--primary); }
#venue .vn-bead--gate .loc-sv { max-width: 492px; margin: 14px 0 0 -6px; }
#venue .vn-note { margin: 32px 0 0; font: italic 400 17px/1.55 var(--font-title); color: var(--ink-soft); text-wrap: pretty; }

/* ------------------------------------------------------------------ wide screens */
/* the three plates stand in one row, each at its own ratio (so they are equally tall), their captions under them;
   then the way there as two columns about the page's axis: the card, which stays in view, and the drive */
@media screen and (min-width: 1100px) {
  #venue .vn-plates:has(.vn-pair) {
    display: flex; align-items: flex-start; gap: 20px; box-sizing: border-box; width: 100%;
    max-width: calc(1200px + 2 * var(--gut)); margin-inline: auto; padding-inline: var(--gut);
  }
  #venue .vn-plates:has(.vn-pair) .vn-lead { flex: 1.419 1 0; width: auto; max-width: none; margin: 0; padding: 0; }
  #venue .vn-plates:has(.vn-pair) .vn-pair { display: contents; }
  #venue .vn-plates:has(.vn-pair) .vn-plate { flex: .8 1 0; }
  #venue .vn-plates:has(.vn-pair) .vn-photo { border-radius: 14px; }
  #venue .vn-plates:has(.vn-pair) .vn-cap { margin: 12px 2px 0; }
  #venue .vn-way {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 96px; align-items: start;
    box-sizing: border-box; max-width: calc(var(--wide) + 2 * var(--gut)); margin: 72px auto 0; padding-inline: var(--gut);
  }
  #venue .vn-way > .vn-arrive, #venue .vn-way > .vn-getting { max-width: none; margin: 0; padding: 0; }
  #venue .vn-arrive__card { padding: 36px 40px 32px; }
  #venue .vn-map { margin-top: 80px; }
}
@media screen and (min-width: 1100px) and (min-height: 600px) {
  #venue .vn-way > .vn-arrive { position: sticky; top: calc(var(--hdr) + 28px); }
}

/* ------------------------------------------------------------------ motion (P1; with reduced motion all is drawn and still) */
@keyframes vn-pop { from { scale: .6; opacity: 0; } }
@keyframes vn-draw { from { transform: scaleY(0); } }
@keyframes vn-drift { from { transform: translateY(-3%) scale(1.06); } to { transform: translateY(3%) scale(1.06); } }
@media (prefers-reduced-motion: no-preference) {
  /* the drive's beads pop in as their words rise (60ms apart) */
  html.ww-js #venue .vn-bead.rv.in::before { animation: vn-pop 300ms var(--out) calc(var(--d, 0ms) + 80ms) backwards; }
  /* the press of a place row */
  #venue .vn-place:active .vn-place__go { scale: .92; }
  @supports (animation-timeline: view()) {
    /* the lead drifts a little against the page (its print-in plays on the button around it) */
    #venue .vn-lead .vn-photo img { animation: vn-drift linear both; animation-timeline: view(); animation-range: cover; }
    @media (min-width: 1100px) { #venue .vn-plate .vn-photo img { animation: vn-drift linear both; animation-timeline: view(); animation-range: cover; } }
    /* the thread of the drive is drawn down to the gate as it passes the reading line (without scroll timelines it is
       simply drawn) */
    #venue .vn-drive { view-timeline: --vn-drive block; }
    #venue .vn-drive__line { animation: vn-draw linear both; animation-timeline: --vn-drive; animation-range: cover 25vh cover calc(100% - 45vh); }
  }
}

@media print {
  #venue .vn-open, #venue .vn-places, #venue .loc-far--card, #venue .vn-dir { display: none !important; }
}
/* ---- w/css/s-stay.css ---- */
/* THE SMITH WEDDING · IV Where to Stay: the booking ticket and the nearby stays (WP4). Scope: #stay, st- */
/* =====================================================================
   The ticket: one box of blush paper with a perforated left edge (a radial-gradient mask, as if torn from a book
   of tickets): Recommended, the heading, "Breakfast is included" (#breakfastPill), the words, the reference to
   quote with Copy, Call and Email (48px), and the way to ask for a room in the reply. Then the stays nearby: one
   swipeable row of cards (a [data-snap] row: story.js pages it), each with one photo (the couple's own, one from
   Google Maps through places.js, or an engraving of the toile), the drive, the name, the area, the blurb, three
   52px actions and the email address; under the row its pager, "All the stays on the map" and the note.
   Motion (compositor-only, only with prefers-reduced-motion: no-preference; with reduce all is still and whole):
   the ticket rises (.rv) while its perforation is drawn down the edge (.st-perf slides away), Copy flashes the
   reference in a rose wash, the first two cards slide in from the right (the row is a [data-rv="group"]), a card
   reached from the map flashes (.is-flash, location.js), a Google photo fades in as it arrives.
   ===================================================================== */

#stay { --st-paper: #FCF3F4; --st-edge: #F0DCE0; --st-hole: 4.5px; --st-pitch: 14px; }

/* ------------------------------------------------------------------ the ticket */
#stay .st-ticket { position: relative; max-width: 560px; margin-inline: auto; }
#stay .st-paper {
  position: relative; container-type: inline-size;
  padding: 22px 18px 20px 26px; border-radius: 6px 18px 18px 6px;
  background: var(--st-paper); box-shadow: inset 0 0 0 1px var(--st-edge);
  /* the perforation: a half hole every 14px down the left edge (a whole number of them, whatever the height) */
  -webkit-mask: radial-gradient(circle at 0 50%, transparent var(--st-hole), #000 calc(var(--st-hole) + .6px)) 0 0 / 100% var(--st-pitch) no-repeat round;
  mask: radial-gradient(circle at 0 50%, transparent var(--st-hole), #000 calc(var(--st-hole) + .6px)) 0 0 / 100% var(--st-pitch) no-repeat round;
}
@media (max-width: 359px) { #stay .st-paper { padding-inline: 24px 16px; } }
/* an engraved hairline inside the edge, clear of the holes */
#stay .st-paper::before {
  content: ""; position: absolute; inset: 7px 7px 7px 12px; z-index: 0; pointer-events: none;
  border: 1px solid rgba(180, 138, 147, .3); border-radius: 3px 12px 12px 3px;
}
#stay .st-paper > * { position: relative; z-index: 1; }
#stay .st-eyebrow { margin: 0; font: 600 13px/1.4 var(--font-body); letter-spacing: .2em; text-transform: uppercase; color: var(--accent-text); }
#stay .st-title { margin: 6px 0 0; font: 400 22px/1.2 var(--font-title); color: var(--primary); text-wrap: balance; }
#stay .st-bf { display: flex; align-items: center; gap: 8px; margin: 6px 0 0; font: italic 400 16px/1.4 var(--font-title); color: var(--accent-text); }
#stay .st-bf[hidden] { display: none; }
#stay .st-bf svg { flex: none; width: 18px; height: 18px; translate: 0 -1px; }
#stay .st-text { margin: 12px 0 0; font-size: 16px; line-height: 1.6; color: var(--ink-soft); text-wrap: pretty; }
#stay .st-text:empty { display: none; }

/* the reference, over a dashed tear line: the words to quote and Copy */
#stay .st-ref {
  display: flex; flex-wrap: wrap; align-items: center; column-gap: 12px; row-gap: 2px;
  margin: 18px 0 0; padding-top: 14px; border-top: 1px dashed rgba(180, 138, 147, .5);
}
#stay .st-ref__label { flex: 1 0 100%; margin: 0; font: 600 13px/1.4 var(--font-body); letter-spacing: .18em; text-transform: uppercase; color: var(--accent-text); }
#stay .st-ref__value {
  position: relative; flex: 0 1 auto; min-width: 0; margin: 0 auto 0 0; overflow-wrap: anywhere;
  font: 400 clamp(24px, 6.6vw, 28px)/1.25 var(--font-title); color: var(--primary);
}
/* (Copy's rose wash, under the words) */
#stay .st-ref__value::before {
  content: ""; position: absolute; z-index: -1; inset: -2px -10px; border-radius: 10px; pointer-events: none;
  background: rgba(240, 196, 203, .6); opacity: 0;
}
#stay .st-copy {
  flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-width: 44px; height: 44px;
  padding: 0 16px 0 13px; border: 1px solid var(--sage-mist); border-radius: 999px; background: #fff; color: var(--primary);
  font: 600 15px/1 var(--font-body); letter-spacing: .02em; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: border-color 160ms var(--out), scale 160ms var(--out);
}
#stay .st-copy:hover { border-color: var(--primary); }
#stay .st-copy:active { scale: .96; }
#stay .st-copy svg { flex: none; width: 17px; height: 17px; }
#stay .st-copy__ok { display: none; }
#stay .st-ref.is-copied .st-copy__ic { display: none; }
#stay .st-ref.is-copied .st-copy__ok { display: block; color: var(--accent-text); }
/* a narrow ticket: Copy is its icon (its name stays "Copy the reference") */
@container (max-width: 299px) {
  #stay .st-copy { width: 44px; padding: 0; }
  #stay .st-copy__t { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* Call and Email: full width, one above the other; side by side once the ticket is wide enough for both */
#stay .st-reach { display: grid; gap: 8px; margin: 16px 0 0; }
#stay .st-reach > [hidden] { display: none; }
#stay .st-reach .btn { gap: 10px; min-height: 48px; padding: 0 18px; font-size: 16px; white-space: nowrap; }
#stay .st-reach .btn svg { flex: none; width: 19px; height: 19px; }
@container (min-width: 430px) {
  #stay .st-reach { grid-template-columns: 1fr 1fr; }
}
/* (a 44px row: its own air stands in for the paper's foot) */
#stay .st-ask { margin: 6px 0 -10px; }
#stay .st-ask .text-btn { font-size: 15px; }
#stay .st-ask[hidden], html:not(.rsvp-open) #stay .st-ask { display: none; }

/* the perforation is drawn down the edge as the ticket rises: a strip of the same paper slides away over the
   holes (it rests out of the way; the animation is under motion, below) */
#stay .st-perf { position: absolute; left: 0; top: 0; bottom: 0; width: calc(var(--st-hole) + 3px); overflow: hidden; pointer-events: none; border-radius: 6px 0 0 6px; }
#stay .st-perf::before { content: ""; position: absolute; inset: 0; background: var(--st-paper); box-shadow: inset 1px 0 0 var(--st-edge); transform: translateY(101%); }

/* ------------------------------------------------------------------ the stays nearby */
#stay .st-nearby { margin-top: 48px; }
#stay .st-head h3 { margin: 0; font: 400 22px/1.2 var(--font-title); color: var(--primary); text-wrap: balance; }
#stay .st-head p { margin: 6px 0 0; font-size: 16px; line-height: 1.55; color: var(--ink-soft); text-wrap: pretty; }
#stay .st-snap { min-width: 0; margin-top: 20px; }
#stay .st-snap[hidden], #stay .st-onmap[hidden], #stay .st-note[hidden], #stay .st-soon[hidden] { display: none; }
/* the row (story.css [data-snap]: a flex row, 12px apart, snapping to each card's start): full width, its first
   card on the reading column's edge (in vw, not %: story.js reads the scroll padding as a length) */
#stay .st-cards {
  --st-in: max(var(--gut), calc((100vw - var(--col)) / 2));
  align-items: stretch; padding: 2px var(--st-in) 16px; scroll-padding-inline: var(--st-in);
}
#stay .st-card {
  position: relative; display: flex; flex-direction: column; width: min(84vw, 340px);
  background: #fff; border-radius: 18px;
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(52, 62, 58, .04), 0 12px 26px -16px rgba(52, 62, 58, .26);
}
/* arriving from the map ("See the stay"): a rose ring and wash for a moment (location.js sets .is-flash) */
#stay .st-card::after {
  content: ""; position: absolute; inset: 0; z-index: 3; border-radius: inherit; pointer-events: none;
  background: rgba(240, 196, 203, .16); box-shadow: 0 0 0 3px var(--blush), inset 0 0 0 1px rgba(180, 138, 147, .5);
  opacity: 0; transition: opacity 700ms var(--out);
}
#stay .st-card.is-flash::after { opacity: 1; transition-duration: 220ms; }

/* the photo, 16:10: the couple's own, a Google Maps photo (places.js), or the engraving */
#stay .st-photo { position: relative; margin: 0; }
#stay .st-ph { position: relative; aspect-ratio: 16 / 10; overflow: hidden; border-radius: 18px 18px 0 0; background: #F7F6F2; }
#stay .st-ph img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
#stay .st-ph-open { position: absolute; inset: 0; display: block; width: 100%; height: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; }
#stay .st-ph-open:focus-visible { outline-offset: -4px; }
#stay .st-gphoto { opacity: 0; transition: opacity 800ms var(--e-ink); }
#stay .st-gphoto.is-in { opacity: 1; }
/* the engraving: the highlands toile in sage ink, a different stretch of it on every card (once the page's
   decoration has loaded and IV is near: places.js sets .is-near, so the picture is never fetched before). A Google
   photo is laid over it (after it, so painted on top) and fades in across it; then places.js takes it away */
#stay .st-art { position: absolute; inset: 0; }
html.ww-deco #stay .is-near .st-art::before {
  content: ""; position: absolute; inset: 0; background: #7F8D86;
  -webkit-mask: url(../img/ornament/toile-wall.webp) calc(var(--i, 0) * -173px) calc(var(--i, 0) * -97px) / 600px repeat;
  mask: url(../img/ornament/toile-wall.webp) calc(var(--i, 0) * -173px) calc(var(--i, 0) * -97px) / 600px repeat;
}
/* the drive from the estate */
#stay .st-dist {
  position: absolute; z-index: 2; left: 12px; top: 12px; display: inline-flex; align-items: center; gap: 6px;
  min-height: 30px; padding: 0 12px 0 10px; border-radius: 999px; background: rgba(255, 255, 255, .95); color: var(--primary);
  font: 600 13px/1 var(--font-body); letter-spacing: .01em; white-space: nowrap; box-shadow: 0 2px 10px rgba(46, 53, 50, .1);
}
#stay .st-dist svg { flex: none; width: 16px; height: 16px; }
/* the photographer and Google Maps (Google's terms), on the photo's foot: a photo arriving moves nothing. A long
   credit wraps (upward, over the photo) and is never cut: "Google Maps" is always shown whole, on one line */
#stay .st-credit {
  position: absolute; z-index: 2; left: 10px; bottom: 10px; max-width: calc(100% - 20px); margin: 0; padding: 2px 10px;
  border-radius: 12px; background: rgba(255, 255, 255, .92); color: var(--ink-soft);
  font-size: 13px; line-height: 20px; overflow-wrap: anywhere;
}
#stay .st-credit:empty { display: none; }
#stay .st-credit [translate="no"] { white-space: nowrap; }
#stay .st-credit a { color: inherit; text-decoration: underline; text-decoration-color: rgba(98, 106, 102, .45); text-underline-offset: 3px; }
#stay .st-credit a:hover { color: var(--primary); }

/* the words and the actions (pinned to the card's foot, so every card in the row lines up) */
#stay .st-body { display: flex; flex-direction: column; flex: 1; padding: 14px 16px 4px; }
#stay .st-name { margin: 0; font: 400 21px/1.25 var(--font-title); color: var(--primary); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
#stay .st-area { margin: 4px 0 0; font: italic 400 15px/1.4 var(--font-title); color: var(--accent-text); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
#stay .st-blurb { margin: 8px 0 0; font-size: 16px; line-height: 1.5; color: var(--ink-soft); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }
#stay .st-acts { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 6px; margin-top: auto; padding-top: 16px; }
#stay .st-act {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; min-height: 56px; padding: 6px 2px;
  border-radius: 12px; background: var(--sage-wash); box-shadow: inset 0 0 0 1px #E3E9E5; color: var(--primary);
  font: 600 14px/1.15 var(--font-body); letter-spacing: .01em; text-align: center; text-decoration: none; white-space: nowrap;
  -webkit-tap-highlight-color: transparent; transition: background-color 160ms var(--out), scale 160ms var(--out);
}
#stay .st-act svg { flex: none; width: 20px; height: 20px; }
@media (max-width: 359px) { #stay .st-act { font-size: 13px; letter-spacing: 0; } }
#stay .st-act:hover { background-color: #EAF0EC; color: var(--primary); }
#stay .st-act:active { scale: .96; }
#stay .st-act[aria-busy="true"] { opacity: .6; }
#stay .st-email { display: flex; justify-content: center; min-height: 44px; margin: 4px 0 0; }
#stay .st-email a {
  display: inline-flex; align-items: center; min-height: 44px; max-width: 100%; overflow-wrap: anywhere; text-align: center;
  font: 500 15px/1.3 var(--font-body); color: var(--accent-text); text-decoration: underline; text-decoration-color: rgba(126, 95, 110, .4); text-underline-offset: 4px;
}
#stay .st-email a:hover { color: var(--primary); text-decoration-color: currentColor; }

/* the pager under the row: ‹ 2 of 6 › */
#stay .st-pager { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 4px; }
#stay .st-pager [aria-disabled="true"] { opacity: .35; cursor: default; }
#stay .st-onmap { margin-top: 14px; margin-bottom: 0; }
#stay .st-note { margin-top: 6px; margin-bottom: 0; font-size: 13px; line-height: 1.55; color: var(--ink-soft); text-wrap: pretty; }
#stay .st-soon { margin-top: 16px; margin-bottom: 0; font: italic 400 17px/1.5 var(--font-title); color: var(--ink-soft); }

/* ------------------------------------------------------------------ a phone held sideways: each card lies on its side
   (the photo on the left, the words on the right), so a whole card fits under the header */
@media (orientation: landscape) and (max-height: 520px) {
  #stay .st-card { flex-direction: row; width: min(560px, 68vw); }
  #stay .st-photo { flex: none; width: 42%; }
  #stay .st-ph { aspect-ratio: auto; height: 100%; border-radius: 18px 0 0 18px; }
  #stay .st-body { padding-top: 12px; }
  #stay .st-blurb { -webkit-line-clamp: 2; }
  #stay .st-acts { padding-top: 12px; }
  #stay .st-email { margin-top: 0; }
}

/* ------------------------------------------------------------------ desktop: the ticket and the stays side by side,
   the row running out to the window's edge */
@media (min-width: 1100px) {
  #stay { --st-bleed: calc((100vw - min(100vw, var(--wide) + 2 * var(--gut))) / 2 + var(--gut)); }
  #stay .st-layout {
    display: grid; grid-template-columns: minmax(0, 400px) minmax(0, 1fr); column-gap: 56px; align-items: start;
    max-width: calc(var(--wide) + 2 * var(--gut)); margin-inline: auto; padding-inline: var(--gut);
  }
  #stay .st-layout > .ch-col, #stay .st-nearby > .ch-col { max-width: none; margin-inline: 0; padding-inline: 0; }
  #stay .st-ticket { max-width: none; }
  #stay .st-paper { padding: 30px 28px 26px 34px; }
  #stay .st-nearby { min-width: 0; margin-top: 0; }
  #stay .st-snap { margin-right: calc(-1 * var(--st-bleed)); }
  #stay .st-cards { padding-inline: 0 var(--st-bleed); scroll-padding-inline: 0; }
  #stay .st-card { width: 300px; }
  #stay .st-pager { justify-content: flex-start; margin-left: -2px; }
}

/* ------------------------------------------------------------------ motion */
@keyframes st-perf { from { transform: translateY(0); } }
@keyframes st-flash { 0% { opacity: 0; } 30% { opacity: 1; } 100% { opacity: 0; } }
@keyframes st-slide { from { opacity: 0; translate: 32px 0; } }
@keyframes st-fade { from { opacity: 0; } }
@media (prefers-reduced-motion: no-preference) {
  html.ww-js #stay .st-ticket.rv.in .st-perf::before { animation: st-perf 600ms var(--io) 200ms backwards; }
  #stay .st-ref.is-copied .st-ref__value::before { animation: st-flash 420ms var(--out); }
  html.ww-js #stay .st-snap.rvg .st-card:nth-child(-n+2) { animation: st-slide 700ms var(--out) backwards; }
  html.ww-js #stay .st-snap.rvg .st-card:nth-child(2) { animation-delay: 90ms; }
  html.ww-deco #stay .is-near .st-art::before { animation: st-fade 900ms var(--out) backwards; }
}
/* ---- w/css/s-party.css ---- */
/* THE SMITH WEDDING · V The Wedding Party: the cast and the night band (WP5; VI What to Wear and its swatch book are in dress.css). Scope: #party, pt- */
/* =====================================================================
   V · The Wedding Party (#party).
   app.js renderBridalParty() writes #partyGroups (.pt):
   .pt-maids    the bridesmaids on the white page: the title, the colour they wear, the cast
   .pt-night    the one dark band, full bleed ([data-ink="night"]: the header turns charcoal over it;
                [data-ambient]: its loops rest while it is off screen):
                .pt-ridges  the highlands rise over the page: a far ridge in sage mist behind the near one in
                            charcoal (ridge-fill.svg as a mask; the near one runs into the band, no seam)
                .pt-sky     the champagne thread coming down into the band and three stars
                .pt-men     the groomsmen and the MC (.pt-mc: the feature row)
                .pt-dawn    a ridge of morning white at its foot: the page comes back with no gap
   .pt-cast     li.pt-person[data-rv="group"] > figure.pt-photo (a photograph printed into an arch, or the
                .pt-cameo: initials in script over a sprig) + h4.pt-name + p.pt-role. On a phone two columns,
                every second person a step lower: transform, never translate (the reveals own translate).
   Motion (prefers-reduced-motion: no-preference; a revealed group plays, until then its parts wait on their
   first frame): the bridesmaids are printed in; the night's portraits develop like darkroom prints, then the
   names rise; the thread is drawn, the stars come out and twinkle; the ridges rise with the scroll (a view
   timeline, P1). Pressing a portrait lifts it a little. With reduced motion all of it is finished and still.
   ===================================================================== */

#party .pt { --pt-gap: 14px; --pt-step: 48px; }

/* ------------------------------------------------------------------ the group heads */
#party .pt-h { margin: 0; text-align: center; font: 400 24px/1.2 var(--font-title); color: var(--primary); text-wrap: balance; }
#party .pt-note { display: flex; align-items: center; justify-content: center; gap: 9px; margin: 6px 0 0; font-size: 15px; line-height: 1.5; color: var(--ink-soft); }
#party .pt-note i { flex: none; width: 12px; height: 12px; border-radius: 50%; background: var(--c); box-shadow: 0 0 0 1px rgba(46, 53, 50, .16); }

/* ------------------------------------------------------------------ the cast */
#party .pt-cast { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px var(--pt-gap); margin: 28px 0 0; padding: 0; list-style: none; }
#party .pt-person { display: flex; flex-direction: column; align-items: center; min-width: 0; text-align: center; }
/* the photograph, printed into an arch with an engraved hairline a few millimetres outside it */
#party .pt-photo {
  position: relative; isolation: isolate; width: 100%; aspect-ratio: 4 / 5; margin: 0; overflow: hidden;
  border-radius: 999px 999px 12px 12px; background: var(--sage-wash);
  box-shadow: 0 0 0 5px #fff, 0 0 0 6px rgba(142, 154, 146, .42), 0 20px 30px -24px rgba(46, 53, 50, .55);
  transition: scale 300ms var(--out); -webkit-tap-highlight-color: transparent;
}
#party .pt-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 24%; }
/* the bridesmaids' photographs keep their own colour (the couple love them as they are): the grain and the pressed
   edge of the print, without the print grade */
#party .pt-maids .pt-photo img { filter: none; }
#party .pt-photo:active { scale: 1.02; }
/* someone without a photograph: a cameo, their initials in script over a sprig inside an inset hairline arch */
#party .pt-photo--cameo { display: grid; place-items: center; }
#party .pt-photo--cameo::before {
  content: ""; position: absolute; inset: 9px; border-radius: 999px 999px 7px 7px; pointer-events: none;
  box-shadow: inset 0 0 0 1px rgba(142, 154, 146, .5);
}
#party .pt-cameo { position: relative; display: flex; flex-direction: column; align-items: center; padding-top: 8%; font: 400 44px/1.1 var(--font-script); color: var(--accent-text); }
#party .pt-cameo::after {
  content: ""; display: block; width: 74px; aspect-ratio: 355 / 141; margin-top: 6px; background: var(--ink-sage); opacity: .55;
  -webkit-mask: url(../img/ornament/sprig.svg) center / contain no-repeat; mask: url(../img/ornament/sprig.svg) center / contain no-repeat;
}
#party .pt-name { margin: 18px 0 0; font: 400 20px/1.25 var(--font-title); color: var(--ink); text-wrap: balance; }
#party .pt-role { margin: 5px 0 0; font: 600 13px/1.45 var(--font-body); letter-spacing: .14em; text-transform: uppercase; color: var(--accent-text); text-wrap: balance; }

/* ------------------------------------------------------------------ the night band */
#party .pt-night {
  --rh: clamp(44px, 6.2vw, 96px);           /* how tall the near ridge stands */
  position: relative; margin-top: calc(var(--rh) + 60px); padding: 62px 0 calc(var(--rh) + 58px);
  background: var(--tie); color: var(--night-ink);
}
#party .pt-night:first-child { margin-top: calc(var(--rh) + 24px); }
#party .pt-ridges { position: absolute; left: 0; right: 0; bottom: 100%; height: calc(var(--rh) + 14px); pointer-events: none; }
#party .pt-ridge { position: absolute; left: 0; right: 0; }
/* the near ridge runs a pixel into the band, so the two never show a seam */
#party .pt-ridge--near {
  bottom: -1px; height: calc(var(--rh) + 1px); background: var(--tie);
  -webkit-mask: url(../img/ornament/ridge-fill.svg) 0 0 / 100% 100% no-repeat; mask: url(../img/ornament/ridge-fill.svg) 0 0 / 100% 100% no-repeat;
}
/* the far ridge: the same highlands seen the other way, 14px higher, in sage mist (solid below its line) */
#party .pt-ridge--far {
  top: 0; bottom: 0; background: var(--ink-mist); opacity: .75; scale: -1 1;
  -webkit-mask: url(../img/ornament/ridge-fill.svg) 0 0 / 100% var(--rh) no-repeat, linear-gradient(#000, #000) 0 100% / 100% 15px no-repeat;
  mask: url(../img/ornament/ridge-fill.svg) 0 0 / 100% var(--rh) no-repeat, linear-gradient(#000, #000) 0 100% / 100% 15px no-repeat;
}
/* the sky: the thread comes down out of the ridge into a star, and three champagne stars */
#party .pt-sky { position: absolute; left: 0; right: 0; top: 0; height: 110px; pointer-events: none; }
#party .pt-thread { position: absolute; left: 50%; top: -12px; width: 1.25px; height: 56px; margin-left: -.625px; background: var(--thread-night); transform-origin: 50% 0; }
#party .pt-thread::after {
  content: ""; position: absolute; left: 50%; bottom: -6px; width: 11px; height: 11px; margin-left: -5.5px; background: var(--thread-night);
  -webkit-mask: var(--star) center / contain no-repeat; mask: var(--star) center / contain no-repeat;
}
#party .pt-star { position: absolute; display: block; width: 11px; height: 11px; }
#party .pt-star b {
  display: block; width: 100%; height: 100%; background: var(--thread-night); opacity: .7;
  -webkit-mask: var(--star) center / contain no-repeat; mask: var(--star) center / contain no-repeat;
}
#party .pt-star:nth-of-type(1) { left: 14%; top: 22px; }
#party .pt-star:nth-of-type(2) { left: 80%; top: 8px; width: 9px; height: 9px; }
#party .pt-star:nth-of-type(3) { left: 67%; top: 46px; width: 7px; height: 7px; }
/* a ridge of morning white rises out of the foot of the band: the page comes back without a gap */
#party .pt-dawn {
  position: absolute; left: 0; right: 0; bottom: -1px; height: calc(var(--rh) + 1px); background: #fff; scale: -1 1; pointer-events: none;
  -webkit-mask: url(../img/ornament/ridge-fill.svg) 0 0 / 100% 100% no-repeat; mask: url(../img/ornament/ridge-fill.svg) 0 0 / 100% 100% no-repeat;
}
/* black tie: moonbone names, champagne roles, B&W studio portraits in a champagne hairline */
#party .pt-men { position: relative; }
#party .pt-night .pt-h { font-size: 26px; color: var(--night-ink); }
#party .pt-night .pt-note { color: var(--night-soft); }
#party .pt-night .pt-note i { box-shadow: 0 0 0 1px rgba(242, 238, 233, .3); }
#party .pt-night .pt-photo {
  background: radial-gradient(70% 60% at 50% 32%, #555A57, #1B1E1D 75%);
  box-shadow: 0 0 0 5px var(--tie), 0 0 0 6px rgba(205, 187, 164, .4), 0 24px 40px -20px rgba(0, 0, 0, .75);
}
#party .pt-night .pt-photo img { filter: grayscale(1) contrast(1.05); }
#party .pt-night .pt-photo--cameo::before { box-shadow: inset 0 0 0 1px rgba(205, 187, 164, .4); }
#party .pt-night .pt-cameo { color: var(--night-role); }
#party .pt-night .pt-cameo::after { background: var(--night-role); opacity: .5; }
#party .pt-night .pt-name { color: var(--night-ink); }
#party .pt-night .pt-role { color: var(--night-role); }
/* the MC: a hairline divider, then the feature row (the portrait at 42%, the name beside it) */
#party .pt-mc { margin-top: 76px; }
#party .pt-mc:first-child { margin-top: 0; }
#party .pt-mc__h { display: flex; align-items: center; gap: 16px; margin: 0; font: italic 400 22px/1.2 var(--font-title); color: var(--night-role); white-space: nowrap; }
#party .pt-mc__h::before, #party .pt-mc__h::after { content: ""; flex: 1; height: 1px; background: rgba(205, 187, 164, .3); }
#party .pt-mc__row { display: grid; grid-template-columns: 42% minmax(0, 1fr); align-items: center; gap: 22px; margin-top: 30px; }
#party .pt-mc__row + .pt-mc__row { margin-top: 40px; }
#party .pt-mc__words { min-width: 0; }
#party .pt-mc__row .pt-name { margin: 0; font-size: 26px; line-height: 1.2; }
#party .pt-mc__row .pt-role { margin-top: 8px; }

/* ------------------------------------------------------------------ the MC on the seam (.pt-night--host)
   One MC whose portrait also comes as a cut-out stands between the two sides, where the white page turns to night:
   .pt-moonbox > .pt-moon   a pale moon rising behind the ridge (clipped at the band's edge, behind both ridges)
   .pt-host                 his bust in black and white, before the moon: head and shoulders on the bridesmaids'
                            white page; the dinner jacket is toned to the band's own charcoal, so it runs into the
                            night, and the picture's lower part fades out in it
   .pt-hostwords            "Our MC", his name and role on the dark, then the thread down to the groomsmen
   --hw is the bust's width; its picture is 1016 x 1228 and the band's edge crosses it at 62% of its height.
   He is one of the party, not its centrepiece (James, v19): about the size of a portrait in the cast. What keeps
   him company fills the room round him: the moon is a little wider than he is, a fine ring turns round it with two
   small stars, two drifts of mist pass before it, a few stars stand on the page (.pt-orb, .pt-halo, .pt-mist, .pt-spark). */
#party .pt-night.pt-night--host {
  --hw: min(176px, 47vw);
  --md: calc(var(--hw) * 1.14);             /* the moon */
  --mb: calc(var(--hh) * .39 - var(--md) / 2);      /* its foot above the band's edge: it is centred on his face, 23% down the picture */
  --hh: calc(var(--hw) * 1228 / 1016);
  --hup: calc(var(--hh) * .62);             /* how much of him stands above the band */
  --hdown: calc(var(--hh) * .38);           /* and how much runs into it */
  margin-top: calc(var(--hup) + 64px); padding-top: calc(var(--hdown) - 22px);
}
#party .pt-night.pt-night--host:first-child { margin-top: calc(var(--hup) + 40px); }
#party .pt-moonbox { position: absolute; left: 0; right: 0; bottom: 100%; height: calc(var(--mb) + var(--md) + 96px); overflow: hidden; pointer-events: none; }
#party .pt-orb { position: absolute; left: 50%; bottom: var(--mb); width: var(--md); height: var(--md); margin-left: calc(var(--md) / -2); }
#party .pt-moon {
  position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 50% 36%, #fff 0, #F2F5F3 44%, #E3E9E5 100%);
  box-shadow: 0 0 0 1px rgba(142, 154, 146, .36), 0 0 0 7px #fff, 0 0 0 8px rgba(142, 154, 146, .24), 0 0 54px 8px rgba(185, 196, 189, .26);
}
/* the ring round the moon, with a star at its head and a smaller one at its foot */
#party .pt-halo { position: absolute; inset: -22px; border-radius: 50%; border: 1px dashed rgba(142, 154, 146, .55); }
#party .pt-halo::before, #party .pt-halo::after {
  content: ""; position: absolute; left: 50%; width: 11px; height: 11px; margin-left: -5.5px; background: var(--dusk-rose, #B48A93);
  -webkit-mask: var(--star) center / contain no-repeat; mask: var(--star) center / contain no-repeat;
}
#party .pt-halo::before { top: -6px; }
#party .pt-halo::after { bottom: -5px; width: 8px; height: 8px; margin-left: -4px; background: #8E9A92; }
/* mist: two drifts before the moon, behind him */
#party .pt-mist { position: absolute; left: 50%; background: #9FACA5; opacity: .7; }
#party .pt-mist--a { bottom: calc(var(--mb) + var(--md) * .36); width: calc(var(--md) * .94); aspect-ratio: 300 / 92; margin-left: calc(var(--md) * -1.22);
  -webkit-mask: url(../img/ornament/cloud-1.svg) center / contain no-repeat; mask: url(../img/ornament/cloud-1.svg) center / contain no-repeat; }
#party .pt-mist--b { bottom: calc(var(--mb) + var(--md) * .58); width: calc(var(--md) * .78); aspect-ratio: 300 / 92; margin-left: calc(var(--md) * .34); opacity: .6;
  -webkit-mask: url(../img/ornament/cloud-2.svg) center / contain no-repeat; mask: url(../img/ornament/cloud-2.svg) center / contain no-repeat; }
/* stars on the page: --x / --y in moon widths from the moon's foot, --s its size */
#party .pt-spark {
  position: absolute; left: calc(50% + var(--x) * var(--md)); bottom: calc(var(--mb) + var(--y) * var(--md)); width: var(--s); height: var(--s); margin: 0 0 0 calc(var(--s) / -2);
  background: #A9B4AD; opacity: .8; -webkit-mask: var(--star) center / contain no-repeat; mask: var(--star) center / contain no-repeat;
}
#party .pt-spark:nth-of-type(odd) { background: var(--dusk-rose, #B48A93); opacity: .6; }
#party .pt-host {
  position: absolute; left: 50%; bottom: calc(100% - var(--hdown)); width: var(--hw); height: var(--hh);
  margin: 0 0 0 calc(var(--hw) / -2); pointer-events: none;
}
#party .pt-host__img {
  display: block; width: 100%; height: 100%;
  /* the jacket runs out into the band: nothing of the picture's lower edge is left */
  -webkit-mask-image: linear-gradient(#000 0, #000 62%, rgba(0, 0, 0, .74) 71%, rgba(0, 0, 0, .4) 80%, rgba(0, 0, 0, .13) 88%, transparent 94%);
  mask-image: linear-gradient(#000 0, #000 62%, rgba(0, 0, 0, .74) 71%, rgba(0, 0, 0, .4) 80%, rgba(0, 0, 0, .13) 88%, transparent 94%);
}
/* (the sky's own thread would cross his shirt front: his words carry the thread instead) */
#party .pt-night--host .pt-thread { display: none; }
#party .pt-hostwords { position: relative; text-align: center; }
#party .pt-host__k { margin: 0; font: 400 34px/1.1 var(--font-script); color: var(--night-role); }
#party .pt-hostwords .pt-name { margin: 4px 0 0; font-size: 24px; line-height: 1.2; }
#party .pt-hostwords .pt-role { margin-top: 8px; }
#party .pt-host__thread { position: relative; display: block; width: 1.25px; height: 44px; margin: 24px auto 0; background: var(--thread-night); transform-origin: 50% 0; }
#party .pt-host__thread::after {
  content: ""; position: absolute; left: 50%; bottom: -6px; width: 11px; height: 11px; margin-left: -5.5px; background: var(--thread-night);
  -webkit-mask: var(--star) center / contain no-repeat; mask: var(--star) center / contain no-repeat;
}
#party .pt-hostwords + .pt-h { margin-top: 30px; }

/* ------------------------------------------------------------------ the bridge to VI */
#party .pt-bridge { margin-top: 18px; margin-bottom: 0; text-align: center; font: italic 400 18px/1.55 var(--font-title); color: var(--ink-soft); text-wrap: balance; }
#party .pt:not(.pt--night) + .pt-bridge { margin-top: 48px; }

/* ------------------------------------------------------------------ phones: the staggered cast */
@media (max-width: 599px) {
  #party .pt-person:nth-child(even) { transform: translateY(var(--pt-step)); }
  /* an even cast ends a step lower: keep the room for it */
  #party .pt-cast--even { padding-bottom: var(--pt-step); }
  /* an odd cast: its last card stands alone, in the middle */
  #party .pt-person:last-child:nth-child(odd) { grid-column: 1 / -1; justify-self: center; width: calc(50% - var(--pt-gap) / 2); }
  /* the MC on the seam fills a phone's width: the stars keep clear of his shoulders */
  #party .pt-night--host .pt-star:nth-of-type(1) { left: 5%; top: 44px; }
  #party .pt-night--host .pt-star:nth-of-type(2) { left: 91%; top: 20px; }
  #party .pt-night--host .pt-star:nth-of-type(3) { left: 86%; top: calc(var(--hdown) * .72); }
}
@media (max-width: 359px) {
  #party .pt { --pt-gap: 12px; --pt-step: 40px; }
  #party .pt-name { font-size: 19px; }
  #party .pt-cameo { font-size: 38px; }
  #party .pt-cameo::after { width: 62px; }
}

/* ------------------------------------------------------------------ larger screens: the cast in a row, no stagger */
@media (min-width: 600px) {
  #party .pt-cast { display: flex; flex-wrap: wrap; justify-content: center; gap: 44px 28px; }
  #party .pt-person { width: calc((100% - 2 * 28px) / 3); }
  #party .pt-mc { max-width: 600px; margin-inline: auto; }
  /* the MC's portrait as large as the cast's, the row centred */
  #party .pt-mc__row { grid-template-columns: min(200px, 42%) minmax(0, max-content); justify-content: center; gap: 32px; }
  #party .pt-night.pt-night--host { --hw: 196px; margin-top: calc(var(--hup) + 84px); }
}
@media (min-width: 900px) {
  #party .pt-maids, #party .pt-men { max-width: calc(1040px + 2 * var(--gut)); }
  #party .pt-person { width: calc((100% - (var(--cols, 4) - 1) * 32px) / var(--cols, 4)); max-width: 240px; }
  #party .pt-cast { gap: 48px 32px; }
  #party .pt-h { font-size: 28px; }
  #party .pt-night .pt-h { font-size: 30px; }
  #party .pt-night { padding-top: 92px; }
  #party .pt-sky { height: 140px; }
  #party .pt-thread { height: 76px; }
  #party .pt-mc { max-width: 720px; }
  #party .pt-mc__row .pt-name { font-size: 30px; }
  #party .pt-night.pt-night--host { --hw: 214px; margin-top: calc(var(--hup) + 96px); padding-top: calc(var(--hdown) - 22px); }
  #party .pt-host__k { font-size: 40px; }
  #party .pt-hostwords .pt-name { font-size: 28px; }
  #party .pt-host__thread { height: 56px; margin-top: 28px; }
  #party .pt-hostwords + .pt-h { margin-top: 36px; }
}

/* ------------------------------------------------------------------ motion (never with reduced motion) */
@media (prefers-reduced-motion: no-preference) {
  /* a photograph is printed into its arch from the foot as it comes into focus */
  @keyframes pt-print {
    0% { -webkit-mask-image: linear-gradient(0deg, #000 40%, transparent 60%); mask-image: linear-gradient(0deg, #000 40%, transparent 60%);
         -webkit-mask-size: 100% 300%; mask-size: 100% 300%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 0 0; mask-position: 0 0; filter: saturate(.6) blur(6px); }
    65% { filter: saturate(.8) blur(.8px); }
    100% { -webkit-mask-image: linear-gradient(0deg, #000 40%, transparent 60%); mask-image: linear-gradient(0deg, #000 40%, transparent 60%);
         -webkit-mask-size: 100% 300%; mask-size: 100% 300%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
         -webkit-mask-position: 0 100%; mask-position: 0 100%; filter: saturate(1) blur(0); }
  }
  /* a darkroom print: out of the dark, the contrast settling */
  @keyframes pt-develop { from { opacity: .6; filter: grayscale(1) brightness(.15) contrast(1.4); } to { opacity: 1; filter: grayscale(1) brightness(1) contrast(1.05); } }
  @keyframes pt-develop-c { from { opacity: .12; } }
  @keyframes pt-rise { from { opacity: 0; translate: 0 var(--pt-rise, 10px); } }
  @keyframes pt-fade { from { opacity: 0; } }
  @keyframes pt-draw { from { transform: scaleY(0); } }
  @keyframes pt-twinkle { from { opacity: .8; } to { opacity: .35; } }

  /* the bridesmaids: printed in (90 ms apart), then their names rise */
  html.ww-js #party .pt-maids .pt-person.rvg .pt-photo img { animation: pt-print 1500ms var(--e-ink) calc(var(--d, 0ms) * 9 / 7) backwards; }
  html.ww-js #party .pt-maids .pt-person.rvg .pt-cameo { animation: pt-rise 1100ms var(--out) calc(var(--d, 0ms) * 9 / 7 + 200ms) backwards; --pt-rise: 8px; }
  html.ww-js #party .rvg .pt-name { animation: pt-rise 800ms var(--out) calc(var(--d, 0ms) + 260ms) backwards; }
  html.ww-js #party .rvg .pt-role { animation: pt-rise 800ms var(--out) calc(var(--d, 0ms) + 340ms) backwards; }
  /* the night: each portrait develops (1400 ms, 90 ms apart), then the name and the role rise */
  html.ww-js #party .pt-night .rvg .pt-photo img { animation: pt-develop 1400ms var(--e-ink) calc(var(--d, 0ms) * 9 / 7) backwards; }
  html.ww-js #party .pt-night .rvg .pt-cameo { animation: pt-develop-c 1400ms var(--e-ink) calc(var(--d, 0ms) * 9 / 7) backwards; }
  html.ww-js #party .pt-night .rvg .pt-name { animation-delay: calc(var(--d, 0ms) + 760ms); }
  html.ww-js #party .pt-night .rvg .pt-role { animation-delay: calc(var(--d, 0ms) + 840ms); }
  /* the thread is drawn down into its star; the stars come out (300 ms apart), then twinkle while in view */
  html.ww-js #party .pt-sky.rvg .pt-thread { animation: pt-draw 900ms var(--io) 120ms backwards; }
  html.ww-js #party .pt-sky.rvg .pt-star { animation: pt-fade 1200ms var(--out) calc(500ms + var(--i, 0) * 300ms) backwards; }
  html.ww-js #party .pt-sky .pt-star b { animation: pt-twinkle 3.6s var(--io) calc(1800ms + var(--i, 0) * 1.3s) infinite alternate; }
  /* the MC on the seam: he develops like the night's prints and comes up a step; "Our MC" rises, then his name and
     role, and the thread is drawn down to the groomsmen */
  @keyframes pt-host-in { from { opacity: 0; filter: brightness(.35) contrast(1.3) blur(3px); transform: translateY(16px); } }
  html.ww-js #party .pt-host.rvg .pt-host__img { animation: pt-host-in 1700ms var(--e-ink) 120ms backwards; }
  html.ww-js #party .pt-hostwords.rvg .pt-host__k { animation: pt-rise 900ms var(--out) 160ms backwards; --pt-rise: 12px; }
  html.ww-js #party .pt-night .pt-hostwords.rvg .pt-name { animation-delay: 360ms; }
  html.ww-js #party .pt-night .pt-hostwords.rvg .pt-role { animation-delay: 460ms; }
  html.ww-js #party .pt-hostwords.rvg .pt-host__thread { animation: pt-draw 900ms var(--io) 760ms backwards; }
  /* what keeps him company: the ring turns once in two minutes, the mist drifts, the page's stars twinkle, the moon breathes */
  @keyframes pt-turn { to { rotate: 360deg; } }
  @keyframes pt-drift { from { translate: -14px 0; } to { translate: 16px 0; } }
  @keyframes pt-glow { to { box-shadow: 0 0 0 1px rgba(142, 154, 146, .36), 0 0 0 7px #fff, 0 0 0 8px rgba(142, 154, 146, .24), 0 0 70px 16px rgba(185, 196, 189, .42); } }
  html.ww-js #party .pt-halo { animation: pt-turn 120s linear infinite; }
  html.ww-js #party .pt-moon { animation: pt-glow 7s var(--io) infinite alternate; }
  html.ww-js #party .pt-mist--a { animation: pt-drift 31s var(--io) infinite alternate; }
  html.ww-js #party .pt-mist--b { animation: pt-drift 43s var(--io) -9s infinite alternate-reverse; }
  html.ww-js #party .pt-spark { animation: pt-twinkle 3.4s var(--io) calc(var(--i, 0) * -1.1s) infinite alternate; }

  /* the ridges rise over the page as the band comes up the screen (a scrub on their wrapper; elsewhere still) */
  @supports (animation-timeline: view()) {
    @keyframes pt-ridges { from { transform: translateY(24px); } }
    #party .pt-night { view-timeline: --night block; }
    #party .pt-ridges { animation: pt-ridges linear both; animation-timeline: --night; animation-range: entry 0% entry 40%; }
    /* the moon comes up behind the ridge as the band rises into view */
    @keyframes pt-moonrise { from { transform: translateY(54px); } }
    #party .pt-orb { animation: pt-moonrise linear both; animation-timeline: --night; animation-range: entry 0% entry 80%; }
  }
}
/* ---- w/css/s-reply.css ---- */
/* =====================================================================
   THE SMITH WEDDING · VIII Good to Know and IX Kindly Reply (WP6; VII Our Photos lives in gallery.css)
   Scope: #faq, #rsvp and the faq- / rp- prefixes only. Rules that replace style.css's older FAQ and RSVP looks
   (.faq-list, .faq-item, .faq-a; .label, .input inside #rsvp) are scoped here; the old ones are listed for deletion.
   Motion: transform and opacity only (rotate, translate, scale), each one-shot (nothing loops), inside
   prefers-reduced-motion: no-preference; with reduced motion every state is simply there, finished and still.
   ===================================================================== */

/* ------------------------------------------------------------------ VIII · Good to Know
   Quiet hairline rows (<details name="faq">: all closed, one open at a time): the question in Playfair 19, a 44px
   + that turns into a x; the answer in 17px. Then a way to ask anything else (a note on the reply, or the couple
   once replies have closed). */
#faq .faq-list { display: block; margin: 0; border-bottom: 1px solid var(--line); }
#faq .faq-item { margin: 0; background: none; border: 0; border-top: 1px solid var(--line); border-radius: 0; overflow: visible; }
#faq .faq-item > summary {
  display: flex; align-items: center; gap: 16px; min-height: 64px; padding: 10px 0; margin: 0;
  list-style: none; background: none; border: 0; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
#faq .faq-item > summary::-webkit-details-marker { display: none; }
#faq .faq-item > summary::marker { content: ""; }
#faq .faq-q { flex: 1; min-width: 0; font: 400 19px/1.35 var(--font-title); color: var(--primary); text-wrap: balance; }
#faq .faq-item > summary:hover .faq-q { color: var(--accent-text); }
#faq .faq-item > summary:focus-visible { outline: 3px solid var(--heather); outline-offset: 2px; border-radius: 6px; }
/* the + (two hairlines in a 44px ring); open, it turns a quarter and a half into a x */
#faq .faq-x { position: relative; flex: none; width: 44px; height: 44px; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--line); }
#faq .faq-x::before, #faq .faq-x::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 14px; height: 1.5px; margin: -.75px 0 0 -7px;
  border-radius: 1px; background: var(--accent-text);
}
#faq .faq-x::after { rotate: 90deg; }
#faq .faq-item[open] .faq-x { rotate: 45deg; background: var(--blush-wash); box-shadow: none; }
#faq .faq-a { margin: 0; padding: 0 0 22px; font-size: 17px; line-height: 1.65; color: var(--ink-soft); }
#faq .faq-a p { margin: 0; }
#faq .faq-a p + p { margin-top: .8em; }
#faq .faq-soon { margin: 0; padding: 20px 0; text-align: center; color: var(--ink-soft); }
#faq .faq-end { display: flex; flex-wrap: wrap; align-items: center; column-gap: 10px; margin: 18px 0 0; font: italic 400 17px/1.4 var(--font-title); color: var(--ink-soft); }
#faq .faq-end .text-btn { font-style: normal; }
html:not(.rsvp-open) #faq .faq-end__go, html.rsvp-open #faq .faq-end__ask { display: none; }
@media (min-width: 600px) {
  #faq .faq-a { padding-right: 60px; }
}

/* ------------------------------------------------------------------ IX · Kindly Reply
   One reply card: white stationery on the moonbone table (the chapter's field), a double inset frame and engraved
   corners. It holds one state at a time (app.js): closed (.rp-closed), a household's own code opening (.rp-wait),
   the lookup (.rp-lookup), the steps (.rp-form: the step thread, the step, Back / Next in a sticky .step-nav at
   the card's foot) or the sealed thank-you (.rp-thanks). */
#rsvp .rp-card {
  position: relative; isolation: isolate; max-width: 560px; margin: 0 auto; padding: 40px 20px 24px;
  background: #fff; border-radius: 6px; text-align: left;
  box-shadow: inset 0 0 0 1px rgba(185, 196, 189, .62), 0 24px 46px -30px rgba(52, 62, 58, .42), 0 2px 8px rgba(52, 62, 58, .05);
}
/* the frame's inner line, 6px in (two pseudo-elements, so each pair of sides can be drawn in on its own) */
#rsvp .rp-card::before, #rsvp .rp-card::after { content: ""; position: absolute; inset: 6px; z-index: 0; border-radius: 3px; pointer-events: none; }
#rsvp .rp-card::before { border-block: 1px solid rgba(185, 196, 189, .4); }
#rsvp .rp-card::after { border-inline: 1px solid rgba(185, 196, 189, .4); }
#rsvp .rp-card > .orn { inset: 12px; --cs: 34px; opacity: .55; }
#rsvp .rp-card > :not(.orn) { position: relative; z-index: 1; }

/* the words of the card */
#rsvp .rp-h { margin: 0; font: 400 24px/1.25 var(--font-title); color: var(--primary); text-align: center; text-wrap: balance; }
#rsvp .rp-lead { margin: 8px 0 0; font-size: 17px; line-height: 1.6; color: var(--ink); text-wrap: pretty; }
#rsvp .rp-note { margin: 10px 0 0; font-size: 15px; line-height: 1.5; color: var(--ink-soft); text-wrap: pretty; }
#rsvp .rp-note .ic { margin-right: 2px; color: var(--accent-text); }
#rsvp .rp-note--lock { font-weight: 500; color: var(--accent-text); }

/* fields: 52px, 17px (no zoom on iOS) */
#rsvp .label, #rsvp .rp-q { display: block; margin: 20px 0 8px; font: 600 15px/1.4 var(--font-body); color: var(--ink); }
#rsvp .input {
  display: block; width: 100%; min-height: 52px; padding: 12px 16px; border: 1px solid #D6CFC8; border-radius: 12px;
  background-color: #fff; font: 400 17px/1.4 var(--font-body); color: var(--ink);
}
#rsvp .input::placeholder { color: #6E7672; opacity: 1; }
#rsvp .input:focus { border-color: var(--primary); outline: none; box-shadow: 0 0 0 3px rgba(90, 105, 100, .16); }
#rsvp textarea.input { min-height: 120px; resize: vertical; }
#rsvp select.input {
  -webkit-appearance: none; appearance: none; padding-right: 44px;
  background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235A6964' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 14px center / 18px;
}
#rsvp .form-msg { margin: 10px 0 0; font-size: 15px; line-height: 1.5; font-weight: 600; color: var(--ink-soft); }
#rsvp .form-msg.error { color: #9B2C2C; }
#rsvp .form-msg:empty { margin: 0; }

/* closed (rsvp.closedText, or paused), and a household's own code opening */
#rsvp .rp-closed { text-align: center; }
#rsvp .rp-closed p { max-width: 30em; margin: 10px auto 4px; font-size: 17px; line-height: 1.6; color: var(--ink-soft); }
#rsvp .rp-wait { min-height: 120px; margin: 0; display: grid; place-items: center; text-align: center; font: italic 400 19px/1.4 var(--font-title); color: var(--accent-text); }
#rsvp .rp-wait[hidden] { display: none; }

/* the lookup: the name, Find my invitation, then the personal link's code (a device that has replied is told how
   to change it) */
#rsvp .rp-replied { display: none; text-align: center; }
html.has-replied #rsvp .rp-replied { display: block; }
#rsvp .rp-find { margin-top: 16px; }
#rsvp .rp-hint { margin: 24px 0 0; padding-top: 18px; border-top: 1px solid var(--line); font-size: 15px; line-height: 1.5; color: var(--ink-soft); text-align: center; text-wrap: balance; }
#rsvp .rp-usecode { display: flex; margin: 0 auto; }
#rsvp .rp-codebox .btn { margin-top: 12px; }
#rsvp .rp-code { letter-spacing: .14em; text-transform: uppercase; font-variant-numeric: lining-nums; }
#rsvp .rp-code::placeholder { letter-spacing: .04em; text-transform: none; }

/* the step thread: a bead per step on a hairline, filled up to the current step; the current bead is a filled,
   haloed knot (.rp-steps__go) that travels there from the step before */
#rsvp .rp-steps { --bead: 14px; position: relative; margin: -12px -6px 24px; }
#rsvp .rp-steps ol { position: relative; z-index: 1; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); margin: 0; padding: 0; list-style: none; }
#rsvp .rp-steps li {
  display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 0 4px; text-align: center;
  font: 600 13px/1.3 var(--font-body); letter-spacing: .02em; color: var(--ink-soft);
}
#rsvp .rp-steps li.is-current { color: var(--accent-text); }
#rsvp .rp-steps__bead { width: var(--bead); height: var(--bead); border-radius: 50%; background: #fff; box-shadow: inset 0 0 0 1.5px var(--thread); }
#rsvp .rp-steps li.is-done .rp-steps__bead { background: var(--thread); box-shadow: none; }
#rsvp .rp-steps::before, #rsvp .rp-steps__fill {
  content: ""; position: absolute; top: calc(var(--bead) / 2 - .625px); left: calc(50% / var(--n)); right: calc(50% / var(--n));
  height: 1.25px; background: var(--line);
}
#rsvp .rp-steps__fill { background: var(--thread); transform-origin: 0 50%; transform: scaleX(calc(var(--at) / (var(--n) - 1))); }
#rsvp .rp-steps__go { position: absolute; z-index: 2; top: 0; left: 0; width: calc(100% / var(--n)); height: var(--bead); translate: calc(var(--at) * 100%) 0; pointer-events: none; }
#rsvp .rp-steps__go::before {
  content: ""; position: absolute; left: 50%; top: 0; width: var(--bead); height: var(--bead); margin-left: calc(var(--bead) / -2);
  border-radius: 50%; background: var(--accent-text); box-shadow: 0 0 0 4px rgba(180, 138, 147, .22);
}

/* a step: the greeting, then one section per person (the role over the name), on hairlines */
#rsvp .rp-step { min-width: 0; }
#rsvp .rp-hello { text-align: center; }
#rsvp .rp-notyou { display: flex; margin: 2px auto 0; }
#rsvp .rp-person { min-width: 0; margin: 24px 0 0; padding: 22px 0 0; border: 0; border-top: 1px solid var(--line); }
#rsvp .rp-legend { float: left; width: 100%; margin: 0 0 14px; padding: 0; }
#rsvp .rp-legend + * { clear: left; }
#rsvp .rp-role { display: block; font: 600 13px/1.4 var(--font-body); letter-spacing: .16em; text-transform: uppercase; color: var(--accent-text); }
#rsvp .rp-role .ic { margin-right: 6px; color: inherit; }
#rsvp .rp-name { margin: 4px 0 0; font: 400 21px/1.25 var(--font-title); color: var(--primary); text-wrap: balance; }
#rsvp .rp-person.is-locked .rp-choices { opacity: .75; }

/* accepts / declines: two 52px choices side by side from 360px; a press and a fill */
#rsvp .rp-choices { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
#rsvp .rp-choice { position: relative; display: flex; min-width: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }
#rsvp .rp-choice input { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
#rsvp .rp-choice span {
  position: relative; isolation: isolate; flex: 1; display: flex; align-items: center; justify-content: center; min-height: 52px; padding: 7px 12px;
  border-radius: 12px; background: #fff; box-shadow: inset 0 0 0 1.5px #D6CFC8;
  font: 600 16px/1.25 var(--font-body); color: var(--primary); text-align: center; text-wrap: balance;
}
#rsvp .rp-choice span::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; background: var(--primary); opacity: 0; }
#rsvp .rp-choice--no span::before { background: var(--accent-text); }
#rsvp .rp-choice input:checked + span { color: #fff; box-shadow: none; }
#rsvp .rp-choice input:checked + span::before { opacity: 1; }
#rsvp .rp-choice input:focus-visible + span { outline: 3px solid var(--heather); outline-offset: 2px; }
#rsvp .rp-choice input:disabled { cursor: not-allowed; }
#rsvp .rp-choice input:disabled + span { opacity: .55; }
#rsvp .rp-choice:active span { scale: .97; }
@media (min-width: 360px) {
  #rsvp .rp-choices { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* rows: a checkbox (.rp-check) or a radio (.rp-opt), 48px, the whole row its input; .rp-box draws it */
#rsvp .rp-q { margin-top: 22px; }
#rsvp .rp-day { margin: 18px 0 8px; font: 400 18px/1.3 var(--font-title); color: var(--primary); }
#rsvp .rp-check, #rsvp .rp-opt {
  position: relative; display: flex; align-items: flex-start; gap: 12px; min-height: 48px; margin: 0 0 8px; padding: 12px 14px;
  border-radius: 12px; background: #fff; box-shadow: inset 0 0 0 1px var(--line); cursor: pointer; -webkit-tap-highlight-color: transparent;
}
#rsvp .rp-check input, #rsvp .rp-opt input { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
#rsvp .rp-box { position: relative; flex: none; width: 22px; height: 22px; margin-top: 1px; border-radius: 6px; background: #fff; box-shadow: inset 0 0 0 1.5px #A9B3AD; }
#rsvp .rp-opt .rp-box { border-radius: 50%; }
#rsvp input:checked + .rp-box { background: var(--primary); box-shadow: none; }
#rsvp .rp-check input:checked + .rp-box::after {
  content: ""; position: absolute; left: 8px; top: 4px; width: 6px; height: 11px; box-sizing: border-box;
  border: solid #fff; border-width: 0 2px 2px 0; rotate: 45deg;
}
#rsvp .rp-opt input:checked + .rp-box::after { content: ""; position: absolute; inset: 7px; border-radius: 50%; background: #fff; }
#rsvp .rp-check:has(input:checked), #rsvp .rp-opt:has(input:checked) { background: var(--sage-wash); box-shadow: inset 0 0 0 1.5px var(--primary); }
#rsvp .rp-check:has(input:focus-visible), #rsvp .rp-opt:has(input:focus-visible) { outline: 3px solid var(--heather); outline-offset: 2px; }
#rsvp .rp-row__t { min-width: 0; }
#rsvp .rp-row__t strong { display: block; font-weight: 600; font-size: 16px; line-height: 1.4; color: var(--ink); }
#rsvp .rp-row__m { display: block; margin-top: 2px; font-size: 15px; line-height: 1.45; color: var(--ink-soft); }
#rsvp .rp-opt.is-fixed { cursor: default; background: var(--bg-soft); box-shadow: none; }

/* the menu: a course to choose is a group of its own (its title the legend), one served to all is shown */
#rsvp .rp-course { min-width: 0; margin: 18px 0 0; padding: 0; border: 0; }
#rsvp .rp-course__t { margin: 0 0 8px; padding: 0; font: 400 18px/1.3 var(--font-title); color: var(--primary); }
#rsvp legend.rp-course__t { float: left; width: 100%; }
#rsvp legend.rp-course__t + * { clear: left; }
#rsvp .rp-tag { margin-left: 6px; font: 600 13px/1.4 var(--font-body); letter-spacing: .12em; text-transform: uppercase; color: var(--accent-text); white-space: nowrap; }
#rsvp .rp-person .grid-2 { column-gap: 16px; }

/* Back / Next: sticky at the card's foot (and the screen's, above the home indicator), with the step's message.
   A field the focus moves to is scrolled clear of it (the browser keeps an element's scroll-margin in view) */
#rsvp .rp-step :is(input, select, textarea, button, a[href]) { scroll-margin-bottom: calc(112px + env(safe-area-inset-bottom, 0px)); }
#rsvp .step-nav {
  position: sticky; bottom: 0; z-index: 3; display: flex; flex-wrap: wrap; align-items: center; column-gap: 10px; row-gap: 0;
  margin: 28px -13px -18px; padding: 12px 13px calc(12px + env(safe-area-inset-bottom, 0px));
  background: rgba(255, 255, 255, .97); border-top: 1px solid var(--line); border-radius: 0 0 3px 3px;
}
#rsvp .step-nav .btn { flex: 1 1 auto; min-width: 0; min-height: 48px; padding-inline: 16px; letter-spacing: .01em; }
#rsvp .step-nav .btn-outline { flex: 0 0 auto; padding-inline: 20px; }
/* (a short landscape screen keeps its height for the form: the bar stays at the card's foot) */
@media (max-height: 499px) {
  #rsvp .step-nav { position: relative; }
}
#rsvp .rp-msg { flex: 1 1 100%; margin: 0; font-size: 15px; line-height: 1.45; }
#rsvp .rp-msg:not(:empty) { margin-bottom: 10px; }
#rsvp .rp-msg .btn { flex: none; margin-top: 8px; }

/* the thank-you: the reply sealed in its envelope, tied with the thread */
#rsvp .rp-thanks { text-align: center; }
#rsvp .rp-seal { position: relative; width: 132px; height: 104px; margin: -4px auto 4px; }
#rsvp .rp-env { position: absolute; left: 0; top: 18px; width: 132px; height: 86px; overflow: visible; }
#rsvp .rp-flap { position: absolute; left: 0; top: 18px; width: 132px; height: 56px; overflow: visible; transform-origin: 50% 0; }
#rsvp .rp-bow { position: absolute; left: 14px; top: 52px; width: 104px; height: 44px; overflow: hidden; }
#rsvp .rp-bow svg { display: block; width: 100%; height: 100%; }
#rsvp .rp-wax { position: absolute; left: 50%; top: 50px; width: 44px; height: 44px; margin-left: -22px; rotate: -6deg; }
#rsvp .rp-thanks__t { margin: 8px 0 0; padding: 0 .1em; font: 400 clamp(2.5rem, 11vw, 3.4rem)/1.15 var(--font-script); color: var(--accent-text); text-wrap: balance; }
#rsvp .rp-thanks__n { display: block; }
#rsvp .rp-thanks .rp-lead { margin-top: 12px; text-align: center; }
#rsvp .rp-sum { margin: 18px 0 0; padding: 0; list-style: none; text-align: left; border-top: 1px solid var(--line); }
#rsvp .rp-sum li { padding: 12px 0; border-bottom: 1px solid var(--line); }
#rsvp .rp-sum strong { display: block; font: 400 19px/1.3 var(--font-title); color: var(--primary); }
#rsvp .rp-sum__m { display: block; margin-top: 2px; font-size: 15px; line-height: 1.5; color: var(--ink-soft); }
#rsvp .rp-thanks .rp-note { text-align: left; }
#rsvp .rp-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 22px; }
/* (replies closed: "Change my reply" is hidden, and the row with it when nothing else is in it) */
#rsvp .rp-actions [hidden] { display: none; }
#rsvp .rp-actions:not(:has(> :not([hidden]))) { display: none; }
#rsvp .rp-next { display: flex; flex-wrap: wrap; justify-content: center; column-gap: 22px; margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--line); }
#rsvp .rp-next__t { flex: 1 1 100%; margin: 0; font: 600 13px/1.4 var(--font-body); letter-spacing: .16em; text-transform: uppercase; color: var(--accent-text); }

/* ------------------------------------------------------------------ the invitation (v25)
   The lookup shows the invitation sealed in its envelope; a household that opens sees it open (.rp-seal--open: the
   flap up, the letter standing out of the pocket), "Dear ..." in Pinyon, what it is invited to (.rp-plan: a line a
   part of the weekend, with its day, its hours and its place), a few facts (.rp-facts: the seats, the room, the
   date to reply by) and one button. */
#rsvp .rp-lookup .rp-seal { margin: -10px auto 8px; }
#rsvp .rp-lookup__lead { max-width: 26em; margin: 8px auto 4px; text-align: center; font-size: 16px; color: var(--ink-soft); }
#rsvp .rp-seal--open { height: 132px; margin: -2px auto 10px; }
#rsvp .rp-seal--open .rp-env { top: 46px; z-index: 3; }
#rsvp .rp-seal--open .rp-flap { top: 46px; z-index: 1; scale: 1 -1; }
#rsvp .rp-letter { position: absolute; z-index: 2; left: 15px; top: 10px; width: 102px; height: 96px; border-radius: 3px; background: #fff; box-shadow: inset 0 0 0 1.5px #C5CEC8; }
#rsvp .rp-letter i { display: block; height: 1.5px; margin: 9px 18px 0; border-radius: 1px; background: #DCE2DE; }
#rsvp .rp-letter i:first-child { width: 40px; margin: 15px auto 0; background: #B48A93; }
#rsvp .rp-eyebrow { margin: 0; text-align: center; font: 600 13px/1.4 var(--font-body); letter-spacing: .2em; text-transform: uppercase; color: var(--accent-text); }
#rsvp .rp-dear { margin-top: 8px; font-size: 22px; }
#rsvp .rp-dear__n { display: block; margin-top: 2px; padding: 0 .1em; font: 400 clamp(2.4rem, 10.5vw, 3.3rem)/1.15 var(--font-script); color: var(--accent-text); text-wrap: balance; }
#rsvp .rp-invite__lead { max-width: 30em; margin: 10px auto 0; text-align: center; }
#rsvp .rp-sub { margin: 24px 0 0; padding-top: 18px; border-top: 1px solid var(--line); text-align: center; font: 600 13px/1.4 var(--font-body); letter-spacing: .16em; text-transform: uppercase; color: var(--accent-text); }
#rsvp .rp-plan { margin: 8px 0 0; padding: 0; list-style: none; text-align: left; counter-reset: none; }
#rsvp .rp-plan__i { display: grid; grid-template-columns: 58px minmax(0, 1fr); column-gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--line); }
#rsvp .rp-plan__i:last-child { border-bottom: 0; }
#rsvp .rp-plan__i:nth-child(2) { --i: 1; } #rsvp .rp-plan__i:nth-child(3) { --i: 2; } #rsvp .rp-plan__i:nth-child(4) { --i: 3; } #rsvp .rp-plan__i:nth-child(n+5) { --i: 4; }
#rsvp .rp-plan__d { display: flex; flex-direction: column; align-items: center; justify-content: center; align-self: start; min-height: 58px; border-radius: 12px; background: var(--sage-wash); color: var(--primary); }
#rsvp .rp-plan__d b { font: 600 12px/1.2 var(--font-body); letter-spacing: .14em; text-transform: uppercase; }
#rsvp .rp-plan__d i { margin-top: 2px; font: 400 15px/1.3 var(--font-title); font-style: normal; }
#rsvp .rp-plan__i.is-main .rp-plan__d { background: var(--blush-wash); color: var(--accent-text); box-shadow: inset 0 0 0 1px rgba(180, 138, 147, .35); }
#rsvp .rp-plan__w { min-width: 0; }
#rsvp .rp-plan__w strong { display: block; font: 400 19px/1.3 var(--font-title); color: var(--primary); text-wrap: balance; }
#rsvp .rp-plan__m { display: block; margin-top: 2px; font-size: 15px; line-height: 1.45; color: var(--ink-soft); }
#rsvp .rp-plan__dress { font-style: italic; }
#rsvp .rp-plan__who { display: inline-block; margin-top: 6px; padding: 2px 10px; border-radius: 999px; background: var(--bg-soft); box-shadow: inset 0 0 0 1px var(--line); font: 600 13px/1.5 var(--font-body); color: var(--primary); }
#rsvp .rp-facts { margin: 16px 0 0; padding: 14px 16px; list-style: none; border-radius: 12px; background: var(--bg-soft); text-align: left; }
#rsvp .rp-facts li { display: flex; align-items: flex-start; gap: 12px; font-size: 15.5px; line-height: 1.5; color: var(--ink); }
#rsvp .rp-facts li + li { margin-top: 10px; }
#rsvp .rp-facts .ic { flex: none; margin: 2px 0 0; color: var(--accent-text); }
#rsvp .rp-facts .ic svg { width: 20px; height: 20px; }
#rsvp .rp-invite .rp-notyou { margin-top: 14px; }
#rsvp .rp-invite .rp-sum { margin-top: 16px; }
#rsvp .rp-invite .rp-note { text-align: left; }
#rsvp .rp-nav0 .btn-outline { flex: 1 1 auto; }

/* the weekend's step: the day's dress beside its name; parts at the same time as one question on a soft panel; a room
   that is set aside */
#rsvp .rp-day__dress { display: block; margin-top: 2px; font: 600 12px/1.4 var(--font-body); letter-spacing: .12em; text-transform: uppercase; color: var(--accent-text); }
#rsvp .rp-pick { margin: 0 0 8px; padding: 12px 12px 4px; border-radius: 14px; background: var(--bg-soft); }
#rsvp .rp-pick__q { margin: 0 2px 10px; font: 600 15px/1.4 var(--font-body); color: var(--ink); }
#rsvp .rp-pick__q span { display: block; font-weight: 400; color: var(--ink-soft); }
#rsvp .rp-held__note { display: flex; align-items: flex-start; gap: 12px; margin: 0 0 12px; padding: 14px 16px; border-radius: 12px; background: var(--sage-wash); font-size: 16px; line-height: 1.5; color: var(--ink); }
#rsvp .rp-held__note .ic { flex: none; margin: 2px 0 0; }
#rsvp .rp-held__note .ic svg { width: 22px; height: 22px; }
#rsvp .rp-review .rp-sum { margin-top: 10px; }
#rsvp .rp-sum + .rp-note .ic svg { width: 18px; height: 18px; }

/* the smallest phones: a little more room inside the card */
@media (max-width: 359px) {
  #rsvp .rp-card { padding-inline: 16px; }
  #rsvp .step-nav { margin-inline: -9px; padding-inline: 9px; }
}
@media (min-width: 600px) {
  #rsvp .rp-card { padding: 48px 32px 32px; }
  #rsvp .rp-card > .orn { --cs: 40px; inset: 14px; }
  #rsvp .step-nav { margin: 32px -25px -26px; padding-inline: 25px; }
  #rsvp .rp-actions { flex-direction: row; justify-content: center; }
}

/* ------------------------------------------------------------------ motion (P1): transform and opacity, one-shot
   VIII: the rows rise 60 ms apart (motion.js .rv), the + turns, an answer fades down into place.
   IX: the card rises (.rv) and its inner frame is drawn in; Next / Back: the step leaves 16px to one side (200 ms)
   and the next comes in from the other (320 ms) while the thread's bead travels (400 ms); a choice presses (160 ms)
   and fills. The thank-you (.reply-seal, held on its first frame until it is in view: motion.js [data-rv="group"]):
   the flap shuts, the wax is pressed, the thread ties a bow, and the words rise. */
@keyframes faq-open { from { opacity: 0; translate: 0 -6px; } }
@keyframes rp-frame-x { from { scale: 0 1; } }
@keyframes rp-frame-y { from { scale: 1 0; } }
@keyframes rp-in-next { from { opacity: 0; translate: 16px 0; } }
@keyframes rp-in-back { from { opacity: 0; translate: -16px 0; } }
@keyframes rp-out-next { to { opacity: 0; translate: -16px 0; } }
@keyframes rp-out-back { to { opacity: 0; translate: 16px 0; } }
@keyframes rp-go { from { translate: calc(var(--from) * 100%) 0; } }
@keyframes rp-fill { from { transform: scaleX(calc(var(--from) / (var(--n) - 1))); } }
@keyframes rp-flap { from { scale: 1 -1; } }
@keyframes rp-press { 0% { opacity: 0; scale: 1.7; rotate: -24deg; } 55% { opacity: 1; scale: .94; } 100% { opacity: 1; scale: 1; rotate: -6deg; } }
@keyframes rp-wipe { from { translate: -100% 0; } }
@keyframes rp-unwipe { from { translate: 100% 0; } }
@keyframes rp-rise { from { opacity: 0; translate: 0 12px; } }
@keyframes rp-unflap { 0% { scale: 1 1; z-index: 4; } 49% { z-index: 4; } 50% { scale: 1 0; z-index: 1; } 100% { scale: 1 -1; z-index: 1; } }
@keyframes rp-letter { from { translate: 0 34px; } }
@media (prefers-reduced-motion: no-preference) {
  #faq .faq-x { transition: rotate 280ms var(--io); }
  #faq .faq-item[open] > .faq-a { animation: faq-open 280ms var(--io) both; }
  html.ww-js #faq .faq-item.rv.in { transition-delay: calc(var(--d, 0ms) * 6 / 7); }

  html.ww-js #rsvp .rp-card.rv.in::before { animation: rp-frame-x 1100ms var(--io) 240ms backwards; }
  html.ww-js #rsvp .rp-card.rv.in::after { animation: rp-frame-y 1100ms var(--io) 240ms backwards; }
  #rsvp .rp-step[data-enter="next"] { animation: rp-in-next 320ms var(--out) both; }
  #rsvp .rp-step[data-enter="back"] { animation: rp-in-back 320ms var(--out) both; }
  #rsvp .rp-step.is-leaving { animation: rp-out-next 200ms var(--io) forwards; pointer-events: none; }
  #rsvp .rp-step.is-leaving-back { animation: rp-out-back 200ms var(--io) forwards; pointer-events: none; }
  #rsvp .rp-steps__go { animation: rp-go 400ms var(--io) both; }
  #rsvp .rp-steps__fill { animation: rp-fill 400ms var(--io) both; }
  #rsvp .rp-choice span { transition: scale 160ms var(--out); }
  #rsvp .rp-choice span::before { transition: opacity 200ms var(--out); }

  /* the invitation opens: the flap lifts, the letter stands up out of the envelope, then its words rise */
  #rsvp .rp-invite.is-opening .rp-flap { animation: rp-unflap 900ms var(--io) 150ms backwards; }
  #rsvp .rp-invite.is-opening .rp-letter { animation: rp-letter 800ms var(--out) 800ms backwards; }
  #rsvp .rp-invite.is-opening > :not(.rp-seal) { animation: rp-rise 800ms var(--out) 1250ms backwards; }
  #rsvp .rp-invite.is-opening > .rp-eyebrow { animation-delay: 1050ms; }
  #rsvp .rp-invite.is-opening > .rp-dear { animation-delay: 1150ms; }
  #rsvp .rp-invite.is-opening .rp-plan__i { animation: rp-rise 700ms var(--out) calc(1400ms + var(--i, 0) * 90ms) backwards; }
  html.ww-js #rsvp .reply-seal .rp-flap { animation: rp-flap 1100ms var(--io) 100ms backwards; }
  html.ww-js #rsvp .reply-seal .rp-wax { animation: rp-press 820ms var(--out) 1000ms backwards; }
  html.ww-js #rsvp .reply-seal .rp-bow { animation: rp-wipe 900ms var(--io) 1450ms backwards; }
  html.ww-js #rsvp .reply-seal .rp-bow svg { animation: rp-unwipe 900ms var(--io) 1450ms backwards; }
  html.ww-js #rsvp .reply-seal .rp-thanks__t { animation: rp-rise 900ms var(--out) 240ms backwards; }
  html.ww-js #rsvp .reply-seal :is(.rp-lead, .rp-sum, .rp-note, .rp-actions, .rp-next) { animation: rp-rise 800ms var(--out) 420ms backwards; }
}
