/* global React, JOURNEY, ERAS, Reveal, Star, Glyph */ const { useRef:useRefJ, useEffect:useEffectJ, useState:useStateJ } = React; /* ---------- PRECISION MEDICINE, vertical journey ---------- */ function Journey(){ const spineRef=useRefJ(null), fillRef=useRefJ(null); useEffectJ(()=>{ const on=()=>{ const el=spineRef.current; if(!el) return; const r=el.getBoundingClientRect(); const vh=window.innerHeight; const total=r.height; const p=Math.max(0,Math.min(1,(vh*0.5 - r.top)/total)); if(fillRef.current) fillRef.current.style.transform=`scaleY(${p})`; }; window.addEventListener('scroll',on,{passive:true}); on(); return ()=>window.removeEventListener('scroll',on); },[]); return React.createElement('section',{className:'section marble veined grain',id:'journey'}, React.createElement('div',{className:'wrap'}, React.createElement('div',{className:'eyebrow-row'},React.createElement(Reveal,{as:'span',className:'kicker center'},'Precision Medicine')), React.createElement(Reveal,{as:'h2',className:'display h-lg center',delay:80,style:{marginTop:'18px'}}, 'One patient. ',React.createElement('span',{className:'gild italic'},'A complete loop.')), React.createElement(Reveal,{as:'p',className:'serif-lead center mx-auto',delay:140,style:{maxWidth:'640px',marginTop:'22px'}}, 'Every signal feeds one continuous loop of interpretation, design, and restoration.'), React.createElement('div',{className:'timeline',ref:spineRef}, React.createElement('div',{className:'timeline-spine'},React.createElement('div',{className:'timeline-fill',ref:fillRef})), JOURNEY.map((s,i)=>React.createElement(Reveal,{key:s.n,variant:i%2?'r-right':'r-left', className:`tl-row ${i%2?'right':'left'}`,delay:40}, React.createElement('div',{className:'tl-card card-marble'}, React.createElement('div',{className:'tl-icon'},React.createElement(Glyph,{name:s.icon,width:24,height:24})), React.createElement('div',{className:'tl-body'}, React.createElement('div',{className:'tl-t'},s.t), React.createElement('div',{className:'tl-d'},s.d) ) ), React.createElement('div',{className:'tl-node'},React.createElement('span',{className:'tl-node-n stat-num'},s.n)), React.createElement('div',{className:'tl-spacer'}) )) ) ) ); } /* ---------- FUTURE OF MEDICINE, auto left/right carousel ---------- */ function Future(){ const trackRef=useRefJ(null), viewRef=useRefJ(null); const stateRef=useRefJ({pos:0, dir:1, paused:false, drag:null}); useEffectJ(()=>{ let raf, running=true, maxDist=0, last=performance.now(); const SPEED=26; // px per second drift const measure=()=>{ const track=trackRef.current, view=viewRef.current; if(!track||!view) return; maxDist=Math.max(0, track.scrollWidth - view.clientWidth); if(stateRef.current.pos>maxDist) stateRef.current.pos=maxDist; }; const loop=(now)=>{ if(!running) return; const dt=Math.min(0.05,(now-last)/1000); last=now; const s=stateRef.current; if(!s.paused && s.drag===null && maxDist>0){ s.pos += s.dir*SPEED*dt; if(s.pos>=maxDist){ s.pos=maxDist; s.dir=-1; } // reached right, drift back else if(s.pos<=0){ s.pos=0; s.dir=1; } // reached left, drift forward } if(trackRef.current) trackRef.current.style.transform=`translate3d(${(-s.pos).toFixed(2)}px,0,0)`; raf=requestAnimationFrame(loop); }; measure(); raf=requestAnimationFrame(loop); window.addEventListener('resize',measure); const t=setTimeout(measure,500); // re-measure after fonts settle // expose nudge for arrow buttons viewRef.current && (viewRef.current.__nudge=(delta)=>{ const s=stateRef.current; s.pos=Math.max(0,Math.min(maxDist,s.pos+delta)); s.dir=delta>0?1:-1; }); return ()=>{running=false;cancelAnimationFrame(raf);clearTimeout(t);window.removeEventListener('resize',measure);}; },[]); const pause=(v)=>()=>{ stateRef.current.paused=v; }; // pointer drag to scrub const onDown=(e)=>{ const s=stateRef.current; s.drag={x:e.clientX,pos:s.pos}; }; const onMove=(e)=>{ const s=stateRef.current; if(s.drag===null) return; const view=viewRef.current; const track=trackRef.current; const maxDist=Math.max(0,(track?track.scrollWidth:0)-(view?view.clientWidth:0)); s.pos=Math.max(0,Math.min(maxDist, s.drag.pos-(e.clientX-s.drag.x))); }; const onUp=()=>{ stateRef.current.drag=null; }; const nudge=(d)=>()=>{ const v=viewRef.current; v&&v.__nudge&&v.__nudge(d); }; return React.createElement('section',{className:'future-carousel marble-deep veined grain',id:'future'}, React.createElement('div',{className:'wrap'}, React.createElement('div',{className:'eyebrow-row'},React.createElement(Reveal,{as:'span',className:'kicker center'},'The Future of Medicine')), React.createElement(Reveal,{as:'h2',className:'display h-lg center',delay:80,style:{marginTop:'18px'}}, 'A century of ',React.createElement('span',{className:'gild italic'},'medicine,'),' rewritten.'), React.createElement(Reveal,{as:'p',className:'serif-lead center mx-auto',delay:140,style:{maxWidth:'620px',marginTop:'22px'}}, 'The arc from reactive care to a fully engineered biology.') ), React.createElement(Reveal,{variant:'r-scale',className:'fc-stage',delay:160}, React.createElement('button',{className:'fc-arrow left','aria-label':'Previous',onClick:nudge(-360)},'\u2190'), React.createElement('button',{className:'fc-arrow right','aria-label':'Next',onClick:nudge(360)},'\u2192'), React.createElement('div',{className:'fc-view',ref:viewRef, onMouseEnter:pause(true),onMouseLeave:()=>{stateRef.current.paused=false;stateRef.current.drag=null;}, onPointerDown:onDown,onPointerMove:onMove,onPointerUp:onUp,onPointerCancel:onUp}, React.createElement('div',{className:'fc-track',ref:trackRef}, ERAS.map((e,i)=>React.createElement('div',{key:e.yr,className:'era-panel'}, React.createElement('div',{className:'era-card'}, React.createElement('div',{className:'era-card-top'}, React.createElement('div',{className:'era-icon'},React.createElement(Glyph,{name:e.icon,width:34,height:34})), React.createElement('div',{className:'era-index stat-num'},'0'+(i+1))), React.createElement('div',{className:'era-yr stat-num gild'},e.yr), React.createElement('h3',{className:'display era-t'},e.t), React.createElement('p',{className:'era-d'},e.d) ), i