/* ==========================================================================
   Bougie Booking — guest stylesheet.

   This is `docs/design/mockups/assets/venue.css`, ported. Two changes, and
   only two:

   1. Every `--v-*` token is now `--bb-*`, and the values left in `:root` are
      NEUTRAL defaults (monochrome, AA-safe). Marni's literal values did not
      disappear — they moved into that venue's `brand_json` and are emitted by
      `src/pages/theme.ts` into the one nonce-carrying `<style>` on the page.
      A venue that has set nothing renders in these defaults.
   2. The mockup-only `.mock` controls box and the yellow `.flag` copy tags are
      gone. They are not product UI (Plan 4 Global Constraints).

   Everything else — class names, selectors, numbers — is the approved mockup.
   Page-specific CSS still living in each mockup's `<style>` block (the hero,
   the map, the hold timer, the ticket) joins this file as its page is built:
   the CSP allows exactly ONE inline style per response, the theme block.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts. Served from /assets/fonts (Workers Static Assets) — absolute paths,
   because this stylesheet is loaded from guest pages at many depths.
   Inter is SIL OFL 1.1; see /assets/fonts/LICENSE-Inter.txt.

   Montserrat and Playfair Display are NOT shipped here: the files that were
   in this directory had no accompanying OFL licence text, which the SIL Open
   Font License requires for redistribution, so they were removed (Plan 4
   Task 1 fix round 1). `FONT_STACKS` in src/pages/theme.ts still lists
   "montserrat" and "playfair" as font keys — each stack's first family has no
   `@font-face` here, so the browser silently falls through to the next
   family in the stack (system-ui / Georgia). No guest page selects them
   today. Add the `@font-face` rules back, with both families' OFL.txt beside
   the files in /assets/fonts/, before any venue is given those font keys.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/inter-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* --- venue tokens: neutral defaults, overridden per venue by theme.ts --- */
  --bb-ink: #1a1a1a;
  --bb-accent: #1a1a1a;       /* fills only — a venue's accent may fail AA as text */
  --bb-accent-ink: #ffffff;   /* text ON the accent */
  --bb-accent-text: #1a1a1a;  /* the accent darkened enough to be TEXT on --bb-bg */
  --bb-support: #e4e4e1;
  --bb-bg: #f7f7f6;
  --bb-surface: #ffffff;
  --bb-dark: #1a1a1a;
  --bb-on-dark: #f7f7f6;
  --bb-muted: #5a5a5a;
  --bb-muted-on-dark: #c9c9c6;
  /* Rules are the ink at low opacity, so they follow whatever ink a venue set.
     A venue may still override them with a flat #rrggbb. */
  --bb-line: rgba(26, 26, 26, 0.16);
  --bb-line-strong: rgba(26, 26, 26, 0.45);
  /* NOT venue-settable (see src/lib/venues/brand.ts): a pale focus ring is a
     WCAG 2.4.7 failure, and a venue picking its own is exactly how one happens.
     It follows whatever ink the venue set, which is the darkest thing on the
     page by definition. */
  --bb-focus: var(--bb-ink);
  --bb-font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --bb-font-display: var(--bb-font-body);
  --bb-radius: 12px;
  --bb-radius-pill: 999px;

  /* --- platform tokens (same for every venue, not settable) --- */
  --ok: #1d6b45;
  --ok-bg: #e2f1e8;
  --warn: #8a5300;
  --warn-bg: #fdf0d8;
  --bad: #a1271b;
  --bad-bg: #fbe6e3;
  --tap: 44px;
  --shadow: 0 8px 28px rgba(26, 26, 26, 0.14);
}

/* The three tokens above are DERIVED from the venue's ink, which needs
   `color-mix`. An ordinary declaration can simply be written twice — the
   browser keeps the last one it understands — but a custom property cannot:
   `--bb-line` holds an unresolved token either way, so a browser without
   `color-mix` accepts the declaration, stores the text, and only discovers it
   is invalid at use time, where it becomes the guaranteed-invalid value rather
   than falling back to the earlier one. So the derivations go behind a feature
   query and the flat values above stand on iOS Safari before 16.2. A venue's
   own `#rrggbb` override is a later `<style>` element and still wins over both. */
@supports (color: color-mix(in srgb, red 50%, transparent)) {
  :root {
    --bb-line: color-mix(in srgb, var(--bb-ink) 16%, transparent);
    --bb-line-strong: color-mix(in srgb, var(--bb-ink) 45%, transparent);
    --shadow: 0 8px 28px color-mix(in srgb, var(--bb-ink) 14%, transparent);
  }
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--bb-font-body);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--bb-ink);
  background: var(--bb-bg);
  font-feature-settings: "ss01", "cv11";
}

img, svg { display: block; max-width: 100%; }
button, input, select { font: inherit; color: inherit; }
h1, h2, h3, p { margin: 0; }
a { color: inherit; }

/* Focus: a two-ring outline that survives on light, accent and dark grounds. */
:focus-visible {
  outline: 3px solid var(--bb-focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px #fff;
  border-radius: 6px;
}
.on-dark :focus-visible, .hero :focus-visible {
  outline-color: #fff;
  box-shadow: 0 0 0 6px var(--bb-ink);
}

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: 8px; top: -60px; z-index: 100;
  background: var(--bb-ink); color: var(--bb-on-dark);
  padding: 12px 16px; border-radius: 8px;
}
.skip:focus { top: 8px; }

/* ---------- page frame ---------- */
.page { max-width: 1040px; margin: 0 auto; padding: 0 16px 140px; }
.page--narrow { max-width: 560px; }

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 10px 16px;
  max-width: 1040px; margin: 0 auto;
}
/* Fixed height (matches the mockup's intrinsic 44px) plus a cap on width, so a
   venue logo of unknown aspect ratio reserves a bounded box before it loads
   instead of reflowing the topbar around it. `object-fit: contain` keeps a wide
   wordmark (Chez Bacchus is 400×52) in proportion inside that box instead of
   squashing it to the cap. */
.topbar__logo { height: 44px; width: auto; max-width: 200px; object-fit: contain; object-position: left center; display: block; }
.topbar__name { font-weight: 650; font-size: 1.0625rem; text-decoration: none; }
.topbar__back {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--tap); padding: 0 12px 0 6px;
  font-size: 0.9375rem; font-weight: 500; text-decoration: none;
  border-radius: var(--bb-radius-pill);
}
.topbar__back:hover { background: color-mix(in srgb, var(--bb-ink) 6%, transparent); }

/* step indicator: 3 guest steps + pay */
.steps {
  display: flex; gap: 6px; list-style: none; margin: 0; padding: 6px 16px 12px;
  max-width: 1040px; margin-inline: auto;
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--bb-muted);
}
.steps li { flex: 1; padding-top: 8px; border-top: 3px solid var(--bb-line); }
/* Current step: ink bar + an accent cap. An accent alone can be far too low
   contrast on the ground, so it is never the only signal. */
.steps li[aria-current="step"] { border-color: var(--bb-ink); color: var(--bb-ink); font-weight: 750; box-shadow: 0 -3px 0 var(--bb-accent); }
.steps li.done { border-color: var(--bb-ink); color: var(--bb-ink); }
/* Decoration only — the step's own text carries a visually-hidden "Completed:"
   prefix, so nothing depends on a generated glyph being announced. */
.steps li.done::before { content: "✓ "; }

/* A narrow page pins its column to 560px, and the mockups pin the topbar and
   the step indicator to that same column. Both sit OUTSIDE <main>, so they
   cannot be reached from `.page--narrow`; `page()` marks the document instead
   (src/pages/html.ts). Without this they ran to the wide 1040px while the
   content beneath them stopped at 560px. */
body.narrow .topbar, body.narrow .steps { max-width: 560px; }

/* ---------- type ---------- */
.eyebrow {
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
}
.h1 { font-family: var(--bb-font-display); font-size: clamp(2rem, 1.4rem + 3vw, 3.25rem); line-height: 1.02; font-weight: 700; letter-spacing: -0.02em; text-wrap: balance; }
.h2 { font-family: var(--bb-font-display); font-size: 1.375rem; line-height: 1.2; font-weight: 650; letter-spacing: -0.01em; }
.h3 { font-family: var(--bb-font-display); font-size: 1.0625rem; line-height: 1.3; font-weight: 650; }
.muted { color: var(--bb-muted); }
.small { font-size: 0.875rem; }
.tnum { font-variant-numeric: tabular-nums; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 52px; padding: 0 22px;
  border: 2px solid transparent; border-radius: var(--bb-radius-pill);
  font-weight: 650; font-size: 1rem; letter-spacing: 0.01em;
  text-decoration: none; cursor: pointer;
  transition: transform 120ms ease, background-color 160ms ease;
}
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--bb-accent); color: var(--bb-accent-ink); }
.btn--primary:hover { background: color-mix(in srgb, var(--bb-accent) 92%, #000); }
.btn--dark { background: var(--bb-ink); color: var(--bb-on-dark); }
.btn--dark:hover { background: color-mix(in srgb, var(--bb-ink) 88%, #fff); }
.btn--ghost { background: transparent; border-color: var(--bb-line-strong); }
.btn--ghost:hover { background: color-mix(in srgb, var(--bb-ink) 6%, transparent); }
.btn--block { width: 100%; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.btn--sm { min-height: var(--tap); padding: 0 16px; font-size: 0.9375rem; }

.linkbtn {
  background: none; border: 0; padding: 0; min-height: var(--tap);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer; font-weight: 550;
}

/* ---------- cards ---------- */
.card {
  background: var(--bb-surface); border: 1px solid var(--bb-line);
  border-radius: var(--bb-radius); padding: 18px;
}
.card + .card { margin-top: 14px; }
.stack > * + * { margin-top: 14px; }
.stack-lg > * + * { margin-top: 24px; }

/* ---------- price block (SB 478 pattern: all-in first, itemised beneath) ---------- */
.price { display: grid; gap: 4px; }
.price__allin { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.price__amount { font-size: 2.25rem; font-weight: 750; letter-spacing: -0.02em; line-height: 1; }
.price__unit { font-size: 1rem; font-weight: 550; }
.price__note { font-size: 0.875rem; color: var(--bb-muted); }
.lines { list-style: none; margin: 12px 0 0; padding: 12px 0 0; border-top: 1px dashed var(--bb-line-strong); display: grid; gap: 8px; font-size: 0.9375rem; }
.lines li { display: flex; justify-content: space-between; gap: 16px; }
/* The DIRECT last child only (the amount column). `span:last-child` also matched a
   `.sub` note nested inside the label span, so a long add-on note could never wrap and
   pushed the whole card past a phone's width (Mike, 2026-09-28). */
.lines li > span:last-child { font-variant-numeric: tabular-nums; white-space: nowrap; }
.lines .total { padding-top: 10px; border-top: 1px solid var(--bb-line); font-weight: 700; font-size: 1.0625rem; }
.lines .sub { color: var(--bb-muted); font-size: 0.8125rem; display: block; white-space: normal; }
.lines li > span:first-child { min-width: 0; }

/* ---------- notices ---------- */
.notice {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 16px; border-radius: var(--bb-radius);
  background: #e6eef3; border: 1px solid #9fb9c9; font-size: 0.9375rem;
}
.notice svg { flex: none; margin-top: 2px; }
.notice--ok { background: var(--ok-bg); border-color: #8fc3a5; }
.notice--warn { background: var(--warn-bg); border-color: #e3bd72; }
.notice--bad { background: var(--bad-bg); border-color: #e2a39c; }
.notice strong { display: block; }
/* Each error-summary entry is a standalone control, not a link inside a
   sentence — WCAG 2.5.8's inline exception does not apply — so every <a>
   gets the full 44px tap target as a block, not 18px of inline text. */
.errsum ul { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.errsum a { display: flex; align-items: center; min-height: var(--tap); color: inherit; font-weight: 600; }
.returned__h { margin: 0; }
.returned__body { margin-top: 6px; }
.returned__act { margin-top: 12px; }

/* ---------- stepper (party size / seats) ---------- */
.stepper { display: inline-flex; align-items: center; gap: 4px; background: var(--bb-surface); border: 1px solid var(--bb-line-strong); border-radius: var(--bb-radius-pill); padding: 4px; }
.stepper button {
  width: 48px; height: 48px; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--bb-bg); font-size: 1.5rem; line-height: 1; font-weight: 500;
  display: grid; place-items: center;
}
.stepper button:hover:not([disabled]) { background: var(--bb-support); }
.stepper button[disabled] { opacity: 0.35; cursor: not-allowed; }
.stepper output { min-width: 56px; text-align: center; font-size: 1.375rem; font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---------- sticky action bar (thumb zone) ---------- */
.actionbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  background: var(--bb-surface); border-top: 1px solid var(--bb-line);
  box-shadow: 0 -6px 24px color-mix(in srgb, var(--bb-ink) 10%, transparent);
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
}
.actionbar__inner { max-width: 1008px; margin: 0 auto; display: flex; align-items: center; gap: 14px; }
.actionbar__sum { flex: 1; min-width: 0; line-height: 1.25; }
.actionbar__sum strong { display: block; font-size: 1.0625rem; }
.actionbar__sum span { font-size: 0.8125rem; color: var(--bb-muted); }
.actionbar .btn { flex: none; }
/* Turnstile's mount (Plan 7 Task 4): empty unless Cloudflare needs the guest to click. */
.turnstile { display: flex; justify-content: center; }

/* ---------- powered-by ---------- */
.powered {
  margin: 40px auto 0; text-align: center; font-size: 0.75rem; color: var(--bb-muted);
}
.powered b { font-weight: 650; color: var(--bb-ink); letter-spacing: 0.01em; }
/* The platform's Terms · Privacy · Support, under "Powered by" on every guest page. */
.legallinks {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 0;
  margin: 6px auto 0; font-size: 0.75rem;
}
.legallinks a { color: var(--bb-muted); padding: 6px 10px; text-underline-offset: 2px; }
.legallinks a + a { border-left: 1px solid var(--bb-line); }
/* Links inside the policy checkbox label and the privacy note under it. */
.check a, .legalnote a { color: var(--bb-ink); text-decoration: underline; text-underline-offset: 2px; }
.legalnote { margin: 4px 2px 0; }

/* ---------- forms ---------- */
.field { display: grid; gap: 6px; }
.field label { font-weight: 600; font-size: 0.9375rem; }
.field .hint { font-size: 0.8125rem; color: var(--bb-muted); }
.field input {
  min-height: 52px; padding: 0 14px; font-size: 1rem; /* 16px stops iOS zoom */
  background: var(--bb-surface); border: 1.5px solid var(--bb-line-strong); border-radius: 10px; width: 100%;
}
.field input:hover { border-color: var(--bb-ink); }
.field input[aria-invalid="true"] { border-color: var(--bad); background: #fffafa; }
.field .err { color: var(--bad); font-size: 0.875rem; font-weight: 550; display: none; }
.field input[aria-invalid="true"] ~ .err { display: block; }

/* Plan 13 — the discount code field */
.discount__row { display: flex; gap: 8px; align-items: stretch; }
.discount__row input { flex: 1 1 auto; text-transform: uppercase; }
.discount__row .btn { flex: 0 0 auto; min-height: var(--tap); }
/* Its input is a grandchild, not a sibling, of its error, so the rule above
   can never reach it: this one is shown and hidden by the island's `hidden`
   attribute instead. */
.field.discount .err:not([hidden]) { display: block; }
/* Plan 13 moved the ONE Turnstile mount out of the expired panel, because an
   Apply needs the widget while the hold is still live (details-page.ts). As a
   child of `.details__stack` it would otherwise take the stack's own 14px top
   margin while showing nothing at all: Turnstile leaves its hidden input in
   the container even on a visit it never challenges, so `:empty` cannot be
   the test. Zero here; the form below keeps its own 14px, so an idle mount
   costs no space, and a widget Cloudflare really renders grows the box
   downwards from the panel above it. */
.details__stack > .turnstile { margin-top: 0; }

.check { display: grid; grid-template-columns: 28px 1fr; gap: 12px; align-items: start; padding: 12px; border-radius: 10px; border: 1.5px solid var(--bb-line); background: var(--bb-surface); cursor: pointer; min-height: var(--tap); }
.check input { width: 26px; height: 26px; margin: 1px 0 0; accent-color: var(--bb-ink); cursor: pointer; }
/* The policy checkbox's label, its policy text and its error are three
   siblings inside `.checkgroup` (see src/pages/details-page.ts: inside the
   label they became part of the checkbox's accessible name). The invalid state
   therefore lives on the GROUP and reaches the label from there. */
.checkgroup.invalid .check { border-color: var(--bad); }
.check .req { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--bb-muted); display: block; margin-bottom: 2px; }

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

/* ==========================================================================
   Page CSS that lived in each mockup's own <style> block. It moves here as its
   page is built: the CSP allows exactly ONE inline style per response and that
   is the per-venue theme. Marni's literals in those blocks (the hero's coral
   and blue washes, the pill hairline) are derived from the venue tokens with
   color-mix, the same way Task 1 handled the hovers.
   ========================================================================== */

/* ---------- event page (01-event.html) ---------- */
.hero {
  background:
    radial-gradient(90% 90% at 95% 0%, color-mix(in srgb, var(--bb-accent) 28%, transparent), transparent 60%),
    radial-gradient(60% 70% at 0% 120%, color-mix(in srgb, var(--bb-support) 18%, transparent), transparent 70%),
    var(--bb-dark);
  color: var(--bb-on-dark);
}
.hero__inner { max-width: 1040px; margin: 0 auto; padding: 28px 16px 32px; }
.hero .eyebrow { color: var(--bb-accent); margin-bottom: 12px; }
/* The state pages put the hero over a 560px column. */
.hero--narrow .hero__inner { max-width: 560px; }

.pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; padding: 0; list-style: none; }
.pills li {
  font-size: 0.8125rem; font-weight: 550; padding: 6px 12px;
  border: 1px solid color-mix(in srgb, var(--bb-on-dark) 35%, transparent);
  border-radius: var(--bb-radius-pill);
}
.pills li.free { background: var(--bb-on-dark); color: var(--bb-ink); border-color: var(--bb-on-dark); }

.layout { display: grid; gap: 20px; margin-top: 20px; }
@media (min-width: 860px) {
  .layout { grid-template-columns: 1fr 400px; align-items: start; gap: 40px; margin-top: 36px; }
  .book { position: sticky; top: 16px; order: 2; }
}

.book .price { margin-top: 14px; }
.book__notice { margin-top: 16px; }
.book__cta { margin-top: 16px; }
.book__reassure { margin-top: 10px; text-align: center; }

.party {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--bb-line);
}
.party label, .party .lab { font-weight: 650; }
/* The no-JavaScript control. The island hides it and puts − / <output> / + in
   its place; it keeps the name, so it is still what submits either way. */
.stepper__input {
  width: 84px; min-height: 48px; text-align: center;
  font-size: 1.375rem; font-weight: 700;
  border: 0; background: transparent;
}

details.why { margin-top: 12px; font-size: 0.875rem; }
details.why summary {
  cursor: pointer; min-height: var(--tap); display: inline-flex; align-items: center;
  font-weight: 600; text-decoration: underline; text-underline-offset: 3px;
}
.why__body { margin-top: 6px; }

/* The "your total" list is a single row directly under the stepper, so it
   carries neither of the price block's dividers. */
.lines--total { margin-top: 14px; padding-top: 0; border-top: 0; }
.lines--total .total { padding-top: 0; border-top: 0; }
.lines .sub--plain { font-weight: 450; }

.facts { list-style: none; padding: 0; margin: 12px 0 0; display: grid; gap: 14px; }
.facts li { display: grid; grid-template-columns: 28px 1fr; gap: 12px; }
.facts svg { margin-top: 2px; color: var(--bb-accent-text); }

.how { counter-reset: how; list-style: none; padding: 0; margin: 12px 0 0; display: grid; gap: 12px; }
.how li { counter-increment: how; display: grid; grid-template-columns: 32px 1fr; gap: 12px; align-items: start; }
.how li::before {
  content: counter(how); width: 32px; height: 32px; border-radius: 50%;
  background: var(--bb-support); display: grid; place-items: center;
  font-weight: 700; font-size: 0.875rem;
}

/* Venue-entered. The description keeps its line breaks here rather than by
   being turned into markup. */
.event__image { width: 100%; border-radius: var(--bb-radius); margin-top: 12px; }
.event__blurb { margin-top: 10px; white-space: pre-line; }

/* ---------- sold out (states/sold-out.html) ---------- */
.so { text-align: center; padding: 30px 18px; }
.so svg { margin: 0 auto 12px; color: var(--bb-accent-text); }
.so__body { margin-top: 8px; }
.so__note { margin-top: 14px; }
.times { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 18px; }
/* The mockup showed doors AND music; only the show time is data we hold. */
.times--single { grid-template-columns: 1fr; }
.times div { background: var(--bb-bg); border-radius: 12px; padding: 14px 8px; }
.times b { display: block; font-size: 1.5rem; font-weight: 750; }
.times span {
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--bb-muted);
}

/* ---------- show cancelled (states/cancelled.html) ---------- */
.banner { background: var(--bb-ink); color: var(--bb-on-dark); }
.banner__inner { max-width: 560px; margin: 0 auto; padding: 26px 16px 30px; }
.banner .eyebrow { color: var(--bb-accent); }
.banner s { opacity: 0.75; }
.banner__title { font-size: 2rem; margin-top: 8px; }
.tag {
  display: inline-block; margin-top: 12px;
  font-size: 0.75rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  background: var(--bb-accent); color: var(--bb-accent-ink);
  padding: 6px 10px; border-radius: 6px;
}

/* ---------- state pages and the venue index ---------- */
.page--state { margin-top: 20px; }
.card__body { margin-top: 8px; }
.card__action { margin-top: 16px; }
.center { text-align: center; }

.index__title { margin-top: 20px; font-size: clamp(1.75rem, 1.4rem + 2vw, 2.5rem); }
.index__empty { margin-top: 16px; }
.cards { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 14px; }
.cardlink { display: block; text-decoration: none; }
.cardlink:hover { border-color: var(--bb-line-strong); }
.cardlink .eyebrow { color: var(--bb-accent-text); }
.cardlink__title { margin-top: 4px; }
.cardlink__price { margin-top: 6px; color: var(--bb-muted); }

/* ---------- the picker (02-picker.html) ---------- */
.head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-top: 4px; }
.head__meta { font-size: 0.875rem; color: var(--bb-muted); }
.head .stepper button { width: 44px; height: 44px; }
.head .stepper output { min-width: 84px; font-size: 1rem; }

/* The party control is a real GET form; the island hides the field and the
   Update button and puts − / <output> / + in their place. */
.partyform { display: flex; align-items: center; gap: 8px; }

 /* `.notice` is a flex row for its icon; this one has no icon and its lines
    are sentences, so it stacks. */
.pick__error { display: block; margin-top: 14px; }
.pick__error p + p { margin-top: 6px; }
.pick__error a { font-weight: 650; }
.pick__nojs { margin-top: 12px; }

.seg {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px; padding: 4px; margin-top: 14px;
  background: color-mix(in srgb, var(--bb-ink) 10%, var(--bb-bg)); border-radius: var(--bb-radius-pill);
}
.seg button {
  min-height: var(--tap); border: 0; border-radius: var(--bb-radius-pill); background: transparent;
  font-weight: 650; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
}
.seg button[aria-pressed="true"] {
  background: var(--bb-surface);
  box-shadow: 0 1px 4px color-mix(in srgb, var(--bb-ink) 18%, transparent);
}

.cols { display: grid; gap: 16px; margin-top: 14px; }
@media (min-width: 860px) {
  .cols { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); align-items: start; gap: 28px; }
  /* Both panes at once — but only once the island has drawn the map, or a
     browser with JavaScript off would be shown an empty frame. */
  #tables-ui.ready .seg { display: none; }
  #tables-ui.ready .pane[hidden] { display: block !important; }
}

/* ---------- map ---------- */
.mapwrap {
  position: relative; background: var(--bb-surface); border: 1px solid var(--bb-line);
  border-radius: var(--bb-radius); overflow: hidden;
}
/* No aspect-ratio: the SVG's own viewBox — which is the LAYOUT's size, per
   venue — gives it its intrinsic ratio, and a per-layout ratio could only be
   written as an inline style, which the CSP does not allow. */
#map { width: 100%; height: auto; touch-action: pan-y; cursor: grab; user-select: none; -webkit-user-select: none; }
#map.zoomed { touch-action: none; }
#map.dragging { cursor: grabbing; }
.map__ground { fill: var(--bb-surface); }
.map__glow { fill: url(#glow); }
#hatch .pat-bg { fill: color-mix(in srgb, var(--bb-ink) 12%, var(--bb-bg)); }
#hatch .pat-line { fill: color-mix(in srgb, var(--bb-ink) 28%, var(--bb-bg)); }
#dots .pat-walk-bg { fill: var(--bb-support); }
#dots .pat-walk-dot { fill: color-mix(in srgb, var(--bb-support) 45%, #000); }
#glow .glow-in { stop-color: var(--bb-accent); }
#glow .glow-out { stop-color: var(--bb-accent); }
.stage__box { fill: var(--bb-dark); }
.stage__text {
  fill: var(--bb-on-dark); font-family: var(--bb-font-body); text-anchor: middle;
  font-size: 26px; font-weight: 700; letter-spacing: 6px;
}
#scenery { pointer-events: none; }
.scenery__shape { fill: var(--bb-scenery, rgba(0, 0, 0, .05)); stroke: rgba(0, 0, 0, .14); stroke-width: 2; }
.scenery__label {
  font-size: 20px; text-anchor: middle; dominant-baseline: middle;
  fill: rgba(0, 0, 0, .45); letter-spacing: .08em; text-transform: uppercase;
}

.maptools { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 8px; }
.zoom { display: flex; gap: 6px; }
.zoom button {
  width: 48px; height: 44px; border-radius: 10px; border: 1px solid var(--bb-line-strong);
  background: var(--bb-surface); font-size: 1.375rem; font-weight: 600; cursor: pointer; display: grid; place-items: center;
}
.zoom button[disabled] { opacity: 0.4; cursor: not-allowed; }
.hint { display: inline-flex; gap: 8px; align-items: center; font-size: 0.8125rem; font-weight: 550; color: var(--bb-muted); }
.hint svg { flex: none; }

/* A table is a real button: focusable, named, and never distinguished by
   colour alone — every state also differs by pattern and by a word. */
.t { cursor: pointer; }
.t[aria-disabled="true"] { cursor: not-allowed; }
.t .shape { stroke: var(--bb-ink); stroke-width: 3; transition: fill 300ms ease; }
.t .chair { fill: color-mix(in srgb, var(--bb-ink) 22%, var(--bb-bg)); transition: fill 300ms ease; }
.t text { font-family: var(--bb-font-body); text-anchor: middle; pointer-events: none; fill: var(--bb-ink); }
.t .num { font-size: 34px; font-weight: 750; }
.t .cap { font-size: 21px; font-weight: 600; }
.t--fit .shape { fill: var(--bb-accent); }
.t--fit .chair { fill: var(--bb-ink); }
.t--fit:hover .shape { fill: color-mix(in srgb, var(--bb-accent) 92%, #000); }
.t--nofit .shape {
  fill: var(--bb-bg); stroke-dasharray: 8 7; stroke-width: 2.5;
  stroke: color-mix(in srgb, var(--bb-ink) 65%, var(--bb-bg));
}
.t--nofit text { fill: var(--bb-muted); }
.t--booked .shape, .t--held .shape, .t--blocked .shape {
  fill: url(#hatch); stroke: color-mix(in srgb, var(--bb-ink) 65%, var(--bb-bg)); stroke-width: 2.5;
}
.t--booked text, .t--held text, .t--blocked text {
  fill: color-mix(in srgb, var(--bb-ink) 80%, var(--bb-bg));
  paint-order: stroke; stroke: color-mix(in srgb, var(--bb-ink) 12%, var(--bb-bg));
  stroke-width: 7px; stroke-linejoin: round;
}
.t--booked .num, .t--held .num, .t--blocked .num { text-decoration: line-through; }
.t--walkin .shape { fill: url(#dots); stroke: color-mix(in srgb, var(--bb-support) 45%, #000); stroke-width: 2.5; }
.t--walkin text { paint-order: stroke; stroke: var(--bb-support); stroke-width: 7px; stroke-linejoin: round; }
.t--walkin .chair { fill: color-mix(in srgb, var(--bb-support) 30%, #000); }
.t--selected .shape { fill: var(--bb-ink); }
.t--selected text { fill: var(--bb-on-dark); }
.t.t--selected .ring { stroke: var(--bb-ink); stroke-width: 4; fill: none; stroke-dasharray: none; opacity: 1; }
.t .ring { opacity: 0; }
.t:focus-visible { outline: none; box-shadow: none; }
.t:focus-visible .ring { opacity: 1; stroke: var(--bb-focus); stroke-width: 5; fill: none; stroke-dasharray: 10 6; }
.t--flash .shape { animation: flash 900ms ease 2; }
@keyframes flash { 50% { fill: var(--warn-bg); } }

.legend { display: flex; flex-wrap: wrap; gap: 8px 16px; list-style: none; margin: 12px 0 0; padding: 0; font-size: 0.8125rem; }
.legend li { display: inline-flex; align-items: center; gap: 8px; }
.sw { width: 22px; height: 22px; border-radius: 6px; border: 2px solid var(--bb-ink); flex: none; }
.sw--fit { background: var(--bb-accent); }
.sw--nofit { background: var(--bb-bg); border: 2px dashed color-mix(in srgb, var(--bb-ink) 65%, var(--bb-bg)); }
.sw--booked {
  background: repeating-linear-gradient(45deg,
    color-mix(in srgb, var(--bb-ink) 12%, var(--bb-bg)) 0 4px,
    color-mix(in srgb, var(--bb-ink) 28%, var(--bb-bg)) 4px 6px);
  border-color: color-mix(in srgb, var(--bb-ink) 65%, var(--bb-bg));
}
.sw--walkin {
  background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--bb-support) 45%, #000) 1.5px, transparent 2px) 0 0 / 7px 7px, var(--bb-support);
  border-color: color-mix(in srgb, var(--bb-support) 45%, #000);
}
.sw--sel { background: var(--bb-ink); }

/* ---------- list ---------- */
.tlist { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.row {
  width: 100%; text-align: left; display: grid; grid-template-columns: 52px 1fr auto; gap: 12px; align-items: center;
  min-height: 68px; padding: 10px 14px 10px 10px; border-radius: var(--bb-radius);
  background: var(--bb-surface); border: 1.5px solid var(--bb-line); cursor: pointer;
}
.row:hover:not([aria-disabled="true"]) { border-color: var(--bb-ink); }
.row__n {
  width: 52px; height: 52px; border-radius: 12px; display: grid; place-items: center;
  font-size: 1.25rem; font-weight: 750; background: var(--bb-accent); border: 2px solid var(--bb-ink);
  color: var(--bb-accent-ink);
}
.row__t { font-weight: 650; line-height: 1.25; }
.row__s { font-size: 0.8125rem; color: var(--bb-muted); display: block; font-weight: 450; }
.row__p { text-align: right; font-weight: 700; line-height: 1.25; }
.row__p small { display: block; font-weight: 500; color: var(--bb-muted); font-size: 0.75rem; }
.row[aria-pressed="true"] {
  border-color: var(--bb-ink); border-width: 2.5px;
  background: color-mix(in srgb, var(--bb-accent) 8%, var(--bb-surface));
}
.row[aria-pressed="true"] .row__n { background: var(--bb-ink); color: var(--bb-on-dark); }
.row[aria-disabled="true"] { cursor: not-allowed; background: transparent; }
.row[aria-disabled="true"] .row__n {
  background: repeating-linear-gradient(45deg,
    color-mix(in srgb, var(--bb-ink) 12%, var(--bb-bg)) 0 4px,
    color-mix(in srgb, var(--bb-ink) 28%, var(--bb-bg)) 4px 6px);
  border-color: color-mix(in srgb, var(--bb-ink) 65%, var(--bb-bg));
  color: color-mix(in srgb, var(--bb-ink) 80%, var(--bb-bg)); text-decoration: line-through;
}
.row.walkin[aria-disabled="true"] .row__n {
  background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--bb-support) 45%, #000) 1.5px, transparent 2px) 0 0 / 7px 7px, var(--bb-support);
  border-color: color-mix(in srgb, var(--bb-support) 45%, #000);
  text-decoration: none; color: var(--bb-ink);
}
.row.nofit[aria-disabled="true"] .row__n {
  background: var(--bb-bg); border: 2px dashed color-mix(in srgb, var(--bb-ink) 65%, var(--bb-bg));
  color: var(--bb-ink); text-decoration: none;
}
.chip {
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 4px 8px; border-radius: 6px; white-space: nowrap;
  background: color-mix(in srgb, var(--bb-ink) 10%, var(--bb-bg)); color: var(--bb-ink);
}
.listhead {
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--bb-muted); margin: 14px 0 8px;
}

/* ---------- toast (the polite live region) ---------- */
.toast {
  position: fixed; left: 16px; right: 16px; bottom: 104px; z-index: 60; margin: 0 auto; max-width: 480px;
  background: var(--bb-ink); color: var(--bb-on-dark); padding: 14px 16px; border-radius: 12px;
  box-shadow: var(--shadow); font-size: 0.9375rem; display: flex; gap: 10px; align-items: center;
  transform: translateY(20px); opacity: 0; transition: all 260ms ease; pointer-events: none;
}
.toast.show { transform: none; opacity: 1; }
.live {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: color-mix(in srgb, var(--ok) 55%, #fff);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 55%, transparent); animation: pulse 2s infinite;
}
@keyframes pulse {
  70% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--ok) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 0%, transparent); }
}
.livebar { display: inline-flex; align-items: center; gap: 8px; font-size: 0.8125rem; color: var(--bb-muted); margin-top: 10px; }
.livebar .live { background: var(--ok); animation: none; box-shadow: none; }
.livebar--center { justify-content: center; width: 100%; }

/* ---------- seat mode ---------- */
.seats { text-align: center; padding: 28px 18px; }
.seats__note { margin-top: 4px; }
.seats__control { margin-top: 20px; display: flex; justify-content: center; }
.seats .stepper button { width: 60px; height: 60px; font-size: 1.75rem; }
.seats .stepper output { min-width: 88px; font-size: 2.25rem; }
.seats .stepper__input { width: 100px; font-size: 2rem; }

/* Plan 10 — add-on steppers on the picker */
.addons__list { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 12px; }
/* Text first, stepper after; on a phone the stepper wraps under the text rather
   than squeezing the name and note into a sliver (checked at 375px). */
.addon { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 12px; }
.addon__text { flex: 1 1 12rem; min-width: 0; }
.addon__stepper { flex: 0 0 auto; margin-left: auto; }
.addon__label { font-weight: 650; }
.addon__note, .addon__price { margin: 2px 0 0; }
.addon__stepper output { min-width: 4.5em; text-align: center; }
/* The event page's "Optional extras" list sits under the per-person total. */
.addons { margin-top: 16px; }
.addons__h { margin: 0 0 2px; }
.addons__hint { margin: 0 0 6px; }
.lines--addons .sub { display: block; font-size: 0.875em; color: var(--bb-muted); }
.meter { height: 10px; border-radius: var(--bb-radius-pill); overflow: hidden; margin: 18px auto 8px; max-width: 320px; width: 100%; display: block; }
.meter__track { fill: color-mix(in srgb, var(--bb-ink) 10%, var(--bb-bg)); }
.meter__sold { fill: color-mix(in srgb, var(--bb-ink) 45%, var(--bb-bg)); }
.meter__mine { fill: var(--bb-accent); }
.meter__walk { fill: var(--bb-support); }

/* ---------- sold out while browsing ---------- */
.soldout { text-align: center; padding: 36px 20px; }
.soldout svg { margin: 0 auto 14px; color: var(--bb-accent-text); }
.soldout .so__body { margin-top: 8px; }
.soldout .so__note { margin-top: 12px; }
.soldout .so__cta { margin-top: 18px; }

/* ---------- details page (03-details.html, states/declined.html) ---------- */

/* The hold bar: always visible, never alarming until it has to be.
   The width of .hold__fill is set by details.js through the CSSOM — a `style`
   attribute would be a second inline style and the CSP allows exactly one.
   The global prefers-reduced-motion rule above already stops its transition. */
.hold { position: sticky; top: 0; z-index: 50; background: var(--bb-ink); color: var(--bb-on-dark); }
.hold__inner {
  max-width: 560px; margin: 0 auto; padding: 10px 16px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.hold__label { font-size: 0.9375rem; line-height: 1.25; }
.hold__label small { display: block; color: var(--bb-muted-on-dark); font-size: 0.75rem; }
.hold__time {
  font-size: 1.625rem; font-weight: 750; font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em; min-width: 4.2ch; text-align: right;
}
.hold__track { height: 4px; background: rgba(244, 239, 233, 0.2); }
.hold__fill { height: 100%; width: 100%; background: var(--bb-accent); transition: width 1s linear; }
/* Platform status colours, like --ok / --warn / --bad: a venue must not be able
   to make "your hold is about to run out" look comfortable. The mockup's own
   values. */
.hold.low { background: #6e2a1c; }
.hold.low .hold__fill { background: #fff; }
.hold.over { background: #4a4446; }
.hold.over .hold__fill { width: 0; }
.hold :focus-visible { outline-color: #fff; box-shadow: 0 0 0 6px var(--bb-ink); }

.details__stack { margin-top: 14px; }

.summary { display: grid; grid-template-columns: 56px 1fr; gap: 14px; align-items: center; }
.summary__n {
  width: 56px; height: 56px; border-radius: 14px;
  background: var(--bb-ink); color: var(--bb-on-dark);
  display: grid; place-items: center; font-size: 1.375rem; font-weight: 750;
}

.expired { text-align: center; padding: 26px 18px; border: 2px solid var(--bb-ink); }
.expired svg { margin: 0 auto 10px; }
/* Focus is sent here programmatically so the panel is announced; the ring would
   be a rectangle round the whole card and says nothing extra. */
.expired:focus, .expired:focus-visible { outline: none; box-shadow: none; }
.expired__body { margin-top: 6px; }
.expired__act { margin-top: 16px; }
.expired__act + .expired__act { margin-top: 10px; }
.expired__note { margin-top: 10px; }

.beforepay { border: 0; padding: 0; margin: 26px 0 0; }
.beforepay__legend { padding: 0; margin-bottom: 10px; }
/* The venue's own policy text, as plain text: `pre-line` keeps the line breaks
   they typed without any markup being interpreted. The mockup's flat #efe9e2
   becomes a tint of the venue's ink so it follows whatever palette is set. */
.policy {
  display: block; font-size: 0.875rem; margin-top: 8px; padding: 12px 14px;
  border-radius: 10px; white-space: pre-line;
  background: color-mix(in srgb, var(--bb-ink) 8%, var(--bb-bg));
}
.policy__err { display: none; margin-top: 6px; }
.checkgroup.invalid .policy__err { display: block; }

.details__error { margin-top: 12px; }
.details__error p + p { margin-top: 6px; }
.details__error a { font-weight: 650; }
.details__nojs { margin-top: 12px; }

.paynote {
  display: flex; gap: 8px; align-items: center; justify-content: center;
  font-size: 0.8125rem; color: var(--bb-muted); margin-top: 10px; text-align: center;
}
.paynote svg { flex: none; }

/* ---------- confirmation + read-only manage (04-confirmation.html, 04b-manage.html) ---------- */

/* The mockup's dark "done" header, with its radial accent glow built from the
   venue's own accent rather than Marni's coral. It replaces the topbar, so the
   venue lockup sits inside it.

   Scoped to `header` ON PURPOSE, and asserted by test/architecture.test.ts. The
   step indicator marks a finished step `<li class="done">`, so an unscoped
   `.done` painted the details page's completed step in `--bb-on-dark` over
   `--bb-dark` — the same colour on itself, 1.00:1 — and centred it. The two
   uses of the word are unrelated elements; the element name is what keeps them
   apart. */
header.done {
  background:
    radial-gradient(90% 120% at 95% 0%, color-mix(in srgb, var(--bb-accent) 28%, transparent), transparent 60%),
    var(--bb-dark);
  color: var(--bb-on-dark);
  text-align: center;
}
.done__inner { max-width: 560px; margin: 0 auto; padding: 28px 16px 84px; }
.done__lockup { margin-bottom: 18px; }
/* The mockup inverts Marni's lockup to white over the dark ground exactly as
   marnisoc.com's own nav does. Here rather than as an inline `style`: the CSP
   allows one inline style per response and that one is the venue theme. */
.done__lockup .topbar__logo { filter: brightness(0) invert(1); margin: 0 auto; object-position: center; }
.done__lockup .topbar__name { color: var(--bb-on-dark); }
.done__tick {
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--bb-accent); color: var(--bb-accent-ink);
  display: grid; place-items: center; margin: 0 auto 14px;
}
.done__h { font-size: 2rem; }
.done__h:focus, .done__h:focus-visible { outline: none; }
.done__sub { color: var(--bb-muted-on-dark); margin-top: 8px; }
.done__sub strong { color: var(--bb-on-dark); }

/* The ticket rides up over the header's padding, with two punched notches. */
.ticket {
  margin-top: -60px; position: relative;
  background: var(--bb-surface); border-radius: 18px; box-shadow: var(--shadow); overflow: hidden;
}
.ticket:focus, .ticket:focus-visible { outline: none; }
.ticket__top { padding: 22px 18px 18px; text-align: center; }
.ticket__note { margin-top: 8px; }
.code {
  display: inline-flex; align-items: center; gap: 10px; margin-top: 6px;
  padding: 6px 8px 6px 16px; border-radius: 12px;
  border: 2px dashed var(--bb-line-strong); background: var(--bb-bg);
  min-height: var(--tap); font: inherit; color: inherit;
}
/* Only the JavaScript-upgraded version is interactive; the server renders a
   plain <p class="code"> so the code is readable with scripting off. */
.code--button { cursor: pointer; }
.code b { font-size: 2rem; font-weight: 800; letter-spacing: 0.14em; }
.code__tag {
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  background: var(--bb-ink); color: var(--bb-on-dark); padding: 8px 10px; border-radius: 8px;
}
.ticket__cut { position: relative; border-top: 2px dashed var(--bb-line-strong); }
.ticket__cut::before, .ticket__cut::after {
  content: ""; position: absolute; top: -12px; width: 24px; height: 24px;
  border-radius: 50%; background: var(--bb-bg);
}
.ticket__cut::before { left: -12px; }
.ticket__cut::after { right: -12px; }

/* The ticket's fact grid. `.facts` on the event page is a single-column icon
   list, so this variant resets it rather than inheriting a shape it is not. */
.facts--ticket {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px 12px; padding: 18px; margin: 0;
}
.facts--ticket div { display: block; min-width: 0; }
.facts--ticket dt {
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--bb-muted);
}
.facts--ticket dd { margin: 2px 0 0; font-weight: 650; font-size: 1.0625rem; line-height: 1.25; }
.facts--ticket .wide { grid-column: 1 / -1; }
.facts__note { display: block; font-weight: 450; }
.prepaid { margin: 0 18px 18px; }

.confirm__stack { margin-top: 16px; }
.acts { display: grid; gap: 10px; }
@media (min-width: 480px) {
  .acts { grid-template-columns: 1fr 1fr; }
  /* The mockup's second button ("Directions") is not rendered — `venues` has no
     address column — so the row has one child, which would otherwise sit in a
     half-width left column with a hole beside it. */
  .acts > :only-child { grid-column: 1 / -1; }
}
.lines--paid { border-top: 0; padding-top: 0; }
.paid__note { margin-top: 10px; }
.manage__name { margin-top: 4px; }
.manage__policy { margin-top: 6px; }
.manage__contact { margin-top: 10px; }
.manage__bearer { margin-top: 10px; }
/* The name change and the cancel (04b-manage.html, Plan 3b Task 7). */
.manage__lede { margin-top: 4px; }
.manage__form { margin-top: 12px; }
.manage__start { margin-top: 12px; }
.manage__panel { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--bb-line); }
.manage__lines { border-top: 0; padding-top: 0; margin-top: 0; }
.manage__go { margin-top: 12px; }
.manage__keep { margin-top: 10px; }
.manage__say:focus, .manage__say:focus-visible { outline: none; }
.btn--danger { background: var(--bad); color: #fff; }
.btn--danger:hover { background: #861f15; }

/* Waiting for the webhook, and the states a manage link can still open. */
.confirming { text-align: center; padding: 30px 18px; margin-top: 20px; }
.confirming:focus, .confirming:focus-visible { outline: none; }
.confirming__spin { color: var(--bb-accent-text); display: grid; place-items: center; margin-bottom: 10px; }
.confirming__code { margin-top: 12px; }
.confirming__nojs { margin-top: 12px; }
.confirming__slow { margin-top: 14px; }
