/* ============================================================
   static/css/app/gauntlet.css
   Gauntlet arcade styles — single consolidated file (v2.2).

   Section order (render order, top -> bottom of the experience):
     1.  Tokens
     2.  Screens (shell)
     3.  Intro screen
     4.  Intro settings (language + notation + note system)
     5.  HUD (exit + tier + Q + points + sfx/timer toggles)
     6.  Top meters (tier progress + heat + meta row/combo pill)
     7.  Error dots
     8.  Play area (button, wave, chord title, timing bar)
     9.  Answer grid
     10. PM elements (melody dots, count, ready/distract cards)
     11. Chord multi-select
     12. Points popup + floating callouts + combo banner
     13. Milestone overlay
     14. End screen (+ best-combo badge)
     15. Piano keyboard
     16. Revive / joker overlay
     17. Exit modal
     18. Credit modal layer
     19. Funnel result page (fr-*)
     20. Display name (intro)
     21. Keyframes
     22. Media queries
   ============================================================ */


/* -- 1. Tokens ------------------------------------------------- */
:root {
  --g-bg: #08061a;
  --g-card: #110d2a;
  --g-border: rgba(255, 255, 255, 0.07);
  --tier-color: #64748b;
}


/* -- 2. Screens (shell) --------------------------------------- */
.g-screen {
  display: none;
  flex-direction: column;
  align-items: center;
  min-height: 80vh;
  position: relative;
}

.g-screen.active {
  display: flex;
}


/* -- 3. Intro screen ------------------------------------------ */
.g-intro-icon {
  margin: 30px 0 12px;
}

.g-intro-icon-bg {
  width: 86px;
  height: 86px;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.g-intro-icon-bg--ap {
  background: rgba(110, 168, 255, 0.15);
}

.g-intro-icon-bg--rp {
  background: rgba(72, 194, 135, 0.15);
}

.g-intro-icon-bg--pm {
  background: rgba(251, 109, 109, 0.12);
}

.g-intro-title {
  font-family: 'Unbounded', sans-serif;
  font-size: 1.4rem;
  font-weight: 800;
  text-align: center;
  margin: 0 0 4px;
  letter-spacing: -0.02em;
}

.g-intro-sub {
  font-size: 0.8rem;
  color: var(--app-text-d);
  text-align: center;
  margin-bottom: 20px;
}

.g-intro-best {
  background: rgba(108, 92, 231, 0.1);
  border: 1px solid rgba(108, 92, 231, 0.25);
  border-radius: 12px;
  padding: 12px 16px;
  width: 100%;
  max-width: 420px;
  margin-bottom: 16px;
  text-align: center;
}

.g-intro-best-label {
  font-size: 0.68rem;
  color: var(--app-text-d);
  margin-bottom: 4px;
}

.g-intro-best-val {
  font-family: 'Unbounded', sans-serif;
  font-size: 1.6rem;
  font-weight: 800;
  color: var(--app-primary-l);
}

.g-rules {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  max-width: 420px;
  margin-bottom: 20px;
}

/* Note-system row — /g/ gauntlet only, sits below g-rules */
/* Note system rule — inline select inside last bullet */
.g-rule--ns {
  justify-content: space-between;
}

.g-rule-ns-sel {
  margin-left: auto;
  min-width: 110px;
  flex-shrink: 0;
}

.g-ns-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  max-width: 340px;
  padding: 12px 0 4px;
  margin-top: 20px;
  margin-bottom: 20px;
  border-top: 1px solid #2f2543;
  gap: 8px;
  flex-wrap: wrap;
}

.g-ns-row-label {
  font-size: 0.72rem;
  color: var(--app-text-d);
  text-transform: uppercase;
  letter-spacing: .04em;
  flex-shrink: 0;
}

.g-ns-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.g-ns-chip {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 999px;
  color: var(--app-text-m, #a99fc7);
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 5px 12px;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
  white-space: nowrap;
}

.g-ns-chip:hover {
  border-color: rgba(255, 255, 255, 0.35);
  color: #fff;
}

.g-ns-chip--active {
  border-color: var(--app-primary, #6c5ce7);
  color: #fff;
  background: rgba(108, 92, 231, 0.15);
}

.g-rule {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 10px;
  font-size: 0.8rem;
  color: var(--app-text-m);
}

.g-rule-icon {
  font-size: 1.3rem;
  flex-shrink: 0;
  width: 20px;
  text-align: center;
  color: var(--accent, #00cec9);
  opacity: 0.85;
}

.g-start-btn {
  width: 100%;
  max-width: 340px;
  padding: 18px;
  border-radius: 50px;
  border: none;
  background: linear-gradient(135deg, var(--app-primary) 0%, #5a4fcf 100%);
  color: #fff;
  font-family: 'Unbounded', sans-serif;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 6px 28px rgba(108, 92, 231, 0.45);
  transition: transform 0.1s, box-shadow 0.1s;
  letter-spacing: 0.04em;
}

.g-start-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 36px rgba(108, 92, 231, 0.55);
}

.g-start-btn:active {
  transform: translateY(0);
}

.g-credit-note {
  font-size: 0.76rem;
  color: var(--app-text-m);
  margin-top: 22px;
  text-align: center;
  line-height: 1.5;
}


/* -- 4. Intro settings (language + notation + note system) ---- */
.g-intro-settings {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 12px;
  width: 100%;
  max-width: 340px;
  margin: 0 0 22px;
}

.g-setting {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

.g-setting--center {
  align-items: center;
  margin-top: 18px;
}

.g-setting-label {
  font-size: 0.66rem;
  color: var(--app-text-d);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.g-mini-select {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 8px;
  color: var(--app-text, #fff);
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 500;
  padding: 6px 26px 6px 10px;
  cursor: pointer;
  outline: none;
  max-width: none;
  min-width: 130px;
  text-overflow: ellipsis;
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='rgba(255,255,255,0.5)' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 10px;
  transition: background-color 0.15s, border-color 0.15s;
}

.g-mini-select:hover {
  background-color: rgba(255, 255, 255, 0.10);
}

.g-mini-select:focus {
  border-color: var(--app-primary-l, #a29bfe);
}

.g-mini-select option {
  background: #1a1230;
  color: #f5f0ff;
}


/* -- 5. HUD --------------------------------------------------- */
.g-hud {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  padding: 10px 0 0;
  border-bottom: 1px solid var(--g-border);
  margin-bottom: 14px;
}

/* ── Row shared ── */
.g-hud-row {
  display: flex;
  align-items: center;
  width: 100%;
  gap: 8px;
}

.g-hud-spacer {
  flex: 1;
}

/* ── Row 1 ── */
.g-hud-row--top {
  justify-content: flex-start;
}

/* Q number — bigger, centered */
.g-hud-row--top .g-qnum {
  font-size: 1.1rem;
  font-weight: 800;
  color: var(--app-text);
  letter-spacing: -0.01em;
}

/* Score group: pts stacked above heat bar, right-aligned */
.g-score-group {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0px;
  flex-shrink: 0;
}

.g-score-group .g-pts-display {
  margin: 0;
}

.g-score-group .g-heat-wrap {
  margin: 0;
}

.g-tier-pill {
  flex-shrink: 1;
  padding: 5px 10px;
  border-radius: 99px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #fff;
  background: var(--tier-color);
  transition: background 0.4s, transform 0.2s;
}

.g-tier-pill.bump {
  animation: tierBump 0.3s ease;
}

.g-qnum {
  color: var(--app-text-d);
  text-align: center;
  font-weight: 600;
  font-size: 0.85rem;
}

.g-pts-display {
  font-family: 'Unbounded', sans-serif;
  font-size: 0.85rem;
  font-weight: 800;
  color: var(--app-text);
  min-width: 60px;
  text-align: right;
  transition: color 0.15s;
}

.g-pts-display.flash {
  color: var(--app-accent);
}

/* Round HUD controls: exit (left, run-only), sfx + timer toggle (right) */
.g-sfx-btn,
.g-timer-btn {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1.5px solid var(--app-accent);
  background: rgba(0, 206, 201, 0.12);
  color: var(--app-accent);
  font-size: 0.9rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.1s, box-shadow 0.15s;
  box-shadow: 0 0 8px rgba(0, 206, 201, 0.25);
}

/* Exit button — plain, not teal */
.g-exit-btn {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--g-border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--app-text-d);
  font-size: 0.9rem;
  cursor: pointer;
  display: none;
  align-items: center;
  justify-content: center;
  transition: background 0.15s, color 0.15s, transform 0.1s;
}

.g-exit-btn.visible {
  display: inline-flex;
}

.g-exit-btn:hover {
  background: rgba(255, 255, 255, 0.1);
  color: var(--app-text);
  transform: scale(1.08);
}

.g-sfx-btn:hover,
.g-timer-btn:hover {
  background: rgba(0, 206, 201, 0.22);
  border-color: var(--app-accent);
  color: #fff;
  transform: scale(1.08);
  box-shadow: 0 0 14px rgba(0, 206, 201, 0.45);
}

.g-exit-btn:active,
.g-sfx-btn:active,
.g-timer-btn:active {
  transform: scale(0.94);
}

/* OFF state — clearly inactive */
.g-sfx-btn.off,
.g-timer-btn.off {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--g-border);
  color: var(--app-text-d);
  box-shadow: none;
  opacity: 1;
}

.g-sfx-btn.off:hover,
.g-timer-btn.off:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.2);
  color: var(--app-text);
  box-shadow: none;
}


/* -- 6. Top meters -------------------------------------------- */
/* Tier-progress journey bar. Optional: if you want a lighter top,
   delete the #g-progress markup in the templates and this block. */
.g-progress {
  position: relative;
  width: 100%;
  height: 12px;
  margin-bottom: 8px;
}

.g-prog-track {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 4px;
  transform: translateY(-50%);
  background: rgba(255, 255, 255, 0.08);
  border-radius: 99px;
  overflow: hidden;
}

.g-prog-fill {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--tier-color), #f59e0b);
  border-radius: 99px;
  transition: width 0.5s ease;
}

.g-prog-knob {
  position: absolute;
  top: 50%;
  left: 0;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--tier-color);
  transform: translate(-50%, -50%);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
  transition: left 0.5s ease, border-color 0.4s;
}

/* Heat: a compact charge meter docked under the score. It fills toward
   an 8s Hot Streak (all points x2). Kept small and tied to the points so
   it reads as "score fuel" instead of another full-width bar at the top.
   JS still drives #g-heat-fill width and toggles .hot on #g-heat-wrap. */
.g-heat-wrap {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 96px;
}

.g-heat-bar {
  position: relative;
  flex: 1;
  height: 5px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 99px;
  overflow: hidden;
}

.g-heat-fill {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, #f59e0b, #f97316, #ef4444);
  border-radius: 99px;
  transition: width 0.18s linear;
}

.g-heat-x2 {
  font-family: 'Unbounded', sans-serif;
  font-size: 0.56rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: var(--app-text-d);
  opacity: 0.5;
  transition: color 0.2s, opacity 0.2s;
}

.g-heat-wrap.hot .g-heat-bar {
  box-shadow: 0 0 12px rgba(255, 45, 45, 0.55);
}

.g-heat-wrap.hot .g-heat-fill {
  background: linear-gradient(90deg, #ff7675, #ff2d2d);
}

.g-heat-wrap.hot .g-heat-x2 {
  color: #ff6b6b;
  opacity: 1;
}

/* Meta row: error dots (left) + live combo pill (right) */
.g-meta-row {
  display: flex;
  align-items: center;
  width: 100%;
  margin-bottom: 14px;
  justify-content: space-between;
}

.g-meta-row .g-score-group {
  flex: 1;
}

.g-meta-row .g-combo-pill {
  flex: 0 1 auto;
  margin: 0 auto;
}

.g-meta-row .g-error-row {
  flex: 1;
  margin: 0;
  gap: 6px;
}

.g-combo-pill {
  margin-left: unset;
  display: none;
  /* shown by JS at mult >= 1.5 */
  align-items: center;
  gap: 7px;
  padding: 4px 13px;
  border-radius: 99px;
  border: 1px solid rgba(245, 158, 11, 0.5);
  background: rgba(245, 158, 11, 0.12);
  color: #fbbf24;
  font-size: 0.72rem;
  font-weight: 700;
  animation: comboPillPop 0.25s ease;
}

.g-combo-mult {
  font-family: 'Unbounded', sans-serif;
  font-weight: 800;
}

.g-combo-streak {
  font-size: 0.6rem;
  color: var(--app-text-d);
  font-weight: 600;
}


/* -- 7. Error dots -------------------------------------------- */
.g-error-row {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

.g-edot {
  font-size: 1.3rem;
  color: #e17055;
  transition: color 0.2s, opacity 0.2s, transform 0.15s;
  filter: drop-shadow(0 0 4px rgba(225, 112, 85, 0.5));
}

.g-edot.filled {
  color: rgba(255, 255, 255, 0.25);
  filter: none;
}

.g-edot.boom {
  animation: dotBoom 0.3s ease;
}

.g-heart-minus {
  font-family: 'Unbounded', sans-serif;
  font-size: 1.1rem;
  font-weight: 900;
  color: #e17055;
  text-shadow: 0 2px 12px rgba(225, 112, 85, 0.6);
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
}

.g-heart-minus.pop {
  animation: heartMinus 1.2s ease-out forwards;
}

@keyframes heartMinus {
  0% {
    opacity: 0;
    transform: translateY(4px) scale(0.8);
  }

  15% {
    opacity: 1;
    transform: translateY(0) scale(1.15);
  }

  30% {
    transform: translateY(0) scale(1);
  }

  75% {
    opacity: 1;
    transform: translateY(-18px) scale(1);
  }

  100% {
    opacity: 0;
    transform: translateY(-28px) scale(1);
  }
}


/* -- 8. Play area --------------------------------------------- */
/* Centered so the answer block sits consistently in the middle of the
   play area across every sub-screen (listen, same/different, ready, count).
   flex:1 with default content sizing means tall content (AP grid + piano)
   simply stops centering instead of getting clipped, so nothing scrolls
   that didn't before. */
.g-play-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: clamp(16px, 3.5vh, 36px);
  flex: 1;
  width: 100%;
  padding-top: 80px;
}

[data-challenge="pm"] .g-play-area {
  justify-content: flex-start;
}

.g-play-wrap {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

.g-play-core {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100px;
  height: 100px;
}

.g-play-area:has(.g-grid-wrap.visible) .g-play-core,
.g-play-area:has(.g-grid-wrap.visible) #g-pm-state {
  display: none !important;
}

.g-play-btn {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  border: none;
  background: linear-gradient(135deg, rgb(14, 164, 160) 0%, rgb(39, 194, 190) 100%);
  color: #fff;
  font-size: 2.4rem;
  cursor: pointer;
  box-shadow: rgb(40 194 190 / 29%) 0px 6px 28px;
  transition: transform 0.12s, box-shadow 0.12s, opacity 0.15s;
  display: flex;
  align-items: center;
  justify-content: center;
}

.g-play-btn:hover:not(:disabled) {
  transform: scale(1.06);
  box-shadow: rgb(40 194 190 / 45%) 0px 10px 40px;
}

.g-play-btn:active:not(:disabled) {
  transform: scale(0.94);
}

.g-play-btn:disabled {
  opacity: 0.3;
  cursor: default;
}

.g-play-btn.playing {
  animation: playPulse 0.8s ease-in-out infinite alternate;
}

.g-play-hint {
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--app-text);
  text-align: center;
  letter-spacing: -0.01em;
  line-height: 1.4;
  min-height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.2s;
}

/* Chord title — a real heading, not a tiny label/pill */
.g-chord-badge {
  display: none;
  /* shown by JS for chord questions */
  font-family: 'Unbounded', sans-serif;
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--app-warning, #fdcb6e);
  text-align: center;
  margin-bottom: 2px;
}

/* Wave animation during playback */
.g-wave {
  position: absolute;
  inset: 0;
  display: flex;
  gap: 4px;
  align-items: center;
  justify-content: center;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.2s, visibility 0.2s;
  pointer-events: none;
}

.g-wave.active {
  visibility: visible;
  opacity: 1;
}

.g-wave span {
  border-radius: 2px;
  background: var(--app-accent);
  animation: waveBar 0.45s ease-in-out infinite alternate;
}

.g-wave span {
  width: 4px;
  height: 30%;
}

.g-wave span:nth-child(2) {
  animation-delay: .06s;
  height: 55%;
}

.g-wave span:nth-child(3) {
  animation-delay: .12s;
  height: 70%;
}

.g-wave span:nth-child(4) {
  animation-delay: .18s;
  height: 45%;
}

.g-wave span:nth-child(5) {
  animation-delay: .24s;
  height: 25%;
}

/* Timing bar — horizontal, crowns the answer area, depletes L->R.
   Speed-bonus visualiser only; never fails the player. Add the
   .hidden class (via the HUD timer toggle) to remove it for players
   who find the countdown stressful — scoring is unaffected. */
.g-timing {
  position: relative;
  width: 100%;
  height: 4px;
  margin-top: 10px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.06);
  overflow: hidden;
  opacity: 0;
  transition: opacity 0.2s;
  grid-column: 1 / -1;
}

.g-timing.active {
  opacity: 1;
}

.g-timing.hidden {
  opacity: 0 !important;
  pointer-events: none;
}

.g-timing-fill {
  height: 100%;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  border-radius: 99px;
  background: linear-gradient(90deg, var(--app-accent, #00cec9), var(--tier-color, #6C5CE7));
  box-shadow: 0 0 12px rgba(0, 206, 201, 0.55);
  will-change: transform;
}

.g-timing.warn .g-timing-fill {
  background: #fbbf24;
  box-shadow: 0 0 12px rgba(251, 191, 36, 0.6);
}

.g-timing.danger .g-timing-fill {
  background: #ef4444;
  box-shadow: 0 0 12px rgba(239, 68, 68, 0.6);
}


/* -- 9. Answer grid ------------------------------------------- */
.g-grid-wrap {
  position: relative;
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}

.g-grid-wrap.visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.g-note-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.g-pm-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.g-answer-btn {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Unbounded', sans-serif;
  font-size: 0.78rem;
  font-weight: 700;
  background: var(--app-card);
  border: 2px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  color: var(--app-text);
  cursor: pointer;
  transition: border-color 0.1s, background 0.1s, transform 0.08s;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  max-height: 50px;
  width: 100%;
}

.g-answer-btn:hover:not(:disabled) {
  border-color: var(--app-primary-l);
  background: rgba(108, 92, 231, 0.12);
  transform: translateY(-2px);
}

.g-answer-btn:active:not(:disabled) {
  transform: scale(0.91);
}

.g-answer-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.g-answer-btn.correct {
  border-color: var(--app-success) !important;
  background: rgba(0, 184, 148, 0.2) !important;
  color: #34d399;
  box-shadow: 0 0 16px rgba(0, 184, 148, 0.35);
  transform: scale(1.06);
}

.g-answer-btn.wrong {
  border-color: #e17055 !important;
  background: rgba(225, 112, 85, 0.18) !important;
  color: #e17055;
}

.g-pm-btn {
  aspect-ratio: unset;
  flex-direction: row;
  max-height: 80px;
  padding: 16px 20px;
  gap: 12px;
  border-radius: 16px;
}

.g-pm-icon {
  font-size: 1.5rem;
  line-height: 1;
  flex-shrink: 0;
}

#g-pm-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 0 20px;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.2s, visibility 0.2s;
}

#g-pm-state.visible {
  visibility: visible;
  opacity: 1;
}

.g-pm-label {
  font-family: 'Inter', sans-serif;
  font-size: 1rem;
  font-weight: 600;
  color: white;
}

.g-pm-btn--same {
  color: #34d399;
  border-color: rgba(52, 211, 153, 0.3);
}

.g-pm-btn--same:hover:not(:disabled) {
  background: rgba(52, 211, 153, 0.12);
  border-color: #34d399;
}

.g-pm-btn--different {
  color: #e17055;
  border-color: rgba(225, 112, 85, 0.3);
}

.g-pm-btn--different:hover:not(:disabled) {
  background: rgba(225, 112, 85, 0.12);
  border-color: #e17055;
}


/* -- 10. PM elements ------------------------------------------ */
.g-melody-dots {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin: 8px 0;
}

.g-melody-dot {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgb(148 143 182 / 30%);
  transition: background 0.12s;
}

.g-melody-dot.playing {
  background: var(--app-accent);
}

.g-melody-dot.played {
  background: rgba(0, 206, 201, 0.4);
}

/* The masked note currently being answered. */
.g-melody-dot.target {
  box-shadow: 0 0 0 3px rgb(153 140 255 / 63%);
  animation: rpTargetPulse 1s ease-in-out infinite;
}

.g-melody-dot.solved {
  background: var(--app-success, #00b894);
  display: flex;
  align-items: center;
  justify-content: center;
}

.g-melody-dot.wrong {
  background: var(--app-danger, #ff7675);
  display: flex;
  align-items: center;
  justify-content: center;
}

@keyframes rpTargetPulse {

  0%,
  100% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.18);
  }
}

.g-gap-label {
  font-size: 0.75rem;
  color: var(--app-text-d);
  text-align: center;
  margin: 4px 0;
}

.g-count-grid {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
}

.g-count-prompt {
  font-size: 0.84rem;
  font-weight: 700;
  color: var(--app-text-m);
  letter-spacing: .1em;
  text-transform: uppercase;
  text-align: center;
  margin: 0 0 12px;
  line-height: 1.4;
}

.g-count-btn {
  aspect-ratio: unset !important;
  width: 100%;
  max-width: 200px;
  padding: 16px 24px;
  font-family: 'Unbounded', sans-serif;
  font-size: 1.3rem;
  font-weight: 800;
  border-radius: 14px;
  letter-spacing: -0.02em;
}

.g-ready-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 28px 20px;
  background: rgba(0, 206, 201, 0.07);
  border: 1px solid rgba(0, 206, 201, 0.2);
  border-radius: 16px;
  text-align: center;
  width: 100%;
  animation: fadeSlideIn 0.25s ease forwards;
}

.g-ready-icon {
  font-size: 2rem;
}

.g-ready-title {
  font-family: 'Unbounded', sans-serif;
  font-size: 1rem;
  font-weight: 800;
  color: var(--app-text);
  letter-spacing: -0.01em;
}

.g-ready-sub {
  font-size: 0.85rem;
  color: var(--app-text-d);
  margin-bottom: 4px;
}

.g-ready-btn {
  padding: 12px 24px;
  border-radius: 50px;
  border: none;
  background: var(--app-accent);
  color: #0a1a1a;
  font-family: 'Unbounded', sans-serif;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0, 206, 201, 0.35);
  transition: transform 0.1s, box-shadow 0.1s;
}

.g-ready-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(0, 206, 201, 0.5);
}

.g-ready-btn:active {
  transform: translateY(0);
}

.g-distract-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 24px 20px;
  background: rgba(108, 92, 231, 0.1);
  border: 1px solid rgba(108, 92, 231, 0.25);
  border-radius: 16px;
  text-align: center;
  width: 100%;
  animation: fadeSlideIn 0.25s ease forwards;
}

.g-distract-icon {
  font-size: 2rem;
}

.g-distract-title {
  font-family: 'Unbounded', sans-serif;
  font-size: 0.9rem;
  font-weight: 800;
  color: var(--app-text);
  letter-spacing: -0.01em;
}

.g-distract-sub {
  font-size: 0.75rem;
  color: var(--app-text-d);
}

.g-melody-dot.correct {
  background: var(--app-success, #00b894);
}

.g-melody-dot.wrong {
  background: #e17055;
}

.g-melody-dot.gap {
  background: transparent;
  border: 2px solid var(--app-primary-l, #a29bfe);
  animation: hintPulse 0.7s ease-in-out infinite alternate;
}

/* ear intro icon tint */
.g-intro-icon-bg--ear {
  background: rgba(108, 92, 231, 0.15);
}

.g-melody-dot.hidden-q {
  background: transparent;
  border: 1px solid var(--app-primary, #6C5CE7);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: hintPulse 0.7s ease-in-out infinite alternate;
}

.g-melody-dot.hidden-q .bi-question-lg {
  font-size: 16px;
  color: #a59aff;
  line-height: 1;
  margin-left: 2px;
}

/* rp intro icon tint (reuses the rp colour) */
.g-intro-icon-bg--rp {
  background: rgba(72, 194, 135, 0.15);
}

/* -- 11. Chord multi-select ----------------------------------- */
.g-chord-grid-wrap {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.g-chord-grid-wrap .g-note-grid {
  width: 100%;
}

.g-chord-instr {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  width: 100%;
  max-width: 360px;
  margin: 0 auto 4px;
  padding: 0;
  font-size: 0.72rem;
  color: var(--app-text-d);
}

.g-chord-counter {
  font-size: 0.78rem;
  font-weight: 800;
  font-family: 'Unbounded', sans-serif;
  color: var(--app-primary-l);
  letter-spacing: 0.04em;
}

.g-answer-btn.chord-selected {
  border-color: var(--app-primary-l) !important;
  background: rgba(108, 92, 231, 0.2) !important;
  color: var(--app-primary-l);
  box-shadow: 0 0 14px rgba(108, 92, 231, 0.35);
  transform: translateY(-2px) scale(1.03);
}


/* -- 12. Points popup + callouts + combo banner --------------- */
/* Floating +points above the tapped tile (slowed for readability). */
.g-pts-popup {
  position: fixed;
  font-family: 'Unbounded', sans-serif;
  font-size: 1rem;
  font-weight: 800;
  color: var(--app-accent);
  pointer-events: none;
  z-index: 999;
  animation: ptsFloat 1700ms ease-out forwards;
  text-shadow: 0 0 20px rgba(0, 206, 201, 0.5);
}

/* Floating callouts (PERFECT / FAST / xN COMBO / HOT STREAK).
   Anchored to the top of the answer grid so they always clear the
   buttons, regardless of where the grid sits in the viewport
   (in-app has a header offset; the funnel is full-screen). */
.g-callouts {
  position: absolute;
  left: 50%;
  bottom: 100%;
  margin-bottom: 140px;
  /* lifted clear above the combo banner */
  transform: translateX(-50%);
  z-index: 450;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: max-content;
}

.g-callout {
  font-family: 'Unbounded', sans-serif;
  font-weight: 800;
  font-size: 1rem;
  letter-spacing: 0.04em;
  text-shadow: 0 0 16px rgba(0, 0, 0, 0.4);
  animation: gpPopUp 1600ms ease-out forwards;
  /* keep in sync with pushPop() */
}

.gp-perfect {
  color: #fbbf24;
}

.gp-fast {
  color: var(--app-accent);
}

.gp-combo {
  color: #fbbf24;
}

.gp-hot {
  color: #ff5e57;
  font-size: 1.25rem;
  letter-spacing: 0.08em;
}

/* Combo banner (xN COMBO / +pts). Anchored just above the answer grid so
   it sits in the gap above the buttons in every layout. JS clears it on
   each new question (removes .show) so it never lingers. */
.g-combo-banner {
  position: absolute;
  left: 50%;
  bottom: 100%;
  margin-bottom: 20px;
  /* small gap above the grid's top edge */
  transform: translateX(-50%);
  text-align: center;
  pointer-events: none;
  z-index: 400;
  opacity: 0;
  width: max-content;
}

.g-combo-banner.show {
  animation: comboBanner 1.9s ease-out forwards;
}

.g-combo-banner-mult {
  font-family: 'Unbounded', sans-serif;
  font-size: 2rem;
  font-weight: 900;
  color: #fbbf24;
  letter-spacing: -0.02em;
  text-shadow: 0 2px 20px rgba(245, 158, 11, 0.5);
}

.g-combo-banner-pts {
  font-family: 'Unbounded', sans-serif;
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--app-accent);
  margin-top: 2px;
  text-shadow: 0 0 20px rgba(0, 206, 201, 0.5);
}


/* -- 13. Milestone overlay ------------------------------------ */
#g-milestone {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s;
  cursor: pointer;
}

#g-milestone.show {
  opacity: 1;
  pointer-events: auto;
}

.g-ms-bg {
  position: absolute;
  inset: 0;
  background: var(--tier-color);
  opacity: 1;
}

.g-ms-content {
  position: relative;
  z-index: 1;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.g-ms-sup {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
}

.g-ms-label {
  font-family: 'Unbounded', sans-serif;
  font-size: 3rem;
  font-weight: 900;
  color: #fff;
  letter-spacing: -0.03em;
  animation: msLabelIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.g-ms-sub {
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.75);
}

.g-ms-particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.g-ms-particle {
  position: absolute;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.6);
  animation: particleFloat linear forwards;
}

/* Continue button on the level-up overlay. White pill on the tier-coloured
   background so it pops; text picks up the current tier colour. */
.g-ms-continue {
  position: relative;
  z-index: 1;
  margin-top: 16px;
  padding: 13px 30px;
  border: none;
  border-radius: 50px;
  background: #fff;
  color: var(--tier-color, #6C5CE7);
  font-family: 'Unbounded', sans-serif;
  font-size: 0.92rem;
  font-weight: 800;
  letter-spacing: 0.01em;
  cursor: pointer;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.28);
  transition: transform 0.1s, box-shadow 0.1s;
}

.g-ms-continue:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.34);
}

.g-ms-continue:active {
  transform: translateY(0);
}


/* -- 14. End screen ------------------------------------------- */
.g-end-icon {
  margin: 30px 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.g-end-icon-img {
  width: 90px;
  height: 90px;
  margin-bottom: 10px;
  object-fit: contain;
}

.g-end-title {
  font-family: 'Unbounded', sans-serif;
  font-size: 1.5rem;
  font-weight: 800;
  text-align: center;
  margin-bottom: 4px;
}

.g-end-tier {
  font-size: 0.85rem;
  color: var(--app-text-d);
  text-align: center;
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.g-end-pts-card {
  background: linear-gradient(135deg, rgba(108, 92, 231, 0.15), rgba(0, 206, 201, 0.1));
  border: 1px solid rgba(108, 92, 231, 0.3);
  border-radius: 16px;
  padding: 20px;
  width: 100%;
  max-width: 340px;
  text-align: center;
  margin: 12px 0;
}

.g-end-pts-label {
  font-size: 0.68rem;
  color: var(--app-text-d);
  margin-bottom: 4px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.g-end-pts-val {
  font-family: 'Unbounded', sans-serif;
  font-size: 2rem;
  font-weight: 900;
  color: var(--app-accent);
  letter-spacing: -0.03em;
  line-height: 1;
}

.g-end-pts-sub {
  font-size: 0.72rem;
  color: var(--app-text-d);
  margin-top: 4px;
}

/* Best-combo badge (set by gauntlet.js) */
.g-end-combo-badge {
  display: none;
  font-size: 0.74rem;
  font-weight: 700;
  color: var(--app-text-m);
  text-align: center;
  margin-bottom: 14px;
}

.g-end-combo-badge strong {
  color: #fbbf24;
  font-family: 'Unbounded', sans-serif;
}

.g-end-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  width: 100%;
  max-width: 340px;
  margin-bottom: 12px;
}

.g-end-stat {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--g-border);
  border-radius: 10px;
  padding: 12px;
  text-align: center;
  background: var(--pf-bg-card);
  border: 1px solid var(--pf-border);
}

.g-end-stat-label {
  font-size: 0.82rem;
  color: var(--app-text-d);
  margin-bottom: 3px;
}

.g-end-stat-val {
  font-size: 1.1rem;
  font-weight: 800;
  color: var(--app-primary-l);
}

/* Pulsing placeholder while the server rank is in flight */
.g-end-stat-val.g-stat-loading {
  color: var(--app-text-d);
  letter-spacing: 0.15em;
  animation: statLoading 1s ease-in-out infinite;
}

.g-end-gap {
  font-size: 0.78rem;
  color: var(--app-text-d);
  text-align: center;
  margin-bottom: 20px;
  padding: 8px 16px;
  background: rgba(253, 203, 110, 0.07);
  border: 1px solid rgba(253, 203, 110, 0.2);
  border-radius: 10px;
  max-width: 340px;
  width: 100%;
}

.g-end-gap strong {
  color: var(--app-warning);
}

#g-workout-next {
  margin: 0 0 4px;
  padding: 0;
  border-top: 0;
  text-wrap-style: pretty;
  width: 100%;
    max-width: 340px;
}

#g-workout-next:empty {
  margin: 0;
}

.g-new-best-badge {
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--app-accent);
  background: rgba(0, 206, 201, 0.12);
  border: 1px solid rgba(0, 206, 201, 0.3);
  border-radius: 20px;
  padding: 4px 12px;
  margin-bottom: 12px;
  display: none;
}

.g-new-best-badge.show {
  display: inline-block;
}

.g-again-btn {
  width: 100%;
  max-width: 340px;
  padding: 16px;
  border-radius: 50px;
  border: none;
  background: linear-gradient(135deg, var(--app-primary), #5a4fcf);
  color: #fff;
  font-family: 'Unbounded', sans-serif;
  font-size: 0.9rem;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 4px 20px rgba(108, 92, 231, 0.4);
  text-decoration: none;
  text-align: center;
  display: block;
  margin-bottom: 8px;
  transition: transform 0.15s, box-shadow 0.15s;
}


.g-again-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 32px rgba(108, 92, 231, 0.6);
}

.g-again-btn:active {
  transform: translateY(0);
  box-shadow: 0 4px 16px rgba(108, 92, 231, 0.35);
}

.g-home-btn {
  color: var(--app-accent);
  text-underline-offset: 2px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
  font-size: 0.95rem;
    margin-top: 10px;
}

/* -- 15. Piano keyboard (realistic grey, visible front faces) - */
.g-piano-wrap {
  width: 100%;
  margin-top: 14px;
  padding-top: 4px;
}

.g-piano {
  position: relative;
  height: 96px;
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
  background:
    linear-gradient(180deg, #2a2a30 0%, #16161b 12%) top / 100% 9px no-repeat,
    #0c0c10;
  border-radius: 5px 5px 8px 8px;
  padding: 7px 4px 8px;
  box-shadow:
    0 6px 22px rgba(0, 0, 0, 0.6),
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    inset 0 -1px 0 rgba(0, 0, 0, 0.7);
  user-select: none;
  --wkw: 7.143%;
}

.g-pkey {
  position: absolute;
  border: none;
  outline: none;
  padding: 0;
  cursor: pointer;
  transition: filter 0.06s, transform 0.06s;
  -webkit-tap-highlight-color: transparent;
}

/* WHITE KEY
   Element = top playing surface (slightly matte).
   ::after  = the lit front face we can see, with a crease line above it. */
.g-pkey-w {
  top: 7px;
  bottom: 6px;
  left: calc(var(--wi) * var(--wkw));
  width: calc(var(--wkw) - 2px);
  background: linear-gradient(180deg, #ffffff 0%, #f4f4f4 60%, #e9e9ee 100%);
  border-radius: 0 0 6px 6px;
  z-index: 1;
  box-shadow:
    inset 1px 0 1px rgba(255, 255, 255, 0.8),
    /* left bevel */
    inset -2px 0 3px rgba(0, 0, 0, 0.14),
    /* right-edge gap shadow */
    0 3px 4px rgba(0, 0, 0, 0.35);
  /* drop onto case */
}

.g-pkey-w::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 16px;
  border-radius: 0 0 6px 6px;
  /* brighter than the top surface = the lit front face */
  background: linear-gradient(180deg, #ededf1 0%, #dedde4 50%, #c8c8d0 100%);
  box-shadow: inset 0 2px 3px rgba(0, 0, 0, 0.13);
  /* crease: the fold edge */
  pointer-events: none;
}

.g-pkey-w:hover {
  filter: brightness(1.02);
}

.g-pkey-w:active {
  filter: brightness(0.94);
  transform: translateY(1px) scaleY(0.99);
  transform-origin: top;
}

/* BLACK KEY
   Element = dark top, brightening toward the bottom (front face lit).
   ::after  = rounded gloss on the LOWER front, not the top. */
.g-pkey-b {
  top: 7px;
  height: 60%;
  left: calc(var(--slot) * var(--wkw));
  width: calc(var(--wkw) * 0.6 - 1px);
  background: linear-gradient(180deg, #15151a 0%, #101015 45%, #232329 90%, #34343c 100%);
  border-radius: 0 0 5px 5px;
  z-index: 2;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    /* faint top edge only */
    inset 0 -3px 4px rgba(0, 0, 0, 0.55),
    1px 4px 9px rgba(0, 0, 0, 0.65);
  /* cast onto whites */
}

.g-pkey-b::after {
  content: "";
  position: absolute;
  left: 20%;
  right: 20%;
  bottom: 14%;
  height: 38%;
  border-radius: 4px;
  /* gloss fades UP from the lit front face */
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(200, 200, 212, 0.55) 100%);
  pointer-events: none;
}

.g-pkey-b:hover {
  filter: brightness(1.18);
}

.g-pkey-b:active {
  filter: brightness(0.8);
  transform: translateY(1px) scaleY(0.97);
  transform-origin: top;
}

/* State highlights — your colors, retuned. The ::after still rides on top,
   so correct/wrong/selected keep their front-face sheen. */
.g-pkey.key-correct {
  background: linear-gradient(180deg, #00e6bd 0%, #00b894 100%) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6), 0 0 16px rgba(0, 184, 148, 0.6) !important;
}

.g-pkey.key-wrong {
  background: linear-gradient(180deg, #ff8a89 0%, #e17055 100%) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 0 10px rgba(225, 112, 85, 0.55) !important;
}

.g-pkey.key-selected {
  background: linear-gradient(180deg, #a29bfe 0%, #6c5ce7 100%) !important;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    0 0 12px rgba(108, 92, 231, 0.6) !important;
}

.g-pkey:disabled {
  cursor: default;
}

/* When a key is in a result/selected state, tint its 3D front face too,
   so the color runs all the way to the bottom instead of stopping at
   the grey lip. Slightly darker at the base = keeps the rounded look. */
.g-pkey.key-correct::after {
  background: linear-gradient(180deg,
      rgba(0, 230, 189, 0.55) 0%, rgba(0, 184, 148, 0.85) 60%, #00a884 100%);
  box-shadow: none;
}

.g-pkey.key-wrong::after {
  background: linear-gradient(180deg,
      rgba(255, 138, 137, 0.55) 0%, rgba(225, 112, 85, 0.85) 60%, #d9603f 100%);
  box-shadow: none;
}

.g-pkey.key-selected::after {
  background: linear-gradient(180deg,
      rgba(162, 155, 254, 0.55) 0%, rgba(108, 92, 231, 0.9) 60%, #5a4fcf 100%);
  box-shadow: none;
}

/* Masked note sounding — every key flashes a ? so the player hears the
   pitch but isn't shown where it lives. */
.g-pkey.key-quiz::before {
  content: "?";
  position: absolute;
  left: 50%;
  bottom: 8px;
  transform: translateX(-50%);
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #6c5ce7b1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Unbounded', sans-serif;
  font-weight: 800;
  font-size: 1rem;
  color: white;
  pointer-events: none;
  z-index: 3;
}

.g-pkey-b.key-quiz::before {
  font-size: 1rem;
  bottom: 6px;
}

/* RP hidden mode: reference keys — the heard, visible neighbours of the
   masked note. Lit but clearly "given", distinct from an answer state. */
.g-pkey.key-ref {
  background: linear-gradient(180deg, #a29bfe 0%, #6c5ce7 100%) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5), 0 0 10px rgba(108, 92, 231, 0.45) !important;
}

.g-pkey.key-ref::after {
  background: linear-gradient(180deg,
      rgba(162, 155, 254, 0.5) 0%, rgba(108, 92, 231, 0.85) 60%, #5a4fcf 100%);
  box-shadow: none;
}

/* Keep the melody dots (with the ? marker) visible beside the keyboard. */
.g-play-area.rp-hidden:has(.g-grid-wrap.visible) #g-pm-state {
  display: flex !important;
}

/* RP stays within a single octave, so collapse the keyboard to one octave
   on all widths. Scoped to RP so AP/EAR/PM keep their default layout. */
.g-play-area.rp-hidden .g-piano {
  --wkw: 14.286%;
  height: 200px;
}

.g-play-area.rp-hidden .g-pkey[data-oct="2"] {
  display: none;
}

/* -- 16. Revive / joker overlay ------------------------------- */
#g-revive {
  position: fixed;
  inset: 0;
  z-index: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s;
}

#g-revive.show {
  opacity: 1;
  pointer-events: auto;
}

.g-rev-bg {
  position: absolute;
  inset: 0;
  background: rgba(8, 6, 26, 0.82);
  backdrop-filter: blur(6px);
}

.g-rev-card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 340px;
  background: var(--g-card);
  border-radius: 20px;
  padding: 28px 22px 22px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
  animation: msLabelIn 0.32s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.g-rev-icon {
  font-size: 2.6rem;
  line-height: 1;
}

.g-rev-title {
  font-family: 'Unbounded', sans-serif;
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--app-text);
  letter-spacing: -0.02em;
}

.g-rev-sub {
  font-size: 0.82rem;
  color: var(--app-text-d);
  line-height: 1.5;
  margin-bottom: 6px;
}

.g-rev-use {
  width: 100%;
  padding: 16px;
  border-radius: 50px;
  border: none;
  background: linear-gradient(135deg, var(--app-primary), #5a4fcf);
  color: #fff;
  font-family: 'Unbounded', sans-serif;
  font-size: 0.92rem;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.1s, box-shadow 0.1s, opacity 0.15s;
}

.g-rev-use:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 8px 30px rgba(108, 92, 231, 0.55);
}

.g-rev-use:active:not(:disabled) {
  transform: translateY(0);
}

.g-rev-use:disabled {
  opacity: 0.5;
  cursor: default;
}

.g-rev-decline {
  font-size: 0.8rem;
  color: var(--app-text-d);
  background: none;
  border: none;
  cursor: pointer;
  text-underline-offset: 2px;
  padding: 6px;
}

.g-rev-err {
  font-size: 0.74rem;
  color: #e17055;
  min-height: 1em;
}

.g-rev-buy-link {
  color: var(--app-primary-l);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}


/* -- 17. Exit modal ------------------------------------------- */
#g-exit-modal {
  position: fixed;
  inset: 0;
  z-index: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s;
}

#g-exit-modal.show {
  opacity: 1;
  pointer-events: auto;
}


/* -- 18. Credit modal layer ----------------------------------- */
#credit-modal-overlay {
  z-index: 700;
}


/* -- 19. Funnel result page (fr-*) ---------------------------- */
.fr-wrap {
  max-width: 420px;
  margin: 0 auto;
  text-align: center;
  padding: 24px 20px 48px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* Header */
.fr-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}

.fr-icon-img {
  width: 72px;
  height: 72px;
  object-fit: contain;
}

.fr-title {
  font-family: 'Unbounded', sans-serif;
  font-size: 1.35rem;
  font-weight: 800;
  margin: 0;
  letter-spacing: -0.02em;
}

.fr-sub {
  font-size: 0.8rem;
  color: var(--app-text-d);
  margin: 0;
}

/* Score card */
.fr-score-card {
  background: linear-gradient(135deg, rgba(108, 92, 231, 0.15), rgba(0, 206, 201, 0.08));
  border: 1px solid rgba(108, 92, 231, 0.3);
  border-radius: 18px;
  padding: 24px 20px 20px;
}

.fr-score-label {
  font-size: 0.64rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--app-text-d);
  margin-bottom: 6px;
}

.fr-score-val {
  font-family: 'Unbounded', sans-serif;
  font-size: 2rem;
  font-weight: 900;
  color: var(--app-accent);
  line-height: 1;
}

.fr-pct {
  font-size: 0.82rem;
  color: var(--app-primary-l);
  margin-top: 10px;
  font-weight: 600;
}

/* Distribution */
.fr-dist-card {
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid var(--g-border, rgba(255, 255, 255, 0.07));
  border-radius: 18px;
  padding: 18px 16px 14px;
}

.fr-dist-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.7rem;
  color: var(--app-text-d);
  margin-bottom: 14px;
  text-transform: uppercase;
  letter-spacing: .05em;
}

.fr-dist-top {
  font-weight: 700;
  color: var(--app-text);
  letter-spacing: 0;
  text-transform: none;
}

.fr-dist-bars {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 100px;
}

.fr-bar-col {
  flex: 1;
  height: 100%;
  display: flex;
  align-items: flex-end;
}

.fr-bar {
  width: 100%;
  border-radius: 4px 4px 2px 2px;
  background: rgba(255, 255, 255, 0.1);
  transition: height .4s ease;
}

.fr-bar-you {
  background: linear-gradient(180deg, var(--app-accent), #00b894);
  box-shadow: 0 0 14px rgba(0, 206, 201, 0.45);
}

.fr-dist-axis {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.6rem;
  color: var(--app-text-d);
  margin-top: 10px;
}

.fr-you-tag {
  color: var(--app-accent);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .06em;
}

/* Save / countdown card */
.fr-save-card {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(108, 92, 231, 0.2);
  border-radius: 18px;
  padding: 20px 20px 18px;
}

.fr-save-row {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 12px;
  justify-content: space-between;
}

.fr-save-icon {
  color: var(--app-text-d);
  font-size: 0.82rem;
  flex-shrink: 0;
}

.fr-save-text {
  font-size: 0.82rem;
  color: var(--app-text-d);
  margin-left: 6px;
}

.fr-save-val {
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--app-text);
  flex-shrink: 0;
}

.fr-progress {
  height: 5px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.07);
  overflow: hidden;
}

.fr-progress-fill {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--app-primary), var(--app-accent));
  border-radius: 99px;
  transition: width .6s ease;
}

.fr-save-btn {
  width: 100%;
  padding: 16px;
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, var(--app-primary) 0%, #5a4fcf 100%);
  color: #fff;
  font-family: 'Unbounded', sans-serif;
  font-size: 0.9rem;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 6px 24px rgba(108, 92, 231, 0.4);
  transition: transform 0.15s, box-shadow 0.15s;
  letter-spacing: 0.02em;
}

.fr-save-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 32px rgba(108, 92, 231, 0.55);
}

.fr-save-btn:active {
  transform: translateY(0);
  box-shadow: 0 4px 16px rgba(108, 92, 231, 0.35);
}

/* Claim / signup card */
.fr-claim-card {
  background: linear-gradient(135deg, rgba(0, 206, 201, 0.07), rgba(108, 92, 231, 0.07));
  border: 1px solid rgba(0, 206, 201, 0.2);
  border-radius: 18px;
  padding: 28px 22px 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.fr-claim-img {
  width: 56px;
  height: 56px;
  object-fit: contain;
}

.fr-claim-title {
  font-family: 'Unbounded', sans-serif;
  font-size: 1rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--app-text);
  margin: 0;
}

.fr-claim-sub {
  font-size: 0.82rem;
  color: var(--app-text-d);
  line-height: 1.55;
  margin: 0 0 4px;
  max-width: 300px;
}

.fr-compare-sub {
  font-size: 14px;
}

.fr-claim-cta {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 16px;
  border-radius: 50px;
  text-decoration: none;
  text-align: center;
  background: var(--app-accent);
  color: #0a1a1a;
  font-family: 'Unbounded', sans-serif;
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  box-shadow: 0 6px 24px rgba(0, 206, 201, 0.35);
  transition: transform 0.15s, box-shadow 0.15s;
}

.fr-claim-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 32px rgba(0, 206, 201, 0.5);
  background: #00B5B0;
}

.fr-claim-cta:active {
  transform: translateY(0);
  box-shadow: 0 4px 16px rgba(0, 206, 201, 0.25);
}

.fr-powered {
  font-size: 0.66rem;
  color: var(--app-text-d);
  margin: 4px 0 0;
}

/* Keep modal classes for any other templates that reference them */
.fr-modal {
  position: fixed;
  inset: 0;
  z-index: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s;
}

.fr-modal.show {
  opacity: 1;
  pointer-events: auto;
}

.fr-modal-bg {
  position: absolute;
  inset: 0;
  background: rgba(8, 6, 26, 0.82);
  backdrop-filter: blur(6px);
}

.fr-modal-card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 340px;
  background: var(--g-card, #110d2a);
  border: 1px solid rgba(108, 92, 231, 0.3);
  border-radius: 20px;
  padding: 28px 22px 20px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}

.fr-modal-icon {
  font-size: 2.4rem;
}

.fr-modal-title {
  font-family: 'Unbounded', sans-serif;
  font-size: 1.15rem;
  font-weight: 800;
}

.fr-modal-sub {
  font-size: 0.82rem;
  color: var(--app-text-d);
  line-height: 1.5;
  margin: 0 0 6px;
}

.fr-modal-cta {
  width: 100%;
  box-sizing: border-box;
  padding: 15px;
  border-radius: 50px;
  text-decoration: none;
  text-align: center;
  background: linear-gradient(135deg, var(--app-primary), #5a4fcf);
  color: #fff;
  font-family: 'Unbounded', sans-serif;
  font-size: 0.9rem;
  font-weight: 700;
  transition: transform 0.15s, box-shadow 0.15s;
}

.fr-modal-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 28px rgba(108, 92, 231, 0.5);
}

.fr-modal-cta:active {
  transform: translateY(0);
}

.fr-modal-close {
  font-size: 0.8rem;
  color: var(--app-text-d);
  background: none;
  border: none;
  cursor: pointer;
  text-underline-offset: 2px;
  padding: 6px;
}

/* -- 20. Display name (intro) --------------------------------- */
.g-name-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 0.8rem;
  color: var(--app-text-d);
}

.g-name-value {
  color: var(--app-text);
  font-weight: 700;
}

.g-name-edit {
  background: none;
  border: none;
  color: var(--app-primary-l);
  cursor: pointer;
  font-size: 0.85rem;
  padding: 2px 4px;
}

.g-name-editor {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 14px;
  width: 100%;
  max-width: 340px;
  flex-wrap: wrap;
  justify-content: center;
}

.g-mini-input {
  flex: 1;
  min-width: 140px;
  padding: 8px 12px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 8px;
  color: var(--app-text);
  font-size: 0.82rem;
  outline: none;
}

.g-mini-input:focus {
  border-color: var(--app-primary-l);
}

.g-name-save,
.g-name-cancel {
  padding: 8px 14px;
  border-radius: 8px;
  border: none;
  cursor: pointer;
  font-size: 0.78rem;
  font-weight: 700;
}

.g-name-save {
  background: var(--app-primary);
  color: #fff;
}

.g-name-cancel {
  background: rgba(255, 255, 255, 0.08);
  color: var(--app-text-d);
}

.g-name-hint {
  font-size: 0.72rem;
  margin-top: 6px;
  min-height: 1em;
  text-align: center;
}


/* -- 21. Keyframes -------------------------------------------- */
@keyframes playPulse {
  from {
    box-shadow: 0 8px 32px rgba(108, 92, 231, 0.5);
  }

  to {
    box-shadow: 0 8px 48px rgba(0, 206, 201, 0.65);
  }
}

@keyframes waveBar {
  from {
    height: 4px;
    opacity: 0.5;
  }

  to {
    height: 22px;
    opacity: 1;
  }
}

@keyframes dotBoom {
  0% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.7);
  }

  100% {
    transform: scale(1);
  }
}

@keyframes tierBump {
  0% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.15);
  }

  100% {
    transform: scale(1);
  }
}

@keyframes msLabelIn {
  0% {
    transform: scale(0.4) translateY(20px);
    opacity: 0;
  }

  100% {
    transform: scale(1) translateY(0);
    opacity: 1;
  }
}

@keyframes particleFloat {
  0% {
    transform: translateY(0) rotate(0deg);
    opacity: 1;
  }

  100% {
    transform: translateY(-100vh) rotate(720deg);
    opacity: 0;
  }
}

@keyframes hintPulse {
  from {
    opacity: 0.3;
  }

  to {
    opacity: 0.85;
  }
}

@keyframes fadeSlideIn {
  from {
    opacity: 0;
    transform: translateY(8px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes screenShake {

  0%,
  100% {
    transform: translateX(0);
  }

  20% {
    transform: translateX(-10px);
  }

  40% {
    transform: translateX(10px);
  }

  60% {
    transform: translateX(-7px);
  }

  80% {
    transform: translateX(7px);
  }
}

.shake {
  animation: screenShake 0.4s ease;
}

@keyframes correctFlash {
  0% {
    background: rgba(0, 206, 201, 0.25);
  }

  100% {
    background: transparent;
  }
}

.correct-flash {
  animation: correctFlash 0.4s ease;
}

/* combo pill pop-in */
@keyframes comboPillPop {
  0% {
    transform: scale(0.8);
    opacity: 0.4;
  }

  60% {
    transform: scale(1.08);
  }

  100% {
    transform: scale(1);
    opacity: 1;
  }
}

/* rank placeholder pulse */
@keyframes statLoading {

  0%,
  100% {
    opacity: 0.35;
  }

  50% {
    opacity: 0.9;
  }
}

/* floating +points (slow, with a hold) */
@keyframes ptsFloat {
  0% {
    opacity: 0;
    transform: translateY(6px) scale(0.9);
  }

  14% {
    opacity: 1;
    transform: translateY(0) scale(1.05);
  }

  26% {
    transform: translateY(-4px) scale(1);
  }

  74% {
    opacity: 1;
    transform: translateY(-22px) scale(1);
  }

  100% {
    opacity: 0;
    transform: translateY(-52px) scale(1);
  }
}

/* floating callouts (slow, with a hold) */
@keyframes gpPopUp {
  0% {
    opacity: 0;
    transform: translateY(8px) scale(0.9);
  }

  12% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }

  72% {
    opacity: 1;
    transform: translateY(-10px) scale(1);
  }

  100% {
    opacity: 0;
    transform: translateY(-46px) scale(1);
  }
}

/* big combo banner (slow, with a long hold).
   Banner is bottom-anchored above the grid and centred via translateX(-50%),
   so only translateY animates the float. */
@keyframes comboBanner {
  0% {
    opacity: 0;
    transform: translateX(-50%) translateY(12px) scale(0.85);
  }

  12% {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1.05);
  }

  22% {
    transform: translateX(-50%) translateY(0) scale(1);
  }

  78% {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }

  100% {
    opacity: 0;
    transform: translateX(-50%) translateY(-12px) scale(1);
  }
}


/* -- 22. Media queries ---------------------------------------- */
@media (min-width: 769px) {
  .g-grid-wrap {
    max-width: 560px;
  }

  .g-note-grid {
    max-width: 380px;
    margin: 0 auto;
  }

  .g-piano-wrap {
    max-width: 100%;
    margin-top: 18px;
  }

  .g-piano {
    height: 138px;
    max-width: 100%;
  }

  .g-pkey-b {
    height: 62%;
  }

  .g-pm-grid {
    max-width: 420px;
    margin: 0 auto;
  }

  .pfw-grid {
    flex-direction: column !important;
    align-items: center;
  }
}

/* On phones, two octaves makes each key too thin to read. Drop to a single
   octave: 7 white keys span the full width and the second octave is hidden.
   One key per pitch class also means the answer highlight lands on exactly
   one key. Driven entirely by --wkw, so no per-key overrides are needed. */
@media (max-width: 768px) {
  .g-piano {
    --wkw: 14.286%;
    height: 150px;
  }

  .g-pkey[data-oct="2"] {
    display: none;
  }

  #g-workout-next {
    width: 100%;
  }
}