/* Pixl motion - effect A, thread.

   A hairline spine down the left page margin, running from the top of
   the content to the footer rule. A small teal square rides it as a pure
   function of scroll position.

   Every rule is scoped under [data-motion="thread"], so in any other
   mode this file matches nothing. Below 1100px the left margin is too
   narrow to hold a spine without crowding the text, so the effect is
   hidden rather than squeezed.

   Geometry is written in by thread.js as inline pixel values, measured
   on mount and on resize: the track's top, left and height, and the
   overlay that redraws the line across the ink numbers band. The
   rider's transform is written every frame by thread.js from
   window.PixlMotion.onProgress (core.js's shared scroll progress
   source), as translateY(progress * travel) - not a CSS scroll-timeline.
   See core.js for why.

   Deleting this effect is this file, thread.js, and their two tags in
   index.html. Nothing of it lives in styles.css. */

[data-motion="thread"] .thread {
  position: absolute;
  top: 0;
  left: 0;
  width: 12px;
  height: 0;
  pointer-events: none;
}

[data-motion="thread"] .thread-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(50% - .5px);
  width: 1px;
  background: var(--hairline);
}

/* The numbers band is ink on ink, and the page hairline disappears
   against it. This redraws the spine in paper for exactly the band's
   height, so the line reads as continuous through it. */
[data-motion="thread"] .thread-band {
  position: absolute;
  top: 0;
  left: calc(50% - .5px);
  width: 1px;
  height: 0;
  background: rgba(247, 248, 246, .22);
}

/* thread.js writes this element's transform every frame; the container
   itself carries no size of its own, only the ::after square below. */
[data-motion="thread"] .thread-rider {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
}

[data-motion="thread"] .thread-rider::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 12px;
  height: 12px;
  background: var(--teal-bright);
}

@media (prefers-reduced-motion: no-preference) {
  /* One quiet fade for the whole spine when it mounts, so switching
     modes does not snap it into place. */
  [data-motion="thread"] .thread {
    animation: thread-in .8s cubic-bezier(.22, .61, .36, 1) both;
  }

  /* No transition on the rider itself: thread.js writes its transform on
     every animation frame from the shared scroll progress source, and a
     CSS transition racing against a per-frame write would only ever lag
     behind it. */

  @keyframes thread-in {
    from { opacity: 0; }
    to { opacity: 1; }
  }
}

/* The margin runs out here. Crowding the text would be worse than having
   no signature at all. */
@media (max-width: 1099.98px) {
  [data-motion="thread"] .thread {
    display: none;
  }
}

/* Core switches the whole motion layer off under reduced motion and
   thread.js refuses to mount under it, so this is the third lock on the
   same door. */
@media (prefers-reduced-motion: reduce) {
  [data-motion="thread"] .thread {
    display: none;
  }
}

@media print {
  [data-motion="thread"] .thread {
    display: none;
  }
}
