/* Scroll-driven motion. Everything here reads --p (0 when a stage sticks, 1 when
   the next stage starts to cover it, or at the page end for the last scene; written
   by site.js) and the variables from site.css: --speed, --travel, --motion. Only
   transform and opacity move; every transform multiplies by --motion, which is 0
   under reduced motion, so the page then rests exactly on its static composition. */

:root {
  --koi-dx: 6vw;
  --koi-dy: 10vh;
  --hand-lift: 80vh;
}

@media (max-width: 767px) {
  :root {
    --koi-dx: 8vw;
    --koi-dy: 6vh;
  }
}

/* Parallax on the scene's whole timeline: a layer sits +amp low as its stage begins
   to enter, passes its rest position mid-dwell, and is amp high by the time the next
   stage has covered it. Scenery therefore keeps descending through both handoffs. */
.layer,
.reveal,
.band {
  transform: translate3d(0, calc((.5 - var(--pe)) * 2 * var(--amp) * var(--motion)), 0);
}

/* Once a stage has pinned, its painted edge slides up and out over the first 12%
   of the scene, leaving the full painting. */
.scene + .scene .stage {
  --k: clamp(0, calc(var(--p) / .12), 1);
}

/* Mountains to riverbank: the mist thickens as the valley ends, and the riverbank
   comes in through it with the pines and rock still passing in front. */
.mist {
  opacity: calc(var(--motion) * clamp(0, calc((var(--p) - .6) / .4), 1));
}

/* Riverbank to water: the bank cools toward teal over the last quarter of the
   scene, after the demos, as the surface rises over it. */
.tint {
  opacity: calc(var(--motion) * clamp(0, calc((var(--p) - .75) / .25), 1) * .5);
}

/* The koi swims down and right toward where the phone will settle, and fades as
   the hand comes up. */
.koi {
  --koi-fade: clamp(0, calc((var(--p) - .55) / .3), 1);
  transform: translate3d(calc(var(--motion) * var(--p) * var(--koi-dx)), calc(var(--motion) * var(--p) * var(--koi-dy)), 0);
  opacity: calc(1 - var(--motion) * var(--koi-fade));
}

@keyframes koi-bob {
  0%,
  100% {
    translate: 0 0;
    rotate: 0deg;
  }
  50% {
    translate: 0 -14px;
    rotate: 4deg;
  }
}

.koi img {
  animation: koi-bob 6s ease-in-out infinite;
  animation-play-state: paused;
}

.stage.swim .koi img {
  animation-play-state: running;
}

/* The hand rises into the pinned stage between 45% and 85% of the water scene and
   is still by the time the form finishes arriving at the page end. */
.hand-stage {
  --hand-progress: clamp(0, calc((var(--p) - .45) / .4), 1);
  translate: 0 calc(var(--hand-lift) * (1 - var(--hand-progress)) * var(--motion));
}

/* Opening: the mountains come up out of a paper wash and settle, the pines rise
   into place, then the words and the phone follow. It plays once on load and
   never covers the form: the form is interactive from the first frame. */
@keyframes wash-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes settle {
  from { scale: 1.06; }
}

@keyframes rise-far {
  from { translate: 0 8%; }
}

@keyframes rise {
  from {
    opacity: 0;
    translate: 0 18px;
  }
}

@keyframes rise-phone {
  from {
    opacity: 0;
    translate: 0 60px;
  }
}

#mountains .stage::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--paper);
  pointer-events: none;
  animation: wash-out 1.4s cubic-bezier(.2, .7, .2, 1) both;
}

#mountains .layer.bg {
  animation: settle 2.4s cubic-bezier(.2, .7, .2, 1) both;
}

#mountains .layer.fg {
  animation: rise-far 2s cubic-bezier(.2, .7, .2, 1) .1s both;
}

.hero h1 span,
.hero .sub,
.hero form.join,
.hero .cue {
  animation: rise .8s cubic-bezier(.2, .7, .2, 1) both;
}

.hero h1 span:nth-child(1) { animation-delay: .42s; }
.hero h1 span:nth-child(2) { animation-delay: .54s; }
.hero h1 span:nth-child(3) { animation-delay: .66s; }
.hero .sub { animation-delay: .8s; }
.hero form.join { animation-delay: .9s; }
.hero .cue { animation-delay: 1.05s; }

.hero-phone {
  animation: rise-phone 1.2s cubic-bezier(.2, .7, .2, 1) .6s both;
}

/* Demo phones. site.js adds s1, s2… on each phone as its timeline runs; every
   rule below is the state from that step on, so later rules win. */
.phone * {
  transition: opacity .45s, translate .45s, scale .45s, transform .6s cubic-bezier(.2, .7, .2, 1), background-color .3s, color .3s, text-decoration-color .3s, outline-color .3s;
}

.phone.reset * {
  transition: none !important;
}

/* Assistant: captions arrive word by word (site.js wraps each word in .w with
   its index), the orb pulses while it listens, then three notes drop out. */
.assistant .say,
.assistant .w,
.assistant .state,
.assistant .note {
  opacity: 0;
}

.assistant .w {
  transition-delay: calc(var(--i) * 70ms);
}

.assistant .note {
  translate: 0 calc(14 * var(--u));
}

.assistant .orb {
  opacity: .35;
}

.play.assistant .orb span {
  animation: orb-pulse 1.4s ease-in-out infinite;
}

@keyframes orb-pulse {
  50% { scale: 1.35; }
}

.s1 .orb { opacity: 1; }
.s1 .listen { opacity: 1; }
.s2 .u1, .s2 .u1 .w { opacity: 1; }
.s3 .orb { opacity: .5; }
.s3 .listen { opacity: 0; }
.s3 .think { opacity: 1; }
.s4 .a1, .s4 .a1 .w { opacity: 1; }
.s4 .u1 { opacity: .6; }
.s5 .orb { opacity: 1; }
.s5 .think { opacity: 0; }
.s5 .listen { opacity: 1; }
.s6 .u2, .s6 .u2 .w { opacity: 1; }
.s7 .orb { opacity: .5; }
.s7 .listen { opacity: 0; }
.s7 .think { opacity: 1; }
.s8 .a2, .s8 .a2 .w { opacity: 1; }
.s9 .u1, .s9 .a1, .s9 .u2 { opacity: .3; }
.s9 .orb { opacity: .35; }
.s9 .think { opacity: 0; }
.s9 .done { opacity: 1; }
.s9 .note { opacity: 1; translate: 0 0; }
.s9 .note:nth-child(2) { transition-delay: .25s; }
.s9 .note:nth-child(3) { transition-delay: .5s; }

/* Flow map: the focus, then the next step beside it, then the ochre thread draws
   down through what it affects to the milestone. Then a tap on "Getting in the
   way": the map scrolls under the pinned focus, the rest dims, the sheet rises. */
.flow .back, .flow .title, .flow .subtitle,
.flow .card, .flow .ln, .flow .task, .flow .pin, .flow .tag {
  opacity: 0;
}

.flow .card {
  scale: .96;
}

.flow .ochre-ln {
  transform: scaleY(0);
  transform-origin: top;
}

.flow .l2 {
  transition-duration: .45s, .45s, .45s, .9s;
}

.flow .world {
  transition: transform .7s cubic-bezier(.3, .7, .2, 1);
}

.flow .sheet {
  transform: translateY(105%);
}

.s1 .back, .s1 .title, .s1 .subtitle { opacity: 1; }
.s2 .c1 { opacity: 1; scale: 1; }
.s3 .c2, .s3 .teal-ln { opacity: 1; scale: 1; }
.s4 .l1 { opacity: 1; transform: none; }
.s4 .c3 { opacity: 1; scale: 1; transition-delay: .2s; }
.s4 .task { opacity: 1; }
.s4 .task:nth-of-type(1) { transition-delay: .45s; }
.s4 .task:nth-of-type(2) { transition-delay: .6s; }
.s4 .task:nth-of-type(3) { transition-delay: .75s; }
.s5 .c4, .s5 .l3 { opacity: 1; scale: 1; }
.s5 .c4.pick { transition-delay: .15s; }
.s6 .l2 { opacity: 1; transform: none; }
.s6 .c5 { opacity: 1; scale: 1; transition-delay: .6s; }
.s7 .world { transform: translateY(calc(-181 * var(--u))); }
.s7 .back, .s7 .title, .s7 .subtitle, .s7 .c1, .s7 .c2, .s7 .teal-ln, .s7 .l1 { opacity: 0; transition-delay: 0s; }
.s7 .c3, .s7 .c4, .s7 .c5, .s7 .l2, .s7 .l3 { opacity: .3; transition-delay: 0s; }
.s7 .c4.pick { opacity: 1; outline: 1.5px solid rgba(244, 244, 242, 0.9); outline-offset: 3px; }
.s7 .pin, .s7 .tag { opacity: 1; }
.s8 .sheet { transform: none; }

/* Today: the top task is marked as the next step, gets checked and clears, the
   count drops, and the mark moves to the task after it. */
.day .date, .day .count, .day .focusrow, .day .list, .day .row b, .day .n2 {
  opacity: 0;
}

.day .date, .day .count, .day .focusrow, .day .list {
  translate: 0 calc(12 * var(--u));
}

.day .row.r1 {
  text-decoration: line-through;
  text-decoration-color: transparent;
  overflow: hidden;
  transition: opacity .3s, height .45s cubic-bezier(.3, .7, .2, 1), background-color .3s, color .3s, text-decoration-color .3s;
}

.s1 .date, .s1 .count, .s1 .focusrow, .s1 .list { opacity: 1; translate: 0 0; }
.s1 .count { transition-delay: .08s; }
.s1 .focusrow { transition-delay: .16s; }
.s1 .list { transition-delay: .24s; }
.s2 .r1 { background-color: rgba(114, 184, 172, 0.08); }
.s2 .r1 b { opacity: 1; }
.s3 .r1 { color: var(--mute); text-decoration-color: var(--mute); }
.s3 .r1 i { background: var(--fg); }
.s3 .r1 b { opacity: 0; }
.s4 .r1 { opacity: 0; height: 0; border-top-width: 0; }
.s4 .n3 { opacity: 0; }
.s4 .n2 { opacity: 1; }
.s5 .r2 { background-color: rgba(114, 184, 172, 0.08); }
.s5 .r2 b { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  :root {
    --motion: 0;
  }

  .tint {
    opacity: .3;
  }

  .koi img,
  #mountains .stage::after,
  #mountains .layer,
  .hero *,
  .hero-phone,
  .phone * {
    animation: none !important;
  }

  #mountains .stage::after {
    display: none;
  }

  .phone *,
  .phone::after {
    transition: none !important;
  }
}
