/* ==========================================================================
   Open Ground — the arrival grammar.

   One entrance, cascaded by reading order, played once. Content is visible
   by default: the [data-rise] attribute is only set to "out" by JS after it
   has confirmed motion is wanted, so a failed script leaves a readable page
   rather than a blank one.
   ========================================================================== */

[data-rise='out'] {
  opacity: 0;
  transform: translateY(22px);
  filter: blur(6px);
}

[data-rise='in'] {
  opacity: 1;
  transform: none;
  filter: none;
  transition:
    opacity 760ms var(--out) var(--rd, 0ms),
    transform 900ms var(--out) var(--rd, 0ms),
    filter 700ms var(--out) var(--rd, 0ms);
}

/* Rows in a list cascade individually rather than as one block. */
[data-rise-rows] > * { opacity: 0; transform: translateY(14px); }
[data-rise-rows='in'] > * {
  opacity: 1;
  transform: none;
  transition: opacity 560ms var(--out) var(--d, 0ms), transform 640ms var(--out) var(--d, 0ms);
}

/* A hovered thing does something, rather than changing tint. */
.lift { transition: transform var(--ease-s), box-shadow var(--ease-s); }
.lift:hover { transform: translateY(-3px); box-shadow: var(--lift-2); }

/* the little arrow in a circle that spins into place */
.spin { transition: transform var(--spring); }
:where(a, button):hover > .spin { transform: rotate(45deg); }

@media (prefers-reduced-motion: reduce) {
  [data-rise='out'] { opacity: 1; transform: none; filter: none; }
  [data-rise-rows] > * { opacity: 1; transform: none; }
}

/* A drawn line completes itself: used by the event tiles' course outlines. */
@keyframes draw { to { stroke-dashoffset: 0; } }
