/* Motion system for appearing / disappearing UI.
   Durations and easings live in tokens.css (--motion-*, --ease-*).
   Only opacity/transform are animated, except <details> height (progressive
   enhancement) and the colour cross-fade while the theme toggle is clicked.
   JS side: static/js/motion.js toggles [data-motion="in" | "out"] and waits for
   animationend before setting [hidden]. */

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

@keyframes mshp-fade-out {
  to { opacity: 0; }
}

@keyframes mshp-drawer-in-right {
  from { opacity: 0; transform: translateX(24px); }
}

@keyframes mshp-drawer-out-right {
  to { opacity: 0; transform: translateX(24px); }
}

@keyframes mshp-drawer-in-left {
  from { opacity: 0; transform: translateX(-24px); }
}

@keyframes mshp-pop-in {
  from { opacity: 0; transform: scale(0.98); }
}

@keyframes mshp-pop-out {
  to { opacity: 0; transform: scale(0.98); }
}

@keyframes mshp-rise-in {
  from { opacity: 0; transform: translateY(6px); }
}

@keyframes mshp-drop-in {
  from { opacity: 0; transform: translateY(-4px); }
}

@keyframes mshp-pulse {
  from { opacity: 0.45; }
  to { opacity: 1; }
}

@keyframes mshp-icon-in {
  from { opacity: 0; transform: rotate(-60deg) scale(0.7); }
}

/* Generic: content that just appeared (fetched panel content, swapped fragments,
   quiz card switch, run results). Added by JS, so it never runs on page load. */
.motion-enter {
  animation: mshp-rise-in var(--motion-base) var(--ease-enter) both;
}

/* Flash messages: rendered by the server, slide/fade in once on load. */
.messages > .message {
  animation: mshp-rise-in var(--motion-base) var(--ease-enter) both;
}

.messages > .message:nth-child(2) { animation-delay: 40ms; }
.messages > .message:nth-child(n + 3) { animation-delay: 80ms; }

/* Status lines that are toggled via [hidden] (feedback widget). Keyframes
   re-run each time the element goes from display:none to visible. */
.feedback-box__status:not([hidden]) {
  animation: mshp-fade-in var(--motion-base) var(--ease-enter) both;
}

/* Skeleton placeholders while a panel is loading. */
.skeleton {
  display: grid;
  gap: var(--space-3);
  padding-top: var(--space-2);
  /* Short delay: fast responses never show the skeleton at all. */
  animation: mshp-fade-in var(--motion-base) var(--ease-enter) 120ms both;
}

.skeleton__line {
  display: block;
  height: 0.9rem;
  border-radius: 6px;
  background: var(--mshp-line);
  animation: mshp-pulse 0.9s ease-in-out infinite alternate;
}

.skeleton__line--title { height: 1.4rem; width: 60%; margin-bottom: var(--space-2); }
.skeleton__line--short { width: 40%; }
.skeleton__line--block { height: 4.5rem; border-radius: var(--radius-md); }

/* <details>: animate open/close height where the browser supports it
   (Chrome 131+). Elsewhere it simply snaps, exactly as before. */
@supports (interpolate-size: allow-keywords) and selector(::details-content) {
  details {
    interpolate-size: allow-keywords;
  }

  details::details-content {
    block-size: 0;
    opacity: 0;
    overflow: clip;
    overflow-clip-margin: 4px;
    transition:
      block-size var(--motion-base) var(--ease-exit),
      opacity var(--motion-fast) var(--ease-exit),
      content-visibility var(--motion-base) allow-discrete;
  }

  details[open]::details-content {
    block-size: auto;
    opacity: 1;
    transition-timing-function: var(--ease-enter);
    transition-duration: var(--motion-slow), var(--motion-base), var(--motion-slow);
  }

  /* Once fully open, don't clip (focus rings, wide code, popovers inside). */
  details[open][data-motion-settled]::details-content {
    overflow: visible;
  }
}

/* Theme switch: colours cross-fade only while html.theme-switching is set
   (added by theme.js on click, never on load). */
html.theme-switching,
html.theme-switching *,
html.theme-switching *::before,
html.theme-switching *::after {
  transition:
    background-color var(--motion-slow) ease,
    color var(--motion-slow) ease,
    border-color var(--motion-slow) ease,
    fill var(--motion-slow) ease,
    stroke var(--motion-slow) ease,
    box-shadow var(--motion-slow) ease !important;
  transition-delay: 0s !important;
}

html.theme-switching .theme-toggle__icon {
  animation: mshp-icon-in var(--motion-slow) var(--ease-enter) both;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-fast: 0ms;
    --motion-base: 0ms;
    --motion-slow: 0ms;
  }

  .skeleton,
  .skeleton__line,
  .motion-enter,
  .messages > .message {
    animation: none !important;
  }

  details::details-content {
    transition: none !important;
  }
}
