/* ==========================================================================
   Wedding invitation — soft pastel romance
   Direction inspired by theweddingwebsite.in: sage-and-cream, hairline rules,
   romantic high-contrast serif, generous whitespace. No photography, no glass.
   Layout is flow-based: nothing is positioned on top of content, so nothing
   can overlap it.
   ========================================================================== */

:root {
  /* pastels — sage taken from the reference site, blush for warmth */
  --ivory:     #fdfbf6;
  --sage-50:   #f1f4ec;
  --sage-100:  #e3ead8;
  --sage-200:  #d0dfb9;
  --sage-500:  #8a9a6b;
  --sage-700:  #4e5e32;
  --blush:     #f9eaee;
  --blush-200: #f0d5dd;
  --butter:    #fbf0d9;

  /* festive — marigold and gold. Kept as accents only: the sage/blush base
     stays the page, these mark the celebratory moments (toran, diyas,
     the main-event block) so "festive" reads as warmth rather than noise. */
  --marigold:      #f0a72a;
  --marigold-soft: #fdeccb;
  --marigold-deep: #b8770f;
  --gold:          #c9a227;
  /* Foil tones for the wedding card. Separate from --gold because foil on a
     dark maroon ground has to be lighter to read as metal rather than mud. */
  --maroon:        #7e1f2b;
  --gold-light:    #e3c766;
  --gold-soft:     #f6ecc9;
  --saffron:       #dd7a3c;
  --saffron-soft:  #fbe4d3;

  /* text — warm near-black so it stays readable on every wash above */
  --ink:       #2e2b26;
  --ink-soft:  #57524a;
  --ink-mute:  #726c61;

  --rose:      #a8566b;
  --rose-deep: #8c4055;

  --card:      #ffffff;
  --cream:     #fbf8f1;
  --line:      rgba(78, 94, 50, 0.16);
  --line-soft: rgba(78, 94, 50, 0.10);

  --display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --sans:    "Jost", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* whisper-soft, not drop-shadows */
  --shadow-sm: 0 2px 10px -6px rgba(78, 70, 52, 0.22);
  --shadow:    0 10px 30px -18px rgba(78, 70, 52, 0.30);

  --r-sm: 6px;
  --r:    14px;
  --r-lg: 22px;
  --maxw: 1040px;
}

* { box-sizing: border-box; }

/* Author display rules would otherwise beat the UA [hidden] rule. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  /* clears the fixed action bar so it never sits on top of the footer. The
     safe-area term keeps it clear of the iPhone home indicator too. */
  padding-bottom: calc(104px + env(safe-area-inset-bottom, 0px));
  font-family: var(--sans);
  font-weight: 400;
  color: var(--ink);
  background: var(--ivory);
  line-height: 1.65;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

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

/* Display tracking. Cormorant is a high-contrast old-style with generous
   sidebearings; at 40px+ the default spacing reads as loose rather than
   grand, so the big sizes get pulled in. Small-caps labels go the other way
   and are pushed out, which is where the letterforms were drawn to be used. */
.hero__names   { letter-spacing: -.02em; }
.section__title, .feature__title { letter-spacing: -.012em; }
.count__num, .hero__day { letter-spacing: -.015em; font-feature-settings: "lnum" 1; }
.family__names, .venue__name { letter-spacing: -.005em; }

a { color: var(--rose-deep); }
img { max-width: 100%; display: block; }

:focus-visible {
  outline: 2px solid var(--rose);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ------------------------------------------------------------- paper grain
   A fixed noise wash over the whole page. It sits above everything, including
   the action bar, because paper grain belongs on top of the ink — but it is
   pointer-events: none, so it can never intercept a tap. Kept at a very low
   opacity: enough to stop the flats reading as screen plastic, not enough to
   read as noise on a cheap panel. */
body::after {
  content: "";
  position: fixed; inset: 0; z-index: 200;
  pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------- scroll reveal
   Progressive enhancement. The hiding rule is scoped to .js, which app.js adds
   as its very first act — so if the script is blocked, fails to parse, or the
   visitor has JS off, nothing is ever hidden. The page degrades to fully
   visible rather than blank. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.22, 1, .36, 1);
  transition-delay: var(--reveal-delay, 0ms);
}
.js [data-reveal].is-in { opacity: 1; transform: none; }

/* ------------------------------------------------------------- card intro
   A physical-style Indian wedding card in two beats. The cover is pastel to
   match the page; the inner face is the printed invitation. The cover hinges
   on the left edge and swings open, and the guest taps a second control to
   read on.

   Two taps, but never a dead end: if the guest never taps, the CSS timings
   carry the same sequence on their own, and only then is the Continue control
   revealed without script, because a button that cannot be pressed should not
   be on screen.

   The previous intro was `pointer-events: none`, which meant it could never
   intercept a click and therefore could never block the page. A card that
   opens on tap cannot keep that property, so two other guarantees replace it:

   1. `.intro` is display:none unless `html.js` is present. The class is added by
      a three-line inline script in <head>, so if scripting is unavailable the
      overlay never renders at all and the page is simply the page.
   2. If the class is added but app.js then fails, every animation below is
      written to run on its own — the cover lifts at 4.6s and the overlay
      retires at 12s. JS only ever makes that happen sooner.

   The inner face is staggered rather than revealed at once, because arriving
   all in one beat reads as a glitch instead of a card opening. */
.intro {
  position: fixed; inset: 0; z-index: 100;
  display: none;
  place-items: center;
  padding: 24px;
  background: radial-gradient(circle at 50% 42%, rgba(253, 251, 246, .94), rgba(243, 236, 224, .97));
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  /* No timer retires this. The cover opens when the guest taps it, and the
     site appears when they press the control on the inner face. */
}
.js .intro { display: grid; }
/* Once the cover has been lifted, nothing advances on its own — the invitation
   moves on only when the guest presses the control on the inner face. This has
   to cancel the 12s outro above, not merely delay it, or the page would carry
   on regardless of what the guest (or the script) intends. */
.intro.is-open { animation: none; }
/* beat two, tapped: go now */
.intro.is-going { animation: intro-out .85s ease 0s forwards; }

.intro__glow {
  position: absolute; inset: -20%;
  background:
    radial-gradient(closest-side, var(--blush) 0%, transparent 70%),
    radial-gradient(closest-side, var(--sage-50) 0%, transparent 70%);
  background-size: 90% 90%, 90% 90%;
  background-position: 24% 16%, 76% 84%;
  background-repeat: no-repeat;
  animation: intro-glow 3s ease .05s both;
}

/* ------------------------------------------------------------------- card
   A plain <div>. The two controls are siblings rather than nested, because a
   button inside a button is invalid and the inner face needs its own. */
.card {
  position: relative;
  width: min(78vw, 340px);
  aspect-ratio: 5 / 7;
  perspective: 1400px;
  animation: intro-rise .7s ease .1s both;
}

/* Shared paper. Both faces carry a gold double rule and corner brackets, so
   they read as two sides of one printed card. */
.card__base, .card__leaf {
  position: absolute; inset: 0;
  border-radius: 8px;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* --- inner face: the printed invitation --------------------------------- */
.card__base {
  z-index: 1;
  display: flex; flex-direction: column; align-items: center;
  padding: 34px 24px 28px;
  text-align: center;
  color: var(--maroon);
  background: linear-gradient(158deg, #fffdf8 0%, #fbf4e6 52%, #f6ecd9 100%);
  border: 1px solid rgba(201, 162, 39, .5);
  box-shadow: 0 18px 40px rgba(45, 54, 34, .16);
  overflow: hidden;
}
.card__base::before {
  content: ""; position: absolute; inset: 7px;
  border: 1px solid rgba(201, 162, 39, .42);
  border-radius: 4px; pointer-events: none;
}
.card__base::after {
  content: ""; position: absolute; inset: 12px;
  border: 1px solid rgba(201, 162, 39, .18);
  border-radius: 2px; pointer-events: none;
}

  /* Every line of the inner face is hidden until the cover is opened. */
  .card__base > * { opacity: 0; }
  .intro.is-open .card__base > * { animation: card-in .8s ease both; }
  /* The reading-order stagger, now measured from the tap instead of from a
     clock. The cover passes 90deg at about 1.1s, which is the first moment the
     base is actually uncovered, so the blessing waits for it and each line
     after that trails in 0.25s behind. The Continue control is a direct child
     too, so it needs its own slot or it would ride in with the blessing; it
     lands last, once the invitation has settled and there is something to do. */
  .intro.is-open .card__blessing { animation-delay: 1.1s; }
  .intro.is-open .card__parents   { animation-delay: 1.35s; }
  .intro.is-open .card__names     { animation-delay: 1.6s; }
  .intro.is-open .card__invite    { animation-delay: 1.85s; }
  .intro.is-open .card__when      { animation-delay: 2.1s; }
  .intro.is-open .card__go        { animation-delay: 2.4s; }

.card__blessing {
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: clamp(.86rem, 3.1vw, 1rem); line-height: 1.5;
  color: #8a6a2e;
}
.card__parents {
  display: flex; gap: 14px; align-items: flex-start;
  margin: 22px 0 0; width: 100%;
}
.card__parent { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.card__parent + .card__parent { border-left: 1px solid rgba(201, 162, 39, .4); padding-left: 14px; }
.card__role {
  font-family: var(--sans); font-size: .5rem; letter-spacing: .16em;
  text-transform: uppercase; color: #a08a53;
}
.card__pname {
  font-family: var(--display); font-weight: 400;
  font-size: clamp(.8rem, 3.1vw, .96rem); line-height: 1.3; color: var(--maroon);
}
.card__names {
  display: flex; flex-direction: column; align-items: center;
  margin: 20px 0 0;
  font-family: var(--display); font-weight: 400;
  font-size: clamp(1.5rem, 6.4vw, 2.15rem); line-height: 1.18;
  color: var(--maroon);
}
.card__gname, .card__bname { display: block; }
.card__amp {
  display: block; margin: 2px 0;
  font-size: .58em; font-style: italic; color: var(--gold);
}
.card__invite {
  margin: 16px 0 0; max-width: 22ch;
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: clamp(.82rem, 3.2vw, 1rem); line-height: 1.5;
  color: #6d5a3c;
}
.card__when {
  margin: auto 0 0; padding-top: 16px;
  font-family: var(--sans); font-size: .56rem; letter-spacing: .2em;
  text-transform: uppercase; color: #a08a53;
}

/* beat two. Hidden outright without script, because a control that cannot be
   pressed should not be on screen; the CSS timings reveal the site regardless. */
.card__go {
  display: none;
  margin: 14px 0 0;
  padding: 9px 22px;
  font-family: var(--sans); font-size: .58rem; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--maroon);
  background: transparent;
  border: 1px solid rgba(201, 162, 39, .7);
  border-radius: 999px;
  cursor: pointer;
}
.js .card__go { display: block; }
.card__go:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.card__go:active { transform: translateY(1px); }
/* The family page drops the date from the card, and the date was what held the
   control at the foot of the card with its `margin: auto 0 0`. Without a
   replacement the button rides up under the invitation and the card reads
   top-heavy, so the control takes the anchor over. Keyed on the date's absence
   rather than a page class, so putting the date back restores the old layout. */
.card__base:not(:has(.card__when)) .card__go { margin-top: auto; }

/* --- cover: pastel, to match the page ----------------------------------- */
.card__leaf {
  z-index: 2;
  display: flex; flex-direction: column; align-items: center;
  padding: 30px 26px 26px;
  color: var(--rose);
  background:
    radial-gradient(105% 62% at 50% 8%, #fff8f4 0%, rgba(255, 248, 244, 0) 62%),
    linear-gradient(160deg, #fffaf6 0%, #fdf0e8 48%, #f6e9e6 100%);
  border: 1px solid rgba(201, 162, 39, .45);
  box-shadow: 0 18px 40px rgba(45, 54, 34, .16);
  transform-origin: 0% 50%;
  transform-style: preserve-3d;
  /* Opens like a card on its spine. `backface-visibility: hidden` is what makes
     the cover disappear past 90°; without it the back of the cover would sit
     there mirrored and the opening would read as a glitch. */
  transform: rotateY(0deg);
}
.intro.is-open .card__leaf { animation: card-open 1.4s ease 0s both; }

.card__leaf::before {
  content: ""; position: absolute; inset: 9px;
  border: 1.5px solid rgba(201, 162, 39, .55);
  border-radius: 4px; pointer-events: none;
}
.card__leaf::after {
  content: ""; position: absolute; inset: 15px;
  border: 1px solid rgba(201, 162, 39, .28);
  border-radius: 2px; pointer-events: none;
}

/* Gold corner brackets, the way printed invitation cards carry them. */
.card__corner {
  position: absolute; width: 22px; height: 22px;
  border: 0 solid rgba(201, 162, 39, .8); pointer-events: none;
}
.card__corner--tl { top: 18px;    left: 18px;  border-top-width: 1.5px; border-left-width: 1.5px; }
.card__corner--tr { top: 18px;    right: 18px; border-top-width: 1.5px; border-right-width: 1.5px; }
.card__corner--bl { bottom: 18px; left: 18px;  border-bottom-width: 1.5px; border-left-width: 1.5px; }
.card__corner--br { bottom: 18px; right: 18px; border-bottom-width: 1.5px; border-right-width: 1.5px; }

.card__crown { position: relative; display: block; width: min(38vw, 132px); margin: 4px 0 0; }
.card__arch { width: 100%; height: auto; overflow: visible; }
.card__draw {
  fill: none; stroke: #c9a227; stroke-linecap: round;
  stroke-dasharray: 100; stroke-dashoffset: 0;
  animation: card-draw 1.2s ease .3s both;
}
.card__draw--outer  { stroke-width: 2.2; }
.card__draw--inner  { stroke-width: 1; }
.card__draw--finial { stroke-width: 1.4; }
.card__draw--base   { stroke-width: 1.4; }

/* Ganesha, seated inside the arch. Positioned off the crown's own box so the
   arch geometry is untouched: the deity's base lands on the arch's base line,
   which is what makes it look seated rather than floating. */
.card__deity {
  position: absolute; left: 50%; bottom: 4%;
  width: 60%;
  translate: -50% 0;
  animation: intro-rise 1s ease .8s both;
}
.card__ganesh { width: 100%; height: auto; overflow: visible; }
.card__ganesh path, .card__ganesh circle {
  fill: none; stroke: #c9a227; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}

.card__deva {
  margin: 16px 0 0;
  font-size: clamp(1.3rem, 5.4vw, 1.75rem); font-weight: 600;
  color: var(--rose); letter-spacing: .02em;
}
.card__latin {
  margin: 5px 0 0;
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: clamp(.92rem, 3.5vw, 1.15rem); letter-spacing: .1em;
  color: var(--sage-700);
}
.card__rule {
  width: 54px; height: 1px; margin: 14px 0 0;
  background: linear-gradient(90deg, transparent, #c9a227, transparent);
  opacity: .7;
}
.card__diya { display: block; width: min(24vw, 84px); margin: auto 0 0; }
.card__diya svg { width: 100%; height: auto; }
.card__flame { fill: #e8890c; transform-origin: 50% 92%; animation: intro-flame 1.4s ease-in-out infinite; }
.card__bowl { fill: none; stroke: #c9a227; stroke-width: 2; }
.card__rim  { fill: none; stroke: #c9a227; stroke-width: 2; stroke-linecap: round; }

/* The tap target for beat one. It covers the closed card, so a tap anywhere
   works, and it is taken out of play once the cover is open. */
.card__open {
  position: absolute; inset: 0; z-index: 4;
  padding: 0; border: 0; background: none;
  cursor: pointer; color: transparent; font: inherit;
  border-radius: 8px;
}
.card__open:focus-visible { outline: 2px solid var(--gold); outline-offset: 8px; }
.intro.is-open .card__open, .intro.is-going .card__open { pointer-events: none; }

/* The seal sits on the cover's free edge and is what "breaks" on open. */
.card__seal {
  position: absolute; z-index: 3;
  top: 50%; right: 14px;
  translate: 50% -50%;
  width: 66px; height: 66px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, #f0e0ae, #ddc477 62%, rgba(221, 196, 119, 0) 100%);
  color: #7a5c12;
  font-family: var(--sans); font-size: .55rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  box-shadow: 0 3px 10px rgba(120, 90, 20, .22);
}
.intro.is-open .card__seal { animation: seal-break .4s ease 0s both; }

.card__hint {
  position: absolute; left: 0; right: 0;
  top: calc(50% + min(39vw, 170px) + 30px);
  margin: 0; text-align: center;
  font-family: var(--sans); font-size: .58rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ink-mute);
  animation: intro-hint 2.6s ease 1s infinite;
}
.intro.is-open .card__hint { animation: hint-out .3s ease .15s both; }

@keyframes card-open {
  0%   { transform: rotateY(0deg); }
  55%  { transform: rotateY(-13deg); }
  100% { transform: rotateY(-168deg); }
}
@keyframes card-in   { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
@keyframes seal-break {
  0%   { opacity: 1; scale: 1; }
  40%  { opacity: 1; scale: 1.07; }
  100% { opacity: 0; scale: 1.32; }
}
@keyframes hint-out  { to { opacity: 0; } }
@keyframes card-draw { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes intro-rise  { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes intro-hint { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
@keyframes intro-glow { 0% { opacity: 0; } 45% { opacity: 1; } 100% { opacity: .8; } }
@keyframes intro-flame {
  0%, 100% { transform: scaleY(1) scaleX(1); opacity: 1; }
  35%      { transform: scaleY(1.14) scaleX(.94); opacity: .92; }
  60%      { transform: scaleY(.94) scaleX(1.05); opacity: 1; }
}
@keyframes intro-out {
  to { opacity: 0; visibility: hidden; pointer-events: none; }
}

/* ------------------------------------------------------------- pastel wash */
.bg { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.bg__wash { position: absolute; border-radius: 50%; opacity: .85; }
.bg__wash--blush {
  width: 72vw; height: 72vw; top: -18vw; left: -22vw;
  background: radial-gradient(closest-side, var(--blush) 0%, transparent 72%);
}
.bg__wash--sage {
  width: 66vw; height: 66vw; top: 62vh; right: -24vw;
  background: radial-gradient(closest-side, var(--sage-50) 0%, transparent 72%);
}
.bg__wash--butter {
  width: 70vw; height: 70vw; top: 168vh; left: -26vw;
  background: radial-gradient(closest-side, var(--butter) 0%, transparent 72%);
}

/* ------------------------------------------------------------- topbar */
.topbar {
  position: relative; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  max-width: var(--maxw); margin: 0 auto; padding: 26px 24px 0;
}
.topbar__tag {
  font-family: var(--sans); font-size: .68rem; font-weight: 400;
  letter-spacing: .3em; text-transform: uppercase; color: var(--sage-700);
}
.topbar__tag:empty { display: none; }

/* ------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 26px; border: 1px solid transparent; border-radius: 999px;
  font-family: var(--sans); font-size: .72rem; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; text-decoration: none;
  cursor: pointer; white-space: nowrap;
  transition: background .2s ease, color .2s ease, border-color .2s ease, transform .2s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--solid {
  background: var(--sage-700); color: #fff;
  box-shadow: 0 8px 20px -12px rgba(78, 94, 50, .9);
}
.btn--solid:hover { background: #3f4c28; }

.btn--soft {
  /* Was fully transparent. It now sits over the couple artwork, so it carries
     its own translucent card and a blur, or the picture shows straight through
     the label and the button becomes unreadable. */
  background: rgba(255, 255, 255, .82);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  color: var(--ink);
  border-color: var(--line);
}
.btn--soft:hover { border-color: var(--sage-500); color: var(--sage-700); background: rgba(255, 255, 255, .95); }

.btn--ghost { background: transparent; color: var(--ink-soft); border-color: var(--line); }
.btn--ghost:hover { border-color: var(--sage-500); color: var(--sage-700); }

/* Used by app.js for the per-venue "Open in Maps" link. */
.btn--gold {
  background: var(--sage-100); color: var(--sage-700);
  border-color: var(--sage-200);
}
.btn--gold:hover { background: var(--sage-200); }

.btn--whatsapp { background: #25d366; color: #06331a; }
.btn--sm { padding: 9px 18px; font-size: .64rem; }

/* ------------------------------------------------------------- hero */
.hero {
  position: relative;
  max-width: var(--maxw); margin: 34px auto 0; padding: 0 24px;
}
.hero__card {
  position: relative; z-index: 1;
  max-width: 660px; margin: 0 auto;
  /* Lifted. Less space above the kalash and the names, a little more below, so
     the type block and the SVG art sit higher in the card with clearer air
     between them and the portrait band. Top and bottom are traded against each
     other (114px of vertical padding before, 106px now) rather than the top
     simply being cut, so the card height — and therefore the 58% band, which is
     a share of it — barely moves. */
  /* Bottom padding traded against .hero__line's top margin. This is the lever
     that lowers the closing line: cut here, add the same amount to .hero__line
     above, and the line drops while the card height — and therefore the 58%
     portrait band, which is a share of it — stays put. Never cut this padding
     on its own; that grows the card and rescales the photo.

     History: 62/26 -> 44/44 -> 26/62 -> 10/78. The sum has been 88px at every
     step. At 10px the line's descenders sit about 10px off the border, which is
     the tightest this card has been. It reads as deliberate only while the
     line is centred and short; on a narrow phone it will touch the bottom
     padding's edge, so check it there before shipping. */
  padding: 44px 44px 10px;
  text-align: center;
  background: var(--card);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
}

.hero__kalash { width: 52px; margin: 0 auto 18px; opacity: .9; }

.hero__blessing {
  font-family: var(--sans); font-size: .68rem; font-weight: 400;
  letter-spacing: .3em; text-transform: uppercase;
  color: var(--ink-mute); margin: 0 0 26px;
}

.hero__names {
  display: flex; align-items: baseline; justify-content: center;
  flex-wrap: wrap; gap: 4px 20px; margin: 0;
  font-size: clamp(2.6rem, 10vw, 4.4rem);
  font-weight: 300;
  letter-spacing: .01em;
}
.hero__name { color: var(--rose); }
.hero__amp {
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: .52em; color: var(--sage-500);
}

/* The closing request. It is the last child of the card, so its distance from
   the foot is whatever the card's bottom padding leaves, and the space above it
   is the margin here. Lowering the line means raising this and cutting the
   padding by the same amount, never the padding alone, or the card grows and
   the portrait band (58% of the card) scales with it.

   It now sits low enough to be over the photograph, where the band's white
   wash has already faded out, so it carries a soft shadow. That is the first
   text-shadow in the stylesheet: it is needed only here, because this is the
   only type that overlaps the picture with nothing behind it. */
.hero__line {
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: 1.2rem; color: var(--ink-soft); margin: 78px 0 0;
  text-shadow: 0 1px 10px rgba(255, 255, 255, .95), 0 0 3px rgba(255, 255, 255, .8);
}

.hero__date {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  gap: 10px 16px; margin: 30px 0 0;
}
.hero__day   { font-size: clamp(1.7rem, 5.5vw, 2.2rem); font-weight: 400; color: var(--sage-700); }
.hero__month { font-family: var(--sans); font-size: .74rem; font-weight: 400; letter-spacing: .28em; text-transform: uppercase; color: var(--ink-soft); }
.hero__year  { font-family: var(--sans); font-size: .74rem; font-weight: 400; letter-spacing: .28em; color: var(--ink-soft); }
.hero__sep { width: 5px; height: 5px; border-radius: 50%; background: var(--sage-200); }


/* Lives outside .hero__card now, so it is no longer bounded by the card's
   660px measure or lifted in with the card's reveal. Both are re-applied here:
   the max-width keeps the row centred under the card rather than under the full
   1040px hero, and auto side margins centre it on the page. `margin: 36px auto
   0` keeps the original gap above the row. */
.hero__cta {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: center;
  max-width: 660px; margin: 36px auto 0;
}

/* ------------------------------------------------------------- shared labels */
.section__eyebrow {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  font-family: var(--sans); font-size: .66rem; font-weight: 400;
  letter-spacing: .32em; text-transform: uppercase;
  color: var(--sage-700); margin: 0 0 14px;
}

/* ------------------------------------------------------------- countdown */
.countdown { max-width: 820px; margin: 0 auto; padding: 84px 24px 24px; text-align: center; }

.countdown__grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
  margin-top: 26px;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
}
.count { padding: 30px 10px; position: relative; }
/* hairline separators between the four cells */
.count + .count::before {
  content: ""; position: absolute; left: 0; top: 22%; bottom: 22%;
  width: 1px; background: var(--line-soft);
}
.count__num {
  display: block; font-family: var(--display); font-weight: 300;
  font-size: clamp(2.2rem, 8vw, 3.2rem); line-height: 1;
  color: var(--sage-700); font-variant-numeric: tabular-nums;
}
.count__lbl {
  display: block; margin-top: 12px;
  font-family: var(--sans); font-size: .58rem; font-weight: 400;
  letter-spacing: .24em; text-transform: uppercase; color: var(--ink-mute);
}
.countdown__done { font-family: var(--display); font-style: italic; font-size: 1.25rem; color: var(--rose-deep); margin-top: 26px; }

/* ------------------------------------------------------------- invitation line */
.banner {
  max-width: 640px; margin: 0 auto; padding: 56px 24px 4px;
  text-align: center;
}
.banner__rule {
  display: block; width: 100%; height: 1px; margin: 0 0 22px;
  background: linear-gradient(90deg, transparent, var(--sage-200) 22%, var(--sage-200) 78%, transparent);
}
.banner__rule:last-child { margin: 22px 0 0; }
.banner__text {
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: clamp(1.15rem, 3.4vw, 1.55rem); color: var(--ink); margin: 0;
}

/* ------------------------------------------------------------- families */
.families {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 24px 28px;
  max-width: 780px; margin: 0 auto; padding: 68px 24px 12px;
}
.family { flex: 1 1 220px; }
.family { text-align: center; }
.family__side {
  font-family: var(--sans); font-size: .64rem; font-weight: 400;
  letter-spacing: .28em; text-transform: uppercase; color: var(--sage-700); margin: 0 0 10px;
}
.family__names { font-family: var(--display); font-size: 1.3rem; font-weight: 500; color: var(--ink); margin: 0; }
.family__names:empty { display: none; }
.family__divider { width: 60px; height: 1px; background: var(--sage-200); }

/* ------------------------------------------------------------- sections */
.section { max-width: var(--maxw); margin: 0 auto; padding: 88px 24px; text-align: center; }
/* The tint used to jump straight to sage on both edges. Fading to transparent
   first, and carrying a marigold bloom through the middle, blends the section
   into its neighbours instead of banding against them. */
.section--tint {
  max-width: none; padding-inline: max(24px, calc((100% - var(--maxw)) / 2 + 24px));
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(227, 234, 216, .34) 34%,
    rgba(253, 236, 203, .30) 62%,
    rgba(255, 255, 255, 0) 100%);
}
.section__title { font-size: clamp(1.9rem, 5.5vw, 2.9rem); font-weight: 400; color: var(--ink); }
.section__sub {
  max-width: 58ch; margin: 16px auto 0;
  font-size: .95rem; color: var(--ink-soft);
}

/* ------------------------------------------------------------- day tabs */
.tabs {
  display: flex; flex-wrap: wrap; gap: 0;
  justify-content: center; margin: 40px 0 30px;
  border-bottom: 1px solid var(--line-soft);
}
.tab {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  min-width: 116px; padding: 14px 20px 16px;
  background: transparent; border: 0; border-bottom: 2px solid transparent;
  margin-bottom: -1px; cursor: pointer;
  font-family: var(--display); font-size: 1.08rem; font-weight: 500; color: var(--ink-mute);
  transition: color .2s ease, border-color .2s ease;
}
.tab:hover { color: var(--sage-700); }
.tab[aria-selected="true"] { color: var(--sage-700); border-bottom-color: var(--sage-700); }
.tab__dow {
  font-family: var(--sans); font-size: .56rem; font-weight: 400;
  letter-spacing: .22em; text-transform: uppercase; color: var(--ink-mute);
}

.day-panel { display: grid; gap: 14px; text-align: left; }
.events { display: grid; gap: 12px; }
.day-panel[hidden] { display: none; }

/* ------------------------------------------------------------- event rows */
.event {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 12px 18px;
  padding: 18px 24px;
  background: var(--card); border: 1px solid var(--line-soft);
  border-radius: var(--r);
  transition: border-color .2s ease, transform .2s ease;
}
.event__icon { flex: 0 0 auto; }
.event__time { flex: 0 0 116px; }
.event__venue { flex: 0 0 auto; margin-left: auto; text-align: right; }
.event:hover { border-color: var(--sage-200); transform: translateY(-1px); }
.event[data-now="true"] { border-color: var(--sage-500); box-shadow: inset 3px 0 0 var(--sage-500); }

.event__icon {
  display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--sage-50); border: 1px solid var(--line-soft);
}
.event__icon .icon { width: 25px; height: 25px; }

.event__time { font-size: .82rem; font-weight: 500; letter-spacing: .04em; color: var(--sage-700); }
.event__time small { display: block; font-weight: 300; color: var(--ink-mute); }

.event__name { font-family: var(--display); font-size: 1.15rem; font-weight: 500; color: var(--ink); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.event__tag {
  font-family: var(--sans); font-size: .58rem; font-weight: 400;
  letter-spacing: .12em; text-transform: uppercase;
  padding: 4px 11px; border-radius: 999px;
  background: var(--butter); color: var(--ink-soft);
}
.event__happen {
  font-family: var(--sans); font-size: .56rem; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  padding: 4px 11px; border-radius: 999px;
  background: var(--sage-700); color: #fff;
}
.event__venue { font-size: .78rem; color: var(--ink-mute); text-align: right; }

/* ------------------------------------------------------------- baraat feature */
.feature {
  max-width: 620px; margin: 8px auto 0; padding: 20px 24px;
  text-align: center;
}
.feature__rule { display: block; height: 1px; width: 180px; margin: 0 auto; background: var(--sage-200); }
.feature__rule:last-of-type { margin-top: 22px; }
.feature__body { padding: 22px 0; }
.feature__title { font-size: clamp(1.6rem, 5vw, 2.3rem); font-weight: 400; color: var(--rose); }
.feature__when { font-family: var(--sans); font-size: .72rem; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-soft); margin: 12px 0 0; }

/* ------------------------------------------------------------- venues */
.venue-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-top: 40px; }
.venue {
  padding: 32px 28px; text-align: left;
  background: var(--card); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
}
.venue__what {
  font-family: var(--sans); font-size: .6rem; font-weight: 400;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--sage-700); margin: 0 0 10px;
}
.venue__name { font-size: 1.45rem; font-weight: 500; color: var(--ink); }
.venue__addr { font-size: .92rem; color: var(--ink-soft); margin: 12px 0 0; }
.venue__links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }

  /* ------------------------------------------------------------ blessings
     Replaces the card grid. The mandala is the one ornament that was styled
     but never placed once the portrait took the hero, so it carries this panel
     instead of adding a new asset. */
  .section--blessings { max-width: 720px; padding-block: 76px; }
  .section--blessings > *:not(.deco) { position: relative; z-index: 1; }
  .blessings__text {
    font-family: var(--display); font-style: italic; font-weight: 400;
    font-size: clamp(1.2rem, 3.4vw, 1.55rem); line-height: 1.7;
    color: var(--ink-soft); margin: 22px auto 0; max-width: 26em;
  }
  .blessings__text:empty { display: none; }


/* ------------------------------------------------------------- rsvp */
.rsvp-form {
  max-width: 600px; margin: 40px auto 0; text-align: left;
  padding: 36px 32px;
  background: var(--card); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
}
.field { display: block; margin-bottom: 20px; border: 0; padding: 0; }
.field > label, .field > legend {
  display: block; padding: 0;
  font-size: .64rem; font-weight: 400; letter-spacing: .2em;
  text-transform: uppercase; color: var(--sage-700); margin-bottom: 9px;
}
.field input[type="text"], .field input[type="tel"], .field input[type="number"], .field select, .field textarea {
  width: 100%; padding: 13px 15px;
  font-family: var(--sans); font-size: .95rem; color: var(--ink);
  background: var(--cream); border: 1px solid var(--line-soft);
  border-radius: var(--r-sm); transition: border-color .2s ease, box-shadow .2s ease;
}
.field textarea { resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--sage-500);
  box-shadow: 0 0 0 3px rgba(138, 154, 107, .18);
}
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

.choices { display: grid; gap: 10px; }
.choice {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 16px; cursor: pointer;
  background: var(--cream); border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  font-size: .92rem; color: var(--ink);
  transition: border-color .2s ease, background .2s ease;
}
.choice:hover { border-color: var(--sage-200); }
.choice:has(input:checked) { border-color: var(--sage-500); background: var(--card); }
.choice input { accent-color: var(--sage-700); width: 17px; height: 17px; flex: none; }

.form-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; }
.form-status { font-size: .88rem; color: var(--rose-deep); margin: 16px 0 0; min-height: 1.2em; }

.saved {
  max-width: 600px; margin: 26px auto 0; text-align: left;
  padding: 18px 22px; background: var(--card);
  border: 1px solid var(--line-soft); border-radius: var(--r);
}
.saved summary { cursor: pointer; font-size: .88rem; color: var(--ink-soft); }
.saved-list-item {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--line-soft);
  font-size: .88rem; color: var(--ink);
}

/* ------------------------------------------------------------- verse */
.section--verse { max-width: 720px; padding-block: 64px; }
.verse__text {
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: clamp(1.2rem, 3.6vw, 1.6rem); line-height: 1.7;
  color: var(--ink-soft); margin: 0;
}

/* ------------------------------------------------------------- footer */
.footer {
  position: relative; text-align: center; padding: 64px 24px 44px;
  background: linear-gradient(180deg, rgba(255,255,255,0), rgba(227, 234, 216, .45));
}
.footer__hashtag {
  font-family: var(--sans); font-size: .74rem; font-weight: 400;
  letter-spacing: .26em; color: var(--sage-700); margin: 0 0 12px;
}
.footer__hashtag:empty { display: none; }
.footer__note { font-size: .88rem; color: var(--ink-soft); margin: 0 0 10px; }
.footer__note:empty { display: none; }
.footer__tiny { font-family: var(--display); font-style: italic; font-size: .88rem; color: var(--ink-mute); margin: 0; }

/* ------------------------------------------------------------- actions */
.actions {
  position: fixed; z-index: 30; left: 50%;
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  /* the inset terms keep the bar off a landscape notch as well as the home bar */
  margin-left: env(safe-area-inset-left, 0px);
  margin-right: env(safe-area-inset-right, 0px);
  transform: translateX(-50%);
  display: flex; gap: 4px; padding: 6px 10px;
  background: rgba(255, 255, 255, .94);
  border: 1px solid var(--line); border-radius: 999px; box-shadow: var(--shadow);
}
.act {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  width: 62px; padding: 8px 4px; border: 0; border-radius: 999px;
  background: transparent; color: var(--ink-soft); cursor: pointer;
  font-family: var(--sans); font-size: .52rem; font-weight: 400;
  letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
  transition: background .2s ease, color .2s ease;
}
.act:hover { background: var(--sage-50); color: var(--sage-700); }
.act svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
/* Muted state keeps the speaker and drops the waves, then crosses the whole
   icon, so it reads as "currently silent" without relying on the label. */
#soundBtn[aria-pressed="true"] .act__wave { display: none; }
#soundBtn { position: relative; }
#soundBtn[aria-pressed="true"]::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 20px; height: 1.6px; margin: -1px 0 0 -10px;
  background: currentColor; border-radius: 1px; rotate: -45deg;
}

/* ------------------------------------------------------------- decoration
   Discipline, because the previous version of this page was cluttered: every
   decoration below is absolutely positioned, non-interactive, and sits at
   z-index 0 with its content lifted to z-index 1. Nothing is ever placed on
   top of text, and no decoration can widen the page. */

.deco {
  position: absolute;
  pointer-events: none;
  user-select: none;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  z-index: 0;
}

/* toran — the marigold-and-scarf doorway hanging. In normal flow at the very
   top, not fixed, so it can never sit over the topbar. */
.deco--toran {
  position: relative;
  width: 100%;
  height: 64px;
  background-image: url("assets/toran.svg");
  background-size: 640px 64px;
  background-position: center top;
  z-index: 1;
}
@media (max-width: 700px) {
  .deco--toran { height: 48px; background-size: 480px 48px; }
}

/* the couple — generated artwork, 1100x614 (1.79:1), so it sits as a band
   anchored to the bottom of the hero card rather than flanking the names.
   A 1.79:1 image is too wide to place the figures either side of the type,
   so the composition puts the card's lower half over the picture and leaves
   the names and the kalash on clean card.

   The mask is the important part. Without it the band ends on a hard
   horizontal edge and reads as a pasted-in strip; fading the top out lets it
   dissolve into the card instead. The flat wash on top is what keeps the type
   legible where the two overlap. */
.deco--portrait {
  inset: auto 0 0 0;
  /* Left at the committed 58% deliberately. This is a share of the card, so
     raising it changes the image's size and crop — which is the thing that was
     asked to stay as-is. The visibility fix below is contrast, not scale. */
  height: 58%;
  background-image: url("assets/couple-portrait.jpg");
  background-size: cover;
  background-position: center bottom;
  background-repeat: no-repeat;
  /* Three separate layers were dimming this, and that is why raising `opacity`
     alone barely moved it. They compounded:
       1. element opacity          (.68)
       2. the mask ramp           (top 36% faded from transparent to opaque)
       3. the ::after white wash  (up to .9 white over the top 28%)
     At the vertical midpoint the mask was ~.9 and the wash ~.6, so a .68
     element resolved to roughly 35% of the photo over a white card. Each knob
     alone looked like the thing to turn, so each was turned alone.

     opacity is now the single overall-strength control and the other two are
     left alone: the fade is the mask's job, the type legibility is the wash's
     job. Turning one of them at a time is what finally made this tunable.

     .85. Fading the element also fades its ::after child, but that is harmless
     here because the top of the band is already protected twice over — the
     mask is `transparent` at 0% and the wash is solid --card there — so this
     mostly softens the lower half, which is the half meant to be seen. .8 and
     .9 are the next stops either way. */
  opacity: .85;
  /* Ramp is shorter and reaches full strength earlier, so more of the picture
     is seen at true contrast. The long soft ramp is what made the top half
     read as a gradient rather than a photograph. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, .5) 9%, #000 20%);
  mask-image: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, .5) 9%, #000 20%);
}
/* Protects the type zone, then gets out of the way. The opaque card colour is
   held only to 14% (was 28%) and the mid wash is much lighter (.3, was .42),
   because with the mask now reaching full strength at 20% there is far less
   fade underneath to hide behind. The type sits at the top of the band, which
   is exactly where this stays opaque. */
.deco--portrait::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    var(--card) 0%,
    rgba(255, 255, 255, .78) 14%,
    rgba(255, 255, 255, .3) 34%,
    transparent 58%);
}
@media (max-width: 700px) {
  .deco--portrait { height: 50%; }
}

/* mandala — watermark behind the names, the one place the hero earns texture */
.deco--mandala {
  inset: 0;
  background-image: url("assets/mandala.svg");
  background-size: min(78%, 330px);
  opacity: .07;
}

/* corner flourishes on the hero card */
.deco--corner {
  width: 76px; height: 76px;
  background-image: url("assets/corner.svg");
  background-size: contain;
  opacity: .3;
}
.deco--corner--tl { top: 12px;    left: 12px;   background-position: top left; }
.deco--corner--tr { top: 12px;    right: 12px;  background-position: top right; transform: scaleX(-1); }
.deco--corner--bl { bottom: 12px; left: 12px;   background-position: bottom left; transform: scaleY(-1); }
.deco--corner--br { bottom: 12px; right: 12px;  background-position: bottom right; transform: scale(-1); }
@media (max-width: 700px) {
  .deco--corner { width: 52px; height: 52px; opacity: .24; }
}

/* jali — lattice screen, the texture of a venue wall. Venue section only. */
.deco--jali {
  inset: 0;
  background-image: url("assets/jali.svg");
  background-size: 340px;
  background-position: center top;
  opacity: .09;
}

/* mandap — behind the Baraat, the one genuinely celebratory block */
.deco--mandap {
  inset: -10% 0;
  background-image: url("assets/mandap.svg");
  background-size: min(88%, 360px);
  opacity: .09;
}

/* hawa-arch — a delicate arch behind the verse, which is otherwise bare text */
.deco--arch {
  inset: 0;
  background-image: url("assets/hawa-arch.svg");
  background-size: min(52%, 240px);
  background-position: center top;
  opacity: .12;
}

/* diyas — a row of lit lamps above the footer, with a slow warm pulse */
.deco--diyas {
  position: relative;
  width: 100%;
  height: 72px;
  background-image: url("assets/diyas.svg");
  background-size: 520px 72px;
  background-position: center bottom;
  z-index: 1;
  animation: diya-glow 3.4s ease-in-out infinite;
}
@keyframes diya-glow { 0%, 100% { opacity: .82; } 50% { opacity: 1; } }

/* peacock — corner flourish on the footer */
.deco--peacock {
  width: 120px; height: 120px;
  background-image: url("assets/peacock.svg");
  background-size: contain;
  opacity: .12;
}
.deco--peacock--l { bottom: 4px; left: 4px; background-position: bottom left; }
.deco--peacock--r { bottom: 4px; right: 4px; background-position: bottom right; transform: scaleX(-1); }
@media (max-width: 700px) {
  .deco--diyas { height: 54px; background-size: 380px 54px; }
  .deco--peacock { width: 78px; height: 78px; opacity: .1; }
}

/* divider — a small ornament between the hero band and the families */
.deco--divider {
  position: relative;
  width: 150px; height: 26px;
  margin: 0 auto;
  background-image: url("assets/divider.svg");
  background-size: contain;
  z-index: 1;
  opacity: .8;
}

/* Any element holding a decoration must lift its own content above it. */
.hero__card > *:not(.deco),
.families > *:not(.deco),
.feature > *:not(.deco),
.section > *:not(.deco),
.section--verse > *:not(.deco),
.footer > *:not(.deco) { position: relative; z-index: 1; }

.hero__card, .families, .feature, .section, .section--verse, .footer { position: relative; overflow: hidden; }
/* .feature and the section rules already centre their own content; making them
   a clipping context must not change the box, so the ornaments bleed instead. */
.feature { isolation: isolate; }

/* ------------------------------------------------------------- responsive */
@media (max-width: 900px) {
  .event__venue { margin-left: 0; text-align: left; }
}

@media (max-width: 700px) {
  body { padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px)); }

  .hero { padding: 0 16px; margin-top: 20px; }
  /* Same top/bottom trade as desktop, lifted by a slightly smaller amount since
     the viewport is already tight here. */
  .hero__card { padding: 32px 22px 48px; border-radius: var(--r); }
  .hero__kalash { width: 42px; }
  .hero__names { font-size: clamp(2.2rem, 13vw, 3.1rem); gap: 2px 12px; }

  .countdown { padding: 60px 16px 16px; }
  .countdown__grid { grid-template-columns: repeat(2, 1fr); }
  /* two columns means the hairline must also run horizontally between rows */
  .count { border-bottom: 1px solid var(--line-soft); }
  .count:nth-child(odd)::before { display: none; }
  .count:nth-child(n+3) { border-bottom: 0; }

  .banner { padding: 44px 16px 4px; }

  .families { grid-template-columns: 1fr; gap: 26px; padding: 52px 18px 8px; }
  .family__divider { width: 100%; }

  .section { padding: 60px 16px; }

  .event { padding: 16px 18px; }
  .event:hover { transform: none; }
  .event__icon { width: 40px; height: 40px; }
  .event__icon .icon { width: 22px; height: 22px; }
  .event__time { flex: 1 1 auto; }
  /* The name takes the rest of the first row, the venue drops beneath it. */
  .event > div:nth-child(3) { flex: 1 1 100%; order: 3; }
  .event__venue { flex: 1 1 100%; order: 4; }

  .feature { padding: 8px 16px 4px; }
  .feature__title { font-size: 1.7rem; }

  .field-row { grid-template-columns: 1fr; }
  .rsvp-form { padding: 26px 18px; }

  .tab { min-width: 0; flex: 1 1 42%; padding: 12px 8px 14px; }
  .actions { gap: 2px; padding: 6px; bottom: calc(10px + env(safe-area-inset-bottom, 0px)); }
  .act { width: 54px; font-size: .46rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  /* Must come after the blanket rule above. `animation: none` would stop the
     intro's outro from ever running, leaving it opaque and click-eating on
     screen forever, so it is removed from the page entirely instead. */
  .intro { display: none !important; }
  /* The reveal hiding is a transition, which the blanket rule above has just
     disabled. Without this the observer would leave every section at opacity 0
     and the page would read as blank, so the end state is forced. */
  .js [data-reveal] { opacity: 1 !important; transform: none !important; }
}

@media print {
  .bg, .intro, .actions, .topbar, .hero__cta, .rsvp-form, .tabs, .saved,
  .deco, body::after { display: none !important; }
  body { background: #fff; padding-bottom: 0; }
  /* The `page-break-inside: avoid` that used to sit here was on .section, which
     covers the schedule, the family list and the cards — all of them several
     pages tall. An unsatisfiable break-inside is supposed to be dropped, but
     Chrome and Safari treat it greedily and push the whole block to the next
     page first, leaving large blank pages before the three tallest sections.
     Sections now flow, and the individual cards that should not be split are
     named explicitly instead. */
  .section { padding: 18px 0; }
  .contact, .logistic, .event, .venue, .count, .day-panel, .family {
    break-inside: avoid;
  }
  .contact, .logistic, .family {
    box-shadow: none; border-color: #ccc; background: #fff;
  }
  .hero__card { box-shadow: none; border: 1px solid #ddd; background: #fff; }
  .count, .event, .venue { box-shadow: none; border-color: #ccc; }
  .day-panel[hidden] { display: block !important; }
  .day-panel + .day-panel { margin-top: 26px; border-top: 1px solid #ddd; padding-top: 20px; }
  /* Nothing is animated on paper, so reveals must be pinned to their end state. */
  .js [data-reveal] { opacity: 1 !important; transform: none !important; }
}

/* ==========================================================================
   Family page additions — docs/family.html only.

   Scoped to classes that appear nowhere in index.html, so none of this can
   change the friends page. Every block is left-aligned: these are paragraphs
   to be read, not display type, and centring a three-line explanation makes
   the eye lose the start of the next one.
   ========================================================================== */

/* ------------------------------------------------- formal invitation */
.formal {
  max-width: 62ch; margin: 34px auto 0;
  text-align: center;
}
.formal__line {
  margin: 0 0 18px;
  font-size: clamp(.95rem, 2.4vw, 1.06rem);
  color: var(--ink-soft);
  line-height: 1.75;
}
/* The couple's names are the one line the page is built around, so they get
   the display face and the largest size here that is still below the hero. */
.formal__names {
  margin: 26px 0;
  font-family: var(--display);
  font-size: clamp(1.7rem, 6vw, 2.6rem);
  font-weight: 300;
  color: var(--blush-ink, var(--maroon));
  line-height: 1.2;
}
.formal__ask {
  margin: 0 0 20px;
  font-family: var(--display);
  font-size: clamp(1.05rem, 3vw, 1.3rem);
  font-style: italic;
  color: var(--ink);
  line-height: 1.65;
}
.formal__dates {
  margin: 0;
  font-size: .82rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-mute);
}
.formal__line:empty, .formal__names:empty, .formal__ask:empty,
.formal__dates:empty { display: none; }
.formal__note {
  max-width: 58ch; margin: 30px auto 0; padding-top: 22px;
  border-top: 1px solid var(--sage-100);
  font-size: .95rem; color: var(--ink-soft); line-height: 1.75; text-align: left;
}
.formal__note:empty { display: none; }

/* ----------------------------------------------------------- contacts */
.contacts {
  max-width: 720px; margin: 34px auto 0;
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  text-align: left;
}
.contact {
  padding: 20px 22px;
  background: rgba(255, 255, 255, .7);
  border: 1px solid var(--sage-100);
  border-radius: 4px;
}
.contact__name { margin: 0; font-size: 1.02rem; font-weight: 500; color: var(--ink); }
.contact__role { margin: 3px 0 0; font-size: .88rem; color: var(--ink-mute); }
.contact__about { margin: 8px 0 0; font-size: .9rem; color: var(--ink-soft); line-height: 1.6; }
.contact__phone {
  display: inline-block; margin-top: 10px;
  font-size: 1rem; color: var(--sage-700); text-decoration: none;
  border-bottom: 1px solid var(--sage-200);
}
.contact__phone:hover { border-bottom-color: var(--sage-700); }

/* ---------------------------------------------------------- logistics */
/* The practical details now sit inside Venue & Directions, so they are
   centred under the venue cards like the rest of the section, with their own
   heading to separate the two halves without needing a new section. */
.logistics-wrap { margin-top: 52px; }
.logistics-wrap .section__eyebrow { margin-bottom: 12px; }
.section__subtitle {
  margin: 0 0 8px;
  font-family: var(--display); font-weight: 500;
  font-size: clamp(1.4rem, 3vw, 1.8rem); color: var(--ink);
  text-align: center;
}
.logistics {
  max-width: 760px; margin: 34px auto 0;
  display: grid; gap: 20px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  text-align: left;
}
.logistic {
  padding: 22px 24px;
  background: var(--butter);
  border-radius: 4px;
  border: 1px solid rgba(200, 162, 39, .3);
}
.logistic__title {
  margin: 0 0 8px;
  font-family: var(--display);
  font-size: 1.15rem; font-weight: 500; color: var(--maroon);
}
.logistic__text { margin: 0; font-size: .93rem; color: var(--ink-soft); line-height: 1.7; }
.logistic__link { margin-top: 14px; display: inline-block; }

/* --------------------------------------------------------- responsive */
@media (max-width: 700px) {
}

/* The family note is the one block that is likely to be pasted from a
   relative's own notes and run long, so it wraps rather than being clipped. */
.formal__note, .logistic__text {
  overflow-wrap: break-word;
}

@media print {
  /* A relative may print this to take with them. Keep the practical details
     and drop the ornament and the RSVP form, as index.html already does. */
  .contact, .logistic { box-shadow: none; border-color: #ccc; background: #fff; }
}

/* ============================================================ parents (labelled)
   Father and mother are on their own lines with a small role label, instead of
   one joined string. The label is what makes the pair readable: "Father
   Randhir" and "Mother Kamla" cannot be misread the way "Randhir & Kamla" can
   when a guest is checking who is hosting them. */
.family__names { display: flex; flex-direction: column; gap: .3rem; }
.family__names:empty { display: none; }
.family__line { display: flex; align-items: baseline; justify-content: center; gap: .45rem; }
.family__role {
  font-family: var(--body);
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  flex: 0 0 auto;
}
.family__name { font-family: var(--display); font-size: 1.3rem; font-weight: 500; color: var(--ink); }

/* ============================================ eagerly awaiting your presence
   The named relatives. Grouped by side and set as a list of names with the
   relation underneath, which is how this appears on a printed card -- the
   relation is the useful part, and it is smaller than the name on purpose. */
.awaiting__note {
  font-family: var(--body);
  font-size: .95rem;
  color: var(--ink-soft);
  text-align: center;
  margin: -.4rem 0 1.4rem;
}
/* The 38px top margin matches the card lists above, so the gap under a section
   title reads the same going down the page. Without it the names butted
   straight up against "Eagerly Awaiting Your Presence". */
.awaiting { display: flex; flex-direction: column; gap: 1.6rem; align-items: center; margin: 38px auto 0; }
.awaiting__group { text-align: center; }
.awaiting__side {
  font-family: var(--body);
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 .7rem;
}
.awaiting__names { list-style: none; margin: 0; padding: 0; }
.awaiting__person { margin: 0 0 .85rem; break-inside: avoid; }
.awaiting__person:last-child { margin-bottom: 0; }
.awaiting__name { display: block; font-family: var(--display); font-size: 1.15rem; font-weight: 500; color: var(--ink); overflow-wrap: break-word; }
.awaiting__detail { display: block; font-size: .8rem; color: var(--ink-soft); margin-top: .1rem; overflow-wrap: break-word; }

/* A real list of relatives runs to fifteen or twenty names, which as one tall
   column is a lot of scrolling for a section nobody needs to read closely.
   Above the phone breakpoint it flows into balanced columns instead, and each
   name stays whole rather than being split across a column break. */
@media (min-width: 34rem) {
  .awaiting__group { max-width: 46rem; }
  .awaiting__names { columns: 2; column-gap: 2.4rem; }
  .awaiting__person { display: inline-block; width: 100%; }
}
@media (min-width: 60rem) {
  /* The group has to widen along with the column count. Left at 46rem, the
     third column was bought by making all three about a third narrower than
     the two above it, and the longest name in the list ran to 91% of the
     column. body clips overflow rather than scrolling it, so a long name was
     cut off mid-word with no way to reach the rest. */
  .awaiting__group { max-width: 64rem; }
  .awaiting__names { columns: 3; }
}
