/* ============================================================================
   animations.css — motion.

   Everything here is meant to read as a physical printing process: sheets drop
   onto the stack, stamps slam, pins are pushed into paper, ink lines are drawn
   rather than faded in. Nothing eases in from nowhere.
   ========================================================================= */

/* A screen arriving = a fresh sheet laid down. */
@keyframes sheet-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes sheet-drop {
  0%   { opacity: 0; transform: translateY(-24px) rotate(-1.2deg) scale(1.03); }
  60%  { opacity: 1; transform: translateY(3px) rotate(0.3deg) scale(0.998); }
  100% { opacity: 1; transform: none; }
}

/* The verdict stamp: falls from above, overshoots, settles askew. */
@keyframes stamp-slam {
  0%   { opacity: 0; transform: rotate(-24deg) scale(2.6); }
  55%  { opacity: 0.95; transform: rotate(-11deg) scale(0.92); }
  75%  { transform: rotate(-13deg) scale(1.04); }
  100% { opacity: 0.88; transform: rotate(-12deg) scale(1); }
}

/* A pin pushed into the sheet, with a little bounce. */
@keyframes pin-drop {
  0%   { opacity: 0; transform: translateY(-26px) scale(2.2); }
  70%  { opacity: 1; }
  100% { opacity: 1; transform: none; }
}

/* The route drawing itself, nib-first. */
@keyframes draw-passage {
  to { stroke-dashoffset: 0; }
}

/* A hint arriving as a slip pushed under the fold. */
@keyframes hint-in {
  0%   { opacity: 0; transform: translateX(-14px) rotate(-0.6deg); }
  100% { opacity: 1; transform: none; }
}

.hint.is-new { animation: hint-in 420ms cubic-bezier(.2, .9, .3, 1) both; }
/* The bought clue arrives the same way the free ones do. */
.cause.is-new { animation: hint-in 420ms cubic-bezier(.2, .9, .3, 1) both; }

/* A rejected guess. Short, sharp, not a wobble. */
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  15% { transform: translateX(-7px); }
  30% { transform: translateX(6px); }
  45% { transform: translateX(-4px); }
  60% { transform: translateX(3px); }
  80% { transform: translateX(-1px); }
}

.is-shaking { animation: shake 380ms cubic-bezier(.36, .07, .19, .97); }

/* The inset plate irising open. */
@keyframes inset-open {
  from { opacity: 0; transform: scale(0.6); }
  to   { opacity: 1; transform: none; }
}

/* The masthead settling on first paint. */
@keyframes ink-set {
  from { opacity: 0; letter-spacing: 0.14em; filter: blur(3px); }
  to   { opacity: 1; letter-spacing: 0.01em; filter: none; }
}

.masthead__home { animation: ink-set 900ms ease-out both; }

/* ── reduced motion ────────────────────────────────────────────────────────
   Honoured even though the full accessibility pass is out of scope: the map
   arc, the stamp slam and the pin drops are large-amplitude movements, and
   this is the one setting where ignoring the preference can make someone
   physically unwell.
   ------------------------------------------------------------------------ */

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

  /* Keep the end states legible rather than mid-animation. */
  .broadside__stamp.is-stamped { opacity: 0.88; transform: rotate(-12deg) scale(1); }
  .passage { stroke-dashoffset: 0 !important; }
}
