/**
 * Dust in the light. A nearer, faster layer than Drift's registration marks —
 * those are deliberately subliminal, this one is meant to actually read as
 * movement without ever asking to be looked at.
 *
 * Fixed like Drift, so the motes are dust hanging in front of the lens rather
 * than something belonging to any one section.
 */
.Motes__layer {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/**
 * Every value that varies between motes arrives as a custom property from the
 * component, so there is one keyframe here instead of two dozen classes.
 */
.Motes__mote {
  position: absolute;
  top: 100%;
  left: var(--x);
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  background: var(--fg);
  opacity: 0;
  /**
   * Linear, like Drift. An eased curve on a continuous drift visibly stalls and
   * surges once per cycle, and constant velocity is the whole point of ambient
   * motion.
   *
   * The delays are negative so the field is already mid-flight on first paint
   * rather than starting empty and filling up from the bottom edge.
   */
  animation: mote-rise var(--dur) linear var(--delay) infinite;
  will-change: transform, opacity;
}

@keyframes mote-rise {
  from {
    transform: translate3d(0, 0, 0);
    opacity: 0;
  }
  12% {
    opacity: var(--peak);
  }
  88% {
    opacity: var(--peak);
  }
  to {
    transform: translate3d(var(--sway), -118vh, 0);
    opacity: 0;
  }
}

/* Thinner on a phone: the budget there is 45fps, and a full field of composited
   layers is not worth spending it on. */
@media (max-width: 720px) {
  .Motes__mote:nth-child(2n) {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .Motes__layer {
    display: none;
  }
}
