/* ============================================================
   animations.css — 页面进场与切换过渡（心动溶解）
   口令门已按需求移除。
   ============================================================ */

@keyframes page-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes rise-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes tab-pop {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.28); }
  100% { transform: scale(1); }
}

@keyframes pulse-ring {
  0%   { box-shadow: 0 0 0 0 rgba(201, 56, 92, .55); }
  70%  { box-shadow: 0 0 0 9px rgba(201, 56, 92, 0); }
  100% { box-shadow: 0 0 0 0 rgba(201, 56, 92, 0); }
}

@keyframes breath {
  0%, 100% { transform: scale(1); opacity: .9; }
  50%      { transform: scale(1.06); opacity: 1; }
}

@keyframes shake-x {
  0%, 100% { transform: translateX(0); }
  18% { transform: translateX(-9px); }
  36% { transform: translateX(8px); }
  54% { transform: translateX(-6px); }
  72% { transform: translateX(4px); }
}

@keyframes fade-up-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------------- 切换过渡：心动溶解 ---------------- */
.dissolve {
  position: fixed;
  inset: 0;
  z-index: 80;
  pointer-events: none;
  opacity: 0;
  transition: opacity .5s var(--ease-inner);
}
.dissolve.is-on { opacity: 1; }

.dissolve canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.dissolve-vignette {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .55s var(--ease-inner);
  background:
    radial-gradient(120% 90% at 50% 50%, rgba(255, 160, 190, .95) 0%, rgba(120, 30, 60, .95) 46%, #0B0510 100%);
}
.dissolve.is-veil .dissolve-vignette { opacity: 1; }

/* 内层内容进场 */
.page-inner > * { animation: rise-in .55s var(--ease-inner) both; }
