/* ===========================================================================
   Bargames.live homepage.

   Aesthetic: the artifacts of the game itself. A real bingo card is cream
   stock, navy ink and red dauber marks, so that is the palette. Display face
   is a Clarendon-ish slab, the kind of type a pub tacks in its window.

   Two scenes drive the theme, and the page honours both:
     - a patron in a dim, loud bar at 8pm, squinting to type a code  -> ink hero,
       one huge target, maximum contrast.
     - a bar owner on a laptop at noon deciding whether to book       -> paper body,
       long-form, comfortable to read.

   ── 2026 pass (Dave, 2026-08-04) ─────────────────────────────────────────
   Identity unchanged. The execution underneath it was rebuilt:

     - @layer, so specificity is decided by section order, not by accident.
     - light-dark() dual theme. The paper scene is still the default; a phone
       set to dark gets an ink page instead of a torch in a dark bar.
       PRODUCT.md names "a bright screen in a dark room" as an anti-reference.
     - EVERY foreground/background pair was checked against WCAG AA before it
       was written, on BOTH themes. The shipped "Play now" button was failing
       at 4.33:1; it is 5.18:1 now. See the token comments below.
     - Real responsive behaviour from 320px to 2560px. The old file died at
       320 (a 330px grid minimum inside a 320px viewport) and hid the whole
       nav from 0-860px with nothing in its place.
     - Container queries where a component's own width is what matters, media
       queries only where the DEVICE is what matters.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   Fonts, self-hosted.

   These used to come from fonts.googleapis.com, which cost a render-blocking
   third-party stylesheet plus two DNS/TLS handshakes before a single glyph
   could be requested: Lighthouse measured 849ms of blocking on that one link.
   The files are ours now (52 KB total, Open Font License), preloaded from the
   document, so the first paint has the real type in hand.

   Only the weights the page actually uses are here. Karla ships as a variable
   font, so 400-800 is one file rather than four.
   --------------------------------------------------------------------------- */
@font-face {
  font-family: "Karla";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/karla-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Karla";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/karla-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Ultra";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/ultra-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@layer reset, tokens, base, layout, components, motion;

/* ═══════════════════════════════════════════════════════════════════════════
   TOKENS
   ═══════════════════════════════════════════════════════════════════════════ */
@layer tokens {
  :root {
    /* Both schemes are authored. light-dark() picks per the user's setting. */
    color-scheme: light dark;

    /* ---- surfaces ------------------------------------------------------
       Light: cream card stock. Dark: the same navy ink, taken down.
       No pure black and no pure white anywhere; every neutral is tinted
       toward the ink hue. */
    --paper:      light-dark(oklch(0.965 0.010 85),  oklch(0.180 0.026 262));
    --paper-deep: light-dark(oklch(0.925 0.016 82),  oklch(0.232 0.030 262));
    --ink-deep:   light-dark(oklch(0.185 0.040 262), oklch(0.140 0.024 262));

    /* ---- text ----------------------------------------------------------
       ink on paper       14.27:1   |  paper on ink        16.51:1
       ink-soft on paper   7.33:1   |  ink-soft on ink      8.76:1 */
    --ink:      light-dark(oklch(0.255 0.045 260), oklch(0.955 0.010 85));
    --ink-soft: light-dark(oklch(0.430 0.038 260), oklch(0.760 0.020 262));

    /* Text that sits on the ink hero, in EITHER scheme. */
    --on-ink:      oklch(0.965 0.010 85);
    --on-ink-soft: oklch(0.965 0.010 85 / 0.76);

    /* ---- the dauber ----------------------------------------------------
       Two reds, and the split is load-bearing:
         --dauber      the MARK. Blots, rules, decoration, and display text
                       big enough for the 3:1 large-text threshold.
                       4.35:1 on paper -> large text only, never body copy.
         --dauber-ink  small accent TEXT and the button fill.
                       5.18:1 both ways on paper. This is the AA fix.
       On dark the accent lifts instead of darkening (5.57:1 on surface), and
       the button flips to a near-black label on a lit red (5.89:1), because a
       dark-red fill with pale text cannot clear AA on a dark page. */
    --dauber:     light-dark(oklch(0.575 0.195 27), oklch(0.660 0.185 30));
    --dauber-ink: light-dark(oklch(0.532 0.180 27), oklch(0.660 0.185 30));
    --dauber-lit: light-dark(oklch(0.655 0.185 30), oklch(0.720 0.170 32));
    --on-dauber:  light-dark(oklch(0.965 0.010 85), oklch(0.140 0.024 262));

    /* The only warm accent. 8.59:1 on the hero, 9.96:1 on dark surface. */
    --brass: light-dark(oklch(0.760 0.115 78), oklch(0.800 0.110 78));

    /* ---- lines and washes ---------------------------------------------- */
    --rule:      light-dark(oklch(0.255 0.045 260 / 0.16), oklch(0.955 0.010 85 / 0.15));
    --rule-firm: light-dark(oklch(0.255 0.045 260 / 0.32), oklch(0.955 0.010 85 / 0.30));
    --rule-lit:  oklch(0.965 0.010 85 / 0.22);
    --grain:     light-dark(oklch(0.255 0.045 260 / 0.030), oklch(0.955 0.010 85 / 0.022));
    --grain-2:   light-dark(oklch(0.255 0.045 260 / 0.022), oklch(0.955 0.010 85 / 0.016));
    --bar-bg:    light-dark(oklch(0.965 0.010 85 / 0.88), oklch(0.180 0.026 262 / 0.88));

    /* Card stock stays stock in both schemes: it is a paper bingo card and a
       paper ticket. Knocked back on dark so it is not a light source. */
    --stock:      light-dark(oklch(0.965 0.010 85), oklch(0.232 0.030 262));
    --stock-edge: light-dark(oklch(0.925 0.016 82), oklch(0.290 0.030 262));

    --shadow-lift: light-dark(oklch(0.185 0.040 262 / 0.55), oklch(0.05 0.02 262 / 0.75));
    --shadow-soft: light-dark(oklch(0.185 0.040 262 / 0.45), oklch(0.05 0.02 262 / 0.65));

    --ok: light-dark(oklch(0.480 0.130 155), oklch(0.780 0.150 155));

    /* ---- type ---------------------------------------------------------- */
    --slab: "Ultra", "Rockwell", "Clarendon", Georgia, serif;
    --sans: "Karla", ui-sans-serif, system-ui, -apple-system, sans-serif;

    --fs-body:    clamp(1rem, 0.96rem + 0.2vw, 1.09rem);
    --fs-lede:    clamp(1.05rem, 1rem + 0.28vw, 1.2rem);
    --fs-h1:      clamp(2.5rem, 1.15rem + 5.1vw, 4.5rem);
    --fs-h2:      clamp(1.95rem, 1.15rem + 2.7vw, 3.15rem);
    --fs-h3:      clamp(1.2rem, 1.1rem + 0.5vw, 1.38rem);
    /* 13px floor. The old 11.5px labels were unreadable at arm's length in a
       dim room, which is the whole scene this page is designed for. */
    --fs-label:   0.8125rem;
    --fs-small:   0.9rem;

    /* ---- space --------------------------------------------------------- */
    --gutter:    clamp(1.125rem, 4vw, 3.5rem);
    --section-y: clamp(3.75rem, 8vw, 7.25rem);
    --w-page:    75rem;    /* 1200 — hero and wide sections   */
    --w-prose:   70rem;    /* 1120 — the reading column       */
    --w-narrow:  54rem;    /*  864 — FAQ                      */
    --measure:   68ch;     /* body copy never runs past this  */

    /* Ease-out-quint. No bounce, no elastic. */
    --ease: cubic-bezier(0.22, 1, 0.36, 1);
    --tap: 44px;           /* minimum touch target, everywhere */
  }

  /* Ultrawide: give the page more air rather than stranding a 1120px column
     in the middle of a 27-inch monitor. Prose measure is untouched. */
  @media (min-width: 1800px) {
    :root {
      --w-page: 82rem;
      --w-prose: 76rem;
      --gutter: 4.5rem;
    }
  }

  /* Respect a stated preference for firmer edges. */
  @media (prefers-contrast: more) {
    :root {
      --rule:      light-dark(oklch(0.255 0.045 260 / 0.42), oklch(0.955 0.010 85 / 0.40));
      --rule-firm: light-dark(oklch(0.255 0.045 260 / 0.62), oklch(0.955 0.010 85 / 0.58));
      --ink-soft:  light-dark(oklch(0.330 0.040 260), oklch(0.880 0.014 262));
    }
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   RESET
   ═══════════════════════════════════════════════════════════════════════════ */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }

  html {
    scroll-behavior: smooth;
    /* Sticky header height, so #anchors do not land under the bar. */
    scroll-padding-top: 5.5rem;
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
  }

  body, h1, h2, h3, p, dl, dd, ol, ul, figure { margin: 0; }
  ol[class] { list-style: none; padding: 0; }

  img, picture, svg { max-width: 100%; height: auto; display: block; }

  input, button, textarea, select { font: inherit; color: inherit; }
  button { background: none; border: 0; }

  /* Never let a long word or an unbreakable string blow out the layout. */
  h1, h2, h3, p, dd, dt, li, summary, a { overflow-wrap: break-word; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   BASE
   ═══════════════════════════════════════════════════════════════════════════ */
@layer base {
  body {
    background: var(--paper);
    color: var(--ink);
    font: 400 var(--fs-body)/1.62 var(--sans);
    -webkit-font-smoothing: antialiased;
    /* Paper grain. Cheap, static, no image request. */
    background-image:
      radial-gradient(var(--grain) 0.6px, transparent 0.6px),
      radial-gradient(var(--grain-2) 0.5px, transparent 0.5px);
    background-size: 13px 13px, 7px 7px;
    background-position: 0 0, 4px 5px;
    /* Notched phones and the iOS home indicator. */
    padding-inline: env(safe-area-inset-left) env(safe-area-inset-right);
    overflow-x: hidden;
  }

  a { color: inherit; }

  p, dd, li { text-wrap: pretty; }
  h1, h2, h3 { text-wrap: balance; }

  .skip {
    position: absolute; left: -9999px; top: 0; z-index: 60;
    background: var(--dauber-ink); color: var(--on-dauber);
    padding: 14px 20px; font-weight: 700; border-radius: 0 0 4px 0;
  }
  .skip:focus { left: 0; }

  :where(a, button, input, textarea, summary, [popovertarget]):focus-visible {
    outline: 3px solid var(--dauber);
    outline-offset: 3px;
    border-radius: 2px;
  }

  /* Anything interactive is at least a 44px target. Inline links inside
     running prose are exempt per WCAG 2.2 SC 2.5.8. */
  .nav a, .menu a, .foot-social a, .brand, .btn, .faq summary {
    min-height: var(--tap);
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LAYOUT
   ═══════════════════════════════════════════════════════════════════════════ */
@layer layout {
  .shell {
    width: min(100%, var(--w-prose));
    margin-inline: auto;
    padding-inline: var(--gutter);
  }
  .shell-wide  { width: min(100%, var(--w-page)); }
  .shell-narrow{ width: min(100%, var(--w-narrow)); }

  .section { padding-block-start: var(--section-y); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   COMPONENTS
   ═══════════════════════════════════════════════════════════════════════════ */
@layer components {

  /* ---------- buttons --------------------------------------------------- */
  .btn {
    display: inline-flex; align-items: center; justify-content: center;
    font: 800 0.95rem/1.15 var(--sans);
    letter-spacing: 0.02em; text-decoration: none;
    padding: 13px 22px; border-radius: 3px; cursor: pointer;
    border: 2px solid transparent;
    transition: transform 0.18s var(--ease), background-color 0.18s var(--ease),
                border-color 0.18s var(--ease), color 0.18s var(--ease);

    &:active { transform: translateY(1px); }
  }

  .btn-play {
    /* 5.18:1 light, 5.89:1 dark. The shipped version was 4.33:1. */
    background: var(--dauber-ink);
    color: var(--on-dauber);
    border-color: var(--dauber-ink);
    width: 100%;
    font-size: 1.05rem;
    padding: 17px 22px;

    &:hover { background: var(--dauber-lit); border-color: var(--dauber-lit); }
  }

  .btn-ghost {
    background: transparent; color: var(--ink); border-color: var(--rule-firm);
    &:hover { border-color: var(--ink); }
    &.dark { color: var(--on-ink); border-color: var(--rule-lit); }
    &.dark:hover { border-color: var(--on-ink); }
  }

  /* ---------- header ---------------------------------------------------- */
  .bar {
    position: sticky; top: 0; z-index: 30;
    display: flex; align-items: center; gap: clamp(14px, 3vw, 28px);
    padding: 10px var(--gutter);
    padding-top: max(10px, env(safe-area-inset-top));
    border-bottom: 1px solid var(--rule);
    background: var(--bar-bg);
    backdrop-filter: blur(12px) saturate(1.3);
  }

  .brand {
    display: inline-flex; align-items: center; gap: 11px;
    text-decoration: none; margin-right: auto;

    .brand-mark {
      display: grid; place-items: center;
      width: 34px; height: 34px; flex: none;
      background: var(--dauber-ink); color: var(--on-dauber);
      border-radius: 50%;
      font: 400 1.1rem/1 var(--slab); padding-bottom: 2px;
    }
    .brand-word {
      font: 400 clamp(1.2rem, 1.05rem + 0.5vw, 1.4rem)/1 var(--slab);
      letter-spacing: -0.01em;
    }
  }

  .nav {
    display: flex; align-items: center; gap: clamp(16px, 2.2vw, 26px);

    a {
      display: inline-flex; align-items: center;
      text-decoration: none; font-weight: 500; color: var(--ink-soft);
      border-bottom: 2px solid transparent;
      transition: color 0.18s var(--ease), border-color 0.18s var(--ease);
    }
    a:hover { color: var(--ink); border-bottom-color: var(--dauber); }
  }

  /* The desktop nav and the menu button are mutually exclusive, and the
     handover is driven by the space the words actually need. */
  .menu-btn { display: none; }
  @media (max-width: 60rem) {
    .nav, .bar .btn-ghost { display: none; }
    .menu-btn {
      display: inline-flex; align-items: center; gap: 9px;
      min-height: var(--tap); padding: 10px 14px;
      border: 2px solid var(--rule-firm); border-radius: 3px;
      font: 800 var(--fs-label)/1 var(--sans);
      letter-spacing: 0.12em; text-transform: uppercase;
      color: var(--ink); cursor: pointer;
    }
    .menu-btn::before {
      content: ""; width: 17px; height: 2px; flex: none;
      background: currentColor;
      box-shadow: 0 -5px 0 currentColor, 0 5px 0 currentColor;
    }
  }

  /* ---------- the menu: native popover, no JS --------------------------- */
  .menu {
    /* The Popover API gives light-dismiss, Escape, top-layer stacking and
       focus handling for free. None of that is worth hand-writing. */
    position: fixed; inset: 0 0 auto auto;
    width: min(21rem, 100vw); max-width: 100vw;
    height: 100dvh; max-height: 100dvh;
    margin: 0; border: 0; padding: 0;
    background: var(--ink-deep); color: var(--on-ink);
    box-shadow: -20px 0 60px var(--shadow-lift);
    overflow-y: auto; overscroll-behavior: contain;

    &::backdrop { background: oklch(0.12 0.03 262 / 0.55); }

    .menu-inner {
      display: flex; flex-direction: column;
      gap: 6px; padding: 16px var(--gutter) calc(28px + env(safe-area-inset-bottom));
      padding-top: max(16px, env(safe-area-inset-top));
      min-height: 100%;
    }
    .menu-head { display: flex; justify-content: flex-end; margin-bottom: 8px; }
    .menu-close {
      display: grid; place-items: center;
      width: var(--tap); height: var(--tap);
      border-radius: 50%; cursor: pointer;
      color: var(--on-ink); border: 2px solid var(--rule-lit);
      font: 400 1.5rem/1 var(--sans);
    }
    a {
      display: flex; align-items: center;
      padding: 15px 4px; text-decoration: none;
      font: 400 1.5rem/1.1 var(--slab);
      border-bottom: 1px solid var(--rule-lit);
    }
    a:hover, a:focus-visible { color: var(--dauber-lit); }
    .menu-cta { margin-top: auto; padding-top: 26px; }
    .menu-cta .btn { width: 100%; }
    .menu-note {
      margin-top: 14px; font-size: var(--fs-small); color: var(--on-ink-soft);
      a { display: inline; padding: 0; border: 0; font: inherit; font-weight: 700;
          text-decoration: underline; text-underline-offset: 3px;
          text-decoration-color: var(--dauber-lit); }
    }
  }

  /* ---------- hero: drenched ink ---------------------------------------- */
  .hero {
    background: var(--ink-deep);
    color: var(--on-ink);
    padding: clamp(34px, 5vw, 76px) var(--gutter) clamp(44px, 5vw, 76px);
    padding-bottom: calc(clamp(44px, 5vw, 76px) + env(safe-area-inset-bottom));
    position: relative; overflow: hidden;
  }
  /* Faint dauber wash, off-centre. Atmosphere, not a gradient hero. */
  .hero::before {
    content: ""; position: absolute; inset: -30% -10% auto auto;
    width: 70vw; height: 70vw; pointer-events: none;
    background: radial-gradient(circle, oklch(0.575 0.195 27 / 0.16), transparent 62%);
  }

  .hero-grid {
    position: relative;
    width: min(100%, var(--w-page)); margin-inline: auto;
    display: grid; gap: clamp(24px, 3.4vw, 48px) clamp(28px, 4vw, 56px);
    grid-template-columns: minmax(0, 1.15fr) minmax(19rem, 0.85fr);
    grid-template-areas:
      "say    ticket"
      "lede   ticket"
      "card   ticket";
    align-items: start;
    align-content: start;
  }
  .hero-say { grid-area: say; }
  .lede     { grid-area: lede; align-self: start; }
  .ticket   { grid-area: ticket; container: ticket / inline-size; }
  .card-wrap{ grid-area: card; align-self: end; }

  .eyebrow {
    margin-bottom: clamp(16px, 2.4vw, 22px);
    font-size: var(--fs-label); font-weight: 800; letter-spacing: 0.15em;
    text-transform: uppercase; color: var(--brass);
  }
  h1 {
    font: 400 var(--fs-h1)/0.98 var(--slab);
    letter-spacing: -0.015em;

    span { display: block; }
    .l3 { color: var(--dauber-lit); }
  }
  .lede {
    max-width: 46ch; color: var(--on-ink-soft); font-size: var(--fs-lede);
  }

  /* Stacked: the code box comes BEFORE the explanation. Someone holding a
     phone in a bar already knows why they are here; they need the box. */
  @media (max-width: 56rem) {
    .hero-grid {
      grid-template-columns: minmax(0, 1fr);
      grid-template-areas: "say" "ticket" "lede" "card";
    }
    /* Stacked, the stub should still read as a ticket rather than stretch
       into a banner across a tablet. Still an enormous target at 448px. */
    .ticket { width: min(28rem, 100%); margin-inline: auto; }
  }

  /* ---------- the ticket stub ------------------------------------------- */
  .ticket {
    background: var(--stock); color: var(--ink);
    border-radius: 4px;
    padding: clamp(22px, 4cqi, 30px) clamp(18px, 4cqi, 28px) 0;
    box-shadow: 0 26px 60px var(--shadow-lift);
    position: relative;
  }
  .ticket-label {
    display: block; margin-bottom: 9px;
    font-size: var(--fs-label); font-weight: 800; letter-spacing: 0.16em;
    text-transform: uppercase; color: var(--ink-soft);
  }
  #code {
    width: 100%;
    /* 16px+ or iOS zooms the whole page on focus. */
    font: 800 clamp(1.15rem, 4.5cqi, 1.5rem)/1.2 var(--sans);
    letter-spacing: 0.06em;
    padding: 15px 14px; margin-bottom: 12px;
    min-height: var(--tap);
    color: var(--ink); background: var(--paper-deep);
    border: 2px solid var(--rule-firm); border-radius: 3px;
    font-variant-numeric: tabular-nums;

    &::placeholder {
      font-size: 0.95rem; font-weight: 500; letter-spacing: 0;
      color: var(--ink-soft); opacity: 0.8;
    }
    &:focus { border-color: var(--ink); background: var(--stock); }
    &[aria-invalid="true"] { border-color: var(--dauber-ink); }
  }

  .ticket-msg {
    min-height: 1.35em; margin-top: 8px;
    font-size: 0.88rem; font-weight: 700;

    &.err { color: var(--dauber-ink); }
    &.ok  { color: var(--ok); }
  }

  /* The tear: a perforated edge, drawn not imaged. */
  .ticket-tear {
    margin: 12px calc(-1 * clamp(18px, 4cqi, 28px)) 0;
    height: 18px;
    background:
      radial-gradient(circle at 9px 0, transparent 8px, var(--stock) 8.5px)
      repeat-x 0 0 / 18px 18px;
    filter: drop-shadow(0 -1px 0 var(--rule));
    transform: scaleY(-1);
  }
  .ticket-alt {
    padding: 16px clamp(18px, 4cqi, 28px) 24px;
    font-size: 0.86rem; line-height: 1.55;
    color: var(--ink-soft); background: var(--stock);
    border-radius: 0 0 4px 4px;

    a {
      font-weight: 800; color: var(--ink);
      text-decoration-color: var(--dauber);
      text-decoration-thickness: 2px; text-underline-offset: 3px;
      /* A phone number IS the fallback path. Give it a real target. */
      display: inline-block; padding-block: 4px;
    }
  }

  /* ---------- the bingo card -------------------------------------------- */
  .bcard {
    width: min(21rem, 100%);
    background: var(--stock); border-radius: 5px; padding: 10px;
    box-shadow: 0 18px 44px var(--shadow-soft);
    transform: rotate(-1.6deg);
  }
  .bcard-head {
    display: grid; grid-template-columns: repeat(5, 1fr);
    background: light-dark(oklch(0.255 0.045 260), oklch(0.140 0.024 262));
    color: var(--on-ink);
    border-radius: 3px 3px 0 0;

    span { text-align: center; padding: 7px 0 5px; font: 400 1.25rem/1 var(--slab); }
  }
  .bcard-grid { display: grid; grid-template-columns: repeat(5, 1fr); }
  .cell {
    aspect-ratio: 1; display: grid; place-items: center; position: relative;
    border: 1px solid var(--rule); margin: -0.5px;
    font: 800 clamp(0.9rem, 3.6cqi, 1.35rem)/1 var(--sans);
    color: var(--ink);
    font-variant-numeric: tabular-nums;

    /* The dauber mark: an ink blot behind the number. */
    &::before {
      content: ""; position: absolute; inset: 12%; border-radius: 50%;
      background: var(--dauber); opacity: 0; transform: scale(0.35);
      transition: opacity 0.28s var(--ease), transform 0.34s var(--ease);
    }
    &.daub::before { opacity: 0.9; transform: scale(1); }
    &.daub { color: var(--on-dauber); }
    &.free { font: 800 0.6rem/1.25 var(--sans); text-align: center; letter-spacing: 0.04em; }
    span { position: relative; }
  }
  /* The container must STRETCH. `container-type: inline-size` applies inline
     containment, so a shrink-to-fit box (justify-self: center) would size
     itself from a width that depends on itself and collapse to a sliver.
     Stretch the wrapper, centre the card inside it. */
  .card-wrap { container: card / inline-size; justify-self: stretch; }
  @media (max-width: 56rem) {
    .bcard { transform: none; margin-inline: auto; }
  }

  /* ---------- shared section furniture ---------------------------------- */
  .section-h {
    font: 400 var(--fs-h2)/1.02 var(--slab);
    letter-spacing: -0.01em; margin-bottom: clamp(30px, 4vw, 44px);

    &.left { margin-bottom: 22px; }
    em { font-style: normal; color: var(--dauber); }
  }

  /* ---------- how: numbered, ruled, no cards ---------------------------- */
  .steps {
    display: grid;

    li {
      display: grid;
      grid-template-columns: minmax(4.6rem, 6.9rem) minmax(0, 1fr);
      grid-template-rows: auto auto;
      column-gap: clamp(16px, 4vw, 62px);
      align-items: baseline;
      padding-block: clamp(24px, 3.4vw, 34px);
      border-top: 1px solid var(--rule);
    }
    li:last-child { border-bottom: 1px solid var(--rule); }

    h3 { grid-column: 2; grid-row: 1; margin-bottom: 8px; font-size: var(--fs-h3); font-weight: 800; letter-spacing: -0.01em; }
    p  { grid-column: 2; grid-row: 2; color: var(--ink-soft); max-width: 62ch; }
  }
  .step-n {
    grid-column: 1; grid-row: 1 / span 2;
    /* Large text, so the mark red clears the 3:1 threshold at 4.35:1. */
    font: 400 clamp(1.9rem, 3vw, 2.9rem)/1 var(--slab);
    color: var(--dauber);
  }
  @media (max-width: 40rem) {
    .steps li { grid-template-columns: 1fr; row-gap: 6px; }
    .step-n { grid-column: 1; grid-row: 1; }
    .steps h3 { grid-column: 1; grid-row: 2; }
    .steps p  { grid-column: 1; grid-row: 3; }
  }

  /* ---------- split: two prose columns ---------------------------------- */
  .split {
    display: grid;
    /* min() is the 320px fix. A bare minmax(330px,1fr) cannot shrink below
       330 and blew 28px out of the viewport on a 320px phone. */
    grid-template-columns: repeat(auto-fit, minmax(min(20.6rem, 100%), 1fr));
    gap: clamp(34px, 5vw, 82px);
  }
  .col-h {
    font: 800 1.02rem/1.3 var(--sans);
    letter-spacing: 0.13em; text-transform: uppercase;
    /* Small uppercase text, so it needs the 4.5:1 red, not the mark red. */
    color: var(--dauber-ink);
    margin-bottom: 24px;
  }
  .facts {
    dt { font-size: 1.2rem; font-weight: 800; letter-spacing: -0.01em; margin-top: 26px; }
    dt:first-of-type { margin-top: 0; }
    dd { margin-top: 7px; color: var(--ink-soft); max-width: var(--measure); }
    dd.quiet { font-size: var(--fs-small); opacity: 0.85; }
  }
  .col-cta {
    margin-top: 28px; font-weight: 700;
    a { text-decoration-color: var(--dauber); text-decoration-thickness: 2px; text-underline-offset: 3px; }
  }

  /* ---------- revenue: offset, duotone ---------------------------------- */
  .revenue {
    display: grid;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: clamp(26px, 5vw, 72px);
    align-items: center;
  }
  .rev-shot {
    position: relative;

    img {
      width: 100%; border-radius: 4px;
      /* Duotone: the photo joins the palette instead of fighting it. */
      filter: grayscale(1) contrast(1.12);
      mix-blend-mode: multiply;
    }
    &::after {
      content: ""; position: absolute; inset: 0; border-radius: 4px;
      pointer-events: none; mix-blend-mode: screen;
      background: linear-gradient(150deg,
        oklch(0.255 0.045 260 / 0.42), oklch(0.575 0.195 27 / 0.20));
    }
  }
  /* multiply against a dark page turns the photo to mud; screen keeps it. */
  @media (prefers-color-scheme: dark) {
    .rev-shot img { mix-blend-mode: screen; filter: grayscale(1) contrast(1.05) brightness(0.82); }
    .rev-shot::after { mix-blend-mode: multiply; opacity: 0.75; }
  }
  .rev-say p { color: var(--ink-soft); max-width: var(--measure); }
  .rev-say p + p { margin-top: 1em; }
  .rev-kicker { font-weight: 800; color: var(--ink) !important; font-size: 1.1rem; }
  @media (max-width: 50rem) { .revenue { grid-template-columns: 1fr; } }

  /* ---------- faq -------------------------------------------------------- */
  .faq {
    details { border-top: 1px solid var(--rule); }
    details:last-of-type { border-bottom: 1px solid var(--rule); }

    summary {
      display: flex; align-items: center;
      cursor: pointer; list-style: none;
      padding: 18px 44px 18px 0; position: relative;
      font-size: clamp(1.05rem, 1rem + 0.3vw, 1.16rem);
      font-weight: 800; letter-spacing: -0.01em;
    }
    summary::-webkit-details-marker { display: none; }
    summary::after {
      content: "+"; position: absolute; right: 4px; top: 50%;
      translate: 0 -50%;
      font: 400 1.7rem/1 var(--sans); color: var(--dauber);
      transition: rotate 0.3s var(--ease);
    }
    details[open] summary::after { rotate: 45deg; }

    p { padding-bottom: 24px; color: var(--ink-soft); max-width: var(--measure); }
    a {
      text-decoration-color: var(--dauber); text-decoration-thickness: 2px;
      text-underline-offset: 3px; font-weight: 700;
    }
  }

  /* ---------- contact ---------------------------------------------------- */
  .contact {
    display: grid;
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
    gap: clamp(26px, 5vw, 72px);
    align-items: start;
  }
  .contact-say p { color: var(--ink-soft); max-width: 44ch; }

  .contact-form {
    label {
      display: block; margin: 18px 0 6px;
      font-size: var(--fs-label); font-weight: 800; letter-spacing: 0.13em;
      text-transform: uppercase; color: var(--ink-soft);
    }
    input, textarea {
      width: 100%; min-height: var(--tap);
      /* 1rem minimum: anything smaller and iOS zooms on focus. */
      font: 500 1rem/1.5 var(--sans); color: var(--ink);
      padding: 12px; background: var(--paper-deep);
      border: 2px solid var(--rule-firm); border-radius: 3px;
      resize: vertical;
    }
    textarea { field-sizing: content; min-height: 7rem; }
    input:focus, textarea:focus { border-color: var(--ink); background: var(--stock); }
    input[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: var(--dauber-ink); }
    .btn-play { margin-top: 24px; }
  }
  .cf-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); gap: 0 16px; }
  @media (max-width: 50rem) { .contact { grid-template-columns: 1fr; } }

  /* ---------- footer ----------------------------------------------------- */
  .foot {
    margin-top: var(--section-y);
    padding: 36px var(--gutter);
    padding-bottom: calc(36px + env(safe-area-inset-bottom));
    background: var(--ink-deep); color: var(--on-ink-soft);
    display: flex; flex-wrap: wrap; gap: 14px clamp(24px, 4vw, 40px);
    align-items: center; justify-content: space-between;

    p { font-size: 0.86rem; }
    a {
      color: var(--on-ink);
      text-decoration-color: var(--dauber-lit);
      text-decoration-thickness: 2px; text-underline-offset: 3px;
    }
  }
  .foot-legal { max-width: 62ch; }
  .foot-social {
    display: flex; flex-wrap: wrap; gap: 4px clamp(14px, 3vw, 22px);
    font-weight: 700;

    a { display: inline-flex; align-items: center; min-height: var(--tap); padding-inline: 2px; }
  }

  /* ---------- host dialog (the arriving-from-Gigbuilder path) ------------ */
  .hostdlg {
    border: 0; padding: 0; border-radius: 5px;
    width: min(27rem, 92vw);
    background: var(--ink-deep); color: var(--on-ink);
    box-shadow: 0 30px 90px var(--shadow-lift);

    &::backdrop { background: oklch(0.12 0.03 262 / 0.72); }
    form { padding: 28px var(--gutter) 24px; }
    h2 { font: 400 clamp(1.6rem, 1.3rem + 1vw, 1.9rem)/1 var(--slab); }
    label {
      display: block; margin: 20px 0 6px;
      font-size: var(--fs-label); font-weight: 800; letter-spacing: 0.13em;
      text-transform: uppercase; color: var(--brass);
    }
    input {
      width: 100%; min-height: var(--tap);
      font: 700 1.05rem/1.2 var(--sans); padding: 13px 12px;
      color: var(--on-ink);
      background: oklch(0.965 0.010 85 / 0.07);
      border: 2px solid var(--rule-lit); border-radius: 3px;
    }
    input:focus { border-color: var(--brass); background: oklch(0.965 0.010 85 / 0.12); }
    .ticket-msg.err { color: oklch(0.760 0.150 30); }
  }
  .hostdlg-sub  { margin: 10px 0 6px; font-size: 0.9rem; color: var(--on-ink-soft); }
  .hostdlg-act  { display: grid; grid-template-columns: auto 1fr; gap: 12px; margin-top: 10px; }
  .hostdlg-foot { margin-top: 20px; font-size: var(--fs-label); color: oklch(0.965 0.010 85 / 0.62); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   MOTION
   Every animation in this file is inside this layer and inside a
   no-preference guard, so "reduce" is one switch and cannot be missed.
   ═══════════════════════════════════════════════════════════════════════════ */
@layer motion {
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
      animation-duration: 1ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 1ms !important;
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    /* One orchestrated page-load moment, staggered. */
    .hero-say > *, .lede, .ticket, .card-wrap {
      animation: rise 0.85s var(--ease) both;
    }
    .eyebrow   { animation-delay: 0.02s; }
    h1         { animation-delay: 0.08s; }
    .ticket    { animation-delay: 0.18s; }
    .lede      { animation-delay: 0.26s; }
    .card-wrap { animation-delay: 0.34s; }

    /* The menu, animated declaratively. @starting-style supplies the
       entry frame; allow-discrete keeps display/overlay in the transition
       so the exit is not instant. */
    .menu {
      transition:
        translate 0.32s var(--ease),
        opacity 0.32s var(--ease),
        overlay 0.32s var(--ease) allow-discrete,
        display 0.32s var(--ease) allow-discrete;
      translate: 100% 0; opacity: 0;
    }
    .menu:popover-open { translate: 0 0; opacity: 1; }
    @starting-style {
      .menu:popover-open { translate: 100% 0; opacity: 0; }
    }
    .menu::backdrop {
      transition: opacity 0.32s var(--ease), overlay 0.32s var(--ease) allow-discrete,
                  display 0.32s var(--ease) allow-discrete;
      opacity: 0;
    }
    .menu:popover-open::backdrop { opacity: 1; }
    @starting-style { .menu:popover-open::backdrop { opacity: 0; } }

    /* Section entrances, driven by scroll position rather than by an
       IntersectionObserver. Guarded twice over: where view() is unsupported
       the elements never get an animation and stay visible, and the range
       ENDS inside the entry phase rather than in cover, so a section can
       never be stranded part-transparent because the document ran out of
       scroll beneath it. Content staying hidden is a correctness bug, not a
       missed flourish. */
    @supports (animation-timeline: view()) {
      .reveal {
        animation: rise-in linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 45%;
      }
    }

    .faq details[open] p { animation: fade-in 0.32s var(--ease) both; }
  }

  @keyframes rise {
    from { opacity: 0; translate: 0 18px; }
    to   { opacity: 1; translate: 0 0; }
  }
  @keyframes rise-in {
    from { opacity: 0; translate: 0 26px; }
    to   { opacity: 1; translate: 0 0; }
  }
  @keyframes fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
}
