/* ============================================================
   MOTION LAYER — shared by all four format studies.

   Rules this obeys:
   · Only transform and opacity are animated. Never width, height,
     margin or padding — those thrash layout (the detector caught
     exactly that bug on the live page).
   · Expo-out easing. Long, decelerating, no overshoot — v3 has no
     patience for bounce.
   · Everything is reversible-safe: state is carried by one class,
     so a re-observed element cannot land half-animated.
   · prefers-reduced-motion switches the whole layer off and every
     element renders in its final state.
   ============================================================ */

:root{
  --ease-out:cubic-bezier(.16,1,.3,1);
  --ease-soft:cubic-bezier(.33,1,.68,1);
  --dur:820ms;
  --dur-fast:520ms;
}

/* ---- scroll progress hairline ---- */
.mo-progress{
  position:fixed;top:0;left:0;right:0;height:1px;z-index:60;
  background:var(--signal);
  transform:scaleX(0);transform-origin:0 50%;
  will-change:transform;
}

/* ---- base reveal: rise + fade ---- */
[data-rv]{
  opacity:0;
  transform:translate3d(0,22px,0);
  transition:opacity var(--dur) var(--ease-out),
             transform var(--dur) var(--ease-out);
  transition-delay:var(--rv-d,0ms);
}
[data-rv].mo-in{opacity:1;transform:translate3d(0,0,0)}

/* softer, longer travel for large display type */
[data-rv="lead"]{transform:translate3d(0,40px,0)}
/* lateral entry for marginal notes and captions */
[data-rv="side"]{transform:translate3d(26px,0,0)}
/* rows slide from the rule they hang on */
[data-rv="row"]{transform:translate3d(-14px,0,0);transition-duration:var(--dur-fast)}

/* The whole-element scaleX draw was removed: applied to a content block it
   does not draw a rule, it horizontally squashes the type inside it. */

/* ---- masked line reveal for the big statements ---- */
.mo-line{display:block;overflow:hidden}
.mo-line > span{
  display:block;
  transform:translate3d(0,102%,0);
  transition:transform 1s var(--ease-out);
  transition-delay:var(--rv-d,0ms);
}
.mo-line.mo-in > span{transform:translate3d(0,0,0)}

/* ---- counters hold their box while ticking ---- */
.mo-num{font-variant-numeric:tabular-nums}

/* ---- hover affordances gain a little life ---- */
.idx-row,.layer,tbody tr,.run{
  transition:background 260ms var(--ease-soft),
             transform 380ms var(--ease-out);
}
.idx-row:hover,.layer:hover,.run:hover{transform:translate3d(5px,0,0)}

.btn{transition:background 180ms var(--ease-soft),
                transform 340ms var(--ease-out),
                border-color 180ms var(--ease-soft)}
.btn:hover{transform:translate3d(0,-2px,0)}

/* ---- parallax targets get promoted, nothing else does ---- */
[data-par]{will-change:transform}

/* ---- belt-and-braces: hero/masthead content must never be hidden by a
   late script-injection race, even if something re-tags it ---- */
section.hero [data-rv], header.masthead [data-rv],
section.hero .mo-line > span, header.masthead .mo-line > span{
  opacity:1;transform:none;transition:none;
}

/* ---- V3: panels ease as they enter the snap position ---- */
body[data-variant="poster"] .panel > *{
  transition:opacity 900ms var(--ease-out), transform 900ms var(--ease-out);
}

/* ============================================================
   Reduced motion: no transitions, no transforms, final state.
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  [data-rv],.mo-line > span,
  body[data-variant="poster"] .panel > *{
    opacity:1 !important;
    transform:none !important;
    transition:none !important;
  }
  .mo-progress{display:none}
  .idx-row:hover,.layer:hover,.run:hover,.btn:hover{transform:none}
}
