/* ============================================================================
   visuals.css — per-slide right-half visuals (ported from the fidex onboarding
   step animations). Pure CSS + SVG, no library. The animation primitives below
   are lifted from the product's onboarding (onb-* + ih-*) and re-bound to the
   deck's tokens. Visuals are (re)built per slide enter, so they replay.
   ============================================================================ */

/* ---- slot wrapper: centre the visual in the reserved right half ----------- */
.viz {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  width: 100%;
  max-width: 580px;
  padding: var(--space-md);
}
.viz__caption {
  max-width: 34ch;
  text-align: center;
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
  text-wrap: balance;
  margin: 0;
}

/* ---- icon pop (tiles, action icons, stage icons) -------------------------- */
@keyframes onb-icon-pop {
  from { opacity: 0; transform: scale(0.25); filter: blur(4px); }
  to   { opacity: 1; transform: scale(1);    filter: blur(0); }
}
.onb-icon-pop {
  animation: onb-icon-pop 260ms cubic-bezier(0.2, 0, 0, 1) both;
  animation-delay: var(--onb-delay, 0ms);
}

/* ---- grid card reveal (engagement tiles) ---------------------------------- */
@keyframes onb-card-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.onb-card-stagger {
  opacity: 0;
  animation: onb-card-in 240ms cubic-bezier(0.2, 0, 0, 1) both;
  animation-delay: calc(min(var(--i, 0), 5) * 50ms + 40ms);
}

/* ---- terminal line reveal + caret ----------------------------------------- */
@keyframes onb-line-in {
  from { opacity: 0; transform: translateY(3px); }
  to   { opacity: 1; transform: translateY(0); }
}
.onb-line-stagger {
  opacity: 0;
  animation: onb-line-in 200ms cubic-bezier(0.2, 0, 0, 1) both;
  animation-delay: calc(min(var(--i, 0), 3) * 120ms + 80ms);
}
@keyframes onb-caret-blink {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}
.onb-caret { animation: onb-caret-blink 1s steps(1, start) infinite; }

/* ---- contribute pipeline: stage lift + chevron activate ------------------- */
@keyframes onb-stage-in {
  from { opacity: 0; transform: translateY(6px) scale(0.92); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.onb-stage-stagger {
  opacity: 0;
  animation: onb-stage-in 260ms cubic-bezier(0.2, 0, 0, 1) both;
  animation-delay: calc(min(var(--i, 0), 2) * 110ms + 40ms);
}
@keyframes onb-chevron-in {
  from { opacity: 0; transform: scale(0.6); }
  to   { opacity: 1; transform: scale(1); }
}
.onb-chevron-in {
  opacity: 0;
  animation: onb-chevron-in 160ms cubic-bezier(0.2, 0, 0, 1) both;
  animation-delay: calc(min(var(--i, 0), 2) * 110ms + 120ms);
}

/* ---- data-flow constellation (IntegrationHub) ----------------------------- */
@keyframes ih-base-in { from { opacity: 0; } to { opacity: 0.55; } }
.ih-link-base {
  opacity: 0;
  stroke: var(--line);
  stroke-width: 1.25;
  animation: ih-base-in 420ms cubic-bezier(0.2, 0, 0, 1) both;
  animation-delay: 360ms;
}
@keyframes ih-flow {
  0%   { stroke-dashoffset: 12;  opacity: 0; }
  12%  { opacity: 1; }
  82%  { opacity: 1; }
  100% { stroke-dashoffset: -90; opacity: 0; }
}
.ih-link-pulse {
  stroke: var(--brand);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 12 90;
  opacity: 0;
  filter: drop-shadow(0 0 2px var(--brand-soft));
  animation: ih-flow 2.6s linear infinite;
}
@keyframes ih-center-bloom {
  from { opacity: 0; transform: scale(0.4); filter: blur(4px); }
  to   { opacity: 1; transform: scale(1);   filter: blur(0); }
}
.ih-center {
  transform-box: fill-box;
  transform-origin: center;
  animation: ih-center-bloom 380ms cubic-bezier(0.2, 0, 0, 1) both;
  animation-delay: 60ms;
}
@keyframes ih-halo-breathe {
  0%, 100% { opacity: 0.25; transform: scale(0.96); }
  50%      { opacity: 0.5;  transform: scale(1.06); }
}
.ih-center-halo {
  transform-box: fill-box;
  transform-origin: center;
  animation: ih-halo-breathe 3.2s ease-in-out infinite;
}

/* ---- engagement content card (like beats/fills, count ticks, bookmark fills,
   what's-new dot pulses) ---------------------------------------------------- */
@keyframes onb-eng-card-in {
  from { opacity: 0; transform: translateY(10px) scale(0.97); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.onb-eng-card { opacity: 0; animation: onb-eng-card-in 320ms cubic-bezier(0.2,0,0,1) both; animation-delay: 60ms; }
@keyframes onb-eng-beat {
  0% { transform: scale(1); } 30% { transform: scale(1.28); }
  55% { transform: scale(0.9); } 80% { transform: scale(1.08); } 100% { transform: scale(1); }
}
.onb-eng-heart { animation: onb-eng-beat 560ms cubic-bezier(0.2,0,0,1) both; animation-delay: 760ms; }
@keyframes onb-eng-fill-in {
  0% { opacity: 0; transform: scale(0.4); } 60% { opacity: 1; transform: scale(1.12); } 100% { opacity: 1; transform: scale(1); }
}
@keyframes onb-eng-fill-out { from { opacity: 1; } to { opacity: 0; } }
.onb-eng-filled  { opacity: 0; animation: onb-eng-fill-in 420ms cubic-bezier(0.2,0,0,1) both; animation-delay: 800ms; }
.onb-eng-outline { animation: onb-eng-fill-out 200ms linear both; animation-delay: 820ms; }
.onb-eng-bm-filled  { opacity: 0; animation: onb-eng-fill-in 420ms cubic-bezier(0.2,0,0,1) both; animation-delay: 1180ms; }
.onb-eng-bm-outline { animation: onb-eng-fill-out 200ms linear both; animation-delay: 1200ms; }
@keyframes onb-eng-num-out { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-80%); } }
@keyframes onb-eng-num-in  { from { opacity: 0; transform: translateY(80%); } to { opacity: 1; transform: translateY(0); } }
.onb-eng-num-old { animation: onb-eng-num-out 300ms cubic-bezier(0.2,0,0,1) both; animation-delay: 820ms; }
.onb-eng-num-new { opacity: 0; animation: onb-eng-num-in 300ms cubic-bezier(0.2,0,0,1) both; animation-delay: 860ms; }
@keyframes onb-eng-dot {
  0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.6); opacity: 0.5; }
}
.onb-eng-dot { transform-box: fill-box; transform-origin: center; animation: onb-eng-dot 1.8s ease-in-out 1400ms infinite; }

/* ---- approved seal: stamp-in + a slowly rotating dashed ring -------------- */
@keyframes viz-stamp {
  0%   { opacity: 0; transform: scale(1.4); filter: blur(4px); }
  60%  { opacity: 1; transform: scale(0.96); filter: blur(0); }
  100% { transform: scale(1); }
}
.viz-stamp {
  transform-box: fill-box; transform-origin: center;
  animation: viz-stamp 520ms cubic-bezier(0.2, 0, 0, 1) both; animation-delay: 80ms;
}
@keyframes viz-spin { to { transform: rotate(360deg); } }
.viz-spin {
  transform-box: fill-box; transform-origin: center;
  animation: viz-spin 24s linear infinite;
}

/* slide 12 — deferred feature-flag visual: an OFF toggle that keeps teasing on,
   and a dashed "~ similar" advisory link that travels. */
.defer-toggle {
  position: relative; width: 38px; height: 22px; flex: 0 0 auto;
  border-radius: 999px; background: var(--warn-soft);
  border: 1px solid rgba(181, 119, 0, 0.35);
}
.defer-knob {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--warn);
  animation: defer-nudge 2.8s ease-in-out infinite;
}
@keyframes defer-nudge { 0%, 68%, 100% { transform: translateX(0); } 84% { transform: translateX(5px); } }
.defer-dash { animation: defer-dash 0.9s linear infinite; }
@keyframes defer-dash { to { stroke-dashoffset: -8; } }
@media (prefers-reduced-motion: reduce) {
  .defer-knob, .defer-dash { animation: none; }
}

/* slide 5b — "no friction": the knob glides the full path and back, no snag. */
.friction-glide {
  transform-box: fill-box;
  animation: friction-glide 3.4s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes friction-glide {
  0%, 10%   { transform: translateX(0); }
  50%, 60%  { transform: translateX(280px); }
  100%      { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) { .friction-glide { animation: none; } }

@media (prefers-reduced-motion: reduce) {
  .onb-icon-pop, .onb-card-stagger, .onb-line-stagger, .onb-caret,
  .onb-stage-stagger, .onb-chevron-in, .ih-center, .viz-stamp,
  .onb-eng-card, .onb-eng-heart, .onb-eng-filled, .onb-eng-bm-filled, .onb-eng-num-new {
    animation: none; opacity: 1; transform: none; filter: none;
  }
  .onb-eng-outline, .onb-eng-bm-outline, .onb-eng-num-old { animation: none; opacity: 0; }
  .onb-eng-dot, .viz-spin { animation: none; }
  .ih-link-base   { animation: none; opacity: 0.55; }
  .ih-link-pulse  { animation: none; opacity: 0; }
  .ih-center-halo { animation: none; opacity: 0.35; transform: none; }
}
