/* ==========================================================================
   TOOLNOVA DESIGN SYSTEM — ANIMATION UTILITIES
   Applied as classes to any element, not baked into individual
   components — a card, a table row, and a dialog can all use
   .tn-anim-fade-in without duplicating keyframes. All animations use
   only transform/opacity (GPU-accelerated, never trigger layout) and
   read their timing from the duration/ease tokens, so reduced-motion
   is respected automatically via tokens.css.
   ========================================================================== */

@keyframes tn-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes tn-slide-up { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes tn-slide-down { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes tn-slide-in-start { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: translateX(0); } }
[dir="rtl"] .tn-anim-slide-in-start { animation-name: tn-slide-in-end; }
@keyframes tn-slide-in-end { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: translateX(0); } }
@keyframes tn-scale-in { from { opacity: 0; transform: scale(0.94); } to { opacity: 1; transform: scale(1); } }
@keyframes tn-spring-in { from { opacity: 0; transform: translateY(8px) scale(0.92); } to { opacity: 1; transform: translateY(0) scale(1); } }
@keyframes tn-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
@keyframes tn-pulse-scale { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.15); } }
@keyframes tn-ring-expand { 0% { transform: scale(0.4); opacity: 0.7; } 100% { transform: scale(1.6); opacity: 0; } }
@keyframes tn-shimmer { 0% { background-position: 160% 0; } 100% { background-position: -60% 0; } }
@keyframes tn-spin { to { transform: rotate(360deg); } }
@keyframes tn-ripple { from { opacity: 0.5; width: 8px; height: 8px; } to { opacity: 0; width: 240px; height: 240px; } }
@keyframes tn-shake { 10%, 90% { transform: translateX(-1px); } 20%, 80% { transform: translateX(2px); } 30%, 50%, 70% { transform: translateX(-4px); } 40%, 60% { transform: translateX(4px); } }
@keyframes tn-check-draw { from { stroke-dashoffset: 24; } to { stroke-dashoffset: 0; } }

.tn-anim-fade-in { animation: tn-fade-in var(--tn-duration-slow) var(--tn-ease-out) both; }
.tn-anim-slide-up { animation: tn-slide-up var(--tn-duration-slow) var(--tn-ease-out) both; }
.tn-anim-slide-down { animation: tn-slide-down var(--tn-duration-base) var(--tn-ease-out) both; }
.tn-anim-slide-in-start { animation: tn-slide-in-start var(--tn-duration-base) var(--tn-ease-out) both; }
.tn-anim-scale-in { animation: tn-scale-in var(--tn-duration-base) var(--tn-ease-out) both; }
.tn-anim-spring-in { animation: tn-spring-in var(--tn-duration-slow) var(--tn-ease-spring) both; }
.tn-anim-pulse { animation: tn-pulse 2.2s var(--tn-ease-in-out) infinite; }
.tn-anim-shake { animation: tn-shake var(--tn-duration-slower) var(--tn-ease-in-out) both; }

/* Stagger helper — pairs with inline --tn-stagger-index on each child */
.tn-anim-stagger > * {
  animation: tn-spring-in var(--tn-duration-slow) var(--tn-ease-spring) both;
  animation-delay: calc(var(--tn-stagger-index, 0) * 50ms);
}

/* Skeleton loading */
.tn-skeleton {
  border-radius: var(--tn-radius-md);
  background: linear-gradient(100deg, var(--tn-color-panel-raised) 30%, rgba(255,255,255,0.06) 45%, var(--tn-color-panel-raised) 60%);
  background-size: 250% 100%;
  animation: tn-shimmer 1.6s var(--tn-ease-in-out) infinite;
}

/* Spinner */
.tn-spinner { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--tn-color-hairline); border-block-start-color: var(--tn-color-coral); animation: tn-spin 0.7s linear infinite; }

/* Success / error one-shot moments */
.tn-anim-success-check { stroke-dasharray: 24; stroke-dashoffset: 24; animation: tn-check-draw var(--tn-duration-slow) var(--tn-ease-out) forwards; }
.tn-anim-error-shake { animation: tn-shake var(--tn-duration-slower) var(--tn-ease-in-out); }

/* Ripple (paired with .tn-ripple-surface in components.css, triggered via JS toggling this class) */
.tn-rippling::after { animation: tn-ripple 0.55s var(--tn-ease-out); }
