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'),menu=q('.menu-panels'),toggle=q('#toggle');let desiredOpen=true,phase='held open',menuTimeline=null; function reflect(){toggle.textContent=desiredOpen?'닫기':'열기';toggle.setAttribute('aria-expanded',String(desiredOpen));menu.setAttribute('aria-hidden',String(!desiredOpen));reading('상태: '+phase+(phase==='exiting'&&desiredOpen?' · 열기 1회 대기':''));} function closeBase(){gsap.set(panels,{xPercent:-110,yPercent:0,rotation:0,autoAlpha:0});} function finishExit(){const reopen=desiredOpen;menuTimeline.pause(0,true);closeBase();phase='closed';reflect();if(reopen&&!isStatic()){phase='entering';menuTimeline.play(0);reflect();}} menuTimeline=gsap.timeline({paused:true,onComplete:finishExit,onReverseComplete:()=>{phase='closed';desiredOpen=false;reflect();}}) .fromTo(panels,{xPercent:-110,yPercent:0,rotation:0,autoAlpha:0},{xPercent:0,autoAlpha:1,duration:.6,stagger:.06,ease:'back.out(1.4)',easeReverse:'power3.in'}) .addLabel('open').addPause('open',()=>{phase='held open';reflect();if(!desiredOpen){phase='exiting';menuTimeline.play();reflect();}}) .to(panels,{yPercent:150,rotation:i=>[-12,9,14][i],autoAlpha:0,duration:.45,ease:'power2.in'},'open'); function requestToggle(){desiredOpen=!desiredOpen; if(isStatic()){menuTimeline.pause();gsap.set(panels,{xPercent:0,yPercent:0,rotation:0,autoAlpha:desiredOpen?1:0});phase=desiredOpen?'held open':'closed';reflect();return;} if(phase==='exiting'){reflect();return;} if(desiredOpen){phase='entering';menuTimeline.play();} else if(phase==='held open'){phase='exiting';menuTimeline.play();} else {phase='reversing entry';menuTimeline.reverse();}reflect();} function reset(){desiredOpen=false;phase='closed';menuTimeline.pause(0,true).reversed(false);closeBase();reflect();} listen(toggle,'click',requestToggle);listen(q('#slow'),'change',e=>{const speed=e.target.checked?0.25:1;menuTimeline.timeScale(menuTimeline.reversed()?-speed:speed);});listen(q('#reset'),'click',reset); applyMode=()=>{menuTimeline.pause('open',true).reversed(false);desiredOpen=true;phase='held open';gsap.set(panels,{xPercent:0,yPercent:0,rotation:0,autoAlpha:1});reflect();};studyCleanup.push(()=>menuTimeline.kill());applyMode();