/* ============================================================
   site.css — structural styles shared by ALL five variants.
   Every color/font/radius comes from custom properties that each
   theme.css sets. Layout mechanics live here so the five themes
   stay visually different but behaviorally identical.
   ============================================================ */

:root {
  --bg: #0b0b0f;
  --bg-accent: #111118;
  --panel: #17171f;
  --panel-2: #20202a;
  --line: #26262f;
  --txt: #f2f2f7;
  --dim: #8e8e9d;
  --accent: #7c5cff;
  --accent-2: #00d4aa;
  --danger: #ff5c8a;
  --radius: 12px;
  --font-body: 16px/1.55 'Segoe UI', system-ui, sans-serif;
  --font-head: inherit;
  --card-art-h: 130px;
  --shell-max: 1200px;
  --shell-pad: clamp(16px, 4vw, 40px);
}

* { margin: 0; box-sizing: border-box; }

body {
  background: var(--bg);
  color: var(--txt);
  font: var(--font-body);
  min-height: 100vh;
}

a { color: inherit; }
img { max-width: 100%; height: auto; }
h1, h2, h3 { font-family: var(--font-head); }

.page-shell { max-width: var(--shell-max); margin: 0 auto; padding: 0 var(--shell-pad) 60px; }

kbd {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1px 7px;
  font-size: 11px;
  color: var(--dim);
}

/* ---------- header / nav ---------- */

.site-header {
  display: flex; align-items: center; gap: 26px;
  padding: 14px var(--shell-pad);
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.logo { font-weight: 900; font-size: 21px; letter-spacing: 1px; text-decoration: none; }
.main-nav { display: flex; gap: 18px; flex-wrap: wrap; }
.main-nav a {
  color: var(--dim); text-decoration: none; font-size: 14px;
  letter-spacing: .5px; transition: color .15s;
}
.main-nav a:hover, .main-nav a.on { color: var(--txt); }

.search-trigger {
  margin-left: auto; display: flex; align-items: center; gap: 10px;
  background: var(--panel); border: 1px solid var(--line); color: var(--dim);
  border-radius: 10px; padding: 8px 14px; min-width: 220px;
  font: inherit; font-size: 13.5px; cursor: pointer; text-align: left;
}
.search-trigger.inline { min-width: 0; margin-left: 0; }
.search-trigger:hover { border-color: var(--accent); }
.search-trigger span { flex: 1; }

/* Member sign-out (partials/member-signout): logout is POST-only, so the
   control is a <form> button dressed as a nav link. --dim/--txt only — every
   theme defines both; bespoke-chrome themes restyle it in their theme.css. */
.member-signout { display: inline-flex; }
.member-signout button {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: 14px; letter-spacing: .5px;
  color: var(--dim); transition: color .15s;
}
.member-signout button:hover { color: var(--txt); }
/* second surface on /my/history — 3 themes hide .main-nav on phones */
.category-head .member-signout { margin-top: 10px; }

/* ---------- hero / stats ---------- */

.hero { text-align: center; padding: 56px 0 34px; position: relative; z-index: 1; }
.hero h1 { font-size: clamp(30px, 5vw, 54px); letter-spacing: -.5px; }
.hero-sub { color: var(--dim); max-width: 54ch; margin: 14px auto 26px; }
.cta {
  display: inline-block; background: var(--accent); color: var(--bg);
  font-weight: 800; letter-spacing: 1px; text-decoration: none;
  padding: 13px 34px; border-radius: 10px; transition: transform .15s, box-shadow .15s;
}
.cta:hover { transform: translateY(-2px); }
/* Registration CTAs are <button>s, not links: `register` is a POST-only route
   (Clean Registration happens in the clouded pop-open), so an href there 404s.
   Buttons don't inherit page typography, hence the reset. */
button.cta, button.ghost { font: inherit; border: 0; cursor: pointer; }
button.cta { font-weight: 800; letter-spacing: 1px; }
button.ghost { border: 1px solid var(--line); }
.linklike {
  background: none; border: 0; padding: 0; font: inherit; color: var(--accent-2);
  text-decoration: underline; cursor: pointer;
}
.stats { display: flex; gap: 34px; justify-content: center; margin-top: 30px; flex-wrap: wrap; }
.stat b { font-size: 24px; display: block; color: var(--accent-2); }
.stat span { font-size: 12px; color: var(--dim); text-transform: uppercase; letter-spacing: 1px; }

/* ---------- experience strip (home) ---------- */

.exp-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px; padding: 8px 0 4px; position: relative; z-index: 1;
}
.exp {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 18px; display: flex; flex-direction: column; gap: 6px;
}
.exp b { font-size: 14.5px; }
.exp > span:last-child { color: var(--dim); font-size: 12.5px; line-height: 1.45; }
.exp-glyph {
  width: 34px; height: 34px; border-radius: 9px; position: relative;
  border: 2px solid var(--accent-2); opacity: .9; margin-bottom: 2px;
}
.exp-glyph.play::after {
  content: ""; position: absolute; left: 12px; top: 8px;
  border-left: 11px solid var(--accent-2); border-block: 7px solid transparent;
}
.exp-glyph.save::after {
  content: ""; position: absolute; inset: 7px 7px 12px;
  border: 2px solid var(--accent-2); border-radius: 2px;
}
.exp-glyph.save::before {
  content: ""; position: absolute; left: 11px; bottom: 6px; width: 8px; height: 4px;
  background: var(--accent-2);
}
.exp-glyph.pad::after {
  content: ""; position: absolute; left: 6px; top: 12px; width: 6px; height: 6px;
  background: var(--accent-2); box-shadow: 12px 0 0 var(--accent-2);
  border-radius: 50%;
}
.exp-glyph.pad::before {
  content: ""; position: absolute; left: 13px; top: 8px; width: 4px; height: 14px;
  background: var(--accent-2);
}
.exp-glyph.shield::after {
  content: ""; position: absolute; left: 10px; top: 7px; width: 10px; height: 13px;
  border: 2px solid var(--accent-2); border-radius: 50% 50% 50% 50% / 20% 20% 70% 70%;
}

/* ---------- spotlights (home trio) ---------- */

.spotlights { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
.spot {
  background: var(--panel); border: 1px solid var(--line); border-radius: calc(var(--radius) + 2px);
  padding: 20px; text-decoration: none; display: flex; flex-direction: column; gap: 8px;
  transition: transform .18s, border-color .18s;
}
.spot:hover { transform: translateY(-4px); border-color: var(--accent); }
.spot-kick { font-size: 11px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; color: var(--accent-2); }
.spot b { font-size: 18px; }
.spot p { color: var(--dim); font-size: 13.5px; flex: 1; }
.spot-play { color: var(--accent); font-weight: 700; font-size: 13px; }

/* ---------- full library groups (home) ---------- */

.library-group { margin: 18px 0 26px; }
.library-group h3 { font-size: 16px; margin-bottom: 12px; }
.library-group h3 a { text-decoration: none; }
.library-group h3 a:hover { color: var(--accent); }
.lib-count { color: var(--dim); font-size: 12px; font-weight: 400; margin-left: 8px; }

/* ---------- feature banner ---------- */

.feature-banner {
  margin: 22px 0; border-radius: calc(var(--radius) + 6px); overflow: hidden;
  background: linear-gradient(115deg, var(--panel-2), var(--panel));
  border: 1px solid var(--line);
  display: flex; align-items: flex-end; min-height: 230px; position: relative; z-index: 1;
}
.fmeta { padding: 28px; max-width: 560px; }
.fkick { font-size: 11px; font-weight: 800; letter-spacing: 2px; color: var(--accent-2); text-transform: uppercase; }
.fmeta h2 { font-size: 32px; margin: 6px 0 10px; }
.fmeta p { color: var(--dim); margin-bottom: 16px; }
.fbtns { display: flex; gap: 12px; }
.playbig {
  background: var(--txt); color: var(--bg); border: 0; font-weight: 800;
  border-radius: 10px; padding: 11px 26px; cursor: pointer; text-decoration: none; font-size: 15px;
}
.playbig:hover { background: var(--accent-2); }
.ghost {
  background: transparent; color: var(--txt); border: 1px solid var(--line);
  border-radius: 10px; padding: 11px 18px; text-decoration: none; font-size: 14px;
}
.fstats { display: flex; gap: 16px; margin-top: 14px; font-size: 12px; color: var(--dim); flex-wrap: wrap; }

/* A brand or title with no spaces — "RetroPlayers.Club" — is a single
   unbreakable word. In a heading at phone widths it ran past the viewport and
   gave the whole page a horizontal scrollbar (measured: a 455px H1 inside a
   328px column). Headings may break inside a word when there is no alternative. */
h1, h2, h3, .lane-title, .legal-body h2 { overflow-wrap: break-word; }

/* ---------- sign in ---------- */

.auth-shell { display: flex; justify-content: center; padding: 54px 0 70px; }
.auth-panel {
  width: min(430px, 94vw); background: var(--panel, var(--bg-accent, #140b2e));
  border: 1px solid var(--line); border-radius: 16px; padding: 30px 30px 26px;
  box-shadow: 0 0 40px rgba(0, 0, 0, .45);
}
.auth-panel h1 { font-size: 27px; margin: 2px 0 18px; }
.auth-form { display: flex; flex-direction: column; }
.auth-form label { font-size: 12px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--dim); margin-bottom: 6px; }
.auth-form input {
  background: rgba(0, 0, 0, .35); border: 1px solid var(--line); border-radius: 9px;
  color: var(--txt); padding: 11px 13px; font: inherit; margin-bottom: 16px;
}
.auth-form input:focus { outline: 2px solid var(--accent-2); outline-offset: 1px; }
.auth-form .cta { width: 100%; text-align: center; border: 0; cursor: pointer; margin-top: 2px; }
/* R263 (David 2026-10-14): "one of those 'eye icons' to the right they can click so that we
   can show them the password they are typing in" - site.js wraps EVERY password field on the
   site (sign-in page, the registration pop-open's register + sign-in steps, the password-reset
   page) in .pw-wrap and adds the .pw-eye button. The wrapper takes over the field's own
   vertical margins (moved by site.js) so the eye sits centred on the box on every theme. */
.pw-wrap { position: relative; display: block; }
.pw-wrap > input { display: block; width: 100%; box-sizing: border-box; padding-right: 50px !important; }
.pw-eye {
  position: absolute; right: 7px; top: 50%; transform: translateY(-50%);
  width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 0; border-radius: 8px; padding: 0; margin: 0;
  color: inherit; opacity: .55; cursor: pointer; line-height: 0;
}
.pw-eye:hover, .pw-eye.is-on { opacity: 1; }
.pw-eye:focus-visible { opacity: 1; outline: 2px solid currentColor; outline-offset: 1px; }
.pw-eye svg { width: 22px; height: 22px; display: block; }
.auth-error {
  background: rgba(255, 45, 149, .12); border: 1px solid var(--accent);
  border-radius: 9px; padding: 10px 13px; margin-bottom: 16px; font-size: 14px;
}
.auth-ok {
  background: rgba(74, 222, 128, .12); border: 1px solid rgba(74, 222, 128, .55);
  border-radius: 9px; padding: 10px 13px; margin-bottom: 16px; font-size: 14px;
}
.auth-resend { margin-top: 14px; font-size: 13.5px; color: var(--dim); }
.auth-resend summary { cursor: pointer; padding: 6px 0; }
.auth-resend[open] summary { margin-bottom: 8px; }
.auth-resend .auth-form { margin-top: 6px; }
.auth-alt { font-size: 13.5px; color: var(--dim); margin-top: 14px; line-height: 1.6; }

/* ---------- club pages (about / privacy / dmca) ---------- */

.legal-hero { padding: 46px 0 10px; max-width: 78ch; text-align: left; }
.legal-hero h1 { font-size: 38px; line-height: 1.1; margin-bottom: 10px; }
/* .hero-sub is centred+inset for the home hero; these pages read as documents,
   so it aligns with the h1 instead of floating in from the left margin. */
.legal-hero .hero-sub { margin: 0; padding: 0; max-width: 70ch; text-align: left; }
.legal-updated { font-size: 12px; color: var(--dim); text-transform: uppercase; letter-spacing: 1.5px; margin-top: 14px; }
.legal-body { max-width: 78ch; padding-bottom: 60px; }
.legal-body h2 {
  font-size: 15px; text-transform: uppercase; letter-spacing: 2.5px;
  color: var(--accent-2); margin: 32px 0 10px;
}
.legal-body p { margin-bottom: 14px; line-height: 1.75; }
.legal-list { margin: 0 0 16px 22px; }
.legal-list li { margin-bottom: 9px; line-height: 1.7; }
/* An operator detail that is not filled in yet says so, loudly, rather than
   printing an invented address a rights holder would send notices into. */
.legal-pending {
  display: inline-block; background: rgba(255, 209, 102, .12); border: 1px dashed #ffd166;
  color: #ffd166; border-radius: 6px; padding: 2px 9px; font-size: 13px;
}

/* R200 — the seven client-written club pages.

   .legal-body h3 exists for the one sub-heading in the set (the Privacy
   Policy's California notice); without it that heading inherited nothing and
   rendered at the same weight as body copy, so a distinct section read as a
   run-on paragraph.

   .legal-notice carries the ALL-CAPS conspicuous blocks — the warranty
   disclaimer, the limitation of liability, the "ALL SALES ARE FINAL" notice.
   Those capitals are a legal convention (a disclaimer has to be conspicuous to
   bind), so they are never sentence-cased in the markup; the job here is to
   make a wall of capitals READABLE: full body colour rather than the dim grey,
   a little extra letter-spacing and line-height, and a rule down the left so
   the eye can see where the block starts and ends. */
.legal-body h3 {
  font-size: 14px; letter-spacing: 1px; color: var(--accent);
  margin: 26px 0 8px; font-weight: 700;
}
.legal-notice {
  border-left: 3px solid var(--accent-2);
  background: rgba(255, 255, 255, .03);
  padding: 13px 16px; margin: 18px 0 16px; border-radius: 0 6px 6px 0;
  font-size: 13px; letter-spacing: .3px; line-height: 1.85;
}
/* Eight footer links wrap on a phone; without an explicit line-height the
   wrapped rows sit on top of each other at the footer's 12.5px base. */
.footer-links { line-height: 2; }
/* David closes the About copy with "Live Long, and Play Retro!" — a sign-off,
   not a body paragraph. Given a little air and the accent colour it reads as
   one; left as a plain <p> it looked like a sentence someone forgot to finish. */
.legal-signoff {
  margin-top: 26px; color: var(--accent); font-size: 16px;
  letter-spacing: .6px; font-weight: 700;
}

/* ---------- lanes / cards ---------- */

.lane { padding: 26px 0; position: relative; z-index: 1; }
.lane-title {
  font-size: 15px; text-transform: uppercase; letter-spacing: 2.5px;
  color: var(--accent); margin-bottom: 16px;
}
.card-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(165px, 1fr)); gap: 16px;
}
.game-card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; text-decoration: none; transition: transform .18s, border-color .18s, box-shadow .18s;
  display: block; position: relative;
}
.game-card:hover { transform: translateY(-5px); border-color: var(--accent); }
.game-card .art {
  height: var(--card-art-h); position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(140deg, var(--panel-2), var(--bg-accent));
}
.game-card .art img { width: 100%; height: 100%; object-fit: cover; }
/* R170 attract tiles: the marked card's <video> occupies exactly the img's
   box; pointer-events off so every click lands on the wrapping card link. */
.game-card .art video { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; background: #000; }
/* ==========================================================================
   R191-BANDS — David's pick: #2 FADEBAND (2026-08-31). Alternating title
   bands on result-grid thumbnails: translucent dark band fading INTO the
   art, white title, accent console chip; TOP band on odd cells, BOTTOM on
   even ("top of one thumbnail and then the bottom of the other
   sequentially"). Opt-in per grid via .band-grid on the grid container +
   the .tb-band span inside each cell's media box (.game-card .art or the
   .wall-cell itself), so unrelated game-card uses stay untouched. Rides
   OVER the R170 attract-tile <video>; pointer-events none keeps the whole
   cell one click target. Black-gradient + white text = safe on all themes.
   ========================================================================== */
.tb-band {
  position: absolute; left: 0; right: 0; z-index: 3;
  display: flex; align-items: flex-end; gap: 8px;
  pointer-events: none; min-height: 34px; padding: 5px 9px;
  color: #fff;
}
.tb-title { font-style: normal; font-weight: 700; font-size: 12.5px; line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.tb-console { font-style: normal; font-weight: 700; font-size: 10px; letter-spacing: .08em;
  flex: 0 0 auto; background: color-mix(in srgb, var(--accent) 80%, #000); color: #fff;
  padding: 1px 6px; border-radius: 3px; }
.band-grid > :nth-child(odd) .tb-band {
  top: 0; align-items: flex-start;
  background: linear-gradient(rgba(0, 0, 0, .85), transparent);
}
.band-grid > :nth-child(even) .tb-band {
  bottom: 0;
  background: linear-gradient(transparent, rgba(0, 0, 0, .85));
}
/* Search wall cells: the band replaces the old hover-only title overlay. */
.band-grid .wall-cell > b { display: none; }
/* R191b (David 2026-08-31, live-vs-mockup): mobile grids are TWO WIDE
   columns, not shrunken desktop cells — the first cut hid the console chip
   under 520px and kept the 34px fade, which read as a different design on
   his phone. The chip stays ALWAYS (it is part of the approved look), and
   the band scales UP with the taller mobile cells so the fade keeps the
   mockup's proportion. */
@media (max-width: 820px) {
  .tb-band { min-height: 48px; padding: 7px 10px; }
  .tb-title { font-size: 13px; }
}

/* R175-TAGS — "This Game is Also Known As:" line under the FAQ. Inline links
   in the heading, theme accent, readable weight at body scale. */
.aka-tags { margin-top: 22px; }
.aka-head { font-size: 15px; line-height: 1.8; font-weight: 700; }
.aka-head a { color: var(--accent); text-decoration: underline; font-weight: 600; white-space: nowrap; }
.art-initials { font-size: 34px; font-weight: 900; color: var(--dim); letter-spacing: 2px; }
[data-fallback-art="0"] { background: linear-gradient(135deg, #b13a5e, #4a1230); }
[data-fallback-art="1"] { background: linear-gradient(135deg, #2c66c4, #101c45); }
[data-fallback-art="2"] { background: linear-gradient(135deg, #c98a12, #3d2703); }
[data-fallback-art="3"] { background: linear-gradient(135deg, #1d8a4a, #07260f); }
[data-fallback-art="4"] { background: linear-gradient(135deg, #7a3aa8, #1e0b33); }
[data-fallback-art="5"] { background: linear-gradient(135deg, #17939d, #062a2e); }
.play-hover {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 70%, transparent);
  color: var(--accent-2); font-weight: 800; letter-spacing: 2px; font-size: 13px;
  opacity: 0; transition: opacity .18s;
}
.game-card:hover .play-hover { opacity: 1; }
.game-card .meta { padding: 10px 12px; }
.game-card .meta b {
  font-size: 13.5px; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.game-card .sub {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 6px; color: var(--dim); font-size: 11px;
}
.tag {
  font-size: 10.5px; color: var(--bg); background: var(--accent-2);
  border-radius: 4px; padding: 1px 7px; font-weight: 800; letter-spacing: 1px;
}

/* ---------- console tiles ---------- */

.console-row { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 8px; }
.console-tile {
  min-width: 126px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px; text-align: center;
  text-decoration: none; transition: border-color .15s, transform .15s;
}
.console-tile:hover { border-color: var(--accent); transform: translateY(-3px); }
.console-tile svg { width: 30px; height: 30px; }
.console-tile b { display: block; font-size: 13px; margin-top: 8px; }
.console-tile span { font-size: 11px; color: var(--dim); }

/* ---------- console category hero ---------- */

.cat-hero {
  display: grid; grid-template-columns: 1.15fr .85fr; gap: 30px;
  margin: 22px 0; padding: 30px; align-items: center;
  background: linear-gradient(115deg, var(--panel-2), var(--panel));
  border: 1px solid var(--line); border-radius: calc(var(--radius) + 6px);
  position: relative; z-index: 1; overflow: hidden;
}
.cat-kick {
  font-size: 11px; font-weight: 800; letter-spacing: 2px;
  text-transform: uppercase; color: var(--accent-2); margin-bottom: 8px;
}
.cat-hero h1 { font-size: clamp(26px, 4vw, 42px); }
.cat-blurb { color: var(--dim); margin: 12px 0; max-width: 56ch; font-size: 16px; }
.cat-cta-row { display: flex; gap: 12px; margin-top: 16px; flex-wrap: wrap; align-items: center; }
.cat-cta-row .playbig, .cat-cta-row .ghost { text-decoration: none; display: inline-block; }

.cat-glyph-panel {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 26px; border: 1px solid var(--line); border-radius: var(--radius);
  background: color-mix(in srgb, var(--bg) 40%, transparent);
}
.console-glyph.big { width: 120px; height: 78px; border-width: 4px; border-radius: 16px; color: var(--accent); }
.console-glyph.big::before { left: 18px; width: 26px; height: 26px; border-width: 4px; }
.console-glyph.big::after { right: 20px; width: 16px; height: 16px; box-shadow: -26px 0 0 -2px currentColor; }
.cat-glyph-name { font-weight: 900; letter-spacing: 4px; font-size: 18px; color: var(--accent); }
.cat-chips { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.cat-chip {
  font-size: 11px; font-weight: 700; letter-spacing: .5px;
  border: 1px solid var(--line); border-radius: 99px; padding: 4px 12px; color: var(--dim);
}
.cat-chip.beta { border-color: var(--danger); color: var(--danger); }

/* genre chips */
.chip-row { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
  font-size: 12.5px; border: 1px solid var(--line); border-radius: 99px;
  padding: 5px 14px; color: var(--dim); text-decoration: none; transition: .15s;
}
.chip:hover { color: var(--txt); border-color: var(--accent); }
.chip.on { color: var(--bg); background: var(--accent); border-color: var(--accent); font-weight: 700; }

/* Genre filter — collapsed by default so the game grid stays above the fold
   (R192, David: the flat ~40-chip list pushed all live games down on mobile). */
.genre-filter { margin: 12px 0 2px; }
.genre-toggle {
  display: inline-flex; align-items: center; gap: 9px; cursor: pointer;
  list-style: none; user-select: none; -webkit-tap-highlight-color: transparent;
  font-size: 12.5px; color: var(--dim);
  border: 1px solid var(--line); border-radius: 99px; padding: 6px 15px;
  transition: color .15s, border-color .15s;
}
.genre-toggle::-webkit-details-marker { display: none; }
.genre-toggle::before {
  content: ""; width: 0; height: 0; flex: 0 0 auto;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform .15s;
}
.genre-filter[open] > .genre-toggle::before { transform: rotate(90deg); }
.genre-toggle:hover { color: var(--txt); border-color: var(--accent); }
.genre-toggle-active { color: var(--accent); font-weight: 700; }
.genre-toggle-active::before { content: "· "; color: var(--dim); font-weight: 400; }
.genre-toggle-count {
  font-size: 11px; line-height: 1; padding: 3px 7px; border-radius: 99px;
  background: var(--line); color: var(--dim);
}
.genre-filter > .chip-row { margin-top: 12px; }

/* empty shelf */
.cat-empty {
  text-align: center; padding: 40px 24px; margin: 22px 0;
  border: 1px dashed var(--line); border-radius: calc(var(--radius) + 6px);
  position: relative; z-index: 1;
}
.cat-empty .console-glyph.big { margin: 0 auto 14px; color: var(--dim); }
.cat-empty h2 { font-size: 24px; }
.cat-empty > p { color: var(--dim); max-width: 62ch; margin: 12px auto 0; }
.cat-empty .card-grid { text-align: initial; margin-top: 14px; }

@media (max-width: 820px) {
  .cat-hero { grid-template-columns: 1fr; }
  .cat-glyph-panel { order: -1; }
}

/* ---------- breadcrumbs / category ---------- */

.breadcrumbs { padding: 18px 0 0; font-size: 12.5px; color: var(--dim); position: relative; z-index: 1; }
.breadcrumbs a { color: var(--dim); text-decoration: none; }
.breadcrumbs a:hover { color: var(--txt); }

.category-head { padding: 22px 0 6px; position: relative; z-index: 1; }
.category-head h1 { font-size: clamp(26px, 4vw, 40px); }
.category-sub { color: var(--dim); margin: 10px 0; max-width: 70ch; }
.category-toolbar {
  display: flex; align-items: center; gap: 18px; margin-top: 14px;
  padding: 10px 0; border-block: 1px solid var(--line); font-size: 13px;
}
.category-toolbar .count { color: var(--dim); }
.sorts { margin-left: auto; display: flex; gap: 12px; }
.sorts a { color: var(--dim); text-decoration: none; }
.sorts a.on { color: var(--accent); font-weight: 700; }

/* ---------- game page ---------- */

.game-head { padding: 20px 0 4px; position: relative; z-index: 1; }
.game-head h1 { font-size: clamp(26px, 4vw, 40px); }
.game-facts { display: flex; gap: 10px; align-items: center; margin: 12px 0; flex-wrap: wrap; font-size: 13px; color: var(--dim); }
.seo-intro { max-width: 76ch; color: var(--txt); }
.seo-intro p { margin: 10px 0; }

.player-zone { position: relative; margin: 22px 0; z-index: 1; }
.player-frame {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: calc(var(--radius) + 4px); overflow: hidden;
  transition: filter .35s;
}
.game-screen { aspect-ratio: 4 / 3; max-height: 70vh; width: 100%; background: #000; position: relative; }
/* R157 (David live): DS renders PORTRAIT — two 256x192 screens stacked = 2:3. In the shared
   4:3 landscape box it letterboxed to ~30% of the width; give melonds (DS) a tall portrait
   window instead. Desktop is height-bound (fill ~88vh, width follows the 2:3, centered — no
   black side-bars); mobile portrait is width-bound (fill the phone width, height follows).
   Landscape phones keep the existing height rule below. Verified: desktop 1118x504 -> 422x634
   (+26% taller), mobile 375x503 -> 375x563 (fills width, true 2:3). */
.player-zone[data-core="melonds"]:not(.is-mobile) .game-screen {
  aspect-ratio: 2 / 3; height: 88vh; max-height: 88vh;
  width: auto; max-width: 100%; margin-inline: auto;
}
@media (orientation: portrait) {
  .player-zone[data-core="melonds"].is-mobile .game-screen {
    aspect-ratio: 2 / 3; width: 100%; height: auto; max-height: 90vh;
  }
}
.emulator-frame { width: 100%; height: 100%; border: 0; display: block; }
.boot-state {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px; text-align: center;
}
/* R100.4 (David): "Screenshots should show fast while the 'games show a
   loading bar'" — the action screenshot is the INSTANT full-frame backdrop of
   every loading state (it is a small, fetchpriority=high image, so it paints
   long before any core/ROM/FMV byte arrives). Text + progress ride above it. */
.boot-art { position: absolute; inset: 0; margin: 0; }
.boot-art img {
  width: 100%; height: 100%; max-height: none; object-fit: cover;
  opacity: .45; filter: saturate(.9); transition: opacity .5s ease;
}
.boot-text, .boot-progress, .boot-mascot { position: relative; }
/* R201 (David 2026-09-02): the overlay no longer prints a two-word status — it
   rotates his ten STATEMENTS, so the old blinking 2px-tracked Courier had to
   go (a blinking sentence is unreadable, and the tracking broke it over three
   ragged lines). Colour still comes from each theme's own .boot-text rule;
   loading-messages.js adds .rpc-load-msg for the size, measure and crossfade. */
.boot-text {
  color: var(--accent-2); max-width: 34ch; padding: 0 14px;
  font: 600 15px/1.45 system-ui, -apple-system, 'Segoe UI', sans-serif;
  letter-spacing: .2px; text-wrap: balance;
  /* A whole sentence has to survive whatever the action screenshot behind it is
     doing — the old two-word label could get away with none of this. */
  text-shadow: 0 1px 10px rgba(0, 0, 0, .9), 0 0 3px rgba(0, 0, 0, .85);
}
/* Soft pool of shade under the statement + bar so they read over a bright shot.
   Sits below both (they are position:relative, this is the first child). */
.boot-state::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 70% 45% at 50% 60%,
              rgba(4, 2, 10, .74), rgba(4, 2, 10, .34) 62%, transparent 82%);
}
/* boot-blink is NO LONGER used by .boot-text (R201) but three other rules still
   ride it — the remap "listening" key, the USB-pad flash, and the live badge —
   so the keyframes stay. */
@keyframes boot-blink { 50% { opacity: .3; } }
/* The animated seal (#7) / stick-figure dancer (#10) sit right above the bar.
   Colour is INHERITED, never var(--accent-2): the five themes disagree about
   what that token is, and playdeck's is #16161a — a near-black mascot on a dark
   scrim, i.e. the invisible-on-2-of-5-themes bug this project has shipped
   before. loading-messages.js additionally copies the computed colour of the
   statement itself onto this element, so the art always matches the words. */
.boot-mascot { color: inherit; line-height: 0; }
.boot-mascot:empty { display: none; }
@media (max-width: 560px) { .boot-text { font-size: 14px; max-width: 26ch; } }
/* Honest experimental-core notice (round-26) — sits above the game canvas so a
   visitor is told PS2/Play! is early-beta rather than shown a slideshow that
   never becomes playable. */
.emu-experimental {
  position: absolute; top: 0; left: 0; right: 0; z-index: 6;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 16px; text-align: left;
  background: color-mix(in srgb, #b8860b 30%, color-mix(in srgb, var(--bg) 82%, transparent));
  border-bottom: 1px solid color-mix(in srgb, #f6c453 55%, transparent);
  backdrop-filter: blur(2px);
}
.emu-experimental-badge {
  flex: 0 0 auto; font-size: 11px; font-weight: 900; letter-spacing: 2px;
  color: #ffd873; border: 1px solid #f6c453; border-radius: 99px; padding: 4px 12px;
  white-space: nowrap;
}
.emu-experimental p { margin: 0; color: var(--fg, #eee); font-size: 12.5px; line-height: 1.45; max-width: 68ch; }

/* Native desktop full-speed CTA (round-28 PS2 handback) — sits under the
   experimental notice as the real play path for heavy PS2 titles. */
.native-desktop-cta {
  margin: 12px 0; padding: 16px 18px; border-radius: 12px; text-align: left;
  background: color-mix(in srgb, var(--accent, #39c0ff) 12%, color-mix(in srgb, var(--bg) 88%, transparent));
  border: 1px solid color-mix(in srgb, var(--accent, #39c0ff) 45%, transparent);
}
.native-cta-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 6px; }
.native-cta-head strong { font-size: 15px; color: var(--fg, #fff); }
.native-cta-badge {
  flex: 0 0 auto; font-size: 11px; font-weight: 900; letter-spacing: 1.5px;
  color: var(--accent, #39c0ff); border: 1px solid color-mix(in srgb, var(--accent, #39c0ff) 60%, transparent);
  border-radius: 99px; padding: 3px 11px; white-space: nowrap;
}
.native-cta-body { margin: 0 0 10px; color: var(--fg, #ddd); font-size: 13px; line-height: 1.5; max-width: 70ch; }
.native-cta-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.pbtn-native { background: var(--accent, #39c0ff); color: #06121a; font-weight: 800; }
.native-cta-launch { font-size: 12.5px; text-decoration: underline; }
.native-cta-soon { margin: 0; font-size: 13px; font-weight: 700; color: var(--accent, #39c0ff); }
.native-cta-note { margin: 10px 0 0; font-size: 11.5px; color: color-mix(in srgb, var(--fg, #ccc) 70%, transparent); line-height: 1.4; }

/* ============================================================================
   Round-29 NATIVE-DOWNLOAD HERO (PS2 + Dreamcast).
   Fills the game-screen with a looping gameplay FMV; the "Download Our Mini App"
   CTA sits over a scrim. Uses the theme CSS vars so it styles across all five
   variants. When no FMV asset exists yet, the media area falls back to an
   on-brand gradient slate (never fabricated gameplay).
   ============================================================================ */
.native-hero { position: absolute; inset: 0; display: flex; align-items: flex-end; overflow: hidden; }
.native-hero-media {
  position: absolute; inset: 0; z-index: 0;
  background: radial-gradient(130% 120% at 50% 0%, color-mix(in srgb, var(--accent, #39c0ff) 24%, var(--panel)) 0%, var(--panel) 72%);
}
.native-hero-video, .native-hero-still { width: 100%; height: 100%; object-fit: cover; display: block; }
.native-hero-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--bg) 12%, transparent) 0%,
    color-mix(in srgb, var(--bg) 40%, transparent) 42%,
    color-mix(in srgb, var(--bg) 90%, transparent) 100%);
}
.native-hero-body {
  position: relative; z-index: 2; width: 100%;
  padding: clamp(16px, 4vw, 34px);
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
}
.native-hero-badge {
  font-size: 11px; font-weight: 900; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--accent, #39c0ff);
  border: 1px solid color-mix(in srgb, var(--accent, #39c0ff) 60%, transparent);
  border-radius: 99px; padding: 4px 12px;
  background: color-mix(in srgb, var(--bg) 55%, transparent);
}
.native-hero-title { margin: 2px 0 2px; font-size: clamp(20px, 3.4vw, 30px); color: #fff; text-shadow: 0 2px 18px rgba(0, 0, 0, .6); }
.native-hero-cta {
  display: inline-block; max-width: 100%;
  background: var(--accent, #39c0ff); color: #06121a; font-weight: 800;
  font-size: clamp(14px, 1.7vw, 16px); line-height: 1.25;
  padding: 13px 22px; border-radius: 12px; text-decoration: none;
  box-shadow: 0 10px 30px color-mix(in srgb, var(--accent, #39c0ff) 40%, transparent);
  transition: transform .12s ease, box-shadow .12s ease;
  animation: native-cta-pulse 2.6s ease-in-out infinite;
}
.native-hero-cta:hover { transform: translateY(-1px); box-shadow: 0 14px 40px color-mix(in srgb, var(--accent, #39c0ff) 58%, transparent); }
.native-hero-cta.is-soon {
  background: color-mix(in srgb, var(--accent, #39c0ff) 42%, var(--panel));
  color: #fff; cursor: default; box-shadow: none; animation: none;
}
@keyframes native-cta-pulse {
  0%, 100% { box-shadow: 0 10px 30px color-mix(in srgb, var(--accent, #39c0ff) 34%, transparent); }
  50% { box-shadow: 0 12px 42px color-mix(in srgb, var(--accent, #39c0ff) 62%, transparent); }
}
.native-hero-launch { color: var(--accent-2, #ffd873); font-size: 13px; text-decoration: none; }
.native-hero-launch:hover { text-decoration: underline; }
.native-hero-soon { margin: 0; font-size: 13px; color: #e9e9ef; max-width: 66ch; line-height: 1.5; text-shadow: 0 1px 8px rgba(0, 0, 0, .5); }
.native-hero-soon a { color: var(--accent-2, #ffd873); }
.native-hero-note { margin: 4px 0 0; font-size: 12px; color: #cfd2da; line-height: 1.5; max-width: 72ch; text-shadow: 0 1px 8px rgba(0, 0, 0, .5); }

/* R62.2 — APP MODE: the RetroPlayers.Club Player renders this same branded page
   in its own window. R66 rework: the game runs IN THE PAGE FRAME (.app-stage —
   the Player embeds the emulator window over that exact box), with the
   web-style controller information bar (.app-ctx) beneath it. Full screen is
   the bar's button; nothing boots fullscreen. */
.app-mode-page .story-comments-grid { grid-template-columns: 1fr; }
/* The web .game-screen is a fixed 4:3 box — in app mode it holds the stage +
   the controller bar stacked, so it must grow with them or the bar is clipped
   below the box (caught by the R66 screenshot proof). */
.app-mode-page .game-screen { aspect-ratio: auto; max-height: none; height: auto; }
.app-shell { display: flex; flex-direction: column; gap: 0; }
.app-stage { position: relative; aspect-ratio: 16 / 9; min-height: 320px; background: #000; border-radius: 14px 14px 0 0; overflow: hidden; }
/* R164 (David, 2026-08-21, twice in one session — supersedes R104.1): the
   Live Game Window "should stay Static to the FMV Window", i.e. anchored to
   the page slot the FMV occupied, NOT to the viewport. The R104.1
   position:FIXED pin held the game glued to the viewport, so scrolling down
   to reach the controller configuration slid the page's own options UNDER the
   pinned game — his screenshot: the window covering the mid-page while the
   game cards peeked out below. The stage now stays IN FLOW (like the FMV it
   replaces); the app tracks it via frame-rect scroll reports, THROTTLED in
   game.blade.php so the R103.1 reposition flood ("slows down the game")
   cannot come back. The old R104.1 lesson about sticky is kept for history:
   position:sticky had no travel room inside .app-shell and rode the scroll —
   do not resurrect sticky here; in-flow + native tracking is the contract. */
.app-stage-holder { display: none; }
/* R104.3: the DC "you will Need to Restart" YES/NO prompt (David's copy). */
.app-restart-ask { position: fixed; inset: 0; z-index: 4200; display: grid; place-items: center; background: rgba(4,4,10,.72); }
.app-restart-card { max-width: 460px; padding: 22px 24px; border-radius: 14px; background: #14141c; border: 1px solid #33334a; box-shadow: 0 24px 60px rgba(0,0,0,.6); text-align: center; }
.app-restart-card p { margin: 0 0 16px; font-weight: 700; line-height: 1.45; color: #f0f0f7; }
.app-restart-row { display: flex; gap: 12px; justify-content: center; }
/* R254b: under the screen-shape buttons - which widescreen this game gets */
.app-restart-card p.app-restart-note { margin: 14px 0 0; font-weight: 500; font-size: .86rem; line-height: 1.4; color: #b9b9cc; }
.app-stage .native-hero-media { position: absolute; inset: 0; }
.app-stage .native-hero-video, .app-stage .native-hero-still { width: 100%; height: 100%; object-fit: cover; }
/* Fullscreen = the stage swallows the window (the Player also fullscreens the
   OS window). ESC — owned by the Player's key hook — brings this back. */
/* Fullscreen keeps explicit position/size (R104.1's static_window_e2e lesson:
   `inset: 0` alone loses to any explicit width/height — Full once rendered a
   small corner window). R164 removed the session-live viewport pin, but keep
   the explicit values here: they cost nothing and guard against any future
   rule that sizes .app-stage. */
.app-shell.fs .app-stage { position: fixed; inset: 0; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 4000; aspect-ratio: auto; border-radius: 0; min-height: 100vh; }
.app-gate { position: relative; z-index: 2; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 8px; padding: clamp(16px, 4vw, 42px); }
.app-gate[hidden] { display: none; }
.app-shell .app-attest { display: flex; gap: 10px; align-items: flex-start; max-width: 66ch; margin: 2px 0 6px; font-size: 13px; line-height: 1.5; color: #e9e9ef; text-shadow: 0 1px 8px rgba(0, 0, 0, .5); }
.app-shell .app-attest input { margin-top: 3px; width: 17px; height: 17px; flex: 0 0 auto; }
.app-shell .app-play-btn:disabled { opacity: .45; cursor: not-allowed; filter: grayscale(.5); }
.app-shell .app-status { font-size: 13px; color: #e9e9ef; min-height: 18px; text-shadow: 0 1px 8px rgba(0, 0, 0, .5); }
/* R201: David's rotating statements + the seal / dancer in the Mini App too. */
.app-shell .app-status.rpc-load-msg { font-size: 14px; max-width: 34ch; margin: 0 auto; }
.app-shell .app-load-mascot { color: #e9e9ef; line-height: 0; margin-bottom: 2px; }
.app-shell .app-load-mascot:empty { display: none; }
.app-shell .app-bar { height: 8px; width: min(420px, 100%); background: rgba(255, 255, 255, .14); border-radius: 5px; overflow: hidden; margin: 4px 0 8px; }
.app-shell .app-bar > i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--accent, #8b5cf6), var(--accent-2, #ffd873)); transition: width .2s; }
/* The controller information bar — same .controller-context/.pbtn chrome as
   the web player pages (and never .locked in app mode: premium is the gate). */
.app-ctx { border-radius: 0 0 14px 14px; }
.app-ctx .app-ctx-status { font-size: 12px; color: #cfd2da; margin-left: auto; align-self: center; }
/* R252 (David: "there was no messaging to let me know my video was being processed"):
   the recording panel under the controller bar — the processing steps after Stop, then
   the finished video. In flow, never over the stage (the game window paints over it). */
.app-rec-panel { position: relative; margin: 12px 0 2px; padding: 14px 16px; border-radius: 12px;
  background: rgba(0, 0, 0, .55); border: 1px solid color-mix(in srgb, var(--accent, #7c5cff) 55%, transparent);
  color: #f2f2f7; box-shadow: 0 6px 22px rgba(0, 0, 0, .35); }
.app-rec-panel[hidden] { display: none; }
.app-rec-panel.is-error { border-color: color-mix(in srgb, var(--danger, #ff5c8a) 70%, transparent); }
.app-rec-panel .app-rec-head { display: flex; align-items: center; gap: 10px; }
.app-rec-panel .app-rec-title { font-size: 15px; font-weight: 800; display: block; }
.app-rec-panel .app-rec-line { font-size: 13px; color: #cfd2da; margin-top: 4px; }
.app-rec-panel .app-rec-spin { width: 16px; height: 16px; flex: 0 0 16px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .25); border-top-color: var(--accent-2, #00d4aa); animation: app-rec-spin .8s linear infinite; }
@keyframes app-rec-spin { to { transform: rotate(360deg); } }
.app-rec-panel .app-rec-bar { height: 8px; margin-top: 10px; border-radius: 5px; overflow: hidden; background: rgba(255, 255, 255, .14); max-width: 520px; }
.app-rec-panel .app-rec-bar > span { display: block; height: 100%; width: 2%; border-radius: 5px;
  background: linear-gradient(90deg, var(--accent, #7c5cff), var(--accent-2, #00d4aa)); transition: width .25s; }
.app-rec-panel .app-rec-bar.is-indeterminate > span { width: 35%; animation: app-rec-slide 1.2s ease-in-out infinite; }
@keyframes app-rec-slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(300%); } }
@media (prefers-reduced-motion: reduce) {
  .app-rec-panel .app-rec-spin, .app-rec-panel .app-rec-bar.is-indeterminate > span { animation: none; }
}
.app-rec-panel .app-rec-body { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
.app-rec-panel .app-rec-thumb { width: 240px; max-width: 100%; aspect-ratio: 16 / 9; object-fit: contain; background: #000; border-radius: 8px; }
.app-rec-panel .app-rec-thumb.is-clickable { cursor: pointer; }
.app-rec-panel .app-rec-info { flex: 1 1 280px; min-width: 0; }
.app-rec-panel .app-rec-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.app-rec-panel .app-rec-status { margin-top: 10px; font-size: 13px; }
.app-rec-panel .app-rec-status .rec-ok { color: #46d17a; font-weight: 600; }
.app-rec-panel .app-rec-status .rec-err { color: var(--danger, #ff6b6b); }
.app-rec-panel .app-rec-link { background: none; border: 0; padding: 0; color: var(--accent-2, #00d4aa); text-decoration: underline; cursor: pointer; font: inherit; }
.app-rec-panel .app-rec-discard { opacity: .8; }
.app-rec-panel .app-rec-x { position: absolute; top: 6px; right: 10px; background: none; border: 0; color: #9a9ab0; font-size: 22px; line-height: 1; cursor: pointer; }
.app-rec-panel .app-rec-x:hover { color: #fff; }
.app-shell .app-tool-btn { padding: 7px 13px; border-radius: 9px; border: 1px solid rgba(255, 255, 255, .25); background: rgba(0, 0, 0, .35); color: #fff; font-size: 13px; font-weight: 600; cursor: pointer; }
.app-shell .app-tool-btn:hover { border-color: var(--accent-2, #ffd873); }
.app-shell .app-tool-note { font-size: 12px; color: #cfd2da; }
.app-shell .app-controls-panel { background: rgba(0, 0, 0, .55); border: 1px solid rgba(255, 255, 255, .18); border-radius: 12px; padding: 14px; margin: 10px 0 4px; max-width: 640px; }
.app-shell .app-map-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; margin: 10px 0; }
.app-shell .app-map-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; background: rgba(255, 255, 255, .07); border: 1px solid rgba(255, 255, 255, .12); border-radius: 8px; padding: 6px 9px; }
.app-shell .app-map-row .lbl { font-size: 12px; color: #e9e9ef; }
.app-shell .app-map-key { min-width: 52px; padding: 4px 8px; border: 1px solid rgba(255, 255, 255, .3); border-radius: 7px; background: rgba(0, 0, 0, .4); color: #fff; font-weight: 700; font-size: 12px; cursor: pointer; }
/* R105 (David, Dreamcast: "only 2 action buttons were mapped"): a bind the
   emulator's config cannot carry — two buttons on one key — is MARKED here.
   The panel must never show a binding that the config silently discards. */
/* R130: the CONTROLLER cell beside each key — dim until a pad bind exists. */
.app-shell .app-map-pad-cell { opacity: .75; border-style: dashed; }
.app-shell .app-map-pad-cell:hover { opacity: 1; }
.app-shell .app-map-row.is-unmapped { border-color: #ffb04d; background: rgba(255, 176, 77, .14); }
.app-shell .app-map-row.is-unmapped .app-map-key { border-color: #ffb04d; color: #ffd9a8; }
.app-shell .app-map-warn { flex: 0 0 auto; width: 16px; height: 16px; border-radius: 50%; background: #ffb04d; color: #201400; font-size: 11px; font-weight: 800; line-height: 16px; text-align: center; }
.app-shell .app-controls-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* Exit confirmation (double-ESC / Exit Game) — the Player hides the game
   window first, so this dialog is genuinely visible + clickable. */
.app-confirm { position: fixed; inset: 0; z-index: 2147483000; display: flex; align-items: center; justify-content: center; background: rgba(4, 4, 12, .72); backdrop-filter: blur(3px); }
.app-confirm[hidden] { display: none; }
.app-confirm-box { background: var(--panel, #14141f); border: 1px solid rgba(255, 255, 255, .2); border-radius: 14px; padding: 26px 30px; max-width: 420px; text-align: center; box-shadow: 0 18px 60px rgba(0, 0, 0, .55); }
.app-confirm-box h3 { margin: 0 0 8px; font-size: 20px; color: #fff; }
.app-confirm-box p { margin: 0 0 18px; font-size: 13px; color: #cfd2da; line-height: 1.5; }
.app-confirm-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* Native-only pages have no in-browser emulator, so every emulator-bound control
   (save/record/online/chat + remap panels) and the device-mode notes are hidden
   — the FMV hero + download CTA is the whole interaction. R66: the APP-MODE
   controller bar (.app-ctx) is exempt — in the Player, the game really does
   run in the page and the bar is its control surface. */
.player-zone.is-native-only .controller-context:not(.app-ctx),
.player-zone.is-native-only .device-switch-note,
.player-zone.is-native-only .mobile-controls-note,
.player-zone.is-native-only .online-cta { display: none !important; }
/* R100.5: the challenge CTA (David's 2-player flags) is EXEMPT on native
   pages — presence now includes Mini App players, so the flash is real. The
   element still starts [hidden]; player.js reveals it only when another
   member is detected playing right now. */
.player-zone.is-native-only .online-cta.challenge-eligible { display: flex !important; }
.player-zone.is-native-only .online-cta.challenge-eligible[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .native-hero-cta { animation: none; }
  /* player.js additionally pauses the <video> loop under reduced motion. */
}

/* R201 (David): "The 'Visual Loading Bar' should still be shown with the above
   textual messaging shown." It is no longer the PS1-only download meter it was
   — every game page shows it for the whole boot, sweeping (.rpc-indet, from
   loading-messages.js) until an engine reports a real percentage and filling
   from there. The fill starts at 100% so the sweep has something to move. */
.boot-progress {
  width: min(320px, 70%); height: 8px; border-radius: 999px;
  background: rgba(255, 255, 255, .12); overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .15);
}
.boot-progress-fill {
  height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width .3s ease;
}
.boot-progress.rpc-indet .boot-progress-fill { transition: none; }
.boot-state.downloading .boot-text { animation: none; }

/* ============ R50 — the Club home ============ */
/* Header logo (crest + wordmark SVG) — text-logo glow rules don't apply */
.logo.logo-svg { display: inline-flex; align-items: center; text-shadow: none; }
.logo.logo-svg .rpc-logo { height: 40px; width: auto; display: block; }
@media (max-width: 640px) { .logo.logo-svg .rpc-logo { height: 30px; } }
/* R142: David's tagline under the logo (neon-arcade only — the element exists
   in no other theme's chrome). Logo mark is untouched; this is text-only. */
.brand-block { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 3px; text-decoration: none; }
.brand-tagline { font: 900 11px/1 "Arial Black", Arial, sans-serif; letter-spacing: 2.5px; text-transform: uppercase; color: #22e4f2; text-shadow: 0 0 8px rgba(34, 228, 242, .55); white-space: nowrap; }
@media (max-width: 640px) { .brand-tagline { font-size: 9px; letter-spacing: 1.5px; } }

.club-hero .club-kicker {
  color: var(--accent-2); text-transform: uppercase; letter-spacing: 5px;
  font-size: 13px; font-weight: 700; margin-bottom: 10px;
}
.cta.club-join {
  display: inline-block; font-size: 20px; font-weight: 800; letter-spacing: .5px;
  padding: 16px 30px; margin: 18px 0 14px;
  background: linear-gradient(135deg, var(--accent), #b3186a);
  color: #fff; border-radius: 12px; text-decoration: none;
  box-shadow: 0 0 24px rgba(255, 45, 149, .45);
}
.cta.club-join:hover { transform: translateY(-2px); box-shadow: 0 0 34px rgba(255, 45, 149, .65); }
.club-ease { max-width: 62ch; margin: 0 auto 20px; color: var(--dim, #b9a8d8); font-size: 15px; line-height: 1.65; }

.lane-note { color: var(--dim, #b9a8d8); margin: -6px 0 14px; font-size: 14px; }

/* International Top Players */
.tp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
.tp-card { background: var(--panel, rgba(255,255,255,.04)); border: 1px solid rgba(255,45,149,.25); border-radius: 12px; overflow: hidden; }
.tp-video { width: 100%; aspect-ratio: 16/9; background: #000; display: block; }
.tp-video-empty { display: flex; align-items: center; justify-content: center; font-size: 42px; opacity: .85; }
/* Click-to-play facade — the poster as a button, so no media element exists
   until someone asks for one (see site.js: a <video> here never lets WebKit
   finish loading the page). */
.tp-play {
  border: 0; padding: 0; cursor: pointer; position: relative;
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
.tp-play .tp-play-icon {
  position: absolute; inset: 0; margin: auto; width: 62px; height: 62px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; background: rgba(10, 1, 24, .62); border: 2px solid #fff;
  color: #fff; font-size: 22px; padding-left: 4px; transition: transform .15s, background .15s;
}
.tp-play:hover .tp-play-icon, .tp-play:focus-visible .tp-play-icon {
  transform: scale(1.08); background: var(--accent);
}
.tp-meta { padding: 12px 14px 14px; display: grid; gap: 3px; }
.tp-name { font-size: 16px; }
.tp-game { color: var(--accent-2); font-size: 13px; }
.tp-score { color: var(--accent); font-weight: 700; font-size: 13px; }
.tp-note { color: var(--dim, #b9a8d8); font-size: 13px; }
.tp-cta { margin-top: 16px; font-size: 15px; }
.tp-cta a { color: var(--accent-2); font-weight: 700; }

/* Play-count call-out badge on game-card art */
.game-card .art { position: relative; }
.plays-badge {
  position: absolute; left: 8px; bottom: 8px; z-index: 2;
  /* The pill is a HARD-CODED dark colour on every theme, so its text must not
     be theme-derived: playdeck's --accent-2 is #16161a (near black), which
     painted the play counts black-on-black at 1.13:1 — the R50 "showcase call
     to action Play counts" unreadable on that variant. The border keeps the
     theme accent; the label is white because the pill is always dark. */
  background: rgba(10, 1, 24, .85); border: 1px solid var(--accent-2);
  color: #fff; font-size: 12px; font-weight: 700;
  padding: 3px 9px; border-radius: 999px; letter-spacing: .3px;
}

/* Premium band */
.club-premium {
  margin: 34px 0; padding: 26px 28px; border-radius: 14px;
  border: 1px solid rgba(34, 228, 242, .35);
  background: linear-gradient(135deg, rgba(255,45,149,.12), rgba(34,228,242,.08));
  display: grid; gap: 16px;
}
.cp-noads b { display: block; font-size: 30px; letter-spacing: 1px; color: var(--accent); text-shadow: 0 0 14px rgba(255,45,149,.6); }
.cp-noads span { color: var(--ink, #f4ecff); font-size: 15px; }
.cp-perks { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.cp-perks li { font-size: 15px; }
.cp-cta { justify-self: start; }
@media (max-width: 640px) { .cp-noads b { font-size: 24px; } }
/* R45.2 — loading FMV: the game's real clip fills the frame while a big ISO
   streams; the boot text + progress bar ride over it on a soft scrim. */
.loading-fmv {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 0; filter: brightness(.55) saturate(.9);
  transition: opacity .5s ease;
}
.boot-state.has-fmv { z-index: 1; background: linear-gradient(180deg, rgba(0,0,0,.25), rgba(0,0,0,.55)); }
/* R100.4: the art STAYS visible under has-fmv (it used to be display:none,
   which left NEITHER art nor the still-downloading FMV on screen — David:
   "The loading is slow… Screenshots should show fast"). Once the clip truly
   plays, player.js tags fmv-live and the art fades out to reveal it. */
.boot-state.has-fmv.fmv-live .boot-art img { opacity: 0; }
/* R201: MOBILE hand-over. EmulatorJS waits for a tap on its own start button,
   so the overlay used to be REMOVED at 'ready' — which left the phone with no
   statement and no bar for the rest of the download (measured 14s on a
   throttled PS1). It now stays, but click-through and without its backdrop:
   the FMV/start screen shows and takes the tap, David's statements and the bar
   keep running over it, and 'started' still takes the whole overlay away. */
.boot-state.handed-over { pointer-events: none; background: none; }
.boot-state.handed-over::before,
.boot-state.handed-over .boot-art { display: none; }
/* R201c: between 'started' and the engine's FIRST PAINTED FRAME the overlay
   stays up (measured 10-15s of pure black on a PS1 disc). The loading clip is
   torn down at 'running', so bring the action screenshot back as the backdrop
   for that stretch — otherwise the statements would sit on a black rectangle,
   which is the very thing this is here to avoid. */
.boot-state.awaiting-paint.has-fmv.fmv-live .boot-art img { opacity: .45; }
/* R202c: AWAITING THE TAP is not loading. On mobile EmulatorJS downloads
   nothing until the start button is tapped, so until then there are no words
   and no bar — the tap cue is the only voice. The art/clip still shows, and the
   overlay is click-through so the tap reaches the engine. player.js drops this
   class the moment the engine creates its own loading text. */
.boot-state.awaiting-tap { pointer-events: none; background: none; }
.boot-state.awaiting-tap::before,
.boot-state.awaiting-tap .boot-text,
.boot-state.awaiting-tap .boot-mascot,
.boot-state.awaiting-tap .boot-progress { display: none !important; }
.boot-error { text-align: center; display: flex; flex-direction: column; gap: 12px; align-items: center; }
.boot-error p { color: var(--danger); font-size: 14px; max-width: 46ch; }

/* When the gate is up, the player is "clouded": blurred + dimmed but running */
/* R201d (David live: "I get the usual engagement modal but I am not getting
   everything that is supposed to show when loading"). The cloud used to be a
   `filter` on .player-FRAME — which CONTAINS the loading overlay, and a
   descendant cannot opt out of an ancestor's filter, so the moment the pop-open
   appeared David's statements and the bar were smeared into an illegible dark
   blob (photographed). The brief asks to cloud the GAME while the gate is up,
   not our own words: the blur moves onto the game CONTENT (the engine iframe/canvas and the loading
   clip) rather than any ancestor of the overlay — #boot-state lives INSIDE
   .game-screen, so blurring that was the same mistake one level down. The loading
   overlay (plus the honest experimental / being-prepared notices) stays sharp
   above it. pointer-events stays on the frame — the gate's own UI is outside
   it, and nothing inside the overlay is interactive. */
.player-zone.gated .player-frame { pointer-events: none; }
.player-zone.gated .game-screen > iframe,
.player-zone.gated .game-screen > canvas,
.player-zone.gated .game-screen > video { filter: blur(9px) brightness(.55) saturate(.7); }

.controller-context { padding: 12px 16px; border-top: 1px solid var(--line); position: relative; }
.player-controls { display: flex; gap: 8px; flex-wrap: wrap; }
.pbtn {
  background: none; border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 6px 13px; cursor: pointer; font-size: 12.5px; transition: border-color .15s, color .15s;
}
.pbtn:hover { border-color: var(--accent-2); color: var(--accent-2); }
.controller-context.locked .pbtn { opacity: .45; cursor: pointer; }
.controller-context.locked::after {
  content: "Create a free account to unlock saves, rewind & controller setup";
  display: block; margin-top: 8px; font-size: 12px; color: var(--dim);
}
.controller-setup {
  margin-top: 12px; padding: 14px 16px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--panel);
}
.controller-setup[hidden] { display: none; }
.cs-gamepad { margin: 0 0 10px; font-size: 13.5px; }
/* R206-N64m: the "advanced functions" Mini App mention under the controller line (both viewports) */
.cs-miniapp a { text-decoration: underline; font-weight: 600; }
.cs-miniapp-soon { display: block; font-size: 12px; color: var(--dim); margin-top: 3px; }
.cs-remap-cta { margin: 0 0 10px; font-size: 13px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cs-remap-cta.muted { color: var(--dim); }
.pbtn.sm { padding: 4px 10px; font-size: 12px; }
kbd.remappable { cursor: pointer; transition: border-color .15s, background .15s; }
kbd.remappable:hover, kbd.remappable:focus { border-color: var(--accent-2); color: var(--accent-2); outline: none; }
kbd.remap-key.listening { border-color: var(--accent); color: var(--accent); animation: boot-blink 1s infinite; }
/* R129: live gamepad binding shown in the Controller column (painted by
   player.js paintPad from the ENGINE's value2 truth). currentColor keeps it
   legible on all five themes without a per-theme variable. */
.remap-pad { display: inline-block; padding: 1px 8px; border: 1px solid currentColor; border-radius: 4px; font-size: 12px; opacity: .8; white-space: nowrap; }
.controls-map { margin-top: 12px; font-size: 13.5px; }
.controls-map summary { cursor: pointer; color: var(--dim); }
.controls-table { width: 100%; border-collapse: collapse; margin-top: 10px; }
.controls-table th, .controls-table td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--line); font-size: 13px; }
.controls-table th { color: var(--dim); text-transform: uppercase; font-size: 11px; letter-spacing: 1px; }

/* ---------- ad slots (banner anchors) + preroll ---------- */

.ad-slot {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  margin: 18px 0; position: relative; z-index: 1;
}
.ad-label {
  font-size: 9.5px; letter-spacing: 2px; text-transform: uppercase;
  color: var(--dim); opacity: .75;
}
.ad-placeholder {
  display: flex; align-items: center; justify-content: center;
  border: 1px dashed var(--line); border-radius: 8px;
  background: color-mix(in srgb, var(--panel) 60%, transparent);
  color: var(--dim); font-size: 12px; letter-spacing: 1.5px; font-weight: 700;
}
.ad-slot iframe, .ad-slot img { max-width: 100%; }

.ad-preroll {
  position: absolute; inset: 0; z-index: 25;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  border-radius: calc(var(--radius) + 4px);
  transition: opacity .28s;
}
.ad-preroll.leaving { opacity: 0; pointer-events: none; }
.ad-preroll-inner {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  width: min(560px, 92%); text-align: center;
}
.preroll-placeholder { width: 100%; height: min(46vh, 300px); font-size: 14px; }
/* Hilltop video-player embed: fills the preroll footprint, capped so it can
   never overflow the game screen on mobile (playability directive). */
.ad-preroll-inner .ad-embed {
  display: block; width: 100%; height: min(46vh, 300px);
  border: 0; border-radius: 8px; background: #05050a; overflow: hidden;
}
/* Self-hosted VAST video-ad player (ad-vast.js) — used in the preroll and the
   nag "Watch an ad" screen. The container's size comes from the surface rule
   above / .nag-ad-screen; this only paints the video + its controls. */
.ad-vast { position: relative; background: #000; overflow: hidden; }
.ad-vast-video { width: 100%; height: 100%; display: block; object-fit: contain; background: #000; cursor: pointer; }
.ad-vast-ui { position: absolute; left: 0; right: 0; bottom: 0; display: flex; align-items: center; gap: 8px; padding: 8px 10px; pointer-events: none; }
.ad-vast-ui > * { pointer-events: auto; }
.ad-vast-count { color: #fff; font-size: 12px; letter-spacing: .02em; background: rgba(0,0,0,.55); padding: 3px 8px; border-radius: 6px; margin-right: auto; font-variant-numeric: tabular-nums; }
.ad-vast-unmute, .ad-vast-skip { font: 600 12px/1 system-ui, sans-serif; color: #fff; background: rgba(0,0,0,.62); border: 1px solid rgba(255,255,255,.35); border-radius: 6px; padding: 7px 11px; cursor: pointer; }
.ad-vast-skip { background: rgba(0,0,0,.8); border-color: rgba(255,255,255,.55); }
.ad-preroll-status {
  display: flex; align-items: center; gap: 10px; color: var(--dim); font-size: 13px;
}
.ad-loading-dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--accent-2);
  animation: boot-blink 1.1s infinite;
}
.ad-skip { border-color: var(--accent-2); color: var(--accent-2); }

/* ---------- mobile emulation profile ---------- */

.mobile-controls-note, .device-switch-note {
  padding: 8px 16px; font-size: 12px; color: var(--dim);
  border-top: 1px dashed var(--line);
}
.mobile-controls-note a, .device-switch-note a { color: var(--accent-2); }

/* Mobile profile: the player owns the viewport — full-bleed, tall,
   thumb-reachable; EmulatorJS's virtual gamepad overlays inside the frame. */
.player-zone.is-mobile .player-frame {
  border-radius: 0; border-left: 0; border-right: 0;
  margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
}
.player-zone.is-mobile .game-screen {
  aspect-ratio: auto;
  height: min(72vh, 560px);
}
@media (max-width: 700px) {
  .player-zone.is-mobile .game-screen { height: 62vh; }
  .player-zone.is-mobile .player-controls .pbtn { padding: 10px 16px; font-size: 14px; } /* thumb targets */
  .fomo-strip { padding: 16px; }
}
/* Landscape phones: emulator becomes the whole show */
@media (max-height: 500px) and (orientation: landscape) {
  .player-zone.is-mobile .game-screen { height: 88vh; }
  .player-zone.is-mobile .mobile-controls-note { display: none; }
}

/* ---------- registration gate (clouded pop-open) ---------- */
/* R144 "Fast Start" signup (David's design handoff, 2026-08-19).
   Deliberately a FIXED palette, not theme vars: the modal is its own brand
   surface and must render identically on all five variant themes (the
   var(--muted)-undefined trap is exactly what fixed hexes avoid). Fonts are
   SELF-HOSTED woff2 (assets/fonts/) — the CSP allows no Google Fonts. */

@font-face {
  font-family: 'Chakra Petch'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/assets/fonts/chakra-petch-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Chakra Petch'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/assets/fonts/chakra-petch-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Chakra Petch'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('/assets/fonts/chakra-petch-700.woff2') format('woff2');
}
@font-face {
  font-family: 'Press Start 2P'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/assets/fonts/press-start-2p-400.woff2') format('woff2');
}

.reg-gate { position: absolute; inset: 0; z-index: 30; display: flex; overflow-y: auto; padding: 12px 0; }
.reg-gate[hidden] { display: none; }
.reg-cloud {
  position: fixed; inset: 0;
  background: rgba(10, 5, 20, .8);
  backdrop-filter: blur(2px);
}
.reg-panel {
  position: relative; margin: auto;                 /* centers when it fits, scrolls when it can't */
  width: min(390px, calc(100% - 20px));
  background: #160a29; border: 2px solid #2fe6d8; border-radius: 20px;
  padding: 28px 22px;
  box-shadow: 0 0 44px rgba(47, 230, 216, .3);
  text-align: center;
  font-family: 'Chakra Petch', 'Segoe UI', system-ui, sans-serif;
  color: #e9e2f7;
  animation: gate-pop .3s cubic-bezier(.2, .9, .3, 1.2);
}
/* Victory state re-borders the shell in yellow (set by JS on the panel). */
.reg-panel.rs-victory { border-color: #ffd23f; box-shadow: 0 0 44px rgba(255, 210, 63, .3); }
@keyframes gate-pop { from { transform: translateY(14px) scale(.96); opacity: 0; } }
.reg-close {
  position: absolute; top: 12px; right: 14px; background: none; border: 0;
  color: #8f7fb8; font-size: 18px; cursor: pointer; line-height: 1; z-index: 2;
}
.reg-close:hover { color: #fff; }

/* ---- step shell + transition ---- */
/* NOTE: never give .reg-step a bare display rule — it would beat the [hidden]
   UA default and render every step stacked (the site.css R120.2 trap). */
.reg-step[hidden] { display: none; }
.reg-step.rs-in { animation: rs-step-in .2s ease-out; }
@keyframes rs-step-in { from { opacity: 0; transform: translateX(10px); } }

/* ---- shared pieces ---- */
.rs-emoji { font-size: 40px; line-height: 1; margin-bottom: 10px; }
.rs-headline { font-family: 'Chakra Petch', sans-serif; font-weight: 700; font-size: 28px; line-height: 1.1; color: #fff; margin: 0 0 8px; }
.rs-h-sm { font-size: 26px; }
.rs-sub { font-size: 15px; color: #b9a9dd; margin: 0 0 16px; line-height: 1.4; }
.rs-sub .rs-email { color: #2fe6d8; font-weight: 600; }
/* R183: the verbatim two-line sub — "Free Registration" leads in cyan caps. */
.rs-sub-lead { display: inline-block; color: #2fe6d8; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; margin-bottom: 2px; }

.rs-input {
  display: block; width: 100%; box-sizing: border-box;
  background: #0c0519; border: 2px solid #46307c; border-radius: 14px;
  color: #fff; font-family: inherit; font-size: 17px; padding: 16px;
  margin: 0 0 10px; outline: 0; transition: border-color .15s, box-shadow .15s;
  text-align: left;
}
.rs-input-cyan { border-color: #2fe6d8; }
.rs-input:focus { border-color: #2fe6d8; box-shadow: 0 0 14px rgba(47, 230, 216, .35); }
.rs-input::placeholder { color: #8f7fb8; }
.rs-center { text-align: center; }
.rs-input.rs-bad { border-color: #ff2d87; }

.rs-cta {
  display: block; width: 100%; box-sizing: border-box; border: 0; cursor: pointer;
  background: linear-gradient(90deg, #ff2d87, #7b2dff); color: #fff;
  font-family: inherit; font-weight: 700; font-size: 19px;
  border-radius: 14px; padding: 18px; margin: 6px 0 0;
  box-shadow: 0 0 34px rgba(255, 45, 135, .55);
  transition: filter .15s;
}
.rs-cta:hover { filter: brightness(1.1); }
.rs-cta:disabled, .rs-cta.rs-busy { opacity: .6; cursor: wait; }
.rs-cta-victory { background: linear-gradient(90deg, #ff2d87, #ff6a3d); animation: ctaPulse 2.2s ease-in-out infinite; }
@keyframes ctaPulse {
  0%, 100% { box-shadow: 0 0 24px rgba(255, 45, 135, .55), 0 0 60px rgba(255, 45, 135, .25); }
  50% { box-shadow: 0 0 36px rgba(255, 45, 135, .85), 0 0 90px rgba(255, 45, 135, .4); }
}

.rs-micro { font-size: 13px; color: #8f7fb8; margin: 10px 0 0; }
/* R183: helper line living directly under an input (the phone field). */
.rs-micro-tight { margin: -4px 0 10px; text-align: left; }
.rs-error { color: #ff2d87; font-size: 13px; font-weight: 600; margin: 8px 0 0; }
.rs-foot-link { font-size: 14px; color: #8f7fb8; margin: 16px 0 0; }
.rs-foot-link a, .rs-foot-row a { color: #2fe6d8; font-weight: 600; text-decoration: none; }
.rs-foot-link a:hover, .rs-foot-row a:hover { color: #ff2d87; }
/* R158: the "Forgot your password?" link under the sign-in card password field. */
.rs-forgot { text-align: right; margin: 8px 2px 0; font-size: 13px; }
.rs-forgot a { color: #8f7fb8; text-decoration: none; }
.rs-forgot a:hover { color: #2fe6d8; }
.rs-foot-row { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; font-size: 14px; color: #8f7fb8; }
.rs-foot-row a[data-reg-back] { color: #8f7fb8; font-weight: 400; }
.rs-foot-row a[data-reg-back]:hover { color: #fff; }
a.rs-disabled { opacity: .45; pointer-events: none; }

/* ---- 1e: social proof ---- */
.rs-proof { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 16px 0 0; }
.rs-proof-avs { display: inline-flex; }
.rs-proof-avs i { width: 26px; height: 26px; border-radius: 999px; border: 2px solid #160a29; }
.rs-proof-avs i:nth-child(1) { background: #ff2d87; }
.rs-proof-avs i:nth-child(2) { background: #7b2dff; margin-left: -8px; }
.rs-proof-avs i:nth-child(3) { background: #2fe6d8; margin-left: -8px; }
.rs-proof-txt { font-size: 13px; font-weight: 600; color: #e9e2f7; }

/* ---- 2d: OTP boxes + loading bar ---- */
.rs-otp { display: flex; justify-content: center; gap: 8px; margin: 4px 0 16px; }
.rs-otp-box {
  width: 44px; height: 56px; box-sizing: border-box; text-align: center;
  background: #0c0519; border: 2px solid #2b1a52; border-radius: 12px;
  color: #fff; font-family: inherit; font-weight: 700; font-size: 24px; outline: 0;
  transition: border-color .12s, box-shadow .12s; padding: 0;
}
.rs-otp-box.filled { border-color: #2fe6d8; }
.rs-otp-box:focus { border-color: #ff2d87; box-shadow: 0 0 14px rgba(255, 45, 135, .45); }
.rs-progress { background: #0c0519; border-radius: 12px; padding: 14px 16px; margin: 0 0 16px; text-align: left; }
.rs-progress-row { display: flex; justify-content: space-between; font-size: 13px; color: #b9a9dd; margin-bottom: 8px; }
.rs-progress-row b { color: #ffd23f; font-weight: 700; }
.rs-progress-track { height: 10px; border-radius: 6px; background: #1f1140; overflow: hidden; }
.rs-progress-fill {
  height: 100%; border-radius: 6px; transition: width .25s ease;
  background: repeating-linear-gradient(90deg, #ff2d87 0 10px, #7b2dff 10px 20px);
}

/* ---- 2a: pips + stage + availability ---- */
.rs-pips { display: flex; justify-content: center; gap: 8px; margin: 2px 0 10px; }
.rs-pips i { width: 34px; height: 8px; border-radius: 4px; background: #2b1a52; }
.rs-pips i.done { background: #2fe6d8; }
.rs-pips i.current { background: #ff2d87; box-shadow: 0 0 12px rgba(255, 45, 135, .7); }
.rs-stage { font-family: 'Press Start 2P', monospace; font-size: 9px; color: #2fe6d8; letter-spacing: 1px; margin: 0 0 12px; }
.rs-avail { font-size: 13px; font-weight: 600; text-align: left; margin: -4px 0 10px; }
.rs-avail.is-ok { color: #2fe6d8; }
.rs-avail.is-bad { color: #ff2d87; }
.rs-avail a { color: #2fe6d8; text-decoration: underline; }

/* ---- 2b: pixel title + avatar grid ---- */
.rs-pixel-title {
  font-family: 'Press Start 2P', monospace; font-size: 12px; color: #ffd23f;
  text-shadow: 0 0 14px rgba(255, 210, 63, .6); letter-spacing: 2px; margin: 6px 0 12px;
}
.rs-avatars { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 0 0 14px; }
.rs-avatar {
  aspect-ratio: 1; border-radius: 14px; background: #0c0519; cursor: pointer;
  border: 2px solid #2b1a52; padding: 0; display: flex; align-items: center; justify-content: center;
  transition: border-color .12s, box-shadow .12s;
}
.rs-avatar img { width: 62%; height: 62%; image-rendering: pixelated; }
.rs-avatar.on { border-color: #ff2d87; box-shadow: 0 0 14px rgba(255, 45, 135, .5); }
.rs-avatar:hover { border-color: #46307c; }
.rs-avatar.on:hover { border-color: #ff2d87; }

/* ---- 2c: console loadout chips ---- */
.rs-loadout { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 0 0 14px; }
.rs-chip {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: #0c0519; border: 2px solid #2b1a52; border-radius: 14px;
  color: #b9a9dd; font-family: inherit; font-weight: 600; font-size: 15px;
  padding: 12px 14px; cursor: pointer; transition: border-color .12s, box-shadow .12s;
}
.rs-chip .rs-chip-check { visibility: hidden; color: #ff2d87; font-weight: 700; }
.rs-chip.on { border-color: #ff2d87; color: #fff; box-shadow: 0 0 12px rgba(255, 45, 135, .4); }
.rs-chip.on .rs-chip-check { visibility: visible; }
.rs-skip { font-weight: 600; }

/* ---- 2e: victory ---- */
.rs-victory-title { font-size: 16px; text-shadow: 0 0 18px rgba(255, 210, 63, .7); }
.rs-stars { font-size: 22px; letter-spacing: 6px; margin: 0 0 16px; }
.rs-player-card {
  display: flex; align-items: center; gap: 12px; text-align: left;
  background: #0c0519; border: 1px solid #2b1a52; border-radius: 14px;
  padding: 14px 16px; margin: 0 0 16px;
}
.rs-card-avatar {
  width: 48px; height: 48px; flex: none; border-radius: 12px;
  background: #1f1140; border: 2px solid #ff2d87;
  display: flex; align-items: center; justify-content: center;
}
.rs-card-avatar img { width: 70%; height: 70%; image-rendering: pixelated; }
.rs-card-id { flex: 1; min-width: 0; }
.rs-card-id b { display: block; color: #fff; font-weight: 700; font-size: 17px; }
.rs-card-id small { display: block; color: #8f7fb8; font-size: 13px; }
.rs-card-1up { font-family: 'Press Start 2P', monospace; font-size: 9px; color: #2fe6d8; }
.rs-unlocks { list-style: none; margin: 0 0 16px; padding: 0; text-align: left; }
.rs-unlocks li { font-size: 15px; color: #e9e2f7; padding: 5px 0; }
.rs-unlocks li i { color: #2fe6d8; font-style: normal; font-weight: 700; margin-right: 8px; }

/* The upsell block inherits the new panel; keep its own type on-brand. */
.reg-upsell { font-family: 'Chakra Petch', 'Segoe UI', system-ui, sans-serif; }
.reg-submit {
  width: 100%; margin-top: 14px; background: linear-gradient(90deg, #ff2d87, #7b2dff); color: #fff;
  font-weight: 700; border: 0; border-radius: 14px; padding: 14px; font-size: 15.5px;
  cursor: pointer; letter-spacing: .5px; font-family: inherit;
  box-shadow: 0 0 24px rgba(255, 45, 135, .4);
}
.reg-submit:hover { filter: brightness(1.12); }
.reg-submit:disabled { opacity: .6; cursor: wait; }
.reg-error { color: #ff2d87; font-size: 13px; margin-top: 8px; }
.reg-form label { display: block; font-size: 12.5px; color: #b9a9dd; margin: 10px 0 4px; text-align: left; }
.reg-form input, .pay-form input {
  width: 100%; box-sizing: border-box; background: #0c0519; border: 2px solid #46307c; color: #fff;
  border-radius: 12px; padding: 10px 12px; font-size: 14px; outline: 0; font-family: inherit;
}
.reg-form input:focus, .pay-form input:focus { border-color: #2fe6d8; }

/* Small phones: keep the panel comfortably inside the zone. */
@media (max-width: 420px) {
  .reg-panel { padding: 24px 16px; }
  .rs-headline { font-size: 24px; }
  .rs-h-sm { font-size: 22px; }
  .rs-otp { gap: 6px; }
  .rs-otp-box { width: 40px; height: 52px; font-size: 21px; }
}

/* ---------- step 2: the $7 upsell ---------- */

.reg-upsell { text-align: center; }
.upsell-burst { font-size: 34px; animation: trophy-pulse 1.6s ease-in-out infinite; }
.upsell-title { font-size: 21px; margin: 6px 0 2px; }
.upsell-title span {
  color: var(--danger);
  text-shadow: 0 0 14px color-mix(in srgb, var(--danger) 60%, transparent);
}
.upsell-price { margin: 8px 0 12px; }
/* R144b (David): "a better font and move the numbers closer together" — the
   modal's own Chakra Petch bold, digits pulled tight (was wide Courier). */
.upsell-price b { font-size: 38px; color: var(--accent-2); font-family: 'Chakra Petch', 'Segoe UI', system-ui, sans-serif; font-weight: 700; letter-spacing: -2px; }
.upsell-price span { color: var(--dim); font-size: 12.5px; }
.upsell-perks { list-style: none; margin: 0 0 6px; padding: 0; text-align: left; }
.upsell-perks li { padding: 5px 0; font-size: 13.5px; }
.upsell-tag { color: var(--dim); font-size: 12.5px; font-style: italic; margin-bottom: 12px; }

.pay-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.pay-tab {
  flex: 1; background: var(--panel-2); border: 1px solid var(--line); color: var(--dim);
  border-radius: 8px; padding: 8px; font-size: 13px; cursor: pointer;
}
.pay-tab.on { color: var(--txt); border-color: var(--accent-2); }
.pay-form { text-align: left; }
.pay-form label { display: block; font-size: 12.5px; color: var(--dim); margin: 8px 0 4px; }
.pay-form input {
  width: 100%; background: var(--bg-accent); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 10px 12px; font-size: 14px; outline: 0;
  font-family: 'Courier New', monospace; letter-spacing: 1px;
}
.pay-form input:focus { border-color: var(--accent-2); }
.pay-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.testmode-ribbon {
  display: block; text-align: center; font-size: 10.5px; font-weight: 800; letter-spacing: 1px;
  color: var(--danger); border: 1px dashed var(--danger); border-radius: 6px;
  padding: 4px 8px; margin-bottom: 4px;
}
/* R144b (David): "neon purple color that is the same as the word 'Club' in our
   logo" — the logo's .CLUB tspan is #ff2d95 (partials/logo-rpc.blade.php). */
.upsell-submit { background: #ff2d95; color: #fff; box-shadow: 0 0 26px rgba(255, 45, 149, .55); }
.paypal-btn {
  width: 100%; padding: 12px; border-radius: 9px; border: 0; cursor: pointer;
  background: #ffc439; color: #253b80; font-weight: 800; font-size: 15px;
}
.paypal-btn b { font-style: italic; }
.paypal-btn b span { color: #179bd7; }
.upsell-success {
  border: 1px solid var(--accent-2); color: var(--accent-2);
  border-radius: 9px; padding: 12px; font-size: 14px; margin-top: 10px;
}
.upsell-skip {
  background: none; border: 0; color: var(--dim); font-size: 12px;
  margin-top: 12px; cursor: pointer; text-decoration: underline;
}
.upsell-skip:hover { color: var(--txt); }

/* ---------- SEO body / FAQ ---------- */

.seo-body { max-width: 76ch; padding: 20px 0; position: relative; z-index: 1; }
.seo-body h2 { font-size: 22px; margin: 26px 0 10px; }
.seo-body p { margin: 10px 0; color: color-mix(in srgb, var(--txt) 88%, var(--dim)); }
.faq-item { border-bottom: 1px solid var(--line); padding: 10px 0; }
.faq-item summary { cursor: pointer; font-weight: 600; font-size: 15px; }
.faq-item p { margin-top: 8px; color: var(--dim); }

/* ---------- purchase CTA ---------- */

.purchase-cta {
  margin: 30px 0; padding: 26px; border-radius: calc(var(--radius) + 6px);
  background: var(--panel); border: 1px solid var(--line); position: relative; z-index: 1;
}
.purchase-cta h2 { font-size: 22px; }
.purchase-sub { color: var(--dim); font-size: 14px; margin: 8px 0 18px; }
.purchase-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.purchase-card {
  display: flex; flex-direction: column; gap: 4px;
  background: var(--bg-accent); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px; text-decoration: none; transition: border-color .15s, transform .15s;
}
.purchase-card:hover { border-color: var(--accent-2); transform: translateY(-3px); }
.purchase-card .merchant { font-size: 11px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--accent-2); font-weight: 800; }
.purchase-card b { font-size: 14.5px; }
.purchase-card .price { color: var(--dim); font-size: 12.5px; }
.purchase-card .go { margin-top: 6px; font-size: 12.5px; color: var(--accent); font-weight: 700; }

/* ---------- report a problem ---------- */

/* R105: the report control moved OUT of .controller-context (which native
   pages hide wholesale, taking the report link with it — David: "there is no
   'Report this game not working' link" on Dreamcast). This wrapper carries the
   horizontal padding the controller bar used to give it, and draws its own
   separator on the native pages where that bar is not rendered. */
.report-zone { padding: 0 16px 12px; }
.player-zone.is-native-only .report-zone { border-top: 1px solid var(--line); padding-top: 12px; }
.report-problem { margin-top: 12px; font-size: 13px; }
.report-problem summary { cursor: pointer; color: var(--dim); }
.report-problem summary:hover { color: var(--danger); }
/* R214 (David): the warning icon is deep red so a broken-game report is easy
   to spot. Literal red, not a theme var - several themes leave --danger muted. */
.report-warn-icon { color: #d61f27; font-weight: 700; }
.report-form { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; align-items: center; }
.report-form select, .report-form input {
  background: var(--bg-accent); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 8px 10px; font-size: 13px; outline: 0;
}
.report-form input { flex: 1; min-width: 200px; }
.report-result { color: var(--accent-2); font-size: 12.5px; width: 100%; }

/* ---------- R128e: "Add Game to My Favorites" star CTA ----------
   David 2026-08-10, with a screenshot: a bright star call-to-action to the
   RIGHT of "Report this game not working", on web AND native Mini App pages.

   The gold is a LITERAL, not a theme var, on purpose. David asked for "bright",
   and the five variants define their accents independently — two of them resolve
   to a muted colour that would read as a disabled control. A fixed gold is the
   only way "bright" is true on all five. (Same reason the Upgrade CTA is gold.)
   `--line` / `--dim` are used for the surrounding chrome because those ARE
   defined by every theme. */
.report-row { display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap; }
.report-row .report-problem { flex: 1 1 260px; min-width: 0; }  /* min-width:0 or the
   open report form cannot shrink below its content and pushes the CTA off-row */

/* R214 (David): favourites + "Send this Game to a Friend" share on ONE row. */
.report-ctas { display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 12px; }

.fav-cta {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px;                       /* R214: trimmed to free room for share */
  border: 1px solid #f6c453; border-radius: 999px;
  background: linear-gradient(180deg, #ffd76a, #f0a92a);
  color: #241a02; font-weight: 800; font-size: 12.5px; letter-spacing: .2px;
  cursor: pointer; white-space: nowrap;
  box-shadow: 0 0 0 rgba(246,196,83,.55);
  transition: box-shadow .18s ease, transform .12s ease, filter .18s ease;
}
.fav-cta:hover { filter: brightness(1.07); box-shadow: 0 0 14px rgba(246,196,83,.55); }
.fav-cta:active { transform: translateY(1px); }
.fav-cta:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.fav-cta .fav-star { fill: #241a02; flex: none; }

/* Already a favourite: stays legible but stops shouting, so a page the player
   has already claimed does not compete with the controls they came to use. */
.fav-cta.is-fav {
  background: transparent; color: #f6c453; border-color: #f6c453;
  box-shadow: none;
}
.fav-cta.is-fav .fav-star { fill: #f6c453; }
.fav-cta.is-fav:hover { background: rgba(246,196,83,.12); }

.fav-cta[disabled] { opacity: .6; cursor: progress; }
.fav-result { font-size: 12.5px; color: var(--accent-2); align-self: center; }
.fav-result.is-warn { color: var(--danger); }

/* R214 (David): the secondary "Send this Game to a Friend" CTA - outline pill,
   same size as the trimmed favourites button, distinct so it doesn't compete
   with the gold star. Desktop = copy link to clipboard; mobile = native share. */
.share-cta {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px;
  border: 1px solid var(--accent-2); border-radius: 999px;
  background: transparent; color: var(--accent-2);
  font-weight: 700; font-size: 12.5px; letter-spacing: .2px;
  cursor: pointer; white-space: nowrap;
  transition: box-shadow .18s ease, transform .12s ease, background .18s ease;
}
.share-cta:hover { background: color-mix(in srgb, var(--accent-2) 12%, transparent);
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent-2) 40%, transparent); }
.share-cta:active { transform: translateY(1px); }
.share-cta:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.share-cta .share-icon { fill: var(--accent-2); flex: none; }
.share-cta.is-done { border-color: #46d19e; color: #46d19e; }
.share-cta.is-done .share-icon { fill: #46d19e; }
.share-result { font-size: 12.5px; color: var(--accent-2); align-self: center; }
.share-result.is-warn { color: var(--danger); }

@media (max-width: 560px) {
  .report-row { gap: 10px; }
  .report-ctas { width: 100%; }
  /* Two columns so both CTAs stay on the same visual line; the labels wrap
     inside their pill rather than knocking one button to its own row. */
  .fav-cta, .share-cta { flex: 1 1 45%; min-width: 0; justify-content: center; white-space: normal; }
}

/* ---------- retro arcade animations for competitive CTAs ----------
   Applied to the "competitive call outs": FOMO strip, tournament badge,
   claim/premium CTAs. All gated by prefers-reduced-motion. */

@keyframes insert-coin-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: .15; } }
@keyframes trophy-pulse {
  0%, 100% { transform: scale(1) rotate(0deg); filter: drop-shadow(0 0 4px color-mix(in srgb, var(--danger) 60%, transparent)); }
  50% { transform: scale(1.18) rotate(-6deg); filter: drop-shadow(0 0 16px var(--danger)); }
}
@keyframes challenger-flash {
  0%, 92%, 100% { text-shadow: none; }
  94% { text-shadow: 0 0 18px var(--accent-2), 0 0 34px var(--accent-2); }
  96% { text-shadow: none; }
  98% { text-shadow: 0 0 18px var(--accent-2); }
}
@keyframes crt-scan {
  0% { background-position: 0 -120%; }
  100% { background-position: 0 220%; }
}
@keyframes marquee-glow {
  0%, 100% { box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 35%, transparent); }
  50% { box-shadow: 0 0 26px color-mix(in srgb, var(--accent) 70%, transparent); }
}

/* FOMO strip: the kicker blinks like an attract screen, the score value
   flashes like a NEW CHALLENGER prompt, the whole strip breathes neon */
.fomo-kick::after {
  content: " ▮"; animation: insert-coin-blink 1.1s step-end infinite;
}
.fomo-value { animation: challenger-flash 6s linear infinite; }
.fomo-strip { animation: marquee-glow 3.4s ease-in-out infinite; }

/* Trophy iconography pulses on tournament callouts + snapshot button */
.ft-badge { animation: trophy-pulse 2.2s ease-in-out infinite; transform-origin: center; }
.fomo-claim:not(:disabled) { position: relative; overflow: hidden; }
.fomo-claim:not(:disabled)::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, transparent 0%, color-mix(in srgb, var(--accent-2) 22%, transparent) 50%, transparent 100%);
  background-size: 100% 45%; background-repeat: no-repeat;
  animation: crt-scan 2.6s linear infinite;
}

/* Premium/tournament entry CTAs get the arcade marquee treatment */
.premium-lock .playbig, .ft-cta, .upsell-submit {
  animation: marquee-glow 2.8s ease-in-out infinite;
}
.upsell-burst { display: inline-block; }

/* Leaderboard top spot: champion crown shimmer */
.fomo-board li:first-child .fb-name::after {
  content: " 👑"; display: inline-block;
  animation: trophy-pulse 2.8s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .fomo-kick::after, .fomo-value, .fomo-strip, .ft-badge,
  .fomo-claim::after, .premium-lock .playbig, .ft-cta, .upsell-submit,
  .fomo-board li:first-child .fb-name::after, .upsell-burst {
    animation: none !important;
  }
}

/* ---------- competitive FOMO strip + tournament ---------- */

.fomo-strip {
  display: grid; grid-template-columns: 1.2fr .8fr; gap: 22px;
  margin: 22px 0; padding: 22px 26px; position: relative; z-index: 1;
  background: linear-gradient(115deg, var(--panel), color-mix(in srgb, var(--accent) 10%, var(--panel)));
  border: 1px solid var(--accent); border-radius: calc(var(--radius) + 4px);
}
.fomo-kick { font-size: 10.5px; font-weight: 900; letter-spacing: 2.5px; color: var(--danger); }
.fomo-line { display: flex; gap: 14px; align-items: baseline; margin: 8px 0; flex-wrap: wrap; }
.fomo-holder { font-size: 20px; font-weight: 800; }
.fomo-value {
  font-size: 26px; font-weight: 900; color: var(--accent-2);
  font-family: 'Courier New', monospace; letter-spacing: 1px;
}
.fomo-tease { color: var(--dim); font-size: 13.5px; max-width: 52ch; }
.fomo-claim { margin-top: 10px; border-color: var(--accent-2); color: var(--accent-2); }
.fomo-signin { color: var(--dim); font-size: 12px; margin-top: 8px; }

.fomo-board { list-style: none; margin: 0; padding: 0; align-self: center; }
.fomo-board li {
  display: grid; grid-template-columns: 30px 1fr auto; gap: 10px;
  padding: 5px 10px; font-size: 13px; border-radius: 7px;
}
.fomo-board li.top-decile { background: color-mix(in srgb, var(--danger) 14%, transparent); }
.fomo-board .fb-rank { color: var(--dim); font-weight: 800; }
.fomo-board .fb-score { font-family: 'Courier New', monospace; color: var(--accent-2); font-weight: 700; }

.fomo-tournament {
  grid-column: 1 / -1; display: flex; gap: 14px; align-items: center; flex-wrap: wrap;
  border-top: 1px dashed var(--line); padding-top: 14px; font-size: 13px; color: var(--dim);
}
.ft-badge {
  font-size: 10.5px; font-weight: 900; letter-spacing: 2px; color: var(--bg);
  background: var(--danger); border-radius: 99px; padding: 4px 12px;
}
.fomo-tournament b { color: var(--txt); }
.ft-cta { margin-left: auto; text-decoration: none; padding: 7px 14px; border-radius: 9px; }
@media (max-width: 760px) { .fomo-strip { grid-template-columns: 1fr; } }

/* ---------- premium ---------- */

.premium-lock {
  position: absolute; inset: 0; z-index: 5;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; text-align: center; padding: 24px;
  background:
    radial-gradient(ellipse at center, color-mix(in srgb, var(--accent) 18%, transparent), transparent 70%),
    color-mix(in srgb, var(--bg) 88%, transparent);
}
.premium-lock-badge {
  font-size: 11px; font-weight: 900; letter-spacing: 3px;
  color: var(--danger); border: 1px solid var(--danger);
  border-radius: 99px; padding: 4px 14px;
}
.premium-lock h2 { font-size: 22px; max-width: 30ch; }
.premium-lock p { color: var(--dim); font-size: 13.5px; max-width: 52ch; }
.premium-lock .playbig { text-decoration: none; }
.premium-fine { color: var(--dim); font-size: 12px; margin-top: 8px; }
.premium-flash {
  color: var(--accent-2); font-weight: 600; margin-bottom: 12px;
  border: 1px solid var(--accent-2); border-radius: 9px; padding: 9px 16px; display: inline-block;
}
.premium-active { font-size: 16px; margin-bottom: 12px; }
.hero form { display: inline-block; }
.hero .ghost { cursor: pointer; }
.hero .cta { border: 0; cursor: pointer; font-size: 15px; }

/* ---------- my games (user history) ---------- */

.history-list { display: flex; flex-direction: column; gap: 12px; }
.history-row {
  display: grid; grid-template-columns: 120px 1fr auto; gap: 18px; align-items: center;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 16px; text-decoration: none; transition: border-color .15s, transform .15s;
}
.history-row:hover { border-color: var(--accent); transform: translateX(4px); }
.hist-art { height: 80px; border-radius: 9px; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.hist-art img { width: 100%; height: 100%; object-fit: cover; }
.hist-body b { font-size: 16px; display: block; margin-bottom: 6px; }
.hist-meta { color: var(--dim); font-size: 12.5px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.hist-resume { color: var(--accent-2); font-weight: 700; font-size: 13px; white-space: nowrap; }
@media (max-width: 640px) { .history-row { grid-template-columns: 84px 1fr; } .hist-resume { display: none; } }

/* ---------- search palette ---------- */

.palette { position: fixed; inset: 0; z-index: 90; display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; }
.palette[hidden] { display: none; }
.palette-backdrop { position: absolute; inset: 0; background: color-mix(in srgb, var(--bg) 78%, transparent); backdrop-filter: blur(3px); }
.palette-box {
  position: relative; width: min(600px, 92vw);
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  overflow: hidden; box-shadow: 0 30px 80px rgba(0, 0, 0, .5);
}
.palette-input-row { display: flex; align-items: center; gap: 12px; padding: 15px 18px; border-bottom: 1px solid var(--line); color: var(--dim); }
.palette-input-row input { flex: 1; background: none; border: 0; outline: 0; color: var(--txt); font-size: 17px; }
/* R123 — the palette is a real GET form to /search now (the auto-suggest list
   and its .palette-res rows are gone). These four classes shipped with the new
   markup and had NO styles in site.css or ANY of the five theme.css files, which
   is the trap CLAUDE.md names verbatim: "new page containers must reuse a themed
   class ... or four variants render them unstyled". The visible symptom was the
   .sr-only label rendering as literal body text — "Search games" jammed into the
   input row next to the magnifier — on all five themes. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.palette-form { display: block; }
.palette-go {
  flex: 0 0 auto; background: var(--accent); color: var(--bg);
  border: 0; border-radius: 8px; padding: 8px 16px;
  font-weight: 700; font-size: 13.5px; letter-spacing: .02em; cursor: pointer;
}
.palette-go:hover { filter: brightness(1.1); }
.palette-hint { margin: 0; padding: 11px 18px; color: var(--dim); font-size: 12.5px; }
.palette-hint kbd {
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 4px;
  padding: 1px 5px; font-size: 11.5px;
}

/* ---------- search page / pagination / footer ---------- */

.search-page-form { display: flex; gap: 10px; margin: 14px 0; }
.search-page-form input {
  /* min-width:0 — a flex item defaults to min-width:auto and refuses to shrink
     below its intrinsic width, so `flex: 1` alone let this row push past narrow
     screens (the search page scrolled sideways on vault and gamebox). */
  flex: 1; min-width: 0; max-width: 480px; background: var(--panel); border: 1px solid var(--line);
  color: var(--txt); border-radius: 10px; padding: 11px 14px; font-size: 15px; outline: 0;
}
.search-page-form button {
  background: var(--accent); color: var(--bg); border: 0; border-radius: 10px;
  padding: 11px 22px; font-weight: 700; cursor: pointer;
}

/* Pagination — styled for the project's own .pagination/.page-link markup
   (resources/views/pagination/default.blade.php), set as the global default in
   AppServiceProvider. Before that switch, ->links() rendered Laravel 12's
   Tailwind view: no Tailwind here, so its <svg class="w-5 h-5"> chevrons had no
   working size class and ballooned into the "big < >" broken pager. */
.pagination { display: flex; gap: 6px; justify-content: center; align-items: center; flex-wrap: wrap; margin-top: 26px; }
.pagination .page-link {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; height: 40px; padding: 0 13px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel); color: var(--txt);
  font-size: 14px; font-weight: 700; line-height: 1; text-decoration: none;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.pagination a.page-link:hover { border-color: var(--accent); color: var(--accent); }
.pagination .page-link.is-current { background: var(--accent); border-color: var(--accent); color: var(--bg); cursor: default; }
.pagination .page-link.is-nav { font-size: 20px; color: var(--dim); }
.pagination a.page-link.is-nav:hover { color: var(--accent); }
.pagination .page-link.is-disabled { opacity: .35; cursor: default; }
.pagination .page-link.is-gap { border: 0; background: transparent; min-width: 22px; padding: 0; color: var(--dim); font-weight: 700; }

.site-footer {
  border-top: 1px solid var(--line); padding: 30px var(--shell-pad) 44px;
  color: var(--dim); font-size: 12.5px;
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  position: relative; z-index: 1;
}
.footer-links a { color: var(--dim); }

/* ---------- responsive ---------- */

@media (max-width: 720px) {
  .main-nav { display: none; }
  .search-trigger { min-width: 0; }
  .card-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
  .fmeta h2 { font-size: 24px; }
}

/* ===== Online multiplayer (round-19) ===================================== */
.online-btn { position: relative; }
.online-btn .online-badge {
  display: inline-block; margin-left: 7px; padding: 1px 7px; border-radius: 999px;
  background: var(--accent-2); color: var(--bg); font-size: 11px; font-weight: 800;
  letter-spacing: .3px; vertical-align: middle;
}
/* Flashing state: a live room exists — entice the solo player to join. */
.online-btn.someone-online {
  border-color: var(--accent-2);
  animation: onlinePulse 1.15s ease-in-out infinite;
}
.online-btn.someone-online .online-badge { animation: badgeBlink 1.15s steps(1) infinite; }
@keyframes onlinePulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-2) 70%, transparent); }
  50%      { box-shadow: 0 0 10px 3px color-mix(in srgb, var(--accent-2) 60%, transparent); }
}
@keyframes badgeBlink { 0%, 60% { opacity: 1; } 61%, 100% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) {
  .online-btn.someone-online, .online-btn.someone-online .online-badge { animation: none; }
  .online-btn.someone-online { box-shadow: 0 0 8px 2px color-mix(in srgb, var(--accent-2) 55%, transparent); }
}

/* Lobby overlay — a viewport-centred modal (fixed so it's always in view). */
.online-lobby {
  position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 82%, transparent); backdrop-filter: blur(3px); padding: 18px;
}
.online-lobby[hidden] { display: none; }
.lobby-card {
  position: relative; width: min(440px, 100%); background: var(--panel); color: var(--fg);
  border: 1px solid var(--line); border-radius: calc(var(--radius) + 2px); padding: 22px 22px 18px;
  box-shadow: 0 20px 60px rgba(0,0,0,.5);
}
.lobby-close {
  position: absolute; top: 10px; right: 12px; background: none; border: none; color: var(--dim);
  font-size: 24px; line-height: 1; cursor: pointer;
}
.lobby-close:hover { color: var(--fg); }
.lobby-kick { font-size: 11px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; color: var(--accent-2); }
.lobby-head h3 { margin: 4px 0 6px; font-size: 22px; }
.lobby-status { color: var(--dim); font-size: 14px; margin: 0 0 12px; min-height: 20px; }
.lobby-players { list-style: none; padding: 0; margin: 0 0 12px; display: grid; gap: 6px; }
.lobby-player {
  padding: 9px 12px; border-radius: 8px; background: var(--panel-2); border: 1px solid var(--line);
  font-weight: 600; font-size: 14px;
}
.lobby-player.me { border-color: var(--accent); }
.lobby-player.empty { color: var(--dim); font-weight: 500; font-style: italic; border-style: dashed; }
.lobby-invite label { display: block; font-size: 12px; color: var(--dim); margin-bottom: 5px; }
.lobby-invite-row { display: flex; gap: 6px; }
.lobby-invite-row input {
  flex: 1; min-width: 0; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--line);
  background: var(--bg-accent); color: var(--fg); font-size: 12.5px;
}
.lobby-soon {
  margin: 12px 0; padding: 11px 13px; border-radius: 8px; font-size: 13px; line-height: 1.5;
  background: color-mix(in srgb, var(--accent-2) 12%, var(--panel-2));
  border: 1px solid color-mix(in srgb, var(--accent-2) 40%, var(--line));
}
.lobby-actions { display: flex; gap: 8px; margin-top: 14px; }
.lobby-actions .pbtn { flex: 1; }
.lobby-actions .pbtn.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.lobby-local-hint { color: var(--dim); font-size: 12px; line-height: 1.5; margin: 12px 0 0; }
.lobby-local-hint kbd {
  display: inline-block; padding: 1px 5px; border-radius: 4px; background: var(--panel-2);
  border: 1px solid var(--line); font-size: 11px;
}

/* ===== Arcade "Controls for This Game" deck (round-21) =================== */
.game-controls { margin-top: 10px; }
.arcade-deck {
  display: flex; align-items: center; justify-content: center; gap: 34px; flex-wrap: wrap;
  padding: 22px 18px 16px; margin-bottom: 14px;
  background: linear-gradient(180deg, var(--panel-2), color-mix(in srgb, var(--panel) 70%, black));
  border: 1px solid var(--line); border-radius: calc(var(--radius) + 2px);
  box-shadow: inset 0 2px 12px rgba(0,0,0,.45);
}
.deck-stick { text-align: center; }
.stick-graphic { position: relative; width: 84px; height: 84px; margin: 0 auto 8px; }
.stick-base {
  position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
  width: 74px; height: 22px; border-radius: 50%;
  background: radial-gradient(ellipse at 50% 30%, var(--panel-2), #000 85%);
  border: 1px solid var(--line);
}
.stick-shaft {
  position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%) rotate(-8deg);
  transform-origin: bottom center; width: 8px; height: 46px; border-radius: 4px;
  background: linear-gradient(90deg, #666, #2c2c34 70%);
}
.stick-ball {
  position: absolute; left: 50%; bottom: 48px; transform: translateX(-58%);
  width: 30px; height: 30px; border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #ff8888, #d40000 60%, #7a0000);
  box-shadow: 0 3px 8px rgba(0,0,0,.6);
}
.stick-keys { display: flex; gap: 4px; justify-content: center; margin-bottom: 3px; }
.deck-buttons { display: flex; gap: 18px; align-items: flex-end; flex-wrap: wrap; justify-content: center; }
/* R115.3 (David): a 6-button arcade game shows 3-on-top / 3-on-bottom — the
   physical cabinet layout. Cap the flow at 3 per row for the 6-button case only,
   so 4-button decks (e.g. NARC) keep their natural single row. */
.deck-buttons-6 { max-width: 300px; }
.deck-buttons-6 .deck-btn { flex: 0 0 calc(33.333% - 12px); }
/* R213 (David): Mortal Kombat's cabinet diamond - High Punch (top-left) + High
   Kick (top-right), Block in the CENTRE, Low Punch (bottom-left) + Low Kick
   (bottom-right), Run to the side (MK3/UMK3). Buttons arrive in ADB order
   1=HP 2=Block 3=HK 4=LP 5=LK 6=Run, placed on a 3x3 grid. */
.deck-buttons-mk { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, auto); gap: 8px 20px; max-width: 260px; margin: 0 auto; justify-items: center; align-items: center; }
.deck-buttons-mk .deck-btn { flex: none; }
.deck-buttons-mk .deck-btn:nth-child(1) { grid-column: 1; grid-row: 1; }
.deck-buttons-mk .deck-btn:nth-child(2) { grid-column: 2; grid-row: 2; }
.deck-buttons-mk .deck-btn:nth-child(3) { grid-column: 3; grid-row: 1; }
.deck-buttons-mk .deck-btn:nth-child(4) { grid-column: 1; grid-row: 3; }
.deck-buttons-mk .deck-btn:nth-child(5) { grid-column: 3; grid-row: 3; }
.deck-buttons-mk .deck-btn:nth-child(6) { grid-column: 3; grid-row: 2; }
.deck-btn { text-align: center; }
.deck-btn-cap {
  display: flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; margin: 0 auto 7px; border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, color-mix(in srgb, var(--accent) 75%, white), var(--accent) 55%, color-mix(in srgb, var(--accent) 55%, black));
  border: 2px solid color-mix(in srgb, var(--accent) 60%, black);
  box-shadow: 0 4px 10px rgba(0,0,0,.55), inset 0 -3px 6px rgba(0,0,0,.35);
}
.deck-btn:nth-child(even) .deck-btn-cap {
  background: radial-gradient(circle at 34% 28%, color-mix(in srgb, var(--accent-2) 75%, white), var(--accent-2) 55%, color-mix(in srgb, var(--accent-2) 55%, black));
  border-color: color-mix(in srgb, var(--accent-2) 60%, black);
}
.deck-btn-cap .deck-key { background: rgba(0,0,0,.5); }
.deck-key {
  display: inline-block; min-width: 20px; padding: 1px 6px; border-radius: 5px;
  background: rgba(0,0,0,.4); border: 1px solid rgba(255,255,255,.25);
  color: #fff; font: 700 11.5px/1.5 monospace; text-align: center;
}
.deck-label { font-size: 11px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase; color: var(--dim); max-width: 88px; margin: 0 auto; }
.deck-pills { display: flex; flex-direction: column; gap: 8px; }
.deck-pill {
  display: flex; align-items: center; gap: 7px; padding: 6px 12px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--line);
  font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; color: var(--dim);
}

/* ===== ADB screenshot gallery (round-22) ================================= */
.game-gallery {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; margin: 0 0 26px;
}
.gallery-shot {
  margin: 0; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
}
.gallery-shot img { display: block; width: 100%; height: 150px; object-fit: cover; }
.gallery-shot figcaption {
  padding: 6px 10px; font-size: 11px; font-weight: 700; letter-spacing: .8px;
  text-transform: uppercase; color: var(--dim);
}

/* ===== Hop-in CTA strip (round-21) ======================================= */
.online-cta {
  display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  margin: 10px 0 4px; padding: 11px 16px; border-radius: 10px;
  background: color-mix(in srgb, var(--accent-2) 10%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--accent-2) 45%, var(--line));
  font-size: 14px;
}
.online-cta[hidden] { display: none; }
.online-cta.live { animation: ctaGlow 1.4s ease-in-out infinite; }
.online-cta-btn { border-color: var(--accent-2); white-space: nowrap; }
@keyframes ctaGlow {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-2) 55%, transparent); }
  50%      { box-shadow: 0 0 14px 2px color-mix(in srgb, var(--accent-2) 45%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .online-cta.live { animation: none; box-shadow: 0 0 10px 2px color-mix(in srgb, var(--accent-2) 40%, transparent); }
}

/* ===== Competitive rollback advanced-option (R110) ======================= */
/* The prompted premium upgrade on eligible arcade-fighter pages. Additive to
   in-browser online (which stays the default). Themed with the shared vars so
   all five variants render it — never a bare color (invisible-text trap). */
.rollback-cta {
  margin: 12px 0 4px; padding: 14px 16px; border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 9%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--line));
  color: var(--txt);
}
.rollback-cta-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; }
.rollback-cta-badge {
  font-size: 10px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px; color: var(--bg);
  background: var(--accent); align-self: center;
}
.rollback-cta-title { font-size: 16px; font-weight: 800; color: var(--txt); }
.rollback-cta-sub { font-size: 13px; color: var(--dim); }
.rollback-cta-note { margin: 8px 0 12px; font-size: 13.5px; line-height: 1.5; color: var(--dim); }
.rollback-cta-note b { color: var(--txt); }
.rollback-cta-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; }
.rollback-cta-btn {
  display: inline-block; padding: 11px 18px; border-radius: 10px;
  background: var(--accent); color: var(--bg); font-weight: 800; font-size: 14px;
  text-decoration: none; border: 1px solid var(--accent); cursor: pointer;
  transition: transform .12s ease, box-shadow .12s ease;
}
.rollback-cta-btn:hover { transform: translateY(-1px); box-shadow: 0 12px 34px color-mix(in srgb, var(--accent) 52%, transparent); }
.rollback-cta-btn.is-soon { opacity: .7; cursor: default; background: var(--panel-2); color: var(--dim); border-color: var(--line); }
.rollback-cta-btn.is-soon:hover { transform: none; box-shadow: none; }
.rollback-cta-launch { font-size: 13px; color: var(--accent-2); text-decoration: none; }
.rollback-cta-launch:hover { text-decoration: underline; }
.rollback-cta-soon { margin: 4px 0 0; font-size: 12.5px; color: var(--dim); }
.player-zone.is-native-only .rollback-cta { display: none !important; }

/* Toast (local co-op ready etc.) */
.online-toast {
  position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 20px);
  z-index: 90; max-width: min(520px, 92vw); padding: 12px 18px; border-radius: 10px;
  background: var(--panel); color: var(--fg); border: 1px solid var(--accent-2);
  box-shadow: 0 12px 40px rgba(0,0,0,.45); font-size: 14px; opacity: 0; transition: opacity .3s, transform .3s;
}
.online-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ============================================================
   Premium gameplay recording (round-27) — recorder.mjs UI.
   Styles live here (already-loaded site.css); the LOGIC is a
   lazy-imported module, so the game page still ships 0 new JS.
   ============================================================ */
.pbtn-record { border-color: color-mix(in srgb, var(--danger, #ff4d6d) 55%, transparent); }
.pbtn-record:hover { background: color-mix(in srgb, var(--danger, #ff4d6d) 16%, transparent); }

.rec-hud {
  position: absolute; top: 12px; left: 12px; z-index: 40;
  display: flex; align-items: center; gap: 8px;
  font-family: 'Courier New', monospace; font-weight: 700; letter-spacing: 1px;
  background: rgba(10,10,16,.82); color: #fff; border: 1px solid rgba(255,255,255,.18);
  padding: 7px 12px; border-radius: 999px; font-size: 13px; backdrop-filter: blur(3px);
}
.rec-dot { width: 10px; height: 10px; border-radius: 50%; background: #ff3b4e; box-shadow: 0 0 8px #ff3b4e;
  animation: rec-blink 1s steps(2, start) infinite; }
@keyframes rec-blink { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .rec-dot { animation: none; } }
.rec-stop { margin-left: 4px; border: 1px solid rgba(255,255,255,.35); background: transparent; color: #fff;
  border-radius: 999px; padding: 3px 12px; font: inherit; font-size: 12px; cursor: pointer; }
.rec-stop:hover { background: #ff3b4e; border-color: #ff3b4e; }

.rec-modal-back {
  position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center;
  background: rgba(5,5,12,.72); backdrop-filter: blur(4px); padding: 20px;
}
.rec-modal {
  background: var(--surface, #14141f); color: var(--fg, #eee);
  border: 1px solid var(--border, #2a2a3d); border-radius: 16px;
  width: min(560px, 96vw); max-height: 92vh; overflow: auto; padding: 22px; position: relative;
  box-shadow: 0 24px 70px rgba(0,0,0,.55);
}
.rec-modal h3 { margin: 0 0 14px; font-size: 20px; }
.rec-x { position: absolute; top: 12px; right: 14px; background: none; border: none; color: var(--dim, #999);
  font-size: 26px; line-height: 1; cursor: pointer; }
.rec-x:hover { color: var(--fg, #eee); }
.rec-preview { width: 100%; border-radius: 10px; background: #000; aspect-ratio: 4 / 3; }
.rec-meta { font-family: 'Courier New', monospace; font-size: 12.5px; color: var(--dim, #9a9ab0); margin: 10px 0 4px; }
.rec-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.rec-actions .pbtn { text-decoration: none; flex: 1 1 auto; text-align: center; min-width: 150px; }
.rec-status { margin-top: 14px; font-size: 14px; min-height: 1px; }
.rec-ok { color: #46d17a; font-weight: 600; }
.rec-err { color: var(--danger, #ff6b6b); }
.rec-showcase { margin-top: 12px; padding: 14px; border-radius: 12px;
  background: color-mix(in srgb, var(--accent, #22d3ee) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent, #22d3ee) 40%, transparent); }
.rec-showcase p { margin: 0 0 10px; font-size: 13.5px; color: var(--fg, #eee); }

/* ---- live-now discovery strip (round-27 P6b) ---- */
.live-strip { display: flex; gap: 10px; flex-wrap: wrap; margin: 0 0 12px; }
.live-card { display: flex; align-items: center; gap: 10px; text-decoration: none;
  background: linear-gradient(100deg, color-mix(in srgb, #ff3b4e 22%, var(--panel, #17171f)), var(--panel, #17171f));
  border: 1px solid color-mix(in srgb, #ff3b4e 45%, transparent); border-radius: 12px;
  padding: 9px 14px; color: var(--txt, #eee); transition: transform .15s, border-color .15s; }
.live-card:hover { transform: translateY(-2px); border-color: #ff3b4e; }
.live-dot { width: 9px; height: 9px; border-radius: 50%; background: #ff3b4e; box-shadow: 0 0 8px #ff3b4e;
  animation: rec-blink 1s steps(2, start) infinite; }
.live-live { font-family: 'Courier New', monospace; font-size: 11px; font-weight: 800; letter-spacing: 1px; color: #ff6b7d; }
.live-who { font-size: 13.5px; }
.live-go { margin-left: auto; font-size: 12.5px; color: var(--accent-2, #00d4aa); font-weight: 700; }
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }

/* ---- broadcast (round-27 P6): live HUD + viewer page ---- */
.pbtn-live { border-color: color-mix(in srgb, #ff3b4e 55%, transparent); }
.pbtn-live:hover { background: color-mix(in srgb, #ff3b4e 16%, transparent); }
.rec-hud-live { gap: 6px; }
.rec-hud-live .bcast-viewers { font-variant-numeric: tabular-nums; }
.rec-hud-live .bcast-link { color: var(--accent-2, #00d4aa); text-decoration: underline; font-size: 11px; margin: 0 4px; }

.watch-shell { padding-top: 20px; }
.watch-head { display: flex; align-items: center; gap: 14px; margin: 10px 0 14px; flex-wrap: wrap; }
.watch-head h1 { font-size: clamp(22px, 4vw, 32px); }
.watch-badge { font-family: 'Courier New', monospace; font-size: 12px; text-transform: uppercase; letter-spacing: .1em;
  color: #fff; background: #ff3b4e; border-radius: 999px; padding: 4px 12px; }
.watch-stage { position: relative; width: 100%; aspect-ratio: 4 / 3; max-height: 74vh; background: #000;
  border: 1px solid var(--line, #26262f); border-radius: 14px; overflow: hidden;
  display: flex; align-items: center; justify-content: center; }
.watch-stage .watch-video { width: 100%; height: 100%; object-fit: contain; background: #000; }
.watch-hint { color: var(--dim, #8e8e9d); font-size: 14px; }
.watch-cta { display: flex; gap: 12px; margin-top: 16px; flex-wrap: wrap; align-items: center; }

/* ---- live chat panel (round-27 P5, lazy chat.mjs) ---- */
.chat-panel {
  position: absolute; top: 12px; right: 12px; z-index: 45;
  width: min(320px, 86vw); max-height: min(430px, 70vh);
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--panel, #17171f) 92%, transparent);
  border: 1px solid var(--line, #26262f); border-radius: 14px;
  box-shadow: 0 18px 50px rgba(0,0,0,.5); backdrop-filter: blur(6px);
}
.chat-head { display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-bottom: 1px solid var(--line, #26262f); font-size: 14px; }
.chat-status { margin-left: auto; font-family: 'Courier New', monospace; font-size: 11px;
  color: var(--accent-2, #00d4aa); text-transform: uppercase; letter-spacing: .06em; }
.chat-x { background: none; border: none; color: var(--dim, #8e8e9d); font-size: 20px; cursor: pointer; line-height: 1; }
.chat-x:hover { color: var(--txt, #eee); }
.chat-list { list-style: none; margin: 0; padding: 10px 14px; overflow-y: auto; flex: 1;
  display: flex; flex-direction: column; gap: 7px; min-height: 120px; }
.chat-list li { font-size: 13px; line-height: 1.4; overflow-wrap: anywhere; }
.chat-list li b { color: var(--accent-2, #00d4aa); font-weight: 700; margin-right: 6px; }
.chat-list li time { display: inline-block; margin-left: 8px; color: var(--dim, #8e8e9d); font-size: 10.5px; }
.chat-new { animation: chat-pop .25s ease-out; }
@keyframes chat-pop { from { transform: translateY(4px); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .chat-new { animation: none; } }
.chat-form { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--line, #26262f); }
.chat-input { flex: 1; background: var(--panel-2, #20202a); border: 1px solid var(--line, #26262f);
  border-radius: 9px; color: var(--txt, #eee); padding: 8px 11px; font: inherit; font-size: 13px; }
.chat-input:focus { outline: none; border-color: var(--accent, #7c5cff); }
.chat-send { flex: 0 0 auto; }
.chat-signin { margin: 0; padding: 10px 14px; border-top: 1px solid var(--line, #26262f);
  color: var(--dim, #8e8e9d); font-size: 12.5px; }

/* "▶ Watch" chip on a Top-Players board entry that has a public showcase run. */
.fb-watch { margin-left: 8px; font-family: 'Courier New', monospace; font-size: 11px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; text-decoration: none;
  color: var(--accent-2, #ff6ec7); border: 1px solid currentColor; border-radius: 999px; padding: 1px 8px;
  cursor: pointer; background: transparent; }
.fb-watch:hover { background: color-mix(in srgb, var(--accent-2, #ff6ec7) 18%, transparent); }

/* R41.4b — per-console controller layout (partials/console-pad) */
.console-pad{margin:14px auto 6px;max-width:420px}
.console-pad svg{width:100%;height:auto;display:block}
.cp-body{fill:rgba(255,255,255,.05);stroke:rgba(255,255,255,.16);stroke-width:1.5}
.cp-shoulder,.cp-pill{fill:rgba(255,255,255,.10);stroke:rgba(255,255,255,.22);stroke-width:1}
.cp-dpad-bar{fill:rgba(255,255,255,.12);stroke:rgba(255,255,255,.22);stroke-width:1}
.cp-face{fill:rgba(139,92,246,.20);stroke:rgba(139,92,246,.65);stroke-width:1.5}
.cp-face-name{fill:#e6e0f8;font:700 11px system-ui,sans-serif;text-anchor:middle}
.cp-btn-name{fill:#8f89a8;font:600 8.5px system-ui,sans-serif;text-anchor:middle;letter-spacing:.4px}
.cp-key{fill:#22d3ee;font:700 11px ui-monospace,Consolas,monospace;text-anchor:middle}
.cp-key.sm{font-size:10px}
.cp-caption{text-align:center;font-size:11.5px;color:var(--dim,#a79fc4);margin-top:4px}

/* R41.5 — chat rebuilt as a floating, draggable popup on <body>: fixed
   BOTTOM-RIGHT (not stuck inside the game frame), above everything, drag by
   the header (cursor set in chat.mjs). Overrides the legacy in-frame rules. */
.chat-panel.chat-float{
  position:fixed; top:auto; right:18px; bottom:18px; left:auto;
  z-index:9999; width:min(320px,86vw); max-height:min(430px,70vh);
  touch-action:none;
}
.chat-panel.chat-float .chat-head{user-select:none}

/* R41.6 — recording HUD: STICKY lower-left of the PAGE (on <body>, outside the
   gameplay box) + unmistakable pulsing ring while recording. Overrides the
   legacy in-frame top-left rules. */
.rec-hud{
  position:fixed; top:auto; left:18px; bottom:18px; z-index:9998;
  animation:rec-glow 1.4s ease-in-out infinite;
}
@keyframes rec-glow{
  0%,100%{box-shadow:0 0 0 0 rgba(228,50,50,.55), 0 8px 26px rgba(0,0,0,.5)}
  50%{box-shadow:0 0 0 9px rgba(228,50,50,0), 0 8px 26px rgba(0,0,0,.5)}
}
.rec-hud .rec-dot{animation:rec-blink 1s steps(2,start) infinite}
@keyframes rec-blink{to{visibility:hidden}}
/* R41.6 — the Play Cloud upload is the primary action */
.rec-upload-primary{
  background:linear-gradient(90deg,#8b5cf6,#22d3ee); color:#fff; font-weight:800;
  border:0; box-shadow:0 6px 18px rgba(139,92,246,.35);
}

/* R42 — shaped pads: PSP handheld + DualShock */
.console-pad-psp{max-width:520px}
.console-pad-dualshock{max-width:460px}
.cp-screen{fill:#0b0a12;stroke:rgba(139,92,246,.5);stroke-width:1.5}
.cp-screen-label{fill:rgba(139,92,246,.35);font:700 26px system-ui,sans-serif;text-anchor:middle;letter-spacing:6px}
.cp-analog{fill:rgba(255,255,255,.08);stroke:rgba(255,255,255,.25);stroke-width:1.2}
.cp-analog-nub{fill:rgba(255,255,255,.16)}
.cp-face-ps{fill:rgba(255,255,255,.06);stroke:rgba(255,255,255,.35)}
.console-pad .cp-face-name{font-size:12px}
/* ===== R120.2 — full console navigation + central profile menu ===== */
.nav-consoles,.nav-profile{position:relative;display:inline-flex}
.nav-consoles-trigger,.nav-profile-trigger{
  display:inline-flex;align-items:center;gap:6px;background:none;border:0;cursor:pointer;
  color:inherit;font:inherit;padding:6px 8px;border-radius:8px}
.nav-consoles-trigger:hover,.nav-profile-trigger:hover,
.nav-consoles-trigger[aria-expanded="true"],.nav-profile-trigger[aria-expanded="true"]{
  background:rgba(255,255,255,.08)}
.nav-consoles-menu,.nav-profile-menu{
  position:absolute;top:calc(100% + 8px);z-index:120;
  background:var(--panel,#17171f);border:1px solid var(--line,#26262f);
  border-radius:12px;box-shadow:0 18px 44px rgba(0,0,0,.5);padding:10px}
.nav-consoles-menu{left:0;width:min(560px,92vw)}
.nav-profile-menu{right:0;min-width:220px;display:flex;flex-direction:column}
/* R120.2 FIX: the panel ships with the `hidden` ATTRIBUTE, but `[hidden]` is only
   `display:none` from the UA stylesheet — any class that sets `display` outranks
   it. `.nav-profile-menu{display:flex}` therefore forced the profile menu OPEN on
   every page of every theme, covering the nav and clipping the H1. `.nav-consoles-menu`
   sets no `display`, which is exactly why the Consoles dropdown stayed correctly
   shut — the two side by side are the proof. Give the attribute its meaning back.
   Any future panel that sets `display` must be added here too. */
.nav-consoles-menu[hidden],.nav-profile-menu[hidden]{display:none}
.nav-consoles-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:4px;
  max-height:min(60vh,420px);overflow-y:auto}
.nav-consoles-grid a{display:flex;justify-content:space-between;align-items:center;gap:8px;
  padding:8px 10px;border-radius:8px;text-decoration:none;font-size:14px}
.nav-consoles-grid a:hover,.nav-consoles-grid a.on{background:rgba(255,255,255,.09)}
.ncm-count{font-size:11px;color:var(--dim,#8e8e9d);font-variant-numeric:tabular-nums}
.nav-profile-name{font-size:13px;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.npm-head{padding:8px 10px 10px;border-bottom:1px solid var(--line,#26262f);margin-bottom:6px;
  display:flex;flex-direction:column;gap:2px}
.npm-head span{font-size:11.5px;color:var(--dim,#8e8e9d)}
.nav-profile-menu a,.npm-signout button{
  display:block;width:100%;text-align:left;padding:8px 10px;border-radius:8px;
  text-decoration:none;font-size:14px;background:none;border:0;color:inherit;font-family:inherit;cursor:pointer}
.nav-profile-menu a:hover,.npm-signout button:hover{background:rgba(255,255,255,.09)}
.npm-signout{margin-top:4px;border-top:1px solid var(--line,#26262f);padding-top:4px}
@media (max-width:720px){
  .nav-consoles-menu{left:auto;right:0;width:min(420px,94vw)}
  .nav-profile-name{display:none}
  /* R120.2 phone header: the profile icon was added to an already-tight row, so
     the search trigger is cramped ("Search games…" wraps, the `Ctrl K` chip
     crowds the icon). `Ctrl K` is a desktop-only affordance — a phone has no
     Ctrl key — so hide it and the label, and keep the button SHRINKABLE.
     Never pin flex-shrink:0 on a header item: doing so removed the only element
     that could absorb slack and pushed the row 125-144px past the viewport
     (16 sweep failures on neon-arcade + playdeck). */
  .search-trigger kbd,.search-trigger span{display:none}
  .search-trigger{min-width:0;flex-shrink:1;justify-content:center}
}
/* R142h (David live, iOS): a clean header on TOUCH devices, in BOTH orientations.
   The width media queries above only fire =<720px, so a phone in LANDSCAPE (~900px
   wide) fell back to the full desktop nav + the "Ctrl K" search chip — an action a
   touchscreen can't take. And in portrait the nav was hidden outright, so there was
   NO navigation. Key off the INPUT type instead: on any touch device show the (now
   minimal Consoles + Premium) nav, cluster it to the right, and collapse search to
   its icon. Search stays SHRINKABLE — pinning flex-shrink:0 here once pushed the row
   125-144px off-screen (see the note in the =<720px block above). */
@media (hover: none) and (pointer: coarse) {
  /* Scoped to the neon-arcade site (retroplayers.club) — the theme David tests and
     reported against. The other four sites keep their prior mobile chrome; extend
     this deliberately if asked, don't inherit it by accident.
     R142i (David): KEEP the full logo + tagline at their normal size — his call,
     "there is more than enough space." Only drop the redundant Home/Arcade links
     (done in the blade) and the Ctrl-K search chip (a touchscreen has no Ctrl key).
     Show the Consoles + Premium nav, vertically CENTRED so Premium lines up with the
     Consoles dropdown, and collapse search to its icon. No logo shrink, no tagline
     hide — those were the R142h overreach David asked to undo. */
  .theme-neon-arcade .site-header .main-nav { display: flex; flex-wrap: nowrap; align-items: center; gap: 16px; }
  .theme-neon-arcade .search-trigger kbd, .theme-neon-arcade .search-trigger span { display: none; }
  .theme-neon-arcade .search-trigger { min-width: 0; flex-shrink: 1; justify-content: center; padding: 8px 10px; }
  /* The Consoles trigger no longer sits at the viewport's right edge (search +
     profile are to its right), so the pre-existing `right:0` anchored the panel to
     the trigger and ran it off the LEFT of a phone screen. Anchor it to the
     full-width sticky header instead (nav-consoles goes static). Profile menu is
     untouched — it IS at the right edge, so its right:0 already lands on screen. */
  .theme-neon-arcade .site-header .nav-consoles { position: static; }
  .theme-neon-arcade .site-header .nav-consoles-menu { left: 10px; right: 10px; width: auto; top: calc(100% + 6px); max-height: calc(100dvh - 96px); overflow-y: auto; }
}
/* Narrow touch (portrait phones): the full-size logo + tagline will not share one
   row with the nav at ~390px, so wrap the header cleanly — brand + search + profile
   on row 1, the Consoles + Premium nav on its own centred row 2. Landscape phones
   (>700px, the state David screenshotted) keep a single row with room to spare, so
   the logo stays large there. */
@media (hover: none) and (pointer: coarse) and (max-width: 700px) {
  .theme-neon-arcade .site-header { flex-wrap: wrap; gap: 8px 14px; }
  .theme-neon-arcade .site-header .search-trigger { order: 2; margin-left: auto; }
  .theme-neon-arcade .site-header .nav-profile { order: 3; }
  .theme-neon-arcade .site-header .main-nav { order: 4; flex-basis: 100%; justify-content: center; }
}
/* R115.6 — Sega Genesis 6-button pad (Sega CD / 32X / Genesis), per David's image */
.console-pad-genesis6{max-width:520px}
.cp-start{fill:#2f4bd6;stroke:#5b73e8;stroke-width:1.2}
.cp-face-xyz{fill:#e3c84a;stroke:#c9ae2f;stroke-width:1.5}
.cp-face-abc{fill:#3a3a44;stroke:rgba(255,255,255,.28);stroke-width:1.5}
.console-pad-genesis6 .cp-face-name{fill:#15151b;font-weight:800}
.console-pad-genesis6 .cp-face-abc + .cp-face-name{fill:#f2f2f7}
/* R116.3 — ColecoVision controller (joystick + 12-key keypad + 2 fire buttons) */
.console-pad-coleco{max-width:540px}
.cp-brand{fill:#e8e8ef;font:800 20px 'Segoe UI',system-ui,sans-serif;letter-spacing:1px}
.cp-ball{fill:#f2f2f7}
.cp-keypad-key{fill:rgba(255,255,255,.07);stroke:rgba(255,255,255,.22);stroke-width:1}
.cp-keypad-lbl{fill:#c9c9d2;font:600 16px 'Segoe UI',system-ui,sans-serif;text-anchor:middle}
.cp-fire{fill:#ededf2;stroke:#c9c9d2;stroke-width:2}
.console-pad-coleco .cp-btn-name{font-size:12px}
.console-pad-coleco .cp-key{font-size:14px}
/* R125 — Intellivision hand controller: a recessed 12-key keypad over a large
   metallic 16-direction disc, four side buttons carrying three signals. Drawn
   to David's supplied reference (intellivision_controller_configuration.png) —
   pale keys in a dark well, lowercase clear/0/enter, silver disc — under the
   HANDOFF ruling that SVG is allowed for these eight consoles provided it
   follows the reference's real parameters. Portrait, so NARROWER than every
   other pad. */
.console-pad-intv{max-width:300px}
.console-pad-intv .cp-body{fill:#26262e;stroke:rgba(255,255,255,.20);stroke-width:1.5}
.console-pad-intv .cp-brand{font:800 12px 'Segoe UI',system-ui,sans-serif;letter-spacing:2px;fill:#9a9aa8}
.cp-keypad-well{fill:rgba(0,0,0,.45);stroke:rgba(255,255,255,.10);stroke-width:1}
.console-pad-intv .cp-keypad-key{fill:#d9d5c8;stroke:#a9a597;stroke-width:1}
.console-pad-intv .cp-keypad-lbl{fill:#2a2a2f;font:700 15px 'Segoe UI',system-ui,sans-serif}
.cp-disc-well{fill:rgba(0,0,0,.45);stroke:rgba(255,255,255,.10);stroke-width:1}
.cp-disc{fill:#b9b6ad;stroke:#8d8a82;stroke-width:2}
.console-pad-intv .cp-fire{fill:#ededf2;stroke:#c9c9d2;stroke-width:1.5}
.console-pad-intv .cp-btn-name{font-size:8px}
/* Key labels drawn ON the pale keypad keys or ON the silver disc need a DARK
   fill — the sitewide cyan (#22d3ee) is near-invisible on either. Carried on an
   explicit class rather than a positional selector, so the labels that sit
   outside the body (the side buttons, on the page background) keep the normal
   cyan and stay readable. Blanket-darkening every .cp-key inside this shape is
   exactly how the "invisible text on 2 of 5 themes" class of bug happens. */
.console-pad-intv .cp-key-dark{fill:#173a5e}

/* R125 — six new console-pad shapes (atari 2600/5200/7800, gb/gbc, gba, lynx).
   Each replaces the generic gamepad body, which drew L/R shoulders and 4 face
   buttons for hardware that has neither. Colours follow the reference images
   in laravel/public/assets/img/ enough to be recognisable, without inventing
   detail (David's ruling: "You can redraw only based on the existing
   parameters of the images"). */
.console-pad-atari2600, .console-pad-atari7800{max-width:260px}
.console-pad-atari2600 .cp-body, .console-pad-atari7800 .cp-body{fill:#1a1a20;stroke:rgba(255,255,255,.20);stroke-width:1.5}
.cp-stick{fill:#101015;stroke:rgba(255,255,255,.18);stroke-width:1.2}
.cp-stick-base{fill:#111117;stroke:rgba(255,255,255,.14);stroke-width:1}
.cp-stick-knob{fill:#e0dccb;stroke:#8d8a7c;stroke-width:1.5}
.cp-fire-red{fill:#c8351d;stroke:#7d1f0f;stroke-width:1.5}

.console-pad-atari5200{max-width:280px}
.console-pad-atari5200 .cp-body{fill:#1a1a20;stroke:rgba(255,255,255,.20);stroke-width:1.5}
.cp-5200-pills .cp-pill-start{fill:#3a8b3a;stroke:#256b25}
.cp-5200-pills .cp-pill-pause{fill:#c4a83a;stroke:#8f7a24}
.cp-5200-pills .cp-pill-reset{fill:#c8351d;stroke:#7d1f0f}
.console-pad-atari5200 .cp-keypad-key{fill:#141419;stroke:rgba(255,255,255,.20)}
.console-pad-atari5200 .cp-keypad-lbl{fill:#c9be3a;font:700 14px 'Segoe UI',system-ui,sans-serif;text-anchor:middle}

.console-pad-gameboy{max-width:320px}
.console-pad-gameboy .cp-gb-body{fill:#c0c1c4;stroke:#7f7f83;stroke-width:1.5}
.console-pad-gameboy .cp-gb-bezel{fill:#3c3c42;stroke:#22222a;stroke-width:1}
.console-pad-gameboy .cp-gb-screen{fill:#8f9f68;stroke:#4c5a32;stroke-width:1}
.cp-face-red{fill:#8a2649;stroke:#5d1732;stroke-width:1.2}
.console-pad-gameboy .cp-face-name, .console-pad-lynx .cp-face-name{fill:#f4ecff}
/* R125 CHILD — the sitewide cyan cp-key (#22d3ee) is near-invisible against
   the Game Boy's light-grey body (1.0:1 measured by verify_new_pad_shapes.py).
   Same pattern as .console-pad-intv .cp-key-dark for the pale keypad keys.
   Applied blanket: every key label inside a gameboy shape is dark navy, which
   has 8.7:1 against the light-grey body and 12+:1 against the dark red faces. */
.console-pad-gameboy .cp-key{fill:#173a5e}

.console-pad-gba{max-width:520px}
.console-pad-gba .cp-gba-body{fill:#3a3fb9;stroke:#232878;stroke-width:1.5}
.console-pad-gba .cp-gb-bezel{fill:#141520;stroke:#0b0c15;stroke-width:1}
.console-pad-gba .cp-gb-screen{fill:#4c4e60;stroke:#2a2c3a;stroke-width:1}
.console-pad-gba .cp-dpad-bar{fill:#c9c9d2;stroke:#8b8b95}
.console-pad-gba .cp-face{fill:#dcdce4;stroke:#8f8f97}
.console-pad-gba .cp-face-name{fill:#1f1f28;font-weight:800}

/* David directive 2026-09-01 v3 — "Use the original referenced image minus
   the white background." Uses David's stylised bitmap saved as a transparent
   PNG (JPG background color-keyed to alpha), with an SVG hotspot overlay
   above at PIXEL-ACCURATE button centroids detected from the image (no more
   guessed coords). Overlay shares the image viewBox (420 × 408). */
.console-pad-n64{max-width:420px}
.console-pad-n64 .cp-n64-frame{position:relative;width:100%}
.console-pad-n64 .cp-n64-img{width:100%;height:auto;display:block}
.console-pad-n64 .cp-n64-overlay{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.console-pad-n64 .cp-n64-name{fill:#1a1a20;font:800 11px system-ui,sans-serif;text-anchor:middle;paint-order:stroke;stroke:rgba(255,255,255,.85);stroke-width:2.5;stroke-linejoin:round}
.console-pad-n64 .cp-n64-caption{fill:#3a3a40;font:700 9px system-ui,sans-serif;text-anchor:middle;letter-spacing:1px;paint-order:stroke;stroke:rgba(255,255,255,.85);stroke-width:2;stroke-linejoin:round}
.console-pad-n64 .cp-n64-key{font:800 13px system-ui,sans-serif;text-anchor:middle;dominant-baseline:middle;paint-order:stroke;stroke-width:2.5;stroke-linejoin:round}
.console-pad-n64 .cp-n64-key-dark{fill:#0a1a2e;stroke:rgba(255,255,255,.85)}
/* Keys sitting INSIDE the coloured face buttons — white on red/green/blue. */
.console-pad-n64 .cp-n64-key-btn{fill:#fff;stroke:rgba(0,0,0,.55);font-size:11px}
/* Keys sitting INSIDE the tiny yellow C-diamond — dark on the yellow. */
.console-pad-n64 .cp-n64-key-c{fill:#2a1e00;stroke:rgba(255,255,255,.55);font-size:10px}
.console-pad-n64 .cp-n64-tab-name{fill:#1a1a20;font:800 10px system-ui,sans-serif;text-anchor:middle;paint-order:stroke;stroke:rgba(255,255,255,.85);stroke-width:2}
.console-pad-n64 .cp-n64-tab-key{fill:#0a1a2e;font:800 12px system-ui,sans-serif;text-anchor:middle;paint-order:stroke;stroke:rgba(255,255,255,.85);stroke-width:2.5}

.console-pad-lynx{max-width:620px}
.console-pad-lynx .cp-lynx-body{fill:#3f414a;stroke:#22232a;stroke-width:1.5}
.console-pad-lynx .cp-gb-bezel{fill:#111116;stroke:#000;stroke-width:1}
.console-pad-lynx .cp-gb-screen{fill:#20232c;stroke:#000;stroke-width:1}
.cp-lynx-dpad-well{fill:rgba(0,0,0,.35);stroke:rgba(255,255,255,.10);stroke-width:1}
.cp-pill-ref{opacity:.42}

/* R129b — Visual Controller Mapper: the player's USB pad drawn beside the
   console pad. player.js polls navigator.getGamepads while the Controllers
   panel is open; a pressed control gets .usb-live, its console action is
   painted into the .usb-assign badge from the ENGINE's value2 truth. */
.mapper-stage{display:flex;flex-wrap:wrap;gap:18px;align-items:flex-start;justify-content:center}
.mapper-stage > *{flex:1 1 320px;min-width:0}
.mapper-stage .console-pad{margin-top:0}
.usb-mapper{max-width:560px;margin:0 auto}
.usb-mapper-head{font-weight:700;font-size:14px;letter-spacing:.5px;margin:2px 0 6px;text-align:center}
.usb-mapper-status{margin:0 0 6px;font-size:12.5px;color:var(--dim);text-align:center;min-height:1.4em}
/* live-state TEXT takes the theme's own accent: hardcoded cyan measured
   1.8:1 on playdeck's white / gamebox's cream panels (mapper_theme_check),
   and every theme defines --accent-2 readable on its own panel. The SHAPE
   light-up below stays cyan on purpose — a filled glow, not text. */
.usb-mapper-status[data-state="live"]{color:var(--accent-2, #22d3ee)}
.usb-mapper-hint{font-size:12px;color:var(--dim);margin:6px 0 0;text-align:center}
.usb-pad svg{width:100%;height:auto;display:block}
.usb-assign{fill:#8f89a8;font:600 8.5px system-ui,sans-serif}
.usb-arrow{fill:rgba(255,255,255,.35);font:700 11px system-ui,sans-serif}
.usb-ctl{cursor:pointer}
/* Light-up: shape fills go accent-cyan; the arrow glyphs recolour. The
   drop-shadow glow reads on every theme because the base shapes are
   translucent white — no per-theme variable needed. */
rect.usb-ctl.usb-live,circle.usb-ctl.usb-live{fill:rgba(34,211,238,.50);stroke:#22d3ee;filter:drop-shadow(0 0 6px rgba(34,211,238,.85))}
text.usb-arrow.usb-live{fill:#22d3ee}

/* R139 — adaptive controller-type picker + per-type controller drawings. The
   <select> swaps which .usb-pad-shape is visible; the light-up JS rescopes to
   the visible one. Colours are explicit (not theme tokens) because they are
   the CONTROLLER's own hardware colours — an N64's blue A, green B, yellow C —
   and read on the dark controls panel every theme shows the mapper in. */
.usb-pad-picker{display:flex;align-items:center;justify-content:center;gap:8px;margin:2px 0 8px;flex-wrap:wrap;min-width:0}
.usb-pad-type-label{font-size:12px;color:var(--dim);display:inline-flex;align-items:center;gap:6px}
.usb-pad-type{background:rgba(255,255,255,.06);color:inherit;border:1px solid rgba(255,255,255,.22);border-radius:6px;padding:3px 8px;font-size:12.5px;font-family:inherit;cursor:pointer}
.usb-pad-type:focus{outline:2px solid var(--accent-2,#22d3ee);outline-offset:1px}
.usb-pad-type option{background:#1b1b24;color:#f0f0f5}
.usb-pad-auto{font-size:11px;color:var(--accent-2,#22d3ee);border:1px solid rgba(34,211,238,.4);border-radius:10px;padding:1px 8px;white-space:nowrap}
.usb-pad-shape[hidden]{display:none}
/* letters on coloured buttons — white with a dark halo reads on blue/green/
   red/yellow/lavender alike, so no per-colour letter juggling. */
.usb-on-color{fill:#fff;font-weight:800;paint-order:stroke;stroke:#0d0d12;stroke-width:2.4px;stroke-linejoin:round}
/* N64 hardware colours */
.usb-n64-body{fill:rgba(210,210,220,.10);stroke:rgba(255,255,255,.22);stroke-width:1.5}
.usb-n64-start{fill:#d23b3b;stroke:#a12a2a;stroke-width:1.5}
.usb-n64-stick{fill:#eceff4;stroke:#b9bdc7;stroke-width:1.2}
.usb-n64-z{fill:#4a4a56;stroke:rgba(255,255,255,.28);stroke-width:1.2}
.usb-n64-a{fill:#3b6fd2;stroke:#2a52a0;stroke-width:1.5}
.usb-n64-b{fill:#2ba361;stroke:#1f7d4a;stroke-width:1.5}
.usb-n64-c{fill:#e3c84a;stroke:#c9ae2f;stroke-width:1.4}
.usb-n64-c-label{fill:#e3c84a;font:800 13px system-ui,sans-serif}
/* SNES lavender faces; Genesis 6-button yellow (top) + dark (bottom) */
.usb-snes-face{fill:#7c74c7;stroke:#5a52a0;stroke-width:1.5}
.usb-genesis-xyz{fill:#e3c84a;stroke:#c9ae2f;stroke-width:1.5}
.usb-genesis-abc{fill:#3a3a44;stroke:rgba(255,255,255,.28);stroke-width:1.5}
kbd.usb-flash{border-color:var(--accent-2, #22d3ee);color:var(--accent-2, #22d3ee);animation:boot-blink .5s 2}
/* R136: the native app-mode map rows are not kbd — clicking a control on the
   Visual Controller Mapper flashes the matching action row here. */
.app-map-row.usb-flash{outline:2px solid var(--accent-2, #22d3ee);outline-offset:2px;border-radius:6px;animation:boot-blink .5s 2}
.cp-key-armable{cursor:pointer}

/* R42 — chat optimistic echo states */
.chat-list li.chat-pending{opacity:.55}
.chat-list li.chat-failed{opacity:.75}
.chat-list li.chat-failed time{color:#ff8fa5}

/* R42 — "What Do You Think About This Game" comments beside the story */
.story-comments-grid{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:26px;align-items:start}
@media (max-width:980px){.story-comments-grid{grid-template-columns:1fr}}
.game-comments{background:var(--panel,#17171f);border:1px solid var(--line,#26262f);border-radius:14px;padding:16px 18px;position:sticky;top:14px}
.game-comments h2{margin:0 0 10px;font-size:17px}
.gc-list{list-style:none;margin:0 0 12px;padding:0;max-height:420px;overflow-y:auto;display:flex;flex-direction:column;gap:10px}
.gc-list li{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);border-radius:10px;padding:8px 11px;font-size:13.5px;line-height:1.45}
.gc-list li b{color:var(--accent,#8b5cf6);font-size:12.5px;display:block;margin-bottom:2px}
.gc-list li time{display:block;color:var(--dim,#8f89a8);font-size:11px;margin-top:4px}
.gc-list .gc-empty{color:var(--dim,#8f89a8);background:none;border:0;text-align:center}
.gc-form textarea{width:100%;background:rgba(255,255,255,.05);border:1px solid var(--line,#26262f);border-radius:10px;color:inherit;padding:9px 11px;font:inherit;font-size:13.5px;resize:vertical;margin-bottom:8px}
.gc-form .gc-status{margin-left:10px;font-size:12px;color:var(--dim,#8f89a8)}
.gc-signin{color:var(--dim,#8f89a8);font-size:13px}
.gc-pending{opacity:.55}
/* R227b (David): "Videos for This {Game}" — its OWN full-width area UNDER the comments
   (separate from the comments box). Click-to-play facade: a YouTube thumbnail + play
   button, swapped for the youtube-nocookie iframe on tap (fast; a lazy iframe here
   rendered a black box on iOS). 2-up on desktop, stacked on mobile. */
.game-videos{margin:22px 0 8px}
.game-videos h3{margin:0 0 12px;font-size:18px;line-height:1.3}
.gv-grid{display:grid;grid-template-columns:1fr;gap:16px}
@media (min-width:640px){.gv-grid{grid-template-columns:1fr 1fr}}
.gv-embed{position:relative;aspect-ratio:16/9;background:#000 center/cover no-repeat;border:1px solid var(--line,#26262f);border-radius:12px;overflow:hidden;cursor:pointer;padding:0;display:block;width:100%}
.gv-embed .gv-thumb{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.gv-embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.gv-play{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:68px;height:48px;border:0;border-radius:14px;background:rgba(0,0,0,.55);cursor:pointer;transition:background .15s}
.gv-play::before{content:"";position:absolute;left:50%;top:50%;transform:translate(-38%,-50%);border-style:solid;border-width:11px 0 11px 19px;border-color:transparent transparent transparent #fff}
.gv-embed:hover .gv-play{background:#e0242c}
/* R227h Phase 2 (David): game-page video thumbnails LINK to the dedicated Gameplay
   Videos page; JS upgrades to a grow-open MODAL for viewers who can inline-play (guests). */
.game-videos .gv-head{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;margin:0 0 12px}
.game-videos .gv-head h3{margin:0}
.gv-seeall{margin-left:auto;font-size:13px;color:#ff2e88;text-decoration:none;white-space:nowrap;font-weight:600}
.gv-seeall:hover{text-decoration:underline}
.game-videos a.gv-embed{text-decoration:none}
.gvm{position:fixed;inset:0;z-index:9999;display:grid;place-items:center;padding:20px}
.gvm[hidden]{display:none!important}
.gvm-backdrop{position:absolute;inset:0;background:rgba(6,4,14,.82);opacity:0;transition:opacity .2s}
.gvm.show .gvm-backdrop{opacity:1}
.gvm-box{position:relative;width:min(960px,94vw);background:var(--surface,#151228);border:1px solid var(--line,#2c2650);border-radius:14px;overflow:hidden;box-shadow:0 30px 80px -30px #000;transform:scale(.92);opacity:0;transition:transform .2s,opacity .2s}
.gvm.show .gvm-box{transform:scale(1);opacity:1}
.gvm-x{position:absolute;right:8px;top:8px;z-index:3;width:34px;height:34px;border-radius:9px;border:1px solid var(--line,#2c2650);background:rgba(8,6,16,.72);color:#fff;font-size:20px;line-height:1;cursor:pointer}
.gvm-x:hover{background:#ff2e88;border-color:#ff2e88;color:#2a0416}
.gvm-stage{position:relative;aspect-ratio:16/9;background:#000}
.gvm-stage iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.gvm-bar{display:flex;align-items:center;gap:12px;padding:11px 14px;border-top:1px solid var(--line,#2c2650)}
.gvm-title{font-size:13.5px;color:var(--ink,#ece9f8);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gvm-nav{width:34px;height:34px;border-radius:9px;border:1px solid var(--line,#2c2650);background:transparent;color:var(--dim,#9990c4);font-size:18px;cursor:pointer;flex:none}
.gvm-nav:hover{color:#fff;border-color:#ff2e88}
.gvm-all{font-size:12.5px;color:#ff2e88;text-decoration:none;white-space:nowrap}
.gvm-all:hover{text-decoration:underline}
@media (prefers-reduced-motion:reduce){.gvm-backdrop,.gvm-box{transition:none}}


/* R96 (David): the remap save needs a DISTINGUISHED "definitely saved +
   transferred to the emulator" confirmation, not a quiet status line. The save
   button flashes green with a check, and a badge pops over the pad visual
   naming exactly what happened (live push vs applies-at-launch). Colors are
   self-contained — var(--muted)/theme vars are NOT defined on all variants. */
.app-tool-btn.app-save-flash{background:#1f7a3d;border-color:#2ecc71;color:#eafff1;
  animation:appSavePulse .5s ease-out 2}
@keyframes appSavePulse{0%{box-shadow:0 0 0 0 rgba(46,204,113,.75)}
  100%{box-shadow:0 0 0 14px rgba(46,204,113,0)}}
.app-saved-badge{position:absolute;right:12px;top:12px;z-index:40;pointer-events:none;
  background:linear-gradient(135deg,#123d24,#1f7a3d);border:1px solid #2ecc71;color:#eafff1;
  font-size:13px;font-weight:700;letter-spacing:.02em;padding:9px 14px;border-radius:10px;
  box-shadow:0 6px 22px rgba(0,0,0,.45);display:flex;align-items:center;gap:8px;
  animation:appSavedIn .28s cubic-bezier(.2,.9,.3,1.4),appSavedOut .35s ease-in 2.3s forwards}
.app-saved-badge .tick{width:18px;height:18px;border-radius:50%;background:#2ecc71;color:#06220f;
  display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:900}
@keyframes appSavedIn{0%{opacity:0;transform:translateY(-8px) scale(.92)}
  100%{opacity:1;transform:translateY(0) scale(1)}}
@keyframes appSavedOut{to{opacity:0;transform:translateY(-6px)}}
/* P1 — public player profile (/player/{username}). Layout only rides on the
   universal theme vars (panel/line/accent/dim/radius) so all five variants
   style it; colors never invent new vars. */
.profile-hero .profile-avatar{width:96px;height:96px;border-radius:18px;border:1px solid var(--line,#26262f);
  box-shadow:0 10px 30px rgba(0,0,0,.35);margin-bottom:12px}
.profile-rank{margin:6px 0 0}
.profile-rank .rank-tag{font-size:13px;padding:5px 14px;text-transform:uppercase;letter-spacing:.08em}
.profile-stats{display:flex;gap:26px;justify-content:center;flex-wrap:wrap;margin-top:18px}
.pstat{display:flex;flex-direction:column;min-width:0}
.pstat b{font-size:clamp(18px,3vw,26px);font-variant-numeric:tabular-nums}
.pstat span{color:var(--dim,#8f89a8);font-size:12px;text-transform:uppercase;letter-spacing:.06em;margin-top:2px}
.profile-about{max-width:60ch;margin-left:auto;margin-right:auto}
.profile-empty{color:var(--dim,#8f89a8);padding:8px 0}
.profile-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}
.ppanel{position:relative;background:var(--panel,#17171f);border:1px solid var(--line,#26262f);
  border-radius:var(--radius,14px);padding:18px;overflow:hidden;min-width:0}
.ppanel h3{font-size:16px;margin:0}
.ppanel p{color:var(--dim,#8f89a8);font-size:13.5px;line-height:1.5;margin:10px 0 0}
.ppanel-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.ppanel .cta{display:inline-block;margin-top:14px;font-size:13px}
/* Locked premium panel: blurred DECORATIVE bars behind the pitch — pure
   layout shapes, never fake numbers. */
.ppanel.locked{border-style:dashed}
.plock-veil{position:absolute;inset:0;display:flex;flex-direction:column;gap:10px;padding:16px;
  filter:blur(5px);opacity:.35;pointer-events:none}
.plock-veil span{display:block;height:18px;border-radius:6px;
  background:linear-gradient(90deg,var(--accent,#8b5cf6),transparent 80%)}
.plock-veil span:nth-child(2){width:70%;background:linear-gradient(90deg,var(--accent-2,#22d3ee),transparent 85%)}
.plock-veil span:nth-child(3){width:45%}
.plock-body{position:relative;z-index:1}
.profile-videos{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}
.pvideo{margin:0;background:var(--panel,#17171f);border:1px solid var(--line,#26262f);
  border-radius:var(--radius,14px);overflow:hidden;min-width:0}
.pvideo video{display:block;width:100%;aspect-ratio:16/9;background:#000}
.pvideo figcaption{padding:10px 12px 12px;font-size:13.5px}
.pvideo figcaption b{display:block;margin-bottom:6px}
.pvideo-meta{display:flex;align-items:center;gap:8px;color:var(--dim,#8f89a8);font-size:12px}
.pvideo-tags{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.pvideo-tags .tag{font-size:10.5px}
.ppanel .pstand{color:inherit;font-size:14px;margin-top:12px}
.ppanel .pstand b{font-size:22px;font-variant-numeric:tabular-nums}
.pruns{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:8px}
.pruns li{display:flex;align-items:center;gap:10px;font-size:13.5px;min-width:0}
.pruns li a{color:inherit;text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}
.pruns li a:hover{color:var(--accent,#8b5cf6)}
.pruns li b{font-variant-numeric:tabular-nums}
.pruns li span{color:var(--dim,#8f89a8);font-size:12px;white-space:nowrap}
.rank-history{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px;max-width:520px}
.rank-history li{display:flex;align-items:center;gap:12px;background:var(--panel,#17171f);
  border:1px solid var(--line,#26262f);border-radius:10px;padding:9px 13px;font-size:13.5px}
.rank-history li b{font-variant-numeric:tabular-nums}
.rank-history li time{margin-left:auto;color:var(--dim,#8f89a8);font-size:12px}
@media (max-width:640px){.profile-stats{gap:16px}}

/* R141h (David live, iOS): mobile fullscreen TAKEOVER. iPhone Safari has no
   element-fullscreen API, so the Full button toggles this class instead — the
   player zone fills the entire viewport and the game covers everything behind it. */
.player-zone.rw-mobile-fs{position:fixed;inset:0;z-index:2147483000;margin:0;padding:0;max-width:none;width:100vw;height:100vh;height:100dvh;background:#000;overflow-y:auto;-webkit-overflow-scrolling:touch;display:flex;flex-direction:column}
/* R141i2: keep #game-screen IN FLOW (a flex item) so the function buttons in
   #controller-context flow BELOW it instead of being overlapped. Game+pad fill
   the top; Save/Load/… sit neatly underneath. */
.player-zone.rw-mobile-fs .player-frame{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;width:100%}
/* R141l: game GROWS to fill the height left over the one-line button row, and the
   redundant touch-hint note is hidden in fullscreen. */
.player-zone.rw-mobile-fs #game-screen{position:relative!important;inset:auto!important;flex:1 1 auto;min-height:50vh;width:100%!important;max-width:none;margin:0;border-radius:0}
.player-zone.rw-mobile-fs #game-screen iframe{width:100%!important;height:100%!important;border:0;border-radius:0}
.player-zone.rw-mobile-fs .mobile-controls-note{display:none!important}
/* R192 (David live, battle-circuit landscape): in the fullscreen takeover the
   #controller-context bar goes FIXED over the bottom strip while .report-zone
   (Report link + the R128e Favorites CTA) stays in flow at the same y — the
   two button rows stack and taps fire the wrong/one action. R139b shipped
   exactly this hide; its Aug-26 revert (aimed at the portrait game-height
   change) collaterally removed it. A fullscreen PLAY mode has no business
   rendering the report/favorites row — exit the takeover to reach them. */
.player-zone.rw-mobile-fs .report-zone{display:none!important}
/* R224n (David 2026-09-13, UMK3 on iPhone — relayed by the arcade session): "the 'Full
   Screen' is bringing up the lower page content instead of making the gameplay full
   screen." The arcade fighters' rollback Mini App upsell (#rollback-cta, ~215px) sits in
   .player-frame UNDER the control bar, so in the takeover it was the "lower page content"
   the portrait zone scrolled to, and in landscape it ate the flex height — #game-screen
   (flex:1 1 0) collapsed to 58px with the game a strip at the top. Same rule as the
   .report-zone hide above: a fullscreen PLAY mode renders no upsell; it is back on exit. */
.player-zone.rw-mobile-fs .rollback-cta{display:none!important}
.player-zone.rw-mobile-fs #controller-context{flex:0 0 auto;width:100%;background:#0a0a16}
/* R141l (David): the menu buttons on ONE line on mobile (Save/Load/Full/Verified
   Run). Force a single non-wrapping row; buttons flex to equal widths + shrink. */
.player-zone.is-mobile #controller-context .player-controls{flex-wrap:wrap!important;gap:6px;align-items:stretch;justify-content:center}
.player-zone.is-mobile #controller-context .player-controls .pbtn{flex:0 1 auto;min-width:0;padding:9px 12px;font-size:12px;line-height:1.15;white-space:nowrap;text-align:center}
.rw-mobile-fs-exit{position:fixed;top:calc(env(safe-area-inset-top,0px) + 12px);right:calc(env(safe-area-inset-right,0px) + 12px);z-index:2147483001;width:38px;height:38px;border-radius:999px;border:0;background:rgba(0,0,0,.55);color:#fff;font:700 17px/1 system-ui,-apple-system,sans-serif;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
/* R154d (David): while the mobile game takeover owns the screen, HIDE every page
   chrome element that was bleeding over the top of the game — the site header
   (logo + search + account "hamburger"), the footer, the ad slot. The floating
   ✕ (rw-mobile-fs-exit, z above everything) stays to leave the takeover. */
html.rw-fs-on .site-header,html.rw-fs-on .site-footer,html.rw-fs-on .ad-slot,html.rw-fs-on [data-ad-slot],html.rw-fs-on .preroll-wrap,html.rw-fs-on .ckn{display:none!important}
html.rw-fs-on{overflow:hidden!important}
/* R226i (David 2026-09-14): PORTRAIT fullscreen gives the GAME ~2/3 of the phone.
   Landscape already compacts the control bar; portrait did not, so the Save/Load
   bar + Mini App / Bluetooth lines squeezed the game to a strip. Floor the game at
   2/3 of the viewport and hide those extras in the takeover (they return on exit). */
@media (orientation: portrait){
  .player-zone.rw-mobile-fs #game-screen{min-height:66vh!important}
  .player-zone.rw-mobile-fs #controller-context .cs-miniapp,
  .player-zone.rw-mobile-fs #controller-context .cs-gamepad,
  .player-zone.rw-mobile-fs #controller-context .mobile-note,
  .player-zone.rw-mobile-fs #controller-context .reg-nudge{display:none!important}
}
/* Landscape takeover: give the GAME the whole screen and let the touch pad overlay
   it — the controller-context bar (Save/Load/Full) drops to a slim translucent
   strip pinned at the very bottom instead of eating a third of the height. */
@media(orientation:landscape) and (max-height:500px){
  /* R158c (David): overflow locked so the DS split's classic<->split toggle can
     never jump the page scroll to the bottom. */
  .player-zone.rw-mobile-fs{overflow:hidden!important}
  /* R224 (David 2026-09-12) — MAXIMISE the game in landscape. Before: #game-screen
     sat at its 72vh base height (game ~263px tall / ~351px wide, SMALLER than
     portrait) while the control bar was FIXED over the bottom. Now the bar is a
     slim IN-FLOW strip and #game-screen uses flex:1 1 0 to fill the rest, so the
     4:3 game grows to ~437px wide (+55% area) with NO bar overlap. The Mini App /
     Bluetooth lines belong to the scrollable portrait view — hidden here so the bar
     stays one slim row; the touch pad overlays the side letterbox (player.js). */
  .player-zone.rw-mobile-fs .player-frame{min-height:0!important}
  .player-zone.rw-mobile-fs #game-screen{flex:1 1 0!important;height:0!important;min-height:0!important;max-height:none!important}
  /* R224b (David 2026-09-13): with the touch pad centred on the side letterbox, the
     top shoulder (SNES/GBA R, PS1 R2) reaches the top-right corner on phones with no
     safe-area inset — move the floating ✕ in from the corner so nothing sits under it. */
  .rw-mobile-fs-exit{right:calc(env(safe-area-inset-right,0px) + 68px)}
  /* R224l → R224m (David 2026-09-13): the picture is already the full frame height at
     its true aspect, and he wants no stretching, so R224l tried the only other lever —
     a SLIMMER bar (3px top, 6px caps, bottom clearance = home-indicator inset − 7px) for
     ~20px more height / ~26px more width. David on his phone: "Things are getting cut
     off now" → "revert the PS1 and N64 picture sizes to what they were previously".
     REVERTED to the R224b bar exactly (5px top, 9px caps, inset + 5px). The landscape
     picture is at its true-aspect maximum for this bar — do not re-try slimming it. */
  .player-zone.rw-mobile-fs #controller-context{position:static!important;flex:0 0 auto!important;height:auto!important;min-height:0!important;padding:5px 8px calc(env(safe-area-inset-bottom,0px) + 5px)!important;display:flex!important;align-items:center!important;overflow:hidden!important;background:rgba(10,10,22,.92)!important;z-index:2147483001}
  .player-zone.rw-mobile-fs #controller-context .player-controls{margin:0!important;width:100%}
  .player-zone.rw-mobile-fs #controller-context .mobile-note,
  .player-zone.rw-mobile-fs #controller-context .reg-nudge,
  .player-zone.rw-mobile-fs #controller-context .cs-miniapp,
  .player-zone.rw-mobile-fs #controller-context .cs-gamepad{display:none!important}
}

/* ===== R224 (David 2026-09-12) — mobile game-page fixes ===== */
/* Fix 1: the Full button SIGNIFIES fullscreen state. player.js swaps the label to
   "Exit Full Screen" and adds .is-fs-on; accent it so it reads as an active,
   tappable exit (not just another grey control). --accent-2 is base-:root safe. */
.player-controls .pbtn.is-fs-on{
  border-color:var(--accent-2);color:var(--accent-2);
  box-shadow:0 0 0 1px var(--accent-2) inset;
}
/* Fix 3: the PORTRAIT takeover surfaces the game's existing Favorites +
   "Send this Game to a Friend" actions — player.js moves the single wired
   .report-ctas node in here (out of the hidden .report-zone) so the space under
   the game/controls is useful instead of empty. Matches the control bar's dark
   surface; the fav/share buttons keep their own theme styling. */
.player-zone.rw-mobile-fs .rw-fs-actions{
  display:flex;flex-wrap:wrap;justify-content:center;gap:10px;
  width:100%;padding:10px 12px calc(env(safe-area-inset-bottom,0px) + 12px);
  border-top:1px solid var(--line);
}
.player-zone.rw-mobile-fs .rw-fs-actions .report-ctas{
  display:flex;flex-wrap:wrap;justify-content:center;gap:10px;margin:0;width:100%;
}
/* Landscape takeover stays maximal — the game owns the screen there (Fix 4), so
   these extras are hidden; they return to portrait / to .report-zone on exit. */
@media(orientation:landscape) and (max-height:500px){
  .player-zone.rw-mobile-fs .rw-fs-actions{display:none!important}
}

/* R193 (David): cloud save-state result toast — brief Save/Load feedback by the
   player so those buttons are no longer silent. Theme-independent (fixed dark
   pill), fixed bottom-centre, auto-hides. Green = saved/loaded, red = problem. */
/* R204h — the save/load toast: INSIDE .player-zone (position:relative), top-centre
   OVER the game where the player is looking, big enough to notice. It used to be a
   13.5px pill fixed to the viewport's bottom edge — off-screen on a scrolled page.
   Green = saved (shown the instant the quick save lands; the account sync only
   updates the sub-line), red = the account copy failed. Icons are inline SVG.
   NOT at the zone's top edge: with the page scrolled to the game, that edge sits
   under the sticky site header and the toast was hidden behind it (measured on
   prod) — it now sits in the upper part of the game screen itself. */
.rpc-save-toast{position:absolute;left:50%;top:clamp(72px,22%,180px);transform:translateX(-50%) translateY(-8px) scale(.96);
  z-index:100000;max-width:min(92%,560px);display:flex;align-items:center;gap:12px;padding:14px 20px;border-radius:14px;
  background:#0f3f16;color:#e9ffe4;border:2px solid #4ad65a;
  font:700 17px/1.25 inherit;box-shadow:0 0 0 4px rgba(74,214,90,.22),0 18px 46px rgba(0,0,0,.55);
  opacity:0;pointer-events:none;text-align:left;transition:opacity .18s,transform .18s;}
.rpc-save-toast.show{opacity:1;transform:translateX(-50%) translateY(0) scale(1);}
.rpc-save-toast-icon{display:inline-flex;flex:0 0 auto;line-height:0}
.rpc-save-toast-body{display:flex;flex-direction:column;gap:2px;min-width:0}
.rpc-save-toast-sub{font-weight:600;font-size:13.5px;opacity:.92}
.rpc-save-toast-sub[hidden]{display:none}
.rpc-save-toast.is-warn{background:#4a1414;color:#ffe0e0;border-color:#ff5c5c;box-shadow:0 0 0 4px rgba(255,92,92,.22),0 18px 46px rgba(0,0,0,.55);}
.rpc-save-spin{animation:rpc-save-spin 1s linear infinite;transform-origin:50% 50%}
@keyframes rpc-save-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.rpc-save-spin{animation:none}}
/* ---------- R202 cookie notice (COIN TAB, David's pick) ---------- */
/* [hidden] MUST out-specify the display rule below. A class that sets `display`
   beats the attribute's UA style, and on the design candidates that meant a
   dismissed notice came back for returning visitors — invisible to every check
   except an explicit dismiss-then-reload assertion. */
.ckn[hidden]{ display:none; }
.ckn{
  position:fixed; right:18px; bottom:18px; z-index:60;
  display:flex; flex-direction:column; align-items:flex-end; gap:8px;
  opacity:0; transform:translateY(8px); transition:opacity .22s ease, transform .22s ease;
}
.ckn.ckn-in{ opacity:1; transform:translateY(0); }
.ckn.ckn-still{ transition:none; }
.ckn-tab{
  display:inline-flex; align-items:center; gap:7px; cursor:pointer;
  background:var(--panel); color:var(--dim);
  border:1px solid var(--line); border-radius:999px;
  padding:6px 14px; font:inherit; font-size:12px; letter-spacing:.4px;
}
.ckn-tab:hover{ color:var(--accent); border-color:var(--accent); }
.ckn-tab:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.ckn-body{
  width:280px; max-width:calc(100vw - 36px);
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  padding:14px 16px 12px;
}
.ckn-txt{ margin:0 0 6px; font-size:12.5px; line-height:1.6; color:var(--txt); }
.ckn-dim{ color:var(--dim); }
.ckn-foot{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin-top:10px; }
.ckn-link{ font-size:12px; color:var(--accent); }
.ckn-btn{
  cursor:pointer; background:transparent; color:var(--txt);
  border:1px solid var(--line); border-radius:6px; padding:5px 14px; font:inherit; font-size:12.5px;
}
.ckn-btn:hover{ border-color:var(--accent); color:var(--accent); }
.ckn-btn:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
@media (max-width:600px){ .ckn{ right:12px; bottom:12px; } }
