/* RojoBingo public marketing + directory site — design tokens + vocabulary
   per docs/ui/03-control-panel-admin-marketing.md §4.1. Dark felt table by
   default (the site sells the table), Rojo-red primary, GOLD RESERVED FOR
   MONEY/PRIZES/WINS ONLY (never decorative). Icons are inline SVG only — no
   icon fonts, no external requests, no external font/CDN loads (CSP-safe). */
:root {
  color-scheme: dark;
  --bg: #1a0d11;             /* felt-7 — the table, not a generic dark navy  */
  --bg-soft: #241419;        /* felt-6                                      */
  --panel: rgba(255, 255, 255, 0.03);
  --panel-2: linear-gradient(160deg, rgba(72, 35, 44, .55), rgba(36, 20, 25, .55));
  --border: rgba(255, 255, 255, 0.10);
  --border-strong: rgba(255, 255, 255, 0.16);
  --text: #f4ecee;
  --muted: #bda8ae;
  --muted-2: #8d767d;
  --brand: #ef4444;          /* rojo 5 */
  --brand-2: #f87171;        /* rojo 4 */
  --brand-glow: rgba(239, 68, 68, 0.38);
  --brand-ink: #ffffff;      /* text placed on top of a solid --brand fill  */
  --gold: #fbbf24;           /* PRIZE ACCENT ONLY — never decorative        */
  --gold-2: #fcd34d;
  --gold-glow: rgba(245, 158, 11, 0.32);
  --accent: #38bdf8;         /* "live" indicator — matches app LivePill     */
  --danger: #f87171;
  --paper: #ffffff;          /* card-paper band sections                    */
  --radius: 18px;
  --maxw: 1120px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background:
    radial-gradient(1200px 620px at 50% -8%, #3d1016 0%, rgba(61, 16, 22, 0) 60%),
    radial-gradient(900px 500px at 85% 8%, rgba(251, 191, 36, .06), transparent 55%),
    var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
a { color: inherit; }
img, svg { display: block; }
.tnum { font-variant-numeric: tabular-nums; }
.gold { color: var(--gold); }
/* Credit coin — gold token marking credit amounts (replaces the old ✦ glyph).
   Inline SVG data-URI: no extra request, CSP-safe. */
.coin { display:inline-block; width:.92em; height:.92em; margin-right:.14em; vertical-align:-.13em; background:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="%23fbbf24" stroke="%23b45309" stroke-width="1.6"/><text x="12" y="16.5" text-anchor="middle" font-family="Arial,Helvetica,sans-serif" font-size="14" font-weight="700" fill="%23b45309">C</text></svg>') center/contain no-repeat; }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }
h1, h2, h3 { letter-spacing: -0.02em; line-height: 1.1; margin: 0; }
/* Icon inline with heading — shared row layout so a tile's icon sits BESIDE
   its heading on one line instead of stacked above it (owner call: no more
   "icon block above, text below"). Icon boxes themselves shrink to ~28-32px
   at each call site (.feat-icon/.pc-icon/.aud-icon/.at-glyph below); this
   class just rules the row. Decorative icons stay aria-hidden in markup. */
.icon-head { display: flex; align-items: center; gap: 10px; }
.icon-head h2, .icon-head h3, .icon-head h4 { margin: 0; }
.section { padding: 96px 0; position: relative; }
.section.tight { padding: 56px 0; }
.section-head { max-width: 90%; margin: 0 auto 56px; text-align: center; }
.section-head h2 { font-size: clamp(28px, 4vw, 40px); font-weight: 800; }
.section-head p { color: var(--muted); font-size: 17px; margin: 16px 0 0; }
.section-alt { background: linear-gradient(180deg, rgba(255, 255, 255, 0.015), transparent); }
/* Paper band — the "how it works" rhythm break (doc 04 §9). Was a light/white
   ink band; owner call: hard on the eyes and inconsistent with the rest of
   the dark felt site. Now a subtle dark variant (bg-soft + hairline rules)
   with NO light-ink variable overrides, so every default dark-mode rule
   (text/muted/btn-ghost/.step panel idiom) just applies as-is. */
.section-paper {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.015), transparent), var(--bg-soft);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

/* Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: inherit; font-size: 15px; font-weight: 600; text-decoration: none;
  padding: 12px 22px; border-radius: 12px; border: 1px solid transparent;
  cursor: pointer; transition: transform .14s ease, box-shadow .14s ease, background .14s ease, border-color .14s ease;
  white-space: nowrap;
}
.btn-primary {
  color: var(--brand-ink); background: linear-gradient(180deg, #f87171, #dc2626);
  box-shadow: 0 10px 30px -10px var(--brand-glow), inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 16px 40px -12px var(--brand-glow), inset 0 1px 0 rgba(255, 255, 255, 0.26); }
.btn-ghost { color: var(--text); background: rgba(255, 255, 255, 0.04); border-color: var(--border); }
.btn-ghost:hover { transform: translateY(-2px); border-color: var(--border-strong); background: rgba(255, 255, 255, 0.07); }
.btn-sm { padding: 9px 16px; font-size: 14px; }
.btn-block { width: 100%; }
button.btn { font-family: inherit; }
a:focus-visible, button:focus-visible, .btn:focus-visible, input.f:focus-visible, select.f:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Skip-to-content link — off-screen until keyboard-focused (a11y). */
.skip-link { position: absolute; left: -9999px; top: 0; z-index: 200; padding: 10px 16px; background: var(--accent); color: #fff; text-decoration: none; border-radius: 0 0 8px 0; }
.skip-link:focus { left: 0; }

/* Nav */
header.nav {
  position: sticky; top: 0; z-index: 50;
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  background: rgba(26, 13, 17, 0.66);
  border-bottom: 1px solid transparent;
  transition: border-color .2s ease, background .2s ease;
}
header.nav.scrolled { border-bottom-color: var(--border); background: rgba(26, 13, 17, 0.90); }
.nav-inner { display: flex; align-items: center; justify-content: space-between; height: 66px; position: relative; }
.brand { display: inline-flex; align-items: center; gap: 10px; font-weight: 800; font-size: 19px; letter-spacing: -0.02em; text-decoration: none; color: var(--text); }
.brand .logo {
  width: 30px; height: 30px; border-radius: 9px;
  background: linear-gradient(160deg, var(--brand), #b91c1c);
  display: grid; place-items: center; box-shadow: 0 6px 18px -6px var(--brand-glow), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
.nav-links { display: flex; align-items: center; gap: 8px; }
.nav-links a.link { color: var(--muted); text-decoration: none; font-size: 14.5px; font-weight: 500; padding: 8px 12px; border-radius: 9px; transition: color .14s ease, background .14s ease; }
.nav-links a.link:hover { color: var(--text); background: rgba(255, 255, 255, 0.05); }
.nav-links a.link.active { color: var(--text); background: rgba(255, 255, 255, 0.06); }
.nav-menu { display: flex; align-items: center; gap: 18px; }
.nav-cta { display: flex; align-items: center; gap: 10px; }

.nav-toggle {
  display: none; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 10px; border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04); color: var(--text); cursor: pointer; flex: 0 0 auto;
}
.nav-toggle:hover { border-color: var(--border-strong); }
.nav-toggle svg { width: 20px; height: 20px; }
.nav-toggle .icon-close { display: none; }
.nav-toggle.open .icon-menu { display: none; }
.nav-toggle.open .icon-close { display: block; }

/* Hero */
.hero { padding: 80px 0 64px; text-align: center; position: relative; }
.hero > .container > * { animation: hero-in .6s ease both; }
.hero > .container > *:nth-child(2) { animation-delay: .04s; }
.hero > .container > *:nth-child(3) { animation-delay: .08s; }
.hero > .container > *:nth-child(4) { animation-delay: .12s; }
.hero > .container > *:nth-child(5) { animation-delay: .16s; }
.hero > .container > *:nth-child(6) { animation-delay: .2s; }
.hero > .container > *:nth-child(7) { animation-delay: .24s; }
@keyframes hero-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
/* Free-to-play chip row (docs/ui/27 §2 item 1) — pill chip recipe, --accent border. */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 18px 0 0; }
.chip {
  display: inline-flex; align-items: center; font-size: 12px; font-weight: 600;
  color: var(--text); background: rgba(56, 189, 248, 0.08); border: 1px solid rgba(56, 189, 248, 0.28);
  border-radius: 999px; padding: 5px 13px;
}
.chip .pulse-dot { margin-right: 6px; }
.hero h1 { font-size: clamp(34px, 5.6vw, 58px); font-weight: 900; max-width: 90%; margin: 20px auto 0; }
.hero h1 .grad { background: linear-gradient(120deg, var(--brand-2), var(--gold)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hero p.sub { font-size: clamp(16px, 2.2vw, 20px); color: var(--muted); max-width: 90%; margin: 20px auto 0; }
.hero .cta-row { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 30px; }
/* Fineprint under the primary CTA (T2-8) — sets expectations, not a legal wall. */
.cta-fineprint { font-size: 12.5px; color: var(--muted-2); text-align: center; margin: 10px 0 0; }
.page-hero { padding: 68px 0 20px; text-align: center; }
.page-hero h1 { font-size: clamp(30px, 5vw, 46px); font-weight: 900; margin-top: 18px; }
.page-hero p.sub { font-size: 17px; color: var(--muted); max-width: 90%; margin: 16px auto 0; }

/* Live line — real GET /api/rooms liveRound data, short server cache. */
.live-line {
  display: inline-flex; align-items: center; gap: 10px; margin: 26px auto 0;
  font-size: 14px; color: var(--muted); background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border); border-radius: 999px; padding: 8px 18px;
}
.live-line b { color: var(--text); font-weight: 700; }
.live-line .amt { color: var(--gold); font-weight: 700; }
.pulse-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 0 rgba(56, 189, 248, .5); animation: pulse 1.8s infinite; display: inline-block; flex: 0 0 auto; }
.pulse-dot.pot { background: var(--gold); box-shadow: 0 0 0 0 var(--gold-glow); }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(56, 189, 248, .45); } 70% { box-shadow: 0 0 0 8px rgba(56, 189, 248, 0); } 100% { box-shadow: 0 0 0 0 rgba(56, 189, 248, 0); } }

/* Winners marquee (docs/ui/27 T1) — real /ticker.json data only, duplicated
   track for a seamless scroll; ticker.js keeps it live, SSR renders the
   initial snapshot so the marquee is complete without JS. */
.marquee {
  margin: 22px auto 0; max-width: 720px; overflow: hidden; position: relative; display: flex;
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.marquee-track { flex: 0 0 auto; display: flex; gap: 28px; white-space: nowrap; padding-right: 28px; animation: marquee 34s linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
/* Two identical tracks sit side-by-side as flex items; each scrolls -100% of
   its OWN width, so as the first exits left the second slides into its place —
   a seamless loop with no overlap (the old absolute left:100% referenced the
   720px .marquee, not the wider track, which stacked the copies). */
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.marquee-item { display: inline-flex; flex: 0 0 auto; align-items: center; gap: 8px; font-size: 13.5px; color: var(--muted); }
.marquee-item b { color: var(--text); }
.marquee-item .amt { color: var(--gold); font-weight: 700; }
.marquee-item .mi-when { color: var(--muted-2); font-size: 12px; }
.ticker-empty { padding: 10px 0 0; font-size: 13.5px; }

/* Hero visual: CSS-only mini play table — illustrative chrome, not live data. */
.play-mock {
  margin: 52px auto 0; max-width: 620px; border-radius: 22px;
  border: 1px solid var(--border); background: var(--panel-2);
  box-shadow: 0 40px 90px -40px rgba(0, 0, 0, 0.8), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  padding: 20px; position: relative; overflow: hidden;
  /* .play-mock's own single-class specificity would otherwise beat (and drop)
     the `.hero > .container > *` entrance fade — so both animations are
     combined here explicitly, float starting once the fade-in finishes. */
  animation: hero-in .6s ease both, pm-float 6s ease-in-out .6s infinite;
}
@keyframes pm-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
.play-mock::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(600px 200px at 50% -20%, rgba(239, 68, 68, 0.16), transparent 70%);
  pointer-events: none;
}
.pm-top { display: flex; align-items: center; justify-content: space-between; font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted-2); padding: 2px 4px 16px; position: relative; }
.pm-top b { color: var(--gold); font-size: 13px; }
.pm-row { display: flex; align-items: center; gap: 14px; position: relative; }
.pm-ball {
  flex: 0 0 auto; width: 64px; height: 64px; border-radius: 50%;
  background: linear-gradient(160deg, var(--brand-2), #b91c1c);
  display: grid; place-items: center; color: #fff; font-weight: 800; font-size: 17px;
  box-shadow: 0 10px 26px -10px var(--brand-glow), inset 0 2px 0 rgba(255, 255, 255, .3);
  animation: pm-pop 2.4s ease-in-out infinite;
}
@keyframes pm-pop { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
.pm-calls { display: flex; gap: 8px; flex-wrap: wrap; }
.pm-call {
  font-size: 12.5px; font-weight: 700; color: var(--muted); background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border); border-radius: 8px; padding: 5px 9px;
}
.pm-card { margin-top: 18px; border: 1px solid var(--border); border-radius: 14px; overflow: hidden; background: rgba(0, 0, 0, .18); }
.pm-card-row { display: grid; grid-template-columns: repeat(5, 1fr); }
.pm-cell {
  aspect-ratio: 1; display: grid; place-items: center; font-size: 13px; font-weight: 700;
  color: var(--muted); border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.pm-card-row:last-child .pm-cell { border-bottom: none; }
.pm-cell:last-child { border-right: none; }
.pm-cell.head { color: var(--brand-2); background: rgba(239, 68, 68, .08); font-size: 14px; }
.pm-cell.free { color: var(--gold); font-size: 11px; letter-spacing: .04em; }

/* Playable hero mock — tap-to-daub + win celebration (T1-5). Daubed state is
   gold, not rojo-red like the ambient `.daub` demo cells: this is a player
   action / near-win moment, not decorative call chrome. */
.pm-cell[data-daubable] { cursor: pointer; }
.pm-cell.on {
  color: #2a1c04; background: radial-gradient(circle, var(--gold-2), var(--gold) 70%);
  position: relative; animation: pm-on-pop .38s ease;
}
@keyframes pm-on-pop { 0% { transform: scale(.7); } 60% { transform: scale(1.14); } 100% { transform: scale(1); } }
/* Celebration overlay — hidden until `.show` (added by ticker.js on a completed line/col). */
.mock-bingo {
  position: absolute; inset: 0; z-index: 5; display: flex; align-items: center; justify-content: center;
  font-size: clamp(30px, 8vw, 52px); font-weight: 900; letter-spacing: -0.02em; text-align: center;
  color: var(--gold); text-shadow: 0 0 34px var(--gold-glow), 0 4px 20px rgba(0, 0, 0, .5);
  background: radial-gradient(circle, rgba(251, 191, 36, .20), rgba(26, 13, 17, .58) 72%);
  border-radius: 22px; opacity: 0; transform: scale(.6); pointer-events: none;
  transition: opacity .3s ease, transform .3s ease;
}
.mock-bingo.show { opacity: 1; transform: scale(1); animation: mock-bingo-burst .5s ease; pointer-events: auto; }
@keyframes mock-bingo-burst { 0% { transform: scale(.4); opacity: 0; } 60% { transform: scale(1.16); opacity: 1; } 100% { transform: scale(1); opacity: 1; } }
/* Confetti — ticker.js spawns ~16 `.confetti-piece` divs into this layer. */
.mock-confetti { position: absolute; inset: 0; z-index: 4; overflow: hidden; pointer-events: none; }
.confetti-piece {
  position: absolute; top: -8%; width: 8px; height: 14px; border-radius: 2px;
  background: var(--gold); opacity: .95; animation: confetti-fall 1.6s ease-in forwards;
}
.confetti-piece:nth-child(3n) { background: var(--brand-2); }
.confetti-piece:nth-child(3n+1) { background: var(--gold-2); }
@keyframes confetti-fall {
  0% { transform: translateY(0) rotate(0deg); opacity: .95; }
  100% { transform: translateY(320px) rotate(300deg); opacity: 0; }
}
/* Post-win CTA — hidden pill until `.show`. */
.mock-cta {
  position: absolute; left: 50%; bottom: 14px; z-index: 6; transform: translate(-50%, 8px);
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  font-size: 13.5px; font-weight: 700; color: #2a1c04; text-decoration: none;
  background: linear-gradient(180deg, var(--gold-2), var(--gold)); border-radius: 999px; padding: 10px 20px;
  box-shadow: 0 10px 26px -10px var(--gold-glow); opacity: 0; pointer-events: none;
  transition: opacity .3s ease .1s, transform .3s ease .1s;
}
.mock-cta.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.mock-hint { text-align: center; font-size: 12.5px; color: var(--muted-2); margin: 12px 0 0; }

/* Stats strip */
.stats { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px 56px; padding: 8px 0 0; }
.stat { text-align: center; }
.stat .n { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; }
.stat .n.gold { color: var(--gold); }
.stat .l { font-size: 13px; color: var(--muted-2); }
/* Hero stat row only (NOT `.stat-strip .stat`, the solutions-page column
   reuse below, which still wants the larger 26px number) — the number and
   its label read as the same size, with a clear gap between them instead of
   the number looming over its own caption. */
.stats .stat .n { font-size: 13px; margin-right: 6px; }

/* How it works — number LEFT, copy beside it. */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.step {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 26px; position: relative; display: flex; flex-direction: row; align-items: flex-start; gap: 16px;
}
.step .num {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 11px; display: grid; place-items: center;
  font-weight: 800; font-size: 17px; color: var(--brand-ink);
  background: linear-gradient(160deg, var(--brand), #b91c1c);
  box-shadow: 0 8px 22px -10px var(--brand-glow);
}
.step .sbody { min-width: 0; flex: 1; }
.step h3 { font-size: 17px; font-weight: 700; }
.step p { color: var(--muted); font-size: 14.5px; margin: 8px 0 0; }

/* Rooms showcase */
.room-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.room-card {
  background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 22px; position: relative; transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
  display: flex; flex-direction: column; gap: 12px;
}
.room-card:hover { transform: translateY(-3px); border-color: rgba(239, 68, 68, 0.4); box-shadow: 0 24px 50px -28px rgba(0, 0, 0, 0.7); }
/* room-card is also used as a whole-card anchor (help hub, patterns index,
   how-to-play index) — same idiom as .aud-panel: no underline anywhere in
   the card, base or hover, on title or description text. */
a.room-card { text-decoration: none; }
.room-card.vip { border-color: rgba(251, 191, 36, 0.4); background: linear-gradient(160deg, rgba(72, 55, 20, .30), rgba(36, 20, 25, .55)); }
.room-card .rc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.room-card h3 { font-size: 17px; font-weight: 700; }
.room-card .rc-tag { color: var(--muted); font-size: 13.5px; margin: 4px 0 0; }
.badge { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; padding: 4px 9px; border-radius: 999px; white-space: nowrap; }
.badge-vip { color: #2a1c04; background: linear-gradient(180deg, var(--gold-2), var(--gold)); }
.badge-live { color: var(--accent); background: rgba(56, 189, 248, .18); border: 1px solid rgba(56, 189, 248, .38); }
.room-card .rc-facts { display: flex; flex-wrap: wrap; gap: 8px; font-size: 12.5px; color: var(--muted); }
.room-card .rc-fact { background: rgba(255, 255, 255, .04); border: 1px solid var(--border); border-radius: 8px; padding: 4px 9px; }
.room-card .rc-pot { margin-top: auto; display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--muted); padding-top: 6px; border-top: 1px solid var(--border); }
.room-card .rc-pot .amt { color: var(--gold); font-weight: 800; margin-left: auto; }
.room-card .rc-foot { display: flex; }
.room-card .rc-foot .btn { width: 100%; }
/* Room-card image band — mirrors app RoomCard RoomCardImageBand: 75px full-bleed placeholder gradient + photo glyph until room images ship. */
.room-card .rc-media { height:75px; margin:-22px -22px 4px; flex:0 0 auto; display:grid; place-items:center; background:linear-gradient(135deg,#100c0b,var(--bg-soft)); border-bottom:1px solid var(--border); border-radius:calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0; }
.room-card .rc-media svg { width:22px; height:22px; color:var(--muted-2); }
/* Live-urgency pill: ball count + next-call countdown (T3-13). Gold, not the
   blue `.pulse-dot` live indicator — this is pace/urgency, not raw liveness. */
.room-tick {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700;
  color: #2a1c04; background: linear-gradient(180deg, var(--gold-2), var(--gold));
  border-radius: 999px; padding: 4px 11px; white-space: nowrap;
  animation: room-tick-pulse 2.4s infinite;
}
@keyframes room-tick-pulse {
  0% { box-shadow: 0 0 0 0 var(--gold-glow); }
  70% { box-shadow: 0 0 0 6px rgba(245, 158, 11, 0); }
  100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); }
}

/* Winners wall preview top-3 chips (docs/ui/27 §4 item 7) */
.top3 { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin: 0 0 28px; }
.top3-item {
  display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600;
  background: var(--panel); border: 1px solid var(--border); border-radius: 999px; padding: 8px 16px;
}
.top3-item .rank { color: var(--gold); font-weight: 800; }

/* Promotions band */
.promo-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.earn-grid { grid-template-columns: repeat(3, 1fr); }
.promo-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 22px; display: flex; flex-direction: column; gap: 10px; position: relative;
}
.promo-card .pc-icon {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center;
  background: linear-gradient(160deg, rgba(239, 68, 68, .20), rgba(251, 191, 36, .10));
  border: 1px solid rgba(239, 68, 68, .26); color: var(--brand-2);
}
.promo-card .pc-icon svg { width: 16px; height: 16px; }
.promo-card h3 { font-size: 15.5px; font-weight: 700; }
.promo-card p { font-size: 13.5px; color: var(--muted); margin: 0; }
.promo-card .amt { color: var(--gold); font-weight: 700; }

/* Arcade showcase band (T1-7) — 6 quick-game tiles, same credits/fairness,
   glass cards over the felt with a restrained gold hover accent. */
.arcade-band { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.arcade-tile {
  position: relative; overflow: hidden; display: flex; flex-direction: column; gap: 10px;
  background: rgba(255, 255, 255, 0.04); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 22px; text-decoration: none; color: var(--text);
  backdrop-filter: blur(8px) saturate(140%); -webkit-backdrop-filter: blur(8px) saturate(140%);
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease, background .16s ease;
}
.arcade-tile::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(160px 110px at 88% -12%, rgba(251, 191, 36, .18), transparent 70%);
}
.arcade-tile:hover {
  transform: translateY(-4px); border-color: rgba(251, 191, 36, 0.4);
  box-shadow: 0 24px 50px -28px rgba(0, 0, 0, 0.7); background: rgba(255, 255, 255, 0.065);
}
.arcade-tile .at-glyph { flex: 0 0 auto; font-size: 28px; line-height: 1; }
.arcade-tile h3 { font-size: 15.5px; font-weight: 700; }
.arcade-tile p { font-size: 13px; color: var(--muted); margin: 0; }
/* Subtle per-glyph motion — apply to the emoji span, e.g. Spin's wheel or
   Plinko's dot; both are decorative only and reduced-motion-safe. */
.arcade-tile .spin-glyph { display: inline-block; animation: arcade-spin 3.4s linear infinite; }
@keyframes arcade-spin { to { transform: rotate(360deg); } }
.arcade-tile .drop-glyph { display: inline-block; animation: arcade-drop 1.8s ease-in-out infinite; }
@keyframes arcade-drop { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(5px); } }

.dir-empty { text-align: center; color: var(--muted); padding: 40px 20px; }

.center-link { text-align: center; margin-top: 32px; }
.form-actions { margin-top: 14px; }
.alert-wrap { max-width: 640px; margin: 24px auto 0; }
.fair-result { max-width: 820px; margin: 32px auto 0; }
.fair-card.spaced { margin-top: 20px; }
.fair-facts { color: var(--muted); font-size: 14.5px; }
.fair-explain { color: var(--muted); font-size: 14.5px; line-height: 1.7; }
.hash-inline { display: inline; padding: 2px 6px; }
.fair-intro { max-width: 640px; margin: 28px auto 0; }

/* For-halls: product cards (deliberately thin) */
.product-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.product-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 24px; display: flex; flex-direction: column; gap: 10px;
}
.product-card .pc-icon {
  width: 44px; height: 44px; border-radius: 12px; display: grid; place-items: center;
  background: rgba(239, 68, 68, .12); color: var(--brand-2); border: 1px solid rgba(239, 68, 68, .24);
}
.product-card .pc-icon svg { width: 22px; height: 22px; }
.product-card h3 { font-size: 15.5px; font-weight: 700; }
.product-card p { font-size: 14px; color: var(--muted); margin: 0; }
.product-card .pc-tbd { font-size: 11.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted-2); }
.product-card .pc-hook { font-size: 14.5px; font-weight: 600; color: var(--text); margin: 0; }
.alt-cta { text-align: center; margin-top: 24px; color: var(--muted); font-size: 14.5px; }
.alt-cta a { color: var(--brand-2); text-decoration: none; font-weight: 600; }

/* Licensing spec sheet — checklist grid of engine capabilities. */
.spec-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 32px; max-width: 880px; margin: 0 auto; list-style: none; padding: 0; }
.spec-grid li { position: relative; padding-left: 26px; color: var(--muted); font-size: 14.5px; line-height: 1.55; }
.spec-grid li::before { content: "✓"; position: absolute; left: 0; top: 0; color: var(--brand-2); font-weight: 800; }
.spec-grid li b { color: var(--text); }
@media (max-width: 760px) { .spec-grid { grid-template-columns: 1fr; } }

/* Forms (lead capture, fairness verifier, hall search) */
.form-card {
  max-width: 640px; margin: 0 auto; background: var(--panel-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 32px;
}
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.form-grid .full { grid-column: 1 / -1; }
/* Non-grid blocks below .form-grid (products check-grid, message textarea) —
   same top rhythm as the grid's own row gap, so the form reads as one
   consistent stack rather than a grid followed by loosely-spaced extras. */
.form-section { margin-top: 16px; }
.state-noscript { margin-top: 16px; }
label.f { display: block; font-size: 13px; font-weight: 600; color: var(--muted); margin-bottom: 6px; }
label.f .opt { font-weight: 400; color: var(--muted-2); }
input.f, select.f, textarea.f {
  width: 100%; font-family: inherit; font-size: 14.5px; color: var(--text);
  background: rgba(255, 255, 255, 0.05); border: 1px solid var(--border); border-radius: 10px;
  padding: 11px 13px; outline: none; transition: border-color .14s ease;
}
input.f:focus, select.f:focus, textarea.f:focus { border-color: rgba(239, 68, 68, 0.55); }
textarea.f { resize: vertical; min-height: 100px; }
.form-note { color: var(--muted-2); font-size: 13px; margin-top: 14px; }
.alert { border-radius: 12px; padding: 13px 16px; font-size: 14.5px; margin-bottom: 18px; }
.alert.err { background: rgba(248, 113, 113, 0.10); border: 1px solid rgba(248, 113, 113, 0.35); color: #fca5a5; }
.alert.ok { background: rgba(52, 211, 153, 0.10); border: 1px solid rgba(52, 211, 153, 0.35); color: #6ee7b7; }
.alert.info { background: rgba(56, 189, 248, 0.10); border: 1px solid rgba(56, 189, 248, 0.35); color: #7dd3fc; }

/* Winners page */
.lb-table { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.lb-table th, .lb-table td { text-align: left; padding: 13px 18px; border-bottom: 1px solid var(--border); font-size: 14.5px; }
.lb-table th { color: var(--muted-2); font-size: 12px; text-transform: uppercase; letter-spacing: .05em; font-weight: 700; background: rgba(255, 255, 255, .02); }
.lb-table tr:last-child td { border-bottom: none; }
.lb-table td.rank { color: var(--muted-2); font-weight: 700; width: 48px; }
.lb-table tr:nth-child(1) td.rank { color: var(--gold); }
.lb-table td.pts { color: var(--gold); font-weight: 700; }
.raffle-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
.raffle-card { background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radius); padding: 22px; }
.raffle-card h3 { font-size: 16px; font-weight: 700; }
.raffle-card .rf-prize { color: var(--gold); font-weight: 700; font-size: 14.5px; margin: 6px 0 14px; }
.raffle-card .rf-winners { font-size: 14px; color: var(--text); margin-bottom: 14px; }
.raffle-card .rf-winners b { color: var(--gold); }
.hash-row { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.hash-row .hl { font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted-2); }
.hash-val { font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 12px; color: var(--muted); background: rgba(0, 0, 0, .22); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; word-break: break-all; }
.round-winners { list-style: none; padding: 0; margin: 0; display: grid; gap: 10px; max-width: 760px; margin: 0 auto; }
.round-winners li { display: flex; align-items: center; gap: 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 12px 18px; font-size: 14.5px; }
.round-winners b { color: var(--text); }
.round-winners .amt { color: var(--gold); font-weight: 700; }
.round-winners .rw-meta { margin-left: auto; text-align: right; color: var(--muted-2); font-size: 12.5px; }
.round-winners a { color: var(--muted-2); text-decoration: none; }
.round-winners a:hover { color: var(--brand-2); }

/* Fairness verifier */
.verdict {
  display: flex; align-items: center; gap: 12px; border-radius: 14px; padding: 16px 20px; font-size: 15px; font-weight: 700;
  margin-bottom: 24px;
}
.verdict.ok { background: rgba(52, 211, 153, 0.10); border: 1px solid rgba(52, 211, 153, 0.35); color: #6ee7b7; }
.verdict.bad { background: rgba(248, 113, 113, 0.10); border: 1px solid rgba(248, 113, 113, 0.35); color: #fca5a5; }
.verdict.pending { background: rgba(56, 189, 248, .10); border: 1px solid rgba(56, 189, 248, .3); color: var(--accent); }
.verdict svg { width: 22px; height: 22px; flex: 0 0 auto; }
.fair-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px; }
.fair-card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 22px; }
.fair-card h3 { font-size: 13px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted-2); margin-bottom: 12px; }
.fair-recipe { font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 12.5px; color: var(--muted); background: rgba(0, 0, 0, .22); border-radius: 10px; padding: 14px; margin-top: 14px; line-height: 1.7; word-break: break-word; }
.call-strip { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; max-height: 160px; overflow-y: auto; }
.call-chip { font-size: 11.5px; font-weight: 700; color: var(--muted); background: rgba(255, 255, 255, .05); border: 1px solid var(--border); border-radius: 6px; padding: 4px 7px; }

/* FAQ / help */
.faq { max-width: 760px; margin: 0 auto; display: grid; gap: 14px; }
.faq details { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 18px 22px; }
.faq summary { cursor: pointer; font-weight: 700; font-size: 15.5px; }
.faq details p { color: var(--muted); font-size: 14.5px; margin: 12px 0 0; }

/* Pattern mini-grids — CSS-only preview of a daubed pattern shape, reused on
   the patterns index cards and the pattern detail page. Column count varies
   by ballType's real grid (75=5×5, 90=9×3, 80=4×4, 30=3×3 — docs/ui/72
   follow-up, mask decoding verified against packages/ui/src/lib/modes.ts) —
   a `.mini-grid-cols-N` class picks the column count (CSP is `style-src
   'self'`, no unsafe-inline, so a CSS custom property via inline `style=""`
   would be silently dropped; a server-chosen class name is CSP-safe). */
.mini-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 2px; width: 68px; margin: 0 auto; }
.mini-grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
.mini-grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
.mini-grid-cols-5 { grid-template-columns: repeat(5, 1fr); }
.mini-grid-cols-9 { grid-template-columns: repeat(9, 1fr); }
.mini-cell { aspect-ratio: 1; border-radius: 2px; background: rgba(255, 255, 255, 0.06); border: 1px solid var(--border); }
/* Filled cells match the app's daub red (packages/ui/src/theme.ts
   `--brand-fill: linear-gradient(180deg, #f05252, #dc2626)`) — same gradient
   family as this site's own .btn-primary, never gold (gold stays reserved
   for money/prizes per docs/ui/09). */
.mini-cell.on { background: linear-gradient(180deg, #f87171, #dc2626); border-color: var(--brand); }

/* Guide/content pages (P1-2) — help, patterns, how-to-play: CSP kills inline
   `style=""` attributes (style-src 'self', no unsafe-inline), so these
   classes replace the ad hoc inline styles those templates used. */
.guide-section { max-width:760px; margin:48px auto 0; }
.guide-section h2 { font-size:21px; font-weight:800; margin:40px 0 14px; }
.guide-section p, .guide-section ul, .guide-section ol { color:var(--muted); font-size:15px; line-height:1.75; }
.tagline { color:var(--muted); font-size:13.5px; margin:6px 0 0; }
.room-meta { margin-top:12px; display:flex; gap:8px; font-size:12px; color:var(--muted-2); text-transform:uppercase; letter-spacing:.04em; }
.room-type, .room-price { display:inline-flex; align-items:center; background:rgba(255,255,255,.04); border:1px solid var(--border); border-radius:8px; padding:4px 9px; }
.pill-row { display:flex; gap:8px; flex-wrap:wrap; }
.pill { padding:8px 16px; background:rgba(255,255,255,.04); border:1px solid var(--border); border-radius:8px; text-decoration:none; font-size:14px; }
.pill.active { background:rgba(239,68,68,.1); border-color:transparent; }
.rule-top { margin-top:48px; padding-top:32px; border-top:1px solid var(--border); }
.cta-panel { margin-top:48px; padding:32px; background:rgba(239,68,68,.1); border-radius:14px; text-align:center; }

/* 404 */
.error-page { text-align: center; padding: 100px 0; }
.error-page .code { font-size: 88px; font-weight: 900; background: linear-gradient(120deg, var(--brand-2), var(--gold)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.error-page p.sub { margin: 16px auto 0; color: var(--muted); max-width: 50ch; }
.error-page .cta-row { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 28px; }

/* CTA band */
.cta-band {
  text-align: center; border: 1px solid var(--border); border-radius: 24px;
  background: radial-gradient(700px 240px at 50% -30%, rgba(239, 68, 68, 0.22), transparent 70%), var(--panel-2);
  padding: 56px 28px; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.cta-band h2 { font-size: clamp(26px, 4vw, 36px); font-weight: 800; }
.cta-band p { color: var(--muted); font-size: 17px; margin: 14px auto 0; max-width: 52ch; }
.cta-band .cta-row { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 28px; }

/* Legal pages (Terms/Privacy/AUP) */
.draft-banner {
  display: flex; gap: 12px; align-items: flex-start;
  background: rgba(251, 146, 60, 0.10); border: 1px solid rgba(251, 146, 60, 0.35); color: #fdba74;
  border-radius: 14px; padding: 16px 20px; font-size: 14.5px; line-height: 1.6; margin-bottom: 36px;
}
.draft-banner svg { width: 20px; height: 20px; flex: 0 0 auto; margin-top: 2px; }
.legal { max-width: 760px; margin: 0 auto; }
.legal .updated { color: var(--muted-2); font-size: 13.5px; margin-bottom: 28px; }
.legal h2 { font-size: 21px; font-weight: 800; margin: 40px 0 14px; }
.legal h2:first-of-type { margin-top: 0; }
.legal h3 { font-size: 16px; font-weight: 700; margin: 22px 0 10px; }
.legal p { color: var(--muted); font-size: 15px; line-height: 1.75; margin: 0 0 14px; }
.legal ul, .legal ol { color: var(--muted); font-size: 15px; line-height: 1.75; margin: 0 0 14px; padding-left: 22px; }
.legal li { margin-bottom: 6px; }
.legal strong { color: var(--text); }
.legal a { color: var(--brand-2); text-decoration: underline; }

/* Footer */
footer.site { border-top: 1px solid var(--border); padding: 44px 0 40px; margin-top: 40px; }
/* doc 72 — single nav-mirroring link row (+ Licensing), replacing the
   logo/brand block and the 3-column Players/Business/Company grid (doc 71
   §3.5 W5 / §3.6 W6). Centered + wrapping, the same idiom as .chip-row: no
   brand anchor sits to its left anymore, so a left-hung row of 6 short
   links would read lopsided on wide viewports. Wraps naturally at any width
   (no dedicated breakpoint needed). */
.foot-links { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 10px 28px; margin-bottom: 28px; }
.foot-links a { color: var(--muted); text-decoration: none; font-size: 14px; font-weight: 500; transition: color .14s ease; }
.foot-links a:hover { color: var(--text); }
.foot-bottom {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 20px;
  margin-top: 32px; padding-top: 24px; border-top: 1px solid var(--border);
}
.foot-legal { color: var(--muted-2); font-size: 12.5px; margin-top: 18px; line-height: 1.6; }
.foot-copy { color: var(--muted-2); font-size: 13px; }
/* Right-hand legal-link cluster in the bottom bar (Terms/Privacy/AUP). */
.foot-legal-links { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; }
.foot-legal-links a { color: var(--muted-2); text-decoration: none; font-size: 12.5px; transition: color .14s ease; }
.foot-legal-links a:hover { color: var(--text); }

@media (max-width: 980px) {
  .room-grid, .promo-grid, .product-grid { grid-template-columns: 1fr 1fr; }
  .raffle-grid { grid-template-columns: 1fr 1fr; }
  .fair-grid { grid-template-columns: 1fr; }
  .arcade-band { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 760px) {
  .section { padding: 72px 0; }
  .room-grid, .promo-grid, .product-grid, .raffle-grid, .steps { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .hero { padding: 52px 0 44px; }
  .play-mock { padding: 14px; }
  .stats { gap: 10px 28px; }

  .nav-toggle { display: flex; }
  .nav-menu {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 4px;
    background: rgba(26, 13, 17, 0.97); border: 1px solid var(--border); border-top: none;
    border-radius: 0 0 16px 16px; padding: 12px 20px 20px;
    box-shadow: 0 24px 50px -20px rgba(0, 0, 0, 0.6);
  }
  .nav-menu.open { display: flex; }
  .nav-menu .nav-links { flex-direction: column; align-items: stretch; gap: 2px; }
  .nav-menu .nav-links a.link { padding: 12px 10px; }
  /* Two-column CTA row (lang dropdown 40% / Login 60%) instead of a stacked
     column. `.lang-dd` is fixed at exactly 40% (flex-shrink:0 via the `0 0`
     shorthand); `.btn` takes the rest via flex:1, so the 8px gap comes out
     of the button's share, not the dropdown's — i.e. "40/60 including the
     gap" reads as a firm 40% column and a slightly-under-60% button column.
     align-items:center (not stretch, unlike the old column layout above) so
     opening the language menu below the summary can't drag the Login
     button's own height along with it. */
  .nav-menu .nav-cta { flex-direction: row; align-items: center; gap: 8px; margin-top: 10px; }
  .nav-menu .nav-cta .lang-dd { flex: 0 0 40%; min-width: 0; margin-right: 0; }
  .nav-menu .nav-cta .btn {
    flex: 1 1 60%; width: auto; min-width: 0;
    /* Defensive only: the fixed 40% column leaves less room than the old
       full-width button had, and "Iniciar sesión →" is the longest label
       this CTA ever renders — ellipsize rather than overflow/wrap on the
       narrowest phones instead of breaking the row height match below. */
    overflow: hidden; text-overflow: ellipsis;
  }
  /* Match the summary's rendered height to .btn-sm's: both now share the
     same vertical padding (9px), border width (1px) and font-size (14px),
     so the two boxes come out to the same total height (18 + 2 + 14×1.6 =
     42.4px either way) without needing a stretch/percentage-height hack. */
  .nav-menu .nav-cta .lang-dd summary { justify-content: center; padding: 9px 12px; font-size: 14px; }
  /* Open state: kept position:absolute (the desktop default) rather than
     reusing the old column layout's position:static — in a ROW this matters,
     not just cosmetics. `.nav-cta` no longer stretches its children (see
     align-items:center above), but a `position:static` menu still sits IN
     FLOW inside `.lang-dd`, so opening it grows `.lang-dd`'s content height
     past the Login button's, which grows the whole flex line's cross size
     and re-centers `.btn` down into the middle of that taller line —
     verified in headless Chrome: the Login button visually slides down
     behind the open menu. Anchoring left (not the desktop rule's `right:0`,
     which would hang the menu off the LEFT edge of the viewport from this
     40%-column position) removes it from flow entirely, floating it below
     the row without touching sibling layout — confirmed empirically to land
     at the same on-screen footprint (x≈20–160 inside a 320px viewport) the
     old static-in-flow rule produced, just no longer coupled to `.btn`. */
  .nav-menu .nav-cta .lang-menu { position: absolute; left: 0; right: auto; top: calc(100% + 6px); width: max-content; min-width: 140px; margin-top: 0; }

  /* Footer bottom bar (doc 72) — stack copyright above the legal links
     instead of space-between on one row; left-aligned to match the mobile
     nav-menu's stacked, left-hung link list above. */
  .foot-bottom { flex-direction: column; align-items: flex-start; }
}
/* Share page — win card announcement. */
.share-hero {
  padding: 76px 0 52px;
}
.share-card {
  max-width: 680px; margin: 0 auto; position: relative;
}
.share-top {
  display: flex; justify-content: center; margin-bottom: 24px;
}
.share-top svg { width: 16px; height: 16px; color: var(--gold); }
.share-title {
  font-size: clamp(28px, 5vw, 44px); font-weight: 900; text-align: center;
  margin: 0 0 40px; line-height: 1.1;
}
.share-title .grad { background: linear-gradient(160deg, var(--gold), var(--gold-2)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }

/* Win-burst (T3-11) — gold rays + drifting confetti dots behind the headline,
   CSS-only (single element; dots are ::before/::after background layers, not
   spawned nodes). Sits inside .share-card (now `position:relative`), behind
   the BINGO/winner headline; decorative only, aria-hidden in markup. */
.win-burst {
  position: absolute; left: 50%; top: -30px; transform: translateX(-50%); z-index: 0;
  width: 640px; max-width: 94vw; height: 300px; pointer-events: none; border-radius: 50%;
  background:
    repeating-conic-gradient(from 0deg, rgba(251, 191, 36, .16) 0deg 8deg, transparent 8deg 24deg),
    radial-gradient(220px 220px at 50% 32%, rgba(251, 191, 36, .30), transparent 72%);
  animation: win-burst-spin 20s linear infinite, win-burst-pulse 2.6s ease-in-out infinite;
}
.win-burst::before, .win-burst::after {
  content: ""; position: absolute; inset: 0;
  background-image:
    radial-gradient(4px 4px at 20% 30%, var(--gold) 50%, transparent 52%),
    radial-gradient(4px 4px at 70% 20%, var(--brand-2) 50%, transparent 52%),
    radial-gradient(3px 3px at 40% 62%, var(--gold-2) 50%, transparent 52%),
    radial-gradient(3px 3px at 85% 55%, var(--gold) 50%, transparent 52%),
    radial-gradient(4px 4px at 55% 80%, var(--brand-2) 50%, transparent 52%),
    radial-gradient(3px 3px at 12% 70%, var(--gold-2) 50%, transparent 52%);
  animation: win-burst-fall 3.6s ease-in infinite;
}
.win-burst::after { animation-delay: 1.8s; opacity: .7; }
@keyframes win-burst-spin { to { transform: translateX(-50%) rotate(360deg); } }
@keyframes win-burst-pulse { 0%, 100% { opacity: .7; } 50% { opacity: 1; } }
@keyframes win-burst-fall { 0% { transform: translateY(-14px); opacity: 0; } 15% { opacity: 1; } 100% { transform: translateY(56px); opacity: 0; } }
.share-title { position: relative; z-index: 1; }

.win-card-main {
  margin: 0 0 32px;
}
.win-card {
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: var(--radius); padding: 28px;
  box-shadow: 0 40px 80px -40px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.wc-header {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 20px;
  margin-bottom: 20px;
}
.wc-player h2 {
  font-size: 24px; font-weight: 900; margin: 0; color: var(--text);
}
.wc-pattern {
  font-size: 14.5px; color: var(--muted); margin: 6px 0 0;
  font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
}
.wc-amount {
  display: flex; flex-direction: column; align-items: flex-end;
  text-align: right;
}
.wc-label {
  font-size: 12px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted-2); display: block;
}
.wc-value {
  font-size: 26px; font-weight: 900; color: var(--gold);
  display: block; margin-top: 4px;
}

.wc-divider {
  height: 1px; background: var(--border); margin: 20px 0;
}

.wc-details {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
}
.wc-detail {
  display: flex; flex-direction: column; gap: 4px;
}
.wc-detail .wc-label {
  display: block;
}
.wc-detail .wc-value {
  font-size: 15px; color: var(--text);
}

.other-winners {
  background: rgba(255, 255, 255, 0.04); border: 1px solid var(--border);
  border-radius: 14px; padding: 18px;
  margin-bottom: 28px;
}
.other-winners .wc-label {
  display: block; margin-bottom: 12px;
}
.winner-list-full {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.winner-list-full li {
  font-size: 13.5px; color: var(--muted);
  display: flex; justify-content: space-between; align-items: center;
}
.winner-handle {
  font-weight: 700; color: var(--text);
}
.winner-prize {
  color: var(--muted-2); font-size: 12.5px;
}

.share-actions {
  text-align: center;
}
.share-actions .btn {
  display: inline-flex; margin-bottom: 16px;
}
.verify-note {
  font-size: 13px; color: var(--muted-2); margin: 0;
}

/* Responsive: cards stack vertically on smaller screens */
@media (max-width: 640px) {
  .wc-details {
    grid-template-columns: 1fr;
  }
  .wc-header {
    flex-direction: column;
    align-items: flex-start;
  }
  .wc-amount {
    align-items: flex-start;
    text-align: left;
  }
}

/* Language switcher — no-JS-functional <details> dropdown (site.js only
   adds a close-on-outside-click enhancement; the summary/menu work via
   native <details> semantics without it). */
.lang-dd { position: relative; margin-right: 12px; }
.lang-dd summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 600; color: var(--muted);
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px;
  transition: color .14s ease, border-color .14s ease;
}
.lang-dd summary::-webkit-details-marker { display: none; }
.lang-dd summary:hover { color: var(--text); }
.lang-dd[open] summary { color: var(--text); }
.lang-caret { transition: transform .16s ease; }
.lang-dd[open] .lang-caret { transform: rotate(180deg); }
.lang-menu {
  position: absolute; top: calc(100% + 6px); right: 0; min-width: 140px;
  background: var(--panel-2, #1a1a1f); border: 1px solid var(--border); border-radius: 10px;
  padding: 6px; z-index: 60; display: grid; gap: 2px;
  box-shadow: 0 16px 40px -18px rgba(0, 0, 0, .6);
}
.lang-item {
  display: block; padding: 8px 10px; border-radius: 7px; font-size: 13.5px;
  color: var(--muted); text-decoration: none;
  transition: color .14s ease, background .14s ease;
}
.lang-item:hover { background: rgba(255, 255, 255, .05); color: var(--text); }
.lang-item.active { color: var(--text); font-weight: 700; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; scroll-behavior: auto !important; transition: none !important; }
  /* The blanket rule above already kills the marquee/hero/play-mock keyframe
     animations; these overrides fix the LAYOUT so a de-animated marquee reads
     as a plain static stacked list (docs/ui/27 §2 item 4) instead of two
     overlapping horizontal tracks frozen mid-scroll. */
  .marquee { display: block; overflow: visible; mask-image: none; -webkit-mask-image: none; }
  .marquee-track { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; white-space: normal; padding-right: 0; }
  .marquee-track + .marquee-track { display: none; }

  /* T1-5 playable mock — `.on`/`.show` states still apply instantly (they set
     opacity/transform directly, not only via the animation); only the
     pop/burst/fall motion is removed. Confetti pieces are pure motion, so
     hide them outright rather than show a frozen pile of static dots. */
  .confetti-piece { display: none; }

  /* T1-7 arcade glyphs — no spin/drop loop, glyph sits static. */
  .arcade-tile .spin-glyph, .arcade-tile .drop-glyph { transform: none; }

  /* T3-11 win-burst — static gold glow, no spin/rise/fall; drop the second
     confetti layer so it isn't just a frozen double-exposure. */
  .win-burst::after { display: none; }

  /* T3-13 room-tick — solid pill, no pulsing ring. */
  .room-tick { box-shadow: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Solutions (docs/ui/34-halls-solutions-site.md) — B2B hall-facing product
   suite (/solutions/*). Same felt-dark + rojo tokens as the consumer site,
   just a quieter register (wider measure, more air — this section sells the
   operation, not the table). GOLD STAYS RESERVED FOR MONEY/PRIZE COPY
   (ruling 2) — product wordmarks use a two-tone RED treatment instead. No
   new custom properties: every rule below reuses existing --tokens.
   ══════════════════════════════════════════════════════════════════════════ */

/* Product hero — image optional (.sol-hero-media), gradient overlay so H1
   stays readable over any source photo. Identity has no product photo (ruling:
   its inline SVG diagram IS the hero) — .sol-hero works with zero media. */
.sol-hero {
  position: relative; overflow: hidden; padding: 100px 0 68px;
  background: radial-gradient(900px 420px at 12% -12%, rgba(239, 68, 68, .14), transparent 60%), var(--bg-soft);
}
.sol-hero-media { position: absolute; inset: 0; z-index: 0; }
.sol-hero-media img { width: 100%; height: 100%; object-fit: cover; }
.sol-hero-media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(26, 13, 17, .30) 0%, rgba(26, 13, 17, .86) 74%, var(--bg) 100%);
}
.sol-hero-inner { position: relative; z-index: 1; max-width: 90%; }
.sol-hero h1 { font-size: clamp(32px, 5vw, 52px); font-weight: 900; margin-top: 16px; }
.sol-hero .hook { font-size: 18px; color: var(--muted); max-width: 90%; margin: 14px 0 0; }
/* The split hero's CTA row (events.mustache .sol-hero-copy) had no dedicated
   rule at all — it isn't inside `.hero`, so it inherited zero spacing from
   the hook text above it. Owner call: ~30px gap (docs/ui request 2026-08-22). */
.sol-hero .cta-row { margin-top: 30px; }
/* Hub variant — centered, wider, taller (full-bleed marketing hero). */
.sol-hero-hub { text-align: center; padding: 128px 0 72px; }
.sol-hero-hub .sol-hero-inner { max-width: 90%; margin: 0 auto; }
.sol-hero-hub .hook { margin-left: auto; margin-right: auto; }

/* Two-tone wordmark — the one typographic device repeated everywhere (hero
   H1, program-board rows, sol-subnav chips, runs-on chips). `.wm` just
   prevents an awkward mid-word line-break; `.wm-a` carries the color split. */
.wm { white-space: nowrap; }
.wm-a { color: var(--brand-2); }
.wm sup { font-size: .55em; margin-left: 1px; }

/* Session-type tag — program-board "what kind of entry is this" chip.
   4 variants differentiated by weight/existing hue, not new colors. */
.tag {
  display: inline-flex; align-items: center; flex: 0 0 auto;
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--border);
  color: var(--muted); background: rgba(255, 255, 255, .04);
}
.tag-core { color: var(--accent); background: rgba(56, 189, 248, .10); border-color: rgba(56, 189, 248, .30); }
.tag-game { color: var(--brand-2); background: rgba(239, 68, 68, .10); border-color: rgba(239, 68, 68, .28); }
.tag-program, .tag-usecase { color: var(--text); background: rgba(255, 255, 255, .07); border-color: var(--border-strong); }
.tag-platform { color: var(--muted-2); background: rgba(255, 255, 255, .03); border-color: var(--border); }

/* Program board — the hub's signature index, styled like a hall's session
   program: a lined board, each row wordmark + hook + tag, linking out. */
.program-board { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--panel); }
.pb-row {
  display: flex; align-items: center; gap: 18px; padding: 20px 26px;
  text-decoration: none; color: var(--text); border-bottom: 1px solid var(--border);
  transition: background .14s ease, transform .14s ease;
}
.pb-row:last-child { border-bottom: none; }
.pb-row:hover { background: rgba(255, 255, 255, .04); transform: translateX(4px); }
.pb-num { flex: 0 0 auto; width: 28px; font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 13px; color: var(--muted-2); }
.pb-main { flex: 1 1 auto; min-width: 0; }
.pb-main .wm { font-size: 18px; font-weight: 800; display: block; }
.pb-hook { font-size: 13.5px; color: var(--muted); margin: 4px 0 0; }
/* Right-aligned chevron — signals every program-board row is clickable.
   Muted by default; turns brand-red and nudges right on row hover. */
.pb-chev { flex: 0 0 auto; width: 28px; height: 28px; color: var(--muted-2); transition: color .14s ease, transform .14s ease; }
.pb-chev svg { width: 100%; height: 100%; }
.pb-row:hover .pb-chev { color: var(--brand-2); transform: translateX(4px); }

/* Hub image marquee — reuses the winners-ticker `.marquee`/`.marquee-track`
   scroll mechanics verbatim (existing rules, untouched — including the
   prefers-reduced-motion static-stack fallback below, which already applies
   to any `.marquee-track`). `.sol-marquee` is a new modifier scoped to bare
   <img> children only, since `.marquee-item` (text ticker rows) never has one. */
.sol-marquee { max-width: 100%; }
.sol-marquee .marquee-track { animation-duration: 46s; }
.sol-marquee .marquee-track img { height: 120px; width: auto; border-radius: 12px; flex: 0 0 auto; margin-right: 14px; }

/* Detail-page alternating media rows — SPA `details` distilled into 2-3
   themed subsections, image alternating sides for rhythm. */
.media-row { display: flex; align-items: center; gap: 48px; margin: 64px 0; }
.media-row.rev { flex-direction: row-reverse; }
.media-row .media-frame { flex: 1 1 46%; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--border); box-shadow: 0 30px 70px -36px rgba(0, 0, 0, .6); }
.media-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.media-row .media-copy { flex: 1 1 46%; min-width: 0; }
.media-row h3 { font-size: 22px; font-weight: 800; }
.media-row p { color: var(--muted); font-size: 15px; line-height: 1.7; margin: 12px 0 0; }

/* "What's included" feature grid — bullets distilled from SPA `details`. */
.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.feat { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 22px; display: flex; flex-direction: column; gap: 10px; }
.feat-icon { flex: 0 0 auto; width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; background: rgba(239, 68, 68, .12); border: 1px solid rgba(239, 68, 68, .24); color: var(--brand-2); }
.feat-icon svg { width: 16px; height: 16px; }
.feat h4 { font-size: 15px; font-weight: 700; }
.feat p { font-size: 13.5px; color: var(--muted); margin: 0; }

/* "Runs on" strip — chips linking sibling core services (e.g. CardTrack™
   runs inside MyBingo™, accounts by RoJo Identity). */
.runs-on { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; padding: 22px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); margin: 48px 0; }
.runs-on .rl { font-size: 12.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted-2); margin-right: 4px; }
.chip-link {
  display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px; font-weight: 600;
  color: var(--text); background: rgba(255, 255, 255, .04); border: 1px solid var(--border);
  border-radius: 999px; padding: 7px 14px; text-decoration: none;
  transition: border-color .14s ease, transform .14s ease;
}
.chip-link:hover { border-color: var(--border-strong); transform: translateY(-2px); }

/* Detail-page subnav — horizontal-scroll chip row (8 products + Contact),
   sticky just under the 66px main nav. Active state via server `is_sol_*`. */
.sol-subnav { position: sticky; top: 66px; z-index: 40; background: rgba(26, 13, 17, .92); backdrop-filter: saturate(160%) blur(10px); -webkit-backdrop-filter: saturate(160%) blur(10px); border-bottom: 1px solid var(--border); }
.sol-subnav-inner { display: flex; gap: 8px; overflow-x: auto; padding: 12px 0; scrollbar-width: none; }
.sol-subnav-inner::-webkit-scrollbar { display: none; }
.sol-subnav a {
  flex: 0 0 auto; display: inline-flex; align-items: center; font-size: 13px; font-weight: 600;
  color: var(--muted); background: rgba(255, 255, 255, .03); border: 1px solid var(--border);
  border-radius: 999px; padding: 8px 15px; text-decoration: none; white-space: nowrap;
  transition: color .14s ease, border-color .14s ease, background .14s ease;
}
.sol-subnav a:hover { color: var(--text); border-color: var(--border-strong); }
.sol-subnav a.active { color: var(--text); background: rgba(239, 68, 68, .14); border-color: rgba(239, 68, 68, .35); }

/* Stat strip — reuses the existing `.stat`/.n/.l node styling (defined under
   `.stats` above) inside a new flex container so no existing rule changes. */
.stat-strip { display: flex; flex-wrap: wrap; gap: 14px 48px; padding: 28px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); margin: 40px 0; justify-content: center; }
/* .n/.l are inline spans in their original context — stack them here. */
.stat-strip .stat { display: flex; flex-direction: column; gap: 2px; }

/* Identity page — inline-SVG account/network diagram (no SPA photo exists;
   the diagram IS the hero, per plan). CSP-safe (inline markup, no image load). */
.diagram { max-width: 620px; margin: 0 auto; }
.diagram svg { width: 100%; height: auto; display: block; }
/* SVG fill can't take a CSS gradient function (--panel-2) — solid felt tone. */
.diagram-node { fill: var(--bg-soft); stroke: var(--border-strong); stroke-width: 1.5; }
.diagram-node.center { stroke: var(--brand-2); }
.diagram-line { stroke: var(--border-strong); stroke-width: 1.5; fill: none; }
.diagram-label { fill: var(--muted); font-size: 12px; font-family: system-ui, sans-serif; }

/* Contact form — product-interest checkboxes + honeypot. textarea.f reuses
   the existing input.f/select.f/textarea.f styling (forms block above)
   as-is — no override needed. */
.check-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px 16px; margin-top: 6px; list-style: none; padding: 0; }
.check-item { display: flex; align-items: center; gap: 9px; font-size: 13.5px; color: var(--text); background: rgba(255, 255, 255, .03); border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; cursor: pointer; transition: border-color .14s ease; }
.check-item:hover { border-color: var(--border-strong); }
.check-item input { accent-color: var(--brand); width: 16px; height: 16px; flex: 0 0 auto; }
.check-item input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Honeypot — CSS-hidden from sighted users, still in the tab/DOM order for
   bots that fill every field blindly (site-wide `.vh` clips visually + a11y;
   `.hp` additionally opts fully out of layout/tab order since a real user
   should never reach it). */
.hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }

@media (max-width: 980px) {
  .feature-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 760px) {
  .sol-hero { padding: 72px 0 48px; }
  .sol-hero-hub { padding: 88px 0 56px; }
  .media-row, .media-row.rev { flex-direction: column; gap: 24px; margin: 44px 0; }
  .media-row .media-frame, .media-row .media-copy { flex: 1 1 auto; width: 100%; }
  .feature-grid { grid-template-columns: 1fr; }
  .pb-row { padding: 16px 18px; gap: 12px; }
}
@media (max-width: 420px) {
  .sol-hero h1 { font-size: 28px; }
  .check-grid { grid-template-columns: 1fr; }
  .stat-strip { gap: 10px 28px; }
  .sol-marquee .marquee-track img { height: 84px; }
  .pb-main .wm { font-size: 16px; }
  .runs-on { gap: 8px 10px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Solutions — RojoEvents revamp (doc 68, W1 foundation) — the platform-page
   split hero, automation tiers, use-case feature cards, screenshot
   placeholders, and comparison table shared by events/halls/fundraisers/
   autobingo/fasttrack (server.js SOLUTIONS registry + views/solutions/*).
   Same GOLD-ONLY-ON-MONEY-WORDS + existing-tokens-only rules as the block
   above; no new custom properties.
   ══════════════════════════════════════════════════════════════════════════ */

/* Screenshot placeholder — a felt-toned canvas standing in for a real
   capture until product shots are dropped in (S09/S10/S13 already are:
   `.shot-canvas > img`, no felt/dashes needed once a real <img> covers it).
   Default aspect is 16:10; modifiers below retarget the canvas per surface. */
.shot { position: relative; }
.shot-canvas {
  position: relative; width: 100%; aspect-ratio: 16 / 10; overflow: hidden;
  border: 1px solid var(--border); border-radius: 5px;
  background:
    radial-gradient(560px 320px at 82% 6%, rgba(239, 68, 68, .16), transparent 60%),
    linear-gradient(160deg, var(--bg-soft), var(--bg));
}
.shot-canvas::before {
  content: ""; position: absolute; inset: 10px; pointer-events: none;
  border: 1px dashed var(--border-strong); border-radius: 3px;
}
/* A real capture fills the canvas — the placeholder's dashed inner outline
   must not draw on top of it (progressive: without :has the dashes remain). */
.shot-canvas:has(img)::before { display: none; }
.shot-chip {
  position: absolute; top: 14px; left: 14px; z-index: 1;
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted-2); background: rgba(255, 255, 255, .06); border: 1px solid var(--border);
  border-radius: 999px; padding: 5px 11px;
}
.shot-play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1;
  width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(255, 255, 255, .08); border: 1px solid var(--border-strong);
}
.shot-play svg { width: 20px; height: 20px; fill: var(--text); margin-left: 2px; }
/* Real capture: let the image dictate its own box instead of being cropped
   to fit a placeholder aspect-ratio — full width, natural height, no cover. */
.shot img { width: 100%; height: auto; display: block; }
.shot figcaption { padding: 12px 2px 0; font-size: 13px; color: var(--muted); line-height: 1.5; }
.shot-tv .shot-canvas { aspect-ratio: 16 / 9; }
.shot-kiosk .shot-canvas { aspect-ratio: 4 / 3; }
.shot-video .shot-canvas { aspect-ratio: 16 / 9; }
.shot-video { max-width: 760px; margin: 0 auto; }
.shot-phone { max-width: 250px; margin-inline: auto; }
.shot-phone .shot-canvas { aspect-ratio: 9 / 18; }
/* A real capture's aspect ratio wins over the fixed 16:9/4:3/9:18 placeholder
   ratios above — same (0,2,0) specificity as `.shot-tv .shot-canvas` etc., so
   this must stay LAST among the `.shot-canvas` aspect-ratio rules to win the
   source-order tiebreak. Placeholder canvases (no img) are untouched. */
.shot-canvas:has(img) { aspect-ratio: auto; }
/* Sitting as the media child of `.media-row` in place of `.media-frame`
   (brief.md), or centred alone (`.shot-phone` above) — either way it never
   inherits `.media-frame`'s extra drop-shadow, only the canvas border. */
.media-row .shot { flex: 1 1 46%; margin: 0; }
/* Pricing/CTA band directly under a .steps grid needs its own breathing room. */
.steps + .cta-band { margin-top: 32px; }
/* A second section-head inside the same .section (e.g. "What you need" right
   under a feature grid) needs section-scale air above it. */
.feature-grid + .section-head, .stat-strip + .section-head, .tiers + .section-head { margin-top: 64px; }
/* Four-step run sheets (halls / fundraisers): 2×2 instead of a 3+1 orphan. */
@media (min-width: 761px) { .steps.four { grid-template-columns: repeat(2, 1fr); } }
/* "What you need" strip — five short device labels, not big numbers: smaller
   .n, equal columns, centred, so it reads as one row instead of 4+1. */
.stat-strip.need { gap: 18px 24px; }
.stat-strip.need .stat { flex: 1 1 150px; align-items: center; text-align: center; }
.stat-strip.need .n { font-size: 20px; }


/* Automation-level cards — the platform page's signature "choose your level
   of automation" section. `.tier-hi` (fully automated) gets a soft brand
   glow to read as the default recommendation without extra copy. */
.tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.tier {
  display: flex; flex-direction: column; gap: 12px; text-decoration: none; color: var(--text);
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 26px; transition: transform .16s ease, border-color .16s ease;
}
.tier:hover { transform: translateY(-4px); border-color: var(--border-strong); }
.tier-hi { border-color: rgba(239, 68, 68, .35); box-shadow: 0 24px 60px -30px var(--brand-glow); }
.tier-meter { display: flex; gap: 5px; }
.tier-meter span { width: 26px; height: 6px; border-radius: 999px; background: rgba(255, 255, 255, .08); }
.tier-meter span.on { background: var(--brand); box-shadow: 0 0 12px var(--brand-glow); }
.tier h3 { font-size: 19px; font-weight: 800; }
.tier-staff { font-size: 12.5px; font-weight: 700; color: var(--muted-2); text-transform: uppercase; letter-spacing: .05em; margin: -4px 0 0; }
.tier > p { font-size: 14px; color: var(--muted); line-height: 1.65; margin: 0; }
.tier-good { font-size: 13px; color: var(--muted-2); margin: 0; }
.tier-cta { font-size: 14px; font-weight: 700; color: var(--brand-2); margin-top: auto; }

/* "What's included" cards, now also linkable (`a.feat`, use-case cards on
   the hub) — the bare `.feat` div rules above stay untouched; this just
   makes the anchor variant behave like a card, not a link. `.feat-more`
   is the linkable card's own "See how →" affordance (`.chip-link` already
   covers the runs-on strip; this one sits inside the card, flush bottom). */
a.feat { color: inherit; text-decoration: none; transition: transform .16s ease, border-color .16s ease; }
a.feat:hover { transform: translateY(-4px); border-color: var(--border-strong); }
.feat-more { margin-top: auto; font-size: 13.5px; font-weight: 700; color: var(--brand-2); }
.feature-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }

/* Benefit checklist — inside `.tier`, `.feat`, or `.media-copy`. */
.ticks { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.ticks li { position: relative; padding-left: 24px; font-size: 14px; color: var(--muted); line-height: 1.55; }
.ticks li::before { content: "✓"; position: absolute; left: 0; top: 0; color: var(--brand-2); font-weight: 700; }

/* Hub program board — group heading row (splits the board into "Run the
   game" / "Grow the room"), same lined-board container as `.pb-row`. */
.pb-group {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 13px 26px; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted-2); background: rgba(255, 255, 255, .025); border-bottom: 1px solid var(--border);
}
.pb-group-sub { text-transform: none; font-weight: 500; letter-spacing: 0; color: var(--muted-2); font-size: 12.5px; }

/* .tag-usecase (Bingo Halls, Fundraisers, AutoBingo™'s "Bars & resorts"
   chip) shares `.tag-program`'s look — edited in place above, near the
   other `.tag-*` variants, rather than redeclared here. */

/* Comparison table (platform page: "the old way" vs RojoEvents). */
.compare { overflow-x: auto; }
.compare table { width: 100%; min-width: 560px; border-collapse: collapse; }
.compare th, .compare td { padding: 14px 16px; text-align: left; border-bottom: 1px solid var(--border); font-size: 14px; vertical-align: top; }
.compare thead th { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--muted-2); }
.compare thead th.hi { color: var(--brand-2); }
.compare td.hi { color: var(--text); }
.compare tbody th { width: 22%; color: var(--muted); font-weight: 600; }
.compare tbody tr:last-child th, .compare tbody tr:last-child td { border-bottom: none; }

/* Jump-link row under a split hero (siblings: halls/fundraisers/autobingo/
   FastTrack™ from the platform page). */
.jump { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }

/* Split hero (platform page) — copy left, one `.shot` right; falls back to
   a single column under 900px. The `.shot` here carries no extra shadow
   beyond its own canvas border (brief.md). */
.sol-hero-split .sol-hero-inner {
  max-width: none; display: grid; grid-template-columns: 1.05fr .95fr; gap: 44px; align-items: center;
}
.sol-hero-split .sol-hero-copy { min-width: 0; }

/* Testimonials (hub, `SHOW_TESTIMONIALS`-flagged — off until real quotes
   exist). */
.quote-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.quote { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; }
.quote blockquote { margin: 0; font-size: 15px; color: var(--muted); line-height: 1.65; }
.quote cite { display: block; margin-top: 14px; font-size: 13px; color: var(--muted-2); font-style: normal; }

@media (max-width: 980px) {
  .feature-grid.cols-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
  .tiers { grid-template-columns: 1fr; }
  .quote-grid { grid-template-columns: 1fr; }
  .sol-hero-split .sol-hero-inner { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .tier { padding: 22px; }
}
@media (max-width: 560px) {
  .feature-grid.cols-4 { grid-template-columns: 1fr; }
}
@media (max-width: 420px) {
  .shot-play { width: 46px; height: 46px; }
  .shot-play svg { width: 16px; height: 16px; }
  .compare th, .compare td { padding: 11px 12px; font-size: 13px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Landing (docs/ui/35-homepage-split-and-players-ia.md) — the full-bleed
   split landing at `/`. Reuses existing vocabulary everywhere it can
   (.chip/.chip-row, .live-line, .pulse-dot, .marquee, .section*); this block
   only adds what's genuinely new: full-bleed hero sizing + the two audience
   panels that are the whole point of the page.
   ══════════════════════════════════════════════════════════════════════════ */
.land-hero {
  position: relative; overflow: hidden; min-height: min(72vh, 660px);
  display: flex; align-items: center; justify-content: center; text-align: center;
}
.land-hero-media { position: absolute; inset: 0; z-index: 0; }
.land-hero-media img { width: 100%; height: 100%; object-fit: cover; }
.land-hero-media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(26, 13, 17, .35) 0%, rgba(26, 13, 17, .80) 68%, var(--bg) 100%);
}
.land-hero-inner { position: relative; z-index: 1; max-width: 90%; margin: 0 auto; padding: 64px 24px; }
.land-hero h1 { font-size: clamp(34px, 6vw, 64px); font-weight: 900; }
.land-hero .sub { font-size: clamp(16px, 2.2vw, 20px); color: var(--muted); max-width: 90%; margin: 18px auto 0; }

/* The fork rides the hero's bottom fade — one composition, not two stacked
   sections with a void between them. */
.land-fork { position: relative; z-index: 2; margin-top: -64px; }

/* Live-proof strip wrapper — centers the marquee + "N playing now" line +
   trust chips as ONE compact band (separate sections left a void when the
   marquee has no winners yet). */
.land-proof { text-align: center; }
.land-proof .chip-row { margin-top: 22px; justify-content: center; }
/* Slimmer than .section.tight — this band trails the fork, it doesn't need
   its own full section breathing room. */
.land-proofband { padding: 10px 0 72px; }

/* Two audience blocks — the split's whole job. Each a large linked panel
   (whole-card anchor, same idiom as .room-card used as a link elsewhere). */
.aud-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.aud-panel {
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  text-decoration: none; color: var(--text);
  background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 40px 36px; transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.aud-panel:hover { transform: translateY(-4px); border-color: rgba(239, 68, 68, .4); box-shadow: 0 30px 60px -30px rgba(0, 0, 0, .7); }
.aud-icon {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: 10px; display: grid; place-items: center;
  background: linear-gradient(160deg, rgba(239, 68, 68, .20), rgba(251, 191, 36, .10));
  border: 1px solid rgba(239, 68, 68, .26); color: var(--brand-2);
}
.aud-icon svg { width: 18px; height: 18px; }
.aud-panel h2 { font-size: clamp(25px, 3.2vw, 31px); font-weight: 800; }
.aud-panel p { color: var(--muted); font-size: 15px; line-height: 1.6; margin: 0; }
.aud-live { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--muted); margin: 4px 0 0; }
.aud-cta {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: auto; align-self: flex-start;
  padding: 12px 22px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.04); color: var(--text);
  border: 1px solid var(--border);
  font-size: 16px; font-weight: 800;
  transition: filter .16s ease, box-shadow .16s ease;
}
.aud-panel:hover .aud-cta { text-decoration: none; border-color: var(--border-strong); background: rgba(255, 255, 255, 0.07); }

@media (max-width: 900px) {
  .aud-grid { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .land-hero { min-height: 64vh; }
  .land-hero-inner { padding: 48px 20px; }
}
@media (max-width: 420px) {
  .aud-panel { padding: 28px 22px; }
  .land-hero h1 { font-size: 30px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Slideshow (doc 69 §5 Q3) — a scroll-snap track of `figure.shot` slides,
   fully usable with JS off (a swipeable snap row, no arrows/dots — those
   are injected by site.js so a no-JS visitor never sees a control that
   doesn't work). Reuses `.shot`/`.shot-canvas`/`.shot-tv`/`.shot-phone`
   as-is so slide frames match every other screenshot on the site.
   ══════════════════════════════════════════════════════════════════════════ */
.slides { position: relative; }
.slides-track {
  display: flex; align-items: flex-start; overflow-x: auto; scroll-behavior: smooth;
  scroll-snap-type: x mandatory; scrollbar-width: none; -ms-overflow-style: none;
}
.slides-track::-webkit-scrollbar { display: none; }
.slides-track .slide { flex: 0 0 100%; min-width: 0; scroll-snap-align: center; scroll-snap-stop: always; }
.slides-track .slide .shot { margin: 0; }
.slides-nav { position: absolute; inset: 0; pointer-events: none; }
.slides-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); pointer-events: auto;
  width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
  background: var(--panel); border: 1px solid var(--border-strong); color: var(--text);
  cursor: pointer; transition: background .16s ease, border-color .16s ease;
}
.slides-arrow:hover { background: rgba(255, 255, 255, .08); }
.slides-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.slides-arrow svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.slides-prev { left: 10px; }
.slides-next { right: 10px; }
.slides-dots { display: flex; justify-content: center; gap: 8px; margin-top: 16px; }
.slides-dot { width: 8px; height: 8px; padding: 0; border-radius: 999px; border: none; background: rgba(255, 255, 255, .18); cursor: pointer; }
.slides-dot.on { background: var(--brand-2); }
.slides-dot:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .slides-track { scroll-behavior: auto; }
}
@media (max-width: 420px) {
  .slides-arrow { width: 32px; height: 32px; }
  .slides-arrow svg { width: 14px; height: 14px; }
  .slides-prev { left: 4px; }
  .slides-next { right: 4px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Screenshot lightbox (owner ask, 2026-08-22) — site.js builds a single
   overlay lazily on first click over any `.shot-canvas img`. z-index sits
   above the skip-link (200, the highest existing value) so it always wins.
   Matches the 5px border-radius used on every other screenshot frame
   (`.shot-canvas`). A plain opacity fade only — the global
   `prefers-reduced-motion` block above already kills it outright.
   ══════════════════════════════════════════════════════════════════════════ */
.shot-canvas.shot-zoom { cursor: zoom-in; }
.lightbox {
  position: fixed; inset: 0; z-index: 300; display: flex;
  align-items: center; justify-content: center; padding: 60px;
  background: rgba(0, 0, 0, .92);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .18s ease;
}
.lightbox.open { opacity: 1; visibility: visible; pointer-events: auto; }
.lightbox-body {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  max-width: 100%; max-height: 100%;
}
.lightbox-img {
  max-width: 92vw; max-height: 84vh; width: auto; height: auto;
  object-fit: contain; border-radius: 5px; display: block;
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .7);
}
.lightbox-caption { color: var(--muted); font-size: 13.5px; text-align: center; margin: 0; max-width: 68ch; }
.lightbox-count { color: var(--muted-2); font-size: 12.5px; text-align: center; margin: 0; }
.lightbox-close, .lightbox-arrow {
  position: fixed; z-index: 1; display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--panel-2, rgba(255, 255, 255, .06)); border: 1px solid var(--border-strong); color: var(--text);
  cursor: pointer; transition: background .16s ease, border-color .16s ease;
}
.lightbox-close:hover, .lightbox-arrow:hover { background: rgba(255, 255, 255, .14); }
.lightbox-close:focus-visible, .lightbox-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lightbox-close svg, .lightbox-arrow svg {
  width: 20px; height: 20px; fill: none; stroke: currentColor;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}
.lightbox-close { top: 20px; right: 20px; }
.lightbox-arrow { top: 50%; transform: translateY(-50%); }
.lightbox-prev { left: 20px; }
.lightbox-next { right: 20px; }

@media (max-width: 760px) {
  .lightbox { padding: 20px; }
  .lightbox-close, .lightbox-arrow { width: 36px; height: 36px; }
  .lightbox-close svg, .lightbox-arrow svg { width: 16px; height: 16px; }
  .lightbox-close { top: 10px; right: 10px; }
  .lightbox-prev { left: 8px; }
  .lightbox-next { right: 8px; }
}

/* ── Help Center (wiki, docs/ui/72) ──────────────────────────────────────── */
/* Visually-hidden but accessible — used for the filter input's <label>. */
.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;
}

.help-search { max-width: 480px; margin: 28px auto 0; }
.help-filter-input {
  width: 100%; padding: 12px 16px; border-radius: 10px; border: 1px solid var(--border);
  background: rgba(255, 255, 255, .03); color: var(--text); font-size: 15px; font-family: inherit;
}
.help-filter-input:focus { outline: 2px solid var(--brand-2); outline-offset: 1px; }
.help-filter-hint { font-size: 12.5px; color: var(--muted-2); margin: 8px 0 0; }

.help-crumb { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; font-size: 13px; color: var(--muted); margin: 0 0 14px; }
.help-crumb a { color: var(--muted); text-decoration: none; }
.help-crumb a:hover { color: var(--text); text-decoration: underline; }
.help-crumb .crumb-sep { color: var(--muted-2); margin: 0 2px; }
.help-crumb [aria-current="page"] { color: var(--text); font-weight: 600; }

.help-cat { margin: 0 0 56px; }
.help-cat:last-of-type { margin-bottom: 0; }
.help-cat-head { display: flex; align-items: center; gap: 12px; margin: 0 0 20px; }
.help-cat-icon {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: 9px; display: grid; place-items: center;
  background: rgba(239, 68, 68, .12); border: 1px solid rgba(239, 68, 68, .24); color: var(--brand-2);
}
.help-cat-icon svg { width: 17px; height: 17px; }
.help-cat-head h2 { font-size: 22px; font-weight: 800; margin: 0; }
.help-grid { margin-bottom: 16px; }
.help-extra-links { margin-top: 4px; }

/* Patterns index — ballType section header count + family sub-labels
   (docs/ui/72 follow-up: 198-pattern DB-sourced library, grouped by ballType
   then family so the page stays readable). Reuses .help-cat/.help-cat-head
   for the ballType sections. */
.pattern-total-count { color: var(--muted); font-size: 14px; margin: 10px 0 0; }
.pattern-count-badge {
  display: inline-flex; align-items: center; font-size: 13px; font-weight: 700; color: var(--muted);
  background: rgba(255, 255, 255, .04); border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px; margin-left: 8px; vertical-align: middle;
}
.pattern-family-label { margin: 0 0 12px; }

.help-article-body { max-width: 760px; margin: 0 auto; }
.help-article-body h3 { font-size: 19px; font-weight: 800; margin: 32px 0 12px; }
.help-article-body h3:first-child { margin-top: 0; }
.help-article-body p, .help-article-body ul, .help-article-body ol { color: var(--muted); font-size: 15px; line-height: 1.75; margin: 0 0 14px; }
.help-article-body ul, .help-article-body ol { padding-left: 22px; }
.help-article-body a { color: var(--brand-2); }
.help-article-body strong { color: var(--text); }
/* Wide tables scroll horizontally instead of blowing out the page — the
   content sanitizer whitelist has no wrapper <div>, so this is done purely
   via `table { display: block }`, the standard no-wrapper responsive trick. */
.help-article-body table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; margin: 20px 0; }
.help-article-body th, .help-article-body td { border: 1px solid var(--border); padding: 8px 12px; text-align: left; font-size: 14px; white-space: nowrap; }

@media (max-width: 760px) {
  .help-cat-head h2 { font-size: 19px; }
}
