/* ═══════════════════════════════════════════════════════
   ✦ QQ空间豪华 × 少女游戏 × 星河宇宙 ✦
   Mobile-first · 480px max · No libraries
   ═══════════════════════════════════════════════════════ */

/* ──────── Safe-area custom properties ──────── */
:root {
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --appH: 100vh; /* overridden by JS for iOS Safari */
}

/* ──────── Reset ──────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: 100%;
  height: 100%;
  height: -webkit-fill-available;
}

body {
  min-height: var(--appH);
  height: var(--appH);
  font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
               system-ui, -apple-system, sans-serif;
  color: #e8dffe;
  background: #0a0618;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  /* Prevent WeChat screenshot overlay + text selection globally */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* ──────── Galaxy Canvas ──────── */
#galaxyCanvas {
  position: fixed;
  inset: 0;
  width: 100%; height: 100%;
  z-index: 0;
  pointer-events: none;
}

/* ──────── Overlay: Light Rays ──────── */
.overlay-rays {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    conic-gradient(from 30deg at 25% 15%,
      transparent 0deg, rgba(180, 140, 255, 0.04) 15deg,
      transparent 30deg, transparent 90deg,
      rgba(255, 180, 220, 0.03) 105deg, transparent 120deg,
      transparent 180deg, rgba(140, 200, 255, 0.03) 195deg,
      transparent 210deg, transparent 270deg,
      rgba(200, 160, 255, 0.04) 285deg, transparent 300deg,
      transparent 360deg);
  animation: raysRotate 45s linear infinite;
  opacity: 0.8;
}
@keyframes raysRotate {
  to { transform: rotate(360deg); }
}

/* ──────── Overlay: Shimmer ──────── */
.overlay-shimmer {
  position: fixed;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(
    120deg,
    transparent 30%,
    rgba(200, 180, 255, 0.06) 38%,
    rgba(255, 200, 230, 0.04) 42%,
    transparent 50%
  );
  background-size: 200% 100%;
  animation: shimmerSlide 6s ease-in-out infinite;
}
@keyframes shimmerSlide {
  0%, 100% { background-position: 200% 0; }
  50%      { background-position: -100% 0; }
}

/* ──────── Cross-shaped Stars (CSS) ──────── */
.cross-stars {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  overflow: hidden;
}
.cross-star {
  position: absolute;
  width: 2px; height: 2px;
  /* 4-point cross via box-shadow */
  background: #fff;
  border-radius: 50%;
  box-shadow:
    0 -6px 3px -2px rgba(255,255,255,0.8),
    0  6px 3px -2px rgba(255,255,255,0.8),
   -6px 0  3px -2px rgba(255,255,255,0.8),
    6px 0  3px -2px rgba(255,255,255,0.8),
    0 0 8px 2px rgba(200,180,255,0.6),
    0 0 16px 4px rgba(200,180,255,0.25);
  animation: crossTwinkle var(--dur) ease-in-out infinite;
  animation-delay: var(--delay);
  opacity: 0;
}
@keyframes crossTwinkle {
  0%, 100% { opacity: 0; transform: scale(0.5) rotate(0deg); }
  50%      { opacity: 1; transform: scale(1.2) rotate(45deg); }
}

/* ──────── Floating Dust (CSS) ──────── */
.dust-layer {
  position: fixed;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  overflow: hidden;
}
.dust {
  position: absolute;
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,220,255,0.9), transparent 70%);
  animation: dustFloat var(--dur) ease-in-out infinite;
  animation-delay: var(--delay);
  opacity: 0;
}
@keyframes dustFloat {
  0%   { opacity: 0; transform: translateY(0) translateX(0); }
  20%  { opacity: 0.7; }
  80%  { opacity: 0.5; }
  100% { opacity: 0; transform: translateY(calc(-40vh - 30px)) translateX(calc(var(--drift))); }
}

/* ──────── Vignette (edge darkening) ──────── */
.overlay-vignette {
  position: fixed;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: radial-gradient(ellipse 70% 65% at 50% 50%,
    transparent 40%,
    rgba(5, 2, 20, 0.35) 70%,
    rgba(5, 2, 20, 0.7) 100%);
}

/* ──────── Center Bloom (soft radial light) ──────── */
.overlay-bloom {
  position: fixed;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: radial-gradient(ellipse 50% 40% at 50% 48%,
    rgba(180, 140, 255, 0.06) 0%,
    rgba(255, 130, 200, 0.03) 30%,
    transparent 65%);
  animation: bloomPulse 6s ease-in-out infinite;
}
@keyframes bloomPulse {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1; }
}

/* ──────── Main Wrap ──────── */
.wrap {
  position: relative;
  z-index: 10;
  width: min(480px, 94vw);
  min-height: var(--appH);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sat) 0 var(--sab);
}

/* ──────── Page Transitions ──────── */
.page {
  width: 100%;
  transition: opacity 0.8s ease, transform 0.8s ease;
}
.page.hidden { display: none !important; }
.page.fade-out {
  opacity: 0;
  transform: translateY(16px) scale(0.96);
}
.page.fade-in {
  animation: pageFadeIn 0.9s ease both;
}
@keyframes pageFadeIn {
  from { opacity: 0; transform: translateY(20px) scale(0.95); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ═══════════════════════════════════
   Headphone Prompt Page (first visit)
   ═══════════════════════════════════ */
.headphone-page {
  position: fixed;
  inset: 0;
  z-index: 25;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: var(--appH);
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
}
.headphone-page.hidden {
  display: none !important;
}
.headphone-page.fade-out {
  opacity: 0;
  transition: opacity 0.5s ease;
  pointer-events: none;
}
.headphone-inner {
  text-align: center;
  animation: hpFadeIn 1s ease both;
}
@keyframes hpFadeIn {
  from { opacity: 0; transform: translateY(18px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.hp-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 10px;
}
.hp-headphone {
  width: 46px;
  height: 46px;
  color: rgba(220,190,255,0.88);
  filter:
    drop-shadow(0 0 6px rgba(210,170,255,0.45))
    drop-shadow(0 0 16px rgba(180,140,255,0.25));
  opacity: 0.95;
  animation: hpGlow 2.6s ease-in-out infinite;
}
@keyframes hpGlow {
  0%, 100% {
    transform: translateY(0) scale(1);
    filter:
      drop-shadow(0 0 6px rgba(210,170,255,0.38))
      drop-shadow(0 0 16px rgba(180,140,255,0.20));
    opacity: 0.86;
  }
  50% {
    transform: translateY(-1px) scale(1.03);
    filter:
      drop-shadow(0 0 10px rgba(230,200,255,0.62))
      drop-shadow(0 0 26px rgba(190,150,255,0.34));
    opacity: 1;
  }
}
.headphone-title {
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 5px;
  color: rgba(220,210,245,0.6);
  margin-bottom: 12px;
  text-shadow: 0 0 14px rgba(200,160,255,0.2);
}
.headphone-subtitle {
  font-size: 13px;
  letter-spacing: 2px;
  color: rgba(200,180,255,0.45);
  margin-bottom: 36px;
  text-shadow: 0 0 10px rgba(180,140,255,0.15);
}

/* ═══════════════════════════════════
   Gate — Full-screen Cosmic Mirror
   Signature + Long-press + Ripples
   ═══════════════════════════════════ */
.gate-page {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100% !important;
  height: var(--appH) !important;
  padding: 0 !important;
  cursor: default;
  -webkit-user-select: none;
  user-select: none;
}

/* Overlay canvases */
#rippleCanvas,
#dustTrailCanvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
#dustTrailCanvas { z-index: 1; }
#rippleCanvas    { z-index: 3; }

/* Floating content */
.gate-content {
  position: relative;
  z-index: 5;
  text-align: center;
  pointer-events: auto;
  animation: gateContentFloat 5s ease-in-out infinite;
}
@keyframes gateContentFloat {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}

/* Step visibility */
.gate-step {
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.gate-step-hidden {
  display: none;
}
.gate-step.step-exit {
  opacity: 0;
  transform: translateY(-12px) scale(0.96);
  pointer-events: none;
}
.gate-step.step-enter {
  animation: stepFadeIn 0.8s ease both;
}
@keyframes stepFadeIn {
  from { opacity: 0; transform: translateY(16px) scale(0.95); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ── Gate Whisper (typewriter text) ── */
.gate-whisper {
  font-size: 22px;
  font-weight: 600;
  line-height: 1.8;
  min-height: 1.8em;
  color: rgba(240, 230, 255, 0.92);
  letter-spacing: 3px;
  margin-bottom: 6px;
  text-shadow:
    0 0 18px rgba(200, 160, 255, 0.55),
    0 0 45px rgba(200, 160, 255, 0.22),
    0 0 90px rgba(180, 140, 255, 0.10),
    0 1px 3px rgba(0, 0, 0, 0.45);
  animation: whisperBreathe 3.5s ease-in-out infinite;
}
@keyframes whisperBreathe {
  0%, 100% { opacity: 0.85; text-shadow:
    0 0 18px rgba(200, 160, 255, 0.55),
    0 0 45px rgba(200, 160, 255, 0.22),
    0 0 90px rgba(180, 140, 255, 0.10),
    0 1px 3px rgba(0, 0, 0, 0.45); }
  50% { opacity: 1; text-shadow:
    0 0 24px rgba(200, 160, 255, 0.70),
    0 0 55px rgba(200, 160, 255, 0.30),
    0 0 110px rgba(180, 140, 255, 0.15),
    0 1px 3px rgba(0, 0, 0, 0.45); }
}
.gate-whisper.typing::after {
  content: "▍";
  font-weight: 300;
  color: rgba(212, 170, 255, 0.7);
  animation: cursorBlink 0.7s step-end infinite;
}
@keyframes cursorBlink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0; }
}

/* ── Handwriting instruction label ── */
.gate-hw-label {
  font-size: 13px;
  letter-spacing: 3px;
  color: rgba(200, 180, 255, 0.5);
  margin-bottom: 16px;
  opacity: 0;
  transition: opacity 0.8s ease 0.3s;
  text-shadow: 0 0 10px rgba(180, 140, 255, 0.25);
}
.gate-hw-label.visible {
  opacity: 1;
}

/* ── Glassy signature area ── */
.gate-sign-wrap {
  position: relative;
  width: min(260px, 78vw);
  height: 120px;
  margin: 0 auto 16px;
  border-radius: 16px;
  overflow: hidden;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.8s ease 0.5s, transform 0.8s ease 0.5s;
  background:
    radial-gradient(ellipse at 30% 20%, rgba(180,140,255,0.08), transparent 60%),
    radial-gradient(ellipse at 70% 80%, rgba(255,140,200,0.05), transparent 55%),
    rgba(15, 8, 40, 0.45);
  backdrop-filter: blur(16px) saturate(1.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
  border: 1px solid rgba(180, 160, 255, 0.18);
  box-shadow:
    0 0 20px rgba(180, 140, 255, 0.08),
    0 0 60px rgba(140, 100, 200, 0.04),
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 0 30px rgba(180, 140, 255, 0.04);
}
.gate-sign-wrap.visible {
  opacity: 1;
  transform: translateY(0);
}
.gate-sign-wrap.shake {
  animation: shakeWrap 0.4s ease;
}
@keyframes shakeWrap {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-6px); }
  40%      { transform: translateX(5px); }
  60%      { transform: translateX(-4px); }
  80%      { transform: translateX(3px); }
}

#signCanvas {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: crosshair;
}
.gate-sign-ph {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 14px;
  color: rgba(200, 180, 255, 0.25);
  letter-spacing: 4px;
  pointer-events: none;
  transition: opacity 0.3s ease;
  text-shadow: 0 0 12px rgba(180, 140, 255, 0.15);
}
.gate-sign-ph.faded {
  opacity: 0;
}

/* ── Glow buttons ── */
.gate-sign-btns {
  display: flex;
  justify-content: center;
  gap: 16px;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.8s ease 0.7s, transform 0.8s ease 0.7s;
}
.gate-sign-btns.visible {
  opacity: 1;
  transform: translateY(0);
}
.gate-glow-btn {
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  letter-spacing: 2px;
  padding: 8px 22px;
  border-radius: 20px;
  color: rgba(220, 200, 255, 0.85);
  background:
    radial-gradient(ellipse at 40% 30%, rgba(180,140,255,0.12), transparent 70%),
    rgba(30, 15, 65, 0.55);
  border: 1px solid rgba(180, 160, 255, 0.2);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow:
    0 0 12px rgba(180, 140, 255, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
  transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}
.gate-glow-btn:active {
  transform: scale(0.94);
}
.gate-glow-btn-primary {
  background:
    radial-gradient(ellipse at 40% 30%, rgba(200,160,255,0.18), transparent 60%),
    linear-gradient(145deg, rgba(160, 100, 240, 0.45), rgba(200, 80, 180, 0.35));
  border-color: rgba(200, 170, 255, 0.3);
  box-shadow:
    0 0 18px rgba(180, 140, 255, 0.15),
    0 0 40px rgba(160, 100, 240, 0.06),
    inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* ── Gate response text ── */
.gate-response {
  font-size: 20px;
  font-weight: 600;
  line-height: 1.8;
  min-height: 1.8em;
  color: rgba(255, 220, 240, 0.9);
  letter-spacing: 2px;
  margin-bottom: 10px;
  text-shadow:
    0 0 16px rgba(255, 180, 220, 0.5),
    0 0 40px rgba(255, 160, 200, 0.2),
    0 1px 3px rgba(0, 0, 0, 0.4);
}
.gate-response.typing::after {
  content: "▍";
  display: inline;
  animation: cursorBlink 0.6s step-end infinite;
  color: rgba(255, 200, 230, 0.8);
  margin-left: 2px;
}

/* ── Hold prompt ── */
.gate-prompt {
  margin-top: 18px;
  font-size: 13px;
  letter-spacing: 3px;
  color: rgba(200, 180, 255, 0.0);
  text-shadow: 0 0 12px rgba(180, 140, 255, 0.3);
  transition: color 1.2s ease, text-shadow 1.2s ease;
}
.gate-prompt.visible {
  color: rgba(200, 180, 255, 0.55);
  animation: promptPulse 3s ease-in-out infinite;
}
@keyframes promptPulse {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 0.9; }
}

/* ── Transition flash ── */
.gate-flash {
  position: fixed;
  inset: 0;
  z-index: 30;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(ellipse at var(--fx, 50%) var(--fy, 50%),
    rgba(220, 200, 255, 0.95) 0%,
    rgba(180, 140, 255, 0.6) 30%,
    rgba(100, 60, 180, 0.3) 60%,
    transparent 100%);
  transition: opacity 0.8s ease;
}
.gate-flash.active {
  opacity: 1;
}

/* ── Content exit transition ── */
.gate-content.cosmic-exit {
  transition: opacity 1s ease, transform 1s ease;
  opacity: 0;
  transform: scale(1.08);
}

/* ═══════════════════════════════════
   ✦ Cosmic Singing — Player Page
   Full-screen immersive · Star core
   Glass dock · Floating lyrics
   ═══════════════════════════════════ */

/* ─── Player layout (full-screen, no card) ─── */
.player-page {
  position: fixed;
  inset: 0;
  z-index: 15;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  width: 100% !important;
  height: var(--appH);
  padding: var(--sat) 0 0 !important;
  overflow: hidden;
}

/* ═══════════════════════════════════
   Star Core — Deep luminous sphere
   Dynamic color via --cr/--cg/--cb
   ═══════════════════════════════════ */
.star-core-stage {
  --cr: 200; --cg: 160; --cb: 255;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: calc(6vh + 10px);
  margin-bottom: 8px;
  flex-shrink: 0;
  /* Stage reveal */
  opacity: 0;
  transform: translateY(10px) scale(0.92);
  transition: opacity 0.9s cubic-bezier(0.23, 1, 0.32, 1),
              transform 0.9s cubic-bezier(0.23, 1, 0.32, 1);
}
.star-core-stage.stage-reveal {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* ── Halo bloom ── */
.star-core-halo {
  position: absolute;
  width: 170px; height: 170px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(var(--cr), var(--cg), var(--cb), 0.10) 0%,
    rgba(var(--cr), var(--cg), var(--cb), 0.05) 40%,
    transparent 70%);
  filter: blur(18px);
  pointer-events: none;
  transition: opacity 0.8s ease, transform 0.8s ease;
  opacity: 0.40;
}
.star-core-halo.playing {
  opacity: 0.85;
  animation: haloBreathe 3.5s ease-in-out infinite;
}
@keyframes haloBreathe {
  0%, 100% { transform: scale(1);    opacity: 0.75; }
  50%      { transform: scale(1.06); opacity: 0.90; }
}

/* ── Core orb — deep luminous sphere ── */
.star-core {
  position: relative;
  width: 100px; height: 100px;
  border-radius: 50%;
  background:
    /* bright center spot */
    radial-gradient(circle at 45% 40%,
      rgba(255, 255, 255, 0.12) 0%,
      transparent 40%),
    /* warm secondary reflection */
    radial-gradient(circle at 60% 65%,
      rgba(var(--cr), var(--cg), var(--cb), 0.18) 0%,
      transparent 45%),
    /* main sphere gradient: bright center → deep edge */
    radial-gradient(circle at 50% 50%,
      rgba(var(--cr), var(--cg), var(--cb), 0.50) 0%,
      rgba(var(--cr), var(--cg), var(--cb), 0.65) 30%,
      rgba(calc(var(--cr) * 0.5), calc(var(--cg) * 0.35), calc(var(--cb) * 0.6), 0.80) 65%,
      rgba(calc(var(--cr) * 0.3), calc(var(--cg) * 0.2), calc(var(--cb) * 0.4), 0.88) 100%);
  box-shadow:
    0 0 22px rgba(var(--cr), var(--cg), var(--cb), 0.15),
    0 0 50px rgba(var(--cr), var(--cg), var(--cb), 0.06),
    inset 0 0 20px rgba(255, 255, 255, 0.06);
  transition: box-shadow 0.8s ease;
  cursor: pointer;
  overflow: hidden;
  /* subtle outer ring via border */
  border: 1px solid rgba(var(--cr), var(--cg), var(--cb), 0.08);
}

/* Internal gradient blob that drifts — adds depth */
.star-core-inner {
  position: absolute;
  inset: -20%;
  border-radius: 50%;
  background:
    radial-gradient(ellipse at 30% 28%,
      rgba(255, 255, 255, 0.10), transparent 50%),
    radial-gradient(ellipse at 68% 72%,
      rgba(var(--cr), var(--cg), var(--cb), 0.12), transparent 45%);
  animation: coreInnerDrift 9s ease-in-out infinite;
  pointer-events: none;
}
@keyframes coreInnerDrift {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  33%      { transform: translate(6px, -5px) rotate(4deg); }
  66%      { transform: translate(-5px, 6px) rotate(-3deg); }
}

/* Specular highlight — glass depth cue */
.star-core-highlight {
  position: absolute;
  width: 32%;
  height: 32%;
  top: 16%;
  left: 22%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%,
    rgba(255, 255, 255, 0.15), transparent 70%);
  pointer-events: none;
  animation: highlightDrift 7s ease-in-out infinite;
}
@keyframes highlightDrift {
  0%, 100% { transform: translate(0, 0); opacity: 0.7; }
  50%      { transform: translate(2px, -2px); opacity: 0.95; }
}

/* Playing: gentle breathing + soft glow lift */
.star-core.playing {
  box-shadow:
    0 0 30px rgba(var(--cr), var(--cg), var(--cb), 0.25),
    0 0 60px rgba(var(--cr), var(--cg), var(--cb), 0.10),
    0 0 100px rgba(var(--cr), var(--cg), var(--cb), 0.04),
    inset 0 0 22px rgba(255, 255, 255, 0.08);
  animation: coreBreathe 3.5s ease-in-out infinite;
}
@keyframes coreBreathe {
  0%, 100% {
    transform: scale(1.00);
    box-shadow:
      0 0 30px rgba(var(--cr), var(--cg), var(--cb), 0.25),
      0 0 60px rgba(var(--cr), var(--cg), var(--cb), 0.10),
      0 0 100px rgba(var(--cr), var(--cg), var(--cb), 0.04),
      inset 0 0 22px rgba(255, 255, 255, 0.08);
  }
  50% {
    transform: scale(1.02);
    box-shadow:
      0 0 35px rgba(var(--cr), var(--cg), var(--cb), 0.30),
      0 0 70px rgba(var(--cr), var(--cg), var(--cb), 0.13),
      0 0 110px rgba(var(--cr), var(--cg), var(--cb), 0.06),
      inset 0 0 25px rgba(255, 255, 255, 0.10);
  }
}

/* Tap ripple */
.core-ripple {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(var(--cr), var(--cg), var(--cb), 0.14) 0%,
    rgba(var(--cr), var(--cg), var(--cb), 0.04) 50%,
    transparent 70%);
  transform: scale(0);
  animation: coreRippleOut 0.7s ease-out forwards;
  pointer-events: none;
  z-index: 5;
}
@keyframes coreRippleOut {
  to { transform: scale(1.3); opacity: 0; }
}

/* ─── Song Info Block ─── */
.song-info-block {
  position: relative;
  text-align: center;
  margin: 8px 20px 2px;
  flex-shrink: 0;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.8s ease, transform 0.8s ease;
  z-index: 2;
}
.song-info-block.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Real song title — clear, readable, soft glow */
.song-real-title {
  margin: 0;
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 2.5px;
  line-height: 1.4;
  color: rgba(235, 225, 255, 0.92);
  text-shadow:
    0 0 10px rgba(var(--cr), var(--cg), var(--cb), 0.20),
    0 0 25px rgba(var(--cr), var(--cg), var(--cb), 0.06);
  animation: titleSoftBreathe 4.5s ease-in-out infinite;
}
@keyframes titleSoftBreathe {
  0%, 100% { opacity: 0.90; }
  50%      { opacity: 1; }
}

/* ─── Opening Text — dialogue line (under title) ─── */
.opening {
  position: relative;
  min-height: 22px;
  max-width: min(380px, 88vw);
  margin: 6px auto 12px;
  padding: 8px 20px;
  font-size: 13px;
  letter-spacing: 1.2px;
  color: rgba(215, 200, 245, 0.82);
  line-height: 1.75;
  text-align: center;
  opacity: 0;
  transition: opacity 0.7s ease;
  text-shadow: 0 0 6px rgba(180, 140, 255, 0.15);
  flex-shrink: 0;
  border-radius: 10px;
  word-break: break-word;
}
.opening.visible { opacity: 1; }
.opening.visible.settled { opacity: 0.85; transition: opacity 1.2s ease; }
.opening.typing::after {
  content: "▍";
  font-weight: 300;
  color: rgba(212, 170, 255, 0.6);
  animation: cursorBlink 0.7s step-end infinite;
}

/* ─── Player Whisper (above dock) ─── */
.player-whisper {
  position: relative;
  z-index: 8;
  margin: 0 auto 4px;
  padding: 0 24px;
  min-height: 18px;
  font-size: 12px;
  letter-spacing: 2px;
  color: rgba(210, 195, 255, 0);
  text-shadow: 0 0 8px rgba(180, 140, 255, 0.15);
  text-align: center;
  pointer-events: none;
  flex-shrink: 0;
  opacity: 0;
  transition: color 0.6s ease, opacity 0.6s ease;
}
.player-whisper.visible {
  color: rgba(210, 195, 255, 0.55);
  opacity: 1;
}
.player-whisper.fade-out {
  color: rgba(210, 195, 255, 0);
  opacity: 0;
  transition: color 0.8s ease, opacity 0.8s ease;
}

/* ═══════════════════════════════════
   Lyrics — Floating drift with
   line highlighting + vignette mask
   ═══════════════════════════════════ */
.lyrics-viewport {
  position: relative;
  width: min(420px, 88vw);
  flex: 1 1 auto;
  overflow: hidden;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  margin: 0 auto;
  min-height: 0;
  /* Stage reveal */
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.8s ease, transform 0.8s ease;
}
.lyrics-viewport.stage-reveal {
  opacity: 1;
  transform: translateY(0);
}

/* Vignette mask (top + bottom fade) */
.lyrics-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  background: linear-gradient(
    to bottom,
    rgba(10, 6, 24, 0.85) 0%,
    transparent 22%,
    transparent 78%,
    rgba(10, 6, 24, 0.85) 100%
  );
}

/* Track that slides up on line change */
.lyrics-track {
  text-align: center;
  transition: transform 600ms cubic-bezier(0.25, 0.8, 0.25, 1);
  will-change: transform;
  padding: 60px 0;
}

.lyric-line {
  line-height: 1.8;
  font-size: 15px;
  color: rgba(200, 180, 255, 0.30);
  transition: color 0.5s ease, transform 0.5s ease,
              opacity 0.5s ease, text-shadow 0.5s ease,
              filter 0.5s ease;
  padding: 5px 12px;
  white-space: pre-wrap;
  filter: blur(1.5px);
  opacity: 0;
  pointer-events: none;
}

/* ±2 lines from active — faintly visible */
.lyric-line.far {
  opacity: 0.35;
  filter: blur(0.6px);
  color: rgba(200, 180, 255, 0.25);
}

/* Adjacent lines (±1) — semi-visible */
.lyric-line.near {
  color: rgba(220, 200, 255, 0.55);
  filter: blur(0px);
  opacity: 0.75;
}

/* Active current line */
.lyric-line.active {
  font-size: 17px;
  font-weight: 600;
  color: rgba(240, 230, 255, 0.95);
  transform: scale(1.03);
  filter: blur(0px);
  opacity: 1;
  text-shadow:
    0 0 14px rgba(200, 160, 255, 0.50),
    0 0 35px rgba(180, 140, 255, 0.20);
}

/* No-lyrics placeholder */
.lyric-line.lyric-empty {
  font-style: italic;
  font-size: 16px;
  letter-spacing: 2px;
  color: rgba(200, 180, 255, 0.4);
  filter: blur(0px);
}

/* ═══════════════════════════════════
   Glass Dock — bottom control bar
   ═══════════════════════════════════ */
.glass-dock {
  position: relative;
  z-index: 10;
  width: min(480px, 90vw);
  flex-shrink: 0;
  margin: 0 auto;
  margin-top: auto;
  padding: 0 0 max(var(--sab), 12px);
  /* Stage reveal */
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
/* Soft vignette above dock for readability */
.glass-dock::before {
  content: "";
  position: absolute;
  left: -10%;
  right: -10%;
  bottom: 0;
  height: 120px;
  background: linear-gradient(
    to top,
    rgba(8, 4, 24, 0.35) 0%,
    rgba(8, 4, 24, 0.15) 40%,
    transparent 100%
  );
  border-radius: 50% 50% 0 0 / 30% 30% 0 0;
  pointer-events: none;
  z-index: -1;
}
.glass-dock.stage-reveal {
  opacity: 1;
  transform: translateY(0);
}

.dock-inner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border-radius: 20px;
  background:
    radial-gradient(ellipse at 30% 30%, rgba(180,140,255,0.07), transparent 60%),
    radial-gradient(ellipse at 70% 70%, rgba(255,140,200,0.04), transparent 55%),
    rgba(15, 8, 40, 0.50);
  backdrop-filter: blur(24px) saturate(1.3);
  -webkit-backdrop-filter: blur(24px) saturate(1.3);
  border: 1px solid rgba(180, 160, 255, 0.14);
  box-shadow:
    0 0 24px rgba(180, 140, 255, 0.06),
    0 -4px 20px rgba(0, 0, 0, 0.25),
    inset 0 1px 0 rgba(255, 255, 255, 0.07);
}

/* Dock buttons */
.dock-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  background: transparent;
  color: rgba(210, 190, 255, 0.75);
  padding: 0;
  font-family: inherit;
  text-decoration: none;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
  transition: transform 0.2s ease, color 0.2s ease;
}
.dock-btn:active { transform: scale(0.90); }

.dock-btn-back {
  width: 32px; height: 32px;
}
.dock-btn-dl {
  width: 32px; height: 32px;
}

/* Play / Pause button — Cosmic Energy Ring */
.dock-btn-play {
  width: 52px; height: 52px;
  border-radius: 50%;
  background: transparent;
  color: #fff;
  overflow: hidden;
  position: relative;
  flex-shrink: 0;
  /* hit area */
  min-width: 48px;
  min-height: 48px;
}

/* Outer halo ring (gradient border) */
.play-halo {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  padding: 2px;
  background: linear-gradient(
    145deg,
    rgba(180, 140, 255, 0.55),
    rgba(220, 160, 240, 0.35),
    rgba(255, 140, 200, 0.40)
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0.7;
  transition: opacity 0.5s ease;
}

/* Inner soft glow fill */
.play-glow {
  position: absolute;
  inset: 2px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 38% 32%, rgba(255,255,255,0.08), transparent 50%),
    radial-gradient(circle at 55% 65%, rgba(200,140,255,0.06), transparent 45%),
    rgba(30, 15, 70, 0.50);
  box-shadow:
    inset 0 0 12px rgba(180, 140, 255, 0.10),
    0 0 20px rgba(180, 140, 255, 0.08);
  transition: box-shadow 0.6s ease, background 0.6s ease;
}

/* Playing state — energy ring pulses */
.dock-btn-play.playing .play-halo {
  opacity: 1;
  animation: playHaloPulse 3s ease-in-out infinite;
}
.dock-btn-play.playing .play-glow {
  box-shadow:
    inset 0 0 16px rgba(180, 140, 255, 0.18),
    0 0 28px rgba(180, 140, 255, 0.15),
    0 0 50px rgba(160, 120, 240, 0.06);
  animation: playGlowPulse 3s ease-in-out infinite;
}

@keyframes playHaloPulse {
  0%, 100% { transform: scale(1.00); opacity: 0.85; }
  50%      { transform: scale(1.04); opacity: 1; }
}
@keyframes playGlowPulse {
  0%, 100% {
    box-shadow:
      inset 0 0 16px rgba(180, 140, 255, 0.18),
      0 0 28px rgba(180, 140, 255, 0.15),
      0 0 50px rgba(160, 120, 240, 0.06);
  }
  50% {
    box-shadow:
      inset 0 0 20px rgba(180, 140, 255, 0.25),
      0 0 35px rgba(180, 140, 255, 0.20),
      0 0 60px rgba(160, 120, 240, 0.10);
  }
}

/* Paused state — dimmer */
.dock-btn-play:not(.playing) .play-halo {
  opacity: 0.45;
}
.dock-btn-play:not(.playing) .play-glow {
  box-shadow:
    inset 0 0 8px rgba(180, 140, 255, 0.06),
    0 0 12px rgba(180, 140, 255, 0.04);
}

.dock-btn-play svg {
  width: 18px; height: 18px;
  fill: rgba(220, 200, 255, 0.90);
  filter: drop-shadow(0 0 4px rgba(180,140,255,0.30));
  position: relative;
  z-index: 2;
  transition: fill 0.3s ease;
}
.dock-btn-play.playing svg {
  fill: #fff;
  filter: drop-shadow(0 0 6px rgba(200,160,255,0.40));
}

/* Ripple inside play button */
.dock-btn-play .ripple {
  position: absolute;
  border-radius: 50%;
  background: rgba(200, 170, 255, 0.25);
  transform: scale(0);
  animation: rippleOut 0.65s ease-out forwards;
  pointer-events: none;
  z-index: 1;
}
@keyframes rippleOut {
  to { transform: scale(3); opacity: 0; }
}

/* Seek bar group */
.dock-seek-group {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

/* ─── Starlight Progress Bar ─── */
.progress-wrap {
  position: relative;
  height: 16px;       /* touch-friendly hit area */
  border-radius: 3px;
  overflow: visible;
  cursor: pointer;
  touch-action: none;
  display: flex;
  align-items: center;
}
.progress-track {
  position: absolute;
  left: 0; right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 3px;
  background: rgba(255,255,255,0.06);
  border-radius: 2px;
  overflow: hidden;
}
/* Subtle shimmer moving along the track */
.progress-track::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(200, 170, 255, 0.08) 45%,
    rgba(255, 200, 240, 0.06) 55%,
    transparent 100%
  );
  background-size: 200% 100%;
  animation: trackShimmer 6s ease-in-out infinite;
}
@keyframes trackShimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

.progress-bar {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 0%;
  height: 3px;
  background: linear-gradient(90deg,
    rgba(180, 150, 255, 0.50),
    rgba(200, 160, 240, 0.55),
    rgba(220, 170, 255, 0.45));
  border-radius: 2px;
  z-index: 1;
  transition: width 0.15s linear;
  box-shadow: 0 0 6px rgba(180, 140, 255, 0.15);
}
.progress-glow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  width: 0%;
  height: 7px;
  background: linear-gradient(90deg,
    rgba(180, 150, 255, 0.18),
    rgba(200, 160, 240, 0.12));
  border-radius: 4px;
  filter: blur(3px);
  z-index: 0;
  transition: width 0.15s linear;
}
.progress-thumb {
  position: absolute;
  top: 50%;
  left: 0%;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: radial-gradient(circle at 40% 35%,
    rgba(240, 230, 255, 0.95),
    rgba(200, 170, 255, 0.70));
  box-shadow:
    0 0 6px rgba(180, 140, 255, 0.40),
    0 0 14px rgba(160, 120, 240, 0.15);
  transform: translate(-50%, -50%) scale(0.6);
  z-index: 3;
  pointer-events: none;
  transition: left 0.15s linear, transform 0.25s ease, opacity 0.25s ease,
              box-shadow 0.3s ease;
  opacity: 0.4;
}
/* Always show thumb subtly */
.progress-thumb.active,
.progress-wrap.dragging .progress-thumb {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
  box-shadow:
    0 0 10px rgba(180, 140, 255, 0.55),
    0 0 22px rgba(160, 120, 240, 0.20);
}
/* Dragging state: brighter bar */
.progress-wrap.dragging .progress-bar {
  background: linear-gradient(90deg,
    rgba(200, 170, 255, 0.65),
    rgba(220, 180, 250, 0.70),
    rgba(240, 190, 255, 0.60));
  box-shadow: 0 0 10px rgba(180, 140, 255, 0.25);
}

.time-label {
  display: block;
  font-size: 10px;
  color: rgba(200,180,255,0.35);
  font-variant-numeric: tabular-nums;
  text-align: right;
  line-height: 1;
  letter-spacing: 0.3px;
}

/* ─── Final message ─── */
.final-msg {
  position: absolute;
  bottom: 100px;
  left: 0; right: 0;
  text-align: center;
  font-size: 14px;
  color: rgba(220, 200, 255, 0.7);
  line-height: 1.6;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 1s ease, transform 1s ease;
  text-shadow: 0 0 10px rgba(180,140,255,0.3);
  padding: 0 20px;
}
.final-msg.visible {
  opacity: 1;
  transform: translateY(0);
}
.final-msg.hidden { display: none; }

/* ──────── Utility ──────── */
.hidden { display: none !important; }

/* ═══════════════════════════════════
   Galaxy Star Map — Song Selection
   Immersive floating stars · no grid
   ═══════════════════════════════════ */
.starmap-page {
  position: fixed;
  inset: 0;
  z-index: 18;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100% !important;
  height: var(--appH) !important;
  padding: 0 !important;
  overflow: hidden;
}

/* Foreground dust canvas */
.starmap-dust-canvas {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  z-index: 3;
}

/* Star field container — full viewport + cosmic breathing */
.starmap-field {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  animation: cosmicBreathe 20s ease-in-out infinite;
  transform-origin: 50% 50%;
}
@keyframes cosmicBreathe {
  0%, 100% { transform: scale(1.000); }
  50%      { transform: scale(1.008); }
}

/* Star proximity glow boost (magnetic reaction) */
.song-star.star-near .song-star-orb {
  box-shadow:
    0 0 calc(var(--star-size) * 0.55) var(--star-glow-inner),
    0 0 calc(var(--star-size) * 1.1) var(--star-glow-mid),
    0 0 calc(var(--star-size) * 1.9) var(--star-glow-outer);
  filter: brightness(1.08);
}
.song-star.star-near .song-star-halo {
  opacity: 0.45;
}

/* Individual song star */
.song-star {
  position: absolute;
  pointer-events: auto;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transform: translate(-50%, -50%);
  z-index: 2;
}

/* The visual orb */
.song-star-orb {
  position: relative;
  width: var(--star-size);
  height: var(--star-size);
  border-radius: 50%;
  background: radial-gradient(circle at 38% 35%,
    var(--star-highlight) 0%,
    var(--star-core) 35%,
    var(--star-mid) 60%,
    var(--star-edge) 100%);
  box-shadow:
    0 0 calc(var(--star-size) * 0.4) var(--star-glow-inner),
    0 0 calc(var(--star-size) * 0.9) var(--star-glow-mid),
    0 0 calc(var(--star-size) * 1.6) var(--star-glow-outer);
  transition: transform 0.6s cubic-bezier(0.23,1,0.32,1),
              box-shadow 0.6s ease,
              filter 0.3s ease;
  animation: starBreathe var(--breathe-dur, 4s) ease-in-out infinite,
             starFloat var(--float-dur, 7s) ease-in-out infinite;
  animation-delay: var(--breathe-delay, 0s), var(--float-delay, 0s);
  overflow: hidden;
}

/* Subtle internal glow rotation — rotating highlight spot */
.song-star-orb::before {
  content: "";
  position: absolute;
  inset: -20%;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%,
    rgba(255,255,255,0.18) 0%,
    transparent 55%);
  animation: starInnerRotate var(--rotate-dur, 10s) linear infinite;
  animation-delay: var(--rotate-delay, 0s);
  pointer-events: none;
}
@keyframes starInnerRotate {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

@keyframes starBreathe {
  0%, 100% { transform: scale(1.00); }
  50%      { transform: scale(1.025); }
}
@keyframes starFloat {
  0%, 100% { translate: 0 0; }
  25%      { translate: var(--float-x, 3px) var(--float-y, -4px); }
  50%      { translate: calc(var(--float-x, 3px) * -0.6) calc(var(--float-y, -4px) * 1.2); }
  75%      { translate: calc(var(--float-x, 3px) * 0.8) calc(var(--float-y, -4px) * -0.5); }
}

/* Outer halo ring */
.song-star-halo {
  position: absolute;
  inset: -60%;
  border-radius: 50%;
  background: radial-gradient(circle,
    var(--star-glow-inner) 0%,
    transparent 70%);
  filter: blur(12px);
  opacity: 0.3;
  pointer-events: none;
  transition: opacity 0.5s ease;
}

/* --- Tap-selected (first tap) --- */
.song-star.selected .song-star-orb {
  transform: scale(1.15);
  box-shadow:
    0 0 calc(var(--star-size) * 0.6) var(--star-glow-inner),
    0 0 calc(var(--star-size) * 1.3) var(--star-glow-mid),
    0 0 calc(var(--star-size) * 2.2) var(--star-glow-outer);
  animation: none;
}
.song-star.selected .song-star-halo {
  opacity: 0.7;
}

/* Selection ring pulse */
.song-star-ring {
  position: absolute;
  inset: -35%;
  border-radius: 50%;
  border: 1.5px solid var(--star-glow-inner);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}
.song-star.selected .song-star-ring {
  opacity: 0.6;
  animation: starRingPulse 2s ease-in-out infinite;
}
@keyframes starRingPulse {
  0%, 100% { transform: scale(1); opacity: 0.6; }
  50%      { transform: scale(1.12); opacity: 0.3; }
}

/* --- Dimmed (non-selected when one is chosen) --- */
.song-star.dimmed .song-star-orb {
  filter: brightness(0.35);
}
.song-star.dimmed .song-star-halo {
  opacity: 0.08;
}

/* --- Phase 1: Confirming pulse (pre-absorb) — subtle & dreamy --- */
.song-star.confirming .song-star-orb {
  animation: none;
  transform: scale(1.14);
  filter: brightness(1.15);
  box-shadow:
    0 0 calc(var(--star-size) * 0.5) var(--star-glow-inner),
    0 0 calc(var(--star-size) * 1.1) var(--star-glow-mid),
    0 0 calc(var(--star-size) * 2.0) var(--star-glow-outer);
  transition: transform 0.4s cubic-bezier(0.25, 1, 0.5, 1),
              filter 0.4s ease,
              box-shadow 0.4s ease;
}
.song-star.confirming .song-star-halo {
  opacity: 0.7;
  transform: scale(1.08);
  transition: opacity 0.4s ease, transform 0.4s ease;
}
.song-star.confirming .song-star-ring {
  animation: none;
  opacity: 0;
}

/* Cosmic ripple ring — spawned dynamically */
.cosmic-ripple {
  position: absolute;
  left: 50%; top: 50%;
  width: var(--star-size, 50px);
  height: var(--star-size, 50px);
  transform: translate(-50%, -50%) scale(1);
  border-radius: 50%;
  border: 1.5px solid var(--star-glow-inner, rgba(200,160,255,0.3));
  box-shadow: 0 0 10px var(--star-glow-mid, rgba(180,140,255,0.15));
  opacity: 0.18;
  pointer-events: none;
  animation: cosmicRippleExpand 1s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
@keyframes cosmicRippleExpand {
  0%   { transform: translate(-50%, -50%) scale(1); opacity: 0.18; }
  100% { transform: translate(-50%, -50%) scale(4); opacity: 0; }
}

/* Orbiting sparkles during transition */
.orbit-sparkle {
  position: absolute;
  width: 3px; height: 3px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.5);
  box-shadow: 0 0 4px rgba(200, 180, 255, 0.45), 0 0 8px rgba(180, 140, 255, 0.2);
  pointer-events: none;
  animation: orbitSpin var(--orbit-dur, 0.8s) linear infinite;
  offset-path: circle(var(--orbit-r, 40px));
  offset-distance: var(--orbit-start, 0deg);
}
@keyframes orbitSpin {
  to { offset-distance: calc(var(--orbit-start, 0deg) + 360deg); }
}
/* Fallback for browsers without offset-path: use rotating container */
@supports not (offset-path: circle(40px)) {
  .orbit-sparkle {
    animation: orbitFallback var(--orbit-dur, 0.8s) linear infinite;
    left: 50%; top: 50%;
  }
  @keyframes orbitFallback {
    0%   { transform: rotate(var(--orbit-start, 0deg)) translateX(var(--orbit-r, 40px)) scale(1); }
    50%  { transform: rotate(calc(var(--orbit-start, 0deg) + 180deg)) translateX(var(--orbit-r, 40px)) scale(0.7); }
    100% { transform: rotate(calc(var(--orbit-start, 0deg) + 360deg)) translateX(var(--orbit-r, 40px)) scale(1); }
  }
}

/* --- Phase 2: Absorbing into portal — slow dreamy pull --- */
.song-star.absorbing .song-star-orb {
  animation: none;
  will-change: transform, filter, box-shadow, opacity;
  transition: transform 1.4s cubic-bezier(0.22, 1, 0.36, 1),
              filter 1.2s ease,
              box-shadow 1.2s ease,
              opacity 0.6s ease 0.8s;
}
.song-star.absorbing .song-star-halo {
  opacity: 0;
  transition: opacity 0.8s ease;
}
.song-star.absorbing .song-star-ring {
  opacity: 0;
  transition: opacity 0.5s ease;
}

/* Dimmed stars being gently pulled toward chosen star */
.song-star.dimmed.sucked {
  transition: transform 1.3s cubic-bezier(0.25, 1, 0.5, 1),
              opacity 1.2s ease;
  opacity: 0 !important;
}

/* --- Vignette overlay (edge darkening during warp) --- */
.starmap-vignette {
  position: absolute;
  inset: 0;
  z-index: 10;
  pointer-events: none;
  background: radial-gradient(circle at 50% 50%,
    transparent 0%,
    transparent 30%,
    rgba(0, 0, 0, 0.18) 60%,
    rgba(0, 0, 0, 0.55) 100%);
  opacity: 0;
  transition: opacity 1.2s ease;
}
.starmap-vignette.active {
  opacity: 1;
}

/* --- Soft veil overlay (gentle cross-fade at handoff, NO flash) --- */
.starmap-flash {
  position: absolute;
  inset: 0;
  z-index: 20;
  pointer-events: none;
  background: radial-gradient(circle at var(--flash-x, 50%) var(--flash-y, 50%),
    rgba(255, 255, 255, 0.12) 0%,
    var(--flash-color, rgba(200, 180, 255, 0.08)) 45%,
    transparent 85%);
  opacity: 0;
  transition: opacity 0.5s ease;
}
.starmap-flash.active {
  opacity: 1;
}
.starmap-flash.fade-out {
  opacity: 0;
  transition: opacity 0.6s ease;
}

/* --- Expanding to player (legacy, kept for reset compat) --- */
.song-star.expanding .song-star-orb {
  animation: none;
  transition: transform 0.8s cubic-bezier(0.23,1,0.32,1),
              box-shadow 0.8s ease,
              opacity 0.6s ease 0.4s;
}

/* Floating title near star */
.starmap-title-float {
  position: fixed;
  z-index: 5;
  pointer-events: none;
  font-size: 14px;
  letter-spacing: 2px;
  color: rgba(230, 220, 255, 0.9);
  text-shadow:
    0 0 12px rgba(200,160,255,0.6),
    0 0 30px rgba(180,140,255,0.25);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.5s ease, transform 0.5s ease;
  white-space: nowrap;
}
.starmap-title-float.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Bottom hint */
.starmap-hint {
  position: fixed;
  bottom: max(var(--sab), 30px);
  left: 0; right: 0;
  text-align: center;
  z-index: 4;
  font-size: 12px;
  letter-spacing: 3px;
  color: rgba(200, 180, 255, 0.0);
  text-shadow: 0 0 10px rgba(180,140,255,0.25);
  transition: color 1s ease;
  pointer-events: none;
}
.starmap-hint.visible {
  color: rgba(200, 180, 255, 0.45);
  animation: promptPulse 3s ease-in-out infinite;
}

/* Idle whisper (above bottom hint) */
.starmap-whisper {
  position: fixed;
  bottom: calc(max(var(--sab), 30px) + 90px);
  left: 0; right: 0;
  text-align: center;
  z-index: 4;
  font-size: 13px;
  letter-spacing: 2px;
  color: rgba(210, 195, 255, 0);
  text-shadow: 0 0 10px rgba(180,140,255,0.2);
  pointer-events: none;
  max-width: 80%;
  margin: 0 auto;
  transition: color 0.3s ease, opacity 0.3s ease;
  opacity: 0;
}
.starmap-whisper.visible {
  color: rgba(210, 195, 255, 0.5);
  opacity: 1;
}
.starmap-whisper.fade-out {
  color: rgba(210, 195, 255, 0);
  opacity: 0;
  transition: color 0.6s ease, opacity 0.6s ease;
}

/* Song end overlay (center of lyrics area) */
.song-end-overlay {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 12;
  pointer-events: none;
  font-size: 14px;
  letter-spacing: 2px;
  color: rgba(220, 205, 255, 0.0);
  text-shadow: 0 0 12px rgba(180,140,255,0.3);
  opacity: 0;
  transition: opacity 0.5s ease, color 0.5s ease;
}
.song-end-overlay.visible {
  color: rgba(220, 205, 255, 0.8);
  opacity: 1;
}
.song-end-overlay.fade-out {
  color: rgba(220, 205, 255, 0.0);
  opacity: 0;
  transition: opacity 0.6s ease, color 0.6s ease;
}

/* Hidden star (initially invisible, pearl layered glow) */
.song-star.hidden-star {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.3);
  transition: opacity 2s ease, transform 1.8s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
  z-index: 5;
}
.song-star.hidden-star.revealed {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
  pointer-events: auto;
}
/* Pearl-like layered orb: white core + pink inner + blue outer */
.song-star.hidden-star .song-star-orb {
  background:
    radial-gradient(circle at 38% 35%,
      rgba(255,255,255,0.50) 0%,
      rgba(255,230,240,0.40) 20%,
      rgba(220,210,255,0.30) 45%,
      rgba(200,195,240,0.12) 70%,
      transparent 100%);
  box-shadow:
    0 0 12px rgba(255,240,250,0.25),
    0 0 28px rgba(230,215,255,0.12),
    0 0 48px rgba(255,225,200,0.06);
}
/* Double halo effect */
.song-star.hidden-star .song-star-halo {
  opacity: 0.4;
  box-shadow:
    0 0 20px rgba(246,241,255,0.20),
    0 0 50px rgba(255,230,245,0.10),
    0 0 80px rgba(220,210,255,0.06);
}
.song-star.hidden-star .song-star-halo::after {
  content: "";
  position: absolute;
  inset: -30%;
  border-radius: 50%;
  border: 1px solid rgba(255,245,255,0.08);
  animation: hiddenHaloRing 6s ease-in-out infinite;
}
@keyframes hiddenHaloRing {
  0%, 100% { transform: scale(0.9); opacity: 0.3; }
  50%      { transform: scale(1.15); opacity: 0.6; }
}
/* Subtle ring with cross-twinkle */
.song-star.hidden-star .song-star-ring {
  opacity: 0.25;
}
.song-star.hidden-star .song-star-ring::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background:
    conic-gradient(from 0deg,
      transparent 0deg, rgba(255,250,255,0.10) 45deg,
      transparent 90deg, transparent 180deg,
      rgba(255,250,255,0.08) 225deg, transparent 270deg,
      transparent 360deg);
  animation: hiddenCrossTwinkle 8s linear infinite;
}
@keyframes hiddenCrossTwinkle {
  to { transform: rotate(360deg); }
}
/* Slow breathing override */
.song-star.hidden-star .song-star-orb {
  animation-duration: 6s;
}

/* ──────── Back Button Highlight (all songs completed) ──────── */
.dock-btn-back.highlight-glow {
  position: relative;
}
.dock-btn-back.highlight-glow::before {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(220, 200, 255, 0.25) 0%,
    rgba(200, 170, 255, 0.10) 50%,
    transparent 70%);
  animation: backBtnPulse 2.5s ease-in-out infinite;
  pointer-events: none;
}
@keyframes backBtnPulse {
  0%, 100% { transform: scale(0.85); opacity: 0.5; }
  50%      { transform: scale(1.3); opacity: 1; }
}
.back-hint-tooltip {
  position: absolute;
  bottom: calc(100% + 68px);
  left: 24px;
  font-size: 12px;
  letter-spacing: 1.5px;
  color: rgba(220, 205, 255, 0);
  text-shadow: 0 0 10px rgba(200, 170, 255, 0.25);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.8s ease, transform 0.8s ease, color 0.8s ease;
}
.back-hint-tooltip.visible {
  color: rgba(220, 205, 255, 0.7);
  opacity: 1;
  transform: translateY(0);
}

/* ──────── Hidden Page — Multi-Phase Ritual ──────── */
.hidden-page {
  position: fixed;
  inset: 0;
  z-index: 25;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100% !important;
  background: transparent;
  opacity: 0;
  transition: opacity 1.2s ease;
  overflow: hidden;
}
.hidden-page.fade-in {
  opacity: 1;
}

/* Ripple canvas fills the page */
.hp-ripple-canvas {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  z-index: 1;
  pointer-events: none;
}

/* Phase 3: Question overlay */
.hp-question-overlay {
  position: fixed;
  inset: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  padding:
    calc(var(--sat) + 24px)
    24px
    calc(var(--sab) + 24px);
  opacity: 0;
  transition: opacity 0.8s ease;
  pointer-events: none;
}
.hp-question-overlay.visible {
  opacity: 1;
  pointer-events: auto;
}
.hp-question-inner {
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  text-align: center;
  max-height: calc(100dvh - 120px);
  overflow-y: auto;
}
.hp-question-text {
  font-size: 17px;
  letter-spacing: 3px;
  color: rgba(240, 235, 255, 0.85);
  text-shadow: 0 0 18px rgba(200, 170, 255, 0.2);
  margin-bottom: 32px;
  line-height: 1.6;
}
.hp-question-btns {
  display: flex;
  gap: 24px;
  justify-content: center;
}
.hp-glass-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 72px;
  padding: 10px 28px;
  border: 1px solid rgba(200, 180, 255, 0.18);
  border-radius: 24px;
  background:
    radial-gradient(ellipse at 30% 30%, rgba(180, 140, 255, 0.08), transparent 60%),
    rgba(15, 8, 40, 0.45);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  color: rgba(230, 220, 255, 0.85);
  font-size: 15px;
  letter-spacing: 3px;
  font-family: inherit;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.3s ease, border-color 0.3s ease;
  box-shadow: 0 0 16px rgba(180, 140, 255, 0.06);
}
.hp-glass-btn:active {
  transform: scale(0.93);
}
.hp-glass-btn:hover {
  border-color: rgba(220, 200, 255, 0.30);
  box-shadow: 0 0 24px rgba(200, 170, 255, 0.12);
}

/* Phase 4: Achievement popup (Steam-style, bottom-right) */
.hp-achievement-popup {
  position: fixed;
  bottom: 32px;
  right: 24px;
  z-index: 30;
  width: 320px;
  height: 88px;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(18, 18, 24, 0.75);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow:
    0 0 24px rgba(255, 255, 255, 0.08),
    inset 0 0 18px rgba(255, 255, 255, 0.03);
  transform: translateX(120%);
  opacity: 0;
  transition:
    transform 0.6s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.4s ease;
  pointer-events: none;
}
.hp-achievement-popup.show {
  transform: translateX(0);
  opacity: 1;
  pointer-events: auto;
}
.hp-achieve-icon {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  color: rgba(255, 240, 220, 0.95);
  background:
    radial-gradient(circle,
      rgba(255, 255, 255, 0.95),
      rgba(255, 200, 240, 0.5),
      transparent);
  box-shadow: 0 0 18px rgba(255, 200, 240, 0.4);
}
.hp-achieve-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.hp-achieve-label {
  font-size: 11px;
  letter-spacing: 2px;
  color: rgba(200, 185, 255, 0.55);
  text-transform: uppercase;
}
.hp-achieve-title {
  font-size: 15px;
  letter-spacing: 2px;
  color: rgba(246, 241, 255, 0.9);
  text-shadow: 0 0 10px rgba(246, 241, 255, 0.1);
}
.hp-achieve-subtitle {
  font-size: 12px;
  letter-spacing: 1px;
  opacity: 0.5;
  color: rgba(220, 210, 245, 0.7);
  margin-top: 2px;
}

/* Phase 3b: Final interaction panel */
.hp-final-interact {
  position: fixed;
  inset: 0;
  z-index: 8;
  display: flex;
  align-items: center;
  justify-content: center;
  padding:
    calc(env(safe-area-inset-top, 0px) + 20px)
    20px
    calc(env(safe-area-inset-bottom, 0px) + 20px);
  opacity: 0;
  transition: opacity 0.8s ease;
  pointer-events: none;
}
.hp-final-interact.visible {
  opacity: 1;
  pointer-events: auto;
}
.hp-final-interact-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
}
.hp-final-interact-text {
  font-size: 18px;
  letter-spacing: 3px;
  color: rgba(246, 241, 255, 0.85);
  text-shadow: 0 0 20px rgba(200, 170, 255, 0.15);
  text-align: center;
}
.hp-final-interact-btns {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  justify-content: center;
}
@media (max-width: 480px) {
  .hp-achievement-popup {
    right: 16px;
    bottom: calc(24px + var(--sab));
    width: min(92vw, 360px);
    height: auto;
  }
}

/* Phase 4: Card preview */
.hp-card-wrap {
  position: fixed;
  inset: 0;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding:
    calc(var(--sat) + 20px)
    20px
    calc(var(--sab) + 20px);
  opacity: 0;
  transition: opacity 0.8s ease;
  pointer-events: none;
}
.hp-card-wrap.visible {
  opacity: 1;
  pointer-events: auto;
}
.hp-card-img {
  max-width: min(420px, 88vw);
  width: 100%;
  height: auto;
  border-radius: 14px;
  box-shadow:
    0 4px 30px rgba(0, 0, 0, 0.35),
    0 0 20px rgba(180, 140, 255, 0.08);
  border: 1px solid rgba(200, 180, 255, 0.10);
  /* Allow native long-press save on mobile */
  -webkit-touch-callout: default;
  user-select: auto;
  -webkit-user-select: auto;
}
.hp-card-hint {
  font-size: 12px;
  letter-spacing: 2px;
  color: rgba(210, 195, 255, 0.45);
  text-align: center;
}
.hp-card-btns {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
}
.hp-card-dl, .hp-card-share, .hp-card-close {
  font-size: 13px;
  padding: 8px 22px;
  min-width: 0;
}
.hp-card-close {
  margin-top: 4px;
  opacity: 0.6;
}

/* Phase 5: Final reveal */
.hp-final-reveal {
  position: absolute;
  z-index: 7;
  text-align: center;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.8s ease, transform 0.8s ease;
  pointer-events: none;
}
/* ── Reset cosmic memory ── */
.hp-reset-wrap {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 8;
  text-align: center;
  padding-bottom: calc(28px + env(safe-area-inset-bottom));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s ease;
}
.hp-reset-wrap.visible {
  opacity: 1;
  pointer-events: auto;
}
.hp-reset-btn {
  display: inline-block;
  background: none;
  border: 1px solid rgba(200,180,255,0.12);
  color: rgba(200,185,255,0.30);
  font-size: 11px;
  letter-spacing: 1px;
  padding: 6px 18px;
  border-radius: 20px;
  cursor: pointer;
  transition: color 0.3s, border-color 0.3s;
  -webkit-tap-highlight-color: transparent;
}
.hp-reset-btn:active {
  color: rgba(200,185,255,0.50);
  border-color: rgba(200,180,255,0.25);
}
.hp-reset-confirm {
  display: none;
  flex-direction: column;
  align-items: center;
  margin-top: 16px;
  gap: 10px;
}
.hp-reset-confirm.visible {
  display: flex;
}
.hp-reset-text {
  font-size: 12px;
  color: rgba(220,210,245,0.45);
}
.hp-reset-btns {
  display: flex;
  gap: 20px;
}
.hp-reset-btns button {
  background: none;
  border: 1px solid rgba(200,180,255,0.15);
  color: rgba(220,210,245,0.50);
  font-size: 12px;
  padding: 4px 22px;
  border-radius: 16px;
  cursor: pointer;
  transition: color 0.3s, border-color 0.3s, background 0.3s;
  -webkit-tap-highlight-color: transparent;
}
.hp-reset-btns button:active {
  background: rgba(200,180,255,0.08);
  color: rgba(220,210,245,0.70);
}

.hp-final-reveal.visible {
  opacity: 1;
  transform: translateY(0);
}
.hp-final-name {
  font-size: 24px;
  letter-spacing: 5px;
  color: rgba(246, 241, 255, 0.88);
  text-shadow: 0 0 24px rgba(246, 241, 255, 0.15);
  margin-bottom: 14px;
}
.hp-final-date {
  font-size: 14px;
  letter-spacing: 3px;
  color: rgba(220, 210, 245, 0.55);
  text-shadow: 0 0 14px rgba(200, 170, 255, 0.15);
}

/* Back button hidden initially, shown in final phase */
.hp-back-hidden {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s ease;
}
.hp-back-hidden.visible {
  opacity: 1;
  pointer-events: auto;
}

.hidden-page-back {
  position: fixed;
  top: calc(var(--sat) + 16px);
  left: 20px;
  z-index: 30;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  border: 1px solid rgba(200, 180, 255, 0.15);
  border-radius: 50%;
  background: rgba(15, 8, 40, 0.4);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: rgba(220, 205, 255, 0.7);
  cursor: pointer;
  transition: transform 0.2s ease, opacity 0.3s ease;
}
.hidden-page-back:active { transform: scale(0.9); }

/* Skip recording button */
.hp-skip-btn {
  position: fixed;
  bottom: calc(var(--sab) + 32px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  font-size: 13px;
  letter-spacing: 2px;
  color: rgba(220, 210, 245, 0.5);
  background: rgba(15, 8, 40, 0.3);
  border: 1px solid rgba(200, 180, 255, 0.12);
  border-radius: 20px;
  padding: 8px 24px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s ease;
}
.hp-skip-btn.visible {
  opacity: 1;
  pointer-events: auto;
}
.hp-skip-btn:active {
  transform: translateX(-50%) scale(0.95);
}

/* Star reposition transition class */
.song-star.reposition {
  transition: left 1.2s cubic-bezier(0.22, 1, 0.36, 1), top 1.2s cubic-bezier(0.22, 1, 0.36, 1) !important;
}

/* ──────── Desktop tweaks ──────── */
@media (min-width: 520px) {
  .star-core { width: 120px; height: 120px; }
  .star-core-halo { width: 200px; height: 200px; }
  .song-star-orb { --star-size-mult: 1.15; }
}
