/* Blue Balls Challenge storefront.
   Colours come from the active palette (Admin > Appearance), injected as CSS variables.
   The values below are fallbacks only. */

:root {
  --brand: #1E3BFF;
  --accent: #D2FF3C;
  --ink: #0A0B2E;
  --surface: #EDF0FF;
  --deep: #23255A;
  --heat: #FF4B1F;
  --on-brand: #FFFFFF;
  --on-accent: #0A0B2E;
  --on-ink: #FFFFFF;
  --on-deep: #FFFFFF;
  --brand-text: #1E3BFF;
  --accent-on-ink: #D2FF3C;
  --accent-on-brand: #D2FF3C;
  --text-soft: #3A3F72;
  --text-softer: #4A4F80;
  --on-ink-soft: #C3C6E0;
  --on-brand-soft: #E6EAFF;
  --line: #C9CEEA;
  --track: #E4E7F7;
  --choice: #F6F7FF;
  --white: #FFFFFF;
  --danger: #B42318;

  --font-display: "Unbounded", "Arial Black", "Helvetica Neue", sans-serif;
  --font-body: "Bricolage Grotesque", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --pad: 20px;
  --section: 64px;
}

@media (min-width: 900px) {
  :root { --pad: 48px; --section: 112px; }
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.45;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }
h1, h2, h3 { font-family: var(--font-display); line-height: 1.08; letter-spacing: -0.02em; margin: 0; }
p { margin: 0; }

:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; box-shadow: 0 0 0 6px var(--accent); }
.section-ink :focus-visible, .hero :focus-visible, .site-header :focus-visible, .confirmed :focus-visible,
.site-footer :focus-visible, .page-head :focus-visible, .mini-challenge :focus-visible, .cabinet :focus-visible {
  outline-color: var(--accent); box-shadow: none;
}

.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; }
.skip-link { position: absolute; left: -9999px; top: 12px; z-index: 200; background: var(--accent); color: var(--on-accent); border: 3px solid var(--ink); padding: 12px 16px; font-weight: 800; }
.skip-link:focus { left: 12px; }

.wrap { width: 100%; max-width: 1344px; margin: 0 auto; padding: 0 var(--pad); }
.muted { color: var(--text-softer); }
.small { font-size: 14px; }
.text-link { font-weight: 800; color: var(--brand-text); text-decoration: underline; text-underline-offset: 3px; display: inline-flex; align-items: center; gap: 6px; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 52px; padding: 0 24px;
  border: 3px solid var(--ink); border-radius: 999px;
  font-family: var(--font-display); font-weight: 800; font-size: 14px; letter-spacing: 0.01em;
  text-decoration: none; text-align: center; cursor: pointer;
  transition: transform 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
}
.btn-lg { min-height: 60px; font-size: 15px; }
.btn-sm { min-height: 42px; padding: 0 16px; font-size: 12px; }
.btn-block { width: 100%; }
.btn-lime { background: var(--accent); color: var(--on-accent); box-shadow: 4px 4px 0 var(--ink); }
.btn-lime:hover { transform: translate(-1px, -1px); box-shadow: 6px 6px 0 var(--ink); }
.btn-lime:active { transform: translate(3px, 3px); box-shadow: 1px 1px 0 var(--ink); }
.btn-ink { background: var(--ink); color: var(--on-ink); }
.btn-ink:hover { background: var(--deep); color: var(--on-deep); }
.btn-ghost-light { background: transparent; color: inherit; border-color: currentColor; }
.btn-ghost-light { background: transparent; color: inherit; border-color: color-mix(in srgb, currentColor 70%, transparent); }
.btn-ghost-light:hover { border-color: currentColor; background: transparent; }
.btn-ghost-light:hover { border-color: currentColor; background: color-mix(in srgb, currentColor 8%, transparent); }
.btn-outline-lime { background: transparent; color: var(--accent-on-ink); border-color: var(--accent-on-ink); }
.btn-outline-lime:hover { background: rgb(var(--accent-rgb) / 12%); }
.btn-outline-lime:hover { background: rgb(var(--accent-rgb) / 12%); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }
.link-btn { background: none; border: 0; padding: 8px 0; min-height: 44px; font-weight: 700; color: var(--text-soft); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }

/* ---------- Announcement + preview bars ---------- */
.promo-bar { background: var(--accent); color: var(--on-accent); border-bottom: 3px solid var(--ink); font-weight: 800; font-size: 14px; text-align: center; }
.promo-bar .wrap { padding-top: 10px; padding-bottom: 10px; }
.promo-bar a { text-underline-offset: 3px; }
.preview-bar { background: var(--ink); color: var(--on-ink); font-size: 14px; }
.preview-bar .wrap { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; justify-content: space-between; padding-top: 10px; padding-bottom: 10px; }
.preview-bar a { color: var(--accent-on-ink); font-weight: 800; }

/* ---------- Header ---------- */
.site-header { background: var(--brand); color: var(--on-brand); position: relative; z-index: 20; }
.header-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 72px; }
/* The hash hangs to the left of BOTH lines, so BLUE BALLS and CHALLENGE line
   up with each other and the mark sits beside the name. The display font
   lives here rather than on .brand-name so the hash — a sibling, not a
   child — tracks the name's size at every breakpoint on its own. */
.brand { display: flex; flex-direction: row; align-items: flex-start; gap: .05em; text-decoration: none;
         font-family: var(--font-display); font-weight: 900; font-size: 18px; line-height: 1; letter-spacing: -0.02em; }
.brand-stack { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.brand-logo { max-height: 48px; width: auto; }
.brand-name { font-size: 1em; }   /* the face and size come from .brand, so the hash matches */
/* Each word opens on a full-height letter and the rest steps down. Sized in
   em so it follows whatever the wordmark is set in — header, footer, or the
   big version on a wide screen — without needing a value per place.
   inline-block keeps the two runs sitting on the same baseline; without it
   the smaller run can drift on a line that wraps. */
.wm-lead, .wm-rest { display: inline-block; vertical-align: baseline; }
.wm-rest { font-size: 0.87em; }
.brand-sub { font-family: var(--font-display); font-weight: 700; font-size: 9px; line-height: 1; letter-spacing: 0.42em; color: var(--accent-on-brand); }
.site-nav { display: none; }
.site-nav a { text-decoration: none; font-weight: 700; font-size: 16px; }
.site-nav a:hover { text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 2px; }
.header-actions { display: flex; align-items: center; gap: 8px; }
.icon-btn {
  position: relative; width: 48px; height: 48px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: inherit; border: 2px solid currentColor;
  background: transparent; color: inherit; border: 2px solid color-mix(in srgb, currentColor 55%, transparent);
  text-decoration: none; cursor: pointer;
}
.cart-btn { background: var(--ink); color: var(--on-ink); border-color: var(--ink); }
.cart-count {
  position: absolute; top: -5px; right: -5px; min-width: 24px; height: 24px; padding: 0 6px;
  border-radius: 12px; border: 2px solid var(--brand); background: var(--accent); color: var(--on-accent);
  font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center;
}
.cart-count[hidden] { display: none; }
.cart-count.is-bumped { animation: bump 0.35s ease; }
@keyframes bump { 50% { transform: scale(1.3); } }

@media (max-width: 899px) {
  .site-nav.is-open {
    display: flex; flex-direction: column; position: absolute; left: 0; right: 0; top: 100%;
    background: var(--ink); color: var(--on-ink); padding: 8px var(--pad) 20px; border-bottom: 3px solid var(--accent);
  }
  .site-nav.is-open a { padding: 14px 0; border-bottom: 1px solid rgb(var(--on-ink-rgb) / 12%); font-family: var(--font-display); font-size: 18px; }
  .site-nav.is-open a { padding: 14px 0; border-bottom: 1px solid rgb(var(--on-ink-rgb) / 12%); font-family: var(--font-display); font-size: 18px; }
}
@media (max-width: 359px) {
  /* Very narrow screens (large text or zoom settings): keep the logo and three buttons on one line. */
  .header-row { gap: 10px; }
  .header-actions { gap: 6px; }
  .icon-btn { width: 42px; height: 42px; }
  .brand { font-size: 15px; }
  .brand-sub { font-size: 8px; letter-spacing: 0.34em; }
}
@media (min-width: 900px) {
  .header-row { min-height: 88px; }
  .brand { font-size: 22px; }
  .brand-sub { font-size: 10px; }
  .site-nav { display: flex; gap: 36px; }
  .menu-btn { display: none; }
}

/* ---------- Candy art ---------- */
.ball {
  --ball: var(--brand);
  /* Sugar speckle. The tile is a variable and the dots are sized as a
     percentage OF the tile, so turning --speckle up on a big ball scales
     the grain with it. A fixed tile was the bug: 9px dots are candy on a
     40px ball and film noise on a 300px one. */
  --speckle: 9px;
  display: block; aspect-ratio: 1; border-radius: 50%;
  border: 3px solid var(--ink);
  box-shadow: 8px 10px 0 var(--ink);
  /* Plain sphere. Every browser gets at least this. */
  background: radial-gradient(circle at 34% 28%, #fff 0%, #fff 4%, var(--ball) 45%, var(--ink) 120%);
}
/* The sugared version, behind @supports rather than as a plain override.
   The candy colour is a per-element variable, so these stops can only be
   built with color-mix — and a color-mix carrying a var() does not get
   politely ignored by a browser that cannot read it. It wipes the whole
   background, plain fallback line and all, which is how the candy came out
   with no colour at all on an older iPhone. Behind @supports that browser
   never sees it and keeps the sphere above.

   Topmost layer is a vignette: it dims the sugar toward the rim so the
   grains sit ON a sphere instead of floating in a flat grid. Then three
   speckle layers at pitches that don't divide into each other (1 : 1.27 :
   1.91) — three regular grids that almost never line up read as scattered
   sugar, where one grid reads as a golf ball. Sphere shading last. */
@supports (background: color-mix(in srgb, red 50%, blue)) {
  .ball {
    background:
      radial-gradient(circle at 34% 28%, transparent 42%, rgba(0, 0, 0, 0.38) 100%),
      radial-gradient(circle, rgba(255, 255, 255, 0.42) 0 12%, transparent 24%)
        0 0 / var(--speckle) var(--speckle),
      radial-gradient(circle, rgba(255, 255, 255, 0.26) 0 10%, transparent 22%)
        37% 41% / calc(var(--speckle) * 1.27) calc(var(--speckle) * 1.27),
      radial-gradient(circle, rgba(255, 255, 255, 0.2) 0 9%, transparent 20%)
        63% 19% / calc(var(--speckle) * 1.91) calc(var(--speckle) * 1.91),
      radial-gradient(circle at 34% 28%,
        #fff 0%,
        color-mix(in srgb, var(--ball) 18%, #fff) 5%,
        color-mix(in srgb, var(--ball) 62%, #fff) 18%,
        color-mix(in srgb, var(--ball) 90%, #fff) 40%,
        color-mix(in srgb, var(--ball) 72%, #000) 72%,
        color-mix(in srgb, var(--ball) 45%, #000) 100%);
  }
}
.balls { display: grid; justify-content: center; align-content: center; }
.balls-1 .ball { width: 132px; }
.balls-4 { grid-template-columns: repeat(2, 64px); gap: 12px; }
.balls-4 .ball { box-shadow: 4px 5px 0 var(--ink); }
.balls-12 { grid-template-columns: repeat(6, 36px); gap: 10px; }
.balls-12 .ball { border-width: 2px; box-shadow: 3px 3px 0 var(--ink); }
@media (min-width: 900px) {
  .balls-1 .ball { width: 150px; }
  .balls-4 { grid-template-columns: repeat(2, 76px); gap: 14px; }
  .balls-12 { grid-template-columns: repeat(6, 44px); }
}

/* ---------- Hero ---------- */
.hero { background: var(--brand); color: var(--on-brand); padding: 8px 0 36px; overflow: hidden; }
.hero-grid { display: grid; gap: 28px; }
.sticker {
  display: inline-block; transform: rotate(-4deg);
  background: var(--accent); color: var(--on-accent);
  border: 3px solid var(--ink); border-radius: 8px; box-shadow: 4px 4px 0 var(--ink);
  padding: 10px 14px; font-family: var(--font-display); font-weight: 800; font-size: 12px; letter-spacing: 0.06em;
}
.hero-title {
  margin: 24px 0 20px;
  font-weight: 900; text-transform: uppercase;
  font-size: clamp(3.4rem, 1.4rem + 5.6vw, 6.6rem);
  line-height: 0.92; letter-spacing: -0.035em;
}
.hero-lede { max-width: 34ch; font-size: 18px; color: var(--on-brand-soft); }
.hero-ctas { display: flex; gap: 10px; margin-top: 28px; }
.hero-ctas .btn { flex: 1 1 0; padding: 0 14px; }
.hero-art { position: relative; height: 300px; max-width: 560px; }
.hero-ball-main { position: absolute; width: 62%; left: 16%; top: 4%; }
.hero-ball-sm { position: absolute; width: 20%; right: 3%; top: 58%; border-width: 3px; box-shadow: 5px 6px 0 var(--ink); }
.hero-ball-xs { position: absolute; width: 11%; left: 4%; top: 12%; border-width: 2px; box-shadow: 3px 4px 0 var(--ink); }
.hero-badge {
  position: absolute; left: 0; bottom: 6%;
  width: 104px; height: 104px; border-radius: 50%; transform: rotate(-10deg);
  background: var(--accent); color: var(--on-accent); border: 3px solid var(--ink); box-shadow: 4px 4px 0 var(--ink);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
}
.hero-badge strong { font-family: var(--font-display); font-weight: 900; font-size: 38px; line-height: 1; }
.hero-badge span { font-weight: 800; font-size: 11px; letter-spacing: 0.08em; }

/* Phones and tablets: headline, buttons and candy all fit on the first screen.
   The candy area takes whatever height is left and the balls scale with it.
   --hero-offset (header + any top bars) is measured by site.js. */
@media (max-width: 1099px) {
  .hero {
    display: flex; flex-direction: column;
    min-height: calc(100vh - var(--hero-offset, 72px));
    min-height: calc(100svh - var(--hero-offset, 72px));
    padding: 6px 0 18px;
  }
  .hero-grid { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 14px; }
  .hero-title { margin: 14px 0 12px; font-size: clamp(2.6rem, 1rem + 7.4vw, 3.6rem); }
  .hero-lede { font-size: 16px; }
  .hero-ctas { margin-top: 18px; }
  .hero-art {
    flex: 1 1 auto; width: 100%; height: auto;
    min-height: 150px;
    max-height: min(360px, calc((100vw - 40px) * 0.94));
  }
  .hero-ball-main { width: auto; height: 90%; left: 50%; top: 5%; transform: translateX(-46%); }
  .hero-ball-sm { width: auto; height: 24%; right: 2%; top: 60%; }
  .hero-ball-xs { width: auto; height: 12%; left: 6%; top: 8%; }
  .hero-badge { width: 92px; height: 92px; bottom: 3%; }
  .hero-badge strong { font-size: 34px; }
  .hero-badge span { font-size: 10px; }
}
/* Set by site.js when the text is bigger than planned (large-text settings): tighten up so the candy still shows. */
@media (max-width: 1099px) {
  .hero.is-tight { padding-top: 2px; padding-bottom: 10px; }
  .hero.is-tight .hero-grid { gap: 8px; }
  .hero.is-tight .hero-title { margin: 8px 0 8px; }
  .hero.is-tight .sticker { margin-top: 8px; }
  .hero.is-tight .hero-lede-more { display: none; }
  .hero.is-tight .hero-ctas { margin-top: 12px; }
  .hero.is-tight .hero-art { min-height: 112px; }
}
/* Short screens (iPhone SE, small Androids): tighten the text so the candy still shows. */
@media (max-width: 1099px) and (max-height: 620px) {
  .promo-bar { font-size: 13px; }
  .promo-bar .wrap { padding-top: 7px; padding-bottom: 7px; }
  .hero { padding: 2px 0 10px; }
  .hero-grid { gap: 10px; }
  .hero-art { min-height: 124px; }
  .sticker { padding: 7px 11px; font-size: 11px; }
  .hero-title { margin: 10px 0 8px; font-size: clamp(2.3rem, 0.9rem + 6.6vw, 2.9rem); }
  .hero-lede { font-size: 15px; }
  .hero-lede-more { display: none; }
  .hero-ctas { margin-top: 14px; }
  .hero-ctas .btn { min-height: 48px; }
  .hero-badge { width: 80px; height: 80px; }
  .hero-badge strong { font-size: 29px; }
}

@media (min-width: 1100px) {
  .hero { padding: 32px 0 72px; }
  .hero-grid { grid-template-columns: 1fr 1fr; align-items: center; gap: 48px; }
  .hero-lede { font-size: 22px; }
  .hero-ctas { margin-top: 40px; gap: 14px; }
  .hero-ctas .btn { flex: 0 0 auto; min-height: 60px; padding: 0 30px; font-size: 16px; }
  .hero-art { height: 540px; justify-self: end; width: 100%; }
  .hero-ball-main { width: 78%; left: 12%; top: 6%; box-shadow: 14px 16px 0 var(--ink); border-width: 4px; }
  .hero-badge { width: 150px; height: 150px; bottom: 4%; }
  .hero-badge strong { font-size: 54px; }
  .hero-badge span { font-size: 13px; }
}

/* ---------- Marquee strip ---------- */
.strip-clip { overflow: hidden; padding: 12px 0; background: linear-gradient(var(--brand) 50%, var(--ink) 50%); }
.strip {
  margin: 0 -40px; padding: 14px 0;
  background: var(--accent); color: var(--on-accent); border-block: 3px solid var(--ink);
  transform: rotate(-2deg); overflow: hidden; white-space: nowrap;
  font-family: var(--font-display); font-weight: 800; font-size: 14px; letter-spacing: 0.03em; text-transform: uppercase;
}
.strip-track { display: inline-flex; gap: 22px; padding-left: 22px; }
@media (min-width: 900px) { .strip-clip { padding: 14px 0 18px; } .strip { font-size: 20px; padding: 18px 0; } .strip-track { gap: 32px; } }
@media (prefers-reduced-motion: no-preference) {
  .strip-track { animation: marquee 40s linear infinite; }
}
@keyframes marquee { to { transform: translateX(-50%); } }

/* ---------- Sections ---------- */
.section { padding: var(--section) 0; }
.section-tight { padding: 32px 0 var(--section); }
.section-ink { background: var(--ink); color: var(--on-ink); }
.section-lime { background: var(--accent); color: var(--on-accent); }
.section-ice { background: var(--surface); }
.section-head { display: flex; flex-direction: column; gap: 14px; margin-bottom: 28px; }
.section-head h2 { font-size: clamp(30px, 2rem + 1.8vw, 56px); font-weight: 900; }
.section-head-split { gap: 20px; }
.section-lede { font-size: 17px; color: var(--text-soft); max-width: 60ch; margin-top: 6px; }
.section-ink .section-lede { color: var(--on-ink-soft); }
.eyebrow { font-family: var(--font-display); font-weight: 700; font-size: 12px; letter-spacing: 0.22em; text-transform: uppercase; color: var(--brand-text); }
.section-ink .eyebrow { color: var(--accent-on-ink); }
.section-lime .eyebrow { color: var(--on-accent); }
@media (min-width: 900px) {
  .section-head { margin-bottom: 48px; }
  .section-head-split { flex-direction: row; justify-content: space-between; align-items: flex-end; }
  .section-lede { font-size: 19px; }
}
.secure-note { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; color: var(--text-soft); }

/* ---------- Challenge + timer ---------- */
.challenge-grid { display: grid; gap: 32px; }
@media (min-width: 900px) { .challenge-grid { grid-template-columns: 1fr 1fr; gap: 80px; align-items: center; } }
.rules { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.rules li {
  display: flex; gap: 16px; align-items: flex-start; padding: 16px; border-radius: 14px;
  background: rgb(var(--on-ink-rgb) / 6%); border: 1px solid rgb(var(--on-ink-rgb) / 14%);
  background: rgb(var(--on-ink-rgb) / 6%); border: 1px solid rgb(var(--on-ink-rgb) / 14%);
}
.rules strong { display: block; font-size: 18px; }
.rules span:not(.rule-num) { color: var(--on-ink-soft); font-size: 15px; }
.rule-num {
  flex: none; width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent); color: var(--on-accent); font-family: var(--font-display); font-weight: 900; font-size: 15px;
}
/* ---------- Sour curve ---------- */
.stages { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; }
@media (min-width: 700px) { .stages { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .stages { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; } }
.stage {
  display: flex; flex-direction: column; gap: 12px; padding: 20px; color: var(--ink);
  background: var(--white); border: 3px solid var(--ink); border-radius: 16px; box-shadow: 5px 5px 0 var(--ink);
}
.stage-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.stage-time { background: var(--ink); color: var(--accent-on-ink); font-family: var(--font-display); font-weight: 800; font-size: 13px; padding: 6px 10px; border-radius: 8px; }
.stage-name { font-family: var(--font-display); font-weight: 800; font-size: 18px; }
.stage p { color: var(--text-soft); font-size: 15px; flex: 1; }
.bar { display: block; height: 10px; border-radius: 5px; background: var(--track); overflow: hidden; }
.bar > span { display: block; height: 100%; background: var(--brand); border-radius: inherit; }
.bar-outlined { height: 12px; border: 2px solid var(--ink); background: var(--white); }
.bar-outlined > span { background: var(--accent); border-radius: 0; }

/* ---------- Cards ---------- */
.cards { display: grid; gap: 20px; }
@media (min-width: 700px) { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px; } }
.card {
  display: flex; flex-direction: column; overflow: hidden; color: var(--ink);
  background: var(--white); border: 3px solid var(--ink); border-radius: 20px; box-shadow: 6px 6px 0 var(--ink);
}
.card-art {
  --art: var(--brand);
  position: relative; height: 200px; display: flex; align-items: center; justify-content: center;
  background: var(--art); border-bottom: 3px solid var(--ink); overflow: hidden;
}
.card-art img { width: 100%; height: 100%; object-fit: cover; }
.card-badge {
  position: absolute; top: 14px; left: 14px; z-index: 1; transform: rotate(-3deg);
  background: var(--accent); color: var(--on-accent); border: 2px solid var(--ink); border-radius: 6px;
  padding: 6px 9px; font-family: var(--font-display); font-weight: 800; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
}
.card-body { flex: 1; display: flex; flex-direction: column; gap: 10px; padding: 20px; }
.card-title-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.card-title { font-size: 20px; font-weight: 800; }
.card-title a { text-decoration: none; }
.card-title a:hover { text-decoration: underline; text-underline-offset: 4px; }
.card-price { font-family: var(--font-display); font-weight: 800; font-size: 20px; color: var(--brand-text); white-space: nowrap; }
.card-detail { font-size: 12px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-soft); }
.card-text { color: var(--text-soft); flex: 1; }
.card .add-form, .card > .card-body > .btn { margin-top: 6px; }
@media (min-width: 900px) {
  .card-art { height: 260px; }
  .card-body { padding: 24px; gap: 12px; }
  .card-title, .card-price { font-size: 24px; }
}
.lineup { margin-top: 56px; }
.lineup-head { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; margin-bottom: 20px; }
.lineup-head h2, .lineup-head h3 { font-size: 24px; font-weight: 900; }
.lineup-head .text-link { white-space: nowrap; }
.empty-note { font-weight: 700; color: var(--text-soft); }

/* ---------- Meter ---------- */
.meter { --meter: var(--brand); display: flex; align-items: center; gap: 10px; font-size: 13px; font-weight: 800; }
.meter-heat { --meter: var(--heat); }
.meter-fizz { --meter: var(--accent); }
.meter-label { min-width: 34px; }
.meter-pips { display: flex; gap: 4px; }
.pip { width: 20px; height: 12px; border-radius: 3px; border: 2px solid var(--ink); background: var(--track); }
.pip.on { background: var(--meter); }

/* ---------- Wall of Sour ---------- */
.wall { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
@media (min-width: 900px) { .wall { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; } }
.wall-tile {
  position: relative; aspect-ratio: 9 / 14; border-radius: 16px; overflow: hidden;
  background-color: var(--deep); color: var(--on-deep); border: 2px solid rgb(var(--on-ink-rgb) / 25%);
  background-color: var(--deep); color: var(--on-deep); border: 2px solid rgb(var(--on-ink-rgb) / 25%);
  background-image: radial-gradient(circle at 50% 38%, rgba(255, 255, 255, 0.08) 0 28%, transparent 29%);
}
.wall-tile.is-blue { background-color: var(--brand); color: var(--on-brand); }
.wall-chip { position: absolute; top: 10px; left: 10px; padding: 5px 8px; border-radius: 6px; background: var(--white); color: var(--ink); font-size: 11px; font-weight: 800; }
.wall-chip.is-lime { background: var(--accent); color: var(--on-accent); }
.wall-play {
  position: absolute; left: 50%; top: 44%; transform: translate(-50%, -50%);
  width: 56px; height: 56px; border-radius: 50%; background: rgba(255, 255, 255, 0.92); color: var(--ink);
  display: grid; place-items: center;
}
.wall-handle { position: absolute; left: 12px; right: 12px; bottom: 12px; font-size: 13px; font-weight: 700; }

/* The weekly prize, and its small print at the foot of the section. The tag
   and the rule make it a claim rather than another line of body copy; the
   star is a real link, so the fine print is one tap away on a phone. */
.wall-prize {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 16px 0 0; padding-top: 14px;
  border-top: 2px solid rgb(var(--on-ink-rgb) / 18%);
  border-top: 2px solid rgb(var(--on-ink-rgb) / 18%);
  font-size: 16px; font-weight: 700; line-height: 1.35; color: var(--on-ink);
}
.wall-prize-tag {
  flex: none; padding: 5px 10px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent);
  font-family: var(--font-display); font-weight: 800; font-size: 10px;
  letter-spacing: .14em; text-transform: uppercase;
}
.wall-star {
  color: var(--accent-on-ink); text-decoration: none; font-weight: 800;
  padding: 0 2px; vertical-align: super; font-size: .85em;
}
.wall-star:hover, .wall-star:focus-visible { text-decoration: underline; }
.wall-fine {
  display: flex; gap: 6px; margin: 20px 0 0; scroll-margin-top: 80px;
  max-width: 68ch; font-size: 13px; line-height: 1.5; color: var(--on-ink-soft);
}
.wall-fine-star { flex: none; color: var(--accent-on-ink); font-weight: 800; }
@media (min-width: 900px) {
  .wall-prize { font-size: 17px; }
  .wall-fine { margin-top: 24px; }
}

/* ---------- Hazard label ---------- */
.hazard {
  padding: var(--section) 0;
  background: repeating-linear-gradient(-45deg, var(--accent) 0 22px, var(--ink) 22px 44px);
}
.hazard-card {
  max-width: 820px; margin: 0 auto; padding: 24px; color: var(--ink);
  background: var(--white); border: 3px solid var(--ink); border-radius: 20px; box-shadow: 6px 6px 0 var(--ink);
  display: flex; flex-direction: column; gap: 14px;
}
.hazard-card h2 { font-size: 22px; font-weight: 900; }
.hazard-card p { color: var(--text-soft); }
.hazard-card .hazard-small { font-size: 14px; color: var(--text-softer); }
@media (min-width: 900px) { .hazard-card { padding: 40px 48px; } .hazard-card h2 { font-size: 30px; } .hazard-card p { font-size: 18px; } .hazard-card .hazard-small { font-size: 14px; } }

/* ---------- Footer ---------- */
.site-footer { background: var(--ink); color: var(--on-ink); padding: 48px 0 28px; }
.site-footer .brand-sub { color: var(--accent-on-ink); }
.footer-grid { display: grid; gap: 32px; }
.footer-brand { display: flex; flex-direction: row; align-items: flex-start; gap: .05em; font-family: var(--font-display); font-weight: 900; font-size: 22px; margin-bottom: 16px; }
.footer-brand .brand-stack { gap: 6px; }
.signup label { display: block; font-weight: 700; margin-bottom: 10px; color: var(--on-ink-soft); }
.signup-row { display: flex; gap: 8px; max-width: 460px; }
.signup-row .input { flex: 1; border-color: var(--on-ink); }
.signup-msg { font-size: 14px; margin-top: 8px; min-height: 1.2em; color: var(--accent-on-ink); }
.footer-links { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 24px; align-content: start; }
.footer-links a, .footer-social a { text-decoration: none; font-weight: 700; padding: 4px 0; }
.footer-links a:hover, .footer-social a:hover { text-decoration: underline; text-underline-offset: 4px; }
.footer-social { display: flex; gap: 20px; flex-wrap: wrap; align-content: start; }
.footer-base { margin-top: 36px; padding-top: 20px; border-top: 1px solid rgb(var(--on-ink-rgb) / 14%); font-size: 14px; color: var(--on-ink-soft); }
.footer-base { margin-top: 36px; padding-top: 20px; border-top: 1px solid rgb(var(--on-ink-rgb) / 14%); font-size: 14px; color: var(--on-ink-soft); }
@media (min-width: 900px) { .footer-grid { grid-template-columns: 1.4fr 1fr auto; gap: 48px; } .site-footer { padding: 72px 0 32px; } }

/* ---------- Forms ---------- */
.input {
  width: 100%; height: 52px; padding: 0 14px;
  background: var(--white); color: var(--ink);
  border: 2px solid var(--ink); border-radius: 12px; font-size: 16px;
}
select.input { padding-right: 36px; appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%), linear-gradient(135deg, var(--ink) 50%, transparent 50%); background-position: calc(100% - 20px) 22px, calc(100% - 14px) 22px; background-size: 6px 6px; background-repeat: no-repeat; }
.input:focus-visible { outline: 3px solid var(--brand); outline-offset: 1px; box-shadow: none; }
.input[aria-invalid="true"] { border-color: var(--danger); background: #FFF6F4; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 14px; font-weight: 700; }
.field-row { display: grid; grid-template-columns: 1.4fr 1fr; gap: 10px; }
.field-error { color: var(--danger); font-size: 14px; font-weight: 700; }
.check { display: flex; align-items: center; gap: 10px; min-height: 44px; font-size: 15px; cursor: pointer; }
.check input { width: 22px; height: 22px; accent-color: var(--brand); flex: none; }
.alert { padding: 14px 16px; border-radius: 12px; border: 2px solid; font-weight: 700; margin-bottom: 16px; color: var(--ink); }
.alert:focus { outline: none; box-shadow: none; }
.alert-error { background: #FFE9E4; border-color: var(--danger); color: #7A1409; }
.alert-warn { background: #FFF9D6; border-color: var(--ink); }
.alert-ok { background: rgb(var(--accent-rgb) / 35%); border-color: var(--ink); }
.alert-ok { background: var(--accent-tn35); border-color: var(--ink); }

/* ---------- Discount code ---------- */
.discount-box { display: flex; flex-direction: column; gap: 8px; }
.code-form { display: flex; gap: 8px; }
.code-form .input { flex: 1; height: 48px; text-transform: uppercase; }
.code-form .input::placeholder { text-transform: none; }
.code-form .btn { min-height: 48px; }
.code-applied { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px; border-radius: 12px; border: 2px dashed var(--ink); background: rgb(var(--accent-rgb) / 30%); font-weight: 800; }
.code-applied { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px; border-radius: 12px; border: 2px dashed var(--ink); background: var(--accent-tn30); font-weight: 800; }
.code-applied .link-btn { min-height: 32px; padding: 0; }
.code-note { font-size: 14px; font-weight: 700; }
.code-note.is-error { color: var(--danger); }
.summary-discount { color: var(--brand-text); font-weight: 800; }

/* ---------- Page head / shop ---------- */
.page-head { background: var(--brand); color: var(--on-brand); padding: 24px 0 44px; }
.page-head h1 { font-size: clamp(40px, 1.6rem + 4vw, 88px); font-weight: 900; text-transform: uppercase; letter-spacing: -0.03em; line-height: 0.95; }
.page-lede { margin-top: 12px; font-size: 18px; color: var(--on-brand-soft); max-width: 50ch; }
.shop-tools { display: flex; flex-wrap: wrap; gap: 12px 20px; align-items: center; justify-content: space-between; margin-bottom: 28px; }
.pills { display: flex; gap: 8px; flex-wrap: wrap; }
.pill {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 18px;
  border: 2px solid var(--ink); border-radius: 999px; background: var(--white); color: var(--ink);
  font-weight: 800; text-decoration: none;
}
.pill:hover { background: var(--accent); color: var(--on-accent); }
.pill[aria-current="page"] { background: var(--ink); color: var(--on-ink); }
.sort-form { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 15px; }
.sort-form .input { height: 44px; width: auto; min-width: 190px; }
.empty-state { max-width: 560px; margin: 24px auto; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 14px; }
.empty-state h1, .empty-state h2 { font-size: 30px; font-weight: 900; }
.empty-state p { color: var(--text-soft); }

/* ---------- Product page ---------- */
.product { padding: 24px 0 var(--section); }
.product-grid { display: grid; gap: 28px; }
@media (min-width: 900px) { .product-grid { grid-template-columns: 1fr 1fr; gap: 64px; align-items: start; } .product-art { position: sticky; top: 24px; } }
.product-art {
  --art: var(--brand);
  position: relative; aspect-ratio: 1; max-height: 560px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--art); border: 3px solid var(--ink); border-radius: 24px; box-shadow: 8px 8px 0 var(--ink);
}
.product-art img { width: 100%; height: 100%; object-fit: cover; }
.product-art .balls-1 .ball { --speckle: 22px; width: min(260px, 55vw); box-shadow: 12px 14px 0 var(--ink); border-width: 4px; }
.product-info { display: flex; flex-direction: column; gap: 18px; }
.crumbs { display: flex; gap: 8px; font-size: 14px; font-weight: 700; color: var(--text-soft); }
.crumbs a { text-underline-offset: 3px; }
.product-title { font-size: clamp(36px, 1.6rem + 3vw, 64px); font-weight: 900; text-transform: uppercase; letter-spacing: -0.03em; line-height: 0.95; }
.product-tagline { font-size: 19px; color: var(--text-soft); }
.buy-form { display: flex; flex-direction: column; gap: 16px; }
.variant-list { border: 0; margin: 0; padding: 0; display: grid; gap: 10px; }
.variant-list legend { font-weight: 800; margin-bottom: 10px; }
.variant-option {
  display: flex; align-items: center; gap: 14px; padding: 14px 16px; cursor: pointer;
  background: var(--white); border: 3px solid var(--line); border-radius: 14px;
}
.variant-option:has(input:checked) { border-color: var(--ink); box-shadow: 4px 4px 0 var(--ink); }
.variant-option:has(input:focus-visible) { outline: 3px solid var(--brand); outline-offset: 2px; }
.variant-option input { width: 22px; height: 22px; accent-color: var(--brand); flex: none; }
.variant-option.is-soldout { opacity: 0.55; cursor: not-allowed; }
.variant-text { flex: 1; display: flex; flex-direction: column; }
.variant-text strong { font-size: 17px; }
.variant-text span { font-size: 14px; color: var(--text-soft); }
.variant-price { font-family: var(--font-display); font-weight: 800; font-size: 18px; white-space: nowrap; }
.variant-price s { font-family: var(--font-body); font-weight: 600; font-size: 14px; color: var(--text-softer); margin-right: 6px; }
.buy-row { display: flex; gap: 10px; }
.qty-input { width: 84px; flex: none; text-align: center; height: 60px; }
.buy-btn { flex: 1; min-height: 60px; }
.prose { color: var(--text-soft); font-size: 17px; max-width: 62ch; }
.mini-challenge {
  display: grid; grid-template-columns: auto 1fr; gap: 20px; align-items: center;
  padding: 18px; border-radius: 20px; background: var(--ink); color: var(--on-ink);
}
.mini-challenge .dial { --dial-size: 168px; }
.mini-challenge .dial-clock { font-size: 24px; }
.mini-challenge .dial-unit { font-size: 7px; }
.mini-challenge .dial-count span { font-size: 70px; }
.mini-copy { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.mini-copy h2 { font-size: 18px; font-weight: 800; }
.mini-copy .cab-stage { text-align: left; font-size: 14px; min-height: 18px; }
.mini-copy .lamps { gap: 4px; }
.mini-copy .lamp { font-size: 8px; padding: 5px 2px; }
.mini-copy .cab-actions { flex-wrap: wrap; }
.mini-copy .btn { min-height: 44px; font-size: 12px; padding: 0 14px; white-space: nowrap; }
@media (max-width: 520px) {
  .mini-challenge { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .mini-copy { align-items: center; }
  .mini-copy .cab-stage { text-align: center; }
}
.label-details { border: 3px solid var(--ink); border-radius: 16px; background: var(--white); padding: 0 18px; }
.label-details summary { cursor: pointer; padding: 16px 0; font-family: var(--font-display); font-weight: 800; font-size: 15px; }
.label-details p { padding-bottom: 16px; color: var(--text-soft); }

/* ---------- Cart ---------- */
.cart-title-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 20px; }
.cart-title-row h1 { font-size: clamp(32px, 1.4rem + 2vw, 48px); font-weight: 900; }
.cart-layout { display: grid; gap: 24px; }
@media (min-width: 900px) { .cart-layout { grid-template-columns: 1fr 380px; gap: 48px; align-items: start; } .cart-summary { position: sticky; top: 24px; } }
.cart-lines { display: flex; flex-direction: column; gap: 14px; }
.freeship { display: flex; flex-direction: column; gap: 10px; padding: 14px 16px; border-radius: 14px; background: var(--ink); color: var(--on-ink); font-weight: 700; }
.line { display: flex; gap: 14px; padding: 14px; background: var(--white); border: 3px solid var(--ink); border-radius: 16px; }
.line-art { --art: var(--brand); flex: none; width: 88px; height: 88px; border-radius: 12px; border: 2px solid var(--ink); background: var(--art); display: grid; place-items: center; overflow: hidden; }
.line-art img { width: 100%; height: 100%; object-fit: cover; }
.line-art .balls-1 .ball { width: 48px; border-width: 2px; box-shadow: 3px 4px 0 var(--ink); }
.line-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.line-top { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.line-name { font-size: 17px; font-weight: 800; }
.line-name a { text-decoration: none; }
.line-total { font-family: var(--font-display); font-weight: 800; }
.line-variant { font-size: 14px; color: var(--text-soft); }
.line-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 4px; }
.stepper { display: inline-flex; align-items: center; height: 44px; border: 2px solid var(--ink); border-radius: 999px; overflow: hidden; background: var(--white); }
.stepper button { width: 44px; height: 100%; border: 0; background: transparent; font-size: 20px; font-weight: 800; cursor: pointer; }
.stepper button:hover:not(:disabled) { background: var(--accent); color: var(--on-accent); }
.stepper button:disabled { opacity: 0.35; cursor: not-allowed; }
.stepper span { min-width: 28px; text-align: center; font-weight: 800; }
.upsell { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-radius: 16px; background: var(--brand); color: var(--on-brand); }
.upsell div { display: flex; flex-direction: column; gap: 2px; }
.upsell span { font-size: 14px; color: var(--on-brand-soft); }
.upsell .add-form, .upsell > .btn { flex: none; }
.upsell .btn { white-space: nowrap; }
.cart-summary, .checkout-summary, .receipt, .lookup-card {
  display: flex; flex-direction: column; gap: 12px; padding: 20px; color: var(--ink);
  background: var(--white); border: 3px solid var(--ink); border-radius: 18px; box-shadow: 6px 6px 0 var(--ink);
}
.summary-row { display: flex; justify-content: space-between; gap: 12px; }
.summary-row[hidden] { display: none; }
.summary-total { font-size: 19px; font-weight: 800; padding-top: 10px; border-top: 2px dashed var(--line); }
.summary-total strong { font-family: var(--font-display); }

/* ---------- Checkout ---------- */
.checkout-top { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; }
.checkout-top h1 { font-size: clamp(32px, 1.4rem + 2vw, 48px); font-weight: 900; }
.back-link { color: var(--text-soft); align-self: flex-start; }
.checkout-layout { display: grid; gap: 24px; }
@media (min-width: 900px) {
  .checkout-layout { grid-template-columns: minmax(0, 1fr) 400px; gap: 56px; align-items: start; }
  .checkout-summary { order: 2; position: sticky; top: 24px; }
  .checkout-form { order: 1; }
}
.checkout-summary h2, .receipt h2, .lookup-card h2 { font-size: 18px; font-weight: 800; }
.summary-lines { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.summary-lines li { display: flex; align-items: center; gap: 12px; }
.summary-art { --art: var(--brand); flex: none; width: 48px; height: 48px; border-radius: 10px; border: 2px solid var(--ink); background: var(--art); display: grid; place-items: center; overflow: hidden; }
.summary-art img { width: 100%; height: 100%; object-fit: cover; }
.summary-art .balls-1 .ball { width: 26px; border-width: 2px; box-shadow: 2px 2px 0 var(--ink); }
.summary-name { flex: 1; font-weight: 700; display: flex; flex-direction: column; }
.summary-name small { font-weight: 600; font-size: 13px; color: var(--text-soft); }
.summary-rows { display: flex; flex-direction: column; gap: 8px; padding-top: 12px; border-top: 2px solid var(--track); }
.checkout-form { display: flex; flex-direction: column; gap: 28px; }
.step { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.step-title { display: flex; align-items: center; gap: 10px; padding: 0; margin-bottom: 4px; font-family: var(--font-display); font-weight: 800; font-size: 18px; }
.step-num { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; background: var(--accent); color: var(--on-accent); border: 2px solid var(--ink); font-size: 13px; }
.choice {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px; cursor: pointer;
  background: var(--choice); border: 3px solid var(--line); border-radius: 14px;
}
.choice:has(input:checked) { background: var(--white); border-color: var(--brand); }
.choice:has(input:focus-visible) { outline: 3px solid var(--brand); outline-offset: 2px; }
.choice input { width: 22px; height: 22px; accent-color: var(--brand); flex: none; }
.choice-text { flex: 1; display: flex; flex-direction: column; }
.choice-text span { font-size: 14px; color: var(--text-soft); }
.wallets { display: grid; gap: 10px; transition: opacity 0.15s; }
.wallets.is-locked { opacity: 0.45; pointer-events: none; }
#apple-pay-button {
  display: none; width: 100%; height: 50px; border: 0; border-radius: 12px; cursor: pointer;
  -webkit-appearance: -apple-pay-button; -apple-pay-button-type: plain; -apple-pay-button-style: black;
}
#apple-pay-button.is-ready { display: block; }
#google-pay-button, #cash-app-pay { min-height: 50px; }
.divider { display: flex; align-items: center; gap: 12px; font-size: 14px; font-weight: 700; color: var(--text-soft); }
.divider::before, .divider::after { content: ""; flex: 1; height: 2px; background: var(--line); }
.card-container { min-height: 92px; }
.checkout-form .secure-note { font-weight: 600; font-size: 13px; }
.is-busy { cursor: progress; }

/* ---------- Confirmation + order status ---------- */
.confirmed { background: var(--brand); color: var(--on-brand); padding: 40px 0 var(--section); }
.confirmed-grid { display: grid; gap: 32px; }
@media (min-width: 900px) { .confirmed-grid { grid-template-columns: 1fr 420px; gap: 64px; align-items: start; } }
.confirmed-copy { display: flex; flex-direction: column; gap: 18px; }
.confirmed-art { position: relative; width: 150px; height: 150px; }
.confirmed-art .ball { --speckle: 14px; width: 140px; }
.confirmed-check { position: absolute; right: -10px; top: -6px; width: 64px; height: 64px; border-radius: 50%; display: grid; place-items: center; background: var(--accent); color: var(--on-accent); border: 3px solid var(--ink); box-shadow: 4px 4px 0 var(--ink); transform: rotate(8deg); }
.confirmed h1 { font-size: clamp(52px, 2rem + 5vw, 104px); font-weight: 900; text-transform: uppercase; letter-spacing: -0.035em; line-height: 0.92; }
.confirmed-lede { font-size: 18px; color: var(--on-brand-soft); max-width: 44ch; }
.confirmed-lede strong { color: var(--accent-on-brand); }
.wait-card { padding: 18px 20px; border-radius: 16px; background: var(--ink); color: var(--on-ink); max-width: 520px; }
.wait-card h2 { font-size: 16px; color: var(--accent-on-ink); margin-bottom: 8px; }
.wait-card ol { margin: 0; padding-left: 20px; display: grid; gap: 6px; }
.confirmed-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.receipt-address { font-size: 15px; color: var(--text-soft); }
.progress { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.progress li { display: flex; flex-direction: column; gap: 8px; font-size: 13px; font-weight: 800; color: var(--text-softer); }
.progress li::before { content: ""; height: 8px; border-radius: 4px; background: var(--track); border: 2px solid var(--ink); }
.progress li.is-done { color: var(--ink); }
.progress li.is-done::before { background: var(--accent); }
.lookup-grid { display: grid; gap: 24px; max-width: 560px; }
.lookup-card form { display: flex; flex-direction: column; gap: 14px; }

/* ---------- Accounts ---------- */
.page-head-short { padding: 20px 0 32px; }
.page-head-short h1 { font-size: clamp(34px, 1.4rem + 3vw, 64px); }
.stack { display: flex; flex-direction: column; gap: 14px; }
.stack-lg { display: flex; flex-direction: column; gap: 20px; }
.auth-wrap { display: grid; gap: 24px; max-width: 920px; }
.auth-wrap-single { max-width: 520px; }
@media (min-width: 800px) { .auth-wrap:not(.auth-wrap-single) { grid-template-columns: 1.1fr 1fr; align-items: start; gap: 48px; } }
.auth-card { display: flex; flex-direction: column; gap: 14px; padding: 22px; color: var(--ink); background: var(--white); border: 3px solid var(--ink); border-radius: 18px; box-shadow: 6px 6px 0 var(--ink); }
.auth-side { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; padding: 6px 0; }
.auth-side h2, .account-title { font-size: 22px; font-weight: 900; }
.perk-list { margin: 0; padding-left: 20px; display: grid; gap: 6px; color: var(--text-soft); }
.account-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.account-head .page-lede { margin-top: 6px; font-size: 16px; }
.account-nav { margin-top: -22px; position: relative; z-index: 1; }
.account-section { padding-top: 28px; }
.account-grid { display: grid; gap: 24px; }
@media (min-width: 900px) { .account-grid { grid-template-columns: minmax(0, 1fr) 360px; gap: 40px; align-items: start; } .account-grid-even { grid-template-columns: 1fr 1fr; } }
.account-title { margin-bottom: 14px; }
.account-aside { display: flex; flex-direction: column; gap: 14px; }
.account-line { font-size: 15px; color: var(--text-soft); }
.notice-split { display: flex; justify-content: space-between; align-items: center; gap: 8px 14px; flex-wrap: wrap; }
.notice-split .link-btn { min-height: 32px; padding: 0; color: var(--ink); }
.order-list, .address-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.order-row, .address-card { display: flex; flex-direction: column; gap: 8px; padding: 16px 18px; color: var(--ink); background: var(--white); border: 3px solid var(--ink); border-radius: 16px; }
.order-row-top, .order-row-foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.order-number { font-family: var(--font-display); font-weight: 800; font-size: 17px; text-underline-offset: 3px; }
.order-status { font-size: 12px; font-weight: 800; padding: 4px 10px; border-radius: 999px; border: 2px solid var(--ink); background: var(--track); white-space: nowrap; }
.order-status.status-paid, .order-status.status-packed { background: rgb(var(--accent-rgb) / 45%); }
.order-status.status-paid, .order-status.status-packed { background: var(--accent-tn45); }
.order-status.status-shipped { background: var(--accent); color: var(--on-accent); }
.order-status.status-refunded, .order-status.status-cancelled { background: #FFE9E4; }
.order-items { color: var(--text-soft); font-size: 15px; }
.progress-mini li { font-size: 11px; gap: 5px; }
.progress-mini li::before { height: 6px; }
.empty-card { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; padding: 22px; background: var(--white); border: 3px dashed var(--line); border-radius: 16px; color: var(--text-soft); }
.address-card.is-default { box-shadow: 5px 5px 0 var(--ink); }
.address-actions { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.address-actions .link-btn { min-height: 36px; padding: 0; }
.badge-static { position: static; transform: none; display: inline-block; }
.delete-form { padding-bottom: 16px; }
.delete-form p { padding: 0; }
.save-card { max-width: 520px; display: flex; flex-direction: column; gap: 10px; padding: 18px 20px; border-radius: 16px; background: var(--white); color: var(--ink); border: 3px solid var(--ink); box-shadow: 6px 6px 0 var(--ink); }
.save-card h2 { font-size: 18px; font-weight: 800; }
.save-card p { color: var(--text-soft); }
.save-form { display: flex; gap: 8px; flex-wrap: wrap; }
.save-form .input { flex: 1 1 220px; }
.save-note { color: var(--text-softer); }

/* ---------- Info pages ---------- */
.prose-page { max-width: 760px; display: flex; flex-direction: column; gap: 14px; }
.prose-page h2 { font-size: 22px; font-weight: 800; margin-top: 12px; }

/* ---------- Toast ---------- */
.toast {
  position: fixed; left: 50%; bottom: max(16px, env(safe-area-inset-bottom)); z-index: 100;
  width: min(92vw, 460px); transform: translate(-50%, 160%);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 16px; border-radius: 16px; border: 3px solid var(--accent);
  background: var(--ink); color: var(--on-ink); font-weight: 700;
  visibility: hidden; transition: transform 0.22s ease, visibility 0s linear 0.22s;
}
.toast.is-shown { transform: translate(-50%, 0); visibility: visible; transition: transform 0.22s ease; }
.toast.is-error { border-color: #FF8A73; }
.toast-link { color: var(--accent-on-ink); font-weight: 800; white-space: nowrap; text-underline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}

/* ---------- Sour Lenny ----------
   One lemon, drawn once. Every pose hangs off [data-phase] on .lenny, so the
   JS only ever sets one attribute and CSS eases everything between states.
   His body stays lemon-yellow on purpose — a lemon is yellow whatever the
   palette is — but his leaf, outline and heat flush all follow the theme. */
.lenny { position: relative; display: block; }
.lenny svg { display: block; width: 100%; height: 100%; overflow: visible; }

.lenny path, .lenny circle, .lenny ellipse, .lenny rect { stroke: var(--ink); }
/* Face parts default to ink by INHERITING from the group. Inherited values
   lose to any class below, which is what lets the tongue, tears and whites
   keep their own colours; fill="none" in the markup still wins over both. */
.lenny .ln-face { fill: var(--ink); }
.lenny .ln-brow { stroke: var(--ink); }
/* Limbs: an ink outline with a lemon stroke on top, so they read against the
   dark dial as well as on the page. A bare ink stroke vanished. */
.lenny .ln-limb-out { stroke: var(--ink); }
.lenny .ln-limb-in  { stroke: #FFE23D; }
.lenny .ln-fist { fill: #FFE23D; }
.lenny .ln-shadow { fill: var(--ink); stroke: none; }
.lenny .ln-shadow { fill: var(--ink-sh82); stroke: none; }
.lenny .ln-blade { fill: var(--accent); }
.lenny .ln-stem { stroke: #6B4323; }
.lenny .ln-white { fill: #FFFFFF; }
.lenny .ln-teeth { stroke: #FFFFFF; fill: none; }
.lenny .ln-tongue { fill: var(--heat); }
.lenny .ln-tear { fill: #7CF4FF; }
.lenny .ln-vein { stroke: var(--heat); opacity: .9; }
.lenny .ln-crease { opacity: .7; }
.lenny .ln-pore { fill: #8A6B00; stroke: none; opacity: .2; }
.lenny .ln-shine { fill: #FFFFFF; stroke: none; opacity: .5; }

/* Transform boxes: every posed part pivots in viewBox units.

   transform-box MUST be set on every one of these. All the origins below are
   written in viewBox user units, which is only what they mean when the box is
   view-box. Blink resolves an SVG element's box that way by default; WebKit
   does not, and measures the origin from each element's OWN bounding box
   instead — so on Safari the lemon pivots around a point that isn't where the
   rule says, and because .lenny svg is overflow:visible the misplaced body
   paints straight over the rest of the card. That is the giant dark lemon
   across the cabinet on iPhone. Leaving it off any posed element brings it
   back, so it is declared for the whole set in one place. */
.lenny .ln-act, .lenny .ln-pose, .lenny .ln-beat, .lenny .ln-body,
.lenny .ln-body-shadow, .lenny .ln-leaf, .lenny .ln-arm, .lenny .ln-brow,
.lenny .ln-face, .lenny .ln-drip { transform-box: view-box; }

.lenny .ln-act, .lenny .ln-pose { transform-origin: 118px 172px; }
.lenny .ln-beat, .lenny .ln-body, .lenny .ln-body-shadow { transform-origin: 118px 120px; }
.lenny .ln-leaf { transform-origin: 118px 54px; }
/* Both arm pairs pivot at the same two shoulders. */
.lenny .ln-arm-l, .lenny .ln-arm-up-l, .lenny .ln-arm-cheer-l { transform-origin: 88px 150px; }
.lenny .ln-arm-r, .lenny .ln-arm-up-r, .lenny .ln-arm-cheer-r { transform-origin: 148px 150px; }
.lenny .ln-brow-l { transform-origin: 78px 88px; }
.lenny .ln-brow-r { transform-origin: 158px 88px; }

.lenny .ln-pose { transition: transform 360ms cubic-bezier(.2,.7,.3,1); }
.lenny .ln-body, .lenny .ln-body-shadow { transition: transform 300ms cubic-bezier(.2,.7,.3,1); }
.lenny .ln-brow { transition: transform 300ms cubic-bezier(.3,1.2,.5,1); }
.lenny .ln-leaf { transition: transform 460ms cubic-bezier(.34,1.5,.5,1); }
.lenny .ln-hot  { transition: opacity 500ms ease; opacity: 0; }
.lenny .ln-arm  { transition: transform 380ms cubic-bezier(.34,1.12,.5,1), opacity 180ms ease; }
.lenny .ln-face { transition: opacity 240ms ease; opacity: 0; }

/* Per-phase poses */
.lenny[data-phase="0"] .ln-face-ready,
.lenny[data-phase="1"] .ln-face-zap,
.lenny[data-phase="2"] .ln-face-pucker,
.lenny[data-phase="3"] .ln-face-tears,
.lenny[data-phase="4"] .ln-face-final,
.lenny[data-phase="5"] .ln-face-done { opacity: 1; }

.lenny[data-phase="0"] .ln-pose { transform: rotate(0deg); }
.lenny[data-phase="1"] .ln-pose { transform: translate(-6px,-3px) rotate(-5deg); }
.lenny[data-phase="2"] .ln-pose { transform: translate(4px,4px) rotate(6deg); }
.lenny[data-phase="3"] .ln-pose { transform: translate(0,6px) rotate(-2deg); }
.lenny[data-phase="4"] .ln-pose { transform: translate(0,2px) rotate(3deg); }
.lenny[data-phase="5"] .ln-pose { transform: translateY(-4px); }

.lenny[data-phase="1"] .ln-body,
.lenny[data-phase="1"] .ln-body-shadow { transform: scale(1.04,1.04); }
.lenny[data-phase="2"] .ln-body,
.lenny[data-phase="2"] .ln-body-shadow { transform: scale(1.05,.92); }
.lenny[data-phase="3"] .ln-body,
.lenny[data-phase="3"] .ln-body-shadow { transform: scale(.99,1); }
.lenny[data-phase="4"] .ln-body,
.lenny[data-phase="4"] .ln-body-shadow { transform: scale(1,.97); }
.lenny[data-phase="5"] .ln-body,
.lenny[data-phase="5"] .ln-body-shadow { transform: scale(1.03,1.03); }

.lenny[data-phase="1"] .ln-hot { opacity: .14; }
.lenny[data-phase="2"] .ln-hot { opacity: .24; }
.lenny[data-phase="3"] .ln-hot { opacity: .32; }
.lenny[data-phase="4"] .ln-hot { opacity: .55; }

.lenny[data-phase="1"] .ln-leaf { transform: rotate(-20deg); }
.lenny[data-phase="2"] .ln-leaf { transform: rotate(15deg); }
.lenny[data-phase="3"] .ln-leaf { transform: rotate(7deg); }
.lenny[data-phase="4"] .ln-leaf { transform: rotate(-9deg); }
.lenny[data-phase="5"] .ln-leaf { transform: rotate(-15deg); }

/* Arm acting: flung out and waving on the hit, both hands clamped to his
   head at the pucker, slack through the tears, braced at the end, both
   raised on the payoff.

   Rotation only ever works for arms that stay LOW. The hanging pair pivots
   at the shoulder, so any large upward rotation drags the fist out past the
   silhouette at mid-height, where it reads as a spare limb rather than a
   hand. The pucker therefore swaps in the second pair instead of rotating
   this one. */
.lenny[data-phase="3"] .ln-arm-l { transform: rotate(-6deg); }
.lenny[data-phase="3"] .ln-arm-r { transform: rotate(6deg); }
.lenny[data-phase="4"] .ln-arm-l { transform: rotate(22deg); }
.lenny[data-phase="4"] .ln-arm-r { transform: rotate(-22deg); }

/* The two drawn-in-place pairs. Each is hidden until its phase, and the
   hanging pair steps aside for it. The small counter-rotations are the
   head rub and the victory shake. */
.lenny .ln-arm-up, .lenny .ln-arm-cheer { opacity: 0; }
.lenny[data-phase="2"] .ln-arm-up { opacity: 1; }
.lenny[data-phase="5"] .ln-arm-cheer { opacity: 1; }
.lenny[data-phase="2"] .ln-arm-l, .lenny[data-phase="2"] .ln-arm-r,
.lenny[data-phase="5"] .ln-arm-l, .lenny[data-phase="5"] .ln-arm-r { opacity: 0; }
@keyframes ln-rub-l { 0%, 100% { transform: rotate(-5deg); } 50% { transform: rotate(4deg); } }
@keyframes ln-rub-r { 0%, 100% { transform: rotate(5deg); } 50% { transform: rotate(-4deg); } }
.lenny[data-phase="2"] .ln-arm-up-l { animation: ln-rub-l .62s ease-in-out infinite; }
.lenny[data-phase="2"] .ln-arm-up-r { animation: ln-rub-r .62s ease-in-out .07s infinite; }
@keyframes ln-hoot-l { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(-10deg); } }
@keyframes ln-hoot-r { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(10deg); } }
.lenny[data-phase="5"] .ln-arm-cheer-l { animation: ln-hoot-l .5s ease-in-out infinite; }
.lenny[data-phase="5"] .ln-arm-cheer-r { animation: ln-hoot-r .5s ease-in-out .06s infinite; }

/* The hit mark. Lives only in the zap phase and pulses the whole time it is
   there — a mark that sits still next to a moving arm is the thing that read
   as a spare limb last time, so this one never stops moving. */
.lenny .ln-zap { opacity: 0; transform-box: view-box; transform-origin: 118px 120px; }
.lenny .ln-zap path { stroke: var(--accent); stroke-width: 7; stroke-linecap: round; fill: none; }
@keyframes ln-zap-pulse {
  0%, 100% { opacity: .3; transform: scale(.84); }
  50%      { opacity: 1;  transform: scale(1.12); }
}
.lenny[data-phase="1"] .ln-zap { animation: ln-zap-pulse .62s ease-in-out infinite; }

/* The zap actually waves, rather than holding a pose. */
@keyframes ln-wave-l { 0%, 100% { transform: rotate(30deg); } 50% { transform: rotate(52deg); } }
@keyframes ln-wave-r { 0%, 100% { transform: rotate(-30deg); } 50% { transform: rotate(-52deg); } }
.lenny[data-phase="1"] .ln-arm-l { animation: ln-wave-l .42s ease-in-out infinite; }
.lenny[data-phase="1"] .ln-arm-r { animation: ln-wave-r .42s ease-in-out .07s infinite; }

.lenny[data-phase="1"] .ln-brow-l { transform: translateY(-9px) rotate(-7deg); }
.lenny[data-phase="1"] .ln-brow-r { transform: translateY(-9px) rotate(7deg); }
.lenny[data-phase="2"] .ln-brow-l { transform: translateY(-4px) rotate(-9deg); }
.lenny[data-phase="2"] .ln-brow-r { transform: translateY(3px) rotate(-15deg); }
.lenny[data-phase="3"] .ln-brow-l { transform: translateY(-1px) rotate(-11deg); }
.lenny[data-phase="3"] .ln-brow-r { transform: translateY(-1px) rotate(11deg); }
.lenny[data-phase="4"] .ln-brow-l { transform: translateY(4px) rotate(13deg); }
.lenny[data-phase="4"] .ln-brow-r { transform: translateY(4px) rotate(-13deg); }
.lenny[data-phase="5"] .ln-brow-l { transform: translateY(-7px) rotate(-5deg); }
.lenny[data-phase="5"] .ln-brow-r { transform: translateY(-7px) rotate(5deg); }

/* What he is DOING, not just what his face is. Each loop is centred on zero
   so the pose layer underneath can glide without fighting it. */
@keyframes ln-idle { 0%,100% { transform: translateY(0) rotate(-1.2deg); } 50% { transform: translateY(-5px) rotate(1.2deg); } }
@keyframes ln-jolt {
  0%   { transform: translate(0,0) rotate(0deg); }
  6%   { transform: translate(10px,-9px) rotate(7deg); }
  16%  { transform: translate(-7px,3px) rotate(-4deg); }
  26%  { transform: translate(5px,-1px) rotate(2deg); }
  34%  { transform: translate(-2px,0) rotate(-1deg); }
  42%,100% { transform: translate(0,0) rotate(0deg); }
}
@keyframes ln-scrunch { 0%,100% { transform: translate(-3px,1px) rotate(-4deg); } 50% { transform: translate(3px,3px) rotate(4deg); } }
@keyframes ln-wobble { 0%,100% { transform: translate(0,2px) rotate(-6deg); } 50% { transform: translate(0,4px) rotate(6deg); } }
@keyframes ln-strain { 0%,100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-3px) scale(1.015); } }
@keyframes ln-cheer {
  0%   { transform: translateY(0) rotate(0deg); }
  25%  { transform: translateY(-16px) rotate(-5deg); }
  45%  { transform: translateY(0) rotate(0deg); }
  60%  { transform: translateY(-7px) rotate(3deg); }
  78%,100% { transform: translateY(0) rotate(0deg); }
}
.lenny[data-phase="0"] .ln-act { animation: ln-idle 3.2s ease-in-out infinite; }
.lenny[data-phase="1"] .ln-act { animation: ln-jolt 2.4s ease-out infinite; }
.lenny[data-phase="2"] .ln-act { animation: ln-scrunch 1.05s ease-in-out infinite; }
.lenny[data-phase="3"] .ln-act { animation: ln-wobble 2.4s ease-in-out infinite; }
.lenny[data-phase="4"] .ln-act { animation: ln-strain .85s ease-in-out infinite; }
.lenny[data-phase="5"] .ln-act { animation: ln-cheer 1.5s ease-in-out infinite; }

/* A squash on arrival at each stage. Six identical keyframe sets, because
   changing the animation NAME is the only way to replay one in CSS. */
@keyframes ln-beat0 { 0% { transform: scale(1.05,.94); } 100% { transform: scale(1,1); } }
@keyframes ln-beat1 { 0% { transform: scale(1.05,.94); } 100% { transform: scale(1,1); } }
@keyframes ln-beat2 { 0% { transform: scale(1.05,.94); } 100% { transform: scale(1,1); } }
@keyframes ln-beat3 { 0% { transform: scale(1.05,.94); } 100% { transform: scale(1,1); } }
@keyframes ln-beat4 { 0% { transform: scale(1.05,.94); } 100% { transform: scale(1,1); } }
@keyframes ln-beat5 { 0% { transform: scale(1.05,.94); } 100% { transform: scale(1,1); } }
.lenny[data-phase="0"] .ln-beat { animation: ln-beat0 .5s cubic-bezier(.2,1.3,.4,1); }
.lenny[data-phase="1"] .ln-beat { animation: ln-beat1 .5s cubic-bezier(.2,1.3,.4,1); }
.lenny[data-phase="2"] .ln-beat { animation: ln-beat2 .5s cubic-bezier(.2,1.3,.4,1); }
.lenny[data-phase="3"] .ln-beat { animation: ln-beat3 .5s cubic-bezier(.2,1.3,.4,1); }
.lenny[data-phase="4"] .ln-beat { animation: ln-beat4 .5s cubic-bezier(.2,1.3,.4,1); }
.lenny[data-phase="5"] .ln-beat { animation: ln-beat5 .5s cubic-bezier(.2,1.3,.4,1); }

@keyframes ln-drip {
  0%   { transform: translateY(0) scale(.7); opacity: 0; }
  25%  { transform: translateY(0) scale(1); opacity: 1; }
  100% { transform: translateY(26px) scale(.85); opacity: 0; }
}
.lenny .ln-drip { animation: ln-drip 1.9s ease-in infinite; }
.lenny .ln-drip-b { animation-delay: .95s; }

/* ---------- The dial ----------
   A stopwatch bezel whose ticks burn off as the clock runs. --live is the one
   variable the whole instrument reads; .is-hot flips it for the last seconds. */
.dial {
  --live: var(--accent);
  --dial-size: 300px;
  position: relative; width: var(--dial-size); height: var(--dial-size);
  display: grid; place-items: center; flex: none;
}
/* ---------- Stage colours ----------
   Each stage of the dare gets its own bright signal colour, so a glance at the
   cabinet tells you how deep in you are before you have read a word.

   --live is the one variable the whole instrument reads — the arc, the ticks,
   the marker, the shockwave, the rays, the bulbs, the wash and the flash. Only
   the rules below ever set it; nothing downstream names a colour of its own.

   To change a stage, change its pair here and nothing else. Keep the hex and
   the triplet in step: the triplet is what the glows and washes need, because
   rgb(R G B / N%) is the way to get a see-through version of a custom property.

   These are plain bright hues rather than anything derived from the brand
   palette, because they have to read as distinct signals against a near-black
   cabinet. Four stages that were all tints of one blue would not. */
:root {
  --stage-1: #1FEFFF;  --stage-1-rgb: 31 239 255;   /* the zap    — electric blue */
  --stage-2: #FF2BCB;  --stage-2-rgb: 255 43 203;   /* the pucker — hot pink */
  --stage-3: #FFD60A;  --stage-3-rgb: 255 214 10;   /* the tears  — amber */
  /* the final stretch is the heat colour, and surviving is the accent */
}

/* These stay sRGB on purpose, and it cost an afternoon to learn why.

   The obvious way to get brighter colour is color(display-p3 …), which phones
   have rendered for years and which @supports reports as supported. It does
   work — for HTML backgrounds. Feed one through a custom property into SVG
   fill or stroke and Chromium resolves it to oklab() and then paints nothing
   at all: the ring, the tick marks and the marker bead simply disappear, with
   no error and no warning. @supports cannot help, because the browser is not
   lying about support; it only fails on the SVG side.

   Since the dial is SVG and reads the same --live as everything else, the
   whole instrument went invisible. If you ever reach for a wider gamut here,
   that is what to expect, and it has to be a second variable used only by the
   HTML layers — never this one. The brightness below comes from how hard each
   layer is painted, which was the bigger half of it anyway. */

[data-timer], .dial          { --live: var(--accent); --live-rgb: var(--accent-rgb); }
[data-phase="1"]             { --live: var(--stage-1); --live-rgb: var(--stage-1-rgb); }
[data-phase="2"]             { --live: var(--stage-2); --live-rgb: var(--stage-2-rgb); }
[data-phase="3"]             { --live: var(--stage-3); --live-rgb: var(--stage-3-rgb); }
[data-phase="4"]             { --live: var(--heat);    --live-rgb: var(--heat-rgb); }
[data-phase="5"]             { --live: var(--accent);  --live-rgb: var(--accent-rgb); }
/* The last seconds are red and surviving is green whatever stage says, because
   the hot window and the fourth stage only line up exactly at twenty seconds.
   Class beats attribute, so these win wherever they disagree. */
[data-timer].is-hot,  .dial.is-hot  { --live: var(--heat);   --live-rgb: var(--heat-rgb); }
[data-timer].is-done, .dial.is-done { --live: var(--accent); --live-rgb: var(--accent-rgb); }
.dial-svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.dial-tick-off { stroke: rgb(var(--on-ink-rgb) / 18%); stroke-width: 4; stroke-linecap: round; fill: none; }
.dial-tick-off { stroke: rgb(var(--on-ink-rgb) / 18%); stroke-width: 4; stroke-linecap: round; fill: none; }
.dial-tick-on  { stroke: var(--live); stroke-width: 5; stroke-linecap: round; fill: none; transition: stroke 420ms ease; }
.dial-track { stroke: rgb(var(--on-ink-rgb) / 9%); stroke-width: 18; fill: none; }
.dial-track { stroke: rgb(var(--on-ink-rgb) / 9%); stroke-width: 18; fill: none; }
.dial-arc {
  stroke: var(--live); stroke-width: 18; stroke-linecap: round; fill: none;
  stroke-dasharray: 879.65; stroke-dashoffset: 879.65;
  transition: stroke-dashoffset 120ms linear, stroke 420ms ease;
}
.dial-marker { transform-box: view-box; transform-origin: 180px 180px; transition: transform 120ms linear, opacity 200ms ease; opacity: 0; }
.dial-marker circle { fill: var(--live); stroke: var(--ink); stroke-width: 5; transition: fill 420ms ease; }
.dial.is-running .dial-marker { opacity: 1; }
.dial.is-done .dial-marker { opacity: 0; }
/* Surviving grows the clock, which pushes its label down onto the rim and into
   the glow. The marker is hidden by now, so the face can afford to bleed a lot
   more dark outward without anything to paint over. */
.dial.is-done .dial-face { box-shadow: 0 0 28px 18px var(--ink); }

/* Shockwave out of the dial on every stage change */
.dial-wave { transform-box: view-box; transform-origin: 180px 180px; stroke: var(--live); stroke-width: 9; fill: none; opacity: 0; }
@keyframes dial-wave0 { 0% { transform: scale(.7); opacity: .9; } 100% { transform: scale(1.16); opacity: 0; } }
@keyframes dial-wave1 { 0% { transform: scale(.7); opacity: .9; } 100% { transform: scale(1.16); opacity: 0; } }
@keyframes dial-wave2 { 0% { transform: scale(.7); opacity: .9; } 100% { transform: scale(1.16); opacity: 0; } }
@keyframes dial-wave3 { 0% { transform: scale(.7); opacity: .9; } 100% { transform: scale(1.16); opacity: 0; } }
@keyframes dial-wave4 { 0% { transform: scale(.7); opacity: .9; } 100% { transform: scale(1.16); opacity: 0; } }
@keyframes dial-wave5 { 0% { transform: scale(.7); opacity: .9; } 100% { transform: scale(1.16); opacity: 0; } }
.dial[data-phase="1"] .dial-wave { animation: dial-wave1 .75s ease-out; }
.dial[data-phase="2"] .dial-wave { animation: dial-wave2 .75s ease-out; }
.dial[data-phase="3"] .dial-wave { animation: dial-wave3 .75s ease-out; }
.dial[data-phase="4"] .dial-wave { animation: dial-wave4 .75s ease-out; }
.dial[data-phase="5"] .dial-wave { animation: dial-wave5 .75s ease-out; }

/* Red glow under the dial for the last seconds */
.dial-danger {
  position: absolute; inset: -5%; border-radius: 50%; pointer-events: none; opacity: 0;
  /* A halo ring, not a filled disc. Hugging the bezel is where a glow belongs
     anyway, and it keeps the middle dark so the clock and its label stay
     readable against it instead of sitting in the brightest part. */
  background: radial-gradient(circle, transparent 34%, rgb(var(--live-rgb) / 78%) 52%, transparent 78%);
  transition: opacity 320ms ease, background 420ms ease;
}
/* It used to be a red glow for the last seconds only. Now it is the stage's
   own glow, lit the whole way through, which is what stops the ring looking
   like a drawing of a lit ring. The red seconds still get it hardest, and
   still pulse. A radial gradient rather than a drop-shadow on the arc: the arc
   is repainted every 120ms as it burns down, and a filter on it would make
   phones work for the privilege. */
.dial.is-running .dial-danger { opacity: .62; }
.dial.is-hot .dial-danger { opacity: 1; animation: dial-danger .72s ease-in-out infinite; }
.dial.is-done .dial-danger { opacity: .85; }
/* The marker is one small shape that moves, so it can afford a real glow. */
.dial-marker circle { filter: drop-shadow(0 0 7px rgb(var(--live-rgb) / 95%)); }
@keyframes dial-danger { 0%,100% { opacity: .3; transform: scale(.96); } 50% { opacity: .85; transform: scale(1.05); } }

/* ---------- Lenny asks ----------
   While nobody has touched the clock, he leans toward the glass and raps on it
   twice, and each rap throws a flash across the cabinet and a ring out of the
   dial. The flash is what carries the meaning: in two dimensions an arm coming
   toward you looks much the same as an arm waving, but an arm that makes the
   whole cabinet jump reads as knuckles on glass.

   Driven by [data-nudge], which the script puts on and takes off again. Taking
   it off matters — an animation that stays applied under the same name never
   restarts, which is why the stage pops each have a name of their own. Here
   the attribute goes away between raps, so one name is enough.

   The two raps land at 36% and 54% of the run. Everything below is timed to
   those two numbers; move one and you move all of them. */
.lenny[data-nudge] .ln-act   { animation: ln-rap-body 1.7s cubic-bezier(.3,.8,.3,1); }
.lenny[data-nudge] .ln-arm-l { animation: ln-rap-arm-l 1.7s cubic-bezier(.3,.8,.3,1); }
.lenny[data-nudge] .ln-arm-r { animation: ln-rap-arm-r 1.7s cubic-bezier(.3,.8,.3,1); }
.cabinet[data-nudge] .cab-flash { animation: cab-rap 1.7s linear; }
.dial[data-nudge] .dial-wave { animation: ln-rap-wave 1.7s ease-out; }

@keyframes ln-rap-body {
  0%   { transform: scale(1) translateY(0); }
  16%  { transform: scale(1.055) translateY(-5px); }
  36%  { transform: scale(1.075) translateY(-6px); }
  41%  { transform: scale(1.045) translateY(-3px); }
  54%  { transform: scale(1.075) translateY(-6px); }
  59%  { transform: scale(1.045) translateY(-3px); }
  80%  { transform: scale(1.03) translateY(-2px); }
  100% { transform: scale(1) translateY(0); }
}
/* Both arms, and they stay low on purpose.

   The arms are drawn before the body in the SVG, so they sit behind it: they
   are meant to poke out of the silhouette, not cross it. Swing one up to
   head height and the fist disappears behind his face, which looks like a
   bug. Anything past about -40deg is behind him.

   So the knock is a short outward jab at shoulder height, where the fists are
   actually visible, with the arm lengthening on contact. The scale is doing
   the real work: an arm getting longer is the only way a flat drawing says
   "toward you". */
@keyframes ln-rap-arm-r {
  0%   { transform: rotate(0deg) scale(1); }
  22%  { transform: rotate(-38deg) scale(1.06); }
  36%  { transform: rotate(-20deg) scale(1.2); }
  46%  { transform: rotate(-38deg) scale(1.06); }
  54%  { transform: rotate(-20deg) scale(1.2); }
  66%  { transform: rotate(-38deg) scale(1.06); }
  88%  { transform: rotate(0deg) scale(1); }
  100% { transform: rotate(0deg) scale(1); }
}
@keyframes ln-rap-arm-l {
  0%   { transform: rotate(0deg) scale(1); }
  22%  { transform: rotate(38deg) scale(1.06); }
  36%  { transform: rotate(20deg) scale(1.2); }
  46%  { transform: rotate(38deg) scale(1.06); }
  54%  { transform: rotate(20deg) scale(1.2); }
  66%  { transform: rotate(38deg) scale(1.06); }
  88%  { transform: rotate(0deg) scale(1); }
  100% { transform: rotate(0deg) scale(1); }
}
/* Short and not very bright. It is a knock, not an arrival. */
@keyframes cab-rap {
  0%, 33% { opacity: 0; }
  36%     { opacity: .34; }
  44%     { opacity: 0; }
  51%     { opacity: 0; }
  54%     { opacity: .34; }
  62%     { opacity: 0; }
  100%    { opacity: 0; }
}
@keyframes ln-rap-wave {
  0%, 34% { opacity: 0; transform: scale(.72); }
  37%     { opacity: .9; transform: scale(.76); }
  50%     { opacity: 0; transform: scale(1.1); }
  52%     { opacity: 0; transform: scale(.72); }
  55%     { opacity: .9; transform: scale(.76); }
  70%     { opacity: 0; transform: scale(1.12); }
  100%    { opacity: 0; transform: scale(1.12); }
}

/* Payoff */
.dial-burst { opacity: 0; transform-box: view-box; transform-origin: 180px 180px; }
.dial.is-done .dial-burst { opacity: 1; animation: dial-burst 1.1s ease-out; }
@keyframes dial-burst { 0% { transform: scale(.2); opacity: 0; } 30% { opacity: 1; } 100% { transform: scale(1.3); opacity: 0; } }

.dial-face {
  position: relative; z-index: 1; width: 70%; height: 70%; border-radius: 50%;
  background: var(--ink); color: var(--on-ink);
  /* A whisper of dark past the edge, to soften where the face meets the glow.
     It has to stay small: the marker orbits only about 12px outside this
     circle, and anything that reaches it paints ink straight over the bead. */
  box-shadow: 0 0 10px 1px var(--ink);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.dial-lenny { transition: transform 200ms ease; }
.dial.is-hot .dial-lenny { animation: dial-shake .26s linear infinite; }
.dial.is-done .dial-lenny { animation: dial-pop .5s cubic-bezier(.3,1.4,.4,1); }
@keyframes dial-shake { 0%,100% { transform: translate(0,0) rotate(0deg); } 25% { transform: translate(-3px,1px) rotate(-1.4deg); } 75% { transform: translate(3px,-1px) rotate(1.4deg); } }
@keyframes dial-pop { 0% { transform: scale(.84) rotate(-5deg); } 55% { transform: scale(1.06) rotate(2deg); } 100% { transform: scale(1) rotate(0deg); } }

.dial-clock {
  display: inline-block; font-family: var(--font-display); font-weight: 900;
  font-size: clamp(30px, 12vw, 46px);
  font-size: clamp(30px, 13cqw, 46px);
  line-height: 1; font-variant-numeric: tabular-nums;
  transition: color 300ms ease, transform 110ms linear;
}
.dial.is-hot .dial-clock { color: rgb(var(--heat-rgb) / 55%); }
.dial.is-hot .dial-clock { color: var(--heat-tn55); }
.dial.is-done .dial-clock { color: var(--accent-on-ink); font-size: clamp(22px, 8vw, 32px); font-size: clamp(22px, 9cqw, 32px); }
.dial-clock.is-kick { transform: scale(1.14); }
/* Lenny is 160px tall inside a 210px face, which pushes this label about 14px
   past the bottom of the dark disc it is supposed to be sitting on. That never
   showed while the outside of the face was dark too. Now that it is lit, the
   label carries its own dark backing rather than relying on what is behind it. */
.dial-unit {
  font-size: 9px; font-weight: 800; letter-spacing: .2em; text-transform: uppercase;
  color: var(--accent-on-ink);
  padding: 3px 10px; border-radius: 999px;
  background: rgb(var(--ink-rgb) / 92%);
  box-shadow: 0 0 10px 5px rgb(var(--ink-rgb) / 92%);
}

/* 3 · 2 · 1 before the clock actually moves */
.dial-count {
  position: absolute; inset: 0; z-index: 3; display: grid; place-items: center;
  pointer-events: none; opacity: 0;
}
.dial.is-counting .dial-count { opacity: 1; }
.dial-count span {
  font-family: var(--font-display); font-weight: 900; line-height: 1;
  font-size: clamp(76px, 31vw, 140px);
  font-size: clamp(76px, 34cqw, 140px);
  color: var(--on-ink); text-shadow: 0 0 36px rgb(var(--accent-rgb) / 85%), 6px 6px 0 var(--ink);
  color: var(--on-ink); text-shadow: 0 0 36px rgb(var(--accent-rgb) / 85%), 6px 6px 0 var(--ink);
}
@keyframes dial-cnt3 { 0% { transform: scale(2.6); opacity: 0; } 26% { transform: scale(1); opacity: 1; } 100% { transform: scale(.78); opacity: 0; } }
@keyframes dial-cnt2 { 0% { transform: scale(2.6); opacity: 0; } 26% { transform: scale(1); opacity: 1; } 100% { transform: scale(.78); opacity: 0; } }
@keyframes dial-cnt1 { 0% { transform: scale(2.6); opacity: 0; } 26% { transform: scale(1); opacity: 1; } 100% { transform: scale(.78); opacity: 0; } }
.dial[data-count="3"] .dial-count span { animation: dial-cnt3 .62s ease-out; }
.dial[data-count="2"] .dial-count span { animation: dial-cnt2 .62s ease-out; }
.dial[data-count="1"] .dial-count span { animation: dial-cnt1 .62s ease-out; }

/* ---------- Stage ladder ---------- */
.lamps { display: flex; gap: 6px; width: 100%; }
.lamp {
  flex: 1; text-align: center; border-radius: 8px; padding: 5px 3px;
  font-family: var(--font-display); font-weight: 800; font-size: 9px; letter-spacing: .1em; text-transform: uppercase;
  background: rgb(var(--on-ink-rgb) / 7%); color: rgb(var(--on-ink-rgb) / 48%);
  background: rgb(var(--on-ink-rgb) / 7%); color: rgb(var(--on-ink-rgb) / 48%);
  transition: background 260ms ease, color 260ms ease, box-shadow 260ms ease;
}
.lamp { white-space: nowrap; overflow: hidden; text-overflow: clip; }

/* ---------- The row before anything has started ----------
   Four grey tabs under a neon cabinet looked like a form. Idle, each chip now
   wears a ghost of the colour it will become, so the row reads as the route
   ahead — and a light walks along them in order every few seconds, which is
   the bit that says these happen one after another rather than all at once.

   Each chip's colour is fixed to its stage, not taken from --live, because
   this is a preview of four different things, not a reading of one. */
.lamp[data-timer-lamp="0"] { --chip-rgb: var(--stage-1-rgb); }
.lamp[data-timer-lamp="1"] { --chip-rgb: var(--stage-2-rgb); }
.lamp[data-timer-lamp="2"] { --chip-rgb: var(--stage-3-rgb); }
.lamp[data-timer-lamp="3"] { --chip-rgb: var(--heat-rgb); }

[data-timer][data-phase="0"] .lamp {
  background: rgb(var(--chip-rgb) / 13%);
  color: rgb(var(--chip-rgb) / 92%);
  box-shadow: inset 0 0 0 1.5px rgb(var(--chip-rgb) / 40%);
  animation: lamp-tease 5.2s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * .4s);
}
@keyframes lamp-tease {
  0%, 58%, 100% { background: rgb(var(--chip-rgb) / 13%); box-shadow: inset 0 0 0 1.5px rgb(var(--chip-rgb) / 40%); }
  68%           { background: rgb(var(--chip-rgb) / 36%); box-shadow: inset 0 0 0 1.5px rgb(var(--chip-rgb) / 95%), 0 0 14px rgb(var(--chip-rgb) / 50%); }
}

.lamp.is-lit { background: var(--accent); color: var(--on-accent); }
/* Each lamp keeps its own stage's colour once lit, so the row reads as a trail
   of where you have been rather than four identical green chips. These are
   fixed per lamp, not taken from --live, because a lamp you passed two stages
   ago should still be showing its own colour. */
.lamp[data-timer-lamp="0"].is-lit { background: var(--stage-1); }
.lamp[data-timer-lamp="1"].is-lit { background: var(--stage-2); }
.lamp[data-timer-lamp="2"].is-lit { background: var(--stage-3); }
.lamp[data-timer-lamp="3"].is-lit { background: var(--heat); color: var(--white); }

/* The stage you are on wears its own colour and glows. Ink on top, because
   every stage colour is a bright one; the red seconds switch to white. */
.lamp.is-now { background: var(--live); color: var(--ink); box-shadow: 0 0 0 2px rgb(var(--on-ink-rgb) / 35%), 0 0 16px rgb(var(--live-rgb) / 85%); }
.is-hot .lamp.is-now { color: var(--white); }

/* Surviving turns the whole row green. The trail has done its job by then, and
   the payoff should be one colour, not a rainbow. */
.is-done .lamp.is-lit { background: var(--accent); color: var(--on-accent); }

/* ---------- The cabinet ----------
   Marquee bulbs round the card, a ray field behind the dial, and a backdrop
   that heats up. One --chase variable drives every bulb. */
.cabinet {
  --chase: 1.7s;
  scroll-margin-top: 16px; scroll-margin-bottom: 16px;
  position: relative; overflow: hidden; background: var(--ink); color: var(--on-ink);
  border-radius: 22px; box-shadow: 9px 9px 0 var(--ink);
  border-radius: 22px; box-shadow: 9px 9px 0 var(--ink-sh70);
  container-type: inline-size;
}
.cabinet.is-running { --chase: .95s; }
.cabinet.is-hot { --chase: .42s; animation: cab-panic .3s linear infinite; }
.cabinet.is-done { --chase: .34s; }
@keyframes cab-panic { 0%,100% { transform: translate(0,0); } 25% { transform: translate(-2px,1px); } 75% { transform: translate(2px,-1px); } }

.cab-frame { position: absolute; inset: 12px; border: 12px solid rgb(var(--on-ink-rgb) / 9%); border-radius: 22px; pointer-events: none; z-index: 3; }
.cab-frame { position: absolute; inset: 12px; border: 12px solid rgb(var(--on-ink-rgb) / 9%); border-radius: 22px; pointer-events: none; z-index: 3; }
.cab-bulbs { position: absolute; inset: 12px; pointer-events: none; z-index: 4; }
.cab-bulbs .row, .cab-bulbs .col { position: absolute; display: flex; justify-content: space-between; align-items: center; }
.cab-bulbs .row { left: 22px; right: 22px; height: 0; }
.cab-bulbs .col { top: 22px; bottom: 22px; width: 0; flex-direction: column; }
.cab-bulbs .top { top: 0; }
.cab-bulbs .bottom { bottom: 0; }
.cab-bulbs .left { left: 0; }
.cab-bulbs .right { right: 0; }
.cab-bulbs i {
  display: block; width: 9px; height: 9px; border-radius: 50%; background: var(--live);
  opacity: .13; animation: cab-bulb var(--chase) linear infinite;
  transition: background 300ms ease;
  animation-delay: calc(var(--p, 0) * var(--chase) * -1);
}
/* Real bulbs spill light onto what they are mounted on. A flat dot reads as a
   sticker; a dot with a halo reads as lit, and that is most of the difference
   between a marquee and a border. Only while the clock runs — an idle cabinet
   with every bulb blazing has nowhere left to go. */
.cabinet.is-running .cab-bulbs i,
.cabinet.is-done .cab-bulbs i {
  box-shadow: 0 0 9px rgb(var(--live-rgb) / 90%), 0 0 20px rgb(var(--live-rgb) / 55%);
}
.cabinet.is-running .cab-bulbs i { animation-name: cab-bulb-lit; }
@keyframes cab-bulb-lit { 0%,100% { opacity: .34; } 42% { opacity: 1; } }
/* Surviving keeps its own colour: the marquee going fairground-yellow is the
   payoff, and it should not be a colour any stage already used. */
.cabinet.is-done .cab-bulbs i { background: #FFE23D; }
@keyframes cab-bulb { 0%,100% { opacity: .13; } 42% { opacity: 1; } }

.cab-rays { position: absolute; left: 50%; top: 42%; width: 180%; aspect-ratio: 1; translate: -50% -50%; pointer-events: none; z-index: 0; opacity: .08; color: rgb(var(--brand-rgb) / 70%); transition: opacity 600ms ease, color 600ms ease; animation: cab-spin 30s linear infinite; }
.cab-rays { position: absolute; left: 50%; top: 42%; width: 180%; aspect-ratio: 1; translate: -50% -50%; pointer-events: none; z-index: 0; opacity: .08; color: var(--brand-tn70); transition: opacity 600ms ease, color 600ms ease; animation: cab-spin 30s linear infinite; }
/* The pinwheel takes the stage colour and winds up as the dare goes on: it
   brightens and spins faster each stage, so the thing in the corner of your eye
   is the thing that is actually changing. Colour comes from --live alone — the
   hot and done rules below only touch speed and strength. */
.cabinet.is-running .cab-rays { color: var(--live); opacity: .34; animation-duration: 16s; }
.cabinet.is-running[data-phase="2"] .cab-rays { opacity: .42; animation-duration: 13s; }
.cabinet.is-running[data-phase="3"] .cab-rays { opacity: .5;  animation-duration: 11s; }
.cabinet.is-hot .cab-rays  { opacity: .56; animation-duration: 9s; }
.cabinet.is-done .cab-rays { color: var(--live); opacity: .6; animation-duration: 7s; }
@keyframes cab-spin { to { transform: rotate(360deg); } }

/* A pool of the stage colour behind the dial. It fades in as soon as the clock
   is running rather than only in the red seconds, so the whole cabinet carries
   the colour and not just the instrument. */
.cab-wash { position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: 0; transition: opacity 600ms ease, background 600ms ease; background: radial-gradient(ellipse at 50% 42%, rgb(var(--live-rgb) / 52%) 0%, transparent 72%); }
.cabinet.is-running .cab-wash { opacity: .9; }
.cabinet.is-hot .cab-wash { opacity: 1; }
.cabinet.is-done .cab-wash { opacity: 1; background: radial-gradient(ellipse at 50% 42%, rgb(var(--live-rgb) / 40%) 0%, transparent 72%); }

/* Scanlines, plus a scrim that holds the colour back where words are.
   The rays are bright enough now to eat the copy under them, so this darkens
   the top and bottom bands and leaves the middle — where the dial is, and
   where there is nothing to read — at full strength. Painted after the rays
   and before the content, so it dims the background without touching the text.
   Sits in the same layer stack rather than a new element, because the cabinet
   already has enough overlays to keep track of. */
.cab-scan {
  position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: 1;
  background:
    repeating-linear-gradient(to bottom, rgba(255,255,255,.016) 0 1px, rgba(0,0,0,0) 1px 4px),
    linear-gradient(to bottom,
      rgb(var(--ink-rgb) / 70%) 0%,
      rgb(var(--ink-rgb) / 20%) 11%,
      rgb(var(--ink-rgb) / 0%) 22%,
      rgb(var(--ink-rgb) / 0%) 52%,
      rgb(var(--ink-rgb) / 55%) 68%,
      rgb(var(--ink-rgb) / 80%) 100%);
}

.cab-flash { position: absolute; inset: 0; z-index: 5; pointer-events: none; background: var(--live); opacity: 0; }

/* A pop of the new colour over the whole cabinet every time a stage turns
   over. Four identical animations under four names, because a browser only
   restarts an animation when the animation itself changes — the same trick
   .dial-wave uses. Reusing one name would fire it once and never again.

   Kept well under the done flash: these land four times in twenty seconds, and
   something that bright, that often, stops reading as an event. */
@keyframes cab-pop1 { 0% { opacity: .62; } 100% { opacity: 0; } }
@keyframes cab-pop2 { 0% { opacity: .62; } 100% { opacity: 0; } }
@keyframes cab-pop3 { 0% { opacity: .62; } 100% { opacity: 0; } }
@keyframes cab-pop4 { 0% { opacity: .62; } 100% { opacity: 0; } }
.cabinet.is-running[data-phase="1"] .cab-flash { animation: cab-pop1 .45s ease-out; }
.cabinet.is-running[data-phase="2"] .cab-flash { animation: cab-pop2 .45s ease-out; }
.cabinet.is-running[data-phase="3"] .cab-flash { animation: cab-pop3 .45s ease-out; }
.cabinet.is-running[data-phase="4"] .cab-flash { animation: cab-pop4 .45s ease-out; }
.cabinet.is-done .cab-flash { animation: cab-flash .55s ease-out; }
@keyframes cab-flash { 0% { opacity: .85; } 100% { opacity: 0; } }

/* Side padding clears the bulb rail. The rail sits 12px in and each bulb
   is 9px across, so its inner edge is 16.5px from the cabinet edge —
   content needs to start well past that or it reads as crossing into the
   lights. Vertical padding is tuned separately: it decides whether the
   cabinet still lands inside the fold. */
.cab-body { position: relative; z-index: 2; padding: 30px 28px; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.cab-head { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.cab-eyebrow { font-family: var(--font-display); font-weight: 800; font-size: 9px; letter-spacing: .2em; text-transform: uppercase; color: var(--accent-on-ink); }
.cab-pill {
  font-family: var(--font-display); font-weight: 800; font-size: 9px; letter-spacing: .08em;
  padding: 6px 11px; border-radius: 999px; white-space: nowrap;
  background: #FFE23D; color: var(--on-accent); transition: background 300ms ease, color 300ms ease;
}
[data-timer].is-hot .cab-pill { background: var(--heat); color: var(--white); }
[data-timer].is-done .cab-pill { background: var(--accent); color: var(--on-accent); }

.cab-stage {
  font-family: var(--font-display); font-weight: 800; font-size: 15px; text-transform: uppercase;
  text-align: center; min-height: 22px; color: var(--on-ink);
}
[data-timer].is-hot .cab-stage { color: rgb(var(--heat-rgb) / 55%); }
[data-timer].is-hot .cab-stage { color: var(--heat-tn55); }
@keyframes cab-slam0 { 0% { transform: scale(1.8); opacity: 0; } 60% { transform: scale(.96); } 100% { transform: scale(1); opacity: 1; } }
@keyframes cab-slam1 { 0% { transform: scale(1.8); opacity: 0; } 60% { transform: scale(.96); } 100% { transform: scale(1); opacity: 1; } }
@keyframes cab-slam2 { 0% { transform: scale(1.8); opacity: 0; } 60% { transform: scale(.96); } 100% { transform: scale(1); opacity: 1; } }
@keyframes cab-slam3 { 0% { transform: scale(1.8); opacity: 0; } 60% { transform: scale(.96); } 100% { transform: scale(1); opacity: 1; } }
@keyframes cab-slam4 { 0% { transform: scale(1.8); opacity: 0; } 60% { transform: scale(.96); } 100% { transform: scale(1); opacity: 1; } }
@keyframes cab-slam5 { 0% { transform: scale(1.8); opacity: 0; } 60% { transform: scale(.96); } 100% { transform: scale(1); opacity: 1; } }
[data-timer][data-phase="1"] .cab-stage { animation: cab-slam1 .45s cubic-bezier(.2,1.4,.4,1); }
[data-timer][data-phase="2"] .cab-stage { animation: cab-slam2 .45s cubic-bezier(.2,1.4,.4,1); }
[data-timer][data-phase="3"] .cab-stage { animation: cab-slam3 .45s cubic-bezier(.2,1.4,.4,1); }
[data-timer][data-phase="4"] .cab-stage { animation: cab-slam4 .45s cubic-bezier(.2,1.4,.4,1); }
[data-timer][data-phase="5"] .cab-stage { animation: cab-slam5 .45s cubic-bezier(.2,1.4,.4,1); }

.cab-note { margin: 0; min-height: 36px; font-size: 13px; line-height: 1.4; color: var(--on-ink-soft); text-align: center; }
.cab-note b { color: var(--accent-on-ink); font-weight: 800; }
/* The idle copy changes every few seconds. Fading through it keeps the swap
   from reading as a glitch, and the min-heights above stop the buttons moving
   when one line is longer than the last. */
.cab-stage, .cab-note { transition: opacity 240ms ease; }
[data-timer].is-swapping .cab-stage, [data-timer].is-swapping .cab-note { opacity: 0; }
/* The min-heights above are the measured height of the tallest line each one
   has to hold, so swapping copy never shoves the buttons under a thumb. Every
   line fits on one row from 360px up; below that one of them wraps, so that
   width reserves the second row rather than jumping. */
@media (max-width: 345px) { .cab-stage { min-height: 44px; } }
.cab-actions { display: flex; gap: 9px; width: 100%; }
.cab-actions .btn { min-height: 46px; padding: 0 18px; font-size: 13.5px; }
.cab-actions .btn:first-child { flex: 1; }

/* Narrow phones. This repeats what the @container rule below does, as a
   plain media query, because container queries are Safari 16+ and a 320px
   layout viewport is exactly the case that needs the tightening. */
@media (max-width: 360px) {
  .cab-body { padding: 22px 20px; }
  .cab-actions .btn { padding: 0 12px; font-size: 12.5px; }
  .cab-note { display: none; }
}

@container (max-width: 340px) {
  .cab-body { padding: 26px 26px; }
  .cab-note { display: none; }
}

/* Anyone who asked for less motion gets the instrument without the strobe. */
@media (prefers-reduced-motion: reduce) {
  .lenny .ln-act, .lenny .ln-beat, .lenny .ln-drip, .lenny .ln-arm,
  .dial-wave, .dial .dial-lenny, .dial-burst,
  .cabinet, .cab-bulbs i, .cab-rays, .cab-flash, .cab-stage, .dial-danger, .dial-count span, .lamp {
    animation: none !important;
  }
  .cab-bulbs i { opacity: .6; }
  /* The burst is drawn by its animation, so stopping the animation would
     erase it. Hold it at full size instead. */
  .lenny .ln-zap { animation: none !important; }
  .lenny[data-phase="1"] .ln-zap { opacity: 1; transform: scale(1); }
}

/* ---------- The fold ----------
   Headline, live dial and the four jump cards all above the scroll line.
   Phones get copy → dial → shots, so the dare is the first thing in reach. */
.fold { position: relative; background: var(--brand); color: var(--on-brand); padding: 10px 0 20px; overflow: hidden; }
.fold > .wrap { position: relative; z-index: 1; }

/* Backdrop. Decorative only: it sits behind everything and fills the wide
   margins the centred container leaves on large screens. */
.fold-bg { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.fold-rays {
  position: absolute; top: 50%; left: 72%; width: 150vmax; aspect-ratio: 1;
  translate: -50% -50%; animation: fold-spin 90s linear infinite;
}
@keyframes fold-spin { to { rotate: 360deg; } }
.fold-dots { position: absolute; left: -26px; bottom: -14px; width: 300px; opacity: .2; }
/* Backdrop candy keeps the real ball surface — speckle and all — just with a
   coarser grain to match its size, a softer shadow and a lot less opacity. */
.fold-ball {
  position: absolute; border-width: 3px;
  box-shadow: 7px 8px 0 rgb(var(--ink-rgb) / 55%);
  box-shadow: 7px 8px 0 rgb(var(--ink-rgb) / 55%);
}
.fold-ball-a { --speckle: 26px; width: clamp(180px, 20vw, 300px); left: -5%; top: 48%; opacity: .5; animation: fold-float 7s ease-in-out infinite; }
.fold-ball-b { --speckle: 14px; width: clamp(76px, 8vw, 132px); left: 49%; top: 7%; opacity: .45; animation: fold-float 9s ease-in-out 1.4s infinite; }
.fold-ball-c { --speckle: 11px; width: clamp(60px, 6vw, 96px); right: 2%; top: 70%; opacity: .4; animation: fold-float 11s ease-in-out .6s infinite; }
@keyframes fold-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -14px; } }
@media (prefers-reduced-motion: reduce) {
  .fold-rays, .fold-ball { animation: none !important; }
}
.fold-grid {
  display: grid; gap: 20px;
  grid-template-areas: "copy" "dial" "shots";
}
.fold-copy { grid-area: copy; }
.fold-dial { grid-area: dial; display: flex; justify-content: center; }
.fold-dial .cabinet { width: 100%; max-width: 420px; }
.shots { grid-area: shots; display: flex; gap: 10px; }

.fold-title {
  margin: 18px 0 14px;
  font-weight: 900; text-transform: uppercase;
  font-size: clamp(2.7rem, 1rem + 7.6vw, 3.9rem);
  line-height: .9; letter-spacing: -.04em;
}
.fold-lede { max-width: 32ch; font-size: 16px; line-height: 1.45; color: var(--on-brand-soft); }
.fold-ctas { display: flex; gap: 10px; margin-top: 18px; }
.fold-ctas .btn { flex: 1 1 0; padding: 0 14px; }
.fold-note { margin-top: 10px; font-size: 13px; color: rgb(var(--on-brand-rgb) / 72%); }
.fold-note { margin-top: 10px; font-size: 13px; color: rgb(var(--on-brand-rgb) / 72%); }

/* Product shots: photo when there is one, drawn candy until then. */
.shot {
  flex: 1; margin: 0; aspect-ratio: 1; position: relative; overflow: hidden;
  background: var(--ink); border: 3px solid var(--ink); border-radius: 13px;
  box-shadow: 4px 4px 0 var(--ink);
  box-shadow: 4px 4px 0 var(--ink-sh60);
  display: grid; place-items: center;
}
.shot:nth-child(1) { rotate: -3deg; }
.shot:nth-child(2) { rotate: 2deg; }
.shot:nth-child(3) { rotate: -2deg; }
.shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shot .shot-one { width: 76%; box-shadow: 5px 6px 0 var(--ink); }
.shot-cluster { position: relative; width: 92%; aspect-ratio: 1; }
.shot-cluster .ball { position: absolute; width: 52%; box-shadow: 3px 4px 0 var(--ink); border-width: 2px; }
.shot-cluster .ball:nth-child(1) { left: 0; bottom: 4%; }
.shot-cluster .ball:nth-child(2) { right: 0; bottom: 8%; width: 46%; }
.shot-cluster .ball:nth-child(3) { left: 24%; top: 0; width: 56%; }
.shot-pack-art { width: 88%; height: 88%; }
.shot-wall-art { width: 100%; height: 100%; }
/* The drawn art sits a little smaller on a labelled tile so it is not
   crowding the bar along the bottom. */
.shot.is-link .shot-one { width: 66%; }
.shot.is-link .shot-cluster { width: 82%; }
.shot.is-link .shot-pack-art, .shot.is-link .shot-wall-art { width: 92%; height: 92%; }

/* The three tiles are the shortest route into the three things somebody
   actually came for: buy it, read the rules, watch the reactions. A drawing
   of a sweet cannot say where it goes, so each one is labelled and the whole
   tile is the hit area. */
.shot.is-link { text-decoration: none; color: inherit; cursor: pointer; padding-bottom: 27px; }
/* A photo still fills the whole tile and sits behind the bar; only the drawn
   art is pushed up to clear it. */
.shot.is-link img { position: absolute; inset: 0; }
.shot-label {
  position: absolute; inset: auto 0 0 0;
  padding: 7px 6px 8px;
  background: var(--accent); color: var(--ink);
  font-family: var(--font-display); font-weight: 900;
  font-size: 12px; line-height: 1; letter-spacing: .02em;
  text-transform: uppercase; text-align: center;
  border-top: 3px solid var(--ink);
}
@media (prefers-reduced-motion: no-preference) {
  .shot.is-link { transition: rotate .18s ease, translate .18s ease; }
}
.shot.is-link:hover, .shot.is-link:focus-visible { rotate: 0deg; translate: 0 -3px; }
.shot.is-link:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.shot figcaption { position: absolute; left: 8px; bottom: 6px; font-size: 10px; font-weight: 800; color: var(--accent-on-ink); }

/* Everything else, one click away instead of one scroll. */
.jump-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 16px; }
.jump {
  display: block; background: var(--ink); color: var(--on-ink);
  border: 3px solid var(--ink); border-radius: 14px;
  box-shadow: 5px 5px 0 var(--ink);
  box-shadow: 5px 5px 0 var(--ink-sh55);
  padding: 12px 14px; text-decoration: none;
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.jump:hover, .jump:focus-visible { transform: translate(-2px, -2px); box-shadow: 7px 7px 0 var(--ink); }
.jump:hover, .jump:focus-visible { transform: translate(-2px, -2px); box-shadow: 7px 7px 0 var(--ink-sh55); }
.jump-n { display: block; font-family: var(--font-display); font-weight: 900; font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--accent-on-ink); margin-bottom: 5px; }
.jump strong { display: block; font-family: var(--font-display); font-weight: 800; font-size: 13px; line-height: 1.2; }
.jump span:not(.jump-n) { display: block; margin-top: 3px; font-size: 12px; color: var(--on-ink-soft); }

.challenge-art { display: flex; justify-content: center; }
.challenge-back { margin-top: 18px; }

@media (min-width: 720px) {
  .jump-row { grid-template-columns: repeat(4, 1fr); gap: 12px; }
  .shots { max-width: 380px; }
}

@media (min-width: 1100px) {
  .fold { padding: 16px 0 20px; }
  .fold-grid {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "copy dial" "shots dial";
    column-gap: 44px; row-gap: 12px; align-items: start;
  }
  .fold-dial { align-self: center; }
  .fold-dial .cabinet { width: 400px; }
  .fold-title { margin: 20px 0 16px; font-size: clamp(3.4rem, 1rem + 4.2vw, 4.4rem); }
  .fold-lede { font-size: 18px; }
  .fold-ctas { margin-top: 24px; }
  .fold-ctas .btn { flex: 0 0 auto; min-height: 56px; padding: 0 28px; font-size: 15px; }
  .jump-row { margin-top: 18px; }
  .shots { max-width: 340px; }
}

/* Short phones: trim the copy so the dial still lands in the first screen. */
@media (max-width: 1099px) and (max-height: 700px) {
  .fold { padding: 4px 0 16px; }
  .fold-grid { gap: 14px; }
  .fold-title { margin: 10px 0 8px; font-size: clamp(2.3rem, .9rem + 6.6vw, 3rem); }
  .fold-lede { font-size: 15px; }
  .hero-lede-more { display: none; }
  .fold-ctas { margin-top: 12px; }
  .fold-note { display: none; }
}

/* ---------- Phones: the dial has to land in the first screen ----------
   Measured on a 390x844 viewport: trimming the copy and sizing the dial to
   the viewport puts the start button at ~750px instead of 932px. */
@media (max-width: 1099px) {
  .dial { --dial-size: min(300px, 64vw); }
  .cab-body { padding: 25px 26px; gap: 8px; }
  .cab-note { display: none; }          /* the lamps already name the stage */
  .fold { padding: 6px 0 20px; }
  .fold-grid { gap: 16px; }
  .fold-title { margin: 12px 0 10px; font-size: clamp(2.5rem, 1rem + 6.8vw, 3.4rem); }
  .fold-lede { font-size: 15px; }
  .hero-lede-more { display: none; }
  .fold-ctas { margin-top: 14px; }
  .fold-ctas .btn { min-height: 50px; }
  .fold-note { margin-top: 8px; font-size: 12px; }
  .jump-row { margin-top: 16px; }
  .challenge-art .lenny { width: min(240px, 62vw) !important; height: auto !important; }
  .challenge-art .lenny svg { height: auto; }
}

/* ---------- Short desktop screens ----------
   The cabinet is the tallest thing in the fold, so it is what decides
   whether the marquee lands in the first screen. Scale it to the viewport
   height rather than letting the banner slide off a 13" laptop. */
@media (min-width: 1100px) and (max-height: 900px) {
  .dial { --dial-size: 250px; }
  .cab-body { padding: 25px 28px; gap: 7px; }
  .fold { padding: 10px 0 14px; }
  .fold-title { margin: 14px 0 12px; font-size: clamp(3rem, 1rem + 3.6vw, 3.9rem); }
  .jump-row { margin-top: 14px; }
}
@media (min-width: 1100px) and (max-height: 800px) {
  .dial { --dial-size: 216px; }
  .cab-note { display: none; }
  .fold-lede { font-size: 16px; }
  .shots { max-width: 300px; }
}

/* ---------- Phones: the dare comes first ----------
   Measured on a 390x664 window — an iPhone with the URL bar still open,
   which is about the smallest a phone realistically gets. Header 72 +
   cabinet 447 = 519, so the whole clock already fits with ~145px to spare;
   it was only ever pushed under the fold by the 249px headline block
   sitting above it. So on a phone the clock comes first and the headline
   follows it, which also leaves the top of the headline visible as a cue
   that there is more below.

   PHONES ONLY. 768px and up keeps headline-then-clock: a tablet in portrait
   has the height for both, and the desktop two-column fold is untouched. */
@media (max-width: 767px) {
  .fold-grid { grid-template-areas: "dial" "copy" "shots"; }

  /* Cap the dial by available HEIGHT as well as width, so a short window —
     a landscape phone, a browser with a fat toolbar — shrinks the clock to
     fit instead of pushing the start button off screen.

     This MUST go behind @supports. I previously wrote it as a plain override
     and assumed an older browser would ignore it, the way it ignores any
     value it cannot parse. Custom properties do not work like that: they
     swallow almost anything at parse time and only fail later, at the point
     of use — so on Safari 15 the dial ended up with no usable size at all
     and collapsed, taking the whole card down with it. Behind @supports the
     old browser never sees it and keeps the width-only rule above. */
  @supports (height: 100dvh) {
    .dial { --dial-size: min(300px, 64vw, 42dvh); }
  }

  /* The nav is already a hamburger here, so the header's height is only the
     logo lockup and the three round buttons. 14px back off the top of the
     page, with the buttons still at a 44px touch target. */
  .header-row { min-height: 58px; }
  .icon-btn { width: 44px; height: 44px; }
}

/* ---------- Phones: selling first ----------
   Measured before this block: the home page ran 10.4 phone screens and the
   first Add to cart sat at screen 6.7, behind three screens of explainer.
   Nobody arriving from a video scrolls that far for a $4.99 impulse buy.

   The order below puts the clock, then the price, then the proof, then
   everything else. Sections are reordered with flex `order` rather than
   moved in the markup, so the reading order for search engines and screen
   readers stays the sensible one and desktop is untouched. The single
   exception is the headline block, which lives inside the fold and so has
   to be moved by hand — site.js does that, and if the script never runs the
   page simply keeps today's layout. */
@media (max-width: 767px) {
  main { display: flex; flex-direction: column; }
  .fold        { order: 1; }
  .strip-clip  { order: 2; }
  .shots       { order: 3; }   /* lifted out of the fold, so it needs its own */

  /* The headline and the shots have been lifted out of the fold, but the grid
     still declared their rows. An empty row collapses to nothing while its
     16px gap does not, so 32px of dead space was sitting under the clock.
     This is the one piece of the fit worth keeping: it is a defect, not a
     squeeze — nothing on the page gets smaller, a gap that should not have
     existed just stops existing. */
  .fold-grid { grid-template-areas: "dial"; gap: 0; }
  .shots { padding: 18px var(--pad) 0; }
  #shop        { order: 4; }
  #wall        { order: 5; }
  .fold-copy   { order: 6; }
  #challenge   { order: 7; }
  .section-lime{ order: 8; }
  #label       { order: 9; }

  /* Desktop nav furniture that costs 245px before anything useful. */
  .jump-row { display: none; }
  /* The big mascot and the second product rail both push the shop down. */
  .challenge-art, .lineup, .secure-note { display: none; }

  /* The claim, once the script has moved it below the shop. It leaves the
     fold's blue behind when it goes, so it brings its own — otherwise the
     lede ends up light text on a light page, which is exactly what happened
     the first time I moved it. */
  .fold-copy {
    background: var(--brand); color: var(--on-brand);
    padding: 26px var(--pad) 28px;
  }
  .fold-copy .fold-title { margin: 12px 0 8px; }
  .fold-copy .fold-lede { color: var(--on-brand-soft); }
  .fold-copy .fold-note { color: rgb(var(--on-brand-rgb) / 72%); }

  /* --- Shop: two across, with the big pack full width underneath. Three
         products is too few to hide any behind a swipe. --- */
  #shop .cards { grid-template-columns: 1fr 1fr; gap: 11px; }
  #shop .card-art { aspect-ratio: 1; }
  #shop .card-body { padding: 10px 11px 12px; gap: 5px; }
  /* Name on its own line. Sitting it beside the price broke "Solo Dare"
     across two lines at half width. */
  #shop .card-title-row { flex-direction: column; align-items: flex-start; gap: 1px; }
  #shop .card-title { font-size: 15px; line-height: 1.1; }
  #shop .card-price { font-size: 19px; }
  #shop .card-detail { font-size: 10px; letter-spacing: .1em; }
  #shop .card-text { display: none; }
  /* The page-level button is sized for a full-width hero; at half width its
     padding alone wrapped "Add to cart" onto two lines. */
  #shop .card-body .btn { min-height: 42px; padding: 0 10px; font-size: 13px; white-space: nowrap; }
  #shop .card .add-form { margin-top: 3px; }

  /* The big pack, full width: art panel, then name and price with the pack
     count under them, then the button. Laid out as a grid so the button
     stays put instead of being pushed around by the text beside it. */
  #shop .cards > :nth-child(3) { grid-column: 1 / -1; flex-direction: row; align-items: stretch; }
  /* The base art panel is a fixed 200px tall, which is right for a card you
     look down at and far too tall for a row you read across. */
  #shop .cards > :nth-child(3) .card-art { flex: none; width: 112px; height: auto; aspect-ratio: auto; padding: 12px 10px; border-bottom: none; border-right: 3px solid var(--ink); }
  /* Twelve full-size candies do not fit a 112px panel — they were spilling
     out of it. Four across at a third the size does. */
  #shop .cards > :nth-child(3) .balls-12 { grid-template-columns: repeat(4, 20px); gap: 5px; }
  #shop .cards > :nth-child(3) .balls-12 .ball { border-width: 2px; box-shadow: 2px 2px 0 var(--ink); }
  #shop .cards > :nth-child(3) .balls-4 { grid-template-columns: repeat(2, 34px); gap: 7px; }
  #shop .cards > :nth-child(3) .card-badge { display: none; }
  #shop .cards > :nth-child(3) .card-body {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "title btn" "detail btn";
    align-items: center; align-content: center; gap: 2px 10px; padding: 14px 12px;
  }
  #shop .cards > :nth-child(3) .card-title-row { grid-area: title; flex-direction: column; align-items: flex-start; gap: 0; }
  #shop .cards > :nth-child(3) .card-detail { grid-area: detail; }
  #shop .cards > :nth-child(3) .add-form { grid-area: btn; margin: 0; }

  /* --- The rules: three beats across, not three paragraphs down. --- */
  #challenge .rules { grid-template-columns: repeat(3, 1fr); gap: 8px; align-items: stretch; }
  #challenge .rules li { flex-direction: column; align-items: flex-start; gap: 6px; padding: 11px 9px; min-width: 0; }
  #challenge .rules li > div { min-width: 0; }
  #challenge .rules strong { font-size: 12.5px; line-height: 1.15; overflow-wrap: anywhere; }
  #challenge .rules span:not(.rule-num) { font-size: 10.5px; line-height: 1.25; overflow-wrap: anywhere; }
  #challenge .rule-num { width: 22px; height: 22px; font-size: 11px; }
  #challenge .challenge-back { display: none; }
  #challenge .section-head h2 { font-size: 24px; }

  /* --- The curve: every stage still written out, but as compact rows with
         a colour bar that ramps so the heat is visible at a glance. --- */
  .section-lime .stages { gap: 6px; }
  .section-lime .stage {
    display: flex; flex-direction: column; gap: 3px; align-items: stretch;
    padding: 9px 10px 9px 8px; border-left: 5px solid var(--stage-c, var(--accent));
    border-radius: 10px;
  }
  /* Time and name share the top line, sentence underneath. A narrow side
     column looked tidy until "The pucker" broke across two lines. */
  .section-lime .stage-head { flex-direction: row; align-items: baseline; gap: 8px; flex-wrap: nowrap; }
  .section-lime .stage-time { background: none; padding: 0; font-size: 10px; color: var(--stage-c, var(--ink)); flex: none; }
  .section-lime .stage-name { font-size: 13.5px; white-space: nowrap; }
  .section-lime .stage p { font-size: 11.5px; line-height: 1.32; }
  .section-lime .stage .bar { display: none; }
  .section-lime .stage:nth-child(1) { --stage-c: #D2FF3C; }
  .section-lime .stage:nth-child(2) { --stage-c: #E8D92F; }
  .section-lime .stage:nth-child(3) { --stage-c: #FFB03A; }
  .section-lime .stage:nth-child(4) { --stage-c: #FF6B3A; }


  /* --- Proof: a rail you flick, not a grid you scroll past. This is the one
         place a sideways row genuinely fits: the clips are interchangeable
         and endless, so nobody needs to see them all — the same shape as a
         stories row, which is the gesture this audience already has. The
         tiles deliberately run off the right edge so it reads as more. --- */
  #wall .wall {
    display: flex; gap: 10px; grid-template-columns: none;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory; scrollbar-width: none;
    margin: 0 calc(var(--pad) * -1); padding: 0 var(--pad) 4px;
  }
  #wall .wall::-webkit-scrollbar { display: none; }
  #wall .wall-tile { flex: none; width: 150px; scroll-snap-align: start; }
  #wall .wall-play { width: 42px; height: 42px; }
  #wall .wall-handle { font-size: 11px; }

  /* Sections carry desktop air on a phone; this is where the rest of the
     height was hiding. */
  .section { padding: 26px 0; }
  .section-head { gap: 9px; margin-bottom: 14px; }
  .section-head h2 { font-size: 27px; }
  .section-lede { font-size: 14px; margin-top: 4px; }
  .hazard { padding: 24px 0 0; }
  .hazard-card { padding: 16px; }
  .strip-clip { margin: 0; }

  /* --- The buy bar. Nothing else on the page matters as much: it is what
         takes "first add to cart" from screen 6.7 to wherever you are. --- */
  .buybar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    display: flex; align-items: center; gap: 10px;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
    background: var(--ink); color: var(--on-ink);
    border-top: 3px solid var(--accent);
    transform: translateY(110%); transition: transform 240ms cubic-bezier(.2,.8,.3,1);
  }
  .buybar.is-up { transform: translateY(0); }
  .buybar-who { flex: 1; min-width: 0; text-decoration: none; color: inherit; }
  .buybar-who strong { display: block; font-family: var(--font-display); font-weight: 800; font-size: 13px; }
  .buybar-who span { display: block; font-size: 11.5px; color: var(--on-ink-soft); }
  .buybar .add-form { margin: 0; flex: none; }
  .buybar-cta { min-height: 44px; padding: 0 16px; font-size: 13px; }
  /* Room so the bar never covers the last thing on the page. Written without
     :has(), which Safari did not get until 15.4. */
  #label { padding-bottom: 96px; }
  .buybar[hidden] { display: none; }
}
@media (min-width: 768px) {
  .buybar { display: none; }
}

/* ---------- The creator dashboard ----------
   Deliberately plain CSS: no color-mix(), no container queries, no :has().
   Creators open this on a phone, and phones in the wild include Safari 15. */
.subhead { font-size: 15px; font-weight: 800; margin: 16px 0 6px; }
.plain-rows { list-style: none; margin: 0; padding: 0; }
.plain-rows li { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
.plain-rows li:last-child { border-bottom: 0; }

.creator-code {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 18px;
  padding: 20px 22px; margin-bottom: 14px;
  color: var(--ink); background: var(--white);
  border: 3px solid var(--ink); border-radius: 18px; box-shadow: 6px 6px 0 var(--ink);
}
.creator-code-label { font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-soft); }
.creator-code-value {
  font-family: var(--font-display); font-weight: 900; line-height: 1;
  font-size: clamp(34px, 1.3rem + 5vw, 56px); letter-spacing: -0.02em;
  margin: 4px 0 8px;
}
.creator-code-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.creator-code-link { overflow-wrap: anywhere; max-width: 34ch; }

.creator-scores { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 0 0 14px; }
@media (min-width: 620px) { .creator-scores { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .creator-scores { grid-template-columns: repeat(6, minmax(0, 1fr)); } }
.score {
  display: flex; flex-direction: column; gap: 2px;
  padding: 14px 16px; color: var(--ink); background: var(--white);
  border: 3px solid var(--ink); border-radius: 14px;
}
.score-value { font-family: var(--font-display); font-weight: 900; font-size: 24px; line-height: 1.05; }
.score-label { font-size: 12px; font-weight: 700; color: var(--text-soft); }
.score-lead { background: var(--accent); }
.score-lead .score-value, .score-lead .score-label { color: var(--on-accent); }

/* 30 columns, one per day. A plain flex row rather than a chart library: it is
   six numbers' worth of shape, and it has to work with the page's own colours. */
.spark {
  display: flex; align-items: flex-end; gap: 3px; height: 92px;
  padding: 10px 12px; margin-bottom: 8px;
  background: var(--white); border: 3px solid var(--ink); border-radius: 14px;
}
.spark-col { flex: 1 1 0; display: flex; align-items: flex-end; height: 100%; min-width: 0; }
.spark-fill { display: block; width: 100%; background: var(--brand); border-radius: 3px 3px 0 0; }
/* A quiet day is a flat grey tick, not a short blue bar. Otherwise a month of
   nothing reads as a dashed line of something. */
.spark-col.is-quiet .spark-fill { background: var(--line); border-radius: 2px; }
/* The honeypot. Off-screen rather than display:none, because some bots skip
   fields they can tell are hidden. Nothing a person uses is in here. */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- The speaker switch ----------
   Small and quiet in the corner of the cabinet head. It is the only thing on
   the page that can start a noise, so it reads as off until it is on: a muted
   speaker with a cross, going solid and lime when it is live. */
.cab-head-right { display: flex; align-items: center; gap: 8px; }
.mini-head { display: flex; align-items: center; gap: 10px; }
.cab-sound {
  flex: none; width: 30px; height: 30px; padding: 0;
  display: grid; place-items: center; cursor: pointer;
  background: rgb(var(--on-ink-rgb) / 9%); color: var(--on-ink-soft);
  border: 1.5px solid rgb(var(--on-ink-rgb) / 22%); border-radius: 999px;
  transition: background 200ms ease, color 200ms ease, border-color 200ms ease;
}
.cab-sound svg { width: 17px; height: 17px; }
.cab-sound path { fill: currentColor; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.cab-sound-body { stroke-linejoin: round; }
.cab-sound-wave { opacity: 0; }
.cab-sound:hover { color: var(--on-ink); border-color: rgb(var(--on-ink-rgb) / 45%); }
.cab-sound[aria-pressed="true"] {
  background: var(--accent); color: var(--on-accent); border-color: var(--accent);
}
.cab-sound[aria-pressed="true"] .cab-sound-wave { opacity: 1; }
.cab-sound[aria-pressed="true"] .cab-sound-off { opacity: 0; }
.cab-sound[hidden] { display: none; }

/* ---------- Creator disclosure ---------- */
/* Shown on the apply form, the dashboard and the creator terms page. The
   point is that a creator can copy the exact line rather than paraphrase it
   into something that no longer discloses anything. */
.disclosure-head { margin: 0 0 8px; font-size: 18px; }
.disclosure.is-compact .disclosure-head { font-size: 16px; }
.disclosure p { margin: 0 0 10px; }
.disclosure-lines { list-style: none; margin: 12px 0; padding: 0; display: grid; gap: 8px; }
.disclosure-lines li {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; border-radius: 10px;
  background: rgb(var(--ink-rgb) / 6%);
  border: 2px solid rgb(var(--ink-rgb) / 14%);
}
.disclosure-lines code { font-size: 13px; line-height: 1.35; flex: 1 1 14ch; }
.disclosure-sub { margin: 16px 0 6px; font-weight: 800; }
.disclosure-rules { margin: 0 0 12px; padding-left: 20px; display: grid; gap: 7px; }
.disclosure-rules li { line-height: 1.45; }
.disclosure.is-compact .disclosure-lines li { padding: 8px 10px; }
.disclosure.is-compact .disclosure-lines code { font-size: 12px; }

/* The # in front of the wordmark. Its own element so it can be sized and
   coloured apart from the letters — it is a mark, not a letter of the name.
   Full height, not stepped: it is the loud part, and in this face the hash
   already rises above the cap line and drops below the baseline, so at the
   same size it reads taller than the B rather than competing with it. The B
   still leads the word because it is the first letter. Colour follows
   whichever accent the CHALLENGE line uses in the same place, so the two
   always agree. */
.wm-hash { display: inline-block; color: var(--accent-on-brand); }
.site-footer .wm-hash { color: var(--accent-on-ink); }
