/* ==========================================================================
   Motion system — shared by the claim page and the admin panel.
   ONE scale for the whole site: never hand-pick a duration or curve inline.
   ========================================================================== */
:root {
  --dur-instant: 100ms;  /* press feedback */
  --dur-fast:    160ms;  /* hover, focus, small state flips */
  --dur-base:    240ms;  /* the default: messages, dialogs */
  --dur-slow:    400ms;  /* view entrances, reveals */
  --dur-slower:  600ms;  /* hero choreography */
  --dur-exit-base: 160ms; /* exits run ~65% of entrances — the user already decided */

  --ease-out:    cubic-bezier(0.22, 1, 0.36, 1);   /* default for anything entering/responding */
  --ease-in:     cubic-bezier(0.4, 0, 1, 1);       /* leaving the screen entirely */
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);   /* moves that start and end on screen */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);/* one overshoot, used sparingly */
  --ease-linear: linear;                            /* continuous motion only */

  --stagger: 40ms;
  --travel-xs: 4px;
  --travel-sm: 8px;
  --travel-md: 16px;
}

/* Reduced motion: keep every state change, drop the travel. Nothing may depend
   on an animation finishing to become visible, so durations go to 1ms rather
   than animations being deleted wholesale. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 1ms; --dur-fast: 1ms; --dur-base: 1ms;
    --dur-slow: 1ms; --dur-slower: 1ms; --dur-exit-base: 1ms;
    --stagger: 0ms; --travel-xs: 0px; --travel-sm: 0px; --travel-md: 0px;
  }
  *, *::before, *::after {
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* --- Shared keyframes ---------------------------------------------------- */
@keyframes view-in {
  from { opacity: 0; transform: translateY(var(--travel-md)); }
  to   { opacity: 1; transform: none; }
}
@keyframes msg-in {
  from { opacity: 0; transform: translateY(calc(var(--travel-sm) * -1)); }
  to   { opacity: 1; transform: none; }
}
/* Causality: "that input was wrong". Decays so it reads as a head-shake, not a buzz. */
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* --- Utilities ------------------------------------------------------------
   fill-mode is `backwards`, never `both`: the end frame equals the element's
   own style anyway, and a forwards fill would pin `transform: none` on top of
   every later :hover / :active state (press feedback silently stops working). */
.view-in { animation: view-in var(--dur-slow) var(--ease-out) backwards; }
.msg-in  { animation: msg-in var(--dur-base) var(--ease-out) backwards; }
.shake   { animation: shake var(--dur-slow) var(--ease-out); }
@media (prefers-reduced-motion: reduce) {
  .shake { animation: none; }
}
