/* Shared keyframes, so no component re-authors its own spinner or fade. */

@keyframes spin {
  to {
    transform: rotate(1turn);
  }
}

@keyframes pulse {
  50% {
    opacity: 0.45;
  }
}

/* Scale-only, no opacity — the element is already on screen, so a fade would
   blink it. Used for the lesson-complete check the moment it's earned. */
@keyframes pop {
  0% {
    scale: 1;
  }
  45% {
    scale: 1.18;
  }
  100% {
    scale: 1;
  }
}

/* Pair with an animation-delay so brief states can skip it entirely — a fast
   form round-trip never flashes its spinner. */
@keyframes appear {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* For the typed hero title; step-end elsewhere gives a hard on/off, not a fade. */
@keyframes caret-blink {
  50% {
    opacity: 0;
  }
}

/* Homepage hero headline stack; pair with per-child animation-delay for a
   light stagger. */
@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(0.75rem);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Toast lifecycle in one keyframe, timed to land exactly when the
   element-removal controller pulls the node (4s). */
@keyframes appear-then-fade {
  0% {
    opacity: 0;
    transform: translateY(-0.5rem);
  }
  6%,
  92% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(-0.5rem);
  }
}

/* :where() keeps specificity at zero, so a component can still override
   transform-origin/--overlay-duration. Gated on reduced-motion so the base
   opacity:0 never leaves a surface invisible when motion is off; browsers
   without allow-discrete/@starting-style support just show it instantly. */
@media (prefers-reduced-motion: no-preference) {
  :where(dialog, [popover]) {
    opacity: 0;
    scale: 0.97;
    transition:
      opacity var(--overlay-duration, 180ms) ease,
      scale var(--overlay-duration, 180ms) ease,
      overlay var(--overlay-duration, 180ms) ease allow-discrete,
      display var(--overlay-duration, 180ms) ease allow-discrete;
  }

  :where(dialog[open], [popover]:popover-open) {
    opacity: 1;
    scale: 1;
  }

  @starting-style {
    :where(dialog[open], [popover]:popover-open) {
      opacity: 0;
      scale: 0.97;
    }
  }

  :where(dialog)::backdrop {
    opacity: 0;
    transition:
      opacity var(--overlay-duration, 180ms) ease,
      overlay var(--overlay-duration, 180ms) ease allow-discrete,
      display var(--overlay-duration, 180ms) ease allow-discrete;
  }

  :where(dialog[open])::backdrop {
    opacity: 1;
  }

  @starting-style {
    :where(dialog[open])::backdrop {
      opacity: 0;
    }
  }
}
