:root {
  --bg: #0f1020;
  --bg-card: #1a1b34;
  --accent: #ff4d6d;
  --accent-2: #4dd0ff;
  --text: #e8e8f0;
  --muted: #9a9ab5;
  --ok: #4ade80;
}

* { box-sizing: border-box; }

/* The browser's native [hidden] behavior is only display:none in the LOWEST-priority user-agent
   stylesheet, so any of our own class rules that set display:flex/grid/block on the same element
   (very common: most panels are flex containers) silently wins and the element stays visible
   despite `el.hidden = true`. This one rule makes [hidden] authoritative everywhere, full stop,
   so every current and future hidden panel just works without a per-class override to remember. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
  background: radial-gradient(1200px 800px at 50% -10%, #24264a 0%, var(--bg) 60%);
  color: var(--text);
  min-height: 100vh;
}

.lobby {
  max-width: 760px;
  margin: 0 auto;
  padding: 2.5rem 1.25rem 4rem;
}

header { text-align: center; margin-bottom: 2rem; }
h1 { font-size: 2.6rem; margin: 0; letter-spacing: -1px; }
.tagline { color: var(--muted); font-size: 1.1rem; margin-top: .4rem; }

/* Brand wordmark: co [●red] [●blue] pcade, the double-o as two co-op player tokens. */
.brand { display: inline-flex; align-items: center; gap: .7rem; text-decoration: none; justify-content: center; }
.brand-mark { width: 46px; height: 46px; flex: none; }
.brand-name { font-size: 2.6rem; font-weight: 800; letter-spacing: -1.5px; color: var(--text); display: inline-flex; align-items: center; line-height: 1; }
.brand-name .dot { display: inline-block; width: .60em; height: .60em; border-radius: 50%; margin: 0 .015em; box-shadow: 0 0 12px rgba(255,255,255,.12) inset; }
.brand-name .dot.r { background: var(--accent); }
.brand-name .dot.b { background: var(--accent-2); }
.play-bar .brand-sm { display: inline-flex; align-items: center; gap: .4rem; text-decoration: none; color: var(--text); font-weight: 800; }
.play-bar .brand-sm img { width: 22px; height: 22px; }
.play-bar .brand-sm .dot { display: inline-block; width: .55em; height: .55em; border-radius: 50%; }
.play-bar .brand-sm .dot.r { background: var(--accent); }
.play-bar .brand-sm .dot.b { background: var(--accent-2); }

.card {
  background: var(--bg-card);
  border: 1px solid #2b2d52;
  border-radius: 16px;
  padding: 1.4rem 1.5rem;
  margin-bottom: 1.25rem;
  box-shadow: 0 8px 30px rgba(0,0,0,.35);
}
.card h2 { margin: 0 0 1rem; font-size: 1.15rem; color: var(--accent-2); }

.muted { color: var(--muted); }
.small { font-size: .85rem; }

.game-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: .75rem;
}
.game-tile {
  background: linear-gradient(180deg, #23254a, #1d1f40);
  border: 1px solid #2b2d55;
  border-radius: 14px;
  padding: 1rem .55rem .8rem;
  text-align: center;
  cursor: pointer;
  transition: transform .14s ease, border-color .14s, box-shadow .14s;
  user-select: none;
  position: relative;
  overflow: hidden;
}
/* A thin accent bar in the console's colour along the top of each tile. */
.game-tile::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--c, var(--accent)); opacity: .8; }
.game-tile:hover { transform: translateY(-3px); border-color: var(--c, var(--accent)); box-shadow: 0 10px 28px color-mix(in srgb, var(--c, var(--accent)) 28%, transparent); }
.game-tile.selected { border-color: var(--c, var(--accent)); background: #29234e; box-shadow: 0 0 0 1px var(--c, var(--accent)), 0 10px 30px color-mix(in srgb, var(--c, var(--accent)) 38%, transparent); }
/* Taller than the icon-only box used to be: real box art (see .art-img) needs the room, and an
   icon still centers fine at this height. */
.game-tile .art { display: flex; align-items: center; justify-content: center; height: 64px; }
.game-tile .art-svg { width: 44px; height: 44px; color: var(--c, var(--accent)); filter: drop-shadow(0 0 6px color-mix(in srgb, var(--c, var(--accent)) 42%, transparent)); }
.game-tile .art-img { width: 100%; height: 100%; object-fit: cover; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,.35); }
.game-tile .name { font-size: .82rem; margin-top: .5rem; line-height: 1.2; }
.game-tile .sys { font-size: .68rem; color: var(--muted); margin-top: .2rem; text-transform: uppercase; letter-spacing: .3px; }

.room-row {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin-bottom: .75rem;
  flex-wrap: wrap;
}
.room-row label { width: 90px; color: var(--muted); font-size: .9rem; }
.room-row input, .room-row select {
  flex: 1;
  min-width: 160px;
  padding: .6rem .8rem;
  border-radius: 10px;
  border: 1px solid #34365e;
  background: #12132a;
  color: var(--text);
  font-size: 1rem;
}
.room-row select { cursor: pointer; }
.room-row input:focus, .room-row select:focus { outline: 2px solid var(--accent-2); border-color: transparent; }

button {
  cursor: pointer;
  font-family: inherit;
  border: none;
  border-radius: 10px;
}
button.ghost {
  background: transparent;
  border: 1px solid #34365e;
  color: var(--text);
  padding: .6rem .8rem;
}
.play-btn {
  width: 100%;
  padding: 1rem;
  font-size: 1.15rem;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(90deg, var(--accent), #ff7a5c);
  transition: opacity .15s, transform .1s;
}
.play-btn:disabled { opacity: .4; cursor: not-allowed; }
.play-btn:not(:disabled):hover { transform: translateY(-1px); }

.browse-all {
  display: inline-block;
  margin-top: 1rem;
  color: var(--accent-2);
  text-decoration: none;
  font-weight: 600;
}
.browse-all:hover { text-decoration: underline; }

.byo { border-color: #3a3d6e; }
.consent {
  display: flex;
  gap: .6rem;
  align-items: flex-start;
  margin: .5rem 0 1rem;
  font-size: .9rem;
  color: var(--text);
  cursor: pointer;
}
.consent input { margin-top: .2rem; width: 18px; height: 18px; accent-color: var(--accent); }

footer { margin-top: 1.5rem; text-align: center; }

/* Supported-systems showcase: names only (nominative), no game titles, no trademarked logos. */
.consoles-band { margin-bottom: 1.25rem; text-align: center; }
.band-title { font-size: 1rem; color: var(--muted); font-weight: 600; margin: 0 0 .9rem; }
.console-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: .6rem; }
.console-chip {
  display: flex; align-items: center; gap: .55rem; padding: .6rem .75rem; text-align: left;
  border-radius: 12px; background: var(--bg-card); border: 1px solid #2b2d52;
  border-left: 3px solid var(--c, var(--accent)); transition: transform .12s, border-color .12s;
}
.console-chip:hover { transform: translateY(-2px); border-color: var(--c, var(--accent)); box-shadow: 0 8px 22px color-mix(in srgb, var(--c, var(--accent)) 20%, transparent); }
.console-chip .cc-icon { width: 30px; height: 30px; color: var(--c, var(--accent)); flex: none; filter: drop-shadow(0 0 5px color-mix(in srgb, var(--c, var(--accent)) 45%, transparent)); }
.console-chip .cc-name { font-size: .84rem; font-weight: 600; }

/* --- Homepage glow-up ------------------------------------------------------------------- */
/* A very subtle CRT scanline + top vignette over the whole page. Decorative and non-interactive;
   the scanlines are dropped entirely for reduced-motion / high-contrast preferences. */
body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 1;
  background:
    repeating-linear-gradient(0deg, rgba(0,0,0,0) 0 2px, rgba(0,0,0,.045) 2px 3px),
    radial-gradient(120% 80% at 50% 0%, transparent 62%, rgba(0,0,0,.32) 100%);
}
@media (prefers-reduced-motion: reduce) {
  body::before { background: radial-gradient(120% 80% at 50% 0%, transparent 62%, rgba(0,0,0,.32) 100%); }
}
/* Not on the PLAY page: the fixed full-viewport overlay would sit over the live game/video and force
   the compositor to blend it over every decoded frame — pure GPU cost during a session. The scanline
   is a homepage aesthetic; the play page has the actual game to look at. */
body.play-page::before { content: none; }
.lobby, .authbar { position: relative; z-index: 2; }

/* Neon on the wordmark + the two player-token dots. */
.brand-name { text-shadow: 0 0 26px rgba(255,77,109,.22), 0 0 54px rgba(77,208,255,.14); }
.brand-name .dot.r { box-shadow: 0 0 14px rgba(255,77,109,.7); }
.brand-name .dot.b { box-shadow: 0 0 14px rgba(77,208,255,.7); }

/* "How it works" three-step row. */
.how { display: flex; align-items: stretch; gap: .6rem; margin-bottom: 1.25rem; }
.how-step { flex: 1; background: var(--bg-card); border: 1px solid #2b2d52; border-radius: 14px; padding: .85rem 1rem; display: flex; flex-direction: column; gap: .2rem; box-shadow: 0 6px 20px rgba(0,0,0,.25); }
.how-step b { font-size: .98rem; }
.how-num { width: 1.6rem; height: 1.6rem; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; font-weight: 800; color: #0f1020; background: linear-gradient(135deg, var(--accent), var(--accent-2)); margin-bottom: .25rem; }
.how-arrow { align-self: center; color: var(--muted); font-size: 1.3rem; }
@media (max-width: 640px) { .how { flex-direction: column; } .how-arrow { transform: rotate(90deg); margin: -.2rem 0; } }

/* Join-a-friend card (guest entry point). */
.join-card { border-color: #33506b; background: linear-gradient(180deg, #16223a, var(--bg-card)); }
.join-card #join-code { flex: 1; min-width: 0; }

/* Two front doors, side by side on desktop, stacked on phones. Each is a full-height card so the
   primary action (host CTA / join input) lines up along the bottom. */
.doors { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.25rem; }
.doors .door { margin-bottom: 0; display: flex; flex-direction: column; }
.doors .door h2 { margin-bottom: .5rem; }
.doors .door p { flex: 1; }
.door-host { border-color: #5a4a86; background: linear-gradient(180deg, #221a3a, var(--bg-card)); }
.door-host .play-btn { margin-top: .8rem; }
.door-join { border-color: #33506b; background: linear-gradient(180deg, #16223a, var(--bg-card)); }
.door-join #join-code { flex: 1; min-width: 0; }
@media (max-width: 640px) { .doors { grid-template-columns: 1fr; } }

/* Game search box + recently-played chips. */
.game-search-row { margin-bottom: .9rem; }
#game-search { width: 100%; padding: .6rem .85rem; border-radius: 10px; border: 1px solid #34365e; background: #12132a; color: var(--text); font-size: .95rem; }
#game-search:focus { outline: 2px solid var(--accent-2); border-color: transparent; }
.recent-strip { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: .9rem; }
.recent-lbl { font-size: .7rem; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); }
.recent-chip { display: inline-flex; align-items: center; gap: .4rem; padding: .32rem .7rem; border-radius: 999px; border: 1px solid var(--c, #34365e); background: #1b1d3a; color: var(--text); font-size: .82rem; font-weight: 600; cursor: pointer; transition: background .12s, transform .12s; }
.recent-chip:hover { background: #24264c; transform: translateY(-1px); }
.recent-ico { width: 18px; height: 18px; color: var(--c, var(--accent)); flex: none; }

/* Extra pop on the primary Play button. */
.play-btn:not(:disabled) { box-shadow: 0 8px 26px rgba(255,77,109,.28); }
.play-btn:not(:disabled):hover { box-shadow: 0 10px 32px rgba(255,77,109,.42); }
.band-note { margin-top: .85rem; }

/* Optional sign-in card: reassures that play is anonymous and account-free. */
.signin-card { border-color: #3a3d6e; }
.signin-card h2 { color: var(--text); }
#signin-actions { margin-bottom: 0; }

/* ---- play page ---- */
.play-page {
  margin: 0;
  background: #000;
  height: 100vh;
  height: 100dvh;          /* dynamic viewport height: no cutoff under mobile URL bars */
  display: flex;
  flex-direction: column;
  /* EmulatorJS can inject its own UI (menus, virtual gamepad container) into the page. If any of
     that ever escapes the flex layout's implicit clamp, this stops it from growing the window
     scrollbar instead of just clipping to the viewport. */
  overflow: hidden;
}
.play-bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  row-gap: .35rem;
  flex-wrap: wrap;         /* pills wrap instead of overflowing on narrow screens */
  padding: .5rem 1rem;
  background: var(--bg-card);
  color: var(--text);
  font-size: .9rem;
  position: relative;      /* anchors the Controls popover */
}
.play-bar a { color: var(--accent-2); text-decoration: none; }
.play-bar .spacer { flex: 1; }
.play-bar .pill {
  background: #23254a;
  padding: .25rem .7rem;
  border-radius: 999px;
  font-size: .82rem;
}
/* The stage holds the game (host emulator or guest video stream) and the slide-in chat. */
/* overflow:hidden is defensive: #game's pixel size is set explicitly by play.js and only
   re-measured asynchronously (ResizeObserver) when a sibling like the invite bar changes the
   space available, so there's a real window where it can be briefly larger than .stage actually
   has room for. Without this, that overflow visually spills onto whatever's above .stage instead
   of just being clipped to it. */
.stage { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; position: relative; overflow: hidden; }
/* #game does NOT grow to fill .stage: EmulatorJS's own canvas is unconditionally width:100%/
   height:100% of whatever box it is given (verified from its shipped CSS -- it has no aspect-
   ratio logic of its own), so a full-bleed #game stretches every game to match the window instead
   of letterboxing it. play.js's pinGameBoxSize() sizes #game to the console's real aspect ratio in
   pixels; flex:none (not flex:1) lets that explicit size stick instead of being grown back out to
   fill .stage, and .stage's centering above places the correctly-shaped box in the middle. */
#game { flex: none; min-height: 0; }
/* Guest (watch-and-play) mode: <video> handles aspect ratio natively via object-fit, so it can
   safely fill the whole stage -- unlike the host's raw EmulatorJS canvas above. */
#remote { flex: 1; min-height: 0; width: 100%; height: 100%; background: #000; object-fit: contain; cursor: pointer; }
/* Fill mode (the ⤢ toggle): fill the whole stage, cropping the letterbox -- makes the picture much
   bigger on a phone at the cost of trimming the edges. */
#remote.fill { object-fit: cover; }
.guest-mode #game { display: none; }

/* Chat: a panel overlaid on the right of the stage, everywhere (desktop and phone alike) -- it
   never shrinks the game/video, it just sits over whatever letterbox space is there. play.js
   auto-opens it when there's genuinely enough dead space beside the picture to not cover any of
   it. backdrop-filter:blur only has a visible effect over something WITH detail behind it (game
   art, text); over the plain black letterbox bars it deliberately sits in, a blur of flat black is
   still flat black, so a gradient + a lit top edge give it presence as a panel on its own, not
   just when it happens to overlap something busy. Always lets it be opened by hand regardless of
   screen size. */
.chat {
  position: absolute; top: 0; right: 0; bottom: 0; width: min(320px, 92vw); z-index: 35;
  display: flex; flex-direction: column;
  /* Nearly-opaque gradient instead of backdrop-filter: the panel sits over the LIVE 60fps video, and
     a blur forces the compositor to re-sample+blur that region every frame (one of the most
     expensive GPU ops) — for a panel that deliberately sits over flat black bars where a blur is
     invisible anyway. The solid gradient reads the same and costs nothing per frame. */
  background: linear-gradient(180deg, rgba(31,33,68,.97), rgba(16,17,38,.97));
  border-left: 1px solid rgba(150,155,220,.3);
  box-shadow: -12px 0 40px rgba(0,0,0,.5), inset 1px 0 0 rgba(255,255,255,.04);
}
.chat-head { display: flex; justify-content: space-between; align-items: center; gap: .4rem; padding: .5rem .75rem; border-bottom: 1px solid rgba(120,124,180,.18); font-weight: 600; }
.chat-head .spacer { flex: 1; }
.chat-log { flex: 1; min-height: 0; overflow-y: auto; list-style: none; margin: 0; padding: .5rem .75rem; display: flex; flex-direction: column; gap: .35rem; }
.chat-line { font-size: .88rem; line-height: 1.35; word-break: break-word; }
.chat-line b { color: var(--accent-2); margin-right: .25rem; }
.chat-line.self b { color: var(--accent); }
.chat-roster { display: flex; flex-wrap: wrap; gap: .3rem; padding: .4rem .75rem; border-top: 1px solid rgba(120,124,180,.18); }
.who-pill { font-size: .72rem; background: rgba(35,37,74,.85); color: var(--muted); padding: .12rem .5rem; border-radius: 999px; white-space: nowrap; }
.who-pill.ctl { color: var(--ok); background: rgba(18,51,31,.85); }
/* Per-player ping chip inside a roster pill. */
.who-ping { font-size: .64rem; font-weight: 700; opacity: .95; }
.who-ping.good { color: #4ade80; }
.who-ping.ok { color: #fbbf24; }
.who-ping.bad { color: #fb7185; }
.chat-form { display: flex; gap: .4rem; padding: .5rem .75rem; border-top: 1px solid rgba(120,124,180,.18); }
.chat-form input { flex: 1; min-width: 0; padding: .45rem .6rem; border-radius: 8px; border: 1px solid #34365e; background: rgba(12,13,28,.85); color: var(--text); font-size: .9rem; }
.chat-unread { background: var(--accent); color: #fff; border-radius: 999px; padding: 0 .35rem; margin-left: .2rem; font-size: .68rem; }
.pw-bar input::placeholder { color: var(--muted); }

/* Guest video starts muted (the only autoplay every browser reliably allows) with this as a
   clear, deliberate tap target for sound, instead of the whole video silently listening for a
   click with no visible cue. Removes itself the moment unmuting actually succeeds. */
.unmute-btn {
  position: absolute; left: 50%; bottom: 1.25rem; transform: translateX(-50%); z-index: 32;
  background: rgba(20,21,45,.85); backdrop-filter: blur(6px); color: var(--text);
  border: 1px solid rgba(150,155,220,.35); border-radius: 999px; padding: .55rem 1.1rem;
  font-size: .9rem; font-weight: 600; box-shadow: 0 8px 24px rgba(0,0,0,.4);
}

/* Guest "connecting…" overlay: a centered spinner + live status over the stage while the relay
   connection comes up and the first frame arrives, so the guest isn't staring at a bare black
   rectangle wondering if it's broken. Removed the instant real frames land. */
.stage-overlay {
  position: absolute; inset: 0; z-index: 24; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1rem; text-align: center; padding: 1.25rem;
  background: rgba(10,11,25,.6); backdrop-filter: blur(2px); color: var(--text);
}
.stage-spinner {
  width: 42px; height: 42px; border-radius: 50%;
  border: 3px solid rgba(150,155,220,.25); border-top-color: var(--accent);
  animation: cc-spin .9s linear infinite;
}
.stage-overlay-msg { margin: 0; font-weight: 600; max-width: 34ch; line-height: 1.4; }
@keyframes cc-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .stage-spinner { animation-duration: 2.4s; } }

/* "Rotate your phone" nudge: retro games letterbox to a useless strip in portrait once the touch
   pad eats the bottom half. Shown only while a phone guest is actually holding a controller in
   portrait, dismissable, and gone the moment they turn landscape. */
.rotate-hint {
  display: none; position: absolute; left: 50%; top: 1rem; transform: translateX(-50%); z-index: 33;
  background: rgba(20,21,45,.9); backdrop-filter: blur(6px); color: var(--text);
  border: 1px solid rgba(150,155,220,.35); border-radius: 999px; padding: .5rem 1rem;
  font-size: .85rem; font-weight: 600; box-shadow: 0 8px 24px rgba(0,0,0,.4); max-width: 90vw;
}
@media (orientation: portrait) and (max-width: 820px) {
  body.playing-touch .rotate-hint:not(.dismissed) { display: block; }
}

/* Guest controller picker + tester (play-bar "🕹️ Controller" popover). One row per connected pad
   with a "use this" toggle, then a live tester grid whose keys light up as buttons are pressed. */
.cc-pad-row { display: flex; align-items: center; gap: .5rem; padding: .35rem 0; }
.cc-pad-row.on { }
.cc-pad-use { flex: 0 0 auto; }
.cc-pad-use[disabled] { opacity: 1; color: var(--accent); border-color: rgba(255,77,109,.5); cursor: default; }
.cc-pad-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .85rem; }
.cc-pad-warn { flex: 0 0 auto; font-size: .72rem; color: #ffcf6b; cursor: help; }
.cc-pad-empty, .cc-pad-hint { color: var(--muted); font-size: .82rem; line-height: 1.5; margin: .5rem 0 0; }
.cc-tester { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .7rem; }
.cc-key {
  min-width: 2rem; padding: .3rem .45rem; text-align: center; border-radius: 7px;
  border: 1px solid #34365e; background: rgba(12,13,28,.85); color: var(--muted);
  font-size: .8rem; font-weight: 700; transition: transform .05s, background .05s, color .05s;
}
.cc-key.on { background: var(--accent); color: #fff; border-color: var(--accent); transform: translateY(-2px); }

/* Guest button remapper (for non-standard pads — e.g. a real N64 controller on a USB adapter). */
.cc-remap-row { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .6rem; }
.cc-remap { text-align: center; padding: .4rem 0 .2rem; }
.cc-remap-prog { color: var(--muted); font-size: .74rem; letter-spacing: .04em; text-transform: uppercase; margin: 0 0 .3rem; }
.cc-remap-ask { font-size: 1.15rem; font-weight: 700; margin: .2rem 0 .7rem; }
.cc-remap-ask b { color: var(--accent); }
.cc-remap .cc-remap-row { justify-content: center; }

/* On-screen touch gamepad for phones: translucent, fixed to the bottom, over the video. The whole
   pad is built PER CONSOLE (see mountTouchControls), so the exact controls vary — an analog stick
   for N64/PSX, C-buttons for N64, 6 face buttons for Genesis, etc. The layout is: an optional
   shoulder row across the top, then a main row of left cluster (D-pad and/or stick), centre
   (Start/Select), and right cluster (face buttons, plus C-buttons for N64). */
.touch-host { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; pointer-events: none; }
.touchpad { display: flex; flex-direction: column; padding: .5rem .9rem calc(.7rem + env(safe-area-inset-bottom)); gap: .4rem; pointer-events: none; }
.touchpad .tp-btn, .touchpad .tp-stick { pointer-events: auto; }
.tp-btn {
  pointer-events: auto; touch-action: none; user-select: none; -webkit-user-select: none;
  background: rgba(30,32,60,.55); color: #fff; border: 1px solid rgba(255,255,255,.18);
  border-radius: 12px; font-size: 1rem; font-weight: 700; width: 52px; height: 52px;
  display: flex; align-items: center; justify-content: center; backdrop-filter: blur(3px);
}
.tp-btn.on { background: rgba(255,77,109,.75); transform: scale(.94); }

.tp-shoulders { display: flex; justify-content: space-between; align-items: flex-start; }
.tp-sh { display: flex; gap: .4rem; }
.tp-shbtn { width: auto; min-width: 44px; padding: 0 .8rem; height: 38px; border-radius: 12px; font-size: .8rem; }

.tp-main { display: flex; justify-content: space-between; align-items: flex-end; gap: .5rem; flex: 1; }
.tp-col-left, .tp-col-right { display: flex; flex-direction: column; gap: .55rem; justify-content: flex-end; }
.tp-col-left { align-items: flex-start; } .tp-col-right { align-items: flex-end; }
.tp-center { display: flex; align-self: flex-end; }

/* D-pad + C-pad + 4-button faces are absolute diamonds inside a square. */
.tp-dpad, .tp-face-4, .tp-cpad { position: relative; width: 156px; height: 156px; }
.tp-dpad .tp-btn, .tp-face-4 .tp-btn, .tp-cpad .tp-btn { position: absolute; }
.tp-face-4 .tp-btn, .tp-cpad .tp-btn { border-radius: 50%; }
.fpos-top { top: 0; left: 52px; } .fpos-bottom { bottom: 0; left: 52px; }
.fpos-left { top: 52px; left: 0; } .fpos-right { top: 52px; right: 0; }
.tp-dpad .tp-up { top: 0; left: 52px; } .tp-dpad .tp-down { bottom: 0; left: 52px; }
.tp-dpad .tp-left { top: 52px; left: 0; } .tp-dpad .tp-right { top: 52px; right: 0; }
/* When a console also has an analog stick, shrink the (secondary) D-pad to make room for it. */
.tp-has-stick .tp-dpad { transform: scale(.66); transform-origin: top left; margin-bottom: -52px; }
.tp-cpad { width: 132px; height: 132px; }
.tp-cpad .tp-btn { width: 44px; height: 44px; font-size: .72rem; }
.tp-cpad .fpos-top { left: 44px; } .tp-cpad .fpos-bottom { left: 44px; }
.tp-cpad .fpos-left { top: 44px; } .tp-cpad .fpos-right { top: 44px; }

/* Analog thumbstick: a round zone with a draggable knob (real 0..32767 analog values). */
.tp-stick { position: relative; width: 132px; height: 132px; border-radius: 50%; touch-action: none;
  background: rgba(30,32,60,.4); border: 1px solid rgba(255,255,255,.18); backdrop-filter: blur(3px); }
.tp-stick-knob { position: absolute; left: 50%; top: 50%; width: 58px; height: 58px; margin: -29px 0 0 -29px;
  border-radius: 50%; background: rgba(255,77,109,.6); border: 1px solid rgba(255,255,255,.35);
  will-change: transform; pointer-events: none; }
.tp-stick-right { width: 108px; height: 108px; }
.tp-stick-right .tp-stick-knob { width: 46px; height: 46px; margin: -23px 0 0 -23px; }

/* Non-diamond faces: 1 button, a 2-button pair, a 3-button row, or the 6-button Genesis grid. */
.tp-face-1, .tp-face-2, .tp-face-3 { display: flex; gap: .55rem; align-items: center; }
.tp-face-1 .tp-btn, .tp-face-2 .tp-btn, .tp-face-3 .tp-btn { border-radius: 50%; width: 60px; height: 60px; }
.tp-face-6 { display: grid; grid-template-columns: repeat(3, auto); gap: .45rem; }
.tp-face-6 .tp-btn { border-radius: 50%; width: 48px; height: 48px; font-size: .9rem; }

.tp-mid { display: flex; gap: .5rem; }
.tp-sysbtn { width: auto; min-width: 40px; padding: 0 .7rem; height: 34px; border-radius: 999px; font-size: .72rem; }

.share-bar {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; position: relative;
  padding: .5rem 1rem; background: #14264a; color: var(--text);
  border-bottom: 1px solid #24345e; font-size: .85rem;
}
/* Invite popover: a dropdown under the top bar instead of a full-width row, so it never eats the
   stage's vertical space. Toggled by the top-bar 🔗 Invite button and auto-shown once when the room
   opens; closes on outside click. Anchored to .play-bar (position:relative). */
.share-pop {
  position: absolute; top: 100%; left: 1rem; right: 1rem; z-index: 45; margin-top: .4rem;
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; font-size: .85rem;
  padding: .7rem .9rem; background: #14264a; color: var(--text);
  border: 1px solid #34365e; border-radius: 12px; box-shadow: 0 12px 40px rgba(0,0,0,.5);
}
/* Keep the native [hidden] winning over the display:flex above (specificity would otherwise leave
   the popover visible while hidden — the same trap the old .share-bar had). */
.share-pop[hidden] { display: none; }
.share-pop #share-close { margin-left: auto; }
/* Account chip in the play top bar: shows who you're signed in as, links to the account page. */
.acct-chip {
  display: inline-flex; align-items: center; gap: .35rem; max-width: 22ch;
  padding: .25rem .7rem; border-radius: 999px; background: #23254a;
  color: var(--text) !important; font-size: .82rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct-chip::before { content: "👤"; font-weight: 400; }
.acct-chip:hover { background: #2c2f5e; }
.share-lbl { font-weight: 600; }
.share-input {
  flex: 1; min-width: 180px; padding: .4rem .6rem; border-radius: 8px;
  border: 1px solid #34365e; background: #0c0d1c; color: var(--accent-2); font-size: .8rem;
}
/* QR popover: anchored under the share bar, closes itself on outside click. */
.qr-pop {
  position: absolute; top: 100%; right: 1rem; z-index: 40; margin-top: .4rem;
  background: var(--bg-card); border: 1px solid #34365e; border-radius: 12px;
  padding: .9rem; box-shadow: 0 12px 40px rgba(0,0,0,.5); text-align: center;
}
#qr-canvas-wrap { background: #fff; padding: 8px; border-radius: 8px; line-height: 0; }
#qr-canvas-wrap img { display: block; width: 200px; height: 200px; image-rendering: pixelated; }

.controls-pop { text-align: left; width: min(320px, 90vw); max-height: 70vh; overflow-y: auto; }
.controls-body dl { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: .3rem .8rem; font-size: .85rem; }
.controls-body dt { color: var(--accent-2); font-weight: 600; white-space: nowrap; }
.controls-body dd { margin: 0; color: var(--text); }
.controls-body p { font-size: .82rem; color: var(--muted); margin: .7rem 0 0; }
.controls-body h4 { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin: .8rem 0 .3rem; }
.controls-body h4:first-child { margin-top: 0; }

/* ---- narrow screens / phones ---- */
@media (max-width: 600px) {
  .lobby { padding: 1.5rem 1rem 3rem; }
  h1 { font-size: 2.1rem; }
  .card { padding: 1.1rem 1rem; }
  .room-row { gap: .4rem; }
  .room-row label { width: 100%; }          /* label above the field, not squeezed beside it */
  .game-grid { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
  .game-tile .art { height: 56px; }
  .game-tile .art-svg { width: 38px; height: 38px; }
  .play-bar { gap: .5rem; padding: .45rem .7rem; font-size: .82rem; }
  .play-bar .pill { padding: .2rem .5rem; font-size: .72rem; }
  .chat { width: min(88vw, 340px); }
  /* The play top bar has a lot of controls; on phones drop the always-on status text and the account
     chip (the invite popover still shows the peer count, and the chip is one tap away on the account
     page) so the buttons don't wrap into several rows above the game. */
  #invite-status, #netplay-status, #gamepad-status, .acct-chip { display: none; }
  /* Let the invite link take its own full row in the popover instead of fighting the buttons. */
  .share-pop .share-input { min-width: 0; flex-basis: 100%; }
  /* Keep the QR image from being clipped by the page's overflow:hidden on short screens. */
  #qr-pop { max-height: 80vh; overflow: auto; }
  /* Slightly smaller pad so it doesn't crowd a small screen. */
  .tp-btn { width: 46px; height: 46px; }
  .tp-dpad, .tp-face { width: 150px; height: 150px; }
  .tp-up, .tp-down, .tp-y, .tp-a { left: 52px; } .tp-left, .tp-right, .tp-x, .tp-b { top: 52px; }
}

/* The play page hides the room-label pill on very narrow screens to keep the bar tidy. */
@media (max-width: 420px) { #room-label { display: none; } }

/* Account bar: a slim full-width strip pinned to the true top-right of the window, with a soft
   backdrop so it reads as a real app header rather than a button floating mid-page. */
.authbar { position: sticky; top: 0; z-index: 40; display: flex; justify-content: flex-end; align-items: center; gap: .6rem; padding: .55rem 1.1rem; font-size: .88rem; flex-wrap: wrap; background: rgba(15,16,32,.7); backdrop-filter: blur(8px); border-bottom: 1px solid rgba(120,124,180,.12); }
.authbar .who { color: var(--text); max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-decoration: none; }
.authbar .who:hover { text-decoration: underline; }
.authbar .auth-account-link { display: inline-block; text-decoration: none; }
.authbar .atag { background: #23254a; color: var(--accent-2); padding: .15rem .55rem; border-radius: 999px; font-size: .78rem; }
.authbar .atag.comp { background: #12331f; color: var(--ok); }
.authbar .atag.sub { background: #2c2140; color: #ffb3c1; }
.auth-modal { position: fixed; inset: 0; background: rgba(4,5,15,.82); display: flex; align-items: center; justify-content: center; padding: 1rem; z-index: 60; }
.auth-box { background: var(--bg-card); border: 1px solid #34365e; border-radius: 16px; max-width: 400px; width: 100%; padding: 1.6rem; box-shadow: 0 20px 60px rgba(0,0,0,.5); }
.auth-box h3 { margin: .2rem 0 .3rem; }
.auth-box label { display: block; color: var(--muted); font-size: .82rem; margin: .9rem 0 .3rem; }
.auth-box input { width: 100%; padding: .6rem .8rem; border-radius: 10px; border: 1px solid #34365e; background: #12132a; color: var(--text); font-size: 1rem; }
.auth-box input:focus { outline: 2px solid var(--accent-2); border-color: transparent; }
.auth-box .auth-x { float: right; cursor: pointer; color: var(--muted); font-size: 1.1rem; }
.auth-box .err { color: #ff9db0; font-size: .85rem; min-height: 1.1rem; margin-top: .6rem; }

/* Keyboard navigation: a clear, consistent focus ring everywhere. */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
.game-tile:focus-visible, .console:focus-visible, .gcard:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

/* Respect users who prefer reduced motion. */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ============================================================================
   Front-end polish pass — neon hero, watch-party badges, heading accents, CTA
   pulse. Purely decorative; every animation is gated behind
   prefers-reduced-motion: no-preference so it stays calm for those who ask.
   ============================================================================ */

/* Brand wordmark: soft neon glow, and the two signature dots glow like arcade
   power LEDs (and slowly breathe, alternating). */
.brand-name { text-shadow: 0 0 18px rgba(77,208,255,.22), 0 0 42px rgba(255,77,109,.12); }
.brand-name .dot.r { background: var(--accent); box-shadow: 0 0 10px var(--accent), 0 0 22px color-mix(in srgb, var(--accent) 55%, transparent); }
.brand-name .dot.b { background: var(--accent-2); box-shadow: 0 0 10px var(--accent-2), 0 0 22px color-mix(in srgb, var(--accent-2) 55%, transparent); }
.brand-mark { filter: drop-shadow(0 0 9px rgba(77,208,255,.32)); }
@media (prefers-reduced-motion: no-preference) {
  .brand-name .dot { animation: cc-led 2.6s ease-in-out infinite; }
  .brand-name .dot.b { animation-delay: 1.3s; }
}
@keyframes cc-led { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }

/* Hero "what this is" pills under the tagline. */
.hero-badges { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; margin-top: 1rem; }
.hero-badge {
  font-size: .82rem; font-weight: 600; color: var(--text);
  background: color-mix(in srgb, var(--bg-card) 82%, transparent);
  border: 1px solid #2b2d52; border-radius: 999px; padding: .32rem .8rem;
}

/* Always-visible entry point to the room browser + lobby chat, right under the hero — unlike
   #hero-live (only appears when a public room happens to be open), this is never hidden, so
   "where's the chat" has an answer without scrolling. */
.rooms-chat-pill {
  display: inline-flex; align-items: center; gap: .4rem; margin-top: .9rem;
  padding: .5rem 1.1rem; border-radius: 999px; text-decoration: none;
  font-size: .92rem; font-weight: 700; color: var(--text);
  background: color-mix(in srgb, var(--accent-2) 16%, var(--bg-card));
  border: 1px solid color-mix(in srgb, var(--accent-2) 55%, #2b2d52);
  transition: transform .12s, box-shadow .12s, border-color .12s;
}
.rooms-chat-pill:hover { transform: translateY(-2px); border-color: var(--accent-2); box-shadow: 0 8px 22px rgba(77,208,255,.25); }

/* Card headings get a small neon tab for vertical rhythm down the page. */
.card > h2 { position: relative; padding-left: .8rem; }
.card > h2::before {
  content: ""; position: absolute; left: 0; top: .14em; bottom: .14em; width: 4px;
  border-radius: 3px; background: linear-gradient(var(--accent), var(--accent-2));
  box-shadow: 0 0 10px color-mix(in srgb, var(--accent-2) 40%, transparent);
}

/* Once a game is picked the Play button gently pulses to pull the eye down to it.
   Pause it on hover so the hover lift/shadow reads cleanly. */
@media (prefers-reduced-motion: no-preference) {
  .play-btn:not(:disabled) { animation: cc-cta 2.2s ease-in-out infinite; }
  .play-btn:not(:disabled):hover { animation: none; }
}
@keyframes cc-cta {
  0%, 100% { box-shadow: 0 8px 26px rgba(255,77,109,.28); }
  50% { box-shadow: 0 12px 36px rgba(255,77,109,.5), 0 0 0 1px rgba(255,122,92,.55); }
}

/* ============================================================================
   Public "Live now" lobby + the host's public-listing toggle.
   ============================================================================ */

/* Toggle switch (shared with the admin panel's inline copy). */
.switch { position: relative; width: 46px; height: 26px; flex: none; display: inline-block; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider { position: absolute; inset: 0; background: #34365e; border-radius: 999px; transition: .2s; cursor: pointer; }
.switch .slider::before { content: ""; position: absolute; height: 20px; width: 20px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: .2s; }
.switch input:checked + .slider { background: var(--accent); }
.switch input:checked + .slider::before { transform: translateX(20px); }
.switch input:disabled + .slider { opacity: .45; cursor: not-allowed; }

.public-row { align-items: center; }
.public-row .public-lbl { font-weight: 600; font-size: .92rem; }
.public-row.disabled .public-lbl { color: var(--muted); }

/* Live lobby list. */
.live-card { border-color: #3a3d6e; }
.live-list { display: flex; flex-direction: column; gap: .5rem; margin: .2rem 0 .9rem; }
.live-room {
  display: flex; align-items: center; gap: .7rem; text-decoration: none; color: var(--text);
  background: #12132a; border: 1px solid #2b2d55; border-radius: 12px; padding: .6rem .8rem;
  transition: transform .12s, border-color .12s, box-shadow .12s;
}
.live-room:hover { transform: translateY(-2px); border-color: var(--accent-2); box-shadow: 0 8px 22px rgba(77,208,255,.18); }
.live-info { display: flex; flex-direction: column; gap: .1rem; flex: 1; min-width: 0; }
.live-info b { font-size: .95rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.live-join { font-weight: 700; color: var(--accent-2); white-space: nowrap; }
.live-dot, .live-title-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: none; display: inline-block;
  background: #ff3b52; box-shadow: 0 0 8px #ff3b52;
}
.live-title-dot { margin-right: .1rem; vertical-align: middle; }
.live-browse-btn {
  display: inline-flex; align-items: center; gap: .3rem; margin-top: .3rem;
  padding: .55rem 1rem; border-radius: 10px; text-decoration: none;
  font-weight: 700; font-size: .92rem; color: #fff;
  background: linear-gradient(90deg, var(--accent-2), #7ab8ff);
  box-shadow: 0 6px 18px rgba(77,208,255,.22);
  transition: transform .12s, box-shadow .12s;
}
.live-browse-btn:hover { transform: translateY(-1px); box-shadow: 0 8px 24px rgba(77,208,255,.35); }
@media (prefers-reduced-motion: no-preference) {
  .live-dot, .live-title-dot { animation: cc-live 1.6s ease-in-out infinite; }
}
@keyframes cc-live { 0%, 100% { opacity: 1; box-shadow: 0 0 8px #ff3b52; } 50% { opacity: .4; box-shadow: 0 0 3px #ff3b52; } }

/* Room browser (web/rooms.html): box-art thumbnail on each room card, filter chips, open-slot badge. */
.live-art { width: 40px; height: 40px; border-radius: 8px; overflow: hidden; flex: none; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.04); }
.live-art img { width: 100%; height: 100%; object-fit: cover; }
.live-art svg { width: 26px; height: 26px; color: var(--c, var(--accent)); }
.chip-row { display: flex; flex-wrap: wrap; gap: .4rem; margin: .5rem 0; }
.chip { display: inline-flex; align-items: center; padding: .3rem .7rem; border-radius: 999px; border: 1px solid #34365e; background: #1b1d3a; color: var(--muted); font-size: .78rem; font-weight: 600; cursor: pointer; transition: background .12s, color .12s, border-color .12s; }
.chip:hover { background: #24264c; }
.chip.active { color: var(--text); border-color: var(--accent-2); background: color-mix(in srgb, var(--accent-2) 18%, #1b1d3a); }
.slot-badge { font-size: .68rem; font-weight: 700; color: var(--ok); background: rgba(18,51,31,.85); border-radius: 999px; padding: .1rem .5rem; white-space: nowrap; }

/* Hero "live now" pill — appears only when public rooms exist, links to the busiest one. */
.hero-live {
  display: inline-flex; align-items: center; gap: .45rem; margin-top: .9rem;
  padding: .4rem .9rem; border-radius: 999px; text-decoration: none;
  font-size: .9rem; font-weight: 600; color: var(--text);
  background: color-mix(in srgb, #ff3b52 16%, var(--bg-card));
  border: 1px solid color-mix(in srgb, #ff3b52 45%, #2b2d52);
  transition: transform .12s, box-shadow .12s, border-color .12s;
}
.hero-live b { color: #ff6b7d; }
.hero-live:hover { transform: translateY(-2px); border-color: #ff3b52; box-shadow: 0 8px 22px rgba(255,59,82,.28); }

/* Public toggle inside the invite popover. */
.share-public-wrap { display: inline-flex; align-items: center; gap: .4rem; }
.share-public-wrap .switch { width: 40px; height: 23px; }
.share-public-wrap .switch .slider::before { height: 17px; width: 17px; }
.share-public-wrap .switch input:checked + .slider::before { transform: translateX(17px); }

/* Muted "system" chat line (e.g. the moderation filter telling the sender a message was blocked). */
.chat-line.chat-system { color: var(--muted); font-style: italic; font-size: .82rem; }

/* Clip button while recording. */
#clip-btn.recording { color: #ff6b7d; border-color: #ff3b52; }
@media (prefers-reduced-motion: no-preference) { #clip-btn.recording { animation: cc-live 1.2s ease-in-out infinite; } }
