/* ========================================
   Animations — Lunati
   CSS keyframes + Anime.js motion helpers
   ======================================== */

@keyframes spin { to { transform: rotate(360deg); } }

@keyframes menuPop {
  from { opacity: 0.35; transform: translateY(-4px) scale(0.98); }
  to { opacity: 1; transform: none; }
}

@keyframes typing {
  0%, 80%, 100% { transform: scale(0.6); opacity: 0.3; }
  40% { transform: scale(1); opacity: 0.8; }
}

@keyframes sendPulse {
  50% { filter: brightness(1.18); box-shadow: 0 0 0 8px var(--accent-muted); }
}

@keyframes dropIn {
  from { opacity: 0; transform: translateY(-8px) scale(0.96); }
  to { opacity: 1; transform: none; }
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}

@keyframes msgIn {
  from { opacity: 0.35; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* AI 气泡与页面切换：motion layer 就绪后由 JS 接管，避免与 CSS 关键帧叠加 */
html:not([data-motion="ready"]) .ai-msg { animation: msgIn 0.14s var(--ease-out); }
html:not([data-motion="ready"]) .page.active { animation: fadeInUp 0.4s var(--ease-in-out); }

/* ── Page transition ── */
.page.transition-out {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: -1;
}

/* ── Ripple ── */
.ripple.run { animation: rippleOut 0.6s var(--ease-out) forwards; }
@keyframes rippleOut {
  to { transform: scale(2.5); opacity: 0; }
}

/* ── Hero orb breathing (motion-friendly, transform only) ── */
@keyframes orbFloat {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); opacity: 0.55; }
  50% { transform: translate3d(30px, -40px, 0) scale(1.08); opacity: 0.85; }
}

.hero-orb-1 { animation: orbFloat 14s ease-in-out infinite; }
.hero-orb-2 { animation: orbFloat 18s ease-in-out infinite -6s; }

/* ── Marquee-ish subtle shimmer for active tabs ── */
@keyframes shimmer {
  0% { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}

/* ── Anime.js friendly default state hooks ── */
.anim-fade-in { opacity: 0; }
.anim-slide-up { opacity: 0; transform: translateY(24px); }
.anim-scale-in { opacity: 0; transform: scale(0.94); }
.anim-blur-in { opacity: 0; filter: blur(8px); }

/* ══════════════════════════════════════════════════════════
   与 /js/motion-layer.js 的协调
   data-motion 属性由该模块写入：
     未设置  = 模块尚未加载完 → 走 CSS 关键帧，避免内容永久隐藏
     ready   = anime.js/motion 已接管 → 关闭等价 CSS 动画，防止叠加
     fallback= CDN/本地库都不可用 → 保留 CSS 动画能力
   ══════════════════════════════════════════════════════════ */
html:not([data-motion]) .modal-box { animation: sheetUp 0.3s var(--spring) both; }
html:not([data-motion]) .lang-ui-menu.open { animation: menuPop 0.15s var(--ease-out) both; }
html[data-motion="ready"] .modal-box,
html[data-motion="ready"] .lang-ui-menu.open { animation: none; }
/* .hero-orb 的 orbFloat 使用 transform，motion 视差写入 translate，二者可叠加 */
