(() => {
  "use strict";
  const programs = window.WORKSPACE_ENTRIES || [];
  const byId = new Map(programs.flatMap(p => p.member_ids.map(id => [id, p])));
  const subjects = [{key:"all",name:"全部"},...(window.WORKSPACE_CATEGORIES || [])];
  const state = {projects: [], preferences: {favorites: [], recent: []}, project: null, query: "", subject: "all", selected: "4-02", opened: [], frames: new Map(), resources: new Map(), expanded: new Set(), targets: new Map(), ready: false};
  const canonical = id => byId.get(id)?.program_id || id;
  const canonicalList = ids => [...new Set((ids || []).map(canonical))];
  function entryTarget(id) {
    const entry=byId.get(id);
    return state.targets.get(entry?.program_id) || state.preferences.recent.find(mid=>canonical(mid)===entry?.program_id) || entry?.member_ids.find(mid=>state.project?.drafts?.[mid]) || entry?.program_id || id;
  }
  const $ = s => document.querySelector(s);
  const esc = x => String(x ?? "").replace(/[&<>"']/g, c => ({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]));
  const icon = name => '<i data-lucide="' + name + '"></i>';
  const icons = () => window.lucide?.createIcons();
  const date = value => value ? new Date(value).toLocaleString("zh-CN", {hour12:false}) : "";
  const api = () => window.pywebview?.api;
  async function call(method, ...args) {
    if (!api()?.[method]) throw new Error("请从桌面软件打开，以连接本地工程文件。");
    const response = await api()[method](...args);
    if (response?.ok === false) throw new Error(response.message || "操作未完成");
    return response;
  }
  function toast(message) {
    const el = $("#toast"); el.textContent = message; el.classList.add("show");
    clearTimeout(toast.timer); toast.timer = setTimeout(() => el.classList.remove("show"), 4000);
  }
  function safe(task) { return Promise.resolve().then(task).catch(e => toast(e.message || String(e))); }
  function heading(title, subtitle, actions = "") {
    return '<div class="view-heading"><div><h1>' + esc(title) + '</h1><p>' + esc(subtitle) + '</p></div><div class="heading-actions">' + actions + '</div></div>';
  }
  function empty(title, text, action = "") {
    return '<div class="empty-state">' + icon("folder-search") + '<h2>' + esc(title) + '</h2><p>' + esc(text) + '</p>' + action + '</div>';
  }
  function button(label, glyph, attr, primary = false) {
    return '<button ' + attr + (primary ? ' class="primary"' : '') + ' title="' + esc(label) + '">' + icon(glyph) + '<span class="button-label">' + esc(label) + '</span></button>';
  }
  async function prefs(change) {
    Object.assign(state.preferences, change);
    sidebar();
    if (state.ready) await call("workspace_preferences", change);
  }
  function sidebar() {
    $("#library-count").textContent = programs.length;
    $("#project-select").innerHTML=state.projects.length?state.projects.map(p=>'<option value="'+esc(p.id)+'">'+esc(p.name)+'</option>').join(''):'<option value="">本地工作区</option>';
    $("#project-select").value=state.project?.id || '';
    specialtyNavigation();
    const recent=(state.preferences.recent || []).filter((id,index,items)=>byId.has(id)&&items.findIndex(other=>canonical(other)===canonical(id))===index);
    $("#recent-programs").innerHTML = recent.slice(0, 6).map(id =>
      '<a href="#calc/' + id + '" title="' + esc(byId.get(id).name) + '"><span>' + esc(byId.get(id).name) + '</span></a>').join("") ||
      '<p class="muted" style="font-size:11px;padding:10px">暂无最近打开的计算</p>';
    document.body.classList.toggle("compact", state.preferences.density === "compact");
    icons();
  }
  function specialtyNavigation(){
    const expanded=innerWidth<760?document.body.classList.contains('sidebar-open'):!document.body.classList.contains('nav-collapsed');
    const toggle=$('#sidebar-toggle');
    toggle.setAttribute('aria-expanded',String(expanded));toggle.title=expanded?'收起导航':'展开导航';toggle.setAttribute('aria-label',toggle.title);
    const active=byId.get(location.hash.split('/')[1]);
    $('#specialty-navigation').innerHTML=subjects.slice(1).map(category=>{
      const entries=programs.filter(p=>p.category_key===category.key),open=state.expanded.has(category.key);
      const selected=active?.category_key===category.key || (location.hash.startsWith('#library/')&&state.subject===category.key);
      return '<div class="specialty-nav '+(selected?'selected':'')+'"><button data-category-toggle="'+category.key+'" aria-expanded="'+open+'" title="'+category.name+'">'+icon(category.icon)+'<span>'+category.name+'</span>'+icon(open?'chevron-up':'chevron-down')+'</button><div class="specialty-children" '+(open?'':'hidden')+'><a class="specialty-all" href="#library/'+category.key+'">'+category.name+'<small>'+entries.length+' 项</small></a>'+entries.map(p=>'<a class="'+(active?.program_id===p.program_id?'active':'')+'" href="#calc/'+entryTarget(p.program_id)+'" title="'+esc(p.name)+'">'+esc(p.name)+'</a>').join('')+'</div></div>';
    }).join('');
  }
  function filtered() {
    const words = state.query.trim().toLowerCase().split(/\s+/).filter(Boolean);
    let items = programs.filter(p => words.every(word => [p.name,p.category,p.source,...p.member_ids,...p.search_names,...p.inputs,...p.outputs].join(" ").toLowerCase().includes(word)));
    if (state.subject !== "all") items = items.filter(p => p.category_key === state.subject);
    if (location.hash === "#favorites") items = items.filter(p => (state.preferences.favorites || []).includes(p.program_id));
    return items;
  }
  function renderLibrary() {
    const favoriteView = location.hash === "#favorites";
    const category=subjects.find(s=>s.key===state.subject);
    const title=favoriteView?'常用计算':state.subject==='all'?'慧通智达水利计算工作台':category.name;
    $("#workspace-view").innerHTML = '<section class="view-page">' +
      heading(title, state.project ? state.project.name : "本地工作区", button("新建工程","plus",'data-create',true)) +
      '<div class="library-intro"><div class="library-stat"><strong>' + (subjects.length-1) + '</strong>专业分类</div><div class="library-stat"><strong>' + programs.length + '</strong>独立入口</div><div class="library-stat"><strong>' + (state.project?.records.length || 0) + '</strong>工程成果</div></div>' +
      '<div class="library-tools"><label class="library-search">' + icon("search") + '<input id="library-query" type="search" aria-label="搜索计算程序" placeholder="搜索名称、公式或参数" value="' + esc(state.query) + '"></label>' +
      '<div class="segmented" aria-label="显示密度"><button data-density="normal" title="标准密度">' + icon("list") + '</button><button data-density="compact" title="紧凑密度">' + icon("list-collapse") + '</button></div></div>' +
      '<div class="library-layout"><div class="library-main"><div class="table-caption"><span id="match-count"></span><span>参数 · 公式 · 成果</span></div><div id="catalog-rows"></div></div><aside class="catalog-aside" id="program-inspector" aria-label="程序详情"></aside></div></section>';
    $("#library-query").addEventListener("input", e => {state.query = e.target.value; renderRows();});
    renderRows();
  }
  function renderRows() {
    const items = filtered();
    $("#match-count").textContent = items.length + " 项计算";
    if (!items.some(p => p.program_id === state.selected)) state.selected = items[0]?.program_id || "";
    const overview=!state.query.trim()&&location.hash!=='#favorites';
    $('.library-layout').classList.toggle('is-list',!overview);
    $('#program-inspector').hidden=overview;
    $("#catalog-rows").innerHTML = items.length ? overview?overviewGroups(items):'<table class="catalog-table"><thead><tr><th class="star-col"><span class="muted">常用</span></th><th class="name-col">计算程序</th><th class="category-col">专业分类</th><th class="output-col">主要成果</th><th class="arrow-col"></th></tr></thead><tbody>' +
      items.map(p => '<tr class="catalog-item ' + (p.program_id === state.selected ? "selected" : "") + '" data-entry="'+p.program_id+'"><td>' + star(p.program_id) + '</td><td><button class="program-name" data-inspect="' + p.program_id + '">' + esc(p.name) + '</button><span class="program-sub">' + esc(p.inputs.slice(0,3).join(" · ")) + '</span></td><td class="category-col muted">' + esc(p.category) + '</td><td class="output-col cell-text" title="' + esc(p.outputs.join("、")) + '">' + esc(p.outputs.slice(0,3).join(" · ")) + '</td><td><a href="#calc/' + entryTarget(p.program_id) + '" title="打开计算" aria-label="打开' + esc(p.name) + '">' + icon("arrow-up-right") + '</a></td></tr>').join("") + '</tbody></table>' :
      empty("没有匹配的计算程序", location.hash === "#favorites" ? "在计算库中点击星标后，程序将显示在这里。" : "试试更短的名称或参数关键词。");
    inspector(); icons();
  }
  function overviewGroups(items){
    return '<div class="specialty-grid">'+subjects.slice(1).map(category=>{
      const entries=items.filter(p=>p.category_key===category.key);if(!entries.length)return '';
      const sections=[...new Set(entries.map(p=>p.section || ''))];
      return '<section class="specialty-section" data-specialty="'+category.key+'"><header><div>'+icon(category.icon)+'<h2>'+category.name+'</h2></div><span>'+category.description+'</span></header>'+sections.map(section=>(section?'<h3 class="specialty-subheading">'+section+'</h3>':'')+'<ul>'+entries.filter(p=>(p.section||'')===section).map(p=>'<li class="catalog-item program-entry" data-entry="'+p.program_id+'"><a href="#calc/'+entryTarget(p.program_id)+'"><strong>'+esc(p.name)+'</strong><span>'+esc(p.outputs.join(' · '))+'</span>'+icon('arrow-right')+'</a>'+star(p.program_id)+'</li>').join('')+'</ul>').join('')+'</section>';
    }).join('')+'</div>';
  }
  function star(id) {
    const selected = (state.preferences.favorites || []).includes(id);
    return '<button class="star-button ' + (selected ? "selected" : "") + '" data-star="' + id + '" aria-pressed="' + selected + '" title="' + (selected ? "取消收藏" : "收藏程序") + '">' + icon("star") + '</button>';
  }
  function inspector() {
    const p = byId.get(state.selected), el = $("#program-inspector");
    if (!p) {el.innerHTML = ""; return;}
    el.innerHTML = '<div class="aside-top"><span>程序详情</span><span>' + esc(p.category) + '</span></div><h2>' + esc(p.name) + '</h2><p>' + esc(p.source) + '</p><div class="aside-label">输入资料</div><div class="detail-tags">' + p.inputs.map(x => '<span>' + esc(x) + '</span>').join("") + '</div><div class="aside-label">计算成果</div><ul class="detail-list">' + p.outputs.map(x => '<li>' + icon("check") + esc(x) + '</li>').join("") + '</ul><button class="primary" data-open="' + p.program_id + '">' + icon("arrow-up-right") + '打开计算</button>';
  }
  function renderProjects() {
    $("#workspace-view").innerHTML = '<section class="view-page">' + heading("工程文件", state.projects.length + " 个本地工程",button("导入工程","upload",'data-import') + button("新建工程","plus",'data-create',true)) +
      '<div class="project-list">' + (state.projects.length ? state.projects.map(p =>
        '<article class="project-row ' + (p.id === state.project?.id ? "active" : "") + '">' + icon("folder") + '<div class="project-copy"><h3>' + esc(p.name) + (p.id === state.project?.id ? ' <small>当前</small>' : "") + '</h3><p>' + esc(p.description || "未填写工程说明") + '</p><div class="project-meta">' + p.records + ' 份成果 · ' + p.drafts + ' 个参数草稿 · ' + esc(date(p.updated_at)) + '</div></div><div class="project-controls"><button data-rename="' + p.id + '" class="icon-button" title="编辑工程">' + icon("pencil") + '</button><button data-export-project="' + p.id + '" class="icon-button" title="导出工程文件">' + icon("download") + '</button><button data-project="' + p.id + '">打开</button></div></article>').join("") :
        empty("还没有工程文件","新建工程后，参数草稿和每次计算成果将在本机保存。",button("新建工程","plus",'data-create',true))) + '</div><p class="source-foot">' + esc(state.path || "桌面软件连接后显示工程保存位置") + '</p></section>';
  }
  function renderRecords() {
    const records = [...(state.project?.records || [])].reverse();
    $("#workspace-view").innerHTML = '<section class="view-page">' + heading("成果记录",state.project?.name || "尚未打开工程") +
      (records.length ? '<table class="record-table"><thead><tr><th>计算程序</th><th class="record-time">计算时间</th><th class="record-id">参数摘要</th><th></th></tr></thead><tbody>' + records.map(r =>
        '<tr><td>' + esc(byId.get(r.program_id)?.name || r.program_id) + '</td><td class="record-time">' + esc(date(r.created_at)) + '</td><td class="record-id mono">' + esc(r.result?.parameter_hash || r.id) + '</td><td><button data-record="' + esc(r.id) + '">查看成果</button></td></tr>').join("") + '</tbody></table>' :
        empty("暂无计算成果","完成计算后，参数快照、结果和计算书将保存在当前工程。",'<a href="#library">进入计算库</a>')) + '</section>';
  }
  function renderResources() {
    const rows = [
      ["scan-line","CAD 断面资料","DXF 图层识别、地形线映射与断面参数导入。","cad","导入断面"],
      ["mountain","DEM 地形资料","GeoTIFF / ASC 元数据、工程点高程与测线纵断面。","dem","导入地形"],
      ["book-open","公式与规范索引","从程序的计算依据、输入资料和成果要求检索。","formula","查找公式"],
      ["folder-down","工程文件交换","导入或导出包含参数草稿与成果快照的工程文件。","project","导入工程"]
    ];
    $("#workspace-view").innerHTML = '<section class="view-page">' + heading("资料与导入","工程资料与计算依据") + '<div class="resource-list">' + rows.map(r => '<article class="resource-row">' + icon(r[0]) + '<div><h3>' + r[1] + '</h3><p>' + r[2] + '</p></div><button data-resource="' + r[3] + '">' + r[4] + icon("arrow-up-right") + '</button></article>').join("") + '</div></section>';
  }
  function renderTabs(active) {
    $("#document-tabs").hidden = !state.opened.length;
    $("#document-tabs").innerHTML = state.opened.map(id => '<div class="document-tab ' + (active === id ? "active" : "") + '"><a role="tab" aria-selected="' + (active === id) + '" href="#calc/' + entryTarget(id) + '">' + esc(byId.get(id)?.name || id) + '</a><button data-close-tab="' + id + '" title="关闭此计算" aria-label="关闭' + esc(byId.get(id)?.name || id) + '">' + icon("x") + '</button></div>').join("");
  }
  function showCalculation(id, recordId = "") {
    if (!byId.has(id)) {location.hash = "library"; return;}
    if (!state.initialized) return;
    const entryId=canonical(id);
    state.expanded.add(byId.get(id).category_key);
    if (!state.opened.includes(entryId)) state.opened.push(entryId);
    state.targets.set(entryId,id);
    const frameKey = id + (recordId ? "/" + recordId : "");
    let frame = state.frames.get(frameKey);
    if (!frame) {
      frame = document.createElement("iframe");
      frame.className = "calculation-frame";
      frame.title = byId.get(id).name;
      frame.dataset.projectId = state.project?.id || "";
      frame.src = "modules/calculation.html?program=" + encodeURIComponent(id) + (recordId ? "&record=" + encodeURIComponent(recordId) : "");
      state.frames.set(frameKey,frame);
      $("#frame-host").append(frame);
    }
    frame.hidden = false;
    $("#view-breadcrumb").textContent = byId.get(id).name;
    renderTabs(entryId);
    safe(() => prefs({recent:[id,...(state.preferences.recent || []).filter(x=>x!==id)].slice(0,12)}));
  }
  function route() {
    const hash = location.hash.slice(1) || "library";
    const [view,id,recordId] = hash.split("/");
    if(view==='library'){const subject=subjects.some(s=>s.key===id)?id:'all';if(state.subject!==subject)state.query='';state.subject=subject;}
    if(view==='favorites')state.subject='all';
    document.body.classList.remove("sidebar-open");
    const framed=['calc','cad','dem'].includes(view);
    $("#workspace-view").hidden = framed;
    $("#frame-host").hidden = !framed;
    state.frames.forEach(frame => {frame.hidden = true;});
    state.resources.forEach(frame=>{frame.hidden=true;});
    const names = {library:state.subject==='all'?"工作台":subjects.find(s=>s.key===state.subject).name,favorites:"常用计算",projects:"工程文件",records:"成果记录",resources:"资料与导入",cad:"CAD 断面资料",dem:"DEM 地形分析"};
    $("#view-breadcrumb").textContent = names[view] || "计算工作区";
    document.querySelectorAll(".primary-nav a").forEach(a => a.classList.toggle("active", a.dataset.view===view&&!(view==='library'&&state.subject!=='all')));
    renderTabs("");
    if (view === "calc") showCalculation(id,recordId);
    else if (view === "projects") {renderProjects();if(state.ready)safe(async()=>{await refresh();if(location.hash==="#projects")renderProjects();});}
    else if (view === "records") renderRecords();
    else if (view === "resources") renderResources();
    else if (["cad","dem"].includes(view)) {
      let frame=state.resources.get(view);
      if(!frame){frame=document.createElement('iframe');frame.className='calculation-frame resource-frame';frame.title=names[view];frame.src='modules/'+(view==='cad'?'section-cad.html':'dem-import.html')+'?workspace=1';state.resources.set(view,frame);$('#frame-host').append(frame);}
      frame.hidden=false;
    }
    else renderLibrary();
    specialtyNavigation();
    icons();
  }
  function downloadJSON(value, name) {
    const url = URL.createObjectURL(new Blob([JSON.stringify(value,null,2)],{type:"application/json"}));
    const a = document.createElement("a"); a.href=url; a.download=name; a.click(); setTimeout(()=>URL.revokeObjectURL(url),1000);
  }
  async function flushFrames() {
    for (const frame of state.frames.values()) await frame.contentWindow.CalculationWorkspace?.flush();
  }
  async function refresh() {
    const payload = await call("workspace_state");
    state.projects=payload.projects; state.preferences={favorites:[],recent:[],...payload.preferences}; state.path=payload.path;
    state.preferences.favorites=canonicalList(state.preferences.favorites);
    if (payload.unreadable?.length) toast(payload.unreadable.length + " 个工程文件读取失败，原文件已保留。");
    sidebar();
  }
  async function openProject(id) {
    await flushFrames();
    const payload = await call("workspace_open", id);
    state.project = payload.project;
    state.frames.forEach(frame=>frame.remove());state.frames.clear();state.opened=[];state.targets.clear();
    state.resources.forEach(frame=>frame.remove());state.resources.clear();
    await prefs({active_project:id});
    await refresh();
    location.hash="library";route();
  }
  function projectDialog(project = null) {
    const dialog=document.createElement("dialog");
    dialog.innerHTML='<form><h2>' + (project ? "编辑工程" : "新建工程") + '</h2><label>工程名称<input name="name" maxlength="120" required value="' + esc(project?.name || "") + '"></label><label>工程说明<textarea name="description" maxlength="2000">' + esc(project?.description || "") + '</textarea></label><p class="form-error"></p><footer><button type="button" data-cancel>取消</button><button class="primary" type="submit">' + (project ? "保存" : "创建工程") + '</button></footer></form>';
    dialog.querySelector("[data-cancel]").onclick=()=>dialog.close();
    dialog.addEventListener("close",()=>dialog.remove());
    dialog.querySelector("form").onsubmit=async e=>{
      e.preventDefault();const submit=dialog.querySelector('[type="submit"]');submit.disabled=true;
      const data=Object.fromEntries(new FormData(e.target));
      try {
        const response=project ? await call("workspace_update",project.id,data) : await call("workspace_create",data.name,data.description);
        if (!project) await openProject(response.project.id);
        else {if(state.project?.id === project.id)state.project=response.project;await refresh();route();}
        dialog.close();
      } catch(error){dialog.querySelector(".form-error").textContent=error.message;} finally{submit.disabled=false;}
    };
    document.body.append(dialog);dialog.showModal();dialog.querySelector("input").focus();
  }
  function importProject() {
    const input=document.createElement("input");input.type="file";input.accept=".json,.htzd";
    input.onchange=()=>safe(async()=>{
      if(!input.files?.length)return;
      if(input.files[0].size>50*1024*1024)throw new Error("工程文件超过 50 MB，请拆分成果后导入。");
      const payload=JSON.parse(await input.files[0].text());
      const response=await call("workspace_import",payload);await openProject(response.project.id);toast("工程已导入为独立副本");
    });input.click();
  }
  window.Workspace = {
    icons,toast,call,flush:flushFrames,
    entryForProgram:id=>byId.get(id),
    getProject:()=>state.project,
    getDraft:id=>state.project?.drafts?.[id] || null,
    getRecord:id=>state.project?.records.find(r=>r.id===id) || null,
    saveDraft:async(id,draft,projectId)=>{
      if(!projectId)return {ok:false,message:"尚未连接工程"};
      const response=await call("workspace_save_draft",projectId,id,draft);
      if(state.project?.id===projectId)state.project.drafts[id]=draft;
      return response;
    },
    saveRecord:async(id,params,result,projectId)=>{
      const response=await call("workspace_add_record",projectId,id,params,result);
      if(state.project?.id===projectId)state.project.records.push(response.record);
      return response;
    },
    navigate:target=>{location.hash=target;},
  };
  document.addEventListener("click",event=>safe(async()=>{
    const el=event.target.closest("button");if(!el)return;
    if(el.hasAttribute("data-create")) projectDialog();
    else if(el.hasAttribute("data-import")) importProject();
    else if(el.dataset.open) location.hash="calc/"+entryTarget(el.dataset.open);
    else if(el.dataset.inspect){state.selected=el.dataset.inspect;renderRows();}
    else if(el.dataset.star){const list=state.preferences.favorites || [];await prefs({favorites:list.includes(el.dataset.star)?list.filter(x=>x!==el.dataset.star):[...list,el.dataset.star]});renderRows();}
    else if(el.dataset.categoryToggle){const key=el.dataset.categoryToggle;document.body.classList.remove('nav-collapsed');if(state.expanded.has(key))state.expanded.delete(key);else state.expanded.add(key);specialtyNavigation();icons();}
    else if(el.dataset.density){await prefs({density:el.dataset.density});}
    else if(el.dataset.project)await openProject(el.dataset.project);
    else if(el.dataset.rename)projectDialog(state.projects.find(p=>p.id===el.dataset.rename));
    else if(el.dataset.exportProject){await flushFrames();const data=await call("workspace_export",el.dataset.exportProject);downloadJSON(data.project,data.project.name.replace(/[\\/:*?"<>|]/g,"_")+".htzd");}
    else if(el.dataset.record){const record=state.project.records.find(r=>r.id===el.dataset.record);if(record)location.hash="calc/"+record.program_id+"/"+record.id;}
    else if(el.dataset.resource){if(el.dataset.resource==="project")importProject();else location.hash=el.dataset.resource==="formula"?"library":el.dataset.resource;}
    else if(el.dataset.closeTab){
      const id=el.dataset.closeTab;
      for(const [key,frame] of state.frames){if(canonical(key.split("/")[0])===id){await frame.contentWindow.CalculationWorkspace?.flush();frame.remove();state.frames.delete(key);}}
      state.opened=state.opened.filter(x=>x!==id);
      state.targets.delete(id);
      if(canonical(location.hash.split("/")[1])===id)location.hash=state.opened.length?"calc/"+entryTarget(state.opened[state.opened.length-1]):"library";
      route();
    }
  }));
  document.addEventListener("DOMContentLoaded",()=>{
    const host=document.createElement("div");host.id="frame-host";$("#workspace-view").after(host);
    $("#project-switch").onclick=()=>{location.hash="projects";};
    $("#sidebar-toggle").onclick=()=>{
      const mobile=innerWidth<760;
      document.body.classList.toggle(mobile?'sidebar-open':'nav-collapsed');
      const expanded=mobile?document.body.classList.contains('sidebar-open'):!document.body.classList.contains('nav-collapsed');
      $('#sidebar-toggle').setAttribute('aria-expanded',String(expanded));
      $('#sidebar-toggle').title=expanded?'收起导航':'展开导航';
      $('#sidebar-toggle').setAttribute('aria-label',$('#sidebar-toggle').title);
    };
    $('#sidebar-close').onclick=()=>{document.body.classList.remove('sidebar-open');specialtyNavigation();icons();$('#sidebar-toggle').focus();};
    window.addEventListener('resize',()=>{if(innerWidth<760)document.body.classList.remove('nav-collapsed');});
    document.addEventListener('keydown',e=>{if(e.key==='Escape'){document.body.classList.remove('sidebar-open');specialtyNavigation();icons();}});
    $('#project-select').onchange=e=>safe(async()=>{if(e.target.value&&e.target.value!==state.project?.id){try{await openProject(e.target.value);}catch(error){e.target.value=state.project?.id||'';throw error;}}});
    $("#global-search").onclick=()=>{location.hash="library";route();$("#library-query")?.focus();};
    window.addEventListener("hashchange",route);
    document.addEventListener("keydown",e=>{if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==="k"){e.preventDefault();$("#global-search").click();}});
    sidebar();route();
    let attempts=0;
    const timer=setInterval(async()=>{
      if(api()?.workspace_state){clearInterval(timer);await safe(async()=>{
        state.ready=true;await refresh();
        let active=state.preferences.active_project;
        if(!state.projects.some(p=>p.id===active))active=state.projects[0]?.id;
        if(!active){const response=await call("workspace_create","我的计算工程","");active=response.project.id;await refresh();}
        const response=await call("workspace_open",active);state.project=response.project;
        await prefs({active_project:active});
        $("#storage-status").textContent="本地计算已连接";
        state.initialized=true;
        state.frames.forEach(f=>f.remove());state.frames.clear();route();
      });}
      else if(++attempts>30){clearInterval(timer);$("#storage-status").textContent="界面预览 · 未连接本地工程";}
    },150);
  });
})();
