/* ============================================================================
 * v4 关键帧 —— 逐字移植自 DC 源 <helmet><style>（知识星图 v4.dc.html 行 22-31）
 *   全部 zzm 前缀，全局注册无副作用。v4 屏以 inline `animation:` 引用。
 *   reduced-motion 由旧 index.css 的全局媒体查询兜底关停，无需在此重复。
 * [PROTOCOL]: 变更时更新此头部，然后检查 CLAUDE.md
 * ========================================================================== */

@keyframes zzmPulse { 0%, 100% { opacity: .15 } 50% { opacity: .55 } }
@keyframes zzmIn    { from { opacity: 0; transform: translateY(12px) } to { opacity: 1; transform: none } }
@keyframes zzmUp    { from { opacity: 0; transform: translateY(10px) } to { opacity: 1; transform: none } }
@keyframes zzmSlide { from { opacity: 0; transform: translateX(-14px) } to { opacity: 1; transform: none } }
@keyframes zzmGrow  { from { max-height: 0; opacity: 0 } to { max-height: 960px; opacity: 1 } }
@keyframes zzmSpring {
  0%   { transform: translateX(0) }
  38%  { transform: translateX(150px) }
  62%  { transform: translateX(128px) }
  80%  { transform: translateX(142px) }
  92%  { transform: translateX(136px) }
  100% { transform: translateX(138px) }
}
@keyframes zzmIn2   { from { opacity: 0; transform: translateY(12px) } to { opacity: 1; transform: none } }
@keyframes zzmUp2   { from { opacity: 0; transform: translateY(10px) } to { opacity: 1; transform: none } }
@keyframes zzmFade  { from { opacity: 0 } to { opacity: 1 } }
@keyframes zzmPayIn { from { opacity: 0; transform: translateY(20px) scale(.985) } to { opacity: 1; transform: none } }
@keyframes zzmShimmer { 100% { transform: translateX(100%) } }
@keyframes zzmBtnSpin { to { transform: rotate(360deg) } }
/* 一道反光扫过（时不时闪一下）：快扫一次(0→14%)后长歇——档位胶囊 .zzm-pill-shine 与 saving 键
   .zzm-btn--busy 共用这一条，同一视觉语言。reduced-motion 由 index.css 全局兜底关停。 */
@keyframes zzmPillShine { 0% { transform: translateX(-180%) } 14% { transform: translateX(180%) } 100% { transform: translateX(180%) } }
