diff --git a/web/app.js b/web/app.js
index b8174e3..b9aaf0e 100644
--- a/web/app.js
+++ b/web/app.js
@@ -33,6 +33,7 @@ function drawProfile(f){
c.fillStyle='#587455';c.textAlign='left';c.fillText(`관저 ${fmt(z1,3)}`,13,142);c.textAlign='right';c.fillText(`${fmt(z2,3)} m`,227,142);
}
export function selectFacility(f){
+ if(f&&window.innerWidth<=1000)setPanel('inspector',true);
if(!f)return;app.selected=f;app.renderer.set({selected:f.pickId});$('#view-name').textContent=f.id;
let html=`${labels[f.type]}
${esc(f.id)}
`;
const reviewReasons=app.network.issues.filter(i=>['length_mismatch','adverse_slope','missing_coordinate','unplaced_link','coincident_endpoints'].includes(i.code)&&i.ids.includes(f.id));
@@ -87,6 +88,29 @@ function updateScales(){
const height=Number($('#height-scale').value),size=Number($('#size-scale').value);app.renderer.set({height,size,section:$('#section-mode').checked});
$('#height-output').value=`×${height}`;$('#size-output').value=`×${size}`;$('#height-badge').textContent=`높이 ×${height}`;$('#size-badge').textContent=`단면·맨홀 폭 ×${size}`;$('#section-badge').hidden=!$('#section-mode').checked;
}
+function setPanel(panel,open){
+ const narrow=window.innerWidth<=1000;
+ if(narrow&&open)document.body.classList.add(panel==='controls'?'hide-inspector':'hide-controls');
+ document.body.classList.toggle(`hide-${panel}`,!open);
+ for(const name of ['controls','inspector']){
+ const visible=!document.body.classList.contains(`hide-${name}`);
+ $(`#toggle-${name}`).setAttribute('aria-expanded',String(visible));
+ $(`#${name}-panel`).inert=!visible;
+ }
+ $('#panel-backdrop').hidden=!narrow||['controls','inspector'].every(n=>document.body.classList.contains(`hide-${n}`));
+}
+function initPanels(){
+ const narrow=matchMedia('(max-width: 1000px)');
+ const layout=()=>{setPanel('controls',!narrow.matches);setPanel('inspector',!narrow.matches);};
+ layout();narrow.addEventListener('change',layout);
+ for(const name of ['controls','inspector'])$(`#toggle-${name}`).onclick=()=>setPanel(name,document.body.classList.contains(`hide-${name}`));
+ $('#panel-backdrop').onclick=()=>{setPanel('controls',false);setPanel('inspector',false);};
+ document.addEventListener('keydown',e=>{if(e.key==='Escape'&&narrow.matches&&!$('dialog[open]')){
+ const wasControls=!document.body.classList.contains('hide-controls');
+ setPanel('controls',false);setPanel('inspector',false);
+ $(`#toggle-${wasControls?'controls':'inspector'}`).focus();
+ }});
+}
function syncAuditHighlight(){
const enabled=$('#audit-highlight').checked,reduced=matchMedia('(prefers-reduced-motion: reduce)').matches;
const steady=$('#audit-steady').checked||reduced;
@@ -114,6 +138,7 @@ function updateAudit(){
}
function fatal(message){$('#loading').hidden=true;$('#fatal-error').hidden=false;$('#fatal-error').textContent=message;$('#render-status').textContent='실행 확인 필요';}
async function main(){
+ initPanels();
try{
const response=await fetch('data/network.json',{cache:'no-store'});if(!response.ok)throw Error('관망 데이터를 읽을 수 없습니다. web/data/network.json 파일이 포함되어 있는지 확인해 주세요.');
app.network=await response.json();const n=app.network,s=n.summary;