/* =====================================================================
   Alexandria & Michael — wedding site
   Aesthetic cloned from withjoy.com/alexandria-michael (measured 14 Sep 2026):
     names       Parisienne 56px, #848484
     body        Optima 18.75px / 1.5, #848484   (Optima is an Apple system
                 font — iPhone/Mac guests see the real thing; others get the
                 Google-Fonts fallback loaded in index.html)
     nav         16px, active item underlined
     headings    light weight, ~40px
     buttons     pill outline, 1px, same gray
   Everything below is driven by the tokens in :root. Change a token, the
   whole site follows.
   ===================================================================== */

:root {
  --ink:        #848484;   /* body text */
  --ink-strong: #5f5f5f;   /* headings, bold Q&A questions, names */
  --ink-soft:   #8f8f8f;   /* meta lines, captions, footer — 3.2:1 on white (#a3a3a3 was 2.5:1) */
  --rule:       #e9e5df;   /* hairlines */
  --paper:      #ffffff;   /* page background */
  --accent:     #b8912f;   /* honeycomb gold — one job only: active-nav underline,
                               schedule hex dots, chapter dividers, footer hex,
                               and the Travel icon hexagons (27 Sep 2026) */

  --font-script: "Parisienne", "Pinyon Script", cursive;
  --font-body:   "Optima", "Optima Nova", "Ysabeau Office", "Alegreya Sans",
                 "Gill Sans", "Segoe UI", sans-serif;

  --measure: 62rem;        /* max width of text columns (~992px) */
  --wide:    68rem;        /* section photos */
  --gutter:  clamp(1rem, 4vw, 2.5rem);

  --nav-h: 3.5rem;
  --hero-h: clamp(260px, 46vw, 500px);
}

/* ---------- reset-ish ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.1719rem;          /* 18.75px */
  line-height: 1.5;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
/* a link inside running text must be findable without a hover — a hairline in
   the accent, well below the baseline, so it reads as a link and not as emphasis */
.section p a, .qa a, .moments-add-link { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 4px; }
h1, h2, h3, h4 { font-weight: 400; margin: 0; color: var(--ink-strong); }
p { margin: 0 0 1em; }
ul { margin: 0; padding: 0; list-style: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---------- masthead ---------- */
.masthead {
  text-align: center;
  padding: clamp(2.5rem, 6vw, 4.5rem) var(--gutter) 0;
}
.masthead .names {
  font-family: var(--font-script);
  font-size: clamp(2.6rem, 6vw, 3.5rem);   /* 56px at desktop */
  line-height: 1.15;
  letter-spacing: 0;   /* Parisienne is a connected script: any tracking breaks the joins between letters (Michael, 16 Oct) */
  color: var(--ink);
}

/* ---------- the names, on first load ----------
   Added 15 Sep 2026. Two things, both once and both short: the names rise a
   few pixels as they fade in, and then a single soft gold sheen crosses them
   left to right. It runs one time per page load and never repeats — this is a
   greeting, not an effect.

   The sheen is a gradient clipped to the glyphs, which needs
   `color: transparent` to show. That would hide the names outright on a
   browser without background-clip:text, so the transparent colour and the
   animation both live inside @supports — everywhere else the names simply
   render in --ink, which is exactly what they did before. */
.masthead .names {
  animation: name-rise 1s cubic-bezier(.22,.61,.36,1) both;
}
@keyframes name-rise {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: none; }
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .masthead .names {
    /* The gradient is 3x the box and the sweep runs 100% -> 0%. Both matter:
       with background-clip:text, ANY glyph area the background image does not
       cover renders invisible, so the image has to stay over the whole box for
       the entire animation. Percentage positions between 0% and 100% guarantee
       that when the image is wider than the box; going outside that range
       (135% -> -35%, the first attempt) slides the image off and wipes the
       names letter by letter instead of lighting them. Both ends of the
       gradient are solid --ink, so the resting state is the old colour. */
    background-image: linear-gradient(100deg,
      var(--ink) 0%, var(--ink) 46.5%,
      #cbaa61 48.6%, #e8d29c 50%, #cbaa61 51.4%,
      var(--ink) 53.5%, var(--ink) 100%);
    background-size: 300% 100%;
    background-repeat: no-repeat;
    background-position: 100% 0;
    -webkit-background-clip: text;
            background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    animation: name-rise 1s cubic-bezier(.22,.61,.36,1) both,
               name-sheen 3s cubic-bezier(.45,0,.25,1) 0.7s 1 both;
  }
}
@keyframes name-sheen {
  from { background-position: 100% 0; }
  to   { background-position: 0% 0; }
}

@media (prefers-reduced-motion: reduce) {
  /* no rise, no sheen — the names are just the names */
  .masthead .names {
    animation: none;
    background-image: none;
    color: var(--ink);
    -webkit-text-fill-color: var(--ink);
  }
}

/* ---------- sticky nav ---------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  padding: 0 var(--gutter);
}
.nav ul {
  display: flex; gap: clamp(1rem, 2.6vw, 2.2rem);
  flex-wrap: nowrap;
  overflow-x: auto; scrollbar-width: none;
  height: var(--nav-h); align-items: center;
  font-size: 1rem;
}
.nav ul::-webkit-scrollbar { display: none; }
.nav li { flex: 0 0 auto; }
/* auto margins center the row when it fits and let it scroll from the
   left edge when it doesn't (plain justify-content:center clips the start) */
.nav li:first-child { margin-left: auto; }
.nav li:last-child  { margin-right: auto; }
.nav a {
  display: inline-block; padding: 0.95rem 0.1rem;   /* the whole bar height is the target, not the 33px text box */
  border-bottom: 1px solid transparent;
  white-space: nowrap;
}
.nav a:hover { text-decoration: none; }
.nav a.is-active { border-bottom-color: var(--accent); }

/* right-edge fade so a phone knows the nav row scrolls (.nav is already
   position:sticky above, which is a positioned element, so ::after can
   anchor to it without touching that rule) */
.nav::after {
  content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 2.25rem;
  background: linear-gradient(to right, transparent, color-mix(in srgb, var(--paper) 92%, transparent) 65%);
  pointer-events: none;
}
@media (min-width: 900px) { .nav::after { display: none; } }

/* ---------- hero: scrolling photo strip ----------
   A single row of landscape photos at a fixed height, edge to edge, that
   drifts left on its own and can be dragged / scrolled by hand. The list is
   duplicated once in the DOM by js/site.js so the drift can loop seamlessly.
   Photos use object-fit: cover so mixed aspect ratios sit flush. */
.hero { margin-top: 1.5rem; }
.hero-track {
  display: flex; gap: 6px;
  height: var(--hero-h);
  overflow-x: auto; overflow-y: hidden;
  /* No scroll-snap while the strip auto-drifts (fix, 15 Sep 2026). SPEED is
     0.35 px/frame, and a snap container pulls any sub-pixel offset straight
     back to the nearest photo edge — which is 0 — so the strip never moved,
     whatever the JS did. Verified A/B in headless Chromium: with snap on,
     scrollLeft stayed at 0 for five seconds at both 1440 and 400 px; with it
     off, ~30 px/s. Snapping is restored under prefers-reduced-motion below,
     where the auto-drift is switched off anyway and snapping is a real
     convenience. .hero-track.is-dragging already sets none, so a manual drag
     is unchanged. */
  scroll-snap-type: none;
  scrollbar-width: none;
  cursor: grab;
  user-select: none;
  -webkit-overflow-scrolling: touch;
}
.hero-track::-webkit-scrollbar { display: none; }
/* The lane is what the autoplay transforms; the track is what the browser
   scrolls. Keeping them separate is what lets a sub-pixel, GPU-composited
   drift coexist with native scrolling and touch momentum. */
.hero-lane {
  display: flex; gap: 6px; height: 100%;
  will-change: transform;
  backface-visibility: hidden;
}
.hero-track.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.hero-lane figure {
  flex: 0 0 auto; margin: 0; height: 100%;
  scroll-snap-align: start;
}
.hero-lane img {
  height: 100%; width: auto; object-fit: cover;
  pointer-events: none;                 /* so drag never turns into image-drag */
}

/* ---------- section scaffolding ---------- */
.section {
  padding: clamp(3rem, 8vw, 6rem) var(--gutter);
  scroll-margin-top: calc(var(--nav-h) + 0.5rem);
}
.section > .inner { max-width: var(--measure); margin: 0 auto; }
.section-photo {
  max-width: var(--wide); margin: 0 auto clamp(2rem, 5vw, 3.5rem);
}
.section-photo img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.section-title {
  font-size: clamp(2rem, 4.2vw, 2.6rem);
  font-weight: 300;
  text-align: center;
  margin-bottom: clamp(1.5rem, 4vw, 2.5rem);
  letter-spacing: 0.01em;
}
.center { text-align: center; }
.lede { max-width: 34rem; margin: 0 auto; text-align: center; }

/* ---------- welcome block ---------- */
.welcome .date { font-size: clamp(2rem, 5vw, 3rem); font-weight: 300; color: var(--ink-strong); }
.welcome .place { font-size: clamp(1.25rem, 2.4vw, 1.6rem); font-weight: 300; margin-top: 0.4rem; }
/* ---------- countdown ----------
   Enlarged 15 Sep 2026 at Michael's request: at 1.05rem it sat below the body
   size under a 3rem date, which read as a warning rather than as anticipation.
   The number is now the largest thing above the fold — bigger than the date —
   but it gets there through scale alone, in the same 300 weight and the same
   two grays. The only gold is the pair of hairlines and the two small hexes
   flanking the label, which is the site's existing divider device at a size
   that reads as punctuation. */
.welcome .countdown {
  margin: 2.2rem 0 2.4rem;
  display: flex; flex-direction: column; align-items: center; gap: 0.35rem;
}
.welcome .count-num {
  font-size: clamp(3.6rem, 9.5vw, 6rem);
  font-weight: 300;
  line-height: 1;
  color: var(--ink-strong);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.welcome .count-label {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  font-size: 0.78rem; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--ink-soft);
}
.welcome .count-label::before,
.welcome .count-label::after {
  content: ""; display: block; width: clamp(1.5rem, 6vw, 2.6rem); height: 1px;
  background: var(--accent); opacity: 0.55;
}
.welcome .count-label svg {
  width: 0.42rem; height: 0.46rem; flex: 0 0 auto;
  fill: var(--accent); opacity: 0.75;
}

/* ---------- chapter divider: gold hairline + hexagon ----------
   Same device front-to-back as the save-the-date's reverse side. Used
   between the Welcome date block and its intro paragraph, and again as
   the seam between every top-level section ("nine sections become nine
   chapters"). Gold is used here and nowhere else but the nav underline,
   the schedule timeline dots, and the footer hex. */
.divider {
  display: flex; align-items: center; justify-content: center; gap: 0.6rem;
  max-width: 148px; margin: 0 auto; padding: clamp(1.75rem, 4.5vw, 2.75rem) 0;
}
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--accent); }
.divider svg { width: 38px; height: 15px; flex: none; }   /* three cells, not one:
     the motif reduced to its smallest honest unit, so it survives every width */
.divider svg path { fill: none; stroke: var(--accent); stroke-width: 1.3; stroke-linejoin: round;
  vector-effect: non-scaling-stroke; }
.welcome .divider { padding: 2rem 0 0.5rem; }

/* ---------- buttons ---------- */
.btn {
  display: inline-block;
  border: 1px solid var(--ink); border-radius: 999px;
  padding: 0.75rem 1.6rem;
  font: inherit; font-size: 1rem; color: var(--ink);
  background: transparent; cursor: pointer;
  transition: background 160ms, color 160ms;
}
.btn:hover { background: var(--ink); color: var(--paper); text-decoration: none; }
.btn-sm { padding: 0.5rem 1.1rem; font-size: 0.9rem; }
/* the one solid object above the fold — everything else on the page stays outline */
.btn-filled { background: var(--ink); color: var(--paper); }
.btn-filled:hover { background: transparent; color: var(--ink); }

/* ---------- Q&A lists (Our Story + Q&A) ---------- */
.qa { display: grid; gap: clamp(1.6rem, 3vw, 2.4rem); }
.qa h3 { font-size: 1.05em; font-weight: 700; color: var(--ink-strong); margin-bottom: 0.35rem; }
.qa p:last-child { margin-bottom: 0; }

/* ---------- schedule timeline ---------- */
.day { margin-top: clamp(2rem, 5vw, 3rem); }
.day-label { letter-spacing: 0.22em; text-transform: uppercase; font-size: 0.95rem; margin-bottom: 1.25rem; }
.timeline { border-left: 1px solid var(--rule); margin-left: 0.5rem; }
.event { position: relative; padding: 0 0 2.5rem 2.75rem; }
.event:last-child { padding-bottom: 0.5rem; }
.event::before {
  /* tiny gold hexagon in place of the plain dot — the schedule timeline's
     honeycomb job */
  content: ""; position: absolute; left: -0.35rem; top: 0.5rem;
  width: 0.6rem; height: 0.6rem; background: var(--accent);
  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
}
.event .time { letter-spacing: 0.08em; font-size: 0.95rem; color: var(--ink-soft); }
.event h3 { font-size: 1.6rem; font-weight: 300; margin: 0.15rem 0 0.6rem; }
.event .meta { display: grid; gap: 0.35rem; font-size: 1rem; }
.event .meta li { display: flex; gap: 0.6rem; align-items: baseline; }
.event .meta svg { width: 1rem; height: 1rem; flex: none; stroke: currentColor; fill: none; stroke-width: 1.4; translate: 0 0.15rem; }
.event .desc { margin: 0.9rem 0 0; }
.event .links { margin-top: 0.6rem; font-size: 0.8rem; letter-spacing: 0.12em; text-transform: uppercase; display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center; }
.event .links a { display: inline-block; padding: 0.8rem 0; }   /* 44px tap height without changing the look */
.event .links a + a::before { content: "|"; margin-right: 0.75rem; color: var(--rule); }

/* ---------- hotel cards ---------- */
.hotels { display: grid; gap: 1.5rem; margin-top: 2rem; }
.hotel {
  display: grid; grid-template-columns: 1fr; gap: 0.9rem 1.5rem;
  padding: 1.5rem 0; border-top: 1px solid var(--rule);
}
.hotel:last-child { border-bottom: 1px solid var(--rule); }
.hotel h3 { font-size: 1.25rem; font-weight: 700; color: var(--ink-strong); }
.hotel .dist { font-size: 0.9rem; color: var(--ink-soft); }
.hotel .rate { display: flex; gap: 2rem; font-size: 0.95rem; flex-wrap: wrap; }
.hotel .rate b { display: block; font-weight: 400; color: var(--ink-soft); font-size: 0.8rem; letter-spacing: 0.04em; }
.hotel .rate strong { font-size: 1.3rem; font-weight: 400; }
@media (min-width: 720px) {
  .hotel { grid-template-columns: 1.4fr 1fr; align-items: start; }
  .hotel .cta { justify-self: end; align-self: center; grid-row: span 2; }
}

/* ---------- travel rows (icon | heading | body) ---------- */
.travel-row {
  display: grid; grid-template-columns: 2.75rem 1fr; gap: 0.5rem 1rem;
  padding: 2rem 0; border-top: 1px solid var(--rule);
}
.travel-row:first-of-type { border-top: 0; }
.travel-row svg { width: 2rem; height: 2rem; stroke: currentColor; fill: none; stroke-width: 1.2; }
/* the hexagon icon set (27 Sep 2026): a gold hairline hexagon with the glyph
   inside at 60%. The glyph stroke is 1.9 in the 24-unit box, which renders at
   about 1.1px after the scale, matching the old hairline weight. */
.travel-row svg.ti { width: 2.6rem; height: 2.6rem; margin-top: -0.3rem; color: var(--ink); }
.travel-row svg.ti .ti-hex { fill: none; stroke: var(--accent); stroke-width: 1; stroke-linejoin: round; }
.travel-row svg.ti .ti-g { fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.travel-row h3 { font-size: 1.35rem; font-weight: 700; color: var(--ink-strong); }
.travel-row .body { grid-column: 2; }
.travel-row .body p:last-child { margin-bottom: 0; }
.travel-row .contact { display: grid; gap: 0.4rem; margin-top: 0.9rem; font-size: 1rem; }
.travel-row .contact a { text-decoration: underline; text-underline-offset: 3px; }
.travel-row .list { columns: 2; column-gap: 2rem; }
.travel-row .list li { break-inside: avoid; padding: 0.2rem 0; }
.travel-row .list a { text-decoration: underline; text-underline-offset: 3px; }
.callout { border: 1px solid var(--rule); border-radius: 0.5rem; overflow: hidden; margin-top: 0.5rem; }
.callout header { padding: 0.9rem 1.2rem; border-bottom: 1px solid var(--rule); text-align: center; }
.callout div { padding: 1.1rem 1.2rem; }
@media (min-width: 720px) {
  .travel-row { grid-template-columns: 2.75rem 1fr 1.4fr; }
  .travel-row .body { grid-column: 3; grid-row: 1; }
}

/* ---------- wedding party monograms ----------
   Joy renders these as PNGs; here they are pure CSS/text so names and
   initials can be edited in place. */
.party { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: 3rem 2rem; margin-top: 1rem; }
.member { text-align: left; }
.mono {
  position: relative; width: 8.5rem; aspect-ratio: 1; margin: 0 auto 1.5rem;
  display: grid; place-items: center;
  font-family: "Cormorant Garamond", "Cormorant", Georgia, serif;
  font-size: 3.4rem; font-weight: 300; letter-spacing: 0.02em; color: #2b2b2b;
}
.mono::before, .mono::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
}
.mono::before { border-top: 1px solid #2b2b2b; border-left: 1px solid #2b2b2b; width: 65%; height: 82%; left: 0; top: 0; }
.mono::after  { border-bottom: 1px solid #2b2b2b; border-right: 1px solid #2b2b2b; width: 65%; height: 82%; left: auto; top: auto; right: 0; bottom: 0; }
.member .name { font-weight: 700; color: var(--ink-strong); border-top: 1px solid var(--rule); padding-top: 0.9rem; }
.member .role { font-size: 1rem; }

/* ---------- footer ---------- */
.footer { text-align: center; padding: 3rem var(--gutter) 4rem; color: var(--ink-soft); font-size: 0.95rem; }
.footer-names {
  font-family: var(--font-script); color: var(--ink-strong);
  font-size: clamp(1.9rem, 4.5vw, 2.4rem); line-height: 1.15; margin-bottom: 0.9rem;
}
.footer .hex { display: inline-block; width: 22px; height: 24px; margin-bottom: 1rem; }
.footer .hex path { fill: none; stroke: var(--accent); stroke-width: 1.5; }
.footer-domain { margin: 0 0 0.35rem; }
.footer-line { font-style: italic; margin: 0; }

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero-track { scroll-snap-type: x mandatory; }
}

/* ---------- RSVP: css/rsvp.css (5 Oct 2026). The message line stays here;
   Moments uses it too. ---------- */
.rsvp-message { margin-top: 1rem; text-align: center; min-height: 1.2em; }
.rsvp-message.is-error { color: #a33; }
.rsvp-message.is-ok { color: var(--ink-strong); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }

/* ---------- Moments (gallery-first: grid loads on open, "Add yours" is a
   quiet link that reveals the upload form — a form isn't the first thing
   a guest should see) ---------- */
.moments-app { max-width: 40rem; margin: 2rem auto 0; }
.moments-add-link {
  display: block; margin: 1.75rem auto 0; background: none; border: none;
  font: inherit; font-size: 0.95rem; color: var(--ink-soft);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.moments-add-link:hover { color: var(--ink); }
.moments-upload { margin-top: 1.5rem; display: flex; gap: .75rem; flex-wrap: wrap; justify-content: center; align-items: center; }
.moments-upload[hidden] { display: none; }
.moments-upload input[type=text] {
  flex: 1 1 12rem; font: inherit; font-size: 1rem; color: var(--ink); background: transparent;
  border: 1px solid var(--rule); border-radius: 999px; padding: .7rem 1.2rem;
}
.moments-file-btn { position: relative; cursor: pointer; }
.moments-grid { margin-top: 2rem; columns: 2; column-gap: .5rem; }
@media (min-width: 640px) { .moments-grid { columns: 3; } }
.moments-grid figure { margin: 0 0 .5rem; break-inside: avoid; }
.moments-grid img { width: 100%; border-radius: .3rem; }
.moments-grid figcaption { font-size: .8rem; color: var(--ink-soft); margin-top: .3rem; }

/* ---------- proposal video (under "How did he propose?" in Our Story) ---------- */
.proposal-video { margin-top: 0.5rem; }
.proposal-video h3 { font-size: 1.05em; font-weight: 700; color: var(--ink-strong); margin-bottom: 0.75rem; }
.proposal-video-frame { position: relative; max-width: 32rem; border-radius: 0.5rem; overflow: hidden; background: #000; }
.proposal-video-frame video { width: 100%; display: block; }
.proposal-play-btn {
  position: absolute; left: 50%; bottom: 1rem; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 0.5rem;
  border: 1px solid var(--paper); border-radius: 999px;
  background: color-mix(in srgb, #000 55%, transparent);
  color: var(--paper); font: inherit; font-size: 0.85rem; padding: 0.55rem 1.1rem;
  cursor: pointer; transition: background 160ms;
}
.proposal-play-btn:hover { background: color-mix(in srgb, #000 75%, transparent); }
.proposal-play-btn svg { width: 0.85rem; height: 0.85rem; fill: var(--paper); flex: none; }
/* desktop (9 Oct 2026, Michael): the video is the full reading column, not a 32rem thumbnail. It lines up with
   the text edges above and below it (the photos run a little wider, at --wide), and it is capped by the window's
   height so the whole 16:9 frame and the menu bar fit on screen even on a 1280x720 laptop. The teaser and the
   full film are 1080p, so they stay sharp at this size; phones and small tablets keep the old width. */
@media (min-width: 900px) {
  .proposal-video-frame { max-width: min(100%, calc((100vh - var(--nav-h) - 6rem) * 16 / 9)); margin-inline: auto; }
  .proposal-play-btn { bottom: 1.25rem; font-size: .95rem; padding: .7rem 1.35rem; }
  .proposal-play-btn svg { width: .95rem; height: .95rem; }
}
/* =====================================================================
   Wedding site — map component styles (.wmap-* namespace)
   Assumes site.css's :root tokens are already loaded: --ink, --ink-strong,
   --ink-soft, --accent, --paper, --rule, --font-body, --wide.
   Append this whole block to site.css at integration time.
   ===================================================================== */

.wmap-root {
  max-width: var(--wide, 68rem);
  margin: 0 auto;
}

/* ---------- the map's companion list ----------------------------------------
   Every pin is numbered and every number has a row here, so a guest can read
   what is on the map without hovering anything — which also means it works on
   a phone, where there is no hover at all. Hovering or focusing a row lifts its
   pin; opening a pin scrolls its row into view. No borders: the rows are
   separated by air and one hairline, like the rest of the page. */
.wmap-list {
  list-style: none; margin: 1.1rem 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 2.5rem;
}
@media (max-width: 720px) { .wmap-list { grid-template-columns: 1fr; } }

.wmap-item {
  display: flex; align-items: baseline; gap: .85rem;
  padding: .85rem .5rem .85rem .25rem;
  border-bottom: 1px solid var(--rule);
  cursor: pointer; border-radius: 6px;
  transition: background .2s cubic-bezier(.22,.61,.36,1);
}
.wmap-item:last-child { border-bottom: 0; }
.wmap-item:hover, .wmap-item.is-active { background: #fbf9f4; }
.wmap-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.wmap-num {
  flex: none; width: 1.55rem; height: 1.55rem; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .78rem; line-height: 1; color: #fff; background: var(--ink-soft);
  transition: background .2s cubic-bezier(.22,.61,.36,1);
}
.wmap-item.is-active .wmap-num, .wmap-item:hover .wmap-num { background: var(--accent); }

.wmap-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .15rem; }
.wmap-name { color: var(--ink-strong); font-size: 1.02rem; line-height: 1.3; }
.wmap-sub  { color: var(--ink-soft); font-size: .82rem; line-height: 1.45; }
.wmap-go {
  flex: none; align-self: center; color: var(--accent); text-decoration: none;
  font-size: .78rem; letter-spacing: .08em; text-transform: uppercase;
  padding: .35rem .1rem;
}
.wmap-go:hover, .wmap-go:focus-visible { text-decoration: underline; }

/* ── the event location cards ────────────────────────────────────────────────
   Each event's map is a drawn SVG, not a screenshot: real OpenStreetMap
   geometry projected and set in the site's own palette, with the same balloon
   pin the live map uses and, where the event is not at the venue, the walk
   between the two drawn in the dotted line the bee flies on /journey.

   What it replaced: a 640x240 PNG screenshot per event with the Leaflet
   attribution bar burned into the image, a flat unlabelled gold hexagon for a
   pin, and no way to tell which building was which — soft on any retina
   screen, and 100KB each. These are sharp at every size, smaller, and they
   say what they are. */
.event-map { display: block; width: 100%; height: auto; margin: .85rem 0; border-radius: 0; }

/* ── the marker family ───────────────────────────────────────────────────────
   Balloons, with the tip on the coordinate. See js/map.js for why that shape
   and not a centred circle.

   The scale lives on the INNER span, never on the marker root. Leaflet
   positions every marker by writing `transform: translate3d(...)` straight
   onto the root as an inline style, so the old `.wmap-icon-num.is-active
   { transform: scale(1.28) }` could only ever do one of two things: lose to
   the inline style and do nothing (what actually happened), or win and fling
   the pin to the corner of the map. Scaling the child is the fix, and
   `transform-origin: 50% 100%` is the tip — so an active pin grows upward out
   of its point and the point itself never moves. */
.wmap-pin {
  position: relative; display: block; line-height: 0;
  transform-origin: 50% 100%;
  transition: transform .22s cubic-bezier(.22,.61,.36,1), filter .22s ease;
  filter: drop-shadow(0 1.5px 2px rgba(74,60,28,.30)) drop-shadow(0 4px 7px rgba(74,60,28,.16));
}
/* A 19px balloon is a fine thing to look at and a poor thing to hit. The pad
   takes every pin past the 44px touch target without changing what is drawn. */
.wmap-pin::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 44px; height: 46px; transform: translate(-50%, -50%);
}
.wmap-icon:hover .wmap-pin,
.wmap-icon.is-active .wmap-pin {
  transform: scale(1.16);
  filter: drop-shadow(0 2px 3px rgba(74,60,28,.34)) drop-shadow(0 7px 12px rgba(74,60,28,.20));
}
.wmap-icon-venue .wmap-pin { filter: drop-shadow(0 2px 3px rgba(74,60,28,.34)) drop-shadow(0 6px 11px rgba(74,60,28,.18)); }
.wmap-icon-venue:hover .wmap-pin { transform: scale(1.08); }
/* the active pin turns gold, exactly as its row's number does */
.wmap-icon-num.is-active .wmap-pin path,
.wmap-icon-num:hover .wmap-pin path { fill: var(--accent); }
.wmap-icon-num .wmap-pin path { transition: fill .2s cubic-bezier(.22,.61,.36,1); }

/* ── names on the map ─────────────────────────────────────────────────────── */
.wmap-canvas .wmap-label {
  background: rgba(255,253,249,.94);
  border: 1px solid var(--rule);
  border-radius: 3px;
  box-shadow: 0 1px 4px rgba(74,60,28,.10);
  padding: .2rem .45rem;
  font-family: var(--font-body);
  font-size: .76rem; line-height: 1.25; letter-spacing: .01em;
  color: var(--ink-strong);
  white-space: nowrap;
}
.wmap-canvas .wmap-label::before { display: none; }   /* no callout arrow */
/* place names of our own for the zoomed-out view (map.js, PLACES): set in the
   page's face, quiet, centred on their point, and never in front of a pin */
.wmap-canvas .wmap-place { pointer-events: none; }
.wmap-canvas .wmap-place span {
  position: absolute; transform: translate(-50%, -50%); white-space: nowrap;
  font-family: var(--font-body); font-size: .74rem; letter-spacing: .06em;
  color: #6f6b64; text-shadow: 0 0 2px #f5f0e6, 0 0 4px #f5f0e6;
}
@media (max-width: 700px) { .wmap-canvas .wmap-place span { font-size: .68rem; } }
/* a label that will not fit, or that would print through a more important
   one, steps back entirely — see labelPlacer() in map.js */
.wmap-canvas .wmap-label.is-hidden { display: none; }
.wmap-canvas .wmap-label.is-venue {
  color: var(--accent); border-color: rgba(184,145,47,.42);
  font-size: .8rem; letter-spacing: .02em;
}
/* Three labels inside four blocks is a pile on a phone. The venue keeps its
   name at every width; the other two fall back to their pin and the list. */
@media (max-width: 700px) {
  .wmap-canvas .wmap-label.is-event { display: none; }
  .wmap-canvas .wmap-label { font-size: .72rem; padding: .16rem .38rem; }
}

@media (prefers-reduced-motion: reduce) {
  .wmap-item, .wmap-num, .wmap-pin, .wmap-icon-num .wmap-pin path { transition: none; }
  .wmap-icon:hover .wmap-pin, .wmap-icon.is-active .wmap-pin,
  .wmap-icon-venue:hover .wmap-pin { transform: none; }
}

/* ---------- chips ---------- */
.wmap-chips {
  display: flex;
  gap: 0.6rem;
  margin: 0 0 1rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.wmap-chips::-webkit-scrollbar { display: none; }
.wmap-chip {
  flex: 0 0 auto;
  display: inline-block;
  border: 1px solid var(--ink);
  border-radius: 999px;
  padding: 0.5rem 1.1rem;
  font: inherit;
  font-size: 0.9rem;
  color: var(--ink);
  background: transparent;
  cursor: pointer;
  transition: background 160ms, color 160ms;
  white-space: nowrap;
}
.wmap-chip:hover { background: var(--rule); }
.wmap-chip.is-active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

/* ---------- canvas ---------- */
/* the "tap to move the map" hint on touch screens — see map.js; goes away on the first tap */
.wmap-canvas.wmap-tap-to-pan::after {
  content: "Tap the map to move it"; position: absolute; left: 50%; top: .6rem; transform: translateX(-50%);
  z-index: 800;   /* top-centre: the attribution bar owns the bottom edge and would cover it */ pointer-events: none; font-size: .72rem; letter-spacing: .06em; color: var(--ink);
  background: rgba(255,255,255,.9); padding: .3rem .7rem; border-radius: 999px; white-space: nowrap;
}
.wmap-canvas {
  width: 100%;
  height: 420px;
  border-radius: 4px;
  overflow: hidden;
  /* the cream the basemap is washed over — see the note on the tile pane */
  background: #f3e8d0;
}

@media (max-width: 700px) {
  .wmap-canvas { height: 260px; }
  .wmap-chips { flex-wrap: nowrap; }
}

/* ── the basemap, warmed ─────────────────────────────────────────────────────
   Esri's Light Gray Canvas is a cold neutral: correct, free, key-free, and the
   one rectangle on this site that was not in the palette. The filter pulls it
   toward the page's cream and drops its contrast, so the map reads as a ground
   the pins sit ON rather than a grey panel competing with them.

   It is scoped to the TILE PANE only. Markers, labels, popups and controls
   live in other panes and are never filtered — which matters, because a
   filter on the whole canvas would drag the gold off-brand and mute the very
   marks the filter exists to make legible.

   Two things do the work, and it took measuring to find out why one alone
   could not. A `sepia()` filter cannot warm white: sepia preserves luminance,
   so near-white pavement comes out near-white and all the warmth lands in the
   midtones — which on this basemap means the LAKE goes beige while the land
   stays grey, the exact opposite of what is wanted. So the cream is put UNDER
   the tiles (the canvas background) and the base tile layer is drawn at 80%
   over it. That lifts the white paper to cream, and the filter then only has
   to take the remaining chill out and drop the contrast.

   Measured at the settings below: land #f5f0e6 (r−b +15), water #dbd6d0
   (r−b +11) — the water stays both cooler and 26 values darker than the land,
   which is what keeps Lake Monona reading as water and not as a beach. Push
   the wash further (65–75% tile opacity) and it does become a beach, and the
   street names start to disappear with it. This is tuned to that edge. */
.wmap-canvas .leaflet-tile-pane {
  filter: sepia(.12) saturate(.82) contrast(.92) brightness(1.02);
}

/* ---------- Leaflet overrides, kept minimal and on-brand ---------- */
.wmap-canvas .leaflet-control-attribution {
  font-family: var(--font-body);
  font-size: 0.65rem;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.75);
}
.wmap-canvas .leaflet-control-zoom a {
  color: var(--ink);
  font-family: var(--font-body);
}
/* The callout, in the same materials as the rest of the page: a hairline, a
   warm shadow rather than a black one, and the paper it is printed on. */
.wmap-canvas .leaflet-popup-content-wrapper {
  border-radius: 5px;
  border: 1px solid var(--rule);
  background: #fffdf9;
  box-shadow: 0 6px 22px -8px rgba(74,60,28,.34), 0 2px 5px rgba(74,60,28,.10);
}
.wmap-canvas .leaflet-popup-content { margin: .8rem .95rem .75rem; }
.wmap-canvas .leaflet-popup-tip {
  background: #fffdf9; border: 1px solid var(--rule);
  box-shadow: none;
}
.wmap-canvas .leaflet-popup-close-button {
  color: var(--ink-soft); font-size: 1.1rem; padding: .45rem .5rem 0 0;
  width: 26px; height: 26px;
}
.wmap-canvas .leaflet-popup-close-button:hover { color: var(--ink-strong); background: none; }
/* the zoom control, in the site's materials too */
.wmap-canvas .leaflet-control-zoom {
  border: 1px solid var(--rule); border-radius: 5px; overflow: hidden;
  box-shadow: 0 2px 8px -3px rgba(74,60,28,.28);
}
.wmap-canvas .leaflet-control-zoom a {
  background: #fffdf9; border-bottom-color: var(--rule);
  width: 32px; height: 32px; line-height: 32px; font-size: 1.05rem;
}
.wmap-canvas .leaflet-control-zoom a:hover { background: #f8f2e6; color: var(--accent); }

/* ---------- popup content ---------- */
.wmap-popup { font-family: var(--font-body); color: var(--ink); min-width: 160px; }
.wmap-popup h4 {
  margin: 0 0 0.25rem;
  font-weight: 400;
  font-size: 1rem;
  color: var(--ink-strong);
}
.wmap-popup-sub {
  margin: 0 0 0.35rem;
  font-size: 0.85rem;
  color: var(--ink-strong);
}
.wmap-popup-walk {
  margin: 0 0 0.35rem;
  font-size: 0.85rem;
  color: var(--accent);
  font-weight: 600;
}
.wmap-popup-addr {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  color: var(--ink-soft);
}
.wmap-popup a {
  font-size: 0.85rem;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ---------- marker icons: no hover animation, ever ---------- */
.wmap-icon { transition: none; }

/* ---------- reduced motion: Leaflet's own zoom/pan easing is disabled
   via JS options (fadeAnimation/zoomAnimation false); this just makes
   sure nothing in our own CSS adds motion back in. ---------- */
@media (prefers-reduced-motion: reduce) {
  .wmap-chip { transition: none; }
}
/* ─────────────────────────────────────────────────────────────────────────
   "Our Journey" — homepage section
   Appends to css/site.css. Uses only the site's existing tokens
   (--ink, --ink-strong, --ink-soft, --rule, --paper, --accent,
    --font-script, --font-body, --wide) — no new palette.
   Every rule is namespaced under .journey so nothing here can leak into
   the rest of the site.
   ───────────────────────────────────────────────────────────────────────── */

.journey{
  max-width: var(--wide);
  margin: 0 auto;
  --j-land:  #f1eee8;
  --j-line:  #ddd7cb;
  --j-wash:  #fbfaf8;
  --j-gold-deep:#96762a;
}

.journey-grid{
  display: grid;
  grid-template-columns: minmax(0, 46fr) minmax(0, 54fr);
  gap: clamp(1.25rem, 3vw, 2.25rem);
  align-items: start;
}

/* ── map ───────────────────────────────────────────────── */
.journey-map{
  background: var(--j-wash);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: .75rem .75rem .4rem;
  overflow: hidden;
}
.journey-map svg{ display: block; width: 100%; height: auto; }
.journey .land{ fill: var(--j-land); stroke: var(--j-line); stroke-width: 1.1; stroke-linejoin: round; }
.journey .route-base{
  fill: none; stroke: var(--accent); stroke-width: 2.6;
  stroke-linecap: round; stroke-dasharray: 1.5 11; opacity: .22;
}
.journey .route-run{
  fill: none; stroke: var(--accent); stroke-width: 2.6;
  stroke-linecap: round; opacity: 0;
}
/* The marks, held to the standard set on the Madison map and on /journey:
   above the ground they sit on, named legibly over anything, and the current
   one unmistakable. This map has no camera, so the sizes are plain pixels. */
.journey .pin{
  filter: drop-shadow(0 0 2.4px rgba(255,255,255,.95))
          drop-shadow(0 1.3px 1.5px rgba(74,60,28,.30));
}
.journey .pin-dot{
  fill: #fff; stroke: var(--accent); stroke-width: 3.2;
  transform-box: fill-box; transform-origin: center;
  transition: fill .3s ease, stroke .3s ease, transform .38s cubic-bezier(.22,.61,.36,1);
}
.journey .pin.is-on .pin-dot{ fill: var(--j-gold-deep); stroke: var(--j-gold-deep); transform: scale(1.28); }
.journey .pin-label{
  font-family: var(--font-body); font-size: 26px; letter-spacing: .13em;
  text-transform: uppercase; fill: var(--ink-soft); transition: fill .3s ease;
  paint-order: stroke; stroke: #fffdf9; stroke-width: 4.5px; stroke-linejoin: round;
}
.journey .pin.is-on .pin-label{ fill: var(--ink-strong); }
@media (prefers-reduced-motion: reduce) {
  .journey .pin-dot{ transition: none; }
  .journey .pin.is-on .pin-dot{ transform: none; }
}
.journey .bee{
  opacity: 0; transition: opacity .45s ease;
  filter: drop-shadow(0 0 7px rgba(255,255,255,.95)) drop-shadow(0 2px 4px rgba(120,100,60,.25));
}
.journey .bee.is-flying{ opacity: 1; }

/* ── the stop that is currently showing ────────────────── */
.journey-card{ min-width: 0; }
.journey-card .shot{
  position: relative; border: 1px solid var(--rule); border-radius: 12px;
  overflow: hidden; background: var(--j-wash);
  aspect-ratio: 4 / 3;
}
.journey-card .shot img{
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 38%; opacity: 0; transition: opacity .55s ease;
}
.journey-card .shot img.is-shown{ opacity: 1; }
.journey-card .shot .placeholder{
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: .4rem; text-align: center; padding: 1.5rem;
  background: repeating-linear-gradient(135deg,#fbf8f1,#fbf8f1 11px,#f6f1e5 11px,#f6f1e5 22px);
  opacity: 0; transition: opacity .4s ease; pointer-events: none;
}
.journey-card .shot .placeholder.is-shown{ opacity: 1; }
.journey-card .placeholder b{
  font-family: var(--font-script); font-weight: 400; font-size: 1.6rem; color: var(--j-gold-deep);
}
.journey-card .placeholder em{ font-style: normal; font-size: .85rem; color: var(--ink); }

.journey-card h3{
  font-family: var(--font-script); font-weight: 400;
  font-size: clamp(1.9rem, 3.6vw, 2.4rem); line-height: 1.1;
  color: var(--ink-strong); margin: .9rem 0 .2rem;
}
.journey-card .when{
  font-size: .72rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink-soft); margin-bottom: .5rem;
}
.journey-card .line{ font-size: 1rem; color: var(--ink); margin: 0; }

/* ── the six titles, as a tappable row ─────────────────── */
.journey-stops{
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: .4rem .25rem;
  margin: clamp(1.25rem, 3vw, 2rem) 0 0;
  padding: 0; list-style: none;
}
.journey-stops li{ display: flex; align-items: center; }
.journey-stops li + li::before{
  content: ""; width: 7px; height: 8px; margin: 0 .5rem; flex: none;
  background: var(--accent); opacity: .55;
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}
.journey-stops button{
  appearance: none; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: .92rem; letter-spacing: .01em;
  color: var(--ink-soft); padding: .45rem .55rem;      /* ≥44px tap target with the row gap */
  border-bottom: 1px solid transparent;
  transition: color .25s ease, border-color .25s ease;
}
.journey-stops button:hover{ color: var(--ink); }
.journey-stops button[aria-current="true"]{
  color: var(--ink-strong); border-bottom-color: var(--accent);
}

.journey-more{ text-align: center; margin-top: clamp(1.25rem, 3vw, 1.75rem); }

/* ── phone ─────────────────────────────────────────────── */
@media (max-width: 780px){
  .journey-grid{ grid-template-columns: 1fr; gap: 1rem; }
  /* the map keeps a readable floor and never widens past the screen */
  .journey-map{ padding: .55rem .55rem .3rem; }
  .journey-map svg{ max-height: 42vh; min-height: 170px; width: 100%; margin: 0 auto; }
  .journey .pin-label{ display: none; }
  .journey-card h3{ margin-top: .75rem; }
  .journey-stops{
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .15rem; justify-items: stretch;
  }
  .journey-stops li{ justify-content: center; }
  .journey-stops li + li::before{ display: none; }   /* separators would strand on wrap */
  .journey-stops button{ font-size: .88rem; padding: .6rem .35rem; width: 100%; }
}

/* ── reduced motion: all pins lit, the whole line drawn,
      no flight, and the stop row still switches the photo ── */
@media (prefers-reduced-motion: reduce){
  .journey .bee{ display: none; }
  .journey .route-base{ opacity: .7; }
  .journey .pin-dot{ fill: var(--j-gold-deep); stroke: var(--j-gold-deep); }
  .journey .pin-label{ fill: var(--ink-strong); }
  .journey-card .shot img,
  .journey-card .shot .placeholder{ transition: none; }
}

/* ---------- integration-pass-2: design-review item 3 (crop variety + captions) ---------- */

/* Schedule photo — full-bleed edge to edge; inner content keeps its normal gutters */
#schedule.section { padding-left: 0; padding-right: 0; }
#schedule .section-photo { max-width: none; margin-left: 0; margin-right: 0; }
#schedule .inner { padding-left: var(--gutter); padding-right: var(--gutter); }
#schedule .section-photo .photo-caption { padding: 0.5rem var(--gutter) 0; margin: 0; max-width: none; }

/* Wedding Party — tighter, taller crop */
/* 1:1, not 3:4: the source is an 1800×1200 landscape, and a 3:4 cover crop at
   the 1088px column had to UPSCALE it (1200 → 1451px tall) — soft on every
   screen. A square keeps the tighter crop the design review asked for without
   ever asking the browser for pixels that are not in the file. */
#party .section-photo img { aspect-ratio: 1 / 1; object-position: center 35%; }
@media (min-width: 900px) { #party .section-photo img { aspect-ratio: 4 / 3; } }

/* Captions — small italic, right-aligned, under each section photo */
.photo-caption {
  display: block;
  font-style: italic;
  text-align: right;
  color: var(--ink-soft);
  font-size: 0.9rem;
  max-width: var(--wide);
  margin: 0.5rem auto 0;
}

/* =====================================================================
   THE HIVE MOTIF                                      (added 2026-09-17)

   Allie's necklace and the comb on Michael's ring, carried over from
   byrne.buzz. Two things it is NOT: the full-bleed tile that page used to
   have, and a section decoration that scrolls away after the first screen.

   It is ONE fixed layer behind the whole page, sitting at z-index 0 while
   every section sits at 1 — so the clusters persist the entire scroll, and
   the photographs simply cover them where they overlap. Each cluster is
   radially masked so its outer cells dissolve rather than end on a cut line.

   Below 1200px the content column fills the width and there is no margin
   left to live in. The motif does not shrink or hide there — it hands off
   to the section dividers, which are the same comb at working size and
   read at every width, phones included.
   ===================================================================== */
.motif { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.motif .cl { position: absolute;
  -webkit-mask-image: radial-gradient(farthest-side at 50% 50%, #000 42%, rgba(0,0,0,.45) 74%, transparent 100%);
          mask-image: radial-gradient(farthest-side at 50% 50%, #000 42%, rgba(0,0,0,.45) 74%, transparent 100%);
}
.motif .cl svg { display: block; width: 100%; height: auto; overflow: visible; }
.motif .cl path {
  fill: none; stroke: var(--accent); stroke-width: 1.35;
  stroke-linejoin: round; vector-effect: non-scaling-stroke;
}
/* everything real sits above the layer */
.masthead, .hero, .section, .footer, .divider { position: relative; z-index: 1; }

.motif .cl-a { top: 8rem;  left: -4rem;    width: 15rem;   opacity: .26; rotate: -7deg; }
.motif .cl-b { top: 46%;   right: -3.5rem; width: 11.5rem; opacity: .22; rotate: 10deg; }
.motif .cl-c { bottom: 9%; left: -1rem;    width: 8.5rem;  opacity: .18; rotate: 4deg; }
.motif .cl-d { bottom: 6%; right: -2rem;   width: 7rem;    opacity: .15; rotate: -14deg; }

/* the trailing bounce: a second copy of the comb, weaker gradient, on top */
.motif .cl .sheen-bounce path { stroke: none; }
.motif.is-lit .cl .sheen-bounce path { stroke: url(#combSheen2); }

/* On a phone there are no margins to hide in, so the clusters sit behind the
   content at an opacity well under where they interfere with reading. Hiding
   them outright meant most guests — who will open this on a phone — never saw
   the motif at all. The section dividers still carry it at every width. */
@media (max-width: 1200px) {
  .motif { display: block; }
  .motif .cl-a { top: 6rem;   left: -5rem;    width: 14rem;  opacity: .12; }
  .motif .cl-b { top: 44%;    right: -4.5rem; width: 10.5rem;opacity: .10; }
  .motif .cl-c { bottom: 18%; left: -3rem;    width: 8.5rem; opacity: .09; }
  .motif .cl-d { bottom: 5%;  right: -3rem;   width: 7.5rem; opacity: .08; }
}
@media (max-width: 560px) {
  .section-photo img { aspect-ratio: 4 / 3; }
  #party .section-photo img { aspect-ratio: 1 / 1; }
  .party { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2.25rem 1.25rem; }
  .mono { width: 6.5rem; font-size: 2.6rem; }
  .motif .cl-a { top: 5rem;   left: -4rem;    width: 11rem;  opacity: .11; }
  .motif .cl-b { top: 46%;    right: -3.5rem; width: 8.5rem; opacity: .09; }
  .motif .cl-c { bottom: 20%; left: -2.5rem;  width: 7rem;   opacity: .08; }
  .motif .cl-d { display: none; }
}
/* the highlight only applies once the script has confirmed motion is welcome;
   without it the stroke stays flat gold, which is the reduced-motion state too */
.motif.is-lit .cl path{stroke:url(#combSheen)}
.motif .cl{translate:0 var(--drift,0)}


/* ---------- hero pause control (added 27 Sep 2026, decision S-3) ----------
   Small, quiet, and a real button: a 44px target drawn as a 34px disc. */
.hero { position: relative; }
.hero-pause {
  position: absolute; right: clamp(.5rem, 2vw, 1.25rem); bottom: .75rem; z-index: 3;
  width: 44px; height: 44px; padding: 5px; border: 0; background: none; cursor: pointer;
  display: grid; place-items: center;
}
.hero-pause::before {
  content: ""; position: absolute; inset: 5px; border-radius: 50%;
  background: rgba(255,255,255,.82); box-shadow: 0 1px 4px rgba(0,0,0,.18);
}
.hero-pause svg { position: relative; width: 14px; height: 14px; fill: none; stroke: var(--ink-strong); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.hero-pause .i-play { display: none; fill: var(--ink-strong); stroke-width: 1.6; }
.hero-pause[aria-pressed="true"] .i-pause { display: none; }
.hero-pause[aria-pressed="true"] .i-play { display: block; }
.hero-pause:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; border-radius: 50%; }

/* ---------- getting here & around (Round 1, Oct 2026) ---------- */
.travel-row .getting-around { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.85rem; }
.travel-row .getting-around b { color: var(--ink-strong); font-weight: 700; }
.travel-row .getting-around .btn { display: table; margin-top: 0.6rem; }

/* =====================================================================
   Typography pass (8 Oct 2026, type lab Phase B; picked from Claude/type-lab)
   - SoftQuotes: a 0.7 KB face holding only ‘ ’ “ ” (and ′ ″) from EB Garamond, first in
     the stack, so every apostrophe is a soft teardrop and every other letter stays Optima.
   - Ysabeau Office for devices without Optima (Windows, Android): Optima-like, 105% so
     lines wrap as they do on an iPhone. Apple devices never download it.
   - Body #6e6e6e (5.10:1) and small text #767676 (4.54:1); the names keep #848484.
   - Reading tune: nothing under ~14px, 1.6 leading for running text on phones.
   - A small comb by the names on desktop (>=1180px).
   Specimen, audit and the other options: Claude/type-lab (index.html, AUDIT.md).
   ===================================================================== */

/* ---- T1-soft-quotes-eb ---- */
@font-face {
  font-family: "SoftQuotes";
  src: url('/customweddingwebsite/fonts/softquotes-ebgaramond-400.woff2') format("woff2");
  font-style: normal;
  font-weight: 100 349;
  font-display: swap;
  size-adjust: 105%;
  unicode-range: U+2018-201F, U+2032-2033;
}
@font-face {
  font-family: "SoftQuotes";
  src: url('/customweddingwebsite/fonts/softquotes-ebgaramond-500.woff2') format("woff2");
  font-style: normal;
  font-weight: 350 599;
  font-display: swap;
  size-adjust: 105%;
  unicode-range: U+2018-201F, U+2032-2033;
}
@font-face {
  font-family: "SoftQuotes";
  src: url('/customweddingwebsite/fonts/softquotes-ebgaramond-700.woff2') format("woff2");
  font-style: normal;
  font-weight: 600 1000;
  font-display: swap;
  size-adjust: 105%;
  unicode-range: U+2018-201F, U+2032-2033;
}

:root {
  /* SoftQuotes first: it has only the quote marks, so every other letter falls through to Optima / the fallback */
  --font-body: "SoftQuotes", "Optima", "Optima Nova", "Ysabeau Office", "Alegreya Sans", "Gill Sans", "Segoe UI", sans-serif;
}

/* ---- fallback-ysabeau ---- */
@font-face {
  font-family: "Ysabeau Office";
  src: url('/customweddingwebsite/fonts/ysabeau-office-latin.woff2') format("woff2");
  font-style: normal;
  font-weight: 1 1000;
  font-display: swap;
  size-adjust: 105%;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Ysabeau Office";
  src: url('/customweddingwebsite/fonts/ysabeau-office-latin-ext.woff2') format("woff2");
  font-style: normal;
  font-weight: 1 1000;
  font-display: swap;
  size-adjust: 105%;
  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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Ysabeau Office";
  src: url('/customweddingwebsite/fonts/ysabeau-office-italic-latin.woff2') format("woff2");
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  size-adjust: 105%;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Ysabeau Office";
  src: url('/customweddingwebsite/fonts/ysabeau-office-italic-latin-ext.woff2') format("woff2");
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  size-adjust: 105%;
  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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---- gray-6e ---- */
:root { --ink: #6e6e6e; }   /* body text, buttons, pills */

/* The names keep today's softer gray (a 56px script passes the 3:1 large-text bar
   at #848484); only the reading text darkens. */
:root { --ink-names: #848484; }
.admin-names { color: var(--ink-names); }
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .masthead .names { color: var(--ink-names); }
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .masthead .names {
    background-image: linear-gradient(100deg,
      var(--ink-names) 0%, var(--ink-names) 46.5%,
      #cbaa61 48.6%, #e8d29c 50%, #cbaa61 51.4%,
      var(--ink-names) 53.5%, var(--ink-names) 100%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .masthead .names { color: var(--ink-names); -webkit-text-fill-color: var(--ink-names); }
}
:root { --ink-soft: #767676; }   /* captions, labels, hints, meta lines: the lightest gray that still passes 4.5:1 on white */
/* the RSVP's soft panels (9 Oct) are tinted ~#fbfaf5: one step darker there to keep 4.5:1 (4.54) */
.rsvp-form .rsvp-food { --ink-soft: #737373; }

/* ---- reading-tune ---- */
/* Reading tune. Nothing in the RSVP gets smaller; the rest of the page
   comes up to the RSVP's floor (9 Oct 2026): uppercase labels ~14px with
   their tracking, lowercase small text 15–16px. Body stays 18.75px. */
.welcome .count-label { font-size: .9rem; }      /* 12.5 → 14.4px, uppercase */
.event .links { font-size: .9rem; }              /* 12.8 → 14.4px, uppercase */
.hotel .rate b { font-size: .9rem; }             /* 12.8 → 14.4px */
.hotel .dist { font-size: 1rem; }                /* 14.4 → 16px */
.photo-caption { font-size: 1rem; }              /* 14.4 → 16px */
.event .time { font-size: 1rem; }                /* 15.2 → 16px */
.footer { font-size: 1rem; }                     /* 15.2 → 16px */
.btn-sm { font-size: .95rem; }                   /* 14.4 → 15.2px */
.wmap-sub { font-size: .9rem; }                  /* 13.1 → 14.4px */
.moments-grid figcaption { font-size: .9rem; }   /* 12.8 → 14.4px */
.admin-tile span, .ov-legend span, .ov-legend .ov-of { font-size: .9rem; }
.admin-table th button { font-size: .875rem; }
/* phones: a little more air between lines of running text (the column is ~42
   characters wide there, so 1.5 is tight for older eyes) */
@media (max-width: 560px) {
  .section p, .section li, .travel-row .body, .event .desc { line-height: 1.6; }
  .qa h3 { line-height: 1.4; margin-bottom: .45rem; }
}

/* ---- honeycomb-names ---- */
/* A small comb by the names (desktop only, where the margins have room): the
   necklace and the ring, and a cell the bee can come out of. Same strokes and
   mask as the margin clusters. Markup: one <div class="names-comb"> after the h1. */
.names-comb { display: none; }
@media (min-width: 1180px) {
  .names-comb {
    display: block; position: absolute; z-index: 0; pointer-events: none;
    /* the names are 56px Parisienne at every width ≥1180px: 526px wide, centered,
       so their last letter ends 263px (16.4rem) right of center; the comb starts ~12px later */
    left: calc(50% + 17.2rem); top: calc(clamp(2.5rem, 6vw, 4.5rem) - .1rem);
    width: 4.2rem; opacity: .5; rotate: 9deg;
    -webkit-mask-image: radial-gradient(farthest-side at 50% 50%, #000 48%, rgba(0,0,0,.5) 76%, transparent 100%);
            mask-image: radial-gradient(farthest-side at 50% 50%, #000 48%, rgba(0,0,0,.5) 76%, transparent 100%);
  }
  .names-comb svg { display: block; width: 100%; height: auto; overflow: visible; }
  .names-comb path { fill: none; stroke: var(--accent); stroke-width: 1.3; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
}

/* ---- honeycomb left of the names (8 Oct 2026, Michael) ----
   The same comb to the left of "Alexandria" (mirrored). Decoration only (aria-hidden).
   (The nav-row bookends were taken out 9 Oct 2026.) */
@media (min-width: 1180px) {
  .names-comb-l { left: auto; right: calc(50% + 17.2rem); rotate: -9deg; transform: scaleX(-1); }
}
/* "Your weekend" stays hidden until a guest has replied, so the last visible item
   carries the right auto margin that centres the row */
.nav li:has(+ li[hidden]:last-child) { margin-right: auto; }

/* ---- the wedding party as the ceremony stands (9 Oct 2026, Michael) ----
   One front row: Gabby, Stephan, Mason (Stephan stays first in the markup, so a
   screen reader still meets the officiant first; `order` seats him in the middle).
   Below it the bridesmaids on the left and the groomsmen on the right with an aisle
   between, three to a row and then two, each row centred on its side. Every card is
   one width, so the sides mirror. On a phone the same order keeps to the two columns:
   Stephan, then Gabby | Mason, then bridesmaids down the left, groomsmen down the right. */
.party { display: block; --card: 10rem; --aisle: 3.5rem; --row-gap: 2.75rem; --col-gap: 1.25rem; }
/* six across plus the aisle is a little wider than the text column, so the party
   may run past it (centred on the page), never past the gutters */
@media (min-width: 561px) {
  .party { width: min(calc(100vw - 2 * var(--gutter)), 70rem); position: relative; left: 50%; translate: -50% 0; }
}
.party .member { width: var(--card); text-align: center; }
.party .mono { width: 6.75rem; font-size: 2.8rem; margin-bottom: 1.2rem; }
.party-lead, .party-sides { display: flex; justify-content: center; }
.party-lead { gap: var(--aisle); }
.party-lead .honor-l { order: -1; }
.party-sides { gap: var(--aisle); margin-top: var(--row-gap); }
.party-side {
  flex: 0 1 calc(3 * var(--card) + 2 * var(--col-gap));
  display: flex; flex-wrap: wrap; justify-content: center; align-content: flex-start;
  gap: var(--row-gap) var(--col-gap);
}
@media (max-width: 760px) { .party { --aisle: 2rem; } }
@media (max-width: 560px) {
  .party { --aisle: 1.25rem; --row-gap: 2.25rem; }
  .party .member { width: auto; flex: 1 1 0; min-width: 0; }
  .party-lead { flex-wrap: wrap; row-gap: var(--row-gap); }
  .party-lead .officiant { order: -2; flex: 0 0 100%; display: flex; flex-direction: column; align-items: center; }
  .party-lead .officiant > * { width: calc(50% - var(--aisle) / 2); }
  .party-side { flex: 1 1 0; flex-direction: column; flex-wrap: nowrap; }
  .party-side .member { flex: none; width: 100%; }
  .party .mono { width: 6.5rem; font-size: 2.6rem; }
}

/* ---- the Welcome line, centred between its two combs (9 Oct 2026, Michael) ----
   "We can't wait to celebrate with you in Madison." sat 8px under the comb above it
   and 140px over the next one (the section's bottom padding plus that divider's own
   top padding). Same air on both sides now: the section ends sooner, and the comb
   above leaves exactly what is left below. */
.section.welcome { padding-bottom: clamp(1rem, 2.5vw, 1.25rem); }
.welcome .divider { padding-bottom: calc(clamp(1rem, 2.5vw, 1.25rem) + clamp(1.75rem, 4.5vw, 2.75rem)); }

/* ---- Wedding Party on phones: one grid for both sides (9 Oct 2026, Michael) ----
   The bridesmaids and groomsmen were two separate columns, each centred vertically, so whenever a
   name took two lines (e.g. "Natalia Hernández" on a 320–360px phone) the shorter column dropped and
   every pair below slid out of line. One shared grid keeps each pair on its own row. */
@media (max-width: 560px) {
  .party-sides { display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: row dense; gap: var(--row-gap) var(--aisle); }
  .party-side { display: contents; }
  .party-side:first-child .member { grid-column: 1; }
  .party-side:last-child .member { grid-column: 2; }
  .party-side .member { width: auto; }
}

/* =====================================================================
   The Romantic theme (9 Oct 2026, Michael & Allie; chosen from the preview's three formats)
   - Cormorant Garamond (the monograms' face) for titles, subheadings and photo captions;
     reading text, the menu, buttons and the RSVP stay Optima.
   - A rose before "Alexandria" (the comb stays after "Michael"), and three roses in the margins
     beside the comb clusters, drawn as tapered gold hairlines like the combs.
   - The butterfly lands on the rose and the bee on the comb: js/perch.js.
   To go back to the honeycomb-only site: git tag honeycomb-only-2026-10-09.
   ===================================================================== */

/* ---- fonts ---- */
.section-title, .welcome .date, .welcome .place, .welcome .count-num, .wk-title, .rsvp-party-name, .journey-head h2 {
  font-family: "Cormorant Garamond", "Cormorant", Georgia, serif;
}
.qa h3, .proposal-video h3, .event h3, .hotel h3, .travel-row h3, .member .name {
  font-family: "Cormorant Garamond", "Cormorant", Georgia, serif;
}
.photo-caption, figcaption { font-family: "Cormorant Garamond", "Cormorant", Georgia, serif; font-style: italic; letter-spacing: .01em; }
/* Cormorant sits small on its body and thin at 300: brought up to Optima's x-height, a step heavier */
.section-title, .welcome .date, .welcome .place, .wk-title, .rsvp-party-name,
.qa h3, .proposal-video h3, .event h3, .hotel h3, .travel-row h3, .member .name,
.photo-caption, figcaption { font-size-adjust: .47; }
.section-title, .welcome .date, .welcome .place { font-weight: 500; }
.qa h3, .proposal-video h3, .hotel h3, .travel-row h3, .member .name { font-weight: 600; }
/* the countdown: lining figures (old-style 7 and 9 drop below the line onto "days to go"), a little more line */
.welcome .count-num { font-variant-numeric: lining-nums tabular-nums; line-height: 1.12; }
/* the script and the monograms keep their own size */
.masthead .names, .journey-card h3, .mono, .wk-names { font-size-adjust: none; }

/* ---- the rose before "Alexandria" (computers, where the comb shows): balanced with the comb by
   measured weight — bloom ~85% of the comb's width — and clear of the names and the menu band ---- */
.names-rose { display: none; }
@media (min-width: 1180px) {
  .names-rose {
    display: block; position: absolute; z-index: 0; pointer-events: none;
    right: calc(50% + 17.1rem); top: calc(clamp(2.5rem, 6vw, 4.5rem) - .3rem);
    width: 3.8rem; height: 3.95rem; opacity: .5; rotate: -8deg;
    -webkit-mask-image: radial-gradient(farthest-side at 50% 42%, #000 64%, rgba(0,0,0,.6) 86%, transparent 100%);
            mask-image: radial-gradient(farthest-side at 50% 42%, #000 64%, rgba(0,0,0,.6) 86%, transparent 100%);
  }
  .names-rose svg { display: block; width: 100%; height: 100%; overflow: visible; }
  .names-rose path { fill: var(--accent); stroke: none; }
}

/* ---- the margin roses: filled tapered strokes, so fill takes the combs' stroke job (sheen included).
   Each has a slot of its own between the comb clusters and below the menu bar's full-width band
   (~12.5rem down before scrolling), sized by height so it fits short windows too. ---- */
.motif .cl.fl path { fill: var(--accent); stroke: none; }
.motif.is-lit .cl.fl path { fill: url(#combSheen); stroke: none; }
.motif .cl.fl .sheen-bounce path { fill: none; }
.motif.is-lit .cl.fl .sheen-bounce path { fill: url(#combSheen2); stroke: none; }
.motif .cl.fl {
  -webkit-mask-image: radial-gradient(farthest-side at 50% 45%, #000 58%, rgba(0,0,0,.5) 84%, transparent 100%);
          mask-image: radial-gradient(farthest-side at 50% 45%, #000 58%, rgba(0,0,0,.5) 84%, transparent 100%);
  translate: 0 calc(var(--drift, 0px) * .4);
}
.motif .cl.fl svg { width: 100%; height: 100%; }
.motif .fl-a { top: 13.2rem; right: .6rem; width: 9.4rem; height: clamp(5rem, calc(46vh - 14.2rem), 13rem); opacity: .34; rotate: -10deg; }
.motif .fl-b { top: 23rem; left: -.4rem; width: 9.4rem; height: clamp(5rem, calc(91vh - 9.4rem - 23rem - 1.2rem), 12rem); opacity: .28; rotate: 6deg; }
.motif .fl-c { bottom: calc(6% + 2rem); right: 5.2rem; width: 4.5rem; height: 4.3rem; opacity: .26; rotate: 8deg; }   /* beside the lower-right comb, not on it */
@media (max-width: 1200px) {
  .motif .fl-a { right: -1.6rem; width: 8rem; height: clamp(4rem, calc(44vh - 14.6rem), 11rem); opacity: .14; }
  .motif .fl-b { left: -2.4rem; width: 8rem; height: clamp(4rem, calc(82vh - 9rem - 23rem - .8rem), 11rem); opacity: .12; }
  .motif .fl-c { bottom: calc(5% + 2.2rem); right: 4.6rem; width: 4rem; height: 3.9rem; opacity: .11; }
}
@media (max-width: 560px) {
  .motif .fl-a { top: 13.4rem; right: -2rem; width: 6.6rem; height: clamp(4rem, calc(46vh - 14.6rem), 9rem); opacity: .13; }
  .motif .fl-b { top: 20rem; left: -2rem; width: 6.8rem; height: clamp(4rem, calc(80vh - 8rem - 20rem - .8rem), 10rem); opacity: .11; }
  .motif .fl-c { display: none; }
}

/* =====================================================================
   the recommended layout (9 Oct 2026, late — Michael & Allie: "your recommended settings are amazing, push those")
   Photos on a white mat with a soft shadow; the Q&A in three topics ("Index"); Our Story's questions on cards;
   the Travel map full width with the Capitol labelled and photos in the things-to-do list; the Hilton as our pick.
   ===================================================================== */

/* ---- photos: a white mat and a soft shadow, like a print on the wall ---- */
.section-photo .ph { display: block; position: relative; }
.section-photo .ph img { display: block; }
.section-photo:not(#schedule *) .ph {
  padding: clamp(6px, .8vw, 11px); background: #fff; border: 1px solid #ebe6dd;
  box-shadow: 0 2px 4px rgba(60,45,20,.06), 0 22px 44px -24px rgba(60,45,20,.42);
}
/* the schedule photo runs edge to edge, so it gets a fine line inside the picture instead of a mat */
#schedule .section-photo .ph::after {
  content: ""; position: absolute; inset: clamp(8px, 1.2vw, 15px); pointer-events: none; border: 1px solid rgba(255,255,255,.8);
}
.proposal-video-frame {
  padding: clamp(6px, .8vw, 11px); background: #fff; border: 1px solid #ebe6dd; border-radius: 4px;
  box-shadow: 0 2px 4px rgba(60,45,20,.06), 0 22px 44px -24px rgba(60,45,20,.42);
}
.proposal-video-frame video { border-radius: 2px; }
.proposal-play-btn { bottom: calc(1rem + 8px); }
@media (min-width: 900px) { .proposal-play-btn { bottom: calc(1.25rem + 10px); } }

/* ---- the Q&A: three topics, Index layout ---- */
.qa-g { display: grid; gap: clamp(1.6rem, 3vw, 2.2rem); }
.qa-items { display: grid; gap: clamp(1.5rem, 3vw, 2.1rem); }
.qa-g h4 {
  font-family: "Cormorant Garamond", "Cormorant", Georgia, serif; font-size: 1.05em; font-size-adjust: .47;
  font-weight: 600; line-height: 1.35; color: var(--ink-strong); margin-bottom: .35rem;
}
.qa-a p:last-child { margin-bottom: 0; }
.qa-cat {
  display: block; margin: 0 0 1.1rem;
  font-family: "Cormorant Garamond", "Cormorant", Georgia, serif; font-size: 1.6rem; font-size-adjust: .47; font-weight: 500;
  letter-spacing: .01em; color: var(--ink-strong); line-height: 1.2;
}
.qa-cat::after { content: ""; display: block; width: 2.2rem; height: 1px; margin-top: .7rem; background: rgba(184,145,47,.55); }
.qa-group + .qa-group { padding-top: clamp(1.6rem, 5vw, 2.2rem); border-top: 1px solid var(--rule); }
@media (min-width: 900px) {
  /* computers: the topic in its own column on the left, staying in view while its questions scroll by */
  .qa-group { display: grid; grid-template-columns: 12.5rem minmax(0, 1fr); gap: 2.75rem; padding-top: clamp(1.6rem, 3vw, 2.2rem); border-top: 1px solid var(--rule); }
  .qa-cat { align-self: start; position: sticky; top: calc(var(--nav-h) + 1.25rem); margin: 0; font-size: 1.7rem; }
  .qa-cat::after { margin-top: .9rem; }
}

/* ---- Our Story's questions on cards (tablets and computers; phones keep the open list) ---- */
.story-more { display: contents; }
@media (min-width: 760px) {
  .story-qa { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; }
  .story-qa > div:not(.proposal-video):not(.story-more), .story-more > div {
    border: 1px solid #ebe6dd; border-radius: 12px; background: #fffefb;
    padding: clamp(1.05rem, 2.2vw, 1.35rem) clamp(1.1rem, 2.4vw, 1.5rem) clamp(1.1rem, 2.3vw, 1.4rem);
  }
  .story-qa > .proposal-video { grid-column: 1 / -1; margin: .9rem 0 1.1rem; }
  /* after the video: two balanced columns, each card its own height */
  .story-more { grid-column: 1 / -1; display: block; columns: 2; column-gap: 1.25rem; }
  .story-more > div { break-inside: avoid; margin-bottom: 1.25rem; }
  .story-more > div:last-child { margin-bottom: 0; }
}

/* ---- Travel: the map row full width (it was squeezed into the right-hand column) ---- */
@media (min-width: 720px) {
  .travel-row.tr-map { grid-template-columns: 2.75rem 1fr; }
  .travel-row.tr-map .body { grid-column: 1 / -1; grid-row: 2; margin-top: .4rem; }
}
.photo-credits { margin: .9rem 0 0; font-size: .78rem; line-height: 1.5; color: var(--ink-soft); }
.photo-credits a { color: inherit; text-decoration: underline; text-decoration-color: var(--rule); text-underline-offset: 3px; }
/* photos in the map's lists (things to do, from Wikimedia Commons) */
.wmap-item:has(.wmap-thumb) { align-items: center; }
.wmap-thumb { flex: none; width: 3.6rem; height: 3.6rem; object-fit: cover; border-radius: 8px; box-shadow: 0 1px 2px rgba(60,45,20,.12); }
@media (min-width: 900px) { .wmap-thumb { width: 4.4rem; height: 4.4rem; } }
/* the Capitol: a small grey hexagon and a quiet label */
.wmap-landmark span { display: block; width: 12px; height: 12px; background: #9a9a9a; opacity: .85;
  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%); }
.wmap-canvas .wmap-label.is-landmark { color: #6e6e6e; background: rgba(255,255,255,.88); border-color: #d9d4ca; font-style: italic; }

/* ---- Where to Stay: the Hilton is our pick ---- */
.hotel-pick {
  display: inline-block; margin: .25rem 0 .45rem; padding: .22rem .7rem; border: 1px solid rgba(184,145,47,.55); border-radius: 999px;
  font-size: .72rem; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-strong);
}
@media (max-width: 460px) { .hotel-pick { letter-spacing: .08em; font-size: .68rem; padding: .2rem .55rem; } }

/* ---- heading rules and detail cards (9 Oct 2026, late — Michael & Allie: "the lines next to the 'Where to Stay'
   and other headings … but also with the detail cards beneath"; cards for the places, Index for the Q&A) ---- */
/* short gold hairlines either side of each section title */
.section-title { display: flex; align-items: center; justify-content: center; gap: clamp(.8rem, 2vw, 1.3rem); }
.section-title::before, .section-title::after { content: ""; width: clamp(1.6rem, 5vw, 3.4rem); height: 1px; background: rgba(184,145,47,.55); flex: none; }
/* the schedule's events, the hotels and the travel rows on hairline cards (tablets and computers; on a phone the
   width is worth more than the frame, so the open list stays) */
@media (min-width: 700px) {
  .event {
    margin: 0 0 1.5rem clamp(1rem, 2.4vw, 1.75rem); padding: clamp(1.1rem, 2.4vw, 1.5rem) clamp(1.1rem, 2.6vw, 1.75rem) .6rem;
    border: 1px solid #ebe6dd; border-radius: 12px; background: #fffefb;
  }
  .event:last-child { padding-bottom: .6rem; margin-bottom: .25rem; }
  .event::before { left: calc(-1 * clamp(1rem, 2.4vw, 1.75rem) - .35rem - 1px); top: calc(clamp(1.1rem, 2.4vw, 1.5rem) + .45rem); }
  .event .event-map { border: 1px solid #ebe6dd; }
  .hotels { gap: 1.1rem; }
  .hotel, .hotel:last-child {
    border: 1px solid #ebe6dd; border-radius: 12px; background: #fffefb;
    padding: clamp(1.1rem, 2.4vw, 1.5rem) clamp(1.1rem, 2.6vw, 1.75rem);
  }
  .hotel .rate:empty { display: none; }
  .travel-row, .travel-row:first-of-type {
    border: 1px solid #ebe6dd; border-radius: 12px; background: #fffefb;
    padding: clamp(1.2rem, 2.6vw, 1.75rem) clamp(1.1rem, 2.6vw, 1.75rem); margin-bottom: 1.1rem;
  }
}
@media (min-width: 900px) {
  /* the two room blocks run full width; the three without a block sit three across */
  .hotels { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .hotel { grid-column: span 6; }
  .hotel:nth-child(n+3) { grid-column: span 2; display: flex; flex-direction: column; gap: .7rem; }
  .hotel:nth-child(n+3) .cta { margin-top: auto; align-self: flex-start; }
  .hotel:nth-child(n+3) h3 { font-size: 1.15rem; }
}

/* ---- hotel photos, cards on phones, a stronger motif on phones (10 Oct 2026, Michael: "push the pictures",
   "make the cards or improve how it looks on mobile, the honeycomb and rose are still too transparent on mobile") ---- */
.hotel-ph {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: 8px; background: #f3f0ea; box-shadow: 0 1px 2px rgba(60,45,20,.1);
}
/* phones: a small square beside the name; the words wrap round it and then run the full width
   (a grid column left the Hilton's paragraph in a narrow strip) */
@media (max-width: 719px) {
  .hotel { display: block; }
  .hotel::after { content: ""; display: block; clear: both; }
  .hotel-ph { float: left; width: 5.25rem; aspect-ratio: 1 / 1; margin: .2rem .9rem .5rem 0; }
  .hotel > .rate { clear: both; padding-top: .9rem; }
  .hotel > .cta { clear: both; display: table; margin-top: .9rem; }
  .hotel .rate:empty { display: none; }
}
/* tablets and computers: the photo in its own column on the left */
@media (min-width: 720px) {
  .hotel { grid-template-columns: 10.5rem 1.4fr 1fr; }
  .hotel-ph { grid-row: span 2; aspect-ratio: 4 / 3; align-self: start; }
  .hotel .cta { grid-column: 3; }
}
/* the three small cards three across: the photo across the top */
@media (min-width: 900px) {
  .hotel:nth-child(n+3) .hotel-ph { aspect-ratio: 16 / 9; }
}

/* phones: the schedule, the hotels and the travel rows on the same hairline cards as on computers,
   with tighter padding so the width still goes to the words */
@media (max-width: 699px) {
  .event {
    margin: 0 0 1rem .9rem; padding: 1rem 1rem .4rem;
    border: 1px solid #ebe6dd; border-radius: 12px; background: #fffefb;
  }
  .event:last-child { padding-bottom: .4rem; margin-bottom: .25rem; }
  .event::before { left: calc(-.9rem - .35rem - 1px); top: 1.45rem; }
  .event .event-map { border: 1px solid #ebe6dd; }
  /* the narrower card wraps the links, and a wrapped line began with its "|" */
  .event .links { column-gap: 1.4rem; }
  .event .links a + a::before { content: none; }
  .hotels { display: grid; gap: .9rem; }
  .hotel, .hotel:last-child {
    border: 1px solid #ebe6dd; border-radius: 12px; background: #fffefb; padding: 1rem;
  }
  .travel-row, .travel-row:first-of-type {
    border: 1px solid #ebe6dd; border-radius: 12px; background: #fffefb;
    padding: 1.15rem 1rem; margin-bottom: .9rem;
  }
  /* inside a card the body runs the full width under the icon and heading (beside the icon, the map,
     its tabs and the list's links ran past the card's right edge) */
  .travel-row { align-items: center; }
  .travel-row .body { grid-column: 1 / -1; min-width: 0; margin-top: .35rem; }
}

/* phones and tablets: the combs and roses a clear step stronger (they were .08–.14 and read as almost nothing);
   still hairlines behind the words, still masked to soft edges */
@media (max-width: 1200px) {
  .motif .cl-a { opacity: .34; }
  .motif .cl-b { opacity: .30; }
  .motif .cl-c { opacity: .27; }
  .motif .cl-d { opacity: .24; }
  .motif .fl-a { opacity: .40; }
  .motif .fl-b { opacity: .36; }
  .motif .fl-c { opacity: .32; }
}

/* 19 Oct 2026: the "|" between the event-card links (Add to calendar | Apple/Outlook | Where to stay | Directions)
   sat inside each link, so it inherited the link's underline as a short stub. As an inline-block it no longer does. */
.event .links a + a::before { display: inline-block; text-decoration: none; }

/* ---- 26 Oct 2026: Madison, National Geographic's Best of the World 2027 ----
   The badge under the Welcome line, and the "Why Madison" Travel row as a postcard (Lake Mendota sunset on the
   front, our note and the quote on the back; both faces one link). Our own drawing: no CNN or National Geographic
   logos, photos, headline type or layout. The photo is credited on the card and under the map. */
.ng-badge { margin: 1.1rem auto 0; }
.ng-badge a {
  display: inline-flex; align-items: center; gap: .55rem; max-width: 100%;
  min-height: 2.75rem; padding: .45rem 1.05rem .45rem .7rem;
  border: 1px solid #d9c79a; border-radius: 999px; background: #fbf8f0;
  font-family: var(--font-body); font-size: .82rem; letter-spacing: .03em; line-height: 1.3;
  color: #5f5f5f; text-decoration: none; text-align: left;
  transition: border-color .2s ease, background .2s ease;
}
.ng-badge a:hover { border-color: #b8912f; background: #f7f1e3; }
.ng-badge a:focus-visible { outline: 2px solid #8a6c26; outline-offset: 3px; }
.ng-badge svg { flex: none; width: 1.35rem; height: 1.5rem; fill: none; stroke: #b8912f; stroke-width: 1.2; }
.ng-badge b { font-weight: 700; color: #5f5f5f; }
.ng-badge .ng-arrow { flex: none; color: #8a6c26; }
.section p.ng-badge a { text-decoration: none; }   /* beats ".section p a" (the gold underline on text links) */
#why-madison { scroll-margin-top: calc(var(--nav-h) + 1.5rem); }

/* the postcard row takes the full width under its heading, like the map row */
.travel-row.ng-row .body { min-width: 0; }
@media (min-width: 720px) {
  .travel-row.ng-row { grid-template-columns: 2.75rem 1fr; }
  .travel-row.ng-row .body { grid-column: 1 / -1; grid-row: 2; margin-top: .5rem; }
}
.ng-post { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; align-items: start; max-width: 46rem; margin: .7rem auto .4rem;
  text-decoration: none; color: #3d3830; -webkit-tap-highlight-color: transparent; }
.ng-face { position: relative; display: block; border-radius: 4px; background: #fbf8f1;
  box-shadow: 0 1px 2px rgba(60,50,35,.22), 0 10px 22px rgba(60,50,35,.14); transition: transform .25s ease, box-shadow .25s ease; }
.ng-front { transform: rotate(-1.8deg); padding: .55rem; }
.ng-back { transform: rotate(1.2deg); display: grid; grid-template-columns: 1.35fr 1fr; gap: .9rem; padding: 1rem 1rem .9rem;
  background-image: linear-gradient(#e7dfcf, #e7dfcf); background-size: 1px 78%; background-position: 57% 50%; background-repeat: no-repeat; }
.ng-post:hover .ng-front, .ng-post:focus-visible .ng-front { transform: rotate(-.6deg) translateY(-2px); }
.ng-post:hover .ng-back, .ng-post:focus-visible .ng-back { transform: rotate(.4deg) translateY(-2px); }
.ng-post:focus { outline: none; }
.ng-post:focus-visible { outline: 2px solid #8a6c26; outline-offset: 8px; border-radius: 6px; }
.ng-front-pic { display: block; aspect-ratio: 3 / 2; overflow: hidden; border-radius: 2px; background: #3a2c22; }
.ng-front-pic img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ng-front-type { position: absolute; left: 1.2rem; right: 1.2rem; bottom: 1.35rem; color: #fff; text-shadow: 0 1px 6px rgba(0,0,0,.55); }
.ng-front-k { display: block; font-family: var(--font-body); font-size: .66rem; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; }
.ng-front-h { display: block; font-family: "Cormorant Garamond", Georgia, serif; font-style: italic; font-weight: 500; font-size: 1.75rem; line-height: 1.1; }
.ng-credit { font-family: var(--font-body); font-size: .68rem; letter-spacing: .02em; color: #6b5f4b; white-space: nowrap; }
.ng-front-credit { position: absolute; right: .85rem; top: .85rem; padding: .1rem .35rem; border-radius: 2px; background: rgba(0,0,0,.42); color: #fff; font-size: .62rem; }
.ng-back-note, .ng-back-addr { display: block; min-width: 0; }
.ng-hand { display: block; font-family: "Caveat", "Bradley Hand", "Segoe Print", cursive; font-weight: 500; font-size: 1.22rem; line-height: 1.22; color: #36414f; }
.ng-sign { margin-top: .25rem; text-align: right; }
.ng-quote {
  display: block; margin: .6rem 0 0; padding: .1rem 0 .1rem .85rem; border-left: 2px solid #b8912f;
  font-family: "Cormorant Garamond", Georgia, serif; font-style: italic; font-size: 1.02rem; line-height: 1.35; color: #2f2b25;
}
.ng-cite { display: block; margin-top: .3rem; font-family: var(--font-body); font-style: normal; font-size: .66rem; letter-spacing: .02em; color: #6b5f4b; }
.ng-back-addr { position: relative; padding-top: 4.9rem; }
.ng-post svg.ng-stamp { position: absolute; top: 0; right: 0; width: 2.9rem; height: 3.5rem; fill: none; stroke: #b8912f; stroke-width: 1.3; }
.ng-post svg.ng-stamp text { fill: #8a6c26; stroke: none; font-family: var(--font-body); font-size: 9px; font-weight: 700; letter-spacing: .05em; }
.ng-postmark { position: absolute; top: .9rem; right: 3.3rem; width: 4.4rem; height: 4.4rem; border: 1px solid rgba(90,90,110,.45); border-radius: 50%;
  display: flex; align-items: center; justify-content: center; text-align: center; transform: rotate(-12deg);
  font-family: var(--font-body); font-size: .5rem; line-height: 1.25; letter-spacing: .06em; text-transform: uppercase; color: rgba(70,70,95,.75); padding: .3rem; }
.ng-line { display: block; font-family: "Caveat", "Bradley Hand", cursive; font-size: 1.12rem; line-height: 1.5; color: #36414f; }
.ng-more {
  display: inline-block; margin-top: .7rem; font-family: var(--font-body); font-size: .76rem; font-weight: 700;
  letter-spacing: .04em; color: #7a5f22; border-bottom: 1px solid currentColor; padding-bottom: 1px;
}
.ng-post:hover .ng-more { color: #5e4818; }
@media (prefers-reduced-motion: reduce) { .ng-face, .ng-badge a { transition: none; } }
/* phones and narrow columns: the back goes under the front, still one link */
@media (max-width: 860px) {
  .ng-post { grid-template-columns: 1fr; gap: .9rem; max-width: 26rem; }
  .ng-back { grid-template-columns: 1fr; background-image: none; }
  .ng-back-addr { position: static; border-top: 1px solid #e7dfcf; padding-top: .7rem; }
  .ng-post svg.ng-stamp { top: .9rem; right: .9rem; }
  .ng-postmark { display: none; }
  .ng-back-note { padding-right: 3.4rem; }
  .ng-front-h { font-size: 1.45rem; }
}
@media (max-width: 380px) { .ng-back-note { padding-right: 0; } .ng-post svg.ng-stamp { display: none; } }
