/* ==========================================================================
   EITRI — motion layer

   Scroll-driven behaviour for the landing page: the persistent Get started
   rail, reveal-on-enter, the depth strip, and the kinetic headline.

   RULES THIS FILE OBEYS
   - Mobile is the base. Every rule here is the phone rule.
   - Only `transform` and `opacity` animate. Nothing here may cause layout.
   - Every effect has a `prefers-reduced-motion` off-switch at the bottom, and
     the off-switch shows the finished state — never a blank page.
   - No effect may sit between a reader and the words. Motion is depth, not
     decoration.
   ========================================================================== */

/* ------------------------------------------------------- 1. reveal-on-enter */
/* The page ships with content visible. JS adds `js-motion` to <html>, and only
   then does anything hide — so a JS failure costs an animation, not the page. */
.js-motion [data-reveal]{
  opacity:0;
  transform:translate3d(0,14px,0);
  transition:opacity .7s var(--enter),transform .7s var(--enter);
  transition-delay:var(--d,0ms);
  will-change:opacity,transform;
}
.js-motion [data-reveal].is-in{opacity:1;transform:none;will-change:auto}

/* Children stagger without needing a delay written on each one. */
.js-motion [data-reveal-group]>*{
  opacity:0;
  transform:translate3d(0,16px,0);
  transition:opacity .6s var(--enter),transform .6s var(--enter);
}
.js-motion [data-reveal-group].is-in>*{opacity:1;transform:none}
.js-motion [data-reveal-group].is-in>*:nth-child(1){transition-delay:0ms}
.js-motion [data-reveal-group].is-in>*:nth-child(2){transition-delay:70ms}
.js-motion [data-reveal-group].is-in>*:nth-child(3){transition-delay:140ms}
.js-motion [data-reveal-group].is-in>*:nth-child(4){transition-delay:210ms}
.js-motion [data-reveal-group].is-in>*:nth-child(5){transition-delay:280ms}
.js-motion [data-reveal-group].is-in>*:nth-child(6){transition-delay:350ms}

/* ------------------------------------------------------ 2. kinetic headline */
/* Each word rises out of its own clipping box. The words stay real text: the
   spans are wrapped by JS around the existing text, so with JS off the
   headline is an ordinary <h1> and loses nothing. */
.kin{display:block}
/* The clip box has to be taller than the line, or `overflow:hidden` shaves the
   descenders off y, p and g — h1 runs at line-height 1.02. The padding is
   pulled back out with a negative margin so the headline occupies exactly the
   height it did before the words were wrapped. */
.kin-w{
  display:inline-block;
  overflow:hidden;
  vertical-align:top;
  padding-block:.04em .18em;
  margin-bottom:-.18em;
}
.kin-i{
  display:inline-block;
  transform:translate3d(0,105%,0);
  transition:transform .82s var(--enter);
  transition-delay:var(--d,0ms);
}
.is-in .kin-i,.kin.is-in .kin-i{transform:none}

/* ----------------------------------------------------------- 3. depth strip */
/* Four frames on a shared Z axis, tilted. Pure CSS 3D — no canvas, no WebGL,
   no library. It costs one composited layer per frame and runs on a five-year
   old Android. `--p` is written by JS from scroll position, 0 to 1. */
.depth{
  position:relative;
  height:clamp(220px,58vw,420px);
  perspective:1100px;
  perspective-origin:50% 45%;
  margin-block:clamp(1.5rem,4vw,3rem);
}
.depth-stage{
  position:absolute;inset:0;
  transform-style:preserve-3d;
  transform:rotateX(calc(6deg - var(--p,0) * 10deg)) rotateZ(-1.5deg);
  transition:transform .1s linear;
}
.depth-card{
  position:absolute;
  left:50%;top:50%;
  width:min(74vw,420px);
  aspect-ratio:16/10;
  border:1px solid var(--line-2);
  border-radius:var(--r-card);
  background:var(--panel-2);
  overflow:hidden;
  transform-style:preserve-3d;
  /* --i is the index 0..3, set inline. Cards sit further back and lower as it
     grows; --p pulls the whole stack toward the reader on scroll. */
  transform:
    translate3d(-50%,-50%,0)
    translate3d(calc(var(--i) * 5%),calc(var(--i) * 5%),calc(var(--i) * -120px))
    translateZ(calc(var(--p,0) * 90px));
  box-shadow:0 24px 60px -24px rgba(0,0,0,.85);
  transition:transform .1s linear;
}
.depth-card img,.depth-card video{width:100%;height:100%;object-fit:cover;display:block}
.depth-card::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,transparent 40%,rgba(10,10,12,.72));
}
.depth-tag{
  position:absolute;left:10px;bottom:9px;z-index:2;
  font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--text);
  background:rgba(10,10,12,.6);
  border:1px solid var(--line-2);
  border-radius:var(--r-pill);
  padding:3px 9px;
  backdrop-filter:blur(6px);
}
.depth-card[data-lead] .depth-tag{color:var(--orange);border-color:var(--orange-dim)}

/* --------------------------------------------------------- 4. sticky action */
/* The brief: Get started follows the reader the entire way down. On the phone
   that is a bottom bar above the home indicator; on desktop it docks bottom
   right so it never covers body copy. Hidden until the hero's own button has
   scrolled away, so the two are never on screen together. */
.cta-dock{
  position:fixed;
  left:0;right:0;bottom:0;
  z-index:60;
  display:flex;align-items:center;gap:12px;
  padding:10px var(--gut);
  padding-bottom:calc(10px + env(safe-area-inset-bottom));
  background:rgba(10,10,12,.82);
  backdrop-filter:blur(14px) saturate(1.3);
  border-top:1px solid var(--line);
  transform:translate3d(0,110%,0);
  transition:transform .45s var(--enter),opacity .3s linear;
  opacity:0;
  pointer-events:none;
}
.cta-dock.is-on{transform:none;opacity:1;pointer-events:auto}
.cta-dock-txt{min-width:0;flex:1}
.cta-dock-txt b{display:block;font-size:13px;font-weight:800;letter-spacing:-.01em}
.cta-dock-txt span{
  display:block;
  font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.cta-dock .btn{flex:0 0 auto}

/* A hairline of read-progress along the top edge of the dock. Ambient, not a
   control — it says how much page is left. */
.cta-dock::before{
  content:"";
  position:absolute;left:0;top:-1px;height:2px;
  width:calc(var(--read,0) * 100%);
  background:linear-gradient(90deg,var(--orange-press),var(--orange));
  transition:width .1s linear;
}

@media (min-width:760px){
  .cta-dock{
    left:auto;right:24px;bottom:24px;
    border:1px solid var(--line-2);
    border-radius:var(--r-pill);
    padding:10px 10px 10px 20px;
    box-shadow:0 20px 50px -20px rgba(0,0,0,.9);
    max-width:min(420px,calc(100vw - 48px));
  }
  .cta-dock::before{
    top:auto;bottom:0;left:20px;right:20px;
    width:auto;
    transform:scaleX(var(--read,0));transform-origin:0 50%;
    border-radius:2px;
  }
}

/* --------------------------------------------------------- 5. section index */
/* A numbered rail down the left of a section, desktop only. Typographic depth
   — it makes the page read as authored rather than stacked. */
.rail{position:relative}
@media (min-width:1120px){
  .rail::before{
    content:attr(data-rail);
    position:absolute;
    left:-56px;top:6px;
    font-family:var(--mono);font-size:11px;letter-spacing:.18em;
    color:var(--text-3);
    writing-mode:vertical-rl;
  }
}

/* ------------------------------------------------------------- 6. tilt card */
/* Pointer-driven parallax, capped at a few degrees. Off on touch, where there
   is no hover and the transform would only fight the scroll. */
@media (hover:hover) and (pointer:fine){
  .tilt{
    transform:perspective(900px) rotateX(var(--ty,0deg)) rotateY(var(--tx,0deg)) translateZ(0);
    transition:transform .4s var(--enter);
  }
  .tilt.is-live{transition:transform .08s linear}
}

/* -------------------------------------------------------------- 7. marquee */
/* Duplicated content, translated by exactly one copy, so the loop has no seam. */
.mq{
  overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
}
.mq-in{display:flex;width:max-content;animation:mq 38s linear infinite}
.mq-in>*{flex:0 0 auto;padding-inline:clamp(14px,4vw,34px)}
.mq:hover .mq-in{animation-play-state:paused}
@keyframes mq{to{transform:translate3d(-50%,0,0)}}
.mq-item{
  display:flex;align-items:center;gap:10px;
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--text-3);
  white-space:nowrap;
}
.mq-item i{width:5px;height:5px;border-radius:50%;background:var(--orange);font-style:normal}

/* The presence dot that used to live here is now section 15b of
   system.css: the chat header needs it too, and a component two files need
   belongs to the design system, not to the motion layer. */

/* -------------------------------------------------------------- 9. answers */
/* The what/how split. Two columns of prose on desktop, stacked on the phone,
   with a hairline between them rather than a card each — cards would make two
   equal boxes out of a question and its answer. */
.duo{display:grid;gap:clamp(1.25rem,4vw,2.5rem)}
@media (min-width:820px){
  .duo{grid-template-columns:1fr 1fr}
  .duo>*+*{border-left:1px solid var(--line);padding-left:clamp(1.5rem,3vw,2.5rem)}
}

/* --------------------------------------------------------- 10. reduced motion */
@media (prefers-reduced-motion:reduce){
  .js-motion [data-reveal],
  .js-motion [data-reveal-group]>*{opacity:1;transform:none;transition:none}
  .kin-i{transform:none;transition:none}
  .depth{height:auto;perspective:none}
  .depth-stage{transform:none;transition:none;position:static;display:grid;gap:10px}
  .depth-card{position:relative;left:auto;top:auto;width:auto;transform:none;transition:none}
  .mq-in{animation:none}
  .cta-dock{transition:none}
  .tilt{transform:none !important}
}
