/* ---------------------------------------------------------------------------
   THE MOTION LAYER for the landing page (2026-10-04). Method:
   E:\automation\misc\zysec-website-motion-study (docs 08/09; patterns noted [n]).

   Every rule here is scoped under html.js, which motion.js sets as its first
   act. No JS, a failed load, or ?nomotion: nothing below applies and the page
   is exactly its static self. One easing curve, three durations (200/320/600).
   Reduced motion gets the finished stills, not slower motion.
   --------------------------------------------------------------------------- */

/* [5] reveals: 12px, once, staggered from sibling index */
.js .rv{opacity:0;transform:translateY(12px);
  transition:opacity 600ms var(--ease),transform 600ms var(--ease);transition-delay:var(--d,0s)}
.js .rv.in{opacity:1;transform:none}

/* hero headline: words arrive on load (not on scroll; it is above the fold) */
.js h1 .w{display:inline-block;opacity:.01;transform:translateY(12px);
  transition:opacity 600ms var(--ease),transform 600ms var(--ease);transition-delay:var(--d,0s)}
.js.hero-in h1 .w{opacity:1;transform:none}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* [20 + 16] the hero motif: typed sentence, then the page's sections tilt
   apart as glass layers and scroll flattens them into one page (--p, --pi) */
.js .build .bubble--you.is-typing:after{content:"";display:inline-block;width:2px;height:1.05em;margin-left:2px;
  vertical-align:-3px;background:currentColor;animation:wh-caret 1s steps(1) infinite}
@keyframes wh-caret{50%{opacity:0}}
.js .build [data-after]{opacity:0;transform:translateY(12px);transition:opacity 600ms var(--ease),transform 600ms var(--ease)}
.js .build.is-built [data-after]{opacity:1;transform:none}
.js .build.is-built p.bubble--bot[data-after]{transition-delay:120ms}
/* the tilted layers may poke past the viewport edge: clip, without making a scroll container (sticky keeps working) */
.js .build{overflow-x:clip}
.js .build .stack__page{transform-origin:50% 40%;
  transform:rotateX(calc(50deg * (1 - var(--p,1)))) rotateZ(calc(-16deg * (1 - var(--p,1)))) scale(calc(.84 + .16 * var(--p,1)))}
.js .build .stack__card{opacity:0;
  transform:translateZ(calc(var(--i) * 90px * (1 - var(--pi,1)))) translateY(calc(var(--i) * 30px * (1 - var(--pi,1))));
  box-shadow:0 calc(30px * (1 - var(--pi,1))) calc(50px * (1 - var(--pi,1))) -20px rgba(10,10,10,calc(.32 * (1 - var(--pi,1))));
  transition:opacity 600ms var(--ease);transition-delay:calc(var(--i) * 90ms)}
.js .build.is-built .stack__card{opacity:1}
.js .build .stack__url{opacity:var(--p,1)}
@media (min-width:901px){
  /* [4] a sticky scene on desktop: the section's height is the running time */
  .js .build.is-sticky{height:190vh;padding:0}
  .js .build.is-sticky .build__stage{position:sticky;top:66px;height:calc(100svh - 66px);align-content:center}
  .js .build.is-sticky .stack{width:min(100%,460px,calc((100svh - 230px) * .5093))}
}

/* [15] the line through the three steps draws itself */
.js .steps__line .ink{stroke-dasharray:1;stroke-dashoffset:calc(1 - var(--p,0))}

/* [17] the phone: question, a typing pause, the answer */
.js [data-scene="phone"] [data-beat]{opacity:0;transform:translateY(12px);
  transition:opacity 320ms var(--ease),transform 320ms var(--ease)}
.js [data-scene="phone"] [data-beat].on{opacity:1;transform:none}
.js .phone .typing{display:flex;gap:4px;width:max-content;padding:12px 14px;margin:6px 0 0 auto;border-radius:18px;
  background:var(--assistant);opacity:0;transition:opacity 200ms var(--ease)}
.js .phone .typing.on{opacity:1}
.js .phone .typing i{width:6px;height:6px;border-radius:50%;background:var(--ink);opacity:.5;animation:wh-dot 1s var(--ease) infinite}
.js .phone .typing i:nth-child(2){animation-delay:.15s}.js .phone .typing i:nth-child(3){animation-delay:.3s}
@keyframes wh-dot{40%{transform:translateY(-3px);opacity:1}}

/* [30] the final panel opens out of a button-sized shape as it arrives.
   Shape and timing copied from VoicyAgent's closing band (2026-10-05, owner:
   "the box expand timing is better in that"): clipped on all four sides, so it
   starts as a button, and its content is never faded, only uncovered. */
.js .final{clip-path:inset(calc(var(--k,0) * 22%) calc(var(--k,0) * 34%) round calc(28px + var(--k,0) * 60px))}

@media (prefers-reduced-motion:reduce){
  .js .rv,.js h1 .w,.js .build [data-after],.js .build .stack__card,.js [data-scene="phone"] [data-beat]{
    opacity:1!important;transform:none!important;transition:none!important}
  .js .build .stack__page{transform:none!important}
  .js .build .stack__card{box-shadow:none!important}
  .js .final{clip-path:none!important}
  .js .phone .typing{display:none!important}
  .js .build .bubble--you.is-typing:after{display:none}
}
