/* ==========================================================================
   Animations — keyframes + scroll reveal system
   All animations are transform/opacity only (GPU-cheap) and are neutralised
   globally by the prefers-reduced-motion rule in base.css.
   ========================================================================== */

@keyframes blobFloat {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(3%, -4%) scale(1.05); }
  66%      { transform: translate(-3%, 3%) scale(0.97); }
}

@keyframes floatCard {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}

@keyframes fadeSlideUp {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes fadeScale {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: scale(1); }
}

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

@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* ---- Scroll reveal --------------------------------------------------------
   animations.js toggles .is-visible once an element crosses the viewport.
--------------------------------------------------------------------------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity var(--duration-slow) var(--ease-out-soft),
              transform var(--duration-slow) var(--ease-out-soft);
}

[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
}

[data-reveal="left"] { transform: translateX(-32px); }
[dir="rtl"] [data-reveal="left"] { transform: translateX(32px); }
[data-reveal="left"].is-visible { transform: translateX(0); }

[data-reveal="right"] { transform: translateX(32px); }
[dir="rtl"] [data-reveal="right"] { transform: translateX(-32px); }
[data-reveal="right"].is-visible { transform: translateX(0); }

[data-reveal="scale"] { transform: scale(0.94); }
[data-reveal="scale"].is-visible { transform: scale(1); }

/* Staggered children: animations.js reads data-reveal-group and applies
   incrementally delayed transition-delay to direct children. */
[data-reveal-group] > * {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--duration-slow) var(--ease-out-soft),
              transform var(--duration-slow) var(--ease-out-soft);
}

[data-reveal-group].is-visible > * {
  opacity: 1;
  transform: translateY(0);
}

/* ---- Loading skeleton (used only while an embed iframe boots) ------------*/
.skeleton {
  background: linear-gradient(90deg, var(--color-border) 25%, var(--color-bg-subtle) 50%, var(--color-border) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.6s linear infinite;
  border-radius: var(--radius-sm);
}

/* ---- Spinner ---------------------------------------------------------- */
.spinner {
  width: 20px; height: 20px;
  border: 2px solid var(--color-primary-soft);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
