/**
 * Motion (blueprint sections 51, 111).
 *
 * Every animation here is doing one of three jobs, and anything that was doing
 * none of them is not here:
 *
 *   1. **Explaining where something came from.** A card that rises into place
 *      tells you it is new; one that simply appears could have been there all
 *      along.
 *   2. **Confirming a press.** A tap with no response reads as a tap that did
 *      not register, and the next thing the reader does is press again.
 *   3. **Showing that something is still working.** A drawing mark during boot
 *      is the difference between "loading" and "broken".
 *
 * Two rules the whole file obeys:
 *
 * - **Nothing moves on the critical path.** Transforms only, so the compositor
 *   does the work and nothing triggers layout. A phone on a bus in a dead spot
 *   has better things to do.
 * - **`prefers-reduced-motion` removes motion, not information.** Elements end
 *   in their final state immediately; nothing fades out of reach and nothing
 *   becomes invisible. Vestibular disorders are common, and a pilgrimage app
 *   is used by people who are tired, in the sun, and moving.
 */

/* ---------------------------------------------------------------- entry -- */

/**
 * Entrance movement, and deliberately **no opacity**.
 *
 * The first version faded from 0. Measured in a browser that was not
 * compositing frames — a backgrounded tab, an embedded webview, a machine
 * under load — every card sat at `opacity: 0` with its animation "running" at
 * time zero and never advancing. `animation-fill-mode: both` faithfully held
 * the *from* state, so the entire results list was invisible while being
 * perfectly present in the DOM. An animation that can hide content when it
 * fails to run is not a nicety, it is a blank screen.
 *
 * Transform-only cannot do that. If the animation never ticks, the card is
 * ten pixels low and completely readable.
 */
@keyframes kt-rise {
  from {
    transform: translate3d(0, 10px, 0);
  }
  to {
    transform: none;
  }
}

/**
 * A staggered entrance for a list of results.
 *
 * Capped at eight steps: beyond that the last card waits long enough for the
 * delay to read as slowness rather than sequence, and on a long list the
 * reader has scrolled past it anyway.
 */
.stack > *,
.card-grid > *,
.rail > * {
  animation: kt-rise 320ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.stack > *:nth-child(1),
.card-grid > *:nth-child(1),
.rail > *:nth-child(1) {
  animation-delay: 0ms;
}
.stack > *:nth-child(2),
.card-grid > *:nth-child(2),
.rail > *:nth-child(2) {
  animation-delay: 40ms;
}
.stack > *:nth-child(3),
.card-grid > *:nth-child(3),
.rail > *:nth-child(3) {
  animation-delay: 80ms;
}
.stack > *:nth-child(4),
.card-grid > *:nth-child(4),
.rail > *:nth-child(4) {
  animation-delay: 120ms;
}
.stack > *:nth-child(5),
.card-grid > *:nth-child(5),
.rail > *:nth-child(5) {
  animation-delay: 160ms;
}
.stack > *:nth-child(6),
.card-grid > *:nth-child(6),
.rail > *:nth-child(6) {
  animation-delay: 200ms;
}
.stack > *:nth-child(n + 7),
.card-grid > *:nth-child(n + 7),
.rail > *:nth-child(n + 7) {
  animation-delay: 240ms;
}

.hero-card,
.quick-grid {
  animation: kt-rise 380ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

/* ------------------------------------------------------------- feedback -- */

/**
 * Press feedback.
 *
 * 60 ms and two per cent: enough for a thumb to feel, too small to notice as
 * an animation. The `:active` state is the one that matters on touch — hover
 * does not exist there.
 */
.button,
.chip--interactive,
.icon-button,
.quick-tile,
.temple-card,
.tile,
.card--interactive {
  transition:
    transform 120ms cubic-bezier(0.22, 0.61, 0.36, 1),
    border-color 160ms ease,
    background-color 160ms ease,
    box-shadow 160ms ease;
}
.button:active,
.chip--interactive:active,
.icon-button:active,
.quick-tile:active,
.temple-card:active,
.tile:active {
  transform: scale(0.98);
  transition-duration: 60ms;
}

@media (hover: hover) {
  .temple-card:hover,
  .tile:hover {
    transform: translate3d(0, -2px, 0);
    box-shadow: var(--shadow-md);
  }
  .hero-card:hover img {
    transform: scale(1.02);
  }
}
.hero-card img {
  transition: transform 600ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* --------------------------------------------------------------- marks -- */

/**
 * The mark drawing itself.
 *
 * Used on the splash and on any full-screen wait. The path lengths are set
 * generously and clipped by `stroke-dasharray`, so the exact geometry can
 * change without the animation needing to be re-measured.
 */
@keyframes kt-draw {
  from {
    stroke-dashoffset: 320;
  }
  to {
    stroke-dashoffset: 0;
  }
}

.mark--drawing path,
.mark--drawing circle {
  stroke-dasharray: 320;
  animation: kt-draw 1400ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
}
.mark--drawing circle {
  animation-duration: 1800ms;
  animation-delay: 120ms;
}
.mark--drawing path:nth-of-type(2) {
  animation-delay: 320ms;
}
.mark--drawing path:nth-of-type(3) {
  animation-delay: 520ms;
}
.mark--drawing path:nth-of-type(4) {
  animation-delay: 700ms;
}

/* The splash itself: a full-bleed dark field the app paints over. */
.splash {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-4);
  background: radial-gradient(90% 70% at 50% 40%, #1e1a15, #100d0a 70%);
  color: var(--kt-bronze-300);
  transition: opacity 180ms ease;
}
.splash[data-leaving='true'] {
  opacity: 0;
  pointer-events: none;
}
.splash__word {
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  letter-spacing: 0.34em;
  text-indent: 0.34em;
}
.splash__tagline {
  font-size: var(--text-xs);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  opacity: 0.6;
}
.splash__bar {
  width: 8rem;
  height: 2px;
  border-radius: var(--radius-pill);
  background: rgba(224, 184, 119, 0.18);
  overflow: hidden;
}
.splash__bar::after {
  content: '';
  display: block;
  width: 40%;
  height: 100%;
  border-radius: inherit;
  background: var(--kt-bronze-300);
  animation: kt-sweep 1200ms ease-in-out infinite;
}
@keyframes kt-sweep {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(350%);
  }
}

/* ------------------------------------------------------------ progress -- */

/**
 * A collection's progress, drawn as a ring.
 *
 * The dash offset is set inline from the real number; the transition here is
 * what makes it sweep from empty on first paint rather than snapping. A ring
 * reads as "part of a whole" more immediately than a bar, which is exactly
 * what a sacred circuit is.
 */
.progress-ring__value {
  transition: stroke-dashoffset 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Popups arriving on the map, rather than blinking into being. */
.leaflet-popup {
  animation: kt-rise 180ms ease both;
}

/*
 * The one place a fade is safe: the splash *leaving*. It is driven by a
 * transition on an element that is removed by a timer regardless, so a browser
 * that never runs the transition still ends up with the splash gone.
 */

/* ------------------------------------------------------------- respect -- */

@media (prefers-reduced-motion: reduce) {
  /*
   * Everything lands in its final state at once. Note that the entrance
   * animations are switched to `none` rather than shortened: `both` fill mode
   * with a zero duration would leave elements at opacity 0 on some engines,
   * which is not "less motion", it is an invisible interface.
   */
  .stack > *,
  .card-grid > *,
  .rail > *,
  .hero-card,
  .quick-grid,
  .leaflet-popup {
    animation: none;
    transform: none;
  }
  .mark--drawing path,
  .mark--drawing circle {
    animation: none;
    stroke-dasharray: none;
    stroke-dashoffset: 0;
  }
  .splash__bar::after {
    animation: none;
    width: 100%;
  }
  .button:active,
  .chip--interactive:active,
  .icon-button:active,
  .quick-tile:active,
  .temple-card:active,
  .tile:active,
  .temple-card:hover,
  .tile:hover,
  .hero-card:hover img {
    transform: none;
  }
  .progress-ring__value {
    transition: none;
  }
}
