/* ============================================================
   动画库
   ============================================================ */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeInUp { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes fadeInDown { from { opacity: 0; transform: translateY(-16px); } to { opacity: 1; transform: none; } }
@keyframes slideInLeft { from { opacity: 0; transform: translateX(-22px); } to { opacity: 1; transform: none; } }
@keyframes slideInRight { from { opacity: 0; transform: translateX(22px); } to { opacity: 1; transform: none; } }
@keyframes scaleIn { from { opacity: 0; transform: scale(.92); } to { opacity: 1; transform: none; } }
@keyframes pulse { 0%,100% { box-shadow: 0 0 0 0 rgba(46,92,230,.35); } 50% { box-shadow: 0 0 0 7px rgba(46,92,230,0); } }
@keyframes alertPulse { 0%,100% { opacity: 1; } 50% { opacity: .55; } }
@keyframes successGlow { 0%,100% { box-shadow: 0 0 0 0 rgba(22,163,74,.3); } 50% { box-shadow: 0 0 0 10px rgba(22,163,74,0); } }
@keyframes progressFlow { from { background-position: 0 0; } to { background-position: 18px 0; } }
@keyframes blink { 0%,49% { opacity: 1; } 50%,100% { opacity: 0; } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes typingBounce { 0%,60%,100% { transform: translateY(0); } 30% { transform: translateY(-5px); } }
@keyframes countUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes dashFlow { to { stroke-dashoffset: 0; } }
@keyframes shimmer { from { background-position: -200% 0; } to { background-position: 200% 0; } }

.fade-in { animation: fadeIn .5s both; }
.fade-in-up { animation: fadeInUp .55s both; }
.fade-in-down { animation: fadeInDown .5s both; }
.slide-in-left { animation: slideInLeft .5s both; }
.slide-in-right { animation: slideInRight .5s both; }
.scale-in { animation: scaleIn .45s both; }

.delay-1 { animation-delay: .08s; } .delay-2 { animation-delay: .16s; }
.delay-3 { animation-delay: .24s; } .delay-4 { animation-delay: .32s; }
.delay-5 { animation-delay: .40s; } .delay-6 { animation-delay: .48s; }
.delay-7 { animation-delay: .56s; } .delay-8 { animation-delay: .64s; }

.spinner {
    width: 17px; height: 17px; border-radius: 50%;
    border: 2.5px solid rgba(255,255,255,.35); border-top-color: #fff;
    animation: spin .7s linear infinite; display: inline-block;
}
.spinner-dark { border-color: var(--slate-200); border-top-color: var(--role-color); }

/* 终端光标 */
.term-cursor {
    display: inline-block; width: 8px; height: 15px; background: #7aa2f7;
    vertical-align: -2px; animation: blink 1s step-end infinite;
}

/* skeleton 骨架屏 */
.skeleton {
    background: linear-gradient(90deg, var(--slate-100) 25%, var(--slate-200) 50%, var(--slate-100) 75%);
    background-size: 200% 100%; animation: shimmer 1.4s infinite;
    border-radius: 7px;
}
