/* ==========================================================================
   hedrick.photos — Colleen & Casey
   Ported from the Claude Design source (Hedrick Photos.dc.html). The palette,
   type scale, easing and keyframes below are the design's values verbatim.
   ========================================================================== */

:root {
  --cream: #F6F1E8;
  --cream-raised: #FFFDF8;
  --cream-sunk: #FAF6EE;
  --ink: #2A241D;
  --sage: #5E6E66;
  --sage-deep: #4C5A53;
  --sage-landing: #7D8D85;
  --gold: #C8A45E;
  --brown-1: #6B5B4D;
  --brown-2: #7C6A5B;
  --brown-3: #8C7864;
  --brown-4: #9C8877;
  --brown-5: #A5937F;
  --line: #E9DFCF;
  --line-2: #E2D7C5;
  --line-3: #EFE5D5;
  --line-4: #DBCFBD;
  /* The hero's mat board and the edge of a print lying on it. Paper, not UI:
     the border sits one step off the mat so it reads as stock rather than as
     a white keyline, and the shadow does the separating. */
  --mat: #EFE8DA;
  --print-edge: #F7F2E7;

  --night: #1E2421;
  --night-ink: #F7F0E6;
  --danger: #96513E;

  --ease: cubic-bezier(.2, .8, .2, 1);
  --serif: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --sans: 'DM Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --script: 'Allura', 'Snell Roundhand', cursive;
}

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Set while the photo viewer is open: it covers the screen, and the grid
   behind it must not scroll along with a swipe that wanders off horizontal. */
body.is-locked { overflow: hidden; }

a { color: var(--sage); text-decoration: none; }
a:hover { color: #3E4A44; }
button { font: inherit; color: inherit; }
img { max-width: 100%; }

*:focus-visible {
  outline: 2px solid var(--sage);
  outline-offset: 3px;
  border-radius: 4px;
}
.screen--live *:focus-visible,
.lightbox *:focus-visible { outline-color: #E8C97E; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 999;
  padding: 10px 16px;
  background: var(--cream-raised);
  border-radius: 999px;
  box-shadow: 0 6px 18px rgba(60, 44, 28, .2);
}
.skip-link:focus { left: 8px; }

/* The app is its own container so the design's cqw-based type scale — which
   was authored against a phone frame — keeps working at any viewport. */
.app {
  container-type: inline-size;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--cream);
}
.screen { flex: 1; display: flex; flex-direction: column; min-height: 100dvh; }

/* ---------- keyframes (design source) ---------- */
@keyframes fadeUp { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes liveFadeA { from { opacity: 0; transform: scale(1.03); } to { opacity: 1; transform: none; } }
@keyframes liveFadeB { from { opacity: 0; transform: scale(1.03); } to { opacity: 1; transform: none; } }
@keyframes drift { from { transform: scale(1.05) translate3d(-1%, .7%, 0); } to { transform: scale(1.13) translate3d(1%, -.7%, 0); } }
@keyframes pulseDot { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .45; transform: scale(.82); } }
@keyframes shimmer { from { background-position: -220% 0; } to { background-position: 220% 0; } }
@keyframes sheetUp { from { transform: translateY(101%); } to { transform: none; } }
@keyframes heroDeal {
  from { opacity: .4; transform: translate(78%, 26%) rotate(16deg) scale(1.04);
         box-shadow: 0 4px 10px rgba(38,30,20,.14), 0 26px 44px rgba(38,30,20,.24); }
  to   { opacity: 1; transform: rotate(var(--rest, 0deg));
         box-shadow: 0 1px 2px rgba(38,30,20,.10), 0 14px 30px rgba(38,30,20,.15); }
}
@keyframes pop { 0% { transform: scale(.86); opacity: 0; } 60% { transform: scale(1.04); } 100% { transform: scale(1); opacity: 1; } }
@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- boot ---------- */
.boot {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--brown-3);
  font-size: 14px;
}
.boot-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--gold);
  animation: pulseDot 1.4s ease-in-out infinite;
}

/* ---------- shared bits ---------- */
.eyebrow {
  font: 400 clamp(10px, 2.6cqw, 11px)/1 var(--mono);
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--brown-5);
}
.wordmark { display: flex; align-items: baseline; gap: 1px; letter-spacing: -.01em; }
.wordmark b { font-weight: 600; }
.wordmark span { font-weight: 400; }

.btn {
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font-weight: 500;
  transition: transform .18s var(--ease), background .2s, box-shadow .2s, border-color .2s, color .2s;
}
.btn:active { transform: scale(.98); }
.btn[disabled] { cursor: default; opacity: .75; }
.btn--primary {
  min-height: 58px; padding: 0 26px;
  background: var(--sage); color: #FFF9F3;
  font-size: 17px;
  box-shadow: 0 10px 26px rgba(94, 110, 102, .26);
}
.btn--primary:hover:not([disabled]) { background: var(--sage-deep); }
.btn--quiet {
  min-height: 54px; padding: 0 26px;
  background: transparent; border: 1px solid var(--line-4);
  font-size: 16px;
}
.btn--quiet:hover { background: #F0E9DB; }
.btn--ghost {
  min-height: 40px; padding: 0 14px;
  background: transparent; border: 1px solid var(--line-4);
  color: #4A3B2F; font-size: 13px; white-space: nowrap;
}
.btn--ghost:hover { background: #F0E9DB; }
.btn--danger { border-color: #E0C0B4; color: var(--danger); }
.btn--danger.is-confirming { background: var(--danger); color: #FFF6F0; }
.btn--text {
  min-height: 44px; padding: 0 10px;
  background: none; border: 0; font-size: 14px; color: var(--brown-3); cursor: pointer;
}
.btn--text:hover { color: var(--ink); }

.backlink {
  display: flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 12px 0 4px;
  background: none; border: 0; cursor: pointer;
  font-size: 14px; color: var(--brown-1);
  border-radius: 999px; transition: background .2s;
}
.backlink:hover { background: #EFE7D9; }
.backlink .chev { font-size: 17px; line-height: 1; }

.topbar {
  position: sticky; top: 0; z-index: 6;
  padding: 14px clamp(16px, 4cqw, 40px) 12px;
  background: rgba(246, 241, 232, .9);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.topbar__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.topbar__actions { display: flex; gap: 10px; }

/* Photo tiles ------------------------------------------------------------- */
/* The gradient sits behind every image so a tile has the design's colour the
   instant it lays out, then the photo fades in over it. */
.tile { position: relative; overflow: hidden; background: #E7DED2; display: block; }
.tile img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  opacity: 0; transition: opacity .55s var(--ease);
}
.tile img.is-loaded { opacity: 1; }
.tile__weave {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(135deg, rgba(255,255,255,.10) 0 2px, transparent 2px 9px);
}
.tile--square { width: 100%; aspect-ratio: 1 / 1; border-radius: 10px; }

/* ==========================================================================
   Landing
   ========================================================================== */
.screen--landing {
  padding: 0 0 30px;
  background: var(--sage-landing);
  color: #FFFDF9;
}
.landing__nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: clamp(16px, 4cqw, 28px) clamp(18px, 5cqw, 44px);
}
.landing__nav .wordmark { font-size: clamp(12px, 3.1cqw, 14px); }
.landing__nav .wordmark span { color: rgba(255, 253, 249, .72); }
.landing__navactions { display: none; align-items: center; gap: 10px; }
.landing__navlink {
  background: none; border: 0; padding: 10px 14px;
  font-size: 14px; font-weight: 500; color: rgba(255, 253, 249, .86);
  cursor: pointer; border-radius: 999px; transition: color .2s, background .2s;
}
.landing__navlink:hover { background: rgba(255, 255, 255, .16); color: #FFFDF9; }
.landing__navcta {
  background: #FFFDF9; color: #3A453F; border: 0;
  padding: 12px 22px; border-radius: 999px;
  font-size: 14px; font-weight: 500; cursor: pointer;
  transition: transform .18s var(--ease), background .2s;
}
.landing__navcta:hover { background: #F1ECE1; transform: translateY(-1px); }

.landing__body {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  text-align: center;
  padding: clamp(8px, 3cqw, 22px) clamp(22px, 6cqw, 60px) 0;
}
.hero {
  width: min(100%, 540px);
  animation: fadeUp .9s var(--ease) both;
}
.hero__frame {
  position: relative; width: 100%;
  height: clamp(320px, 86cqw, 480px);
  border-radius: 16px; overflow: hidden;
  background: var(--mat);
  box-shadow: 0 26px 60px rgba(30, 42, 35, .3);
}
.hero__frame .tile { position: absolute; inset: 0; }

/* ---------- the hero as a pile of prints ----------
   Each photo is a print laid on the mat rather than a fill of the frame: the
   new one is dealt in from the lower right and squares itself up, and the one
   it lands on stays underneath, so there is always a pile to land on.
   Two treatments for the print's edge, switched by the modifier on the frame:
   --paper gives it a quiet paper border, --feather melts it into the mat. */
.hero__frame .hero__layer {
  position: absolute;
  inset: 7% 6%;
  border-radius: 3px;
  transform: rotate(var(--rest, 0deg));
  box-shadow:
    0 1px 2px rgba(38, 30, 20, .10),
    0 14px 30px rgba(38, 30, 20, .15);
  animation: heroDeal .95s var(--ease) both;
}
/* The print's face is its own element so the edge treatment can feather it
   without also feathering away the shadow that lifts it off the mat. */
.hero__print {
  position: absolute; inset: 0;
  overflow: hidden; border-radius: 2px;
}
.hero__frame--paper .hero__layer {
  border: 5px solid var(--print-edge);
}
.hero__frame--paper .hero__print {
  box-shadow: inset 0 0 0 1px rgba(58, 46, 32, .09);
}
.hero__frame--feather .hero__print {
  -webkit-mask-image:
    linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-image:
    linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
.hero__scrim {
  position: absolute;
  inset: calc(7% + 5px) calc(6% + 5px);
  border-radius: 2px;
  background: linear-gradient(to top, rgba(30,22,14,.36) 0%, rgba(30,22,14,0) 44%);
}
.hero__frame--feather .hero__scrim { inset: calc(7% + 10px) calc(6% + 10px); }
.hero__foot {
  position: absolute;
  left: calc(6% + 18px); right: calc(6% + 18px); bottom: calc(7% + 16px);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.hero__live {
  position: relative;
  display: flex; align-items: center; gap: 8px;
  /* A button now — it opens the live view — so undo the UA chrome. */
  appearance: none; background: rgba(20, 16, 12, .28); border: 0;
  margin: -9px -12px; padding: 9px 12px; border-radius: 999px;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background .25s var(--ease);
}
/* The pill stays small so it doesn't crowd the photo; the tap target doesn't. */
.hero__live::after { content: ''; position: absolute; inset: -7px -6px; }
.hero__live:hover { background: rgba(20, 16, 12, .46); }
.hero__live:active { background: rgba(20, 16, 12, .54); }
.hero__live > span:not(.dot-gold) {
  font: 400 9.5px/1 var(--mono);
  letter-spacing: .2em; text-transform: uppercase;
  color: rgba(255, 250, 242, .92);
}
.hero__live .hero__live-go {
  font-size: 12px; letter-spacing: 0; margin-left: -2px;
  transition: transform .25s var(--ease);
}
.hero__live:hover .hero__live-go { transform: translateX(2px); }
.hero__live:focus-visible { outline-color: #E8C97E; }
.dot-gold {
  width: 6px; height: 6px; border-radius: 50%;
  background: #E8C97E;
  animation: pulseDot 2.6s ease-in-out infinite;
}
.hero__dots { display: flex; gap: 5px; }
.hero__dots i {
  width: 5px; height: 5px; border-radius: 99px;
  background: rgba(255, 250, 242, .42);
  transition: width .4s var(--ease), background .4s;
}
.hero__dots i.is-on { width: 14px; background: rgba(255, 250, 242, .95); }

.landing__meta {
  margin-top: clamp(24px, 6cqw, 36px);
  color: rgba(255, 253, 249, .76);
  animation: fadeUp .9s .2s var(--ease) both;
}
/* The wordmark is a supplied PNG. Until that file exists the <img> removes
   itself and the Allura setting behind it shows through, so the lockup is
   never a broken image. */
.landing__title {
  margin: clamp(6px, 2cqw, 14px) 0 0;
  animation: fadeUp .9s .26s var(--ease) both;
}
.landing__wordmark {
  display: block;
  width: min(100%, 480px);
  height: auto;
  margin: 0 auto;
  /* Decorative lettering: never a click target, never stacked over the line above. */
  pointer-events: none;
  position: relative;
  z-index: 0;
}
.landing__wordmark-text {
  display: block;
  font-family: var(--script);
  font-weight: 400;
  font-size: clamp(54px, 15cqw, 104px);
  line-height: 1.06;
  letter-spacing: .01em;
  color: #FFFDF9;
}
.landing__wordmark ~ .landing__wordmark-text { display: none; }
.landing__copy {
  margin: clamp(20px, 5cqw, 32px) 0 0;
  max-width: 30ch;
  font-size: clamp(16px, 4.2cqw, 19px);
  line-height: 1.5;
  color: rgba(255, 253, 249, .9);
  text-wrap: pretty;
  animation: fadeUp .9s .34s var(--ease) both;
}
.landing__cta {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 12px;
  margin-top: clamp(26px, 6cqw, 36px);
  width: 100%; max-width: 380px;
  animation: fadeUp .9s .42s var(--ease) both;
}
.landing__cta .btn { flex: 1 1 100%; }
.landing__cta .btn--primary {
  background: #FFFDF9; color: #34403A;
  box-shadow: 0 12px 28px rgba(28, 40, 33, .22);
}
.landing__cta .btn--primary:hover {
  background: #F1ECE1;
  box-shadow: 0 16px 34px rgba(28, 40, 33, .26);
  transform: translateY(-2px);
}
.landing__cta .btn--quiet { color: #FFFDF9; border-color: rgba(255, 255, 255, .5); }
.landing__cta .btn--quiet:hover { background: rgba(255, 255, 255, .16); border-color: #FFF; }

.landing__count {
  display: flex; align-items: center; gap: 9px;
  margin-top: clamp(24px, 5cqw, 34px);
  font-size: clamp(13px, 3.4cqw, 14px);
  color: rgba(255, 253, 249, .82);
  animation: fadeIn 1.2s .6s both;
}
.landing__count .dot-gold { background: var(--gold); }

.landing__foot {
  margin-top: clamp(24px, 6cqw, 40px);
  display: flex; flex-direction: column; align-items: center; gap: 12px;
}
.landing__zola {
  min-height: 44px; display: inline-flex; align-items: center; padding: 0 18px;
  border: 1px solid rgba(255, 255, 255, .48);
  border-radius: 999px; font-size: 13.5px; color: #FFFDF9;
  transition: background .2s;
}
.landing__zola:hover { background: rgba(255, 255, 255, .16); color: #FFF; }
.landing__credit { text-align: center; font-size: 10.5px; color: rgba(255, 253, 249, .72); }
.landing__credit .heart { color: #EFCDB9; }
.landing__credit a {
  color: #FFFDF9; text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, .5); text-underline-offset: 2px;
}

/* ==========================================================================
   Upload
   ========================================================================== */
.screen--upload { background: var(--cream); }
.upload__bar {
  position: sticky; top: 0; z-index: 6;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px clamp(16px, 4cqw, 32px);
  background: rgba(246, 241, 232, .88);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.upload__count {
  font: 400 11px/1 var(--mono);
  letter-spacing: .14em; text-transform: uppercase; color: var(--brown-4);
}
.upload__empty {
  flex: 1; display: flex; flex-direction: column; justify-content: center;
  padding: clamp(24px, 6cqw, 56px);
}
.upload__lead { text-align: center; animation: fadeUp .7s var(--ease) both; }
.upload__lead h2 {
  margin: 0; font-family: var(--serif); font-weight: 400;
  font-size: clamp(30px, 8.4cqw, 50px); line-height: 1.08; letter-spacing: -.01em;
}
.upload__lead p {
  margin: 12px auto 0; max-width: 32ch;
  font-size: clamp(15px, 3.9cqw, 17px); line-height: 1.5; color: var(--brown-1);
}
.dropzone {
  margin-top: clamp(26px, 6cqw, 40px);
  width: 100%;
  padding: clamp(34px, 9cqw, 60px) 24px;
  background: linear-gradient(180deg, #FCF7ED 0%, #F5EEDF 100%);
  border: 1px solid #E6DAC7;
  border-radius: 26px;
  cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 18px;
  transition: transform .2s var(--ease), box-shadow .25s, border-color .2s;
  animation: fadeUp .7s .08s var(--ease) both;
}
.dropzone:hover, .dropzone.is-dragging {
  border-color: #D3C0A8;
  box-shadow: 0 18px 40px rgba(120, 86, 54, .12);
  transform: translateY(-2px);
}
.dropzone:active { transform: scale(.99); }
.dropzone__art { position: relative; display: block; width: 82px; height: 66px; }
.dropzone__art i { position: absolute; display: block; }
.dropzone__art .a { left: 6px; top: 10px; width: 52px; height: 46px; border-radius: 8px; background: #E4D4BF; transform: rotate(-8deg); }
.dropzone__art .b { left: 22px; top: 4px; width: 54px; height: 50px; border-radius: 8px; background: #FFF; border: 1px solid #E2D2BD; box-shadow: 0 6px 16px rgba(120,86,54,.12); }
.dropzone__art .c { left: 33px; top: 21px; width: 32px; height: 3px; border-radius: 2px; background: var(--sage); }
.dropzone__art .d { left: 47px; top: 14px; width: 3px; height: 17px; border-radius: 2px; background: var(--sage); }
.dropzone__title { font-size: clamp(16px, 4.2cqw, 18px); font-weight: 500; color: var(--ink); }
.dropzone__hint { font-size: 13px; color: var(--brown-3); }
.upload__fineprint {
  margin: 22px auto 0; text-align: center;
  font-size: 13px; line-height: 1.5; color: var(--brown-4); max-width: 36ch;
}
.notice {
  margin-top: clamp(26px, 6cqw, 40px);
  padding: 30px 26px; text-align: center;
  background: #FAF3E7; border: 1px solid #E8D8BE; border-radius: 22px;
  animation: fadeUp .6s both;
}
.notice__label {
  font: 400 10px/1 var(--mono);
  letter-spacing: .24em; text-transform: uppercase; color: var(--brown-5);
}
.notice p { margin: 12px 0 0; font-size: 16px; line-height: 1.5; color: #5C4C3F; }

.stage { flex: 1; display: flex; flex-direction: column; }
.stage__head { padding: clamp(18px, 5cqw, 34px) clamp(16px, 4cqw, 34px) 8px; }
.stage__head h2 {
  margin: 0; font-family: var(--serif); font-weight: 400;
  font-size: clamp(26px, 7cqw, 40px); line-height: 1.08;
}
.stage__head p { margin: 8px 0 0; font-size: 14px; color: var(--brown-2); }
.stage__grid {
  padding: 14px clamp(16px, 4cqw, 34px) 24px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 10px;
}
.stage__grid--pad { padding-bottom: 176px; }
.chip {
  position: relative; padding: 0; border: 0; background: none; cursor: pointer;
  animation: pop .38s var(--ease) both;
}
.chip__x {
  position: absolute; top: -6px; right: -6px;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--cream-raised); border: 1px solid #E5D8C6; color: var(--brown-1);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; line-height: 1;
  box-shadow: 0 4px 12px rgba(90, 64, 40, .14);
}
.chip__add {
  aspect-ratio: 1 / 1; border: 1px dashed #D8C8B0; border-radius: 10px;
  background: #FAF4E9; color: var(--brown-3); font-size: 26px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background .2s, border-color .2s;
}
.chip__add:hover { background: #F4EBDA; border-color: #C6AF95; }

.stage__foot {
  position: sticky; bottom: 0;
  padding: 14px clamp(16px, 4cqw, 34px) 22px;
  background: linear-gradient(180deg, rgba(246,241,232,0) 0%, var(--cream) 30%);
  display: flex; flex-direction: column; gap: 10px;
}
.namefield { display: flex; flex-direction: column; gap: 6px; }
.namefield label {
  font: 400 10px/1 var(--mono);
  letter-spacing: .2em; text-transform: uppercase; color: var(--brown-5);
}
.namefield input {
  min-height: 48px; padding: 0 14px;
  font: inherit; font-size: 16px; color: var(--ink);
  background: var(--cream-raised);
  border: 1px solid var(--line-3); border-radius: 14px;
  transition: border-color .2s, box-shadow .2s;
}
.namefield input::placeholder { color: #B7A695; }
.namefield input:focus {
  outline: none;
  border-color: var(--sage);
  box-shadow: 0 0 0 3px rgba(94, 110, 102, .16);
}
.namefield .hint { font-size: 12px; color: var(--brown-4); }

.turnstile {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px;
  background: #FBF5EA; border: 1px solid #EADFCC; border-radius: 14px;
}
.turnstile__dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px;
  background: #CFC0AB;
}
.turnstile[data-state="checking"] .turnstile__dot { background: var(--gold); animation: pulseDot 1.2s ease-in-out infinite; }
.turnstile[data-state="ok"] .turnstile__dot { background: #6E8F62; }
.turnstile[data-state="error"] .turnstile__dot { background: var(--danger); }
.turnstile__text { flex: 1; font-size: 12.5px; color: var(--brown-1); }
.turnstile__brand {
  font: 400 9px/1 var(--mono);
  letter-spacing: .16em; text-transform: uppercase; color: #B7A695;
}
#turnstile-widget:not(:empty) { margin-top: 4px; }

.progress { margin-top: 16px; height: 8px; border-radius: 99px; background: #ECE2D2; overflow: hidden; }
.progress__bar {
  height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, var(--gold), var(--sage));
  transition: width .3s ease;
}
.veil {
  position: absolute; inset: 0;
  background: rgba(246, 241, 232, .62);
  transition: transform .3s linear;
}
.badge-done {
  position: absolute; right: 6px; bottom: 6px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--cream-raised); color: #4E7A52;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; line-height: 1;
  box-shadow: 0 3px 10px rgba(60, 44, 28, .18);
  animation: pop .34s var(--ease) both;
}
.badge-failed {
  position: absolute; inset: 0;
  background: rgba(246, 241, 232, .84);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  animation: fadeIn .3s both;
}
.badge-failed i {
  width: 22px; height: 22px; border-radius: 50%;
  border: 1.5px solid #9E5B4A; color: #9E5B4A;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; line-height: 1; font-style: normal;
}
.badge-failed span { font-size: 10px; letter-spacing: .04em; color: #8B5545; }

.retry {
  margin-top: 20px; display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  background: #FAF0E9; border: 1px solid #E9D3C8; border-radius: 16px;
}
.retry span { flex: 1; font-size: 13.5px; line-height: 1.45; color: #7A4A3B; }
.retry .btn {
  min-height: 40px; padding: 0 16px;
  background: var(--sage); color: #FFF9F3; border: 0;
  font-size: 13.5px; font-weight: 500;
}

.done {
  flex: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center;
  padding: clamp(30px, 8cqw, 70px) clamp(24px, 6cqw, 56px);
}
.done__mark {
  position: relative; width: 96px; height: 96px;
  display: flex; align-items: center; justify-content: center;
  animation: pop .6s var(--ease) both;
}
.done__mark::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 50% 45%, #F5E2C6 0%, #F1E5D4 70%, rgba(241,229,212,0) 100%);
}
.done__mark span { position: relative; font-family: var(--serif); font-size: 42px; color: var(--gold); line-height: 1; }
.done h2 {
  margin: 20px 0 0; font-family: var(--serif); font-weight: 400;
  font-size: clamp(32px, 9.4cqw, 56px); line-height: 1.04; letter-spacing: -.01em;
  animation: fadeUp .7s .1s var(--ease) both;
}
.done p {
  margin: 14px 0 0; max-width: 30ch;
  font-size: clamp(15px, 4cqw, 18px); line-height: 1.5; color: #5C4C3F;
  animation: fadeUp .7s .18s var(--ease) both;
}
.done__actions {
  display: flex; flex-direction: column; gap: 10px;
  width: 100%; max-width: 340px; margin-top: clamp(28px, 7cqw, 40px);
  animation: fadeUp .7s .26s var(--ease) both;
}

/* ==========================================================================
   Gallery
   ========================================================================== */
.screen--gallery { background: var(--cream); padding-bottom: 120px; }
.tabs { display: flex; align-items: center; gap: 6px; margin-top: 12px; }
.tabs__caption {
  margin-right: auto;
  font: 400 11px/1 var(--mono);
  letter-spacing: .12em; text-transform: uppercase; color: var(--brown-5);
}


/* Timeline groups ---------------------------------------------------------- */
/* The gallery is one scroll, cut into runs by when the photos were taken. The
   headings are deliberately not sticky: the topbar above them is, and a second
   thing pinning itself as you scroll makes a quiet page feel busy. */
.group + .group { border-top: 1px solid var(--line); }
.grouphead {
  display: flex; align-items: baseline; gap: 10px;
  padding: clamp(18px, 3cqw, 28px) clamp(14px, 3cqw, 28px) 0;
}
.grouphead__label {
  margin: 0;
  font: 400 12px/1 var(--mono);
  letter-spacing: .18em; text-transform: uppercase; color: var(--brown-1);
}
.grouphead__count {
  font: 400 11px/1 var(--mono);
  letter-spacing: .12em; color: var(--brown-5);
}
/* The same dot the live screen uses, because it means the same thing here:
   this is the run still filling in. */
.grouphead--live .grouphead__label { color: var(--ink); font-weight: 600; }
.grouphead__dot {
  align-self: center;
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: #C08A3E; box-shadow: 0 0 0 4px rgba(192, 138, 62, .14);
  animation: pulseDot 2.4s ease-in-out infinite;
}
/* The heading already carries the space above each run. */
.group .masonry { padding-top: clamp(10px, 2cqw, 16px); }

/* The auto-refresh switch. Reads as a status first and a control second,
   which is the order a guest cares about them in. */
.livetoggle {
  display: flex; align-items: center; gap: 7px;
  min-height: 32px; padding: 0 12px; margin-left: 10px;
  border: 1px solid var(--line-2); border-radius: 999px;
  background: transparent; cursor: pointer;
  font: 400 11px/1 var(--mono);
  letter-spacing: .12em; text-transform: uppercase; color: var(--brown-5);
  transition: color .2s, border-color .2s;
}
.livetoggle i {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--brown-5); transition: background .2s, box-shadow .2s;
}
.livetoggle[aria-pressed="true"] { color: var(--brown-1); border-color: var(--line-2); }
.livetoggle[aria-pressed="true"] i {
  background: #C08A3E; box-shadow: 0 0 0 3px rgba(192, 138, 62, .14);
  animation: pulseDot 2.4s ease-in-out infinite;
}
.livetoggle:hover { color: var(--ink); }

/* A photo you just added, marked wherever it landed — which for one taken
   earlier in the day is well down the page. */
.masonry__new {
  position: absolute; top: 8px; left: 8px; z-index: 2;
  padding: 4px 9px; border-radius: 999px;
  background: rgba(30, 22, 14, .78); color: #F9F5EC;
  font: 400 10px/1 var(--mono);
  letter-spacing: .12em; text-transform: uppercase;
  animation: fadeUp .5s var(--ease) both;
}

.done__filed {
  margin-top: 10px;
  font-size: 14px; line-height: 1.5; color: var(--brown-1);
}
.done__filed b { font-weight: 600; color: var(--ink); }

.masonry { padding: clamp(14px, 3cqw, 28px); columns: 150px; column-gap: 12px; }
@container (min-width: 700px) { .masonry { columns: 220px; } }
.masonry__item {
  display: block; width: 100%; padding: 0; border: 0;
  border-radius: 12px; break-inside: avoid; margin-bottom: 12px;
  cursor: pointer; box-shadow: 0 2px 10px rgba(90, 64, 40, .06);
  animation: fadeUp .6s var(--ease) both;
}
.masonry__item .scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(40,28,18,.5), rgba(40,28,18,0) 55%);
  opacity: 0; transition: opacity .3s;
}
.masonry__item:hover .scrim { opacity: 1; }
.masonry__credit {
  position: absolute; left: 10px; right: 10px; bottom: 9px;
  font: 400 10px/1.3 var(--mono);
  letter-spacing: .06em;
  color: rgba(255, 250, 242, .94);
  text-shadow: 0 1px 6px rgba(30, 20, 12, .55);
  text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  pointer-events: none;
}
/* The name sits on its own soft gradient so it stays legible on pale photos. */
.masonry__item .credit-scrim {
  position: absolute; left: 0; right: 0; bottom: 0; height: 46%;
  background: linear-gradient(to top, rgba(28, 20, 12, .5), rgba(28, 20, 12, 0));
  pointer-events: none;
}
.skeleton {
  width: 100%; border-radius: 12px; margin-bottom: 12px; break-inside: avoid;
  background: linear-gradient(100deg, #EFE7DA 30%, #F7F1E6 50%, #EFE7DA 70%);
  background-size: 220% 100%;
  animation: shimmer 1.4s linear infinite;
}

.empty {
  padding: clamp(50px, 14cqw, 110px) clamp(26px, 6cqw, 56px);
  text-align: center; display: flex; flex-direction: column; align-items: center;
}
.empty__cards { display: flex; gap: 8px; margin-bottom: 26px; }
.empty__cards i { width: 44px; height: 56px; border-radius: 6px; background: #F0E7D8; display: block; }
.empty__cards i:nth-child(1) { transform: rotate(-7deg); }
.empty__cards i:nth-child(2) { background: #EADFCC; }
.empty__cards i:nth-child(3) { transform: rotate(7deg); }
.empty h2 {
  margin: 0; font-family: var(--serif); font-weight: 400;
  font-size: clamp(26px, 7.4cqw, 42px); line-height: 1.1;
}
.empty p {
  margin: 12px 0 0; max-width: 30ch;
  font-size: clamp(15px, 4cqw, 17px); line-height: 1.5; color: var(--brown-1);
}
.empty .btn { margin-top: 28px; }

.mobilebar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 15;
  display: flex; justify-content: center;
  padding: 14px 16px calc(18px + env(safe-area-inset-bottom));
  background: linear-gradient(180deg, rgba(246,241,232,0) 0%, rgba(246,241,232,.95) 42%);
  pointer-events: none;
}
.mobilebar__inner { display: flex; gap: 8px; width: 100%; max-width: 420px; pointer-events: auto; }
.mobilebar .btn--primary { flex: 2; min-height: 56px; font-size: 16px; }
.mobilebar .btn--quiet {
  flex: 1; min-height: 56px; font-size: 15px;
  background: var(--cream-raised); color: var(--ink); border-color: var(--line-2);
}

/* ==========================================================================
   Live gallery
   ========================================================================== */
.screen--live {
  position: relative; height: 100dvh; min-height: 100dvh;
  background: var(--night); color: var(--night-ink);
  overflow: hidden; display: flex; flex-direction: column;
}
.screen--live::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 100% at 50% 0%, rgba(200,164,94,.12) 0%, rgba(28,22,17,0) 60%);
}
.live__bar {
  position: relative; z-index: 3;
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px 14px;
  padding: clamp(14px, 3cqw, 30px) clamp(16px, 4cqw, 40px);
}
.live__status { display: flex; align-items: center; gap: 10px; min-width: 0; }
.live__status i {
  flex: none;
  width: 8px; height: 8px; border-radius: 50%;
  background: #D8B26A; box-shadow: 0 0 0 4px rgba(216, 178, 106, .16);
  animation: pulseDot 2.4s ease-in-out infinite;
}
.live__status span {
  font: 400 clamp(10px, 2.2cqw, 12px)/1 var(--mono);
  letter-spacing: .22em; text-transform: uppercase; color: #E6D6BC;
  /* Broken across lines this label collides with itself at line-height 1, and
     it drags the pulsing dot off the text's centre. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.live__meta { display: flex; align-items: center; gap: 10px; }
.live__count {
  font-size: clamp(11px, 2.2cqw, 13px); color: rgba(247, 240, 230, .6);
  white-space: nowrap;
}
.live__btn {
  flex: none;
  min-width: 44px; min-height: 44px; padding: 0 16px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: rgba(247, 240, 230, .08);
  border: 1px solid rgba(247, 240, 230, .16);
  border-radius: 999px; color: var(--night-ink);
  font-size: 13px; line-height: 1; white-space: nowrap; cursor: pointer;
  transition: background .2s;
}
/* Drawn rather than set in emoji, so the icon matches the label's weight and
   both buttons come out the same height. */
.live__btn svg { flex: none; width: 14px; height: 14px; display: block; }
.live__btn:hover { background: rgba(247, 240, 230, .16); }
.live__stage {
  position: relative; z-index: 2; flex: 1; min-height: 0;
  padding: 0 clamp(14px, 3cqw, 40px) clamp(12px, 3cqw, 30px);
}
.live__solo { position: relative; width: 100%; height: 100%; border-radius: 18px; overflow: hidden; box-shadow: 0 30px 80px rgba(0,0,0,.45); }
.live__hero { display: grid; grid-template-columns: 2.1fr 1fr; grid-template-rows: 1fr 1fr; gap: clamp(8px, 1.6cqw, 16px); width: 100%; height: 100%; }
.live__hero > .live__slot:first-child { grid-row: span 2; border-radius: 16px; box-shadow: 0 24px 60px rgba(0,0,0,.4); }
.live__mosaic { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); grid-auto-rows: 1fr; gap: clamp(8px, 1.6cqw, 16px); width: 100%; height: 100%; }
.live__slot { position: relative; overflow: hidden; border-radius: 14px; background: #232A26; box-shadow: 0 14px 34px rgba(0,0,0,.3); }
.live__scrim { position: absolute; inset: 0; background: linear-gradient(to top, rgba(20,14,9,.6) 0%, rgba(20,14,9,0) 48%); }
.live__caption { position: absolute; left: clamp(16px, 3cqw, 34px); right: 16px; bottom: clamp(16px, 3cqw, 30px); }
.live__credit {
  margin-top: 6px;
  font: 400 clamp(10px, 1.9cqw, 13px)/1 var(--mono);
  letter-spacing: .16em; text-transform: uppercase; color: rgba(255, 248, 237, .72);
}
.live__foot {
  position: relative; z-index: 3;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 0 clamp(16px, 4cqw, 40px) clamp(16px, 3cqw, 34px);
}
.live__foot .wordmark { font-size: clamp(11px, 2.2cqw, 14px); color: rgba(247, 240, 230, .5); }
.live__exit {
  min-height: 44px; padding: 0 18px;
  background: none; border: 1px solid rgba(247, 240, 230, .18);
  border-radius: 999px; color: rgba(247, 240, 230, .8); font-size: 13px; cursor: pointer;
  transition: background .2s;
}
.live__exit:hover { background: rgba(247, 240, 230, .1); }
.live__empty {
  flex: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px; text-align: center;
  color: rgba(247, 240, 230, .74); padding: 0 32px;
}
.live__empty h2 { margin: 0; font-family: var(--serif); font-weight: 400; font-size: clamp(28px, 6cqw, 52px); color: #FFF8ED; }

/* A phone can't hold the whole bar on one line, and squeezing it there is what
   made the labels wrap and the last button run off the edge. Give the status
   its own row and let the count share the row beneath it with the controls. */
@container (max-width: 560px) {
  .live__status { flex: 1 0 100%; }
  .live__meta { width: 100%; flex-wrap: wrap; justify-content: flex-end; row-gap: 8px; }
  .live__count { margin-right: auto; }
}

/* On the narrowest phones the controls need the extra few pixels to stay on
   one row with the count. */
@container (max-width: 380px) {
  .live__meta { gap: 6px; }
  .live__btn { padding: 0 12px; }
}

/* ==========================================================================
   Host view
   ========================================================================== */
.screen--host { background: var(--cream-sunk); padding-bottom: 60px; }
.host__wrap { padding: clamp(22px, 5cqw, 44px) clamp(18px, 4cqw, 44px) 0; max-width: 780px; margin: 0 auto; width: 100%; }
.host__label { font: 400 11px/1 var(--mono); letter-spacing: .24em; text-transform: uppercase; color: var(--brown-5); }
.host__wrap h2 {
  margin: 12px 0 0; font-family: var(--serif); font-weight: 400;
  font-size: clamp(28px, 7.4cqw, 46px); line-height: 1.06;
}
.host__stats {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: clamp(18px, 4cqw, 40px);
  margin-top: 22px; padding-bottom: 22px; border-bottom: 1px solid #EBE0CE;
}
.host__stat b { display: block; font-family: var(--serif); font-weight: 400; font-size: 32px; line-height: 1; }
.host__stat span { display: block; margin-top: 4px; font-size: 12px; color: var(--brown-3); }
.host__stats .btn--ghost { margin-left: auto; min-height: 44px; padding: 0 18px; }
.host__note { margin: 20px 0 0; font-size: 14px; line-height: 1.55; color: var(--brown-1); max-width: 50ch; }
.pausebox {
  margin-top: 20px; padding: 16px 18px;
  background: #FAF3E7; border: 1px solid #E8D8BE; border-radius: 16px;
  display: flex; flex-direction: column; gap: 10px; max-width: 52ch;
}
.pausebox__label {
  font: 400 10px/1 var(--mono);
  letter-spacing: .24em; text-transform: uppercase; color: var(--brown-5);
}
.pausebox__check { display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--brown-1); cursor: pointer; }
.pausebox__check input { width: 18px; height: 18px; accent-color: var(--sage); cursor: pointer; }
.pausebox__hint, .pausebox__shown { margin: 0; font-size: 14px; line-height: 1.5; color: var(--brown-2); }
.pausebox__shown { color: #5C4C3F; }
.pausebox input[type="text"] {
  min-height: 46px; padding: 0 14px;
  font: inherit; font-size: 16px; color: var(--ink);
  background: var(--cream-raised);
  border: 1px solid var(--line-3); border-radius: 12px;
  transition: border-color .2s, box-shadow .2s;
}
.pausebox input[type="text"]::placeholder { color: #B7A695; }
.pausebox input[type="text"]:focus {
  outline: none; border-color: var(--sage); box-shadow: 0 0 0 3px rgba(94, 110, 102, .16);
}
.pausebox__row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.host__rows { margin-top: 22px; display: flex; flex-direction: column; gap: 8px; }
.host__row {
  display: flex; align-items: center; gap: 14px; padding: 10px 12px;
  background: var(--cream-raised); border: 1px solid var(--line-3);
  border-radius: 14px; transition: opacity .2s, background .2s;
}
.host__row.is-hidden { background: #F4EEE3; border-color: #E8DDCA; opacity: .68; }
.host__thumb { position: relative; width: 58px; height: 58px; flex: 0 0 58px; border-radius: 8px; overflow: hidden; background: #E7DED2; }
/* The tile's <img> is absolutely positioned, so the tile itself needs to be
   stretched to the thumb — left in flow it collapses to no height at all. */
.host__thumb .tile { position: absolute; inset: 0; }
.host__info { flex: 1; min-width: 0; }
.host__key {
  font: 400 12.5px/1.3 var(--mono); color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.host__meta { margin-top: 4px; font-size: 12.5px; color: var(--brown-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.host__actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.host__pill {
  font: 400 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--brown-4); border: 1px solid var(--line-2); border-radius: 999px; padding: 6px 10px;
}

/* Credit editing — the host's correction for a name a guest typed. */
.namebox {
  margin-top: 7px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 13px; color: var(--brown-1);
}
.namebox b { font-weight: 500; }
.namebox i { color: var(--brown-4); font-style: italic; }
.namebox__row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.namebox--open { flex-direction: column; align-items: stretch; gap: 10px; max-width: 42ch; }
.namebox--open input {
  width: 100%; min-height: 44px; padding: 0 14px;
  font: inherit; font-size: 15px; color: var(--brown-0);
  background: #fff; border: 1px solid #E8D8BE; border-radius: 12px;
}
.namebox--open input:focus-visible { outline: 2px solid var(--sage); outline-offset: 1px; }
.namebox--open .btn { min-height: 40px; padding: 0 16px; }
.host__was { font-size: 12px; color: var(--brown-4); font-style: italic; }
.host__pill--soft { color: var(--brown-3); border-color: var(--line-2); }

/* A flagged name is a prompt to look, not a verdict — amber, not red. */
.host__flag {
  font: 400 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: #8A5A12; background: #FBF0DA; border: 1px solid #E6C98A;
  border-radius: 999px; padding: 6px 10px;
}
.host__row.is-flagged { border-left: 3px solid #E6C98A; padding-left: 9px; }
.host__stat--flag b { color: #8A5A12; }

/* ==========================================================================
   QR sign
   ========================================================================== */
.screen--sign {
  align-items: center; justify-content: center; gap: 20px;
  padding: clamp(24px, 6cqw, 60px);
  background: repeating-linear-gradient(45deg, #EFE8DC 0 12px, #ECE5D8 12px 24px);
}
.sign__card {
  width: min(100%, 420px); aspect-ratio: 5 / 7;
  background: var(--cream-raised); border-radius: 4px;
  box-shadow: 0 30px 70px rgba(80, 58, 36, .22);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: clamp(22px, 6cqw, 46px);
  border: 1px solid var(--line-3);
}
.sign__date { font: 400 clamp(9px, 2.2cqw, 11px)/1 var(--mono); letter-spacing: .3em; text-transform: uppercase; color: var(--brown-5); }
.sign__card h2 {
  margin: clamp(12px, 3cqw, 20px) 0 0; font-family: var(--serif); font-weight: 400;
  font-size: clamp(28px, 8.4cqw, 42px); line-height: 1.06; letter-spacing: -.01em;
}
.sign__card p { margin: 10px 0 0; max-width: 24ch; font-size: clamp(13px, 3.4cqw, 15px); line-height: 1.5; color: var(--brown-1); }
.sign__qr { margin: clamp(20px, 5cqw, 32px) 0; padding: 14px; background: #FFF; border: 1px solid #EFE6D9; border-radius: 12px; }
.sign__qr svg { display: block; width: clamp(140px, 40cqw, 190px); height: auto; }
.sign__card .wordmark { font-size: clamp(14px, 3.8cqw, 17px); }
.sign__card .wordmark span { color: var(--sage); }
.sign__hint { margin-top: 8px; font-size: clamp(11px, 2.8cqw, 13px); color: var(--brown-4); }
.sign__spec { font-size: 12px; color: var(--brown-3); }

@media print {
  .sign__spec, .toast, .mobilebar { display: none !important; }
  .screen--sign { background: #FFF; padding: 0; }
  .sign__card { box-shadow: none; border: 0; width: 5in; height: 7in; aspect-ratio: auto; }
}

/* ==========================================================================
   Lightbox + toast
   ========================================================================== */
.lightbox {
  position: fixed; inset: 0; z-index: 40;
  background: rgba(22, 17, 12, .96);
  display: flex; flex-direction: column;
  animation: fadeIn .22s both;
}
.lightbox__bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; color: rgba(247, 240, 230, .72);
}
.lightbox__pos { font: 400 11px/1 var(--mono); letter-spacing: .16em; }
.lightbox__bar .row { display: flex; gap: 8px; }
/* Save is an <a> and Close is a <button>; without an explicit box the anchor
   stays display:inline, where min-height and vertical padding do nothing. */
.lightbox__act {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; height: 44px; padding: 0 18px;
  background: rgba(247, 240, 230, .1); border: 0; border-radius: 999px;
  color: var(--night-ink); font-size: 13px; line-height: 1; cursor: pointer;
  text-decoration: none; white-space: nowrap; transition: background .2s;
}
.lightbox__act:hover { color: var(--night-ink); }
.lightbox__act:hover { background: rgba(247, 240, 230, .2); }
.lightbox__close { width: 44px; min-width: 44px; padding: 0; border-radius: 50%; font-size: 20px; }
.lightbox__stage { flex: 1; position: relative; min-height: 0; }

/* A real horizontal scroller, one screen-wide slide per photo, snapping to
   each. Native scrolling is what makes a swipe follow the finger and keep its
   momentum; the padding lives on the slide rather than here so a thumb can
   still start its swipe at the very edge of the screen. */
.lightbox__scroller {
  position: absolute; inset: 0;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.lightbox__scroller::-webkit-scrollbar { display: none; }

/* The track spans the whole gallery even though only the slides around the one
   on screen exist. A slide's offset works out to its index times the viewport
   width whatever --lb-n happens to be, so building or dropping one never moves
   another — which is what lets the window be rebuilt mid-scroll. */
.lightbox__track { position: relative; height: 100%; width: calc(100% * var(--lb-n, 1)); }
.lightbox__slide {
  position: absolute; top: 0; bottom: 0;
  width: calc(100% / var(--lb-n, 1));
  left: calc(var(--i, 0) * 100% / var(--lb-n, 1));
  display: flex; align-items: center; justify-content: center;
  padding: 0 clamp(10px, 3cqw, 60px);
  scroll-snap-align: center;
  /* One flick, one photo — so a guest can never get ahead of the handful of
     slides that are actually built. */
  scroll-snap-stop: always;
  /* So the frame inside can be measured against the stage it has to fit. */
  container-type: size;
}
.lightbox__media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain; display: block;
}
/* The gallery-size layer underneath is usually already cached from the grid,
   so a swipe lands on the photo and the full-size one arrives over it. */
.lightbox__media--full { opacity: 0; transition: opacity .3s var(--ease); }
.lightbox__media--full.is-loaded { opacity: 1; }
.lightbox__nav {
  position: absolute; z-index: 2;
  width: 48px; height: 48px; border-radius: 50%;
  background: rgba(247, 240, 230, .1); border: 0; color: var(--night-ink);
  font-size: 20px; cursor: pointer; transition: background .2s;
}
.lightbox__nav:hover { background: rgba(247, 240, 230, .22); }
.lightbox__nav.prev { left: clamp(8px, 2cqw, 26px); }
.lightbox__nav.next { right: clamp(8px, 2cqw, 26px); }
/* At either end there is nowhere to go, and an arrow that does nothing is
   worse than no arrow at all. */
.lightbox__nav[disabled] { opacity: 0; pointer-events: none; }
/* The frame takes the photo's own shape: as wide as the stage allows, but
   never wider than its height at that shape. A fixed width and a capped height
   fought each other on anything tall, and the photo sat letterboxed inside a
   frame the wrong shape for it. --ar is the same ratio as aspect-ratio, as a
   plain number, because only a number can be multiplied by a length. */
.lightbox__frame {
  position: relative;
  width: min(100cqw, 820px, 100cqh * var(--ar, 1));
  max-height: 100%;
  border-radius: 10px; overflow: hidden; background: #232A26;
  box-shadow: 0 30px 70px rgba(0,0,0,.5);
  animation: fadeIn .3s both;
}
.lightbox__foot { padding: 16px 20px 26px; text-align: center; color: rgba(247, 240, 230, .7); }
.lightbox__credit { margin-top: 5px; font: 400 11px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase; }

.toast {
  position: fixed; left: 50%; bottom: 90px; z-index: 60;
  transform: translateX(-50%);
  padding: 12px 20px;
  background: rgba(28, 22, 17, .94); color: var(--night-ink);
  border-radius: 999px; font-size: 14px;
  box-shadow: 0 12px 30px rgba(0,0,0,.28);
  animation: fadeUp .3s var(--ease) both;
  max-width: calc(100cqw - 32px); text-align: center;
}

/* A person's name keeps its own capitalisation; the surrounding mono label
   stays uppercase as the design has it. */
.credit-name { text-transform: none; letter-spacing: .04em; }
.credit-dot { opacity: .6; }

.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;
}

/* Wide-viewport affordances the design gates behind its `isWide` check. */
@container (min-width: 620px) {
  .landing__navactions { display: flex; }
  .topbar__actions { display: flex; }
  .mobilebar { display: none; }
  .screen--gallery { padding-bottom: 40px; }
}
@container (max-width: 619px) {
  .topbar__actions { display: none; }
}

/* ==========================================================================
   Video — tiles, the trim sheet, and the guestbook
   Added alongside guest video upload. The palette, easing and type scale are
   the design's; nothing here introduces a new token.
   ========================================================================== */

/* --- Video inside a tile -------------------------------------------------
   A <video> has to sit exactly where .tile img sits, but without the fade:
   the poster is painted by the element itself, so there is no load event to
   wait on and a transition would only make the tile flash. */
.tile--video video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  background: #E7DED2;
}

/* The play affordance is a hint, not a control — the whole tile is the
   button, so this must never look separately clickable. */
.tile__play {
  position: absolute; left: 50%; top: 50%;
  width: 46px; height: 46px; margin: -23px 0 0 -23px;
  border-radius: 999px;
  background: rgba(20, 14, 9, .38);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .22);
  pointer-events: none;
  transition: background .2s var(--ease), transform .2s var(--ease);
}
.tile__play::after {
  content: ''; position: absolute; left: 53%; top: 50%;
  transform: translate(-50%, -50%);
  border-style: solid; border-width: 8px 0 8px 13px;
  border-color: transparent transparent transparent rgba(255, 250, 242, .95);
}
.masonry__item:hover .tile__play { background: rgba(20, 14, 9, .52); transform: scale(1.06); }

.tile__dur {
  position: absolute; right: 8px; bottom: 8px;
  padding: 3px 7px; border-radius: 5px;
  background: rgba(20, 14, 9, .58);
  font: 400 11px/1 var(--mono);
  letter-spacing: .06em; color: rgba(255, 250, 242, .95);
  pointer-events: none;
}
.tile--square .tile__play { width: 34px; height: 34px; margin: -17px 0 0 -17px; }
.tile--square .tile__play::after { border-width: 6px 0 6px 10px; }
.tile--square .tile__dur { right: 5px; bottom: 5px; font-size: 10px; padding: 2px 5px; }

/* The upload grid stacks a veil and a badge over the tile; both must clear
   the duration pill rather than sit under it. */
.badge-slot { position: absolute; left: 6px; top: 6px; z-index: 3; }

/* --- The record CTA on the landing page ---------------------------------- */
.btn--record {
  min-height: 58px; padding: 0 24px;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  background: var(--cream-raised);
  border: 1px solid var(--line-4);
  font-size: 17px; color: var(--ink);
}
.btn--record:hover { background: #F0E9DB; border-color: var(--brown-5); }
.btn__rec-dot {
  width: 9px; height: 9px; border-radius: 999px;
  background: #B4553F; flex: none;
  box-shadow: 0 0 0 3px rgba(180, 85, 63, .16);
}
/* Two lines inside a 58px pill, so the record CTA stays the same height as the
   primary above it — the caption explains where the message lands without
   letting the middle CTA outweigh the first. */
.btn__rec-label {
  display: flex; flex-direction: column; align-items: center;
  line-height: 1.15;
}
.btn__rec-sub {
  margin-top: 2px;
  font-size: 11px; font-weight: 400; letter-spacing: .04em;
  color: var(--brown-4);
}

/* --- The quiet off-ramp --------------------------------------------------
   Deliberately a line of text, not a button: it competes with nothing. */
.offramp {
  margin: 14px 0 0;
  font-size: 13px; line-height: 1.5; color: var(--brown-4); text-align: center;
}
.offramp a { color: var(--brown-2); text-decoration: underline; text-underline-offset: 2px; }
.offramp a:hover { color: var(--ink); }

/* --- Bottom sheet (the trim UI lives in one) ----------------------------- */
.sheet {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(26, 20, 14, .52);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  animation: sheetIn .28s var(--ease) both;
}
@keyframes sheetIn { from { opacity: 0 } to { opacity: 1 } }
.sheet__card {
  width: min(560px, 100%);
  max-height: 92dvh; overflow-y: auto;
  padding: 22px clamp(16px, 4cqw, 26px) max(22px, env(safe-area-inset-bottom));
  background: var(--cream);
  border-radius: 22px 22px 0 0;
  box-shadow: 0 -20px 60px rgba(40, 28, 16, .3);
  animation: sheetUp .34s var(--ease) both;
}
@keyframes sheetUp { from { transform: translateY(18px) } to { transform: translateY(0) } }
.sheet__head h2 {
  margin: 0; font-family: var(--serif); font-weight: 400;
  font-size: clamp(23px, 6cqw, 30px); line-height: 1.1;
}
.sheet__head p { margin: 8px 0 0; font-size: 14px; line-height: 1.5; color: var(--brown-2); }
.sheet__actions { display: flex; flex-direction: column; gap: 10px; margin-top: 18px; }
.sheet__actions .btn { width: 100%; }

/* --- Trim ---------------------------------------------------------------- */
.trim__preview {
  position: relative; margin-top: 16px;
  border-radius: 14px; overflow: hidden; background: #1E2421;
  aspect-ratio: 16 / 9;
}
.trim__preview video { width: 100%; height: 100%; object-fit: contain; display: block; }
.trim__readout {
  margin-top: 10px;
  font: 400 12px/1 var(--mono);
  letter-spacing: .12em; text-transform: uppercase; color: var(--brown-3);
  text-align: center;
}

.trim__strip {
  position: relative; margin-top: 12px; height: 62px;
  border-radius: 10px; overflow: hidden;
  background: var(--cream-sunk); border: 1px solid var(--line-2);
  touch-action: none; /* the window is dragged; the page must not scroll with it */
  cursor: grab;
}
.trim__strip:active { cursor: grabbing; }
.trim__frames { position: absolute; inset: 0; display: flex; }
.trim__frame {
  flex: 1 1 0; min-width: 0;
  background-size: cover; background-position: center;
  opacity: 0; transition: opacity .3s var(--ease);
}
.trim__frame.is-on { opacity: 1; }

/* Everything outside the window is dimmed by the window's own huge shadow,
   which is cheaper than maintaining two masking elements as it moves. */
.trim__window {
  position: absolute; top: 0; bottom: 0;
  box-shadow: 0 0 0 9999px rgba(26, 20, 14, .55);
  border: 2px solid var(--gold);
  border-radius: 6px;
  cursor: grab;
}
.trim__handle {
  position: absolute; top: 0; bottom: 0; width: 26px;
  display: flex; align-items: center; justify-content: center;
  cursor: ew-resize; touch-action: none;
}
.trim__handle::after {
  content: ''; width: 4px; height: 24px; border-radius: 3px;
  background: var(--gold); box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
}
.trim__handle--l { left: -14px; }
.trim__handle--r { right: -14px; }

/* --- Guestbook ----------------------------------------------------------- */
.screen--guestbook { display: flex; flex-direction: column; min-height: 100dvh; }
.gb { flex: 1; display: flex; flex-direction: column; padding: 0 clamp(16px, 4cqw, 34px) 32px; }
.gb__intro {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; padding: 0 clamp(16px, 4cqw, 34px) 40px; text-align: center;
}
.gb__intro .upload__lead { text-align: center; }
.gb__intro .btn { width: min(340px, 100%); }

.gb__frame {
  position: relative; flex: 1; min-height: 0;
  margin-top: 8px; border-radius: 18px; overflow: hidden;
  background: #1E2421;
  box-shadow: 0 18px 44px rgba(40, 28, 16, .22);
}
.gb__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }

.gb__controls { display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 18px; }
.gb__rec {
  position: relative; width: 84px; height: 84px;
  border: 0; background: transparent; padding: 0; cursor: pointer;
  border-radius: 999px;
}
.gb__ring { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.gb__ring-bg { fill: none; stroke: var(--line-4); stroke-width: 5; }
.gb__ring-fill {
  fill: none; stroke: #B4553F; stroke-width: 5; stroke-linecap: round;
  transition: stroke-dashoffset .12s linear;
}
/* The centre morphs square as it records — the standard "this is capturing"
   language, and it doubles as the stop affordance. */
.gb__dot {
  position: absolute; left: 50%; top: 50%;
  width: 52px; height: 52px; margin: -26px 0 0 -26px;
  border-radius: 999px; background: #B4553F;
  transition: width .22s var(--ease), height .22s var(--ease),
              margin .22s var(--ease), border-radius .22s var(--ease);
}
.gb__rec.is-recording .gb__dot {
  width: 28px; height: 28px; margin: -14px 0 0 -14px; border-radius: 7px;
}
.gb__rec:active .gb__dot { transform: scale(.94); }
.gb__timer {
  margin: 0; font: 400 12px/1 var(--mono);
  letter-spacing: .14em; text-transform: uppercase; color: var(--brown-3);
}

.gb__review { display: flex; flex-direction: column; gap: 12px; padding-top: 18px; }
.gb__review h2 {
  margin: 0; font-family: var(--serif); font-weight: 400;
  font-size: clamp(22px, 6cqw, 28px); line-height: 1.1; text-align: center;
}
.gb__review .btn, .gb__review .btn--text { width: 100%; }
.gb__status { margin: 12px 0 0; font-size: 14px; color: var(--brown-2); }

/* Who hears the message, on the screen rather than in the fineprint. The
   eyebrow does the work an icon would, in the type the rest of the site
   already uses for a label. */
.gb__private {
  display: flex; flex-direction: column; gap: 7px;
  width: min(340px, 100%); padding: 12px 14px;
  border: 1px solid var(--line-4); border-radius: 12px;
  background: var(--cream-raised); text-align: left;
}
.gb__private-label {
  font: 400 10px/1 var(--mono);
  letter-spacing: .2em; text-transform: uppercase; color: #B4553F;
}
.gb__private p {
  margin: 0; font-size: 13px; line-height: 1.5; color: var(--brown-1);
}
/* In the review sheet it sits in a full-width column with the name field. */
.gb__review .gb__private { width: 100%; }
/* On the thank-you screen it follows a line of prose rather than a heading. */
.done .gb__private { margin-top: 18px; }

/* A camera that never started should still look like a considered screen. */
.gb__art { position: relative; width: 92px; height: 92px; }
.gb__art span {
  position: absolute; inset: 0; border-radius: 999px;
  border: 1px solid var(--line-4); background: var(--cream-raised);
}
.gb__art i {
  position: absolute; left: 50%; top: 50%;
  width: 30px; height: 30px; margin: -15px 0 0 -15px;
  border-radius: 999px; background: #B4553F; opacity: .82;
}

/* The live stage fills its slot with the clip itself rather than a poster. */
.live__fill video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* The caption names photos and video separately, which is longer than the old
   "N photos" and sits beside the live toggle. Letting the row wrap gives the
   caption its own line rather than crushing it into a narrow column. */
.tabs { flex-wrap: wrap; }
.tabs__caption { white-space: nowrap; }


/* --- The private guestbook -----------------------------------------------
   A column rather than a grid. Each card is one person talking, and a wall of
   tiles would ask the couple to choose between them instead of sitting
   through them in turn. */
.screen--messages { padding-bottom: 56px; }

.msg__list { display: flex; flex-direction: column; gap: 22px; margin-top: 22px; }

.msg {
  border: 1px solid var(--line-4); border-radius: 16px; overflow: hidden;
  background: var(--cream-raised);
}
/* Portrait, because a phone held up to a face is, and `contain` so the one
   guest who recorded on a laptop is letterboxed rather than cropped. */
.msg__frame { position: relative; aspect-ratio: 3 / 4; background: #232A26; }
.msg__video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; display: block;
}

.msg__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 14px 16px;
}
.msg__who { min-width: 0; }
.msg__who b {
  display: block; font-family: var(--serif); font-weight: 400; font-size: 19px;
  color: var(--ink);
}
.msg__who span {
  display: block; margin-top: 4px;
  font: 400 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--brown-3);
}

@media (min-width: 760px) {
  .msg__list {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    align-items: start;
  }
}
