/* ═══════════════════════════════════════════════════════════
   Maharani · vowstory Shubharambh

   ⚠️ REBUILT on 11 September 2026 from the co-founder's redesign.
   The tokens, the typography and every section's treatment are his;
   what this repository adds is the config pipeline, and in this file
   that is only the small block at the very bottom marked
   "config-driven states". Everything above it is the design.

   ⚠️ Two things were corrected on the way in and are marked ⚠️ where
   they occur: the margin borders (fetched by phones that never show
   them) and the dress-code grid (a track held open for a cell that is
   not there). Both are in decision 0047.

   Utsav's designs keep their original stylesheet and take the redesign
   as a three-way merge; this tier's redesigns replace the sheet
   outright, because the pipeline's share of it is three rules.
   ═══════════════════════════════════════════════════════════ */

/* ⚠️ SELF-HOSTED FONTS. The Google Fonts <link> came out of index.html with
   this redesign — an invitation is opened by a guest who never agreed to
   anything, and that stylesheet made their browser announce itself to a third
   party before the first paint. 92 KB of woff2 we serve ourselves instead.
   ⚠️ Every family named anywhere below must have a rule here. A family with
   no @font-face falls back to a system serif silently: the page looks
   slightly wrong rather than broken, which is how it survives review. */
@font-face {
  font-family: "Bodoni Moda";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(assets/fonts/bodoni-moda-latin-400-normal.woff2) format("woff2");
}
@font-face {
  font-family: "Bodoni Moda";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(assets/fonts/bodoni-moda-latin-500-normal.woff2) format("woff2");
}
@font-face {
  font-family: "Lora";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(assets/fonts/lora-latin-400-normal.woff2) format("woff2");
}
@font-face {
  font-family: "Lora";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(assets/fonts/lora-latin-400-italic.woff2) format("woff2");
}
@font-face {
  font-family: "Tenor Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(assets/fonts/tenor-sans-latin-400-normal.woff2) format("woff2");
}

:root {
  --sand: #f4f0e4;
  --shell: #e9e2d0;
  --paper: #fbf8ef;
  --green: #2c4a38;
  --green-deep: #1c3226;
  --gold: #ae8b4a;
  --gold-deep: #876a32;
  --gold-dim: rgba(174, 139, 74, 0.4);
  --cream: #f3ecd7;
  --cream-soft: #c7bb98;
  --ink: #3b463a;
  --ink-soft: #7c7a64;
  --sage: #7e8a6a;
  --col: 480px;
  --pad: 28px;
  --gap: 80px;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --disp: "Bodoni Moda", Georgia, serif;
  --label: "Tenor Sans", sans-serif;
  --body: "Lora", Georgia, serif;
}
* {
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--shell);
  color: var(--ink);
  font-family: var(--body);
  font-size: 16.5px;
  line-height: 1.78;
  -webkit-font-smoothing: antialiased;
}
img {
  max-width: 100%;
  display: block;
}
sup {
  font-size: 0.58em;
  vertical-align: 0.5em;
}
body:not(.open) {
  overflow: hidden;
  height: 100%;
}

#page {
  max-width: var(--col);
  margin: 0 auto;
  background: var(--sand);
  overflow: clip;
  box-shadow: 0 0 80px rgba(28, 50, 38, 0.18);
  opacity: 0;
  transition: opacity 0.9s var(--ease);
  position: relative;
  z-index: 2;
}
body.open #page {
  opacity: 1;
}

/* ⚠️ Printed margin borders, shown only from 1180px up. These arrived as two
   <img> tags with display:none below that width. Every browser fetches a
   display:none image, so every phone — which never shows them — paid for
   1.5 MB. They are CSS background-images declared INSIDE the media query
   instead, which is fetched only when the query matches.
   The geometry is unchanged: height:100vh with background-size contain in a
   23vw box resolves to the same painted box as width:auto on an <img> did. */
.edge {
  display: none;
  position: fixed;
  top: 0;
  height: 100vh;
  width: 23vw;
  max-width: 23vw;
  opacity: 0.94;
  pointer-events: none;
  z-index: 1;
  background-repeat: no-repeat;
  background-size: contain;
}
.edge-l {
  left: 0;
  background-position: left center;
}
.edge-r {
  right: 0;
  background-position: right center;
}
@media (min-width: 1180px) {
  .edge {
    display: block;
  }
  .edge-l {
    background-image: url(assets/elements/border-l.webp);
  }
  .edge-r {
    background-image: url(assets/elements/border-r.webp);
  }
}

/* ── cover ── */
#cover {
  position: fixed;
  inset: 0;
  z-index: 90;
  max-width: var(--col);
  margin: 0 auto;
  background: radial-gradient(120% 90% at 50% 32%, var(--shell), #dcd3bc);
  overflow: hidden;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  isolation: isolate;
}
.door {
  position: absolute;
  top: 0;
  height: 100%;
  width: 50.4%;
  background: radial-gradient(140% 120% at 50% 30%, var(--shell), #dcd3bc);
  transition: transform 1.35s var(--ease);
  will-change: transform;
}
.door-l {
  left: 0;
}
.door-r {
  right: 0;
}
.door .panel {
  position: absolute;
  inset: 26px 0;
  border-top: 1px solid var(--gold-dim);
  border-bottom: 1px solid var(--gold-dim);
}
.door-l .panel {
  left: 26px;
  right: 0;
  border-left: 1px solid var(--gold-dim);
}
.door-r .panel {
  right: 26px;
  left: 0;
  border-right: 1px solid var(--gold-dim);
}
.seam {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  background: linear-gradient(
    180deg,
    transparent,
    var(--gold-dim) 12%,
    var(--gold-dim) 88%,
    transparent
  );
  transform: translateX(-50%);
  transition: opacity 0.5s ease;
}
body.opening .door-l {
  transform: translateX(-101%);
}
body.opening .door-r {
  transform: translateX(101%);
}
body.opening .seam,
body.opening .cover-inner {
  opacity: 0;
}
body.opened #cover {
  display: none;
}
.cover-inner {
  position: relative;
  z-index: 2;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  transition: opacity 0.45s ease;
  padding: 20px;
}
.cover-frame {
  position: absolute;
  inset: 16px;
  border: 1px solid rgba(174, 139, 74, 0.6);
  box-shadow:
    inset 0 0 0 5px rgba(233, 226, 208, 0.5),
    inset 0 0 0 6px rgba(174, 139, 74, 0.34);
  z-index: 0;
}
.cover-frame::before,
.cover-frame::after {
  content: "";
  position: absolute;
  left: 50%;
  width: 9px;
  height: 9px;
  background: var(--green);
  transform: translateX(-50%) rotate(45deg);
}
.cover-frame::before {
  top: -5px;
}
.cover-frame::after {
  bottom: -5px;
}
.tap-open {
  position: relative;
  z-index: 1;
  font-family: var(--disp);
  font-weight: 500;
  font-size: clamp(26px, 7.4vw, 36px);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  background: linear-gradient(
    100deg,
    #6b5326 0%,
    #ae8b4a 30%,
    #e7d6a6 48%,
    #c7a860 56%,
    #876a32 74%,
    #6b5326 100%
  );
  background-size: 230% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  filter: drop-shadow(0 2px 7px rgba(44, 74, 56, 0.18));
  animation:
    shine 3.2s linear infinite,
    tapbob 2.1s var(--ease) infinite;
}
.tap-hint {
  position: relative;
  z-index: 1;
  color: var(--green);
  animation: tapbob 2.1s var(--ease) infinite;
  animation-delay: 0.12s;
  opacity: 0.7;
}
.tap-hint svg {
  width: 24px;
  height: 24px;
  display: block;
}
@keyframes shine {
  to {
    background-position: 230% 0;
  }
}
@keyframes tapbob {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-9px);
  }
}

/* ── music ── */
.music {
  position: fixed;
  top: 16px;
  z-index: 80;
  right: max(16px, calc(50vw - var(--col) / 2 + 16px));
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: rgba(251, 248, 239, 0.9);
  border: 1px solid rgba(174, 139, 74, 0.5);
  backdrop-filter: blur(6px);
  display: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  color: var(--green);
  transition: transform 0.25s var(--ease);
}
body.open .music {
  display: flex;
  animation: fadein 0.8s 0.5s backwards;
}
.music:hover {
  transform: scale(1.07);
}
.music svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
  stroke: currentColor;
}
.music .ic-off {
  display: none;
}
.music[aria-pressed="false"] .ic-on {
  display: none;
}
.music[aria-pressed="false"] .ic-off {
  display: block;
}
@keyframes fadein {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* ── hero (Hero 1, light centre) ── */
.hero {
  position: relative;
  background: var(--sand);
}
.hero-art {
  position: relative;
  min-height: 100svh;
  background: url(assets/hero.webp) center top/cover no-repeat;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 9vh 34px 22vh;
}
.hero-art::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    /* ⚠️ The PEAK is the redesign's; the FALLOFF is not. At 834px the names
       widen into a lit part of the artwork that the shipped stops had already
       let go — 0.05 opacity by 76% of the radius — and the couple's names
       measured 2.98:1 there against the 3.0:1 large text needs, where the
       pre-redesign hero gave 6.14. The centre is untouched; the veil is only
       held open further out.
       ⚠️ It fails at 834 and NOT at 390: the names widen into the bright part
       of the frame as the column grows, so a phone-only check passes. */
    radial-gradient(
      ellipse 96% 62% at 50% 42%,
      rgba(18, 36, 27, 0.66) 0%,
      rgba(18, 36, 27, 0.56) 48%,
      rgba(18, 36, 27, 0.34) 74%,
      rgba(18, 36, 27, 0.1) 90%,
      rgba(18, 36, 27, 0) 100%
    ),
    linear-gradient(
      180deg,
      rgba(18, 36, 27, 0.4) 0%,
      rgba(18, 36, 27, 0) 26%,
      rgba(18, 36, 27, 0) 70%,
      rgba(18, 36, 27, 0.5) 94%
    );
}
.hero-body {
  position: relative;
  text-align: center;
  width: 100%;
  max-width: 520px;
}
.ganesh {
  width: clamp(108px, 28%, 152px);
  margin: 0 auto 6px;
  filter: drop-shadow(0 6px 16px rgba(44, 74, 56, 0.16));
}
.invocation {
  margin: 0 0 14px;
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--gold-deep);
}
.hero-eyebrow {
  margin: 0 0 12px;
  font-family: var(--label);
  font-size: 10.5px;
  letter-spacing: 0.38em;
  text-transform: uppercase;
  color: var(--cream-soft);
}
.hero-names {
  margin: 0;
  font-family: var(--disp);
  font-weight: 500;
  font-size: clamp(42px, 12vw, 78px);
  line-height: 1.06;
  letter-spacing: 0.005em;
}
.hero-names span {
  display: block;
  background: linear-gradient(96deg, #efe7ce 22%, #e7cf92 50%, #efe7ce 78%);
  background-size: 230% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: shine 6.5s linear infinite;
}
.hero-names em {
  display: block;
  font-family: var(--label);
  font-style: normal;
  font-size: 0.2em;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 10px 0 8px;
  text-indent: 0.42em;
}
.hair {
  display: block;
  width: min(200px, 54%);
  height: 1px;
  margin: 18px auto;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
}
.hair-sm {
  display: block;
  width: min(120px, 44%);
  height: 1px;
  margin: 10px 0 14px;
  background: linear-gradient(90deg, var(--gold), transparent);
}
.hero-date {
  margin: 0 0 10px;
  font-family: var(--label);
  font-size: clamp(13px, 3.2vw, 17px);
  letter-spacing: 0.18em;
  color: var(--gold);
  text-transform: uppercase;
}
.hero-venue {
  margin: 0;
  font-size: clamp(15px, 3.3vw, 18px);
  font-style: italic;
  color: var(--cream);
  line-height: 1.5;
}
.hero-venue span {
  display: inline-block;
  font-style: normal;
  font-size: 0.82em;
  letter-spacing: 0.06em;
  color: var(--cream-soft);
  margin-top: 2px;
}
body.open .hero-body > * {
  animation: heroIn 1.1s var(--ease) backwards;
}
body.open .hero-body > *:nth-child(1) {
  animation-delay: 0.45s;
}
body.open .hero-body > *:nth-child(2) {
  animation-delay: 0.57s;
}
body.open .hero-body > *:nth-child(3) {
  animation-delay: 0.69s;
}
body.open .hero-body > *:nth-child(4) {
  animation-delay: 0.81s;
}
body.open .hero-body > *:nth-child(5) {
  animation-delay: 0.93s;
}
body.open .hero-body > *:nth-child(6) {
  animation-delay: 1.05s;
}
body.open .hero-body > *:nth-child(7) {
  animation-delay: 1.17s;
}
@keyframes heroIn {
  from {
    opacity: 0;
    transform: translateY(24px);
    filter: blur(6px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: none;
  }
}

.scroll-cue {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 24px;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  transition:
    opacity 0.5s ease,
    transform 0.5s ease;
  pointer-events: none;
}
.cue-word {
  font-family: var(--label);
  font-size: 10px;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--cream-soft);
}
.cue-chev {
  color: var(--gold);
  animation: bob 1.6s ease-in-out infinite;
}
.cue-chev svg {
  width: 28px;
  height: 28px;
  display: block;
}
@keyframes bob {
  0%,
  100% {
    transform: translateY(0);
    opacity: 0.55;
  }
  50% {
    transform: translateY(7px);
    opacity: 1;
  }
}
.scroll-cue.gone {
  opacity: 0;
  transform: translateY(10px);
}

/* ── shared ── */
.sec {
  padding: var(--gap) var(--pad);
  position: relative;
  overflow: clip;
  isolation: isolate;
  background: var(--sand);
}
.sec > *:not(.deco),
.foot > *:not(.deco) {
  position: relative;
  z-index: 1;
}
.spine {
  border-left: 1px solid var(--gold-dim);
  padding-left: clamp(18px, 5vw, 30px);
}
.eyebrow {
  margin: 0 0 12px;
  font-family: var(--label);
  font-size: 10.5px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.h2 {
  margin: 0 0 20px;
  font-family: var(--disp);
  font-weight: 500;
  font-size: clamp(28px, 6.8vw, 46px);
  line-height: 1.18;
  color: var(--green);
}
.h2-sm {
  font-size: clamp(25px, 5.6vw, 36px);
}
.prose {
  margin: 0 0 16px;
  max-width: 38ch;
  color: var(--ink);
}
.plate-body .prose {
  margin-left: auto;
  margin-right: auto;
}
.tag {
  margin: 26px 0 0;
  font-family: var(--label);
  font-size: clamp(12px, 2.4vw, 15px);
  letter-spacing: 0.24em;
  color: var(--gold-deep);
}
.tag-sm {
  font-size: 11px;
  letter-spacing: 0.3em;
  margin-top: 14px;
}
/* on-dark variants */
.eyebrow-on {
  color: var(--gold);
}
.h2-on {
  color: var(--cream);
}
.prose-on {
  color: var(--cream-soft);
}

.reveal {
  opacity: 0;
  transform: translateY(28px) scale(0.99);
  filter: blur(6px);
  transition:
    opacity 1.05s var(--ease),
    transform 1.05s var(--ease),
    filter 1.05s var(--ease);
}
.reveal.in {
  opacity: 1;
  transform: none;
  filter: none;
}
.deco {
  position: absolute;
  pointer-events: none;
  z-index: 0;
}

/* ── plates (Hero-2 invite) ── */
.plate {
  position: relative;
  isolation: isolate;
}
.plate-invite {
  background: url(assets/hero2.webp) center top/cover no-repeat;
}
/* ⚠️ THE VEIL IS THE ONLY THING HOLDING THIS SECTION'S COPY ABOVE
   THRESHOLD, and these are not the stops the redesign shipped. Those peaked
   low and fell away fast — measured on the two family columns at 834px, where
   they sit at the outer edges of the plate and the veil has almost run out,
   the parents' line came back well under the 4.5:1 small text needs.
   ⚠️ Widening a veil is not the same as strengthening it: peak opacity is the
   limit, not extent. These stops were set by measurement and still reach zero
   at the edge so the painted border reads.
   ⚠️ Re-export the artwork and they have to be measured again. */
.plate-invite::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    ellipse 106% 96% at 50% 48%,
    rgba(244, 240, 228, 0.94) 0%,
    rgba(244, 240, 228, 0.89) 44%,
    rgba(244, 240, 228, 0.7) 72%,
    rgba(244, 240, 228, 0.24) 88%,
    rgba(244, 240, 228, 0) 100%
  );
}
.plate-body {
  position: relative;
  padding: calc(var(--gap) + 10px) var(--pad);
  text-align: center;
  min-height: clamp(520px, 90vw, 680px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.seal-wrap {
  position: relative;
  width: min(122px, 32%);
  margin: 0 auto 20px;
  aspect-ratio: 1;
}
.seal-ring {
  position: absolute;
  inset: -8px;
  border-radius: 50%;
  border: 1px solid rgba(174, 139, 74, 0.6);
  box-shadow:
    0 0 0 5px var(--sand),
    0 0 0 6px var(--gold-dim);
  z-index: 1;
}
.seal {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.4);
}

/* ── countdown (emerald panel) ── */
.sec-count {
  background: var(--green);
  text-align: center;
}
.deco-vase {
  width: clamp(96px, 24vw, 150px);
  right: -24px;
  bottom: -14px;
  opacity: 0.9;
}
.sec-count .tag {
  color: var(--gold);
}
.clock {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  max-width: 400px;
  margin: 26px auto 0;
}
.unit {
  padding: 18px 4px 14px;
  background: var(--green-deep);
  border: 1px solid rgba(174, 139, 74, 0.4);
}
.unit b {
  display: block;
  font-family: var(--disp);
  font-weight: 500;
  font-size: clamp(23px, 6vw, 34px);
  color: var(--gold);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.unit i {
  display: block;
  margin-top: 9px;
  font-style: normal;
  font-size: 9.5px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--cream-soft);
  font-family: var(--label);
}

/* ── union block ── */
.weds {
  margin: 34px auto 0;
  max-width: 560px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-family: var(--disp);
  font-size: clamp(20px, 4.6vw, 28px);
  line-height: 1.25;
  color: var(--green);
  text-align: center;
}
.weds em {
  font-family: var(--label);
  font-style: normal;
  font-size: 0.42em;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--gold-deep);
  display: flex;
  align-items: center;
  gap: 12px;
  text-indent: 0.34em;
}
.weds em::before,
.weds em::after {
  content: "";
  width: 32px;
  height: 1px;
  background: var(--gold-dim);
}
.side {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.side-name {
  margin: 0 0 9px;
  line-height: 1.2;
}
.side-role {
  margin: 0 0 6px;
  font-family: var(--label);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.side-parents {
  margin: 0;
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink);
  max-width: 26ch;
}
.weds-on {
  color: var(--gold);
}
.weds-on em {
  color: var(--cream-soft);
}
.weds-on em::before,
.weds-on em::after {
  background: rgba(233, 220, 180, 0.4);
}
.weds-on .side-role {
  color: var(--cream-soft);
}
.weds-on .side-parents {
  color: var(--cream);
}
@media (min-width: 640px) {
  .weds {
    flex-direction: row;
    justify-content: center;
    gap: clamp(20px, 4vw, 38px);
    align-items: flex-start;
  }
  .side {
    flex: 1;
    max-width: 300px;
  }
  .weds em {
    margin-top: 10px;
    flex: none;
  }
}

/* ── events (alternating rows) ── */
.row {
  display: grid;
  gap: 20px;
  margin-top: 34px;
  align-items: center;
}
.row-art {
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 1px solid rgba(174, 139, 74, 0.4);
  aspect-ratio: 1;
}
.row-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.row-title {
  margin: 0;
  font-family: var(--disp);
  font-weight: 500;
  font-size: clamp(28px, 6.4vw, 40px);
  color: var(--green);
  line-height: 1;
}
.row-when {
  margin: 0 0 3px;
  font-family: var(--label);
  font-size: clamp(12.5px, 2.8vw, 15px);
  letter-spacing: 0.14em;
  color: var(--gold-deep);
  text-transform: uppercase;
}
.row-time {
  margin: 0 0 14px;
  font-style: italic;
  color: var(--ink-soft);
}
.row-venue {
  margin: 0 0 16px;
  line-height: 1.5;
  color: var(--ink);
}
.row-venue span {
  font-size: 0.85em;
  color: var(--ink-soft);
}
/* Dress code and note, two labelled cells under an event. New with the
   redesign; there was one italic line before it.
   ⚠️ The columns are generated per cell, NOT declared as `1fr 1fr` as they
   arrived. Most couples fill in one of the two, and a declared pair of tracks
   stays open whether or not anything is in it — the lone cell would sit at
   half width beside a hole. `grid-auto-flow: column` with
   `grid-auto-columns: 1fr` makes one track per cell that exists. */
.card-meta {
  margin: 0 0 20px;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 10px;
  max-width: 360px;
}
.card-meta > div {
  background: var(--paper);
  border: 1px solid rgba(174, 139, 74, 0.3);
  padding: 8px 12px;
  min-width: 0;
}
.card-meta dt {
  font-family: var(--label);
  font-size: 9px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.card-meta dd {
  margin: 3px 0 0;
  font-size: 14px;
  color: var(--ink);
}
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 24px;
  border: 1px solid rgba(174, 139, 74, 0.6);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--green);
  text-decoration: none;
  background: var(--paper);
  transition:
    background 0.3s ease,
    color 0.3s ease,
    border-color 0.3s ease;
}
.btn:hover {
  background: var(--green);
  color: var(--cream);
  border-color: var(--green);
}
.btn svg {
  width: 15px;
  height: 15px;
  stroke: currentColor;
  fill: none;
}

/* ── gallery ── */
.sec-gallery {
  background: var(--shell);
}
.frame-wrap {
  position: relative;
  width: min(420px, 94%);
  margin: 28px auto 0;
  aspect-ratio: 1;
}
.photo-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 3;
  filter: drop-shadow(0 12px 26px rgba(28, 50, 38, 0.16));
}
.slides {
  position: absolute;
  inset: 18.5% 18% 15.6% 18%;
  overflow: hidden;
  z-index: 1;
  background: var(--paper);
  border-radius: 3px;
}
.slide-track {
  display: flex;
  height: 100%;
  transition: transform 0.6s var(--ease);
}
.slide {
  margin: 0;
  flex: 0 0 100%;
  height: 100%;
  position: relative;
}
.slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ph {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--label);
  font-size: 9.5px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold-deep);
  border: 1px solid rgba(174, 139, 74, 0.45);
  padding: 4px 12px;
  background: rgba(251, 248, 239, 0.9);
  white-space: nowrap;
  z-index: 2;
}
.nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  background: rgba(251, 248, 239, 0.94);
  border: 1px solid rgba(174, 139, 74, 0.45);
  color: var(--green);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 4;
}
.nav svg {
  width: 15px;
  height: 15px;
  stroke: currentColor;
  fill: none;
}
.prev {
  left: calc(18% - 17px);
}
.next {
  right: calc(18% - 17px);
}
.dots {
  display: flex;
  justify-content: center;
  gap: 7px;
  margin-top: 20px;
}
.dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  background: transparent;
  border: 1px solid var(--gold);
  transition: background 0.3s ease;
}
.dot[aria-current="true"] {
  background: var(--gold);
}

/* ── venue ── */
.deco-gazebo {
  width: min(160px, 40vw);
  right: -14px;
  bottom: -8px;
  opacity: 0.5;
}
.venue-name {
  margin: 0 0 6px;
  font-family: var(--label);
  font-size: clamp(15px, 3.2vw, 19px);
  color: var(--green);
  letter-spacing: 0.04em;
}
.venue-addr {
  margin: 0 0 24px;
  color: var(--ink-soft);
}
.mapcard {
  display: flex;
  align-items: center;
  gap: 16px;
  text-decoration: none;
  color: var(--ink);
  padding: 18px 20px;
  background: var(--paper);
  border: 1px solid rgba(174, 139, 74, 0.45);
  max-width: 520px;
  margin: 6px auto 0;
  text-align: left;
  transition:
    border-color 0.3s ease,
    transform 0.3s var(--ease);
}
.mapcard:hover {
  border-color: var(--gold);
  transform: translateY(-2px);
}
.mapcard-pin,
.mapcard-go {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold-deep);
}
.mapcard-pin svg {
  width: 26px;
  height: 26px;
  stroke: currentColor;
  fill: none;
}
.mapcard-go svg {
  width: 17px;
  height: 17px;
  stroke: currentColor;
  fill: none;
}
.mapcard-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  font-family: var(--body);
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.5;
}
.mapcard-text b {
  font-family: var(--label);
  font-weight: 400;
  font-size: 13px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--green);
  margin-bottom: 3px;
}
.route {
  margin: 30px auto 2px;
  width: min(330px, 86%);
}
.route-svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}

/* ── rsvp (emerald panel) ── */
.sec-rsvp {
  background: var(--green);
  text-align: center;
  overflow: clip;
}
.deco-lotus {
  width: clamp(88px, 22vw, 128px);
  right: -18px;
  bottom: -16px;
  opacity: 0.9;
}
.rsvp {
  display: grid;
  gap: 12px;
  margin-top: 24px;
  max-width: 520px;
  margin-inline: auto;
  width: 100%;
}
.chip {
  display: flex;
  align-items: center;
  gap: 14px;
  text-align: left;
  padding: 14px 20px;
  background: rgba(251, 248, 239, 0.94);
  border: 1px solid rgba(174, 139, 74, 0.4);
  text-decoration: none;
  color: var(--ink);
  transition:
    border-color 0.3s ease,
    transform 0.3s var(--ease);
}
.chip:hover {
  border-color: var(--gold);
  transform: translateY(-2px);
}
.chip svg {
  width: 23px;
  height: 23px;
  flex: none;
  stroke: var(--green);
  fill: var(--green);
}
.chip span {
  display: flex;
  flex-direction: column;
  font-size: 0.85em;
  color: var(--ink-soft);
}
.chip b {
  font-family: var(--label);
  font-weight: 400;
  font-size: 1.1em;
  color: var(--green);
}

/* ── footer ── */
.foot {
  background: var(--sand);
  padding: calc(var(--gap) - 8px) var(--pad) 34px;
  text-align: center;
  position: relative;
  overflow: clip;
  border-top: 1px solid var(--gold-dim);
}
.foot-orn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: min(216px, 58%);
  margin: 0 auto 24px;
}
.foot-orn i {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold));
}
.foot-orn i:last-child {
  background: linear-gradient(90deg, var(--gold), transparent);
}
.foot-orn b {
  width: 7px;
  height: 7px;
  transform: rotate(45deg);
  background: var(--green);
  flex: none;
}
.foot-candles {
  width: min(196px, 54%);
  margin: 8px auto 20px;
  display: block;
  filter: drop-shadow(0 6px 20px rgba(174, 139, 74, 0.22));
}
.foot-line {
  margin: 0 0 6px;
  font-style: italic;
  color: var(--ink-soft);
}
.foot-names {
  margin: 0;
  font-family: var(--disp);
  font-weight: 500;
  font-size: clamp(30px, 7vw, 44px);
  color: var(--green);
}
.ig {
  display: flex;
  width: max-content;
  align-items: center;
  gap: 8px;
  margin: 20px auto 0;
  text-decoration: none;
  color: var(--ink-soft);
  font-size: 0.85em;
  letter-spacing: 0.04em;
  transition: color 0.3s ease;
}
.ig:hover {
  color: var(--green);
}
.ig svg {
  width: 19px;
  height: 19px;
  stroke: currentColor;
  fill: currentColor;
}
.made {
  display: flex;
  width: max-content;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin: 38px auto 0;
  text-decoration: none;
  opacity: 0.9;
  transition: opacity 0.3s ease;
}
.made:hover {
  opacity: 1;
}
.made span {
  font-family: var(--label);
  font-size: 9.5px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.made img {
  width: 98px;
}

/* ── scale up ── */
@media (min-width: 600px) {
  :root {
    --col: 620px;
    --pad: 48px;
    --gap: 96px;
  }
  body {
    font-size: 17.5px;
  }
  .hero-art {
    padding: 9vh 58px 20vh;
  }
  .row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.12fr);
    gap: 28px;
    align-items: start;
  }
  .row-flip .row-art {
    order: 2;
  }
  .row-flip .row-body {
    order: 1;
  }
  .row-flip {
    text-align: right;
  }
  .row-flip .hair-sm {
    margin-left: auto;
    background: linear-gradient(90deg, transparent, var(--gold));
  }
  .row-flip .card-meta {
    margin-left: auto;
  }
}
@media (min-width: 960px) {
  :root {
    --col: 800px;
    --pad: 70px;
    --gap: 114px;
  }
  body {
    font-size: 18.5px;
  }
  .music {
    width: 46px;
    height: 46px;
    top: 22px;
  }
  .hero-art {
    background-position: center 16%;
  }
  .sec-gallery {
    display: grid;
    grid-template-columns: 1fr 1.05fr;
    gap: 44px;
    align-items: center;
  }
  .sec-gallery .spine {
    align-self: center;
  }
  .frame-wrap {
    grid-column: 2;
    grid-row: 1 / span 2;
    margin-top: 0;
  }
  .sec-gallery .dots {
    grid-column: 2;
  }
}
@media (min-width: 1400px) {
  :root {
    --col: 880px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .reveal {
    opacity: 1;
    transform: none;
    filter: none;
  }
  .hero-names span,
  .tap-open {
    -webkit-text-fill-color: var(--green);
    color: var(--green);
  }
}
:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
}

/* ── hosted by ── */
.hosted {
  margin: 32px auto 0;
  text-align: center;
  max-width: 440px;
}
.hosted-rule {
  display: block;
  width: 46px;
  height: 1px;
  margin: 0 auto 14px;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
}
.hosted-label {
  margin: 0 0 6px;
  font-family: var(--label);
  font-weight: 400;
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
.hosted-names {
  margin: 0;
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.65;
  color: var(--ink);
}

/* ══ config-driven states ══════════════════════════════════════════════════
   Everything below this line belongs to the repository's rendering pipeline,
   not to the design. It is what has to be re-applied whenever a redesign
   replaces this sheet. */

/* Slots the config left empty are hidden with [hidden]; several of them are
   flex or grid, so the attribute needs to win over the class. */
[hidden] {
  display: none !important;
}

/* Blessings with no artwork of their own fall back to their glyph, set at the
   same weight as the Ganesha crop it replaces.
   ⚠️ Since 11 September 2026 (decision 0048) every blessing in the catalogue
   ships its own drawing, so the config sends `symbol: null` and NOTHING lands
   here any more. The rule stays as the fallback for a blessing added later
   with no artwork drawn for it yet — without it that one would print at the
   browser's default size in a system serif. */
.glyph {
  margin: 0 0 8px;
  font-family: var(--disp);
  font-size: clamp(40px, 10vw, 58px);
  line-height: 1;
  color: var(--gold);
}

/* The reply chip's second line is an <i> because the blueprint has two text
   slots and only one of them is ever a name. */
.chip i {
  font-style: normal;
}
