Как это устроено
Два уровня: transitions (из A в B при изменении свойства) и animations (@keyframes + animation).
.btn {
transition: background-color 150ms ease, transform 150ms ease;
}
.btn:hover { transform: translateY(-1px); }
@keyframes pulse {
from { opacity: 0.6; }
to { opacity: 1; }
}
.dot { animation: pulse 1s ease-in-out infinite alternate; }
Учитывайте prefers-reduced-motion. Анимируйте по возможности transform/opacity.
Итог
Hover/состояние — transition; циклы и сложные сценарии — @keyframes. Не анимируйте всё подряд.