/* Rhythm-mode specific styles. Layered on top of style.css. */

/* The HTML `hidden` attribute should always win over `display: flex` etc. */
[hidden] { display: none !important; }

/* ----- Always-fullscreen shell -----
   The rhythm page is a single-song fullscreen-first experience. We kill
   the body padding, the white-card shell background, and the teaching
   panels so the canvas area fills the viewport even before the browser
   fullscreen API kicks in (which still happens on first user gesture
   for the proper :fullscreen pseudo-state). The topbar lives inside
   the shell as a slim overlay row at the top of the stage. */
body:has(.rhythm-shell) {
  padding: 0;
  background: #02010a;
  align-items: stretch;
  min-height: 100vh;
}
.rhythm-shell {
  width: 100vw;
  max-width: none;
  padding: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  gap: 0;
  min-height: 100vh;
}
.rhythm-shell .topbar {
  border-radius: 0;
  border-left: 0;
  border-right: 0;
  border-top: 0;
  border-bottom: 1.5px solid rgba(31, 41, 51, 0.18);
}
.rhythm-shell .stage {
  flex: 1 1 auto;
  border-radius: 0;
  border: none;
  background: #02010a;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Hard floor so the canvas always has somewhere to render even on
     a very short viewport. */
  min-height: 360px;
}
/* Letterbox the canvas inside the always-fullscreen stage: it grows
   to fill the larger of width/height while preserving 16:9. */
.rhythm-shell .stage #rhythm-canvas {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  aspect-ratio: 16 / 9;
}
.rhythm-shell .stage #rhythm-canvas[width][height] {
  /* Explicit attrs are still respected for the backing store; the
     CSS above governs displayed size only. */
}
/* Teaching panels (fingers + keyboard) — hidden in fullscreen-first mode.
   They still mount in the DOM so finger highlight callbacks don't error;
   they just don't paint. */
.rhythm-shell .teaching {
  display: none;
}

/* ----- Post-FX overlay layers (CSS-only, never block input) -----
   These sit BETWEEN the canvas (z:1) and the interactive UI (z:10+) so
   the start CTA and result modal are never tinted/bleached by them. */
.fx-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  mix-blend-mode: screen;
}
/* Interactive UI must paint OVER the post-FX, otherwise mix-blend-mode
   on the scanlines/vignette eats the start CTA and finish modal. */
.rhythm-shell .overlay { z-index: 10; }
.rhythm-shell .result  { z-index: 11; }
.fx-scanlines {
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0) 0px,
    rgba(255, 255, 255, 0) 2px,
    rgba(255, 255, 255, 0.035) 3px,
    rgba(255, 255, 255, 0) 4px
  );
  mix-blend-mode: overlay;
  opacity: 0.85;
}
.fx-vignette {
  position: absolute;
  inset: 0;
  /* The --beat-pulse custom property is updated by the renderer every
     frame (0..1); the vignette tightens slightly on the beat so the
     whole frame breathes with the music. */
  background: radial-gradient(
    ellipse at center,
    rgba(0, 0, 0, 0) calc(45% - var(--beat-pulse, 0) * 4%),
    rgba(0, 0, 0, calc(0.55 + var(--beat-pulse, 0) * 0.12)) 100%
  );
  mix-blend-mode: multiply;
}

/* Chromatic aberration applied to the canvas at high combos.
   Two offset drop-shadows in complementary colors fake RGB split. */
.rhythm-shell #rhythm-canvas {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  transition: filter 220ms ease;
}
.rhythm-shell .stage.chromatic #rhythm-canvas {
  filter:
    drop-shadow(1px 0 0 rgba(255, 0, 90, 0.55))
    drop-shadow(-1px 0 0 rgba(0, 220, 255, 0.55));
}

/* HUD score/combo/level numbers ride the beat too — a faint scale bump
   keyed to --beat-pulse so the whole interface pulses with the song. */
.rhythm-shell .hud-item span:last-child {
  display: inline-block;
  transform: scale(calc(1 + var(--beat-pulse, 0) * 0.04));
  transition: transform 60ms linear;
}

/* ----- Combo HUD pop ----- */
#combo {
  display: inline-block;
  transform-origin: center;
  will-change: transform, color, text-shadow;
  transition: color 200ms ease;
}
@keyframes combo-pop {
  0%   { transform: scale(1);   text-shadow: 0 0 0 transparent; }
  35%  { transform: scale(1.4); text-shadow: 0 0 14px currentColor, 0 0 28px currentColor; color: #f0abfc; }
  100% { transform: scale(1);   text-shadow: 0 0 0 transparent; }
}
@keyframes combo-pop-big {
  0%   { transform: scale(1);   text-shadow: 0 0 0 transparent; }
  30%  { transform: scale(1.85); text-shadow: 0 0 18px currentColor, 0 0 40px currentColor; color: #f472b6; }
  100% { transform: scale(1);   text-shadow: 0 0 0 transparent; }
}
#combo.combo-pop      { animation: combo-pop 200ms ease-out; }
#combo.combo-pop-big  { animation: combo-pop-big 420ms cubic-bezier(0.34, 1.56, 0.64, 1); }

/* ----- Transient milestone label (x10!, x25!, ...) ----- */
.combo-flash {
  position: absolute;
  top: 30%;
  left: 0;
  right: 0;
  text-align: center;
  pointer-events: none;
  z-index: 3;
  font-weight: 900;
  font-size: 64px;
  letter-spacing: 0.05em;
  color: #f472b6;
  text-shadow:
    0 0 18px rgba(244, 114, 182, 0.9),
    0 0 36px rgba(244, 114, 182, 0.6),
    0 0 60px rgba(160, 80, 255, 0.5);
  opacity: 0;
}
@keyframes combo-flash-anim {
  0%   { opacity: 0; transform: translateY(20px) scale(0.6); }
  18%  { opacity: 1; transform: translateY(0)    scale(1.3); }
  35%  { opacity: 1; transform: translateY(0)    scale(1);   }
  100% { opacity: 0; transform: translateY(-30px) scale(1.1); }
}
.combo-flash.show { animation: combo-flash-anim 1000ms ease-out forwards; }

/* ----- Fullscreen toggle button ----- */
.fullscreen-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 4;
  width: 36px;
  height: 36px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(0, 0, 0, 0.45);
  color: rgba(255, 255, 255, 0.85);
  font-size: 18px;
  line-height: 1;
  border-radius: 8px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background 0.15s, transform 0.08s, border-color 0.15s;
}
.fullscreen-btn:hover {
  background: rgba(120, 70, 255, 0.45);
  border-color: rgba(255, 255, 255, 0.5);
}
.fullscreen-btn:active { transform: scale(0.92); }

/* When the shell is fullscreen, the topbar stays at top, stage fills
   the rest. Browser chrome hides; the always-fullscreen layout already
   handles the visuals. */
.rhythm-shell:fullscreen,
.rhythm-shell:-webkit-full-screen {
  background: #02010a;
  width: 100vw;
  height: 100vh;
}
.rhythm-shell:fullscreen .stage,
.rhythm-shell:-webkit-full-screen .stage {
  /* In actual fullscreen there's no body padding to worry about, so the
     stage just fills the remaining flex space. The canvas inside still
     letterboxes via aspect-ratio. */
  height: auto;
  max-height: none;
}

/* Reduced motion: kill the optional flourish/scanlines so the page is calm. */
@media (prefers-reduced-motion: reduce) {
  #combo.combo-pop, #combo.combo-pop-big { animation: none; }
  .combo-flash.show { animation: combo-flash-anim 600ms linear forwards; }
  .fx-scanlines { display: none; }
  .rhythm-shell .stage.chromatic #rhythm-canvas { filter: none; }
}

/* ----- Slim unified top bar ----- */
/* One row: More games · HUD · level · play/stop · lang. No second row of
   controls under it. The shell still wraps the bar, stage and teaching
   panels in non-fullscreen browsing; once fullscreen kicks in (default
   on first user gesture), only .stage is visible. */
.topbar {
  display: flex;
  align-items: center;
  gap: 8px;
  background: white;
  padding: 6px 10px;
  border-radius: 14px;
  border: 2px solid rgba(31, 41, 51, 0.08);
  flex-wrap: wrap;
}
.topbar-home {
  text-decoration: none;
  color: #1f2933;
  background: #f1f5f9;
  padding: 7px 12px;
  border-radius: 10px;
  font-weight: 700;
  font-size: 13px;
  border: 1.5px solid rgba(31, 41, 51, 0.08);
  transition: background 0.15s, transform 0.08s;
  white-space: nowrap;
}
.topbar-home:hover { background: #e2e8f0; transform: translateY(-1px); }
.topbar-hud {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.topbar-hud .hud-item {
  /* Tighter than the old .hud-item — slim bar, not a card row. */
  padding: 4px 10px;
  font-size: 14px;
  min-width: 0;
  border-width: 1.5px;
  border-radius: 8px;
}
.topbar-hud .hud-label { font-size: 9px; }
.topbar-actions {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-left: auto;
}
.topbar-actions .primary,
.topbar-actions .secondary {
  font-size: 13px;
  padding: 7px 14px;
  border-radius: 9px;
}
.topbar-select,
.topbar-actions .hud-lang {
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 8px;
  border: 1.5px solid #cbd5e1;
  border-radius: 8px;
  background: white;
  margin-left: 0;
  cursor: pointer;
}

/* ----- Override banner (slim row under the top bar) ----- */
.override-banner {
  margin: 0;
  padding: 0.45rem 0.75rem;
  background: rgba(255, 169, 64, 0.15);
  border: 1px solid rgba(255, 169, 64, 0.4);
  border-radius: 8px;
  color: #b45309;
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.override-banner button {
  margin-left: auto;
  padding: 0.25rem 0.6rem;
  background: transparent;
  color: inherit;
  border: 1px solid currentColor;
  border-radius: 3px;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.85rem;
}

button.primary, button.secondary {
  font: inherit;
  font-weight: 700;
  font-size: 14px;
  padding: 10px 18px;
  border-radius: 10px;
  cursor: pointer;
  border: none;
  transition: transform 0.08s, background 0.15s;
}
button.primary.big-cta {
  font-size: 22px;
  padding: 16px 40px;
  border-radius: 14px;
  margin-top: 8px;
  box-shadow: 0 6px 20px rgba(245, 158, 11, 0.35);
}
button.primary.big-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 28px rgba(245, 158, 11, 0.5);
}
button.primary { background: #f59e0b; color: white; }
button.primary:hover { background: #d97706; }
button.primary:disabled { background: #cbd5e1; cursor: not-allowed; }
button.secondary { background: #e2e8f0; color: #1f2933; }
button.secondary:hover { background: #cbd5e1; }
button.secondary:disabled { opacity: 0.5; cursor: not-allowed; }

/* Result card */
.result {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
}
.result-card {
  background: white;
  padding: 24px 32px;
  border-radius: 16px;
  text-align: center;
  min-width: 320px;
}
.result-card h2 { color: #f59e0b; margin-bottom: 14px; }
.result-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 24px;
  margin-bottom: 16px;
}
.result-stats > div {
  display: flex;
  justify-content: space-between;
  font-weight: 700;
  font-size: 16px;
}
.result-label {
  color: #64748b;
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  align-self: center;
}

/* ----- Vibe Jam portals -----
   Glowing pucks anchored to the bottom corners of the stage. The exit
   portal sends players to the Vibe Jam directory; the back portal only
   appears when arriving via ?portal=true&ref=<X> and returns there.
   Pointer-events live on .portal so clicks register; the rest of the
   stage stays interactive. */
.portal {
  position: absolute;
  bottom: 38px; /* was 18px — lifted 20px total so it doesn't crowd browser chrome */
  z-index: 5; /* above canvas + post-FX, below overlay/result */
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: #f8fafc;
  background: rgba(8, 6, 22, 0.7);
  border: 1.5px solid var(--portal-color, #a78bfa);
  box-shadow:
    0 0 12px var(--portal-color, #a78bfa),
    0 0 28px color-mix(in srgb, var(--portal-color, #a78bfa) 50%, transparent),
    inset 0 0 16px rgba(167, 139, 250, 0.25);
  backdrop-filter: blur(4px);
  cursor: pointer;
  transition: transform 0.12s ease, box-shadow 0.2s ease;
  pointer-events: auto;
  max-width: 40%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.portal:hover {
  transform: translateY(-2px) scale(1.04);
  box-shadow:
    0 0 18px var(--portal-color, #a78bfa),
    0 0 40px color-mix(in srgb, var(--portal-color, #a78bfa) 65%, transparent),
    inset 0 0 22px rgba(167, 139, 250, 0.35);
}
.portal::before {
  content: '';
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--portal-color, #a78bfa);
  box-shadow:
    0 0 10px var(--portal-color, #a78bfa),
    0 0 22px var(--portal-color, #a78bfa);
  animation: portal-pulse 1.4s ease-in-out infinite;
}
@keyframes portal-pulse {
  0%, 100% { transform: scale(1);   opacity: 0.85; }
  50%      { transform: scale(1.4); opacity: 1;    }
}
.portal-exit { right: 18px; }
.portal-back { left: 18px; }
@media (prefers-reduced-motion: reduce) {
  .portal::before { animation: none; }
}

/* Loading spinner shown while decoding/analyzing */
.loading {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 23, 42, 0.85);
  color: white;
  font-weight: 600;
}
.loading::before {
  content: '';
  width: 20px;
  height: 20px;
  border: 3px solid rgba(255,255,255,0.3);
  border-top-color: white;
  border-radius: 50%;
  margin-right: 10px;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
