/* ---------------------------------------------------------------------------
   styles.css — shared by all three pages.
   Ported from the prototype. The card rules are the fiddly part; leave them be.
--------------------------------------------------------------------------- */

:root{
  --paper:#FBF9F6; --paper-2:#F4F0E9; --ink:#17171A; --ink-60:#5C5C63;
  --ink-35:#9A9AA2; --line:#E4DED4; --clay:#C2603D; --clay-dk:#A44E2F;
  --ok:#4F7A5C; --bad:#A4342F;
  --shadow:0 1px 2px rgba(23,23,26,.04),0 8px 28px rgba(23,23,26,.07);
  --shadow-lg:0 2px 4px rgba(23,23,26,.05),0 24px 60px rgba(23,23,26,.13);
  --serif:ui-serif,Georgia,'Iowan Old Style','Times New Roman',serif;
  --sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Inter,system-ui,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--paper);color:var(--ink);font-family:var(--sans);font-size:15px;
  line-height:1.5;-webkit-font-smoothing:antialiased}
button{font-family:inherit;font-size:inherit;cursor:pointer;border:none;background:none;color:inherit}
input,textarea{font-family:inherit;font-size:inherit;color:inherit}
a{color:var(--clay)}

.wrap{max-width:1100px;margin:0 auto;padding:40px 22px 90px}

/* The flash banner borrows .wrap for its width, not its spacing. Inheriting
   the 90px bottom padding meant for the end of a page put 130px of nothing
   between "Payment received" and the heading underneath it. */
#flash{padding:24px 22px 0}
#flash + .wrap{padding-top:18px}
h1{font-family:var(--serif);font-size:36px;font-weight:400;letter-spacing:-.022em;line-height:1.1}
h2{font-family:var(--serif);font-size:22px;font-weight:400;letter-spacing:-.015em}
.lede{color:var(--ink-60);font-size:16px;max-width:58ch;margin-top:10px}
/* 13px, up from 11. Uppercase with heavy tracking is already hard work to
   read; at 11px it was decoration rather than a label. */
.eyebrow{font-size:13px;letter-spacing:.12em;text-transform:uppercase;color:var(--clay);
  font-weight:650;display:block}
.hint{font-size:12.5px;color:var(--ink-35);line-height:1.45}

.brand{font-family:var(--serif);font-size:21px;display:flex;align-items:center;gap:8px;
  text-decoration:none;color:var(--ink)}
/* The full lockup — camera and wordmark — as the header brand.

   Drawing the logo means the HTML text has to go, or the name appears twice.
   It's still in the markup inside .vh so screen readers announce it; it just
   isn't painted.

   Real vector paths with no background, so it sits directly on the paper.
   That's what makes contain safe: there's nothing behind it to letterbox
   against, so the ratio here and the ratio in the file don't have to be
   kept in lockstep the way they did when this was a coloured plate.

   88x48.6 is the artwork's own 1.81:1. The camera takes most of that height,
   so the script only reads at about 20px — which is the floor for a
   connected script and the reason the header had to grow from 68 to 74. */
.brand i{
  width:88px;height:48.6px;flex:0 0 auto;display:block;
  background:url("/logo-lockup.svg") center/contain no-repeat
}

/* Visually hidden, still announced. The wordmark lives in the artwork now,
   but a link whose only content is a background image says nothing to a
   screen reader. */
.vh{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0
}
.topbar{border-bottom:1px solid var(--line);background:rgba(251,249,246,.9);
  position:sticky;top:0;z-index:20;backdrop-filter:blur(10px)}
/* 74px. Sized off the logo, not the other way round: the lockup box is
   48.6px and wants ~12px of air above and below. Anything anchored
   to the header offset moves with it — see .stagecol and design.html's
   scroll-margin-top. */
.topbar-in{max-width:1100px;margin:0 auto;padding:0 22px;height:74px;display:flex;
  align-items:center;justify-content:space-between;gap:16px}

/* --- buttons ------------------------------------------------------------- */
.btn{background:var(--ink);color:var(--paper);padding:11px 22px;border-radius:99px;
  font-size:14px;font-weight:550;display:inline-flex;align-items:center;gap:8px;transition:.15s}
.btn:hover{background:#000;transform:translateY(-1px)}
.btn.clay{background:var(--clay)}
.btn.clay:hover{background:var(--clay-dk)}
.btn.ghost{background:transparent;color:var(--ink);border:1px solid var(--line)}
.btn.ghost:hover{background:var(--paper-2);transform:none}
.btn.sm{padding:8px 15px;font-size:13px}
.btn:disabled{opacity:.45;pointer-events:none}

/* --- forms --------------------------------------------------------------- */
.fset{border:1px solid var(--line);border-radius:12px;padding:18px;background:#fff;margin-bottom:18px}
.fset > .eyebrow{margin-bottom:14px}
.field{margin-bottom:13px}
.field:last-child{margin-bottom:0}
.field label{display:block;font-size:11.5px;font-weight:600;color:var(--ink-60);margin-bottom:5px}
.field input,.field textarea{width:100%;padding:9px 12px;border:1px solid var(--line);
  border-radius:7px;background:var(--paper);font-size:14px;transition:.15s}
.field input:focus,.field textarea:focus{outline:none;border-color:var(--clay);background:#fff;
  box-shadow:0 0 0 3px rgba(194,96,61,.1)}
.field textarea{resize:vertical;min-height:56px}
.row2{display:grid;grid-template-columns:1fr 1fr;gap:10px}

/* Palette swatches. The selected ring uses outline, never box-shadow —
   the inline style on each swatch would override a box-shadow. */
.swatches{display:flex;gap:11px;flex-wrap:wrap;margin-bottom:22px}
.sw{width:38px;height:38px;border-radius:50%;position:relative;transition:.15s;
  border:1px solid rgba(0,0,0,.09);outline:2px solid transparent;outline-offset:3px}
.sw:hover{transform:scale(1.1)}
.sw.on{outline-color:var(--ink)}
.sw.on::after{content:"✓";position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;font-size:15px;font-weight:700;color:var(--sw-ink)}
.sw span{position:absolute;inset:auto 0 -19px;font-size:9.5px;color:var(--ink-35);text-align:center}
.sw.on span{color:var(--ink);font-weight:700}

.chips{display:flex;gap:7px;flex-wrap:wrap}
.chips button{font-size:12px;padding:6px 12px;border-radius:99px;border:1px solid var(--line);
  color:var(--ink-60);background:var(--paper);transition:.15s}
.chips button:hover{border-color:var(--ink-35);color:var(--ink)}
.chips button.on{background:var(--ink);color:var(--paper);border-color:var(--ink)}

/* --- layout -------------------------------------------------------------- */
/* Shared by the designer and the dashboard, and the first column means
   different things on each — the form on one, the preview on the other. Don't
   narrow it to suit one page without checking the other. */
.split{display:grid;grid-template-columns:340px 1fr;gap:40px;align-items:start;margin-top:32px}
/* Header height (74) + 18. Sticks below the bar rather than under it. */
.stagecol{position:sticky;top:92px}
.stage{display:flex;flex-direction:column;align-items:center;gap:14px;padding:22px 20px;
  background:var(--paper-2);border-radius:16px;border:1px solid var(--line)}

/* THE IMPORTANT ONE. .card sizes its type in cqw units against its own width,
   so its container needs a definite width or everything computes to zero and
   the card renders blank. Always wrap a card in .pv */
/* --- the guest album ----------------------------------------------------
   Phone-first without apology. This page is used one-handed, at night, in a
   crowded room, by someone holding a drink. Big targets, high contrast, no
   layout that depends on a wide viewport.
------------------------------------------------------------------------ */
.album-page{max-width:560px;margin:0 auto;padding:22px 18px 40px}
.album-head{text-align:center;margin-bottom:22px}
.album-head h1{font-size:26px;margin-top:8px;line-height:1.15}

/* Deliberately large. A small button is hard to hit while holding a drink,
   and this is the only thing on the page anyone needs to press. */
.shootbtn{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:3px;margin-top:18px;padding:26px 18px;cursor:pointer;
  border:1.5px dashed var(--line);border-radius:5px;
  background:var(--paper-2,#fbf8f3);
  text-align:center;transition:border-color .15s,background .15s
}
.shootbtn:hover,.shootbtn:active{border-color:var(--clay);background:#fff}
/* Used up their allowance. Still visible, clearly not actionable. */
.shootbtn.spent{opacity:.55;cursor:default;border-style:solid}
.shootbtn.spent:hover{border-color:var(--line);background:var(--paper-2,#fbf8f3)}
.shootbtn span{font-size:17px;font-weight:600;letter-spacing:-.01em}
.shootbtn small{font-size:13px;color:var(--ink-35)}

.thumbs{
  display:grid;gap:8px;margin-top:10px;
  grid-template-columns:repeat(auto-fill,minmax(96px,1fr))
}
.thumb{position:relative;aspect-ratio:1;border-radius:4px;overflow:hidden;background:var(--line)}
.thumb img{width:100%;height:100%;object-fit:cover;display:block}

/* Anything not yet safely on the server is dimmed, so "sent" and "sending"
   are never confused at a glance. */
.thumb.sending img,.thumb.retry img,.thumb.waiting img{opacity:.45}
.thumb.failed img{opacity:.3}
.thumb.failed{cursor:pointer;outline:1.5px solid var(--bad)}

.thumb .badge{
  position:absolute;left:0;right:0;bottom:0;padding:5px 6px;
  font-size:10.5px;line-height:1.25;text-align:center;
  background:rgba(0,0,0,.66);color:#fff
}
.thumb .drop{
  position:absolute;top:4px;right:4px;width:24px;height:24px;
  border:0;border-radius:50%;cursor:pointer;
  background:rgba(0,0,0,.55);color:#fff;font-size:16px;line-height:1;
  display:flex;align-items:center;justify-content:center
}
.thumb .drop:hover{background:rgba(0,0,0,.8)}

/* --- the host's album grid ----------------------------------------------
   Denser than the guest grid. The host is triaging hundreds of photos and
   wants as many on screen at once as they can still judge.
------------------------------------------------------------------------ */
.grid-photos{
  display:grid;gap:6px;margin-top:22px;
  grid-template-columns:repeat(auto-fill,minmax(140px,1fr))
}
.ph{position:relative;margin:0;aspect-ratio:1;border-radius:3px;overflow:hidden;
    background:var(--line);cursor:zoom-in}
.ph img{width:100%;height:100%;object-fit:cover;display:block;
        transition:transform .25s ease}
.ph:hover img{transform:scale(1.04)}

/* Always visible on touch — a hover-only control is unusable on the device
   half these hosts will be culling from. */
.ph-x{
  position:absolute;top:5px;right:5px;width:26px;height:26px;
  border:0;border-radius:50%;cursor:pointer;
  background:rgba(0,0,0,.55);color:#fff;font-size:15px;line-height:1;
  display:flex;align-items:center;justify-content:center;
  opacity:.85;transition:opacity .15s,background .15s
}
.ph-x:hover{opacity:1;background:rgba(0,0,0,.85)}

.lightbox{
  position:fixed;inset:0;z-index:50;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:14px;padding:26px;background:rgba(20,18,16,.93)
}
.lightbox[hidden]{display:none}
.lightbox img{max-width:100%;max-height:calc(100vh - 120px);
              object-fit:contain;border-radius:3px}
.lightbar{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.lightbar .btn{background:rgba(255,255,255,.92)}

/* --- the printable card sheet -------------------------------------------
   Hidden on screen, and the only thing on the page when printing. Sizes are
   in inches because the output is a physical object that has to be cut with
   scissors — using pixels here and hoping is how you get cards that don't
   fit the holders.
------------------------------------------------------------------------ */
.sheet{display:none}
.sheet img{display:block;width:4in;height:6in}

@media print{
  /* Everything that isn't the sheet disappears. */
  .noprint{display:none !important}
  .sheet[hidden]{display:none}
  .sheet{
    display:grid;justify-content:center;align-content:start;
    gap:0.18in;padding:0.2in
  }
  .sheet.per2{grid-template-columns:1fr}
  .sheet.per4{grid-template-columns:repeat(2,4in)}
  .sheet.per6{grid-template-columns:repeat(2,4in)}

  /* Six 6-inch-tall cards won't fit on a page at full size, so shrink that
     option to a 3x2in card. Still comfortably scannable, and it's the option
     someone picks when they want a lot of them cheaply. */
  .sheet.per6 img{width:3in;height:4.5in}
  .sheet.per6{grid-template-columns:repeat(2,3in)}

  @page{margin:0.25in}
  body{background:#fff}
}

/* --- the landing page ----------------------------------------------------
   Centred and vertical rather than the usual copy-left / picture-right,
   because the pictures ARE the argument here and splitting the page in two
   halves the size they can be.
------------------------------------------------------------------------ */

.hero{
  border-bottom:1px solid var(--line);
  background:var(--paper-2,#fbf8f3);
  overflow:hidden                       /* the fan tilts past the edges */
}
/* Bottom padding so the cards finish inside the hero. They were sitting on a
   -30px margin against overflow:hidden, which sliced the bottom off all three
   — including the printed address, which is the thing the first bullet below
   is talking about. */
.hero-in{max-width:900px;margin:0 auto;padding:44px 22px 38px;text-align:center}
.hero h1{
  font-size:clamp(38px,6.6vw,68px);line-height:1.0;letter-spacing:-.03em;margin:0
}
.hero-sub{
  margin:14px auto 0;max-width:30ch;
  font-size:clamp(16px,2.1vw,19px);color:var(--ink-55)
}
.hero-cta{margin-top:22px;display:flex;gap:12px;flex-wrap:wrap;justify-content:center}

.btn.lg{padding:13px 26px;font-size:15.5px}

/* Sits in the header beside "Sign in" without making the bar taller. */
.btn.xs{padding:6px 13px;font-size:13px;text-decoration:none}
.topbar-in .hint{display:flex;align-items:center;gap:14px}

/* Three real invitations, overlapped and tilted, cycling through templates.
   The middle card sits forward and larger — a flat row of three equal cards
   reads as a product grid, which is the opposite of the intended feeling. */
.fan{
  margin:34px auto 0;
  display:flex;align-items:flex-end;justify-content:center;
  gap:18px;
  transition:opacity .4s ease
}
.fan.swapping{opacity:0}
.fan canvas{
  display:block;border-radius:4px;background:#fff;
  box-shadow:0 20px 46px rgba(60,40,24,.19)
}
/* The cards no longer overlap. They used to tuck 30px under each other, which
   put one card's text underneath its neighbour — the tilt made it look like
   the type was colliding. A gap plus the rotation still reads as a spread
   without anything covering anything. */
.fan .fan-a{transform:rotate(-6deg);z-index:1}
.fan .fan-b{transform:translateY(-20px);z-index:3}
.fan .fan-c{transform:rotate(6deg);z-index:2}

/* The band butts straight against the hero. .wrap's own 40px top padding was
   stacking with the band's, putting 70px of nothing between the cards and the
   first line of text. */
.hero + .wrap{padding-top:0}

/* A compact band, not a section. It was floating in 70px of margin above and
   below, which made three short lines look like a chapter break. */
.beats{
  display:grid;gap:26px 34px;
  margin:0 -22px;padding:30px 22px;
  border-bottom:1px solid var(--line);
  grid-template-columns:repeat(auto-fit,minmax(220px,1fr))
}
.beats div{display:flex;flex-direction:column;gap:3px}
.beats b{font-size:16px;letter-spacing:-.01em}
.beats span{font-size:14.5px;line-height:1.5;color:var(--ink-55);max-width:32ch}

.center{text-align:center}
.lede.center{margin-left:auto;margin-right:auto}

/* Section labels on the landing page carry more weight than elsewhere — they
   are the only thing naming each block. Tracking eases off as the size goes
   up, because .12em that reads as deliberate at 13px reads as loose at 15. */
.hero .eyebrow,
.feature .eyebrow,
.price .eyebrow{font-size:15px;letter-spacing:.085em}
.price .eyebrow{margin-bottom:2px}

/* No border-top: the band above already ends in one, and two rules 60px apart
   reads as an empty section rather than a divider. */
.feature{
  display:grid;gap:44px;align-items:center;margin-top:0;padding-top:54px;
  grid-template-columns:1.1fr .9fr
}
.feature h2{
  font-size:clamp(26px,4vw,40px);line-height:1.06;letter-spacing:-.024em;
  margin:8px 0 0
}
.feature .lede{font-size:16px;margin-top:14px;max-width:34ch}
.feature .btn{margin-top:20px}
.feature-art{display:flex;justify-content:center}
.feature-art canvas{
  display:block;max-width:100%;border-radius:4px;
  box-shadow:0 16px 38px rgba(60,40,24,.16);
  transform:rotate(2deg)
}

.prices{
  display:grid;gap:14px;margin-top:24px;
  grid-template-columns:repeat(auto-fit,minmax(210px,1fr))
}
.price{padding:22px;border:1px solid var(--line);border-radius:5px;background:#fff}
/* The middle tier is the one that carries the business, so it gets the weight. */
.price.on{border-color:var(--clay);box-shadow:0 6px 20px rgba(140,74,38,.09)}
.price b{display:block;margin:8px 0 12px;font-size:34px;letter-spacing:-.02em}
.price ul{margin:0;padding-left:17px}
.price li{font-size:13.8px;line-height:1.75;color:var(--ink-55)}

.closer{
  margin:44px 0 0;padding:38px 22px 8px;text-align:center;
  border-top:1px solid var(--line)
}
.closer h2{font-size:clamp(26px,4vw,38px);letter-spacing:-.022em;margin-bottom:20px}

/* The landing page's own vertical rhythm. .wrap's 90px bottom padding and the
   footer's 56px top margin are right for the app pages, where content ends
   abruptly; here they stacked with the closer's own spacing and left a screen
   of nothing under the last button. */
.hero + .wrap{padding-bottom:24px}
.hero ~ .sitefoot{margin-top:24px}

@media (max-width:860px){
  .feature{grid-template-columns:1fr;gap:30px}
  .hero-in{padding:44px 18px 0}
  .fan{margin-top:40px;gap:10px}
  /* One card on a phone. Three at a third of the width would be illegible,
     and an invitation you can't read isn't advertising anything. */
  .fan .fan-a,.fan .fan-c{display:none}
  .fan .fan-b{transform:none}
  .feature-art canvas{transform:none}
}

/* The closing panel on the guest album — the page's ending, so it reads as
   somewhere to stop rather than somewhere that ran out. */
.after-box{
  margin-top:28px;padding:18px 18px 16px;
  border:1px solid var(--line);border-radius:5px;background:var(--paper-2,#fbf8f3)
}
.after-box b{font-size:16px}
.after-box p{margin:6px 0 0;font-size:14.5px;line-height:1.55;color:var(--ink-55)}
.after-box .hint{margin-top:8px}

/* --- who can manage an event --------------------------------------------- */
.members{list-style:none;margin:10px 0 0;padding:0;max-width:520px}
.members li{
  display:flex;align-items:center;gap:12px;
  padding:11px 0;border-bottom:1px solid var(--line);font-size:14.5px
}
.members li:last-child{border-bottom:0}
.members li > span:first-child{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
.members .role{
  font-size:11.5px;letter-spacing:.07em;text-transform:uppercase;
  color:var(--ink-35);flex:0 0 auto
}

/* A button that reads as a link — for secondary actions that would look
   heavy-handed as a real button next to the thing they act on. */
.linky{
  border:0;background:none;padding:0;font:inherit;font-size:inherit;
  color:var(--clay);text-decoration:underline;cursor:pointer
}
.linky:hover{opacity:.75}
.linky[disabled]{opacity:.5;cursor:default}

/* Quiet, but present on every page the public lands on. */
.sitefoot{
  max-width:1080px;margin:56px auto 30px;padding:18px 22px 0;
  border-top:1px solid var(--line);
  font-size:12.5px;text-align:center
}
.sitefoot a{color:var(--ink-35);text-decoration:none}
.sitefoot a:hover{color:var(--ink-55);text-decoration:underline}

/* --- the paywall --------------------------------------------------------
   Sits where the share link will be, so activating fills the gap it left
   rather than making something new appear. Not a modal, not an overlay:
   the invite behind it stays fully visible, because seeing the finished
   thing is what makes the price feel reasonable.
------------------------------------------------------------------------ */
.paywall{
  margin:24px 0 4px;padding:20px 22px;max-width:620px;
  display:flex;gap:22px;align-items:center;justify-content:space-between;
  flex-wrap:wrap;
  border:1px solid var(--line);border-radius:4px;
  background:var(--paper-2, #fbf8f3)
}
.paywall b{display:block;font-size:16.5px;letter-spacing:-.01em}
.paywall p{margin:6px 0 0;font-size:14px;line-height:1.55;color:var(--ink-55);max-width:42ch}
.paywall .btn{flex:0 0 auto;white-space:nowrap}
.paywall .msg{flex:1 0 100%;margin:4px 0 0}

/* The bundle chooser. Stacks the price above the label so the three options
   can be compared at a glance rather than read. */
/* Full width, unlike the plain .paywall. Three priced options squeezed into
   620px of a 1100px page left a third of the row empty and made the choice
   look like a footnote. */
.paywall-choose{
  display:flex;flex-wrap:wrap;gap:16px;align-items:stretch;
  max-width:none;padding:22px 24px
}
.paywall-choose > div:first-child p{max-width:60ch}
.bundles{
  display:grid;gap:10px;width:100%;
  grid-template-columns:repeat(auto-fit,minmax(170px,1fr))
}
.bundle{
  display:flex;flex-direction:column;gap:3px;text-align:left;cursor:pointer;
  padding:14px 15px;border:1px solid var(--line);border-radius:5px;
  background:#fff;font:inherit;transition:border-color .14s,box-shadow .14s
}
.bundle:hover{border-color:var(--ink-35)}
.bundle.on{border-color:var(--clay);box-shadow:0 0 0 1px var(--clay) inset}
.bundle-price{font-size:23px;letter-spacing:-.02em;line-height:1.1}
.bundle b{font-size:14px;letter-spacing:-.005em}
.bundle-blurb{font-size:12.5px;line-height:1.4;color:var(--ink-35)}
.paywall .testnote{
  margin-top:10px;font-size:12.5px;color:var(--ink-35);
  padding-top:9px;border-top:1px dashed var(--line)
}
.paywall .testnote code{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;
  background:rgba(0,0,0,.05);padding:1px 5px;border-radius:3px
}

/* Hour / minutes / am-pm across the full field width.

   auto-fit with a 84px floor rather than three equal fractions: a select
   needs room for its widest option plus the browser's dropdown arrow, and
   below roughly 80px the arrow starts covering the text. If the panel is ever
   too narrow for three, they wrap instead of shrinking into illegibility. */
.timepick{display:grid;grid-template-columns:repeat(3,minmax(84px,1fr));gap:8px;max-width:340px}
.timepick select{
  width:100%;padding:10px 10px;font:inherit;font-size:15px;
  border:1px solid var(--line);border-radius:4px;background:#fff;color:inherit;
  /* Keep the native arrow — a custom one is another thing to get wrong on
     three browsers, and the native control is what people recognise. */
  min-width:0
}
.timepick select:focus{outline:2px solid var(--clay);outline-offset:-1px}

@media (max-width:420px){
  .timepick{grid-template-columns:repeat(3,1fr)}
}

.pv{width:min(380px,100%);margin:0 auto;display:block}
.pv > *{width:100%}

/* Canvas invites (render.js). No container-query trap here — the canvas
   has explicit pixel dimensions, which is one more reason it replaced the
   CSS card. */
canvas{display:block;max-width:100%;border-radius:3px;box-shadow:var(--shadow-lg)}
.stage canvas{box-shadow:var(--shadow-lg)}
.tpl .hold canvas{box-shadow:var(--shadow);width:100%;height:auto}
.rsvp-card canvas{border-radius:0;box-shadow:none}

/* --- the card ------------------------------------------------------------ */
.card{aspect-ratio:5/7;background:var(--c-bg);color:var(--c-ink);position:relative;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:11% 10%;text-align:center;overflow:hidden;container-type:inline-size;
  box-shadow:var(--shadow-lg);border-radius:3px}
.card .deco{position:absolute;inset:0;pointer-events:none}
.card .t-host{font-size:3.4cqw;letter-spacing:.19em;text-transform:uppercase;opacity:.72;margin-bottom:7cqw}
.card .t-title{font-family:var(--serif);font-size:12.5cqw;line-height:1.02;letter-spacing:-.02em}
.card .t-sub{font-size:3.6cqw;letter-spacing:.15em;text-transform:uppercase;margin-top:5cqw;opacity:.8}
.card .t-rule{width:16%;height:1px;background:currentColor;opacity:.3;margin:6cqw 0}
.card .t-when{font-size:4.4cqw;line-height:1.55;font-family:var(--serif)}
.card .t-where{font-size:3.3cqw;line-height:1.5;opacity:.72;margin-top:2.5cqw}
.card .t-dress{font-size:2.7cqw;letter-spacing:.17em;text-transform:uppercase;opacity:.62;
  margin-top:4cqw;font-weight:600}
.card .t-note{font-size:3cqw;font-style:italic;opacity:.6;margin-top:3cqw;line-height:1.4}
.card .stamp{position:absolute;left:0;right:0;bottom:4.5cqw;display:flex;align-items:center;
  justify-content:center;gap:2.5cqw;font-size:2.6cqw;letter-spacing:.05em;opacity:.78}
.card .qr{width:7cqw;height:7cqw;display:grid;grid-template-columns:repeat(7,1fr);flex:none}
.card .qr div{background:currentColor}

/* template variations */
.card.t-aurelia .t-title{font-size:13.5cqw}
.card.t-aurelia .deco::before,.card.t-aurelia .deco::after{content:"";position:absolute;
  left:7%;right:7%;height:1px;background:currentColor;opacity:.28}
.card.t-aurelia .deco::before{top:6.5%}
.card.t-aurelia .deco::after{bottom:6.5%}

.card.t-arch{justify-content:flex-end;padding-bottom:16%}
.card.t-arch .deco::before{content:"";position:absolute;left:14%;right:14%;top:9%;bottom:24%;
  border:1.5px solid currentColor;opacity:.3;border-radius:50% 50% 4px 4px/62% 62% 4px 4px}
.card.t-arch .t-title{font-size:11cqw}

.card.t-bloom .t-title{font-size:14cqw;font-style:italic}
.card.t-bloom .deco{opacity:.22}

.card.t-neon{justify-content:flex-start;text-align:left;align-items:flex-start;padding-top:14%}
.card.t-neon .t-title{font-family:var(--sans);font-weight:800;font-size:15cqw;
  letter-spacing:-.045em;line-height:.92;text-transform:uppercase}
.card.t-neon .t-host{margin-bottom:4cqw}
.card.t-neon .t-rule{display:none}
.card.t-neon .t-when{font-family:var(--sans);font-weight:650;margin-top:auto;font-size:4.6cqw}
.card.t-neon .stamp{justify-content:flex-start;left:10%;right:10%}
.card.t-neon .deco::before{content:"";position:absolute;right:-14%;top:-14%;width:62%;height:44%;
  border-radius:50%;background:currentColor;opacity:.14}

.card.t-terrazzo .t-title{font-size:12cqw}
.card.t-terrazzo .deco{opacity:.3}

.card.t-gala .deco::before{content:"";position:absolute;inset:5.5%;border:1px solid currentColor;opacity:.32}
.card.t-gala .deco::after{content:"";position:absolute;inset:7%;border:3px double currentColor;opacity:.16}
.card.t-gala .t-title{font-size:10.5cqw;letter-spacing:.01em}
.card.t-gala .t-host{font-size:3cqw}

/* --- gallery ------------------------------------------------------------- */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:24px;margin-top:28px}
.tpl{text-align:left;transition:.2s}
.tpl .hold{border-radius:3px;overflow:hidden;transition:.2s}
.tpl:hover .hold{transform:translateY(-4px)}
.tpl.on .hold{outline:2px solid var(--clay);outline-offset:4px}
.tpl .meta{margin-top:11px;display:flex;justify-content:space-between;align-items:baseline}
.tpl .meta b{font-size:13.5px;font-weight:600}
.tpl .meta span{font-size:11.5px;color:var(--ink-35)}

/* --- rsvp page ----------------------------------------------------------- */
.rsvp-page{max-width:440px;margin:40px auto}
.rsvp-card{background:#fff;border:1px solid var(--line);border-radius:16px;overflow:hidden;
  box-shadow:var(--shadow-lg)}
.rsvp-card .pv{width:100%}
.rsvp-card .card{border-radius:0;box-shadow:none}
.rsvp-body{padding:26px}
.opts{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin:16px 0}
.opt{padding:13px 6px;border:1px solid var(--line);border-radius:10px;text-align:center;
  font-size:13.5px;font-weight:550;background:var(--paper);transition:.15s}
.opt:hover{border-color:var(--ink-35)}
.opt.on{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.opt em{display:block;font-size:18px;font-style:normal;margin-bottom:3px}

/* --- dashboard ----------------------------------------------------------- */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:14px;margin:24px 0}
.stat{border:1px solid var(--line);border-radius:12px;padding:16px;background:#fff}
.stat b{display:block;font-family:var(--serif);font-size:30px;font-weight:400;line-height:1}
.stat span{font-size:11px;color:var(--ink-35);letter-spacing:.04em;text-transform:uppercase;
  margin-top:7px;display:block;font-weight:600}
.stat.acc b{color:var(--clay)}
table{width:100%;border-collapse:collapse;background:#fff;border:1px solid var(--line);
  border-radius:12px;overflow:hidden}
th{font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-35);
  text-align:left;padding:11px 16px;border-bottom:1px solid var(--line);font-weight:650;
  background:var(--paper-2)}
td{padding:11px 16px;border-bottom:1px solid var(--line);font-size:14px}
tr:last-child td{border:none}
.pill{font-size:11px;padding:3px 10px;border-radius:99px;font-weight:650}
.pill.yes{background:rgba(79,122,92,.13);color:var(--ok)}
.pill.no{background:rgba(23,23,26,.07);color:var(--ink-35)}
.pill.maybe{background:rgba(194,96,61,.13);color:var(--clay-dk)}

/* --- correcting the guest list -------------------------------------------
   A reply turns into a form in place. The row is tinted while it's open so
   it's obvious which one is being edited in a list of thirty, and the cells
   lose a little vertical padding because the inputs bring their own.
------------------------------------------------------------------------ */
tr.editing td{background:var(--paper-2);padding-top:9px;padding-bottom:9px}
.rsvp-in{
  width:100%;padding:6px 9px;border:1px solid var(--line);border-radius:6px;
  background:#fff;font-size:13.5px;font-family:inherit;color:inherit
}
.rsvp-in:focus{outline:none;border-color:var(--clay);box-shadow:0 0 0 3px rgba(194,96,61,.1)}
select.rsvp-in{cursor:pointer}

/* Says where a row came from. Quiet on purpose — it's a footnote to the
   name, not a status of its own, and it must not compete with the pill. */
.rsvp-mark{
  display:inline-block;margin-left:8px;font-size:10.5px;letter-spacing:.04em;
  text-transform:uppercase;font-weight:650;color:var(--ink-35);
  border:1px solid var(--line);border-radius:99px;padding:1px 7px;
  vertical-align:middle
}

/* Remove is the one irreversible action on this page, so it doesn't get to
   look like Edit and Cancel. */
.linky.danger{color:var(--bad)}

/* The action column shouldn't claim width it doesn't need. */
#replies th:last-child,#replies td:last-child{width:1%;white-space:nowrap}

/* --- messages ------------------------------------------------------------ */
.msg{border-radius:10px;padding:13px 16px;font-size:13.5px;margin:16px 0;line-height:1.5}
.msg.err{background:rgba(164,52,47,.07);border:1px solid rgba(164,52,47,.3);color:var(--bad)}
.msg.ok{background:rgba(79,122,92,.08);border:1px solid rgba(79,122,92,.3);color:var(--ok)}
.linkbox{display:flex;gap:8px;margin:12px 0}
.linkbox input{flex:1;padding:11px 14px;border:1px solid var(--line);border-radius:8px;
  background:#fff;font-size:13.5px}

@media(max-width:860px){
  .split{grid-template-columns:1fr;gap:28px}
  .stagecol{position:static}
  h1{font-size:29px}
}
