'use client'; import { motion, useScroll, useSpring } from 'framer-motion'; import { usePrefersReducedMotion } from '@/lib/motion'; // One continuous gold line running the height of the page, drawing itself as // the reader scrolls. It is the spine of the layout: it stitches the sections // together so the landing reads as a route rather than a stack of blocks. // // Positioned `absolute`, never `fixed` — the thread belongs to the document // and scrolls with it. A fixed layer would read as an ornament stuck to the // window. // // Uses the page-level useScroll() with no target ref on purpose: no element // measuring, no "container has a static position" warnings, and one scroll // listener for the whole page. // // It lives in the empty margin band to the left of the centred // `max-w-content` (1152px) column, never over it — some sections are // `position: relative` for unrelated reasons and some are not, so an // absolutely-positioned overlay with no explicit stacking level paints // inconsistently: above the static sections, behind the relative ones. `z-30` // gives it its own stacking context that beats every section root regardless // of that accident, while staying under the sticky header's `z-50`. // // Hidden below `2xl` (1536px): that's the first breakpoint that guarantees a // safe margin outside the 1152px column — (1536 - 1152) / 2 = 192px per side, // comfortable room for the thread's own offset plus breathing space to the // viewport edge. Narrower viewports have no safe band, so the thread simply // doesn't render there rather than creeping over the text. const TRAZO = 'M50 0 C 20 140, 80 260, 50 400 C 20 540, 80 660, 50 800 C 20 940, 80 1060, 50 1200'; export function HiloConductor({ className = '' }: { className?: string }) { const reduced = usePrefersReducedMotion(); const { scrollYProgress } = useScroll(); const avance = useSpring(scrollYProgress, { stiffness: 90, damping: 30, restDelta: 0.001 }); // Percentage-based band geometry against the containing block, never // `100vw` — `100vw` includes the scrollbar and would overshoot the real // document width by ~15px on desktop. `inset-0` and the inner `mx-auto // max-w-content` box both resolve against `
`'s own width instead. const wrapper = `pointer-events-none absolute inset-0 z-30 hidden 2xl:block ${className}`; // Plain for reduced motion: motion.path applies dash scaffolding even // without initial/animate and would leave the thread invisible. const trazo = reduced ? ( ) : ( ); return (
{/* Mirrors Container's own centring (`mx-auto max-w-content`) so the band below is measured from the real column edge. */}
); }