/* =============================================================
   ANIMATIONS  —  subtle, GPU-friendly (transform + opacity only)
   -------------------------------------------------------------
   Keyframes + reusable helper classes. Durations come from the
   --animation-speed / --speed-* tokens, so global speed is one
   variable away. No layout-thrashing properties are animated.
   ============================================================= */

@keyframes ds-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes ds-fade-in-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes ds-scale-in {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: scale(1); }
}

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

/* ---- Reusable helpers ---------------------------------------- */
.ds-fade-in    { animation: ds-fade-in var(--animation-speed) var(--ease) both; }
.ds-fade-in-up { animation: ds-fade-in-up var(--animation-speed) var(--ease-out) both; }
.ds-scale-in   { animation: ds-scale-in var(--speed-fast) var(--ease-out) both; }

/* Gentle page-content entrance (opacity only → no reflow) */
.content-wrapper > .content {
  animation: ds-fade-in var(--animation-speed) var(--ease) both;
}

/* Lightweight inline spinner */
.ds-spinner {
  display: inline-block;
  width: 1em;
  height: 1em;
  border: 2px solid var(--primary-soft);
  border-top-color: var(--primary);
  border-radius: var(--radius-pill);
  animation: ds-spin var(--speed-slow) linear infinite;
  vertical-align: -0.15em;
}

@media (prefers-reduced-motion: reduce) {
  .ds-fade-in,
  .ds-fade-in-up,
  .ds-scale-in,
  .content-wrapper > .content { animation: none; }
}
