/* ==========================================================================
   Animations — keyframes and motion utilities
   docs/06 §6. Every animation completes under 300ms except the dock entrance
   (320ms, once per page load) and chart draws (exempt — the draw is content).
   Animate only transform and opacity.
   ========================================================================== */

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

@keyframes rise-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

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

@keyframes rise-in-message {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* .c-dock centers itself with a static transform: translateX(-50%) — that
   offset must be baked into every keyframe here too. A transform set by a
   *keyframe* replaces the element's transform outright (it does not compose
   with the plain CSS rule), so leaving the -50% out would silently decenter
   the dock the moment this animation's fill-mode holds its end state. */
@keyframes dock-enter {
  from { opacity: 0; transform: translate(-50%, 24px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(16px) scale(.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes toast-out {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(8px); }
}

/* Same reasoning as dock-enter above: .c-modal and .c-palette both center
   with a static transform: translateX(-50%), so it has to be baked into
   these keyframes rather than left to compose with the base rule. */
@keyframes modal-enter {
  from { opacity: 0; transform: translate(-50%, 8px) scale(.97); }
  to   { opacity: 1; transform: translate(-50%, 0) scale(1); }
}

@keyframes modal-exit {
  from { opacity: 1; transform: translate(-50%, 0) scale(1); }
  to   { opacity: 0; transform: translate(-50%, 0) scale(.98); }
}

@keyframes sheet-enter {
  from { transform: translateX(100%); }
  to   { transform: translateX(0); }
}

@keyframes overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes popover-in {
  from { opacity: 0; transform: scale(.98); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes pulse-dot {
  0%, 100% { opacity: .35; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.15); }
}

@keyframes shimmer {
  from { background-position: -300px 0; }
  to   { background-position: 300px 0; }
}

@keyframes spring-pop {
  0%   { transform: scale(.94); opacity: 0; }
  60%  { transform: scale(1.02); opacity: 1; }
  100% { transform: scale(1); }
}

@keyframes shake-x {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}

@keyframes draw-check {
  from { stroke-dashoffset: 24; }
  to   { stroke-dashoffset: 0; }
}

@keyframes bar-grow {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

@keyframes line-draw {
  from { stroke-dashoffset: var(--path-length, 1000); }
  to   { stroke-dashoffset: 0; }
}

@keyframes splash-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.015); }
}

/* ---- Utility classes ---------------------------------------------------- */

.anim-fade-in      { animation: fade-in var(--dur-slow) var(--ease-out) both; }
.anim-rise-in       { animation: rise-in var(--dur-slow) var(--ease-out) both; }
.anim-rise-in-sm    { animation: rise-in-sm var(--dur-base) var(--ease-out) both; }
.anim-message-in    { animation: rise-in-message var(--dur-slow) var(--ease-out) both; }
.anim-dock-enter    { animation: dock-enter 320ms var(--ease-out) both; animation-delay: 120ms; }
.anim-toast-in      { animation: toast-in var(--dur-slow) var(--ease-spring) both; }
.anim-toast-out     { animation: toast-out var(--dur-fast) var(--ease-in) both; }
.anim-modal-enter   { animation: modal-enter var(--dur-slow) var(--ease-out) both; }
.anim-modal-exit    { animation: modal-exit var(--dur-fast) var(--ease-in) both; }
.anim-sheet-enter   { animation: sheet-enter var(--dur-slow) var(--ease-out) both; }
.anim-overlay-in    { animation: overlay-in var(--dur-base) var(--ease-out) both; }
.anim-popover-in    { animation: popover-in var(--dur-fast) var(--ease-out) both; }
.anim-shake         { animation: shake-x 160ms var(--ease-inout) 2; }
.anim-spring-pop    { animation: spring-pop var(--dur-slow) var(--ease-spring) both; }

.anim-pulse-dot {
  animation: pulse-dot 1400ms var(--ease-inout) infinite;
}

.anim-breathe {
  animation: splash-breathe 3000ms var(--ease-inout) infinite;
}

/* Staggering: apply .stagger to a container; children get incremental delay */
.stagger > * { animation-delay: calc(var(--stagger-i, 0) * 40ms); }

/* ---- Skeleton shimmer ---------------------------------------------------- */

.skeleton {
  position: relative;
  background: var(--ink-50);
  border-radius: var(--r-sm);
  overflow: hidden;
  color: transparent !important;
}

.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(
    90deg,
    rgba(255,255,255,0) 0,
    rgba(255,255,255,.65) 60px,
    rgba(255,255,255,0) 120px
  );
  background-size: 300px 100%;
  background-repeat: no-repeat;
  animation: shimmer 1200ms linear infinite;
}

/* ---- Optimistic message pulse -------------------------------------------- */

.is-pending {
  opacity: .6;
}

.is-pending .c-bubble__pulse {
  display: inline-block;
}

/* ---- prefers-reduced-motion overrides ------------------------------------
   Collapse everything to a static end state. base.css already zeroes
   durations globally; this removes transform offsets that would otherwise
   render a frozen mid-animation frame. */

@media (prefers-reduced-motion: reduce) {
  .anim-fade-in, .anim-rise-in, .anim-rise-in-sm, .anim-message-in,
  .anim-toast-in, .anim-sheet-enter, .anim-overlay-in, .anim-popover-in,
  .anim-spring-pop {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  /* .c-dock and .c-modal/.c-palette center themselves with a static
     transform: translateX(-50%) on the same element these classes animate.
     Forcing transform: none here would strip that centering along with the
     animation, so these two are deliberately left to fall back to their
     component rule's own transform once animation: none removes the
     keyframe that was overriding it. */
  .anim-dock-enter, .anim-modal-enter {
    animation: none !important;
    opacity: 1 !important;
  }

  .anim-pulse-dot { animation: none !important; opacity: .8 !important; }
  .anim-breathe { animation: none !important; }
  .skeleton::after { animation: none !important; display: none; }
}
