/* ============================================================
   ANIMATIONS
   ============================================================ */

@keyframes pulse-dot {
  0%, 100% { box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.18); }
  50% { box-shadow: 0 0 0 6px rgba(var(--accent-rgb), 0.06); }
}

@keyframes blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

@keyframes marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

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

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

@keyframes spin-slow {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

@keyframes gradient-shift {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

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

/* ---- Scroll reveal ----
   Fail-safe by design: elements are visible by default. JS adds
   `.pre` only to the elements it is about to observe, right before
   handing them to IntersectionObserver. If JS never runs (blocked,
   errors, no-JS), nothing ever gets hidden in the first place. */
.reveal, .reveal-scale, .reveal-left, .reveal-right { opacity: 1; transform: none; }

.reveal.pre { opacity: 0; transform: translateY(24px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
.reveal.pre.in-view { opacity: 1; transform: translateY(0); }

.reveal-scale.pre { opacity: 0; transform: scale(0.94); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); }
.reveal-scale.pre.in-view { opacity: 1; transform: scale(1); }

.reveal-left.pre { opacity: 0; transform: translateX(-28px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
.reveal-left.pre.in-view { opacity: 1; transform: translateX(0); }

.reveal-right.pre { opacity: 0; transform: translateX(28px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
.reveal-right.pre.in-view { opacity: 1; transform: translateX(0); }

.stagger > * { transition-delay: calc(var(--i, 0) * 70ms); }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal-scale, .reveal-left, .reveal-right {
    opacity: 1 !important; transform: none !important;
  }
}

/* ---- Floating decorative icons (hero) ---- */
.float-icon { animation: float-y 5s ease-in-out infinite; }
.float-icon.d2 { animation-delay: 1.1s; }
.float-icon.d3 { animation-delay: 2.2s; }

/* ---- Page load ---- */
.page-enter { animation: fade-in 0.5s var(--ease); }

/* ---- Loading skeleton (used while cards mount) ---- */
.skeleton {
  background: linear-gradient(90deg, var(--surface) 25%, var(--surface-hover) 50%, var(--surface) 75%);
  background-size: 200% 100%;
  animation: skeleton-sheen 1.4s ease-in-out infinite;
  border-radius: var(--radius-md);
}

/* ---- Loader (initial page paint) ---- */
.route-loader {
  position: fixed; inset: 0; z-index: 300;
  background: var(--bg);
  display: flex; align-items: center; justify-content: center;
  transition: opacity 0.4s ease, visibility 0.4s ease;
}
.route-loader.hidden { opacity: 0; visibility: hidden; }
.route-loader .loader-mark {
  width: 36px; height: 36px;
  border-radius: var(--radius-sm);
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  animation: spin-slow 0.8s linear infinite;
}
