gsap.registerPlugin(); const q=selector=>document.querySelector(selector),qa=selector=>Array.from(document.querySelectorAll(selector)); const studyAbort=new AbortController(),studyCleanup=[]; const listen=(target,type,handler)=>target.addEventListener(type,handler,{signal:studyAbort.signal}); const preference=matchMedia('(prefers-reduced-motion: reduce)'),staticControl=q('#static-mode'); staticControl.checked=preference.matches;staticControl.disabled=preference.matches; const isStatic=()=>staticControl.checked||preference.matches; let applyMode=()=>{}; listen(staticControl,'change',()=>applyMode()); listen(preference,'change',()=>{staticControl.checked=preference.matches;staticControl.disabled=preference.matches;applyMode();}); listen(window,'pagehide',()=>{studyCleanup.forEach(cleanup=>cleanup());studyAbort.abort();}); const reading=text=>q('#reading').textContent=text; const panels=qa('.menu-panel'),labels=qa('.menu-label'),bars=qa('.icon-bars span'),menu=q('.menu-panels'); const routeTimeline=gsap.timeline({paused:true});let desiredOpen=true,route='open',routeGeneration=0,stressTimer=null; function cancelStress(){if(stressTimer!==null){clearTimeout(stressTimer);stressTimer=null;}} function reflect(){q('#toggle-label').textContent=desiredOpen?'닫기':'열기';q('#toggle').setAttribute('aria-expanded',String(desiredOpen));menu.setAttribute('aria-hidden',String(!desiredOpen));reading('경로: '+route+' · 자식 애니메이션 '+routeTimeline.getChildren(true,true,true).length+'개');} function finish(token,open){if(token!==routeGeneration)return;route=open?'open':'closed';reflect();} function buildRoute(open){cancelStress();desiredOpen=open;const token=++routeGeneration;routeTimeline.pause().clear();routeTimeline.eventCallback('onComplete',()=>finish(token,open)); if(open){route='entering';routeTimeline.fromTo(panels,{xPercent:-110,yPercent:0,rotation:0,autoAlpha:0},{xPercent:0,autoAlpha:1,duration:.55,stagger:.06,ease:'power2.out'},0) .fromTo(labels,{opacity:0},{opacity:1,duration:.3,stagger:.05},.15) .fromTo(bars,{rotation:0,y:0},{rotation:i=>i?-45:45,y:i=>i?-3.5:3.5,duration:.3},0);} else {route='exiting';routeTimeline.to(panels,{yPercent:150,rotation:i=>[-10,12,-6][i],autoAlpha:0,duration:.4,ease:'power2.in'},0).to(labels,{opacity:0,duration:.2},0).to(bars,{rotation:0,y:0,duration:.3},0);} routeTimeline.play(0);if(isStatic()){routeTimeline.pause().progress(1,true);finish(token,open);}reflect();} function reset(){cancelStress();routeGeneration++;routeTimeline.pause().clear().eventCallback('onComplete',null);gsap.set(panels,{xPercent:-110,yPercent:0,rotation:0,autoAlpha:0});gsap.set(labels,{opacity:1});gsap.set(bars,{rotation:0,y:0});desiredOpen=false;route='closed';reflect();} listen(q('#toggle'),'click',()=>buildRoute(!desiredOpen));listen(q('#stress'),'click',()=>{buildRoute(true);if(isStatic()){buildRoute(false);return;}stressTimer=setTimeout(()=>{stressTimer=null;buildRoute(false);},150);});listen(q('#reset'),'click',reset); applyMode=()=>{buildRoute(true);routeTimeline.pause().progress(1,true);finish(routeGeneration,true);};studyCleanup.push(()=>{cancelStress();routeTimeline.kill();});applyMode();