/* ═══════════════════════════════════════════════════════════════════
 *  Helios VMS — Animations
 *  ─────────────────────────────────────────────────────────────────
 *  The keyframes that make pages feel alive. Every named animation
 *  here has a *purpose* — it's not decoration, it's feedback.
 *
 *  Guidelines:
 *   - Subtle is better than dramatic
 *   - Always pair with --ease (see tokens.css)
 *   - Respect prefers-reduced-motion
 *   - Pulse / breathe animations are for *passive* indicators
 *   - Arrive / stagger animations are for *new* content
 *   - Spring eases are for *user-triggered* actions
 * ═════════════════════════════════════════════════════════════════ */

/* ── 1. Pulse / breathe — for ambient status indicators ───────────
 *  Used on: status dots, recording badges, "scanning" pills, 
 *  the live-breath dot in the top bar. */

/* Soft opacity pulse — generic */
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.5; }
}

/* Recording red blink — slightly faster, more urgent */
@keyframes rec-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.85); }
}

/* Live breath — for status dots that say "I am alive and well" */
@keyframes live-breath {
  0%, 100% {
    opacity: 1;
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 35%, transparent);
  }
  50% {
    opacity: 0.85;
    box-shadow: 0 0 0 4px transparent;
  }
}

/* CTA breathe — the pulsing border on "ready to add" banners */
@keyframes cta-breathe {
  0%, 100% {
    box-shadow:
      0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent),
      0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent);
  }
  50% {
    box-shadow:
      0 0 0 4px var(--accent-soft),
      0 0 24px 6px var(--accent-soft);
  }
}

/* Fresh breathe — celebration glow on newly-added cameras */
@keyframes fresh-breathe {
  0%, 100% {
    box-shadow:
      0 0 0 1.5px var(--info),
      0 0 0 0 color-mix(in srgb, var(--info) 0%, transparent),
      var(--shadow);
  }
  50% {
    box-shadow:
      0 0 0 1.5px var(--info),
      0 0 28px 4px var(--info-line),
      var(--shadow);
  }
}

/* NEW badge pulse — celebratory but not annoying */
@keyframes new-pulse {
  0%, 100% {
    box-shadow: 0 0 12px color-mix(in srgb, var(--info) 55%, transparent);
    transform: translateY(0);
  }
  50% {
    box-shadow: 0 0 18px var(--info);
    transform: translateY(-0.5px);
  }
}

/* Sparkle spin — the tiny rotating sparkle inside NEW badges */
@keyframes sparkle-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* ── 2. Arrive / stagger — for content streaming in ──────────────
 *  Used on: discovery cards as they're found, camera grid initial
 *  render, AI events feed appending new items, search results. */

/* Stagger-in — gentle slide up + fade */
@keyframes stagger-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Tile arrive — used for camera tiles on first paint */
@keyframes tile-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Slide up — used for sticky bars, banners, toasts */
@keyframes slide-up {
  from {
    opacity: 0;
    transform: translateY(140px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Slide down — used for dropdowns, menus */
@keyframes slide-down {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Modal arrive — slight upward float + scale */
@keyframes modal-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Fade in — pure opacity for backdrops */
@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ── 3. Highlight / celebrate — for arrival feedback ─────────────
 *  Used on: a card that was just acted on, the camera you just
 *  added when arriving via /?live=, search match emphasis. */

/* Highlight pulse — short attention-grabber, plays 1-2 times */
@keyframes highlight-pulse {
  0% {
    box-shadow:
      0 0 0 0 color-mix(in srgb, var(--attn) 55%, transparent),
      0 0 0 0 color-mix(in srgb, var(--attn) 0%, transparent);
  }
  40% {
    box-shadow:
      0 0 0 4px var(--attn-line),
      0 0 24px 8px var(--attn-soft);
  }
  100% {
    box-shadow:
      0 0 0 0 color-mix(in srgb, var(--attn) 0%, transparent),
      0 0 0 0 color-mix(in srgb, var(--attn) 0%, transparent);
  }
}

/* Discovery ring — the radar ring that emanates from a device
 *  pin when something is found on the network */
@keyframes disc-ring {
  0%   { transform: scale(0.3); opacity: 0.8; }
  100% { transform: scale(1.2); opacity: 0; }
}

/* Drop-target pulse — when dragging a card, the target slot
 *  pulses to say "yes, here" */
@keyframes drop-pulse {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1.0; }
}

/* ── 4. Activity / loading — for "I'm working on it" ────────────
 *  Used on: spinners, scanning states, anything that streams. */

/* Spinner — universal loading indicator */
@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Indeterminate progress bar */
@keyframes progress-stripe {
  from { background-position: 0 0; }
  to   { background-position: 40px 0; }
}

/* Feed shift — gentle background drift on placeholder camera
 *  tiles when there's no real video yet */
@keyframes feed-shift {
  0% {
    background-position: 0% 50%;
    transform: scale(1) translateX(0);
  }
  50% {
    transform: scale(1.04) translateX(-1%);
  }
  100% {
    background-position: 100% 50%;
    transform: scale(1.02) translateX(1%);
  }
}

/* Placeholder figure walk — gentle horizontal movement of a
 *  silhouette shape across a placeholder tile to suggest "camera
 *  is alive, just no specific frame yet" */
@keyframes feed-walk {
  0%   { left: -10%; transform: scaleX(1); }
  49%  { left: 110%; transform: scaleX(1); }
  50%  { left: 110%; transform: scaleX(-1); }
  99%  { left: -10%; transform: scaleX(-1); }
  100% { left: -10%; transform: scaleX(1); }
}

/* ── 5. Reduced motion — accessibility ──────────────────────────
 *  When the user has prefers-reduced-motion set, kill the
 *  decorative animations but keep functional ones (spinners,
 *  progress, slide-in arrivals at reduced duration). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01s !important;
  }
  /* Spinners still need to spin for legibility — they're the
   *  feedback signal that something is happening */
  .spinner,
  [class*="spinner"] {
    animation-duration: 0.7s !important;
    animation-iteration-count: infinite !important;
  }
}


/* ── B.5.5b alive topbar animations ─────────────────────────── */
@keyframes helios-heart-beat {
  /* currentColor: the pill's own state (the dot is background:currentColor) */
  0%   { transform: scale(1);   box-shadow: 0 0 6px currentColor, 0 0 0 0 color-mix(in srgb, currentColor 60%, transparent); }
  35%  { transform: scale(1.5); box-shadow: 0 0 18px currentColor, 0 0 0 4px color-mix(in srgb, currentColor 14%, transparent); }
  100% { transform: scale(1);   box-shadow: 0 0 6px currentColor, 0 0 0 0 color-mix(in srgb, currentColor 0%, transparent); }
}
@keyframes helios-ring-out {
  0%   { transform: scale(1); opacity: 0.7; }
  100% { transform: scale(4); opacity: 0; }
}
@keyframes helios-particle-drift {
  from { left: -10%; opacity: 0; }
  20%, 80% { opacity: 1; }
  to   { left: 110%; opacity: 0; }
}
@keyframes helios-notif-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.3); }
}
