/* Invitation design system — Contemporary Nusantara Luxury.

   Every colour comes from the recipe, injected as CSS variables by the template. This
   stylesheet owns composition: the cover, the section skeleton, and the hard rule that no
   ornament may cross a line of text. Cultural identity lives in the recipe (motif, palette,
   frame); the concept decides how the page is built. */

@font-face {
  font-family: 'Fraunces'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/static/fonts/fraunces-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Fraunces'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/static/fonts/fraunces-latin-500-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Fraunces'; font-style: italic; font-weight: 400; font-display: swap;
  src: url('/static/fonts/fraunces-latin-400-italic.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/static/fonts/inter-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/static/fonts/inter-latin-500-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/static/fonts/inter-latin-600-normal.woff2') format('woff2');
}

/* --- concept typefaces. Each concept gets its own display family, not a size tweak.
   All three are SIL OFL, latin subset, and cover the Indonesian alphabet. --- */
@font-face {
  font-family: 'Playfair Display'; font-style: normal; font-weight: 400 600;
  font-display: swap; src: url('/static/fonts/playfair-display-latin-var.woff2') format('woff2');
}
@font-face {
  font-family: 'Lora'; font-style: normal; font-weight: 400 500;
  font-display: swap; src: url('/static/fonts/lora-latin-var.woff2') format('woff2');
}
@font-face {
  font-family: 'Marcellus'; font-style: normal; font-weight: 400;
  font-display: swap; src: url('/static/fonts/marcellus-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Cormorant Garamond'; font-style: normal; font-weight: 300 600;
  font-display: swap; src: url('/static/fonts/cormorant-garamond-latin-var.woff2') format('woff2');
}
@font-face {
  font-family: 'Jost'; font-style: normal; font-weight: 300 500;
  font-display: swap; src: url('/static/fonts/jost-latin-var.woff2') format('woff2');
}

.inv {
  --bg: var(--p-bg);
  --bg-deep: var(--p-bg-deep);
  --bg-ink: var(--p-bg-ink);
  --ink: var(--p-ink);
  --ink-soft: var(--p-ink-soft);
  --gold: var(--p-gold);
  --gold-soft: var(--p-gold-soft);
  --line: var(--p-line);
  --accent: var(--p-accent);
  /* Cinematic: high-contrast didone display over a geometric sans. The contrast in the
     display face is the drama, so the sans stays quiet. */
  --display: 'Playfair Display', 'Fraunces', Georgia, serif;
  --sans: 'Jost', 'Inter', system-ui, sans-serif;
  --d-weight: 500; --d-tracking: .16em; --d-lh: 1.02; --tscale: 1;
  --label-weight: 400; --label-tracking: .34em;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  overflow-x: hidden;
  position: relative;
}

/* ---------------------------------------------------------------- reveal */
/* Progressive by construction: visible unless the script proves it can reveal. */
.rv { opacity: 1; transform: none; }
.rv-armed .rv:not(.in) { opacity: 0; transform: translateY(18px); }
.rv.in { opacity: 1; transform: none;
  transition: opacity .8s cubic-bezier(.22,.61,.36,1), transform .8s cubic-bezier(.22,.61,.36,1); }
.rv.d1 { transition-delay: .10s; } .rv.d2 { transition-delay: .20s; }
.rv.d3 { transition-delay: .30s; } .rv.d4 { transition-delay: .40s; }

@media (prefers-reduced-motion: reduce) {
  .rv, .rv.in, .rv-armed .rv:not(.in) {
    opacity: 1 !important; transform: none !important; transition: none !important; }
  .inv, .inv *, .cover-open::after { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------- ornament layers
   Both layers are inert: no pointer events, no text, and they sit *behind* content.
   Nothing ornamental is ever positioned over a name, a date, or a control. */
.inv-texture {
  /* Confined to the cover's top and bottom margins. A full-bleed ground behind the names
     is exactly the T3 defect: the motif crossed the text and fought it for contrast. */
  /* tied to the cover's own top padding: the band may occupy the margin above the text
     block and nothing more. A fixed min-height used to reach the names on short covers. */
  position: absolute; left: 0; right: 0; top: 0;
  height: clamp(64px, 15vh, 150px); max-height: 26%;
  pointer-events: none; z-index: 0; color: var(--gold); mix-blend-mode: multiply;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 46%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 46%, transparent 100%);
}
.inv-texture svg { width: 100%; height: 100%; display: block; }

.inv-frame {
  position: absolute; pointer-events: none; z-index: 1; color: var(--gold);
  left: 50%; transform: translateX(-50%); width: min(760px, 100%);
}
.inv-frame svg { width: 100%; height: auto; display: block; }
/* a floor on the *box*, never a forced height on the svg: forcing the svg taller than its
   aspect ratio stretched the motif and pushed it down into the names */
.inv-frame[data-pos="top"] {
  max-height: clamp(96px, 15vw, 132px); overflow: hidden;
  display: grid; align-items: start;
}
.inv-frame[data-pos="top"] svg { height: auto; width: 100%; max-height: 100%; }
.inv-frame[data-pos="top"] { top: clamp(-14px, -1vw, 2px); }
.inv-frame[data-pos="bottom"] { bottom: 0; height: clamp(70px, 11vh, 110px);
  overflow: hidden; display: grid; align-items: end; }
.inv-frame[data-pos="bottom"] svg { height: 100%; width: auto; margin-inline: auto; }
/* the culture's feature motif, set large in the empty column beside the text */
.cover-motif {
  /* bleeds past the right edge on purpose, but only a sliver: at -6% a 520px motif ran
     86px off-screen at 1440px wide and read as a clipped mistake */
  position: absolute; top: 50%; right: clamp(-16px, -1.2vw, 0px);
  transform: translateY(-50%);
  width: min(520px, 44%); z-index: 2; pointer-events: none; color: var(--gold);
}
.cover-motif svg { width: 100%; height: auto; display: block; }
@media (max-width: 899px) {
  .cover-motif {
    top: 0; right: 50%; transform: translateX(50%);
    width: min(280px, 68%); height: clamp(104px, 24vw, 140px);
    overflow: hidden; display: grid; align-items: start;
  }
  .cover-motif svg { height: 100%; width: auto; margin-inline: auto; }
}
.inv-frame[data-pos="side"] {
  top: 50%; left: auto; right: -4%; transform: translateY(-50%);
  width: min(460px, 46%); opacity: .8;
}
/* Below the two-column breakpoint a frame at 46% width would run under the names, so it
   narrows and keeps to the margin instead of moving above the text. It used to move to the
   top, where it became indistinguishable from a `top` frame — that collapse is why cultures
   with different frame positions still rendered the same cover on a phone. */
@media (max-width: 899px) {
  .inv-frame[data-pos="side"] {
    top: 50%; right: 0; transform: translateY(-50%);
    width: min(132px, 28%); height: 70%; opacity: .9;
    overflow: hidden; display: block;
  }
  .inv-frame[data-pos="side"] svg {
    /* A roofline is a wide drawing; squeezed into a tall column it becomes a few faint
       horizontal ticks and the side placement reads as nothing. Rotating the silhouette
       turns its long axis along the column, so the culture's own roofline runs down the
       edge of the cover as a vertical motif. */
    height: 100%; width: 100%; margin: 0;
    object-fit: contain; object-position: center;
    transform: rotate(-90deg) scale(0.82);
    transform-origin: center;
    color: var(--gold-soft);
  }
}
.inv-frame[data-pos="closing"] { position: relative; left: auto; transform: none;
  margin: 0 auto clamp(8px, 2vw, 18px); width: min(560px, 90%); }

/* ---------------------------------------------------------------- cover */
.cover {
  position: relative; min-height: 100svh; display: grid; place-items: center;
  /* the bottom pad keeps the last control clear of the viewport edge and of the fixed
     music button; without it the CTA lands exactly on the fold */
  padding: clamp(96px, 16vh, 152px) 24px clamp(112px, 18vh, 168px);
  text-align: center; overflow: hidden; isolation: isolate;
  background:
    radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, var(--gold) 9%, transparent), transparent 62%),
    linear-gradient(172deg, var(--bg) 0%, var(--bg-deep) 54%, var(--bg) 100%);
}

/* full-bleed concept: the photograph is the cover, the scrim carries the type */
.cover-photo { position: absolute; inset: 0; z-index: 0; }
.cover-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cover-scrim {
  position: absolute; inset: 0; display: block;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--bg-ink) 76%, transparent) 0%,
      color-mix(in srgb, var(--bg-ink) 34%, transparent) 34%,
      color-mix(in srgb, var(--bg-ink) 82%, transparent) 100%);
}
.cover[data-layout="fullbleed"] { color: var(--gold-soft); }
/* the gonjong roofline frames the top of a photo cover; it is capped to a band so it can
   never grow down into the names on a short viewport */
.cover[data-layout="fullbleed"] .inv-frame[data-pos="top"] {
  top: 0; height: clamp(96px, 15vh, 132px); overflow: hidden;
  display: grid; align-items: start; width: 100%;
}
.cover[data-layout="fullbleed"] .inv-frame[data-pos="top"] svg {
  /* preserve the 520x230 aspect: stretching it turned the gonjong arcs into a big ring
     behind the names */
  height: 100%; width: auto; min-height: 0; margin-inline: auto;
  max-width: 100%; object-fit: contain;
}
.cover[data-layout="fullbleed"] .inv-frame[data-pos="top"] { overflow: hidden; }
.cover[data-layout="fullbleed"] .inv-texture { color: var(--gold-soft); mix-blend-mode: screen; }
/* On a dark ground the roofline needs to be a drawn line, not a wash: screen-blending a
   thin stroke over maroon erased it. Solid colour + a slightly heavier stroke reads. */
.cover[data-layout="fullbleed"] .inv-frame[data-pos="top"] {
  color: var(--gold-soft); mix-blend-mode: normal; opacity: 1;
}
.cover[data-layout="fullbleed"] .inv-frame[data-pos="top"] svg { stroke-width: 1.6; }

.cover-inner { position: relative; z-index: 3; width: 100%; max-width: 640px; }

/* `data-align` was written into the cover element by the template and never had a rule, so
   every culture's alignment was inert and two cultures that differed only on that axis
   rendered the same cover. It now places the text block. `asymmetric` keeps its own
   left-anchored composition below, which is the point of that layout. */
.cover[data-align="left"]:not([data-layout="asymmetric"]) .cover-inner {
  text-align: left; margin-right: auto; margin-left: 0;
}
.cover[data-align="left"]:not([data-layout="asymmetric"]) .cover-names,
.cover[data-align="left"]:not([data-layout="asymmetric"]) .cover-div,
.cover[data-align="left"]:not([data-layout="asymmetric"]) .cover-foot {
  text-align: left; margin-inline: 0 auto;
}

.cover[data-layout="asymmetric"] { place-items: center start; text-align: left; }
.cover[data-layout="asymmetric"] .cover-inner {
  max-width: 560px; padding-left: clamp(4px, 3vw, 28px);
  border-left: 1px solid color-mix(in srgb, var(--gold) 55%, transparent);
}
@media (max-width: 619px) {
  .cover[data-layout="asymmetric"] { place-items: center; text-align: center; }
  .cover[data-layout="asymmetric"] .cover-inner {
    padding-left: 0; border-left: 0; max-width: 100%; }
}

.mono { width: clamp(72px, 19vw, 98px); margin: 0 auto clamp(26px, 6vw, 38px); color: var(--gold); }
.mono svg { width: 100%; height: auto; display: block; }

.eyebrow-x {
  font-family: var(--sans); font-size: .68rem; font-weight: 600;
  letter-spacing: var(--track); text-transform: uppercase;
  color: var(--gold); margin: 0 0 16px;
}
.cover[data-layout="fullbleed"] .eyebrow-x { color: var(--gold-soft); }
.eyebrow-x--rule { display: flex; align-items: center; gap: 12px; }
.eyebrow-x--rule::after {
  content: ""; flex: 1; height: 1px; max-width: 72px;
  background: color-mix(in srgb, var(--gold) 60%, transparent);
}

.cover-names {
  font-family: var(--display); font-weight: var(--d-weight, 400);
  /* Capped so the display size stays inside the type-scale ratio (1.15-1.45) of the next
     level. At 4.4rem the jump from h1 to the next heading was 1.9x — a jump that reads as
     a missing size step, not as emphasis. */
  font-size: calc(clamp(2.1rem, 8vw, 2.85rem) * var(--tscale));
  line-height: var(--d-lh, 1.03); letter-spacing: var(--d-tracking, -0.028em);
  margin: 0; text-wrap: balance;
  color: var(--ink);
}
.cover:has(.cover-photo) .cover-names { color: #FDF8EC; }
/* the same for the supporting type on a photo cover */
.cover:has(.cover-photo) { color: var(--gold-soft); }
.cover:has(.cover-photo) .eyebrow-x { color: var(--gold-soft); }
.cover-names .nm { display: block; }
.cover-amp {
  display: block; font-style: italic; color: var(--gold);
  font-size: clamp(.95rem, 3.6vw, 1.5rem); line-height: 1;
  margin: .34em 0; letter-spacing: 0;
}
.cover[data-layout="fullbleed"] .cover-amp { color: var(--gold-soft); }

.cover-date {
  font-family: var(--sans); font-size: clamp(.7rem, 2.7vw, .82rem); font-weight: 500;
  letter-spacing: .26em; text-transform: uppercase; color: var(--ink-soft);
  margin: 26px 0 0;
}
.cover:has(.cover-photo) .cover-date { color: #FDF8EC; }
.cover:has(.cover-photo) .cover-sub { color: var(--gold-soft); }

.cover-div { color: var(--gold); width: clamp(150px, 44vw, 220px); margin: 22px auto 0; opacity: .85; }
.cover-div svg { width: 100%; height: auto; display: block; }
.cover[data-layout="asymmetric"] .cover-div { margin-inline: 0; }
.cover[data-layout="fullbleed"] .cover-div { color: var(--gold-soft); }

.cover-sub {
  font-size: clamp(.82rem, 3vw, .94rem); color: var(--ink-soft);
  line-height: 1.78; max-width: 38ch; margin: 20px auto 0;
}
.cover[data-layout="asymmetric"] .cover-sub { margin-inline: 0; }
.cover[data-layout="fullbleed"] .cover-sub { color: color-mix(in srgb, #FDF8EC 82%, transparent); }

.cover-open {
  display: inline-flex; flex-direction: column; align-items: center; gap: 10px;
  margin-top: clamp(32px, 7vw, 52px); padding: 14px 30px 10px; min-height: 52px;
  font-family: var(--sans); font-size: .68rem; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink); background: color-mix(in srgb, var(--gold) 12%, transparent);
  border: 1px solid var(--gold); border-radius: 1px; cursor: pointer;
  transition: background .3s ease, color .3s ease;
}
.cover-open:hover { background: color-mix(in srgb, var(--gold) 22%, transparent); }
.cover-open:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
/* A 1px "scroll hint" used to sit inside the button. At 1×1 css px it read as a stray
   artifact rather than a cue, so the button is now a clean label. */
.cover[data-layout="fullbleed"] .cover-open {
  color: #FDF8EC; border-color: color-mix(in srgb, var(--gold-soft) 85%, transparent);
  background: color-mix(in srgb, var(--bg-ink) 40%, transparent);
  backdrop-filter: blur(3px);
}
@keyframes drop { 0%,100% { opacity: .25; transform: translateY(0); }
                  50% { opacity: 1; transform: translateY(7px); } }

.cover-foot { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; pointer-events: none; }
.cover-rule-top {
  position: absolute; top: 0; left: 0; right: 0; height: 44px; z-index: 2;
  pointer-events: none; color: var(--gold);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.cover-rule-top svg { width: 100%; height: 100%; display: block; }
.cover-band { height: 52px; color: var(--gold); opacity: .55;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent); }
.cover-band svg { width: 100%; height: 100%; display: block; }

/* the opening transition: the cover lifts, the body arrives */
.inv-body { position: relative; z-index: 1; }
.inv[data-opened="1"] .cover {
  animation: cover-lift .9s cubic-bezier(.22,.61,.36,1) forwards;
}
@keyframes cover-lift {
  to { opacity: 0; transform: translateY(-24px) scale(1.012);
       max-height: 0; min-height: 0; padding-block: 0; overflow: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .inv[data-opened="1"] .cover { animation: none; display: none; }
}

/* ---------------------------------------------------------------- sections */
.sec { position: relative; padding: clamp(58px, 13vw, 104px) 22px; z-index: 1; }
.sec-inner { max-width: 620px; margin-inline: auto; }
.sec--tight { padding-block: clamp(38px, 8vw, 66px); }
.center { text-align: center; }
.left { text-align: left; }

/* Each concept gets its own section ground, so the three never read as one template. */
/* --- three typographic systems, one per concept -------------------------------------- */
/* Romantic: a warm transitional serif with visible calligraphic stress, set open and
   low-contrast; labels stay letterspaced but lighter, so the page reads soft. */
.inv[data-concept="romantic"] {
  --display: 'Lora', 'Fraunces', Georgia, serif;
  --sans: 'Inter', system-ui, sans-serif;
  --d-weight: 400; --d-tracking: .02em; --d-lh: 1.18; --tscale: 1.02;
  --label-weight: 400; --label-tracking: .22em;
}
/* Elegant: a quiet classical serif with small serifs and an even colour; labels are the
   only place tracking is used, which is what keeps the page calm. */
.inv[data-concept="elegant"] {
  --display: 'Marcellus', 'Cormorant Garamond', Georgia, serif;
  --sans: 'Jost', system-ui, sans-serif;
  --d-weight: 400; --d-tracking: .10em; --d-lh: 1.10; --tscale: 1;
  /* Elegant was scaled to .96, which shrank every level by 4% and pushed h3 out of
     the type-scale band. The concept is minimal by whitespace and ornament, not by
     making its text smaller. */
  --label-weight: 300; --label-tracking: .28em;
}
/* the display face is chosen per concept, so its weight and tracking must follow it */
.cover-names, .sec-title, .ev-title, .cd-num, .closing-text, .quote-text, .person-amp {
  font-weight: var(--d-weight);
  letter-spacing: var(--d-tracking);
}

.inv[data-concept="elegant"] .sec:nth-child(even) { background: var(--bg); }
.inv[data-concept="elegant"] .cd-cell {
  box-shadow: 0 1px 0 color-mix(in srgb, var(--gold) 10%, transparent),
              0 8px 18px -16px rgba(0, 0, 0, .28);
}
.inv[data-concept="elegant"] .person-visual {
  box-shadow: 0 10px 24px -20px rgba(0, 0, 0, .26);
}
.inv[data-concept="romantic"] .sec--quote,
.inv[data-concept="romantic"] .sec--gallery,
.inv[data-concept="romantic"] .sec--rsvp { background: var(--bg-deep); }
.inv[data-concept="cinematic"] .sec--countdown,
.inv[data-concept="cinematic"] .sec--gift,
.inv[data-concept="cinematic"] .sec--guestbook { background: var(--bg-ink); }
.inv[data-concept="cinematic"] .sec--countdown,
.inv[data-concept="cinematic"] .sec--gift,
.inv[data-concept="cinematic"] .sec--guestbook { color: var(--gold-soft); }
.inv[data-concept="cinematic"] .sec--countdown .sec-title,
.inv[data-concept="cinematic"] .sec--gift .sec-title,
.inv[data-concept="cinematic"] .sec--guestbook .sec-title { color: #FDF8EC; }

.sec-kicker {
  /* 10.6px was below comfortable reading size and left a 1.9x gap to the heading above it.
     0.9rem keeps the kicker subordinate without making it unreadable. */
  font-family: var(--sans); font-size: clamp(1rem, 3vw, 1.3rem); font-weight: 600;
  letter-spacing: .24em; text-transform: uppercase; color: var(--gold); margin: 0 0 12px;
}
.sec-title {
  font-family: var(--display); font-weight: 400;
  font-size: calc(clamp(1.7rem, 6vw, 2.2rem) * var(--tscale));
  line-height: 1.14; letter-spacing: -0.018em; margin: 0 0 8px; text-wrap: balance;
}
.sec-body { color: var(--ink-soft); font-size: clamp(.9rem, 3.3vw, .98rem);
  line-height: 1.8; margin: 0; }
.sec-div { color: var(--gold); width: clamp(120px, 34vw, 180px); margin: 20px auto 0; opacity: .8; }
.sec-div svg { width: 100%; height: auto; display: block; }
.left .sec-div { margin-inline: 0; }

/* a running band, used by the cinematic concept between sections */
.band { height: 40px; color: var(--gold); opacity: .26;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent); }
.band svg { width: 100%; height: 100%; display: block; }
.band--flip { transform: scaleY(-1); }

/* ---------------------------------------------------------------- couple */
.couple { display: grid; gap: clamp(30px, 7vw, 46px); margin-top: 34px; }
@media (min-width: 720px) {
  .couple { grid-template-columns: 1fr auto 1fr; align-items: start; }
}
.person { text-align: center; }
.person-visual { position: relative; margin-bottom: 18px;
  box-shadow: 0 14px 32px -22px rgba(0, 0, 0, .5); border-radius: 50%; }
.person-photo, .person-initial {
  width: clamp(116px, 36vw, 168px); aspect-ratio: 1; border-radius: 50%;
  margin: 0 auto; display: grid; place-items: center; object-fit: cover;
  border: 1px solid color-mix(in srgb, var(--gold) 70%, transparent);
  padding: 6px; background: color-mix(in srgb, var(--gold) 8%, transparent);
}
.person-initial {
  font-family: var(--display); font-size: calc(clamp(1.7rem, 6vw, 2.2rem) * var(--tscale));
  color: var(--gold); font-style: italic;
}
.person-name {
  font-family: var(--display); font-size: calc(clamp(1.35rem, 5vw, 1.7rem) * var(--tscale));
  font-weight: 400; margin: 0 0 10px; line-height: 1.22;
}
.person-meta { display: grid; gap: 3px; font-size: .83rem; color: var(--ink-soft);
  line-height: 1.65; margin: 0; }
.pm-ig { color: var(--gold); font-size: .78rem; }
.person-amp { font-family: var(--display); font-style: italic; color: var(--gold);
  font-size: clamp(1.3rem, 5vw, 1.8rem); text-align: center; }
@media (min-width: 720px) { .person-amp { padding-top: clamp(48px, 9vw, 74px); } }

/* ---------------------------------------------------------------- quote */
.sec--quote .sec-inner { max-width: 640px; }
.quote-frame { position: relative; padding: clamp(26px, 6vw, 40px) clamp(18px, 5vw, 34px);
  border-top: 1px solid color-mix(in srgb, var(--gold) 40%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--gold) 40%, transparent); }
.quote-text {
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: calc(clamp(1.02rem, 4vw, 1.34rem) * var(--tscale));
  line-height: 1.74; margin: 0; text-wrap: balance;
}
.quote-src { font-family: var(--sans); font-size: .66rem; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: var(--gold); margin: 18px 0 0; }

/* ---------------------------------------------------------------- countdown */
.cd { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 28px; }
.cd-cell {
  border: 1px solid color-mix(in srgb, var(--gold) 34%, transparent);
  padding: 14px 4px 12px;
  background: color-mix(in srgb, var(--gold) 6%, transparent);
  /* Depth: the countdown tiles sit above the section ground. A single soft shadow lifts
     them; without any shadow the whole page was flat planes of colour. */
  box-shadow: 0 1px 0 color-mix(in srgb, var(--gold) 16%, transparent),
              0 10px 24px -18px rgba(0, 0, 0, .55);
}
.cd-num { font-family: var(--display); font-size: calc(clamp(1.7rem, 6vw, 2.2rem) * var(--tscale));
  line-height: 1; margin: 0; font-variant-numeric: tabular-nums; }
.cd-lab { font-family: var(--sans); font-size: .58rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); margin: 8px 0 0; }
.inv[data-concept="cinematic"] .cd-lab { color: color-mix(in srgb, var(--gold-soft) 70%, transparent); }
.cd-done { text-align: center; font-family: var(--display); font-size: 1.25rem; color: var(--gold); }

/* ---------------------------------------------------------------- events */
.ev-grid { display: grid; gap: 16px; margin-top: 32px; }
@media (min-width: 720px) { .ev-grid.two { grid-template-columns: 1fr 1fr; } }
.ev {
  position: relative; padding: 26px 22px 28px; text-align: center;
  border: 1px solid color-mix(in srgb, var(--gold) 34%, transparent);
  background: color-mix(in srgb, var(--gold) 4%, transparent);
}
/* a corner cut: the frame device that reads as stationery, not as a card template */
.ev::before, .ev::after {
  content: ""; position: absolute; width: 14px; height: 14px; pointer-events: none;
  border: 1px solid var(--gold); opacity: .75;
}
.ev::before { top: -1px; left: -1px; border-right: 0; border-bottom: 0; }
.ev::after { bottom: -1px; right: -1px; border-left: 0; border-top: 0; }

.ev-kind { font-family: var(--sans); font-size: .62rem; font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase; color: var(--gold); margin: 0 0 10px; }
.ev-title { font-family: var(--display); font-weight: 400;
  font-size: calc(clamp(1.35rem, 5vw, 1.7rem) * var(--tscale)); margin: 0 0 14px; }
.ev-rule { width: 34px; height: 1px; margin: 0 auto 14px;
  background: color-mix(in srgb, var(--gold) 65%, transparent); }
.ev-when { display: grid; gap: 4px; margin: 0 0 14px; }
.ev-date { font-family: var(--sans); font-size: .72rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); }
.ev-time { font-family: var(--display); font-size: 1.02rem; letter-spacing: .04em; }
.ev-where { display: grid; gap: 4px; margin: 0; }
.ev-place { font-size: .9rem; font-weight: 500; }
.ev-addr { font-size: .82rem; color: var(--ink-soft); line-height: 1.65; }
.ev-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 46px; margin-top: 18px; padding: 12px 22px;
  border: 1px solid var(--gold); color: var(--ink); background: transparent;
  font-family: var(--sans); font-size: .78rem; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
  transition: background .25s, color .25s;
}
.ev-btn:hover { background: var(--gold); color: var(--bg); text-decoration: none; }

/* ---------------------------------------------------------------- hero strip */
.hero-photo { position: relative; margin: 0; overflow: hidden; }
.hero-photo img { width: 100%; aspect-ratio: var(--ratio); object-fit: cover; display: block; }
.hero-photo[data-treatment="duotone"] img {
  filter: grayscale(1) sepia(.32) contrast(1.06);
}
.hero-photo[data-treatment="graded"] img { filter: saturate(1.06) contrast(1.05); }
.hero-photo figcaption {
  position: absolute; inset: auto 0 0 0; padding: clamp(46px, 12vw, 74px) 22px 22px;
  display: grid; gap: 6px; text-align: center;
  background: linear-gradient(transparent, color-mix(in srgb, var(--bg-ink) 78%, transparent));
  color: #FDF8EC;
}
.hp-names { font-family: var(--display); font-size: clamp(1.1rem, 4.4vw, 1.6rem);
  letter-spacing: -0.01em; }
.hp-date { font-family: var(--sans); font-size: .68rem; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; opacity: .82; }

/* ---------------------------------------------------------------- story */
.tl { list-style: none; margin: 34px 0 0; padding: 0; position: relative; }
.tl::before {
  content: ""; position: absolute; left: 7px; top: 8px; bottom: 8px; width: 1px;
  background: linear-gradient(color-mix(in srgb, var(--gold) 70%, transparent),
    color-mix(in srgb, var(--gold) 12%, transparent));
}
.tl-item { position: relative; padding: 0 0 clamp(26px, 6vw, 38px) 34px; }
.tl-item:last-child { padding-bottom: 0; }
.tl-dot {
  position: absolute; left: 0; top: 6px; width: 15px; height: 15px;
  border: 1px solid var(--gold); border-radius: 50%; background: var(--bg);
  display: grid; place-items: center;
}
.tl-dot::after { content: ""; width: 4px; height: 4px; border-radius: 50%;
  background: var(--gold); display: block; }
.tl-when { font-family: var(--sans); font-size: .66rem; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; color: var(--gold); margin: 0 0 7px; }
.tl-title { font-family: var(--display); font-weight: 400;
  font-size: calc(clamp(1.04rem, 4.2vw, 1.26rem) * var(--tscale));
  margin: 0 0 7px; line-height: 1.26; }
.tl-text { font-size: .87rem; color: var(--ink-soft); line-height: 1.76; margin: 0; }

/* the offset concept runs the timeline as a two-column editorial spread */
@media (min-width: 760px) {
  .inv[data-concept="romantic"] .tl { padding-left: 0; }
  .inv[data-concept="romantic"] .tl::before { left: 50%; }
  .inv[data-concept="romantic"] .tl-item { padding: 0 0 34px; width: 50%; }
  .inv[data-concept="romantic"] .tl-item:nth-child(odd) { padding-right: 34px; text-align: right; }
  .inv[data-concept="romantic"] .tl-item:nth-child(even) { margin-left: 50%; padding-left: 34px; }
  .inv[data-concept="romantic"] .tl-dot { left: auto; right: -7.5px; }
  .inv[data-concept="romantic"] .tl-item:nth-child(even) .tl-dot { left: -7.5px; right: auto; }
}

/* ---------------------------------------------------------------- gallery */
.gal { display: grid; gap: 7px; grid-template-columns: repeat(2, 1fr); margin-top: 30px; }
@media (min-width: 720px) { .gal { grid-template-columns: repeat(3, 1fr); } }
.gal figure { margin: 0; overflow: hidden; position: relative; }
.gal img { width: 100%; height: 100%; aspect-ratio: 1; object-fit: cover; display: block;
  transition: transform .8s cubic-bezier(.22,.61,.36,1); }
.gal figure:hover img { transform: scale(1.035); }
/* an editorial collage: the first frame runs tall, the rest sit square */
.gal figure:first-child { grid-row: span 2; }
.gal figure:first-child img { aspect-ratio: 1 / 2.04; }

/* --- gallery per concept (4C): same photos, three compositions ---------------------- */
/* Cinematic: an editorial mosaic. The lead frame spans two rows, the rest tile tightly,
   so the eye enters on one image instead of scanning a uniform grid. */
.inv[data-concept="cinematic"] .gal { gap: 4px; grid-template-columns: repeat(3, 1fr); }
.inv[data-concept="cinematic"] .gal figure:nth-child(4n+1) { grid-column: span 2; }
.inv[data-concept="cinematic"] .gal figure:nth-child(4n+1) img { aspect-ratio: 16 / 10; }
.inv[data-concept="cinematic"] .gal figure:nth-child(4n+1) { grid-row: auto; }

/* Romantic: an airy two-column flow with generous gaps and soft corners; nothing is
   cropped into a hard rectangle, which is what keeps it feeling hand-placed. */
.inv[data-concept="romantic"] .gal { gap: 18px; grid-template-columns: repeat(2, 1fr); }
.inv[data-concept="romantic"] .gal figure:first-child { grid-row: auto; }
.inv[data-concept="romantic"] .gal figure:first-child img { aspect-ratio: 1; }
.inv[data-concept="romantic"] .gal figure { border-radius: 6px; }
.inv[data-concept="romantic"] .gal img { aspect-ratio: 4 / 5; }

/* Elegant: a precise three-column grid with wide margins and a single wide opener. */
.inv[data-concept="elegant"] .gal { gap: 10px; grid-template-columns: repeat(3, 1fr); }
.inv[data-concept="elegant"] .gal figure:first-child { grid-column: span 3; grid-row: auto; }
.inv[data-concept="elegant"] .gal figure:first-child img { aspect-ratio: 21 / 9; }
.inv[data-concept="elegant"] .gal img { aspect-ratio: 1; }
@media (prefers-reduced-motion: reduce) {
  .gal img, .gal figure:hover img { transition: none; transform: none; }
}

/* ---------------------------------------------------------------- gift */
.gift-grid { display: grid; gap: 14px; margin-top: 28px; }
@media (min-width: 640px) { .gift-grid.two { grid-template-columns: 1fr 1fr; } }
.gift {
  border: 1px solid color-mix(in srgb, var(--gold) 34%, transparent);
  padding: 22px 20px; text-align: center;
  background: color-mix(in srgb, var(--gold) 5%, transparent);
}
.gift-bank { font-family: var(--sans); font-size: .64rem; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: var(--gold); margin: 0 0 8px; }
.gift-num { font-family: var(--display); font-size: calc(clamp(1.1rem, 4.6vw, 1.4rem) * var(--tscale));
  letter-spacing: .05em; margin: 0; font-variant-numeric: tabular-nums; }
.gift-holder { font-size: .8rem; color: var(--ink-soft); margin: 8px 0 0; }
.gift-copy {
  margin-top: 14px; min-height: 44px; padding: 10px 18px;
  border: 1px solid color-mix(in srgb, var(--gold) 45%, transparent);
  background: transparent; color: var(--ink-soft);
  font-family: var(--sans); font-size: .76rem; cursor: pointer;
  transition: border-color .25s, color .25s;
}
.gift-copy:hover { border-color: var(--gold); color: var(--ink); }

/* ---------------------------------------------------------------- closing */
.closing {
  position: relative; overflow: hidden; text-align: center;
  padding: clamp(70px, 16vw, 130px) 22px clamp(60px, 12vw, 96px);
  background: linear-gradient(180deg, var(--bg) 0%, var(--bg-deep) 100%);
}
.closing-text { font-family: var(--display); font-size: calc(clamp(.95rem, 3.6vw, 1.1rem) * var(--tscale));
  line-height: 1.82; color: var(--ink-soft); margin: 0; text-wrap: balance; }
.closing-div { color: var(--gold); width: clamp(140px, 40vw, 200px); margin: 26px auto 0; opacity: .8; }
.closing-div svg { width: 100%; height: auto; display: block; }
.closing-name { font-family: var(--display); font-weight: 400;
  /* Same level as .sec-title: a closing line is an h2, not a second display size. At
     2.5rem it rendered larger than every other h2 (38.4px vs 36.1px) and broke the scale. */
  font-size: calc(clamp(1.7rem, 6vw, 2.2rem) * var(--tscale));
  letter-spacing: -0.02em; margin: 22px 0 0; }
.closing-date { font-family: var(--sans); font-size: .68rem; font-weight: 600;
  letter-spacing: .24em; text-transform: uppercase; color: var(--gold); margin: 12px 0 0; }

.inv-foot {
  padding: 26px 22px 46px; text-align: center; font-size: .72rem;
  color: var(--ink-soft); letter-spacing: .04em;
  border-top: 1px solid color-mix(in srgb, var(--gold) 22%, transparent);
}

/* ---------------------------------------------------------------- preview bar */
.inv-preview-bar {
  position: sticky; top: 0; z-index: 60; display: flex; align-items: center;
  justify-content: space-between; gap: 10px; padding: 10px 16px; min-height: 48px;
  background: #241C14; color: #FBF7EF; font-size: .8rem; font-family: var(--sans);
}
.inv-preview-bar a { color: #FBF7EF; text-decoration: underline; }
.inv-preview-bar .sw { display: flex; gap: 5px; align-items: center; }
.inv-preview-bar .sw i { width: 12px; height: 12px; border-radius: 50%; display: block;
  border: 1px solid rgb(255 255 255 / .3); }

/* ---------------------------------------------------------------- guest forms */
.guest-form {
  max-width: 470px; margin: 0 auto; display: grid; gap: 14px;
  padding: clamp(20px, 5vw, 30px);
  border: 1px solid color-mix(in srgb, var(--gold) 34%, transparent);
  background: color-mix(in srgb, var(--gold) 4%, transparent);
}
.gf-field { display: grid; gap: 6px; border: 0; padding: 0; margin: 0; }
.gf-field > span, .gf-field > legend {
  font-family: var(--sans); font-size: .68rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft);
}
.gf-field input, .gf-field textarea {
  font: inherit; font-size: 1rem; padding: 12px 14px; min-height: 48px;
  color: var(--ink); background: var(--bg);
  border: 1px solid color-mix(in srgb, var(--gold) 30%, transparent);
  border-radius: 1px; width: 100%;
}
.gf-field textarea { min-height: 84px; resize: vertical; }
.gf-field input:focus-visible, .gf-field textarea:focus-visible {
  outline: 2px solid var(--gold); outline-offset: 2px;
}
.gf-radios { display: flex; flex-wrap: wrap; gap: 8px; }
.gf-radios label {
  display: inline-flex; align-items: center; gap: 8px; min-height: 48px;
  padding: 0 14px; cursor: pointer; font-size: .86rem;
  border: 1px solid color-mix(in srgb, var(--gold) 30%, transparent);
}
.gf-radios input { width: auto; min-height: 0; accent-color: var(--gold); }
.btn-send {
  min-height: 48px; padding: 0 24px; font: inherit; font-size: .76rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; cursor: pointer;
  color: var(--bg); background: var(--gold); border: 0;
}
.btn-send:hover { filter: brightness(1.08); }
.btn-send:disabled { opacity: .6; cursor: default; }
.gf-note { margin: 0; font-size: .82rem; color: var(--ink-soft); min-height: 1.2em; }
.gf-note.ok { color: var(--gold); }
.gf-note.err { color: #B4564A; }
.gf-note.held { color: #B08A3E; }

.gb-list { list-style: none; margin: 0 auto 26px; padding: 0; max-width: 540px;
  display: grid; gap: 12px; }
.gb-item {
  border-left: 2px solid color-mix(in srgb, var(--gold) 55%, transparent);
  padding: 10px 0 10px 16px;
}
.gb-name { margin: 0 0 4px; font-family: var(--display); font-size: 1rem; color: var(--gold); }
.gb-msg { margin: 0; font-size: .9rem; line-height: 1.62; }
.gb-empty { border-left-color: color-mix(in srgb, var(--gold) 20%, transparent);
  color: var(--ink-soft); font-size: .88rem; }

.share-btn {
  display: inline-flex; align-items: center; min-height: 48px; padding: 0 26px;
  border: 1px solid var(--gold); color: var(--ink);
  background: color-mix(in srgb, var(--gold) 10%, transparent);
  font-family: var(--sans); font-size: .74rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; text-decoration: none;
}
.share-btn:hover { background: color-mix(in srgb, var(--gold) 20%, transparent); }

/* The music control sits on the cover beside the open button, so it must be a flow element
   there rather than the fixed badge the first version used. It stays tap-sized (44px). */
.music-btn {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  margin: 10px auto 0; padding: 10px 16px; min-height: 44px;
  border-radius: 999px; font-size: .84rem;
  color: var(--p-ink); background: color-mix(in srgb, var(--p-bg) 86%, transparent);
  border: 1px solid var(--p-gold);
}
.mb-icon { font-size: 1rem; line-height: 1; }
.mb-label { white-space: nowrap; }
.music-btn[aria-pressed="true"] .mb-icon { animation: mspin 2.6s linear infinite; }
@keyframes mspin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .music-btn[aria-pressed="true"] .mb-icon { animation: none; }
}

/* inline links keep the 44px touch minimum */
.sec-body a, .inv a:not(.share-btn):not(.ev-btn) {
  display: inline-block; padding: 12px 2px; min-height: 44px;
}

/* ------------------------------------------------- honest photo placeholders */
/* A slot with no licensed photo says so. It must never look like a photograph:
   the T3 defect was synthetic graphics passing themselves off as wedding photos. */
.cover-photo--empty {
  display: grid; place-items: center;
  background:
    repeating-linear-gradient(135deg,
      color-mix(in srgb, var(--gold) 7%, transparent) 0 10px,
      transparent 10px 20px);
}
.photo-empty-label {
  position: relative; z-index: 2; align-self: end; margin-bottom: clamp(18px, 5vh, 40px);
  font-family: var(--sans); font-size: .62rem; font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--gold); opacity: .9;
  border: 1px dashed color-mix(in srgb, var(--gold) 55%, transparent);
  padding: 7px 14px;
}
.person-initial--empty {
  display: grid; place-content: center; gap: 4px; text-align: center;
  border-style: dashed; background: none;
}
.person-initial--empty .pe-mono { font-family: var(--display); font-style: italic;
  font-size: clamp(1.5rem, 6vw, 2.1rem); color: var(--gold); opacity: .55; line-height: 1; }
.pe-text { font-family: var(--sans); font-size: .56rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft); opacity: .8; }
.gal--empty figure { aspect-ratio: 16 / 9; display: grid; place-items: center;
  border: 1px dashed color-mix(in srgb, var(--gold) 45%, transparent);
  background: color-mix(in srgb, var(--gold) 4%, transparent); }
/* a portrait slot with no photo: the initial carries the space, the label explains it */
.person-initial--empty { border-color: color-mix(in srgb, var(--gold) 40%, transparent); }

/* ==========================================================================
   BANDED COMPOSITION (culture profile: Asmat)
   The body is organised in horizontal registers of alternating weight, read
   bottom-up. This is a structural difference, not a decorative one: section
   boundaries are register boundaries, and the ground alternates by register
   rather than by section index. Three variants keep the three concepts apart.
   ========================================================================== */
.inv[data-composition="banded-dark"],
.inv[data-composition="banded-soft"],
.inv[data-composition="banded-calm"] {
  --band-gap: clamp(0px, 0.6vw, 6px);
}
/* register rule: a doubled hairline above every section, drawn by the section itself */
.inv[data-composition^="banded"] .sec {
  border-top: 1px solid color-mix(in srgb, var(--gold) 26%, transparent);
  box-shadow: inset 0 -3px 0 -2px color-mix(in srgb, var(--gold) 12%, transparent);
  padding-block: clamp(48px, 11vw, 88px);
}
.inv[data-composition^="banded"] .sec:first-child { border-top: 0; }
/* alternate registers: the band, not the nth-child index, decides the ground */
.inv[data-composition^="banded"] .sec--couple,
.inv[data-composition^="banded"] .sec--quote,
.inv[data-composition^="banded"] .sec--gallery,
.inv[data-composition^="banded"] .sec--guestbook {
  background: var(--bg-deep);
}
.inv[data-composition="banded-dark"] .sec--countdown,
.inv[data-composition="banded-dark"] .sec--events,
.inv[data-composition="banded-dark"] .sec--gift {
  background: var(--bg-ink);
  color: var(--gold-soft);
}
.inv[data-composition="banded-soft"] .sec {
  border-top-color: color-mix(in srgb, var(--ink) 12%, transparent);
}
.inv[data-composition="banded-calm"] .sec {
  border-top: 1px solid color-mix(in srgb, var(--ink) 8%, transparent);
  box-shadow: none;
  padding-block: clamp(62px, 14vw, 108px);
}
.inv[data-composition="banded-calm"] .sec--couple,
.inv[data-composition="banded-calm"] .sec--quote,
.inv[data-composition="banded-calm"] .sec--gallery,
.inv[data-composition="banded-calm"] .sec--guestbook {
  background: var(--bg);
}

/* ---- tier craftsmanship ---------------------------------------------------
   Tier changes how much ornament register a section carries and how it is
   drawn, never the palette. A tier that only recolours is not a tier.
   -------------------------------------------------------------------------- */
.inv[data-tier="basic"] .sec-div { opacity: .55; }
.inv[data-tier="premium"] .sec-div { opacity: .8; }
.inv[data-tier="exclusive"] .sec-div { opacity: 1; }
/* exclusive adds a second, inset register to each section head */
.inv[data-tier="exclusive"] .sec-head {
  position: relative;
}
.inv[data-tier="exclusive"] .sec-head::after {
  content: "";
  position: absolute;
  inset: auto 50% -14px auto;
  transform: translateX(50%);
  width: min(58%, 320px);
  height: 1px;
  background: currentColor;
  opacity: .28;
}
.inv[data-tier="exclusive"] .cover-div { opacity: 1; }
/* photo frames: hairline on premium, doubled on exclusive, none on basic */
.inv[data-tier="premium"] .person-visual,
.inv[data-tier="premium"] .cover-photo { outline: 1px solid color-mix(in srgb, var(--gold) 38%, transparent); outline-offset: 6px; }
.inv[data-tier="exclusive"] .person-visual,
.inv[data-tier="exclusive"] .cover-photo {
  outline: 1px solid color-mix(in srgb, var(--gold) 55%, transparent);
  outline-offset: 6px;
  box-shadow: 0 0 0 10px color-mix(in srgb, var(--gold) 7%, transparent);
}

/* ===================================================================== cover layouts
   The cover is the one place a culture can be recognised before a word is read, so it
   carries the composition family rather than only the concept. Four layouts exist and
   each one changes where the eye starts, not how much decoration is piled on.

   Every layout keeps the same rule: nothing crosses the names. Each is written so the
   text block never moves under an ornament at any width. */

/* gateway — the cover is a door: the frame arches over the names and the block sits low,
   as if seen through a gate. Previously referenced by the engine with no CSS at all. */
.cover[data-layout="gateway"] {
  place-items: end center;
  padding-top: clamp(140px, 24vh, 230px);
}
.cover[data-layout="gateway"] .inv-frame[data-pos="top"] {
  top: 0; left: 50%; transform: translateX(-50%);
  width: min(560px, 92vw); height: clamp(150px, 26vh, 240px);
  overflow: hidden; color: var(--gold); opacity: .9;
}
.cover[data-layout="gateway"] .inv-frame[data-pos="top"] svg {
  height: 100%; width: auto; margin-inline: auto; object-fit: contain;
}
.cover[data-layout="gateway"] .cover-inner {
  padding-bottom: clamp(12px, 3vh, 28px);
  border-top: 1px solid color-mix(in srgb, var(--gold) 45%, transparent);
  padding-top: clamp(18px, 4vh, 34px);
}
.cover[data-layout="gateway"] .cover-rule-top { display: none; }

/* stacked — the page is one boarded surface read top to bottom. The texture is the whole
   ground and a drawn rule separates the top register from the names. */
.cover[data-layout="stacked"] {
  place-items: start center;
  padding-top: clamp(150px, 24vh, 210px);
}
/* A frame anchored to the bottom needs room inside the cover. Without this the cover grew
   past the viewport and the bottom frame landed at y=918 on a 900px page — rendered, never
   seen, so `frame_pos="bottom"` and `"side"` produced byte-identical covers. */
.cover[data-layout="stacked"] {
  /* a bottom-anchored frame only exists inside the cover's own box; if the cover is taller
     than the viewport the frame renders below the fold and the position axis is invisible */
  /* a bottom-anchored frame lives inside the cover's own box; the earlier layout let the
     cover grow past the fold, so frame_pos="bottom" rendered at y=918 on a 900px page —
     present in the DOM, absent from the card */
  padding-bottom: clamp(90px, 14vh, 130px);
}
.cover[data-layout="stacked"] .inv-frame[data-pos="bottom"],
.cover[data-layout="stacked"] .inv-frame[data-pos="side"] { z-index: 2; }
.cover[data-layout="stacked"] .inv-texture {
  inset: 0 0 auto 0; height: clamp(120px, 18vh, 190px); width: 100%;
  overflow: hidden;
  display: grid; align-content: start; opacity: .5;
  /* the texture must stay behind the type at every breakpoint; on tablet the full-page
     ground was counted as an ornament overlapping the names */
  pointer-events: none;
}
.cover[data-layout="stacked"] .inv-texture svg { width: 100%; height: auto; }
.cover[data-layout="stacked"] .cover-rule-top {
  position: absolute; top: 0; left: 0; right: 0;
  height: clamp(40px, 7vh, 64px); display: block; overflow: hidden;
}
.cover[data-layout="stacked"] .cover-inner {
  border-bottom: 1px solid color-mix(in srgb, var(--gold) 40%, transparent);
  padding-bottom: clamp(20px, 5vh, 38px);
}
/* the stacked texture is a full-page ground, so it must sit *behind* the names: without a
   stacking order it painted over them and the measure counted 2 ornament hits on the name */
.cover[data-layout="stacked"] .inv-texture { z-index: 0; }
.cover[data-layout="stacked"] .cover-rule-top { z-index: 1; }
.cover[data-layout="stacked"] .cover-inner { z-index: 3; }

/* column — a tall narrow elevation: the text is one measure, the frame closes the bottom
   like the stair you climb to reach the house. */
.cover[data-layout="column"] {
  place-items: start center;
  padding-top: clamp(110px, 18vh, 168px);
  padding-bottom: clamp(150px, 26vh, 230px);
}
.cover[data-layout="column"] .cover-inner { max-width: 430px; }
.cover[data-layout="column"] .inv-frame[data-pos="bottom"] {
  bottom: 0; left: 0; right: 0; top: auto;
  height: clamp(64px, 11vh, 104px); overflow: hidden;
  /* no colour here: --gold-soft is a light ink and measured 1.06:1 on a light ground */
  color: var(--gold); opacity: .85;
}
.cover[data-layout="column"] .inv-frame[data-pos="bottom"] svg {
  height: 100%; width: auto; margin-inline: auto;
}
.cover[data-layout="column"] .cover-rule-top { display: none; }

/* banded — a long low body: wide horizontal grounds, the names sit on the middle band. */
.cover[data-layout="banded"] {
  place-items: center center;
}
.cover[data-layout="banded"] .cover-inner {
  max-width: 100%;
  background: color-mix(in srgb, var(--bg-ink) 22%, transparent);
  padding: clamp(26px, 6vh, 44px) clamp(20px, 5vw, 48px);
  border-block: 1px solid color-mix(in srgb, var(--gold) 38%, transparent);
}
.cover[data-layout="banded"] .cover-rule-top,
.cover[data-layout="banded"] .cover-foot { display: none; }
.cover[data-layout="banded"] .inv-texture { opacity: .35; }

@media (max-width: 619px) {
  .cover[data-layout="column"] .cover-inner { max-width: 100%; }
  .cover[data-layout="gateway"] { padding-top: clamp(120px, 20vh, 180px); }
}

/* pavilion — an open hall: the names stand in the middle of a roofed space held up by four
   posts. Two posts read solid at the outer edge, two fade inward, and a beam closes the
   top and bottom. The space between the posts is what makes it a pavilion rather than a
   gateway: gateway is a doorway you enter from below, this is a hall you stand inside.
   Chosen by the owner as B2 of three candidates. */
.cover[data-layout="pavilion"] {
  place-items: center center;
  padding-inline: clamp(46px, 11vw, 60px);
}
/* The hall is drawn entirely by the cover itself, so it does not depend on the culture
   having a frame motif, and it cannot fall into another layout's frame rules. */
.cover[data-layout="pavilion"]::before,
.cover[data-layout="pavilion"]::after {
  content: ""; position: absolute; pointer-events: none; z-index: 2;
  top: 8%; bottom: 8%; width: 1px;
  background: linear-gradient(to bottom, transparent, var(--gold) 10%,
              var(--gold) 90%, transparent);
}
.cover[data-layout="pavilion"]::before {
  left: clamp(20px, 5.5vw, 30px);
  /* the inner, fainter post of the left pair */
  box-shadow: clamp(7px, 1.5vw, 8px) 0 0 0 color-mix(in srgb, var(--gold) 40%, transparent);
}
.cover[data-layout="pavilion"]::after {
  right: clamp(20px, 5.5vw, 30px);
  box-shadow: calc(-1 * clamp(7px, 1.5vw, 8px)) 0 0 0
              color-mix(in srgb, var(--gold) 40%, transparent);
}
.cover[data-layout="pavilion"] .cover-inner {
  position: relative; z-index: 3; max-width: 100%;
  padding-top: clamp(16px, 3.4vh, 24px);
  padding-bottom: clamp(16px, 3.4vh, 24px);
}
/* the beams: one above the block, one below, spanning the colonnade */
.cover[data-layout="pavilion"] .cover-inner {
  border-top: 1px solid color-mix(in srgb, var(--gold) 50%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--gold) 32%, transparent);
}
.cover[data-layout="pavilion"] .inv-frame { display: none; }
.cover[data-layout="pavilion"] .cover-rule-top,
.cover[data-layout="pavilion"] .cover-foot { display: none; }
/* A very long pair of names must wrap inside the colonnade, never run past it. The
   global 8vw display size is tuned for short names; inside a hall the posts are the hard
   edge, so the type gets its own cap and is allowed to break. */
.cover[data-layout="pavilion"] .cover-names {
  font-size: calc(clamp(1.75rem, 6.6vw, 2.6rem) * var(--tscale));
  overflow-wrap: anywhere; hyphens: auto;
}
.cover[data-layout="pavilion"] .cover-sub { max-width: 46ch; }
/* Over a hero photograph the gold posts read as another shadow. Lift them to the same
   light tone the names already switch to, so the colonnade survives the photo. */
.cover[data-layout="pavilion"]:has(.cover-photo)::before,
.cover[data-layout="pavilion"]:has(.cover-photo)::after {
  background: linear-gradient(to bottom, transparent, #FDF8EC 10%, #FDF8EC 90%, transparent);
  opacity: .62;
}
.cover[data-layout="pavilion"]:has(.cover-photo) .cover-inner {
  border-top-color: rgba(253, 248, 236, .58);
  border-bottom-color: rgba(253, 248, 236, .40);
}
.cover[data-layout="pavilion"]:has(.cover-photo) .eyebrow-x,
.cover[data-layout="pavilion"]:has(.cover-photo) .cover-sub,
.cover[data-layout="pavilion"]:has(.cover-photo) .cover-open {
  color: #FDF8EC;
}
.cover[data-layout="pavilion"]:has(.cover-photo) .cover-open {
  border-color: rgba(253, 248, 236, .62);
}

@media (max-width: 619px) {
  .cover[data-layout="pavilion"] { padding-inline: clamp(38px, 10vw, 48px); }
  .cover[data-layout="pavilion"]::before { left: clamp(16px, 4.5vw, 22px); }
  .cover[data-layout="pavilion"]::after { right: clamp(16px, 4.5vw, 22px); }
}

/* ---------------------------------------------------------------- new cover layouts
   Two more compositions so the cover axis is not exhausted at seven. Both are pure
   layout: no motif, no colour claim, nothing cultural invented. */

/* masthead — an editorial page: a rule across the top, the opener set high and small, the
   names dropped low and large. Reads like a magazine opening spread, not a card. */
.cover[data-layout="masthead"] {
  place-items: end start;
  justify-items: start;
  text-align: left;
  padding-top: clamp(96px, 15vh, 140px);
  padding-bottom: clamp(72px, 12vh, 120px);
}
/* the layout sets place-items, but the inner block still centres its own children unless
   it is told not to — that is why the first masthead render still read as centred */
.cover[data-layout="masthead"] .cover-inner,
.cover[data-layout="masthead"] .cover-inner * { text-align: left; }
.cover[data-layout="masthead"] .cover-names { margin-inline: 0 auto; }
.cover[data-layout="masthead"] .cover-inner {
  max-width: 100%; text-align: left;
}
.cover[data-layout="masthead"] .cover-rule-top { display: none; }
.cover[data-layout="masthead"] .eyebrow-x {
  text-align: left; margin-bottom: clamp(18px, 4vh, 34px);
}
.cover[data-layout="masthead"] .cover-names {
  font-size: clamp(2.4rem, 13vw, 4.2rem); line-height: 1.02; text-align: left;
}
.cover[data-layout="masthead"] .cover-amp {
  display: inline; margin-inline: .18em; font-size: .55em; vertical-align: baseline;
}
.cover[data-layout="masthead"] .cover-div,
.cover[data-layout="masthead"] .cover-foot { text-align: left; margin-inline: 0 auto; }

/* plinth — the names sit on a raised block with the frame above it, like an inscription on
   a base. The block is the composition; the ornament stays clear of it. */
.cover[data-layout="plinth"] {
  place-items: end center;
  padding-bottom: clamp(84px, 14vh, 130px);
}
.cover[data-layout="plinth"] .cover-inner {
  max-width: 100%;
  padding: clamp(22px, 5vh, 36px) clamp(16px, 5vw, 40px);
  background: color-mix(in srgb, var(--bg-ink) 34%, transparent);
  border-top: 1px solid color-mix(in srgb, var(--gold) 46%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--gold) 46%, transparent);
}
.cover[data-layout="plinth"] .cover-rule-top,
.cover[data-layout="plinth"] .cover-foot { display: none; }
.cover[data-layout="plinth"] .inv-frame[data-pos="top"] { opacity: .9; }
