viteboard 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +110 -61
  2. package/content/docs/guide/boards-in-markdown.md +28 -26
  3. package/content/docs/guide/boards.md +44 -82
  4. package/content/docs/guide/getting-started.md +36 -48
  5. package/content/docs/index.md +21 -32
  6. package/dist/assets/index-C30zRPsW.js +60 -0
  7. package/dist/assets/index-e5aqtN8W.css +1 -0
  8. package/dist/index.html +2 -2
  9. package/package.json +1 -1
  10. package/src/app/AppController.ts +7 -0
  11. package/src/elements/renderElement.ts +89 -0
  12. package/src/elements/types.ts +1 -0
  13. package/src/shell/Shell.ts +4 -6
  14. package/src/shell/Sidebar.ts +382 -83
  15. package/src/styles.css +75 -0
  16. package/src/templates/handoffTemplate.ts +34 -0
  17. package/src/templates/helpers.ts +10 -2
  18. package/src/templates/index.ts +14 -0
  19. package/src/templates/systemDiagramTemplate.ts +6 -6
  20. package/src/templates/workflowTemplate.ts +35 -0
  21. package/src/tools/ArrowTool.ts +11 -1
  22. package/src/tools/SelectTool.ts +1 -1
  23. package/src/tools/ShapeTool.ts +2 -2
  24. package/src/tools/ToolContext.ts +7 -0
  25. package/src/ui/TextEditorOverlay.ts +136 -11
  26. package/src/ui/Toolbar.ts +39 -1
  27. package/src/ui/icons.ts +6 -0
  28. package/vite.config.ts +16 -10
  29. package/content/docs/capabilities.md +0 -89
  30. package/content/docs/docs.md +0 -84
  31. package/content/docs/guide/test.md +0 -6
  32. package/content/docs/test.md +0 -219
  33. package/content/docs/tetst-dir/test-board.board.json +0 -15
  34. package/content/docs/tetst-dir/test-test.md +0 -1
  35. package/content/docs/workspace.md +0 -73
  36. package/dist/assets/index-CEpxLM2o.css +0 -1
  37. package/dist/assets/index-D4xvJdEQ.js +0 -60
@@ -0,0 +1,60 @@
1
+ var _n=Object.defineProperty;var Xn=(o,t,e)=>t in o?_n(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var m=(o,t,e)=>Xn(o,typeof t!="symbol"?t+"":t,e);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))n(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const a of i.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&n(a)}).observe(document,{childList:!0,subtree:!0});function e(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerPolicy&&(i.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?i.credentials="include":s.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function n(s){if(s.ep)return;s.ep=!0;const i=e(s);fetch(s.href,i)}})();const N="/__api";async function H(o){var t;if(!o.ok){let e="";try{e=((t=await o.json())==null?void 0:t.error)??""}catch{}throw new Error(`${o.status} ${o.statusText}${e?` — ${e}`:""}`)}return o.json()}const k={async getWorkspace(){return H(await fetch(`${N}/workspace`))},async removeProject(o){await H(await fetch(`${N}/workspace/project?id=${encodeURIComponent(o)}`,{method:"DELETE"}))},async pickAndAddProject(){return H(await fetch(`${N}/workspace/pick-project`,{method:"POST"}))},async ensureProjectDocsRoot(o){return(await H(await fetch(`${N}/workspace/project/docs-root`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:o})}))).root},async getTree(o){return(await H(await fetch(`${N}/tree?rootId=${encodeURIComponent(o)}`))).tree},async getProjectTree(o){return(await H(await fetch(`${N}/project-tree?projectId=${encodeURIComponent(o)}`))).tree},async createDocsFolder(o,t){await H(await fetch(`${N}/workspace/project/create-docs-folder`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:o,parentPath:t})}))},async readFile(o,t){return(await H(await fetch(`${N}/file?rootId=${encodeURIComponent(o)}&path=${encodeURIComponent(t)}`))).content},async writeFile(o,t,e){await H(await fetch(`${N}/file`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,path:t,content:e})}))},async createDirectory(o,t){await H(await fetch(`${N}/directory`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,path:t})}))},async getBoard(o,t){const e=await fetch(`${N}/board?rootId=${encodeURIComponent(o)}&id=${encodeURIComponent(t)}`);return e.status===404?null:(await H(e)).doc},async saveBoard(o,t,e){await H(await fetch(`${N}/board`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,id:t,doc:e})}))},async deleteFile(o,t){await H(await fetch(`${N}/file?rootId=${encodeURIComponent(o)}&path=${encodeURIComponent(t)}`,{method:"DELETE"}))},async renameFile(o,t,e,n=!1){await H(await fetch(`${N}/file`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,oldPath:t,newPath:e,ignoreMissing:n})}))},async deleteBoard(o,t){await H(await fetch(`${N}/board?rootId=${encodeURIComponent(o)}&id=${encodeURIComponent(t)}`,{method:"DELETE"}))},assetUrl(o,t){return`${N}/asset?rootId=${encodeURIComponent(o)}&path=${encodeURIComponent(t)}`},async uploadAsset(o,t,e){return(await H(await fetch(`${N}/asset`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,name:t,base64:e})}))).path}};function qn(o,t){const e=o.find(i=>i.type==="dir"&&i.name===t);if(!e||e.type!=="dir")return[];const n=[],s=i=>{for(const a of i)a.type==="file"?n.push(a):s(a.children)};return s(e.children),n}function ke(o){for(const t of o){if(t.type==="file"&&t.name.endsWith(".md"))return t.path;if(t.type==="dir"){const e=ke(t.children);if(e)return e}}return null}function ht(o){const t=[];for(const e of o.replace(/\\/g,"/").split("/")){const n=e.trim();if(!(!n||n===".")){if(n===".."){t.length>0&&t.pop();continue}t.push(n)}}return t.join("/")}function gn(o){const t=ht(o),e=t.lastIndexOf("/");return e===-1?"":t.slice(0,e)}function Yn(o,t){if(/^(https?:|mailto:|tel:|#|data:)/.test(t))return t;if(t.startsWith("/"))return ht(t);const e=gn(o);return ht(e?`${e}/${t}`:t)}function Te(o,t){const e=gn(o),n=e?e.split("/").filter(Boolean):[],s=ht(t).split("/").filter(Boolean);let i=0;for(;i<n.length&&i<s.length&&n[i]===s[i];)i++;const a=n.slice(i).map(()=>".."),r=s.slice(i);return[...a,...r].join("/")||s[s.length-1]||""}const Kn=["sticky","task","rectangle","ellipse","text","line","arrow","connector","image","screenshot","frame","templateGroup"];function Xt(o){const t=new Set;for(const e of o.elements){const n=e.data.assetId;typeof n=="string"&&t.add(n)}return{version:1,id:o.boardId,title:o.title,createdAt:o.createdAt,updatedAt:Date.now(),viewport:{...o.viewport},theme:o.theme,elements:o.elements,assetIds:[...t]}}function U(o){return typeof o=="number"&&Number.isFinite(o)}function yn(o){if(typeof o!="object"||o===null)return null;const t=o;return typeof t.id!="string"||typeof t.type!="string"||!Kn.includes(t.type)||!U(t.x)||!U(t.y)||!U(t.width)||!U(t.height)?null:{id:t.id,type:t.type,x:t.x,y:t.y,width:t.width,height:t.height,rotation:U(t.rotation)?t.rotation:0,zIndex:U(t.zIndex)?t.zIndex:0,locked:t.locked===!0,hidden:t.hidden===!0,createdAt:U(t.createdAt)?t.createdAt:Date.now(),updatedAt:U(t.updatedAt)?t.updatedAt:Date.now(),style:typeof t.style=="object"&&t.style!==null?t.style:{},data:typeof t.data=="object"&&t.data!==null?t.data:{}}}function ee(o){if(typeof o!="object"||o===null)return null;const t=o;if(t.version!==1||typeof t.id!="string"||!Array.isArray(t.elements))return null;const e=[];for(const s of t.elements){const i=yn(s);i&&e.push(i)}const n=t.viewport??{};return{version:1,id:t.id,title:typeof t.title=="string"?t.title.slice(0,200):"Imported Board",createdAt:U(t.createdAt)?t.createdAt:Date.now(),updatedAt:U(t.updatedAt)?t.updatedAt:Date.now(),viewport:{offsetX:U(n.offsetX)?n.offsetX:0,offsetY:U(n.offsetY)?n.offsetY:0,scale:U(n.scale)&&n.scale>.01&&n.scale<=40?n.scale:1},theme:t.theme==="dark"?"dark":"light",elements:e,assetIds:Array.isArray(t.assetIds)?t.assetIds.filter(s=>typeof s=="string"):[]}}const Vn=".board.json";function _(o){return o.replace(/\.board\.json$/,"")}function Gn(o){return o.trim().replace(/^\/+/,"").replace(/\.board\.json$/,"")}function Zn(o,t){return Ut(o,t)[0]??""}function Ut(o,t){const e=o.trim(),n=Gn(o);if(!n)return[];if(e.startsWith("./")||e.startsWith("../")){const r=t.lastIndexOf("/"),c=r===-1?"":t.slice(0,r);return[ht(c?`${c}/${n}`:n)]}if(e.startsWith("/")){const r=t.lastIndexOf("/"),c=r===-1?"":t.slice(0,r),l=ht(c?`${c}/${n}`:n),d=[n];if(l&&l!==n&&d.push(l),c){const h=c.includes("/")?c.slice(0,c.lastIndexOf("/")):"",p=ht(h?`${h}/${n}`:n);p&&!d.includes(p)&&d.push(p)}return d}const s=t.lastIndexOf("/"),i=s===-1?"":t.slice(0,s),a=ht(i?`${i}/${n}`:n);return a&&a!==n?[a,n]:[n]}function De(o){return o.toLowerCase().replace(/[^\w\s-]/g,"").trim().replace(/\s+/g,"-").slice(0,48)||"board"}function Jn(o){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(o)})}const X={async listIds(o){const t=await k.getTree(o);return Qn(t).map(e=>_(e.path))},async list(o){const t=await this.listIds(o),e=[];for(const n of t){const s=await this.load(o,n);s&&e.push({id:n,title:s.title,elementCount:s.elements.length,updatedAt:s.updatedAt,filePath:`${n}.board.json`})}return e.sort((n,s)=>s.updatedAt-n.updatedAt),e},async load(o,t){const e=await k.getBoard(o,t);if(e)return ee(e)??void 0},async save(o,t){await k.saveBoard(o,t.id,t)},async delete(o,t){await k.deleteBoard(o,t)},async move(o,t,e){const n=await this.load(o,t);if(!n)throw new Error("Board not found");const s=t.split("/").pop()??t,i=e.replace(/^\/+|\/+$/g,""),a=i?`${i}/${s}`:s;if(a===t)return t;if(new Set(await this.listIds(o)).has(a))throw new Error("A board already exists there");const c=Date.now();return await k.saveBoard(o,a,{...n,id:a,updatedAt:c}),await k.deleteBoard(o,t),a},async rename(o,t,e){const n=await this.load(o,t);if(!n)throw new Error("Board not found");const s=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",i=De(e),a=s?`${s}/${i}`:i,r=Date.now();if(a===t)return await k.saveBoard(o,t,{...n,title:e.trim()||n.title,updatedAt:r}),t;if(new Set(await this.listIds(o)).has(a))throw new Error("A board already exists with that name");return await k.saveBoard(o,a,{...n,id:a,title:e.trim()||n.title,updatedAt:r}),await k.deleteBoard(o,t),a},async create(o,t,e,n=""){const s=new Set(await this.listIds(o)),i=De(t);let r=`${n?`${n.replace(/^\/+|\/+$/g,"")}/`:""}${i}`;s.has(r)&&(r=`${r}-${Date.now().toString(36)}`);const c=Date.now(),l={version:1,id:r,title:t.trim()||"Untitled Board",createdAt:c,updatedAt:c,viewport:{offsetX:0,offsetY:0,scale:1},theme:e,elements:[],assetIds:[]};return await k.saveBoard(o,r,l),r},async uploadImage(o,t,e){const n=await Jn(t);return k.uploadAsset(o,e??"image.png",n)}};function Qn(o){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(Vn)&&t.push(s):e(s.children)};return e(o),t}const ts=new Set(["capabilities","assets"]);class es{constructor(t,e){m(this,"element");m(this,"header");m(this,"nav");m(this,"footer");m(this,"links",new Map);m(this,"collapsibles",new Map);m(this,"collapsedState",new Map);m(this,"callbacks");m(this,"contextMenu");m(this,"draggedItem");m(this,"dropExpandTimer");m(this,"dropExpandTarget");m(this,"lastWorkspace",{projects:[]});m(this,"lastTreesByRoot",new Map);m(this,"lastTreesByProject",new Map);m(this,"rawModeProjects",new Set);this.callbacks=e,this.element=document.createElement("aside"),this.element.className="sidebar",this.header=document.createElement("div"),this.header.className="sidebar-header";const n=document.createElement("a");n.className="sidebar-brand",n.href="#/",n.textContent="ViteBoard",this.header.appendChild(n),this.nav=document.createElement("nav"),this.nav.className="sidebar-nav",this.footer=document.createElement("div"),this.footer.className="sidebar-footer";const s=document.createElement("button");s.className="sidebar-add-repo",s.type="button",s.textContent="Add Repo",s.title="Add a local project root",s.addEventListener("click",()=>this.callbacks.onAddRepo()),this.footer.appendChild(s),this.element.append(this.header,this.nav,this.footer),t.appendChild(this.element),document.addEventListener("pointerdown",i=>{this.contextMenu&&(this.contextMenu.contains(i.target)||this.closeContextMenu())},!0)}refresh(t,e,n){this.lastWorkspace=t,this.lastTreesByRoot=e,n&&(this.lastTreesByProject=n),this.render()}render(){const t=this.lastWorkspace,e=this.lastTreesByRoot;if(this.lastTreesByProject,this.nav.replaceChildren(),this.links.clear(),this.collapsibles.clear(),t.projects.length===0){const s=document.createElement("div");s.className="nav-group",s.appendChild(this.groupLabel("Workspace"));const i=document.createElement("div");i.className="nav-label nav-empty-copy",i.textContent="Add a project root to discover docs folders.",s.appendChild(i),this.nav.appendChild(s)}else for(const s of t.projects)this.nav.appendChild(this.projectSection(s,e));const n=document.createElement("div");n.className="nav-group",n.appendChild(this.groupLabel("System")),n.appendChild(this.link("#/tokens","Tokens","tokens-root")),this.nav.appendChild(n),this.setActive(location.hash)}setActive(t){var n,s;for(const i of new Set(this.links.values()))i.classList.remove("active");const e=this.links.get(t);if(e)e.classList.add("active");else if(t.startsWith("#/root/")){const i=t.match(/^#\/root\/([^/]+)\/(boards|capabilities|docs)(?:\/(.+))?$/);if(i){const[,a,r]=i,c=decodeURIComponent(a);r==="boards"?(n=this.links.get(is(c)))==null||n.classList.add("active"):r==="capabilities"&&((s=this.links.get(as(c)))==null||s.classList.add("active"))}}this.syncCollapsed(t)}toggleRawMode(t){this.rawModeProjects.has(t)?this.rawModeProjects.delete(t):this.rawModeProjects.add(t),this.render()}syncCollapsed(t){const e=this.ancestorKeys(t);for(const n of e)this.applyCollapsed(n,!1)}ancestorKeys(t){const e=new Set,n=t.match(/^#\/project\/([^/]+)(?:\/boards)?$/);if(n)return e.add(decodeURIComponent(n[1])),e;const s=t.match(/^#\/root\/([^/]+)\/(docs|boards|capabilities)(?:\/(.+))?$/);if(!s)return e;const i=decodeURIComponent(s[1]),a=s[2],r=s[3]?decodeURIComponent(s[3]):"";let c,l;for(const p of this.lastWorkspace.projects){const u=p.docsRoots.find(g=>g.id===i);if(u){c=p.id,l=u.displayPath;break}}if(!c||!l)return e;e.add(c),e.add(i);const d=l.split("/").filter(Boolean).slice(0,-1);let h="";for(const p of d){h=h?`${h}/${p}`:p;const u=`folder:${c}:${h}`;this.collapsibles.has(u)&&e.add(u)}if((a==="docs"||a==="capabilities")&&r){const p=r.split("/");for(let u=1;u<p.length;u++){const g=p.slice(0,u).join("/"),y=`doc:${i}:${g}`;this.collapsibles.has(y)&&e.add(y)}}return e}projectSection(t,e){const{id:n,label:s,docsRoots:i}=t,a=this.rawModeProjects.has(n),r=document.createElement("div");r.className="nav-repo-body";const c=document.createElement("div");c.className="nav-group nav-repo-group";const l=document.createElement("button");l.className="nav-repo-header",l.type="button";const d=document.createElement("span");d.className="nav-repo-chevron",d.textContent="›";const h=document.createElement("span");h.className="nav-repo-label-text",h.textContent=s;const p=!a&&i.find(b=>pt(b.displayPath)==="docs"),u=document.createElement("span");u.className="nav-tree-badge",u.textContent="DOCS",u.hidden=!p;const g=document.createElement("button");g.className="nav-repo-more",g.type="button",g.title="Project options",g.innerHTML='<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><circle cx="8" cy="3" r="1.3"/><circle cx="8" cy="8" r="1.3"/><circle cx="8" cy="13" r="1.3"/></svg>',g.addEventListener("click",b=>{b.stopPropagation();const x=g.getBoundingClientRect();this.showContextMenu(x.right+4,x.top,s,[{icon:a?mt:Ct,iconClass:a?"nav-ctx-doc":"nav-ctx-dir",label:a?"View: Docs":"View: Raw",action:()=>this.toggleRawMode(n)},{icon:Ae,iconClass:"nav-ctx-edit",label:"Wiki",action:()=>{location.hash=`#/project/${encodeURIComponent(n)}`}},{kind:"divider"},{icon:mt,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateProjectDoc(n)},{icon:xt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateProjectBoard(n)},{icon:Ct,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateProjectDirectory(n)},{kind:"divider"},{icon:qt,iconClass:"nav-ctx-delete",label:"Remove from workspace",action:()=>this.callbacks.onRemoveProject(n,s),danger:!0}])}),l.append(d,h,u,g),this.registerCollapsible(n,r,c,l,!0),l.addEventListener("click",()=>this.toggleCollapsible(n)),l.addEventListener("contextmenu",b=>{b.preventDefault(),b.stopPropagation(),g.click()});const y=cs(t,this.lastTreesByProject.get(n)??[],e),v=a?y:Ee(te(y));if(v.length===0){const b=document.createElement("div");b.className="nav-label nav-empty-copy",b.textContent="No folders found.",r.appendChild(b)}else r.appendChild(this.renderCanonicalNodes(t,v,0,a));return c.append(l,r),c}renderCanonicalNodes(t,e,n,s){const i=document.createElement("div");for(const a of ls(e)){if(a.kind==="doc"||a.kind==="board"||a.kind==="capability"||a.kind==="file"){i.appendChild(this.renderCanonicalFile(a,n));continue}const r=document.createElement("div");r.className="nav-tree-group",r.style.setProperty("--tree-depth",String(n));const c=document.createElement("div");c.className="nav-tree-children";const l=document.createElement("button");l.className="nav-tree-row nav-tree-folder"+(a.kind==="docsRoot"?" nav-tree-docs-root":"")+(a.docsContainerRoot?" nav-tree-docs-container":"")+(a.root?"":" nav-tree-scaffold"),l.type="button",l.style.setProperty("--tree-depth",String(n));const d=document.createElement("span");d.className="nav-repo-chevron",d.textContent="›";const h=document.createElement("span");if(h.textContent=a.name,l.append(d,h),a.kind==="docsRoot"||a.docsContainerRoot){const u=document.createElement("span");u.className="nav-tree-badge",u.textContent="DOCS",l.appendChild(u)}const p=a.kind==="docsRoot"||a.docsContainerRoot?(a.docsContainerRoot??a.root).id:a.root?`doc:${a.root.id}:${a.contentPath??""}`:`folder:${t.id}:${a.projectPath}`;if(this.registerCollapsible(p,c,r,l,!0),l.addEventListener("click",()=>this.toggleCollapsible(p)),a.kind==="docsRoot"||a.docsContainerRoot){const u=a.docsContainerRoot??a.root;l.addEventListener("contextmenu",g=>{g.preventDefault(),this.openDirContextMenu(g.clientX,g.clientY,u,"")}),this.enableDirectoryDropTarget(r,u.id,"")}else if(a.root){const u=a.root,g=a.contentPath??"";this.enableDragSource(l,{kind:"dir",rootId:u.id,path:g}),this.enableDirectoryDropTarget(r,u.id,g),r.addEventListener("contextmenu",y=>{y.preventDefault(),this.openDirContextMenu(y.clientX,y.clientY,u,g)})}else l.addEventListener("contextmenu",u=>{u.preventDefault(),this.showContextMenu(u.clientX,u.clientY,a.name,[{icon:Ct,iconClass:"nav-ctx-dir",label:"Create docs folder here",action:()=>this.callbacks.onCreateDocsFolder(t.id,a.projectPath)}])});c.appendChild(this.renderCanonicalNodes(t,a.children,n+1,s)),r.append(l,c),i.appendChild(r)}return i}renderCanonicalFile(t,e){if(t.kind==="file"){const c=document.createElement("div");return c.className="nav-tree-row nav-tree-file",c.style.setProperty("--tree-depth",String(e)),c.textContent=t.name,c}const n=t.root,s=t.contentPath,i=t.kind==="doc"?Ne(n.id,s):t.kind==="board"?ze(n.id,_(s)):rs(n.id,s),a=t.kind==="doc"&&t.name==="index.md"?"Overview":kt(t.kind==="board"?_(t.name):t.name),r=this.link(i,a,`${t.kind}:${n.id}:${s}`);return r.classList.add("nav-tree-row",`nav-tree-${t.kind}`),r.style.setProperty("--tree-depth",String(e)),r.insertAdjacentHTML("afterbegin",t.kind==="board"?xt:t.kind==="capability"?Pe:mt),this.enableDragSource(r,t.kind==="board"?{kind:"board",rootId:n.id,boardId:_(s)}:t.kind==="capability"?{kind:"capability",rootId:n.id,path:s}:{kind:"doc",rootId:n.id,path:s}),r.addEventListener("contextmenu",c=>{c.preventDefault(),t.kind==="board"?this.openBoardContextMenu(c.clientX,c.clientY,n,_(s)):t.kind==="doc"&&this.openDocContextMenu(c.clientX,c.clientY,n,s)}),r}renderBrowseNode(t,e,n){if(e.type==="file"){const p=document.createElement("div");return p.className="nav-browse-file",p.textContent=e.name,p}if(e.name==="docs"){const p=t.docsRoots.find(u=>u.displayPath===e.path||u.displayPath.endsWith("/"+e.path));if(p){const u=n.get(p.id)??[];return this.docsRootSection(p,u)}}const i=bn(e),a=`browse:${t.id}:${e.path}`,r=document.createElement("div");r.className=i?"nav-subgroup nav-collapsible-dir":"nav-subgroup nav-browse-dir";const c=document.createElement("div");c.className="nav-dir-body";const l=document.createElement("button");l.className=i?"nav-dir-toggle nav-dir-project":"nav-browse-dir-toggle",l.type="button";const d=document.createElement("span");d.className="nav-repo-chevron",d.textContent="›";const h=document.createElement("span");if(h.textContent=e.name,l.append(d,h),l.addEventListener("click",()=>this.toggleCollapsible(a)),i){const p=t.docsRoots.find(u=>u.displayPath.startsWith(e.path+"/")||u.displayPath===e.path);p&&l.addEventListener("contextmenu",u=>{u.preventDefault(),u.stopPropagation(),this.openDirContextMenu(u.clientX,u.clientY,p,"")})}else l.addEventListener("contextmenu",p=>{p.preventDefault(),p.stopPropagation(),this.showContextMenu(p.clientX,p.clientY,e.name,[{icon:Ct,iconClass:"nav-ctx-dir",label:"Create /docs/",action:()=>this.callbacks.onCreateDocsFolder(t.id,e.path)}])});for(const p of e.children)p.type==="dir"&&c.appendChild(this.renderBrowseNode(t,p,n));return this.registerCollapsible(a,c,r,l,!0),r.append(l,c),r}renderPathNodes(t,e,n,s=""){const i=document.createElement("div");for(const a of t)if(a.kind==="root")i.appendChild(this.docsRootSection(a.root,e.get(a.root.id)??[]));else{const r=s?`${s}/${a.segment}`:a.segment,c=`pathseg:${n}:${r}`,l=this.renderPathNodes(a.children,e,n,r);l.classList.add("nav-dir-body");const d=document.createElement("div");d.className="nav-subgroup nav-collapsible-dir";const h=wn(a),{row:p,toggle:u}=this.createDirectoryRow(a.segment,`#/project/${encodeURIComponent(n)}`,`${a.segment} wiki`,()=>this.toggleCollapsible(c),!0);h&&d.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.openDirContextMenu(g.clientX,g.clientY,h,"")}),this.registerCollapsible(c,l,d,u,!0),d.append(p,l),i.appendChild(d)}return i}docsRootSection(t,e){const n=document.createElement("div");n.className="nav-subgroup nav-docs-root";const s=t.displayPath.split("/").pop()??t.displayPath;if(s.toLowerCase()!=="docs"){const a=document.createElement("div");a.className="nav-root-path-label",a.textContent=s,n.appendChild(a),a.addEventListener("contextmenu",r=>{r.preventDefault(),r.stopPropagation(),this.openDirContextMenu(r.clientX,r.clientY,t,"")})}return n.addEventListener("contextmenu",a=>{var r;(r=a.target)!=null&&r.closest(".nav-link, .nav-dir-toggle")||(a.preventDefault(),a.stopPropagation(),this.openDirContextMenu(a.clientX,a.clientY,t,""))}),this.enableDirectoryDropTarget(n,t.id,""),n.appendChild(this.docsNodes(t,ns(e),"",e)),n}createDirectoryRow(t,e,n,s,i=!1){const a=document.createElement("div");a.className="nav-dir-header-row";const r=document.createElement("button");r.className=i?"nav-dir-toggle nav-dir-project":"nav-dir-toggle nav-dir-docs",r.type="button";const c=document.createElement("span");c.className="nav-repo-chevron",c.innerHTML='<svg viewBox="0 0 16 16" width="10" height="10" fill="currentColor"><path d="M6 4l4 4-4 4"/></svg>';const l=document.createElement("span");l.textContent=t,r.append(c,l),r.addEventListener("click",s);const d=document.createElement("a");return d.className="nav-repo-wiki-link nav-dir-wiki-link",d.href=e,d.title=n,d.innerHTML='<svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="2" width="10" height="10" rx="2"/><path d="M5 5h4M5 7h4M5 9h2"/></svg>',d.addEventListener("click",h=>h.stopPropagation()),this.links.set(e,d),a.append(r,d),{row:a,toggle:r}}docsNodes(t,e,n,s){const i=document.createElement("div"),a=vn(e),r=ss(s,n),c=[...a.map(l=>({kind:"doc",node:l})),...r.map(l=>({kind:"board",name:kt(_(l.path).split("/").pop()??_(l.path)),boardId:_(l.path)}))].sort((l,d)=>{const h=l.kind==="doc"&&l.node.type==="file"&&l.node.name==="index.md",p=d.kind==="doc"&&d.node.type==="file"&&d.node.name==="index.md";if(h!==p)return h?-1:1;const u=l.kind==="doc"&&l.node.type==="dir",g=d.kind==="doc"&&d.node.type==="dir";if(u!==g)return u?-1:1;const y=l.kind==="doc"?l.node.name:l.name,v=d.kind==="doc"?d.node.name:d.name;return y.localeCompare(v)});for(const l of c)if(l.kind==="board"){const d=document.createElement("a");d.className="nav-link nav-link-board",d.href=ze(t.id,l.boardId),d.insertAdjacentHTML("afterbegin",xt),d.appendChild(document.createTextNode(l.name));const h=`board:${t.id}:${l.boardId}`;this.links.set(h,d),this.links.set(d.href,d),this.enableDragSource(d,{kind:"board",rootId:t.id,boardId:l.boardId}),d.addEventListener("contextmenu",p=>{p.preventDefault(),p.stopPropagation(),this.openBoardContextMenu(p.clientX,p.clientY,t,l.boardId)}),i.appendChild(d)}else{const{node:d}=l;if(d.type==="file"){if(!d.name.endsWith(".md"))continue;const h=d.name==="index.md"?"Overview":kt(d.name),p=this.link(Ne(t.id,d.path),h,`doc:${t.id}:${d.path}`);p.insertAdjacentHTML("afterbegin",mt),this.enableDragSource(p,{kind:"doc",rootId:t.id,path:d.path}),p.addEventListener("contextmenu",u=>{u.preventDefault(),u.stopPropagation(),this.openDocContextMenu(u.clientX,u.clientY,t,d.path)}),i.appendChild(p)}else{const h=`doc:${t.id}:${d.path}`,p=this.docsNodes(t,d.children,d.path,s);p.classList.add("nav-dir-body");const u=document.createElement("div");u.className="nav-subgroup nav-collapsible-dir";const{row:g,toggle:y}=this.createDirectoryRow(kt(d.name),`#/root/${encodeURIComponent(t.id)}/directory/${encodeURIComponent(d.path)}`,`${d.name} wiki`,v=>{v.button===0&&this.toggleCollapsible(h)},!1);this.enableDragSource(y,{kind:"dir",rootId:t.id,path:d.path}),u.addEventListener("contextmenu",v=>{v.preventDefault(),v.stopPropagation(),this.openDirContextMenu(v.clientX,v.clientY,t,d.path)}),this.enableDirectoryDropTarget(u,t.id,d.path),this.registerCollapsible(h,p,u,y,!0),u.append(g,p),i.appendChild(u)}}return i}enableDragSource(t,e){t.draggable=!0,t.addEventListener("dragstart",n=>{var s,i;this.closeContextMenu(),this.draggedItem=e,t.classList.add("nav-dragging"),(s=n.dataTransfer)==null||s.setData("application/x-docs-nav-item",JSON.stringify(e)),(i=n.dataTransfer)==null||i.setData("text/plain",ds(e)),n.dataTransfer&&(n.dataTransfer.effectAllowed="move")}),t.addEventListener("dragend",()=>{t.classList.remove("nav-dragging"),this.draggedItem=void 0,this.clearDropTargets()})}enableDirectoryDropTarget(t,e,n){t.addEventListener("dragover",s=>{const i=this.currentDragItem(s);!i||!this.canDropItem(i,e,n)||(s.preventDefault(),s.stopPropagation(),s.dataTransfer&&(s.dataTransfer.dropEffect="move"),t.classList.add("nav-drop-target"),this.scheduleDropExpand(t))}),t.addEventListener("dragleave",s=>{t.contains(s.relatedTarget)||(t.classList.remove("nav-drop-target"),this.clearDropExpand(t))}),t.addEventListener("drop",s=>{const i=this.currentDragItem(s);!i||!this.canDropItem(i,e,n)||(s.preventDefault(),s.stopPropagation(),this.clearDropExpand(t),this.clearDropTargets(),this.moveDraggedItem(i,n))})}scheduleDropExpand(t){this.dropExpandTarget===t||!t.dataset.collapsibleKey||(this.clearDropExpand(),this.dropExpandTarget=t,this.dropExpandTimer=window.setTimeout(()=>{const e=t.dataset.collapsibleKey;e&&this.applyCollapsed(e,!1),t.classList.add("nav-drop-auto-expanded"),this.dropExpandTimer=void 0},650))}clearDropExpand(t){var e;t&&this.dropExpandTarget!==t||(this.dropExpandTimer!==void 0&&window.clearTimeout(this.dropExpandTimer),this.dropExpandTimer=void 0,(e=this.dropExpandTarget)==null||e.classList.remove("nav-drop-auto-expanded"),this.dropExpandTarget=void 0)}currentDragItem(t){var n;if(this.draggedItem)return this.draggedItem;const e=(n=t.dataTransfer)==null?void 0:n.getData("application/x-docs-nav-item");if(e)try{const s=JSON.parse(e);if(s&&(s.kind==="doc"||s.kind==="capability"||s.kind==="board"||s.kind==="dir")&&typeof s.rootId=="string")return s}catch{}}canDropItem(t,e,n){if(t.rootId!==e)return!1;const s=pt(n);if(t.kind==="doc")return vt(t.path)!==s;if(t.kind==="capability")return s==="capabilities"||s.startsWith("capabilities/")&&vt(t.path)!==s;if(t.kind==="board")return vt(t.boardId)!==s;const i=pt(t.path);return!i||i===s||vt(i)===s?!1:!s.startsWith(`${i}/`)}moveDraggedItem(t,e){const n=pt(e);t.kind==="doc"||t.kind==="capability"?this.callbacks.onMoveDoc(t.rootId,t.path,n):t.kind==="board"?this.callbacks.onMoveBoard(t.rootId,t.boardId,n):this.callbacks.onMoveDirectory(t.rootId,t.path,n)}clearDropTargets(){this.clearDropExpand(),this.element.querySelectorAll(".nav-drop-target").forEach(t=>{t.classList.remove("nav-drop-target")})}startInlineRename(t,e,n){const s=document.createElement("input");s.className="nav-inline-input",s.value=e.replace(/\.md$/,"");const i=t.parentElement;if(!i)return;t.style.display="none",i.insertBefore(s,t.nextSibling),s.focus(),s.select();let a=!1;const r=c=>{if(!a&&(a=!0,s.remove(),t.style.display="",c)){const l=s.value.trim();l&&l!==e.replace(/\.md$/,"")&&n(l)}};s.addEventListener("keydown",c=>{c.stopPropagation(),c.key==="Enter"&&(c.preventDefault(),r(!0)),c.key==="Escape"&&(c.preventDefault(),r(!1))}),s.addEventListener("blur",()=>r(!0))}startInlineCreate(t,e,n){const s=document.createElement("input");s.className="nav-inline-input",s.placeholder=e,t.insertBefore(s,t.firstChild),s.focus();let i=!1;const a=r=>{if(!i&&(i=!0,s.remove(),r)){const c=s.value.trim();c&&n(c)}};s.addEventListener("keydown",r=>{r.stopPropagation(),r.key==="Enter"&&(r.preventDefault(),a(!0)),r.key==="Escape"&&(r.preventDefault(),a(!1))}),s.addEventListener("blur",()=>a(!0))}registerCollapsible(t,e,n,s,i){this.collapsibles.set(t,{body:e,group:n,btn:s}),n.dataset.collapsibleKey=t,this.applyCollapsed(t,this.collapsedState.get(t)??i)}applyCollapsed(t,e){const n=this.collapsibles.get(t);n&&(this.collapsedState.set(t,e),n.body.hidden=e,n.group.classList.toggle("collapsed",e),n.btn.setAttribute("aria-expanded",String(!e)))}toggleCollapsible(t){const e=this.collapsibles.get(t);e&&this.applyCollapsed(t,!e.body.hidden)}openDirContextMenu(t,e,n,s){const i=s?kt(s.split("/").pop()??s):n.displayPath.split("/").pop()??n.displayPath,a=[{icon:Ct,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateDirectory(n.id,s)},{icon:xt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateBoard(n.id,s)},{icon:mt,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateDoc(n.id,s)},{icon:Pe,iconClass:"nav-ctx-cap",label:"New Capability",action:()=>this.callbacks.onCreateCapability(n.id,s)}];s&&a.push({icon:me,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDirectory(n.id,s)},{icon:qt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDirectory(n.id,s)}),this.showContextMenu(t,e,i,a)}openEmptyProjectContextMenu(t,e,n,s){this.showContextMenu(t,e,s,[{icon:Ct,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateProjectDirectory(n)},{icon:xt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateProjectBoard(n)},{icon:mt,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateProjectDoc(n)}])}openDocContextMenu(t,e,n,s){const i=s.split("/").pop()??s;this.showContextMenu(t,e,i,[{icon:mt,iconClass:"nav-ctx-doc",label:"Open",action:()=>this.callbacks.onOpenDoc(n.id,s)},{icon:Ae,iconClass:"nav-ctx-edit",label:"Edit",action:()=>this.callbacks.onEditDoc(n.id,s)},{kind:"divider"},{icon:me,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDoc(n.id,s)},{icon:qt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDoc(n.id,s),danger:!0}])}openBoardContextMenu(t,e,n,s){const i=kt(s.split("/").pop()??s);this.showContextMenu(t,e,i,[{icon:xt,iconClass:"nav-ctx-board",label:"Open",action:()=>this.callbacks.onOpenBoard(n.id,s)},{kind:"divider"},{icon:me,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameBoard(n.id,s)},{icon:qt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteBoard(n.id,s),danger:!0}])}showContextMenu(t,e,n,s){this.closeContextMenu();const i=document.createElement("div");i.className="nav-context-menu",i.addEventListener("pointerdown",c=>c.stopPropagation());const a=document.createElement("div");a.className="nav-context-label",a.textContent=n,i.appendChild(a);const r=document.createElement("div");r.className="nav-context-divider",i.appendChild(r);for(const c of s){if(c.kind==="divider"){const p=document.createElement("div");p.className="nav-context-divider",i.appendChild(p);continue}const l=document.createElement("button");l.className="nav-context-item"+(c.danger?" nav-context-item-danger":""),l.type="button";const d=document.createElement("span");d.className=`nav-ctx-icon ${c.iconClass}`,d.innerHTML=c.icon;const h=document.createElement("span");h.textContent=c.label,l.append(d,h),l.addEventListener("click",()=>{this.closeContextMenu(),c.action()}),i.appendChild(l)}i.style.position="fixed",i.style.left=`${t}px`,i.style.top=`${e}px`,document.body.appendChild(i),this.contextMenu=i,requestAnimationFrame(()=>{if(!this.contextMenu)return;const c=i.getBoundingClientRect();c.right>window.innerWidth&&(i.style.left=`${Math.max(0,t-c.width)}px`),c.bottom>window.innerHeight&&(i.style.top=`${Math.max(0,e-c.height)}px`)})}closeContextMenu(){var t;(t=this.contextMenu)==null||t.remove(),this.contextMenu=void 0}groupLabel(t){const e=document.createElement("div");return e.className="nav-label",e.textContent=t,e}link(t,e,n){const s=document.createElement("a");return s.className="nav-link",s.href=t,s.textContent=e,this.links.set(n,s),this.links.set(t,s),s}}const xt='<svg class="nav-node-icon nav-node-icon-board" viewBox="0 0 16 16" aria-hidden="true"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>',Pe='<svg class="nav-node-icon nav-node-icon-capability" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 1l2 4.5 4.5 0.7-3.3 3.1 0.8 4.7-4-2.1-4 2.1 0.8-4.7L1.5 6.2l4.5-0.7z"/></svg>',mt='<svg class="nav-node-icon nav-node-icon-doc" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 1.5h6.5l3 3V14.5H3z"/><path d="M9.5 1.5V4.5h3" stroke="none"/><line x1="5" y1="7" x2="11" y2="7" stroke="var(--bg-canvas)" stroke-width="0.8"/><line x1="5" y1="9.5" x2="11" y2="9.5" stroke="var(--bg-canvas)" stroke-width="0.8"/><line x1="5" y1="12" x2="9" y2="12" stroke="var(--bg-canvas)" stroke-width="0.8"/></svg>',Ct='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.45" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4.5h4l1.4 1.6H14v6.4a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z"/><path d="M2 4.5v-1a1 1 0 0 1 1-1h3l1.4 2"/></svg>',Ae='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M11 2l3 3-8 8H3v-3z"/></svg>',me='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12h12M8 3v9M5 6l3-3 3 3"/></svg>',qt='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4h12M5 4V2h6v2M6 7v5M10 7v5M3 4l1 9a1 1 0 001 1h6a1 1 0 001-1l1-9"/></svg>';function vn(o){return o.filter(t=>t.type==="file"?t.name.endsWith(".md"):!ts.has(t.name)).map(t=>t.type==="file"?t:{...t,children:vn(t.children)})}function ns(o){const t=o.find(e=>e.type==="dir"&&e.name.toLowerCase()==="docs");return!t||t.type!=="dir"?o:o.filter(e=>e!==t).concat(t.children)}function ss(o,t){const e=t?`${t}/`:"";return os(o).filter(n=>e?n.path.startsWith(e)?!n.path.slice(e.length).includes("/"):!1:!n.path.includes("/"))}function os(o){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(".board.json")&&t.push(s):e(s.children)};return e(o),t}function Ne(o,t){return`#/root/${encodeURIComponent(o)}/docs/${encodeURIComponent(t)}`}function is(o){return`#/root/${encodeURIComponent(o)}/boards`}function ze(o,t){return`#/root/${encodeURIComponent(o)}/boards/${encodeURIComponent(t)}`}function as(o){return`#/root/${encodeURIComponent(o)}/capabilities`}function rs(o,t){return`#/root/${encodeURIComponent(o)}/capabilities/${encodeURIComponent(t)}`}function cs(o,t,e){const n=new Map,s=[],i=c=>{const l=pt(c),d=n.get(l);if(d)return d;const h=vt(l),p={id:`folder:${o.id}:${l}`,kind:"folder",name:l.split("/").pop()??o.label,projectPath:l,children:[]};return n.set(l,p),l&&h?i(h).children.push(p):s.push(p),p},a=c=>{for(const l of c)if(l.type==="dir")i(l.path),a(l.children);else{const d={id:`file:${o.id}:${l.path}`,kind:"file",name:l.name,projectPath:l.path,children:[]};n.set(l.path,d);const h=vt(l.path);h?i(h).children.push(d):s.push(d)}};a(t);for(const c of o.docsRoots){const l=pt(c.displayPath),d=i(l);d.kind="docsRoot",d.id=`root:${c.id}`,d.root=c,d.contentPath="";const h=p=>{for(const u of p){const g=[l,u.path].filter(Boolean).join("/");if(u.type==="dir"){const C=i(g);C.kind!=="docsRoot"&&(C.root=c,C.contentPath=u.path),h(u.children);continue}if(!u.name.endsWith(".md")&&!u.name.endsWith(".board.json"))continue;const y=vt(g),v=u.name.endsWith(".board.json"),b=u.path.startsWith("capabilities/"),x=n.get(g),S=x??{id:"",kind:"file",name:u.name,projectPath:g,children:[]};S.id=`${v?"board":b?"capability":"doc"}:${c.id}:${u.path}`,S.kind=v?"board":b?"capability":"doc",S.root=c,S.contentPath=u.path,x||(n.set(g,S),y?i(y).children.push(S):s.push(S))}};h(e.get(c.id)??[])}const r=(c,l)=>{const d=c.kind==="docsRoot"?c.root:c.root??l;if(c.kind==="folder"&&d){c.root=d;const h=pt(d.displayPath);c.contentPath=c.projectPath.slice(h.length).replace(/^\//,"")}for(const h of c.children)r(h,d)};for(const c of s)r(c);return s}function ls(o){return[...o].sort((t,e)=>{const n=s=>s.kind==="doc"&&s.name==="index.md"?0:s.kind==="doc"?1:s.kind==="capability"?2:s.kind==="board"?3:s.kind==="folder"||s.kind==="docsRoot"?4:5;return n(t)-n(e)||t.name.localeCompare(e.name,void 0,{sensitivity:"accent"})})}function te(o,t,e=!1){const n=[];for(const s of o){if(s.kind==="docsRoot"){n.push({...s,children:te(s.children,!1,!0)});continue}if(e){if(s.kind==="file")continue;if(s.kind==="folder"){const i=te(s.children,!1,!0);(s.name!=="assets"||i.length>0)&&n.push({...s,children:i})}else n.push(s);continue}if(s.kind==="folder"){const i=te(s.children);i.length>0&&n.push({...s,children:i})}}return n}function Ee(o){var e;const t=[];for(const n of o){if(n.kind==="docsRoot"){t.push(...Ee(n.children));continue}if(n.kind!=="folder"){t.push(n);continue}const s=(e=n.children.find(i=>i.kind==="docsRoot"))==null?void 0:e.root;t.push({...n,docsContainerRoot:s,children:Ee(n.children)})}return t}function kt(o){const t=o.replace(/\.md$/,"").replace(/[-_]/g," ");return t.charAt(0).toUpperCase()+t.slice(1)}function bn(o){if(o.type==="file")return!1;for(const t of o.children)if(t.type==="dir"&&t.name==="docs"||t.type==="dir"&&bn(t))return!0;return!1}function pt(o){return o.replace(/^\/+|\/+$/g,"")}function vt(o){const t=pt(o),e=t.lastIndexOf("/");return e===-1?"":t.slice(0,e)}function ds(o){return o.kind==="doc"||o.kind==="capability"?o.path:o.kind==="board"?o.boardId:o.path}function wn(o){if(o.kind==="root")return o.root;for(const t of o.children){const e=wn(t);if(e)return e}return null}function Wt(o,t={}){const{frontmatter:e,body:n}=hs(o);try{const s=xn(n.split(`
2
+ `),t);return{frontmatter:e,html:s}}catch(s){return console.error("Markdown render failed",s),{frontmatter:e,html:`<div class="md-error"><strong>Could not render this document.</strong><pre>${ae(String(s))}</pre></div>`}}}function hs(o){const t={};if(!o.startsWith("---"))return{frontmatter:t,body:o};const e=o.indexOf(`
3
+ ---`,3);if(e===-1)return{frontmatter:t,body:o};const n=o.slice(3,e).trim();for(const i of n.split(`
4
+ `)){const a=i.indexOf(":");a!==-1&&(t[i.slice(0,a).trim()]=i.slice(a+1).trim())}const s=o.slice(e+4).replace(/^\n+/,"");return{frontmatter:t,body:s}}function xn(o,t){const e=[];let n=0,s=0;const i=o.length*4+1e3;for(;n<o.length;){if(++s>i)throw new Error(`renderBlocks exceeded ${i} iterations at line ${n} — aborting to avoid an infinite loop`);const a=o[n];if(a.trim()===""){n++;continue}const r=a.match(/^(`{3,})\s*(\w+)?\s*$/);if(r){const d=r[1].length,h=(r[2]??"").toLowerCase(),p=new RegExp("^`{"+d+",}\\s*$"),u=[];for(n++;n<o.length&&!p.test(o[n]);)u.push(o[n]),n++;n++,h==="board"?e.push(ms(kn(u.join(`
5
+ `)))):e.push(`<pre class="code-block"><code${h?` class="language-${h}"`:""}>${ae(u.join(`
6
+ `))}</code></pre>`);continue}const c=a.match(/^(#{1,6})\s+(.*)$/);if(c){const d=c[1].length,h=bt(c[2].trim(),t),p=ys(c[2]);e.push(`<h${d} id="${p}">${h}</h${d}>`),n++;continue}if(/^(-{3,}|\*{3,}|_{3,})\s*$/.test(a)){e.push("<hr />"),n++;continue}if(/^>\s?/.test(a)){const d=[];for(;n<o.length&&/^>\s?/.test(o[n]);)d.push(o[n].replace(/^>\s?/,"")),n++;e.push(`<blockquote>${xn(d,t)}</blockquote>`);continue}if(a.includes("|")&&n+1<o.length&&ps(o[n+1])){const d=[];for(;n<o.length&&o[n].includes("|")&&o[n].trim()!=="";)d.push(o[n]),n++;e.push(us(d,t));continue}if(Bt(a)){const d=[];for(;n<o.length&&(Bt(o[n])||/^\s+\S/.test(o[n])||o[n].trim()==="");){if(o[n].trim()===""){const h=o[n+1];if(h===void 0||!Bt(h)&&!/^\s+\S/.test(h))break}d.push(o[n]),n++}e.push(Cn(d,t));continue}const l=[o[n]];for(n++;n<o.length&&o[n].trim()!==""&&!/^`{3,}/.test(o[n])&&!/^#{1,6}\s/.test(o[n])&&!/^>\s?/.test(o[n])&&!Bt(o[n])&&!/^(-{3,}|\*{3,}|_{3,})\s*$/.test(o[n]);)l.push(o[n]),n++;e.push(`<p>${bt(l.join(" ").trim(),t)}</p>`)}return e.join(`
7
+ `)}function Bt(o){return/^\s*([-*+]|\d+\.)\s+/.test(o)}function Cn(o,t){const e=o.filter(l=>Bt(l)).map(l=>l.match(/^\s*/)[0].length);if(e.length===0)return bt(o.join(" ").trim(),t);const n=Math.min(...e),s=[];let i=!1,a=null;for(const l of o){const d=l.match(/^\s*/)[0].length,h=l.match(/^\s*([-*+]|\d+\.)\s+(.*)$/);if(h&&d===n){i=/\d+\./.test(h[1]);let p=h[2],u=null;const g=p.match(/^\[([ xX])\]\s+(.*)$/);g&&(u=g[1].toLowerCase()==="x",p=g[2]),a={ordered:i,content:[p],checked:u},s.push(a)}else a&&a.content.push(l.slice(n))}const r=i?"ol":"ul",c=s.map(l=>{const d=l.content[0],h=l.content.slice(1);let p=bt(d,t);const u=h.filter(g=>g.trim()!=="");return u.some(g=>Bt(g))?p+=Cn(h,t):u.length&&(p+=" "+bt(u.join(" ").trim(),t)),l.checked!==null?`<li class="task">${`<input type="checkbox" disabled${l.checked?" checked":""} /> `}${p}</li>`:`<li>${p}</li>`}).join("");return`<${r}>${c}</${r}>`}function ps(o){return/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(o)}function fe(o){return o.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(t=>t.trim())}function us(o,t){const e=fe(o[0]),n=fe(o[1]).map(r=>{const c=r.startsWith(":"),l=r.endsWith(":");return c&&l?"center":l?"right":c?"left":""}),s=o.slice(2).map(fe),i=e.map((r,c)=>`<th${n[c]?` style="text-align:${n[c]}"`:""}>${bt(r,t)}</th>`).join(""),a=s.map(r=>`<tr>${r.map((c,l)=>`<td${n[l]?` style="text-align:${n[l]}"`:""}>${bt(c,t)}</td>`).join("")}</tr>`).join("");return`<table><thead><tr>${i}</tr></thead><tbody>${a}</tbody></table>`}function kn(o){const t={};for(const n of o.split(`
8
+ `)){const s=n.replace(/#.*$/,"").trim();if(!s)continue;const i=s.indexOf(":");i!==-1&&(t[s.slice(0,i).trim()]=s.slice(i+1).trim())}let e=null;if(t.region){const n=t.region.split(",").map(s=>parseFloat(s.trim()));n.length===4&&n.every(s=>Number.isFinite(s))&&(e=[n[0],n[1],n[2],n[3]])}return{src:t.src??"",region:e,height:t.height?Math.max(120,parseInt(t.height,10)||360):360,title:t.title??null}}function ms(o){const t=o.region?o.region.join(","):"";return`<figure class="board-embed" data-src="${It(o.src)}" data-region="${t}" data-height="${o.height}" data-title="${It(o.title??"")}"></figure>`}function bt(o,t){let e=ae(o);const n=[];e=e.replace(/\\([\\`*_{}\[\]()#+\-.!|])/g,(i,a)=>(n.push(a),`${n.length-1}`));const s=[];return e=e.replace(/`([^`]+)`/g,(i,a)=>(s.push(`<code>${a}</code>`),`\0${s.length-1}\0`)),e=e.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g,(i,a,r)=>{const c=Me(r,t),l=fs(r,t),d=c===r?"":` data-md-src="${It(r)}"`;return`<img src="${l}" alt="${It(a)}" loading="lazy"${d} />`}),e=e.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(i,a,r)=>{const c=gs(r,t),d=/^(https?:|mailto:|tel:)/.test(r)?' target="_blank" rel="noopener noreferrer"':"",h=c===r?"":` data-md-href="${It(r)}"`;return`<a href="${It(c)}"${d}${h}>${a}</a>`}),e=e.replace(/\*\*([\s\S]+?)\*\*/g,"<strong>$1</strong>"),e=e.replace(/__([\s\S]+?)__/g,"<strong>$1</strong>"),e=e.replace(/(^|[^*])\*([^*\s][^*]*)\*/g,"$1<em>$2</em>"),e=e.replace(/(^|[^_])_([^_\s][^_]*)_/g,"$1<em>$2</em>"),e=e.replace(/\u0000(\d+)\u0000/g,(i,a)=>s[Number(a)]),e=e.replace(/\u0001(\d+)\u0001/g,(i,a)=>n[Number(a)]),e}function fs(o,t){if(/^(https?:|data:)/.test(o)||!t.rootId||!t.docPath)return o;const e=Me(o,t);return e?k.assetUrl(t.rootId,e):o}function gs(o,t){if(/^(https?:|mailto:|tel:|#|data:)/.test(o)||!t.rootId||!t.docPath)return o;const e=Me(o,t);return e?e.endsWith(".md")?`#/root/${encodeURIComponent(t.rootId)}/docs/${encodeURIComponent(e)}`:k.assetUrl(t.rootId,e):o}function Me(o,t){return t.docPath?Yn(t.docPath,o):o}function ae(o){return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function It(o){return ae(o).replace(/"/g,"&quot;")}function ys(o){return o.toLowerCase().replace(/[^\w\s-]/g,"").trim().replace(/\s+/g,"-")}class En{constructor(t,e,n){m(this,"cache",new Map);m(this,"loading",new Set);m(this,"missing",new Set);m(this,"assetStore");m(this,"onLoaded");m(this,"resolveSrcUrl");this.assetStore=t,this.onLoaded=e,this.resolveSrcUrl=n}get(t){const e=this.cache.get(t);return e||(!this.loading.has(t)&&!this.missing.has(t)&&this.load(t),null)}isMissing(t){return this.missing.has(t)}srcToUrl(t){return this.resolveSrcUrl?this.resolveSrcUrl(t):/^(https?:)?\/\//.test(t)||t.startsWith("/")||t.startsWith("data:")?t:`/__api/asset?path=${encodeURIComponent(t)}`}keyForSrc(t){return this.srcToUrl(t)}getBySrc(t){const e=this.srcToUrl(t),n=this.cache.get(e);return n||(!this.loading.has(e)&&!this.missing.has(e)&&this.loadUrl(e),null)}isMissingSrc(t){return this.missing.has(this.srcToUrl(t))}async loadUrl(t){this.loading.add(t);try{const e=await fetch(t);if(!e.ok){this.missing.add(t);return}const n=await e.blob(),s=await createImageBitmap(n);this.cache.set(t,s),this.onLoaded()}catch{this.missing.add(t)}finally{this.loading.delete(t)}}set(t,e){this.cache.set(t,e),this.missing.delete(t)}setBySrc(t,e){this.set(this.srcToUrl(t),e)}async load(t){this.loading.add(t);try{const e=await this.assetStore.get(t);if(!e){this.missing.add(t);return}const n=await createImageBitmap(e.blob);this.cache.set(t,n),this.onLoaded()}catch{this.missing.add(t)}finally{this.loading.delete(t)}}evict(t){const e=this.cache.get(t);e&&e.close(),this.cache.delete(t),this.missing.delete(t)}clear(){for(const t of this.cache.values())t.close();this.cache.clear(),this.missing.clear()}get size(){return this.cache.size}}let ge=0;function Rt(){return ge=(ge+1)%65535,Date.now().toString(36)+"-"+ge.toString(36)+"-"+Math.random().toString(36).slice(2,8)}function A(o,t={}){const e=Date.now();return{id:Rt(),type:o,x:0,y:0,width:100,height:100,rotation:0,zIndex:0,locked:!1,hidden:!1,createdAt:e,updatedAt:e,style:{},data:{},...t}}const vs="viteboard",bs=1;class ws{constructor(){m(this,"dbPromise",null)}open(){return this.dbPromise?this.dbPromise:(this.dbPromise=new Promise((t,e)=>{const n=indexedDB.open(vs,bs);n.onupgradeneeded=()=>{const s=n.result;s.objectStoreNames.contains("boards")||s.createObjectStore("boards",{keyPath:"id"}),s.objectStoreNames.contains("assets")||s.createObjectStore("assets",{keyPath:"id"})},n.onsuccess=()=>t(n.result),n.onerror=()=>e(n.error??new Error("IndexedDB open failed")),n.onblocked=()=>e(new Error("IndexedDB blocked"))}),this.dbPromise)}async put(t,e){const n=await this.open();return new Promise((s,i)=>{const a=n.transaction(t,"readwrite");a.objectStore(t).put(e),a.oncomplete=()=>s(),a.onerror=()=>i(a.error??new Error("IndexedDB write failed"))})}async get(t,e){const n=await this.open();return new Promise((s,i)=>{const r=n.transaction(t,"readonly").objectStore(t).get(e);r.onsuccess=()=>s(r.result),r.onerror=()=>i(r.error??new Error("IndexedDB read failed"))})}async delete(t,e){const n=await this.open();return new Promise((s,i)=>{const a=n.transaction(t,"readwrite");a.objectStore(t).delete(e),a.oncomplete=()=>s(),a.onerror=()=>i(a.error??new Error("IndexedDB delete failed"))})}async getAllKeys(t){const e=await this.open();return new Promise((n,s)=>{const a=e.transaction(t,"readonly").objectStore(t).getAllKeys();a.onsuccess=()=>n(a.result),a.onerror=()=>s(a.error??new Error("IndexedDB keys failed"))})}async getAll(t){const e=await this.open();return new Promise((n,s)=>{const a=e.transaction(t,"readonly").objectStore(t).getAll();a.onsuccess=()=>n(a.result),a.onerror=()=>s(a.error??new Error("IndexedDB read failed"))})}async clearStore(t){const e=await this.open();return new Promise((n,s)=>{const i=e.transaction(t,"readwrite");i.objectStore(t).clear(),i.oncomplete=()=>n(),i.onerror=()=>s(i.error??new Error("IndexedDB clear failed"))})}}const Y=new ws;class xs{async get(t){try{return await Y.get("assets",t)}catch{return}}async createFromBlob(t,e){const n=await createImageBitmap(t),s=Date.now(),i={id:Rt(),type:"image",mimeType:t.type||"image/png",blob:t,width:n.width,height:n.height,sizeBytes:t.size,createdAt:s,updatedAt:s,name:e};return n.close(),await Y.put("assets",i),i}async put(t){await Y.put("assets",t)}async delete(t){await Y.delete("assets",t)}async getAllKeys(){try{return await Y.getAllKeys("assets")}catch{return[]}}async getAll(){try{return await Y.getAll("assets")}catch{return[]}}async totalSizeBytes(){return(await this.getAll()).reduce((e,n)=>e+n.sizeBytes,0)}async clearUnused(t){const e=await this.getAllKeys();let n=0;for(const s of e)t.has(s)||(await Y.delete("assets",s),n++);return n}async clearAll(){await Y.clearStore("assets")}}const J=new xs,Lt=new Map,Cs=2e3;function F(o){for(const t of Lt.keys())t.startsWith(o+"|")&&Lt.delete(t)}function Sn(o){if(o.data.shapeKind==="chevron"){const t=Math.abs(o.height)*.34,e=Math.abs(o.width)*.18;return Math.round(Math.max(13,Math.min(48,t,e)))}return o.style.fontSize??14}function ks(o,t,e,n){const s=Lt.get(t);if(s)return s;const i=[];for(const a of e.split(`
9
+ `)){if(a===""){i.push("");continue}const r=a.split(" ");let c="";for(const l of r){const d=c===""?l:c+" "+l;o.measureText(d).width>n&&c!==""?(i.push(c),c=l):c=d}i.push(c)}return Lt.size>Cs&&Lt.clear(),Lt.set(t,i),i}function $t(o,t,e,n,s,i){const a=Math.min(i,n/2,s/2);o.beginPath(),o.moveTo(t+a,e),o.arcTo(t+n,e,t+n,e+s,a),o.arcTo(t+n,e+s,t,e+s,a),o.arcTo(t,e+s,t,e,a),o.arcTo(t,e,t+n,e,a),o.closePath()}function ne(o,t){const{ctx:e,lod:n}=t;if(e.save(),e.globalAlpha=o.style.opacity??1,n===0){Es(o,t),e.restore();return}switch(o.type){case"sticky":Ss(o,t);break;case"task":Ts(o,t);break;case"rectangle":case"frame":je(o,t);break;case"ellipse":Ds(o,t);break;case"text":Ps(o,t);break;case"line":case"arrow":case"connector":As(o,t);break;case"image":case"screenshot":Ns(o,t);break;default:je(o,t)}e.restore()}function Es(o,t){const{ctx:e}=t;if(o.type==="line"||o.type==="arrow"||o.type==="connector"){e.strokeStyle=o.style.stroke??(t.theme==="dark"?"#888":"#999"),e.lineWidth=Math.max(1/t.scale,o.style.strokeWidth??2),e.beginPath(),e.moveTo(o.x,o.y),e.lineTo(o.x+o.width,o.y+o.height),e.stroke();return}e.fillStyle=o.style.fill??(t.theme==="dark"?"#3a3d42":"#d8d8d4"),e.fillRect(o.x,o.y,o.width,o.height)}function re(o,t){o.style.shadow&&t.lod===2&&(t.ctx.shadowColor=t.theme==="dark"?"rgba(0,0,0,0.5)":"rgba(0,0,0,0.14)",t.ctx.shadowBlur=8*t.scale,t.ctx.shadowOffsetY=2*t.scale)}function ce(o){o.ctx.shadowColor="transparent",o.ctx.shadowBlur=0,o.ctx.shadowOffsetY=0}function Ss(o,t){const{ctx:e,lod:n}=t,s=o.style.fill??"#fef08a";if(re(o,t),$t(e,o.x,o.y,o.width,o.height,o.style.borderRadius??12),e.fillStyle=s,e.fill(),ce(t),n===2){const i=o.data.text??"";i&&le(o,t,i,14)}}function Ts(o,t){const{ctx:e,lod:n}=t,s=o.data.checked===!0,i=t.theme==="dark",a=o.style.borderRadius??14;if(re(o,t),$t(e,o.x,o.y,o.width,o.height,a),e.fillStyle=o.style.fill??(i?"#17191b":"#ffffff"),e.fill(),ce(t),e.strokeStyle=o.style.stroke??(i?"rgba(255,255,255,0.12)":"rgba(0,0,0,0.09)"),e.lineWidth=o.style.strokeWidth??1,e.stroke(),n<2)return;const r=Math.min(22,Math.max(16,o.height*.38)),c=o.x+16,l=o.y+o.height/2-r/2;$t(e,c,l,r,r,6),e.fillStyle=s?"#0078d4":i?"#111314":"#f3f2f1",e.fill(),e.strokeStyle=s?"#0078d4":i?"rgba(255,255,255,0.18)":"rgba(0,0,0,0.13)",e.lineWidth=1.4,e.stroke(),s&&(e.strokeStyle="#ffffff",e.lineWidth=2.1,e.lineCap="round",e.lineJoin="round",e.beginPath(),e.moveTo(c+r*.26,l+r*.52),e.lineTo(c+r*.43,l+r*.68),e.lineTo(c+r*.75,l+r*.32),e.stroke());const d=o.data.text??"";if(!d)return;const h=50,p=16,u=o.style.fontSize??15,g=o.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';if(e.font=`${o.style.fontWeight??"650"} ${u}px ${g}`,e.fillStyle=s?i?"#a7aaa8":"#777777":o.style.textColor??(i?"#f6f6f3":"#252829"),e.textAlign="left",e.textBaseline="middle",e.save(),e.beginPath(),e.rect(o.x+h,o.y,Math.max(10,o.width-h-p),o.height),e.clip(),e.fillText(d,o.x+h,o.y+o.height/2),s){const y=e.measureText(d),v=o.y+o.height/2+1;e.strokeStyle=i?"rgba(167,170,168,0.58)":"rgba(119,119,119,0.48)",e.lineWidth=1.3,e.beginPath(),e.moveTo(o.x+h,v),e.lineTo(o.x+h+Math.min(y.width,o.width-h-p),v),e.stroke()}e.restore()}function je(o,t){const{ctx:e,lod:n}=t,s=o.data.shapeKind??"rectangle",i=o.style.borderRadius??0;if(re(o,t),s==="diamond"?Ms(e,o):s==="triangle"?Bs(e,o):s==="chevron"?Is(e,o):s==="parallelogram"?Ls(e,o):s==="hexagon"?Rs(e,o):s==="cylinder"?$s(e,o):s==="pill"?$t(e,o.x,o.y,o.width,o.height,Math.min(Math.abs(o.height)/2,Math.abs(o.width)/2)):i>0?$t(e,o.x,o.y,o.width,o.height,i):(e.beginPath(),e.rect(o.x,o.y,o.width,o.height)),o.style.fill&&o.style.fill!=="transparent"&&(e.fillStyle=o.style.fill,e.fill()),ce(t),o.style.stroke&&(o.style.strokeWidth??0)>0&&(e.strokeStyle=o.style.stroke,e.lineWidth=o.style.strokeWidth??1,e.stroke(),s==="cylinder")){const a=Math.abs(o.width)/2,r=Math.min(Math.abs(o.height)*.18,18);e.beginPath(),e.ellipse(o.x+o.width/2,o.y+r,a,r,0,0,Math.PI*2),e.stroke()}if(n===2){const a=o.data.text??"";if(a){const r=s==="chevron"?Math.min(Math.abs(o.width)*.18,Math.abs(o.height)*.55)+8:10;le(o,t,a,r)}}}function Ms(o,t){const e=t.x,n=t.y,s=t.width,i=t.height;o.beginPath(),o.moveTo(e+s/2,n),o.lineTo(e+s,n+i/2),o.lineTo(e+s/2,n+i),o.lineTo(e,n+i/2),o.closePath()}function Bs(o,t){const e=t.x,n=t.y,s=t.width,i=t.height;o.beginPath(),o.moveTo(e+s/2,n),o.lineTo(e+s,n+i),o.lineTo(e,n+i),o.closePath()}function Is(o,t){const e=t.x,n=t.y,s=t.width,i=t.height,a=Math.min(Math.abs(s)*.22,Math.abs(i)*.62);o.beginPath(),o.moveTo(e,n),o.lineTo(e+s-a,n),o.lineTo(e+s,n+i/2),o.lineTo(e+s-a,n+i),o.lineTo(e,n+i),o.lineTo(e+a,n+i/2),o.closePath()}function Ls(o,t){const e=Math.min(Math.abs(t.width)*.2,Math.abs(t.height)*.55);o.beginPath(),o.moveTo(t.x+e,t.y),o.lineTo(t.x+t.width,t.y),o.lineTo(t.x+t.width-e,t.y+t.height),o.lineTo(t.x,t.y+t.height),o.closePath()}function Rs(o,t){const e=Math.min(Math.abs(t.width)*.22,Math.abs(t.height)*.5);o.beginPath(),o.moveTo(t.x+e,t.y),o.lineTo(t.x+t.width-e,t.y),o.lineTo(t.x+t.width,t.y+t.height/2),o.lineTo(t.x+t.width-e,t.y+t.height),o.lineTo(t.x+e,t.y+t.height),o.lineTo(t.x,t.y+t.height/2),o.closePath()}function $s(o,t){const e=Math.abs(t.width)/2,n=Math.min(Math.abs(t.height)*.18,18),s=t.x+t.width/2;o.beginPath(),o.ellipse(s,t.y+n,e,n,0,Math.PI,Math.PI*2),o.lineTo(t.x+t.width,t.y+t.height-n),o.ellipse(s,t.y+t.height-n,e,n,0,0,Math.PI),o.lineTo(t.x,t.y+n),o.closePath()}function Ds(o,t){const{ctx:e,lod:n}=t;if(re(o,t),e.beginPath(),e.ellipse(o.x+o.width/2,o.y+o.height/2,Math.abs(o.width/2),Math.abs(o.height/2),0,0,Math.PI*2),o.style.fill&&o.style.fill!=="transparent"&&(e.fillStyle=o.style.fill,e.fill()),ce(t),o.style.stroke&&(o.style.strokeWidth??0)>0&&(e.strokeStyle=o.style.stroke,e.lineWidth=o.style.strokeWidth??1,e.stroke()),n===2){const s=o.data.text??"";s&&le(o,t,s,10)}}function Ps(o,t){if(t.lod<2){t.ctx.fillStyle=t.theme==="dark"?"#55585e":"#c5c5c0",t.ctx.fillRect(o.x,o.y,o.width,Math.min(o.height,6/t.scale));return}const e=o.data.text??"";le(o,t,e,0,"left","top")}function le(o,t,e,n,s="center",i="middle"){const{ctx:a}=t,r=o.data.shapeKind==="chevron",c=Sn(o),l=o.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',d=r?"750":o.style.fontWeight??"400";a.font=`${d} ${c}px ${l}`,a.fillStyle=o.style.textColor??(t.theme==="dark"&&o.type==="text"?"#f2f2f2":"#1f2933");const h=Math.max(10,o.width-n*2),p=`${o.id}|${o.updatedAt}|${c}|${h.toFixed(0)}`,u=ks(a,p,e,h),g=c*1.35,y=u.length*g;let v;i==="middle"?v=o.y+o.height/2-y/2+g/2:v=o.y+n+g/2,a.textBaseline="middle",a.textAlign=s;const b=s==="center"?o.x+o.width/2:o.x+n;a.save(),a.beginPath(),a.rect(o.x,o.y,o.width,o.height),a.clip();for(let x=0;x<u.length;x++)a.fillText(u[x],b,v+x*g);a.restore()}function As(o,t){const{ctx:e,lod:n}=t,s=o.x,i=o.y,a=o.x+o.width,r=o.y+o.height,c=o.style.stroke??(t.theme==="dark"?"#d1d5db":"#374151"),l=o.style.strokeWidth??2;if(e.strokeStyle=c,e.fillStyle=c,e.lineWidth=l,e.setLineDash(o.style.strokeDash??[]),e.beginPath(),e.moveTo(s,i),e.lineTo(a,r),e.stroke(),e.setLineDash([]),n>=1){const d=Math.atan2(r-i,a-s),h=Math.max(11,l*5.5);(o.style.arrowEnd??o.type==="arrow")&&He(e,a,r,d,h),o.style.arrowStart&&He(e,s,i,d+Math.PI,h);const p=typeof o.data.text=="string"?o.data.text.trim():"";if(p)if(o.data.labelPosition==="sides"){const[u,g]=p.split("|").map(y=>y.trim());u&&ye(e,u,s,i,a,r,t,.24),g&&ye(e,g,s,i,a,r,t,.76)}else ye(e,p,s,i,a,r,t)}}function ye(o,t,e,n,s,i,a,r=.5){o.font='600 13px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';const h=o.measureText(t).width+7*2,p=21,u=e+(s-e)*r-h/2,g=n+(i-n)*r-p/2;o.fillStyle=a.theme==="dark"?"#202328":"#ffffff",$t(o,u,g,h,p,4),o.fill(),o.strokeStyle=a.theme==="dark"?"#4a4d52":"#d8dade",o.lineWidth=1,o.stroke(),o.fillStyle=a.theme==="dark"?"#f2f2f2":"#1f2933",o.textAlign="center",o.textBaseline="middle",o.fillText(t,u+h/2,g+p/2)}function He(o,t,e,n,s){o.beginPath(),o.moveTo(t,e),o.lineTo(t-s*Math.cos(n-Math.PI/6),e-s*Math.sin(n-Math.PI/6)),o.lineTo(t-s*Math.cos(n+Math.PI/6),e-s*Math.sin(n+Math.PI/6)),o.closePath(),o.fill()}function Ns(o,t){const{ctx:e,imageCache:n}=t,s=o.data.src,i=o.data.assetId,a=s?n.getBySrc(s):i?n.get(i):null;if(a){if(t.lod===1&&t.scale<.15){e.fillStyle=t.theme==="dark"?"#3a3d42":"#d8d8d4",e.fillRect(o.x,o.y,o.width,o.height);return}e.drawImage(a,o.x,o.y,o.width,o.height)}else if(e.fillStyle=t.theme==="dark"?"#2a2d31":"#ececea",e.fillRect(o.x,o.y,o.width,o.height),e.strokeStyle=t.theme==="dark"?"#4a4d52":"#c9c9c5",e.lineWidth=1/t.scale,e.strokeRect(o.x,o.y,o.width,o.height),t.lod===2){const c=(s?n.isMissingSrc(s):i?n.isMissing(i):!1)?"Missing image":"Loading…";e.font="12px -apple-system, sans-serif",e.fillStyle=t.theme==="dark"?"#9ca3af":"#6b7280",e.textAlign="center",e.textBaseline="middle",e.fillText(c,o.x+o.width/2,o.y+o.height/2)}}class zs{constructor(t,e){m(this,"element");m(this,"canvas");m(this,"ctx");m(this,"imageCache");m(this,"doc",null);m(this,"region",[0,0,100,100]);m(this,"opts");m(this,"openLink");m(this,"ro");this.opts=e,this.element=t,t.classList.add("board-embed"),t.textContent="";const n=document.createElement("div");n.className="board-embed-frame",n.style.height=e.height+"px",this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),n.appendChild(this.canvas),t.appendChild(n);const s=document.createElement("a");s.className="board-embed-open";const i=e.region?`?region=${encodeURIComponent(e.region.join(","))}`:"";if(s.href=`#/root/${encodeURIComponent(e.rootId)}/boards/${encodeURIComponent(e.src)}${i}`,s.textContent="Open board →",this.openLink=s,n.appendChild(s),e.title){const a=document.createElement("figcaption");a.textContent=e.title,t.appendChild(a)}this.imageCache=new En(J,()=>this.render(),a=>k.assetUrl(this.opts.rootId,a)),this.ro=new ResizeObserver(()=>this.render()),this.ro.observe(n),this.load()}async load(){var t;try{const e=(t=this.opts.srcCandidates)!=null&&t.length?this.opts.srcCandidates:[this.opts.src];let n=null,s=this.opts.src;for(const a of e){const r=await k.getBoard(this.opts.rootId,a);if(n=r?ee(r):null,n){s=a;break}}if(!n)return this.renderError(`Board "${this.opts.src}" not found`);this.opts.src=s;const i=this.opts.region?`?region=${encodeURIComponent(this.opts.region.join(","))}`:"";this.openLink.href=`#/root/${encodeURIComponent(this.opts.rootId)}/boards/${encodeURIComponent(s)}${i}`,this.doc=n,this.region=this.opts.region??js(n.elements),this.render()}catch{this.renderError("Failed to load board")}}renderError(t){var n;(n=this.element.querySelector(".board-embed-frame"))==null||n.classList.add("error");const e=this.element.querySelector(".board-embed-frame");if(e){e.innerHTML="";const s=document.createElement("span");s.className="board-embed-msg",s.textContent=t,e.appendChild(s)}}render(){if(!this.doc)return;const t=this.canvas.parentElement,e=Math.max(1,t.clientWidth),n=Math.max(1,t.clientHeight),s=Math.max(1,window.devicePixelRatio||1);this.canvas.width=Math.round(e*s),this.canvas.height=Math.round(n*s),this.canvas.style.width=e+"px",this.canvas.style.height=n+"px";const i=this.ctx;i.setTransform(s,0,0,s,0,0),i.clearRect(0,0,e,n),i.fillStyle=this.opts.theme==="dark"?"#111315":"#f3f2f1",i.fillRect(0,0,e,n);const[a,r,c,l]=this.region;if(c<=0||l<=0)return;const d=Math.min(e/c,n/l),h=(e-c*d)/2-a*d,p=(n-l*d)/2-r*d;i.save(),i.translate(h,p),i.scale(d,d);const u={ctx:i,scale:d,lod:2,theme:this.opts.theme,imageCache:this.imageCache},g=Math.max(c,l)*.1;for(const y of[...this.doc.elements].sort((v,b)=>v.zIndex-b.zIndex))y.hidden||y.x+y.width<a-g||y.x>a+c+g||y.y+y.height<r-g||y.y>r+l+g||ne(y,u);i.restore()}destroy(){this.ro.disconnect(),this.imageCache.clear()}}function js(o){if(o.length===0)return[0,0,800,600];let t=1/0,e=1/0,n=-1/0,s=-1/0;for(const a of o)t=Math.min(t,a.x,a.x+a.width),e=Math.min(e,a.y,a.y+a.height),n=Math.max(n,a.x,a.x+a.width),s=Math.max(s,a.y,a.y+a.height);const i=40;return[t-i,e-i,n-t+i*2,s-e+i*2]}function Ft(){return document.documentElement.getAttribute("data-theme")==="dark"?"dark":"light"}function Fe(o,t,e){const{html:n,frontmatter:s}=Wt(t,e),i=document.createElement("article");i.className="markdown-body",i.innerHTML=n,o.replaceChildren(i);const a=[];return i.querySelectorAll("figure.board-embed").forEach(r=>{const c=r.dataset.src??"";if(!c)return;const l=Ut(c,e.docPath),d=l[0]??"",h=r.dataset.region??"",p=h?h.split(",").map(Number):[],u=p.length===4&&p.every(v=>Number.isFinite(v))?[p[0],p[1],p[2],p[3]]:null,g=parseInt(r.dataset.height??"360",10)||360,y=r.dataset.title||null;try{a.push(new zs(r,{rootId:e.rootId,src:d,srcCandidates:l,region:u,height:g,title:y,theme:Ft()}))}catch(v){console.error("Board embed failed to mount",c,v),r.textContent=`Could not load board "${c}".`}}),{frontmatter:s,destroy:()=>{for(const r of a)r.destroy()}}}const Hs=.05,Fs=40,Tn=1;function R(o,t,e){return{x:(o-e.offsetX)/e.scale,y:(t-e.offsetY)/e.scale}}function yt(o,t,e){return{x:o*e.scale+e.offsetX,y:t*e.scale+e.offsetY}}function Mn(o){return Math.min(Fs,Math.max(Hs,o))}function Ot(o,t,e,n){const s=Mn(n),i={x:(t-o.offsetX)/o.scale,y:(e-o.offsetY)/o.scale};o.scale=s,o.offsetX=t-i.x*o.scale,o.offsetY=e-i.y*o.scale}function Ws(o,t,e){const n=R(0,0,o),s=R(t,e,o);return{left:n.x,top:n.y,right:s.x,bottom:s.y}}class Os{constructor(){m(this,"boardId","default-board");m(this,"title","Untitled Board");m(this,"createdAt",Date.now());m(this,"viewport",{offsetX:0,offsetY:0,scale:Tn});m(this,"theme","light");m(this,"elements",[]);m(this,"elementsById",new Map);m(this,"selectedIds",new Set);m(this,"hoveredId",null);m(this,"sortedCache",null);m(this,"changeListeners",[]);m(this,"renderListeners",[])}onChange(t){this.changeListeners.push(t)}onRenderNeeded(t){this.renderListeners.push(t)}emitChange(){this.sortedCache=null;for(const t of this.changeListeners)t();this.requestRender()}requestRender(){for(const t of this.renderListeners)t()}addElement(t){this.elements.push(t),this.elementsById.set(t.id,t),this.sortedCache=null}removeElement(t){const e=this.elementsById.get(t);if(!e)return;this.elementsById.delete(t);const n=this.elements.indexOf(e);return n>=0&&this.elements.splice(n,1),this.selectedIds.delete(t),this.sortedCache=null,e}getSorted(){return this.sortedCache||(this.sortedCache=[...this.elements].sort((t,e)=>t.zIndex-e.zIndex)),this.sortedCache}invalidateSort(){this.sortedCache=null}maxZIndex(){let t=0;for(const e of this.elements)e.zIndex>t&&(t=e.zIndex);return t}minZIndex(){let t=0;for(const e of this.elements)e.zIndex<t&&(t=e.zIndex);return t}getSelected(){const t=[];for(const e of this.selectedIds){const n=this.elementsById.get(e);n&&t.push(n)}return t}clearSelection(){this.selectedIds.clear()}getVisibleElements(t){const e=[];for(const n of this.getSorted())n.hidden||Us(n,t)&&e.push(n);return e}}function Us(o,t){const e=Math.min(o.x,o.x+o.width),n=Math.max(o.x,o.x+o.width),s=Math.min(o.y,o.y+o.height),i=Math.max(o.y,o.y+o.height);return!(n<t.left||e>t.right||i<t.top||s>t.bottom)}const We=200;class _s{constructor(){m(this,"undoStack",[]);m(this,"redoStack",[])}execute(t,e,n){const s={id:Rt(),type:t,timestamp:Date.now(),do:e,undo:n};s.do(),this.undoStack.push(s),this.undoStack.length>We&&this.undoStack.shift(),this.redoStack.length=0}push(t,e,n){const s={id:Rt(),type:t,timestamp:Date.now(),do:e,undo:n};this.undoStack.push(s),this.undoStack.length>We&&this.undoStack.shift(),this.redoStack.length=0}undo(){const t=this.undoStack.pop();return t?(t.undo(),this.redoStack.push(t),!0):!1}redo(){const t=this.redoStack.pop();return t?(t.do(),this.undoStack.push(t),!0):!1}clear(){this.undoStack.length=0,this.redoStack.length=0}}class Xs{constructor(t,e){m(this,"state");m(this,"commands");this.state=t,this.commands=e}deleteSelection(){const t=this.state.getSelected().filter(s=>!s.locked);if(t.length===0)return;const e=this.state,n=t.map(s=>s);this.commands.execute("delete",()=>{for(const s of n)e.removeElement(s.id);e.emitChange()},()=>{for(const s of n)e.elementsById.has(s.id)||e.addElement(s);e.emitChange()})}duplicateSelection(t=24){const e=this.state.getSelected();if(e.length===0)return[];const n=e.map(s=>this.cloneElement(s,t));this.insertElements(n,"duplicate"),this.state.clearSelection();for(const s of n)this.state.selectedIds.add(s.id);return this.state.requestRender(),n}cloneElement(t,e){const n=Date.now();return{...t,id:Rt(),x:t.x+e,y:t.y+e,zIndex:this.state.maxZIndex()+1,createdAt:n,updatedAt:n,style:{...t.style},data:{...t.data}}}insertElements(t,e){const n=this.state;this.commands.execute(e,()=>{for(const s of t)n.elementsById.has(s.id)||n.addElement(s);n.emitChange()},()=>{for(const s of t)n.removeElement(s.id);n.emitChange()})}nudgeSelection(t,e){const n=this.state.getSelected().filter(c=>!c.locked);if(n.length===0)return;const s=this.state,i=n.map(c=>({id:c.id,x:c.x,y:c.y,updatedAt:c.updatedAt})),a=n.map(c=>({id:c.id,x:c.x+t,y:c.y+e,updatedAt:Date.now()})),r=c=>{for(const l of c){const d=s.elementsById.get(l.id);d&&(d.x=l.x,d.y=l.y,d.updatedAt=l.updatedAt)}s.emitChange()};this.commands.execute("nudge",()=>r(a),()=>r(i))}applyZChange(t){const e=this.state.getSelected();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,z:r.zIndex}));for(const r of e)t(r);n.invalidateSort();const i=e.map(r=>({id:r.id,z:r.zIndex})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.zIndex=c.z)}n.invalidateSort(),n.emitChange()};this.commands.push("layer",()=>a(i),()=>a(s)),n.emitChange()}bringForward(){this.applyZChange(t=>t.zIndex+=1)}sendBackward(){this.applyZChange(t=>t.zIndex-=1)}bringToFront(){let t=this.state.maxZIndex();this.applyZChange(e=>e.zIndex=++t)}sendToBack(){let t=this.state.minZIndex();this.applyZChange(e=>e.zIndex=--t)}}const qs=["image/png","image/jpeg","image/webp","image/gif"],Ys=5*1024*1024;class Ks{constructor(t,e,n,s,i){m(this,"state");m(this,"commands");m(this,"imageCache");m(this,"notify");m(this,"uploadImage");this.state=t,this.commands=e,this.imageCache=n,this.notify=s,this.uploadImage=i}async insertBlob(t,e,n,s){if(!qs.includes(t.type)){this.notify("Unsupported image type");return}t.size>Ys&&this.notify("Large image added — consider optimizing it for git");let i=0,a=0,r=null;try{r=await createImageBitmap(t),i=r.width,a=r.height}catch{this.notify("Could not decode image");return}const c={originalWidth:i,originalHeight:a,alt:s};if(this.uploadImage)try{const v=await this.uploadImage(t,s);c.src=v,r&&this.imageCache.setBySrc(v,r)}catch(v){this.notify("Failed to save image to disk"),console.error("Image upload failed",v);return}else try{const v=await J.createFromBlob(t,s);c.assetId=v.id,r&&this.imageCache.set(v.id,r)}catch(v){this.notify("Failed to store image (storage quota?)"),console.error("Asset store failed",v);return}const l=R(e,n,this.state.viewport),d=480/Math.min(1,this.state.viewport.scale);let h=i,p=a;const u=Math.max(h,p);if(u>d){const v=d/u;h*=v,p*=v}const g=A("image",{x:l.x-h/2,y:l.y-p/2,width:h,height:p,zIndex:this.state.maxZIndex()+1,data:c}),y=this.state;this.commands.execute("insert-image",()=>{y.elementsById.has(g.id)||y.addElement(g),y.emitChange()},()=>{y.removeElement(g.id),y.emitChange()}),y.clearSelection(),y.selectedIds.add(g.id),y.requestRender()}async insertFiles(t,e,n){let s=0;for(const i of Array.from(t))i.type.startsWith("image/")&&(await this.insertBlob(i,e+s,n+s,i.name),s+=24)}}class Vs{constructor(t,e,n,s){m(this,"state");m(this,"actions");m(this,"imageInsert");m(this,"internalClipboard",[]);m(this,"lastPointer",{x:window.innerWidth/2,y:window.innerHeight/2});this.state=t,this.actions=e,this.imageInsert=n,window.addEventListener("pointermove",i=>{this.lastPointer={x:i.clientX,y:i.clientY}},{signal:s}),window.addEventListener("paste",i=>{this.isEditingText(i.target)||this.handlePaste(i)},{signal:s}),window.addEventListener("copy",i=>{this.isEditingText(i.target)||this.copySelection()&&i.preventDefault()},{signal:s}),window.addEventListener("cut",i=>{this.isEditingText(i.target)||this.copySelection()&&(this.actions.deleteSelection(),i.preventDefault())},{signal:s})}isEditingText(t){const e=t;return!!e&&(e.tagName==="TEXTAREA"||e.tagName==="INPUT"||e.isContentEditable)}copySelection(){const t=this.state.getSelected();return t.length===0?!1:(this.internalClipboard=t.map(e=>({...e,style:{...e.style},data:{...e.data}})),!0)}async handlePaste(t){var s,i;const e=(s=t.clipboardData)==null?void 0:s.items;if(e){for(const a of e)if(a.type.startsWith("image/")){const r=a.getAsFile();if(r){t.preventDefault(),await this.imageInsert.insertBlob(r,this.lastPointer.x,this.lastPointer.y,"Pasted screenshot");return}}}if(this.internalClipboard.length>0){t.preventDefault(),this.pasteInternal();return}const n=(i=t.clipboardData)==null?void 0:i.getData("text/plain");n&&n.trim()&&(t.preventDefault(),this.pasteText(n.trim()))}pasteInternal(){const t=R(this.lastPointer.x,this.lastPointer.y,this.state.viewport);let e=1/0,n=1/0,s=-1/0,i=-1/0;for(const d of this.internalClipboard)e=Math.min(e,Math.min(d.x,d.x+d.width)),n=Math.min(n,Math.min(d.y,d.y+d.height)),s=Math.max(s,Math.max(d.x,d.x+d.width)),i=Math.max(i,Math.max(d.y,d.y+d.height));const a=(e+s)/2,r=(n+i)/2;let c=this.state.maxZIndex();const l=[];for(const d of this.internalClipboard){const h=yn(d);if(!h)continue;const p=this.actions.cloneElement(h,0);p.x=h.x+(t.x-a),p.y=h.y+(t.y-r),p.zIndex=++c,l.push(p)}if(l.length!==0){this.actions.insertElements(l,"paste"),this.state.clearSelection();for(const d of l)this.state.selectedIds.add(d.id);this.state.requestRender()}}pasteText(t){const e=R(this.lastPointer.x,this.lastPointer.y,this.state.viewport),n=A("text",{x:e.x,y:e.y,width:Math.min(420,Math.max(160,t.length*8)),height:28,zIndex:this.state.maxZIndex()+1,style:{fontSize:16,textColor:this.state.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:t.slice(0,5e3)}});this.actions.insertElements([n],"paste-text"),this.state.clearSelection(),this.state.selectedIds.add(n.id),this.state.requestRender()}}function Gs(o,t){const{state:e,commands:n,actions:s,toolController:i}=o;window.addEventListener("keydown",a=>{const r=a.target;if(r&&(r.tagName==="TEXTAREA"||r.tagName==="INPUT"||r.isContentEditable))return;const c=a.metaKey||a.ctrlKey,l=a.shiftKey?10:1;if(!c)switch(a.key){case"ArrowLeft":a.preventDefault(),s.nudgeSelection(-l,0);return;case"ArrowRight":a.preventDefault(),s.nudgeSelection(l,0);return;case"ArrowUp":a.preventDefault(),s.nudgeSelection(0,-l);return;case"ArrowDown":a.preventDefault(),s.nudgeSelection(0,l);return}if(c){switch(a.key.toLowerCase()){case"d":a.preventDefault(),s.duplicateSelection();return;case"z":a.preventDefault(),a.shiftKey?n.redo():n.undo();return;case"]":a.preventDefault(),a.shiftKey?s.bringToFront():s.bringForward();return;case"[":a.preventDefault(),a.shiftKey?s.sendToBack():s.sendBackward();return;case"=":case"+":a.preventDefault(),Ot(e.viewport,window.innerWidth/2,window.innerHeight/2,e.viewport.scale*1.2),e.requestRender();return;case"-":a.preventDefault(),Ot(e.viewport,window.innerWidth/2,window.innerHeight/2,e.viewport.scale/1.2),e.requestRender();return;case"0":a.preventDefault(),o.resetView();return;case"a":a.preventDefault(),e.clearSelection();for(const d of e.elements)!d.locked&&!d.hidden&&e.selectedIds.add(d.id);e.requestRender();return}return}switch(a.key){case"Delete":case"Backspace":a.preventDefault(),s.deleteSelection();return;case"Escape":i.cancel(),i.setTool("select");return}switch(a.key.toLowerCase()){case"v":i.setTool("select");return;case"h":i.setTool("hand");return;case"s":i.setTool("sticky");return;case"r":i.setTool("rectangle");return;case"o":i.setTool("ellipse");return;case"t":i.setTool("text");return;case"a":i.setTool("arrow");return;case"i":i.setTool("image");return}},{signal:t})}function Zs(o){if(o.elements.length===0)return null;let t=1/0,e=1/0,n=-1/0,s=-1/0;for(const a of o.elements)a.hidden||(t=Math.min(t,Math.min(a.x,a.x+a.width)),e=Math.min(e,Math.min(a.y,a.y+a.height)),n=Math.max(n,Math.max(a.x,a.x+a.width)),s=Math.max(s,Math.max(a.y,a.y+a.height)));if(!Number.isFinite(t))return null;const i=48;return{x:t-i,y:e-i,w:n-t+i*2,h:s-e+i*2}}function Bn(o,t,e,n){let i=Math.round(e.w*n),a=Math.round(e.h*n);if(i>8192||a>8192){const h=8192/Math.max(i,a);n*=h,i=Math.round(e.w*n),a=Math.round(e.h*n)}const r=document.createElement("canvas");r.width=Math.max(1,i),r.height=Math.max(1,a);const c=r.getContext("2d"),l=o.theme==="dark"?"#111315":"#f3f2f1";c.fillStyle=l,c.fillRect(0,0,r.width,r.height),c.scale(n,n),c.translate(-e.x,-e.y);const d=o.getSorted();for(const h of d)h.hidden||Math.max(h.x,h.x+h.width)<e.x||Math.min(h.x,h.x+h.width)>e.x+e.w||Math.max(h.y,h.y+h.height)<e.y||Math.min(h.y,h.y+h.height)>e.y+e.h||ne(h,{ctx:c,scale:n,lod:2,theme:o.theme,imageCache:t});return r}function In(o){return new Promise((t,e)=>{o.toBlob(n=>{n?t(n):e(new Error("PNG encode failed"))},"image/png")})}async function Js(o,t,e,n){const s=o.viewport,i={x:-s.offsetX/s.scale,y:-s.offsetY/s.scale,w:e/s.scale,h:n/s.scale},a=Bn(o,t,i,s.scale);return In(a)}async function Qs(o,t){const e=Zs(o);if(!e)return null;const n=Bn(o,t,e,1);return In(n)}function Oe(o,t){const e=URL.createObjectURL(o),n=document.createElement("a");n.href=e,n.download=t,n.click(),URL.revokeObjectURL(e)}class Be{constructor(t,e){m(this,"overlay");m(this,"rectEl");m(this,"abort",new AbortController);m(this,"start",null);m(this,"onComplete");m(this,"done",!1);this.onComplete=e,this.overlay=document.createElement("div"),this.overlay.className="embed-select-overlay";const n=document.createElement("div");n.className="embed-select-hint",n.textContent="Drag to select the area to embed · Esc to cancel",this.overlay.appendChild(n),this.rectEl=document.createElement("div"),this.rectEl.className="embed-select-rect",this.rectEl.style.display="none",this.overlay.appendChild(this.rectEl),t.appendChild(this.overlay);const s=this.abort.signal;this.overlay.addEventListener("pointerdown",i=>this.onDown(i),{signal:s}),this.overlay.addEventListener("pointermove",i=>this.onMove(i),{signal:s}),this.overlay.addEventListener("pointerup",i=>this.onUp(i),{signal:s}),window.addEventListener("keydown",i=>{i.key==="Escape"&&(i.preventDefault(),this.finish(null))},{signal:s})}static begin(t,e){new Be(t,e)}onDown(t){t.preventDefault(),this.start={x:t.clientX,y:t.clientY},this.rectEl.style.display="block",this.draw(t.clientX,t.clientY),this.overlay.setPointerCapture(t.pointerId)}onMove(t){this.start&&this.draw(t.clientX,t.clientY)}onUp(t){if(!this.start)return;const e=this.rectFrom(t.clientX,t.clientY);if(e.w<8||e.h<8){this.finish(null);return}this.finish(e)}rectFrom(t,e){const n=this.start;return{x:Math.min(n.x,t),y:Math.min(n.y,e),w:Math.abs(t-n.x),h:Math.abs(e-n.y)}}draw(t,e){const n=this.rectFrom(t,e);this.rectEl.style.left=`${n.x}px`,this.rectEl.style.top=`${n.y}px`,this.rectEl.style.width=`${n.w}px`,this.rectEl.style.height=`${n.h}px`}finish(t){this.done||(this.done=!0,this.abort.abort(),this.overlay.remove(),this.onComplete(t))}}class to{constructor(t,e=3,n){m(this,"container");m(this,"layers",[]);m(this,"contexts",[]);m(this,"width",0);m(this,"height",0);m(this,"dpr",1);m(this,"resizeListeners",[]);this.container=document.createElement("div"),this.container.className="canvas-stack",t.appendChild(this.container);for(let s=0;s<e;s++){const i=document.createElement("canvas"),a=i.getContext("2d",{alpha:s!==0});this.container.appendChild(i),this.layers.push(i),this.contexts.push(a)}this.resize(),window.addEventListener("resize",()=>{this.resize();for(const s of this.resizeListeners)s()},{signal:n})}get interactionLayer(){return this.layers[this.layers.length-1]}onResize(t){this.resizeListeners.push(t)}resize(){this.dpr=Math.max(1,window.devicePixelRatio||1),this.width=window.innerWidth,this.height=window.innerHeight;for(const t of this.layers)t.width=Math.round(this.width*this.dpr),t.height=Math.round(this.height*this.dpr),t.style.width=this.width+"px",t.style.height=this.height+"px"}beginLayer(t){const e=this.contexts[t];return e.setTransform(this.dpr,0,0,this.dpr,0,0),e.clearRect(0,0,this.width,this.height),e}}class eo{constructor(t,e,n){m(this,"surface");m(this,"state");m(this,"imageCache");m(this,"overlay",{marquee:null,preview:null});m(this,"lastRenderMs",0);m(this,"visibleCount",0);m(this,"cullingEnabled",!0);m(this,"lodEnabled",!0);this.surface=t,this.state=e,this.imageCache=n}getLod(){if(!this.lodEnabled)return 2;const t=this.state.viewport.scale;return t<.1?0:t<.25?1:2}render(){const t=performance.now();this.renderGrid(),this.renderObjects(),this.renderOverlay(),this.lastRenderMs=performance.now()-t}renderGrid(){const{surface:t,state:e}=this,n=t.beginLayer(0),s=e.viewport,i=getComputedStyle(document.documentElement).getPropertyValue("--bg-canvas").trim(),a=getComputedStyle(document.documentElement).getPropertyValue("--grid-dot").trim();n.fillStyle=i||"#f3f2f1",n.fillRect(0,0,t.width,t.height);let c=32*s.scale;if(!Number.isFinite(c)||c<=0)return;for(;c<16;)c*=2;for(;c>64;)c/=2;if(c<4)return;const l=(s.offsetX%c+c)%c,d=(s.offsetY%c+c)%c,h=Math.min(1.5,Math.max(.75,s.scale*.9));n.fillStyle=a||"rgba(0,0,0,0.14)",n.beginPath();for(let p=l;p<t.width;p+=c)for(let u=d;u<t.height;u+=c)n.moveTo(p+h,u),n.arc(p,u,h,0,Math.PI*2);n.fill()}renderObjects(){const{surface:t,state:e}=this,n=t.beginLayer(1),s=e.viewport;n.translate(s.offsetX,s.offsetY),n.scale(s.scale,s.scale);const i=Ws(s,t.width,t.height),a=this.cullingEnabled?e.getVisibleElements(i):e.getSorted().filter(c=>!c.hidden);this.visibleCount=a.length;const r={ctx:n,scale:s.scale,lod:this.getLod(),theme:e.theme,imageCache:this.imageCache};for(const c of a)ne(c,r)}renderOverlay(){const{surface:t,state:e}=this,n=t.beginLayer(2),s=e.viewport,i=getComputedStyle(document.documentElement).getPropertyValue("--selection").trim()||"#6e6e6e";if(e.hoveredId&&!e.selectedIds.has(e.hoveredId)){const r=e.elementsById.get(e.hoveredId);if(r){const c=this.elementScreenBBox(r);n.strokeStyle=i,n.globalAlpha=.45,n.lineWidth=1.5,n.strokeRect(c.x,c.y,c.w,c.h),n.globalAlpha=1}}const a=e.getSelected();if(a.length>0){n.strokeStyle=i,n.lineWidth=1.5;let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const p of a){const u=this.elementScreenBBox(p);n.strokeRect(u.x,u.y,u.w,u.h),r=Math.min(r,u.x),c=Math.min(c,u.y),l=Math.max(l,u.x+u.w),d=Math.max(d,u.y+u.h)}a.length>1&&(n.setLineDash([4,4]),n.strokeRect(r-4,c-4,l-r+8,d-c+8),n.setLineDash([]));const h=a.length===1?this.elementScreenBBox(a[0]):{x:r,y:c,w:l-r,h:d-c};this.drawHandles(n,h,i)}if(this.overlay.marquee){const r=this.overlay.marquee;n.fillStyle=i+"22",n.strokeStyle=i,n.lineWidth=1,n.fillRect(r.x,r.y,r.w,r.h),n.strokeRect(r.x,r.y,r.w,r.h)}this.overlay.preview&&(n.save(),n.translate(s.offsetX,s.offsetY),n.scale(s.scale,s.scale),n.globalAlpha=.8,ne(this.overlay.preview,{ctx:n,scale:s.scale,lod:2,theme:e.theme,imageCache:this.imageCache}),n.restore())}elementScreenBBox(t){const e=this.state.viewport,n=Math.min(t.x,t.x+t.width),s=Math.min(t.y,t.y+t.height),i=Math.max(t.x,t.x+t.width),a=Math.max(t.y,t.y+t.height),r=yt(n,s,e),c=yt(i,a,e);return{x:r.x,y:r.y,w:c.x-r.x,h:c.y-r.y}}drawHandles(t,e,n){const a=Ln(e);t.fillStyle=getComputedStyle(document.documentElement).getPropertyValue("--bg-panel").trim()||"#fff",t.strokeStyle=n,t.lineWidth=1.5;for(const r of a)t.beginPath(),t.rect(r.x-4,r.y-4,8,8),t.fill(),t.stroke()}}function Ln(o){const{x:t,y:e,w:n,h:s}=o;return[{id:"nw",x:t,y:e},{id:"n",x:t+n/2,y:e},{id:"ne",x:t+n,y:e},{id:"e",x:t+n,y:e+s/2},{id:"se",x:t+n,y:e+s},{id:"s",x:t+n/2,y:e+s},{id:"sw",x:t,y:e+s},{id:"w",x:t,y:e+s/2}]}class no{constructor(t){m(this,"rafId",null);m(this,"renderFn");this.renderFn=t}requestRender(){this.rafId===null&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null,this.renderFn()}))}cancel(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}}function so(o,t,e,n,s,i){const a=s-e,r=i-n,c=a*a+r*r;if(c===0)return Math.hypot(o-e,t-n);let l=((o-e)*a+(t-n)*r)/c;return l=Math.max(0,Math.min(1,l)),Math.hypot(o-(e+l*a),t-(n+l*r))}class oo{constructor(t){m(this,"state");m(this,"lastHitTestMs",0);this.state=t}hitTest(t,e,n){const s=performance.now(),i=this.state.getSorted(),a=6/n;let r=null;for(let c=i.length-1;c>=0;c--){const l=i[c];if(!(l.hidden||l.locked)&&this.hitsElement(l,t,e,a)){r=l;break}}return this.lastHitTestMs=performance.now()-s,r}hitsElement(t,e,n,s){if(t.type==="line"||t.type==="arrow"||t.type==="connector")return so(e,n,t.x,t.y,t.x+t.width,t.y+t.height)<=Math.max(s,(t.style.strokeWidth??2)/2+s);const i=Math.min(t.x,t.x+t.width),a=Math.max(t.x,t.x+t.width),r=Math.min(t.y,t.y+t.height),c=Math.max(t.y,t.y+t.height);if(e<i||e>a||n<r||n>c)return!1;if(t.type==="ellipse"){const l=(i+a)/2,d=(r+c)/2,h=(a-i)/2,p=(c-r)/2;if(h===0||p===0)return!1;const u=(e-l)/h,g=(n-d)/p;return u*u+g*g<=1}return!0}elementsInRect(t,e,n,s){const i=Math.min(t,t+n),a=Math.max(t,t+n),r=Math.min(e,e+s),c=Math.max(e,e+s),l=[];for(const d of this.state.elements){if(d.hidden||d.locked)continue;const h=Math.min(d.x,d.x+d.width),p=Math.max(d.x,d.x+d.width),u=Math.min(d.y,d.y+d.height),g=Math.max(d.y,d.y+d.height);h>=i&&p<=a&&u>=r&&g<=c&&l.push(d)}return l}}class io{constructor(){m(this,"fps",0);m(this,"frameCount",0);m(this,"lastSample",performance.now());m(this,"running",!1)}start(){if(this.running)return;this.running=!0;const t=()=>{if(!this.running)return;this.frameCount++;const e=performance.now(),n=e-this.lastSample;n>=1e3&&(this.fps=Math.round(this.frameCount*1e3/n),this.frameCount=0,this.lastSample=e),requestAnimationFrame(t)};requestAnimationFrame(t)}stop(){this.running=!1}}const ao=16,ro=720,Ue=120,co=.0032;class lo{constructor(t,e,n,s){m(this,"tools",new Map);m(this,"active");m(this,"ctx");m(this,"target");m(this,"spaceDown",!1);m(this,"tempPanning",!1);m(this,"panLast",{x:0,y:0});m(this,"toolChangeListeners",[]);m(this,"signal");this.target=t,this.ctx=e,this.signal=s;for(const i of n)this.tools.set(i.name,i);this.active=this.tools.get("select"),this.bindEvents()}get activeName(){return this.active.name}onToolChange(t){this.toolChangeListeners.push(t)}setTool(t){var n,s,i,a,r;if(this.active.name===t){(s=(n=this.active).onActivate)==null||s.call(n,this.ctx);return}(a=(i=this.active).onDeactivate)==null||a.call(i,this.ctx);const e=this.tools.get(t);if(e){this.active=e,this.ctx.setCursor(e.cursor),(r=e.onActivate)==null||r.call(e,this.ctx);for(const c of this.toolChangeListeners)c(t)}}cancel(){var t,e;(e=(t=this.active).onCancel)==null||e.call(t,this.ctx)}bindEvents(){const t=this.target;t.addEventListener("pointerdown",e=>{if(e.button===1||e.button===2||this.spaceDown){e.preventDefault(),this.tempPanning=!0,this.panLast={x:e.clientX,y:e.clientY},this.ctx.setCursor("grabbing"),t.setPointerCapture(e.pointerId);return}e.button===0&&(t.setPointerCapture(e.pointerId),this.active.onPointerDown(e,this.ctx))}),t.addEventListener("pointermove",e=>{if(this.tempPanning){const n=this.ctx.state.viewport;n.offsetX+=e.clientX-this.panLast.x,n.offsetY+=e.clientY-this.panLast.y,this.panLast={x:e.clientX,y:e.clientY},this.ctx.state.requestRender();return}this.active.onPointerMove(e,this.ctx)}),t.addEventListener("pointerup",e=>{if(this.tempPanning){this.tempPanning=!1,this.ctx.setCursor(this.spaceDown?"grab":this.active.cursor);return}this.active.onPointerUp(e,this.ctx)}),t.addEventListener("pointercancel",()=>{this.tempPanning&&(this.tempPanning=!1,this.ctx.setCursor(this.spaceDown?"grab":this.active.cursor))}),t.addEventListener("dblclick",e=>{var n,s;(s=(n=this.active).onDoubleClick)==null||s.call(n,e,this.ctx)}),t.addEventListener("wheel",e=>{e.preventDefault();const n=this.ctx.state.viewport,s=_e(e.deltaX,e.deltaMode,this.ctx.state.viewport.scale),i=_e(e.deltaY,e.deltaMode,this.ctx.state.viewport.scale);if(e.ctrlKey||e.metaKey){const a=Math.exp(-ho(i)*co);Ot(n,e.clientX,e.clientY,n.scale*a)}else e.shiftKey&&Math.abs(s)<Math.abs(i)?n.offsetX-=i:(n.offsetX-=s,n.offsetY-=i);this.ctx.state.requestRender()},{passive:!1}),window.addEventListener("keydown",e=>{e.code==="Space"&&!this.isEditingText(e)&&(this.spaceDown||(this.spaceDown=!0,this.tempPanning||this.ctx.setCursor("grab")),e.preventDefault())},{signal:this.signal}),window.addEventListener("keyup",e=>{e.code==="Space"&&(this.spaceDown=!1,this.tempPanning||this.ctx.setCursor(this.active.cursor))},{signal:this.signal}),t.addEventListener("contextmenu",e=>e.preventDefault())}isEditingText(t){const e=t.target;return!!e&&(e.tagName==="TEXTAREA"||e.tagName==="INPUT"||e.isContentEditable)}}function _e(o,t,e){const s=o*(t===1?ao:t===2?ro:1),i=e<.5?.8:e>2?1.08:1;return s*i}function ho(o){return Math.max(-Ue,Math.min(Ue,o))}const Yt=7,po={nw:"nwse-resize",n:"ns-resize",ne:"nesw-resize",e:"ew-resize",se:"nwse-resize",s:"ns-resize",sw:"nesw-resize",w:"ew-resize"};class uo{constructor(){m(this,"name","select");m(this,"cursor","default");m(this,"mode","none");m(this,"startScreen",{x:0,y:0});m(this,"startWorld",{x:0,y:0});m(this,"snapshots",[]);m(this,"activeHandle",null);m(this,"endpointIsStart",!1);m(this,"moved",!1);m(this,"pointerDownHitId",null)}onPointerDown(t,e){const{state:n,hitTester:s,renderer:i}=e;this.startScreen={x:t.clientX,y:t.clientY},this.startWorld=R(t.clientX,t.clientY,n.viewport),this.moved=!1;const a=this.hitHandle(t,e);if(a){this.mode="resize",this.activeHandle=a,this.takeSnapshots(n.getSelected());return}const r=n.getSelected();if(r.length===1&&this.isLinear(r[0])){const l=this.hitEndpoint(t,r[0],e);if(l!==null){this.mode="endpoint",this.endpointIsStart=l,this.takeSnapshots(r);return}}const c=s.hitTest(this.startWorld.x,this.startWorld.y,n.viewport.scale);if(c){this.pointerDownHitId=c.id,t.shiftKey?n.selectedIds.has(c.id)?n.selectedIds.delete(c.id):n.selectedIds.add(c.id):n.selectedIds.has(c.id)||(n.clearSelection(),n.selectedIds.add(c.id)),this.mode="move",this.takeSnapshots(n.getSelected()),n.requestRender();return}t.shiftKey||n.clearSelection(),this.mode="marquee",i.overlay.marquee={x:t.clientX,y:t.clientY,w:0,h:0},n.requestRender()}onPointerMove(t,e){const{state:n,renderer:s,hitTester:i}=e;if(this.mode==="none"){const d=this.hitHandle(t,e);if(d){e.setCursor(po[d]);return}const h=R(t.clientX,t.clientY,n.viewport),p=i.hitTest(h.x,h.y,n.viewport.scale),u=p?p.id:null;e.setCursor(p?"move":"default"),u!==n.hoveredId&&(n.hoveredId=u,n.requestRender());return}const a=t.clientX-this.startScreen.x,r=t.clientY-this.startScreen.y;Math.abs(a)+Math.abs(r)>2&&(this.moved=!0);const c=a/n.viewport.scale,l=r/n.viewport.scale;if(this.mode==="move"){for(const d of this.snapshots){const h=n.elementsById.get(d.id);!h||h.locked||(h.x=d.x+c,h.y=d.y+l)}n.requestRender()}else if(this.mode==="marquee")s.overlay.marquee={x:this.startScreen.x,y:this.startScreen.y,w:a,h:r},n.requestRender();else if(this.mode==="resize"&&this.activeHandle)this.applyResize(c,l,t.shiftKey,e),n.requestRender();else if(this.mode==="endpoint"){const d=this.snapshots[0],h=n.elementsById.get(d.id);h&&(this.endpointIsStart?(h.x=d.x+c,h.y=d.y+l,h.width=d.width-c,h.height=d.height-l):(h.width=d.width+c,h.height=d.height+l)),n.requestRender()}}onPointerUp(t,e){const{state:n,renderer:s,hitTester:i,commands:a}=e;if(this.mode==="marquee"){const r=s.overlay.marquee;if(s.overlay.marquee=null,r&&(Math.abs(r.w)>3||Math.abs(r.h)>3)){const c=R(r.x,r.y,n.viewport),l=R(r.x+r.w,r.y+r.h,n.viewport),d=i.elementsInRect(c.x,c.y,l.x-c.x,l.y-c.y);for(const h of d)n.selectedIds.add(h.id)}n.requestRender()}else if((this.mode==="move"||this.mode==="resize"||this.mode==="endpoint")&&this.moved){const r=this.snapshots,c=r.map(d=>{const h=n.elementsById.get(d.id);return{id:d.id,x:h.x,y:h.y,width:h.width,height:h.height}}),l=d=>{for(const h of d){const p=n.elementsById.get(h.id);p&&(p.x=h.x,p.y=h.y,p.width=h.width,p.height=h.height,p.updatedAt=Date.now(),F(p.id))}n.emitChange()};for(const d of c){const h=n.elementsById.get(d.id);h&&(h.updatedAt=Date.now(),F(h.id))}a.push(this.mode,()=>l(c),()=>l(r)),n.emitChange()}else this.mode==="move"&&!this.moved&&this.toggleTaskIfCheckboxClick(t,e);this.mode="none",this.activeHandle=null,this.snapshots=[],this.pointerDownHitId=null}onDoubleClick(t,e){const{state:n,hitTester:s}=e,i=R(t.clientX,t.clientY,n.viewport),a=s.hitTest(i.x,i.y,n.viewport.scale);a&&(a.type==="sticky"||a.type==="task"||a.type==="text"||a.type==="rectangle"||a.type==="ellipse"||a.type==="frame"||a.type==="arrow"||a.type==="line"||a.type==="connector")&&e.openTextEditor(a)}onCancel(t){if(this.mode!=="none"&&this.snapshots.length>0)for(const e of this.snapshots){const n=t.state.elementsById.get(e.id);n&&(n.x=e.x,n.y=e.y,n.width=e.width,n.height=e.height)}t.renderer.overlay.marquee=null,this.mode="none",t.state.clearSelection(),t.state.requestRender()}isLinear(t){return t.type==="line"||t.type==="arrow"||t.type==="connector"}takeSnapshots(t){this.snapshots=t.map(e=>({id:e.id,x:e.x,y:e.y,width:e.width,height:e.height}))}toggleTaskIfCheckboxClick(t,e){const{state:n,hitTester:s,commands:i}=e,a=R(t.clientX,t.clientY,n.viewport),r=s.hitTest(a.x,a.y,n.viewport.scale);if(!r||r.id!==this.pointerDownHitId||r.type!=="task"||!this.hitTaskCheckbox(a.x,a.y,r))return;const c=r.data.checked===!0,l=!c,d=r.id,h=p=>{const u=n.elementsById.get(d);u&&(u.data.checked=p,u.updatedAt=Date.now(),n.emitChange())};i.execute("toggle-task",()=>h(l),()=>h(c))}hitTaskCheckbox(t,e,n){const s=Math.min(22,Math.max(16,n.height*.38)),i=n.x+16,a=n.y+n.height/2-s/2,r=8;return t>=i-r&&t<=i+s+r&&e>=a-r&&e<=a+s+r}hitHandle(t,e){const{state:n,renderer:s}=e,i=n.getSelected();if(i.length===0||i.length===1&&this.isLinear(i[0]))return null;let a;if(i.length===1)a=s.elementScreenBBox(i[0]);else{let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const h of i){const p=s.elementScreenBBox(h);r=Math.min(r,p.x),c=Math.min(c,p.y),l=Math.max(l,p.x+p.w),d=Math.max(d,p.y+p.h)}a={x:r,y:c,w:l-r,h:d-c}}for(const r of Ln(a))if(Math.abs(t.clientX-r.x)<=Yt&&Math.abs(t.clientY-r.y)<=Yt)return r.id;return null}hitEndpoint(t,e,n){const s=n.state.viewport,i=e.x*s.scale+s.offsetX,a=e.y*s.scale+s.offsetY,r=(e.x+e.width)*s.scale+s.offsetX,c=(e.y+e.height)*s.scale+s.offsetY;return Math.hypot(t.clientX-i,t.clientY-a)<=Yt+2?!0:Math.hypot(t.clientX-r,t.clientY-c)<=Yt+2?!1:null}applyResize(t,e,n,s){const{state:i}=s,a=this.activeHandle;let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const C of this.snapshots)r=Math.min(r,Math.min(C.x,C.x+C.width)),c=Math.min(c,Math.min(C.y,C.y+C.height)),l=Math.max(l,Math.max(C.x,C.x+C.width)),d=Math.max(d,Math.max(C.y,C.y+C.height));const h=l-r,p=d-c;if(h===0||p===0)return;let u=r,g=c,y=h,v=p;if(a.includes("e")&&(y=h+t),a.includes("w")&&(u=r+t,y=h-t),a.includes("s")&&(v=p+e),a.includes("n")&&(g=c+e,v=p-e),n&&(a==="nw"||a==="ne"||a==="se"||a==="sw")){const C=h/p;if(Math.abs(y/h)>Math.abs(v/p)){const E=y/C;a.includes("n")&&(g=g+(v-E)),v=E}else{const E=v*C;a.includes("w")&&(u=u+(y-E)),y=E}}const b=4;if(Math.abs(y)<b||Math.abs(v)<b)return;const x=y/h,S=v/p;for(const C of this.snapshots){const E=i.elementsById.get(C.id);!E||E.locked||(E.x=u+(C.x-r)*x,E.y=g+(C.y-c)*S,E.width=C.width*x,E.height=C.height*S,E.updatedAt=Date.now(),F(E.id))}}}class mo{constructor(){m(this,"name","hand");m(this,"cursor","grab");m(this,"panning",!1);m(this,"last",{x:0,y:0})}onPointerDown(t,e){this.panning=!0,this.last={x:t.clientX,y:t.clientY},e.setCursor("grabbing")}onPointerMove(t,e){if(!this.panning)return;const n=e.state.viewport;n.offsetX+=t.clientX-this.last.x,n.offsetY+=t.clientY-this.last.y,this.last={x:t.clientX,y:t.clientY},e.state.requestRender()}onPointerUp(t,e){this.panning=!1,e.setCursor("grab")}onCancel(t){this.panning=!1,t.setCursor("grab")}}const se=["#fef08a","#fdba74","#fca5a5","#f9a8d4","#d8b4fe","#a5b4fc","#93c5fd","#86efac"];let Rn=se[0];function fo(){return Rn}function go(o){Rn=o}class yo{constructor(){m(this,"name","sticky");m(this,"cursor","crosshair")}onPointerDown(t,e){const{state:n,commands:s}=e,i=R(t.clientX,t.clientY,n.viewport),a=A("sticky",{x:i.x-110,y:i.y-80,width:220,height:160,zIndex:n.maxZIndex()+1,style:{fill:fo(),borderRadius:12,shadow:!0,fontSize:15,textColor:"#1f2933"},data:{text:""}});s.execute("create-sticky",()=>{n.elementsById.has(a.id)||n.addElement(a),n.emitChange()},()=>{n.removeElement(a.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(a.id),e.setTool("select"),e.openTextEditor(a)}onPointerMove(t,e){}onPointerUp(t,e){}}class vo{constructor(){m(this,"name","task");m(this,"cursor","crosshair")}onPointerDown(t,e){const{state:n,commands:s}=e,i=R(t.clientX,t.clientY,n.viewport),a=n.theme==="dark",r=A("task",{x:i.x-140,y:i.y-28,width:280,height:56,zIndex:n.maxZIndex()+1,style:{fill:a?"#17191b":"#ffffff",stroke:a?"rgba(255,255,255,0.12)":"rgba(0,0,0,0.09)",strokeWidth:1,borderRadius:14,shadow:!0,fontSize:15,fontWeight:"650",textColor:a?"#f6f6f3":"#252829"},data:{text:"Task title",checked:!1}});s.execute("create-task",()=>{n.elementsById.has(r.id)||n.addElement(r),n.emitChange()},()=>{n.removeElement(r.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(r.id),e.setTool("select"),e.openTextEditor(r)}onPointerMove(t,e){}onPointerUp(t,e){}}class Q{constructor(t){m(this,"name");m(this,"cursor","crosshair");m(this,"shapeType");m(this,"shapeKind");m(this,"drawing",!1);m(this,"startWorld",{x:0,y:0});m(this,"preview",null);this.name=t,this.shapeKind=t,this.shapeType=t==="ellipse"?"ellipse":"rectangle"}onPointerDown(t,e){const{state:n}=e;this.drawing=!0,this.startWorld=R(t.clientX,t.clientY,n.viewport);const s=n.theme==="dark",i=!["rectangle","ellipse","pill","cylinder"].includes(this.shapeKind);this.preview=A(this.shapeType,{x:this.startWorld.x,y:this.startWorld.y,width:0,height:0,zIndex:n.maxZIndex()+1,style:{fill:i?"#0078d4":s?"#2a2d33":"#ffffff",stroke:i?"#495057":s?"#9ca3af":"#374151",strokeWidth:i?0:1.5,borderRadius:this.shapeKind==="pill"?999:this.shapeKind==="rectangle"?8:0,fontSize:14,textColor:i?"#ffffff":s?"#f2f2f2":"#1f2933"},data:{text:"",shapeKind:this.shapeKind}}),e.renderer.overlay.preview=this.preview}onPointerMove(t,e){if(!this.drawing||!this.preview)return;const n=R(t.clientX,t.clientY,e.state.viewport);let s=n.x-this.startWorld.x,i=n.y-this.startWorld.y;if(t.shiftKey){const a=Math.max(Math.abs(s),Math.abs(i));s=Math.sign(s||1)*a,i=Math.sign(i||1)*a}this.preview.x=Math.min(this.startWorld.x,this.startWorld.x+s),this.preview.y=Math.min(this.startWorld.y,this.startWorld.y+i),this.preview.width=Math.abs(s),this.preview.height=Math.abs(i),e.state.requestRender()}onPointerUp(t,e){const{state:n,commands:s}=e;if(!this.drawing||!this.preview)return;this.drawing=!1,e.renderer.overlay.preview=null;const i=this.preview;this.preview=null,(i.width<4||i.height<4)&&(i.width=this.shapeKind==="chevron"?210:160,i.height=this.shapeKind==="chevron"?76:100,i.x-=i.width/2,i.y-=i.height/2),s.execute("create-shape",()=>{n.elementsById.has(i.id)||n.addElement(i),n.emitChange()},()=>{n.removeElement(i.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(i.id),e.setTool("select")}onCancel(t){this.drawing=!1,this.preview=null,t.renderer.overlay.preview=null,t.state.requestRender()}}class bo{constructor(){m(this,"name","text");m(this,"cursor","text")}onPointerDown(t,e){const{state:n,commands:s}=e,i=R(t.clientX,t.clientY,n.viewport),a=A("text",{x:i.x,y:i.y-12,width:240,height:28,zIndex:n.maxZIndex()+1,style:{fontSize:16,textColor:n.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:""}});s.execute("create-text",()=>{n.elementsById.has(a.id)||n.addElement(a),n.emitChange()},()=>{n.removeElement(a.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(a.id),e.setTool("select"),e.openTextEditor(a)}onPointerMove(t,e){}onPointerUp(t,e){}}class At{constructor(t="arrow"){m(this,"name");m(this,"cursor","crosshair");m(this,"drawing",!1);m(this,"startWorld",{x:0,y:0});m(this,"preview",null);this.name=t}onPointerDown(t,e){const{state:n}=e;this.drawing=!0,this.startWorld=R(t.clientX,t.clientY,n.viewport),this.preview=A("arrow",{x:this.startWorld.x,y:this.startWorld.y,width:0,height:0,zIndex:n.maxZIndex()+1,style:{stroke:n.theme==="dark"?"#d1d5db":"#374151",strokeWidth:2,arrowEnd:!0,arrowStart:this.name==="twoWayArrow",strokeDash:this.name==="dashedArrow"||t.altKey?[8,6]:void 0},data:{text:"",labelPosition:this.name==="sidedLabelArrow"?"sides":"center"}}),e.renderer.overlay.preview=this.preview}onPointerMove(t,e){if(!this.drawing||!this.preview)return;const n=R(t.clientX,t.clientY,e.state.viewport);let s=n.x-this.startWorld.x,i=n.y-this.startWorld.y;if(t.shiftKey){const a=Math.atan2(i,s),r=Math.round(a/(Math.PI/4))*(Math.PI/4),c=Math.hypot(s,i);s=Math.cos(r)*c,i=Math.sin(r)*c}this.preview.width=s,this.preview.height=i,e.state.requestRender()}onPointerUp(t,e){const{state:n,commands:s}=e;if(!this.drawing||!this.preview)return;this.drawing=!1,e.renderer.overlay.preview=null;const i=this.preview;if(this.preview=null,Math.hypot(i.width,i.height)<8){n.requestRender();return}s.execute("create-arrow",()=>{n.elementsById.has(i.id)||n.addElement(i),n.emitChange()},()=>{n.removeElement(i.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(i.id),e.setTool("select"),(this.name==="labeledArrow"||this.name==="sidedLabelArrow")&&e.openTextEditor(i)}onCancel(t){this.drawing=!1,this.preview=null,t.renderer.overlay.preview=null,t.state.requestRender()}}class wo{constructor(t){m(this,"name","image");m(this,"cursor","default");m(this,"onInsert");this.onInsert=t}onActivate(t){const e=document.createElement("input");e.type="file",e.accept="image/png,image/jpeg,image/webp,image/gif",e.multiple=!0,e.onchange=()=>{e.files&&e.files.length>0&&this.onInsert(e.files,window.innerWidth/2,window.innerHeight/2),t.setTool("select")},e.oncancel=()=>t.setTool("select"),e.click()}onPointerDown(t,e){}onPointerMove(t,e){}onPointerUp(t,e){}}const Kt="psc:";class xo{constructor(){m(this,"lastSaveMs",0)}async saveBoard(t){const e=performance.now();try{await Y.put("boards",t),this.lastSaveMs=performance.now()-e,this.setPref("lastBoardId",t.id),this.setPref("recovery",JSON.stringify({id:t.id,title:t.title,updatedAt:t.updatedAt,elementCount:t.elements.length}))}catch(n){throw console.error("Board save failed",n),n}}async loadBoard(t){try{return await Y.get("boards",t)}catch(e){console.error("Board load failed",e);return}}async deleteBoard(t){await Y.delete("boards",t)}async clearAllBoards(){await Y.clearStore("boards")}setPref(t,e){try{localStorage.setItem(Kt+t,e)}catch{}}getPref(t){try{return localStorage.getItem(Kt+t)}catch{return null}}removePref(t){try{localStorage.removeItem(Kt+t)}catch{}}clearPrefs(){try{const t=[];for(let e=0;e<localStorage.length;e++){const n=localStorage.key(e);n&&n.startsWith(Kt)&&t.push(n)}for(const e of t)localStorage.removeItem(e)}catch{}}async estimateStorage(){try{if(navigator.storage&&navigator.storage.estimate){const t=await navigator.storage.estimate();return{usage:t.usage??0,quota:t.quota??0}}}catch{}return{usage:0,quota:0}}}const Z=new xo;function Co(o){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(o)})}function ko(o,t){const e=atob(o),n=new Uint8Array(e.length);for(let s=0;s<e.length;s++)n[s]=e.charCodeAt(s);return new Blob([n],{type:t})}function Xe(o,t){const e=new Blob([JSON.stringify(t)],{type:"application/json"}),n=URL.createObjectURL(e),s=document.createElement("a");s.href=n,s.download=o,s.click(),URL.revokeObjectURL(n)}function qe(o){return o.replace(/[^a-z0-9-_ ]/gi,"").trim().slice(0,60)||"board"}class Eo{exportBoardJson(t){Xe(`${qe(t.title)}.json`,t)}async exportFullBundle(t){const e=[];for(const s of t.assetIds){const i=await J.get(s);i&&e.push({id:i.id,mimeType:i.mimeType,width:i.width,height:i.height,name:i.name,base64:await Co(i.blob)})}const n={bundleVersion:1,board:t,assets:e};Xe(`${qe(t.title)}-bundle.json`,n)}async importFromFile(t){let e;try{e=JSON.parse(await t.text())}catch{return null}if(typeof e!="object"||e===null)return null;const n=e;if(n.bundleVersion===1&&Array.isArray(n.assets)){const s=ee(n.board);if(!s)return null;const i=new Map;for(const a of n.assets){const r=await this.importAsset(a);r&&i.set(r.originalId,r.asset.id)}for(const a of s.elements){const r=a.data.assetId;typeof r=="string"&&i.has(r)&&(a.data.assetId=i.get(r))}return s.assetIds=[...i.values()],s}return ee(e)}async importAsset(t){if(typeof t!="object"||t===null)return null;const e=t;if(typeof e.id!="string"||typeof e.base64!="string"||typeof e.mimeType!="string"||!e.mimeType.startsWith("image/"))return null;try{const n=ko(e.base64,e.mimeType),s=Date.now(),i={id:Rt(),type:"image",mimeType:e.mimeType,blob:n,width:typeof e.width=="number"?e.width:0,height:typeof e.height=="number"?e.height:0,sizeBytes:n.size,createdAt:s,updatedAt:s,name:typeof e.name=="string"?e.name.slice(0,100):void 0};return await J.put(i),{originalId:e.id,asset:i}}catch{return null}}}const ve=new Eo,K={select:'<svg viewBox="0 0 24 24"><path d="M4 3l7 18 2.5-7.5L21 11z"/></svg>',hand:'<svg viewBox="0 0 24 24"><path d="M18 11V6.5a1.5 1.5 0 0 0-3 0V11m0-1V4.5a1.5 1.5 0 0 0-3 0V10m0 .5v-5a1.5 1.5 0 0 0-3 0V12m9-1v1.5a1.5 1.5 0 0 1 3 0V14c0 4-2.5 7-6.5 7S8 18.5 6 15l-1.8-3.2a1.4 1.4 0 0 1 2.3-1.5L8 12V7"/></svg>',sticky:'<svg viewBox="0 0 24 24"><path d="M5 4h14a1 1 0 0 1 1 1v9l-6 6H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z"/><path d="M14 20v-5a1 1 0 0 1 1-1h5"/></svg>',task:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="16" height="14" rx="3"/><path d="M8 12l2.3 2.3L16 8.8"/></svg>',rectangle:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="16" height="14" rx="2"/></svg>',ellipse:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="12" rx="8.5" ry="7"/></svg>',diamond:'<svg viewBox="0 0 24 24"><path d="M12 3l8 9-8 9-8-9z"/></svg>',triangle:'<svg viewBox="0 0 24 24"><path d="M12 4l9 16H3z"/></svg>',pill:'<svg viewBox="0 0 24 24"><rect x="3.5" y="7" width="17" height="10" rx="5"/></svg>',chevron:'<svg viewBox="0 0 24 24"><path d="M4 6h12l5 6-5 6H4l5-6z"/></svg>',parallelogram:'<svg viewBox="0 0 24 24"><path d="M7 5h13l-3 14H4z"/></svg>',hexagon:'<svg viewBox="0 0 24 24"><path d="M8 4h8l5 8-5 8H8l-5-8z"/></svg>',cylinder:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="6" rx="7" ry="3"/><path d="M5 6v11c0 1.7 3.1 3 7 3s7-1.3 7-3V6"/></svg>',arrowDashed:'<svg viewBox="0 0 24 24"><path stroke-dasharray="4 3" d="M4 12h14m0 0l-5-5m5 5l-5 5"/></svg>',arrowBoth:'<svg viewBox="0 0 24 24"><path d="M4 12h16m-16 0l5-5m-5 5l5 5m11-5l-5-5m5 5l-5 5"/></svg>',arrowLabel:'<svg viewBox="0 0 24 24"><path d="M3 17L17 7m0 0h-6m6 0v6"/><rect x="7" y="9" width="10" height="6" rx="1"/></svg>',text:'<svg viewBox="0 0 24 24"><path d="M5 6V4h14v2M12 4v16m-3 0h6"/></svg>',arrow:'<svg viewBox="0 0 24 24"><path d="M5 19L19 5m0 0h-7m7 0v7"/></svg>',image:'<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="1.6"/><path d="M21 16l-5-5-9 9"/></svg>',templates:'<svg viewBox="0 0 24 24"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="3" width="8" height="8" rx="1.5"/><rect x="3" y="13" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/></svg>',shapes:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="7" height="7" rx="1.5"/><circle cx="16.5" cy="8.5" r="3.5"/><path d="M7.5 14l3.8 6H3.7z"/><path d="M15 14h4l2 3-2 3h-4l2-3z"/></svg>',sun:'<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4l1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4m11.4-11.4l1.4-1.4"/></svg>',moon:'<svg viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z"/></svg>',export:'<svg viewBox="0 0 24 24"><path d="M12 15V3m0 0L7 8m5-5l5 5M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg>',import:'<svg viewBox="0 0 24 24"><path d="M12 3v12m0 0l-5-5m5 5l5-5M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg>',gauge:'<svg viewBox="0 0 24 24"><path d="M12 14l4-4M3.3 14a9 9 0 1 1 17.4 0"/></svg>',storage:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="5.5" rx="8" ry="2.5"/><path d="M4 5.5V12c0 1.4 3.6 2.5 8 2.5s8-1.1 8-2.5V5.5M4 12v6.5C4 19.9 7.6 21 12 21s8-1.1 8-2.5V12"/></svg>',flask:'<svg viewBox="0 0 24 24"><path d="M9 3h6M10 3v6L4.5 18a2 2 0 0 0 1.8 3h11.4a2 2 0 0 0 1.8-3L14 9V3"/><path d="M7 15h10"/></svg>',reset:'<svg viewBox="0 0 24 24"><path d="M3 12a9 9 0 1 0 2.6-6.3M3 4v5h5"/></svg>',camera:'<svg viewBox="0 0 24 24"><path d="M3 8a2 2 0 0 1 2-2h2l2-2h6l2 2h2a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><circle cx="12" cy="13" r="3.5"/></svg>',trash:'<svg viewBox="0 0 24 24"><path d="M4 7h16M10 11v6m4-6v6M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3"/></svg>',embed:'<svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2" stroke-dasharray="3 3"/><path d="M9 10l-2 2 2 2m6-4l2 2-2 2"/></svg>',arrowLeft:'<svg viewBox="0 0 24 24"><path d="M19 12H5m0 0l6-6m-6 6l6 6"/></svg>',search:'<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/></svg>',panelLeft:'<svg viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M10 4v16"/></svg>',edit:'<svg viewBox="0 0 24 24"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg>',copy:'<svg viewBox="0 0 24 24"><rect x="8" y="8" width="11" height="11" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/></svg>',folder:'<svg viewBox="0 0 24 24"><path d="M4 7a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/></svg>',folderOpen:'<svg viewBox="0 0 24 24"><path d="M4 7a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v1M4 8l1.5 9c.1.6.6 1 1.2 1h10.6c.6 0 1.1-.4 1.2-1L20 8z"/></svg>',file:'<svg viewBox="0 0 24 24"><path d="M13 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10z"/><path d="M13 3v7h7"/></svg>',fileText:'<svg viewBox="0 0 24 24"><path d="M13 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10z"/><path d="M13 3v7h7M10 13h4m-4 4h4"/></svg>',board:'<svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="12" y="3" width="9" height="7" rx="1"/><rect x="3" y="12" width="9" height="9" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/></svg>',doc:'<svg viewBox="0 0 24 24"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><path d="M14 3v6h6M10 13h4m-4 4h4m-4-8h1"/></svg>',skill:'<svg viewBox="0 0 24 24"><path d="M12 2l3.1 6.3 6.9 1-5 4.9 1.2 6.8-6.2-3.3-6.2 3.3 1.2-6.8-5-4.9 6.9-1z"/></svg>',plus:'<svg viewBox="0 0 24 24"><path d="M12 5v14m-7-7h14"/></svg>',moreVertical:'<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>',chevronRight:'<svg viewBox="0 0 24 24"><path d="M9 18l6-6-6-6"/></svg>',chevronDown:'<svg viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></svg>',wiki:'<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M8 13h2m-2 4h6m-6-8h1"/></svg>',list:'<svg viewBox="0 0 24 24"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><circle cx="4" cy="6" r="1"/><circle cx="4" cy="12" r="1"/><circle cx="4" cy="18" r="1"/></svg>'},So=[{tool:"select",icon:"select",label:"Select",key:"V"},{tool:"hand",icon:"hand",label:"Hand",key:"H"},{tool:"sticky",icon:"sticky",label:"Sticky note",key:"S"},{tool:"task",icon:"task",label:"Task",key:""},{tool:"text",icon:"text",label:"Text",key:"T"},{tool:"image",icon:"image",label:"Image",key:"I"}],$n=[{tool:"rectangle",icon:"rectangle",label:"Rectangle",key:"R"},{tool:"ellipse",icon:"ellipse",label:"Ellipse",key:"O"},{tool:"diamond",icon:"diamond",label:"Diamond",key:""},{tool:"triangle",icon:"triangle",label:"Triangle",key:""},{tool:"pill",icon:"pill",label:"Pill",key:""},{tool:"chevron",icon:"chevron",label:"Chevron",key:""},{tool:"parallelogram",icon:"parallelogram",label:"Parallelogram",key:""},{tool:"hexagon",icon:"hexagon",label:"Hexagon",key:""},{tool:"cylinder",icon:"cylinder",label:"Cylinder",key:""}],To=[{tool:"arrow",icon:"arrow",label:"Arrow (hold Shift to snap)",key:"A"},{tool:"dashedArrow",icon:"arrowDashed",label:"Dashed arrow",key:""},{tool:"twoWayArrow",icon:"arrowBoth",label:"Two-way arrow",key:""},{tool:"labeledArrow",icon:"arrowLabel",label:"Centered label arrow",key:""},{tool:"sidedLabelArrow",icon:"arrowLabel",label:"Left and right labels",key:""}],Mo=new Set($n.map(o=>o.tool));class Bo{constructor(t,e){m(this,"element");m(this,"toolButtons",new Map);m(this,"shapeButtons",new Map);m(this,"shapeBtn");m(this,"shapeGroup");m(this,"arrowGroup");m(this,"themeBtn");this.element=document.createElement("div"),this.element.className="toolbar";for(const a of So){const r=this.makeButton(a.icon,a.label,a.key);r.addEventListener("click",()=>e.setTool(a.tool)),this.toolButtons.set(a.tool,r),this.element.appendChild(r),a.tool==="sticky"&&this.element.appendChild(this.makeShapePicker(e)),a.tool==="text"&&this.element.appendChild(this.makeArrowPicker(e))}this.element.appendChild(this.divider());const n=this.makeButton("templates","Templates","");n.addEventListener("click",e.openTemplates),this.element.appendChild(n),this.element.appendChild(this.divider()),this.themeBtn=this.makeButton("moon","Toggle theme",""),this.themeBtn.addEventListener("click",e.toggleTheme),this.element.appendChild(this.themeBtn);const s=this.makeButton("export","Export / Import","");s.addEventListener("click",e.openExportMenu),this.element.appendChild(s);const i=this.makeButton("flask","Stress test","");if(i.addEventListener("click",e.toggleStressPanel),this.element.appendChild(i),e.copyEmbed){this.element.appendChild(this.divider());const a=this.makeButton("embed","Copy embed of a region","");a.addEventListener("click",e.copyEmbed),this.element.appendChild(a)}t.appendChild(this.element)}makeButton(t,e,n){const s=document.createElement("button");s.className="tool-btn",s.setAttribute("aria-label",e),s.innerHTML=K[t]??"";const i=document.createElement("span");if(i.className="tooltip",i.textContent=e,n){const a=document.createElement("kbd");a.textContent=n,i.appendChild(a)}return s.appendChild(i),s}makeShapePicker(t){this.shapeGroup=document.createElement("div"),this.shapeGroup.className="shape-tool-group",this.shapeBtn=this.makeButton("shapes","Shapes",""),this.shapeBtn.classList.add("shape-tool-trigger"),this.shapeBtn.addEventListener("click",n=>{n.stopPropagation(),this.shapeGroup.classList.toggle("open")});const e=document.createElement("div");e.className="shape-tool-popover";for(const n of $n){const s=this.makeButton(n.icon,n.label,n.key);s.classList.add("shape-option-btn"),s.addEventListener("click",i=>{i.stopPropagation(),t.setTool(n.tool),this.shapeGroup.classList.remove("open")}),this.shapeButtons.set(n.tool,s),e.appendChild(s)}return this.shapeGroup.append(this.shapeBtn,e),this.shapeGroup}makeArrowPicker(t){this.arrowGroup=document.createElement("div"),this.arrowGroup.className="shape-tool-group";const e=this.makeButton("arrow","Arrow types","");e.classList.add("shape-tool-trigger"),e.addEventListener("click",s=>{s.stopPropagation(),this.arrowGroup.classList.toggle("open")});const n=document.createElement("div");n.className="shape-tool-popover";for(const s of To){const i=this.makeButton(s.icon,s.label,s.key);i.classList.add("shape-option-btn"),i.addEventListener("click",a=>{a.stopPropagation(),t.setTool(s.tool),this.arrowGroup.classList.remove("open")}),this.toolButtons.set(s.tool,i),n.appendChild(i)}return this.arrowGroup.append(e,n),this.arrowGroup}divider(){const t=document.createElement("div");return t.className="toolbar-divider",t}setActiveTool(t){var e;for(const[n,s]of this.toolButtons)s.classList.toggle("active",n===t);for(const[n,s]of this.shapeButtons)s.classList.toggle("active",n===t);(e=this.shapeBtn)==null||e.classList.toggle("active",Mo.has(t))}setTheme(t){const e=this.themeBtn.querySelector(".tooltip");this.themeBtn.innerHTML=K[t==="dark"?"sun":"moon"],e&&this.themeBtn.appendChild(e)}}class Io{constructor(t,e,n){m(this,"zoomLabel");m(this,"titleInput");m(this,"titleMeasure");const s=document.createElement("div");if(s.className="top-left",e.onExit){const u=document.createElement("button");u.className="control-btn back-btn",u.innerHTML=`${K.arrowLeft}<span>ViteBoard</span>`,u.title="Save and back to ViteBoard",u.setAttribute("aria-label","Back to ViteBoard"),u.addEventListener("click",e.onExit),s.appendChild(u)}this.titleInput=document.createElement("input"),this.titleInput.className="board-title",this.titleInput.value=n,this.titleInput.maxLength=120,this.titleInput.setAttribute("aria-label","Board title"),this.titleInput.addEventListener("change",()=>e.onTitleChange(this.titleInput.value.trim()||"Untitled Board")),this.titleInput.addEventListener("input",()=>this.resizeTitleInput()),this.titleInput.addEventListener("keydown",u=>{u.stopPropagation(),u.key==="Enter"&&this.titleInput.blur()}),this.titleMeasure=document.createElement("span"),this.titleMeasure.className="board-title-measure",s.appendChild(this.titleInput),s.appendChild(this.titleMeasure),t.appendChild(s),this.resizeTitleInput();const i=document.createElement("div");i.className="top-right";const a=document.createElement("div");a.className="control-group";const r=this.btn("−","Zoom out (Ctrl/Cmd + wheel or Ctrl/Cmd + -)");r.addEventListener("click",e.zoomOut),a.appendChild(r),this.zoomLabel=this.btn("100%","Reset zoom to 100% (Ctrl/Cmd + 0)"),this.zoomLabel.classList.add("zoom-label"),this.zoomLabel.addEventListener("click",e.resetView),a.appendChild(this.zoomLabel);const c=this.btn("+","Zoom in (Ctrl/Cmd + wheel or Ctrl/Cmd + +)");c.addEventListener("click",e.zoomIn),a.appendChild(c),i.appendChild(a);const l=document.createElement("div");l.className="control-group";const d=this.iconBtn("reset","Reset view");d.addEventListener("click",e.resetView),l.appendChild(d);const h=this.iconBtn("storage","Storage manager");h.addEventListener("click",e.openStorageManager),l.appendChild(h);const p=this.iconBtn("gauge","Performance overlay");if(p.addEventListener("click",e.togglePerfOverlay),l.appendChild(p),e.deleteBoard){const u=this.iconBtn("trash","Delete board");u.classList.add("danger-control"),u.addEventListener("click",e.deleteBoard),l.appendChild(u)}i.appendChild(l),t.appendChild(i)}btn(t,e){const n=document.createElement("button");return n.className="control-btn",n.textContent=t,n.title=e,n.setAttribute("aria-label",e),n}iconBtn(t,e){const n=document.createElement("button");return n.className="control-btn",n.innerHTML=K[t]??"",n.title=e,n.setAttribute("aria-label",e),n}setZoom(t){this.zoomLabel.textContent=Math.round(t*100)+"%"}setTitle(t){this.titleInput.value=t,this.resizeTitleInput()}resizeTitleInput(){if(!this.titleMeasure||!this.titleInput)return;this.titleMeasure.textContent=this.titleInput.value||"Untitled Board";const t=Math.ceil(this.titleMeasure.getBoundingClientRect().width+22),e=Math.max(180,window.innerWidth-460);this.titleInput.style.width=Math.min(Math.max(90,t),e)+"px"}}class Lo{constructor(t,e){m(this,"state");m(this,"commands");m(this,"textareas",[]);m(this,"editingId",null);this.state=t,this.commands=e}get isEditing(){return this.editingId!==null}open(t){if(this.close(),this.editingId=t.id,t.data.labelPosition==="sides"){this.openSideEditors(t);return}const e=document.createElement("textarea");e.className="text-editor",e.value=t.data.text??"",t.data.labelPosition==="sides"&&(e.placeholder="left label | right label"),this.position(e,t),document.body.appendChild(e),this.textareas=[e],e.focus(),e.select();const n=t.data.text??"";t.data.text="",t.updatedAt=Date.now(),F(t.id),this.state.requestRender();const s=()=>{const i=e.value;if(t.data.text=i,t.updatedAt=Date.now(),F(t.id),i!==n){const a=t.id,r=this.state;this.commands.push("edit-text",()=>{const c=r.elementsById.get(a);c&&(c.data.text=i,c.updatedAt=Date.now(),F(a),r.emitChange())},()=>{const c=r.elementsById.get(a);c&&(c.data.text=n,c.updatedAt=Date.now(),F(a),r.emitChange())})}this.state.emitChange(),this.close()};e.addEventListener("blur",s),e.addEventListener("keydown",i=>{i.stopPropagation(),i.key==="Escape"?(t.data.text=n,F(t.id),this.close(),this.state.requestRender()):i.key==="Enter"&&(i.metaKey||i.ctrlKey)&&e.blur()})}openSideEditors(t){const e=String(t.data.text??""),[n="",s=""]=e.split("|",2).map(d=>d.trim()),i=this.makeSideEditor("Left label",n),a=this.makeSideEditor("Right label",s);this.positionSideEditors(i,a,t),document.body.append(i,a),this.textareas=[i,a],i.focus(),i.select(),t.data.text="",t.updatedAt=Date.now(),F(t.id),this.state.requestRender();let r=!1;const c=()=>{if(r)return;r=!0;const d=`${i.value.trim()} | ${a.value.trim()}`;t.data.text=d,t.updatedAt=Date.now(),F(t.id),d!==e&&this.pushTextCommand(t.id,e,d),this.state.emitChange(),this.close()},l=()=>{r||(r=!0,t.data.text=e,F(t.id),this.close(),this.state.requestRender())};for(const d of[i,a])d.addEventListener("keydown",h=>{h.stopPropagation(),h.key==="Escape"?l():h.key==="Enter"&&(h.metaKey||h.ctrlKey)&&c()}),d.addEventListener("blur",()=>{window.setTimeout(()=>{this.textareas.includes(document.activeElement)||c()},0)})}makeSideEditor(t,e){const n=document.createElement("textarea");return n.className="text-editor text-editor-side",n.placeholder=t,n.value=e,n.style.fontFamily='-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',n.style.fontWeight="600",n.style.textAlign="center",n.style.lineHeight="1.35",n.style.color=this.state.theme==="dark"?"#f2f2f2":"#1f2933",n}positionSideEditors(t,e,n){const s=this.state.viewport,i=yt(n.x,n.y,s),a=yt(n.x+n.width,n.y+n.height,s),r=13*s.scale,c=Math.max(82,Math.min(150,Math.hypot(a.x-i.x,a.y-i.y)*.34)),l=Math.max(24,r*1.35+4);for(const[d,h]of[[t,.24],[e,.76]])d.style.left=i.x+(a.x-i.x)*h-c/2+"px",d.style.top=i.y+(a.y-i.y)*h-l/2+"px",d.style.width=c+"px",d.style.height=l+"px",d.style.fontSize=r+"px"}pushTextCommand(t,e,n){const s=this.state;this.commands.push("edit-text",()=>{const i=s.elementsById.get(t);i&&(i.data.text=n,i.updatedAt=Date.now(),F(t),s.emitChange())},()=>{const i=s.elementsById.get(t);i&&(i.data.text=e,i.updatedAt=Date.now(),F(t),s.emitChange())})}position(t,e){const n=this.state.viewport;if(e.type==="arrow"||e.type==="line"||e.type==="connector"){const v=yt(e.x,e.y,n),b=yt(e.x+e.width,e.y+e.height,n),x=13*n.scale,S=Math.max(100,Math.min(240,Math.hypot(b.x-v.x,b.y-v.y)-16)),C=Math.max(24,x*1.35+4);t.style.left=(v.x+b.x)/2-S/2+"px",t.style.top=(v.y+b.y)/2-C/2+"px",t.style.width=S+"px",t.style.height=C+"px",t.style.fontSize=x+"px",t.style.lineHeight="1.35",t.style.fontFamily='-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',t.style.fontWeight="600",t.style.color=this.state.theme==="dark"?"#f2f2f2":"#1f2933",t.style.textAlign="center";return}const s=yt(e.x,e.y,n),i=e.data.shapeKind==="chevron",a=Sn(e)*n.scale,r=i?Math.min(Math.abs(e.width)*.18,Math.abs(e.height)*.55)+8:10,c=(e.type==="sticky"?14:e.type==="task"?50:e.type==="text"?0:r)*n.scale,l=e.type!=="text"&&e.type!=="task",d=i?e.height*n.scale:e.height*n.scale-(e.type==="sticky"?28:l?r*2:0)*n.scale,h=Math.max(1,String(e.data.text??"").split(/\r?\n/).length),p=Math.max(24,a*(i?1.18:1.35)*h+4),u=l?Math.min(Math.max(24,d),p):Math.max(24,d),g=l?Math.max(0,(e.height*n.scale-u)/2):e.type==="sticky"?14*n.scale:0,y=(e.type==="task"?16:e.type==="sticky"?14:e.type==="text"?0:r)*n.scale;t.style.left=s.x+c+"px",t.style.top=s.y+g+"px",t.style.width=Math.max(40,e.width*n.scale-c-y)+"px",t.style.height=u+"px",t.style.fontSize=a+"px",t.style.lineHeight=i?"1.18":"1.35",t.style.fontFamily=e.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',t.style.fontWeight=i?"750":e.style.fontWeight??"400",t.style.color=e.style.textColor??(this.state.theme==="dark"?"#f2f2f2":"#1f2933"),t.style.textAlign=e.type==="text"||e.type==="task"?"left":"center"}close(){if(this.textareas.length){const t=this.textareas;this.textareas=[],this.editingId=null;for(const e of t)e.remove()}}}function O(o,t){const e=document.createElement("div");e.className="modal-backdrop";const n=document.createElement("div");n.className="modal",n.setAttribute("role","dialog"),n.setAttribute("aria-label",o);const s=document.createElement("button");s.className="modal-close",s.textContent="✕",s.setAttribute("aria-label","Close");const i=document.createElement("h2");i.textContent=o;const a=document.createElement("div"),r=()=>e.remove();s.addEventListener("click",r),e.addEventListener("click",c=>{c.target===e&&r()}),e.addEventListener("keydown",c=>{c.stopPropagation(),c.key==="Escape"&&r()}),n.appendChild(s),n.appendChild(i),n.appendChild(a),e.appendChild(n),document.body.appendChild(e),t(a,r),s.focus()}let tt=null,be=null;function w(o){tt||(tt=document.createElement("div"),tt.className="toast",document.body.appendChild(tt)),tt.textContent=o,tt.classList.add("visible"),be!==null&&clearTimeout(be),be=window.setTimeout(()=>{tt==null||tt.classList.remove("visible")},2600)}function rt(o){return o==="dark"?{card:"#1e2126",cardStroke:"#3a3f46",heading:"#f2f2f2",text:"#c8cdd4",accent:"#4dabf7",sticky:"#fef08a",zone:"#22262c"}:{card:"#ffffff",cardStroke:"#d8dade",heading:"#1f2933",text:"#4b5563",accent:"#6e6e6e",sticky:"#fef08a",zone:"#f0f0ed"}}let Pt=0;function ct(o){Pt=o}function D(o,t,e,n,s,i=""){return A("rectangle",{x:o,y:t,width:e,height:n,zIndex:++Pt,style:{borderRadius:10,...s},data:{text:i}})}function M(o,t,e,n,s,i,a="600"){return A("text",{x:o,y:t,width:e,height:s*1.6,zIndex:++Pt,style:{fontSize:s,textColor:i,fontWeight:a},data:{text:n}})}function z(o,t,e,n,s=180,i=120){return A("sticky",{x:o,y:t,width:s,height:i,zIndex:++Pt,style:{fill:n,borderRadius:12,shadow:!0,fontSize:13,textColor:"#1f2933"},data:{text:e}})}function P(o,t,e,n,s,i={}){return A("arrow",{x:o,y:t,width:e-o,height:n-t,zIndex:++Pt,style:{stroke:s,strokeWidth:2,arrowEnd:!0,arrowStart:i.arrowStart,strokeDash:i.dashed?[8,6]:void 0},data:{text:i.label??"",labelPosition:i.sides?"sides":"center"}})}function Ro(o,t,e,n,s,i=""){return A("ellipse",{x:o,y:t,width:e,height:n,zIndex:++Pt,style:s,data:{text:i}})}function $o(o,t,e,n){const s=rt(e);ct(n);const i=[];return i.push(D(o,t,760,560,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(M(o+28,t+22,400,"User Persona",22,s.heading,"700")),i.push(M(o+28,t+60,300,"Name",13,s.accent)),i.push(z(o+28,t+86,"Jordan Lee",s.sticky,200,64)),i.push(M(o+260,t+60,300,"Role",13,s.accent)),i.push(z(o+260,t+86,"Senior Product Manager","#a5b4fc",220,64)),i.push(M(o+510,t+60,300,"Buying trigger",13,s.accent)),i.push(z(o+510,t+86,"Team scaling pains","#fdba74",220,64)),[["Goals","Ship the right features faster","#86efac"],["Pain points","Scattered docs, unclear priorities","#fca5a5"],["Jobs to be done","Align team on what to build next","#93c5fd"],["Current workaround","Spreadsheets + slide decks","#d8b4fe"],["Success criteria","Stakeholders aligned in 1 meeting","#f9a8d4"],["Key quote",'"I need clarity, not more tools."',"#fef08a"]].forEach(([r,c,l],d)=>{const h=d%3,p=Math.floor(d/3),u=o+28+h*242,g=t+188+p*178;i.push(M(u,g,230,r,13,s.accent)),i.push(z(u,g+26,c,l,220,124))}),i}const we=["Awareness","Discovery","Evaluation","Onboarding","Activation","Retention"],Do=["#93c5fd","#a5b4fc","#d8b4fe","#f9a8d4","#fdba74","#86efac"];function Po(o,t,e,n){const s=rt(e);ct(n);const i=[],a=230,r=we.length*a+56;return i.push(D(o,t,r,640,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(M(o+28,t+22,500,"User Journey Map",22,s.heading,"700")),we.forEach((c,l)=>{const d=o+28+l*a,h=t+70;i.push(D(d,h,a-16,48,{fill:Do[l],borderRadius:10},c)),l<we.length-1&&i.push(P(d+a-14,h+24,d+a-2,h+24,s.heading)),i.push(D(d,h+64,a-16,150,{fill:s.zone,borderRadius:10},"")),i.push(M(d+10,h+70,a-36,"Actions",12,s.accent)),i.push(z(d+14,h+96,"","#fef08a",a-44,100)),i.push(D(d,h+226,a-16,150,{fill:s.zone,borderRadius:10},"")),i.push(M(d+10,h+232,a-36,"Pain points",12,s.accent)),i.push(z(d+14,h+258,"","#fca5a5",a-44,100)),i.push(D(d,h+388,a-16,150,{fill:s.zone,borderRadius:10},"")),i.push(M(d+10,h+394,a-36,"Opportunities",12,s.accent)),i.push(z(d+14,h+420,"","#86efac",a-44,100))}),i}function Ao(o,t,e,n){const s=rt(e);ct(n);const i=[],a=680;i.push(D(o,t,a+120,a+130,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(M(o+28,t+22,500,"Feature Prioritization Matrix",22,s.heading,"700"));const r=o+80,c=t+80,l=a/2;return i.push(D(r,c,l,l,{fill:"#86efac55",borderRadius:8})),i.push(D(r+l,c,l,l,{fill:"#93c5fd55",borderRadius:8})),i.push(D(r,c+l,l,l,{fill:"#fef08a55",borderRadius:8})),i.push(D(r+l,c+l,l,l,{fill:"#fca5a555",borderRadius:8})),i.push(M(r+16,c+12,300,"Quick wins",16,s.heading,"700")),i.push(M(r+l+16,c+12,300,"Strategic bets",16,s.heading,"700")),i.push(M(r+16,c+l+12,300,"Fill-ins",16,s.heading,"700")),i.push(M(r+l+16,c+l+12,300,"Avoid",16,s.heading,"700")),i.push(P(r-24,c+a,r-24,c,s.heading)),i.push(M(r-64,c+l-12,60,"Impact",14,s.text,"600")),i.push(P(r,c+a+24,r+a,c+a+24,s.heading)),i.push(M(r+l-30,c+a+34,80,"Effort",14,s.text,"600")),i.push(z(r+40,c+60,"Feature idea","#fef08a",150,90)),i.push(z(r+l+40,c+60,"Big bet","#a5b4fc",150,90)),i}const Ye=[["Problem","#fca5a5"],["User","#93c5fd"],["Context","#d8b4fe"],["Current workflow","#fdba74"],["Proposed solution","#86efac"],["Edge cases","#f9a8d4"],["Acceptance criteria","#a5b4fc"],["Dependencies","#fef08a"],["Risks","#fca5a5"]];function No(o,t,e,n){const s=rt(e);ct(n);const i=[],a=3,r=280,c=210,l=a*r+56,h=Math.ceil(Ye.length/a)*c+100;return i.push(D(o,t,l,h,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(M(o+28,t+22,500,"Product Requirements Flow",22,s.heading,"700")),Ye.forEach(([p,u],g)=>{const y=g%a,v=Math.floor(g/a),b=o+28+y*r,x=t+72+v*c;i.push(M(b,x,r-30,`${g+1}. ${p}`,14,s.accent)),i.push(z(b,x+30,"",u,r-28,c-60))}),i}function zo(o,t,e,n){const s=rt(e);ct(n);const i=[];i.push(M(o,t-40,400,"System Diagram",22,s.heading,"700"));const a=(r,c,l,d,h,p)=>D(r,c,l,d,{fill:h,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,shadow:!0,fontSize:15,fontWeight:"600",textColor:"#1f2933"},p);return i.push(Ro(o,t+130,110,110,{fill:"#f9a8d4",stroke:s.cardStroke,strokeWidth:1.5,fontSize:14,fontWeight:"600",textColor:"#1f2933"},"User")),i.push(a(o+200,t+140,180,90,"#93c5fd","Frontend")),i.push(a(o+470,t+140,180,90,"#a5b4fc","API / Server")),i.push(a(o+740,t+60,180,90,"#86efac","Database")),i.push(a(o+740,t+200,180,90,"#fdba74","External Service")),i.push(a(o+470,t+330,180,90,"#fef08a","Notification Service")),i.push(P(o+115,t+185,o+195,t+185,s.heading,{label:"uses"})),i.push(P(o+385,t+185,o+465,t+185,s.heading,{label:"request | response",sides:!0,arrowStart:!0})),i.push(P(o+655,t+165,o+735,t+110,s.heading,{label:"read"})),i.push(P(o+655,t+205,o+735,t+240,s.heading,{label:"webhook",dashed:!0})),i.push(P(o+560,t+235,o+560,t+325,s.heading,{label:"event",dashed:!0})),i.push(P(o+470,t+375,o+80,t+245,s.heading,{label:"notify",dashed:!0})),i}function jo(o,t,e,n){const s=rt(e);ct(n);const i=[];i.push(M(o+280,t-40,500,"Opportunity Solution Tree",22,s.heading,"700")),i.push(D(o+300,t,280,80,{fill:"#a5b4fc",borderRadius:12,shadow:!0,fontSize:15,fontWeight:"600",textColor:"#1f2933"},"Desired outcome"));const a=t+160,r=[o,o+300,o+600];for(const d of r)i.push(z(d,a,"Opportunity","#93c5fd",220,100)),i.push(P(o+440,t+85,d+110,a-5,s.heading));const c=a+180;for(const d of r)i.push(z(d,c,"Solution","#86efac",220,100)),i.push(P(d+110,a+105,d+110,c-5,s.heading));const l=c+180;for(const d of r)i.push(z(d,l,"Experiment","#fdba74",220,90)),i.push(P(d+110,c+105,d+110,l-5,s.heading));return i.push(M(o,l+120,400,"Signals / metrics",14,s.accent)),i.push(z(o,l+150,"What signal tells us this is working?","#fef08a",380,100)),i}function Ho(o,t,e,n){const s=rt(e);ct(n);const i=[];i.push(D(o,t,1060,620,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(M(o+28,t+22,500,"Screenshot Review",22,s.heading,"700")),i.push(M(o+28,t+64,300,"Screenshot",13,s.accent));const a=A("frame",{x:o+28,y:t+92,width:480,height:360,zIndex:n+100,style:{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,fontSize:13,textColor:s.text},data:{text:"Paste a screenshot here (Cmd/Ctrl+V)"}});return i.push(a),[["Observations","#93c5fd"],["Problems","#fca5a5"],["UX notes","#d8b4fe"],["Requirements","#86efac"]].forEach(([c,l],d)=>{const h=d%2,p=Math.floor(d/2),u=o+540+h*250,g=t+64+p*200;i.push(M(u,g,230,c,13,s.accent)),i.push(z(u,g+28,"",l,230,140))}),i.push(M(o+28,t+470,300,"Follow-up tasks",13,s.accent)),i.push(z(o+28,t+498,"","#fef08a",480,96)),i.push(M(o+540,t+470,300,"Decision",13,s.accent)),i.push(z(o+540,t+498,"","#fdba74",480,96)),i}function Fo(o,t,e,n){const s=rt(e);ct(n);const i=[];i.push(M(o,t,880,"Workflow map",26,s.heading,"700"));const a=[["Request","#dbeafe"],["Review","#fef3c7"],["Deliver","#dcfce7"]];for(let r=0;r<a.length;r++){const c=o+r*280;i.push(D(c,t+130,180,96,{fill:a[r][1],stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,fontSize:16,fontWeight:"650",textColor:"#1f2933",shadow:!0},a[r][0]))}return i.push(P(o+180,t+178,o+280,t+178,s.accent,{label:"approve"})),i.push(P(o+460,t+178,o+560,t+178,s.accent,{label:"ship"})),i.push(P(o+650,t+226,o+370,t+310,"#9ca3af",{label:"feedback",dashed:!0})),i.push(D(o+280,t+300,180,72,{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:10,fontSize:14,textColor:s.text},"Learn and iterate")),i}function Wo(o,t,e,n){const s=rt(e);ct(n);const i=[];return i.push(M(o,t,800,"Handoff map",26,s.heading,"700")),[["Explore","#dbeafe"],["Decide","#fef3c7"],["Act","#dcfce7"]].forEach(([r,c],l)=>{i.push(D(o+l*270,t+150,170,92,{fill:c,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,shadow:!0,fontSize:16,fontWeight:"650",textColor:"#1f2933"},r))}),i.push(P(o+170,t+196,o+270,t+196,s.accent,{label:"proposal"})),i.push(P(o+440,t+196,o+540,t+196,s.accent,{label:"owner | outcome",sides:!0,arrowStart:!0})),i.push(P(o+625,t+245,o+355,t+330,"#9ca3af",{label:"feedback",dashed:!0})),i.push(D(o+265,t+320,180,70,{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:10,fontSize:14,textColor:s.text},"Review signal")),i}const Oo=[{id:"persona",name:"User Persona Card",description:"Name, role, goals, pain points, JTBD, success criteria.",build:$o},{id:"journey",name:"User Journey Map",description:"Awareness → Retention stages with sticky note areas.",build:Po},{id:"matrix",name:"Prioritization Matrix",description:"Impact vs effort: quick wins, strategic bets, fill-ins, avoid.",build:Ao},{id:"requirements",name:"Requirements Flow",description:"Problem, user, context, solution, edge cases, risks.",build:No},{id:"system",name:"System Diagram Starter",description:"User, frontend, API, database, external services + arrows.",build:zo},{id:"ost",name:"Opportunity Solution Tree",description:"Outcome, opportunities, solutions, experiments, signals.",build:jo},{id:"screenshot-review",name:"Screenshot Review Board",description:"Screenshot zone with observations, problems, UX notes.",build:Ho},{id:"workflow",name:"Workflow Map",description:"Labeled handoffs, a dashed feedback loop, and editable steps.",build:Fo},{id:"handoff",name:"Handoff Map",description:"A shared decision flow with ownership, outcomes, and feedback.",build:Wo}];function Uo(o,t){O("Insert a template",(e,n)=>{const s=document.createElement("div");s.className="template-grid";for(const i of Oo){const a=document.createElement("button");a.className="template-card";const r=document.createElement("span");r.className="t-name",r.textContent=i.name;const c=document.createElement("span");c.className="t-desc",c.textContent=i.description,a.appendChild(r),a.appendChild(c),a.addEventListener("click",()=>{_o(o,t,i.build),n()}),s.appendChild(a)}e.appendChild(s)})}function _o(o,t,e){const n=R(window.innerWidth/2,window.innerHeight/2,o.viewport),s=e(n.x-380,n.y-280,o.theme,o.maxZIndex());t.execute("insert-template",()=>{for(const i of s)o.elementsById.has(i.id)||o.addElement(i);o.emitChange()},()=>{for(const i of s)o.removeElement(i.id);o.emitChange()}),o.clearSelection();for(const i of s)o.selectedIds.add(i.id);o.requestRender()}function Vt(o){return o<1024?o+" B":o<1024*1024?(o/1024).toFixed(1)+" KB":(o/(1024*1024)).toFixed(1)+" MB"}function Xo(o,t,e){O("Local storage",async(n,s)=>{const i=document.createElement("div");n.appendChild(i);const a=(y,v)=>{const b=document.createElement("div");b.className="storage-row";const x=document.createElement("span");x.textContent=y;const S=document.createElement("span");S.textContent=v,b.appendChild(x),b.appendChild(S),i.appendChild(b)};a("Elements on board",String(o.elements.length));const r=JSON.stringify(o.elements);a("Board data size",Vt(r.length));const c=await J.getAllKeys();a("Image assets",String(c.length));const l=await J.totalSizeBytes();a("Image asset size",Vt(l));const d=await Z.estimateStorage();d.quota>0&&a("Browser storage",`${Vt(d.usage)} of ${Vt(d.quota)}`);const h=document.createElement("div");h.className="modal-actions";const p=document.createElement("button");p.className="btn",p.textContent="Clear unused assets",p.addEventListener("click",async()=>{const y=new Set;for(const b of o.elements){const x=b.data.assetId;typeof x=="string"&&y.add(x)}const v=await J.clearUnused(y);w(`Removed ${v} unused asset${v===1?"":"s"}`),s()}),h.appendChild(p);const u=document.createElement("button");u.className="btn danger",u.textContent="Clear board",u.addEventListener("click",()=>{confirm("Remove all elements from this board?")&&(t(),s())}),h.appendChild(u);const g=document.createElement("button");g.className="btn danger",g.textContent="Reset all local data",g.addEventListener("click",()=>{confirm("Delete ALL local boards, assets and preferences? This cannot be undone.")&&(e(),s())}),h.appendChild(g),n.appendChild(h)})}class qo{constructor(t,e,n,s,i,a){m(this,"element");m(this,"visible",!1);m(this,"state");m(this,"renderer");m(this,"hitTester");m(this,"monitor");m(this,"imageCache");m(this,"timer",null);m(this,"storageEstimate","–");this.state=e,this.renderer=n,this.hitTester=s,this.monitor=i,this.imageCache=a,this.element=document.createElement("div"),this.element.className="perf-overlay",t.appendChild(this.element)}toggle(){this.visible=!this.visible,this.element.classList.toggle("visible",this.visible),this.visible?(this.monitor.start(),this.update(),this.timer=window.setInterval(()=>this.update(),500),this.refreshStorage()):this.timer!==null&&(clearInterval(this.timer),this.timer=null)}async refreshStorage(){const t=await J.totalSizeBytes();this.storageEstimate=(t/(1024*1024)).toFixed(1)+"MB"}update(){const t=this.state.viewport,e=[`FPS: ${this.monitor.fps}`,`Total elements: ${this.state.elements.length.toLocaleString()}`,`Visible elements: ${this.renderer.visibleCount.toLocaleString()}`,`Render time: ${this.renderer.lastRenderMs.toFixed(1)}ms`,`Hit-test time: ${this.hitTester.lastHitTestMs.toFixed(2)}ms`,`Save time: ${Z.lastSaveMs.toFixed(0)}ms`,`Image cache: ${this.imageCache.size}`,`Estimated storage: ${this.storageEstimate}`,`Zoom: ${Math.round(t.scale*100)}%`,`Viewport: x: ${Math.round(-t.offsetX/t.scale)}, y: ${Math.round(-t.offsetY/t.scale)}`,`Culling: ${this.renderer.cullingEnabled?"on":"off"} LOD: ${this.renderer.lodEnabled?"on":"off"}`];this.element.textContent=e.join(`
10
+ `)}}const Gt=["#93c5fd","#a5b4fc","#86efac","#fdba74","#fca5a5","#d8b4fe","#f9a8d4","#fef08a","#ffffff","#e5e7eb"],Ke=["Onboarding","Checkout","Retention","Activation","Churn risk","API gateway","User insight","Edge case","Quick win","Tech debt","Experiment","Metric","Persona","Journey","Feature flag"];function V(o,t){return o+Math.random()*(t-o)}function et(o){return o[Math.floor(Math.random()*o.length)]}const nt="stress";class Yo{constructor(t){m(this,"state");m(this,"lastGenerateMs",0);this.state=t}generate(t){const e=performance.now(),n=Math.sqrt(t)*280,s=["sticky","rectangle","ellipse","text","arrow"];let i=this.state.maxZIndex();const a=[];for(let r=0;r<t;r++){const c=et(s),l=V(-n/2,n/2),d=V(-n/2,n/2);let h;c==="sticky"?h=A("sticky",{x:l,y:d,width:220,height:160,zIndex:++i,style:{fill:et(se),borderRadius:12,shadow:!0,fontSize:14,textColor:"#1f2933"},data:{text:et(Ke),[nt]:!0}}):c==="rectangle"||c==="ellipse"?h=A(c,{x:l,y:d,width:V(80,300),height:V(60,200),zIndex:++i,style:{fill:et(Gt),stroke:"#37415188",strokeWidth:1.5,borderRadius:c==="rectangle"?8:0},data:{[nt]:!0}}):c==="text"?h=A("text",{x:l,y:d,width:200,height:28,zIndex:++i,style:{fontSize:16,textColor:this.state.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:et(Ke),[nt]:!0}}):h=A("arrow",{x:l,y:d,width:V(-250,250),height:V(-250,250),zIndex:++i,style:{stroke:et(Gt),strokeWidth:2,arrowEnd:!0},data:{[nt]:!0}}),a.push(h)}for(const r of a)this.state.addElement(r);this.lastGenerateMs=performance.now()-e,this.state.emitChange()}generateImagePlaceholders(t){const e=Math.sqrt(t)*420;let n=this.state.maxZIndex();for(let s=0;s<t;s++){const i=A("image",{x:V(-e/2,e/2),y:V(-e/2,e/2),width:320,height:220,zIndex:++n,data:{assetId:"stress-placeholder-"+s,[nt]:!0}});this.state.addElement(i)}this.state.emitChange()}generateMixedPmBoard(){this.generate(300)}randomizePositions(){const t=Math.sqrt(this.state.elements.length)*280;for(const e of this.state.elements)e.data[nt]&&(e.x=V(-t/2,t/2),e.y=V(-t/2,t/2));this.state.emitChange()}randomizeColors(){for(const t of this.state.elements)t.data[nt]&&(t.type==="sticky"?t.style.fill=et(se):t.type==="rectangle"||t.type==="ellipse"?t.style.fill=et(Gt):t.type==="arrow"&&(t.style.stroke=et(Gt)));this.state.emitChange()}randomizeZIndex(){for(const t of this.state.elements)t.data[nt]&&(t.zIndex=Math.floor(V(0,this.state.elements.length)));this.state.invalidateSort(),this.state.emitChange()}clearGenerated(){const t=this.state.elements.filter(e=>e.data[nt]);for(const e of t)this.state.removeElement(e.id);this.state.emitChange()}}class Ko{constructor(t,e,n){m(this,"element");m(this,"visible",!1);this.element=document.createElement("div"),this.element.className="stress-panel";const s=(a,r,c=!1)=>{const l=document.createElement("button");l.className="btn"+(c?" danger":""),l.textContent=a,l.addEventListener("click",r),this.element.appendChild(l)},i=a=>()=>{e.generate(a),w(`Generated ${a.toLocaleString()} elements in ${e.lastGenerateMs.toFixed(0)}ms`)};s("+100",i(100)),s("+1,000",i(1e3)),s("+5,000",i(5e3)),s("+10,000",i(1e4)),s("+20,000",i(2e4)),s("+100 images",()=>{e.generateImagePlaceholders(100),w("Generated 100 image placeholders")}),s("Mixed PM board",()=>{e.generateMixedPmBoard(),w("Generated mixed PM board")}),s("Shuffle positions",()=>e.randomizePositions()),s("Shuffle colors",()=>e.randomizeColors()),s("Shuffle z-index",()=>e.randomizeZIndex()),s("Toggle culling",()=>{n.cullingEnabled=!n.cullingEnabled,w(`Viewport culling ${n.cullingEnabled?"enabled":"disabled"}`),n.state.requestRender()}),s("Toggle LOD",()=>{n.lodEnabled=!n.lodEnabled,w(`Simplified rendering ${n.lodEnabled?"enabled":"disabled"}`),n.state.requestRender()}),s("Clear generated",()=>{e.clearGenerated(),w("Cleared generated elements")},!0),t.appendChild(this.element)}toggle(){this.visible=!this.visible,this.element.classList.toggle("visible",this.visible)}}const Vo=300,Go=1e3,Ve=[{label:"Small",shortLabel:"S",fontSize:13,fontWeight:"400"},{label:"Body",shortLabel:"Body",fontSize:16,fontWeight:"400"},{label:"H3",shortLabel:"H3",fontSize:18,fontWeight:"650"},{label:"H2",shortLabel:"H2",fontSize:24,fontWeight:"700"},{label:"H1",shortLabel:"H1",fontSize:32,fontWeight:"750"}],Zo=new Set(["text"]),Jo=new Set(["rectangle","ellipse","frame"]),Qo=["#0078d4","#4dabf7","#6e6e6e","#ffffff","#0f0f0f","#fef08a","#93c5fd","#fca5a5"],ti=[{label:"Black text",value:"#1f2933"},{label:"White text",value:"#ffffff"}];class ei{constructor(t,e={}){m(this,"state",new Os);m(this,"commands",new _s);m(this,"surface");m(this,"renderer");m(this,"scheduler");m(this,"hitTester");m(this,"imageCache");m(this,"monitor",new io);m(this,"actions");m(this,"imageInsert");m(this,"toolController");m(this,"textEditor");m(this,"toolbar");m(this,"topControls");m(this,"perfOverlay");m(this,"stressPanel");m(this,"boardSaveTimer",null);m(this,"viewportSaveTimer",null);m(this,"options");m(this,"listenerAbort",new AbortController);m(this,"root");m(this,"bottomToolCluster",null);m(this,"stickyColorPopover",null);m(this,"textSizePopover",null);m(this,"shapeStylePopover",null);m(this,"layerMenu",null);this.root=t,this.options=e,e.boardId&&(this.state.boardId=e.boardId);const n=this.listenerAbort.signal;this.surface=new to(t,3,n),this.imageCache=new En(J,()=>this.state.requestRender(),e.resolveAssetUrl),this.renderer=new eo(this.surface,this.state,this.imageCache),this.scheduler=new no(()=>this.renderer.render()),this.hitTester=new oo(this.state),this.actions=new Xs(this.state,this.commands),this.textEditor=new Lo(this.state,this.commands),this.imageInsert=new Ks(this.state,this.commands,this.imageCache,w,e.uploadImage),this.state.onRenderNeeded(()=>{var s;this.scheduler.requestRender(),(s=this.topControls)==null||s.setZoom(this.state.viewport.scale),this.scheduleViewportSave(),this.updateContextualToolPanels()}),this.state.onChange(()=>this.scheduleBoardSave()),this.surface.onResize(()=>this.state.requestRender()),this.setupTools(t,n),this.setupUi(t),this.setupSelectionOverlays(t,n),this.setupDragDrop(t),new Vs(this.state,this.actions,this.imageInsert,n),Gs({state:this.state,commands:this.commands,actions:this.actions,toolController:this.toolController,resetView:()=>this.resetView()},n),this.loadInitialState()}destroy(){this.boardSaveTimer!==null&&clearTimeout(this.boardSaveTimer),this.viewportSaveTimer!==null&&clearTimeout(this.viewportSaveTimer),this.listenerAbort.abort(),this.imageCache.clear()}setupTools(t,e){const n={state:this.state,renderer:this.renderer,surface:this.surface,hitTester:this.hitTester,commands:this.commands,setTool:s=>this.toolController.setTool(s),setCursor:s=>{this.surface.container.style.cursor=s},openTextEditor:s=>this.textEditor.open(s)};this.toolController=new lo(this.surface.container,n,[new uo,new mo,new yo,new vo,new Q("rectangle"),new Q("ellipse"),new Q("diamond"),new Q("triangle"),new Q("pill"),new Q("chevron"),new Q("parallelogram"),new Q("hexagon"),new Q("cylinder"),new bo,new At,new At("dashedArrow"),new At("twoWayArrow"),new At("labeledArrow"),new At("sidedLabelArrow"),new wo((s,i,a)=>void this.imageInsert.insertFiles(s,i,a))],e),this.toolController.onToolChange(s=>{var i;(i=this.toolbar)==null||i.setActiveTool(s)})}setupUi(t){this.toolbar=new Bo(t,{setTool:n=>this.toolController.setTool(n),openTemplates:()=>Uo(this.state,this.commands),toggleTheme:()=>this.toggleTheme(),openExportMenu:()=>this.openExportMenu(),toggleStressPanel:()=>this.stressPanel.toggle(),copyEmbed:this.options.onExit?()=>this.startEmbedSelection():void 0}),this.toolbar.setActiveTool("select"),this.topControls=new Io(t,{onExit:this.options.onExit?()=>this.exitToDocs():void 0,resetView:()=>this.resetView(),zoomIn:()=>{Ot(this.state.viewport,window.innerWidth/2,window.innerHeight/2,this.state.viewport.scale*1.2),this.state.requestRender()},zoomOut:()=>{Ot(this.state.viewport,window.innerWidth/2,window.innerHeight/2,this.state.viewport.scale/1.2),this.state.requestRender()},openStorageManager:()=>Xo(this.state,()=>this.clearBoard(),()=>void this.resetAllLocalData()),togglePerfOverlay:()=>this.perfOverlay.toggle(),deleteBoard:this.options.deleteBoard?()=>this.confirmDeleteBoard():void 0,onTitleChange:n=>{this.state.title=n,this.state.emitChange()}},this.state.title),this.perfOverlay=new qo(t,this.state,this.renderer,this.hitTester,this.monitor,this.imageCache);const e=new Yo(this.state);this.stressPanel=new Ko(t,e,this.renderer)}setupSelectionOverlays(t,e){this.bottomToolCluster=document.createElement("div"),this.bottomToolCluster.className="bottom-tool-cluster",t.appendChild(this.bottomToolCluster),this.bottomToolCluster.appendChild(this.toolbar.element),this.stickyColorPopover=document.createElement("div"),this.stickyColorPopover.className="context-tool-popover sticky-color-popover",this.stickyColorPopover.setAttribute("aria-hidden","true");for(const s of se){const i=document.createElement("button");i.type="button",i.className="sticky-color-btn",i.title="Set sticky color",i.setAttribute("aria-label",`Set sticky color ${s}`),i.style.setProperty("--swatch",s),i.addEventListener("click",()=>this.setSelectedStickyColor(s)),this.stickyColorPopover.appendChild(i)}this.bottomToolCluster.appendChild(this.stickyColorPopover),this.textSizePopover=document.createElement("div"),this.textSizePopover.className="context-tool-popover text-size-popover",this.textSizePopover.setAttribute("aria-hidden","true");for(const s of Ve){const i=document.createElement("button");i.type="button",i.className="text-size-btn",i.textContent=s.shortLabel,i.setAttribute("aria-label",`Set text size ${s.label}`),i.addEventListener("click",()=>this.setSelectedTextSize(s)),this.textSizePopover.appendChild(i)}this.bottomToolCluster.appendChild(this.textSizePopover),this.shapeStylePopover=document.createElement("div"),this.shapeStylePopover.className="context-tool-popover shape-style-popover",this.shapeStylePopover.setAttribute("aria-hidden","true");for(const s of Qo){const i=document.createElement("button");i.type="button",i.className="shape-fill-btn",i.title="Set shape color",i.setAttribute("aria-label",`Set shape color ${s}`),i.style.setProperty("--swatch",s),i.addEventListener("click",()=>this.setSelectedShapeFill(s)),this.shapeStylePopover.appendChild(i)}const n=document.createElement("div");n.className="context-tool-divider",this.shapeStylePopover.appendChild(n);for(const s of ti){const i=document.createElement("button");i.type="button",i.className="shape-text-color-btn",i.textContent=s.value==="#ffffff"?"W":"B",i.setAttribute("aria-label",s.label),i.addEventListener("click",()=>this.setSelectedShapeTextColor(s.value)),this.shapeStylePopover.appendChild(i)}this.bottomToolCluster.appendChild(this.shapeStylePopover),this.surface.interactionLayer.addEventListener("contextmenu",s=>this.openLayerMenu(s),{signal:e,capture:!0}),document.addEventListener("pointerdown",s=>{this.layerMenu&&!this.layerMenu.contains(s.target)&&this.closeLayerMenu()},{signal:e}),document.addEventListener("keydown",s=>{s.key==="Escape"&&this.closeLayerMenu()},{signal:e})}updateContextualToolPanels(){this.updateStickyColorPopover(),this.updateTextSizePopover(),this.updateShapeStylePopover()}setContextPanelVisible(t,e){t&&(t.classList.toggle("is-visible",e),t.setAttribute("aria-hidden",String(!e)))}updateStickyColorPopover(){var i;const t=this.stickyColorPopover;if(!t)return;const e=this.state.getSelected().filter(a=>a.type==="sticky"),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=(i=e[0])==null?void 0:i.style.fill;for(const a of t.children){const r=a,c=r.style.getPropertyValue("--swatch")===s;r.classList.toggle("active",c),r.setAttribute("aria-pressed",String(c))}}setSelectedStickyColor(t){go(t);const e=this.state.getSelected().filter(r=>r.type==="sticky"&&!r.locked);if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fill:r.style.fill,textColor:r.style.textColor,updatedAt:r.updatedAt})),i=e.map(r=>({id:r.id,fill:t,textColor:"#1f2933",updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fill=c.fill,l.style.textColor=c.textColor,l.updatedAt=c.updatedAt)}n.emitChange()};this.commands.execute("sticky-color",()=>a(i),()=>a(s))}updateTextSizePopover(){var i,a;const t=this.textSizePopover;if(!t)return;const e=this.selectedTextTargets(),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=((i=e[0])==null?void 0:i.style.fontSize)??(((a=e[0])==null?void 0:a.type)==="sticky"?15:16);for(const r of t.children){const c=r,l=Ve.find(h=>h.shortLabel===c.textContent),d=(l==null?void 0:l.fontSize)===s;c.classList.toggle("active",d),c.setAttribute("aria-pressed",String(d))}}selectedTextTargets(){return this.state.getSelected().filter(t=>Zo.has(t.type)&&!t.locked)}setSelectedTextSize(t){const e=this.selectedTextTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fontSize:r.style.fontSize,fontWeight:r.style.fontWeight,height:r.height,updatedAt:r.updatedAt})),i=e.map(r=>({id:r.id,fontSize:t.fontSize,fontWeight:t.fontWeight,height:r.type==="text"?Math.max(r.height,Math.ceil(t.fontSize*1.45)):r.height,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fontSize=c.fontSize,l.style.fontWeight=c.fontWeight,l.height=c.height,l.updatedAt=c.updatedAt,F(l.id))}n.emitChange()};this.commands.execute("text-size",()=>a(i),()=>a(s))}updateShapeStylePopover(){var a,r;const t=this.shapeStylePopover;if(!t)return;const e=this.selectedShapeTargets(),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=(a=e[0])==null?void 0:a.style.fill,i=((r=e[0])==null?void 0:r.style.textColor)??"#1f2933";for(const c of t.children){const l=c;if(l.classList.contains("shape-fill-btn")){const d=l.style.getPropertyValue("--swatch")===s;l.classList.toggle("active",d),l.setAttribute("aria-pressed",String(d))}if(l.classList.contains("shape-text-color-btn")){const h=l.textContent==="W"?i==="#ffffff":i!=="#ffffff";l.classList.toggle("active",h),l.setAttribute("aria-pressed",String(h))}}}selectedShapeTargets(){return this.state.getSelected().filter(t=>Jo.has(t.type)&&!t.locked)}setSelectedShapeFill(t){const e=this.selectedShapeTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fill:r.style.fill,updatedAt:r.updatedAt})),i=e.map(r=>({id:r.id,fill:t,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fill=c.fill,l.updatedAt=c.updatedAt)}n.emitChange()};this.commands.execute("shape-fill",()=>a(i),()=>a(s))}setSelectedShapeTextColor(t){const e=this.selectedShapeTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,textColor:r.style.textColor,updatedAt:r.updatedAt})),i=e.map(r=>({id:r.id,textColor:t,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.textColor=c.textColor,l.updatedAt=c.updatedAt,F(l.id))}n.emitChange()};this.commands.execute("shape-text-color",()=>a(i),()=>a(s))}openLayerMenu(t){if(t.preventDefault(),t.stopPropagation(),this.textEditor.isEditing)return;const e=R(t.clientX,t.clientY,this.state.viewport),n=this.hitTester.hitTest(e.x,e.y,this.state.viewport.scale);n&&!this.state.selectedIds.has(n.id)&&(this.state.clearSelection(),this.state.selectedIds.add(n.id),this.state.requestRender());const s=this.state.getSelected();if(s.length===0){this.closeLayerMenu();return}this.closeLayerMenu();const i=document.createElement("div");i.className="layer-menu",i.setAttribute("role","menu");const a=document.createElement("div");a.className="layer-menu-label",a.textContent=s.length===1?"Layer":`${s.length} layers`,i.appendChild(a);const r=(l,d)=>{const h=document.createElement("button");h.type="button",h.setAttribute("role","menuitem"),h.textContent=l,h.addEventListener("click",()=>{d(),this.closeLayerMenu()}),i.appendChild(h)},c=()=>{const l=document.createElement("div");l.className="layer-menu-divider",i.appendChild(l)};r("Bring forward",()=>this.actions.bringForward()),r("Send backward",()=>this.actions.sendBackward()),c(),r("Bring to front",()=>this.actions.bringToFront()),r("Send to back",()=>this.actions.sendToBack()),this.root.appendChild(i),this.layerMenu=i,this.positionLayerMenu(i,t.clientX,t.clientY)}positionLayerMenu(t,e,n){t.style.left="0px",t.style.top="0px",requestAnimationFrame(()=>{const i=t.getBoundingClientRect(),a=Math.min(Math.max(12,e),window.innerWidth-i.width-12),r=Math.min(Math.max(12,n),window.innerHeight-i.height-12);t.style.left=`${a}px`,t.style.top=`${r}px`})}closeLayerMenu(){var t;(t=this.layerMenu)==null||t.remove(),this.layerMenu=null}exitToDocs(){this.boardSaveTimer!==null&&(clearTimeout(this.boardSaveTimer),this.boardSaveTimer=null),this.saveBoard().finally(()=>{var t,e;return(e=(t=this.options).onExit)==null?void 0:e.call(t)})}startEmbedSelection(){Be.begin(this.root,t=>{t&&this.copyEmbedSnippet(t)})}async copyEmbedSnippet(t){const e=this.state.viewport,n=R(t.x,t.y,e),s=R(t.x+t.w,t.y+t.h,e),i=Math.round(n.x),a=Math.round(n.y),r=Math.round(s.x-n.x),c=Math.round(s.y-n.y),l=`\`\`\`board
11
+ src: /${this.state.boardId}
12
+ region: ${i}, ${a}, ${r}, ${c}
13
+ height: 360
14
+ title: ${this.state.title}
15
+ \`\`\``;try{await navigator.clipboard.writeText(l),w("Embed snippet copied — paste it into any doc")}catch{w("Could not access clipboard")}}setupDragDrop(t){t.addEventListener("dragover",e=>{e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="copy")}),t.addEventListener("drop",e=>{var n;e.preventDefault(),(n=e.dataTransfer)!=null&&n.files&&e.dataTransfer.files.length>0&&this.imageInsert.insertFiles(e.dataTransfer.files,e.clientX,e.clientY)})}async loadInitialState(){const t=Z.getPref("theme");if(t==="dark"||t==="light"?this.applyTheme(t):window.matchMedia("(prefers-color-scheme: dark)").matches&&this.applyTheme("dark"),this.options.loadBoard){try{const n=await this.options.loadBoard(this.options.boardId??this.state.boardId);n&&(this.applyDocument(n),this.fitInitialRegion())}catch(n){console.error("Board file load failed",n),w("Could not load board file")}this.state.requestRender();return}const e=Z.getPref("lastBoardId")??"default-board";try{const n=await Z.loadBoard(e);n&&this.applyDocument(n)}catch(n){console.error("Board recovery failed",n),Z.getPref("recovery")&&w("Could not load saved board — starting fresh")}this.state.requestRender()}applyDocument(t){this.state.boardId=t.id,this.state.title=t.title,this.state.createdAt=t.createdAt,this.state.viewport={...t.viewport},this.state.elements=[],this.state.elementsById.clear();for(const e of t.elements)this.state.addElement(e);this.applyTheme(t.theme),this.topControls.setTitle(t.title),this.topControls.setZoom(t.viewport.scale),this.state.invalidateSort()}fitInitialRegion(){const t=this.options.initialRegion;if(!t)return;const[e,n,s,i]=t;if(s<=0||i<=0)return;const a=Math.min(120,Math.max(48,this.surface.width*.08)),r=88,c=124,l=Math.max(240,this.surface.width-a*2),d=Math.max(180,this.surface.height-r-c),h=Math.min(l/s,d/i),p=Math.max(.7,Math.min(1.1,this.state.viewport.scale*1.15)),u=Mn(Math.min(h*.58,p));this.state.viewport={scale:u,offsetX:a+(l-s*u)/2-e*u,offsetY:r+(d-i*u)/2-n*u},this.topControls.setZoom(u)}scheduleBoardSave(){this.boardSaveTimer!==null&&clearTimeout(this.boardSaveTimer),this.boardSaveTimer=window.setTimeout(()=>{this.boardSaveTimer=null,this.saveBoard()},Vo)}scheduleViewportSave(){this.viewportSaveTimer===null&&(this.viewportSaveTimer=window.setTimeout(()=>{this.viewportSaveTimer=null,this.saveBoard()},Go))}async saveBoard(){try{this.options.saveBoard?await this.options.saveBoard(Xt(this.state)):await Z.saveBoard(Xt(this.state))}catch{w(this.options.saveBoard?"Save to file failed":"Save failed — browser storage may be full")}}applyTheme(t){var e;this.state.theme=t,document.documentElement.setAttribute("data-theme",t),Z.setPref("theme",t),(e=this.toolbar)==null||e.setTheme(t),this.state.requestRender()}toggleTheme(){this.applyTheme(this.state.theme==="dark"?"light":"dark"),this.scheduleBoardSave()}resetView(){this.state.viewport.offsetX=0,this.state.viewport.offsetY=0,this.state.viewport.scale=Tn,this.state.requestRender()}clearBoard(){const t=this.state,e=[...t.elements];this.commands.execute("clear-board",()=>{for(const n of e)t.removeElement(n.id);t.emitChange()},()=>{for(const n of e)t.elementsById.has(n.id)||t.addElement(n);t.emitChange()}),w("Board cleared")}async resetAllLocalData(){await Z.clearAllBoards(),await J.clearAll(),Z.clearPrefs(),this.imageCache.clear(),this.commands.clear(),this.state.elements=[],this.state.elementsById.clear(),this.state.clearSelection(),this.state.invalidateSort(),this.resetView(),w("All local data cleared")}confirmDeleteBoard(){O("Delete board?",(t,e)=>{const n=document.createElement("p");n.className="modal-copy",n.textContent=`This will permanently delete "${this.state.title}" from the active docs root. This cannot be undone.`;const s=document.createElement("div");s.className="modal-actions";const i=document.createElement("button");i.className="btn",i.textContent="Cancel",i.addEventListener("click",e);const a=document.createElement("button");a.className="btn danger",a.textContent="Delete board",a.addEventListener("click",async()=>{var r,c,l;a.disabled=!0,this.boardSaveTimer!==null&&(clearTimeout(this.boardSaveTimer),this.boardSaveTimer=null),this.viewportSaveTimer!==null&&(clearTimeout(this.viewportSaveTimer),this.viewportSaveTimer=null);try{await((c=(r=this.options).deleteBoard)==null?void 0:c.call(r,this.state.boardId)),e(),w("Board deleted"),(l=this.options.onDeleted??this.options.onExit)==null||l()}catch{a.disabled=!1,w("Could not delete board")}}),s.append(i,a),t.append(n,s)})}openExportMenu(){O("Export & import",(t,e)=>{const n=document.createElement("div");n.className="modal-actions",n.style.flexDirection="column",n.style.alignItems="stretch";const s=(i,a,r=!1)=>{const c=document.createElement("button");c.className="btn"+(r?" primary":""),c.textContent=i,c.addEventListener("click",()=>{a(),e()}),n.appendChild(c)};s("Export current view as PNG",async()=>{const i=await Js(this.state,this.imageCache,this.surface.width,this.surface.height);Oe(i,this.state.title+"-view.png")},!0),s("Export full board as PNG",async()=>{const i=await Qs(this.state,this.imageCache);i?Oe(i,this.state.title+"-board.png"):w("Board is empty")}),s("Export board JSON (no images)",()=>{ve.exportBoardJson(Xt(this.state))}),s("Export full bundle (JSON + images)",async()=>{await ve.exportFullBundle(Xt(this.state))}),s("Import board from file…",()=>this.pickImportFile()),t.appendChild(n)})}pickImportFile(){const t=document.createElement("input");t.type="file",t.accept="application/json,.json",t.onchange=async()=>{var s;const e=(s=t.files)==null?void 0:s[0];if(!e)return;const n=await ve.importFromFile(e);if(!n){w("Import failed — invalid board file");return}this.state.boardId=n.id,this.state.title=n.title,this.state.createdAt=n.createdAt,this.state.viewport={...n.viewport},this.state.elements=[],this.state.elementsById.clear(),this.state.clearSelection();for(const i of n.elements)this.state.addElement(i);this.applyTheme(n.theme),this.topControls.setTitle(n.title),this.commands.clear(),this.state.emitChange(),w("Board imported")},t.click()}}const Ge="/__api/asset?path=",Dn=new Set(["P","DIV","UL","OL","H1","H2","H3","H4","H5","H6","BLOCKQUOTE","PRE","TABLE","FIGURE","HR"]);function ni(o){const t=[];for(const e of Array.from(o.childNodes))Ie(t,e);return t.map(e=>e.replace(/[ \t]+$/gm,"")).join(`
16
+
17
+ `).replace(/\n{3,}/g,`
18
+
19
+ `).trim()+`
20
+ `}function Ie(o,t){const e=si(t);e!==null&&e.trim()!==""&&o.push(e)}function si(o){if(o.nodeType===Node.TEXT_NODE){const n=(o.textContent??"").trim();return n||null}if(o.nodeType!==Node.ELEMENT_NODE)return null;const t=o,e=t.tagName;switch(e){case"H1":case"H2":case"H3":case"H4":case"H5":case"H6":return"#".repeat(Number(e[1]))+" "+at(t).trim();case"HR":return"---";case"P":return t.classList.contains("embed-caret-spacer")&&!ii(t)?null:Je(t)?Qe(t):Se(at(t).trim());case"BLOCKQUOTE":return Ze(t).split(`
21
+ `).map(s=>s?`> ${s}`:">").join(`
22
+ `);case"UL":return oe(t,!1,0);case"OL":return oe(t,!0,0);case"PRE":{const n=t.querySelector("code"),s=li(n??t),i=(n??t).textContent??"";return"```"+s+`
23
+ `+i.replace(/\n$/,"")+"\n```"}case"TABLE":return ai(t);case"FIGURE":return t.classList.contains("board-embed")?ri(t):Ze(t)||null;case"DIV":return Je(t)?Qe(t):Se(at(t).trim());case"BR":return null;default:return at(t).trim()||null}}function Ze(o){const t=[];for(const e of Array.from(o.childNodes))Ie(t,e);return t.join(`
24
+
25
+ `)}function Je(o){for(const t of Array.from(o.children))if(Dn.has(t.tagName))return!0;return!1}function Qe(o){const t=[];let e="";const n=()=>{const s=Se(e.trim());s&&t.push(s),e=""};for(const s of Array.from(o.childNodes)){if(oi(s)){n(),Ie(t,s);continue}e+=Le(s)}return n(),t.join(`
26
+
27
+ `)||null}function oi(o){return o.nodeType===Node.ELEMENT_NODE&&Dn.has(o.tagName)}function ii(o){for(const t of Array.from(o.childNodes)){if(t.nodeType===Node.TEXT_NODE&&(t.textContent??"").trim())return!0;if(t.nodeType!==Node.ELEMENT_NODE)continue;const e=t;if(e.tagName!=="BR"&&((e.textContent??"").trim()||["IMG","FIGURE","HR"].includes(e.tagName)))return!0}return!1}function oe(o,t,e){const n=[],s=" ".repeat(e);let i=0;for(const a of Array.from(o.children)){if(a.tagName!=="LI")continue;i++;const r=t?`${i}. `:"- ";let c="";const l=[];let d=null;for(const h of Array.from(a.childNodes)){if(h.nodeType===Node.ELEMENT_NODE){const p=h;if(p.tagName==="UL"){l.push(oe(p,!1,e+1));continue}if(p.tagName==="OL"){l.push(oe(p,!0,e+1));continue}if(p.tagName==="INPUT"){d=p.checked?"[x] ":"[ ] ";continue}}c+=Le(h)}n.push(s+r+(d??"")+c.trim());for(const h of l)h&&n.push(h)}return n.join(`
28
+ `)}function ai(o){const t=Array.from(o.querySelectorAll("tr"));if(t.length===0)return"";const e=i=>Array.from(i.querySelectorAll("th,td")).map(a=>at(a).trim()),n=e(t[0]),s=[];s.push("| "+n.join(" | ")+" |"),s.push("| "+n.map(()=>"---").join(" | ")+" |");for(let i=1;i<t.length;i++)s.push("| "+e(t[i]).join(" | ")+" |");return s.join(`
29
+ `)}function ri(o){const t=["```board",`src: ${o.dataset.src??""}`];return o.dataset.region&&t.push(`region: ${o.dataset.region.split(",").map(e=>e.trim()).join(", ")}`),o.dataset.height&&t.push(`height: ${o.dataset.height}`),o.dataset.title&&t.push(`title: ${o.dataset.title}`),t.push("```"),t.join(`
30
+ `)}function at(o){let t="";for(const e of Array.from(o.childNodes))t+=Le(e);return t}function Le(o){if(o.nodeType===Node.TEXT_NODE)return en(o.textContent??"");if(o.nodeType!==Node.ELEMENT_NODE)return"";const t=o;switch(t.tagName){case"STRONG":case"B":return tn("**",at(t));case"EM":case"I":return tn("*",at(t));case"CODE":return di(t.textContent??"");case"A":{const e=(t.getAttribute("data-md-href")??t.getAttribute("href")??"").trim(),n=at(t).trim()||en(e);return e?`[${nn(n)}](${sn(e)})`:n}case"IMG":return`![${nn(t.alt)}](${sn(ci(t))})`;case"BR":return`
31
+ `;default:return at(t)}}function ci(o){const t=o.getAttribute("data-md-src");if(t)return t;const e=o.getAttribute("src")??"";return e.startsWith(Ge)?decodeURIComponent(e.slice(Ge.length)):e}function li(o){const e=(o.getAttribute("class")??"").match(/language-(\w+)/);return e?e[1]:""}function tn(o,t){const e=t.trim();return e?`${o}${e}${o}`:""}function di(o){if(!o.includes("`"))return"`"+o+"`";const t=Math.max(...(o.match(/`+/g)??[""]).map(n=>n.length)),e="`".repeat(t+1);return`${e} ${o} ${e}`}function en(o){return o.replace(/\\/g,"\\\\").replace(/\[/g,"\\[").replace(/\]/g,"\\]").replace(/\*/g,"\\*").replace(/_/g,"\\_").replace(/`/g,"\\`")}function Se(o){return o?/^#{1,6}\s/.test(o)||/^>\s?/.test(o)||/^([-+*]|\d+\.)\s+/.test(o)||/^`{3,}/.test(o)||/^(-{3,}|\*{3,}|_{3,})$/.test(o)?"\\"+o:o:null}function nn(o){return o.replace(/\\/g,"\\\\").replace(/\]/g,"\\]")}function sn(o){return o.trim().replace(/\s/g,"%20").replace(/\)/g,"%29").replace(/</g,"%3C").replace(/>/g,"%3E")}class Re{constructor(t){m(this,"opts");m(this,"overlay");m(this,"surface");m(this,"statusEl");m(this,"fileInput");m(this,"toolbarButtons",[]);m(this,"abort",new AbortController);m(this,"frontmatter","");m(this,"saveTimer",null);m(this,"closed",!1);m(this,"history",[]);m(this,"historyIndex",-1);m(this,"applyingHistory",!1);this.opts=t,this.build(),this.load()}static open(t){return new Re(t)}build(){this.overlay=st("doc-editor");const t=st("doc-editor-bar"),e=st("doc-editor-bar-left"),n=on("doc-editor-done","Done");n.addEventListener("click",()=>void this.close());const s=st("doc-editor-path");s.textContent=this.opts.path,e.append(n,s),this.statusEl=st("doc-editor-status"),this.setStatus("idle"),t.append(e,this.statusEl);const i=this.buildToolbar(),a=st("doc-editor-scroll");this.surface=st("markdown-body doc-editor-surface"),this.surface.contentEditable="true",this.surface.spellcheck=!0,a.appendChild(this.surface),this.fileInput=document.createElement("input"),this.fileInput.type="file",this.fileInput.accept="image/*",this.fileInput.style.display="none",this.fileInput.addEventListener("change",()=>{var l;const c=(l=this.fileInput.files)==null?void 0:l[0];c&&this.insertImageFile(c),this.fileInput.value=""}),this.overlay.append(t,i,a,this.fileInput),document.body.appendChild(this.overlay);const r=this.abort.signal;this.surface.addEventListener("input",()=>this.handleInput(),{signal:r}),this.surface.addEventListener("keyup",()=>this.updateToolbarState(),{signal:r}),this.surface.addEventListener("mouseup",()=>this.updateToolbarState(),{signal:r}),this.surface.addEventListener("click",c=>this.handleSurfaceClick(c),{signal:r}),document.addEventListener("selectionchange",()=>this.updateToolbarState(),{signal:r}),this.surface.addEventListener("paste",c=>this.onPaste(c),{signal:r}),this.surface.addEventListener("dragover",c=>c.preventDefault(),{signal:r}),this.surface.addEventListener("drop",c=>this.onDrop(c),{signal:r}),window.addEventListener("keydown",c=>{if(c.key==="Escape"&&document.activeElement!==this.surface&&this.close(),(c.metaKey||c.ctrlKey)&&c.key.toLowerCase()==="s"&&(c.preventDefault(),this.save()),(c.metaKey||c.ctrlKey)&&c.key.toLowerCase()==="z"){c.preventDefault(),c.shiftKey?this.redoHistory():this.undoHistory();return}if(c.ctrlKey&&!c.metaKey&&c.key.toLowerCase()==="y"){c.preventDefault(),this.redoHistory();return}this.handleEmbedDeleteKey(c)},{signal:r})}buildToolbar(){const t=st("doc-editor-toolbar"),e=s=>{const i=st("doc-editor-tb-group");return i.append(...s),i},n=(s,i,a,r=!1)=>{const c=on("doc-editor-tb-btn",r?"":s);return r&&(c.innerHTML=K[s]??"",c.classList.add("icon")),c.title=i,c.addEventListener("mousedown",l=>{l.preventDefault(),this.surface.focus(),a(),this.updateToolbarState(),this.scheduleSave()}),this.toolbarButtons.push(c),c};return t.append(e([n("¶","Paragraph",()=>this.formatBlock("P")),ot(n("H1","Heading 1",()=>this.formatBlock("H1")),"block","H1"),ot(n("H2","Heading 2",()=>this.formatBlock("H2")),"block","H2"),ot(n("H3","Heading 3",()=>this.formatBlock("H3")),"block","H3")]),e([ot(n("B","Bold (Cmd+B)",()=>document.execCommand("bold")),"command","bold"),ot(n("I","Italic (Cmd+I)",()=>document.execCommand("italic")),"command","italic"),ot(n("</>","Inline code",()=>this.toggleInlineCode()),"inline","CODE")]),e([ot(n("❝","Quote",()=>this.formatBlock("BLOCKQUOTE")),"block","BLOCKQUOTE"),ot(n("•","Bulleted list",()=>document.execCommand("insertUnorderedList")),"command","insertUnorderedList"),ot(n("1.","Numbered list",()=>document.execCommand("insertOrderedList")),"command","insertOrderedList"),n("{ }","Code block",()=>this.insertCodeBlock())]),e([n("↗","Link",()=>this.insertLink()),n("image","Image",()=>this.fileInput.click(),!0),n("―","Divider",()=>document.execCommand("insertHorizontalRule"))])),t}async load(){let t="";try{t=await k.readFile(this.opts.rootId,this.opts.path)}catch{this.surface.innerHTML="<p></p>",this.setStatus("error","Could not load file");return}const{fm:e,body:n}=hi(t);this.frontmatter=e;const{html:s}=Wt(n,{rootId:this.opts.rootId,docPath:this.opts.path});this.surface.innerHTML=s||"<p></p>",this.decorateEmbeds(),document.execCommand("defaultParagraphSeparator",!1,"p"),this.recordHistorySnapshot(!0),this.updateToolbarState()}decorateEmbeds(){this.normalizeEmbedSpacing(),this.surface.querySelectorAll("figure.board-embed").forEach(t=>{t.contentEditable="false",t.tabIndex=0,t.setAttribute("role","button"),t.setAttribute("aria-label",`Board embed ${t.dataset.src??""}. Press Delete to remove.`),t.classList.add("embed-chip");const e=t.dataset.region?" · region":"";t.innerHTML=`<span class="embed-chip-icon">▦</span> Board embed: <strong>${t.dataset.src??""}</strong>${e}<span class="embed-chip-remove" aria-hidden="true">Delete</span>`,this.ensureEmbedCaretSpace(t)})}ensureEmbedCaretSpace(t){gt(t.previousElementSibling)||t.before(Nt()),gt(t.nextElementSibling)||t.after(Nt())}normalizeEmbedSpacing(){const t=Array.from(this.surface.querySelectorAll("figure.board-embed"));for(const n of t)an(n.previousElementSibling),an(n.nextElementSibling);let e=!1;for(const n of Array.from(this.surface.children)){if(!gt(n)){e=!1;continue}if(Pn(n)){n.classList.remove("embed-caret-spacer"),e=!1;continue}if(e){n.remove();continue}e=!0}}handleSurfaceClick(t){const e=t.target,n=e==null?void 0:e.closest("figure.board-embed.embed-chip");!n||!this.surface.contains(n)||(t.preventDefault(),this.selectEmbed(n))}selectEmbed(t){this.surface.querySelectorAll(".embed-chip.selected").forEach(s=>s.classList.remove("selected")),t.classList.add("selected");const e=document.createRange();e.selectNode(t);const n=window.getSelection();n==null||n.removeAllRanges(),n==null||n.addRange(e),t.focus()}clearEmbedSelection(){this.surface.querySelectorAll(".embed-chip.selected").forEach(t=>t.classList.remove("selected"))}handleEmbedDeleteKey(t){if(t.key!=="Backspace"&&t.key!=="Delete")return!1;const e=document.activeElement,s=(e==null?void 0:e.closest("figure.board-embed.embed-chip.selected"))??this.surface.querySelector("figure.board-embed.embed-chip.selected")??this.embedAdjacentToCaret(t.key);if(!s||!this.surface.contains(s))return!1;t.preventDefault();const i=t.key==="Backspace"?s.previousElementSibling:s.nextElementSibling;return s.remove(),this.clearEmbedSelection(),this.placeCaretInBlock(gt(i)?i:this.surface),this.recordHistorySnapshot(),this.scheduleSave(),!0}embedAdjacentToCaret(t){const e=window.getSelection();if(!e||e.rangeCount===0||!e.isCollapsed)return null;const n=e.anchorNode,s=pi(n,"P");if(!s||!this.surface.contains(s)||!gt(s))return null;const i=t==="Backspace"?s.previousElementSibling:s.nextElementSibling;return i instanceof HTMLElement&&i.matches("figure.board-embed.embed-chip")?i:null}handleInput(){this.applyingHistory||(this.clearEmbedSelection(),this.recordHistorySnapshot(),this.scheduleSave())}placeCaretInBlock(t){const e=document.createRange();e.selectNodeContents(t),e.collapse(!1);const n=window.getSelection();n==null||n.removeAllRanges(),n==null||n.addRange(e),this.surface.focus()}scheduleSave(){this.normalizeEmbedSpacing(),this.saveTimer!==null&&clearTimeout(this.saveTimer),this.setStatus("saving"),this.saveTimer=window.setTimeout(()=>{this.saveTimer=null,this.save()},700)}async save(){this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),this.normalizeEmbedSpacing();const t=ni(this.surface),e=this.frontmatter?`${this.frontmatter}
32
+
33
+ ${t}`:t;try{this.setStatus("saving"),await k.writeFile(this.opts.rootId,this.opts.path,e),this.setStatus("saved")}catch{this.setStatus("error","Save failed")}}async close(){this.closed||(this.closed=!0,await this.save(),this.abort.abort(),this.overlay.remove(),this.opts.onClose())}formatBlock(t){document.execCommand("formatBlock",!1,`<${t}>`)}insertLink(){const t=window.getSelection(),e=t&&!t.isCollapsed?t.toString().trim():"",n=window.prompt("Link URL","https://");if(!n)return;const s=n.trim();s&&(e?document.execCommand("createLink",!1,s):document.execCommand("insertHTML",!1,`<a href="${cn(s)}">${yi(s)}</a>`))}toggleInlineCode(){const t=window.getSelection();if(!t||t.rangeCount===0||t.isCollapsed)return;const e=t.getRangeAt(0),n=xe(e.commonAncestorContainer,"CODE");if(n){const i=n.parentNode;for(;n.firstChild;)i.insertBefore(n.firstChild,n);i.removeChild(n);return}const s=document.createElement("code");s.appendChild(e.extractContents()),e.insertNode(s),e.setStartAfter(s),e.collapse(!0),t.removeAllRanges(),t.addRange(e)}insertCodeBlock(){document.execCommand("insertHTML",!1,'<pre class="code-block"><code>code</code></pre><p><br></p>')}updateToolbarState(){const t=window.getSelection(),e=(t==null?void 0:t.anchorNode)??null,n=!!e&&this.surface.contains(e);for(const s of this.toolbarButtons){const i=s.dataset.stateType,a=s.dataset.stateValue;let r=!1;if(n&&i==="command"&&a)try{r=document.queryCommandState(a)}catch{r=!1}else(n&&i==="block"&&a||n&&i==="inline"&&a)&&(r=!!xe(e,a));s.classList.toggle("active",r),s.setAttribute("aria-pressed",r?"true":"false")}}onPaste(t){var s,i;const e=bi(((s=t.clipboardData)==null?void 0:s.getData("text/plain"))??"");if(e){t.preventDefault(),this.insertSpecialBlock(e);return}const n=(i=t.clipboardData)==null?void 0:i.items;if(n){for(const a of n)if(a.type.startsWith("image/")){const r=a.getAsFile();if(r){t.preventDefault(),this.insertImageFile(r);return}}}}insertSpecialBlock(t){this.surface.focus();const e=xi(t);this.insertBlockNode(e),this.decorateEmbeds(),this.selectEmbed(e),this.recordHistorySnapshot(),this.updateToolbarState(),this.scheduleSave()}insertBlockNode(t){const e=window.getSelection(),n=e&&e.rangeCount>0?e.getRangeAt(0):null;if(!n||!this.surface.contains(n.commonAncestorContainer)){this.surface.append(t,Nt()),this.placeCaretInBlock(this.surface.lastElementChild??this.surface);return}const s=ui(this.surface,n.commonAncestorContainer);if(s&&mi(s)&&!gt(s)){this.replaceBlockWithInsertedNode(s,n,t);return}n.deleteContents();const i=Nt();n.insertNode(i),n.insertNode(t),this.placeCaretInBlock(i)}replaceBlockWithInsertedNode(t,e,n){const s=document.createRange();s.selectNodeContents(t),s.setEnd(e.startContainer,e.startOffset);const i=document.createRange();i.selectNodeContents(t),i.setStart(e.endContainer,e.endOffset);const a=rn(t,s.cloneContents()),r=rn(t,i.cloneContents()),c=t.parentNode;if(!c)return;a&&c.insertBefore(a,t),c.insertBefore(n,t),r&&c.insertBefore(r,t),c.removeChild(t);const l=r??Nt();r||c.insertBefore(l,n.nextSibling),this.placeCaretInBlock(l)}onDrop(t){var n,s;const e=(s=(n=t.dataTransfer)==null?void 0:n.files)==null?void 0:s[0];e&&e.type.startsWith("image/")&&(t.preventDefault(),this.insertImageFile(e))}async insertImageFile(t){this.setStatus("saving","Uploading image…");try{const e=await gi(t),n=await k.uploadAsset(this.opts.rootId,t.name,e),s=Te(this.opts.path,n),i=k.assetUrl(this.opts.rootId,n),a=t.name.replace(/\.[^.]+$/,"");this.surface.focus(),document.execCommand("insertHTML",!1,`<img src="${i}" data-md-src="${s}" alt="${cn(a)}" /><p><br></p>`),this.recordHistorySnapshot(),await this.save()}catch{this.setStatus("error","Image upload failed")}}recordHistorySnapshot(t=!1){if(this.applyingHistory)return;this.normalizeEmbedSpacing();const e=this.surface.innerHTML;if(t){this.history=[e],this.historyIndex=0;return}this.history[this.historyIndex]!==e&&(this.history=this.history.slice(0,this.historyIndex+1),this.history.push(e),this.history.length>100&&this.history.shift(),this.historyIndex=this.history.length-1)}undoHistory(){this.historyIndex<=0||this.applyHistorySnapshot(this.historyIndex-1)}redoHistory(){this.historyIndex>=this.history.length-1||this.applyHistorySnapshot(this.historyIndex+1)}applyHistorySnapshot(t){const e=this.history[t];e!==void 0&&(this.applyingHistory=!0,this.historyIndex=t,this.surface.innerHTML=e,this.decorateEmbeds(),this.clearEmbedSelection(),this.placeCaretInBlock(this.surface.lastElementChild??this.surface),this.applyingHistory=!1,this.updateToolbarState(),this.scheduleSave())}setStatus(t,e){const n={idle:"",saving:e??"Saving…",saved:"Saved",error:e??"Couldn't save"};this.statusEl.textContent=n[t],this.statusEl.dataset.state=t}}function st(o){const t=document.createElement("div");return t.className=o,t}function on(o,t){const e=document.createElement("button");return e.className=o,e.textContent=t,e}function ot(o,t,e){return o.dataset.stateType=t,o.dataset.stateValue=e,o.setAttribute("aria-pressed","false"),o}function Nt(){const o=document.createElement("p");return o.className="embed-caret-spacer",o.appendChild(document.createElement("br")),o}function gt(o){return!!o&&o.tagName==="P"&&o.classList.contains("embed-caret-spacer")}function an(o){gt(o)&&Pn(o)&&o.classList.remove("embed-caret-spacer")}function Pn(o){for(const t of Array.from(o.childNodes)){if(t.nodeType===Node.TEXT_NODE&&(t.textContent??"").trim())return!0;if(t.nodeType!==Node.ELEMENT_NODE)continue;const e=t;if(e.tagName!=="BR"&&((e.textContent??"").trim()||["IMG","FIGURE","HR"].includes(e.tagName)))return!0}return!1}function hi(o){if(!o.startsWith("---"))return{fm:"",body:o};const t=o.indexOf(`
34
+ ---`,3);if(t===-1)return{fm:"",body:o};const e=o.slice(0,t+4),n=o.slice(t+4).replace(/^\n+/,"");return{fm:e,body:n}}function xe(o,t){let e=o;for(;e;){if(e.nodeType===Node.ELEMENT_NODE&&e.tagName===t)return e;e=e.parentNode}return null}function pi(o,t){let e=o;for(;e;){if(e.nodeType===Node.ELEMENT_NODE&&e.matches(t))return e;e=e.parentNode}return null}function ui(o,t){let e=t;for(;e&&e.parentNode!==o;)e=e.parentNode;return e instanceof HTMLElement?e:null}function mi(o){return o.tagName==="P"||o.tagName==="DIV"}function rn(o,t){if(!fi(t))return null;const e=document.createElement(o.tagName);return o.tagName==="P"&&o.classList.contains("embed-caret-spacer")&&(e.className="embed-caret-spacer"),e.appendChild(t),e}function fi(o){for(const t of Array.from(o.childNodes)){if(t.nodeType===Node.TEXT_NODE&&(t.textContent??"").trim())return!0;if(t.nodeType!==Node.ELEMENT_NODE)continue;const e=t;if(e.tagName!=="BR"&&!(e.tagName==="P"&&e.classList.contains("embed-caret-spacer"))&&((e.textContent??"").trim()||["IMG","FIGURE","HR"].includes(e.tagName)))return!0}return!1}function gi(o){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(o)})}function cn(o){return o.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;")}function yi(o){return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}const vi={board:o=>{const t=kn(o);return t.src?{kind:"board",src:t.src,region:t.region,height:t.height,title:t.title}:null}};function bi(o){const t=wi(o);if(!t)return null;const e=vi[t.language];return e?e(t.body):null}function wi(o){const e=o.trim().match(/^(`{3,})\s*([^\s`]+)?\s*\n([\s\S]*?)\n\1\s*$/);return e?{language:(e[2]??"").toLowerCase(),body:e[3]}:null}function xi(o){switch(o.kind){case"board":return Ci(o)}}function Ci(o){const t=document.createElement("figure");return t.className="board-embed",t.dataset.src=o.src,t.dataset.height=String(o.height),o.region&&(t.dataset.region=o.region.join(",")),o.title&&(t.dataset.title=o.title),t}const ln="docs:theme",dn="docs:sidebar-collapsed",Ce=[{group:"Brand Colors",name:"100",variable:"--brand-100",value:"#FFFFFF",description:"lightest brand tone"},{group:"Brand Colors",name:"200",variable:"--brand-200",value:"#4DABF7",description:"light azure accent"},{group:"Brand Colors",name:"300",variable:"--brand-300",value:"#0078D4",description:"primary azure blue"},{group:"Brand Colors",name:"400",variable:"--brand-400",value:"#495057",description:"deep slate gray"},{group:"Brand Colors",name:"500",variable:"--brand-500",value:"#0078D4",description:"primary azure blue"},{group:"Brand Colors",name:"600",variable:"--brand-600",value:"#005A9E",description:"darker azure blue"},{group:"Neutral Colors",name:"100",variable:"--neutral-100",value:"#F3F2F1",description:"page background"},{group:"Neutral Colors",name:"200",variable:"--neutral-200",value:"#EAEAEA",description:"subtle surface"},{group:"Neutral Colors",name:"300",variable:"--neutral-300",value:"#D1D1D1",description:"soft border"},{group:"Neutral Colors",name:"400",variable:"--neutral-400",value:"#C8C8C8",description:"medium gray"},{group:"Neutral Colors",name:"500",variable:"--neutral-500",value:"#6E6E6E",description:"neutral mid-tone"},{group:"Neutral Colors",name:"600",variable:"--neutral-600",value:"#7A7A7A",description:"secondary text"},{group:"Neutral Colors",name:"700",variable:"--neutral-700",value:"#495057",description:"deep slate gray"},{group:"Neutral Colors",name:"800",variable:"--neutral-800",value:"#4A4A4A",description:"strong text"},{group:"Neutral Colors",name:"900",variable:"--neutral-900",value:"#0F0F0F",description:"primary text"},{group:"Neutral Colors",name:"000",variable:"--neutral-000",value:"#FFFFFF",description:"white"},{group:"Semantic Colors",name:"Success Main",variable:"--success-main",value:"#28A745",description:"positive actions"},{group:"Semantic Colors",name:"Success Background",variable:"--success-bg",value:"#E6F4EA",description:"positive surface"},{group:"Semantic Colors",name:"Success Text",variable:"--success-text",value:"#1E7E34",description:"positive text"},{group:"Semantic Colors",name:"Warning Main",variable:"--warning-main",value:"#DC2626",description:"warning actions"},{group:"Semantic Colors",name:"Warning Background",variable:"--warning-bg",value:"#FEF2F2",description:"warning surface"},{group:"Semantic Colors",name:"Warning Text",variable:"--warning-text",value:"#FFFFFF",description:"warning text"},{group:"Semantic Colors",name:"Error Main",variable:"--error-main",value:"#CD0000",description:"destructive actions"},{group:"Semantic Colors",name:"Error Background",variable:"--error-bg",value:"#FFE5E5",description:"destructive surface"},{group:"Semantic Colors",name:"Error Text",variable:"--error-text",value:"#B91C1C",description:"destructive text"},{group:"Semantic Colors",name:"Info Main",variable:"--info-main",value:"#1080A6",description:"informational actions"},{group:"Semantic Colors",name:"Info Background",variable:"--info-bg",value:"#E0F7FA",description:"informational surface"},{group:"Semantic Colors",name:"Info Text",variable:"--info-text",value:"#0369A1",description:"informational text"}];class ki{constructor(t){m(this,"root");m(this,"layout");m(this,"main");m(this,"topbar");m(this,"contentScroll");m(this,"content");m(this,"sidebar");m(this,"searchBtn");m(this,"cartBtn");m(this,"editBtn");m(this,"themeBtn");m(this,"palette");m(this,"paletteInput");m(this,"paletteResults");m(this,"cartPopover");m(this,"searchIndex",[]);m(this,"capabilityCart",new Map);m(this,"selectedTokens",new Set);m(this,"currentEditableFile");m(this,"workspace",{projects:[]});m(this,"treesByRoot",new Map);m(this,"treesByProject",new Map);m(this,"cleanup");m(this,"editor");m(this,"editorHost");m(this,"editingId");m(this,"lastNonBoardHash","#/");m(this,"lastNonBoardScrollTop",0);m(this,"pendingScrollRestore");this.root=t,this.applyInitialTheme(),this.layout=f("div","shell");const e={onAddRepo:()=>void this.addRepoDocs(),onRemoveProject:(n,s)=>void this.promptRemoveProject(n,s),onCreateDirectory:(n,s)=>this.promptNewDirectory(n,s),onCreateDoc:(n,s)=>this.promptNewDoc(n,s),onCreateBoard:(n,s)=>this.promptNewBoard(n,s),onCreateCapability:(n,s)=>this.promptNewCapability(n,s),onCreateDocsFolder:(n,s)=>void this.createDocsFolder(n,s),onCreateProjectDirectory:n=>void this.promptNewProjectDirectory(n),onCreateProjectDoc:n=>void this.promptNewProjectDoc(n),onCreateProjectBoard:n=>void this.promptNewProjectBoard(n),onRenameDirectory:(n,s)=>void this.promptRenameDirectory(n,s),onDeleteDirectory:(n,s)=>void this.promptDeleteDirectory(n,s),onOpenDoc:(n,s)=>{location.hash=W(n,s)},onEditDoc:(n,s)=>this.openDocEditor({rootId:n,path:s}),onRenameDoc:(n,s)=>void this.promptRenameDoc(n,s),onDeleteDoc:(n,s)=>void this.promptDeleteDoc(n,s),onOpenBoard:(n,s)=>{location.hash=q(n,s)},onRenameBoard:(n,s)=>void this.promptRenameBoard(n,s),onDeleteBoard:(n,s)=>void this.promptDeleteBoard(n,s),onMoveDoc:(n,s,i)=>void this.moveDoc(n,s,i),onMoveBoard:(n,s,i)=>void this.moveBoard(n,s,i),onMoveDirectory:(n,s,i)=>void this.moveDirectory(n,s,i)};this.sidebar=new es(this.layout,e),this.main=f("div","shell-main"),this.topbar=this.createTopbar(),this.contentScroll=f("div","content-scroll"),this.content=f("div","content"),this.contentScroll.appendChild(this.content),this.main.append(this.topbar,this.contentScroll),this.layout.appendChild(this.main),this.root.appendChild(this.layout),window.addEventListener("hashchange",()=>this.route()),window.addEventListener("keydown",n=>this.handleGlobalKeydown(n)),localStorage.getItem(dn)==="true"&&this.setSidebarCollapsed(!0),this.refreshContentIndex().then(()=>this.route())}route(t={}){const e=t.preserveScroll?this.contentScroll.scrollTop:this.pendingScrollRestore;this.pendingScrollRestore=void 0;const n=location.hash||"#/";this.sidebar.setActive(n);const s=n.replace(/^#/,"");this.setEditableFile(void 0);const i=s.match(/^\/root\/([^/]+)\/boards\/([^?]+)(?:\?(.*))?$/);if(i){this.lastNonBoardScrollTop=this.contentScroll.scrollTop,this.updateTopbarCart(!0),this.closeCartPopover(),this.openEditor(decodeURIComponent(i[1]),decodeURIComponent(i[2]),zi(i[3]));return}if(this.lastNonBoardHash=n,this.exitEditor(),this.layout.style.display="",this.updateTopbarCart(/\/root\/[^/]+\/boards/.test(s)),/\/root\/[^/]+\/boards/.test(s)&&this.closeCartPopover(),s==="/"||s==="")return void this.renderWorkspaceHome(e);const a=s.match(/^\/root\/([^/]+)\//);if(a){const g=decodeURIComponent(a[1]);if(!this.docsRootById(g))return void this.renderMessage("Project not found","This link points to a docs root that isn't in your workspace. Add the project and try again.")}const r=s.match(/^\/root\/([^/]+)\/docs\/(.+)$/);if(r)return void this.renderDoc(decodeURIComponent(r[1]),decodeURIComponent(r[2]),e);const c=s.match(/^\/root\/([^/]+)\/boards$/);if(c)return void this.renderBoardList(decodeURIComponent(c[1]),e);const l=s.match(/^\/project\/([^/]+)\/boards$/);if(l)return void this.renderProjectBoardList(decodeURIComponent(l[1]),e);const d=s.match(/^\/root\/([^/]+)\/capabilities$/);if(d)return void this.renderCapabilitiesIndex(decodeURIComponent(d[1]),e);const h=s.match(/^\/root\/([^/]+)\/capabilities\/(.+)$/);if(h)return void this.renderCapabilityDoc(decodeURIComponent(h[1]),decodeURIComponent(h[2]),e);const p=s.match(/^\/project\/([^/]+)$/);if(p)return void this.renderProjectWiki(decodeURIComponent(p[1]),e);const u=s.match(/^\/root\/([^/]+)\/directory\/(.+)$/);if(u){const g=decodeURIComponent(u[1]),y=decodeURIComponent(u[2]),v=this.docsRootById(g);if(v)return void this.renderProjectWiki(v.projectId,e,g,y)}if(s==="/tokens")return void this.renderTokenLibrary(e);this.renderMessage("Not found",`No route for ${s}`)}async renderWorkspaceHome(t){this.disposeContent(),this.content.classList.add("content-wide");const e=f("div","page home-page"),n=f("div","home-layout"),s=f("div","home-guide"),i=f("h1","home-hero-title");i.textContent="ViteBoard";const a=f("p","home-hero-sub");a.textContent="A local-first documentation workspace and infinite-canvas whiteboard. Markdown files, boards, and structured capability specs — plain files on disk, tracked by git.",s.append(i,a);const r=[{label:"Docs",kind:"doc",body:"Markdown files discovered inside any docs/ directory you register. The sidebar builds a live tree from the filesystem — create, rename, and delete docs by right-clicking any directory or file.",items:["Standard markdown: headings, lists, tables, code blocks, blockquotes, images, links","Inline board previews via fenced board blocks","Full-text search across all docs — Cmd K / Ctrl K"]},{label:"Boards",kind:"board",body:"Infinite-canvas editors saved as JSON files alongside your docs. Open from the sidebar, edit in full-screen, close to return. Boards are small, diffable, and git-native.",items:["Elements: sticky notes, tasks, shapes, text, arrows, images, frames","Embed any board region into a doc with a fenced board block",'Click "Copy embed" inside the board editor to get the exact region snippet',"Cmd/Ctrl + scroll to zoom · Shift + scroll to pan"]},{label:"Capabilities",kind:"capability",body:"Structured markdown specs with YAML frontmatter (title, summary, tags). Build a cart of specs you need for a task and copy them as a single combined prompt.",items:["Add any spec to the component cart from the sidebar or the capabilities page","Cart lives in the topbar — click to open, review, or copy the prompt","Copied prompt includes all selected specs formatted for an LLM"]},{label:"Search",kind:"",body:"Full-text search across every doc and capability in every registered project. Indexed at startup and refreshed after any content change.",items:["Cmd K / Ctrl K to open from anywhere","Ranked by title, path, headings, and body text","Arrow keys to navigate · Enter to open · Escape to close"]}];for(const y of r){const v=f("div","home-feature"),b=f("div","home-feature-header"),x=f("span",`home-feature-badge home-feature-badge-${y.kind||"neutral"}`);x.textContent=y.label,b.appendChild(x),v.appendChild(b);const S=f("p","home-feature-body");if(S.textContent=y.body,v.appendChild(S),y.items){const C=document.createElement("ul");C.className="home-feature-list";for(const E of y.items){const T=document.createElement("li");T.textContent=E,C.appendChild(T)}v.appendChild(C)}s.appendChild(v)}const c=f("div","home-shortcut-title");c.textContent="Shortcuts & interactions",s.appendChild(c);const l=[["Cmd K / Ctrl K","Open search"],["Right-click project header","Remove from workspace"],["Right-click directory","New doc · New board · New capability"],["Right-click doc","Open · Edit · Rename · Delete"],["Right-click board","Open · Rename · Delete"],["Cmd/Ctrl + scroll on board","Zoom"],["Shift + scroll on board","Pan"],["Copy embed (board toolbar)","Snippet for current view region"]],d=f("div","home-shortcut-table");for(const[y,v]of l){const b=f("div","home-shortcut-row"),x=f("kbd","home-shortcut-key");x.textContent=y;const S=f("span","home-shortcut-desc");S.textContent=v,b.append(x,S),d.appendChild(b)}s.appendChild(d),n.appendChild(s);const h=f("div","home-panel"),p=f("div","home-panel-head"),u=f("div","home-panel-title");u.textContent="Workspace";const g=f("button","btn primary home-panel-add");if(g.textContent="+ Add repo",g.addEventListener("click",()=>void this.addRepoDocs()),p.append(u,g),h.appendChild(p),this.workspace.projects.length===0){const y=f("div","home-panel-empty");y.textContent="No projects yet. Add a project root to discover docs folders.",h.appendChild(y)}else for(const y of this.workspace.projects){const v=f("div","home-panel-project"),b=f("a","home-panel-project-head");b.href=Mt(y.id);const x=f("span","home-panel-project-name");x.textContent=y.label;const S=y.docsRoots.reduce(($,ut)=>{const wt=this.treesByRoot.get(ut.id)??[];return $+zt(wt).length},0),C=y.docsRoots.reduce(($,ut)=>{const wt=this.treesByRoot.get(ut.id)??[];return $+dt(wt).length},0),E=f("span","home-panel-project-meta"),T=[`${y.docsRoots.length} root${y.docsRoots.length===1?"":"s"}`];S&&T.push(`${S} doc${S===1?"":"s"}`),C&&T.push(`${C} board${C===1?"":"s"}`),E.textContent=T.join(" · "),b.append(x,E),v.appendChild(b);const L=6,B=y.docsRoots,I=B.slice(0,L),j=f("div","home-panel-roots");for(const $ of I){const ut=this.treesByRoot.get($.id)??[],wt=ke(Dt(ut)),Un=wt?W($.id,wt):Tt($.id),_t=f("a","home-panel-root");_t.href=Un;const de=f("span","home-panel-root-path");de.textContent=$.displayPath;const he=zt(ut).length,pe=dt(ut).length;if(he||pe){const $e=f("span","home-panel-root-meta"),ue=[];he&&ue.push(String(he)),pe&&ue.push(`${pe}▦`),$e.textContent=ue.join(" · "),_t.append(de,$e)}else _t.appendChild(de);j.appendChild(_t)}if(B.length>L){const $=f("a","home-panel-more");$.href=Mt(y.id),$.textContent=`+ ${B.length-L} more roots`,j.appendChild($)}v.appendChild(j),h.appendChild(v)}n.appendChild(h),e.appendChild(n),this.content.replaceChildren(e),this.contentScroll.scrollTop=t??0}async renderProjectWiki(t,e,n,s){this.disposeContent(),this.content.classList.add("content-wide");const i=this.workspace.projects.find(p=>p.id===t);if(!i){this.renderMessage("Project not found","This project is no longer registered.");return}const a=f("div","page wiki-page"),r=!!n,c=!!s;let l=!1;if(c&&n){const p=this.docsRootById(n);p&&(l=p.displayPath===s||p.displayPath.startsWith(s+"/"))}const d=f("div","wiki-head");if(c&&n){const p=[{label:"Home",href:"#/"}];p.push({label:i.label,href:Mt(i.id)});const u=s.split("/").filter(Boolean);for(let y=0;y<u.length;y++){const v=u.slice(0,y+1).join("/"),b=y===u.length-1;p.push({label:u[y],href:b?void 0:ie(n,v)})}d.appendChild(lt(p));const g=f("h1","wiki-title");g.textContent=u[u.length-1]||i.label,d.appendChild(g)}else if(r&&n){const p=this.docsRootById(n),u=[{label:"Home",href:"#/"}];if(u.push({label:i.label,href:Mt(i.id)}),p){const y=p.displayPath.split("/").filter(Boolean);for(let v=0;v<y.length;v++){const b=y.slice(0,v+1).join("/"),x=v===y.length-1;u.push({label:y[v],href:x?void 0:ie(n,b)})}}d.appendChild(lt(u));const g=f("h1","wiki-title");g.textContent=(p==null?void 0:p.displayPath.split("/").pop())||i.label,d.appendChild(g)}else{d.appendChild(lt([{label:"Home",href:"#/"},{label:i.label}]));const p=f("h1","wiki-title");p.textContent=i.label,d.appendChild(p)}if(!r&&!c){const p=i.docsRoots.reduce((v,b)=>{const x=this.treesByRoot.get(b.id)??[];return v+zt(x).length},0),u=i.docsRoots.reduce((v,b)=>{const x=this.treesByRoot.get(b.id)??[];return v+dt(x).length},0),g=i.docsRoots.reduce((v,b)=>{const S=(this.treesByRoot.get(b.id)??[]).find(C=>C.type==="dir"&&C.name==="capabilities");return v+((S==null?void 0:S.type)==="dir"?S.children.filter(C=>C.name.endsWith(".md")).length:0)},0),y=f("div","wiki-stats");for(const[v,b]of[[String(i.docsRoots.length),"docs roots"],[String(p),"documents"],[String(u),"boards"],[String(g),"capabilities"]]){const x=f("div","wiki-stat"),S=f("div","wiki-stat-val");S.textContent=v;const C=f("div","wiki-stat-label");C.textContent=b,x.append(S,C),y.appendChild(x)}d.appendChild(y)}a.appendChild(d);const h=n?i.docsRoots.filter(p=>p.id===n):i.docsRoots;for(const p of h){const u=this.treesByRoot.get(p.id)??[];let g=u;if(s&&!l){const E=(L,B)=>{for(const I of L){if(I.type==="dir"&&I.path===B)return I;if(I.type==="dir"){const j=E(I.children,B);if(j)return j}}return null},T=E(u,s);g=(T==null?void 0:T.type)==="dir"?T.children:[]}const y=zt(g),v=dt(g),b=g.find(E=>E.type==="dir"&&E.name==="capabilities"),x=(b==null?void 0:b.type)==="dir"?b.children.filter(E=>E.name.endsWith(".md")):[],S=f("div","wiki-root-section");if(!s||l){const E=f("div","wiki-root-head"),T=f("div","wiki-root-path");T.textContent=p.displayPath,E.appendChild(T),S.appendChild(E)}if(!y.length&&!v.length&&!x.length){const E=f("div","wiki-root-empty");E.textContent="No docs, boards, or capabilities yet. Right-click in the sidebar to add content.",S.appendChild(E),a.appendChild(S);continue}const C=f("div","wiki-root-cols");if(y.length>0){const E=f("div","wiki-col"),T=f("div","wiki-col-head");T.textContent=`Docs (${y.length})`,E.appendChild(T);const L=f("div","wiki-col-list");for(const B of y){const I=f("a","wiki-col-item wiki-col-item-doc");I.href=W(p.id,B.path),I.textContent=B.name==="index.md"?"Overview":B.name.replace(/\.md$/,"").replace(/[-_]/g," ");const j=f("span","wiki-col-item-path"),$=B.path.includes("/")?B.path.slice(0,B.path.lastIndexOf("/")):"";j.textContent=$,$&&I.appendChild(j),L.appendChild(I)}E.appendChild(L),C.appendChild(E)}if(v.length>0){const E=f("div","wiki-col"),T=f("div","wiki-col-head");T.textContent=`Boards (${v.length})`,E.appendChild(T);const L=f("div","wiki-col-list");for(const B of v){const I=_(B.path),j=f("a","wiki-col-item wiki-col-item-board");j.href=q(p.id,I),j.textContent=I.split("/").pop().replace(/[-_]/g," ");const $=f("span","wiki-col-item-path");$.textContent=I.includes("/")?I.slice(0,I.lastIndexOf("/")):p.displayPath,j.appendChild($),L.appendChild(j)}E.appendChild(L),C.appendChild(E)}if(x.length>0){const E=f("div","wiki-col"),T=f("div","wiki-col-head");T.textContent=`Capabilities (${x.length})`,E.appendChild(T);const L=f("div","wiki-col-list");for(const B of x){const I=f("a","wiki-col-item wiki-col-item-cap");I.href=St(p.id,B.path),I.textContent=B.name.replace(/\.md$/,"").replace(/[-_]/g," "),L.appendChild(I)}E.appendChild(L),C.appendChild(E)}S.appendChild(C),a.appendChild(S)}this.content.replaceChildren(a),this.contentScroll.scrollTop=e??0}async renderDoc(t,e,n){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}try{const s=await k.readFile(t,e);this.setEditableFile({rootId:t,path:e});const i=f("div","doc-page"),a=this.docsRootById(t),r=Zt(this.workspace,t,{filePath:e});i.appendChild(lt(r));const c=f("div","");i.appendChild(c),this.content.replaceChildren(i);const{destroy:l}=Fe(c,s,{rootId:t,docPath:e});this.cleanup=l;const d=await k.getTree(t),h=Jt(t,d),p=Qt(h,W(t,e));p&&i.appendChild(p),this.contentScroll.scrollTop=n??0}catch{this.renderMessage("Document not found",e)}}openDocEditor(t){this.topbar.classList.add("editing-doc"),this.closeCartPopover(),Re.open({rootId:t.rootId,path:t.path,onClose:()=>{this.topbar.classList.remove("editing-doc"),this.route()}})}async renderCapabilityDoc(t,e,n){var C;if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}let s;try{s=await k.readFile(t,e),this.setEditableFile({rootId:t,path:e})}catch{this.renderMessage("Capability not found",e);return}const i=f("div","page"),a=this.docsRootById(t);a&&this.workspace.projects.find(E=>E.id===a.projectId);const r=G(((C=e.split("/").pop())==null?void 0:C.replace(/\.md$/,""))??e),c=Zt(this.workspace,t,{filePath:e,currentLabel:r});i.appendChild(lt(c));const l=f("div","page-bar"),d=f("div","doc-actions capability-doc-actions"),{frontmatter:h}=Wt(s),p=f("button","btn");p.classList.add("capability-detail-btn");const u=hn(t,e,s,h);this.updateCartButton(p,u.path),p.addEventListener("click",()=>{this.toggleCapabilityCart(u),this.updateCartButton(p,u.path)});const g=f("button","btn primary");g.classList.add("capability-detail-btn"),g.textContent="Copy as LLM prompt",g.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(s),w("Capability copied — paste into your AI assistant")}catch{w("Could not access clipboard")}}),d.append(p,g),l.append(d),i.appendChild(l);const y=f("div","");i.appendChild(y),this.content.replaceChildren(i);const{destroy:v}=Fe(y,s,{rootId:t,docPath:e});this.cleanup=v;const b=this.treesByRoot.get(t)??[],x=Jt(t,b),S=Qt(x,St(t,e));S&&i.appendChild(S),this.contentScroll.scrollTop=n??0}async renderCapabilitiesIndex(t,e){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}this.content.classList.add("content-wide");const n=f("div","page capability-library"),s=Zt(this.workspace,t,{currentLabel:"Capabilities"});n.appendChild(lt(s));const i=f("h1","");i.textContent="Capability library";const a=f("p","page-lead");a.textContent="Select reusable specs into a component cart, then copy one combined prompt for your coding assistant.",n.append(i,a);const r=f("div","capability-layout"),c=f("div","card-grid capability-grid"),l=this.renderCapabilityCart();r.append(c,l),n.appendChild(r),this.content.replaceChildren(n);try{const d=this.treesByRoot.get(t)??await k.getTree(t),h=d.find(y=>y.type==="dir"&&y.name==="capabilities"),p=h&&h.type==="dir"?h.children.filter(y=>y.type==="file"&&y.name.endsWith(".md")):[];for(const y of p){const v=await k.readFile(t,y.path),{frontmatter:b}=Wt(v),x=hn(t,y.path,v,b),S=document.createElement("article");S.className="card",this.capabilityCart.has(x.path)&&S.classList.add("selected");const C=f("div","card-title"),E=document.createElement("a");E.href=St(t,y.path),E.textContent=x.title,C.appendChild(E);const T=f("div","card-desc");if(T.textContent=x.summary,S.append(C,T),x.tags.length){const I=f("div","card-tags");for(const j of x.tags){const $=f("span","tag");$.textContent=j,I.appendChild($)}S.appendChild(I)}const L=f("div","card-actions"),B=f("button","btn");B.classList.add("capability-add-btn"),this.updateCartButton(B,x.path),B.addEventListener("click",()=>{this.toggleCapabilityCart(x),this.renderCapabilitiesIndex(t,this.contentScroll.scrollTop)}),L.appendChild(B),S.appendChild(L),c.appendChild(S)}p.length===0&&c.appendChild(Et("No capabilities yet."));const u=Jt(t,d),g=Qt(u,An(t));g&&n.appendChild(g)}catch{c.appendChild(Et("Could not load capabilities."))}this.contentScroll.scrollTop=e??0}renderTokenLibrary(t){this.disposeContent(),this.content.classList.add("content-wide");const e=f("div","page token-library"),n=f("div","page-bar"),s=f("h1","");s.textContent="Tokens";const i=f("div","token-actions"),a=f("button","btn");a.textContent="Select all",a.addEventListener("click",()=>{this.selectedTokens=new Set(Ce.map(d=>d.variable)),this.renderTokenLibrary(this.contentScroll.scrollTop)});const r=f("button","btn");r.textContent="Clear",r.addEventListener("click",()=>{this.selectedTokens.clear(),this.renderTokenLibrary(this.contentScroll.scrollTop)});const c=f("button","btn primary");c.textContent=`Copy selected (${this.selectedTokens.size})`,c.disabled=this.selectedTokens.size===0,c.addEventListener("click",()=>void this.copySelectedTokens()),i.append(a,r,c),n.append(s,i);const l=f("p","page-lead");l.textContent="Brand, neutral, and semantic CSS variables used throughout the app. Select tokens and copy them as a ready-to-paste :root block.",e.append(n,l);for(const d of["Brand Colors","Neutral Colors","Semantic Colors"]){const h=f("section","token-section"),p=f("h2","");p.textContent=d;const u=f("div","token-grid");for(const g of Ce.filter(y=>y.group===d)){const y=f("div","token-card");this.selectedTokens.has(g.variable)&&y.classList.add("selected");const v=f("label","token-select-zone"),b=document.createElement("input");b.type="checkbox",b.checked=this.selectedTokens.has(g.variable),b.addEventListener("change",()=>{b.checked?this.selectedTokens.add(g.variable):this.selectedTokens.delete(g.variable),this.renderTokenLibrary(this.contentScroll.scrollTop)});const x=f("span","token-swatch");x.style.background=g.value;const S=f("span","token-copy"),C=f("strong","");C.textContent=g.name;const E=f("code","");E.textContent=g.value;const T=f("small","");T.textContent=g.description,S.append(C,E,T),v.append(b,x,S);const L=f("button","token-copy-btn");L.type="button",L.innerHTML=K.copy,L.title=`Copy ${g.variable}`,L.setAttribute("aria-label",`Copy ${g.variable}`),L.addEventListener("click",B=>{B.stopPropagation(),this.copyToken(g)}),y.append(v,L),u.appendChild(y)}h.append(p,u),e.appendChild(h)}this.content.replaceChildren(e),this.contentScroll.scrollTop=t??0}async copySelectedTokens(){const t=Ce.filter(n=>this.selectedTokens.has(n.variable));if(t.length===0)return;const e=[":root {",...t.map(n=>` ${n.variable}: ${n.value};`),"}"].join(`
35
+ `);try{await navigator.clipboard.writeText(e),w(`${t.length} token${t.length===1?"":"s"} copied`)}catch{w("Could not access clipboard")}}async copyToken(t){try{await navigator.clipboard.writeText(`${t.variable}: ${t.value};`),w(`${t.variable} copied`)}catch{w("Could not access clipboard")}}renderCapabilityCart(t){const e=t??(()=>{const h=Ei(location.hash);h&&this.renderCapabilitiesIndex(h,this.contentScroll.scrollTop)}),n=f("aside","capability-cart"),s=f("div","capability-cart-head"),i=f("h2","");i.textContent="Component cart";const a=f("span","capability-cart-count");a.textContent=String(this.capabilityCart.size),s.append(i,a);const r=f("div","capability-cart-body");if(this.capabilityCart.size===0){const h=f("div","capability-cart-empty");h.textContent="Select specs to build a combined prompt.",r.appendChild(h)}else for(const h of this.capabilityCart.values()){const p=f("div","capability-cart-item"),u=f("div",""),g=f("div","capability-cart-item-title");g.textContent=h.title;const y=f("div","capability-cart-item-meta");y.textContent=h.displayPath,u.append(g,y);const v=f("button","capability-cart-remove");v.type="button",v.textContent="Remove",v.addEventListener("click",()=>{this.capabilityCart.delete(h.path),this.updateTopbarCart(),e()}),p.append(u,v),r.appendChild(p)}const c=f("div","capability-cart-actions"),l=f("button","btn primary");l.textContent="Copy prompt",l.disabled=this.capabilityCart.size===0,l.addEventListener("click",()=>void this.copyCapabilityCartPrompt());const d=f("button","btn");return d.textContent="Clear",d.disabled=this.capabilityCart.size===0,d.addEventListener("click",()=>{this.capabilityCart.clear(),this.updateTopbarCart(),e()}),c.append(l,d),n.append(s,r,c),n}toggleCapabilityCart(t){this.capabilityCart.has(t.path)?this.capabilityCart.delete(t.path):this.capabilityCart.set(t.path,t),this.updateTopbarCart()}updateCartButton(t,e){const n=this.capabilityCart.has(e);t.textContent=n?"Remove from cart":"Add to cart",t.classList.toggle("primary",!n),t.classList.toggle("is-selected",n)}async copyCapabilityCartPrompt(){if(this.capabilityCart.size===0)return;const e=`Use these capability/component specs as implementation guidance for the next coding task.
36
+
37
+ `+[...this.capabilityCart.values()].map((n,s)=>`## ${s+1}. ${n.title}
38
+
39
+ ${n.md.trim()}`).join(`
40
+
41
+ ---
42
+
43
+ `);try{await navigator.clipboard.writeText(e),w(`${this.capabilityCart.size} spec${this.capabilityCart.size===1?"":"s"} copied`)}catch{w("Could not access clipboard")}}async renderBoardList(t,e){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}this.content.classList.add("content-wide");const n=f("div","page board-library"),s=Zt(this.workspace,t,{currentLabel:"Boards"});n.appendChild(lt(s));const i=f("div","page-bar"),a=f("h1","");a.textContent="Boards";const r=f("button","btn primary");r.textContent="+ New board",r.addEventListener("click",()=>this.promptNewBoard(t)),i.append(a,r),n.appendChild(i);const c=f("p","page-lead");c.textContent="Each board is a git-tracked JSON file. Open one to edit it, then use “Copy embed” to drop a framed preview into any doc.",n.appendChild(c);const l=f("div","card-grid board-grid");n.appendChild(l),this.content.replaceChildren(n);try{const d=await X.list(t);for(const g of d){const y=document.createElement("a");y.className="card",y.href=q(t,g.id);const v=f("div","card-title");v.textContent=g.title;const b=f("div","card-desc");b.textContent=`${g.elementCount} element${g.elementCount===1?"":"s"} · ${g.filePath}`,y.append(v,b),l.appendChild(y)}d.length===0&&l.appendChild(Et("No boards yet — create one."));const h=await k.getTree(t),p=Jt(t,h),u=Qt(p,Tt(t));u&&n.appendChild(u)}catch{l.appendChild(Et("Could not load boards."))}this.contentScroll.scrollTop=e??0}async renderProjectBoardList(t,e){this.disposeContent(),this.content.classList.add("content-wide");const n=this.workspace.projects.find(d=>d.id===t);if(!n){this.renderMessage("Project unavailable","This project is no longer registered. Re-add it if needed.");return}const s=f("div","page boards-page"),i=[{label:"Home",href:"#/"},{label:n.label,href:Mt(t)},{label:"Boards"}];s.appendChild(lt(i));const a=f("div","page-bar"),r=f("h1","");r.textContent=`${n.label} boards`,a.appendChild(r),s.appendChild(a);const c=f("p","page-lead");c.textContent="Boards across every mounted docs root in this project. Each card shows the docs root and board file path.",s.appendChild(c);const l=f("div","card-grid board-grid");s.appendChild(l),this.content.replaceChildren(s);try{const d=await this.listProjectBoards(n);for(const h of d){const p=document.createElement("a");p.className="card",p.href=q(h.root.id,h.board.id);const u=f("div","card-title");u.textContent=h.board.title;const g=f("div","card-desc");g.textContent=`${h.board.elementCount} element${h.board.elementCount===1?"":"s"} · ${h.root.displayPath} · ${h.board.filePath}`,p.append(u,g),l.appendChild(p)}d.length===0&&l.appendChild(Et("No boards yet — create one."))}catch{l.appendChild(Et("Could not load boards."))}this.contentScroll.scrollTop=e??0}async listProjectBoards(t){const e=[];for(const n of t.docsRoots){const s=await X.list(n.id);for(const i of s)e.push({root:n,board:i})}return e.sort((n,s)=>s.board.updatedAt!==n.board.updatedAt?s.board.updatedAt-n.board.updatedAt:n.root.displayPath!==s.root.displayPath?n.root.displayPath.localeCompare(s.root.displayPath):n.board.filePath.localeCompare(s.board.filePath)),e}promptNewBoard(t,e=""){const n=e?`doc:${t}:${e}`:t,s=this.sidebar.collapsibles.get(n),i=(s==null?void 0:s.body)??this.sidebar.element.querySelector(".nav-repo-body");i?this.sidebar.startInlineCreate(i,"board-name",async a=>{const r=ft(a,"board");if(!r.ok){w(r.message);return}try{const c=await X.create(t,r.raw,Ft(),e);await this.refreshContentIndex(),location.hash=q(t,c)}catch{w("Could not create board")}}):O("New board",(a,r)=>{const c=document.createElement("input");c.className="board-title",c.placeholder="Board title",c.style.width="100%",c.style.marginBottom="12px";const l=f("div","modal-actions"),d=f("button","btn primary");d.textContent="Create";const h=async()=>{const p=ft(c.value,"board");if(!p.ok){w(p.message),c.focus();return}try{const u=await X.create(t,p.raw,Ft(),e);r(),await this.refreshContentIndex(),location.hash=q(t,u)}catch{w("Could not create board file")}};d.addEventListener("click",()=>void h()),c.addEventListener("keydown",p=>{p.stopPropagation(),p.key==="Enter"&&h()}),l.appendChild(d),a.append(c,l),c.focus()})}promptNewDirectory(t,e){const n=e?`doc:${t}:${e}`:t,s=this.sidebar.collapsibles.get(n),i=(s==null?void 0:s.body)??this.sidebar.element.querySelector(".nav-repo-body");i?this.sidebar.startInlineCreate(i,"directory-name",async a=>{const r=ft(a,"directory");if(!r.ok){w(r.message);return}const c=e?`${e}/${r.slug}`:r.slug;try{await k.createDirectory(t,c),await this.refreshContentIndex()}catch{w("Could not create directory")}}):O("New directory",(a,r)=>{const c=document.createElement("input");c.className="board-title",c.placeholder="Directory name",c.style.width="100%",c.style.marginBottom="12px";const l=f("div","modal-actions"),d=f("button","btn primary");d.textContent="Create";const h=async()=>{const p=ft(c.value,"directory");if(!p.ok){w(p.message),c.focus();return}const u=e?`${e}/${p.slug}`:p.slug;try{await k.createDirectory(t,u),r(),await this.refreshContentIndex()}catch{w("Could not create directory")}};d.addEventListener("click",()=>void h()),c.addEventListener("keydown",p=>{p.stopPropagation(),p.key==="Enter"&&h()}),l.appendChild(d),a.append(c,l),c.focus()})}async ensureProjectDocsRoot(t){var n;const e=(n=this.workspace.projects.find(s=>s.id===t))==null?void 0:n.docsRoots[0];if(e)return e;try{const s=await k.ensureProjectDocsRoot(t);return await this.refreshContentIndex(),this.docsRootById(s.id)??s}catch{w("Could not create docs folder");return}}async createDocsFolder(t,e){try{await k.createDocsFolder(t,e),await this.refreshContentIndex(),w(`Created docs/ in ${e||"project root"}`)}catch{w("Could not create docs folder")}}async promptNewProjectDirectory(t){const e=await this.ensureProjectDocsRoot(t);e&&this.promptNewDirectory(e.id,"")}async promptNewProjectDoc(t){const e=await this.ensureProjectDocsRoot(t);e&&this.promptNewDoc(e.id,"")}async promptNewProjectBoard(t){const e=await this.ensureProjectDocsRoot(t);e&&this.promptNewBoard(e.id,"")}promptNewDoc(t,e){const n=e?`doc:${t}:${e}`:t,s=this.sidebar.collapsibles.get(n),i=(s==null?void 0:s.body)??this.sidebar.element.querySelector(".nav-repo-body");i?this.sidebar.startInlineCreate(i,"document-name.md",async a=>{const r=ft(a.replace(/\.md$/i,""),"doc");if(!r.ok){w(r.message);return}const c=e?`${e}/${r.slug}.md`:`${r.slug}.md`;try{await k.writeFile(t,c,`# ${G(r.slug)}
44
+ `),await this.refreshContentIndex(),location.hash=W(t,c)}catch{w("Could not create doc")}}):O("New doc",(a,r)=>{const c=document.createElement("input");c.className="board-title",c.placeholder="Document name (e.g. overview)",c.style.width="100%",c.style.marginBottom="12px";const l=f("div","modal-actions"),d=f("button","btn primary");d.textContent="Create";const h=async()=>{const p=ft(c.value.replace(/\.md$/i,""),"doc");if(!p.ok){w(p.message),c.focus();return}const u=e?`${e}/${p.slug}.md`:`${p.slug}.md`;try{await k.writeFile(t,u,`# ${G(p.slug)}
45
+ `),r(),await this.refreshContentIndex(),location.hash=W(t,u)}catch{w("Could not create doc file")}};d.addEventListener("click",()=>void h()),c.addEventListener("keydown",p=>{p.stopPropagation(),p.key==="Enter"&&h()}),l.appendChild(d),a.append(c,l),c.focus()})}promptNewCapability(t,e){O("New capability",(n,s)=>{const i=document.createElement("input");i.className="board-title",i.placeholder="Capability name (e.g. auth-flow)",i.style.width="100%",i.style.marginBottom="12px";const a=f("div","modal-actions"),r=f("button","btn primary");r.textContent="Create";const c=async()=>{const l=(i.value.trim()||"untitled").replace(/\.md$/,"").replace(/\s+/g,"-").toLowerCase(),d=e.replace(/^capabilities\/?/,""),h=d?`capabilities/${d}/${l}.md`:`capabilities/${l}.md`,p=G(l),u=`---
46
+ title: ${p}
47
+ summary:
48
+ tags:
49
+ ---
50
+
51
+ # ${p}
52
+ `;try{await k.writeFile(t,h,u),s(),await this.refreshContentIndex(),location.hash=St(t,h)}catch{w("Could not create capability")}};r.addEventListener("click",()=>void c()),i.addEventListener("keydown",l=>{l.stopPropagation(),l.key==="Enter"&&c()}),a.appendChild(r),n.append(i,a),i.focus()})}promptRenameDoc(t,e){const n=e.includes("/")?e.slice(0,e.lastIndexOf("/")+1):"",s=e.replace(/\.md$/,"").split("/").pop()??"",i=`doc:${t}:${e}`,a=this.sidebar.links.get(i);a?this.sidebar.startInlineRename(a,s,async r=>{const c=r.replace(/\.md$/,"").replace(/\s+/g,"-").toLowerCase(),l=`${n}${c}.md`;if(l!==e)try{await k.renameFile(t,e,l),await this.refreshContentIndex(),location.hash=W(t,l)}catch{w("Could not rename doc")}}):O("Rename doc",(r,c)=>{const l=document.createElement("input");l.className="board-title",l.value=s,l.style.width="100%",l.style.marginBottom="12px",l.select();const d=f("div","modal-actions"),h=f("button","btn primary");h.textContent="Rename";const p=async()=>{const u=(l.value.trim()||s).replace(/\.md$/,"").replace(/\s+/g,"-").toLowerCase(),g=`${n}${u}.md`;if(g===e){c();return}try{await k.renameFile(t,e,g),c(),await this.refreshContentIndex(),location.hash=W(t,g)}catch{w("Could not rename doc")}};h.addEventListener("click",()=>void p()),l.addEventListener("keydown",u=>{u.stopPropagation(),u.key==="Enter"&&p()}),d.appendChild(h),r.append(l,d),l.focus()})}async moveDoc(t,e,n){const s=fn(n,Ht(e));if(s!==e)try{const i=new Set(dt(await k.getTree(t)).map(c=>_(c.path))),a=await k.readFile(t,e),r=un(a,e,s,i);await k.renameFile(t,e,s),r!==a&&await k.writeFile(t,s,r),await this.refreshContentIndex(),location.hash===W(t,e)&&(location.hash=W(t,s)),w(`Moved ${Ht(e)}`)}catch{w("Could not move doc")}}async moveBoard(t,e,n){try{const s=await X.move(t,e,n),i=await this.updateBoardEmbedReferences(t,e,s);await this.refreshContentIndex(),location.hash===q(t,e)&&(location.hash=q(t,s)),w(i>0?`Moved ${Ht(e)} and updated ${i} embed${i===1?"":"s"}`:`Moved ${Ht(e)}`)}catch(s){w(s instanceof Error?s.message:"Could not move board")}}async updateBoardEmbedReferences(t,e,n){if(e===n)return 0;const s=await k.getTree(t),i=Hn(s);let a=0;for(const r of i){const c=await k.readFile(t,r.path),l=Li(c,r.path,e,n);l!==c&&(await k.writeFile(t,r.path,l),a++)}return a}async moveDirectory(t,e,n){const s=Ht(e),i=fn(n,s);if(i!==e)try{const a=await k.getTree(t),r=new Set(dt(a).map(p=>_(p.path))),c=Bi(a,e),l=Ii(a,e),d=await Promise.all(l.map(async p=>[p.path,await k.readFile(t,p.path)]));await k.renameFile(t,e,i);let h=0;for(const[p,u]of d){const g=`${i}${p.slice(e.length)}`,y=un(u,p,g,r);y!==u&&(await k.writeFile(t,g,y),h++)}for(const p of c){const u=`${i}${p.slice(e.length)}`;await this.rewriteMovedBoardDocumentId(t,p,u),h+=await this.updateBoardEmbedReferences(t,p,u)}await this.refreshContentIndex(),this.rewriteRouteAfterDirectoryMove(t,e,i),w(h>0?`Moved ${s} and updated ${h} embed${h===1?"":"s"}`:`Moved ${s}`)}catch{w("Could not move directory")}}promptRenameDirectory(t,e){const n=e.includes("/")?e.slice(0,e.lastIndexOf("/")+1):"",s=e.split("/").pop()??"";O("Rename directory",(i,a)=>{const r=document.createElement("input");r.className="board-title",r.value=s,r.style.width="100%",r.style.marginBottom="12px",r.select();const c=f("div","modal-actions"),l=f("button","btn primary");l.textContent="Rename";const d=async()=>{const h=(r.value.trim()||s).replace(/\s+/g,"-").toLowerCase(),p=`${n}${h}`;if(p===e){a();return}try{await k.renameFile(t,e,p),a(),await this.refreshContentIndex(),w(`Renamed to ${h}`)}catch{w("Could not rename directory")}};l.addEventListener("click",()=>void d()),r.addEventListener("keydown",h=>{h.stopPropagation(),h.key==="Enter"&&d()}),c.appendChild(l),i.append(r,c),r.focus()})}async promptDeleteDirectory(t,e){const n=e.split("/").pop()??e;if(confirm(`Delete "${n}" and all its contents? This cannot be undone.`))try{await k.deleteFile(t,e),await this.refreshContentIndex(),w(`Deleted ${n}`)}catch{w("Could not delete directory")}}async rewriteMovedBoardDocumentId(t,e,n){const s=await k.getBoard(t,n);s&&s.id!==n&&await k.saveBoard(t,n,{...s,id:n,updatedAt:Date.now()})}rewriteRouteAfterDirectoryMove(t,e,n){const s=encodeURIComponent(t),i=`#/root/${s}/docs/`,a=`#/root/${s}/boards/`,r=location.hash;if(r.startsWith(i)){const c=decodeURIComponent(r.slice(i.length));(c===e||c.startsWith(`${e}/`))&&(location.hash=W(t,`${n}${c.slice(e.length)}`))}else if(r.startsWith(a)){const c=decodeURIComponent(r.slice(a.length));(c===e||c.startsWith(`${e}/`))&&(location.hash=q(t,`${n}${c.slice(e.length)}`))}}async promptDeleteDoc(t,e){const n=e.split("/").pop()??e;O("Delete doc",(s,i)=>{const a=f("p","modal-copy");a.textContent=`Delete "${n}"? This cannot be undone.`;const r=f("div","modal-actions"),c=f("button","btn danger");c.textContent="Delete",c.addEventListener("click",async()=>{try{await k.deleteFile(t,e),i(),await this.refreshContentIndex(),location.hash="#/"}catch{w("Could not delete doc")}});const l=f("button","btn");l.textContent="Cancel",l.addEventListener("click",i),r.append(c,l),s.append(a,r)})}async promptRenameBoard(t,e){const n=await X.load(t,e);if(!n){w("Board not found");return}O("Rename board",(s,i)=>{const a=document.createElement("input");a.className="board-title",a.value=n.title,a.style.width="100%",a.style.marginBottom="12px",a.select();const r=f("div","modal-actions"),c=f("button","btn primary");c.textContent="Rename";const l=async()=>{const d=ft(a.value,"board");if(!d.ok){w(d.message),a.focus();return}try{const h=await X.rename(t,e,d.raw),p=await this.updateBoardEmbedReferences(t,e,h);i(),await this.refreshContentIndex(),location.hash===q(t,e)&&(location.hash=q(t,h)),p>0&&w(`Renamed board and updated ${p} embed${p===1?"":"s"}`)}catch(h){w(h instanceof Error?h.message:"Could not rename board")}};c.addEventListener("click",()=>void l()),a.addEventListener("keydown",d=>{d.stopPropagation(),d.key==="Enter"&&l()}),r.appendChild(c),s.append(a,r),a.focus()})}promptDeleteBoard(t,e){O("Delete board",(n,s)=>{const i=f("p","modal-copy");i.textContent=`Delete "${e}.board.json"? This cannot be undone.`;const a=f("div","modal-actions"),r=f("button","btn danger");r.textContent="Delete",r.addEventListener("click",async()=>{try{await X.delete(t,e),s(),await this.refreshContentIndex(),location.hash=Tt(t)}catch{w("Could not delete board")}});const c=f("button","btn");c.textContent="Cancel",c.addEventListener("click",s),a.append(r,c),n.append(i,a)})}async openEditor(t,e,n){if(!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}this.editor&&this.editingId===`${t}:${e}`||(this.exitEditor(),this.disposeContent(),this.layout.style.display="none",this.editorHost=f("div","board-editor-host"),this.root.appendChild(this.editorHost),this.editingId=`${t}:${e}`,this.editor=new ei(this.editorHost,{boardId:e,loadBoard:s=>X.load(t,s),saveBoard:s=>X.save(t,s),deleteBoard:s=>X.delete(t,s),uploadImage:(s,i)=>X.uploadImage(t,s,i),resolveAssetUrl:s=>k.assetUrl(t,s),initialRegion:n,onExit:()=>{this.pendingScrollRestore=this.lastNonBoardScrollTop,location.hash=this.lastNonBoardHash},onDeleted:()=>{location.hash=Tt(t)}}))}exitEditor(){this.editor&&(this.editor.destroy(),this.editor=void 0),this.editorHost&&(this.editorHost.remove(),this.editorHost=void 0),this.editingId=void 0,this.applyInitialTheme()}applyInitialTheme(){const t=localStorage.getItem(ln),e=t==="dark"||t==="light"?t:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";document.documentElement.setAttribute("data-theme",e)}toggleTheme(){const t=Ft()==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",t),localStorage.setItem(ln,t),this.updateThemeButton(),this.route({preserveScroll:!0})}createTopbar(){const t=f("div","shell-topbar"),e=f("button","topbar-icon-btn");return e.innerHTML=K.panelLeft,e.title="Toggle navigation",e.setAttribute("aria-label","Toggle navigation"),e.addEventListener("click",()=>this.setSidebarCollapsed(!this.layout.classList.contains("sidebar-collapsed"))),this.searchBtn=f("button","topbar-search"),this.searchBtn.type="button",this.searchBtn.innerHTML=`${K.search}<span>Search docs</span><kbd>${this.shortcutLabel()}</kbd>`,this.searchBtn.addEventListener("click",()=>this.openCommandPalette()),this.cartBtn=f("button","topbar-cart"),this.cartBtn.type="button",this.cartBtn.addEventListener("click",()=>this.toggleCartPopover()),this.updateTopbarCart(),this.editBtn=f("button","btn topbar-edit"),this.editBtn.type="button",this.editBtn.innerHTML=`${K.edit}<span>Edit</span>`,this.editBtn.title="Edit this document",this.editBtn.addEventListener("click",()=>{this.currentEditableFile&&this.openDocEditor(this.currentEditableFile)}),this.themeBtn=f("button","topbar-icon-btn topbar-theme"),this.themeBtn.type="button",this.themeBtn.title="Toggle theme",this.themeBtn.setAttribute("aria-label","Toggle theme"),this.themeBtn.addEventListener("click",()=>this.toggleTheme()),this.updateThemeButton(),t.append(e,this.searchBtn,this.cartBtn,this.editBtn,this.themeBtn),t}setSidebarCollapsed(t){this.layout.classList.toggle("sidebar-collapsed",t),localStorage.setItem(dn,String(t))}setEditableFile(t){this.currentEditableFile=t,this.editBtn&&(this.editBtn.hidden=!t,this.editBtn.disabled=!t)}promptRemoveProject(t,e){O("Remove from workspace",(n,s)=>{const i=f("p","modal-copy");i.textContent=`Remove "${e}" from the workspace? The files on disk are not deleted.`;const a=f("div","modal-actions"),r=f("button","btn danger");r.textContent="Remove",r.addEventListener("click",async()=>{try{await k.removeProject(t),s(),await this.refreshContentIndex(),location.hash="#/"}catch{w("Could not remove project")}});const c=f("button","btn");c.textContent="Cancel",c.addEventListener("click",s),a.append(r,c),n.append(i,a)})}async addRepoDocs(){var t;try{const e=new Set(this.allDocsRoots().map(l=>l.id)),n=await k.pickAndAddProject();if(n.cancelled)return;await this.refreshContentIndex();const s=this.allDocsRoots(),a=(n.addedProjectId?(t=this.workspace.projects.find(l=>l.id===n.addedProjectId))==null?void 0:t.docsRoots[0]:s.find(l=>!e.has(l.id)))??s[0];if(!a){w("No docs folders found under that project root.");return}const r=this.treesByRoot.get(a.id)??[],c=ke(Dt(r));c?location.hash=W(a.id,c):location.hash=Tt(a.id),w(`Added ${a.projectLabel}.`)}catch(e){w(e instanceof Error?e.message:"Could not add project root.")}}updateTopbarCart(t=!1){if(!this.cartBtn)return;const e=this.capabilityCart.size;this.cartBtn.hidden=t,this.cartBtn.innerHTML=`<span>Cart</span><strong>${e}</strong>`,this.cartBtn.title=`${e} item${e===1?"":"s"} in component cart`,this.cartBtn.setAttribute("aria-label",this.cartBtn.title),this.cartBtn.disabled=e===0}toggleCartPopover(){var t;if((t=this.cartPopover)!=null&&t.classList.contains("visible")){this.closeCartPopover();return}this.openCartPopover()}openCartPopover(){this.capabilityCart.size!==0&&(this.cartPopover||(this.cartPopover=f("div","topbar-cart-popover"),this.topbar.appendChild(this.cartPopover),document.addEventListener("mousedown",t=>{var n;if(!((n=this.cartPopover)!=null&&n.classList.contains("visible")))return;const e=t.target;this.cartPopover.contains(e)||this.cartBtn.contains(e)||this.closeCartPopover()})),this.cartPopover.replaceChildren(this.renderCapabilityCart(()=>{this.updateTopbarCart(),this.capabilityCart.size===0?this.closeCartPopover():this.openCartPopover()})),this.content.classList.add("cart-popover-open"),this.cartPopover.classList.add("visible"))}closeCartPopover(){var t;this.content.classList.remove("cart-popover-open"),(t=this.cartPopover)==null||t.classList.remove("visible")}updateThemeButton(){if(!this.themeBtn)return;const t=Ft()==="dark";this.themeBtn.innerHTML=t?K.sun:K.moon,this.themeBtn.title=t?"Switch to light mode":"Switch to dark mode",this.themeBtn.setAttribute("aria-label",this.themeBtn.title)}handleGlobalKeydown(t){if((t.metaKey||t.ctrlKey)&&t.key.toLowerCase()==="k"){const e=t.target;if(e!=null&&e.closest(".doc-editor"))return;t.preventDefault(),this.openCommandPalette();return}if(t.key==="F2"){const e=location.hash,n=t.target;if(n!=null&&n.closest(".doc-editor, input, textarea, [contenteditable]"))return;t.preventDefault();const s=e.match(/^#\/root\/([^/]+)\/docs\/(.+)$/);if(s){const r=decodeURIComponent(s[1]),c=decodeURIComponent(s[2]);this.promptRenameDoc(r,c);return}const i=e.match(/^#\/root\/([^/]+)\/boards\/(.+)$/);if(i){const r=decodeURIComponent(i[1]),c=decodeURIComponent(i[2]);this.promptRenameBoard(r,c);return}const a=e.match(/^#\/root\/([^/]+)\/directory\/(.+)$/);if(a){const r=decodeURIComponent(a[1]),c=decodeURIComponent(a[2]);this.promptRenameDirectory(r,c);return}}}allDocsRoots(){return this.workspace.projects.flatMap(t=>t.docsRoots)}docsRootById(t){return this.allDocsRoots().find(e=>e.id===t)}async refreshContentIndex(){try{this.workspace=await k.getWorkspace()}catch{this.workspace={projects:[]},this.treesByRoot=new Map,this.treesByProject=new Map,this.sidebar.refresh(this.workspace,this.treesByRoot),this.searchIndex=[];return}const t=this.allDocsRoots(),e=await Promise.all(t.map(async i=>{try{return[i.id,await k.getTree(i.id)]}catch{return[i.id,[]]}}));this.treesByRoot=new Map(e);const n=await Promise.all(this.workspace.projects.map(async i=>{try{return[i.id,await k.getProjectTree(i.id)]}catch{return[i.id,[]]}}));this.treesByProject=new Map(n),this.sidebar.refresh(this.workspace,this.treesByRoot,this.treesByProject);const s=[];for(const i of t){const a=this.treesByRoot.get(i.id)??[],r=[...zt(a),...qn(a,"capabilities")].filter(c=>c.type==="file"&&c.name.endsWith(".md"));for(const c of r){const l="path"in c?c.path:"";let d="";try{d=await k.readFile(i.id,l)}catch{}const{frontmatter:h}=Wt(d),p=jn(d),u=h.title??Nn(d)??G(c.name),g=h.summary??zn(p),y=l.startsWith("capabilities/")?"Capability":"Doc",v=l.startsWith("capabilities/")?St(i.id,l):W(i.id,l);s.push({title:u,path:`${i.projectLabel}/${i.displayPath}/${l}`,href:v,section:y,summary:g,body:p.map(b=>b.text).join(" "),chunks:p,rootId:i.id})}}this.searchIndex=s.filter(i=>i.body||i.title)}openCommandPalette(){var t;this.palette||this.createCommandPalette(),(t=this.palette)==null||t.classList.add("visible"),document.body.style.overflow="hidden",this.paletteInput.value="",this.renderSearchResults(""),requestAnimationFrame(()=>{var e;return(e=this.paletteInput)==null?void 0:e.focus()})}closeCommandPalette(){var t;(t=this.palette)==null||t.classList.remove("visible"),document.body.style.overflow=""}createCommandPalette(){this.palette=f("div","command-palette");const t=f("div","command-panel"),e=f("div","command-search");e.innerHTML=K.search,this.paletteInput=document.createElement("input"),this.paletteInput.type="search",this.paletteInput.placeholder="Search docs",this.paletteInput.setAttribute("aria-label","Search docs"),e.appendChild(this.paletteInput),this.paletteResults=f("div","command-results"),t.append(e,this.paletteResults),this.palette.appendChild(t),document.body.appendChild(this.palette),this.palette.addEventListener("mousedown",n=>{n.target===this.palette&&this.closeCommandPalette()}),this.paletteInput.addEventListener("input",()=>this.renderSearchResults(this.paletteInput.value)),this.paletteInput.addEventListener("keydown",n=>this.handlePaletteKeydown(n))}handlePaletteKeydown(t){var i,a,r,c,l;if(t.key==="Escape"){t.preventDefault(),this.closeCommandPalette();return}const e=[...((i=this.paletteResults)==null?void 0:i.querySelectorAll(".command-result"))??[]],n=(a=this.paletteResults)==null?void 0:a.querySelector(".command-result.active"),s=n?e.indexOf(n):-1;if(t.key==="ArrowDown"||t.key==="ArrowUp"){t.preventDefault();const d=t.key==="ArrowDown"?Math.min(s+1,e.length-1):Math.max(s-1,0);e.forEach(h=>h.classList.remove("active")),(r=e[d])==null||r.classList.add("active"),(c=e[d])==null||c.scrollIntoView({block:"nearest"})}t.key==="Enter"&&(t.preventDefault(),(l=n??e[0])==null||l.click())}renderSearchResults(t){if(!this.paletteResults)return;const e=Si(t),n=this.rankSearch(e).slice(0,8);if(this.paletteResults.replaceChildren(),n.length===0){const s=f("div","command-empty");s.textContent=this.searchIndex.length?"No matching docs.":"No docs indexed yet.",this.paletteResults.appendChild(s);return}for(const[s,i]of n.entries()){const{entry:a}=i,r=document.createElement("a");r.className="command-result",s===0&&r.classList.add("active"),r.href=a.href,r.addEventListener("click",()=>this.closeCommandPalette());const c=f("div","command-result-title");pn(c,a.title,e);const l=f("div","command-result-meta");l.textContent=[a.section,i.heading,a.path].filter(Boolean).join(" · ");const d=f("div","command-result-summary");pn(d,i.preview,e),r.append(c,l),d.textContent&&r.appendChild(d),this.paletteResults.appendChild(r)}}rankSearch(t){if(t.length===0)return this.searchIndex.map(s=>({entry:s,score:0,heading:"",preview:s.summary||s.body.slice(0,220)}));const e=t.map(it).filter(Boolean),n=it(t.join(" "));return this.searchIndex.map(s=>{const i=it(s.title),a=it(s.path),r=it(s.summary);let c=jt(i,e,n,10);c+=jt(a,e,n,4),c+=jt(r,e,n,3);let l,d=0;for(const p of s.chunks){const u=jt(it(p.heading),e,n,5),g=jt(p.normalized,e,n,p.kind==="heading"?8:2),y=u+g;y>d&&(d=y,l=p)}const h=c+d;return{entry:s,score:h,heading:l!=null&&l.heading&&l.heading!==s.title?l.heading:"",preview:l?Di(l.text,e):s.summary}}).filter(s=>s.score>0).sort((s,i)=>i.score-s.score||s.entry.title.localeCompare(i.entry.title))}shortcutLabel(){return/Mac|iPhone|iPad/.test(navigator.platform)?"⌘K":"Ctrl K"}disposeContent(){this.cleanup&&(this.cleanup(),this.cleanup=void 0),this.content.classList.remove("content-wide"),this.content.replaceChildren()}renderMessage(t,e){this.disposeContent();const n=f("div","page"),s=f("h1","");s.textContent=t;const i=f("p","page-lead");i.textContent=e,n.append(s,i),this.content.replaceChildren(n)}}function Zt(o,t,e={}){const n=[{label:"Home",href:"#/"}];let s;for(const c of o.projects){const l=c.docsRoots.find(d=>d.id===t);if(l){n.push({label:c.label,href:Mt(c.id)}),s=l;break}}if(s){const c=s.displayPath.split("/").filter(Boolean);for(let l=0;l<c.length;l++){const d=c.slice(0,l+1).join("/");n.push({label:c[l],href:ie(t,d)})}}const a=(e.filePath??e.dirPath??"").split("/").filter(Boolean),r=e.filePath?a.slice(0,-1):a;for(let c=0;c<r.length;c++){const l=r.slice(0,c+1).join("/");n.push({label:G(r[c]),href:ie(t,l)})}if(e.currentLabel)n.push({label:e.currentLabel});else if(e.filePath){const c=a[a.length-1];n.push({label:c==="index.md"?"Overview":G(c)})}return n}function lt(o){const t=f("nav","breadcrumb");t.setAttribute("aria-label","Breadcrumb");for(let e=0;e<o.length;e++){const n=o[e],s=e===o.length-1;if(!s&&n.href){const i=document.createElement("a");i.className="breadcrumb-link",i.href=n.href,i.textContent=n.label,t.appendChild(i)}else{const i=f("span","breadcrumb-current");i.textContent=n.label,t.appendChild(i)}if(!s){const i=f("span","breadcrumb-sep");i.textContent="/",i.setAttribute("aria-hidden","true"),t.appendChild(i)}}return t}function f(o,t){const e=document.createElement(o);return t&&(e.className=t),e}function Et(o){const t=f("div","empty-note");return t.textContent=o,t}function hn(o,t,e,n){return{path:`${o}:${t}`,displayPath:t,title:n.title??Nn(e)??G(t.split("/").pop()??t),summary:n.summary??zn(jn(e)),tags:n.tags?n.tags.split(",").map(s=>s.trim()).filter(Boolean):[],md:e}}function Jt(o,t){const e=[];function n(r){const l=[...Dt(r)].sort((d,h)=>{const p=d.type==="file"&&d.name==="index.md"?-1:0,u=h.type==="file"&&h.name==="index.md"?-1:0;return p!==u?p-u:d.type!==h.type?d.type==="dir"?-1:1:d.name.localeCompare(h.name)});for(const d of l)if(d.type==="file"){const h=d.name==="index.md"?"Overview":G(d.name);e.push({label:h,href:W(o,d.path)})}else n(d.children)}n(t);const s=dt(t).sort((r,c)=>r.path.localeCompare(c.path));if(s.length>0){e.push({label:"All Boards",href:Tt(o)});for(const r of s){const c=_(r.path);e.push({label:G(c.split("/").pop()??c),href:q(o,c)})}}const i=t.find(r=>r.type==="dir"&&r.name==="capabilities"),a=(i==null?void 0:i.type)==="dir"?i.children.filter(r=>r.type==="file"&&r.name.endsWith(".md")).sort((r,c)=>r.name.localeCompare(c.name)):[];if(a.length>0){e.push({label:"All Capabilities",href:An(o)});for(const r of a)e.push({label:G(r.name),href:St(o,r.path)})}return e}function Qt(o,t){const e=o.findIndex(a=>a.href===t);if(e===-1)return null;const n=e>0?o[e-1]:null,s=e<o.length-1?o[e+1]:null;if(!n&&!s)return null;const i=f("nav","page-nav");if(n){const a=f("a","page-nav-prev");a.href=n.href,a.innerHTML=`<span class="page-nav-arrow">←</span><span class="page-nav-label">${n.label}</span>`,i.appendChild(a)}else i.appendChild(f("span","page-nav-spacer"));if(s){const a=f("a","page-nav-next");a.href=s.href,a.innerHTML=`<span class="page-nav-label">${s.label}</span><span class="page-nav-arrow">→</span>`,i.appendChild(a)}return i}function An(o){return`#/root/${encodeURIComponent(o)}/capabilities`}function Dt(o){return o.filter(t=>t.type==="file"?t.name.endsWith(".md"):t.name==="capabilities"||t.name==="assets"?!1:Dt(t.children).length>0).map(t=>t.type==="file"?t:{...t,children:Dt(t.children)})}function zt(o){const t=[],e=n=>{for(const s of Dt(n))s.type==="file"?t.push(s):e(s.children)};return e(o),t}function W(o,t){return`#/root/${encodeURIComponent(o)}/docs/${encodeURIComponent(t)}`}function St(o,t){return`#/root/${encodeURIComponent(o)}/capabilities/${encodeURIComponent(t)}`}function Tt(o){return`#/root/${encodeURIComponent(o)}/boards`}function q(o,t){return`#/root/${encodeURIComponent(o)}/boards/${encodeURIComponent(t)}`}function Mt(o){return`#/project/${encodeURIComponent(o)}`}function ie(o,t){return`#/root/${encodeURIComponent(o)}/directory/${encodeURIComponent(t)}`}function Ei(o){const t=o.match(/^#\/root\/([^/]+)/);return t?decodeURIComponent(t[1]):null}function Nn(o){var t,e;return((e=(t=o.match(/^#\s+(.+)$/m))==null?void 0:t[1])==null?void 0:e.trim())??null}function Si(o){return[...new Set(o.trim().split(/\s+/).map(it).filter(Boolean))]}function pn(o,t,e){const n=e.filter(Boolean).sort((a,r)=>r.length-a.length);if(n.length===0){o.textContent=t;return}const s=new RegExp(`(${n.map(Ti).join("|")})`,"ig");let i=0;for(const a of t.matchAll(s)){const r=a.index??0;r>i&&o.appendChild(document.createTextNode(t.slice(i,r)));const c=document.createElement("mark");c.textContent=a[0],o.appendChild(c),i=r+a[0].length}i<t.length&&o.appendChild(document.createTextNode(t.slice(i)))}function Ti(o){return o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function zn(o){var t;return((t=o.find(e=>e.kind==="text"&&e.text.length>0))==null?void 0:t.text.slice(0,180))??""}function jn(o){const e=o.replace(/^---[\s\S]*?---\s*/,"").split(`
53
+ `),n=[];let s="",i=[];const a=(c,l="text",d=s)=>{const h=mn(c);h&&n.push({heading:d,text:h,normalized:it(h),kind:l})},r=()=>{i.length!==0&&(a(i.join(" "),"text"),i=[])};for(let c=0;c<e.length;c++){const l=e[c],d=l.match(/^(`{3,})\s*([\w-]+)?\s*$/);if(d){r();const u=d[1].length,g=(d[2]??"").toLowerCase(),y=new RegExp("^`{"+u+",}\\s*$"),v=[];for(c++;c<e.length&&!y.test(e[c]);)v.push(e[c]),c++;a(g==="board"?Mi(v.join(`
54
+ `)):v.join(`
55
+ `),g==="board"?"board":"code");continue}const h=l.match(/^(#{1,6})\s+(.+)$/);if(h){r(),s=mn(h[2]),a(s,"heading",s);continue}if(l.trim()===""||/^(-{3,}|\*{3,}|_{3,})\s*$/.test(l)){r();continue}if(Pi(l))continue;const p=l.replace(/^>\s?/,"").replace(/^\s*([-*+]|\d+\.)\s+/,"").replace(/^\[([ xX])\]\s+/,"").replace(/\|/g," ");i.push(p)}return r(),n}function Mi(o){return o.split(`
56
+ `).map(t=>t.replace(/#.*$/,"").trim()).filter(Boolean).map(t=>t.replace(/^(\w+)\s*:\s*/,"$1 ")).join(" ")}function Hn(o){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(".md")&&t.push(s):e(s.children)};return e(o),t}function dt(o){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(".board.json")&&t.push(s):e(s.children)};return e(o),t}function Bi(o,t){const e=t.replace(/^\/+|\/+$/g,"");return dt(o).map(n=>_(n.path)).filter(n=>n===e||n.startsWith(`${e}/`))}function Ii(o,t){const e=t.replace(/^\/+|\/+$/g,"");return Hn(o).filter(n=>n.path.startsWith(`${e}/`))}function un(o,t,e,n){if(t===e)return o;const s=o.split(`
57
+ `);let i=!1,a,r=!1;const c=s.map(l=>{if(!i){const u=l.match(/^(`{3,})\s*board\s*$/i);return u&&(i=!0,a=new RegExp("^`{"+u[1].length+",}\\s*$")),l}if(a!=null&&a.test(l))return i=!1,a=void 0,l;const d=l.match(/^(\s*src\s*:\s*)(.*)$/i);if(!d)return l;const h=Fn(d[2]);if(!h.value)return l;const p=$i(h.value,t,e,n);return p===h.value?l:(r=!0,`${d[1]}${p}${h.suffix}`)});return r?c.join(`
58
+ `):o}function Li(o,t,e,n){const s=o.split(`
59
+ `);let i=!1,a,r=!1;const c=s.map(l=>{if(!i){const u=l.match(/^(`{3,})\s*board\s*$/i);return u&&(i=!0,a=new RegExp("^`{"+u[1].length+",}\\s*$")),l}if(a!=null&&a.test(l))return i=!1,a=void 0,l;const d=l.match(/^(\s*src\s*:\s*)(.*)$/i);if(!d)return l;const h=Fn(d[2]);return!h.value||!Ut(h.value,t).includes(e)?l:(r=!0,`${d[1]}${Ri(h.value,t,e,n)}${h.suffix}`)});return r?c.join(`
60
+ `):o}function Fn(o){var i;const t=o.indexOf("#"),e=t===-1?o:o.slice(0,t),n=t===-1?"":o.slice(t),s=((i=e.match(/\s*$/))==null?void 0:i[0])??"";return{value:e.trim(),suffix:`${s}${n}`}}function Ri(o,t,e,n){const s=o.trim(),i=s.startsWith("/"),a=s.startsWith("./")||s.startsWith("../"),r=s.endsWith(".board.json"),c=Ut(s,t),l=!a&&c[0]!==e&&c.includes(e);if(i){const h=`/${n}`;return r&&!h.endsWith(".board.json")?`${h}.board.json`:h}let d=a||l?Wn(Te(t,n)):n;return r&&!d.endsWith(".board.json")&&(d=`${d}.board.json`),d}function $i(o,t,e,n){const s=o.trim(),i=s.startsWith("./")||s.startsWith("../"),a=Ut(s,t),r=a[0]??"",c=a.find(p=>p!==r&&n.has(p));if(!i&&(!c||n.has(r)))return o;const l=s.endsWith(".board.json"),d=i?Zn(s,t):c;if(!d)return o;let h=Wn(Te(e,d));return l&&!h.endsWith(".board.json")&&(h=`${h}.board.json`),h}function Wn(o){return!o||o.startsWith("./")||o.startsWith("../")?o:`./${o}`}function mn(o){return o.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,"$1 $2").replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 $2").replace(/`([^`]+)`/g,"$1").replace(/~~([\s\S]*?)~~/g,"$1").replace(/\*\*\*([\s\S]*?)\*\*\*/g,"$1").replace(/___([\s\S]*?)___/g,"$1").replace(/\*\*([\s\S]*?)\*\*/g,"$1").replace(/__([\s\S]*?)__/g,"$1").replace(/(^|[\s([{])\*([^*\s][\s\S]*?[^*\s])\*(?=$|[\s)\]},.!?:;])/g,"$1$2").replace(/(^|[\s([{])_([^_\s][\s\S]*?[^_\s])_(?=$|[\s)\]},.!?:;])/g,"$1$2").replace(/\\([\\`*_[\]{}()#+\-.!|>])/g,"$1").replace(/<[^>]+>/g," ").replace(/&nbsp;/g," ").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/(^|[\s([{])[*_]{1,3}(?=\S)/g,"$1").replace(new RegExp("(?<=\\S)[*_]{1,3}(?=$|[\\s)\\]},.!?:;])","g"),"").replace(/\s+/g," ").trim()}function it(o){return o.normalize("NFKD").replace(/[\u0300-\u036f]/g,"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function jt(o,t,e,n){if(!o)return 0;let s=e&&o.includes(e)?n*4:0;for(const i of t)o===i&&(s+=n*5),o.startsWith(i)&&(s+=n*3),o.includes(i)&&(s+=n);return s}function Di(o,t){if(t.length===0)return o.slice(0,220);const e=it(o),n=t.map(l=>e.indexOf(l)).filter(l=>l>=0).sort((l,d)=>l-d)[0];if(n===void 0)return o.slice(0,220);const s=e.length===0?0:n/e.length,i=Math.round(o.length*s),a=Math.max(0,i-90),r=Math.min(o.length,i+170),c=o.slice(a,r).trim();return`${a>0?"... ":""}${c}${r<o.length?" ...":""}`}function Pi(o){return/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(o)}function G(o){const t=o.replace(/\.md$/,"").replace(/[-_]/g," ");return t.charAt(0).toUpperCase()+t.slice(1)}function Ai(o){return o.trim().replace(/[\\/]+/g,"-").replace(/\s+/g,"-").replace(/[^a-z0-9-_]/gi,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").toLowerCase()}const Ni=new Set([".","..","assets","boards","capabilities","docs"]);function ft(o,t){const e=t==="doc"?"doc":t,n=o.trim();if(!n)return{ok:!1,message:`Enter a ${e} name.`};if(n.length>80)return{ok:!1,message:"Name must be 80 characters or fewer."};if(/[\\/]/.test(n))return{ok:!1,message:"Name cannot contain slashes."};if(/^\.+$/.test(n))return{ok:!1,message:"Name cannot contain only dots."};if(n.startsWith("."))return{ok:!1,message:"Name cannot start with a dot."};if(/[<>:"|?*\x00-\x1F]/.test(n))return{ok:!1,message:"Name contains characters that are not allowed in files."};const s=Ai(n);return s?s.length>64?{ok:!1,message:"Name is too long after formatting."}:Ni.has(s)?{ok:!1,message:`"${s}" is reserved by the workspace.`}:/[a-z0-9]/.test(s)?{ok:!0,raw:n,slug:s}:{ok:!1,message:"Name must include letters or numbers."}:{ok:!1,message:"Name must include letters or numbers."}}function Ht(o){const t=o.replace(/^\/+|\/+$/g,"");return t.split("/").pop()??t}function fn(o,t){const e=o.replace(/^\/+|\/+$/g,""),n=t.replace(/^\/+|\/+$/g,"");return e?`${e}/${n}`:n}function zi(o){if(!o)return;const t=new URLSearchParams(o).get("region");if(!t)return;const e=t.split(",").map(n=>Number(n.trim()));if(!(e.length!==4||e.some(n=>!Number.isFinite(n))||e[2]<=0||e[3]<=0))return[e[0],e[1],e[2],e[3]]}const On=document.getElementById("app");if(!On)throw new Error("Missing #app root element");new ki(On);