/* Motion. Small, local, and transform or opacity only. The page has one
   orchestrated moment (the icon assembling in the hero, hero-mark.css); what
   else moves either answers a person (a press, a choice, a disclosure) or is
   the product working (a terminal typing, the tour pairing), and those
   scenes run only while they are on screen. Nothing fades in on scroll.
   prefers-reduced-motion stops all of it at its finished state. */

/* ------------------------------------------------------------- ambient --- */

/* A running session's dot breathes, slowly: the only ambient motion the apps
   allow themselves, and the only one here. */
@keyframes breathe {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.4;
  }
}

.d-breathe {
  animation: breathe 2.4s var(--ease-in-out) infinite;
}

/* A block caret steps on and off; it does not dim. */
@keyframes caret {
  0%,
  46% {
    opacity: 1;
  }
  47%,
  100% {
    opacity: 0;
  }
}

.caret {
  display: inline-block;
  width: 3px;
  height: 1.05em;
  margin: 0 -3px 0 0.08em;
  border-radius: 1px;
  background: #2e9bff;
  vertical-align: -0.14em;
  animation: caret 1.15s steps(1) infinite;
}

/* The desktop tab's progress sweep (mockups.css): the band is 35% of the
   track, so -100% is wholly before it and 285.7143% wholly past it. */
@keyframes tab-progress-sweep {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(285.7143%);
  }
}

/* The line the pairing scanner sweeps, once per pass: a scanner that keeps
   sweeping a code it has found is scanning nothing. tour.js rewinds it. */
@keyframes scan-sweep {
  0% {
    background-position: 0% -4px;
    opacity: 0;
  }
  14%,
  82% {
    opacity: 1;
  }
  100% {
    background-position: 0% 100%;
    opacity: 0;
  }
}

.scan-line {
  animation: scan-sweep 1.3s var(--ease-in-out) 1 forwards;
}

/* ------------------------------------------------- opening the app itself ---
   The tour's phone opens the way the app does: rows rise in behind the
   screen on the house curve, the header only fades. The entrances hang off
   an is-entering class tour.js adds on arrival and takes off again, because
   the screens are never display:none and a plain animation would run once.
   `translate`, never `transform`, so it composes with anything else. */
@keyframes app-row-rise {
  from {
    opacity: 0;
    translate: 0 10px;
  }
}

@keyframes app-list-rise {
  from {
    opacity: 0;
    translate: 0 8px;
  }
}

@keyframes app-row-fade {
  from {
    opacity: 0;
  }
}

.scan.is-entering .scan-head {
  animation: app-row-fade 600ms var(--ease-out-soft) 120ms backwards;
}

.scan.is-entering .scan-view {
  animation: app-row-rise 700ms var(--ease-out-soft) 160ms backwards;
}

.scan.is-entering .scan-foot {
  animation: app-row-rise 700ms var(--ease-out-soft) 200ms backwards;
}

/* ------------------------------------------------------------- reduced --- */

/* Every duration collapses to a frame and every loop runs once. site.js and
   the scene scripts read the same query and show each scene's finished state
   directly. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  .caret {
    animation: none;
    opacity: 1;
  }

  /* The tab's sweep holds still, the band resting at the track's start. */
  .tab-bar::before {
    animation: none;
  }

  /* The relay handover has no third state to hold, so the direct session is
     the one shown, and the relay is out of the picture, not left faint. */
  .lane.is-pro .is-relay-peer,
  .lane.is-pro .wire.is-relay {
    opacity: 0;
    visibility: hidden;
  }

  .lane.is-pro .peer-caption:not(.is-direct) {
    opacity: 0;
  }

  .lane.is-pro .wire-direct {
    opacity: 1;
    transform: none;
  }

  .lane.is-pro .peer-caption.is-direct {
    opacity: 1;
  }

  .scan-line {
    animation: none;
    opacity: 1;
    background-position: 0% 50%;
  }

  .scan.is-entering > * {
    animation: none;
    opacity: 1;
    translate: none;
  }
}
