/* ══════════════════════════════════════════════════════════════
   TinselVite marketing site — shared stylesheet.

   Ported from tinselvite-website-wireframe (2).html. Two systematic
   changes from that file, everything else is verbatim:

   1. The wireframe simulated responsiveness by swapping .vp-768 /
      .vp-1280 classes onto a fixed-width .frame. Here those become real
      mobile-first media queries — base = the 390px design, 768px = the
      tablet column, 1120px = desktop. The 1280px design targets a
      1120px container, so that is the breakpoint, not 1280.
   2. The wireframe chrome (tab bar, viewport switcher, build notes,
      spec sheet) is dropped — it was never part of the deliverable.

   Tokens below are from constants/colors.ts. Do not invent new hexes.
   ══════════════════════════════════════════════════════════════ */
:root{
  --navy:#080F1D;
  --navy-mid:#0E1829;
  --navy-card:#0D1628;
  --gold:#C9993A;
  --gold-light:#E2BE7A;
  --gold-pale:#F5E9CC;
  --cream:#FBF6EE;
  --bg:#F5F0E8;
  --text-dark:#1A1208;
  --text-mid:#4A3F2F;
  --text-light:#8A7A65;

  --body-on-navy:rgba(245,233,204,0.70);
  --dim-on-navy:rgba(245,233,204,0.45);
  --rule:rgba(201,153,58,0.30);
  --rule-faint:rgba(201,153,58,0.16);
  --rule-dark:rgba(26,18,8,0.14);
}

*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  background:var(--navy);
  font-family:'Lato',sans-serif;font-weight:300;
  color:var(--cream);
  /* The wireframe set body{overflow:hidden} via the Expo reset. These are
     plain pages — normal document scroll, and never a sideways one. */
  overflow-x:hidden;
}
img{max-width:100%;height:auto;display:block}

@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
}

/* Keyboard-only skip link — lands on <main id="main">. */
.skip{
  position:absolute;left:-9999px;top:0;z-index:100;
  font-family:'Cinzel',serif;font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  background:var(--gold);color:var(--navy);padding:12px 18px;text-decoration:none;
}
.skip:focus{left:0}

/* Visible to screen readers only — used for the menu button's label. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ══════════════════════════════════════════════════════════════
   SHARED SITE PRIMITIVES
   ══════════════════════════════════════════════════════════════ */
.wrap{max-width:520px;margin:0 auto;padding:0 24px}
@media (min-width:768px){ .wrap{max-width:660px;padding:0 40px} }
@media (min-width:1120px){ .wrap{max-width:1120px;padding:0 64px} }

/* Pages with a narrower measure than the grid (About, How it works,
   Support). The wireframe set these inline per page; as a class they stay
   consistent and still widen with the outer wrap. */
.wrap-prose{max-width:760px}
.wrap-prose-wide{max-width:820px}
@media (min-width:1120px){
  .wrap-prose{max-width:760px}
  .wrap-prose-wide{max-width:820px}
}

.dark{background:var(--navy)}
.dark-mid{background:var(--navy-mid)}
.light{background:var(--bg)}

section.band{padding:64px 0}
@media (min-width:768px){ section.band{padding:80px 0} }
@media (min-width:1120px){ section.band{padding:112px 0} }

.eyebrow{
  font-family:'Cinzel',serif;font-weight:400;font-size:10px;
  letter-spacing:.30em;text-transform:uppercase;color:var(--gold);
}
@media (min-width:1120px){ .eyebrow{font-size:11px} }
.eyebrow-b{display:block;margin-bottom:14px}

h1,h2,h3{font-weight:400}
.display{
  font-family:'Cormorant Garamond',serif;font-weight:300;
  font-size:38px;line-height:1.12;letter-spacing:.005em;color:var(--cream);
}
@media (min-width:768px){ .display{font-size:50px} }
@media (min-width:1120px){ .display{font-size:66px} }

/* Designed line breaks in a display line. Below the tablet column they are
   suppressed and the line wraps naturally — a forced break inside a 38px
   Cormorant face overflows the 342px measure a 390px screen actually has. */
.br-wide{display:none}
@media (min-width:768px){ .br-wide{display:inline} }

.h2{
  font-family:'Cormorant Garamond',serif;font-weight:300;
  font-size:30px;line-height:1.18;color:var(--cream);
}
@media (min-width:768px){ .h2{font-size:36px} }
@media (min-width:1120px){ .h2{font-size:44px} }
.light .h2,.light .display{color:var(--text-dark)}

.h3{
  font-family:'Cinzel',serif;font-weight:400;font-size:13px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--gold-pale);
}
.light .h3{color:var(--text-dark)}

.body{font-family:'Lato',sans-serif;font-weight:300;font-size:15px;line-height:1.62;color:var(--body-on-navy)}
@media (min-width:1120px){ .body{font-size:16px;line-height:1.68} }
.light .body{color:var(--text-mid)}
.small{font-size:13px;line-height:1.6;color:var(--dim-on-navy)}
.light .small{color:var(--text-light)}

/* There is no bold Lato. Emphasis is color, size, or a switch to Cinzel. */
.body b,.small b{font-weight:400;color:var(--cream)}
.light .body b,.light .small b{color:var(--text-dark)}

/* Inline link inside prose. */
.tlink{color:var(--gold);text-decoration:underline}
.dark .tlink,.dark-mid .tlink{color:var(--gold-light)}

/* the signature device: hairline rule with four-facet diamond terminals */
.facet-rule{display:flex;align-items:center;gap:12px;width:100%}
.facet-rule i{flex:1;height:1px;background:var(--rule);display:block}
.light .facet-rule i{background:rgba(201,153,58,.42)}
.facet-rule svg{flex-shrink:0}

/* buttons — Cinzel 9px / 2.5px tracking / 0.5px border / 4px radius */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-family:'Cinzel',serif;font-weight:400;font-size:9px;letter-spacing:.25em;
  text-transform:uppercase;text-decoration:none;
  border:0.5px solid var(--gold);border-radius:4px;
  padding:15px 22px;color:var(--gold);background:transparent;cursor:pointer;
}
.btn-solid{background:var(--gold);color:var(--navy);border-color:var(--gold)}
.btn-ghost{border-color:var(--rule);color:var(--gold-pale)}
.light .btn-ghost{border-color:rgba(26,18,8,.2);color:var(--text-dark)}
.btn:focus-visible{outline:2px solid var(--gold-light);outline-offset:3px}
.btnrow{display:flex;flex-direction:column;gap:10px}
@media (min-width:768px){ .btnrow{flex-direction:row;gap:12px} }
.btnrow-center{align-items:center}
@media (min-width:768px){ .btnrow-center{justify-content:center} }

/* Store CTAs, pre-launch. The app is not listed on either store yet, so
   these are <span>, not <a> — same treatment, no dead link. When the
   listings go live they become anchors and .btn-wait / .badge-wait drop. */
.btn-wait{border-color:var(--rule);color:var(--dim-on-navy);cursor:default}
.btn-wait .btn-note{
  font-size:7px;letter-spacing:.18em;color:var(--gold);
}

.store-badge{
  display:flex;align-items:center;gap:10px;
  border:0.5px solid var(--rule);border-radius:5px;
  padding:10px 18px;text-decoration:none;background:rgba(251,246,238,.03);
}
.store-badge .sb-t{font-family:'Lato',sans-serif;font-size:8px;letter-spacing:.16em;text-transform:uppercase;color:var(--dim-on-navy)}
.store-badge .sb-b{font-family:'Cinzel',serif;font-size:12px;letter-spacing:.08em;color:var(--cream)}
.light .store-badge{border-color:rgba(26,18,8,.18);background:rgba(8,15,29,.02)}
.light .store-badge .sb-t{color:var(--text-light)}
.light .store-badge .sb-b{color:var(--text-dark)}

/* ══════════════════════════════════════════════════════════════
   WORDMARK — CSS lockup, matching components/BrandLogo.tsx
   ══════════════════════════════════════════════════════════════ */
.wordmark{display:flex;align-items:flex-end;gap:0;font-family:'Cinzel',serif;font-weight:500;letter-spacing:.14em;line-height:1;text-decoration:none}
.wordmark .wm{color:var(--cream)}
.light .wordmark .wm{color:var(--navy)}
.wordmark .vwrap{display:flex;align-items:baseline}
.wordmark .vee{color:var(--gold)}
.wm-sm{font-size:15px}
.wm-sm .vee{font-size:15px}
.wordmark:focus-visible{outline:2px solid var(--gold-light);outline-offset:4px}

/* ceremonial lockup: flanking hairlines + diamond terminals */
.lockup{display:flex;align-items:center;gap:14px;justify-content:center}
.lockup i{height:1px;background:var(--rule);flex:1;max-width:70px}

.slot{
  border:1px dashed var(--rule);border-radius:3px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:6px;padding:22px 16px;text-align:center;background:rgba(201,153,58,.035);
}
.slot .s1{font-family:'Cinzel',serif;font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--gold)}
.slot .s2{font-family:'Lato',sans-serif;font-size:11px;line-height:1.5;color:var(--dim-on-navy)}
.light .slot{border-color:rgba(26,18,8,.2);background:rgba(26,18,8,.02)}
.light .slot .s2{color:var(--text-light)}

/* ══════════════════════════════════════════════════════════════
   HEADER + NAV
   ══════════════════════════════════════════════════════════════ */
.topbar{display:flex;align-items:center;justify-content:space-between;padding:18px 0;gap:16px}

/* static-page header — same nav on a light ground */
.bhead{border-bottom:1px solid var(--rule-faint);padding:20px 0;display:flex;align-items:center;justify-content:space-between;gap:16px}
.light .bhead{border-color:var(--rule-dark)}

.navlinks{display:none}
@media (min-width:768px){
  .navlinks{display:flex;gap:26px;align-items:center;list-style:none}
}
.navlinks a{
  font-family:'Cinzel',serif;font-size:9px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--dim-on-navy);text-decoration:none;
}
.light .navlinks a{color:var(--text-light)}
.navlinks a.cur,.light .navlinks a.cur{color:var(--gold)}
.navlinks a:focus-visible{outline:2px solid var(--gold-light);outline-offset:3px}

/* Mobile menu. The wireframe's three-line mark was decorative with no
   drawer — all 390px navigation went through the footer. Identical at
   rest here, but it opens a real disclosure panel: five links behind a
   footer scroll is poor for both readers and crawlers. */
.menu-btn{
  display:flex;flex-direction:column;gap:3px;justify-content:center;
  background:none;border:none;cursor:pointer;padding:6px 2px;
}
@media (min-width:768px){ .menu-btn{display:none} }
.menu-btn b{display:block;width:16px;height:1px;background:var(--gold);transition:transform .18s ease,opacity .18s ease}
.menu-btn:focus-visible{outline:2px solid var(--gold-light);outline-offset:3px}
.menu-btn[aria-expanded="true"] b:nth-child(1){transform:translateY(4px) rotate(45deg)}
.menu-btn[aria-expanded="true"] b:nth-child(2){opacity:0}
.menu-btn[aria-expanded="true"] b:nth-child(3){transform:translateY(-4px) rotate(-45deg)}

.menu-panel{display:none;list-style:none;padding:6px 0 18px}
.menu-panel.open{display:block}
@media (min-width:768px){ .menu-panel,.menu-panel.open{display:none} }
.menu-panel li{border-bottom:1px solid var(--rule-faint)}
.light .menu-panel li{border-color:var(--rule-dark)}
.menu-panel li:last-child{border-bottom:none}
.menu-panel a{
  display:block;padding:14px 2px;text-decoration:none;
  font-family:'Cinzel',serif;font-size:10px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--body-on-navy);
}
.light .menu-panel a{color:var(--text-mid)}
.menu-panel a.cur{color:var(--gold)}
.menu-panel a:focus-visible{outline:2px solid var(--gold-light);outline-offset:2px}

/* ══════════════════════════════════════════════════════════════
   HOME — HERO
   ══════════════════════════════════════════════════════════════ */
/* The wireframe nested the topbar inside the hero section. Here <header>
   is its own landmark ahead of <main>, so the hero's top padding moves
   onto the header — same total spacing, correct document outline. */
.site-header{padding-top:38px}
@media (min-width:1120px){ .site-header{padding-top:56px} }

.hero{padding:0 0 60px;position:relative;overflow:hidden}
@media (min-width:1120px){ .hero{padding:0 0 96px} }
.hero-inner{position:relative}
.sparkle{position:absolute;inset:0;pointer-events:none}
.sparkle span{position:absolute;width:2px;height:2px;background:var(--gold-light);border-radius:50%;opacity:.5;animation:tw 4s ease-in-out infinite}
@keyframes tw{0%,100%{opacity:.12;transform:scale(.6)}50%{opacity:.7;transform:scale(1)}}

.hero-grid{display:flex;flex-direction:column;gap:38px;align-items:center;text-align:center;margin-top:26px}
@media (min-width:1120px){
  .hero-grid{flex-direction:row;text-align:left;align-items:center;gap:70px}
  .hero-copy{flex:1.2}
  .hero-art{flex:1;display:flex;justify-content:flex-end}
  .hero-grid .facet-rule,.hero-grid .btnrow{justify-content:flex-start}
}
.hero-copy .eyebrow{display:block;margin-bottom:18px}
.hero-copy .display{margin-bottom:20px}
/* The hero H1 runs longer than the static pages' — "Invitations you text."
   is 21 characters where "Every celebration" was 17 — and at the shared
   66px it broke after "you" at 1120–1400, giving a four-line H1 with a
   dangling word. Scoped to the hero so the other pages keep their size,
   and paired with a wider copy column below. */
@media (min-width:1120px){ .hero-copy .display{font-size:58px} }
.hero-copy .lede{margin-bottom:26px}
@media (min-width:1120px){ .hero-copy .lede{max-width:520px} }

/* sample card — pure CSS, no asset */
/* The hero invitation.
   This was a CSS drawing of an invented couple — .card-mock and its .cc-*
   inner type — used before any real card existed to put here. It is now an
   <img> of the actual committed capture, so the block below is only the frame
   the image sits in. The ~26 rules that drew the fake card are gone rather
   than left behind: dead CSS for a thing the page no longer contains reads as
   a component someone might still use. */
/* Same guest-true width as the example viewer below — see the note there.
   min(100vw - 32px, 480px) is app/(guest)/invite/[id].tsx:164, copied.

   Safe to grow here because .hero-grid is a COLUMN below 1120px with the
   copy first and the art second, so a taller card pushes nothing: the
   headline, lede and store buttons all sit above it. Only at 1120px, where
   the grid becomes a row and the card sits beside the copy, does the width
   go back to a fixed 330. */
/* One token drives the slide width, the track's centring padding and the
   image. Changing the size at a breakpoint means changing this and nothing
   else — the padding that centres a slide is derived from it. */
:root{ --slide-w: min(calc(100vw - 32px), 480px); }
@media (min-width:768px){ :root{ --slide-w: 270px } }
@media (min-width:1120px){ :root{ --slide-w: 330px } }

/* Every card is a button that opens the lightbox. Stripped back to nothing
   visually — the invitation is the affordance, and a button chrome around a
   piece of stationery looks like a mistake. It keeps its focus ring, which is
   the part that has to survive for anyone driving this from a keyboard. */
.hero-open{
  appearance:none;background:transparent;border:0;padding:0;margin:0;
  display:block;cursor:zoom-in;line-height:0;
  border-radius:3px;
}
.hero-open:focus-visible{outline:2px solid var(--gold-light);outline-offset:4px}

.hero-card{
  width:var(--slide-w);
  /* 1224×1836 — the trimmed capture's own proportion, which is the same 2:3
     the CSS drawing used before it. object-fit:cover therefore crops nothing;
     it is here so a future capture that lands a pixel off cannot letterbox. */
  aspect-ratio:1024/1536;object-fit:cover;display:block;
  border:0.5px solid var(--rule);border-radius:3px;
  flex-shrink:0;
}

@media (max-width:767px){
  /* Break out of .wrap's 24px padding so the card can reach the full
     guest width rather than the content column's. */
  .hero-art{margin-left:-24px;margin-right:-24px}
}
@media (min-width:1120px){
  /* At desktop .hero-art is a flex child that right-aligns its card. The
     carousel takes over that job, so the alignment moves onto the track's
     own padding below. */
  .hero-art{display:block}
}

.hero-carousel{position:relative}

/* A real horizontal scroller: swipe, trackpad and keyboard all work with no
   JavaScript at all, which is why the markup is a scroll container rather
   than an absolutely-positioned stack. JS only adds the timer and the dots. */
.hero-track{
  display:flex;gap:16px;list-style:none;margin:0;
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;scroll-behavior:smooth;
  /* Centres whichever slide is snapped, including the first and last —
     without this the outer slides can only ever reach the container edge. */
  padding:0 calc(50% - var(--slide-w) / 2);
  /* The scrollbar is chrome on a picture; the dots say how many there are. */
  scrollbar-width:none;-ms-overflow-style:none;
}
.hero-track::-webkit-scrollbar{display:none}
.hero-track:focus-visible{outline:2px solid var(--gold-light);outline-offset:4px}
.hero-slide{scroll-snap-align:center;flex:0 0 auto}

/* The neighbouring invitation peeks past the edge of the track, which is the
   affordance that says the row scrolls — but cut off square it reads as a
   layout bug rather than an invitation continuing. Fade it out instead.
   36px sits well inside the track's own centring padding (95px at 1440, more
   below that), so the card in view is never touched by the mask.
   Not below 768: there the slide is nearly the full viewport and the padding
   collapses to 16px, so a fade this wide would eat the card itself. */
@media (min-width:768px){
  .hero-track{
    -webkit-mask-image:linear-gradient(to right,transparent 0,#000 36px,#000 calc(100% - 36px),transparent 100%);
    mask-image:linear-gradient(to right,transparent 0,#000 36px,#000 calc(100% - 36px),transparent 100%);
  }
}

@media (prefers-reduced-motion:reduce){
  /* The global reduced-motion rule kills animations but not programmatic
     smooth scrolling, which is the same complaint. site.js also refuses to
     auto-advance under this preference. */
  .hero-track{scroll-behavior:auto}
}

/* ── Arrows, counter + stop control (built by site.js, >1 slide only) ──
   This was a row of dots. With twenty-two invitations it became a strip as
   wide as the card with 6px targets in it, so it is a counter and two arrows
   now — see the note in site.js. The container keeps its name and its id
   because nothing else about the block changed. */
.hero-dots{
  display:flex;align-items:center;justify-content:center;gap:4px;
  margin-top:18px;
}
.hero-arrow{
  appearance:none;background:transparent;border:0;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  width:44px;height:44px;                 /* the target, not the glyph */
  font-family:'Lato',sans-serif;font-size:22px;line-height:1;
  color:var(--dim-on-navy);
  transition:color .2s ease;
  padding-bottom:3px;                     /* optical centring of ‹ › */
}
.hero-arrow:hover{color:var(--gold-light)}
.hero-arrow:focus-visible{outline:2px solid var(--gold-light);outline-offset:1px;border-radius:50%}
.hero-count{
  font-family:'Cinzel',serif;font-size:9px;letter-spacing:.18em;
  color:var(--dim-on-navy);
  min-width:58px;text-align:center;       /* fixed, so 9→10 does not shift the arrows */
  font-variant-numeric:tabular-nums;
}
/* WCAG 2.2.2: anything that moves automatically needs a way to stop it that
   is not "hover and hope". */
.hero-stop{
  appearance:none;background:transparent;border:0;cursor:pointer;
  margin-left:6px;padding:6px 8px;
  font-family:'Cinzel',serif;font-size:8px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--dim-on-navy);
}
.hero-stop:focus-visible{outline:2px solid var(--gold-light);outline-offset:1px}

/* ── Invitation lightbox ────────────────────────────────────────
   Opened from a hero card. The job is to show ONE invitation whole, at a size
   where the small type is readable, and then let someone go closer.

   Whole is the operative word. The carousel crops nothing, and neither does
   this: .lb-img is object-fit:contain inside a stage sized in viewport units,
   so the card always fits entirely on screen at rest no matter the window's
   shape. Zoom is then a transform on top of a complete image, which is the
   difference between "look closer at the card" and "look at part of it". */
.lb{
  /* A dialog defaults to a fixed content-box with a border and margin:auto.
     All of it goes; this one is the whole viewport. */
  width:100%;max-width:100%;height:100%;max-height:100%;
  margin:0;padding:0;border:0;overflow:hidden;
  /* Nearly solid on purpose. At 0.94 the hero headline read straight through
     it and competed with the invitation, which is the one thing on screen. */
  background:rgba(8,15,29,0.985);color:var(--cream);
}
.lb::backdrop{background:rgba(8,15,29,0.97)}
/* Chromium and Safari still paint a focus ring on the dialog itself when
   showModal() moves focus into it. Nothing here is focusable-by-accident, so
   the ring is noise on top of the image. */
.lb:focus{outline:none}

/* The stage owns the space; the image is centred in it. Insets leave room for
   the caption bar below and the close control above, so neither ever sits on
   top of the invitation. */
.lb-stage{
  position:absolute;inset:56px 16px 64px;
  display:flex;align-items:center;justify-content:center;
  overflow:hidden;
  touch-action:none;          /* pan and pinch are handled in JS */
  cursor:zoom-in;
}
.lb-stage.zoomed{cursor:grab}
.lb-stage.zoomed:active{cursor:grabbing}
@media (min-width:768px){ .lb-stage{inset:64px 72px 72px} }

.lb-img{
  max-width:100%;max-height:100%;
  object-fit:contain;display:block;
  border:0.5px solid var(--rule);border-radius:3px;
  /* JS writes the transform. The transition is deliberately NOT on transform
     in general — it is switched off while dragging, or every pan frame would
     lag a quarter second behind the finger. */
  transform-origin:center center;
  will-change:transform;
  -webkit-user-select:none;user-select:none;-webkit-user-drag:none;
}
.lb-img.animating{transition:transform .22s ease}

/* ── Caption + tools ── */
.lb-bar{
  position:absolute;left:0;right:0;bottom:0;height:64px;
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:0 16px;
}
@media (min-width:768px){ .lb-bar{padding:0 24px;height:72px} }
.lb-caption{
  font-family:'Cinzel',serif;font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--body-on-navy);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.lb-count{color:var(--dim-on-navy);margin-left:10px}
.lb-tools{display:flex;align-items:center;gap:6px;flex-shrink:0}

/* One control style for zoom, close and the two arrows. 44px is the minimum
   comfortable touch target and these sit over a busy image, so they carry a
   ground of their own rather than relying on the card behind them. */
.lb-btn,.lb-nav,.lb-close{
  appearance:none;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  width:44px;height:44px;border-radius:50%;
  background:rgba(8,15,29,0.72);
  border:0.5px solid var(--rule);
  color:var(--gold-light);
  font-family:'Lato',sans-serif;font-size:19px;line-height:1;
}
.lb-btn:hover,.lb-nav:hover,.lb-close:hover{background:rgba(201,153,58,0.18)}
.lb-btn:focus-visible,.lb-nav:focus-visible,.lb-close:focus-visible{
  outline:2px solid var(--gold-light);outline-offset:2px;
}
.lb-btn[disabled]{opacity:.35;cursor:default;background:rgba(8,15,29,0.72)}

.lb-close{position:absolute;top:10px;right:12px;font-size:15px}
@media (min-width:768px){ .lb-close{top:14px;right:18px} }

.lb-nav{position:absolute;top:50%;transform:translateY(-50%);font-size:26px;padding-bottom:3px}
.lb-prev{left:8px}
.lb-next{right:8px}
@media (min-width:768px){ .lb-prev{left:16px} .lb-next{right:16px} }
/* Zoomed in, a drag means pan — so the arrows step out of the way rather than
   swallowing the gesture that starts on top of them. */
.lb.zoomed .lb-nav{opacity:0;pointer-events:none}
.lb-nav{transition:opacity .18s ease}

@media (prefers-reduced-motion:reduce){
  .lb-img.animating{transition:none}
  .lb-nav{transition:none}
}

/* ── Three-beat strip, below the hero grid ──────────────────────
   Three across at EVERY width, including 390. Stacked, it added ~170px
   between the lede and the store buttons on a phone — the beats are a
   glance, and a glance that pushes the call to action off-screen is a
   net loss. Below 768 the description line is dropped and only the
   numeral and the verb remain; the full sentences are in How it works,
   which is the section that exists to say them. */
.beats{
  display:flex;list-style:none;margin:34px 0 0;
  border-top:1px solid var(--rule-faint);border-bottom:1px solid var(--rule-faint);
}
.beat{
  flex:1;min-width:0;display:flex;flex-direction:column;gap:5px;
  padding:16px 12px;border-right:1px solid var(--rule-faint);
}
.beat:first-child{padding-left:0}
.beat:last-child{border-right:none;padding-right:0}
.beat-n{
  font-family:'Cinzel',serif;font-size:9px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--gold);
}
.beat-t{
  font-family:'Cormorant Garamond',serif;font-size:19px;line-height:1.1;
  color:var(--cream);
}
.beat-b{display:none;font-family:'Lato',sans-serif;font-size:12.5px;line-height:1.5;color:var(--dim-on-navy)}
@media (min-width:768px){
  .beat{padding:22px 24px}
  .beat-t{font-size:21px}
  .beat-b{display:block}
}

/* ══════════════════════════════════════════════════════════════
   HOME — sections
   ══════════════════════════════════════════════════════════════ */
.cols{display:flex;flex-direction:column;gap:34px}
@media (min-width:768px){
  .cols-2{flex-direction:row;gap:34px}
  .cols-3{flex-direction:row;gap:26px}
}
@media (min-width:1120px){ .cols-3{gap:44px} }
.cols-mid{align-items:center}
.col{flex:1;min-width:0}

.step{display:flex;flex-direction:column;gap:13px;list-style:none}
.step-num{
  font-family:'Cinzel',serif;font-size:10px;letter-spacing:.24em;color:var(--gold);
  display:flex;align-items:center;gap:9px;
}
.step-num i{height:1px;background:var(--rule);flex:1;display:block}
.steps{display:flex;flex-direction:column;gap:34px;list-style:none}
@media (min-width:768px){ .steps{flex-direction:row;gap:26px} }
@media (min-width:1120px){ .steps{gap:44px} }

/* event chip switcher */
.chips{display:flex;flex-wrap:wrap;gap:7px;justify-content:center;list-style:none}
@media (min-width:1120px){ .chips{justify-content:flex-start} }
.chip{
  font-family:'Cinzel',serif;font-size:8px;letter-spacing:.18em;text-transform:uppercase;
  border:0.5px solid var(--rule);border-radius:20px;padding:8px 13px;
  color:var(--dim-on-navy);background:transparent;cursor:pointer;
}
.chip.on{border-color:var(--gold);color:var(--navy);background:var(--gold)}
.chip:focus-visible{outline:2px solid var(--gold-light);outline-offset:2px}
/* Rendered as list items until the gallery exists — nothing to click. */
li.chip{cursor:default}

/* ── The difference: text out, answers back ─────────────────────
   Two mocks side by side from 1120 up, stacked below it. They stack
   rather than shrink because the SMS bubble and the dashboard rows both
   stop being legible under about 300px — a two-column layout that has to
   be squinted at proves nothing. */
.loop{display:flex;flex-direction:column;gap:30px}
@media (min-width:1120px){ .loop{flex-direction:row;gap:44px;align-items:flex-start} }
.loopcol{flex:1;min-width:0}
.loop-label{
  font-family:'Cinzel',serif;font-size:9px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--gold);margin-bottom:14px;
}

/* SMS mock — markup, not an image, so the message stays crisp at any
   pixel density and can be selected and read out. It is also the one
   asset on this page that must track app behaviour: the bubble repeats
   what buildAutoSmsBody() composes in services/sharing.ts. */
.sms{border:0.5px solid var(--rule);border-radius:6px;background:var(--navy-card);padding:18px 16px}
.sms-from{
  font-family:'Lato',sans-serif;font-size:11px;letter-spacing:.1em;
  color:var(--dim-on-navy);text-align:center;margin-bottom:12px;
}
/* Tail on the bottom-left corner — a received message, not a sent one. */
.sms-bubble{
  background:rgba(201,153,58,.13);border:0.5px solid var(--rule-faint);
  border-radius:16px 16px 16px 4px;padding:13px 15px;max-width:88%;
}
.sms-bubble p{font-family:'Lato',sans-serif;font-size:13.5px;line-height:1.5;color:var(--cream);margin:0 0 11px}
.sms-detail{color:var(--body-on-navy)}
.sms-link{border:0.5px solid var(--rule);border-radius:5px;padding:10px 12px;background:rgba(8,15,29,.5)}
.sms-link-t{font-family:'Cormorant Garamond',serif;font-size:14px;color:var(--gold-pale);line-height:1.3}
.sms-link-u{font-family:'Lato',sans-serif;font-size:10.5px;color:var(--dim-on-navy);margin-top:4px}
.sms-meta{font-family:'Lato',sans-serif;font-size:10px;letter-spacing:.08em;color:var(--dim-on-navy);margin-top:9px;padding-left:2px}

/* Proof strip. The separators are ::before dots on the list items rather
   than <i> elements, so the row carries no empty markup and a screen
   reader hears five plain facts. */
.proof{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:10px 14px;margin-top:38px;padding-top:24px;list-style:none;
  border-top:1px solid var(--rule-faint);
}
.proof li{
  display:flex;align-items:center;gap:14px;
  font-family:'Cinzel',serif;font-size:9px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--gold-pale);white-space:nowrap;
}
.proof li+li::before{
  content:"";width:3px;height:3px;border-radius:50%;
  background:var(--gold);opacity:.6;display:block;
}

/* RSVP dashboard — pure CSS, no asset */
.dash{border:0.5px solid var(--rule);border-radius:5px;background:var(--navy-card);overflow:hidden}
.dash-head{padding:16px 18px;border-bottom:1px solid var(--rule-faint);display:flex;justify-content:space-between;align-items:center;gap:12px}
.dash-title{font-family:'Cormorant Garamond',serif;font-size:19px;color:var(--cream)}
.dash-sub{font-size:11px;margin-top:2px}
.dash-stats{display:flex;border-bottom:1px solid var(--rule-faint)}
.dstat{flex:1;padding:16px 8px;text-align:center;border-right:1px solid var(--rule-faint)}
.dstat:last-child{border-right:none}
.dstat b{display:block;font-family:'Cormorant Garamond',serif;font-weight:400;font-size:26px;color:var(--gold-light);line-height:1}
.dstat span{display:block;margin-top:6px;font-family:'Cinzel',serif;font-size:7px;letter-spacing:.2em;text-transform:uppercase;color:var(--dim-on-navy)}
.guest{display:flex;align-items:center;gap:12px;padding:13px 18px;border-bottom:1px solid var(--rule-faint)}
.guest:last-child{border-bottom:none}
.guest .gn{flex:1;font-family:'Lato',sans-serif;font-size:13px;color:var(--cream)}
.guest .gm{font-family:'Lato',sans-serif;font-size:11px;color:var(--dim-on-navy);display:block;margin-top:2px}
.pill{font-family:'Cinzel',serif;font-size:7px;letter-spacing:.16em;text-transform:uppercase;padding:5px 9px;border-radius:12px;border:0.5px solid var(--rule);color:var(--gold-light);white-space:nowrap}
.pill.no{color:var(--dim-on-navy);border-color:var(--rule-faint)}
.pill.wait{color:var(--text-light);border-color:var(--rule-faint)}

/* guest helper block */
.helper{border:0.5px solid var(--rule);border-radius:5px;padding:26px 22px;background:rgba(201,153,58,.05);text-align:center}
@media (min-width:1120px){ .helper{padding:36px 44px} }

/* feature list */
.flist{display:flex;flex-direction:column;gap:0;list-style:none}
.frow{display:flex;gap:14px;padding:16px 0;border-bottom:1px solid var(--rule-faint);align-items:flex-start}
.frow:last-child{border-bottom:none}
.frow .ficon{flex-shrink:0;margin-top:2px;line-height:0}
.frow .ft{font-family:'Cinzel',serif;font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--gold-pale);margin-bottom:6px}
.light .frow{border-color:var(--rule-dark)}
.light .frow .ft{color:var(--text-dark)}

/* accordion */
.acc{border-top:1px solid var(--rule-faint);list-style:none}
.acc-item{border-bottom:1px solid var(--rule-faint)}
.acc-q{
  width:100%;text-align:left;background:none;border:none;cursor:pointer;
  padding:18px 0;display:flex;gap:14px;align-items:center;
  font-family:'Cormorant Garamond',serif;font-size:19px;color:var(--cream);
}
.acc-q .pm{margin-left:auto;flex-shrink:0;color:var(--gold)}
.acc-a{padding:0 0 20px;max-width:640px}
.acc-item:not(.open) .acc-a{display:none}
.light .acc,.light .acc-item{border-color:var(--rule-dark)}
.light .acc-q{color:var(--text-dark)}
.acc-q:focus-visible{outline:2px solid var(--gold-light);outline-offset:2px}

/* pricing */
.tiers{display:flex;flex-direction:column;gap:12px;list-style:none}
@media (min-width:1120px){ .tiers{flex-direction:row;gap:14px} }
.tier{
  border:0.5px solid rgba(26,18,8,.16);border-radius:5px;padding:24px 22px;
  background:rgba(251,246,238,.7);display:flex;flex-direction:column;gap:8px;flex:1;position:relative;
}
.tier.feat{border-color:var(--gold);border-width:1px;background:#fff}
.tier-tag{
  position:absolute;top:-9px;left:22px;background:var(--gold);color:var(--navy);
  font-family:'Cinzel',serif;font-size:7px;letter-spacing:.2em;text-transform:uppercase;padding:4px 10px;border-radius:2px;
}
.tier-n{font-family:'Cinzel',serif;font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--text-dark)}
.tier-p{font-family:'Cormorant Garamond',serif;font-weight:400;font-size:38px;line-height:1;color:var(--text-dark)}
.tier-per{font-family:'Lato',sans-serif;font-size:12px;color:var(--text-light);letter-spacing:.04em}
.tier-note{font-size:13px;margin-top:6px}
/* Five tiers across at desktop is tighter than the four the design was
   drawn for — ease the price size so $149.99 never wraps. */
@media (min-width:1120px){ .tiers-5 .tier-p{font-size:34px} }

/* the support page's email address, set as a display line */
.support-mail{
  font-family:'Cormorant Garamond',serif;font-size:26px;color:var(--text-dark);
  text-decoration:none;border-bottom:1px solid var(--gold);align-self:flex-start;
}
.support-mail:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

.ptable{border:0.5px solid rgba(26,18,8,.16);border-radius:5px;overflow:hidden;background:#fff;width:100%;border-collapse:collapse}
.ptable th,.ptable td{
  text-align:left;padding:13px 14px;border-bottom:1px solid var(--rule-dark);
  font-family:'Lato',sans-serif;font-weight:300;font-size:13px;color:var(--text-mid);vertical-align:top;
}
.ptable tr:last-child th,.ptable tr:last-child td{border-bottom:none}
.ptable thead tr{background:rgba(201,153,58,.10)}
/* Column headings sit a step ABOVE the body text, not four steps below it.
   At 8px they read as a caption for the table rather than as its headings —
   the widest tracking on the site applied to the smallest type on it. The
   tracking comes in as the size goes up, because .18em on 14px Cinzel is a
   different object from .18em on 8px, and would push "150 GUESTS, ONE SEND"
   past its column. */
.ptable thead th{font-family:'Cinzel',serif;font-weight:400;font-size:14px;letter-spacing:.10em;text-transform:uppercase;color:var(--text-dark)}
.ptable tbody th{font-weight:400;color:var(--text-dark)}
.ptable .num{text-align:right;width:110px;white-space:nowrap}
.ptable thead .num{text-align:right}

/* Comparison tables carry a third column, so the fixed .num width widens and
   the row for our own product is marked rather than styled inline. */
.ptable-compare{min-width:520px}
.ptable-compare .num{width:130px}

/* ─── The TinselVite row ───────────────────────────────────────
   This row is the argument the table exists to make, so it stops being a
   line item and becomes the band the rows above build toward: solid gold
   ground, and the wordmark lockup in place of the plain name. It stays LAST
   on purpose — the punchline reads after the bills, not before them.

   The gold ground is the ONLY emphasis device here, and that is deliberate.
   An earlier pass stacked three — gold, a gradient, and the price at 34px —
   which took the row to 1.74x the height of every other and set $3.99 2.6x
   larger than $249. Two things went wrong. The row left the comparison: a
   comparison table only works while its rows stay commensurable, and a
   banner under the table proves nothing about the rows above it. And the
   emphasis inverted, rendering the smallest number in the column as the
   biggest object on the page — the eye reads "big" exactly where the copy
   wants "small". Restraint sells cheap; scale sells expensive.

   So: flat gold, 15px padding, 22px price. Still the largest figure in its
   column and unmistakably the answer, but inside the table's rhythm at
   roughly 1.2x a normal row. If this needs more weight, take it from
   contrast or position, NOT from size.

   The lockup goes solid navy here. The gold V is a device for navy and
   cream grounds; on the gold itself it would disappear, and cream-on-gold
   is 2.6:1, under AA. Navy on gold is 6.9:1. The V still reads as the V
   because the lockup's letterforms carry it, not its colour.

   Both copies of the comparison table (home and /pricing) share this by
   design — same claim, same treatment. Keep them in step. */
.ptable tr.ours{background:var(--gold)}
.ptable tr.ours th,.ptable tr.ours td{
  color:var(--navy);vertical-align:middle;
  padding-top:15px;padding-bottom:15px;
  border-bottom:none;border-top:1px solid rgba(26,18,8,.22);
}
.ptable tr.ours td{font-weight:400}
.ptable tr.ours .num{
  font-family:'Cormorant Garamond',serif;font-weight:400;
  font-size:22px;line-height:1.1;color:var(--navy);
}

/* Mark + wordmark, locked up at row scale. The .sr-only name in the cell
   carries the row header for screen readers, so this lockup is decorative. */
.ours-brand{display:flex;align-items:center;gap:9px}
.ours-mark{display:flex;flex:none}
.ptable tr.ours .wordmark{display:inline-flex}
.ptable tr.ours .wordmark .wm,
.ptable tr.ours .wordmark .vee{color:var(--navy)}
.wm-row{font-size:15px}
.wm-row .vee{font-size:15px}
@media (max-width:520px){ .wm-row,.wm-row .vee{font-size:14px} }


/* ─── The comparison table on a phone ──────────────────────────
   At 390px the wrap is 342px wide and this table's min-width is 520px, so it
   scrolls — and the price column, the entire payload of the comparison, sits
   off the right edge until you swipe for it. A centerpiece you have to go
   looking for is not one.

   Below the breakpoint the "How it's priced" column is dropped so Platform
   and price fit the measure with no scroll at all. That column is
   explanatory, not comparative — the prose above the table and the citation
   below both carry it.

   The gold row does NOT get to keep that column as a second line of its own.
   An earlier pass gave it one, which wrapped and took the row to 1.93x the
   height of its neighbours — the same bloat this file argues against above,
   on the surface where it matters most. Special-pleading one row back into a
   column that was dropped for every other is what caused it. */
@media (max-width:560px){
  .ptable-compare{min-width:0}
  .ptable-compare th:nth-child(2),.ptable-compare td:nth-child(2){display:none}
  .ptable-compare .num{width:auto}
  .ptable-compare th,.ptable-compare td{padding-left:12px;padding-right:12px}
  .ptable tr.ours .num{font-size:21px}
  /* .num is nowrap so a price like $36–192/yr never breaks mid-figure. The
     HEADING over it has no such need, and at 14px "150 GUESTS, ONE SEND"
     held on one line is wide enough on its own to push the table back into
     horizontal scroll. Let the heading wrap; the prices still cannot. */
  .ptable thead .num{white-space:normal}
}

/* Source line under a cited table. Every figure on this site is attributable;
   this is where the attribution goes, and where the check date lives. */
.cite{font-size:12px;line-height:1.65;color:var(--text-light)}
.cite a{color:var(--text-mid)}

/* Wide tables scroll inside their own box rather than the page. */
.table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* ══════════════════════════════════════════════════════════════
   FOOTER
   ══════════════════════════════════════════════════════════════ */
.foot{background:var(--navy);border-top:1px solid var(--rule-faint);padding:48px 0 34px}
.foot-grid{display:flex;flex-direction:column;gap:32px}
@media (min-width:1120px){
  .foot-grid{flex-direction:row;gap:60px}
  .foot-brand{flex:1.4}
}
.foot-col{display:flex;flex-direction:column;gap:11px;flex:1;list-style:none}
.foot-col a{font-family:'Lato',sans-serif;font-size:13px;color:var(--body-on-navy);text-decoration:none}
.foot-col a:hover{color:var(--cream)}
.foot-col a:focus-visible{outline:2px solid var(--gold-light);outline-offset:3px}
.foot-h{font-family:'Cinzel',serif;font-size:9px;letter-spacing:.24em;text-transform:uppercase;color:var(--gold);margin-bottom:3px}
.foot-legal{margin-top:34px;padding-top:22px;border-top:1px solid var(--rule-faint);display:flex;flex-direction:column;gap:8px}
@media (min-width:1120px){ .foot-legal{flex-direction:row;justify-content:space-between;align-items:center} }
.foot-mail{color:var(--gold-light);text-decoration:none}
.foot-wait{color:var(--dim-on-navy)}

/* the compact footer used on the static pages */
.foot-mini{background:var(--navy)}
.foot-mini .foot-legal{border:none;margin:0;padding:34px 0}
.foot-mini a{color:var(--gold);text-decoration:none}
.foot-mini a:hover{text-decoration:underline}

/* ══════════════════════════════════════════════════════════════
   LEGAL PAGES — privacy.html / terms.html
   Long-form prose on the light ground, brand type throughout.
   ══════════════════════════════════════════════════════════════ */
.legal{max-width:760px;margin:0 auto}
.legal h1{
  font-family:'Cormorant Garamond',serif;font-weight:300;font-size:38px;line-height:1.12;
  color:var(--text-dark);text-align:center;margin-bottom:12px;
}
.legal .dates{
  text-align:center;font-family:'Cinzel',serif;font-size:9px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--text-light);margin:0 0 44px;
}
.legal h2{
  font-family:'Cinzel',serif;font-weight:400;font-size:12px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--text-dark);
  margin:38px 0 12px;padding-bottom:9px;border-bottom:1px solid var(--rule-dark);
}
.legal h3{
  font-family:'Cinzel',serif;font-weight:400;font-size:10px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--text-mid);margin:26px 0 10px;
}
.legal p{font-family:'Lato',sans-serif;font-weight:300;font-size:15px;line-height:1.72;color:var(--text-mid);margin:0 0 14px}
.legal p.indent{margin-left:24px}
.legal a{color:var(--gold);text-decoration:underline}
.legal address{font-style:normal;margin:14px 0;font-family:'Lato',sans-serif;font-weight:300;font-size:15px;line-height:1.72;color:var(--text-mid)}
.legal strong,.legal b{font-weight:400;color:var(--text-dark)}
.legal .callout{
  border-left:2px solid var(--gold);background:rgba(201,153,58,.09);
  padding:14px 18px;margin:18px 0;
}
.legal ul,.legal ol{margin:0 0 14px 22px;font-family:'Lato',sans-serif;font-weight:300;font-size:15px;line-height:1.72;color:var(--text-mid)}
.legal li{margin-bottom:7px}
/* the all-caps arbitration / disclaimer blocks in terms.html */
.legal .caps-warning{
  background:#faf4e6;border:0.5px solid var(--rule);border-radius:4px;
  padding:14px 18px;margin:0 0 18px;font-size:13px;line-height:1.66;color:var(--text-dark);
}
.legal .toplinks{margin:0 0 34px;text-align:center}
.legal .toplinks a{
  font-family:'Cinzel',serif;font-size:9px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--gold);text-decoration:none;border-bottom:1px solid var(--rule);
}
.legal > footer{
  margin-top:44px;padding-top:22px;border-top:1px solid var(--rule-dark);
  font-family:'Lato',sans-serif;font-weight:300;font-size:13px;color:var(--text-light);text-align:center;
}

/* ══════════════════════════════════════════════════════════════
   A REAL INVITATION — the two-tab example viewer
   Content comes from public/marketing/, committed. Nothing here
   fetches, so there is no loading or error state to style.
   ══════════════════════════════════════════════════════════════ */

/* The copy column leads on mobile and tablet; at desktop the viewer moves
   beside it. Mirrors .cols-2 rather than introducing a second grid. */
@media (min-width:1120px){ .ex-cols{gap:60px} }
.ex-viewer-col{display:flex;flex-direction:column;align-items:center}

/* Panel width is fixed per breakpoint so the card and the details panel are
   the same object at two sizes — a viewer that resized between tabs would
   read as two different things. */
/* On a phone the card is shown at exactly the size a guest sees it.
   `min(100vw - 32px, 480px)` is not an approximation — it is the guest
   page's own formula, copied:

       app/(guest)/invite/[id].tsx:164
       const cardWidth = Math.min(screenWidth - 32, 480);

   It was 270px, which made the flagship example read as a thumbnail of an
   invitation rather than the invitation. The point of the section is that
   this is what lands in a guest's messages, and that only carries if it is
   the size it will actually be.

   The column breaks out of .wrap's 24px padding to allow it. 100vw includes
   any scrollbar, so the desktop widths below stay fixed — this applies to
   phones only, where there is no scrollbar gutter to worry about. */
.ex-viewer{width:min(calc(100vw - 32px), 480px)}
@media (max-width:767px){
  .ex-viewer-col{margin-left:-24px;margin-right:-24px}
}
@media (min-width:768px){ .ex-viewer{width:300px} }
@media (min-width:1120px){ .ex-viewer{width:340px} }

.ex-tabs{
  display:flex;margin-bottom:14px;
  border:0.5px solid var(--rule);border-radius:4px;overflow:hidden;
}
.ex-tab{
  flex:1;appearance:none;background:transparent;border:0;cursor:pointer;
  /* 10px horizontal at mobile, not 18: half of a 270px viewer leaves ~99px of
     text room at 18, and "THE INVITATION" needs ~109 at this size, so it
     wrapped to two lines while its neighbour stayed on one. */
  padding:12px 10px;
  font-family:'Cinzel',serif;font-size:9px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--dim-on-navy);
  white-space:nowrap;
}
@media (min-width:768px){ .ex-tab{padding:12px 18px} }
.ex-tab + .ex-tab{border-left:0.5px solid var(--rule)}
.ex-tab.on{background:var(--gold);color:var(--navy)}
.ex-tab:focus-visible{outline:2px solid var(--gold-light);outline-offset:-2px}

/* Both panels stay mounted; [hidden] does the swap. Declared explicitly
   because the flex display below would otherwise beat the UA's
   [hidden]{display:none}. */
.ex-panel[hidden]{display:none}

.ex-card{width:100%;height:auto;border-radius:2px;display:block}

/* Tracks the viewer's width at every breakpoint. Pinned to 270 it wrapped
   early under the 340 panel on desktop, which read as a stray third column
   rather than a caption belonging to the thing above it. */
.ex-caption{
  margin-top:14px;text-align:center;width:min(calc(100vw - 32px), 480px);
  color:var(--dim-on-navy);
}
@media (min-width:768px){ .ex-caption{width:300px} }
@media (min-width:1120px){ .ex-caption{width:340px} }

/* ── The details panel ──
   Stationery, not UI: cream ground, a hairline frame inset from the edge,
   and the same Cormorant the card uses. */
.ex-details{
  position:relative;background:#FDFCF9;border-radius:2px;
  padding:30px 30px 34px;
}
.ex-rule{
  position:absolute;inset:11px;border:1px solid rgba(176,148,90,0.55);
  pointer-events:none;
}
.ex-dtitle{
  font-family:'Cormorant Garamond',serif;font-weight:400;
  font-size:12px;letter-spacing:.34em;text-transform:uppercase;
  color:#4A4034;text-align:center;margin:0;
}
.ex-hair{width:34px;height:1px;background:rgba(176,148,90,0.75);margin:9px auto 0}
.ex-sec{margin-top:22px}
.ex-label{
  font-family:'Cormorant Garamond',serif;font-weight:400;
  font-size:9.5px;letter-spacing:.3em;text-transform:uppercase;
  color:#A88C4E;text-align:center;margin:0 0 7px;
}
.ex-body{
  font-family:'Cormorant Garamond',serif;font-weight:400;
  font-size:12.5px;line-height:1.62;color:#2A251E;
  text-align:center;margin:0;
}
/* The opening section carries slightly more presence, as it does on the
   card itself. */
.ex-first{font-size:13.5px;color:#1F1B15}
/* Long prose gets a left edge to return to — the same rule the app applies
   past four rendered lines. Carried from example-details.json's `align`. */
.ex-left{text-align:left}
.ex-link{color:inherit;text-decoration:underline;text-decoration-color:rgba(176,148,90,0.8)}
