/* Story motion for the product illustrations.
 *
 * Each illustration is an SVG carrying `data-story="ms,ms,…"`. motion.js walks
 * it through numbered steps, adding `st1`, `st2`, … to the SVG cumulatively,
 * holds the last step, clears them all (everything eases back out) and loops.
 * An element joins the story at a step with `data-at="N"` plus ONE reveal
 * class saying how it arrives. Optional per-element knobs:
 *   --dl  delay within its step          --du  duration of its reveal
 *   --n   character count for m-cover (drives the steps() "typing" cadence)
 *
 * The FINISHED composition is the static design. Everything below is scoped to
 * `html.motion`, which motion.js sets only when the visitor has not asked for
 * reduced motion — so with reduced motion, or with no JS at all, the page
 * renders exactly the illustration it had before any of this existed.
 *
 * Only transform, opacity and stroke-dashoffset move: all three composite on
 * the GPU, so a looping hero costs no layout or paint work per frame.
 */

[data-story] * { transform-box: fill-box; }

/* ---- pre-step (hidden) states ------------------------------------------ */

html.motion [data-story] [data-at] {
  transition-property: opacity, transform, stroke-dashoffset;
  transition-duration: .45s;              /* the reset: quick, all together */
  transition-delay: 0s;
  transition-timing-function: cubic-bezier(.2, .7, .2, 1);
}
html.motion [data-story] .m-fade  { opacity: 0; }
html.motion [data-story] .m-rise  { opacity: 0; transform: translateY(18px); }
html.motion [data-story] .m-drop  { opacity: 0; transform: translateY(-10px); }
html.motion [data-story] .m-slide { opacity: 0; transform: translateX(22px); }
html.motion [data-story] .m-fly   { opacity: 0; transform: translateX(150px) scale(.9); }
html.motion [data-story] .m-type  { transform: scaleX(0); transform-origin: left center; }
html.motion [data-story] .m-pop   { opacity: 0; transform: scale(.2); transform-origin: center; }
html.motion [data-story] .m-draw  { stroke-dasharray: 1; stroke-dashoffset: 1; }
/* A cover sits on top of text in the background colour and shrinks away to
   the right, uncovering the text left to right — how the terminal "types". */
html.motion [data-story] .m-cover { transform-origin: right center; }

/* ---- step reached: arrive ---------------------------------------------- */

html.motion [data-story].st1 [data-at="1"],
html.motion [data-story].st2 [data-at="2"],
html.motion [data-story].st3 [data-at="3"],
html.motion [data-story].st4 [data-at="4"],
html.motion [data-story].st5 [data-at="5"],
html.motion [data-story].st6 [data-at="6"],
html.motion [data-story].st7 [data-at="7"],
html.motion [data-story].st8 [data-at="8"] {
  transform: none;
  stroke-dashoffset: 0;
  transition-duration: var(--du, .7s);
  transition-delay: var(--dl, 0s);
}
/* Opacity is restored ONLY for the classes that start hidden. m-type, m-draw
   and m-cover never touch it, so an element drawn at opacity=".7" finishes at
   .7. Setting `opacity: 1` on every arriving element — the first version of
   this file — overrode those SVG attributes (CSS beats presentation
   attributes) and left the finished frame brighter than the design. */
html.motion [data-story].st1 :is(.m-fade,.m-rise,.m-drop,.m-slide,.m-fly,.m-pop)[data-at="1"],
html.motion [data-story].st2 :is(.m-fade,.m-rise,.m-drop,.m-slide,.m-fly,.m-pop)[data-at="2"],
html.motion [data-story].st3 :is(.m-fade,.m-rise,.m-drop,.m-slide,.m-fly,.m-pop)[data-at="3"],
html.motion [data-story].st4 :is(.m-fade,.m-rise,.m-drop,.m-slide,.m-fly,.m-pop)[data-at="4"],
html.motion [data-story].st5 :is(.m-fade,.m-rise,.m-drop,.m-slide,.m-fly,.m-pop)[data-at="5"],
html.motion [data-story].st6 :is(.m-fade,.m-rise,.m-drop,.m-slide,.m-fly,.m-pop)[data-at="6"],
html.motion [data-story].st7 :is(.m-fade,.m-rise,.m-drop,.m-slide,.m-fly,.m-pop)[data-at="7"],
html.motion [data-story].st8 :is(.m-fade,.m-rise,.m-drop,.m-slide,.m-fly,.m-pop)[data-at="8"] {
  opacity: 1;
}
/* Checkmarks and badges land with a small overshoot, like a stamp. */
html.motion [data-story].st1 .m-pop[data-at="1"], html.motion [data-story].st2 .m-pop[data-at="2"],
html.motion [data-story].st3 .m-pop[data-at="3"], html.motion [data-story].st4 .m-pop[data-at="4"],
html.motion [data-story].st5 .m-pop[data-at="5"], html.motion [data-story].st6 .m-pop[data-at="6"],
html.motion [data-story].st7 .m-pop[data-at="7"], html.motion [data-story].st8 .m-pop[data-at="8"] {
  transition-timing-function: cubic-bezier(.34, 1.56, .64, 1);
}
html.motion [data-story].st1 .m-cover[data-at="1"], html.motion [data-story].st2 .m-cover[data-at="2"],
html.motion [data-story].st3 .m-cover[data-at="3"], html.motion [data-story].st4 .m-cover[data-at="4"],
html.motion [data-story].st5 .m-cover[data-at="5"], html.motion [data-story].st6 .m-cover[data-at="6"],
html.motion [data-story].st7 .m-cover[data-at="7"], html.motion [data-story].st8 .m-cover[data-at="8"] {
  transform: scaleX(0);
  transition-timing-function: steps(var(--n, 24), end);
}

/* A one-shot press ripple (Material's feedback for "you clicked this"). It is
   an animation rather than a transition because it must END invisible: it
   plays once when its step arrives, and the reset simply removes it. */
html.motion [data-story] .m-ripple { opacity: 0; transform-origin: center; }
html.motion [data-story].st1 .m-ripple[data-at="1"], html.motion [data-story].st2 .m-ripple[data-at="2"],
html.motion [data-story].st3 .m-ripple[data-at="3"], html.motion [data-story].st4 .m-ripple[data-at="4"],
html.motion [data-story].st5 .m-ripple[data-at="5"], html.motion [data-story].st6 .m-ripple[data-at="6"],
html.motion [data-story].st7 .m-ripple[data-at="7"], html.motion [data-story].st8 .m-ripple[data-at="8"] {
  opacity: 0;
  animation: m-ripple .9s cubic-bezier(.2, .7, .2, 1) var(--dl, 0s) 1 both;
}
@keyframes m-ripple { 0% { opacity: .45; transform: scale(0); } 100% { opacity: 0; transform: scale(1); } }

/* ---- ambient: always on while the illustration is on screen ------------- */

html.motion [data-story] .a-bob   { animation: m-bob 6s ease-in-out infinite; animation-delay: var(--ad, 0s); }
html.motion [data-story] .a-sway  { animation: m-sway 5.5s ease-in-out infinite; transform-origin: bottom center; animation-delay: var(--ad, 0s); }
html.motion [data-story] .a-blink { animation: m-blink 1.1s steps(1, end) infinite; }
html.motion [data-story] .a-pulse { animation: m-pulse 3.2s ease-in-out infinite; transform-origin: center; animation-delay: var(--ad, 0s); }
html.motion [data-story].paused .a-bob,
html.motion [data-story].paused .a-sway,
html.motion [data-story].paused .a-blink,
html.motion [data-story].paused .a-pulse { animation-play-state: paused; }

@keyframes m-bob   { 0%, 100% { transform: translateY(0); }  50% { transform: translateY(-7px); } }
@keyframes m-sway  { 0%, 100% { transform: rotate(-2.5deg); } 50% { transform: rotate(2.5deg); } }
@keyframes m-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
@keyframes m-pulse { 0%, 100% { opacity: .15; transform: scale(1); } 50% { opacity: .32; transform: scale(1.12); } }
