:root {
  --bg: #0d1220;
  --surface: #161d30;
  --border: #2a3552;
  --text: #e7ecf7;
  --text-dim: #93a0c2;
  --accent: #6ec3ff;
  --accent-strong: #9bd8ff;
  --good: #5cd499;
  /* Two fonts site-wide: MMRock9 (--pixel-font) ONLY on the big headings listed above its @font-face block, and
     Fira Sans (assets/fonts/firasans, SIL Open Font License - OFL.txt there) for everything else: body text, buttons,
     tables and numbers. --mono-font used to be a monospace stack for numbers/tables; it is Fira Sans now too, with
     tabular (equal-width) digits on body so numbers still line up in columns. */
  --main-font: "Fira Sans", ui-sans-serif, "Segoe UI", system-ui, sans-serif;
  --mono-font: var(--main-font);
  --pixel-font: "MMRock9", ui-monospace, "Cascadia Code", monospace;
}

/* Fira Sans - the main font (see --main-font). Only the weights the site uses: 400, 400 italic, 600, 700. */
@font-face {
  font-family: "Fira Sans";
  src: url("../assets/fonts/firasans/FiraSans-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fira Sans";
  src: url("../assets/fonts/firasans/FiraSans-Italic.ttf") format("truetype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Fira Sans";
  src: url("../assets/fonts/firasans/FiraSans-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fira Sans";
  src: url("../assets/fonts/firasans/FiraSans-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* MMRock9 by Caveras (assets/fonts/mmrock9/license.txt) - used ONLY by --pixel-font, applied only to:
   .app-header h1 / .access-gate h1 (site title), .home-hero-title, .home-section-title,
   .home-speedrun-title, .home-stats-panel::before ("GLOBAL LIFETIME STATS"), .home-stats-panel
   .records-card-title (the misc-stat tile labels, e.g. "TOTAL KILLS"), .filters-panel h2
   ("Filters"), .home-category-title (the home page's category button names, e.g.
   "Matchups"), .home-top-player-name (the Top Players boxes' big winner name - large
   enough that the font's small/body-text readability problem doesn't apply), and
   .home-scope-note (the "FILTERED: ..." note under Global Stats, sized up from the shared
   .filter-note body size for the same reason), and the Shiny Bestiary's large headings:
   .bestiary-game-name (game tiles), .bestiary-game-title, .bestiary-overall-count, and .modes-since-label (the gold
   "Stats Tracked Since 5.0 Release" next to the Modes tabs), .char-results-section-title ("Lifetime" / "Since 5.0 Release"
   headings in the Characters panel). Nowhere else - see the site-wide revert note
   on --mono-font above. */
@font-face {
  font-family: "MMRock9";
  src:
    url("../assets/fonts/mmrock9/MMRock9.woff") format("woff"),
    url("../assets/fonts/mmrock9/MMRock9.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

* {
  box-sizing: border-box;
}

/* Square/pixel UI pass: nothing in this app should have a rounded corner. Form controls
   still explicitly inherit font-family from body - a good idea regardless of which font
   is chosen, since browsers don't do that by default. */
button,
input,
select,
textarea {
  font-family: inherit;
}

.access-gate {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 32px;
  text-align: center;
}

.access-gate-logo {
  width: 64px;
  height: 64px;
  object-fit: contain;
  margin-bottom: 4px;
}

.access-gate h1 {
  margin: 0;
  font-family: var(--pixel-font);
  font-size: 26px;
  color: var(--accent);
  letter-spacing: 0.02em;
}

.access-gate-message {
  color: var(--text-dim);
  font-size: 14px;
  max-width: 380px;
  margin: 0 0 8px;
}

.access-gate-denied {
  color: #e05a5a;
  font-size: 13px;
  max-width: 380px;
  margin: -4px 0 8px;
}

.session-expired-note {
  color: #e05a5a;
  font-size: 12px;
  max-width: 220px;
}

.access-gate .discord-login-btn {
  padding: 10px 22px;
  font-size: 14px;
}

/* TEMP DEBUG - remove alongside the toolbar/JS wiring described in index.html and
   discord-auth.js. Deliberately NOT styled like real app UI (dashed border, warning
   color, fixed-position overlay) so it always reads as "not part of the real app".
   Fixed top-right per its own ask - lives outside the normal header layout entirely so
   it's available even before the access gate opens (see index.html for why). */
.debug-tier-toolbar {
  position: fixed;
  top: 8px;
  right: 8px;
  z-index: 9999;
  display: flex;
  align-items: center;
  gap: 6px;
  background: rgba(13, 18, 32, 0.9);
  border: 1px dashed #e6a23c;
  padding: 5px 8px;
}

.debug-tier-label {
  color: #e6a23c;
  font-size: 9px;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.debug-tier-btn {
  background: transparent;
  color: #e6a23c;
  border: 1px dashed #e6a23c;
  border-radius: 0;
  padding: 4px 8px;
  font-size: 10px;
  cursor: pointer;
}

.debug-tier-btn:hover {
  background: rgba(230, 162, 60, 0.12);
}

.debug-tier-btn.active {
  background: #e6a23c;
  color: #0d1220;
}

body {
  margin: 0;
  /* Background.webp (assets/UI/) is a narrow repeating tile (185x1600), not a scene
     image - repeat it rather than stretching/cover-fitting, and keep the pixel edges
     crisp at native size. --bg is still the fallback color while the image loads. A flat
     dark overlay sits on top of the tile itself (not just a lower opacity on the image)
     so the pattern reads as a muted backdrop texture instead of a loud, fully-saturated
     repeat - tune the 0.55 alpha below to taste. */
  background-color: var(--bg);
  color: var(--text);
  font-family: var(--main-font);
  font-variant-numeric: tabular-nums; /* digits all the same width, so numbers line up in tables */
}

/* The tile itself lives on a fixed layer BEHIND the page instead of on body, so js/parallax.js
   can scroll it at a different speed than the content (parallax). --bg-parallax-y is set by that
   script; with no JS it stays 0 and the tile is simply fixed in place. Everything above is unchanged:
   the same tile, the same dark overlay, the same crisp pixels. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(5, 8, 16, 0.55), rgba(5, 8, 16, 0.55)),
    url("../assets/UI/Background.webp");
  background-repeat: repeat;
  background-position: 0 var(--bg-parallax-y, 0px);
  image-rendering: pixelated;
}

.app-header {
  padding: 24px 24px 12px;
  /* A plain 1px gray line read as a generic/default web divider, not "pixel" - matching
     the same solid-black, hard-edged language every button/card on the page already uses
     (see the pixel-bevel block at the end of this file) instead. Keep the low-opacity
     dark fill behind the header as-is, only the outline changes. */
  border-bottom: 4px solid #000;
  /* The tiled background now runs behind the whole page (see body) - the header/title
     need their own solid backdrop or the pattern shows directly behind the logo/title
     text and hurts legibility. */
  background: rgba(13, 18, 32, 0.92);
}

.header-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
}

.header-title {
  display: flex;
  align-items: center;
  gap: 12px;
}

.header-logo {
  width: 44px;
  height: 44px;
  object-fit: contain;
}

.app-header h1 {
  margin: 0;
  font-family: var(--pixel-font);
  font-size: 24px;
  color: var(--accent);
  letter-spacing: 0.02em;
}

.subtitle {
  margin: 4px 0 0;
  color: var(--text-dim);
  font-size: 13px;
}

.header-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.sync-indicator {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  color: var(--text-dim);
  white-space: nowrap;
}

.hard-refresh-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 0;
  width: 20px;
  height: 20px;
  line-height: 1;
  font-size: 13px;
  cursor: pointer;
  padding: 0;
}

.hard-refresh-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* ---------- discord login ---------- */

.discord-login-btn {
  background: #5865f2;
  color: #fff;
  border: none;
  border-radius: 0;
  padding: 6px 14px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}

.discord-login-btn:hover {
  background: #4752c4;
}

.discord-user {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}

.discord-tier-badge {
  padding: 2px 8px;
  border-radius: 0;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* Matched to the actual Discord role colors for consistency - PLACEHOLDER hex values
   below (--role-developer/--role-dev-contributor/--role-alpha), swap for the real ones
   from Server Settings -> Roles -> click role -> color picker. Public reuses the
   existing --good green token, unrelated to Discord (there's no "Public" role). */
:root {
  --role-developer: #5865f2;
  --role-dev-contributor: #5865f2;
  --role-alpha: #e67e22;
}

.discord-tier-badge.role-public {
  background: rgba(92, 212, 153, 0.15);
  color: var(--good);
}

.discord-tier-badge.role-developer {
  background: color-mix(in srgb, var(--role-developer) 15%, transparent);
  color: var(--role-developer);
}

.discord-tier-badge.role-dev-contributor {
  background: color-mix(in srgb, var(--role-dev-contributor) 15%, transparent);
  color: var(--role-dev-contributor);
}

.discord-tier-badge.role-alpha {
  background: color-mix(in srgb, var(--role-alpha) 15%, transparent);
  color: var(--role-alpha);
}

.discord-logout-btn {
  background: none;
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 0;
  padding: 4px 8px;
  font-size: 11px;
  cursor: pointer;
}

.discord-logout-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.sync-dot {
  width: 8px;
  height: 8px;
  border-radius: 0;
  background: var(--text-dim);
  flex-shrink: 0;
}

.sync-dot.syncing {
  background: var(--accent);
  animation: sync-pulse 1s ease-in-out infinite;
}

.sync-dot.synced {
  background: var(--good);
}

.sync-dot.error {
  background: #ff6b6b;
}

.sync-countdown {
  color: var(--text-dim);
  opacity: 0.75;
}

@keyframes sync-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.tabs {
  display: flex;
  gap: 4px;
  padding: 12px 32px 0;
  /* Same reasoning as .app-header's border - a thin gray line reads as a generic web
     divider, not pixel art. */
  border-bottom: 4px solid #000;
  /* Same reasoning as .app-header - a solid backdrop so the tiled body background
     doesn't run directly behind the nav labels. */
  background: rgba(13, 18, 32, 0.92);
}

.tab-button {
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 14px;
  padding: 10px 16px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
}

.tab-button.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.tab-button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.layout {
  display: flex;
  align-items: flex-start;
}

.layout-main {
  flex: 1;
  min-width: 0;
}

main {
  padding: 32px;
}

.filters-panel {
  width: 220px;
  flex-shrink: 0;
  background: var(--surface);
  border-left: 1px solid var(--border);
  padding: 24px 20px;
  min-height: calc(100vh - 78px);
}

.filters-panel h2 {
  font-family: var(--pixel-font);
  font-size: 15px;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0 0 20px;
}

.filter-group {
  margin-bottom: 22px;
}

.filter-group-label {
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 8px;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  margin-bottom: 6px;
  cursor: pointer;
}

.filter-group select,
.filter-group input[type="text"] {
  width: 100%;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 7px 9px;
  font-size: 13px;
}

.filter-note {
  font-size: 10.5px;
  color: var(--text-dim);
  margin: 6px 0 0;
  line-height: 1.4;
}

/* Bumped up from the shared 10.5px .filter-note size - MMRock9 needs more room than that to
   stay legible (see the font's whitelist comment up top), so this one's sized like the smaller
   pixel-font labels (.home-stats-panel::before) rather than left at body-text size. */
.home-scope-note {
  font-family: var(--pixel-font);
  font-size: 12px;
  text-align: center;
  letter-spacing: 0.02em;
  line-height: 1.6;
}

.filters-panel-intro {
  font-size: 10.5px;
  color: var(--text-dim);
  line-height: 1.5;
  margin: 0 0 20px;
}

.filters-pending-note {
  font-size: 11px;
  color: var(--accent);
  margin: 0 0 8px;
  font-weight: 600;
}

.filters-action-row {
  display: flex;
  gap: 8px;
}

#apply-filters-btn {
  flex: 2;
  background: var(--accent);
  color: #0d1220;
  border: none;
  border-radius: 0;
  padding: 10px;
  font-weight: 600;
  cursor: pointer;
}

#apply-filters-btn:hover {
  background: var(--accent-strong);
}

#reset-filters-btn {
  flex: 1;
  background: var(--surface);
  color: var(--text-dim);
  border: none;
  border-radius: 0;
  padding: 10px;
  font-weight: 600;
  cursor: pointer;
}

#reset-filters-btn:hover {
  color: var(--text);
}

.player-id-input {
  margin-top: 6px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 6px 8px;
  font-size: 12px;
  width: 100%;
}

.hint {
  font-size: 12px;
  color: var(--text-dim);
  max-width: 640px;
  margin: 10px 0 0;
}

.tab-panel {
  display: none;
}

.tab-panel.active {
  display: block;
}

.matchup-picker {
  display: flex;
  align-items: flex-end;
  gap: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 20px;
  max-width: 640px;
}

.picker-column {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1;
}

.picker-column label {
  font-size: 12px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

select {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 8px 10px;
  font-size: 14px;
}

.vs {
  font-family: var(--mono-font);
  color: var(--text-dim);
  padding-bottom: 10px;
}

/* ---------- matchup tab character picker (dropdown replaced with a searchable
   button-grid, same visual language as Specific Mode's character select) ---------- */

.char-picker {
  position: relative;
}

.char-picker-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 6px 10px;
  font-size: 14px;
  cursor: pointer;
  text-align: left;
}

.char-picker-trigger:hover {
  border-color: var(--accent);
}

.char-picker-trigger .head-icon.small {
  width: 24px;
  height: 24px;
  margin-bottom: 0;
  flex-shrink: 0;
}

.char-picker-trigger::after {
  content: "\25BE";
  margin-left: auto;
  color: var(--text-dim);
}

.char-picker-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 20;
  width: 560px;
  max-width: 90vw;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}

.char-picker-panel .search-input {
  margin-bottom: 10px;
}

.char-picker-panel .char-button-grid {
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  max-height: 460px;
  overflow-y: auto;
  padding-right: 2px;
}

#compare-btn {
  background: var(--accent);
  color: #0d1220;
  border: none;
  border-radius: 0;
  padding: 10px 20px;
  font-weight: 600;
  cursor: pointer;
}

#compare-btn:hover {
  background: var(--accent-strong);
}

.matchup-status {
  margin-top: 12px;
  color: var(--text-dim);
  font-size: 13px;
  min-height: 18px;
}

.matchup-result {
  display: flex;
  align-items: center;
  gap: 32px;
  margin-top: 28px;
}

.hidden {
  display: none !important;
}

.result-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 24px;
  text-align: center;
  width: 200px;
}

.head-icon {
  width: 64px;
  height: 64px;
  object-fit: contain;
  image-rendering: pixelated;
  margin-bottom: 12px;
}

.result-name {
  font-weight: 600;
  font-size: 16px;
  margin-bottom: 8px;
}

.result-winpct {
  font-family: var(--mono-font);
  font-size: 28px;
  color: var(--good);
}

.result-label {
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-top: 4px;
}

.result-middle {
  text-align: center;
}

.total-matches {
  font-family: var(--mono-font);
  font-size: 22px;
  color: var(--accent);
}

.matchup-empty {
  margin-top: 28px;
  color: var(--text-dim);
  font-style: italic;
}

/* ---------- matchup card secondary stats ---------- */

.sub-stats {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.sub-stats > div {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.sub-stats span {
  font-family: var(--mono-font);
  font-size: 14px;
  color: var(--text);
}

.sub-stats label {
  font-size: 9px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-align: center;
}

/* ---------- character matchup: dynamic N-player slots ---------- */

.matchup-slots {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 16px;
}

.matchup-slot {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 16px;
  width: 200px;
}

.matchup-slot-stand {
  position: relative;
  height: 140px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0;
  overflow: hidden;
}

.matchup-stand-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}

.matchup-stand-placeholder {
  font-family: var(--mono-font);
  font-size: 40px;
  color: var(--text-dim);
  opacity: 0.5;
}

.matchup-slot-team {
  display: flex;
  gap: 6px;
}

.matchup-team-fixed {
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.matchup-team-btn {
  flex: 1;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 0;
  padding: 5px 6px;
  font-size: 11px;
  cursor: pointer;
}

.matchup-team-btn.active {
  border-color: var(--accent);
  color: var(--accent);
}

.matchup-slot-remove {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 22px;
  height: 22px;
  border-radius: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.matchup-slot-remove:hover {
  border-color: var(--bad, #e05a5a);
  color: var(--bad, #e05a5a);
}

.matchup-add-slot-tile {
  width: 60px;
  align-self: stretch;
  min-height: 200px;
  background: transparent;
  border: 2px dashed var(--border);
  border-radius: 0;
  color: var(--text-dim);
  font-size: 28px;
  font-weight: 600;
  cursor: pointer;
}

.matchup-add-slot-tile:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.matchup-recap {
  margin-top: 16px;
  font-size: 13px;
  color: var(--text-dim);
  min-height: 18px;
}

.matchup-results {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  margin-top: 8px;
}

.char-button-any {
  border-style: dashed;
}

.char-button-any-icon {
  width: 36px;
  height: 36px;
  margin: 0 auto 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono-font);
  font-size: 18px;
  color: var(--text-dim);
  border: 1px dashed var(--border);
  border-radius: 0;
}

.last-played {
  margin-top: 10px;
  font-size: 11px;
  color: var(--text-dim);
}

/* ---------- specific mode tab ---------- */

.mode-picker {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
}

/* Leaderboards: the view picker (Records/Top 5/All Times) stays its own row up top: the
   sub-mode picker (whichever of the 3 matches the current view - Stage/Boss, or Arena/
   Stage/Boss for Top 5) is a second row directly below it, sitting right above the actual
   card grid/content rather than sharing a row with the view picker. The two rows are
   deliberately given INDEPENDENT alignment (align-self on the first child, not a shared
   align-items on the container) - the view picker centers itself, the sub-mode picker
   stays left-aligned to whatever the container's default is. */
.leaderboards-topbar {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 16px;
}

.leaderboards-topbar .mode-picker {
  margin-bottom: 0;
}

/* All Times: Stage / Boss buttons with the CHARACTER picker beside them */
.leaderboards-times-row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 16px;
}
.leaderboards-times-row .raw-anchor-picker {
  margin-bottom: 0;
  width: 280px;
}
/* the stage dropdown's panel holds the stage cards, so it is wider and taller than a character list */
#stage-rawrecords-panel {
  width: 720px;
}
#stage-rawrecords-panel .stage-picker-grid {
  max-height: 420px;
  margin-top: 8px;
}
.stage-picker-any .char-button-any-icon {
  margin: 0 auto;
}

.leaderboards-topbar > .mode-picker:first-child {
  align-self: center;
}

.mode-button {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 0;
  padding: 8px 16px;
  font-size: 13px;
  cursor: pointer;
}

.mode-button.active {
  border-color: var(--accent);
  color: var(--accent);
}

/* Arena/Stage/Boss only - the game's own sprMainMenuButtons art (frames 0/1/3), not
   applied to the other button groups that reuse .mode-button for visual consistency
   (Player Search's by-username/by-ID toggle, the player-detail mode picker). */
.mode-icon-btn {
  width: 104px;
  height: 46px;
  padding: 0;
  font-size: 0;
  background-color: var(--surface);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 84px auto;
  image-rendering: pixelated;
  border-radius: 0;
}

.mode-icon-btn[data-mode="arena"] { background-image: url("../assets/modebuttons/Arena.png"); }
.mode-icon-btn[data-mode="stage"] { background-image: url("../assets/modebuttons/Stage.png"); }
.mode-icon-btn[data-mode="boss"] { background-image: url("../assets/modebuttons/BossButton.png"); }
.mode-icon-btn[data-mode="all"] { background-image: url("../assets/modebuttons/All.png"); }

/* Database tab - All Stats/All Times get their own icon buttons; All Comparisons stays
   plain text on purpose. Anywhere else under those two that sorts by mode (All Stats'
   Stage/Boss, All Times' Stage/Boss) reuses the same Stage.png/Boss.png as Specific Mode
   instead of new art - same mode, same icon. Characters/Misc (All Stats) and vs
   Characters/Stage/Boss (All Comparisons) are left as plain text for now. */
.mode-icon-btn[data-raw-view="stats"] { background-image: url("../assets/modebuttons/DatabaseAllStats.png"); }
.mode-icon-btn[data-raw-view="times"] { background-image: url("../assets/modebuttons/AllTimes.png"); }
.mode-icon-btn[data-anchor-type="character"] { background-image: url("../assets/modebuttons/ByCharacterAnchorButton.png"); }
.mode-icon-btn[data-anchor-type="stage"] { background-image: url("../assets/modebuttons/ByStageButton.png"); }
.mode-icon-btn[data-allstats-mode="stage"] { background-image: url("../assets/modebuttons/Stage.png"); }
.mode-icon-btn[data-allstats-mode="boss"] { background-image: url("../assets/modebuttons/BossButton.png"); }
.mode-icon-btn[data-rawrecords-mode="stage"] { background-image: url("../assets/modebuttons/Stage.png"); }
.mode-icon-btn[data-rawrecords-mode="boss"] { background-image: url("../assets/modebuttons/BossButton.png"); }
.mode-icon-btn[data-records-mode="stage"] { background-image: url("../assets/modebuttons/Stage.png"); }
.mode-icon-btn[data-records-mode="boss"] { background-image: url("../assets/modebuttons/BossButton.png"); }
.mode-icon-btn[data-top5-mode="arena"] { background-image: url("../assets/modebuttons/Arena.png"); }
.mode-icon-btn[data-top5-mode="stage"] { background-image: url("../assets/modebuttons/Stage.png"); }
.mode-icon-btn[data-top5-mode="boss"] { background-image: url("../assets/modebuttons/BossButton.png"); }

.mode-icon-btn:hover {
  filter: brightness(1.15);
}

.mode-icon-btn.active {
  border-color: var(--accent);
}

.search-input {
  display: block;
  width: 100%;
  max-width: 320px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 9px 12px;
  font-size: 13px;
  margin-bottom: 14px;
}

.search-input.stage-results-search {
  margin-top: 24px;
}

.stage-leg-filter {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 12px;
  font-size: 12px;
}

.stage-leg-filter label {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

.stage-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
  padding: 4px;
}

.stage-picker-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 10px;
  text-align: center;
  cursor: pointer;
}

.stage-picker-card:hover {
  border-color: var(--accent);
}

.stage-picker-card.selected {
  border-color: var(--accent);
  background: rgba(110, 195, 255, 0.08);
}

.stage-picker-card .head-icon.small {
  width: 36px;
  height: 36px;
  margin-bottom: 6px;
}

.stage-picker-name {
  font-size: 11px;
  font-weight: 600;
}

/* ---------- specific mode: character button grid ---------- */

.char-button-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  gap: 8px;
  margin-bottom: 20px;
}

.char-button {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 10px 6px;
  text-align: center;
  cursor: pointer;
}

.char-button:hover {
  border-color: var(--accent);
}

.char-button.selected {
  border-color: var(--accent);
  background: rgba(110, 195, 255, 0.08);
}

.char-button .head-icon.small {
  width: 36px;
  height: 36px;
  margin-bottom: 6px;
}

.char-button-name {
  font-size: 11px;
  font-weight: 600;
}

.char-button.untested {
  opacity: 0.4;
  cursor: not-allowed;
}

.char-button-untested {
  font-size: 9px;
  color: var(--text-dim);
  font-style: italic;
  margin-top: 2px;
}

/* ---------- specific mode: two-column layout ---------- */
/* Left column is the picker pair (stage grid + character grid) - a fixed, comfortably
   narrow width since it's just a selection list. Right column is the results panel,
   given the rest of the space so the numbers have real room instead of being squeezed
   under the picker grid. Sticky on the right so scrolling a long character grid on the
   left doesn't scroll the results out of view. */

.specific-mode-layout {
  display: grid;
  grid-template-columns: 1fr 260px;
  gap: 28px;
  align-items: start;
}

.specific-mode-right {
  position: sticky;
  top: 20px;
}

@media (max-width: 900px) {
  .specific-mode-layout {
    grid-template-columns: 1fr;
  }
  .specific-mode-right {
    position: static;
  }
}

/* Player Lookup: same left-picker/right-results idea as .specific-mode-layout, but
   opposite size ratio - the left side here is a plain 3-column results table (narrow is
   fine, minmax gives it room to search/click without being cramped), while the right side
   holds the detail panel's much wider mode-specific table (Character/Played/Win %/Avg
   Kills/Accuracy/Last Played, 6 columns) which actually needs the bulk of the space, not
   the other way around. Selecting a player now updates the right column in place instead
   of appending the detail panel below the results list. */
.player-lookup-layout {
  display: grid;
  /* minmax(0, 1fr), not 1fr: a plain 1fr can't shrink below its content, so a wide detail panel
     used to push the layout instead of staying in its own column. */
  grid-template-columns: minmax(300px, 440px) minmax(0, 1fr);
  gap: 28px;
  align-items: start;
}

/* The list's table used to be wider than its column (the 41-character player IDs), so it spilled
   under the sticky detail panel on the right. A fixed layout makes it fit the column exactly, and
   the long ID is cut off with an ellipsis (the full ID is in each cell's tooltip). */
.player-lookup-left {
  min-width: 0;
}

#player-results-table {
  table-layout: fixed;
  width: 100%;
}

#player-results-table th:nth-child(1) {
  width: 34%;
}
#player-results-table th:nth-child(2) {
  width: 38%;
}
#player-results-table th:nth-child(3) {
  width: 28%;
}

#player-results-table td {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.player-lookup-right {
  position: sticky;
  top: 20px;
}

@media (max-width: 900px) {
  .player-lookup-layout {
    grid-template-columns: 1fr;
  }
  .player-lookup-right {
    position: static;
  }
}

/* ---------- specific mode: results panel ---------- */

.char-results-hint {
  color: var(--text-dim);
  font-style: italic;
  font-size: 13px;
}

.char-results-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 18px;
  margin-bottom: 16px;
}

.char-results-stage-badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-bottom: 16px;
  padding-bottom: 16px;
  border-bottom: 1px dashed var(--border);
  font-size: 12px;
  color: var(--text-dim);
  text-align: center;
}

.char-results-stage-badge img {
  width: 32px;
  height: 32px;
}

.char-results-stage-badge span {
  color: var(--text);
  font-weight: 600;
}

.char-results-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  cursor: pointer;
}

.char-results-header .head-icon {
  width: 64px;
  height: 64px;
  margin-bottom: 0;
  flex-shrink: 0;
}

.char-results-headtext {
  width: 100%;
}

.char-results-name {
  font-weight: 600;
  font-size: 17px;
}

.char-results-quickstats {
  margin-top: 4px;
  font-family: var(--mono-font);
  font-size: 13px;
  color: var(--good);
}

.char-results-expand-hint {
  font-size: 11px;
  color: var(--accent);
  white-space: nowrap;
}

.char-results-detail {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.stat-mode-toggle {
  display: flex;
  gap: 6px;
}

.stat-mode-btn {
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 0;
  padding: 4px 10px;
  font-size: 11px;
  cursor: pointer;
}

.stat-mode-btn.active {
  border-color: var(--accent);
  color: var(--accent);
}

.all-mode-breakdown-loading {
  font-size: 11px;
  color: var(--text-dim);
  font-style: italic;
}

.all-mode-breakdown {
  padding-bottom: 12px;
  margin-bottom: 12px;
  border-bottom: 1px dashed var(--border);
}

.char-results-detail-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.char-results-detail-grid > div {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 64px;
}

.char-results-detail span {
  font-family: var(--mono-font);
  font-size: 14px;
  color: var(--text);
}

.char-results-detail label {
  font-size: 9px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-align: center;
}

/* This panel specifically is now a narrow sidebar column (see .specific-mode-layout) -
   a wrapped grid of boxes doesn't fit that width well, so it's overridden here to a
   stacked vertical list (label left, value right) instead. The shared
   .char-results-detail-grid class above stays untouched since Live Stats/Player Search
   reuse it in wider, horizontal contexts where the wrapped-box layout is still right. */
.char-results-detail .char-results-detail-grid {
  flex-direction: column;
  flex-wrap: nowrap;
  gap: 8px;
}

.char-results-detail .char-results-detail-grid > div {
  flex-direction: row;
  align-items: baseline;
  justify-content: space-between;
  min-width: 0;
  gap: 10px;
}

.char-results-detail .char-results-detail-grid span {
  font-size: 15px;
}

.char-results-detail .char-results-detail-grid label {
  text-align: right;
}

/* ---------- player search tab ---------- */

.player-search-row {
  display: flex;
  gap: 10px;
  max-width: 480px;
  margin-bottom: 14px;
}

.player-search-row .search-input {
  margin-bottom: 0;
  max-width: none;
  flex: 1;
}

.player-search-row button {
  background: var(--accent);
  color: #0d1220;
  border: none;
  border-radius: 0;
  padding: 9px 18px;
  font-weight: 600;
  cursor: pointer;
}

.player-search-row button:hover {
  background: var(--accent-strong);
}

.data-table {
  width: 100%;
  max-width: 720px;
  border-collapse: collapse;
  margin-bottom: 20px;
  font-size: 13px;
  /* Solid backdrop so the tiled body background doesn't run directly behind table rows -
     matches .app-header/.tabs' reasoning, plus a little padding now that there's a
     visible panel edge to it. */
  background: rgba(13, 18, 32, 0.85);
  padding: 4px 8px;
}

.data-table th {
  text-align: left;
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
}

.data-table td {
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  font-family: var(--mono-font);
}

#player-results-tbody tr {
  cursor: pointer;
}

#player-results-tbody tr:hover {
  background: var(--surface);
}

.player-detail-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 20px;
  max-width: 760px;
}

.player-detail-panel h3 {
  margin: 0;
  font-size: 16px;
}

.active-now-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--good);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.active-now-badge::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 0;
  background: var(--good);
}

.player-mode-summary {
  margin: 14px 0 18px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

.lifetime-stats-section {
  margin-bottom: 20px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--border);
}

.lifetime-stats-section h4 {
  margin: 0 0 4px;
  font-size: 14px;
}

.lifetime-stats-section .char-results-detail-grid {
  margin: 10px 0 14px;
}

.lifetime-stats-section .data-table {
  max-width: none;
  font-size: 12px;
}

/* ---------- live stats tab ---------- */

.live-stats-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  align-items: flex-start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 16px 20px;
  margin-bottom: 20px;
}

.live-control {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 140px;
}

.live-control select {
  padding: 7px 9px;
  font-size: 13px;
}

.live-date-custom {
  display: flex;
  gap: 6px;
  margin-top: 6px;
}

.live-date-custom input[type="date"] {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 6px 8px;
  font-size: 12px;
  flex: 1;
  min-width: 0;
}

.live-stats-headline {
  font-family: var(--mono-font);
  font-size: 14px;
  color: var(--text-dim);
  margin-bottom: 14px;
}

.live-headline-number {
  font-size: 22px;
  color: var(--good);
  font-weight: 600;
}

.live-stats-chart-wrap {
  position: relative;
  height: 320px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 16px;
  margin-bottom: 20px;
}

.live-stats-summary {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 16px 20px;
}

#live-total-mode-toggle {
  margin-bottom: 10px;
}

.live-recent-section {
  margin-top: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 16px 20px;
}

.live-recent-heading {
  margin: 0 0 10px;
  font-size: 14px;
}

.live-recent-section .data-table {
  max-width: none;
}

/* ---------- raw data tab ---------- */

.raw-anchor-picker {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-width: 100%;
  margin-bottom: 16px;
}

.raw-anchor-picker label {
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Stage Anchor's picker holds a full stage grid, not just a compact dropdown trigger -
   needs the width the character-anchor variant doesn't. */
#raw-anchor-stage-picker {
  max-width: none;
}

.misc-stat-value {
  font-family: var(--mono-font);
  font-size: 22px;
  font-weight: 600;
  text-align: center;
  color: var(--good);
}

.raw-data-table-wrap {
  overflow-x: auto;
  margin-bottom: 20px;
  /* Same reasoning as .data-table - solid backdrop behind the Database/Leaderboards
     tables (All Comparisons, All Stats, All Times all share this class) instead of the
     tiled body background showing through. */
  background: rgba(13, 18, 32, 0.85);
  padding: 4px 8px;
}

.raw-data-table {
  width: max-content;
  min-width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.raw-data-table th {
  text-align: left;
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}

.raw-data-table th:hover {
  color: var(--text);
}

.raw-data-table td {
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  font-family: var(--mono-font);
  white-space: nowrap;
}

.raw-name-cell {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: inherit;
  font-weight: 600;
}

.raw-name-cell .head-icon.small {
  width: 24px;
  height: 24px;
}

.raw-row-empty {
  opacity: 0.4;
}

.raw-search-th {
  padding: 4px 8px !important;
}

.raw-search-input {
  width: 100%;
  min-width: 140px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 5px 8px;
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: normal;
}

.raw-search-input:focus {
  border-color: var(--accent);
  outline: none;
}

/* ---------- records tab (personal-best leaderboard grid) ---------- */

.records-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
  margin-top: 16px;
}

.records-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 14px;
}

.records-card-icon {
  width: 100%;
  height: 130px;
  object-fit: contain;
  image-rendering: pixelated;
  margin-bottom: 8px;
}

.records-card-title {
  font-weight: 600;
  font-size: 14px;
  text-align: center;
  margin-bottom: 12px;
}

.records-card-legs {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin-bottom: 12px;
}

/* ---------- top 5 tab ---------- */

.top5-matchup-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.top5-matchup-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-top: 1px solid var(--border);
}

.top5-matchup-row:first-child {
  border-top: none;
}

.top5-matchup-side {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
  min-width: 0;
}

.top5-matchup-side .head-icon {
  width: 40px;
  height: 40px;
}

.top5-matchup-side .top5-matchup-name {
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.top5-matchup-side .top5-matchup-pct {
  font-family: var(--mono-font);
  font-size: 15px;
}

.top5-matchup-side.winner .top5-matchup-pct {
  color: var(--good);
}

.top5-matchup-side.loser .top5-matchup-pct {
  color: var(--text-dim);
}

.top5-matchup-vs {
  font-size: 10px;
  color: var(--text-dim);
  font-weight: 600;
  flex-shrink: 0;
}

.records-card-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.records-card-table .head-icon.small {
  width: 24px;
  height: 24px;
}

.records-card-table th {
  padding: 4px;
  font-size: 9px;
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-align: left;
  border-bottom: 1px solid var(--border);
}

.records-card-table td {
  padding: 7px 4px;
  /* Explicit minimum so every row - real data, dash placeholder, icon present or not -
     comes out the exact same height. A td's height is a floor, not a ceiling (real
     content that genuinely needs more, e.g. a wrapped username, can still grow it), but
     without this, rows measured a few px shorter or taller depending on content, which
     was still visibly reflowing the whole card even after padding row COUNT up to a
     fixed 3 - the box the icon sits in wasn't reliably deciding row height on its own. */
  height: 58px;
  border-top: 1px solid var(--border);
  font-family: var(--mono-font);
}

.records-card-table tr:first-child td {
  border-top: none;
}

.records-run-row {
  cursor: pointer;
}

.records-run-row:hover {
  background: rgba(110, 195, 255, 0.08);
}

/* All Times ranking cell: podium treatment for the top 3, plain ordinal text past that. */
.rank-badge {
  font-weight: 600;
}

.rank-gold {
  color: #ffd84a;
  text-shadow: 0 0 4px rgba(255, 216, 74, 0.9), 0 0 10px rgba(255, 216, 74, 0.6);
  animation: rank-gold-pulse 1.8s ease-in-out infinite;
}

@keyframes rank-gold-pulse {
  0%, 100% { text-shadow: 0 0 4px rgba(255, 216, 74, 0.9), 0 0 10px rgba(255, 216, 74, 0.6); }
  50% { text-shadow: 0 0 8px rgba(255, 216, 74, 1), 0 0 18px rgba(255, 216, 74, 0.85), 0 0 26px rgba(255, 216, 74, 0.4); }
}

.rank-silver {
  color: #d7dee8;
  /* Just barely a shine - a soft, static glow, no pulse. */
  text-shadow: 0 0 3px rgba(215, 222, 232, 0.5);
}

.rank-bronze {
  color: #cd7f32;
  /* No effect on purpose - plain bronze-colored text. */
}

.username-copy {
  cursor: pointer;
  border-bottom: 1px dashed var(--text-dim);
}

.username-copy:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* only Developers can click a name to copy the player's ID - for everyone else a name is plain text */
body:not(.dev-tier) .username-copy {
  cursor: inherit;
  border-bottom: none;
}
body:not(.dev-tier) .username-copy:hover {
  color: inherit;
}

/* ---------- raw records tab (paginated full run history) ---------- */

.rawrecords-pagination {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 14px;
}

.rawrecords-pagination button {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 0;
  padding: 6px 12px;
  font-size: 12px;
  cursor: pointer;
}

.rawrecords-pagination button:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
}

.rawrecords-pagination button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.rawrecords-pagination span {
  font-size: 12px;
  color: var(--text-dim);
}

/* ---------- home tab ---------- */

.home-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 12px 0 8px;
}

.home-hero-logo {
  width: 64px;
  height: 64px;
  image-rendering: pixelated;
  margin-bottom: 8px;
}

.home-hero-title {
  margin: 0;
  font-family: var(--pixel-font);
  font-size: 34px;
  color: var(--accent);
  letter-spacing: 0.02em;
}

.home-hero-subtitle {
  margin: 6px 0 0;
  color: var(--text-dim);
  font-size: 14px;
}

/* About Us tab - reuses .home-section-title as-is (already MMRock9 + accent blue, per the
   whitelist comment up top) for the two bold lines from the source doc ("No personal
   information is stored." / "You can OPT out."), so this needed no new pixel-font selector. */
.about-content {
  max-width: 640px;
  margin: 24px auto 0;
  color: var(--text);
  font-size: 14px;
  line-height: 1.6;
}

.about-content p {
  margin: 0 0 16px;
}

.about-content .home-section-title {
  margin: 28px 0 12px;
  font-size: 17px;
}

.about-content ul {
  margin: 0 0 16px;
  padding-left: 22px;
}

.about-content li {
  margin: 0 0 8px;
}

/* Wraps both misc-stat rows in their own tinted, glowing pixel panel so "the big numbers"
   read as a distinct, framed block instead of blending into the same dark tile the rest
   of the page sits on. Same Background.webp tile as body (keeps the pixel-art texture
   consistent app-wide), just re-tinted blue instead of neutral dark, plus a slow pulsing
   glow on the border - a nod to Mega Man's own light-blue palette rather than a generic
   card. */
.home-stats-panel {
  max-width: 1020px;
  margin: 20px auto 0;
  padding: 28px 20px 32px;
  background-color: #12203a;
  background-image:
    linear-gradient(rgba(20, 60, 110, 0.5), rgba(20, 60, 110, 0.5)),
    url("../assets/UI/Background.webp");
  background-repeat: repeat;
  image-rendering: pixelated;
  border: 4px solid #000;
  animation: home-stats-glow 4s ease-in-out infinite;
}

@keyframes home-stats-glow {
  0%,
  100% {
    box-shadow: 0 0 14px rgba(110, 195, 255, 0.25);
  }
  50% {
    box-shadow: 0 0 26px rgba(110, 195, 255, 0.55);
  }
}

/* Section label bridging the stats panel above and the category tiles below - same
   hard-edged divider language as the app header's own border-bottom, just smaller/
   secondary since it's mid-page rather than the page's actual title. */
.home-section-divider {
  max-width: 1020px;
  margin: 32px auto 0;
  padding-bottom: 10px;
  text-align: center;
  border-bottom: 4px solid #000;
}

.home-section-title {
  margin: 0;
  font-family: var(--pixel-font);
  font-size: 22px;
  color: var(--accent);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.home-misc-grid {
  /* flex, not grid - each row centers itself independently regardless of how many cards
     are in it (5 on top, 5 on bottom - grid has no clean native way to center an
     unevenly-sized row, flex-wrap + justify-content does). Two separate row elements
     (.home-misc-row-top/-bottom) rather than one wrapping grid, specifically so the split
     is always exactly 5-and-5 and never depends on viewport width happening to wrap in
     the right place. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  max-width: 960px;
  margin-left: auto;
  margin-right: auto;
}

/* Top row is the "headline" set (Total Plays/Matches Won/Players Online/Kills/Deaths) -
   deliberately bigger cards/icons/numbers than the bottom row underneath it. */
.home-misc-row-top .records-card {
  flex: 0 1 175px;
}

.home-misc-row-top .records-card-icon {
  height: 112px;
}

.home-misc-row-top .misc-stat-value {
  font-size: 34px;
}

.home-misc-row-bottom {
  margin-top: 20px;
}

.home-misc-row-bottom .records-card {
  flex: 0 1 150px;
}

.home-misc-row-bottom .records-card-icon {
  height: 80px;
}

.home-misc-row-bottom .misc-stat-value {
  font-size: 24px;
}

/* ---------- Home stat "exhibits" ----------
   The Home stat cards used to share the button look (4px black border + raised bevel + flat
   fill), so they read as buttons. Here each stat is a sprite standing in a spotlight above a
   sunken readout plate (nameplate + LED-style number), with hairline dividers instead of boxes,
   under faint scanlines - one display, not a row of buttons. Scoped to .home-stats-panel so the
   Leaderboards/chatbot .records-card (same base class) are untouched. */
.home-stats-panel {
  position: relative;
}

.home-stats-panel::before {
  content: "GLOBAL LIFETIME STATS";
  display: block;
  margin: -6px 0 16px;
  text-align: center;
  font-family: var(--pixel-font);
  font-size: 13px;
  letter-spacing: 0.3em;
  color: var(--accent);
}

.home-stats-panel::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.09) 0 2px, transparent 2px 4px);
}

.home-stats-panel .records-card {
  position: relative;
  background: none;
  border: 0;
  box-shadow: none;
  padding: 6px 10px 0;
}

.home-stats-panel .records-card + .records-card {
  border-left: 4px solid rgba(0, 0, 0, 0.35);
}

.home-stats-panel .records-card::before {
  content: "";
  position: absolute;
  left: 6%;
  right: 6%;
  top: 0;
  height: 64%;
  background: radial-gradient(ellipse at 50% 55%, rgba(110, 195, 255, 0.3), rgba(110, 195, 255, 0) 70%);
  pointer-events: none;
}

.home-stats-panel .records-card-icon {
  position: relative;
  margin-bottom: 6px;
  filter: drop-shadow(0 0 6px rgba(110, 195, 255, 0.55));
  animation: home-stat-bob 2.6s steps(2, end) infinite;
}

.home-stats-panel .records-card:nth-child(2) .records-card-icon {
  animation-delay: -0.5s;
}
.home-stats-panel .records-card:nth-child(3) .records-card-icon {
  animation-delay: -1s;
}
.home-stats-panel .records-card:nth-child(4) .records-card-icon {
  animation-delay: -1.5s;
}
.home-stats-panel .records-card:nth-child(5) .records-card-icon {
  animation-delay: -2s;
}

@keyframes home-stat-bob {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-4px);
  }
}

.home-stats-panel .records-card-title {
  position: relative;
  margin: 0;
  padding: 3px 6px;
  background: #0a1428;
  border: 3px solid #000;
  border-bottom: 0;
  font-family: var(--pixel-font);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.home-stats-panel .misc-stat-value {
  position: relative;
  padding: 6px 4px 5px;
  background: #050a14;
  border: 3px solid #000;
  box-shadow: inset 3px 3px 0 0 #000, inset -3px -3px 0 0 rgba(110, 195, 255, 0.22);
  letter-spacing: 0.04em;
  text-shadow: 0 0 10px rgba(92, 212, 153, 0.65);
}

.home-misc-row-bottom {
  padding-top: 18px;
  border-top: 4px solid rgba(0, 0, 0, 0.35);
}

@media (max-width: 720px) {
  .home-stats-panel .records-card + .records-card {
    border-left: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .home-stats-panel .records-card-icon {
    animation: none;
  }
}

/* ---------- Home: fastest clears ---------- */
.home-speedruns,
.home-top-players {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 24px;
  max-width: 1560px;
  margin: 24px auto 0;
}

.home-speedrun-panel {
  flex: 1 1 360px;
  max-width: 490px;
  padding: 16px 18px 18px;
  background: var(--surface);
  border: 4px solid #000;
  box-shadow: inset 3px 3px 0 0 rgba(110, 195, 255, 0.35), inset -3px -3px 0 0 var(--bevel-dark);
}

.home-speedrun-art {
  display: block;
  height: 96px;
  margin: 0 auto 6px;
  object-fit: contain;
  image-rendering: pixelated;
}

.home-speedrun-title {
  margin: 0 0 12px;
  text-align: center;
  font-family: var(--pixel-font);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.home-speedrun-row {
  display: grid;
  grid-template-columns: 26px 44px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 4px 6px;
  border-top: 2px solid rgba(0, 0, 0, 0.35);
}

.home-speedrun-row:first-child {
  border-top: 0;
}

.home-speedrun-rank {
  text-align: right;
  font-family: var(--pixel-font); /* MMRock9 */
  font-size: 12px;
  color: var(--text-dim);
}

.home-speedrun-icon {
  width: 40px;
  height: 40px;
  object-fit: contain;
  image-rendering: pixelated;
}

.home-speedrun-time {
  font-family: var(--pixel-font); /* MMRock9 */
  font-size: 16px;
  font-weight: 600;
  color: #fff;
}

.home-speedrun-row:first-child .home-speedrun-time {
  color: #fff;
}

.home-speedrun-name {
  white-space: nowrap;
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}

.home-speedrun-name:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* Names link into Player Lookup, which is Dev-only - plain text for everyone else. */
body:not(.dev-tier) .home-speedrun-name {
  pointer-events: none;
  cursor: default;
}

.home-speedrun-empty {
  padding: 12px 0;
  text-align: center;
  font-size: 12px;
  color: var(--text-dim);
}

/* Top Players: same bordered panel as the speedrun cards (.home-speedrun-panel), just centered
   and built around one big name instead of a ranked list. */
.home-top-player-panel {
  text-align: center;
}

.home-top-player-body {
  min-height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
}

.home-top-player-main {
  flex: 1 1 auto;
  min-width: 0;
}

.home-top-player-name {
  display: block;
  width: 100%;
  padding: 0;
  margin: 0 0 8px;
  background: none;
  border: 0;
  /* MMRock9 (--pixel-font) and literal white, not --text - the user asked for the name specifically
     to stand out from the rest of the (off-white --text) panel copy, big enough that MMRock9's
     small/body-text readability problem (see the font's own whitelist comment up top) doesn't apply. */
  font-family: var(--pixel-font);
  font-size: 28px;
  font-weight: 400;
  letter-spacing: 0.03em;
  line-height: 1.2;
  color: #fff;
  cursor: pointer;
  /* never cut off: a long name shrinks to fit (fitTopPlayerNames in app.js), and only wraps if it still can't fit */
  overflow: hidden;
  white-space: nowrap;
}

.home-top-player-name:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* Same rule as .home-speedrun-name: the name only links into Player Lookup for Dev. */
body:not(.dev-tier) .home-top-player-name {
  pointer-events: none;
  cursor: default;
}

.home-top-player-value {
  font-family: var(--mono-font);
  font-size: 22px;
  font-weight: 700;
  color: var(--good);
}

.home-top-player-label {
  font-family: var(--mono-font);
  font-size: 13px;
  color: var(--text-dim);
  margin-left: 6px;
}

/* The winner's single most-played character, off to the side of the name/stat block. */
.home-top-player-char {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding-left: 18px;
  border-left: 2px solid rgba(0, 0, 0, 0.35);
}

.home-top-player-char .head-icon.small {
  width: 40px;
  height: 40px;
  margin-bottom: 2px;
}

.home-top-player-char-name {
  max-width: 96px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
}

.home-top-player-char-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}

/* Flex + centered (not a fixed grid of tracks): some tiles are hidden depending on the role
   (Player Lookup / Live Activity are Dev-only), and a grid would leave the empty tracks on the
   right with the remaining tiles stuck to the left. The row is a little wider than the stat panels
   so all six Dev tiles fit on ONE row (they share it, growing up to 236px each); a role with
   fewer tiles gets the same single row, centered. Only a narrow window wraps. */
.home-categories {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  max-width: 1180px;
  margin: 36px auto 0;
}

.home-category-btn {
  flex: 1 1 140px;
  max-width: 236px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 14px 10px;
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s ease, transform 0.15s ease;
}

.home-category-btn:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}

.home-category-title {
  font-family: var(--pixel-font);
  font-size: 19px;
  font-weight: 600;
  color: var(--text);
}

.home-category-btn:hover .home-category-title {
  color: var(--accent-strong);
}

/* Narrower windows (the filters sidebar also eats width): a slightly smaller title so the six Dev
   tiles still fit on one row without the title wrapping. */
@media (max-width: 1400px) {
  .home-category-title {
    font-size: 15px;
  }
}

.home-category-desc {
  font-size: 12px;
  color: var(--text-dim);
}

/* ---------- pixel bevel: "box sprite" UI treatment ---------- */
/* Same technique as the StreamArena project's .px-btn/.px-card (controls.html) - a solid
   black outline plus a two-tone INSET box-shadow (bright top-left, dark bottom-right)
   reads as a raised 3D bevel while staying 100% hard-edged (no blur radius anywhere, no
   border-radius) - a pixel-art bevel, not a rounded corner. :active swaps the inset
   corners and nudges the element 1px down-right, reading as "pressed in." Placed at the
   end of the file deliberately - every selector below already has its own `border: 1px
   solid var(--border)` earlier in the file, and since this block shares the exact same
   selectors at the exact same specificity, being LAST is what makes it win the cascade
   instead of needing every one of those older rules hand-edited individually.
   --bevel-dark is a fixed near-black rather than derived from each element's own
   background, so one recipe reads correctly over --bg, --surface, and --accent alike. */
:root {
  --bevel-dark: rgba(0, 0, 0, 0.7);
}

.mode-button,
.discord-login-btn,
.discord-logout-btn,
.hard-refresh-btn,
#apply-filters-btn,
#reset-filters-btn,
#compare-btn,
.matchup-team-btn,
.matchup-slot-remove,
.matchup-add-slot-tile,
.stat-mode-btn,
.player-search-row button,
.rawrecords-pagination button,
.home-category-btn,
.char-button,
.stage-picker-card,
.mode-icon-btn,
#chatbot-key-save-btn,
#chatbot-key-clear-btn,
#chatbot-ask-btn,
#chatbot-clear-btn {
  border: 4px solid #000;
  box-shadow: inset 3px 3px 0 0 var(--accent), inset -3px -3px 0 0 var(--bevel-dark);
  transition: filter 0.08s, transform 0.08s;
}

.mode-button:hover,
.discord-login-btn:hover,
.discord-logout-btn:hover,
.hard-refresh-btn:hover,
#apply-filters-btn:hover,
#reset-filters-btn:hover,
#compare-btn:hover,
.matchup-team-btn:hover,
.matchup-slot-remove:hover,
.matchup-add-slot-tile:hover,
.stat-mode-btn:hover,
.player-search-row button:hover,
.rawrecords-pagination button:hover,
.home-category-btn:hover,
.char-button:hover,
.stage-picker-card:hover,
#chatbot-key-save-btn:hover,
#chatbot-key-clear-btn:hover,
#chatbot-ask-btn:hover,
#chatbot-clear-btn:hover {
  filter: brightness(1.2);
}

.mode-button:active,
.discord-login-btn:active,
.discord-logout-btn:active,
.hard-refresh-btn:active,
#apply-filters-btn:active,
#reset-filters-btn:active,
#compare-btn:active,
.matchup-team-btn:active,
.matchup-slot-remove:active,
.matchup-add-slot-tile:active,
.stat-mode-btn:active,
.player-search-row button:active,
.rawrecords-pagination button:active,
.home-category-btn:active,
.char-button:active,
.stage-picker-card:active,
.mode-icon-btn:active,
#chatbot-key-save-btn:active,
#chatbot-key-clear-btn:active,
#chatbot-ask-btn:active,
#chatbot-clear-btn:active {
  box-shadow: inset 3px 3px 0 0 var(--bevel-dark), inset -3px -3px 0 0 var(--accent);
  transform: translate(1px, 1px);
}

/* Active/selected states get the bevel pre-inverted, reading as "currently pressed in"
   at rest - same idea as StreamArena's .px-btn.active. */
.mode-button.active,
.mode-icon-btn.active,
.stage-picker-card.selected {
  box-shadow: inset 3px 3px 0 0 var(--bevel-dark), inset -3px -3px 0 0 var(--accent);
}

.records-card,
.player-detail-panel,
.filters-panel,
.char-results-panel,
.live-stats-chart-wrap,
.data-table,
.raw-data-table-wrap {
  border: 4px solid #000;
  box-shadow: inset 3px 3px 0 0 rgba(110, 195, 255, 0.35), inset -3px -3px 0 0 var(--bevel-dark);
}

/* ---------- shared hover/click info popovers ---------- */
/* One floating card, positioned via inline left/top (see showInfoPopover() in app.js) -
   fixed so it isn't clipped by any scrolling container it happens to float over. */
.info-popover {
  position: fixed;
  z-index: 5000;
  width: 220px;
  background: var(--surface);
  border: 4px solid #000;
  box-shadow: inset 3px 3px 0 0 var(--accent), inset -3px -3px 0 0 var(--bevel-dark);
  padding: 12px;
  pointer-events: auto;
}

.info-popover-title {
  font-weight: 600;
  font-size: 13px;
  margin-bottom: 8px;
  color: var(--accent-strong);
}

.info-popover-row {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--text-dim);
  padding: 3px 0;
  border-top: 1px solid var(--border);
}

.info-popover-row:first-of-type {
  border-top: none;
}

.info-popover-row span {
  color: var(--text);
  font-family: var(--mono-font);
  font-weight: 600;
}

.info-popover-loading,
.info-popover-empty {
  font-size: 11px;
  color: var(--text-dim);
}

.info-popover-link {
  display: block;
  margin-top: 8px;
  font-size: 11px;
  color: var(--accent);
  cursor: pointer;
  text-align: center;
}

.info-popover-link:hover {
  color: var(--accent-strong);
}

/* ---------- Chatbot tab (dev-only, BYOK) ---------- */

.chatbot-layout {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 820px;
  margin: 0 auto;
}

.chatbot-settings {
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 14px;
}

.chatbot-settings-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.chatbot-settings-row label {
  font-size: 12px;
  color: var(--text-dim);
  white-space: nowrap;
}

/* Same dark surface/border look as every other text input in the app (.search-input) -
   plain <input>s have no themed default anywhere in this file, so these two need it
   spelled out explicitly same as the rest do. */
#chatbot-api-key,
#chatbot-question-input {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 9px 12px;
  font-size: 13px;
}

#chatbot-api-key {
  flex: 1;
  min-width: 220px;
}

.chatbot-key-note {
  margin: 10px 0 0;
  font-size: 11px;
  color: var(--text-dim);
}

/* Save/Ask are the primary actions (same recipe as #apply-filters-btn/#compare-btn);
   Clear/Clear-chat are secondary (same recipe as #reset-filters-btn/.mode-button) - colored
   by role rather than left at the browser's default white/gray. */
#chatbot-key-save-btn,
#chatbot-ask-btn {
  background: var(--accent);
  color: #0d1220;
  padding: 9px 16px;
  font-weight: 600;
  cursor: pointer;
}

#chatbot-key-clear-btn,
#chatbot-clear-btn {
  background: var(--surface);
  color: var(--text-dim);
  padding: 9px 16px;
  font-weight: 600;
  cursor: pointer;
}

.chatbot-key-note a {
  color: var(--accent);
}

.chatbot-usage-note {
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--text-dim);
  font-family: var(--mono-font);
}

.chatbot-usage-note a {
  color: var(--accent);
  font-family: inherit;
}

/* Scrolls internally rather than growing the whole page - a long back-and-forth session
   should stay navigable without losing the input row off the bottom of the viewport. */
.chatbot-feed {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 220px;
  max-height: 60vh;
  overflow-y: auto;
  border: 1px solid var(--border);
  padding: 16px;
  background: rgba(0, 0, 0, 0.15);
}

.chatbot-empty-hint {
  color: var(--text-dim);
  font-size: 13px;
  text-align: center;
  margin: auto;
}

.chatbot-msg-question {
  align-self: flex-end;
  max-width: 80%;
  background: var(--accent);
  color: #06121f;
  font-weight: 600;
  font-size: 13px;
  padding: 8px 12px;
  border: 1px solid #000;
}

.chatbot-msg-answer {
  align-self: flex-start;
  max-width: 95%;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Widget cards reuse .records-card/.records-card-table/.info-popover-row wholesale (see
   js/chatbot.js) rather than inventing new visual language - the whole point is that an
   AI answer looks like every other card in this app, not like a chat bubble of prose. This
   row just gives .records-card a sane width when it's sitting in a vertical chat feed
   instead of its usual grid. */
.chatbot-widget-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.chatbot-widget-row .records-card {
  flex: 1 1 220px;
  max-width: 100%;
}

.chatbot-card-heading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.chatbot-widget-caption {
  font-size: 10px;
  color: var(--text-dim);
  font-style: italic;
}

.chatbot-widget-text {
  font-size: 13px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 10px 12px;
}

.chatbot-widget-loading {
  font-size: 12px;
  color: var(--text-dim);
  font-style: italic;
}

.chatbot-input-row {
  display: flex;
  gap: 10px;
}

#chatbot-question-input {
  flex: 1;
}

/* Player Lookup is Dev-only (DEV_ONLY_TABS in discord-auth.js sets body.dev-tier for Dev sessions),
   so the in-page "View full profile" links into it are hidden for everyone else. */
body:not(.dev-tier) .info-popover-link[data-goto-player-id] {
  display: none;
}

/* Reminder, under the Player ID box, about how to get your player ID out of the game. */
.filters-userid-hint {
  margin-top: 8px;
}

.filters-userid-hint strong {
  color: var(--text);
  font-weight: 700;
}

/* ---------- Leaderboards: the docked player card ---------- */
/* Records/All Times used to open a floating card (position: fixed, placed under whichever row was
   clicked), which covered the rows below it and stayed at that screen spot while you scrolled.
   Now it fills this reserved column instead: it never covers the results, and it stays in view
   (sticky) while you scroll a long list. Below 1000px wide there's no room for a column, so it's
   hidden and the floating card is used as before (see usePlayerDock() in app.js). */
.leaderboards-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 250px;
  gap: 20px;
  align-items: start;
}

.leaderboards-main {
  min-width: 0;
}

.player-dock {
  position: sticky;
  top: 16px;
  min-height: 120px;
  padding: 12px;
  background: var(--surface);
  border: 4px solid #000;
  box-shadow: inset 3px 3px 0 0 rgba(110, 195, 255, 0.35), inset -3px -3px 0 0 var(--bevel-dark);
}

.player-dock-hint {
  margin: 0;
  font-size: 12px;
  font-style: italic;
  color: var(--text-dim);
}

.player-dock.has-player .player-dock-hint {
  display: none;
}

/* Which run the docked card is about */
.records-run-row.dock-selected td,
.alltimes-run-row.dock-selected td {
  background: rgba(110, 195, 255, 0.16);
}

/* No column on Records (its rows open the run in All Times), Top 5 (hover previews only) or narrow windows */
.leaderboards-body:has(#leaderboards-view-top5:not(.hidden)),
.leaderboards-body:has(#leaderboards-view-records:not(.hidden)) {
  grid-template-columns: minmax(0, 1fr);
}

.leaderboards-body:has(#leaderboards-view-top5:not(.hidden)) .player-dock,
.leaderboards-body:has(#leaderboards-view-records:not(.hidden)) .player-dock {
  display: none;
}

@media (max-width: 1000px) {
  .leaderboards-body {
    grid-template-columns: minmax(0, 1fr);
  }
  .player-dock {
    display: none;
  }
}

/* ---------- Shiny Bestiary (js/bestiary.js) ---------- */
.bestiary-header {
  text-align: center;
  margin-bottom: 18px;
}
.bestiary-sub {
  margin: 6px 0 12px;
  color: var(--text-dim);
  font-size: 13px;
}
.bestiary-overall {
  min-height: 30px;
}
.bestiary-overall-label {
  font-family: var(--mono-font);
  font-size: 13px;
  color: var(--text-dim);
}
.bestiary-overall-count {
  font-family: var(--pixel-font);
  font-size: 26px;
  color: #ffd45c;
  margin-left: 6px;
  text-shadow: 0 0 8px rgba(255, 212, 92, 0.75), 0 0 18px rgba(255, 212, 92, 0.4);
  animation: bestiary-count-glow 2.6s ease-in-out infinite;
}
@keyframes bestiary-count-glow {
  0%, 100% { text-shadow: 0 0 6px rgba(255, 212, 92, 0.55), 0 0 14px rgba(255, 212, 92, 0.25); }
  50% { text-shadow: 0 0 10px rgba(255, 212, 92, 0.95), 0 0 24px rgba(255, 212, 92, 0.55); }
}
@media (prefers-reduced-motion: reduce) {
  .bestiary-overall-count { animation: none; }
}

/* game picker */
.bestiary-games {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  max-width: 1100px;
  margin: 0 auto;
}
.bestiary-game-tile {
  flex: 1 1 190px;
  max-width: 230px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 16px 12px 14px;
  background: var(--surface);
  border: 4px solid #000;
  box-shadow: inset 3px 3px 0 0 rgba(110, 195, 255, 0.35), inset -3px -3px 0 0 var(--bevel-dark);
  cursor: pointer;
  color: var(--text);
  transition: transform 0.15s ease;
}
.bestiary-game-tile:hover {
  transform: translateY(-2px);
}
.bestiary-game-logo-box {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 96px;
  width: 100%;
}
.bestiary-game-logo {
  max-width: 100%;
  max-height: 96px;
  image-rendering: pixelated;
  object-fit: contain;
  /* the game logos are drawn on solid black; "screen" lets the dark tile show through instead of a black box */
  mix-blend-mode: screen;
}
/* the Boss tile uses the small 72x32 BOSS mode button: show it at 2x so it matches the logos' size */
.bestiary-game-logo.boss {
  mix-blend-mode: normal; /* the button's black inside its outline is part of the art - keep it */
  height: 64px;
  width: auto;
  max-width: none;
}
.bestiary-game-name {
  font-family: var(--pixel-font);
  font-size: 20px;
  color: var(--text);
}
/* a loaded logo already names the game (a tile whose logo is missing keeps its text) */
.bestiary-game-tile.has-logo .bestiary-game-name {
  display: none;
}
.bestiary-game-tile:hover .bestiary-game-name {
  color: var(--accent-strong);
}
.bestiary-game-progress {
  font-family: var(--mono-font);
  font-size: 15px;
  font-weight: 700;
  color: var(--good);
}
.bestiary-game-tile.complete .bestiary-game-progress {
  color: #ffd45c;
}
.bestiary-bar {
  width: 100%;
  height: 8px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid var(--border);
}
.bestiary-bar-fill {
  display: block;
  height: 100%;
  background: var(--good);
}
.bestiary-game-tile.complete .bestiary-bar-fill {
  background: #ffd45c;
}

/* a game's page */
.bestiary-gamebar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
  margin-bottom: 14px;
}
.bestiary-back,
.bestiary-filter-btn {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 12px;
  font-size: 12px;
  cursor: pointer;
}
.bestiary-back:hover,
.bestiary-filter-btn:hover {
  border-color: var(--accent);
}
.bestiary-filter-btn.active {
  border-color: var(--accent);
  background: rgba(110, 195, 255, 0.12);
  color: var(--accent-strong);
}
.bestiary-game-title {
  margin: 0;
  font-family: var(--pixel-font);
  font-size: 26px;
  color: #fff;
}
/* a game's page: its logo instead of its name (bestiary.js) */
.bestiary-title-logo {
  display: block;
  height: 120px; /* the logos have a lot of black space around them (256x175), so they need the height to read */
  max-width: 100%;
  image-rendering: pixelated;
  object-fit: contain;
  mix-blend-mode: screen; /* drawn on solid black, like the tiles */
}
.bestiary-title-logo.boss {
  mix-blend-mode: normal;
  height: 48px;
  max-width: none;
}
.bestiary-game-count {
  font-family: var(--mono-font);
  font-size: 13px;
  color: var(--good);
}
.bestiary-filter {
  display: flex;
  gap: 6px;
  margin-left: auto;
}
.bestiary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
}
.bestiary-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 10px 8px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  text-align: center;
}
.bestiary-card.found {
  border-color: #ffd45c;
}
.bestiary-sprite-box {
  height: 88px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.bestiary-sprite {
  image-rendering: pixelated;
  max-width: 100%;
}
/* not found yet: the normal sprite, dimmed so it reads as "still to find" */
.bestiary-card.missing .bestiary-sprite {
  filter: grayscale(0.85) brightness(0.55);
}
.bestiary-name {
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}
/* Bosses page: the bosses' real sprites are big (up to 256 wide), so the cards and their picture boxes are big too */
.bestiary-grid.boss-grid {
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 16px;
}
.bestiary-card.boss .bestiary-sprite-box {
  height: 248px;
}
.bestiary-card.boss .bestiary-sprite {
  max-width: none;
}
.bestiary-game-tag {
  font-family: var(--mono-font);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}
.bestiary-meta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  font-size: 11px;
}
.bestiary-meta.dim {
  color: var(--text-dim);
}
/* flipped back to the normal sprite: the badge says NORMAL, in a neutral colour instead of shiny gold */
.bestiary-star.normal {
  color: var(--text-dim);
}
.bestiary-star {
  font-family: var(--mono-font);
  font-weight: 700;
  color: #ffd45c;
  letter-spacing: 0.04em;
}
.bestiary-detail {
  color: var(--text-dim);
}
.bestiary-flip {
  margin-top: 2px;
  padding: 4px 10px;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--accent);
  font-size: 11px;
  cursor: pointer;
}
.bestiary-flip:hover {
  border-color: var(--accent);
  color: var(--accent-strong);
}

/* Characters tab, Modes view: the Arena/Stage/Boss tabs are match data tracked since the 5.0 release - said in gold
   right next to the tabs (hidden in the Characters/ALL view, see setCharactersView in app.js). */
.modes-since-label {
  align-self: center;
  margin-left: 10px;
  font-family: var(--pixel-font);
  font-size: 0.8rem;
  opacity: 0.85;
  font-weight: 400;
  color: #ffd45c;
  letter-spacing: 0.02em;
}

/* Characters/ALL view: the Lifetime block (save files) and the Since 5.0 block (tracked matches) each get a title. */
.char-results-section-title {
  margin: 12px 0 6px;
  font-family: var(--pixel-font);
  font-weight: 400;
  font-size: 1.05rem;
  color: var(--accent-strong);
}
.char-results-section-title.since {
  margin-top: 18px;
  color: #ffd45c;
}
.char-results-section-note {
  margin-left: 6px;
  font-family: var(--mono-font); /* small text stays in the body font */
  font-weight: 400;
  font-size: 0.8rem;
  opacity: 0.7;
}
.char-results-none {
  opacity: 0.75;
}

/* Leaderboards: a saved best from a save file (no known date) and the OG/EX/OG-EX part of a Stage Mode run. */
.saved-best-tag {
  color: var(--text);
  font-size: 0.85em;
  cursor: help;
}
.run-leg-tag {
  margin-left: 6px;
  padding: 0 5px;
  border: 1px solid var(--accent);
  border-radius: 4px;
  font-size: 0.75em;
  color: var(--accent);
}

/* ---------- Minigames (js/minigames.js) ---------- */
/* the menu: big centered tiles, each a solid box holding the in-game preview with the menu button art underneath */
.minigame-menu {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 28px;
  max-width: 1500px;
  margin: 8px auto 0;
}
.minigame-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  transition: transform 0.15s ease;
}
.minigame-tile:hover {
  transform: translateY(-3px);
}
.minigame-preview-box {
  display: block;
  width: 245px; /* the 163x224 preview at 1.5x */
  height: 336px;
  background: #000;
  border: 4px solid #000;
  box-shadow: 0 0 0 2px var(--border), inset 3px 3px 0 0 rgba(110, 195, 255, 0.35);
  overflow: hidden;
}
.minigame-tile:hover .minigame-preview-box {
  box-shadow: 0 0 0 2px var(--accent), inset 3px 3px 0 0 rgba(110, 195, 255, 0.35);
}
.minigame-preview {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  image-rendering: pixelated;
}
.minigame-button-art {
  width: 192px; /* the 96x32 menu button at 2x */
  height: 64px;
  image-rendering: pixelated;
}
/* a minigame's page */
.minigame-view-button {
  width: 144px;
  height: 48px;
  image-rendering: pixelated;
}
.minigame-table .minigame-result {
  font-weight: 700;
  color: #ffd45c;
}
.minigame-no-char {
  opacity: 0.7;
  cursor: help;
}
/* All-Star ranking: rows open a popup of head icons, one per character cleared with */
.minigame-allstar-row {
  cursor: pointer;
}
.minigame-allstar-icons {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.minigame-allstar-icons .head-icon {
  cursor: help;
}

/* minigame page: the Elevator / All-Star tabs sit next to the minigame's button (not pushed to the far right like the
   bestiary filter), with the "Include losses" box after them */
.bestiary-filter.minigame-tabs {
  margin-left: 0;
}
.minigame-losses {
  margin: 0;
  font-size: 13px;
}
.minigame-loss-tag {
  margin-left: 6px;
  padding: 0 5px;
  border: 1px solid var(--bad, #ff6b6b);
  border-radius: 4px;
  font-size: 0.75em;
  font-weight: 400;
  color: var(--bad, #ff6b6b);
}

/* ---------- profile pictures (js/pfp.js): a head icon in front of a username ---------- */
.pfp {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 26px;
  margin-right: 6px;
  vertical-align: middle;
}
.pfp canvas {
  height: 26px;
  width: auto;
  image-rendering: pixelated;
}
.pfp.pfp-missing {
  display: none;
}
/* Home page Top Players / Shiny Hunter boxes: big */
.home-top-player-who {
  display: flex;
  align-items: center;
  gap: 10px;
}
.home-top-player-who .home-top-player-name {
  flex: 1 1 auto;
  min-width: 0; /* lets the name be measured against the space left beside the profile picture */
}
.pfp.pfp-large {
  width: 56px; /* fixed: the name beside it is sized to fit before the picture has loaded */
  flex: 0 0 56px;
  height: 52px;
  margin-right: 0;
}
.pfp.pfp-large canvas {
  height: 52px;
}

/* ---------- pixel checkboxes (every checkbox on the site) ----------
   Same hard-edged bevel as the buttons: a sunken square, filled with the accent when ticked. */
input[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin: 0;
  border: 2px solid #000;
  border-radius: 0;
  background: var(--bg);
  box-shadow: inset 2px 2px 0 0 var(--bevel-dark), inset -2px -2px 0 0 rgba(110, 195, 255, 0.35);
  cursor: pointer;
  vertical-align: middle;
  image-rendering: pixelated;
}
input[type="checkbox"]:checked {
  background-color: var(--accent);
  box-shadow: inset 2px 2px 0 0 var(--bevel-dark);
}
input[type="checkbox"]:hover {
  filter: brightness(1.2);
}
input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
input[type="checkbox"]:disabled {
  opacity: 0.5;
  cursor: default;
}

/* since-5.0 marker (since50DotHTML in app.js): a small square gold pixel next to a table/card title */
.since50-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: 8px;
  vertical-align: middle;
  background: #ffd45c;
  box-shadow: 0 0 0 2px #000;
  cursor: help;
}

/* Shiny Bestiary: TOTAL SHINIES under the game tiles */
.bestiary-total {
  margin-top: 24px;
  text-align: center;
  font-family: var(--pixel-font);
  font-size: 20px;
  color: var(--text);
}
.bestiary-total-value {
  color: #ffd45c;
}

/* Shiny Bestiary cards: the sprite always sits BEHIND the card text. A big sprite can spill past its box, and a
   dimmed (filtered) "not found" sprite would otherwise paint on top of the name and counts. */
.bestiary-card {
  position: relative;
}
.bestiary-card .bestiary-sprite-box {
  position: relative;
  z-index: 0;
}
.bestiary-card > :not(.bestiary-sprite-box) {
  position: relative;
  z-index: 1;
}

/* ---------- pixel look for the remaining buttons and tabs ----------
   The same hard-edged bevel as .mode-button (see the bevel block above): the top navigation tabs, the "<- All games" /
   "<- All minigames" back buttons, All / Found / Missing, "Show normal", the dropdown triggers (Character / Stage) and
   the developer tier switch. Placed last so it wins over each one's older flat style. */
.tab-button,
.bestiary-back,
.bestiary-filter-btn,
.bestiary-flip,
.char-picker-trigger,
.debug-tier-btn {
  border: 4px solid #000;
  border-radius: 0;
  box-shadow: inset 3px 3px 0 0 var(--accent), inset -3px -3px 0 0 var(--bevel-dark);
  transition: filter 0.08s, transform 0.08s;
}
.tab-button,
.bestiary-back,
.bestiary-filter-btn,
.bestiary-flip {
  background: var(--surface);
}
.tab-button:hover,
.bestiary-back:hover,
.bestiary-filter-btn:hover,
.bestiary-flip:hover,
.char-picker-trigger:hover,
.debug-tier-btn:hover {
  filter: brightness(1.2);
  border-color: #000;
}
.tab-button:active,
.bestiary-back:active,
.bestiary-filter-btn:active,
.bestiary-flip:active,
.char-picker-trigger:active,
.debug-tier-btn:active {
  box-shadow: inset 3px 3px 0 0 var(--bevel-dark), inset -3px -3px 0 0 var(--accent);
  transform: translate(1px, 1px);
}
/* selected = pressed in, like the other button groups */
.tab-button.active,
.bestiary-filter-btn.active,
.debug-tier-btn.active {
  border-color: #000;
  box-shadow: inset 3px 3px 0 0 var(--bevel-dark), inset -3px -3px 0 0 var(--accent);
}
.tab-button.active {
  color: var(--accent);
}
/* the nav tabs sit on the bar's bottom edge as a row of buttons */
.tabs {
  gap: 6px;
  padding-bottom: 8px;
}
.tab-button {
  padding: 8px 14px;
}
/* the developer tier switch keeps its orange */
.debug-tier-btn {
  box-shadow: inset 3px 3px 0 0 #e6a23c, inset -3px -3px 0 0 var(--bevel-dark);
}
.debug-tier-btn.active {
  box-shadow: inset 3px 3px 0 0 var(--bevel-dark), inset -3px -3px 0 0 #e6a23c;
}

/* About Us: kept as the plain text tab (underline when open), at the far right of the nav bar */
.tab-button[data-tab="about"] {
  order: 99;
  margin-left: auto;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  box-shadow: none;
  padding: 10px 16px;
  filter: none;
  transform: none;
}
.tab-button[data-tab="about"]:hover {
  color: var(--text);
}
.tab-button[data-tab="about"].active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  box-shadow: none;
}

/* Database tab: the CHARACTER dropdown is a compact trigger, not a full-width bar (the list it opens is its own panel) */
#raw-anchor-character-picker {
  max-width: 320px;
}

/* Header: the ARENA TRACKER logo replaces the small icon + "ArenaTracker" text */
.app-header h1.header-logo-title {
  margin: 0;
  line-height: 0;
}
.header-wordmark-frame {
  display: block;
  position: relative;
  overflow: hidden;
  width: 207px;
  height: 64px;
}
.header-wordmark {
  /* the whole 1080x1080 file, scaled so its logo is 64px tall and shifted so the frame shows only the logo */
  position: absolute;
  width: 234px;
  height: 234px;
  left: -14px;
  top: -78px;
  max-width: none;
}

/* Minigames, multiplayer Elevator: a slot with no known account, and each player's character icon after their name */
.minigame-local-slot {
  color: var(--text-dim);
  font-weight: 600;
  letter-spacing: 0.04em;
}
.minigame-slot-char {
  margin-left: 6px;
}

/* Home Fastest Clears: the profile picture sits in front of the name; each row is a button into All Times */
.home-speedrun-player {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  min-width: 0;
}
.home-speedrun-row {
  cursor: pointer;
}
.home-speedrun-row:hover,
.home-speedrun-row:focus-visible {
  background: rgba(110, 195, 255, 0.1);
  outline: none;
}
/* All Times: the run opened from the Home page */
.alltimes-run-row.run-highlight td {
  background: rgba(255, 212, 92, 0.18);
  box-shadow: inset 0 2px 0 #ffd45c, inset 0 -2px 0 #ffd45c;
}

/* MMRock9 has no bold weight - font-weight 600 made the browser smear a fake bold over these, which is what made them
   look soft. Same sizes as always, just the font's own (normal) weight. */
.home-stats-panel .records-card-title,
.home-speedrun-title,
.home-speedrun-time,
.home-category-title {
  font-weight: normal;
}

/* Home category buttons: 10% bigger than the original (flex-basis 140px / max 236px / padding 14px 10px / name 19px,
   15px on narrower windows). A name that would not fit its button still shrinks to fit (fitHomeCategoryTitles). */
.home-category-btn {
  flex: 1 1 154px;
  max-width: 260px;
  padding: 15px 11px;
}
.home-category-title {
  font-size: 21px;
}
@media (max-width: 1400px) {
  .home-category-title {
    font-size: 17px;
  }
}

/* Trailer mode (js/trailer.js): the "Trailer" button left of About Us, a plain text tab like About Us */
.trailer-clean-btn {
  display: none;
}
body.trailer-mode .trailer-clean-btn {
  display: inline-block;
  order: 98;
  margin-left: auto;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  box-shadow: none;
  padding: 10px 16px;
  filter: none;
  transform: none;
}
body.trailer-mode .trailer-clean-btn:hover {
  color: var(--text);
}
body.trailer-mode .tab-button[data-tab="about"] {
  margin-left: 0; /* the Trailer button already pushes both to the right */
}
/* clean screen for recording: Alpha/Dev-only controls that aren't stats disappear (the button too; press 1 to undo) */
body.trailer-clean .trailer-clean-btn,
body.trailer-clean #debug-tier-toolbar,
body.trailer-clean #filter-debug-row,
body.trailer-clean #filter-beta-row,
body.trailer-clean #filter-alpha-row,
body.trailer-clean #filter-restrict-visibility-row,
body.trailer-clean #discord-tier-badge,
body.trailer-clean #gate-expired-message,
body.trailer-clean #minigame-losses-row,
body.trailer-clean .tab-button[data-tab="chatbot"],
body.trailer-clean .tab-button[data-tab="players"],
body.trailer-clean .tab-button[data-tab="live"],
body.trailer-clean .home-category-btn[data-goto-tab="players"],
body.trailer-clean .home-category-btn[data-goto-tab="live"],
body.trailer-clean .home-category-btn[data-goto-tab="chatbot"] {
  display: none !important;
}

/* clean screen: the Trailer button is hidden, so About Us pushes itself to the right again */
body.trailer-clean .tab-button[data-tab="about"] {
  margin-left: auto;
}

/* Records cards + All Times: the run time itself in MMRock9 - 16px (MMRock9 is only crisp at multiples of 8px) and its
   normal weight (it has no bold); the "(1m 5s 184ms)" after it stays in the main font */
.pixel-time {
  font-family: var(--pixel-font);
  font-size: 16px;
  font-weight: normal;
  letter-spacing: 0;
  vertical-align: middle;
}

/* MMRock9 run times (pixelTimeHTML in app.js): every MMRock9 character is 8 font pixels wide. The colon's ink is x 2-4
   and the period's x 1-3, so they sit in wide empty cells - pulled in here (in whole font pixels = 1/8em, so it stays
   crisp) to leave 1 font pixel each side, the way the game draws "3:13.450". */
.pt-colon {
  margin-left: -0.25em;
  margin-right: -0.375em;
}
.pt-dot {
  margin-left: -0.125em;
  margin-right: -0.5em;
}

/* breathing room between the MMRock9 time and the "(3m 13s 450ms)" after it */
.pixel-time {
  margin-right: 10px;
}

/* Header: the original logo (logo.png, the file itself unchanged) cut to a circle */
.header-logo-circle {
  display: block;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  object-fit: cover;
}

/* Records cards: the profile picture and name stay on one line; each run row opens that run in All Times */
.records-card-table .records-name-cell {
  white-space: nowrap;
}
.records-card-table .records-name-cell .pfp {
  vertical-align: middle;
  margin-right: 6px;
}
.records-card-table .records-run-row {
  cursor: pointer;
}
.records-card-table .records-run-row:hover td {
  background: rgba(110, 195, 255, 0.08);
}

/* Top Players: the green number in MMRock9 (its normal weight - it has no bold), big and centered under the name.
   24px is a crisp MMRock9 size; a longer value ("1 character cleared") steps down to 16px to fit (fitTopPlayerNames). */
.home-top-player-value {
  display: block;
  width: 100%;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  font-family: var(--pixel-font);
  font-size: 24px;
  font-weight: normal;
  letter-spacing: 0;
  margin-top: 6px;
}
