// ===== Flying-man cursor (appears only on interactive elements) ===== const { useEffect, useRef, useState } = React; function FlyingCursor({ enabled }) { const ref = useRef(null); const [pose, setPose] = useState('fly'); // fly | point | grab const pos = useRef({ x: -100, y: -100, tx: -100, ty: -100 }); const active = useRef(false); useEffect(() => { if (!enabled) { document.body.classList.remove('custom-cursor-on'); return; } document.body.classList.add('custom-cursor-on'); let raf; const onMove = (e) => { pos.current.tx = e.clientX; pos.current.ty = e.clientY; const t = e.target; if (t.closest && t.closest('a, button, [data-interactive], input, textarea, select, .sticker, .service-row, .chip, .client-cell, .tweak-swatch button, .tweak-toggle')) { if (!active.current) { active.current = true; ref.current?.classList.add('active'); } const isGrab = t.closest('.sticker'); setPose(isGrab ? 'grab' : 'point'); } else { if (active.current) { active.current = false; ref.current?.classList.remove('active'); } setPose('fly'); } }; const onDown = () => setPose('grab'); const onUp = () => setPose((p) => p === 'grab' ? 'point' : p); const onLeave = () => { active.current = false; ref.current?.classList.remove('active'); }; window.addEventListener('mousemove', onMove); window.addEventListener('mousedown', onDown); window.addEventListener('mouseup', onUp); window.addEventListener('mouseleave', onLeave); const tick = () => { const p = pos.current; p.x += (p.tx - p.x) * 0.22; p.y += (p.ty - p.y) * 0.22; if (ref.current) { ref.current.style.left = p.x + 'px'; ref.current.style.top = p.y + 'px'; } raf = requestAnimationFrame(tick); }; tick(); return () => { window.removeEventListener('mousemove', onMove); window.removeEventListener('mousedown', onDown); window.removeEventListener('mouseup', onUp); window.removeEventListener('mouseleave', onLeave); cancelAnimationFrame(raf); document.body.classList.remove('custom-cursor-on'); }; }, [enabled]); if (!enabled) return null; return ( ); } function FlyingMan({ pose }) { // Little dude with a cape, arm out, based on navy + coral palette // pose: fly (default), point, grab const tilt = pose === 'fly' ? -15 : pose === 'grab' ? 5 : -5; return ( {/* cape */} {/* body */} {/* head */} {/* goggles */} {/* smile */} {/* arm out — front */} {pose === 'grab' ? : } {/* legs trailing */} {/* speed lines */} ); } window.FlyingCursor = FlyingCursor; window.FlyingMan = FlyingMan;