/* ──────────────────────────────────────────────────────────────────────
   Keyframes, the motion utilities JS applies, and the reduced-motion opt-out.
   ────────────────────────────────────────────────────────────────────── */

/* ── Keyframes ────────────────────────────────────────────────────── */

/* Ink settling onto the page: the default entrance for anything new. */
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes pop {
  0% {
    opacity: 0;
    transform: scale(0.9);
  }
  60% {
    opacity: 1;
    transform: scale(1.04);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Indeterminate progress: a short bar crossing the full width and leaving. */
@keyframes sweep {
  from { transform: translateX(-100%); }
  to { transform: translateX(320%); }
}

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

@keyframes drawRule {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* Matches the 24-unit dash array on .check__tick. */
@keyframes tickDraw {
  from { stroke-dashoffset: 24; }
  to { stroke-dashoffset: 0; }
}

@keyframes pulseSoft {
  0%,
  100% {
    opacity: 0.5;
    transform: scaleX(1);
  }
  50% {
    opacity: 1;
    transform: scaleX(1.8);
  }
}

@keyframes toastIn {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* A distinct name rather than `toastIn reverse`, so swapping the class
   restarts the animation instead of snapping to the finished state. */
@keyframes toastOut {
  from {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
  to {
    opacity: 0;
    transform: translateY(12px) scale(0.96);
  }
}

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

/* ── Utilities ────────────────────────────────────────────────────── */

.anim-rise { animation: rise var(--dur-mid) var(--ease-out) both; }
.anim-pop { animation: pop var(--dur-mid) var(--ease-spring) both; }
.anim-fade { animation: fadeIn var(--dur-mid) var(--ease-out) both; }

/* JS sets --i per item so a list deals itself out like cards. */
.stagger-item {
  animation: rise var(--dur-mid) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 45ms);
}

/* Blinking block caret, shown while a query types itself out. */
.typing::after {
  content: '';
  display: inline-block;
  width: 0.5em;
  height: 1em;
  margin-left: 2px;
  vertical-align: -0.12em;
  background: var(--accent);
  animation: caret 1.1s linear infinite;
}

/* ── First paint ──────────────────────────────────────────────────── */

.topbar {
  animation: fadeIn var(--dur-mid) var(--ease-out) both;
}

.hero {
  animation: rise var(--dur-slow) var(--ease-out) both;
  animation-delay: 60ms;
}

/* The three steps arrive in order, which also reads as "do these in turn". */
.step {
  animation: rise var(--dur-slow) var(--ease-out) both;
}
.step:nth-of-type(1) { animation-delay: 120ms; }
.step:nth-of-type(2) { animation-delay: 190ms; }
.step:nth-of-type(3) { animation-delay: 260ms; }

.actionbar {
  animation: rise var(--dur-slow) var(--ease-spring) both;
  animation-delay: 320ms;
}

/* ── Component motion ─────────────────────────────────────────────── */

.check input:checked + .check__box .check__tick {
  animation: tickDraw var(--dur-mid) var(--ease-out) both;
}

.toast { animation: toastIn var(--dur-mid) var(--ease-spring) both; }
.toast.is-leaving { animation: toastOut var(--dur-mid) var(--ease-out) both; }

/* ── Reduced motion ───────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Land the translate-based entrances in their settled state. The drawer is
     deliberately absent: its translate is a position, not an entrance. */
  .anim-rise,
  .anim-pop,
  .anim-fade,
  .stagger-item,
  .topbar,
  .hero,
  .step,
  .actionbar,
  .toast {
    animation-delay: 0ms !important;
    transform: none !important;
    opacity: 1 !important;
  }

  .typing::after { animation: none !important; }
}
