/* =========================================================
   Arcade Ticketeer - Standardized Component Design System
   Enforces crisp 8-bit/16-bit retro pixel aesthetics.
   ========================================================= */

/* === [SNIPPET: Universal Modal Focus Outline Reset] === */
/* --- Universal Modal Focus Outline Reset (Prevents white click outline bug) --- */
.modal-backdrop,
.modal-dialog,
.modal-dialog:focus,
.modal-dialog:focus-visible,
.modal-dialog:active,
.modal-backdrop:focus,
.modal-backdrop:focus-visible,
.modal-backdrop:active {
  outline: none !important;
}

/* === [SNIPPET: BaseModal Architecture Framework] === */
/* --- BaseModal Architecture Framework --- */
.modal-dialog:not(.fullscreen-dialog) {
  display: flex !important;
  flex-direction: column !important;
  box-sizing: border-box !important;
  position: relative;
  background: var(--pixel-panel, #151126);
  border: 4px solid var(--pixel-black, #000);
  box-shadow: var(--pixel-shadow-xl, 6px 6px 0 #000);
  outline: none !important;
}

.modal-dialog:not(.fullscreen-dialog) .modal-header {
  position: relative !important;
  top: auto !important;
  left: auto !important;
  right: auto !important;
  bottom: auto !important;
  z-index: 10;
  display: flex !important;
  justify-content: space-between !important;
  align-items: center !important;
  width: 100% !important;
  padding: 10px 14px !important;
  border-bottom: 3px solid var(--pixel-black, #000);
  background: #19142e;
  box-sizing: border-box;
  pointer-events: auto !important;
}

.modal-dialog:not(.fullscreen-dialog) .modal-header-title-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
}

.modal-dialog:not(.fullscreen-dialog) .modal-header-title-wrap h2.modal-title,
.modal-dialog:not(.fullscreen-dialog) .modal-title {
  font-family: var(--font-pixel, monospace);
  font-size: 11px;
  font-weight: 700;
  color: var(--pixel-white, #ffffff);
  margin: 0;
  padding: 0;
  line-height: 1.1;
  letter-spacing: 0.5px;
  text-shadow: none !important;
}

.modal-dialog:not(.fullscreen-dialog) .modal-subtitle {
  font-family: var(--font-pixel, monospace);
  font-size: 7.5px;
  color: #8b85ad;
  margin-top: 3px;
  line-height: 1.2;
}

.modal-dialog:not(.fullscreen-dialog) .modal-header-right {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.modal-dialog:not(.fullscreen-dialog) .btn-close {
  width: 28px;
  height: 28px;
  min-width: 28px;
  min-height: 28px;
  font-size: 15px;
  background: var(--pixel-red, #ff2a55);
  border: 2px solid var(--pixel-black, #000);
  box-shadow: 2px 2px 0 var(--pixel-black, #000);
  color: #ffffff;
  font-family: var(--font-pixel, monospace);
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  pointer-events: auto !important;
  outline: none !important;
  padding: 0;
  line-height: 1;
  transition: transform 0.05s ease;
}

.modal-dialog:not(.fullscreen-dialog) .btn-close:active {
  transform: translate(1px, 1px);
  box-shadow: 1px 1px 0 var(--pixel-black, #000);
}

.modal-dialog:not(.fullscreen-dialog) .modal-body {
  width: 100%;
  box-sizing: border-box;
}

/* === [SNIPPET: Standardized Currency Display Tags] === */
/* --- Standardized Currency Display Tags ([SVG ICON] [Amount]) --- */
.currency-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-pixel);
  font-size: 11px;
  font-weight: 700;
  vertical-align: middle;
  line-height: 1;
}

.currency-tag-icon {
  display: inline-block;
  vertical-align: middle;
  image-rendering: pixelated;
  flex-shrink: 0;
}

.currency-icon-wrap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* === [SNIPPET: Mystic Orb Tag] === */
/* Collected Mystic Orbs: [ORB ICON] [text]. The base owns the layout; the variants set only --orb-size / --orb-color. */
.orb-tag {
  --orb-size: 24px;
  --orb-color: #c084fc;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-pixel);
  font-size: 11px;
  line-height: 1;
  vertical-align: middle;
}
.orb-tag-icon {
  width: var(--orb-size);
  height: var(--orb-size);
  flex-shrink: 0;
  image-rendering: pixelated;
  pointer-events: none;
}
.orb-tag-val { color: var(--orb-color); }

.currency-tag.currency-gold_coin .currency-val {
  color: var(--pixel-gold);
}

.currency-tag.currency-ticket .currency-val {
  color: var(--pixel-red);
}

.currency-tag.currency-star_coin .currency-val {
  color: #ffd54f;
}

.currency-tag.currency-diamond .currency-val {
  color: #c084fc;
}

.currency-tag.currency-dollar_bill .currency-val {
  color: #00e676;
}

/* === [SNIPPET: Gamemode Theme Variables Registry] === */
/* --- Gamemode Theme Variables --- */
[data-theme="claw"],
.mode-theme-claw {
  --theme-accent: #00f0ff;
  --theme-accent-alt: #ffcc00;
  --theme-card-border: #3d355e;
  --theme-hover-bg: #292014;
}

[data-theme="coin_flip"],
.mode-theme-coin_flip {
  --theme-accent: #00e676;
  --theme-accent-alt: #059669;
  --theme-card-border: #0d4a2b;
  --theme-hover-bg: #092e1a;
}

[data-theme="plinko"],
.mode-theme-plinko {
  --theme-accent: #ff2252;
  --theme-accent-alt: #d50000;
  --theme-card-border: #52182b;
  --theme-hover-bg: #281836;
}

[data-theme="lab"] {
  --theme-accent: #ff2a85;
  --theme-accent-alt: #ff80ab;
  --theme-card-border: #521d3f;
  --theme-hover-bg: #2b173c;
}

/* The Mint (Coin Flip's secondary Lucky Die shop) - Amber Gold, distinct from Claw Gold (#ffcc00) and
   Cannon Gold (#ffd23f): it reads as "aged banknote gold" rather than a coin/bar metallic yellow. */
[data-theme="coin_mint"],
.mode-theme-coin_mint {
  --theme-accent: #ffc233;
  --theme-accent-alt: #c98a00;
  --theme-card-border: #6b4a00;
  --theme-hover-bg: #2b2008;
}

[data-theme="prestige"] {
  --theme-accent: #c084fc;
  --theme-accent-alt: #9d4edd;
  --theme-card-border: #442468;
  --theme-hover-bg: #291842;
}

/* === [SNIPPET: Sponsored Ad Reward Modal] === */
/* =========================================================
   ADS SYSTEM & SPONSORED REWARD MODAL COMPONENTS
   Search Keyword: ADS_INTEGRATION_HOOK
   ========================================================= */

.ad-tag-badge {
  display: inline-block;
  background: var(--pixel-gold, #ffd54f);
  color: var(--pixel-black, #000);
  font-family: var(--font-pixel);
  font-size: 8px;
  font-weight: 700;
  padding: 2px 5px;
  border: 1px solid var(--pixel-black, #000);
  box-shadow: 1px 1px 0 var(--pixel-black, #000);
  margin-right: 6px;
  vertical-align: middle;
}

.ad-status-pill {
  font-family: var(--font-pixel);
  font-size: 8.5px;
  padding: 3px 6px;
  border: 1px solid var(--pixel-black, #000);
}

.ad-status-pill.ad-status-playing {
  background: #2b1d3d;
  color: #ffaa00;
  border-color: #ffaa00;
}

.ad-status-pill.ad-status-ready {
  background: #112d26;
  color: #00ffaa;
  border-color: #00ffaa;
}


.btn-pixel {
  font-family: var(--font-pixel);
  font-size: 9.5px;
  padding: 8px 14px;
  border: 2px solid var(--pixel-black, #000);
  box-shadow: 2px 2px 0 var(--pixel-black, #000);
  cursor: pointer;
  outline: none !important;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.btn-pixel:focus,
.btn-pixel:focus-visible,
.btn-pixel:active {
  outline: none !important;
}


/* === [SNIPPET: Trial Pre-Flight Briefing Modal] === */
/* =========================================================
   TRIAL PRE-FLIGHT BRIEFING & COOLDOWN MODAL
   ========================================================= */

.trial-confirm-dialog {
  max-width: 440px !important;
  width: 90% !important;
  max-height: 92vh;
  background: #141026 !important;
  border: 4px solid var(--pixel-black, #000) !important;
  box-shadow: 6px 6px 0 var(--pixel-black, #000) !important;
  overflow: hidden;
}

.trial-modal-content {
  padding: 14px 16px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-sizing: border-box;
}

/* The card never grows past the screen: only the HOW TO PLAY area scrolls, the stat tiles and the START / CANCEL buttons stay put */
.trial-confirm-dialog .modal-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.trial-modal-content.ready-view { flex: 1 1 auto; min-height: 0; }
.trial-howto-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-right: 6px;
  scrollbar-width: thin;
  scrollbar-color: var(--px-accent, #ffd23f) #0d0a1a;
  overscroll-behavior: contain;
}
.trial-howto-scroll::-webkit-scrollbar { width: 6px; }
.trial-howto-scroll::-webkit-scrollbar-track { background: #0d0a1a; }
.trial-howto-scroll::-webkit-scrollbar-thumb { background: var(--px-accent, #ffd23f); }

.trial-cd-box {
  background: #1e132b;
  border: 2px solid #ff5577;
  box-shadow: 2px 2px 0 var(--pixel-black, #000);
  padding: 16px;
  text-align: center;
}

.trial-cd-badge {
  font-family: var(--font-pixel);
  font-size: 8px;
  color: #ff5577;
  letter-spacing: 1px;
  margin-bottom: 6px;
}

.trial-cd-timer {
  font-family: var(--font-pixel);
  font-size: 24px;
  color: #ffffff;
  margin-bottom: 8px;
}

.trial-cd-message {
  font-family: var(--font-pixel);
  font-size: 8px;
  color: #b0a8cc;
  line-height: 1.4;
}

.trial-briefing-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.trial-stat-card {
  background: #19162e;
  border: 2px solid var(--pixel-black, #000);
  box-shadow: 2px 2px 0 var(--pixel-black, #000);
  padding: 10px 12px;
}

.trial-stat-card.full-width {
  grid-column: span 2;
}

.stat-card-label {
  font-family: var(--font-pixel);
  font-size: 7.5px;
  color: #7b749e;
  margin-bottom: 5px;
  letter-spacing: 0.5px;
}

.stat-card-val {
  font-family: var(--font-pixel);
  font-size: 9.5px;
  color: #ffffff;
}

.stat-card-val.highlight {
  color: var(--theme-accent, #00f0ff);
}

.stat-card-val.gold {
  color: var(--pixel-gold, #ffd54f);
}

.trial-howto-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.trial-howto-list li {
  font-family: var(--font-pixel);
  font-size: 8px;
  line-height: 1.5;
  color: #e6e1ff;
  padding-left: 12px;
  position: relative;
}

.trial-howto-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 4px;
  width: 5px;
  height: 5px;
  background: var(--theme-accent, #00f0ff);
}

.trial-modal-actions {
  display: flex;
  gap: 10px;
  margin-top: 2px;
}

.btn-trial-ad-skip {
  background: #18283a;
  border-color: #ffd54f;
  color: #ffd54f;
  flex: 1;
}

.btn-ad-tag {
  background: var(--pixel-gold, #ffd54f);
  color: #000;
  padding: 1px 4px;
  font-size: 7.5px;
  font-weight: 700;
}

.btn-trial-start {
  background: var(--theme-accent, #00f0ff);
  color: #000;
  border: 2px solid var(--pixel-black, #000);
  box-shadow: 2px 2px 0 var(--pixel-black, #000);
  flex: 2;
  font-family: var(--font-pixel, monospace);
  font-size: 9.5px;
  font-weight: 700;
  padding: 10px;
  cursor: pointer;
  outline: none !important;
}

.btn-trial-start:active {
  transform: translate(1px, 1px);
  box-shadow: 1px 1px 0 var(--pixel-black, #000);
}

.btn-trial-cancel {
  background: #231f38;
  color: #a49fc4;
  border: 2px solid #3b3459;
  box-shadow: 2px 2px 0 var(--pixel-black, #000);
  flex: 1;
  font-family: var(--font-pixel, monospace);
  font-size: 9.5px;
  font-weight: 700;
  padding: 10px;
  cursor: pointer;
  outline: none !important;
}

.btn-trial-cancel:active {
  transform: translate(1px, 1px);
  box-shadow: 1px 1px 0 var(--pixel-black, #000);
}

/* === [SNIPPET: Plinko Ball Regen Boost Overclock Modal] === */
/* =========================================================
   PLINKO BALL REGEN BOOST OVERCLOCK MODAL & HUD
   ========================================================= */

.plinko-boost-dialog {
  max-width: 460px !important;
  width: 92% !important;
}

.plinko-boost-content {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.boost-status-banner {
  background: #161a2e;
  border: 2px solid var(--pixel-black, #000);
  box-shadow: 2px 2px 0 var(--pixel-black, #000);
  padding: 12px;
  text-align: center;
}

.boost-status-badge {
  font-family: var(--font-pixel);
  font-size: 10px;
  font-weight: 700;
  margin-bottom: 4px;
}

.boost-status-badge.active {
  color: #00ffcc;
}

.boost-status-badge.normal {
  color: #8c86aa;
}

.boost-timer-desc {
  font-family: var(--font-pixel);
  font-size: 8px;
  color: #b3add0;
}

.boost-perks-container {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.boost-perk-card {
  background: #1c1833;
  border: 2px solid var(--pixel-black, #000);
  box-shadow: 2px 2px 0 var(--pixel-black, #000);
  padding: 10px 12px;
}

.perk-label {
  font-family: var(--font-pixel);
  font-size: 8.5px;
  color: #00f0ff;
  margin-bottom: 3px;
  font-weight: 700;
}

.perk-detail {
  font-family: var(--font-pixel);
  font-size: 8px;
  color: #ffffff;
  line-height: 1.3;
}

.perk-detail strong {
  color: var(--pixel-gold, #ffd54f);
}

.boost-modal-actions {
  display: flex;
  gap: 10px;
}

.btn-boost-watch-ad {
  background: #18283a;
  border-color: var(--pixel-gold, #ffd54f);
  color: #ffd54f;
  flex: 1;
}

/* Stays clickable while on cooldown (rather than the native disabled attribute) so pressing it can still shake
   via .btn-denied-shake - see the Standard Denied Button Shake rule */
.btn-boost-watch-ad.ad-on-cooldown {
  background: #1e1b29;
  border-color: #3f3f46;
  color: #71717a;
  cursor: not-allowed;
  opacity: 0.65;
  box-shadow: none;
}

.btn-boost-watch-ad.ad-on-cooldown .btn-ad-tag {
  background: #52525b;
  color: #27272a;
}

.btn-boost-close {
  background: #231f38;
  color: #a49fc4;
  border-color: #3b3459;
}

/* === [SNIPPET: Plinko Ball HUD Interactive Overclock Overlays] === */
/* --- Plinko Ball HUD Overclock Interactive Styling --- */
.plinko-ball-hud {
  cursor: pointer !important;
  pointer-events: auto !important;
  transition: border-color 0.15s ease;
}

.plinko-ball-hud:hover {
  border-color: var(--sb-accent) !important;
}

.plinko-ball-hud.ball-hud-boosted {
  border-color: #ffd54f !important;
}

.plinko-ball-hud-count {
  font-family: var(--font-pixel);
  font-size: 9px;
  font-weight: 700;
  color: var(--pixel-white, #fff);
  margin-left: 8px;
  white-space: nowrap;
}

.plinko-ball-hud.ball-hud-empty .plinko-ball-hud-count {
  color: var(--pixel-red, #ff2252);
}

.plinko-ball-hud-boost {
  background: #ffd54f;
  color: #000;
  font-family: var(--font-pixel);
  font-size: 7px;
  font-weight: 700;
  padding: 1px 4px;
  border: 1px solid #000;
  margin-left: 4px;
  vertical-align: middle;
}

/* === [SNIPPET: Plinko Empty Ball Blink] === */
/* Restarted from JS on every tap / hold repeat while no balls are left */
.plinko-ball-hud.ball-hud-blink {
  animation: ballHudBlink 0.35s steps(2, end) 1;
}

@keyframes ballHudBlink {
  0% {
    border-color: var(--pixel-red, #ff2252);
    background: #5a1020;
  }
  100% {
    border-color: var(--pixel-red, #ff2252);
  }
}

/* === [SNIPPET: Ticket Factory Attention Pulse] === */
/* Blue Ticket blue beacon on the Ticket Factory button until it is opened once */
.btn-sidebar-shop.factory-attention-pulse {
  /* Token-only: the shared beacon (style.css, Shop Unlock Attention Pulse Animation) draws the pulse */
  --beacon-border: #5c9dff;
  --beacon-rest: 0 0 4px rgba(92, 157, 255, 0.35), 2px 2px 0 var(--pixel-black);
  --beacon-glow: 0 0 14px rgba(92, 157, 255, 0.85), 0 0 24px rgba(169, 204, 255, 0.4);
}

/* === [SNIPPET: Onboarding & Objectives Prompts] === */
.onboarding-prompt {
  position: absolute;
  top: calc(var(--playfield-y, 0px) + (var(--playfield-h, 100vh) / 2));
  left: calc(var(--playfield-x, 0px) + (var(--playfield-w, 100vw) / 2));
  transform: translate(-50%, -50%);
  width: max-content;
  max-width: calc(var(--playfield-w, 100vw) * 0.9);
  text-align: center;
  font-family: var(--font-pixel);
  font-size: 13px;
  letter-spacing: 0.5px;
  color: var(--pixel-white);
  text-shadow: 2px 2px 0 var(--pixel-black);
  pointer-events: none;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  opacity: 0;
  animation: promptFadeInOut 4s ease-in-out forwards;
}

.onboarding-prompt .prompt-icon {
  width: 16px;
  height: 16px;
  object-fit: contain;
  image-rendering: pixelated;
  filter: drop-shadow(2px 2px 0 var(--pixel-black));
}

@keyframes promptFadeInOut {
  0% { opacity: 0; transform: translate(-50%, -40%); }
  10% { opacity: 1; transform: translate(-50%, -50%); }
  90% { opacity: 1; transform: translate(-50%, -50%); }
  100% { opacity: 0; transform: translate(-50%, -60%); }
}

/* === [SNIPPET: Retro CRT Scene & Mode Transition Overlay] === */
.scene-transition-overlay {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 99999;
  pointer-events: all;
  user-select: none;
  display: none;
  overflow: hidden;
  --crt-accent: #ffd700;
  --crt-collapse-duration: 0.6s;
  --crt-expand-duration: 0.7s;
}

.scene-transition-overlay.crt-active {
  display: block;
}

/* CRT Backdrop Blur & Dimming Layer */
.crt-backdrop-blur {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
  backdrop-filter: blur(0px);
  -webkit-backdrop-filter: blur(0px);
  background: rgba(7, 5, 15, 0);
  will-change: backdrop-filter, background-color;
}

/* CRT Scanlines Grid across the viewport */
.crt-scanlines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    rgba(18, 16, 26, 0) 50%,
    rgba(0, 0, 0, 0.45) 50%
  );
  background-size: 100% 4px;
  pointer-events: none;
  z-index: 4;
  opacity: 0;
  will-change: opacity;
}

/* Top and Bottom Cathode Shutters */
.crt-shutter-top,
.crt-shutter-bottom {
  position: absolute;
  left: 0;
  right: 0;
  width: 100%;
  height: 50%;
  background: #07050f;
  z-index: 2;
  will-change: transform;
}

.crt-shutter-top {
  top: 0;
  transform-origin: top center;
  transform: translateY(-100%);
  border-bottom: 2px solid var(--crt-accent, #ffd700);
  box-shadow: 0 4px 0 rgba(0, 0, 0, 0.6);
}

.crt-shutter-bottom {
  bottom: 0;
  transform-origin: bottom center;
  transform: translateY(100%);
  border-top: 2px solid var(--crt-accent, #ffd700);
  box-shadow: 0 -4px 0 rgba(0, 0, 0, 0.6);
}

/* Central CRT Razor-Sharp Laser Beam */
.crt-beam-slit {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(50% - 2px);
  width: 100%;
  height: 4px;
  background: #ffffff;
  border-top: 2px solid var(--crt-accent, #ffd700);
  border-bottom: 2px solid var(--crt-accent, #ffd700);
  z-index: 3;
  opacity: 0;
  will-change: transform, opacity;
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.7);
}

/* Collapse Phase Animations */
.scene-transition-overlay.crt-collapsing .crt-backdrop-blur {
  animation: crtBackdropBlurIn var(--crt-collapse-duration, 1.5s) ease-out forwards;
}

.scene-transition-overlay.crt-collapsing .crt-scanlines {
  animation: crtScanlinesFadeIn var(--crt-collapse-duration, 1.5s) ease-out forwards;
}

.scene-transition-overlay.crt-collapsing .crt-shutter-top {
  animation: crtShutterCollapseTop var(--crt-collapse-duration, 1.5s) cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

.scene-transition-overlay.crt-collapsing .crt-shutter-bottom {
  animation: crtShutterCollapseBottom var(--crt-collapse-duration, 1.5s) cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

.scene-transition-overlay.crt-collapsing .crt-beam-slit {
  animation: crtBeamIgnite var(--crt-collapse-duration, 1.5s) ease-in forwards;
}

/* Expand Phase Animations */
.scene-transition-overlay.crt-expanding .crt-backdrop-blur {
  animation: crtBackdropBlurOut var(--crt-expand-duration, 1.7s) ease-in forwards;
}

.scene-transition-overlay.crt-expanding .crt-scanlines {
  animation: crtScanlinesFadeOut var(--crt-expand-duration, 1.7s) ease-in forwards;
}

.scene-transition-overlay.crt-expanding .crt-shutter-top {
  animation: crtShutterExpandTop var(--crt-expand-duration, 1.7s) cubic-bezier(0.15, 0.85, 0.35, 1) forwards;
}

.scene-transition-overlay.crt-expanding .crt-shutter-bottom {
  animation: crtShutterExpandBottom var(--crt-expand-duration, 1.7s) cubic-bezier(0.15, 0.85, 0.35, 1) forwards;
}

.scene-transition-overlay.crt-expanding .crt-beam-slit {
  animation: crtBeamDischarge var(--crt-expand-duration, 1.7s) ease-out forwards;
}

@keyframes crtBackdropBlurIn {
  0% {
    backdrop-filter: blur(0px);
    -webkit-backdrop-filter: blur(0px);
    background: rgba(7, 5, 15, 0);
  }
  100% {
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    background: rgba(7, 5, 15, 0.45);
  }
}

@keyframes crtBackdropBlurOut {
  0% {
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    background: rgba(7, 5, 15, 0.45);
  }
  100% {
    backdrop-filter: blur(0px);
    -webkit-backdrop-filter: blur(0px);
    background: rgba(7, 5, 15, 0);
  }
}

@keyframes crtScanlinesFadeIn {
  0% { opacity: 0; }
  100% { opacity: 0.85; }
}

@keyframes crtScanlinesFadeOut {
  0% { opacity: 0.85; }
  100% { opacity: 0.85; }
  100% { opacity: 0; }
}

@keyframes crtShutterCollapseTop {
  0% { transform: translateY(-100%); }
  100% { transform: translateY(0); }
}

@keyframes crtShutterCollapseBottom {
  0% { transform: translateY(100%); }
  100% { transform: translateY(0); }
}

@keyframes crtShutterExpandTop {
  0% { transform: translateY(0); }
  100% { transform: translateY(-100%); }
}

@keyframes crtShutterExpandBottom {
  0% { transform: translateY(0); }
  100% { transform: translateY(100%); }
}

@keyframes crtBeamIgnite {
  0% { opacity: 0; transform: scaleX(0.2) scaleY(0.5); }
  70% { opacity: 1; transform: scaleX(0.8) scaleY(1.5); }
  100% { opacity: 1; transform: scaleX(1) scaleY(1); }
}

@keyframes crtBeamDischarge {
  0% { opacity: 1; transform: scaleX(1) scaleY(2); }
  40% { opacity: 1; transform: scaleX(1) scaleY(1.2); }
  100% { opacity: 0; transform: scaleX(1.05) scaleY(0.1); }
}


/* === [SNIPPET: Themed Cosmic Background] === */
/* The animated CSS starfield (.cosmic-bg, base look in style.css = Claw cyan) follows the active
   attraction. main.js sets .theme-claw / .theme-plinko / .theme-coin_flip on #gameViewArea.
   Every tile carries the same baked-in 2px blur (see the note above .cosmic-bg in style.css). */
.game-view-area.theme-plinko {
  background-color: #12060c;
}
.game-view-area.theme-plinko .cosmic-bg {
  background-color: #12060c;
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56'%3E%3Cfilter id='b' filterUnits='userSpaceOnUse' x='-16' y='-16' width='88' height='88'%3E%3CfeGaussianBlur stdDeviation='2'/%3E%3C/filter%3E%3Crect width='56' height='56' fill='%2312060c'/%3E%3Cg filter='url(%23b)'%3E%3Cpath d='M-56 -56L112 112M0 -56L112 56M-56 0L56 112' stroke='rgba(255,34,82,0.352)' stroke-width='1.5'/%3E%3Crect x='13' y='42' width='3' height='1' fill='rgba(255,82,120,0.528)'/%3E%3Crect x='14' y='41' width='1' height='3' fill='rgba(255,82,120,0.528)'/%3E%3Crect x='41' y='13' width='2' height='2' fill='rgba(255,204,0,0.484)'/%3E%3C/g%3E%3C/svg%3E");
}
.game-view-area.theme-coin_flip {
  background-color: #05100a;
}
.game-view-area.theme-coin_flip .cosmic-bg {
  background-color: #05100a;
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56'%3E%3Cfilter id='b' filterUnits='userSpaceOnUse' x='-16' y='-16' width='88' height='88'%3E%3CfeGaussianBlur stdDeviation='2'/%3E%3C/filter%3E%3Crect width='56' height='56' fill='%2305100a'/%3E%3Cg filter='url(%23b)'%3E%3Cpath d='M-56 -56L112 112M0 -56L112 56M-56 0L56 112' stroke='rgba(0,230,118,0.33)' stroke-width='1.5'/%3E%3Crect x='13' y='42' width='3' height='1' fill='rgba(0,230,118,0.484)'/%3E%3Crect x='14' y='41' width='1' height='3' fill='rgba(0,230,118,0.484)'/%3E%3Crect x='41' y='13' width='2' height='2' fill='rgba(178,255,89,0.484)'/%3E%3C/g%3E%3C/svg%3E");
}

/* === [SNIPPET: DOM Floating Text (Crisp Popups)] === */
/* Floating currency / status popups are DOM nodes (not canvas) so they render at native device
   resolution. Created by FloatingText in js/core/vfx.js; the CSS animation owns rise + fade. */
.floating-text-layer {
  z-index: 21; /* above #fgCanvas (20) */
}

.floating-text {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

.floating-text-inner {
  --ft-outline: #262135;
  --ft-o: 0.14em;
  position: absolute;
  top: 0;
  left: 0;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  font-family: var(--font-pixel, "Press Start 2P", monospace);
  font-weight: 700;
  line-height: 1;
  image-rendering: auto;
  /* Flat 8-direction pixel outline (zero blur) */
  text-shadow:
    var(--ft-o) 0 0 var(--ft-outline),
    calc(var(--ft-o) * -1) 0 0 var(--ft-outline),
    0 var(--ft-o) 0 var(--ft-outline),
    0 calc(var(--ft-o) * -1) 0 var(--ft-outline),
    var(--ft-o) var(--ft-o) 0 var(--ft-outline),
    calc(var(--ft-o) * -1) var(--ft-o) 0 var(--ft-outline),
    var(--ft-o) calc(var(--ft-o) * -1) 0 var(--ft-outline),
    calc(var(--ft-o) * -1) calc(var(--ft-o) * -1) 0 var(--ft-outline);
  transform: translate(-50%, -50%);
  animation: floatingTextRise 1s linear forwards;
}

.floating-text-inner.has-icon {
  --ft-outline: #000000;
}

.floating-text-icon {
  display: block;
  flex: none;
  image-rendering: pixelated;
}

@keyframes floatingTextRise {
  0%   { transform: translate(-50%, -50%); opacity: 1; }
  100% { transform: translate(-50%, calc(-50% - var(--ft-rise, 50px))); opacity: 0; }
}

/* Stationary text bump (FloatingText.pop): the Coin Flip streak counter pops when the streak goes up */
@keyframes floatingTextPop {
  0%   { transform: translate(-50%, -50%) scale(1); }
  40%  { transform: translate(-50%, -50%) scale(1.05); }
  100% { transform: translate(-50%, -50%) scale(1); }
}
/* === [SNIPPET: Cannon Range Attraction Styles] === */
/* Bright Orange (#ff8a00) attraction: theme tokens, cabinet backdrop, Gold Bars card, selector, mode card. */
[data-theme="cannon"],
.mode-theme-cannon {
  --theme-accent: #ff8a00;
  --theme-accent-alt: #ffd23f;
  --theme-card-border: #5a3010;
  --theme-hover-bg: #2a1608;
}

body[data-game-mode="cannon"],
.game-viewport[data-game-mode="cannon"],
.canvas-wrapper[data-game-mode="cannon"],
.game-view-area.theme-cannon,
.game-view-area.theme-cannon .cosmic-bg {
  background-color: #140a02;
}

.game-view-area.theme-cannon .cosmic-bg {
  background-image: none;
}

.currency-tag.currency-gold_bar .currency-val {
  color: #ffd23f;
}

.gold-bar-icon {
  width: 26px !important;
  height: 15px !important;
  min-width: 26px !important;
  min-height: 15px !important;
  max-width: 26px !important;
  max-height: 15px !important;
  background: url("../assets/svg/global/currencies/gold_bar.svg") no-repeat center / contain !important;
  border: none !important;
  display: inline-block !important;
  position: relative;
  flex-shrink: 0 !important;
  flex-grow: 0 !important;
  box-shadow: none !important;
}

.text-orange {
  color: #ff8a00;
}

.stat-card.cannon-gold-card {
  border-color: var(--pixel-black);
}

.btn-sidebar-shop.mode-cannon {
  border-color: var(--pixel-black);
  --btn-bg: #2a1808;
  --btn-hover-bg: #4d2e12;
}

.btn-sidebar-shop.mode-cannon .shop-btn-text {
  color: #ff8a00;
}

.btn-sidebar-shop.mode-cannon:hover {
  border-color: #ff8a00;
}

@media (hover: none) {
  .btn-sidebar-shop.mode-cannon:hover {
    border-color: var(--pixel-black);
  }
}

.btn-game-selector.mode-theme-cannon {
  --selector-accent: #ff8a00;
  --selector-glow: rgba(255, 138, 0, 0.75);
  --selector-glow-outer: rgba(255, 176, 60, 0.45);
  background: #2a1608;
  border-color: #ff8a00;
  color: #ffffff;
  box-shadow: var(--pixel-shadow-sm);
}

.btn-game-selector.mode-theme-cannon:hover {
  background: #3d200b;
  border-color: #ffb347;
  box-shadow: var(--pixel-shadow-md);
}

.btn-game-selector.mode-theme-cannon .selector-dot {
  background: #ff8a00;
  box-shadow: none;
}

#modeBtnCannon .mode-card-art {
  background-color: #1a0d02;
  background-image: repeating-linear-gradient(45deg, transparent, transparent 27px, rgba(255, 138, 0, 0.10) 28px);
}

#modeBtnCannon.mode-card-btn.active {
  background: #2a1608;
  border-color: #ff8a00;
  outline: none;
}

#modeBtnCannon.active .mode-card-art {
  border-color: #ff8a00;
}

#modeBtnCannon.mode-card-btn.active .mode-card-badge {
  background: #ff8a00;
  color: var(--pixel-black);
  border-color: var(--pixel-black);
}

#modeBtnCannon.mode-card-btn:focus,
#modeBtnCannon.mode-card-btn:focus-visible,
#modeBtnCannon.mode-card-btn:active {
  outline: none;
}

#modeBtnCannon.mode-card-btn.mode-card-unlocking {
  border-color: #ff8a00 !important;
}

/* === [SNIPPET: Cannon Range Shop Theme (Skill Tree)] === */
.modal-backdrop.shop-theme-cannon .fullscreen-dialog {
  background: rgb(26, 13, 2);
  border: none;
  box-shadow: none;
}

.modal-backdrop.shop-theme-cannon .tree-viewport {
  background: transparent;
}

/* [SNIPPET: Skill Tree Viewport Canvas] Viewport-sized canvas drawn by js/ui/skill_tree_renderer.js (rings, links, nodes).
   No will-change / transform: pan and zoom are redrawn into it, so it never becomes a huge scaled compositor layer. */
.tree-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

.modal-backdrop.shop-theme-cannon .modal-coin-balance {
  color: #ff8a00;
}

.modal-backdrop.shop-theme-cannon .node-popup-card {
  border-color: #ff8a00;
  outline: 2px solid #ff8a00;
}

/* [SNIPPET: Plinko Bucket DOM Labels] Vector bucket art, posts, nozzles and crisp text in #plinkoEntitiesLayer */
.plinko-buckets {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.plinko-bucket {
  position: absolute;
  box-shadow: 0 4px 0 rgba(0, 0, 0, 0.6); /* flat pixel drop shadow, no blur */
}

.plinko-bucket-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.plinko-bucket-flash {
  position: absolute;
  inset: 2px;
  background: #ffffff;
  opacity: 0;
  pointer-events: none;
}

.plinko-bucket-post {
  position: absolute;
  display: block;
}

/* [SNIPPET: Plinko Ball Canvas] One canvas draws every ball and trail (plinko_ball_layer.js). z-index 4 keeps balls above the
   DOM pegs and buckets (a resume/resize rebuilds those after balls exist) and below the nozzles (z-index 5) */
.plinko-ball-canvas {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 4;
  pointer-events: none;
  image-rendering: pixelated;
}

.plinko-nozzles {
  position: absolute;
  inset: 0;
  z-index: 5; /* above the ball sprites, below the foreground canvas */
  pointer-events: none;
}

.plinko-nozzle {
  position: absolute;
  display: block;
}

.bucket-label {
  --label-color: #ffffff;
  --label-outline: #000000;
  --label-sub-color: #ffffff;
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  overflow: hidden;
  transform-origin: center center;
  outline: none;
  font-family: var(--font-pixel, "Press Start 2P", monospace);
  line-height: 1;
  white-space: nowrap;
}

.bucket-label-text {
  color: var(--label-color);
  /* hard 1px pixel outline (flat, no blur) keeps white text readable on every bucket colour */
  text-shadow: 1px 0 0 var(--label-outline), -1px 0 0 var(--label-outline), 0 1px 0 var(--label-outline), 0 -1px 0 var(--label-outline), 1px 1px 0 var(--label-outline), -1px 1px 0 var(--label-outline), 1px -1px 0 var(--label-outline), -1px -1px 0 var(--label-outline);
}

.bucket-label-sub {
  font-size: 10px;
  color: var(--label-sub-color);
}

/* Trial basket + void hazard variants only swap tokens */
.bucket-label-basket {
  --label-outline: #33000d;
}

.bucket-label-void {
  --label-color: rgba(255, 23, 68, 0.6);
  background: rgba(255, 23, 68, 0.18);
}

.bucket-label-void-text {
  font-size: 10px;
  color: var(--label-color);
}

/* [SNIPPET: Cannon Range DOM Parts] Rotating SVG barrel, static carriage, mini turrets and sight line */
.cannon-part {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0; /* transforms are written as translate -> rotate -> translate by cannon_dom.js */
  pointer-events: none;
  outline: none;
}

.cannon-part svg {
  display: block;
  overflow: visible;
}

/* The carriage and turret bases never move. Their own compositor layer keeps them from being re-rasterized every time
   a barrel, ball or trail repaints, which nudged their crisp-edged pixel rows by one device pixel (a faint flicker). */
.cannon-carriage,
.cannon-turret-base {
  will-change: transform;
}

/* [SNIPPET: Coin Flip DOM Table & Sprites] Vector table under the canvas, DOM coins / shadows / hands / shockwaves above it */
.cf-table-layer {
  z-index: 0; /* above .cosmic-bg, below #gameCanvas (1) */
  background: #030f07;
}

.cf-table-svg {
  display: block;
}

.cf-table-svg rect {
  shape-rendering: crispEdges; /* circles (rivets, rings) stay anti-aliased */
}

.cf-table-svg .cf-stitch {
  stroke: #2ee57a;
  stroke-opacity: 0.35;
}

.cf-table-layer.frenzy .cf-stitch {
  stroke: #00e676;
  stroke-opacity: 1;
}

.cf-layer {
  position: absolute;
  inset: 0;
  isolation: isolate; /* per-coin z-index (depth sort) stays inside this layer */
}

.cf-shockwave {
  position: absolute;
  top: 0;
  left: 0;
  overflow: visible;
}

.cf-coin-shadow,
.cf-coin,
.cf-die-shadow,
.cf-die {
  --coin-tint: transparent;
  --coin-ring: #ffd700;
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: center center;
  outline: none;
}

.cf-coin-shadow {
  border-radius: 50% !important; /* style.css forces border-radius: 0 !important on everything */
  background: #020c06;
}

.cf-coin-face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  image-rendering: pixelated; /* chunky pixel art, sharp at any display scale */
}

.cf-coin-tint,
.cf-coin-ring,
.cf-coin-pulse,
.cf-coin-cross {
  position: absolute;
  inset: 0;
  border-radius: 50% !important; /* round overlays: override the global square-corner reset */
  display: none;
  box-sizing: border-box;
}

.cf-coin-tint {
  background: var(--coin-tint);
}

.cf-coin-ring {
  inset: -4px;
  border: 3px solid var(--coin-ring);
}

.cf-coin-pulse {
  inset: -6px;
  border: 2px dashed #00e676;
}

/* The ring pulse is stepped by JS (coin_flip_hand_flakes.js pulseStep -> data-pulse on .cf-coins, 5 Hz, sequence 0 1 2 2 1 0),
   not an infinite animation per coin (each animated element was its own compositor layer). */
.cf-coins[data-pulse="1"] .cf-coin-pulse,
.cf-coins[data-pulse="4"] .cf-coin-pulse { transform: scale(1.02); }
.cf-coins[data-pulse="2"] .cf-coin-pulse,
.cf-coins[data-pulse="3"] .cf-coin-pulse { transform: scale(1.04); }

.cf-coin-cross::before,
.cf-coin-cross::after {
  content: '';
  position: absolute;
  left: 25%;
  right: 25%;
  top: calc(50% - 2px);
  height: 4px;
  background: #ff3344;
}

.cf-coin-cross::before { transform: rotate(45deg); }
.cf-coin-cross::after { transform: rotate(-45deg); }

.cf-coin.is-dead { --coin-tint: rgba(30, 8, 12, 0.65); }
.cf-coin.is-cooling { --coin-tint: rgba(15, 20, 30, 0.5); }
.cf-coin.is-dead .cf-coin-tint,
.cf-coin.is-cooling .cf-coin-tint,
.cf-coin.is-dead .cf-coin-cross,
.cf-coin.is-jackpot .cf-coin-ring,
.cf-coin.is-live .cf-coin-pulse {
  display: block;
}

/* Lucky Die: its own table object (NOT a coin). The cube is drawn as pixel art into this canvas by
   coin_flip_die.js - CSS 3D transforms were abandoned here because the browser always anti-aliases a
   rotated element's edges, which kills the pixel-art look no matter what image-rendering says. */
.cf-die {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: center center;
  image-rendering: pixelated; /* chunky pixel art, sharp at any display scale */
  outline: none;
}

.cf-die.is-cooling {
  filter: brightness(0.85);
}

.cf-die-shadow {
  position: absolute;
  top: 0;
  left: 0;
  background: #020c06;
  border-radius: 6px !important; /* square with filleted corners matching the Lucky Die */
  transform-origin: center center;
  outline: none;
}

.cf-hand {
  --flake-color: rgba(128, 222, 234, 0.75);
  position: absolute;
  top: 0;
  left: 0;
  width: 36px;
  height: 42px;
  outline: none;
}

.cf-hand-shadow,
.cf-hand-sprite {
  position: absolute;
  width: 36px;
  height: 42px;
  display: block;
  image-rendering: pixelated;
}

.cf-hand-shadow { left: 4px; top: 8px; }
.cf-hand-sprite { left: 0; top: 0; }

.cf-hand-flake {
  position: absolute;
  width: 2px;
  height: 2px;
  background: var(--flake-color);
  display: none; /* drifts in 24 steps per 2.1s, posed by coin_flip_hand_flakes.js (poseFlakes) while the hand is frozen */
}

.cf-hand-flake-a { left: 4px; top: 8px; }
.cf-hand-flake-b { left: 26px; top: 16px; }
.cf-hand.is-frozen .cf-hand-flake { display: block; }

/* [SNIPPET: Mystic Cups DOM Scene] */
.eg-table-layer {
  z-index: 0; /* above .cosmic-bg, below #gameCanvas (1); transparent so the themed backdrop shows around the table */
}

/* (continued)  Pixel table, DOM cups / orbs / header text, pixel START button, themed background */
.game-view-area.theme-endgame .cosmic-bg {
  background-color: #060312;
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56'%3E%3Cfilter id='b' filterUnits='userSpaceOnUse' x='-16' y='-16' width='88' height='88'%3E%3CfeGaussianBlur stdDeviation='2'/%3E%3C/filter%3E%3Crect width='56' height='56' fill='%23060312'/%3E%3Cg filter='url(%23b)'%3E%3Cpath d='M-56 -56L112 112M0 -56L112 56M-56 0L56 112' stroke='rgba(168,85,247,0.308)' stroke-width='1.5'/%3E%3Crect x='13' y='42' width='3' height='1' fill='rgba(192,132,252,0.616)'/%3E%3Crect x='14' y='41' width='1' height='3' fill='rgba(192,132,252,0.616)'/%3E%3Crect x='41' y='13' width='2' height='2' fill='rgba(250,204,21,0.352)'/%3E%3C/g%3E%3C/svg%3E");
}

/* Pixel-art table: 320x180 canvas (endgame_art.js tableCanvas) stretched 4x to the 1280x720 stage */
.eg-table-canvas {
  display: block;
  width: 1280px;
  height: 720px;
  image-rendering: pixelated;
}

.eg-layer {
  position: absolute;
  inset: 0;
  isolation: isolate;
}

.eg-hud {
  position: absolute;
  left: 640px;
  top: 0;
  width: 1100px;
  margin-left: -550px;
  text-align: center;
  font-family: var(--font-pixel, "Press Start 2P", monospace);
  white-space: nowrap;
}

.eg-title {
  position: absolute;
  top: 48px;
  left: 0;
  right: 0;
  font-size: 18px;
  line-height: 24px;
  color: #c084fc;
  text-shadow: 2px 2px 0 #12042a; /* hard pixel drop, no blur */
}

.eg-subtitle {
  position: absolute;
  top: 98px;
  left: 0;
  right: 0;
  font-size: 14px;
  line-height: 24px;
  text-shadow: 2px 2px 0 #12042a;
}

.eg-cup,
.eg-cup-ghost,
.eg-cup-shadow,
.eg-orb {
  position: absolute;
  top: 0;
  left: 0;
  outline: none;
}

.eg-cup,
.eg-cup-ghost {
  width: 104px;
  height: 120px;
}

.eg-cup-face,
.eg-cup-ghost {
  display: block;
  image-rendering: pixelated; /* chunky pixel art, sharp at any display scale */
}

.eg-cup-face {
  width: 100%;
  height: 100%;
}

.eg-cup-shadow {
  width: 84px;
  height: 12px;
  margin-left: -42px;
  margin-top: -6px;
  background: rgba(6, 1, 14, 0.7);
  clip-path: polygon(6px 0, calc(100% - 6px) 0, calc(100% - 6px) 3px, 100% 3px, 100% calc(100% - 3px), calc(100% - 6px) calc(100% - 3px), calc(100% - 6px) 100%, 6px 100%, 6px calc(100% - 3px), 0 calc(100% - 3px), 0 3px, 6px 3px);
}

.eg-cup-select {
  position: absolute;
  inset: -4px;
  border: 3px solid #facc15;
  display: none;
  box-sizing: border-box;
}

.eg-arrow {
  position: absolute;
  left: 50%;
  top: -34px;
  margin-left: -12px;
  display: none;
  animation: egArrowBounce 0.6s steps(4, end) infinite alternate;
}

.eg-cup.is-hover .eg-cup-select,
.eg-cup.is-hover .eg-arrow,
.eg-orb.is-hover .eg-arrow {
  display: block;
}

@keyframes egArrowBounce {
  from { transform: translateY(-6px); }
  to { transform: translateY(6px); }
}

.eg-orb {
  width: 64px;
  height: 64px;
  pointer-events: none;
}

.eg-orb-img {
  display: block;
  width: 100%;
  height: 100%;
  animation: egOrbBreathe 1.3s steps(6, end) infinite alternate;
}

.eg-orb .eg-arrow {
  top: -22px;
}

@keyframes egOrbBreathe {
  from { transform: scale(0.94); }
  to { transform: scale(1.06); }
}

/* START FINAL GAME: base owns geometry, stair-step silhouette and states; hover only swaps tokens */
.eg-start-btn {
  --btn-border: #a855f7;
  --btn-fill: #4c1d95;
  --btn-top: #5b21b6;
  --btn-text: #f5f3ff;
  position: absolute;
  left: 410px;
  top: 590px;
  width: 460px;
  height: 84px;
  padding: 0;
  border: 0;
  cursor: pointer;
  pointer-events: auto;
  font-family: var(--font-pixel, "Press Start 2P", monospace);
  font-size: 20px;
  color: var(--btn-text);
  text-shadow: 2px 2px 0 #12042a;
  background:
    linear-gradient(var(--btn-top), var(--btn-top)) 8px 8px / calc(100% - 16px) 8px no-repeat,
    linear-gradient(var(--btn-fill), var(--btn-fill)) 8px 8px / calc(100% - 16px) calc(100% - 16px) no-repeat,
    var(--btn-border);
  clip-path: polygon(4px 0, calc(100% - 4px) 0, calc(100% - 4px) 4px, 100% 4px, 100% calc(100% - 4px), calc(100% - 4px) calc(100% - 4px), calc(100% - 4px) 100%, 4px 100%, 4px calc(100% - 4px), 0 calc(100% - 4px), 0 4px, 4px 4px);
  filter: drop-shadow(0 6px 0 #12042a); /* flat pixel shadow */
  animation: egStartPulse 0.9s steps(1, end) infinite;
  outline: none;
}

.eg-start-btn:hover {
  --btn-border: #f5f3ff;
  --btn-fill: #7e22ce;
  --btn-top: #9333ea;
  animation: none;
}

.eg-start-btn:active {
  transform: translateY(3px);
}

.eg-start-btn:focus,
.eg-start-btn:focus-visible {
  outline: none;
}

@keyframes egStartPulse {
  0% { --btn-border: #a855f7; }
  50% { --btn-border: #c084fc; }
}

/* [SNIPPET: Cannon Range DOM Scene] Themed backdrop tile, target column, HP bar, balls, trails, reload bar */
.game-view-area.theme-cannon .cosmic-bg {
  background-color: #1a0d02;
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56'%3E%3Cfilter id='b' filterUnits='userSpaceOnUse' x='-16' y='-16' width='88' height='88'%3E%3CfeGaussianBlur stdDeviation='2'/%3E%3C/filter%3E%3Crect width='56' height='56' fill='%231a0d02'/%3E%3Cg filter='url(%23b)'%3E%3Cpath d='M-56 -56L112 112M0 -56L112 56M-56 0L56 112' stroke='rgba(255,138,0,0.264)' stroke-width='1.5'/%3E%3Crect x='13' y='42' width='3' height='1' fill='rgba(255,210,63,0.44)'/%3E%3Crect x='14' y='41' width='1' height='3' fill='rgba(255,210,63,0.44)'/%3E%3C/g%3E%3C/svg%3E");
}

.cn-target {
  display: block;
  image-rendering: pixelated; /* the column is coarse pixel art, sharp at any display scale */
}

.cn-payout {
  --payout-color: #ffd23f;
  --payout-boost-color: #ff2252;
  width: 240px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  font-family: var(--font-pixel, monospace);
  font-size: 22px;
  pointer-events: none;
  transform-origin: 50% 0;
}

.cn-payout-row {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--payout-color);
  text-shadow: 2px 2px 0 #000000; /* flat pixel drop, no blur */
}

.cn-payout-row.is-boosted {
  --payout-color: var(--payout-boost-color);
}

.cn-payout-icon {
  width: 28px;
  height: 16px;
}

.cn-hp {
  --hp-color: #ffd23f;
  --hp-ghost-color: #ff2252;
  width: 18px;
  padding: 3px;
  box-sizing: border-box;
  background: #000000;
}

.cn-hp-track {
  position: relative;
  width: 12px;
  background: #2b1a08;
}

.cn-hp-ghost {
  position: absolute;
  inset: 0;
  background: var(--hp-ghost-color, #fff3b0);
  transform-origin: bottom center;
}

.cn-hp-fill {
  position: absolute;
  inset: 0;
  background: var(--hp-color);
  transform-origin: bottom center;
}

.cn-reload {
  width: 64px;
  height: 10px;
  background: #000000;
}

.cn-reload-fill {
  position: absolute;
  left: 2px;
  top: 2px;
  width: 60px;
  height: 6px;
  background: #ff8a00;
  transform-origin: left center;
}

.eg-lock {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  pointer-events: none;
  outline: none;
}

.eg-shard {
  position: absolute;
  top: 0;
  left: 0;
}

/* [SNIPPET: Claw & Plinko Chamber Layers] Vector cabinet frame / base / grid under the canvas */
.chamber-layer {
  z-index: 0; /* above .cosmic-bg, below #gameCanvas (1); the SVG draws its own opaque base */
}

.chamber-svg {
  display: block;
  overflow: visible;
}

/* === [SNIPPET: Blue Ticket Icon & Sidebar Card] === */
/* Plinko Ticket Factory currency: pixel-art blue ticket, same size as the red one */
.blue-ticket-icon {
  width: 26px;
  height: 18px;
  min-width: 26px;
  min-height: 18px;
  background: url("../assets/svg/global/currencies/ticket_blue.svg") no-repeat center / contain;
  image-rendering: pixelated;
  display: inline-block;
  flex-shrink: 0;
}

.text-blue {
  color: #5c9dff !important;
}

.stat-card.blue-ticket-card {
  border-color: var(--pixel-black);
}

/* === [SNIPPET: Ticket Factory Modal] === */
/* Plinko accent (#ff2252) for the frame, trade buttons and upgrade cards; the Blue Ticket keeps its own blue */
.factory-dialog {
  --factory-accent: #ff2252;
  width: min(720px, 94vw);
  max-height: 90vh;
}

.factory-dialog .modal-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px;
  overflow-y: auto;
  scrollbar-width: none;
}

.factory-dialog .modal-body::-webkit-scrollbar {
  display: none;
}

.factory-balance {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: #0d1424;
  border: 2px solid var(--pixel-black);
  outline: 1px solid #2b4a8a;
  font-family: var(--font-pixel);
  font-size: 13px;
  color: #5c9dff;
}

.factory-exchange {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 14px;
  padding: 10px 12px;
  background: #170a10;
  border: 2px solid var(--pixel-black);
  outline: 1px solid var(--factory-accent);
}

.factory-rate,
.factory-have {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-pixel);
  font-size: 12px;
  color: #fff;
}

.factory-rate-eq {
  color: #9d8db3;
}

.factory-have {
  color: var(--pixel-red);
}

.btn-factory-trade {
  font-family: var(--font-pixel);
  font-size: 10px;
  color: #fff;
  background: #2a0e18;
  border: 2px solid var(--factory-accent);
  padding: 8px 10px;
  cursor: pointer;
  outline: none;
  box-shadow: 2px 2px 0 var(--pixel-black);
}

.btn-factory-trade:hover:not(:disabled) {
  background: var(--factory-accent);
}

.btn-factory-trade:focus,
.btn-factory-trade:focus-visible,
.btn-factory-trade:active {
  outline: none;
}

.btn-factory-trade:active:not(:disabled) {
  transform: translate(2px, 2px);
  box-shadow: none;
}

.btn-factory-trade:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.factory-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.factory-item .powerup-icon-art svg {
  width: 32px;
  height: 32px;
  color: var(--item-color, var(--factory-accent));
}

.btn-factory-buy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.factory-btn-icon {
  width: 18px;
  height: 12px;
  min-width: 18px;
  min-height: 12px;
}

/* === [SNIPPET: Convert Tickets Popup] === */
/* Dedicated red-to-blue trade popup opened from the Ticket Factory (reuses .factory-dialog + .btn-factory-trade) */
/* The popup's own backdrop is see-through so the Ticket Factory stays visible behind it */
#convertTicketsModal {
  background: rgba(8, 6, 14, 0.6);
}

.convert-dialog {
  width: min(460px, 94vw);
}

.convert-dialog .modal-body {
  gap: 14px;
}

.convert-rate {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-pixel);
  font-size: 14px;
  color: #fff;
}

.convert-balances {
  display: flex;
  gap: 10px;
}

.convert-balance {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background: #0d0a14;
  border: 2px solid var(--pixel-black);
  font-family: var(--font-pixel);
  font-size: 12px;
}

.convert-balance-red {
  color: var(--pixel-red);
  outline: 1px solid var(--factory-accent);
}

.convert-balance-blue {
  color: #5c9dff;
  outline: 1px solid #2b4a8a;
}

.convert-chips {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
}

.convert-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 6px 0;
  font-family: var(--font-pixel);
  font-size: 13px;
}

.convert-preview-side {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.convert-pay {
  color: var(--pixel-red);
}

.convert-get {
  color: #5c9dff;
}

.btn-convert-confirm {
  width: 100%;
  padding: 12px;
  font-size: 12px;
}

/* Respec cooldown popup: reuses the challenge cooldown popup, themed with the attraction accent (--respec-accent set by JS) */
.respec-confirm-dialog .trial-cd-box { border-color: var(--respec-accent, #c084fc); }
.respec-confirm-dialog .trial-cd-badge { color: var(--respec-accent, #c084fc); }
.respec-confirm-dialog .btn-trial-ad-skip { border-color: var(--respec-accent, #ffd54f); }
/* Small (non full-screen) popups: semi-transparent darkened outer background so the screen behind shows through dimmed; still blocks clicks */
.modal-backdrop.popup-backdrop { background: rgba(8, 6, 14, 0.6); }

/* These popups open on top of the Mystic Shop (z-index 99998); the default .modal-backdrop z-index of 1000 left them hidden behind it */
#respecConfirmModal,
#respecCooldownModal { z-index: 99999; }
/* Update Available popup: opens over the title screen (z-index 12000), same size as the other small popups */
#updateAvailableModal { z-index: 13000; }
.update-available-dialog { max-width: 300px; }
/* Demo Complete popup (web demo only, js/ui/demo_complete_modal.js): same small popup, a little wider for the feature list */
#demoCompleteModal { z-index: 13000; }
.demo-complete-dialog { max-width: 340px; }
.respec-small-dialog { max-width: 300px; }
.respec-small-dialog .trial-cd-message .diamond-icon { display: inline-block; vertical-align: middle; }

/* === [SNIPPET: Standard Denied Button Shake] === */
/* Universal "denied" press feedback: any button that's unaffordable or on cooldown shakes when pressed, instead
   of doing nothing or only showing a separate popup/toast. Toggled via js/ui/floating_hint.js:shakeDeniedButton().
   Token-only: works on top of whatever base/disabled styling the button already has (.btn-cannot-afford,
   .respec-empty, .respec-unaffordable, etc.) - it only adds the shake motion. */
.btn-denied-shake {
  animation: btnDeniedShake 0.35s ease;
}

@keyframes btnDeniedShake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-3.2px); }
  40% { transform: translateX(3.2px); }
  60% { transform: translateX(-2.4px); }
  80% { transform: translateX(2.4px); }
}

/* Floating hint (js/ui/floating_hint.js): screen-anchored text that rises above open modals */
.floating-text.floating-hint {
  position: fixed;
  z-index: 1000000; /* above every modal (Mystic Shop is 99998, the highest full-screen overlay is 999999) */
}

/* === [SNIPPET: Currency Card Income Rate] === */
/* "N/s" earning rate, at the right end of the card's rate row, under the currency value (js/core/income_rate.js ->
   js/ui/sidebar_meters.js). Always 3 significant figures, no "+". Color comes from the currency's own text-* class
   (text-gold, text-red, ...) so it matches the amount. Slot width: [SNIPPET: Sidebar Segmented Meter & Rate Row] */
.stat-rate {
  font-family: var(--font-pixel-sub);
  font-size: 10px;
  line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
}

/* === [SNIPPET: Prestige Milestone Progress Bar] === */
/* Inside the Prestige card, below the diamond counter: the shared 10-segment .sidebar-meter on the left (purple,
   js/ui/prestige_progress.js), "+N [unclaimed diamond icon]" centered in the same fixed-width slot as the rate labels */
.sidebar-currencies .stat-card.prestige-card,
.stat-card.prestige-card { height: 52px; }

.prestige-progress {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  margin-top: 4px;
}

.prestige-progress .sidebar-meter {
  flex: 1;
}

.prestige-progress-label {
  font-family: var(--font-pixel-sub);
  font-size: 10px;
  line-height: 1;
  color: #c084fc;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
}

.prestige-progress .prestige-progress-label {
  flex: 0 0 var(--sb-rate-w, 44px);
}

/* === [SNIPPET: Ticket Factory Translucent Backdrop] === */
/* The dim area around the Ticket Factory is see-through so the Plinko board shows behind it (base .modal-backdrop is opaque) */
#ticketFactoryModal.modal-backdrop {
  background: rgba(8, 6, 14, 0.72);
}

/* === [SNIPPET: Sidebar Stat Card Larger Currency Icons] === */
/* Enlarges each currency icon inside a sidebar stat card. Scoped to .stat-card so the shared
   base icon classes (also reused by currency tags, the Mystic Shop, etc.) keep their normal size elsewhere. */
.stat-card .stat-body .coin-icon,
.stat-card .stat-body .star-coin-icon,
.stat-card .stat-body .diamond-icon {
  width: 28px;
  height: 28px;
  min-width: 28px;
  min-height: 28px;
}

.stat-card .stat-body .ticket-icon.red-ticket-icon,
.stat-card .stat-body .blue-ticket-icon {
  width: 32px !important;
  height: 22px !important;
  min-width: 32px !important;
  min-height: 22px !important;
  max-width: 32px !important;
  max-height: 22px !important;
}

.stat-card .stat-body .dollar-bill-icon {
  width: 32px !important;
  height: 20px !important;
  min-width: 32px !important;
  min-height: 20px !important;
  max-width: 32px !important;
  max-height: 20px !important;
}

.stat-card .stat-body .gold-bar-icon {
  width: 32px !important;
  height: 18px !important;
  min-width: 32px !important;
  min-height: 18px !important;
  max-width: 32px !important;
  max-height: 18px !important;
}

.stat-card .stat-body .yellow-bill-icon {
  width: 32px !important;
  height: 20px !important;
  min-width: 32px !important;
  min-height: 20px !important;
  max-width: 32px !important;
  max-height: 20px !important;
}

/* === [SNIPPET: Yellow Bill Icon & The Mint Sidebar Card] === */
/* Coin Flip's Mint currency: pixel-art amber bill, same footprint as the Dollar Bill icon */
.yellow-bill-icon {
  width: 26px;
  height: 16px;
  min-width: 26px;
  min-height: 16px;
  background: url("../assets/svg/global/currencies/yellow_bill.svg") no-repeat center / contain;
  image-rendering: pixelated;
  display: inline-block;
  flex-shrink: 0;
}

.text-mint-amber {
  color: #ffc233 !important;
}

.stat-card.yellow-bill-card {
  border-color: var(--pixel-black);
}

.stat-card.yellow-bill-card .stat-body {
  justify-content: space-between;
}

.btn-sidebar-shop.mode-theme-coin_mint {
  border-color: var(--pixel-black);
  --btn-bg: #261d06;
  --btn-hover-bg: #4a390e;
}

.btn-sidebar-shop.mode-theme-coin_mint .shop-btn-text {
  color: #ffc233;
}

.btn-sidebar-shop.mode-theme-coin_mint:hover {
  border-color: #ffc233;
}

@media (hover: none) {
  .btn-sidebar-shop.mode-theme-coin_mint:hover {
    border-color: var(--pixel-black);
  }
}

/* The Mint's own attention pulse (amber), mirroring the Ticket Factory's blue one but in-theme
   per AGENTS.md rule 3.5 Shop Theme Inheritance - never the shared blue factory-attention-pulse here. */
.btn-sidebar-shop.mint-attention-pulse {
  --beacon-border: #ffc233;
  --beacon-rest: 0 0 4px rgba(255, 194, 51, 0.35), 2px 2px 0 var(--pixel-black);
  --beacon-glow: 0 0 14px rgba(255, 194, 51, 0.85), 0 0 24px rgba(255, 224, 138, 0.4);
}

/* === [SNIPPET: Mint Unlock Prompt Button] === */
/* Locked-feature reveal for the Lucky Die: same can-afford/cannot-afford color language as .btn-mode-unlock
   (AGENTS.md UI standard 2.3), sized to sit inline inside the Yellow Bill sidebar card instead of the
   gamemode-select screen. Token-only differences from that pattern live entirely in these two states. */
.btn-mint-unlock {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 3px 6px;
  font-family: var(--font-pixel);
  cursor: pointer;
  outline: none !important;
}

.btn-mint-unlock:focus,
.btn-mint-unlock:focus-visible,
.btn-mint-unlock:active {
  outline: none !important;
}

.btn-mint-unlock .unlock-label {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.btn-mint-unlock .unlock-cost-text {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  font-weight: 700;
}

.btn-mint-unlock .unlock-dollar-icon {
  width: 16px;
  height: 10px;
  min-width: 16px;
  min-height: 10px;
}

.btn-mint-unlock.can-afford {
  background: #ffd700;
  color: #000000;
  border: 2px solid #ffffff;
}

.btn-mint-unlock.can-afford:hover {
  background: #ffe066;
}

.btn-mint-unlock.can-afford:active {
  transform: translate(1px, 1px);
}

.btn-mint-unlock.cannot-afford {
  background: #1e1b29;
  color: #71717a;
  border: 2px solid #3f3f46;
  cursor: not-allowed;
}

.btn-mint-unlock.cannot-afford:hover,
.btn-mint-unlock.cannot-afford:active,
.btn-mint-unlock.cannot-afford:focus,
.btn-mint-unlock.cannot-afford:focus-visible {
  background: #1e1b29 !important;
  color: #71717a !important;
  border-color: #3f3f46 !important;
  transform: none !important;
  outline: none !important;
}

.btn-mint-unlock.cannot-afford .unlock-dollar-icon {
  opacity: 0.45;
  filter: grayscale(100%);
}

/* === [SNIPPET: The Mint Modal Theme] === */
/* Reuses the Ticket Factory's .factory-dialog layout wholesale (AGENTS.md rule 10 Token-Only Modifier
   Pattern): only the --factory-accent token changes, from Plinko red to The Mint's amber gold. */
.factory-dialog.mode-theme-coin_mint {
  --factory-accent: #ffc233;
}

.factory-dialog.mode-theme-coin_mint .factory-balance {
  color: #ffc233;
  outline-color: #c98a00;
}

/* === [SNIPPET: Offline Reward Yellow Bill Icon] === */
.offline-item-icon.yellow-bill-pixel-icon {
  background: url("../assets/svg/global/currencies/yellow_bill.svg") no-repeat center / contain;
}

/* === [SNIPPET: Scrap Icon & Foundry Sidebar Card] === */
/* Cannon Range Foundry currency: pixel-art steel chunk (scrap.svg). The Foundry button itself reuses .btn-sidebar-shop.mode-cannon. */
.scrap-icon {
  width: 26px;
  height: 19px;
  min-width: 26px;
  min-height: 19px;
  background: url("../assets/svg/global/currencies/scrap.svg") no-repeat center / contain;
  image-rendering: pixelated;
  display: inline-block;
  flex-shrink: 0;
}

.stat-card .stat-body .scrap-icon {
  width: 32px !important;
  height: 23px !important;
  min-width: 32px !important;
  min-height: 23px !important;
  max-width: 32px !important;
  max-height: 23px !important;
}

.text-scrap {
  color: #a9bcd0 !important;
}

.stat-card.scrap-card {
  border-color: var(--pixel-black);
}

/* Cannon orange beacon on the Foundry button until it is opened once (theme color, never the blue factory pulse) */
.btn-sidebar-shop.foundry-attention-pulse {
  --beacon-border: #ff8a00;
  --beacon-rest: 0 0 4px rgba(255, 138, 0, 0.35), 2px 2px 0 var(--pixel-black);
  --beacon-glow: 0 0 14px rgba(255, 138, 0, 0.85), 0 0 24px rgba(255, 194, 102, 0.4);
}

/* === [SNIPPET: Foundry Modal Theme] === */
/* Reuses the Ticket Factory's .factory-dialog layout wholesale (Token-Only Modifier Pattern): only --factory-accent
   changes, to Cannon Range orange; the balance badge keeps the Scrap steel color. */
.factory-dialog.mode-theme-cannon {
  --factory-accent: #ff8a00;
}

.factory-dialog.mode-theme-cannon .factory-balance {
  color: #a9bcd0;
  outline-color: #ff8a00;
}

.factory-dialog.mode-theme-cannon .factory-exchange {
  background: #1a1108;
}

/* === [SNIPPET: Cannon Scrap Drop Sprite] === */
/* A chunk of Scrap lying on the Cannon Range ground (positioned by cannon_dom.js; clicks are hit-tested by cannon_drops.js) */
.cn-drop {
  display: block;
  image-rendering: pixelated;
}
/* === [SNIPPET: Achievements Modal] === */
/* Achievements list (#achievementsModal) and the slide-in unlock banner. Flat pixel styling, gold accent via --ach-accent. */
#achievementsModal { z-index: 15000; }

.ach-dialog {
  --ach-accent: #ffcc00;
  width: min(560px, 94vw);
  max-height: 88vh;
  outline: none;
}

.ach-dialog:focus,
.ach-dialog:focus-visible,
.ach-dialog:active { outline: none; }

.ach-dialog .modal-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 14px 14px;
  overflow-y: auto;
  scrollbar-width: none;
}

.ach-dialog .modal-body::-webkit-scrollbar { display: none; }

.ach-summary {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-pixel);
  font-size: 9px;
  color: var(--ach-accent);
}

.ach-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ach-row {
  --ach-row-accent: #2b3a5c;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  background: #0d1424;
  border: 2px solid var(--ach-row-accent);
}

.ach-row.ach-done { --ach-row-accent: var(--ach-accent); }

.ach-icon {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  image-rendering: pixelated;
}

.ach-locked .ach-icon { filter: grayscale(1) brightness(0.45); }
.ach-secret .ach-icon { filter: grayscale(1) brightness(0.2); }

.ach-info {
  flex: 1;
  min-width: 0;
}

.ach-name {
  font-family: var(--font-pixel);
  font-size: 10px;
  color: #ffffff;
}

.ach-desc {
  margin-top: 4px;
  font-family: var(--font-pixel);
  font-size: 8px;
  line-height: 1.5;
  color: #9fb0d0;
}

.ach-locked .ach-name { color: #8a94ad; }
.ach-locked .ach-desc { color: #6b7590; }

.ach-points {
  min-width: 28px;
  text-align: right;
  font-family: var(--font-pixel);
  font-size: 10px;
  color: var(--ach-accent);
}

.ach-locked .ach-points { color: #6b7590; }

.ach-play-btn {
  align-self: center;
  padding: 8px 14px;
  font-family: var(--font-pixel);
  font-size: 9px;
  color: #0a0e1a;
  background: var(--ach-accent);
  border: 3px solid var(--pixel-black);
  cursor: pointer;
  outline: none;
}

.ach-play-btn:hover { filter: brightness(1.15); }
.ach-play-btn:focus,
.ach-play-btn:focus-visible,
.ach-play-btn:active { outline: none; }

/* =========================================================
   SIDEBAR CABINET REDESIGN (rounded frame, marquee, tinted cards, segmented meters, rolling digits)
   Display only. Markup: .sidebar-frame / .sidebar-marquee / .stat-rate-row in index.html.
   JS: js/ui/sidebar_meters.js, js/ui/sidebar_odometer.js
   ========================================================= */

/* === [SNIPPET: Sidebar Mode Tokens] === */
/* Panel, bevel, accent and MENU / Settings tint follow the active attraction (main.js sets data-game-mode on
   #gameContainer). Default = Claw. Token-only: every sidebar component reads these, nothing else is overridden.
   .pf-themed shares them: the playfield cabinet frame and the top HUD cards (CHALLENGE, BALLS, LUCKY RUSH). */
.arcade-sidebar,
.pf-themed {
  --sb-accent: #00f0ff;
  --sb-accent-dark: #0099a3;
  --sb-panel: #0b1a28;
  --sb-card: #123047;
  --sb-hover: #16405c;
  --sb-bevel-hi: #1f5578;
  --sb-bevel-lo: #050d15;
}
.canvas-wrapper[data-game-mode="plinko"] :is(.arcade-sidebar, .pf-themed) {
  --sb-accent: #ff2252; --sb-accent-dark: #990f2e; --sb-panel: #210914; --sb-card: #3a1224;
  --sb-hover: #4d1830; --sb-bevel-hi: #6b2440; --sb-bevel-lo: #10040a;
}
.canvas-wrapper[data-game-mode="coin_flip"] :is(.arcade-sidebar, .pf-themed) {
  --sb-accent: #00e676; --sb-accent-dark: #008f47; --sb-panel: #08200f; --sb-card: #10361f;
  --sb-hover: #16482a; --sb-bevel-hi: #1f6a3c; --sb-bevel-lo: #031008;
}
.canvas-wrapper[data-game-mode="cannon"] :is(.arcade-sidebar, .pf-themed) {
  --sb-accent: #ff8a00; --sb-accent-dark: #a35800; --sb-panel: #231205; --sb-card: #3a220e;
  --sb-hover: #4d2e12; --sb-bevel-hi: #6b3f14; --sb-bevel-lo: #110802;
}
.canvas-wrapper[data-game-mode="endgame"] :is(.arcade-sidebar, .pf-themed) {
  --sb-accent: #a855f7; --sb-accent-dark: #6b21a8; --sb-panel: #1a0f2b; --sb-card: #2e1a47;
  --sb-hover: #3d2460; --sb-bevel-hi: #553286; --sb-bevel-lo: #0b0614;
}

/* === [SNIPPET: Sidebar Cabinet Frame] === */
/* Rounded (pixel-stepped, 3px steps) cabinet frame drawn by 5 clipped layers behind the content, so nothing inside
   the sidebar is clipped: drop shadow (3px down-right), black outline, bevel highlight + shadow, opaque panel with
   scanlines, and dim accent trim strips down both sides. Content sits above it (z-index 1). */
.sidebar-frame {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  --sf-clip-21: polygon(0 21px, 0 12px, 3px 12px, 3px 9px, 6px 9px, 6px 6px, 9px 6px, 9px 3px, 12px 3px, 12px 0, 21px 0, calc(100% - 21px) 0, calc(100% - 12px) 0, calc(100% - 12px) 3px, calc(100% - 9px) 3px, calc(100% - 9px) 6px, calc(100% - 6px) 6px, calc(100% - 6px) 9px, calc(100% - 3px) 9px, calc(100% - 3px) 12px, 100% 12px, 100% 21px, 100% calc(100% - 21px), 100% calc(100% - 12px), calc(100% - 3px) calc(100% - 12px), calc(100% - 3px) calc(100% - 9px), calc(100% - 6px) calc(100% - 9px), calc(100% - 6px) calc(100% - 6px), calc(100% - 9px) calc(100% - 6px), calc(100% - 9px) calc(100% - 3px), calc(100% - 12px) calc(100% - 3px), calc(100% - 12px) 100%, calc(100% - 21px) 100%, 21px 100%, 12px 100%, 12px calc(100% - 3px), 9px calc(100% - 3px), 9px calc(100% - 6px), 6px calc(100% - 6px), 6px calc(100% - 9px), 3px calc(100% - 9px), 3px calc(100% - 12px), 0 calc(100% - 12px), 0 calc(100% - 21px));
  --sf-clip-18: polygon(0 18px, 0 12px, 3px 12px, 3px 6px, 6px 6px, 6px 3px, 12px 3px, 12px 0, 18px 0, calc(100% - 18px) 0, calc(100% - 12px) 0, calc(100% - 12px) 3px, calc(100% - 6px) 3px, calc(100% - 6px) 6px, calc(100% - 3px) 6px, calc(100% - 3px) 12px, 100% 12px, 100% 18px, 100% calc(100% - 18px), 100% calc(100% - 12px), calc(100% - 3px) calc(100% - 12px), calc(100% - 3px) calc(100% - 6px), calc(100% - 6px) calc(100% - 6px), calc(100% - 6px) calc(100% - 3px), calc(100% - 12px) calc(100% - 3px), calc(100% - 12px) 100%, calc(100% - 18px) 100%, 18px 100%, 12px 100%, 12px calc(100% - 3px), 6px calc(100% - 3px), 6px calc(100% - 6px), 3px calc(100% - 6px), 3px calc(100% - 12px), 0 calc(100% - 12px), 0 calc(100% - 18px));
  --sf-clip-15: polygon(0 15px, 0 9px, 3px 9px, 3px 3px, 9px 3px, 9px 0, 15px 0, calc(100% - 15px) 0, calc(100% - 9px) 0, calc(100% - 9px) 3px, calc(100% - 3px) 3px, calc(100% - 3px) 9px, 100% 9px, 100% 15px, 100% calc(100% - 15px), 100% calc(100% - 9px), calc(100% - 3px) calc(100% - 9px), calc(100% - 3px) calc(100% - 3px), calc(100% - 9px) calc(100% - 3px), calc(100% - 9px) 100%, calc(100% - 15px) 100%, 15px 100%, 9px 100%, 9px calc(100% - 3px), 3px calc(100% - 3px), 3px calc(100% - 9px), 0 calc(100% - 9px), 0 calc(100% - 15px));
}
.sidebar-frame > i {
  position: absolute;
  display: block;
}
.sidebar-frame .sf-shadow { inset: 3px 0 0 3px; background: var(--pixel-black); clip-path: var(--sf-clip-21); }
.sidebar-frame .sf-outline { inset: 0 3px 3px 0; background: var(--pixel-black); clip-path: var(--sf-clip-21); }
.sidebar-frame .sf-hi { inset: 3px 6px 6px 3px; background: var(--sb-bevel-hi); clip-path: var(--sf-clip-18); }
.sidebar-frame .sf-lo { inset: 6px; background: var(--sb-bevel-lo); clip-path: var(--sf-clip-18); }
.sidebar-frame .sf-panel {
  inset: 6px 9px 9px 6px;
  background-color: var(--sb-panel);
  background-image: repeating-linear-gradient(180deg, rgba(0, 0, 0, 0.22) 0 2px, transparent 2px 6px); /* scanlines */
  clip-path: var(--sf-clip-15);
}
.sidebar-frame .sf-panel::after {
  /* Trim strips: accent mixed 18% into the panel so they read as a faint tinted edge, clear of the curves */
  content: "";
  position: absolute;
  top: 33px;
  bottom: 33px;
  left: 2px;
  right: 2px;
  border-left: 3px solid color-mix(in srgb, var(--sb-accent) 18%, var(--sb-panel));
  border-right: 3px solid color-mix(in srgb, var(--sb-accent) 18%, var(--sb-panel));
}
.arcade-sidebar > .sidebar-top,
.arcade-sidebar > .sidebar-currencies,
.arcade-sidebar > .sidebar-actions {
  position: relative;
  z-index: 1;
}

/* === [SNIPPET: Playfield Cabinet Frame] === */
/* SLIM rounded frame around the playfield, same layer language as the sidebar frame (JS: js/ui/playfield_frame.js).
   #playfieldFrame sits behind every field layer (the field art is opaque), is zoomed by the UI scale and spans the
   frame plus the tab band above it. Layers (inset, pixel-stepped clip-path set by JS): 3px drop shadow, black
   outline, bevel highlight + shade, scanline bezel and a black lip against the glass: 9px in all around the field.
   The shadow / outline / bevel / bezel layers are direct children clipped (by JS) to ONE silhouette: the frame plus
   a raised tab for each top HUD card that is showing, flush with the frame's outer side and joined to its top edge
   by a concave fillet, so the tab has no seam. The lip stays a ring around the field (.pff-cabinet) and covers the
   bezel there, so the scanline bezel only shows in the tabs, behind the cards.
   #playfieldCorners is a second copy of the frame above the field layers, clipped (by JS) to the four slivers outside
   the glass's 12px round corners, so the square field layers get round corners. It must stay BELOW #fgCanvas: stacked
   on top of that busy GPU canvas, Chrome now and then drops the rounded clip and keeps only its bounding box (the
   whole field), so the copy's black lip covered the playfield and it flashed black (worst in a maxed Claw Pit).
   Colors: --sb-* tokens ([SNIPPET: Sidebar Mode Tokens]). */
.playfield-frame {
  position: absolute;
  z-index: 0; /* above .cosmic-bg (earlier in the DOM), below the chamber / table layers */
  pointer-events: none;
  zoom: var(--ui-scale, 1);
}
/* Tied with the glass shade (19) and later in the DOM, so above it; below the #fgCanvas particles (20), see above */
.playfield-frame.playfield-corners { z-index: 19; }
.pff-cabinet {
  position: absolute;
  left: 0;
}
.playfield-frame > i { inset: 0; } /* silhouette layers span the whole frame box; their clip-path is the shape */
.playfield-frame i {
  position: absolute;
  display: block;
  z-index: 1;
}
.playfield-frame .pff-shadow { background: var(--pixel-black); transform: translate(3px, 3px); z-index: 0; }
.playfield-frame .pff-outline,
.playfield-frame .pff-lip { background: var(--pixel-black); }
.playfield-frame .pff-hi { background: var(--sb-bevel-hi); }
.playfield-frame .pff-lo { background: var(--sb-bevel-lo); }
.playfield-frame .pff-bezel {
  background-color: var(--sb-panel);
  background-image: repeating-linear-gradient(180deg, rgba(0, 0, 0, 0.22) 0 2px, transparent 2px 6px); /* scanlines */
}

/* Flat 3px shade inside the top and left edge of the field glass: depth without blur */
.playfield-shade {
  position: absolute;
  left: var(--playfield-x, 0);
  top: var(--playfield-y, 0);
  width: var(--playfield-w, 100%);
  height: var(--playfield-h, 100%);
  box-shadow: inset 3px 3px 0 rgba(0, 0, 0, 0.4);
  pointer-events: none;
  z-index: 19; /* above the field layers and the glass, below #fgCanvas particles (20) */
}

/* Claw Pit front glass pane: in front of the claw and prizes (entities 10), below particles (#fgCanvas 20).
   Overlay blend: white glare barely lifts the dark wall but puts a visible sheen on bright coins and the claw, so the
   glass reads as being in front of them. */
.claw-glass-layer {
  z-index: 15;
  mix-blend-mode: overlay;
}
.claw-glass-svg {
  display: block;
}

/* === [SNIPPET: Top HUD Tab Cards] === */
/* Shared card look for the top HUD cards (CHALLENGE, the running-challenge card, Plinko BALLS, Coin Flip LUCKY RUSH): the sidebar
   card language (card tint, black border, inner bevel shade, 1-step pixel corners painted in the bezel color) and a
   segmented meter. js/ui/playfield_frame.js places each card inside its tab on the cabinet frame. Each card sets
   --hud-accent (label, dot, meter) and --hud-segs (meter segments); colors are --sb-* tokens via .pf-themed.
   Slim header: 34px cards in a 37px tab band (PlayfieldFrame.CARD_H / TAB_BAND). */
.trial-btn-group,
.trial-hud-overlay,
.plinko-ball-hud,
.coin-flip-rush-hud {
  position: absolute;
  z-index: 15;
  height: 34px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  padding: 0 9px;
  background: var(--sb-card);
  border: 3px solid var(--pixel-black);
  box-shadow: inset -2px -2px 0 rgba(0, 0, 0, 0.35);
  font-family: var(--font-pixel);
  zoom: var(--ui-scale, 1);
}
.trial-btn-group::after,
.trial-hud-overlay::after,
.plinko-ball-hud::after,
.coin-flip-rush-hud::after {
  content: "";
  position: absolute;
  inset: -3px;
  pointer-events: none;
  background:
    linear-gradient(var(--sb-panel), var(--sb-panel)) left top / 3px 3px no-repeat,
    linear-gradient(var(--sb-panel), var(--sb-panel)) right top / 3px 3px no-repeat,
    linear-gradient(var(--sb-panel), var(--sb-panel)) left bottom / 3px 3px no-repeat,
    linear-gradient(var(--sb-panel), var(--sb-panel)) right bottom / 3px 3px no-repeat;
}
/* Segmented meter: the track's mask cuts 2px gaps through both the dark track and the fill, so the game's JS keeps
   setting the fill width as before */
.trial-progress-bar,
.trial-timer-bar-track,
.plinko-ball-hud-track,
.coin-flip-rush-hud-track {
  position: relative;
  width: 100%;
  height: 5px;
  flex-shrink: 0;
  overflow: hidden;
  border: none;
  background: rgba(0, 0, 0, 0.45);
  -webkit-mask: linear-gradient(90deg, #000 calc(100% - 2px), transparent 0) 0 0 / calc(100% / var(--hud-segs, 14)) 100% repeat-x;
  mask: linear-gradient(90deg, #000 calc(100% - 2px), transparent 0) 0 0 / calc(100% / var(--hud-segs, 14)) 100% repeat-x;
}
.trial-progress-fill,
.trial-timer-bar-fill,
.plinko-ball-hud-fill,
.coin-flip-rush-hud-fill {
  height: 100%;
  background: var(--hud-accent);
  box-shadow: none;
  /* No `transition: width`: every width change ran an 80ms main-thread animation, and these cards share a large squashed
     layer, so each animation frame repainted ~2 Mpx (the playfield frame / HUD layer repainted ~47 times a second on a real
     phone). The bars move in whole-percent steps, so the smoothing was not visible anyway. */
}

/* Running CHALLENGE card (#trialHudOverlay): while a challenge runs it takes the CHALLENGE tab (playfield_frame.js).
   Top row: segmented bar of what is left (time, or balls in Plinko) + clock / count; bottom row: STREAK, LIVES
   (only with the Mystic upgrade), MULTIPLIER, EARNED as label + value. js/ui/trial_hud.js writes the bar and clock
   and sets .trial-low near the end, which turns the card's accent red and blinks the clock. */
.trial-hud-overlay {
  width: 320px;
  --hud-accent: var(--sb-accent);
  --hud-segs: 16;
  gap: 4px;
  pointer-events: none;
}
.trial-hud-overlay.trial-low { --hud-accent: #ff2252; }
.trial-hud-top { display: flex; align-items: center; gap: 8px; }
.trial-hud-top .trial-timer-bar-track { flex: 1; width: auto; }
.trial-hud-clock { min-width: 38px; text-align: right; font-size: 9px; color: var(--hud-accent); white-space: nowrap; }
.trial-hud-clock:empty { display: none; }
.trial-hud-overlay.trial-low .trial-hud-clock { animation: trialClockBlink 1s steps(1, end) infinite; }
@keyframes trialClockBlink { 50% { opacity: 0.3; } }
.trial-hud-stats { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.trial-hud-stat { display: inline-flex; align-items: baseline; gap: 4px; white-space: nowrap; }
.trial-stat-label { font-family: var(--font-pixel-sub); font-size: 9px; color: #b8b2cf; text-transform: uppercase; }
.trial-stat-val { font-family: var(--font-pixel); font-size: 8px; color: #fff; }

/* === [SNIPPET: Claw Pit Powerup Chips] === */
/* Claw Pit's timed boosts at the left end of the tab row (#powerupActiveBar, placed by playfield_frame.js in a tab sized
   to the chips). One chip per boost (js/ui/powerup_chips.js): a socket whose rim fills clockwise with the time left in
   12 hard steps (--t) in the boost color (--pc) around the boost icon. A chip is a 34px square (icon only) until tapped;
   .open widens it to 92px (PlayfieldFrame.PUP_CHIP_W) and shows the time left or the combo multiplier, then it folds
   back after 3s. The boost name is in the chip's tooltip. */
.powerup-active-bar {
  position: absolute;
  z-index: 15;
  display: flex;
  align-items: center;
  gap: 6px;
  pointer-events: none;
}
.pup-chip {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 34px;
  height: 34px;
  box-sizing: border-box;
  padding: 0;
  pointer-events: auto;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background: var(--sb-card);
  border: 3px solid var(--pixel-black);
  clip-path: var(--px-notch);
  box-shadow: inset -2px -2px 0 rgba(0, 0, 0, 0.35);
  font-family: var(--font-pixel);
}
.pup-sock {
  position: relative;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  clip-path: var(--px-notch);
  background: conic-gradient(var(--pc) calc(var(--t, 1) * 1turn), #1d263b 0);
}
.pup-sock-in {
  position: absolute;
  inset: 3px;
  display: grid;
  place-items: center;
  background: #0c1322;
  clip-path: var(--px-notch);
}
.pup-sock-in svg { width: 18px; height: 18px; }
.pup-txt { display: none; flex-direction: column; gap: 4px; font-size: 7px; line-height: 1; color: #fff; white-space: nowrap; }
.pup-chip.open { width: 92px; padding: 0 9px 0 0; }
.pup-chip.open .pup-txt { display: flex; }
.pup-chip:focus,
.pup-chip:focus-visible,
.pup-chip:active { outline: none; }

/* === [SNIPPET: Claw Pit Claw Sprite] === */
/* "Round Lamp" pixel-art claw (js/gamemodes/claw/claw_sprite.js): the dome lamp and prong tips are the Claw Pit cyan
   and turn gold while the claw carries a prize (.caught). The chain is two SVG lines (not a gradient, which
   flickered at fractional scales): a 9px black stroke and a dashed 3px steel core (6px links, 3px gaps). The lines are
   drawn once at full length inside the .claw-chain clip box and only moved by transforms (no per-frame repaint). */
.claw-rig .cl-acc { fill: var(--pixel-cyan, #00f0ff); }
.claw-rig.caught .cl-acc { fill: var(--pixel-gold, #ffcc00); }
.claw-chain { pointer-events: none; }
.claw-chain-body { stroke: #000000; stroke-linecap: butt; }
.claw-chain-links { stroke: #b3bfcf; stroke-dasharray: 6 3; stroke-linecap: butt; }

/* === [SNIPPET: Sidebar Mode Selector Marquee] === */
/* Black marquee box around the mode selector with a row of bulbs above and below. The bulbs repeat in groups of 3
   that rotate full (35%) / half (17.5%) / off, dim on purpose; the selector dots pulse faintly. */
.sidebar-marquee {
  width: 100%;
  box-sizing: border-box;
  background: var(--mq-bg, var(--pixel-black));
  border: 3px solid var(--mq-border, var(--sb-accent-dark));
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.marquee-bulbs {
  display: flex;
  justify-content: space-between;
  padding: 0 2px;
}
/* The chase is NOT a CSS animation: 28 bulbs + 2 dots each running an infinite animation cost about 13% of the main
   thread on a throttled CPU (measured, Claw Pit, 6x throttle). js/ui/marquee_chase.js steps data-chase (0 / 1 / 2, every
   0.8s) and data-dot (0 / 1, every 1.2s) on each .sidebar-marquee instead, and these rules only read the tokens below.
   Phase 0: group A 35%, group B 17.5%, group C off; each phase rotates the three levels one group along. */
.sidebar-marquee {
  --bulb-a: 0.35;
  --bulb-b: 0.175;
  --bulb-c: 0;
  --dot-op: 0.7;
}
.sidebar-marquee[data-chase="1"] { --bulb-a: 0.175; --bulb-b: 0; --bulb-c: 0.35; }
.sidebar-marquee[data-chase="2"] { --bulb-a: 0; --bulb-b: 0.35; --bulb-c: 0.175; }
.sidebar-marquee[data-dot="1"] { --dot-op: 0.45; }
/* Difficulty tiers (css/difficulty_tiers.css) only set --mq-* tokens: border, background, bulb colors and a brightness gain. */
.marquee-bulbs > i {
  width: 5px;
  height: 5px;
  background: var(--mq-bulb, var(--sb-accent));
  opacity: calc(var(--bulb-a) * var(--mq-bulb-gain, 1));
}
.marquee-bulbs > i:nth-child(even) { background: var(--mq-bulb-alt, var(--mq-bulb, var(--sb-accent))); }
.marquee-bulbs > i:nth-child(3n + 2) { opacity: calc(var(--bulb-b) * var(--mq-bulb-gain, 1)); }
.marquee-bulbs > i:nth-child(3n + 3) { opacity: calc(var(--bulb-c) * var(--mq-bulb-gain, 1)); }
.sidebar-marquee .btn-game-selector {
  width: 100%;
  height: 36px;
  border-width: 2px;
  box-shadow: none;
}
.sidebar-marquee .selector-dot {
  opacity: var(--dot-op);
}
/* Short landscape screens: keep the marquee compact (matches the 34px selector in the max-height: 500px block) */
@media (max-height: 500px) {
  .sidebar-marquee { padding: 3px; gap: 3px; }
  .sidebar-marquee .btn-game-selector { height: 30px; }
}
@media (prefers-reduced-motion: reduce) {
  /* marquee_chase.js does not run, so the phase attributes never appear and these tokens stay */
  .sidebar-marquee { --bulb-a: 0.25; --bulb-b: 0.25; --bulb-c: 0.25; --dot-op: 0.25; }
}

/* === [SNIPPET: Sidebar Card & Button Pixel Corners] === */
/* 1-step pixel rounding: each corner's 3x3 outer border pixel is painted over in the panel color (no clip-path, so
   attention glows and border-color pulses still show in full). A shop button is positioned after its card, so it
   covers the card's bottom corners and the pair reads as one piece (rounded top on the card, bottom on the button).
   Inner bevel shadow instead of a drop shadow keeps the rounded corners clean. */
.arcade-sidebar .stat-card,
.arcade-sidebar .btn-sidebar-shop,
.sidebar-actions .btn-menu-header,
.sidebar-actions .btn-settings-header,
.sidebar-marquee {
  position: relative;
}
.arcade-sidebar .stat-card,
.arcade-sidebar .btn-sidebar-shop,
.arcade-sidebar .sidebar-actions .btn-menu-header,
.arcade-sidebar .sidebar-actions .btn-settings-header {
  box-shadow: inset -2px -2px 0 rgba(0, 0, 0, 0.35);
}
.arcade-sidebar .stat-card.prestige-card:hover {
  box-shadow: inset -2px -2px 0 rgba(0, 0, 0, 0.35), 0 4px 0 var(--pixel-black);
}
.arcade-sidebar .stat-card::after,
.sidebar-actions .btn-menu-header::after,
.sidebar-actions .btn-settings-header::after,
.sidebar-marquee::after {
  content: "";
  position: absolute;
  inset: -3px;
  pointer-events: none;
  background:
    linear-gradient(var(--sb-panel), var(--sb-panel)) left top / 3px 3px no-repeat,
    linear-gradient(var(--sb-panel), var(--sb-panel)) right top / 3px 3px no-repeat,
    linear-gradient(var(--sb-panel), var(--sb-panel)) left bottom / 3px 3px no-repeat,
    linear-gradient(var(--sb-panel), var(--sb-panel)) right bottom / 3px 3px no-repeat;
}
.arcade-sidebar .btn-sidebar-shop::after {
  content: "";
  position: absolute;
  inset: -3px;
  pointer-events: none;
  background:
    linear-gradient(var(--sb-panel), var(--sb-panel)) left bottom / 3px 3px no-repeat,
    linear-gradient(var(--sb-panel), var(--sb-panel)) right bottom / 3px 3px no-repeat;
}

/* === [SNIPPET: Sidebar Currency Card Tints] === */
/* Each card (and the shop button under it) takes its currency / shop color, not the attraction's.
   --card-bg feeds .stat-card, --seg-color the meter; shop button colors are --btn-bg / --btn-hover-bg on each
   .btn-sidebar-shop variant ([SNIPPET: Sidebar Attraction Shop Launch Buttons]). */
.arcade-sidebar #coinCard { --card-bg: #33280a; --seg-color: #ffcc00; }
.arcade-sidebar #starCoinCard { --card-bg: #3a1030; }
.arcade-sidebar #redTicketCard { --card-bg: #3a1224; --seg-color: #ff2252; }
.arcade-sidebar #blueTicketCard { --card-bg: #10223f; }
.arcade-sidebar #dollarCard { --card-bg: #10361f; --seg-color: #00e676; }
.arcade-sidebar #yellowBillCard { --card-bg: #36290a; }
.arcade-sidebar #cannonGoldCard { --card-bg: #3a220e; --seg-color: #ff8a00; }
.arcade-sidebar #scrapCard { --card-bg: #1f2833; }
.arcade-sidebar #prestigeCard { --card-bg: #2e1a47; --seg-color: #c084fc; }
.btn-sidebar-shop.mode-plinko.factory-blue { --btn-bg: #0b182e; --btn-hover-bg: #173059; }
#btnFoundry { --btn-bg: #161d25; --btn-hover-bg: #2b3746; } /* steel, matching the Scrap card above it */

/* === [SNIPPET: Sidebar Scroll Edge Fade] === */
/* The currency list scrolls without a scrollbar. Where cards run past the top or bottom edge, that edge fades out
   softly over 28px instead of cutting the card off. js/ui/sidebar_scroll_fade.js toggles .fade-top / .fade-bottom
   from the scroll position, so a fully visible list has no fade at all. */
@property --sb-fade-top { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --sb-fade-bottom { syntax: "<length>"; inherits: false; initial-value: 0px; }
.sidebar-currencies {
  --sb-fade-top: 0px;
  --sb-fade-bottom: 0px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--sb-fade-top), #000 calc(100% - var(--sb-fade-bottom)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--sb-fade-top), #000 calc(100% - var(--sb-fade-bottom)), transparent 100%);
  transition: --sb-fade-top 0.2s ease, --sb-fade-bottom 0.2s ease;
}
.sidebar-currencies.fade-top { --sb-fade-top: 28px; }
.sidebar-currencies.fade-bottom { --sb-fade-bottom: 28px; }

/* === [SNIPPET: Sidebar Segmented Meter & Rate Row] === */
/* 10 segments: .on = solid, .part = half-lit partial step (js/ui/sidebar_meters.js renderSegments).
   Rate row: meter fills the space, the "N/s" label sits in a fixed-width centered slot measured from the longest
   possible label (--sb-rate-w), so the meter never resizes. .rate-exp (rate >= 1e21/s) switches to the wider slot. */
.sidebar-meter {
  display: flex;
  gap: 2px;
  height: 5px;
  min-width: 0;
  margin-left: 1px;
}
.sidebar-meter > i {
  flex: 1;
  height: 5px;
  background: rgba(0, 0, 0, 0.45);
  box-shadow: 0 0 0 1px var(--pixel-black);
}
.sidebar-meter > i.on { background: var(--seg-color, var(--pixel-gold)); }
.sidebar-meter > i.part { background: var(--seg-color, var(--pixel-gold)); opacity: 0.5; }
.stat-rate-row {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  min-width: 0;
}
.stat-rate-row .sidebar-meter { flex: 1; }
.stat-rate-row .stat-rate {
  flex: 0 0 var(--sb-rate-w, 44px);
  text-align: center;
  overflow: hidden;
}
.stat-rate-row.rate-exp .stat-rate { flex-basis: var(--sb-rate-w-exp, 52px); }

/* === [SNIPPET: Sidebar Rolling Digits] === */
/* main.js still writes each amount into its .stat-value (now hidden, .odo-source). The .stat-odometer sibling shows it
   at most 3 significant figures, each digit on a 0-9 strip that jumps in 3 hard steps. Each digit slot is 6px taller
   than the glyph so scaling rounding shows empty space, never the top of the next digit.
   --odo-lh: Press Start 2P's text box is 1.125em tall and its glyphs start at the very top of it, so a 1em line
   pushed the glyph ~1px above the window and clipped its top row. A 1.2em line centers that box with the ink
   (top 7/8 em) inside the 18px window with a little room above and below. */
.stat-value.odo-source { display: none !important; }
.stat-value.stat-odometer {
  --odo-h: 18px;
  --odo-pitch: 24px;
  --odo-lh: 1.2;
  display: inline-flex;
  height: var(--odo-h);
  line-height: var(--odo-lh);
  overflow: hidden;
}
.odo-cell {
  display: inline-block;
  height: var(--odo-h);
  line-height: var(--odo-lh);
  overflow: hidden;
}
.odo-strip {
  display: flex;
  flex-direction: column;
  transform: translateY(calc(var(--odo-digit, 0) * var(--odo-pitch) * -1));
  transition: transform 0.24s steps(3, end);
}
.odo-strip > span {
  display: block;
  height: var(--odo-pitch);
  line-height: var(--odo-lh);
}
.odo-source.highlight + .stat-odometer { filter: brightness(1.35); }
@media (prefers-reduced-motion: reduce) {
  .odo-strip { transition: none; }
}
