/* Santa Got Caught design tokens v2 (site v2, impact pass). Single source of values; see design/DESIGN.md.
   public/base.css opens with an exact copy of this block (tests/copy.test.js checks they match). */
:root {
  /* colour: paper for the page, the camera's night for every picture well, one Christmas red for the action */
  --c-bg: #f6f5f1;
  --c-text: #1f2226;
  --c-text-2: #565b62;
  --c-night: #27302b;
  --c-night-ink: #e9ece6;
  --c-action: #b3261e;
  --c-action-ink: #ffffff;
  --c-error: #8a5300;
  --c-line: rgb(31 34 38 / 0.12);
  --c-fill: rgb(31 34 38 / 0.05);
  --c-scrim: rgb(31 34 38 / 0.40);
  --c-focus: #1f2226;
  /* the camera surface: footage sections only (hero, examples, the end), never a dark mode */
  --c-cam: #151a17;
  --c-cam-ink: #e9ece6;
  --c-cam-ink-2: #a7afa8;
  --c-cam-line: rgb(233 236 230 / 0.16);
  --c-rec: #e02020;
  /* the word CAUGHT. in the home H1: 4.37:1 on cam, 3.37:1 on night (the desktop panel); --c-rec is 2.85:1 on night */
  --c-display-red: #f03232;
  --shadow-osd: 0 0 2px #000000, 0 1px 2px #000000;

  /* type: two families (weights 400 500 600) and one display face (700) for the home H1; phone sizes here, desktop sizes in the media blocks below */
  --font-body: "Geist", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Geist Mono", "SFMono-Regular", Menlo, Consolas, monospace;
  /* display: the home H1 only (Passion One 700, OFL); the two "Passion One fallback" faces in base.css are
     local fonts scaled to its width, so the H1 keeps its two lines before it loads */
  --font-display: "Passion One", "Passion One fallback narrow", "Passion One fallback", Impact, "Arial Narrow Bold", sans-serif;
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-bold: 600;
  --fw-display: 700;
  --fs-small: 14px;
  --fs-body: 18px;
  --fs-h3: 24px;
  --fs-h2: 30px;
  --fs-h1: 40px;
  --fs-h1-app: 36px;
  --fs-osd: 14px;
  --fs-display: 64px;
  --lh-body: 1.5;
  --lh-head: 1.1;
  --lh-display: 1;

  /* space: the skill's scale */
  --s-4: 4px; --s-8: 8px; --s-12: 12px; --s-16: 16px;
  --s-24: 24px; --s-32: 32px; --s-48: 48px; --s-64: 64px;
  --s-96: 96px; --s-128: 128px;

  /* layout: one centred container; app screens and text in narrower columns */
  --container: 1200px;
  --col: 560px;
  --measure: 720px;
  --gutter: 16px;
  --gutter-l: max(var(--gutter), env(safe-area-inset-left));
  --gutter-r: max(var(--gutter), env(safe-area-inset-right));
  --bar: 56px;
  --btn-h: 56px;
  --cta-h: calc(var(--btn-h) + 2 * var(--s-16) + env(safe-area-inset-bottom));
  --tap: 44px;
  --hair: 1px;
  --ring: 2px;
  --icon: 32px;
  --hero-h: 48dvh;
  --feed-h: 58svh;
  --strip-h: 180px; /* the camera roll's frame height (4:3 frames) */

  /* radius and shadow: pictures square, controls pill, panels 8, no shadow */
  --r-img: 0;
  --r-ui: 9999px;
  --r-panel: 8px;
  --shadow: none;

  /* motion */
  --dur-press: 120ms;
  --dur-hover: 200ms;
  --dur-entrance: 640ms;
  --dur-loop: 1400ms;
  --dur-blink: 1000ms;
  --dur-notice: 2800ms;
  --dur-delay: 300ms;
  --dur-strip: 90s; /* one loop of the camera roll: about 27px a second */
  --ease-enter: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-press: ease;
  --ease-loop: ease-in-out;
}

/* small phones (360 and less): the display H1 at 60, so the top half of the hero button shows at 360x560 */
@media (max-width: 374px) {
  :root {
    --fs-display: 60px;
  }
}

@media (min-width: 744px) {
  :root {
    --fs-h3: 24px;
    --fs-h2: 36px;
    --fs-h1: 60px;
    --fs-osd: 18px;
    --fs-display: 80px;
    --gutter: 32px;
    --feed-h: 62svh;
  }
}

@media (min-width: 1024px) {
  :root {
    --gutter: 48px;
    --hero-h: min(60vh, 600px);
    --strip-h: 240px;
    /* 1024 to 1279: the panel beside the picture is too narrow for 80 ("SANTA GOT" is 4.559em) */
    --fs-display: 64px;
  }
}

@media (min-width: 1280px) {
  :root {
    --fs-display: 80px;
  }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-press: 1ms;
    --dur-entrance: 1ms;
    --dur-notice: 1ms;
  }
}
/* Santa Got Caught styles. Every value comes from the tokens above. Phone first. The home page runs in
   bands edge to edge: dark camera bands (--c-cam) for footage, light paper bands for explanation. The
   flow, the private link and the legal pages sit in a 560px column on paper. */
@font-face { font-family: "Geist"; src: url("/fonts/Geist-Variable.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }
@font-face { font-family: "Geist Mono"; src: url("/fonts/GeistMono-Variable.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }
/* the ?v= is views/layout.js v() of this file (the home page preloads that same URL; tests/site.test.js checks they match) */
@font-face { font-family: "Passion One"; src: url("/fonts/PassionOne-Latin-700.woff2?v=0fbc77f090") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
/* fallbacks scaled to Passion One's width ("SANTA GOT": Passion One 4.559em, Impact about 4.6em, DejaVu Sans Bold 6.411em, Arial Bold less) */
@font-face { font-family: "Passion One fallback narrow"; src: local("Impact"); font-weight: 700; size-adjust: 95%; }
@font-face { font-family: "Passion One fallback"; src: local("Arial Bold"), local("Arial-BoldMT"), local("Helvetica Bold"), local("Helvetica-Bold"), local("Liberation Sans Bold"), local("LiberationSans-Bold"), local("DejaVu Sans Bold"), local("DejaVuSans-Bold"); font-weight: 700; size-adjust: 70%; }

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { margin: 0; background: var(--c-bg); color: var(--c-text); font-family: var(--font-body); font-size: var(--fs-body); font-weight: var(--fw-regular); line-height: var(--lh-body); }
input, select, textarea, button { font: inherit; font-size: var(--fs-body); }
a { color: inherit; text-underline-offset: var(--s-4); }
a:hover { text-decoration-thickness: var(--ring); }
img, video { max-width: 100%; }
:focus-visible { outline: var(--ring) solid var(--c-focus); outline-offset: var(--ring); }

/* shell: one centred column; the home page (.wide) runs edge to edge and its bands keep the container */
.app { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; width: 100%; max-width: calc(var(--container) + 2 * var(--gutter)); margin: 0 auto; padding-left: var(--gutter-l); padding-right: var(--gutter-r); }
.top { flex: none; display: flex; align-items: center; min-height: var(--bar); padding-top: env(safe-area-inset-top); }
.brand { display: inline-flex; align-items: center; gap: var(--s-8); min-height: var(--tap); font-family: var(--font-mono); font-weight: var(--fw-bold); text-decoration: none; }
.brand img { width: var(--icon); height: var(--icon); }
.main, .flow, .view { flex: 1; display: flex; flex-direction: column; }
.main { width: 100%; max-width: var(--col); margin: 0 auto; }
.app.wide { max-width: none; padding-left: 0; padding-right: 0; }
[data-view="home"] { background: var(--c-cam); }
.wide .main { max-width: none; }
/* the home header is on the camera surface: its focus ring is light */
.wide .top :focus-visible { outline-color: var(--c-cam-ink); }
.wide .top { padding-left: max(var(--gutter-l), calc((100% - var(--container)) / 2)); padding-right: max(var(--gutter-r), calc((100% - var(--container)) / 2)); background: var(--c-cam); color: var(--c-cam-ink); }
.wide .view:not([data-view="home"]) { width: 100%; max-width: calc(var(--col) + 2 * var(--gutter)); margin: 0 auto; padding-left: var(--gutter-l); padding-right: var(--gutter-r); }

/* type */
h1, h2, h3 { font-weight: var(--fw-bold); line-height: var(--lh-head); text-wrap: balance; }
h1 { font-size: var(--fs-h1); margin: var(--s-16) 0 var(--s-16); }
.app:not(.wide) h1 { font-size: var(--fs-h1-app); }
h2 { font-size: var(--fs-h2); margin: var(--s-48) 0 var(--s-16); }
h3 { font-size: var(--fs-h3); margin: var(--s-32) 0 var(--s-8); }
p { margin: 0 0 var(--s-16); }
.view > h2:first-child, .pick > h2:first-child { margin-top: var(--s-16); }
.sub, .lede { color: var(--c-text-2); }
.note, .notes { color: var(--c-text-2); font-size: var(--fs-small); }
.price { font-family: var(--font-mono); font-weight: var(--fw-bold); }

/* bands: paper for explanation, camera for footage; content keeps the container */
.band { padding: var(--s-64) max(var(--gutter-r), calc((100% - var(--container)) / 2)) var(--s-64) max(var(--gutter-l), calc((100% - var(--container)) / 2)); }
.cam { background: var(--c-cam); color: var(--c-cam-ink); }
.paper { background: var(--c-bg); color: var(--c-text); }
.cam .lede, .cam figcaption, .cam .note { color: var(--c-cam-ink-2); }
.cam :focus-visible { outline-color: var(--c-cam-ink); }
.cam .toggle { border-color: var(--c-cam-line); color: var(--c-cam-ink); }
.cam .toggle:hover { border-color: var(--c-cam-ink); }

/* picture wells: the poster image, with the clip over it once it plays */
figure { margin: 0; }
.well { position: relative; overflow: hidden; background: var(--c-night); border-radius: var(--r-img); }
.cam .well { background: var(--c-cam); }
.well img { display: block; width: 100%; height: auto; }
.well video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity var(--dur-hover) var(--ease-enter); }
.well.on video { opacity: 1; }
figcaption { display: flex; align-items: center; justify-content: space-between; gap: var(--s-8); min-height: var(--tap); color: var(--c-text-2); font-family: var(--font-mono); font-size: var(--fs-small); line-height: var(--lh-head); }
.toggle { flex: none; min-height: var(--tap); padding: 0 var(--s-16); border: var(--hair) solid var(--c-line); border-radius: var(--r-ui); background: transparent; color: var(--c-text); font-family: var(--font-mono); font-size: var(--fs-small); cursor: pointer; transition: border-color var(--dur-hover) var(--ease-press), transform var(--dur-press) var(--ease-press); -webkit-tap-highlight-color: transparent; }
.toggle:hover { border-color: var(--c-text); }
.toggle:active { transform: scale(0.97); }
.toggle-row { grid-column: 1 / -1; margin: 0; }
/* clip frames: a slow zoom inside the fixed frame on hover (desktop pointers only) */
@media (hover: hover) {
  .card .well img, .card .well video { transition: transform var(--dur-entrance) var(--ease-enter), opacity var(--dur-hover) var(--ease-enter); }
  .card:hover .well img, .card:hover .well video { transform: scale(1.03); }
}

/* the hero on a phone, top to bottom: the countdown line (only in season), the H1, the line under it, the
   camera feed edge to edge with exactly its three overlays (clock, REC, camera name), one quiet mono row under
   it (the honest caption and the clip's controls), the one main button, the price line. Phone gaps are the
   scale's small steps (12, 8, 12, 12, 4) so the whole button shows in Safari's visible area (375x630). */
.hero { display: flex; flex-direction: column; padding: max(var(--s-12), env(safe-area-inset-top)) 0 var(--s-24); }
.hero > .kicker, .hero > h1, .hero > .sub, .hero > .hero-go, .hero > .hero-price { padding-left: var(--gutter-l); padding-right: var(--gutter-r); }
.hero .kicker { margin: 0 0 var(--s-8); color: var(--c-cam-ink-2); font-family: var(--font-mono); font-size: var(--fs-small); font-weight: var(--fw-bold); }
.hero h1 { margin: 0 0 var(--s-8); font-family: var(--font-display); font-size: var(--fs-display); font-weight: var(--fw-display); line-height: var(--lh-display); }
.hero h1 span { display: block; color: var(--c-display-red); }
.hero .sub { margin-bottom: var(--s-12); color: var(--c-cam-ink); }
.feed-well { aspect-ratio: 3 / 2; }
.feed-well img, .feed-well video { width: 100%; height: 100%; object-fit: cover; object-position: 45% 50%; }
.osd { position: absolute; inset: 0; padding: var(--s-12) var(--s-16); pointer-events: none; color: var(--c-cam-ink); font-family: var(--font-mono); font-size: var(--fs-osd); font-weight: var(--fw-bold); line-height: var(--lh-head); text-shadow: var(--shadow-osd); }
.osd > span { position: absolute; }
.osd-time { top: var(--s-12); left: var(--s-16); }
.osd-rec { top: var(--s-12); right: var(--s-16); display: flex; align-items: center; gap: var(--s-8); }
.osd-rec i { width: var(--s-12); height: var(--s-12); border-radius: var(--r-ui); background: var(--c-rec); }
.feed.live .osd-rec i { animation: blink var(--dur-blink) steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }
.osd-name { bottom: var(--s-12); left: var(--s-16); }
/* quiet mono controls (the hero's COLOUR / NIGHT and Pause, the strip's Pause): no chrome, a 44px hit area */
.osd-btn { display: inline-flex; align-items: center; justify-content: center; min-width: var(--tap); min-height: var(--tap); padding: 0 var(--s-8); border: 0; border-radius: 0; background: transparent; color: var(--c-cam-ink-2); font-family: var(--font-mono); font-size: var(--fs-small); font-weight: var(--fw-bold); line-height: var(--lh-head); text-transform: uppercase; cursor: pointer; transition: color var(--dur-hover) var(--ease-press); -webkit-tap-highlight-color: transparent; }
.osd-btn:hover, .osd-btn[aria-pressed="true"], .feed-pause { color: var(--c-cam-ink); }
.osd-btn[aria-pressed="true"] { text-decoration: underline; text-decoration-thickness: var(--ring); text-underline-offset: var(--s-4); }
[data-tap] { cursor: pointer; }
/* the row under the clip: the caption on the gutter (it may take two lines), the controls at the right; their
   text's right edge sits on the gutter (the buttons' 8px padding hangs into it) */
.feed-bar { position: relative; padding: 0 var(--gutter-r) 0 var(--gutter-l); color: var(--c-cam-ink-2); line-height: var(--lh-body); }
.feed-bar .hero-note { flex: 1 1 auto; min-width: 0; }
.feed-ctl { display: flex; flex: none; align-items: center; margin-right: calc(-1 * var(--s-8)); }
.feed-looks { display: flex; align-items: center; }
.hero-go { margin: var(--s-12) 0 var(--s-4); }
.hero-price { margin: 0; color: var(--c-cam-ink-2); font-size: var(--fs-small); }
/* phone: the Pause word does not fit the row at 375 next to the caption and the pair, so it is shown only on
   keyboard focus (over the picture's bottom right corner); a tap on the picture pauses the clip */
@media (max-width: 743px) {
  .feed-pause:not(:focus-visible) { position: absolute; width: 1px; height: 1px; min-width: 0; min-height: 0; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .feed-pause:focus-visible { position: absolute; right: var(--s-8); bottom: 100%; background: var(--c-cam); }
  /* the home view needs no header row on a phone: the H1 is the brand (the flow screens keep it) */
  .wide:has([data-view="home"]:not([hidden])) > .top { display: none; }
}
/* small phones (under 375): the scale's smallest steps, so the top half of the button shows at 360x560 even when
   the countdown line takes two lines */
@media (max-width: 374px) {
  .hero { padding-top: max(var(--s-8), env(safe-area-inset-top)); }
  .hero .kicker, .hero h1 { margin-bottom: var(--s-4); }
  .hero .sub { margin-bottom: var(--s-8); }
  .hero-go { margin-top: var(--s-8); }
}
.end-go { margin: var(--s-24) 0 0; }

/* the camera roll: the night's events as camera text, then a strip of 4:3 camera frames, all one height; the
   strip runs edge to edge on a phone. Without JavaScript and under reduce motion it is a row that scrolls
   sideways; site.js adds .moving (the aria-hidden copy of the track appears and the row moves one track's
   width per loop) and .paused. */
.events { margin: 0 0 var(--s-16); padding: 0; list-style: none; color: var(--c-cam-ink-2); font-family: var(--font-mono); font-size: var(--fs-small); line-height: var(--lh-body); white-space: pre-wrap; }
.events li:last-child { color: var(--c-cam-ink); font-weight: var(--fw-bold); }
.roll > p { color: var(--c-cam-ink); }
.strip { margin: var(--s-32) calc(-1 * var(--gutter-r)) 0 calc(-1 * var(--gutter-l)); }
.strip-view { overflow-x: auto; overscroll-behavior-x: contain; }
.strip-move { display: flex; width: max-content; }
.strip-track { display: flex; gap: var(--s-8); margin: 0; padding: 0 var(--s-8) 0 0; list-style: none; }
.strip-track[aria-hidden="true"] { display: none; }
.strip-track .well { width: calc(var(--strip-h) * 4 / 3); height: var(--strip-h); }
.strip-track img { width: 100%; height: 100%; object-fit: cover; }
.strip-track .osd { padding: 0; font-size: var(--fs-small); }
.frame-time { top: var(--s-8); left: var(--s-8); }
.frame-name { bottom: var(--s-8); left: var(--s-8); }
.strip.moving .strip-view { overflow: hidden; cursor: pointer; }
.strip.moving .strip-track[aria-hidden="true"] { display: flex; }
.strip.moving .strip-move { animation: strip var(--dur-strip) linear infinite; }
.strip.paused .strip-move { animation-play-state: paused; }
@keyframes strip { to { transform: translateX(-50%); } }
/* under the strip: the honest line on the gutter, the Pause / Play word at the right on the same row */
.strip-foot { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s-16); padding: var(--s-16) var(--gutter-r) 0 var(--gutter-l); }
.strip-foot .lede { margin: 0; }
.strip-toggle { flex: none; margin-top: calc(-1 * var(--s-12)); }

/* home sections: unrelated 64 apart on a phone, 96 on desktop; related 48 */
.sec + .sec { margin-top: var(--s-64); }
.sec + .sec-near { margin-top: var(--s-48); }
.sec > h2 { margin-top: 0; }
.text, .lede { max-width: var(--measure); }
.how { display: grid; gap: var(--s-24); margin: 0; padding: 0; list-style: none; }
.how li { display: grid; grid-template-columns: 144px 1fr; gap: var(--s-16); align-items: start; }
.how h3 { margin: 0 0 var(--s-8); }
.how p { margin: 0; color: var(--c-text-2); }
.how .toggle-row { margin-top: var(--s-8); }
.gets, .steps, .tips { margin: 0 0 var(--s-16); padding-left: var(--s-24); }
.gets li, .steps li, .tips li { margin-bottom: var(--s-8); }
.tips { color: var(--c-text-2); }
.doc ul { margin: 0 0 var(--s-16); padding-left: var(--s-24); }
.doc li { margin-bottom: var(--s-8); }

/* what you get: the walk-out clip, the price, the list and the button (in the dark band with the camera roll) */
.end { display: grid; gap: var(--s-32); }
.end .well { margin-left: calc(-1 * var(--gutter-l)); margin-right: calc(-1 * var(--gutter-r)); }
.get h2 { margin-top: 0; }
.cam .gets { color: var(--c-cam-ink); }
/* the toy ("One more thing"): a camera picture (4 frames of one picture, stacked, the next one fading in), the
   mono status, the log, and one area where the quiet control and the end line with the red button share a cell.
   The log keeps room for its 3 lines and the area for the end state, so the block has one height in every state
   (nothing jumps, and on desktop the text keeps the picture's centre line). */
.toy { margin-bottom: var(--s-48); }
.toy-grid { display: grid; gap: var(--s-16); }
.toy-shot { position: relative; }
.toy-well { aspect-ratio: 4 / 3; }
.toy-well img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.toy-frame { opacity: 0; transition: opacity var(--dur-entrance) var(--ease-enter); }
.toy-frame.on { opacity: 1; }
.toy-shot figcaption { min-height: 0; padding-top: var(--s-8); }
.toy-text { font-family: var(--font-mono); color: var(--c-cam-ink); }
.toy-status { display: grid; gap: var(--s-8); margin: 0 0 var(--s-16); font-weight: var(--fw-bold); line-height: var(--lh-head); }
.toy-clock { color: var(--c-cam-ink-2); font-size: var(--fs-small); }
.toy-log { min-height: calc(3 * var(--fs-small) * var(--lh-body)); margin: 0 0 var(--s-16); padding: 0; list-style: none; color: var(--c-cam-ink-2); font-size: var(--fs-small); line-height: var(--lh-body); white-space: pre-wrap; }
.toy-act-area { display: grid; }
.toy-act-area > * { grid-area: 1 / 1; }
.toy-act-area > [hidden] { display: block !important; visibility: hidden; }
.toy-act-row { margin: 0; }
.toy-act { display: inline-flex; align-items: center; min-height: var(--tap); padding: 0; border: 0; background: transparent; color: var(--c-cam-ink); font-family: var(--font-mono); font-size: var(--fs-body); text-decoration: underline; text-underline-offset: var(--s-4); cursor: pointer; -webkit-tap-highlight-color: transparent; }
.toy-act:hover { text-decoration-thickness: var(--ring); }
.toy-end { margin: 0 0 var(--s-24); }
.toy-go { margin: 0; }
.toy .btn { font-family: var(--font-body); }

.foot { display: grid; gap: var(--s-8); padding: var(--s-48) 0 var(--s-16); font-size: var(--fs-small); color: var(--c-text-2); }
.foot-links { display: flex; flex-wrap: wrap; column-gap: var(--s-24); }
.foot a { display: inline-flex; align-items: center; min-width: var(--tap); min-height: var(--tap); color: var(--c-text-2); }
.foot p { margin: 0; }
.cam .foot { padding-top: var(--s-16); border-top: var(--hair) solid var(--c-cam-line); color: var(--c-cam-ink-2); }
.cam .foot a { color: var(--c-cam-ink-2); }

/* the pinned main button; on the home page it sits on the camera surface */
.cta { position: sticky; bottom: 0; margin-top: auto; display: grid; gap: var(--s-8); padding: var(--s-16) 0 calc(var(--s-16) + env(safe-area-inset-bottom)); background: var(--c-bg); }
/* home: the pinned bar shows only with JavaScript (site.js adds .pin), and only while neither the hero button
   nor the end block (the price line and its button) is on screen; the page keeps room for it at the bottom */
[data-view="home"] > .cta { display: none; }
[data-view="home"].pin { padding-bottom: calc(var(--s-96) + env(safe-area-inset-bottom)); }
[data-view="home"].pin > .cta { display: grid; position: fixed; left: 0; right: 0; bottom: 0; z-index: 1; padding-left: var(--gutter-l); padding-right: var(--gutter-r); background: var(--c-cam); transform: translateY(100%); visibility: hidden; transition: transform var(--dur-hover) var(--ease-enter), visibility 0s linear var(--dur-hover); }
[data-view="home"].pin.up > .cta { transform: none; visibility: visible; transition: transform var(--dur-hover) var(--ease-enter), visibility 0s; }
.btn { display: flex; align-items: center; justify-content: center; width: 100%; min-height: var(--btn-h); padding: 0 var(--s-24); border: 0; border-radius: var(--r-ui); background: var(--c-action); color: var(--c-action-ink); font-weight: var(--fw-bold); text-decoration: none; cursor: pointer; transition: transform var(--dur-press) var(--ease-press), opacity var(--dur-press) var(--ease-press); -webkit-tap-highlight-color: transparent; }
.btn:hover { text-decoration: underline; text-underline-offset: var(--s-4); }
.btn-alt { min-height: var(--tap); background: transparent; color: var(--c-text); border: var(--hair) solid var(--c-line); }
.btn:active { transform: scale(0.97); opacity: 0.82; }
.vh:focus-visible + .btn { outline: var(--ring) solid var(--c-focus); outline-offset: var(--ring); }
@media (prefers-reduced-motion: reduce) {
  .btn, .toggle, .well video, .card .well img, .card .well video, [data-view="home"].pin > .cta, [data-view="home"].pin.up > .cta, .toy-frame { transition: none; }
  .btn:active, .toggle:active, .card:hover .well img, .card:hover .well video { transform: none; opacity: 1; }
  .feed.live .osd-rec i, .strip.moving .strip-move { animation: none; }
}

/* hidden but present: file inputs, radios, labels for readers; the honeypot sits off screen */
.vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

/* photo tips and the two photo buttons */
.pick { display: flex; flex-direction: column; flex: 1; }

/* the customer's photo, preview and video: square corners, heights in dvh */
.shot { display: flex; align-items: center; justify-content: center; height: 55dvh; margin: 0; overflow: hidden; background: var(--c-night); border-radius: var(--r-img); }
.shot img, .shot video { display: block; width: 100%; height: 100%; object-fit: contain; }
[data-view="wait"] .shot, .shot-sm { height: 36dvh; }
.reveal { animation: reveal var(--dur-entrance) var(--ease-enter) both; }
@keyframes reveal { from { opacity: 0; } to { opacity: 1; } }

/* upload progress (real) and the honest wait (indeterminate, timed lines) */
.bar, .indet { height: var(--s-8); margin: var(--s-16) 0 var(--s-8); overflow: hidden; background: var(--c-fill); border-radius: var(--r-ui); }
.bar span { display: block; height: 100%; background: var(--c-text); transform: scaleX(0); transform-origin: left; transition: transform var(--dur-hover) linear; }
.indet span { display: block; width: 40%; height: 100%; background: var(--c-text); animation: indet var(--dur-loop) var(--ease-loop) infinite; }
@keyframes indet { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
.status { font-weight: var(--fw-medium); }
.cks { margin: var(--s-16) 0; padding: 0; list-style: none; }
.ck { display: flex; align-items: center; gap: var(--s-8); margin-bottom: var(--s-8); opacity: 0.4; animation: ink var(--dur-entrance) var(--ease-enter) forwards; }
.ck::before { content: ""; flex: none; width: var(--s-12); height: var(--s-12); border: var(--ring) solid currentColor; border-radius: var(--r-ui); }
.ck-1 { animation-delay: 300ms; }
.ck-2 { animation-delay: 2600ms; }
.ck-3 { animation-delay: 5200ms; }
@keyframes ink { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .indet span { width: 100%; opacity: 0.3; animation: none; }
  .ck { opacity: 1; animation: none; }
  .reveal { animation: none; }
}

/* the private video: the video large at its own shape, the two switches and Save within thumb reach */
[data-video] .shot { height: auto; }
[data-video] .shot video { height: auto; max-height: var(--hero-h); }
[data-video] .cta { position: static; }
.looks { display: grid; gap: var(--s-8); margin: var(--s-16) 0 0; }
.switch { display: grid; grid-template-columns: 4.5em 1fr 1fr; align-items: center; gap: var(--s-8); font-size: var(--fs-small); }
.sw { color: var(--c-text-2); font-family: var(--font-mono); }
.switch button { display: grid; align-content: center; min-height: var(--tap); padding: var(--s-4) var(--s-8); border: var(--hair) solid var(--c-line); border-radius: var(--r-panel); background: transparent; color: var(--c-text); font-size: var(--fs-small); line-height: var(--lh-head); cursor: pointer; transition: border-color var(--dur-hover) var(--ease-press); -webkit-tap-highlight-color: transparent; }
.switch button:hover:not(:disabled) { border-color: var(--c-text); }
.switch button span { font-weight: var(--fw-medium); }
.switch button small { color: var(--c-text-2); font-size: var(--fs-small); }
.switch button small.gone { display: none; }
.switch button[aria-pressed="true"] { background: var(--c-text); border-color: var(--c-text); color: var(--c-bg); }
.switch button:disabled { cursor: default; color: var(--c-text-2); }

/* preview page and plain screens */
.notes { margin: var(--s-16) 0 0; padding: 0; list-style: none; }
.notes li { margin-bottom: var(--s-4); }
.plain h1, .plain h2, .view.plain > h2:first-child { margin-top: var(--s-48); }
.view > .vh:first-child + .shot { margin-top: var(--s-16); }
.doc { padding-bottom: var(--s-16); }
.doc h2 { font-size: var(--fs-h3); margin: var(--s-32) 0 var(--s-8); }

/* tablets and up: bigger type (tokens), wider frames, examples in a row, the pair side by side and big */
@media (min-width: 744px) {
  .end .well { margin-left: 0; margin-right: 0; }
  .strip { margin-left: 0; margin-right: 0; }
  .strip-foot { padding-left: 0; padding-right: 0; }
  .how li { grid-template-columns: 160px 1fr; }
  [data-view="home"] > .cta { justify-items: center; }
  [data-view="home"] > .cta .btn, .hero-go .btn, .end-go .btn, .toy-go .btn { max-width: 480px; }
  /* working pages: the buttons follow their content, 32 below the text (its own 16 margin plus 16); only a phone keeps
     them at the bottom, in thumb reach */
  .view:not([data-view="home"]) .cta { position: static; margin-top: var(--s-16); padding-top: 0; }
  .view:not([data-view="home"]) .notes + .cta { margin-top: var(--s-32); }
  .notes li:last-child { margin-bottom: 0; }
}

/* desktop: the share card inside the container (the picture left, the dark panel right, the same height), bands at 96 */
@media (min-width: 1024px) {
  .band { padding-top: var(--s-96); padding-bottom: var(--s-96); }
  /* Alignment rule (DESIGN.md): the text block and the visible picture share one vertical centre line and the
     block is never taller than the picture. The picture spans all rows; the two 1fr rows around the text split
     what is left, so the block sits on the picture's centre. The panel (::before) has the picture's height. */
  .hero { display: grid; grid-template-columns: minmax(0, 11fr) minmax(0, 9fr); grid-template-rows: 1fr auto auto auto auto auto 1fr; padding: var(--s-32) max(var(--gutter-r), calc((100% - var(--container)) / 2)) var(--s-64) max(var(--gutter-l), calc((100% - var(--container)) / 2)); }
  .hero::before { content: ""; grid-column: 2; grid-row: 1 / -1; background: var(--c-night); }
  .hero > .kicker, .hero > h1, .hero > .sub, .hero > .hero-go, .hero > .hero-price { grid-column: 2; padding-left: var(--s-48); padding-right: var(--s-48); }
  .hero > .kicker { grid-row: 2; margin-bottom: var(--s-8); }
  .hero > h1 { grid-row: 3; margin-bottom: var(--s-16); }
  .hero > .sub { grid-row: 4; margin-bottom: 0; }
  .hero > .hero-go { grid-row: 5; margin: var(--s-32) 0 var(--s-16); }
  .hero > .hero-price { grid-row: 6; }
  .hero-go .btn { max-width: 360px; }
  /* the picture: 4:3 at the column width (the clip is 3:2, cut at the sides as on the phone); the row under it
     (caption and controls) hangs in the band's bottom padding, so it does not move the picture's centre */
  .feed { position: relative; grid-column: 1; grid-row: 1 / -1; align-self: center; }
  .feed-well { aspect-ratio: 4 / 3; }
  .feed-bar { position: absolute; top: 100%; left: 0; right: 0; padding-left: 0; padding-right: 0; }
  .sec + .sec { margin-top: var(--s-96); }
  .sec + .sec-near { margin-top: var(--s-64); }
  .sec > h2 { margin-bottom: var(--s-24); }
  .how { grid-template-columns: repeat(3, 1fr); gap: var(--s-32); }
  .end { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); align-items: center; column-gap: var(--s-64); }
  .end-go { margin: var(--s-32) 0 0; }
  .end-go .btn, .toy-go .btn { max-width: 360px; }
  .toy { margin-bottom: var(--s-96); }
  .toy-grid { grid-template-columns: minmax(0, 11fr) minmax(0, 9fr); column-gap: var(--s-48); align-items: center; }
  .toy-shot figcaption { position: absolute; top: 100%; left: 0; right: 0; }
  [data-view="home"].pin { padding-bottom: 0; }
  [data-view="home"] > .cta, [data-view="home"].pin > .cta { display: none; }
}

/* 1024 to 1279: the panel is narrow, the countdown can take two lines: a 5:4 picture keeps it at least as tall
   as the text block (alignment rule) */
@media (min-width: 1024px) and (max-width: 1279px) {
  .feed-well { aspect-ratio: 5 / 4; }
}

/* 1280 and up: the display H1 at 80 (tokens), 24 under it */
@media (min-width: 1280px) {
  .hero h1 { margin-bottom: var(--s-24); }
}

/* "Where did you see us?" on the wait screen after payment: answered, the thank you takes the question's place in the same box */
.ask { margin: var(--s-24) 0 var(--s-16); }
.ask-body { display: grid; }
.ask-in, .ask-thanks { grid-area: 1 / 1; }
.ask-q { margin: 0 0 var(--s-8); font-size: var(--fs-h3); }
.ask-opts { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-8); }
.ask-opts button { min-height: var(--tap); padding: var(--s-4) var(--s-8); border: var(--hair) solid var(--c-line); border-radius: var(--r-panel); background: transparent; color: var(--c-text); font: inherit; font-size: var(--fs-small); font-weight: var(--fw-medium); cursor: pointer; transition: border-color var(--dur-hover) var(--ease-press); -webkit-tap-highlight-color: transparent; }
.ask-opts button:hover:not(:disabled) { border-color: var(--c-text); }
.ask-thanks { display: flex; align-items: center; justify-content: center; margin: 0; visibility: hidden; font-weight: var(--fw-medium); }
.ask.done .ask-in { visibility: hidden; }
.ask.done .ask-thanks { visibility: visible; }

/* Referral (views/refer.js). Preview: "Have a code?" is a quiet text control (a details summary, no box), the friend
   line is mono like the price; the free-video form has one optional email field. Video page: the share block after the
   buttons, alt-style controls only, so "Save video" stays the only main button. */
.code { margin: var(--s-16) 0 0; font-size: var(--fs-small); }
.code summary { display: inline-flex; align-items: center; min-height: var(--tap); color: var(--c-text-2); text-decoration: underline; text-underline-offset: var(--s-4); cursor: pointer; list-style: none; }
.code summary::-webkit-details-marker { display: none; }
.code summary:hover { text-decoration-thickness: var(--ring); }
.code-form { display: grid; grid-template-columns: 1fr auto; gap: var(--s-8); margin: var(--s-8) 0 0; }
.code-form .btn { width: auto; }
.code-form input { min-width: 0; }
.code .note { margin: var(--s-8) 0 0; }
.field { display: grid; gap: var(--s-4); color: var(--c-text-2); font-size: var(--fs-small); }
.field input, .code-form input { min-height: var(--tap); padding: 0 var(--s-12); border: var(--hair) solid var(--c-line); border-radius: var(--r-panel); background: transparent; color: var(--c-text); }
.field input:hover, .code-form input:hover { border-color: var(--c-text); }
.friend, .refer-link { font-family: var(--font-mono); }
.friend { margin: var(--s-16) 0 0; color: var(--c-text); }
.refer { margin: var(--s-32) 0 var(--s-16); }
.refer h2 { margin-top: 0; font-size: var(--fs-h3); }
.refer-link { margin: 0 0 var(--s-8); overflow-wrap: normal; font-weight: var(--fw-bold); }
.refer-acts { display: grid; gap: var(--s-8); margin: 0 0 var(--s-16); }
.gifts { display: grid; gap: var(--s-8); margin: var(--s-16) 0 0; padding: 0; list-style: none; }
.gifts li { display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: var(--s-8); }
.gifts li > span:first-child { grid-column: 1 / -1; }
.gifts li.used { grid-template-columns: 1fr auto; }
.gifts li.used > span:first-child { grid-column: auto; }
.gifts span { font-weight: var(--fw-medium); }
.gifts .gift-link { grid-column: 1 / -1; color: var(--c-text-2); font-family: var(--font-mono); font-size: var(--fs-small); font-weight: var(--fw-regular); overflow-wrap: normal; user-select: all; }
/* the add-on box in the pinned bar: one 44px row with the browser's own checkbox; its line only while ticked */
.addon { display: flex; align-items: center; gap: var(--s-8); min-height: var(--tap); font-weight: var(--fw-medium); cursor: pointer; }
.addon input { flex: none; width: var(--s-24); height: var(--s-24); margin: 0; accent-color: var(--c-text); }
.addon-note { margin: 0; }
.addon:has(input:not(:checked)) + .addon-note { display: none; }
/* the friend, "no longer available" and email lines ride inside the pinned bar on a phone, above its button */
.cta > .friend, .cta > .lost, .cta > .bad { margin: 0; }
.bad { color: var(--c-error); }
.stats { display: grid; grid-template-columns: 1fr auto; gap: var(--s-8) var(--s-16); margin: 0 0 var(--s-16); }
.stats dt { color: var(--c-text-2); }
.stats dd { margin: 0; font-family: var(--font-mono); font-weight: var(--fw-bold); text-align: right; }
.more { margin: var(--s-32) 0 var(--s-16); }
.more h2 { margin-top: 0; font-size: var(--fs-h3); }
.more-mine { margin: var(--s-16) 0 0; font-size: var(--fs-body); }
.more-mine + .gifts { margin-bottom: var(--s-24); }
.more-acts { display: grid; gap: var(--s-8); margin: 0 0 var(--s-8); }
.optin { display: grid; gap: var(--s-8); margin: var(--s-24) 0 var(--s-16); }
.optin .note { margin: 0; min-height: var(--s-24); }
@media (min-width: 744px) {
  .refer-acts, .more-acts { grid-template-columns: 1fr 1fr; }
  .gifts li { grid-template-columns: 1fr auto auto; }
  .gifts li > span:first-child { grid-column: auto; }
  .gifts .gift-link { grid-column: 1 / -1; }
  .gifts .btn { width: auto; }
}

/* Front door camera (views/result.js adds .tall): its pictures and clips are portrait, so the frame hugs the
   picture instead of a wide letterbox; the video keeps the same height limit as the living room clip. */
.shot.tall { width: fit-content; max-width: 100%; margin-inline: auto; }
.shot.tall img, .shot.tall video { width: auto; max-width: 100%; height: 100%; }
[data-video] .shot.tall video { height: auto; max-height: var(--hero-h); }
/* The camera choice on the pick step (views/home.js): the video page's switch, with the list spacing below it. Both
   headings (one per camera, one hidden) sit where the first one does. */
.pick > h2[data-for] { margin-top: var(--s-16); }
.pick-cam { margin: 0 0 var(--s-16); }
.pick-name { margin: 0 0 var(--s-16); }
/* The front door page (views/door.js): the home hero and sections with a tall clip. Phones: the clip in the middle of
   the hero, 9:16, as tall as the first screen allows once the countdown (two lines at most), the H1, the line under it
   and the whole button fit (375x630: Safari's visible area on an iPhone X); the price line and the honest caption
   follow under the button. The clip carries the product's own overlays, so nothing is drawn on it; the Pause word
   shows only on keyboard focus (a tap on the clip pauses it). */
.door-hero .feed-well { aspect-ratio: 9 / 16; width: auto; height: clamp(240px, calc(100svh - 336px), 640px); margin: 0 auto; }
.door-hero .feed-pause:not(:focus-visible) { position: absolute; width: 1px; height: 1px; min-width: 0; min-height: 0; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.door-hero .feed-pause:focus-visible { position: absolute; right: var(--s-8); bottom: var(--s-8); background: var(--c-cam); }
.door-hero > .hero-note { margin: var(--s-4) 0 0; padding-left: var(--gutter-l); padding-right: var(--gutter-r); color: var(--c-cam-ink-2); font-family: var(--font-mono); font-size: var(--fs-small); }
/* step 3: the door alert at full width, so the child's name in it can be read on a phone */
.how li.how-wide { grid-template-columns: 1fr; }
.door-back { margin-top: var(--s-32); }

/* The front door page on desktop: the clip column as wide as the clip, the dark panel beside it; the text block on
   the clip's centre line (the home hero's rule), with one more row for the honest caption. */
@media (min-width: 1024px) {
  .door-hero { grid-template-columns: auto minmax(0, 1fr); grid-template-rows: 1fr auto auto auto auto auto auto 1fr; }
  .door-hero .feed-well { height: min(70svh, 640px); }
  .door-hero > .hero-note { grid-column: 2; grid-row: 7; margin: var(--s-8) 0 0; padding-left: var(--s-48); padding-right: var(--s-48); }
  .end.door-get { grid-template-columns: minmax(0, 1fr); }
  .door-get .get { max-width: var(--measure); }
}

/* What you get (views/home.js). Phones: the walk-out clip at full width as before, the tall front door clip on its own
   row below it at half the width, left on the text line, and its three lines in the other half, from the clip's top.
   Tablet and up: side by side at one height (columns in the ratio of their widths at equal height: 640/426 and
   360/630), the three lines under the front door clip, where captions go. */
.end .ex-pair { display: grid; gap: var(--s-16); }
.end .ex-door { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-16); align-items: start; }
.end .ex-door .well { margin-left: 0; margin-right: 0; }
.ex-door-text p { margin: 0 0 var(--s-8); color: var(--c-cam-ink); }
.ex-door-text .ex-cap { color: var(--c-cam-ink-2); font-family: var(--font-mono); font-size: var(--fs-small); line-height: var(--lh-head); }
@media (min-width: 744px) {
  .end .ex-pair { grid-template-columns: 1.5fr 0.57fr; gap: var(--s-8); align-items: start; }
  .end .ex-door { display: block; }
  .ex-door-text { margin-top: var(--s-8); }
  .ex-door-text p { font-size: var(--fs-small); }
}
/* The /v/ picture frames hug a wide picture as .tall hugs a tall one (views/result.js adds .wide from the picture's size,
   which also goes on the img, so the space is kept before it loads): no empty band above or below. */
.shot.wide { height: auto; }
.shot.wide img { height: auto; max-height: 55dvh; }
.shot-sm.wide img { max-height: 36dvh; }
