/* ==========================================================================
   Ailan & Lucyann — Garden Chic
   Palette, type, and shared components. Page-specific rules live at the end.
   ========================================================================== */

:root {
  --ivory:      #FBF8F3;
  --cream:      #F3EDE4;
  --linen:      #EAE2D5;
  --sage:       #7C8B6F;
  --sage-deep:  #55634A;
  --sage-pale:  #C3CDB8;
  --blush:      #D8BCAF;
  --ink:        #2C2E28;
  --muted:      #5F6259;
  --white:      #FFFFFF;

  --display: "Cormorant Garamond", Georgia, serif;
  --body:    "Jost", "Helvetica Neue", Arial, sans-serif;

  --wide:  0.32em;   /* letterspacing for the airy caps treatment */
  --wider: 0.5em;

  --header-h: 69px;   /* sticky header incl. its 1px border */
  --max:   1180px;
  --gutter: clamp(20px, 5vw, 56px);

  --shadow: 0 18px 50px -24px rgba(44, 46, 40, 0.38);
  --ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --out:  cubic-bezier(0.16, 1, 0.3, 1);   /* decelerate: entries */
  --in:   cubic-bezier(0.7, 0, 0.84, 0);   /* accelerate: exits */
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--ivory);
  color: var(--ink);
  font-family: var(--body);
  font-weight: 300;
  font-size: 17px;
  line-height: 1.75;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
a { color: inherit; }

h1, h2, h3, h4 { font-family: var(--display); font-weight: 300; margin: 0; line-height: 1.15; }

/* ---------- layout ---------- */
.wrap { max-width: var(--max); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: 780px; }
section { padding-block: clamp(64px, 9vw, 120px); }
.section--cream { background: var(--cream); }
.section--linen { background: var(--linen); }

/* ---------- type helpers ---------- */
.eyebrow {
  font-size: 11px;
  letter-spacing: var(--wide);
  text-transform: uppercase;
  color: var(--sage-deep);   /* --sage fails AA at this size on cream/linen */
  margin: 0 0 18px;
}
.section-title {
  font-size: clamp(30px, 5vw, 46px);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.section-sub {
  color: var(--muted);
  max-width: 58ch;
  margin: 14px auto 0;
}
.centered { text-align: center; }
.centered .section-sub { margin-inline: auto; }
.rule {
  width: 62px; height: 1px; background: var(--sage-pale);
  border: 0; margin: 26px auto 34px;
}
.rule--left { margin-inline: 0 auto; margin-left: 0; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 34px;
  font-family: var(--body); font-size: 12px; font-weight: 400;
  letter-spacing: var(--wide); text-transform: uppercase; text-decoration: none;
  border: 1px solid var(--sage-deep); background: var(--sage-deep); color: var(--ivory);
  cursor: pointer; transition: background .35s var(--ease), color .35s var(--ease), transform .35s var(--ease);
}
.btn:hover { background: transparent; color: var(--sage-deep); transform: translateY(-2px); }
.btn--ghost { background: transparent; color: var(--sage-deep); }
.btn--ghost:hover { background: var(--sage-deep); color: var(--ivory); }
.btn--light { background: transparent; border-color: rgba(255,255,255,.85); color: #fff; }
.btn--light:hover { background: rgba(255,255,255,.95); color: var(--ink); }
.btn--sm { padding: 11px 22px; font-size: 11px; }
.btn[disabled] { opacity: .45; cursor: not-allowed; transform: none; }

/* ---------- header / nav ---------- */
.site-header {
  position: sticky; top: 0; z-index: 60;
  background: rgba(251, 248, 243, 0.92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(124, 139, 111, 0.16);
}
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; min-height: 68px;
}
.monogram {
  font-family: var(--display); font-size: 21px; letter-spacing: 0.22em;
  text-decoration: none; white-space: nowrap;
}
.nav { display: flex; align-items: center; gap: clamp(14px, 2.1vw, 28px); }
/* :not(.btn) throughout — the RSVP button lives in this nav but must keep its
   own padding and sizing. Without it, `.nav a` (0,1,1) outranks `.btn--sm`
   (0,1,0) and the button renders with no horizontal padding at all. */
.nav a:not(.btn) {
  font-size: 11.5px; letter-spacing: 0.17em; text-transform: uppercase;
  text-decoration: none; color: var(--muted); padding: 6px 0;
  border-bottom: 1px solid transparent; transition: color .3s, border-color .3s; white-space: nowrap;
}
.nav a:not(.btn):hover { color: var(--ink); }
.nav a:not(.btn)[aria-current="page"] { color: var(--sage-deep); border-bottom-color: var(--sage); }
.nav .btn, .nav .btn[aria-current="page"] { color: var(--ivory); border-bottom-color: var(--sage-deep); }
.nav .btn:hover, .nav .btn[aria-current="page"]:hover { color: var(--sage-deep); }

.nav-toggle {
  display: none; background: none; border: 0; cursor: pointer;
  padding: 10px; margin-right: -10px;
}
.nav-toggle span {
  display: block; width: 24px; height: 1.5px; background: var(--ink);
  transition: transform .3s var(--ease), opacity .25s;
}
.nav-toggle span + span { margin-top: 6px; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }

@media (max-width: 900px) {
  .nav-toggle { display: grid; place-items: center; min-width: 44px; min-height: 44px; }
  .nav {
    position: fixed; inset: 68px 0 auto; flex-direction: column; align-items: stretch;
    gap: 0; background: var(--ivory); padding: 8px var(--gutter) 30px;
    border-bottom: 1px solid var(--linen); box-shadow: var(--shadow);
    transform: translateY(-12px); opacity: 0; pointer-events: none;
    transition: opacity .28s var(--ease), transform .28s var(--ease);
    max-height: calc(100vh - 68px); overflow-y: auto;
  }
  .nav[data-open="true"] { transform: none; opacity: 1; pointer-events: auto; }
  .nav a:not(.btn) { padding: 15px 0; border-bottom: 1px solid var(--linen); font-size: 13px; }
  .nav .btn { margin-top: 18px; border-bottom: 0; }
}

/* ---------- footer ---------- */
.site-footer {
  background: var(--sage-deep); color: var(--cream);
  padding-block: clamp(50px, 7vw, 76px); text-align: center;
}
.site-footer .monogram { font-size: 30px; display: inline-block; margin-bottom: 14px; }
.site-footer p { margin: 6px 0; font-size: 13px; letter-spacing: 0.13em; text-transform: uppercase; opacity: .85; }
.footer-nav { display: flex; flex-wrap: wrap; gap: 8px 26px; justify-content: center; margin: 30px 0 0; padding: 0; list-style: none; }
.footer-nav a { font-size: 11px; letter-spacing: 0.17em; text-transform: uppercase; text-decoration: none; opacity: .8; }
.footer-nav a:hover { opacity: 1; }

/* ---------- page banner (interior pages) ---------- */
.page-banner {
  background: var(--cream); text-align: center;
  padding-block: clamp(56px, 8vw, 96px);
  border-bottom: 1px solid var(--linen);
}
.page-banner h1 {
  font-size: clamp(34px, 6.5vw, 60px); letter-spacing: 0.14em; text-transform: uppercase;
}
.page-banner p { color: var(--muted); margin: 16px auto 0; max-width: 56ch; }

/* ---------- reveal animation ---------- */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity .55s var(--out), transform .55s var(--out); }
.reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
}

/* ---------- cards ---------- */
.card {
  background: var(--white); padding: clamp(28px, 4vw, 44px);
  border: 1px solid var(--linen);
}
.grid { display: grid; gap: clamp(20px, 3vw, 36px); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

/* ---------- placeholder art (for photos not yet added) ---------- */
.ph {
  background:
    repeating-linear-gradient(45deg, rgba(124,139,111,.07) 0 12px, transparent 12px 24px),
    var(--linen);
  display: grid; place-items: center; text-align: center;
  color: var(--sage-deep); font-size: 10.5px; letter-spacing: var(--wide);
  text-transform: uppercase; padding: 20px;
}

/* ==========================================================================
   HOME
   ========================================================================== */
/* The sticky header sits above the hero in flow, so a full 100svh hero runs
   past the fold and pushes its own slideshow dots off screen. Subtract the
   header. The 100vh line is a fallback for iOS below 15.4, where svh units
   are unsupported and the declaration is dropped. */
.hero {
  position: relative;
  height: calc(100vh - var(--header-h));
  height: calc(100svh - var(--header-h));
  min-height: 560px;
  overflow: hidden;
}
.hero__slides { position: absolute; inset: 0; }
.hero__slide {
  position: absolute; inset: 0; background-size: cover; background-position: center 30%;
  opacity: 0; transition: opacity 1.6s var(--ease); transform: scale(1.04);
  animation: heroDrift 16s ease-out forwards;
}
.hero__slide.is-active { opacity: 1; }
@keyframes heroDrift { to { transform: scale(1); } }
.hero::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(30,32,27,.36) 0%, rgba(30,32,27,.14) 38%, rgba(30,32,27,.52) 100%);
}
.hero__inner {
  position: relative; z-index: 2; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; color: #fff; padding: 90px var(--gutter) 70px;
}
.hero__names {
  font-size: clamp(34px, 8.2vw, 92px); letter-spacing: 0.17em; text-transform: uppercase;
  text-shadow: 0 2px 26px rgba(0,0,0,.34); margin: 0;
}
.hero__amp { display: block; font-size: .46em; letter-spacing: 0; margin: .12em 0; opacity: .9; }
.hero__meta {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: 10px clamp(18px, 4vw, 42px); margin-top: 26px;
  font-size: clamp(11px, 1.5vw, 14px); letter-spacing: var(--wide); text-transform: uppercase;
  text-shadow: 0 1px 14px rgba(0,0,0,.4);
}
.hero__meta span:not(:last-child)::after {
  content: "\2022"; margin-left: clamp(18px, 4vw, 42px); opacity: .55;
}
.hero__cta { margin-top: 40px; display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; }
.hero__dots { position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); z-index: 3; display: flex; gap: 10px; }
/* the button is just the tap target; ::after draws the visible dot */
.hero__dots button { padding: 0; cursor: pointer; }

/* countdown */
.countdown { display: flex; flex-wrap: wrap; justify-content: center; gap: clamp(22px, 6vw, 68px); margin-top: 8px; }
.countdown div { min-width: 64px; }
.countdown b { display: block; font-family: var(--display); font-size: clamp(34px, 5.5vw, 56px); font-weight: 300; line-height: 1; }
.countdown small { font-size: 10px; letter-spacing: var(--wide); text-transform: uppercase; color: var(--muted); }

/* story */
.story { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 5vw, 70px); align-items: center; }
.story__img img, .story__img .ph { width: 100%; aspect-ratio: 4/5; object-fit: cover; height: 100%; }
@media (max-width: 760px) { .story { grid-template-columns: 1fr; } }

/* detail tiles */
.detail { text-align: center; }
.detail h3 { font-size: 23px; letter-spacing: 0.13em; text-transform: uppercase; margin-bottom: 10px; }
.detail p { margin: 2px 0; color: var(--muted); font-size: 15.5px; }
.detail .btn { margin-top: 20px; }

/* ==========================================================================
   WEDDING WEEKEND
   ========================================================================== */
.venue { text-align: center; }
.venue__img, .venue .ph { width: 100%; aspect-ratio: 3/2; object-fit: cover; margin-bottom: 24px; }
.venue h3 { font-size: 24px; letter-spacing: 0.13em; text-transform: uppercase; }
.venue .time { color: var(--sage-deep); letter-spacing: 0.16em; font-size: 12.5px; text-transform: uppercase; margin: 10px 0 6px; }
.venue address { font-style: normal; color: var(--muted); font-size: 15.5px; }

/* ---------- featured venue illustrations ----------
   No card, no border, no white mount — a boxed frame made these read as
   "a photo dropped into a container" instead of artwork that belongs on
   the page. Both source files are already transparent PNGs with their own
   organic painted edges, so they blend directly into the section's cream
   background with no CSS masking needed. */
.venue__art { width: 100%; margin-bottom: 20px; }
.venue__art img { width: 100%; height: auto; display: block; }

.timeline { max-width: 620px; margin-inline: auto; position: relative; padding-left: 34px; }
.timeline::before {
  content: ""; position: absolute; left: 5px; top: 10px; bottom: 10px;
  width: 1px; background: var(--sage-pale);
}
.timeline li { list-style: none; position: relative; padding-bottom: 32px; }
.timeline li::before {
  content: ""; position: absolute; left: -33px; top: 9px; width: 11px; height: 11px;
  border-radius: 50%; background: var(--ivory); border: 1.5px solid var(--sage);
}
.timeline .t { font-size: 11.5px; letter-spacing: var(--wide); text-transform: uppercase; color: var(--sage-deep); }
.timeline .e { font-family: var(--display); font-size: 25px; margin-top: 2px; }
.timeline .d { color: var(--muted); font-size: 15px; }

.notes { list-style: none; padding: 0; margin: 0; display: grid; gap: 16px; }
.notes li { display: flex; gap: 16px; align-items: flex-start; }
.notes .ico { flex: none; width: 34px; height: 34px; border-radius: 50%; background: var(--sage-pale); display: grid; place-items: center; font-size: 15px; }
.notes b { display: block; font-weight: 400; letter-spacing: 0.06em; }
.notes span.txt { color: var(--muted); font-size: 15px; }

/* ==========================================================================
   REGISTRY
   ========================================================================== */
.registry-card { display: flex; flex-direction: column; text-align: center; }
.registry-card .mark {
  width: 54px; height: 54px; margin: 0 auto 18px; border-radius: 50%;
  background: var(--cream); display: grid; place-items: center; font-size: 22px;
}
.registry-card h3 { font-size: 21px; letter-spacing: 0.1em; text-transform: uppercase; }
.registry-card p { color: var(--muted); font-size: 15px; flex: 1; margin: 12px 0 22px; }

/* ==========================================================================
   RSVP
   ========================================================================== */
.rsvp-shell { max-width: 700px; margin-inline: auto; }
.steps { display: flex; justify-content: center; gap: 0; margin-bottom: 44px; }
.steps li { list-style: none; display: flex; align-items: center; gap: 12px; color: var(--muted); font-size: 10.5px; letter-spacing: 0.18em; text-transform: uppercase; }
.steps li:not(:last-child)::after { content: ""; width: clamp(24px, 7vw, 60px); height: 1px; background: var(--sage-pale); margin: 0 12px; }
.steps .num {
  width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--sage-pale); font-size: 12px; letter-spacing: 0; transition: .3s;
}
.steps li[data-state="active"] { color: var(--ink); }
.steps li[data-state="active"] .num, .steps li[data-state="done"] .num { background: var(--sage-deep); color: #fff; border-color: var(--sage-deep); }
@media (max-width: 560px) { .steps li span:not(.num) { display: none; } }

.step { display: none; }
.step.is-active { display: block; animation: fadeUp .5s var(--ease); }
@keyframes fadeUp { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

.field { margin-bottom: 22px; }
.field label { display: block; font-size: 11px; letter-spacing: var(--wide); text-transform: uppercase; color: var(--sage-deep); margin-bottom: 8px; }
.field input[type="text"], .field input[type="email"], .field input[type="tel"], .field select, .field textarea {
  width: 100%; padding: 13px 15px; font-family: var(--body); font-size: 16px; font-weight: 300;
  color: var(--ink); background: var(--white); border: 1px solid var(--linen); border-radius: 0;
  transition: border-color .25s;
}
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--sage); }
.field textarea { min-height: 96px; resize: vertical; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; } }
.hint { font-size: 13.5px; color: var(--muted); margin: -12px 0 22px; }

.guest {
  background: var(--white); border: 1px solid var(--linen); padding: 22px; margin-bottom: 16px; position: relative;
}
.guest__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.guest__head h4 { font-size: 12px; letter-spacing: var(--wide); text-transform: uppercase; font-family: var(--body); font-weight: 400; color: var(--sage-deep); }
.guest__remove { background: none; border: 0; cursor: pointer; color: var(--muted); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; }
.guest__remove:hover { color: #A6503F; }

.attending { display: flex; gap: 10px; flex-wrap: wrap; }
.attending label {
  flex: 1; min-width: 120px; text-align: center; cursor: pointer;
  padding: 11px; border: 1px solid var(--linen); font-size: 11px; letter-spacing: 0.15em;
  text-transform: uppercase; color: var(--muted); transition: .25s; margin: 0;
}
.attending input { position: absolute; opacity: 0; pointer-events: none; }
.attending input:checked + span { color: inherit; }
.attending label:has(input:checked) { background: var(--sage-deep); border-color: var(--sage-deep); color: #fff; }

.ack {
  background: var(--cream); border-left: 3px solid var(--sage); padding: 24px; margin: 8px 0 26px;
}
.ack p { font-size: 15px; color: var(--muted); margin: 0 0 16px; }
.ack label { display: flex; gap: 12px; align-items: flex-start; cursor: pointer; font-size: 14.5px; }
.ack input { margin-top: 5px; width: 17px; height: 17px; accent-color: var(--sage-deep); flex: none; }

.form-nav { display: flex; justify-content: space-between; gap: 14px; margin-top: 30px; }
.form-error { color: #A6503F; font-size: 14px; min-height: 22px; margin-top: 10px; }
.rsvp-done { text-align: center; }

/* ==========================================================================
   ATTIRE
   ========================================================================== */
.swatches { display: flex; flex-wrap: wrap; gap: 18px; justify-content: center; margin-top: 10px; }
.swatch { text-align: center; }
.swatch i { display: block; width: 62px; height: 62px; border-radius: 50%; border: 1px solid rgba(0,0,0,.08); margin-bottom: 9px; }
.swatch span { font-size: 10px; letter-spacing: 0.15em; text-transform: uppercase; color: var(--muted); }

.dodont { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 3vw, 34px); }
@media (max-width: 760px) { .dodont { grid-template-columns: 1fr; } }
.dodont > div { padding: clamp(24px, 3.4vw, 36px); border: 1px solid var(--linen); background: var(--white); }
.dodont h3 { font-size: 13px; letter-spacing: var(--wide); text-transform: uppercase; font-family: var(--body); font-weight: 400; margin-bottom: 18px; }
.dodont--do { border-top: 3px solid var(--sage); }
.dodont--dont { border-top: 3px solid #B9705C; }
.dodont ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 12px; }
.dodont li { display: flex; gap: 12px; font-size: 15.5px; color: var(--muted); }
.dodont li::before { flex: none; font-size: 13px; }
.dodont--do li::before { content: "\2713"; color: var(--sage); }
.dodont--dont li::before { content: "\2717"; color: #B9705C; }

.look-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 18px; }
.look-grid figure { margin: 0; }
.look-grid img, .look-grid .ph { width: 100%; aspect-ratio: 3/4; object-fit: cover; }
.look-grid figcaption { font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; color: var(--muted); margin-top: 10px; text-align: center; }

/* ==========================================================================
   GALLERY
   ========================================================================== */
.filters { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-bottom: 42px; }
.filters button {
  background: none; border: 1px solid var(--linen); padding: 9px 20px; cursor: pointer;
  font-family: var(--body); font-size: 11px; font-weight: 300; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--muted); transition: .28s;
}
.filters button:hover { border-color: var(--sage); color: var(--ink); }
.filters button[aria-pressed="true"] { background: var(--sage-deep); border-color: var(--sage-deep); color: #fff; }

.masonry { columns: 3 260px; column-gap: 18px; }
.masonry figure { margin: 0 0 18px; break-inside: avoid; position: relative; cursor: zoom-in; overflow: hidden; background: var(--linen); }
.masonry img { width: 100%; transition: transform .7s var(--ease); }
.masonry figure:hover img { transform: scale(1.05); }
.masonry figcaption {
  position: absolute; inset: auto 0 0; padding: 26px 16px 14px; color: #fff;
  font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase;
  background: linear-gradient(transparent, rgba(30,32,27,.75)); opacity: 0; transition: opacity .35s;
}
.masonry figure:hover figcaption, .masonry figure:focus-visible figcaption { opacity: 1; }
.gallery-empty { text-align: center; color: var(--muted); padding: 60px 0; }

.lightbox {
  position: fixed; inset: 0; z-index: 200; background: rgba(24,25,21,.94);
  display: none; align-items: center; justify-content: center; padding: 4vh 4vw;
}
.lightbox[open], .lightbox.is-open { display: flex; }
.lightbox img { max-width: 100%; max-height: 82vh; object-fit: contain; }
.lightbox__cap { position: absolute; bottom: 3vh; left: 0; right: 0; text-align: center; color: rgba(255,255,255,.8); font-size: 11.5px; letter-spacing: 0.16em; text-transform: uppercase; }
.lightbox button {
  position: absolute; background: none; border: 0; color: #fff; cursor: pointer;
  font-size: 30px; line-height: 1; padding: 14px; opacity: .75; transition: opacity .25s;
}
.lightbox button:hover { opacity: 1; }
.lightbox .lb-close { top: 10px; right: 14px; font-size: 26px; }
.lightbox .lb-prev { left: 4px; top: 50%; transform: translateY(-50%); }
.lightbox .lb-next { right: 4px; top: 50%; transform: translateY(-50%); }

/* ==========================================================================
   WEDDING PARTY
   ========================================================================== */
.party-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: clamp(22px, 3vw, 40px); }
.person { text-align: center; }
.person__photo { position: relative; overflow: hidden; margin-bottom: 18px; background: var(--linen); }
.person__photo img, .person__photo .ph { width: 100%; aspect-ratio: 4/5; object-fit: cover; transition: transform .7s var(--ease); }
.person:hover .person__photo img { transform: scale(1.05); }
.person h3 { font-size: 21px; letter-spacing: 0.08em; margin-bottom: 4px; }
.person .role { font-size: 10.5px; letter-spacing: var(--wide); text-transform: uppercase; color: var(--sage); }
.person .memory { color: var(--muted); font-size: 14.5px; margin-top: 12px; line-height: 1.65; }

/* ==========================================================================
   FAQ
   ========================================================================== */
.faq { max-width: 820px; margin-inline: auto; }
.faq details { border-bottom: 1px solid var(--linen); }
.faq summary {
  cursor: pointer; list-style: none; padding: 24px 44px 24px 0; position: relative;
  font-family: var(--display); font-size: clamp(19px, 2.4vw, 23px); transition: color .25s;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--sage-deep); }
.faq summary::after {
  content: "+"; position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  font-family: var(--body); font-size: 22px; font-weight: 300; color: var(--sage); transition: transform .3s var(--ease);
}
.faq details[open] summary::after { transform: translateY(-50%) rotate(45deg); }
.faq .answer { padding: 0 44px 26px 0; color: var(--muted); margin: 0; }
.faq .answer a { color: var(--sage-deep); }
.faq h2.group {
  font-size: 12px; letter-spacing: var(--wide); text-transform: uppercase;
  font-family: var(--body); font-weight: 400; color: var(--sage);
  margin: 52px 0 6px; padding-bottom: 12px;
}
.faq h2.group:first-child { margin-top: 0; }

/* ---------- shared CTA strip ---------- */
.cta-strip { background: var(--sage-deep); color: var(--cream); text-align: center; }
.cta-strip h2 { font-size: clamp(27px, 4.4vw, 42px); letter-spacing: 0.12em; text-transform: uppercase; color: #fff; }
.cta-strip p { opacity: .85; margin: 16px auto 30px; max-width: 48ch; }

/* ---------- utility ---------- */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- hero: phone refinements ---------- */
@media (max-width: 620px) {
  /* the meta line wraps on narrow screens, which left an orphaned separator */
  .hero__meta span:not(:last-child)::after { content: none; }
  .hero__meta { gap: 4px; flex-direction: column; }
  /* the portrait crop frames both faces far better than the landscape one */
  .hero__slide--primary { background-image: url("../img/hero-tall.jpg") !important; }
}

/* ==========================================================================
   KEYBOARD FOCUS
   Every interactive element needs a visible focus ring. Scoped to
   :focus-visible so it appears for keyboard users without ringing on click.
   ========================================================================== */
:focus-visible {
  outline: 2px solid var(--sage-deep);
  outline-offset: 3px;
}
/* on dark or photographic backgrounds the green ring disappears */
.hero :focus-visible,
.cta-strip :focus-visible,
.site-footer :focus-visible,
.lightbox :focus-visible { outline-color: #FFFFFF; }

/* inputs already shift their border on focus — add the ring back for keyboards */
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible { outline: 2px solid var(--sage-deep); outline-offset: 1px; }

/* the radio itself is visually hidden, so the ring has to go on its label */
.attending label:has(input:focus-visible) { outline: 2px solid var(--sage-deep); outline-offset: 2px; }

.faq summary:focus-visible { outline-offset: -2px; }
.masonry figure:focus-visible { outline: 2px solid var(--sage-deep); outline-offset: 2px; }

/* ---------- inline SVG icons (replacing the emoji) ---------- */
.ico-svg { display: block; }
.notes .ico .ico-svg { color: var(--sage-deep); }
.registry-card .mark .ico-svg { color: var(--sage-deep); }
.rsvp-done .mark {
  color: var(--sage); display: flex; justify-content: center; margin: 0 0 6px;
}
.rsvp-done .mark .ico-svg { width: 40px; height: 40px; stroke-width: 1.2; }

/* ==========================================================================
   MOTION
   Five deliberate moments, one per view — not motion everywhere. Every rule
   here is inert unless motion.js adds .motion-on to <html>, so the site is
   fully styled and readable with JS off or reduced-motion on.
   ========================================================================== */

/* ---------- 1. hero: names rise letter by letter ---------- */
.motion-on .hero__names .ch {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.5em) rotateX(-55deg);
  animation: chIn 0.85s var(--out) forwards;
  animation-delay: calc(var(--i) * 0.045s + 0.25s);
  transform-origin: 50% 100%;
  will-change: transform, opacity;
}
@keyframes chIn { to { opacity: 1; transform: none; } }
.motion-on .hero__names { perspective: 600px; }

/* the meta line and buttons follow the name, not alongside it */
.motion-on .hero__meta,
.motion-on .hero__cta {
  opacity: 0;
  animation: heroUp 0.8s var(--out) forwards;
}
.motion-on .hero__meta { animation-delay: 1.15s; }
.motion-on .hero__cta  { animation-delay: 1.32s; }
@keyframes heroUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }

/* ---------- 2. hero: background drifts slower than the page ---------- */
/* decorative layer only — the text above it never moves */
.motion-on .hero__slides { will-change: transform; }

/* ---------- 3. images unveil with a soft wipe ---------- */
.reveal-img { overflow: hidden; }
.reveal-img > img {
  clip-path: inset(0 0 100% 0);
  transform: scale(1.08);
  transition: clip-path 1.1s var(--out), transform 1.4s var(--out);
}
.reveal-img.is-visible > img { clip-path: inset(0 0 0 0); transform: scale(1); }

/* ---------- 4. timeline draws itself as you scroll ---------- */
.motion-on .timeline::before { transform: scaleY(var(--draw, 0)); transform-origin: top; }
.motion-on .timeline li::before {
  transform: scale(0);
  transition: transform 0.45s var(--out);
}
.motion-on .timeline li.lit::before { transform: scale(1); }
/* A one-way reveal, not a scroll-linked dim. Dimming text to sit "ahead of"
   the drawn line looked good but capped body copy at 3.78:1 even at 80%
   opacity — under AA at any level. So the line and dots carry the motion,
   and the words simply arrive and stay. */
.motion-on .timeline li > * {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.5s var(--out), transform 0.5s var(--out);
}
.motion-on .timeline li.lit > * { opacity: 1; transform: none; }

/* ---------- 5. header condenses once you leave the hero ---------- */
.site-header { transition: box-shadow .4s var(--ease), background-color .4s var(--ease); }
.site-header[data-scrolled="true"] {
  box-shadow: 0 1px 24px -12px rgba(44, 46, 40, .4);
  background: rgba(251, 248, 243, 0.97);
}

/* ---------- countdown roll-up on first view ---------- */
.countdown b { font-variant-numeric: tabular-nums; }

/* ---------- buttons gain a subtle fill sweep ---------- */
.btn { position: relative; overflow: hidden; }
.btn > span, .btn { z-index: 0; }
.motion-on .btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: currentColor; opacity: 0;
  transform: translateY(101%);
  transition: transform .45s var(--out), opacity .45s var(--out);
}
.motion-on .btn:hover::before { transform: translateY(0); opacity: .08; }

/* ---------- everything above is off when the guest asks for less motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .motion-on .hero__names .ch,
  .motion-on .hero__meta,
  .motion-on .hero__cta { opacity: 1; transform: none; animation: none; }
  .reveal-img > img { clip-path: none; transform: none; transition: none; }
  .motion-on .timeline::before { transform: scaleY(1); }
  .motion-on .timeline li::before { transform: scale(1); }
  .motion-on .timeline li > * { opacity: 1; }
  .motion-on .btn::before { display: none; }
}

/* the ampersand is a line of its own — .ch's inline-block must not collapse it */
.motion-on .hero__names .hero__amp.ch { display: block; }

/* ==========================================================================
   TOUCH
   Phones have no hover, so every hover-only affordance is invisible there —
   and worse, iOS keeps :hover applied after a tap until you touch elsewhere,
   which left tapped buttons stuck in their inverted state. Hover effects are
   fenced behind (hover: hover); touch gets its own press feedback.
   ========================================================================== */
@media (hover: none) {
  /* undo the desktop hover treatments that would otherwise stick after a tap */
  .btn:hover { background: var(--sage-deep); color: var(--ivory); transform: none; }
  .btn--ghost:hover { background: transparent; color: var(--sage-deep); }
  .btn--light:hover { background: transparent; color: #fff; }
  .motion-on .btn:hover::before { transform: translateY(101%); opacity: 0; }
  .masonry figure:hover img, .person:hover .person__photo img { transform: none; }
  .masonry figure:hover figcaption { opacity: 0; }

  /* immediate, physical feedback on press */
  .btn:active { transform: scale(0.97); opacity: .9; }
  .nav a:active, .footer-nav a:active { opacity: .6; }
  .filters button:active, .steps li:active { transform: scale(0.96); }
  .faq summary:active { color: var(--sage-deep); }
  .masonry figure:active img { transform: scale(0.98); }
  .attending label:active { transform: scale(0.97); }
  .guest__remove:active { opacity: .5; }

  /* gallery captions can't be hovered — show them always on touch */
  .masonry figcaption { opacity: 1; }
}

/* remove the blue flash; we draw our own press state above */
a, button, summary, label, .btn, input, select, textarea {
  -webkit-tap-highlight-color: transparent;
}
/* cut the legacy 300ms tap delay */
a, button, summary, label, input, select, textarea, .masonry figure {
  touch-action: manipulation;
}
/* presses should feel instant, not eased */
.btn, .filters button, .attending label, .masonry figure img { transition-duration: .18s; }
@media (hover: hover) {
  .btn { transition: background .35s var(--ease), color .35s var(--ease), transform .35s var(--ease); }
}

/* ---------- tap targets: 44x44 minimum ----------
   .nav-toggle's own sizing lives in the @media(max-width:900px) block above
   it, not here — an earlier, unguarded copy of this rule set display:grid
   with no width limit, which overrode the base display:none and left the
   hamburger button visible at every viewport width, desktop included. */
.btn--sm { min-height: 44px; }
.site-header .monogram { display: inline-flex; align-items: center; min-height: 44px; }
.guest__remove { min-height: 44px; padding: 0 4px; }
.footer-nav a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 2px; }

/* the slideshow dots stay small to look at, but get a full-size hit area */
.hero__dots { gap: 0; bottom: 18px; }
.hero__dots button {
  width: 44px; height: 44px; border: 0; background: none;
  display: grid; place-items: center; border-radius: 0;
}
.hero__dots button::after {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.85); background: transparent; transition: background .3s;
}
.hero__dots button[aria-selected="true"]::after { background: #fff; }

/* ==========================================================================
   MOTION ON PHONES
   Scroll-linked parallax stutters badly under iOS momentum scrolling, because
   scroll position updates arrive in bursts the compositor can't keep up with.
   On touch the hero gets a slow GPU-composited drift instead — same sense of
   depth, no dependency on scroll at all.
   ========================================================================== */
@media (pointer: coarse) {
  .motion-on .hero__slide.is-active {
    animation: kenBurns 22s var(--ease) forwards;
  }
  @keyframes kenBurns {
    from { transform: scale(1.12) translate3d(0, 0, 0); }
    to   { transform: scale(1.0)  translate3d(0, -1.2%, 0); }
  }
  /* the name lands sooner on a phone — a long tail feels broken on mobile */
  .motion-on .hero__names .ch { animation-delay: calc(var(--i) * 0.032s + 0.18s); }
  .motion-on .hero__meta { animation-delay: 0.82s; }
  .motion-on .hero__cta  { animation-delay: 0.95s; }
  /* shorter travel on a small screen reads better than a long slide */
  .reveal { transform: translateY(10px); }
}

/* a hint that the hero can be swiped, shown once */
.motion-on .hero__hint {
  position: absolute; left: 50%; bottom: 74px; z-index: 3;
  transform: translateX(-50%);
  color: rgba(255,255,255,.82); font-size: 9.5px; letter-spacing: var(--wide);
  text-transform: uppercase; pointer-events: none; white-space: nowrap;
  opacity: 0; animation: hintIn .8s var(--out) 2.2s forwards, hintOut .8s var(--out) 7s forwards;
}
@keyframes hintIn  { to { opacity: 1; } }
@keyframes hintOut { to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .motion-on .hero__slide.is-active { animation: none; }
  .motion-on .hero__hint { animation: none; opacity: 0; }
}

/* ==========================================================================
   CARDS & SECTION HEADERS
   ========================================================================== */

/* cards settle in rather than just fading: a small rise, a touch of scale,
   and a shadow that resolves as they land */
.motion-on .card.reveal,
.motion-on .registry-card.reveal {
  transform: translateY(18px) scale(0.985);
  box-shadow: 0 0 0 rgba(44, 46, 40, 0);
  transition: opacity .6s var(--out), transform .6s var(--out), box-shadow .7s var(--out);
}
.motion-on .card.reveal.is-visible,
.motion-on .registry-card.reveal.is-visible {
  transform: none;
  box-shadow: 0 14px 34px -26px rgba(44, 46, 40, .45);
}

/* hover lift — 200-300ms with a matching reverse, desktop pointers only */
@media (hover: hover) {
  .card, .registry-card {
    transition: transform .28s var(--out), box-shadow .28s var(--out), border-color .28s var(--out);
  }
  /* must outrank .motion-on .card.reveal.is-visible, which pins transform
     and box-shadow as the reveal's end state */
  .card:hover, .registry-card:hover,
  .motion-on .card.reveal.is-visible:hover,
  .motion-on .registry-card.reveal.is-visible:hover {
    transform: translateY(-5px);
    box-shadow: 0 22px 44px -24px rgba(44, 46, 40, .34);
    border-color: var(--sage-pale);
  }
  /* the icon badge lifts slightly further than the card for a parallax feel */
  .registry-card { position: relative; }
  .registry-card .mark { transition: transform .38s var(--out), background-color .38s var(--out); }
  .registry-card:hover .mark { transform: translateY(-3px) scale(1.06); background: var(--sage-pale); }
  .detail .btn, .registry-card .btn { transition: transform .28s var(--out), background-color .35s var(--ease), color .35s var(--ease); }
}

/* the hairline under each section title draws out from the centre */
.motion-on .rule {
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .75s var(--out) .12s;
}
.motion-on .rule.is-visible { transform: scaleX(1); }
.motion-on .rule--left { transform-origin: left; }

/* Headings fade up only. An earlier version animated letter-spacing from wide
   to normal, which looked good but changed how the text WRAPPED: at 375-402px
   (most iPhones) "The Wedding Day" started as two lines and snapped to one
   mid-animation. letter-spacing is a layout property, so it reflows the line
   box every frame, and a "safe" starting value depends on the heading's length,
   its font size and the viewport width all at once. Not worth chasing. */
.motion-on .page-banner h1 { animation: titleFade .9s var(--out) forwards; }
@keyframes titleFade {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .motion-on .card.reveal, .motion-on .registry-card.reveal { transform: none; }
  .motion-on .rule { transform: scaleX(1); }
  .motion-on .page-banner h1 { animation: none; opacity: 1; transform: none; }
  @media (hover: hover) {
    .card:hover, .registry-card:hover { transform: none; }
  }
}

/* ==========================================================================
   REGISTRY: STORE TILES
   Each store's own favicon inside a matched circular frame, so the mixed
   backgrounds/sizes coming from five different retailers still read as one
   consistent row rather than five random icon crops.
   ========================================================================== */
.store-tiles {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start;
  gap: 36px clamp(28px, 5vw, 56px); margin-top: 44px;
}
.store-tile {
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  text-decoration: none; color: var(--ink); width: 128px;
}
.store-tile__icon {
  width: clamp(84px, 9vw, 104px); height: clamp(84px, 9vw, 104px); border-radius: 50%;
  background: var(--white); border: 1px solid var(--linen);
  display: grid; place-items: center; overflow: hidden; flex: none;
}
.store-tile__icon img { width: 56%; height: 56%; object-fit: contain; }
.store-tile__name {
  font-size: 12.5px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); text-align: center; line-height: 1.4;
}
@media (hover: hover) {
  .store-tile__icon { transition: transform .28s var(--out), box-shadow .28s var(--out), border-color .28s var(--out); }
  .store-tile:hover .store-tile__icon {
    transform: translateY(-4px);
    box-shadow: 0 16px 30px -20px rgba(44, 46, 40, .45);
    border-color: var(--sage-pale);
  }
  .store-tile:hover .store-tile__name { color: var(--ink); }
}
@media (hover: none) {
  .store-tile:active .store-tile__icon { transform: scale(0.95); }
}
