viteboard 0.1.4 → 0.1.6

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.
@@ -0,0 +1,95 @@
1
+ var Cs=Object.defineProperty;var ks=(o,t,e)=>t in o?Cs(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var u=(o,t,e)=>ks(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 $="/__api";class se extends Error{constructor(e,n){super(e);u(this,"currentRevision");this.name="RevisionConflictError",this.currentRevision=n}}async function D(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()}function A(o={}){return o}const k={async getWorkspace(){return D(await fetch(`${$}/workspace`,A()))},async removeProject(o){await D(await fetch(`${$}/workspace/project?id=${encodeURIComponent(o)}`,A({method:"DELETE"})))},async pickAndAddProject(){return D(await fetch(`${$}/workspace/pick-project`,A({method:"POST"})))},async ensureProjectDocsRoot(o){return(await D(await fetch(`${$}/workspace/project/docs-root`,A({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:o})})))).root},async getTree(o){return(await D(await fetch(`${$}/tree?rootId=${encodeURIComponent(o)}`,A()))).tree},async getProjectTree(o){return(await D(await fetch(`${$}/project-tree?projectId=${encodeURIComponent(o)}`,A()))).tree},async createDocsFolder(o,t){await D(await fetch(`${$}/workspace/project/create-docs-folder`,A({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:o,parentPath:t})})))},async readFile(o,t){return(await D(await fetch(`${$}/file?rootId=${encodeURIComponent(o)}&path=${encodeURIComponent(t)}`,A()))).content},async readFileWithRevision(o,t){return D(await fetch(`${$}/file?rootId=${encodeURIComponent(o)}&path=${encodeURIComponent(t)}`,A()))},async writeFile(o,t,e,n){const s=await fetch(`${$}/file`,A({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,path:t,content:e,expectedRevision:n})}));if(s.status===409){const a=await s.json();throw new se(a.error??"File changed on disk",a.currentRevision??null)}return(await D(s)).revision},async createDirectory(o,t){await D(await fetch(`${$}/directory`,A({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,path:t})})))},async getBoard(o,t){const e=await fetch(`${$}/board?rootId=${encodeURIComponent(o)}&id=${encodeURIComponent(t)}`,A());return e.status===404?null:(await D(e)).doc},async getBoardWithRevision(o,t){const e=await fetch(`${$}/board?rootId=${encodeURIComponent(o)}&id=${encodeURIComponent(t)}`,A());return e.status===404?null:D(e)},async saveBoard(o,t,e,n){const s=await fetch(`${$}/board`,A({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,id:t,doc:e,expectedRevision:n})}));if(s.status===409){const a=await s.json();throw new se(a.error??"Board changed on disk",a.currentRevision??null)}return(await D(s)).revision},async deleteFile(o,t){await D(await fetch(`${$}/file?rootId=${encodeURIComponent(o)}&path=${encodeURIComponent(t)}`,A({method:"DELETE"})))},async renameFile(o,t,e,n=!1){await D(await fetch(`${$}/file`,A({method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,oldPath:t,newPath:e,ignoreMissing:n})})))},async deleteBoard(o,t){await D(await fetch(`${$}/board?rootId=${encodeURIComponent(o)}&id=${encodeURIComponent(t)}`,A({method:"DELETE"})))},assetUrl(o,t){return`${$}/asset?rootId=${encodeURIComponent(o)}&path=${encodeURIComponent(t)}`},async uploadAsset(o,t,e,n){return(await D(await fetch(`${$}/asset`,A({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,name:t,base64:e,mimeType:n})})))).path},async cleanupManagedAssets(o,t=[]){return(await D(await fetch(`${$}/asset/cleanup`,A({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:o,preservePaths:t})})))).removed}};function Es(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 Ue(o){for(const t of o){if(t.type==="file"&&t.name.endsWith(".md"))return t.path;if(t.type==="dir"){const e=Ue(t.children);if(e)return e}}return null}function wt(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 qn(o){const t=wt(o),e=t.lastIndexOf("/");return e===-1?"":t.slice(0,e)}function Ss(o,t){if(/^(https?:|mailto:|tel:|#|data:)/.test(t))return t;if(t.startsWith("/"))return wt(t);const e=qn(o);return wt(e?`${e}/${t}`:t)}function Ye(o,t){const e=qn(o),n=e?e.split("/").filter(Boolean):[],s=wt(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 Ts=["sticky","task","rectangle","ellipse","text","line","arrow","connector","image","screenshot","frame","templateGroup"];function ce(o){const t=new Set;for(const e of o.elements){const n=e.data.assetId;typeof n=="string"&&t.add(n)}return{...o.schemaUrl?{$schema:o.schemaUrl}:{},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 Y(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"||!Ts.includes(t.type)||!Y(t.x)||!Y(t.y)||!Y(t.width)||!Y(t.height)?null:{id:t.id,type:t.type,x:t.x,y:t.y,width:t.width,height:t.height,rotation:Y(t.rotation)?t.rotation:0,zIndex:Y(t.zIndex)?t.zIndex:0,locked:t.locked===!0,hidden:t.hidden===!0,createdAt:Y(t.createdAt)?t.createdAt:Date.now(),updatedAt:Y(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 we(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{...typeof t.$schema=="string"?{$schema:t.$schema}:{},version:1,id:t.id,title:typeof t.title=="string"?t.title.slice(0,200):"Imported Board",createdAt:Y(t.createdAt)?t.createdAt:Date.now(),updatedAt:Y(t.updatedAt)?t.updatedAt:Date.now(),viewport:{offsetX:Y(n.offsetX)?n.offsetX:0,offsetY:Y(n.offsetY)?n.offsetY:0,scale:Y(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 Ms="/board-v1.schema.json",Bs=".board.json";function G(o){return o.replace(/\.board\.json$/,"")}function Is(o){return o.trim().replace(/^\/+/,"").replace(/\.board\.json$/,"")}function Rs(o,t){return re(o,t)[0]??""}function re(o,t){const e=o.trim(),n=Is(o);if(!n)return[];if(e.startsWith("./")||e.startsWith("../")){const r=t.lastIndexOf("/"),c=r===-1?"":t.slice(0,r);return[wt(c?`${c}/${n}`:n)]}if(e.startsWith("/")){const r=t.lastIndexOf("/"),c=r===-1?"":t.slice(0,r),l=wt(c?`${c}/${n}`:n),d=[n];if(l&&l!==n&&d.push(l),c){const h=c.includes("/")?c.slice(0,c.lastIndexOf("/")):"",p=wt(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=wt(i?`${i}/${n}`:n);return a&&a!==n?[a,n]:[n]}function en(o){return o.toLowerCase().replace(/[^\w\s-]/g,"").trim().replace(/\s+/g,"-").slice(0,48)||"board"}function Ls(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 J={async listIds(o){const t=await k.getTree(o);return $s(t).map(e=>G(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 we(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=en(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=en(t);let r=`${n?`${n.replace(/^\/+|\/+$/g,"")}/`:""}${i}`;s.has(r)&&(r=`${r}-${Date.now().toString(36)}`);const c=Date.now(),l={$schema:Ms,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 Ls(t);return k.uploadAsset(o,e??"image.png",n,t.type)},async cleanupUnusedAssets(o,t=[]){return k.cleanupManagedAssets(o,t)}};function $s(o){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(Bs)&&t.push(s):e(s.children)};return e(o),t}const Ps=new Set(["capabilities","assets"]);class Ds{constructor(t,e){u(this,"element");u(this,"header");u(this,"nav");u(this,"footer");u(this,"links",new Map);u(this,"collapsibles",new Map);u(this,"collapsedState",new Map);u(this,"callbacks");u(this,"contextMenu");u(this,"draggedItem");u(this,"dropExpandTimer");u(this,"dropExpandTarget");u(this,"lastWorkspace",{projects:[]});u(this,"lastTreesByRoot",new Map);u(this,"lastTreesByProject",new Map);u(this,"rawModeProjects",new Set);u(this,"lastActiveHash","");u(this,"forceNextActiveSync",!0);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,{forceSyncAncestors:this.forceNextActiveSync}),this.forceNextActiveSync=!1}setActive(t,e={}){var s,i;for(const a of new Set(this.links.values()))a.classList.remove("active");const n=this.links.get(t);if(n)n.classList.add("active");else if(t.startsWith("#/root/")){const a=t.match(/^#\/root\/([^/]+)\/(boards|capabilities|docs)(?:\/(.+))?$/);if(a){const[,r,c]=a,l=decodeURIComponent(r);c==="boards"?(s=this.links.get(Hs(l)))==null||s.classList.add("active"):c==="capabilities"&&((i=this.links.get(Fs(l)))==null||i.classList.add("active"))}}(e.forceSyncAncestors||t!==this.lastActiveHash)&&this.syncCollapsed(t),this.lastActiveHash=t}toggleRawMode(t){this.rawModeProjects.has(t)?this.rawModeProjects.delete(t):this.rawModeProjects.add(t),this.forceNextActiveSync=!0,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 m=p.docsRoots.find(g=>g.id===i);if(m){c=p.id,l=m.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 m=`folder:${c}:${h}`;this.collapsibles.has(m)&&e.add(m)}if((a==="docs"||a==="capabilities")&&r){const m=(a==="capabilities"?`capabilities/${r}`:r).split("/");for(let g=1;g<m.length;g++){const y=m.slice(0,g).join("/"),b=`doc:${i}:${y}`;this.collapsibles.has(b)&&e.add(b)}}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("div");l.className="nav-repo-header-row";const d=document.createElement("button");d.className="nav-repo-header",d.type="button";const h=document.createElement("span");h.className="nav-repo-chevron",h.textContent="›";const p=document.createElement("span");p.className="nav-repo-label-text",p.textContent=s;const m=!a&&i.find(v=>xt(v.displayPath)==="docs"),g=document.createElement("span");g.className="nav-tree-badge",g.textContent="DOCS",g.hidden=!m;const y=document.createElement("button");y.className="nav-repo-more",y.type="button",y.title="Project options",y.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>',y.addEventListener("click",v=>{v.stopPropagation();const S=y.getBoundingClientRect();this.showContextMenu(S.right+4,S.top,s,[{icon:a?Et:At,iconClass:a?"nav-ctx-doc":"nav-ctx-dir",label:a?"View: Docs":"View: Raw",action:()=>this.toggleRawMode(n)},{icon:$e,iconClass:"nav-ctx-edit",label:"Wiki",action:()=>{location.hash=`#/project/${encodeURIComponent(n)}`}},{kind:"divider"},{icon:Et,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateProjectDoc(n)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateProjectBoard(n)},{icon:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateProjectDirectory(n)},{kind:"divider"},{icon:Vt,iconClass:"nav-ctx-delete",label:"Remove from workspace",action:()=>this.callbacks.onRemoveProject(n,s),danger:!0}])}),d.append(h,p,g),l.append(d,y),this.registerCollapsible(n,r,c,d,!0),d.addEventListener("click",()=>this.toggleCollapsible(n)),l.addEventListener("contextmenu",v=>{v.preventDefault(),v.stopPropagation(),y.click()});const b=Os(t,this.lastTreesByProject.get(n)??[],e),x=a?b:_e(ve(b));if(x.length===0){const v=document.createElement("div");v.className="nav-label nav-empty-copy",v.textContent="No folders found.",r.appendChild(v)}else r.appendChild(this.renderCanonicalNodes(t,x,0,a));return c.append(l,r),c}renderCanonicalNodes(t,e,n,s){const i=document.createElement("div");for(const a of Us(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=_s(a);h&&l.classList.add("nav-tree-capability-folder");const p=document.createElement("span");if(p.textContent=a.name,l.appendChild(d),h&&l.insertAdjacentHTML("beforeend",Re),l.appendChild(p),a.kind==="docsRoot"||a.docsContainerRoot){const g=document.createElement("span");g.className="nav-tree-badge",g.textContent="DOCS",l.appendChild(g)}const m=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(m,c,r,l,!0),l.addEventListener("click",()=>this.toggleCollapsible(m)),a.kind==="docsRoot"||a.docsContainerRoot){const g=a.docsContainerRoot??a.root;l.addEventListener("contextmenu",y=>{y.preventDefault(),y.stopPropagation(),this.openDirContextMenu(y.clientX,y.clientY,g,"")}),this.enableDirectoryDropTarget(r,g.id,"")}else if(a.root){const g=a.root,y=a.contentPath??"";this.enableDragSource(l,{kind:"dir",rootId:g.id,path:y}),this.enableDirectoryDropTarget(r,g.id,y),r.addEventListener("contextmenu",b=>{b.preventDefault(),b.stopPropagation(),this.openDirContextMenu(b.clientX,b.clientY,g,y)})}else l.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.showContextMenu(g.clientX,g.clientY,a.name,[{icon:At,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"){if(t.root&&t.contentPath&&oe(t.contentPath)){const l=document.createElement("button");return l.className="nav-link nav-tree-row nav-tree-file nav-tree-capability-file",l.type="button",l.style.setProperty("--tree-depth",String(e)),l.insertAdjacentHTML("afterbegin",Le),l.appendChild(document.createTextNode(t.name)),l.addEventListener("click",d=>{d.preventDefault(),this.callbacks.onOpenTextFile(t.root.id,t.contentPath)}),l.addEventListener("contextmenu",d=>{d.preventDefault(),d.stopPropagation(),this.openTextFileContextMenu(d.clientX,d.clientY,t.root,t.contentPath)}),l}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"?nn(n.id,s):t.kind==="board"?sn(n.id,G(s)):js(n.id,s),a=t.kind==="doc"&&t.name==="index.md"?"Overview":Nt(t.kind==="board"?G(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"?Dt:t.kind==="capability"?Re:Et),this.enableDragSource(r,t.kind==="board"?{kind:"board",rootId:n.id,boardId:G(s)}:t.kind==="capability"?{kind:"capability",rootId:n.id,path:s}:{kind:"doc",rootId:n.id,path:s}),r.addEventListener("contextmenu",c=>{c.preventDefault(),c.stopPropagation(),t.kind==="board"?this.openBoardContextMenu(c.clientX,c.clientY,n,G(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(m=>m.displayPath===e.path||m.displayPath.endsWith("/"+e.path));if(p){const m=n.get(p.id)??[];return this.docsRootSection(p,m)}}const i=Gn(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(m=>m.displayPath.startsWith(e.path+"/")||m.displayPath===e.path);p&&l.addEventListener("contextmenu",m=>{m.preventDefault(),m.stopPropagation(),this.openDirContextMenu(m.clientX,m.clientY,p,"")})}else l.addEventListener("contextmenu",p=>{p.preventDefault(),p.stopPropagation(),this.showContextMenu(p.clientX,p.clientY,e.name,[{icon:At,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=Zn(a),{row:p,toggle:m}=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,m,!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,As(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=Kn(e),r=Ns(s,n),c=[...a.map(l=>({kind:l.type==="file"&&oe(l.path)?"file":"doc",node:l})),...r.map(l=>({kind:"board",name:Nt(G(l.path).split("/").pop()??G(l.path)),boardId:G(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 m=(l.kind==="doc"||l.kind==="file")&&l.node.type==="file"&&on(l.node.name),g=(d.kind==="doc"||d.kind==="file")&&d.node.type==="file"&&on(d.node.name);if(m!==g)return m?-1:1;const y=(l.kind==="doc"||l.kind==="file")&&l.node.type==="dir",b=(d.kind==="doc"||d.kind==="file")&&d.node.type==="dir";if(y!==b)return y?-1:1;const x=l.kind==="board"?l.name:l.node.name,v=d.kind==="board"?d.name:d.node.name;return x.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=sn(t.id,l.boardId),d.insertAdjacentHTML("afterbegin",Dt),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(l.kind==="file"){const m=document.createElement("button");m.className="nav-link nav-tree-file nav-tree-capability-file",m.type="button",m.insertAdjacentHTML("afterbegin",Le),m.appendChild(document.createTextNode(d.name)),m.addEventListener("click",()=>this.callbacks.onOpenTextFile(t.id,d.path)),m.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.openTextFileContextMenu(g.clientX,g.clientY,t,d.path)}),i.appendChild(m);continue}if(!d.name.endsWith(".md"))continue;const h=d.name==="index.md"?"Overview":Nt(d.name),p=this.link(nn(t.id,d.path),h,`doc:${t.id}:${d.path}`);p.insertAdjacentHTML("afterbegin",Et),this.enableDragSource(p,{kind:"doc",rootId:t.id,path:d.path}),p.addEventListener("contextmenu",m=>{m.preventDefault(),m.stopPropagation(),this.openDocContextMenu(m.clientX,m.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 m=document.createElement("div");m.className="nav-subgroup nav-collapsible-dir";const{row:g,toggle:y}=this.createDirectoryRow(Nt(d.name),`#/root/${encodeURIComponent(t.id)}/directory/${encodeURIComponent(d.path)}`,`${d.name} wiki`,b=>{b.button===0&&this.toggleCollapsible(h)},!1);this.enableDragSource(y,{kind:"dir",rootId:t.id,path:d.path}),m.addEventListener("contextmenu",b=>{b.preventDefault(),b.stopPropagation(),this.openDirContextMenu(b.clientX,b.clientY,t,d.path)}),this.enableDirectoryDropTarget(m,t.id,d.path),this.registerCollapsible(h,p,m,y,!0),m.append(g,p),i.appendChild(m)}}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",Xs(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=xt(n);if(t.kind==="doc")return Ct(t.path)!==s;if(t.kind==="capability")return s==="capabilities"||s.startsWith("capabilities/")&&Ct(t.path)!==s;if(t.kind==="board")return Ct(t.boardId)!==s;const i=xt(t.path);return!i||i===s||Ct(i)===s?!1:!s.startsWith(`${i}/`)}moveDraggedItem(t,e){const n=xt(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?Nt(s.split("/").pop()??s):n.displayPath.split("/").pop()??n.displayPath,a=[{icon:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateDirectory(n.id,s)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateBoard(n.id,s)},{icon:Et,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateDoc(n.id,s)},{icon:Re,iconClass:"nav-ctx-cap",label:"New Capability",action:()=>this.callbacks.onCreateCapability(n.id,s)}];s&&a.push({icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDirectory(n.id,s)},{icon:Vt,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:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateProjectDirectory(n)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateProjectBoard(n)},{icon:Et,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:Et,iconClass:"nav-ctx-doc",label:"Open",action:()=>this.callbacks.onOpenDoc(n.id,s)},{icon:$e,iconClass:"nav-ctx-edit",label:"Edit",action:()=>this.callbacks.onEditDoc(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDoc(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDoc(n.id,s),danger:!0}])}openTextFileContextMenu(t,e,n,s){const i=s.split("/").pop()??s;this.showContextMenu(t,e,i,[{icon:Le,iconClass:"nav-ctx-doc",label:"Open",action:()=>this.callbacks.onOpenTextFile(n.id,s)},{icon:$e,iconClass:"nav-ctx-edit",label:"Edit",action:()=>this.callbacks.onOpenTextFile(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDoc(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDoc(n.id,s),danger:!0}])}openBoardContextMenu(t,e,n,s){const i=Nt(s.split("/").pop()??s);this.showContextMenu(t,e,i,[{icon:Dt,iconClass:"nav-ctx-board",label:"Open",action:()=>this.callbacks.onOpenBoard(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameBoard(n.id,s)},{icon:Vt,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 Dt='<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>',Re='<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>',Et='<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>',Le='<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"/></svg>',At='<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>',$e='<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>',le='<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>',Vt='<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 Kn(o){return o.filter(t=>t.type==="file"?t.name.endsWith(".md")||oe(t.path):!Ps.has(t.name)).map(t=>t.type==="file"?t:{...t,children:Kn(t.children)})}function As(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 Ns(o,t){const e=t?`${t}/`:"";return zs(o).filter(n=>e?n.path.startsWith(e)?!n.path.slice(e.length).includes("/"):!1:!n.path.includes("/"))}function zs(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 nn(o,t){return`#/root/${encodeURIComponent(o)}/docs/${encodeURIComponent(t)}`}function Hs(o){return`#/root/${encodeURIComponent(o)}/boards`}function sn(o,t){return`#/root/${encodeURIComponent(o)}/boards/${encodeURIComponent(t)}`}function Fs(o){return`#/root/${encodeURIComponent(o)}/capabilities`}function js(o,t){return`#/root/${encodeURIComponent(o)}/capabilities/${encodeURIComponent(Ws(t))}`}function Ws(o){return o.replace(/^capabilities\//,"")}function Os(o,t,e){const n=new Map,s=[],i=c=>{const l=xt(c),d=n.get(l);if(d)return d;const h=Ct(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=Ct(l.path);h?i(h).children.push(d):s.push(d)}};a(t);for(const c of o.docsRoots){const l=xt(c.displayPath),d=i(l);d.kind="docsRoot",d.id=`root:${c.id}`,d.root=c,d.contentPath="";const h=p=>{for(const m of p){const g=[l,m.path].filter(Boolean).join("/");if(m.type==="dir"){const E=i(g);E.kind!=="docsRoot"&&(E.root=c,E.contentPath=m.path),h(m.children);continue}const y=m.name.endsWith(".board.json"),b=Vn(m.path),x=oe(m.path);if(!m.name.endsWith(".md")&&!y&&!x)continue;const v=Ct(g),S=n.get(g),w=S??{id:"",kind:"file",name:m.name,projectPath:g,children:[]};w.id=`${y?"board":b?"capability":x?"file":"doc"}:${c.id}:${m.path}`,w.kind=y?"board":b?"capability":x?"file":"doc",w.root=c,w.contentPath=m.path,S||(n.set(g,w),v?i(v).children.push(w):s.push(w))}};h(e.get(c.id)??[])}const r=(c,l)=>{const d=c.kind==="docsRoot"?c.root:c.root??l;if(d&&(c.kind==="folder"||c.kind==="file")&&!c.contentPath){c.root=d;const h=xt(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 Us(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"?4:(s.kind==="docsRoot",5);return n(t)-n(e)||t.name.localeCompare(e.name,void 0,{sensitivity:"accent"})})}function on(o){return/^readme\.(md|txt)$/i.test(o)}function ve(o,t,e=!1){const n=[];for(const s of o){if(s.kind==="docsRoot"){n.push({...s,children:ve(s.children,!1,!0)});continue}if(e){if(s.kind==="file"){oe(s.contentPath??"")&&n.push(s);continue}if(s.kind==="folder"){const i=ve(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=ve(s.children);i.length>0&&n.push({...s,children:i})}}return n}function _e(o){var e;const t=[];for(const n of o){if(n.kind==="docsRoot"){t.push(..._e(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:_e(n.children)})}return t}function Nt(o){const t=o.replace(/\.md$/,"").replace(/[-_]/g," ");return t.charAt(0).toUpperCase()+t.slice(1)}function Vn(o){if(!o.startsWith("capabilities/")||!o.endsWith(".md"))return!1;const t=o.slice(13);return t.includes("/")?t.endsWith("/index.md"):!0}function oe(o){return!o.startsWith("capabilities/")||o.endsWith(".board.json")?!1:!Vn(o)}function _s(o){var t;return o.kind!=="folder"||!((t=o.contentPath)!=null&&t.startsWith("capabilities/"))?null:o.children.find(e=>e.kind==="capability"&&Ct(e.contentPath??"")===o.contentPath)??null}function Gn(o){if(o.type==="file")return!1;for(const t of o.children)if(t.type==="dir"&&t.name==="docs"||t.type==="dir"&&Gn(t))return!0;return!1}function xt(o){return o.replace(/^\/+|\/+$/g,"")}function Ct(o){const t=xt(o),e=t.lastIndexOf("/");return e===-1?"":t.slice(0,e)}function Xs(o){return o.kind==="doc"||o.kind==="capability"?o.path:o.kind==="board"?o.boardId:o.path}function Zn(o){if(o.kind==="root")return o.root;for(const t of o.children){const e=Zn(t);if(e)return e}return null}function ne(o,t={}){const{frontmatter:e,body:n}=qs(o);try{const s=Jn(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>${Ut(String(s))}</pre></div>`}}}function qs(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 Jn(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*$"),m=[];for(n++;n<o.length&&!p.test(o[n]);)m.push(o[n]),n++;n++,h==="board"?e.push(Vs(ts(m.join(`
5
+ `)))):e.push(`<pre class="code-block"><code${h?` class="language-${h}"`:""}>${Ut(m.join(`
6
+ `))}</code></pre>`);continue}const c=a.match(/^(#{1,6})\s+(.*)$/);if(c){const d=c[1].length,h=Lt(c[2].trim(),t),p=Js(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>${Jn(d,t)}</blockquote>`);continue}if(a.includes("|")&&n+1<o.length&&Ys(o[n+1])){const d=[];for(;n<o.length&&o[n].includes("|")&&o[n].trim()!=="";)d.push(o[n]),n++;e.push(Ks(d,t));continue}if(Wt(a)){const d=[];for(;n<o.length&&(Wt(o[n])||/^\s+\S/.test(o[n])||o[n].trim()==="");){if(o[n].trim()===""){const h=o[n+1];if(h===void 0||!Wt(h)&&!/^\s+\S/.test(h))break}d.push(o[n]),n++}e.push(Qn(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])&&!Wt(o[n])&&!/^(-{3,}|\*{3,}|_{3,})\s*$/.test(o[n]);)l.push(o[n]),n++;e.push(`<p>${Lt(l.join(" ").trim(),t)}</p>`)}return e.join(`
7
+ `)}function Wt(o){return/^\s*([-*+]|\d+\.)\s+/.test(o)}function Qn(o,t){const e=o.filter(l=>Wt(l)).map(l=>l.match(/^\s*/)[0].length);if(e.length===0)return Lt(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],m=null;const g=p.match(/^\[([ xX])\]\s+(.*)$/);g&&(m=g[1].toLowerCase()==="x",p=g[2]),a={ordered:i,content:[p],checked:m},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=Lt(d,t);const m=h.filter(g=>g.trim()!=="");return m.some(g=>Wt(g))?p+=Qn(h,t):m.length&&(p+=" "+Lt(m.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 Ys(o){return/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(o)}function Pe(o){return o.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(t=>t.trim())}function Ks(o,t){const e=Pe(o[0]),n=Pe(o[1]).map(r=>{const c=r.startsWith(":"),l=r.endsWith(":");return c&&l?"center":l?"right":c?"left":""}),s=o.slice(2).map(Pe),i=e.map((r,c)=>`<th${n[c]?` style="text-align:${n[c]}"`:""}>${Lt(r,t)}</th>`).join(""),a=s.map(r=>`<tr>${r.map((c,l)=>`<td${n[l]?` style="text-align:${n[l]}"`:""}>${Lt(c,t)}</td>`).join("")}</tr>`).join("");return`<div class="markdown-table-scroll"><table><thead><tr>${i}</tr></thead><tbody>${a}</tbody></table></div>`}function ts(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 Vs(o){const t=o.region?o.region.join(","):"";return`<figure class="board-embed" data-src="${Bt(o.src)}" data-region="${t}" data-height="${o.height}" data-title="${Bt(o.title??"")}"></figure>`}function Lt(o,t){let e=o;const n=[];e=e.replace(/\\([\\`*_{}\[\]()#+\-.!|])/g,(a,r)=>(n.push(r),`${n.length-1}`));const s=[];e=e.replace(/`([^`]+)`/g,(a,r)=>(s.push(`<code>${Ut(de(r,n))}</code>`),`\0${s.length-1}\0`));const i=[];return e=e.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g,(a,r,c)=>{const l=de(c,n),d=Ke(l,t),h=Gs(l,t),p=de(r,n),m=d===l?"":` data-md-src="${Bt(l)}"`;return i.push(`<img src="${Bt(h)}" alt="${Bt(p)}" loading="lazy"${m} />`),`${i.length-1}`}),e=e.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(a,r,c)=>{const l=de(c,n),d=Zs(l,t),p=/^(https?:|mailto:|tel:)/.test(l)?' target="_blank" rel="noopener noreferrer"':"",m=d===l?"":` data-md-href="${Bt(l)}"`;return i.push(`<a href="${Bt(d)}"${p}${m}>${an(r,n,s)}</a>`),`${i.length-1}`}),e=an(e,n,s),e=e.replace(/\u0002(\d+)\u0002/g,(a,r)=>i[Number(r)]??""),e}function an(o,t,e){let n=Ut(o);return n=n.replace(/\*\*([\s\S]+?)\*\*/g,"<strong>$1</strong>"),n=n.replace(/__([\s\S]+?)__/g,"<strong>$1</strong>"),n=n.replace(/(^|[^*])\*([^*\s][^*]*)\*/g,"$1<em>$2</em>"),n=n.replace(/(^|[^_])_([^_\s][^_]*)_/g,"$1<em>$2</em>"),n=n.replace(/\u0000(\d+)\u0000/g,(s,i)=>e[Number(i)]??""),n=n.replace(/\u0001(\d+)\u0001/g,(s,i)=>Ut(t[Number(i)]??"")),n}function de(o,t){return o.replace(/\u0001(\d+)\u0001/g,(e,n)=>t[Number(n)]??"")}function Gs(o,t){if(/^(https?:|data:)/.test(o)||!t.rootId||!t.docPath)return o;const e=Ke(o,t);return e?k.assetUrl(t.rootId,e):o}function Zs(o,t){if(/^(https?:|mailto:|tel:|#|data:)/.test(o)||!t.rootId||!t.docPath)return o;const e=Ke(o,t);return e?e.endsWith(".md")?`#/root/${encodeURIComponent(t.rootId)}/docs/${encodeURIComponent(e)}`:k.assetUrl(t.rootId,e):o}function Ke(o,t){return t.docPath?Ss(t.docPath,o):o}function Ut(o){return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function Bt(o){return Ut(o).replace(/"/g,"&quot;")}function Js(o){return o.toLowerCase().replace(/[^\w\s-]/g,"").trim().replace(/\s+/g,"-")}class es{constructor(t,e,n){u(this,"cache",new Map);u(this,"loading",new Set);u(this,"missing",new Set);u(this,"assetStore");u(this,"onLoaded");u(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}}const Qs="viteboard",to=1;class eo{constructor(){u(this,"dbPromise",null)}open(){return this.dbPromise?this.dbPromise:(this.dbPromise=new Promise((t,e)=>{const n=indexedDB.open(Qs,to);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 K=new eo;class no{async get(t){try{return await K.get("assets",t)}catch{return}}async createFromBlob(t,e){const n=await so(t),s=await this.get(n);if(s)return s;const i=await createImageBitmap(t),a=Date.now(),r={id:n,type:"image",mimeType:t.type||"image/png",blob:t,width:i.width,height:i.height,sizeBytes:t.size,createdAt:a,updatedAt:a,name:e};return i.close(),await K.put("assets",r),r}async put(t){await K.put("assets",t)}async delete(t){await K.delete("assets",t)}async getAllKeys(){try{return await K.getAllKeys("assets")}catch{return[]}}async getAll(){try{return await K.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 K.delete("assets",s),n++);return n}async clearAll(){await K.clearStore("assets")}}const ot=new no;async function so(o){const t=await crypto.subtle.digest("SHA-256",await o.arrayBuffer());return Array.from(new Uint8Array(t),e=>e.toString(16).padStart(2,"0")).join("")}const Ot=new Map,oo=2e3;function X(o){for(const t of Ot.keys())t.startsWith(o+"|")&&Ot.delete(t)}function Te(o){if(o.data.shapeKind==="chevron"){if(typeof o.style.fontSize=="number"&&Number.isFinite(o.style.fontSize))return o.style.fontSize;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 io(o,t,e,n){const s=Ot.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 Ot.size>oo&&Ot.clear(),Ot.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 xe(o,t){const{ctx:e,lod:n}=t;if(e.save(),e.globalAlpha=o.style.opacity??1,n===0){ao(o,t),e.restore();return}switch(o.type){case"sticky":ro(o,t);break;case"task":co(o,t);break;case"rectangle":case"frame":rn(o,t);break;case"ellipse":go(o,t);break;case"text":yo(o,t);break;case"line":case"arrow":case"connector":wo(o,t);break;case"image":case"screenshot":xo(o,t);break;default:rn(o,t)}e.restore()}function ao(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 Me(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 Be(o){o.ctx.shadowColor="transparent",o.ctx.shadowBlur=0,o.ctx.shadowOffsetY=0}function ro(o,t){const{ctx:e,lod:n}=t,s=o.style.fill??"#fef08a";if(Me(o,t),_t(e,o.x,o.y,o.width,o.height,o.style.borderRadius??12),e.fillStyle=s,e.fill(),Be(t),n===2){const i=o.data.text??"";i&&Ve(o,t,i,14)}}function co(o,t){const{ctx:e,lod:n}=t,s=o.data.checked===!0,i=t.theme==="dark",a=o.style.borderRadius??14;if(Me(o,t),_t(e,o.x,o.y,o.width,o.height,a),e.fillStyle=o.style.fill??(i?"#17191b":"#ffffff"),e.fill(),Be(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,m=o.style.fontSize??15,g=o.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';if(e.font=`${o.style.fontWeight??"650"} ${m}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),b=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,b),e.lineTo(o.x+h+Math.min(y.width,o.width-h-p),b),e.stroke()}e.restore()}function rn(o,t){const{ctx:e,lod:n}=t,s=o.data.shapeKind??"rectangle",i=o.style.borderRadius??0;if(Me(o,t),s==="diamond"?lo(e,o):s==="triangle"?ho(e,o):s==="chevron"?po(e,o):s==="parallelogram"?uo(e,o):s==="hexagon"?mo(e,o):s==="cylinder"?fo(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()),Be(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;Ve(o,t,a,r)}}}function lo(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 ho(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 po(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 uo(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 mo(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 fo(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 go(o,t){const{ctx:e,lod:n}=t;if(Me(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()),Be(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&&Ve(o,t,s,10)}}function yo(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??"";bo(o,t,e)}function bo(o,t,e){const{ctx:n}=t,s=Te(o),i=o.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',a=o.style.textColor??(t.theme==="dark"?"#f2f2f2":"#1f2933"),r=Math.max(10,o.width),c=ns(e),l=s*1.35;let d=o.y+l/2;n.save(),n.beginPath(),n.rect(o.x,o.y,o.width,o.height),n.clip(),n.textBaseline="middle",n.textAlign="left";for(const h of c){if(d>o.y+o.height)break;let p=h.text,m=o.x,g=s,y=a;if(h.kind==="heading"?g=h.level===1?s*1.35:h.level===2?s*1.18:s*1.08:h.kind==="quote"?(m+=14,y=t.theme==="dark"?"#cbd5e1":"#475569",n.fillStyle=t.theme==="dark"?"#334155":"#cbd5e1",n.fillRect(o.x+2,d-l/2+2,3,Math.max(l-4,10))):h.kind==="list"&&(m+=16,n.fillStyle=y,n.beginPath(),n.arc(o.x+6,d,2.2,0,Math.PI*2),n.fill()),h.kind==="code"){const v=p.split(/\r?\n/),S=g*1.45,w=v.length*S+12;n.fillStyle=t.theme==="dark"?"#111827":"#eef2f7",n.fillRect(o.x,d-l/2,Math.max(80,o.width),w);for(const E of v){if(d>o.y+o.height)break;const M=cn(n,[{text:E,code:!0}],r-12,g,i);for(const T of M){let R=o.x+8;for(const P of T)Xe(n,P,g,i),n.fillStyle=y,n.fillText(P.text,R,d+6),R+=n.measureText(P.text).width;d+=S}}d+=8;continue}const b=vo(p),x=cn(n,b,r-(m-o.x),g,i);for(const v of x){if(d>o.y+o.height)break;let S=m;for(const w of v){if(Xe(n,w,g,i),w.code){const E=n.measureText(w.text).width;n.fillStyle=t.theme==="dark"?"#1f2937":"#eef2f7",n.fillRect(S-2,d-g*.48,E+4,g*.96),n.fillStyle=y}else n.fillStyle=y;n.fillText(w.text,S,d),S+=n.measureText(w.text).width}d+=l}}n.restore()}function ns(o){const t=o.split(/\r?\n/),e=[];for(let n=0;n<t.length;n++){const s=t[n],i=s.trimStart();if(!i){e.push({kind:"paragraph",text:""});continue}if(/^```/.test(i)){const l=[];for(n++;n<t.length&&!/^```/.test(t[n].trimStart());)l.push(t[n]),n++;e.push({kind:"code",text:l.join(`
10
+ `)});continue}const a=i.match(/^(#{1,3})\s+(.*)$/);if(a){e.push({kind:"heading",level:a[1].length,text:a[2]});continue}const r=i.match(/^>\s?(.*)$/);if(r){e.push({kind:"quote",text:r[1]});continue}const c=i.match(/^([-*+]|\d+\.)\s+(.*)$/);if(c){e.push({kind:"list",text:c[2]});continue}e.push({kind:"paragraph",text:s})}return e}function It(o){if(o.type!=="text")return;const t=String(o.data.text??""),e=ns(t),n=Te(o);let s=0;for(const i of e){if(i.kind==="code"){s+=Math.max(1,i.text.split(/\r?\n/).length)+1;continue}const a=Math.max(1,Math.floor(Math.max(120,o.width)/Math.max(6,n*.6))),r=i.text.replace(/[*_`#>-]/g,"");s+=Math.max(1,Math.ceil(Math.max(1,r.length)/a))}o.height=Math.max(n*1.45,s*n*1.35+8)}function vo(o){const t=[];let e=0;for(;e<o.length;){if(o.startsWith("**",e)){const s=o.indexOf("**",e+2);if(s!==-1){t.push({text:o.slice(e+2,s),bold:!0}),e=s+2;continue}}if(o.startsWith("*",e)){const s=o.indexOf("*",e+1);if(s!==-1){t.push({text:o.slice(e+1,s),italic:!0}),e=s+1;continue}}if(o.startsWith("`",e)){const s=o.indexOf("`",e+1);if(s!==-1){t.push({text:o.slice(e+1,s),code:!0}),e=s+1;continue}}let n=o.length;for(const s of["**","*","`"]){const i=o.indexOf(s,e+1);i!==-1&&i<n&&(n=i)}t.push({text:o.slice(e,n)}),e=n}return t.filter(n=>n.text.length>0)}function cn(o,t,e,n,s){const i=[[]];let a=0;for(const r of t){const c=r.text.split(/(\s+)/);for(const l of c){if(!l)continue;const d={...r,text:l};Xe(o,d,n,s);const h=o.measureText(l).width;a>0&&a+h>e&&l.trim()&&(i.push([]),a=0),i[i.length-1].push(d),a+=h}}return i}function Xe(o,t,e,n){const s=t.bold?"700":"400",i=t.italic?"italic ":"",a=t.code?'"SF Mono", ui-monospace, Menlo, monospace':n;o.font=`${i}${s} ${e}px ${a}`}function Ve(o,t,e,n,s="center",i="middle"){const{ctx:a}=t,r=o.data.shapeKind==="chevron",c=Te(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)}`,m=io(a,p,e,h),g=c*1.35,y=m.length*g;let b;i==="middle"?b=o.y+o.height/2-y/2+g/2:b=o.y+n+g/2,a.textBaseline="middle",a.textAlign=s;const x=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 v=0;v<m.length;v++)a.fillText(m[v],x,b+v*g);a.restore()}function wo(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")&&ln(e,a,r,d,h),o.style.arrowStart&&ln(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[m,g]=p.split("|").map(y=>y.trim());m&&De(e,m,s,i,a,r,t,.24),g&&De(e,g,s,i,a,r,t,.76)}else De(e,p,s,i,a,r,t)}}function De(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,m=e+(s-e)*r-h/2,g=n+(i-n)*r-p/2;o.fillStyle=a.theme==="dark"?"#202328":"#ffffff",_t(o,m,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,m+h/2,g+p/2)}function ln(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 xo(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 Co{constructor(t,e){u(this,"element");u(this,"canvas");u(this,"ctx");u(this,"imageCache");u(this,"doc",null);u(this,"region",[0,0,100,100]);u(this,"opts");u(this,"openLink");u(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 es(ot,()=>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?we(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??ko(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 m={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((b,x)=>b.zIndex-x.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||xe(y,m);i.restore()}setTheme(t){this.opts.theme!==t&&(this.opts.theme=t,this.render())}destroy(){this.ro.disconnect(),this.imageCache.clear()}}function ko(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 ee(){return document.documentElement.getAttribute("data-theme")==="dark"?"dark":"light"}function dn(o,t,e){const{html:n,frontmatter:s}=ne(t,e),i=document.createElement("article");i.className="markdown-body",i.innerHTML=n,o.replaceChildren(i),i.querySelectorAll("pre.code-block").forEach(r=>{var h;const c=r.querySelector("code"),l=(h=c==null?void 0:c.textContent)==null?void 0:h.trimEnd();if(!l)return;const d=document.createElement("button");d.className="code-copy-btn",d.type="button",d.textContent="Copy",d.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(l),d.textContent="Copied"}catch{d.textContent="Failed"}window.setTimeout(()=>{d.textContent="Copy"},1200)}),r.appendChild(d)});const a=[];return i.querySelectorAll("figure.board-embed").forEach(r=>{const c=r.dataset.src??"";if(!c)return;const l=re(c,e.docPath),d=l[0]??"",h=r.dataset.region??"",p=h?h.split(",").map(Number):[],m=p.length===4&&p.every(b=>Number.isFinite(b))?[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 Co(r,{rootId:e.rootId,src:d,srcCandidates:l,region:m,height:g,title:y,theme:ee()}))}catch(b){console.error("Board embed failed to mount",c,b),r.textContent=`Could not load board "${c}".`}}),{frontmatter:s,destroy:()=>{for(const r of a)r.destroy()},setTheme:r=>{for(const c of a)c.setTheme(r)}}}const Eo=.05,So=40,ss=1;function L(o,t,e){return{x:(o-e.offsetX)/e.scale,y:(t-e.offsetY)/e.scale}}function Rt(o,t,e){return{x:o*e.scale+e.offsetX,y:t*e.scale+e.offsetY}}function os(o){return Math.min(So,Math.max(Eo,o))}function ie(o,t,e,n){const s=os(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 To(o,t,e){const n=L(0,0,o),s=L(t,e,o);return{left:n.x,top:n.y,right:s.x,bottom:s.y}}class Mo{constructor(){u(this,"schemaUrl");u(this,"boardId","default-board");u(this,"title","Untitled Board");u(this,"createdAt",Date.now());u(this,"viewport",{offsetX:0,offsetY:0,scale:ss});u(this,"theme","light");u(this,"elements",[]);u(this,"elementsById",new Map);u(this,"selectedIds",new Set);u(this,"hoveredId",null);u(this,"sortedCache",null);u(this,"changeListeners",[]);u(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||Bo(n,t)&&e.push(n);return e}}function Bo(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)}let Ae=0;function ae(){return Ae=(Ae+1)%65535,Date.now().toString(36)+"-"+Ae.toString(36)+"-"+Math.random().toString(36).slice(2,8)}function H(o,t={}){const e=Date.now();return{id:ae(),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 hn=200;class Io{constructor(){u(this,"undoStack",[]);u(this,"redoStack",[])}execute(t,e,n){const s={id:ae(),type:t,timestamp:Date.now(),do:e,undo:n};s.do(),this.undoStack.push(s),this.undoStack.length>hn&&this.undoStack.shift(),this.redoStack.length=0}push(t,e,n){const s={id:ae(),type:t,timestamp:Date.now(),do:e,undo:n};this.undoStack.push(s),this.undoStack.length>hn&&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 Ro{constructor(t,e){u(this,"state");u(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:ae(),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 Lo=["image/png","image/jpeg","image/webp","image/gif"],$o=5*1024*1024;class Po{constructor(t,e,n,s,i){u(this,"state");u(this,"commands");u(this,"imageCache");u(this,"notify");u(this,"uploadImage");u(this,"uploadedImageByHash",new Map);this.state=t,this.commands=e,this.imageCache=n,this.notify=s,this.uploadImage=i}async insertBlob(t,e,n,s){if(!Lo.includes(t.type)){this.notify("Unsupported image type");return}t.size>$o&&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 b=await this.uploadOrReuseImage(t,s);c.src=b,r&&this.imageCache.setBySrc(b,r)}catch(b){this.notify("Failed to save image to disk"),console.error("Image upload failed",b);return}else try{const b=await ot.createFromBlob(t,s);c.assetId=b.id,r&&this.imageCache.set(b.id,r)}catch(b){this.notify("Failed to store image (storage quota?)"),console.error("Asset store failed",b);return}const l=L(e,n,this.state.viewport),d=480/Math.min(1,this.state.viewport.scale);let h=i,p=a;const m=Math.max(h,p);if(m>d){const b=d/m;h*=b,p*=b}const g=H("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)}async uploadOrReuseImage(t,e){if(!this.uploadImage)throw new Error("Missing uploadImage");const n=await Do(t),s=this.uploadedImageByHash.get(n);if(s)return s;const i=await this.uploadImage(t,e);return this.uploadedImageByHash.set(n,i),i}}async function Do(o){const t=await crypto.subtle.digest("SHA-256",await o.arrayBuffer());return Array.from(new Uint8Array(t),e=>e.toString(16).padStart(2,"0")).join("")}const pn="application/x-viteboard-elements";class Ao{constructor(t,e,n,s){u(this,"state");u(this,"actions");u(this,"imageInsert");u(this,"internalClipboard",[]);u(this,"internalClipboardToken","");u(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.clipboardData)&&i.preventDefault()},{signal:s}),window.addEventListener("cut",i=>{this.isEditingText(i.target)||this.copySelection(i.clipboardData)&&(this.actions.deleteSelection(),i.preventDefault())},{signal:s})}isEditingText(t){const e=t;return!!e&&(e.tagName==="TEXTAREA"||e.tagName==="INPUT"||e.isContentEditable)}copySelection(t){const e=this.state.getSelected();return e.length===0?!1:(this.internalClipboard=e.map(n=>({...n,style:{...n.style},data:{...n.data}})),this.internalClipboardToken=Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8),t&&this.writeClipboardPayload(t,e),!0)}async handlePaste(t){const e=t.clipboardData,n=e==null?void 0:e.items,s=e==null?void 0:e.getData("text/plain").trim();if(e&&this.isInternalClipboardPaste(e)){t.preventDefault(),this.pasteInternal();return}if(n){for(const i of n)if(i.type.startsWith("image/")){const a=i.getAsFile();if(a&&!s){t.preventDefault(),await this.imageInsert.insertBlob(a,this.lastPointer.x,this.lastPointer.y,"Pasted screenshot");return}}}if(!e&&this.internalClipboard.length>0){t.preventDefault(),this.pasteInternal();return}s&&(t.preventDefault(),this.pasteText(s))}writeClipboardPayload(t,e){try{t.clearData(),t.setData(pn,this.internalClipboardToken),t.setData("text/plain",this.selectionText(e))}catch{}}isInternalClipboardPaste(t){const e=t.getData(pn).trim();return!!e&&e===this.internalClipboardToken&&this.internalClipboard.length>0}selectionText(t){return t.map(n=>typeof n.data.text=="string"?n.data.text.trim():"").filter(Boolean).join(`
11
+
12
+ `)}pasteInternal(){const t=L(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=L(this.lastPointer.x,this.lastPointer.y,this.state.viewport),n=H("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)}});It(n),this.actions.insertElements([n],"paste-text"),this.state.clearSelection(),this.state.selectedIds.add(n.id),this.state.requestRender()}}function No(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(),ie(e.viewport,window.innerWidth/2,window.innerHeight/2,e.viewport.scale*1.2),e.requestRender();return;case"-":a.preventDefault(),ie(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(a.shiftKey?"task":"text");return;case"a":i.setTool("arrow");return;case"i":i.setTool("image");return}},{signal:t})}function zo(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 is(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||xe(h,{ctx:c,scale:n,lod:2,theme:o.theme,imageCache:t});return r}function as(o){return new Promise((t,e)=>{o.toBlob(n=>{n?t(n):e(new Error("PNG encode failed"))},"image/png")})}async function Ho(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=is(o,t,i,s.scale);return as(a)}async function Fo(o,t){const e=zo(o);if(!e)return null;const n=is(o,t,e,1);return as(n)}function un(o,t){const e=URL.createObjectURL(o),n=document.createElement("a");n.href=e,n.download=t,n.click(),URL.revokeObjectURL(e)}class Ge{constructor(t,e){u(this,"overlay");u(this,"rectEl");u(this,"abort",new AbortController);u(this,"start",null);u(this,"onComplete");u(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 Ge(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 jo{constructor(t,e=3,n){u(this,"container");u(this,"layers",[]);u(this,"contexts",[]);u(this,"width",0);u(this,"height",0);u(this,"dpr",1);u(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 Wo{constructor(t,e,n){u(this,"surface");u(this,"state");u(this,"imageCache");u(this,"overlay",{marquee:null,preview:null});u(this,"lastRenderMs",0);u(this,"visibleCount",0);u(this,"cullingEnabled",!0);u(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 m=d;m<t.height;m+=c)n.moveTo(p+h,m),n.arc(p,m,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=To(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)xe(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 m=this.elementScreenBBox(p);n.strokeRect(m.x,m.y,m.w,m.h),r=Math.min(r,m.x),c=Math.min(c,m.y),l=Math.max(l,m.x+m.w),d=Math.max(d,m.y+m.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,xe(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=Rt(n,s,e),c=Rt(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=rs(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 rs(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 Oo{constructor(t){u(this,"rafId",null);u(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 Uo(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 _o{constructor(t){u(this,"state");u(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 Uo(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 m=(e-l)/h,g=(n-d)/p;return m*m+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),m=Math.min(d.y,d.y+d.height),g=Math.max(d.y,d.y+d.height);h>=i&&p<=a&&m>=r&&g<=c&&l.push(d)}return l}}class Xo{constructor(){u(this,"fps",0);u(this,"frameCount",0);u(this,"lastSample",performance.now());u(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 qo=16,Yo=720,mn=120,Ko=.0032;class Vo{constructor(t,e,n,s){u(this,"tools",new Map);u(this,"active");u(this,"ctx");u(this,"target");u(this,"spaceDown",!1);u(this,"tempPanning",!1);u(this,"panLast",{x:0,y:0});u(this,"toolChangeListeners",[]);u(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=fn(e.deltaX,e.deltaMode,this.ctx.state.viewport.scale),i=fn(e.deltaY,e.deltaMode,this.ctx.state.viewport.scale);if(e.ctrlKey||e.metaKey){const a=Math.exp(-Go(i)*Ko);ie(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 fn(o,t,e){const s=o*(t===1?qo:t===2?Yo:1),i=e<.5?.8:e>2?1.08:1;return s*i}function Go(o){return Math.max(-mn,Math.min(mn,o))}const he=7,Zo={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 Jo{constructor(){u(this,"name","select");u(this,"cursor","default");u(this,"mode","none");u(this,"startScreen",{x:0,y:0});u(this,"startWorld",{x:0,y:0});u(this,"snapshots",[]);u(this,"activeHandle",null);u(this,"endpointIsStart",!1);u(this,"moved",!1);u(this,"pointerDownHitId",null)}onPointerDown(t,e){const{state:n,hitTester:s,renderer:i}=e;this.startScreen={x:t.clientX,y:t.clientY},this.startWorld=L(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(Zo[d]);return}const h=L(t.clientX,t.clientY,n.viewport),p=i.hitTest(h.x,h.y,n.viewport.scale),m=p?p.id:null;e.setCursor(p?"move":"default"),m!==n.hoveredId&&(n.hoveredId=m,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=L(r.x,r.y,n.viewport),l=L(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(),X(p.id))}n.emitChange()};for(const d of c){const h=n.elementsById.get(d.id);h&&(h.updatedAt=Date.now(),X(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=L(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=L(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 m=n.elementsById.get(d);m&&(m.data.checked=p,m.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 rs(a))if(Math.abs(t.clientX-r.x)<=he&&Math.abs(t.clientY-r.y)<=he)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)<=he+2?!0:Math.hypot(t.clientX-r,t.clientY-c)<=he+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 w of this.snapshots)r=Math.min(r,Math.min(w.x,w.x+w.width)),c=Math.min(c,Math.min(w.y,w.y+w.height)),l=Math.max(l,Math.max(w.x,w.x+w.width)),d=Math.max(d,Math.max(w.y,w.y+w.height));const h=l-r,p=d-c;if(h===0||p===0)return;let m=r,g=c,y=h,b=p;if(a.includes("e")&&(y=h+t),a.includes("w")&&(m=r+t,y=h-t),a.includes("s")&&(b=p+e),a.includes("n")&&(g=c+e,b=p-e),n&&(a==="nw"||a==="ne"||a==="se"||a==="sw")){const w=h/p;if(Math.abs(y/h)>Math.abs(b/p)){const E=y/w;a.includes("n")&&(g=g+(b-E)),b=E}else{const E=b*w;a.includes("w")&&(m=m+(y-E)),y=E}}const x=4;if(Math.abs(y)<x||Math.abs(b)<x)return;const v=y/h,S=b/p;for(const w of this.snapshots){const E=i.elementsById.get(w.id);!E||E.locked||(E.x=m+(w.x-r)*v,E.y=g+(w.y-c)*S,E.width=w.width*v,E.height=w.height*S,E.updatedAt=Date.now(),X(E.id))}}}class Qo{constructor(){u(this,"name","hand");u(this,"cursor","grab");u(this,"panning",!1);u(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 Ce=["#fef08a","#fdba74","#fca5a5","#f9a8d4","#d8b4fe","#a5b4fc","#93c5fd","#86efac"];let cs=Ce[0];function ti(){return cs}function ei(o){cs=o}class ni{constructor(){u(this,"name","sticky");u(this,"cursor","crosshair")}onPointerDown(t,e){const{state:n,commands:s}=e,i=L(t.clientX,t.clientY,n.viewport),a=H("sticky",{x:i.x-110,y:i.y-80,width:220,height:160,zIndex:n.maxZIndex()+1,style:{fill:ti(),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 si{constructor(){u(this,"name","task");u(this,"cursor","crosshair")}onPointerDown(t,e){const{state:n,commands:s}=e,i=L(t.clientX,t.clientY,n.viewport),a=n.theme==="dark",r=H("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 ct{constructor(t){u(this,"name");u(this,"cursor","crosshair");u(this,"shapeType");u(this,"shapeKind");u(this,"drawing",!1);u(this,"startWorld",{x:0,y:0});u(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=L(t.clientX,t.clientY,n.viewport);const s=n.theme==="dark",i=!["rectangle","ellipse","pill","cylinder"].includes(this.shapeKind);this.preview=H(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=L(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 oi{constructor(){u(this,"name","text");u(this,"cursor","text")}onPointerDown(t,e){const{state:n,commands:s}=e,i=L(t.clientX,t.clientY,n.viewport),a=H("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:""}});It(a),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 Gt{constructor(t="arrow"){u(this,"name");u(this,"cursor","crosshair");u(this,"drawing",!1);u(this,"startWorld",{x:0,y:0});u(this,"preview",null);this.name=t}onPointerDown(t,e){const{state:n}=e;this.drawing=!0,this.startWorld=L(t.clientX,t.clientY,n.viewport),this.preview=H("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=L(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 ii{constructor(t){u(this,"name","image");u(this,"cursor","default");u(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 pe="psc:";class ai{constructor(){u(this,"lastSaveMs",0)}async saveBoard(t){const e=performance.now();try{await K.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 K.get("boards",t)}catch(e){console.error("Board load failed",e);return}}async deleteBoard(t){await K.delete("boards",t)}async clearAllBoards(){await K.clearStore("boards")}async getAllBoards(){try{return await K.getAll("boards")}catch{return[]}}setPref(t,e){try{localStorage.setItem(pe+t,e)}catch{}}getPref(t){try{return localStorage.getItem(pe+t)}catch{return null}}removePref(t){try{localStorage.removeItem(pe+t)}catch{}}clearPrefs(){try{const t=[];for(let e=0;e<localStorage.length;e++){const n=localStorage.key(e);n&&n.startsWith(pe)&&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 tt=new ai;function ri(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 ci(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 gn(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 yn(o){return o.replace(/[^a-z0-9-_ ]/gi,"").trim().slice(0,60)||"board"}class li{exportBoardJson(t){gn(`${yn(t.title)}.json`,t)}async exportFullBundle(t){const e=[];for(const s of t.assetIds){const i=await ot.get(s);i&&e.push({id:i.id,mimeType:i.mimeType,width:i.width,height:i.height,name:i.name,base64:await ri(i.blob)})}const n={bundleVersion:1,board:t,assets:e};gn(`${yn(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=we(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 we(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=ci(e.base64,e.mimeType),s=Date.now(),i={id:ae(),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 ot.put(i),{originalId:e.id,asset:i}}catch{return null}}}const Ne=new li,V={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>'},di=[{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"}],ls=[{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:""}],hi=[{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:""}],pi=new Set(ls.map(o=>o.tool));class ui{constructor(t,e){u(this,"element");u(this,"toolButtons",new Map);u(this,"shapeButtons",new Map);u(this,"shapeBtn");u(this,"shapeGroup");u(this,"arrowGroup");u(this,"themeBtn");this.element=document.createElement("div"),this.element.className="toolbar";for(const a of di){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=V[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 ls){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 hi){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",pi.has(t))}setTheme(t){const e=this.themeBtn.querySelector(".tooltip");this.themeBtn.innerHTML=V[t==="dark"?"sun":"moon"],e&&this.themeBtn.appendChild(e)}}class mi{constructor(t,e,n){u(this,"zoomLabel");u(this,"titleInput");u(this,"titleMeasure");u(this,"statusEl");u(this,"statusTextEl");u(this,"statusActionBtn");const s=document.createElement("div");if(s.className="top-left",e.onExit){const m=document.createElement("button");m.className="control-btn back-btn",m.innerHTML=`${V.arrowLeft}<span>ViteBoard</span>`,m.title="Save and back to ViteBoard",m.setAttribute("aria-label","Back to ViteBoard"),m.addEventListener("click",e.onExit),s.appendChild(m)}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",m=>{m.stopPropagation(),m.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 m=this.iconBtn("trash","Delete board");m.classList.add("danger-control"),m.addEventListener("click",e.deleteBoard),l.appendChild(m)}i.appendChild(l),this.statusEl=document.createElement("div"),this.statusEl.className="board-live-status",this.statusEl.hidden=!0,this.statusTextEl=document.createElement("span"),this.statusActionBtn=document.createElement("button"),this.statusActionBtn.className="status-action-btn",this.statusActionBtn.hidden=!0,this.statusEl.append(this.statusTextEl,this.statusActionBtn),i.appendChild(this.statusEl),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=V[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()}setStatus(t,e,n){this.statusEl.hidden=!t,this.statusTextEl.textContent=t,this.statusEl.dataset.state=e,this.statusActionBtn.hidden=!n,this.statusActionBtn.textContent=(n==null?void 0:n.label)??"",this.statusActionBtn.onclick=(n==null?void 0:n.onClick)??null}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 fi{constructor(t,e){u(this,"state");u(this,"commands");u(this,"textareas",[]);u(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(),X(t.id),this.state.requestRender();const s=()=>{const i=e.value;if(t.data.text=i,It(t),t.updatedAt=Date.now(),X(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,It(c),c.updatedAt=Date.now(),X(a),r.emitChange())},()=>{const c=r.elementsById.get(a);c&&(c.data.text=n,It(c),c.updatedAt=Date.now(),X(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,X(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(),X(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(),X(t.id),d!==e&&this.pushTextCommand(t.id,e,d),this.state.emitChange(),this.close()},l=()=>{r||(r=!0,t.data.text=e,X(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=Rt(n.x,n.y,s),a=Rt(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,It(i),i.updatedAt=Date.now(),X(t),s.emitChange())},()=>{const i=s.elementsById.get(t);i&&(i.data.text=e,It(i),i.updatedAt=Date.now(),X(t),s.emitChange())})}position(t,e){const n=this.state.viewport;if(e.type==="arrow"||e.type==="line"||e.type==="connector"){const b=Rt(e.x,e.y,n),x=Rt(e.x+e.width,e.y+e.height,n),v=13*n.scale,S=Math.max(100,Math.min(240,Math.hypot(x.x-b.x,x.y-b.y)-16)),w=Math.max(24,v*1.35+4);t.style.left=(b.x+x.x)/2-S/2+"px",t.style.top=(b.y+x.y)/2-w/2+"px",t.style.width=S+"px",t.style.height=w+"px",t.style.fontSize=v+"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=Rt(e.x,e.y,n),i=e.data.shapeKind==="chevron",a=Te(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),m=l?Math.min(Math.max(24,d),p):Math.max(24,d),g=l?Math.max(0,(e.height*n.scale-m)/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=m+"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,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 lt=null,ze=null;function C(o){lt||(lt=document.createElement("div"),lt.className="toast",document.body.appendChild(lt)),lt.textContent=o,lt.classList.add("visible"),ze!==null&&clearTimeout(ze),ze=window.setTimeout(()=>{lt==null||lt.classList.remove("visible")},2600)}function gt(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 Yt=0;function yt(o){Yt=o}function N(o,t,e,n,s,i=""){return H("rectangle",{x:o,y:t,width:e,height:n,zIndex:++Yt,style:{borderRadius:10,...s},data:{text:i}})}function I(o,t,e,n,s,i,a="600"){return H("text",{x:o,y:t,width:e,height:s*1.6,zIndex:++Yt,style:{fontSize:s,textColor:i,fontWeight:a},data:{text:n}})}function W(o,t,e,n,s=180,i=120){return H("sticky",{x:o,y:t,width:s,height:i,zIndex:++Yt,style:{fill:n,borderRadius:12,shadow:!0,fontSize:13,textColor:"#1f2933"},data:{text:e}})}function z(o,t,e,n,s,i={}){return H("arrow",{x:o,y:t,width:e-o,height:n-t,zIndex:++Yt,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 gi(o,t,e,n,s,i=""){return H("ellipse",{x:o,y:t,width:e,height:n,zIndex:++Yt,style:s,data:{text:i}})}function yi(o,t,e,n){const s=gt(e);yt(n);const i=[];return i.push(N(o,t,760,560,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(I(o+28,t+22,400,"User Persona",22,s.heading,"700")),i.push(I(o+28,t+60,300,"Name",13,s.accent)),i.push(W(o+28,t+86,"Jordan Lee",s.sticky,200,64)),i.push(I(o+260,t+60,300,"Role",13,s.accent)),i.push(W(o+260,t+86,"Senior Product Manager","#a5b4fc",220,64)),i.push(I(o+510,t+60,300,"Buying trigger",13,s.accent)),i.push(W(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),m=o+28+h*242,g=t+188+p*178;i.push(I(m,g,230,r,13,s.accent)),i.push(W(m,g+26,c,l,220,124))}),i}const He=["Awareness","Discovery","Evaluation","Onboarding","Activation","Retention"],bi=["#93c5fd","#a5b4fc","#d8b4fe","#f9a8d4","#fdba74","#86efac"];function vi(o,t,e,n){const s=gt(e);yt(n);const i=[],a=230,r=He.length*a+56;return i.push(N(o,t,r,640,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(I(o+28,t+22,500,"User Journey Map",22,s.heading,"700")),He.forEach((c,l)=>{const d=o+28+l*a,h=t+70;i.push(N(d,h,a-16,48,{fill:bi[l],borderRadius:10},c)),l<He.length-1&&i.push(z(d+a-14,h+24,d+a-2,h+24,s.heading)),i.push(N(d,h+64,a-16,150,{fill:s.zone,borderRadius:10},"")),i.push(I(d+10,h+70,a-36,"Actions",12,s.accent)),i.push(W(d+14,h+96,"","#fef08a",a-44,100)),i.push(N(d,h+226,a-16,150,{fill:s.zone,borderRadius:10},"")),i.push(I(d+10,h+232,a-36,"Pain points",12,s.accent)),i.push(W(d+14,h+258,"","#fca5a5",a-44,100)),i.push(N(d,h+388,a-16,150,{fill:s.zone,borderRadius:10},"")),i.push(I(d+10,h+394,a-36,"Opportunities",12,s.accent)),i.push(W(d+14,h+420,"","#86efac",a-44,100))}),i}function wi(o,t,e,n){const s=gt(e);yt(n);const i=[],a=680;i.push(N(o,t,a+120,a+130,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(I(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(N(r,c,l,l,{fill:"#86efac55",borderRadius:8})),i.push(N(r+l,c,l,l,{fill:"#93c5fd55",borderRadius:8})),i.push(N(r,c+l,l,l,{fill:"#fef08a55",borderRadius:8})),i.push(N(r+l,c+l,l,l,{fill:"#fca5a555",borderRadius:8})),i.push(I(r+16,c+12,300,"Quick wins",16,s.heading,"700")),i.push(I(r+l+16,c+12,300,"Strategic bets",16,s.heading,"700")),i.push(I(r+16,c+l+12,300,"Fill-ins",16,s.heading,"700")),i.push(I(r+l+16,c+l+12,300,"Avoid",16,s.heading,"700")),i.push(z(r-24,c+a,r-24,c,s.heading)),i.push(I(r-64,c+l-12,60,"Impact",14,s.text,"600")),i.push(z(r,c+a+24,r+a,c+a+24,s.heading)),i.push(I(r+l-30,c+a+34,80,"Effort",14,s.text,"600")),i.push(W(r+40,c+60,"Feature idea","#fef08a",150,90)),i.push(W(r+l+40,c+60,"Big bet","#a5b4fc",150,90)),i}const bn=[["Problem","#fca5a5"],["User","#93c5fd"],["Context","#d8b4fe"],["Current workflow","#fdba74"],["Proposed solution","#86efac"],["Edge cases","#f9a8d4"],["Acceptance criteria","#a5b4fc"],["Dependencies","#fef08a"],["Risks","#fca5a5"]];function xi(o,t,e,n){const s=gt(e);yt(n);const i=[],a=3,r=280,c=210,l=a*r+56,h=Math.ceil(bn.length/a)*c+100;return i.push(N(o,t,l,h,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(I(o+28,t+22,500,"Product Requirements Flow",22,s.heading,"700")),bn.forEach(([p,m],g)=>{const y=g%a,b=Math.floor(g/a),x=o+28+y*r,v=t+72+b*c;i.push(I(x,v,r-30,`${g+1}. ${p}`,14,s.accent)),i.push(W(x,v+30,"",m,r-28,c-60))}),i}function Ci(o,t,e,n){const s=gt(e);yt(n);const i=[];i.push(I(o,t-40,400,"System Diagram",22,s.heading,"700"));const a=(r,c,l,d,h,p)=>N(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(gi(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(z(o+115,t+185,o+195,t+185,s.heading,{label:"uses"})),i.push(z(o+385,t+185,o+465,t+185,s.heading,{label:"request | response",sides:!0,arrowStart:!0})),i.push(z(o+655,t+165,o+735,t+110,s.heading,{label:"read"})),i.push(z(o+655,t+205,o+735,t+240,s.heading,{label:"webhook",dashed:!0})),i.push(z(o+560,t+235,o+560,t+325,s.heading,{label:"event",dashed:!0})),i.push(z(o+470,t+375,o+80,t+245,s.heading,{label:"notify",dashed:!0})),i}function ki(o,t,e,n){const s=gt(e);yt(n);const i=[];i.push(I(o+280,t-40,500,"Opportunity Solution Tree",22,s.heading,"700")),i.push(N(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(W(d,a,"Opportunity","#93c5fd",220,100)),i.push(z(o+440,t+85,d+110,a-5,s.heading));const c=a+180;for(const d of r)i.push(W(d,c,"Solution","#86efac",220,100)),i.push(z(d+110,a+105,d+110,c-5,s.heading));const l=c+180;for(const d of r)i.push(W(d,l,"Experiment","#fdba74",220,90)),i.push(z(d+110,c+105,d+110,l-5,s.heading));return i.push(I(o,l+120,400,"Signals / metrics",14,s.accent)),i.push(W(o,l+150,"What signal tells us this is working?","#fef08a",380,100)),i}function Ei(o,t,e,n){const s=gt(e);yt(n);const i=[];i.push(N(o,t,1060,620,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),i.push(I(o+28,t+22,500,"Screenshot Review",22,s.heading,"700")),i.push(I(o+28,t+64,300,"Screenshot",13,s.accent));const a=H("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),m=o+540+h*250,g=t+64+p*200;i.push(I(m,g,230,c,13,s.accent)),i.push(W(m,g+28,"",l,230,140))}),i.push(I(o+28,t+470,300,"Follow-up tasks",13,s.accent)),i.push(W(o+28,t+498,"","#fef08a",480,96)),i.push(I(o+540,t+470,300,"Decision",13,s.accent)),i.push(W(o+540,t+498,"","#fdba74",480,96)),i}function Si(o,t,e,n){const s=gt(e);yt(n);const i=[];i.push(I(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(N(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(z(o+180,t+178,o+280,t+178,s.accent,{label:"approve"})),i.push(z(o+460,t+178,o+560,t+178,s.accent,{label:"ship"})),i.push(z(o+650,t+226,o+370,t+310,"#9ca3af",{label:"feedback",dashed:!0})),i.push(N(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 Ti(o,t,e,n){const s=gt(e);yt(n);const i=[];return i.push(I(o,t,800,"Handoff map",26,s.heading,"700")),[["Explore","#dbeafe"],["Decide","#fef3c7"],["Act","#dcfce7"]].forEach(([r,c],l)=>{i.push(N(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(z(o+170,t+196,o+270,t+196,s.accent,{label:"proposal"})),i.push(z(o+440,t+196,o+540,t+196,s.accent,{label:"owner | outcome",sides:!0,arrowStart:!0})),i.push(z(o+625,t+245,o+355,t+330,"#9ca3af",{label:"feedback",dashed:!0})),i.push(N(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 Mi=[{id:"persona",name:"User Persona Card",description:"Name, role, goals, pain points, JTBD, success criteria.",build:yi},{id:"journey",name:"User Journey Map",description:"Awareness → Retention stages with sticky note areas.",build:vi},{id:"matrix",name:"Prioritization Matrix",description:"Impact vs effort: quick wins, strategic bets, fill-ins, avoid.",build:wi},{id:"requirements",name:"Requirements Flow",description:"Problem, user, context, solution, edge cases, risks.",build:xi},{id:"system",name:"System Diagram Starter",description:"User, frontend, API, database, external services + arrows.",build:Ci},{id:"ost",name:"Opportunity Solution Tree",description:"Outcome, opportunities, solutions, experiments, signals.",build:ki},{id:"screenshot-review",name:"Screenshot Review Board",description:"Screenshot zone with observations, problems, UX notes.",build:Ei},{id:"workflow",name:"Workflow Map",description:"Labeled handoffs, a dashed feedback loop, and editable steps.",build:Si},{id:"handoff",name:"Handoff Map",description:"A shared decision flow with ownership, outcomes, and feedback.",build:Ti}];function Bi(o,t){_("Insert a template",(e,n)=>{const s=document.createElement("div");s.className="template-grid";for(const i of Mi){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",()=>{Ii(o,t,i.build),n()}),s.appendChild(a)}e.appendChild(s)})}function Ii(o,t,e){const n=L(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 ue(o){return o<1024?o+" B":o<1024*1024?(o/1024).toFixed(1)+" KB":(o/(1024*1024)).toFixed(1)+" MB"}function Ri(o,t,e,n){_(n?"Storage":"Local storage",async(s,i)=>{const a=document.createElement("div");s.appendChild(a);const r=(g,y)=>{const b=document.createElement("div");b.className="storage-row";const x=document.createElement("span");x.textContent=g;const v=document.createElement("span");v.textContent=y,b.appendChild(x),b.appendChild(v),a.appendChild(b)};r("Elements on board",String(o.elements.length));const c=JSON.stringify(o.elements);if(r("Board data size",ue(c.length)),n)r("Workspace assets","Stored on disk under docs/assets");else{const g=await ot.getAllKeys();r("Image assets",String(g.length));const y=await ot.totalSizeBytes();r("Image asset size",ue(y))}const l=await tt.estimateStorage();!n&&l.quota>0&&r("Browser storage",`${ue(l.usage)} of ${ue(l.quota)}`);const d=document.createElement("div");d.className="modal-actions";const h=document.createElement("button");h.className="btn",h.textContent=n?"Clean unused managed assets":"Clear unused assets",h.addEventListener("click",async()=>{if(n){const x=o.elements.map(v=>typeof v.data.src=="string"?v.data.src:"").filter(Boolean);try{const v=await n(x);C(`Removed ${v} unused managed asset${v===1?"":"s"}`),i()}catch{C("Could not clean workspace assets")}return}const g=new Set,y=await tt.getAllBoards();for(const x of y)for(const v of x.elements){const S=v.data.assetId;typeof S=="string"&&g.add(S)}const b=await ot.clearUnused(g);C(`Removed ${b} unused asset${b===1?"":"s"}`),i()}),d.appendChild(h);const p=document.createElement("button");p.className="btn danger",p.textContent="Clear board",p.addEventListener("click",()=>{confirm("Remove all elements from this board?")&&(t(),i())}),d.appendChild(p);const m=document.createElement("button");m.className="btn danger",m.textContent=n?"Reset local-only data":"Reset all local data",m.addEventListener("click",()=>{confirm("Delete ALL local boards, assets and preferences? This cannot be undone.")&&(e(),i())}),d.appendChild(m),s.appendChild(d)})}class Li{constructor(t,e,n,s,i,a){u(this,"element");u(this,"visible",!1);u(this,"state");u(this,"renderer");u(this,"hitTester");u(this,"monitor");u(this,"imageCache");u(this,"timer",null);u(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 ot.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: ${tt.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(`
13
+ `)}}const me=["#93c5fd","#a5b4fc","#86efac","#fdba74","#fca5a5","#d8b4fe","#f9a8d4","#fef08a","#ffffff","#e5e7eb"],vn=["Onboarding","Checkout","Retention","Activation","Churn risk","API gateway","User insight","Edge case","Quick win","Tech debt","Experiment","Metric","Persona","Journey","Feature flag"];function Q(o,t){return o+Math.random()*(t-o)}function dt(o){return o[Math.floor(Math.random()*o.length)]}const ht="stress";class $i{constructor(t){u(this,"state");u(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=dt(s),l=Q(-n/2,n/2),d=Q(-n/2,n/2);let h;c==="sticky"?h=H("sticky",{x:l,y:d,width:220,height:160,zIndex:++i,style:{fill:dt(Ce),borderRadius:12,shadow:!0,fontSize:14,textColor:"#1f2933"},data:{text:dt(vn),[ht]:!0}}):c==="rectangle"||c==="ellipse"?h=H(c,{x:l,y:d,width:Q(80,300),height:Q(60,200),zIndex:++i,style:{fill:dt(me),stroke:"#37415188",strokeWidth:1.5,borderRadius:c==="rectangle"?8:0},data:{[ht]:!0}}):c==="text"?h=H("text",{x:l,y:d,width:200,height:28,zIndex:++i,style:{fontSize:16,textColor:this.state.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:dt(vn),[ht]:!0}}):h=H("arrow",{x:l,y:d,width:Q(-250,250),height:Q(-250,250),zIndex:++i,style:{stroke:dt(me),strokeWidth:2,arrowEnd:!0},data:{[ht]:!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=H("image",{x:Q(-e/2,e/2),y:Q(-e/2,e/2),width:320,height:220,zIndex:++n,data:{assetId:"stress-placeholder-"+s,[ht]:!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[ht]&&(e.x=Q(-t/2,t/2),e.y=Q(-t/2,t/2));this.state.emitChange()}randomizeColors(){for(const t of this.state.elements)t.data[ht]&&(t.type==="sticky"?t.style.fill=dt(Ce):t.type==="rectangle"||t.type==="ellipse"?t.style.fill=dt(me):t.type==="arrow"&&(t.style.stroke=dt(me)));this.state.emitChange()}randomizeZIndex(){for(const t of this.state.elements)t.data[ht]&&(t.zIndex=Math.floor(Q(0,this.state.elements.length)));this.state.invalidateSort(),this.state.emitChange()}clearGenerated(){const t=this.state.elements.filter(e=>e.data[ht]);for(const e of t)this.state.removeElement(e.id);this.state.emitChange()}}class Pi{constructor(t,e,n){u(this,"element");u(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),C(`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),C("Generated 100 image placeholders")}),s("Mixed PM board",()=>{e.generateMixedPmBoard(),C("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,C(`Viewport culling ${n.cullingEnabled?"enabled":"disabled"}`),n.state.requestRender()}),s("Toggle LOD",()=>{n.lodEnabled=!n.lodEnabled,C(`Simplified rendering ${n.lodEnabled?"enabled":"disabled"}`),n.state.requestRender()}),s("Clear generated",()=>{e.clearGenerated(),C("Cleared generated elements")},!0),t.appendChild(this.element)}toggle(){this.visible=!this.visible,this.element.classList.toggle("visible",this.visible)}}const Di=300,Ai=1e3,wn=[{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"}],Ni=new Set(["text"]),zi=new Set(["rectangle","ellipse","frame"]),Hi=["#0078d4","#4dabf7","#6e6e6e","#ffffff","#0f0f0f","#fef08a","#93c5fd","#fca5a5"],Fi=[{label:"Black text",value:"#1f2933"},{label:"White text",value:"#ffffff"}];class ji{constructor(t,e={}){u(this,"state",new Mo);u(this,"commands",new Io);u(this,"surface");u(this,"renderer");u(this,"scheduler");u(this,"hitTester");u(this,"imageCache");u(this,"monitor",new Xo);u(this,"actions");u(this,"imageInsert");u(this,"toolController");u(this,"textEditor");u(this,"toolbar");u(this,"topControls");u(this,"perfOverlay");u(this,"stressPanel");u(this,"boardSaveTimer",null);u(this,"viewportSaveTimer",null);u(this,"saveInFlight",null);u(this,"saveQueued",!1);u(this,"suppressPersistence",!1);u(this,"options");u(this,"listenerAbort",new AbortController);u(this,"root");u(this,"revision",null);u(this,"stale",!1);u(this,"bottomToolCluster",null);u(this,"stickyColorPopover",null);u(this,"textSizePopover",null);u(this,"shapeStylePopover",null);u(this,"layerMenu",null);this.root=t,this.options=e,e.boardId&&(this.state.boardId=e.boardId);const n=this.listenerAbort.signal;this.surface=new jo(t,3,n),this.imageCache=new es(ot,()=>this.state.requestRender(),e.resolveAssetUrl),this.renderer=new Wo(this.surface,this.state,this.imageCache),this.scheduler=new Oo(()=>this.renderer.render()),this.hitTester=new _o(this.state),this.actions=new Ro(this.state,this.commands),this.textEditor=new fi(this.state,this.commands),this.imageInsert=new Po(this.state,this.commands,this.imageCache,C,e.uploadImage),this.state.onRenderNeeded(()=>{var s;this.scheduler.requestRender(),(s=this.topControls)==null||s.setZoom(this.state.viewport.scale),this.suppressPersistence||this.scheduleViewportSave(),this.updateContextualToolPanels()}),this.state.onChange(()=>{this.suppressPersistence||this.scheduleBoardSave()}),this.surface.onResize(()=>this.state.requestRender()),this.setupTools(t,n),this.setupUi(t),this.setupSelectionOverlays(t,n),this.setupDragDrop(t),new Ao(this.state,this.actions,this.imageInsert,n),No({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 Vo(this.surface.container,n,[new Jo,new Qo,new ni,new si,new ct("rectangle"),new ct("ellipse"),new ct("diamond"),new ct("triangle"),new ct("pill"),new ct("chevron"),new ct("parallelogram"),new ct("hexagon"),new ct("cylinder"),new oi,new Gt,new Gt("dashedArrow"),new Gt("twoWayArrow"),new Gt("labeledArrow"),new Gt("sidedLabelArrow"),new ii((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 ui(t,{setTool:n=>this.toolController.setTool(n),openTemplates:()=>Bi(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 mi(t,{onExit:this.options.onExit?()=>this.exitToDocs():void 0,resetView:()=>this.resetView(),zoomIn:()=>{ie(this.state.viewport,window.innerWidth/2,window.innerHeight/2,this.state.viewport.scale*1.2),this.state.requestRender()},zoomOut:()=>{ie(this.state.viewport,window.innerWidth/2,window.innerHeight/2,this.state.viewport.scale/1.2),this.state.requestRender()},openStorageManager:()=>Ri(this.state,()=>this.clearBoard(),()=>void this.resetAllLocalData(),this.options.cleanupUnusedAssets),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 Li(t,this.state,this.renderer,this.hitTester,this.monitor,this.imageCache);const e=new $i(this.state);this.stressPanel=new Pi(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 Ce){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 wn){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 Hi){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 Fi){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){ei(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=wn.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=>Ni.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,X(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=>zi.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,X(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=L(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().then(t=>{var e,n;t&&((n=(e=this.options).onExit)==null||n.call(e))})}startEmbedSelection(){Ge.begin(this.root,t=>{t&&this.copyEmbedSnippet(t)})}async copyEmbedSnippet(t){const e=this.state.viewport,n=L(t.x,t.y,e),s=L(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
14
+ src: /${this.state.boardId}
15
+ region: ${i}, ${a}, ${r}, ${c}
16
+ height: 360
17
+ title: ${this.state.title}
18
+ \`\`\``;try{await navigator.clipboard.writeText(l),C("Embed snippet copied — paste it into any doc")}catch{C("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(){this.suppressPersistence=!0;const t=tt.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.revision=n.revision,this.stale=!1,this.applyDocument(n.doc),this.fitInitialRegion())}catch(n){console.error("Board file load failed",n),C("Could not load board file")}finally{this.suppressPersistence=!1}this.state.requestRender();return}const e=tt.getPref("lastBoardId")??"default-board";try{const n=await tt.loadBoard(e);n&&this.applyDocument(n)}catch(n){console.error("Board recovery failed",n),tt.getPref("recovery")&&C("Could not load saved board — starting fresh")}this.suppressPersistence=!1,this.state.requestRender()}applyDocument(t){this.state.schemaUrl=t.$schema,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)),m=os(Math.min(h*.58,p));this.state.viewport={scale:m,offsetX:a+(l-s*m)/2-e*m,offsetY:r+(d-i*m)/2-n*m},this.topControls.setZoom(m)}scheduleBoardSave(){this.boardSaveTimer!==null&&clearTimeout(this.boardSaveTimer),this.boardSaveTimer=window.setTimeout(()=>{this.boardSaveTimer=null,this.saveBoard()},Di)}scheduleViewportSave(){this.viewportSaveTimer===null&&(this.viewportSaveTimer=window.setTimeout(()=>{this.viewportSaveTimer=null,this.saveBoard()},Ai))}async saveBoard(){if(this.saveInFlight)return this.saveQueued=!0,this.saveInFlight;const t=async()=>{if(this.stale)return C("Board changed elsewhere — reload before saving"),this.setBoardStatus("Changed elsewhere","stale"),!1;try{return this.options.saveBoard?(this.revision=await this.options.saveBoard(ce(this.state)),this.stale=!1,this.setBoardStatus("Saved","saved")):await tt.saveBoard(ce(this.state)),!0}catch(n){return n instanceof se?(this.revision=n.currentRevision,this.stale=!0,this.setBoardStatus("Changed elsewhere","stale"),C("Board changed elsewhere — reload before saving"),!1):(C(this.options.saveBoard?"Save to file failed":"Save failed — browser storage may be full"),this.options.saveBoard&&this.setBoardStatus("Save failed","error"),!1)}};this.saveInFlight=t();const e=await this.saveInFlight;return this.saveInFlight=null,this.saveQueued&&!this.stale?(this.saveQueued=!1,this.saveBoard()):(this.saveQueued=!1,e)}markStale(){this.stale=!0,this.setBoardStatus("Changed elsewhere","stale")}async reloadLatest(){if(this.options.loadBoard&&window.confirm("Discard local edits and reload the latest board version?"))try{this.suppressPersistence=!0;const t=await this.options.loadBoard(this.options.boardId??this.state.boardId);if(!t){C("Could not reload board file"),this.suppressPersistence=!1;return}this.revision=t.revision,this.stale=!1,this.applyDocument(t.doc),this.state.requestRender(),this.setBoardStatus("Reloaded latest","saved")}catch{this.setBoardStatus("Reload failed","error"),C("Could not reload board file")}finally{this.suppressPersistence=!1}}setBoardStatus(t,e){var n;(n=this.topControls)==null||n.setStatus(t,e,e==="stale"&&this.options.loadBoard?{label:"Reload latest",onClick:()=>void this.reloadLatest()}:void 0)}applyTheme(t){var e;this.state.theme=t,document.documentElement.setAttribute("data-theme",t),tt.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=ss,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()}),C("Board cleared")}async resetAllLocalData(){await tt.clearAllBoards(),await ot.clearAll(),tt.clearPrefs(),this.imageCache.clear(),this.commands.clear(),this.state.elements=[],this.state.elementsById.clear(),this.state.clearSelection(),this.state.invalidateSort(),this.resetView(),C("All local data cleared")}confirmDeleteBoard(){_("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(),C("Board deleted"),(l=this.options.onDeleted??this.options.onExit)==null||l()}catch{a.disabled=!1,C("Could not delete board")}}),s.append(i,a),t.append(n,s)})}openExportMenu(){_("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 Ho(this.state,this.imageCache,this.surface.width,this.surface.height);un(i,this.state.title+"-view.png")},!0),s("Export full board as PNG",async()=>{const i=await Fo(this.state,this.imageCache);i?un(i,this.state.title+"-board.png"):C("Board is empty")}),s("Export board JSON (no images)",()=>{Ne.exportBoardJson(ce(this.state))}),s("Export full bundle (JSON + images)",async()=>{await Ne.exportFullBundle(ce(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 Ne.importFromFile(e);if(!n){C("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(),C("Board imported")},t.click()}}const xn="/__api/asset?path=",ds=new Set(["P","DIV","UL","OL","H1","H2","H3","H4","H5","H6","BLOCKQUOTE","PRE","TABLE","FIGURE","HR"]);function Wi(o){const t=[];for(const e of Array.from(o.childNodes))Ze(t,e);return t.map(e=>e.replace(/[ \t]+$/gm,"")).join(`
19
+
20
+ `).replace(/\n{3,}/g,`
21
+
22
+ `).trim()+`
23
+ `}function Ze(o,t){const e=Oi(t);e!==null&&e.trim()!==""&&o.push(e)}function Oi(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]))+" "+ft(t).trim();case"HR":return"---";case"P":return t.classList.contains("embed-caret-spacer")&&!_i(t)?null:kn(t)?En(t):qe(ft(t).trim());case"BLOCKQUOTE":return Cn(t).split(`
24
+ `).map(s=>s?`> ${s}`:">").join(`
25
+ `);case"UL":return ke(t,!1,0);case"OL":return ke(t,!0,0);case"PRE":{const n=t.querySelector("code"),s=Ki(n??t),i=(n??t).textContent??"";return"```"+s+`
26
+ `+i.replace(/\n$/,"")+"\n```"}case"TABLE":return Xi(t);case"FIGURE":return t.classList.contains("board-embed")?qi(t):Cn(t)||null;case"DIV":return kn(t)?En(t):qe(ft(t).trim());case"BR":return null;default:return ft(t).trim()||null}}function Cn(o){const t=[];for(const e of Array.from(o.childNodes))Ze(t,e);return t.join(`
27
+
28
+ `)}function kn(o){for(const t of Array.from(o.children))if(ds.has(t.tagName))return!0;return!1}function En(o){const t=[];let e="";const n=()=>{const s=qe(e.trim());s&&t.push(s),e=""};for(const s of Array.from(o.childNodes)){if(Ui(s)){n(),Ze(t,s);continue}e+=Je(s)}return n(),t.join(`
29
+
30
+ `)||null}function Ui(o){return o.nodeType===Node.ELEMENT_NODE&&ds.has(o.tagName)}function _i(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 ke(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(ke(p,!1,e+1));continue}if(p.tagName==="OL"){l.push(ke(p,!0,e+1));continue}if(p.tagName==="INPUT"){d=p.checked?"[x] ":"[ ] ";continue}}c+=Je(h)}n.push(s+r+(d??"")+c.trim());for(const h of l)h&&n.push(h)}return n.join(`
31
+ `)}function Xi(o){const t=Array.from(o.querySelectorAll("tr"));if(t.length===0)return"";const e=i=>Array.from(i.querySelectorAll("th,td")).map(a=>ft(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(`
32
+ `)}function qi(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(`
33
+ `)}function ft(o){let t="";for(const e of Array.from(o.childNodes))t+=Je(e);return t}function Je(o){if(o.nodeType===Node.TEXT_NODE)return Tn(o.textContent??"");if(o.nodeType!==Node.ELEMENT_NODE)return"";const t=o;switch(t.tagName){case"STRONG":case"B":return Sn("**",ft(t));case"EM":case"I":return Sn("*",ft(t));case"CODE":return Vi(t.textContent??"");case"A":{const e=(t.getAttribute("data-md-href")??t.getAttribute("href")??"").trim(),n=ft(t).trim()||Tn(e);return e?`[${Mn(n)}](${Bn(e)})`:n}case"IMG":return`![${Mn(t.alt)}](${Bn(Yi(t))})`;case"BR":return`
34
+ `;default:return ft(t)}}function Yi(o){const t=o.getAttribute("data-md-src");if(t)return t;const e=o.getAttribute("src")??"";return e.startsWith(xn)?decodeURIComponent(e.slice(xn.length)):e}function Ki(o){const e=(o.getAttribute("class")??"").match(/language-(\w+)/);return e?e[1]:""}function Sn(o,t){const e=t.trim();return e?`${o}${e}${o}`:""}function Vi(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 Tn(o){return o.replace(/\\/g,"\\\\").replace(/\[/g,"\\[").replace(/\]/g,"\\]").replace(/\*/g,"\\*").replace(/_/g,"\\_").replace(/`/g,"\\`")}function qe(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 Mn(o){return o.replace(/\\/g,"\\\\").replace(/\]/g,"\\]")}function Bn(o){return o.trim().replace(/\s/g,"%20").replace(/\)/g,"%29").replace(/</g,"%3C").replace(/>/g,"%3E")}class Qe{constructor(t){u(this,"opts");u(this,"overlay");u(this,"scrollEl");u(this,"surface");u(this,"statusEl");u(this,"statusTextEl");u(this,"reloadBtn");u(this,"fileInput");u(this,"toolbarButtons",[]);u(this,"abort",new AbortController);u(this,"frontmatter","");u(this,"revision",null);u(this,"stale",!1);u(this,"saveTimer",null);u(this,"closed",!1);u(this,"history",[]);u(this,"historyIndex",-1);u(this,"applyingHistory",!1);this.opts=t,this.build(),this.load()}static open(t){return new Qe(t)}build(){this.overlay=pt("doc-editor");const t=pt("doc-editor-bar"),e=pt("doc-editor-bar-left"),n=Fe("doc-editor-done","Done");n.addEventListener("click",()=>void this.close());const s=pt("doc-editor-path");s.textContent=this.opts.path,e.append(n,s),this.statusEl=pt("doc-editor-status"),this.statusTextEl=document.createElement("span"),this.reloadBtn=Fe("status-action-btn","Reload latest"),this.reloadBtn.hidden=!0,this.reloadBtn.addEventListener("click",()=>void this.reloadLatest()),this.statusEl.append(this.statusTextEl,this.reloadBtn),this.setStatus("idle"),t.append(e,this.statusEl);const i=this.buildToolbar();this.scrollEl=pt("doc-editor-scroll"),this.surface=pt("markdown-body doc-editor-surface"),this.surface.contentEditable="true",this.surface.spellcheck=!0,this.scrollEl.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 c;const r=(c=this.fileInput.files)==null?void 0:c[0];r&&this.insertImageFile(r),this.fileInput.value=""}),this.overlay.append(t,i,this.scrollEl,this.fileInput),document.body.appendChild(this.overlay);const a=this.abort.signal;this.surface.addEventListener("input",()=>this.handleInput(),{signal:a}),this.surface.addEventListener("keyup",()=>this.updateToolbarState(),{signal:a}),this.surface.addEventListener("mouseup",()=>this.updateToolbarState(),{signal:a}),this.surface.addEventListener("click",r=>this.handleSurfaceClick(r),{signal:a}),document.addEventListener("selectionchange",()=>this.updateToolbarState(),{signal:a}),this.surface.addEventListener("paste",r=>this.onPaste(r),{signal:a}),this.surface.addEventListener("dragover",r=>r.preventDefault(),{signal:a}),this.surface.addEventListener("drop",r=>this.onDrop(r),{signal:a}),window.addEventListener("keydown",r=>{if(r.key==="Escape"&&document.activeElement!==this.surface&&this.close(),(r.metaKey||r.ctrlKey)&&r.key.toLowerCase()==="s"&&(r.preventDefault(),this.save()),(r.metaKey||r.ctrlKey)&&r.key.toLowerCase()==="z"){r.preventDefault(),r.shiftKey?this.redoHistory():this.undoHistory();return}if(r.ctrlKey&&!r.metaKey&&r.key.toLowerCase()==="y"){r.preventDefault(),this.redoHistory();return}this.handleEmbedDeleteKey(r)},{signal:a})}buildToolbar(){const t=pt("doc-editor-toolbar"),e=s=>{const i=pt("doc-editor-tb-group");return i.append(...s),i},n=(s,i,a,r=!1)=>{const c=Fe("doc-editor-tb-btn",r?"":s);return r&&(c.innerHTML=V[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")),ut(n("H1","Heading 1",()=>this.formatBlock("H1")),"block","H1"),ut(n("H2","Heading 2",()=>this.formatBlock("H2")),"block","H2"),ut(n("H3","Heading 3",()=>this.formatBlock("H3")),"block","H3")]),e([ut(n("B","Bold (Cmd+B)",()=>document.execCommand("bold")),"command","bold"),ut(n("I","Italic (Cmd+I)",()=>document.execCommand("italic")),"command","italic"),ut(n("</>","Inline code",()=>this.toggleInlineCode()),"inline","CODE")]),e([ut(n("❝","Quote",()=>this.formatBlock("BLOCKQUOTE")),"block","BLOCKQUOTE"),ut(n("•","Bulleted list",()=>document.execCommand("insertUnorderedList")),"command","insertUnorderedList"),ut(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(t=this.opts.initialScrollTop??0,e=this.opts.initialScrollProgress){try{const n=await k.readFileWithRevision(this.opts.rootId,this.opts.path);this.revision=n.revision,this.stale=!1;const s=n.content,{fm:i,body:a}=Zi(s);this.frontmatter=i;const{html:r}=ne(a,{rootId:this.opts.rootId,docPath:this.opts.path});this.surface.innerHTML=r||"<p></p>",this.decorateEmbeds(),document.execCommand("defaultParagraphSeparator",!1,"p"),this.recordHistorySnapshot(!0),this.updateToolbarState(),this.setStatus("idle"),requestAnimationFrame(()=>{if(!this.closed){if(typeof e=="number"){Gi(this.scrollEl,e);return}this.scrollEl.scrollTop=t}})}catch{this.surface.innerHTML="<p></p>",this.setStatus("error","Could not load file");return}}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){Tt(t.previousElementSibling)||t.before(Zt()),Tt(t.nextElementSibling)||t.after(Zt())}normalizeEmbedSpacing(){const t=Array.from(this.surface.querySelectorAll("figure.board-embed"));for(const n of t)In(n.previousElementSibling),In(n.nextElementSibling);let e=!1;for(const n of Array.from(this.surface.children)){if(!Tt(n)){e=!1;continue}if(hs(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(Tt(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=Ji(n,"P");if(!s||!this.surface.contains(s)||!Tt(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(){if(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),this.stale)return this.setStatus("stale","Changed elsewhere — reload before saving"),!1;this.normalizeEmbedSpacing();const t=Wi(this.surface),e=this.frontmatter?`${this.frontmatter}
35
+
36
+ ${t}`:t;try{return this.setStatus("saving"),this.revision=await k.writeFile(this.opts.rootId,this.opts.path,e,this.revision??void 0),this.stale=!1,this.setStatus("saved"),!0}catch(n){return n instanceof se?(this.revision=n.currentRevision,this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving"),!1):(this.setStatus("error","Save failed"),!1)}}async close(){if(this.closed||!await this.save())return;this.closed=!0;const e=this.scrollEl.scrollTop,n=Rn(this.scrollEl);this.abort.abort(),this.overlay.remove(),this.opts.onClose(e,n)}markStale(){this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving")}async reloadLatest(){window.confirm("Discard local edits and reload the latest version?")&&(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),await this.load(this.scrollEl.scrollTop,Rn(this.scrollEl)))}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="${$n(s)}">${sa(s)}</a>`))}toggleInlineCode(){const t=window.getSelection();if(!t||t.rangeCount===0||t.isCollapsed)return;const e=t.getRangeAt(0),n=je(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=!!je(e,a));s.classList.toggle("active",r),s.setAttribute("aria-pressed",r?"true":"false")}}onPaste(t){var s,i;const e=ia(((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=ra(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,Zt()),this.placeCaretInBlock(this.surface.lastElementChild??this.surface);return}const s=Qi(this.surface,n.commonAncestorContainer);if(s&&ta(s)&&!Tt(s)){this.replaceBlockWithInsertedNode(s,n,t);return}n.deleteContents();const i=Zt();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=Ln(t,s.cloneContents()),r=Ln(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??Zt();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 na(t),n=await k.uploadAsset(this.opts.rootId,t.name,e),s=Ye(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="${$n(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",stale:e??"Changed elsewhere",error:e??"Couldn't save"};this.statusTextEl.textContent=n[t],this.statusEl.dataset.state=t,this.reloadBtn.hidden=t!=="stale"}}function pt(o){const t=document.createElement("div");return t.className=o,t}function Fe(o,t){const e=document.createElement("button");return e.className=o,e.textContent=t,e}function ut(o,t,e){return o.dataset.stateType=t,o.dataset.stateValue=e,o.setAttribute("aria-pressed","false"),o}function Zt(){const o=document.createElement("p");return o.className="embed-caret-spacer",o.appendChild(document.createElement("br")),o}function Tt(o){return!!o&&o.tagName==="P"&&o.classList.contains("embed-caret-spacer")}function In(o){Tt(o)&&hs(o)&&o.classList.remove("embed-caret-spacer")}function hs(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 Rn(o){const t=Math.max(1,o.scrollHeight-o.clientHeight);return o.scrollTop/t}function Gi(o,t){const e=Math.max(0,o.scrollHeight-o.clientHeight);o.scrollTop=Math.max(0,Math.min(1,t))*e}function Zi(o){if(!o.startsWith("---"))return{fm:"",body:o};const t=o.indexOf(`
37
+ ---`,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 je(o,t){let e=o;for(;e;){if(e.nodeType===Node.ELEMENT_NODE&&e.tagName===t)return e;e=e.parentNode}return null}function Ji(o,t){let e=o;for(;e;){if(e.nodeType===Node.ELEMENT_NODE&&e.matches(t))return e;e=e.parentNode}return null}function Qi(o,t){let e=t;for(;e&&e.parentNode!==o;)e=e.parentNode;return e instanceof HTMLElement?e:null}function ta(o){return o.tagName==="P"||o.tagName==="DIV"}function Ln(o,t){if(!ea(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 ea(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 na(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 $n(o){return o.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;")}function sa(o){return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}const oa={board:o=>{const t=ts(o);return t.src?{kind:"board",src:t.src,region:t.region,height:t.height,title:t.title}:null}};function ia(o){const t=aa(o);if(!t)return null;const e=oa[t.language];return e?e(t.body):null}function aa(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 ra(o){switch(o.kind){case"board":return ca(o)}}function ca(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}class tn{constructor(t){u(this,"opts");u(this,"root");u(this,"statusEl");u(this,"statusTextEl");u(this,"reloadBtn");u(this,"textarea");u(this,"abort",new AbortController);u(this,"revision",null);u(this,"stale",!1);u(this,"saveTimer",null);u(this,"closed",!1);this.opts=t,this.build(),this.load()}static open(t){return new tn(t)}build(){this.root=zt("doc-editor text-file-editor");const t=zt("doc-editor-bar"),e=zt("doc-editor-bar-left"),n=Pn("doc-editor-done","Done");n.addEventListener("click",()=>void this.close());const s=zt("doc-editor-path");s.textContent=this.opts.path,e.append(n,s),this.statusEl=zt("doc-editor-status"),this.statusTextEl=document.createElement("span"),this.reloadBtn=Pn("status-action-btn","Reload latest"),this.reloadBtn.hidden=!0,this.reloadBtn.addEventListener("click",()=>void this.reloadLatest()),this.statusEl.append(this.statusTextEl,this.reloadBtn),this.setStatus("idle"),t.append(e,this.statusEl);const i=zt("doc-editor-scroll text-file-editor-scroll");this.textarea=document.createElement("textarea"),this.textarea.className="text-file-editor-textarea",this.textarea.spellcheck=!1,i.appendChild(this.textarea),this.root.append(t,i),this.opts.host.appendChild(this.root);const a=this.abort.signal;this.textarea.addEventListener("input",()=>this.scheduleSave(),{signal:a}),window.addEventListener("keydown",r=>{if((r.metaKey||r.ctrlKey)&&r.key.toLowerCase()==="s"){r.preventDefault(),this.save();return}r.key==="Escape"&&document.activeElement!==this.textarea&&this.close()},{signal:a})}async load(){try{const t=await k.readFileWithRevision(this.opts.rootId,this.opts.path);this.revision=t.revision,this.stale=!1,this.textarea.value=t.content,this.setStatus("idle"),requestAnimationFrame(()=>this.textarea.focus())}catch{this.textarea.value="",this.setStatus("error","Could not load file")}}scheduleSave(){this.saveTimer!==null&&clearTimeout(this.saveTimer),this.setStatus("saving"),this.saveTimer=window.setTimeout(()=>{this.saveTimer=null,this.save()},700)}async save(){if(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),this.stale)return this.setStatus("stale","Changed elsewhere — reload before saving"),!1;try{return this.setStatus("saving"),this.revision=await k.writeFile(this.opts.rootId,this.opts.path,this.textarea.value,this.revision??void 0),this.stale=!1,this.setStatus("saved"),!0}catch(t){return t instanceof se?(this.revision=t.currentRevision,this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving"),!1):(this.setStatus("error","Save failed"),!1)}}async close(){return this.closed?!0:await this.save()?(this.closed=!0,this.abort.abort(),this.root.remove(),this.opts.onClose(),!0):!1}destroy(){this.saveTimer!==null&&clearTimeout(this.saveTimer),this.saveTimer=null,this.closed=!0,this.abort.abort(),this.root.remove()}async reloadLatest(){window.confirm("Discard local edits and reload the latest version?")&&(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),await this.load())}setStatus(t,e){const n={idle:e??"Ready",saving:e??"Saving…",saved:e??"Saved",error:e??"Save failed",stale:e??"Changed elsewhere"};this.statusEl.dataset.state=t,this.statusTextEl.textContent=n[t],this.reloadBtn.hidden=t!=="stale"}}function zt(o){const t=document.createElement("div");return t.className=o,t}function Pn(o,t){const e=document.createElement("button");return e.className=o,e.type="button",e.textContent=t,e}const Dn="docs:theme",An="docs:sidebar-collapsed",Nn="docs:sidebar-width",la=220,da=420,We=[{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 ha{constructor(t){u(this,"root");u(this,"layout");u(this,"main");u(this,"topbar");u(this,"contentScroll");u(this,"content");u(this,"sidebar");u(this,"searchBtn");u(this,"cartBtn");u(this,"editBtn");u(this,"themeBtn");u(this,"palette");u(this,"paletteInput");u(this,"paletteResults");u(this,"cartPopover");u(this,"searchIndex",[]);u(this,"capabilityCart",new Map);u(this,"selectedTokens",new Set);u(this,"currentEditableFile");u(this,"workspace",{projects:[]});u(this,"treesByRoot",new Map);u(this,"treesByProject",new Map);u(this,"cleanup");u(this,"updateRenderedTheme");u(this,"editor");u(this,"docEditor");u(this,"textFileEditor");u(this,"editorHost");u(this,"editingId");u(this,"lastNonBoardHash","#/");u(this,"lastNonBoardScrollTop",0);u(this,"pendingScrollRestore");u(this,"sidebarResizeHandle");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=O(n,s)},onEditDoc:(n,s)=>this.openDocEditor({rootId:n,path:s}),onOpenTextFile:(n,s)=>{this.openTextFileEditor({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=Z(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 Ds(this.layout,e),this.sidebarResizeHandle=f("button","sidebar-resize-handle"),this.sidebarResizeHandle.type="button",this.sidebarResizeHandle.innerHTML=V.arrowBoth,this.sidebarResizeHandle.setAttribute("aria-label","Resize sidebar"),this.sidebarResizeHandle.title="Resize sidebar",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.sidebarResizeHandle),this.layout.appendChild(this.main),this.root.appendChild(this.layout),window.addEventListener("hashchange",()=>this.route()),window.addEventListener("keydown",n=>this.handleGlobalKeydown(n)),localStorage.getItem(An)==="true"&&this.setSidebarCollapsed(!0),this.applySidebarWidth(this.readSidebarWidth()),this.setupSidebarResize(),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]),$a(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 m=s.match(/^\/root\/([^/]+)\/directory\/(.+)$/);if(m){const g=decodeURIComponent(m[1]),y=decodeURIComponent(m[2]),b=this.docsRootById(g);if(b)return void this.renderProjectWiki(b.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="Markdown docs, infinite-canvas boards, capabilities, and managed assets all live as normal files on disk. The app should feel trustworthy under real mutation: create content quickly, recover safely from concurrent edits, and keep human and machine workflows pointed at the same file truth.",s.append(i,a);const r=f("div","home-agent-callout"),c=f("p","home-agent-copy");c.textContent="Use the running ViteBoard session as shared context for a human and a coding agent: same origin, same docs roots, same boards, same file truth.";const l=f("button","btn home-agent-btn");l.type="button",l.textContent="Copy agent prompt",l.addEventListener("click",()=>void this.copySetupText(`Connect to ViteBoard at ${window.location.origin} and follow its machine entry at ${window.location.origin}/llms.txt. Work in <project path>, import the project if needed, and create or update docs and boards using normal filesystem edits.`,"Agent prompt copied")),r.append(c,l),s.appendChild(r);const d=[{label:"File truth",kind:"doc",body:"The source of truth is always the filesystem. Docs, boards, capabilities, and assets stay git-native, diffable, and directly editable without inventing a separate database-shaped content layer.",items:["Markdown docs, board JSON, and asset files all live under docs roots","Create, rename, move, and delete content from the sidebar","Search indexes the current workspace rather than a parallel content store"]},{label:"Docs + boards",kind:"board",body:"Boards are not separate from the documentation system. They are sibling files in the same docs roots, embeddable inside markdown, and meant to sharpen the same body of work rather than fragment it.",items:["Open a board from the sidebar, work full-screen, then drop back into docs","Embed a board region into markdown with fenced board blocks",'Use "Copy embed" in the board editor to capture the current region',"Keep visual planning and written explanation in the same repo structure"]},{label:"Collaboration safety",kind:"capability",body:"The product now assumes live mutation is normal. Locks, stale-state detection, reload actions, and visible status all exist to make concurrent work practical instead of surprising.",items:["Docs and boards surface explicit reload actions when stale","Revision-aware saves block silent overwrites","Human and machine actors can cooperate through the same running workspace"]},{label:"Machine workflow",kind:"",body:"ViteBoard is also a machine-readable workspace surface. The app can expose docs roots, boards, schema references, and live coordination routes while the files remain the only persistent truth.",items:["The local HTTP surface advertises machine docs and workspace discovery","Capabilities and selected docs can be assembled into prompts from the UI","The practical goal is faster real work, not another disconnected abstraction layer"]}];for(const v of d){const S=f("div","home-feature"),w=f("div","home-feature-header"),E=f("span",`home-feature-badge home-feature-badge-${v.kind||"neutral"}`);E.textContent=v.label,w.appendChild(E),S.appendChild(w);const B=f("p","home-feature-body");if(B.textContent=v.body,S.appendChild(B),v.items){const M=document.createElement("ul");M.className="home-feature-list";for(const T of v.items){const R=document.createElement("li");R.textContent=T,M.appendChild(R)}S.appendChild(M)}s.appendChild(S)}const h=f("div","home-shortcut-title");h.textContent="Current operating model",s.appendChild(h);const p=[["1. Add repo","Bring a local project into the workspace"],["2. Create docs/ if needed","Start the repo as a writable docs root"],["3. Right-click in the tree","Create docs, boards, directories, and capabilities in place"],["4. Open a board","Think visually, then embed the useful region back into docs"],["5. Cmd K / Ctrl K","Search across the current workspace"],["6. Stale state appears","Use Reload latest instead of guessing which copy is current"],["7. Copy agent prompt","Hand the same workspace context to an AI assistant"],["8. Git stays normal","The files on disk remain the real source of truth"]],m=f("div","home-shortcut-table");for(const[v,S]of p){const w=f("div","home-shortcut-row"),E=f("kbd","home-shortcut-key");E.textContent=v;const B=f("span","home-shortcut-desc");B.textContent=S,w.append(E,B),m.appendChild(w)}s.appendChild(m),n.appendChild(s);const g=f("div","home-panel"),y=f("div","home-panel-head"),b=f("div","home-panel-title");b.textContent="Active workspace";const x=f("button","btn primary home-panel-add");if(x.textContent="+ Add repo",x.addEventListener("click",()=>void this.addRepoDocs()),y.append(b,x),g.appendChild(y),this.workspace.projects.length===0){const v=f("div","home-panel-empty");v.textContent="No projects yet. Add a project root, create docs/ if needed, and start writing against the real filesystem.",g.appendChild(v)}else for(const v of this.workspace.projects){const S=f("div","home-panel-project"),w=f("a","home-panel-project-head");w.href=Mt(v.id);const E=f("span","home-panel-project-name");E.textContent=v.label;const B=v.docsRoots.reduce((q,et)=>{const F=this.treesByRoot.get(et.id)??[];return q+Jt(F).length},0),M=v.docsRoots.reduce((q,et)=>{const F=this.treesByRoot.get(et.id)??[];return q+vt(F).length},0),T=f("span","home-panel-project-meta"),R=[`${v.docsRoots.length} root${v.docsRoots.length===1?"":"s"}`];B&&R.push(`${B} doc${B===1?"":"s"}`),M&&R.push(`${M} board${M===1?"":"s"}`),T.textContent=R.join(" · "),w.append(E,T),S.appendChild(w);const P=6,Kt=v.docsRoots,Ie=Kt.slice(0,P),Pt=f("div","home-panel-roots");for(const q of Ie){const et=this.treesByRoot.get(q.id)??[],F=Ue(Xt(et)),kt=F?O(q.id,F):jt(q.id),nt=f("a","home-panel-root");nt.href=kt;const j=f("span","home-panel-root-path");j.textContent=q.displayPath;const it=Jt(et).length,U=vt(et).length;if(it||U){const at=f("span","home-panel-root-meta"),rt=[];it&&rt.push(String(it)),U&&rt.push(`${U}▦`),at.textContent=rt.join(" · "),nt.append(j,at)}else nt.appendChild(j);Pt.appendChild(nt)}if(Kt.length>P){const q=f("a","home-panel-more");q.href=Mt(v.id),q.textContent=`+ ${Kt.length-P} more roots`,Pt.appendChild(q)}S.appendChild(Pt),g.appendChild(S)}n.appendChild(g),e.appendChild(n),this.content.replaceChildren(e),this.contentScroll.scrollTop=t??0}async copySetupText(t,e){try{await navigator.clipboard.writeText(t),C(e)}catch{C("Could not access clipboard")}}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 m=s.split("/").filter(Boolean);for(let y=0;y<m.length;y++){const b=m.slice(0,y+1).join("/"),x=y===m.length-1;p.push({label:m[y],href:x?void 0:Se(n,b)})}d.appendChild(bt(p));const g=f("h1","wiki-title");g.textContent=m[m.length-1]||i.label,d.appendChild(g)}else if(r&&n){const p=this.docsRootById(n),m=[{label:"Home",href:"#/"}];if(m.push({label:i.label,href:Mt(i.id)}),p){const y=p.displayPath.split("/").filter(Boolean);for(let b=0;b<y.length;b++){const x=y.slice(0,b+1).join("/"),v=b===y.length-1;m.push({label:y[b],href:v?void 0:Se(n,x)})}}d.appendChild(bt(m));const g=f("h1","wiki-title");g.textContent=(p==null?void 0:p.displayPath.split("/").pop())||i.label,d.appendChild(g)}else{d.appendChild(bt([{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((b,x)=>{const v=this.treesByRoot.get(x.id)??[];return b+Jt(v).length},0),m=i.docsRoots.reduce((b,x)=>{const v=this.treesByRoot.get(x.id)??[];return b+vt(v).length},0),g=i.docsRoots.reduce((b,x)=>b+$t(this.treesByRoot.get(x.id)??[]).length,0),y=f("div","wiki-stats");for(const[b,x]of[[String(i.docsRoots.length),"docs roots"],[String(p),"documents"],[String(m),"boards"],[String(g),"capabilities"]]){const v=f("div","wiki-stat"),S=f("div","wiki-stat-val");S.textContent=b;const w=f("div","wiki-stat-label");w.textContent=x,v.append(S,w),y.appendChild(v)}d.appendChild(y)}a.appendChild(d);const h=n?i.docsRoots.filter(p=>p.id===n):i.docsRoots;for(const p of h){const m=this.treesByRoot.get(p.id)??[];let g=m;if(s&&!l){const w=(B,M)=>{for(const T of B){if(T.type==="dir"&&T.path===M)return T;if(T.type==="dir"){const R=w(T.children,M);if(R)return R}}return null},E=w(m,s);g=(E==null?void 0:E.type)==="dir"?E.children:[]}const y=Jt(g),b=vt(g),x=$t(g),v=f("div","wiki-root-section");if(!s||l){const w=f("div","wiki-root-head"),E=f("div","wiki-root-path");E.textContent=p.displayPath,w.appendChild(E),v.appendChild(w)}if(!y.length&&!b.length&&!x.length){const w=f("div","wiki-root-empty");w.textContent="No docs, boards, or capabilities yet. Right-click in the sidebar to add content.",v.appendChild(w),a.appendChild(v);continue}const S=f("div","wiki-root-cols");if(y.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Docs (${y.length})`,w.appendChild(E);const B=f("div","wiki-col-list");for(const M of y){const T=f("a","wiki-col-item wiki-col-item-doc");T.href=O(p.id,M.path),T.textContent=M.name==="index.md"?"Overview":M.name.replace(/\.md$/,"").replace(/[-_]/g," ");const R=f("span","wiki-col-item-path"),P=M.path.includes("/")?M.path.slice(0,M.path.lastIndexOf("/")):"";R.textContent=P,P&&T.appendChild(R),B.appendChild(T)}w.appendChild(B),S.appendChild(w)}if(b.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Boards (${b.length})`,w.appendChild(E);const B=f("div","wiki-col-list");for(const M of b){const T=G(M.path),R=f("a","wiki-col-item wiki-col-item-board");R.href=Z(p.id,T),R.textContent=T.split("/").pop().replace(/[-_]/g," ");const P=f("span","wiki-col-item-path");P.textContent=T.includes("/")?T.slice(0,T.lastIndexOf("/")):p.displayPath,R.appendChild(P),B.appendChild(R)}w.appendChild(B),S.appendChild(w)}if(x.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Capabilities (${x.length})`,w.appendChild(E);const B=f("div","wiki-col-list");for(const M of x){const T=f("a","wiki-col-item wiki-col-item-cap");T.href=Ft(p.id,M.entryPath),T.textContent=Ee(M.entryPath),B.appendChild(T)}w.appendChild(B),S.appendChild(w)}v.appendChild(S),a.appendChild(v)}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=fe(this.workspace,t,{filePath:e});i.appendChild(bt(r));const c=f("div","");i.appendChild(c),this.content.replaceChildren(i);const{destroy:l,setTheme:d}=dn(c,s,{rootId:t,docPath:e});this.cleanup=l,this.updateRenderedTheme=d;const h=await k.getTree(t),p=ge(t,h),m=ye(p,O(t,e));m&&i.appendChild(m),this.contentScroll.scrollTop=n??0}catch{this.renderMessage("Document not found",e)}}openDocEditor(t){const e=this.contentScroll.scrollTop;this.topbar.classList.add("editing-doc"),this.closeCartPopover(),this.docEditor=Qe.open({rootId:t.rootId,path:t.path,initialScrollTop:e,onClose:n=>{this.docEditor=void 0,this.topbar.classList.remove("editing-doc"),this.pendingScrollRestore=n,this.route()}})}async openTextFileEditor(t){this.textFileEditor&&!await this.textFileEditor.close()||(this.closeCartPopover(),this.textFileEditor=tn.open({rootId:t.rootId,path:t.path,host:document.body,onClose:()=>{this.textFileEditor=void 0}}))}async renderCapabilityDoc(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}const s=this.treesByRoot.get(t)??await k.getTree(t),i=pa(s,e)??e,a=Hn(s,e)??Hn(s,i);let r;try{r=await k.readFile(t,i),this.setEditableFile(void 0)}catch{this.renderMessage("Capability not found",e);return}const c=f("div","page"),l=this.docsRootById(t);l&&this.workspace.projects.find(F=>F.id===l.projectId);const d=Ee(i),h=fe(this.workspace,t,{filePath:i,currentLabel:d});c.appendChild(bt(h));const p=f("div","page-bar"),m=f("div","doc-actions capability-doc-actions"),{frontmatter:g}=ne(r),y=f("button","btn");y.classList.add("capability-detail-btn");const b=zn(t,a??ua(i),r,g);this.updateCartButton(y,b.path),y.addEventListener("click",()=>{this.toggleCapabilityCart(b),this.updateCartButton(y,b.path)});const x=f("button","btn primary");x.classList.add("capability-detail-btn"),x.textContent="Copy capability context",x.addEventListener("click",async()=>{await this.copyCapabilityContext(b,s)});const v=f("button","btn");v.classList.add("capability-detail-btn"),v.textContent="Open entry doc",v.addEventListener("click",()=>{location.hash=O(t,i)}),m.append(y,x,v),p.append(m),c.appendChild(p);const S=f("div","card-tags capability-meta-tags"),w=f("span","tag");if(w.textContent=b.displayPath,S.appendChild(w),b.kind){const F=f("span","tag");F.textContent=b.kind,S.appendChild(F)}c.appendChild(S);const E=fa(b.branchPath),B=E?await this.readOptionalFile(t,E):null;if(E&&B){const F=f("section","token-section capability-machine-section"),kt=f("div","page-bar"),nt=f("h2","");nt.textContent="Machine entrypoint";const j=f("div","doc-actions capability-doc-actions"),it=f("button","btn primary");it.textContent="Copy llms.txt",it.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(B),C("Capability machine entrypoint copied")}catch{C("Could not access clipboard")}}),j.appendChild(it),kt.append(nt,j);const U=f("p","page-lead capability-entry-lead");U.textContent="This is the capability-local machine entrypoint. It should be the first file an LLM reads to understand what this capability branch is for, what files matter, and how to use it.";const at=document.createElement("pre");at.className="code-block";const rt=document.createElement("code");rt.textContent=B,at.appendChild(rt),F.append(kt,U,at),c.appendChild(F)}const M=f("div",""),T=f("section","token-section capability-entry-section"),R=f("h2","");R.textContent="Entry document";const P=f("p","page-lead capability-entry-lead");P.textContent="This markdown entry explains the capability branch. The capability itself may also include nested files, scripts, helpers, and other reusable execution material.",T.append(R,P,M),c.appendChild(T),this.content.replaceChildren(c);const{destroy:Kt,setTheme:Ie}=dn(M,r,{rootId:t,docPath:i});this.cleanup=Kt,this.updateRenderedTheme=Ie;const Pt=Fn(s,b.branchPath);if(Pt.length>1){const F=f("section","token-section capability-files-section"),kt=f("h2","");kt.textContent="Files in this capability";const nt=f("div","card-grid capability-files-grid");for(const j of Pt){const it=j.path.endsWith(".md")&&j.path===b.entryPath,U=document.createElement(it?"a":"button");U.className="card",U instanceof HTMLAnchorElement&&(U.href=O(t,j.path)),U instanceof HTMLButtonElement&&(U.type="button",U.addEventListener("click",()=>{this.openTextFileEditor({rootId:t,path:j.path})}));const at=f("div","card-title");at.textContent=j.path===b.entryPath?`${be(j.path)} (entry)`:j.path===E?`${be(j.path)} (machine entrypoint)`:be(j.path);const rt=f("div","card-desc");rt.textContent=qt(j.path),U.append(at,rt),nt.appendChild(U)}F.append(kt,nt),c.appendChild(F)}const q=ge(t,s),et=ye(q,Ft(t,b.branchPath));et&&c.appendChild(et),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=fe(this.workspace,t,{currentLabel:"Capabilities"});n.appendChild(bt(s));const i=f("h1","");i.textContent="Capability library";const a=f("p","page-lead");a.textContent="Browse open-ended capability branches. Inspect their files, understand their entrypoints, and reuse them as working context, automations, or tool-bearing capability units.",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=$t(d);for(const g of h){const y=await k.readFile(t,g.entryPath),{frontmatter:b}=ne(y),x=zn(t,g,y,b),v=document.createElement("article");v.className="card";const S=f("div","card-title"),w=document.createElement("a");w.href=Ft(t,g.branchPath),w.textContent=x.title,S.appendChild(w);const E=f("div","card-desc");E.textContent=x.summary,v.append(S,E);const B=f("div","card-tags"),M=f("span","tag");if(M.textContent=x.displayPath,B.appendChild(M),x.kind){const T=f("span","tag");T.textContent=x.kind,B.appendChild(T)}if(v.appendChild(B),x.tags.length){const T=f("div","card-tags");for(const R of x.tags){const P=f("span","tag");P.textContent=R,T.appendChild(P)}v.appendChild(T)}c.appendChild(v)}h.length===0&&c.appendChild(Ht("No capabilities yet."));const p=ge(t,d),m=ye(p,ps(t));m&&n.appendChild(m)}catch{c.appendChild(Ht("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(We.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 m=f("div","token-grid");for(const g of We.filter(y=>y.group===d)){const y=f("div","token-card");this.selectedTokens.has(g.variable)&&y.classList.add("selected");const b=f("label","token-select-zone"),x=document.createElement("input");x.type="checkbox",x.checked=this.selectedTokens.has(g.variable),x.addEventListener("change",()=>{x.checked?this.selectedTokens.add(g.variable):this.selectedTokens.delete(g.variable),this.renderTokenLibrary(this.contentScroll.scrollTop)});const v=f("span","token-swatch");v.style.background=g.value;const S=f("span","token-copy"),w=f("strong","");w.textContent=g.name;const E=f("code","");E.textContent=g.value;const B=f("small","");B.textContent=g.description,S.append(w,E,B),b.append(x,v,S);const M=f("button","token-copy-btn");M.type="button",M.innerHTML=V.copy,M.title=`Copy ${g.variable}`,M.setAttribute("aria-label",`Copy ${g.variable}`),M.addEventListener("click",T=>{T.stopPropagation(),this.copyToken(g)}),y.append(b,M),m.appendChild(y)}h.append(p,m),e.appendChild(h)}this.content.replaceChildren(e),this.contentScroll.scrollTop=t??0}async copySelectedTokens(){const t=We.filter(n=>this.selectedTokens.has(n.variable));if(t.length===0)return;const e=[":root {",...t.map(n=>` ${n.variable}: ${n.value};`),"}"].join(`
38
+ `);try{await navigator.clipboard.writeText(e),C(`${t.length} token${t.length===1?"":"s"} copied`)}catch{C("Could not access clipboard")}}async copyToken(t){try{await navigator.clipboard.writeText(`${t.variable}: ${t.value};`),C(`${t.variable} copied`)}catch{C("Could not access clipboard")}}renderCapabilityCart(t){const e=t??(()=>{const h=va(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="Capability toolbelt";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="Equip capabilities to build an active toolbelt for the current task.",r.appendChild(h)}else for(const h of this.capabilityCart.values()){const p=f("div","capability-cart-item"),m=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,m.append(g,y);const b=f("button","capability-cart-remove");b.type="button",b.textContent="Remove",b.addEventListener("click",()=>{this.capabilityCart.delete(h.path),this.updateTopbarCart(),e()}),p.append(m,b),r.appendChild(p)}const c=f("div","capability-cart-actions"),l=f("button","btn primary");l.textContent="Copy toolbelt context",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?"Unequip":"Equip",t.classList.toggle("primary",!n),t.classList.toggle("is-selected",n)}async copyCapabilityCartPrompt(){if(this.capabilityCart.size===0)return;const e=`Use this capability toolbelt as implementation guidance for the next coding task. These are integrated capability branches that may contain context, workflows, scripts, helpers, or other reusable execution material.
39
+
40
+ `+(await Promise.all([...this.capabilityCart.values()].map(async(n,s)=>{const i=this.treesByRoot.get(n.rootId)??await k.getTree(n.rootId);return`## ${s+1}. ${n.title}
41
+
42
+ ${await this.capabilityBranchContext(n,i)}`}))).join(`
43
+
44
+ ---
45
+
46
+ `);try{await navigator.clipboard.writeText(e),C(`${this.capabilityCart.size} capabilit${this.capabilityCart.size===1?"y":"ies"} copied`)}catch{C("Could not access clipboard")}}async copyCapabilityContext(t,e){try{const n=e??this.treesByRoot.get(t.rootId)??await k.getTree(t.rootId);await navigator.clipboard.writeText(await this.capabilityBranchContext(t,n)),C("Capability context copied")}catch{C("Could not access clipboard")}}async capabilityBranchContext(t,e){const n=Fn(e,t.branchPath).filter(i=>ga(i.path)),s=await Promise.all(n.map(async i=>{const a=await k.readFile(t.rootId,i.path);return`### ${be(i.path)}
47
+
48
+ ${a.trim()}`}));return[`Capability: ${t.title}`,`Branch: ${t.displayPath}`,...t.kind?[`Kind: ${t.kind}`]:[],"",...s].join(`
49
+ `)}async readOptionalFile(t,e){try{return await k.readFile(t,e)}catch{return null}}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=fe(this.workspace,t,{currentLabel:"Boards"});n.appendChild(bt(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 J.list(t);for(const g of d){const y=document.createElement("a");y.className="card",y.href=Z(t,g.id);const b=f("div","card-title");b.textContent=g.title;const x=f("div","card-desc");x.textContent=`${g.elementCount} element${g.elementCount===1?"":"s"} · ${g.filePath}`,y.append(b,x),l.appendChild(y)}d.length===0&&l.appendChild(Ht("No boards yet — create one."));const h=await k.getTree(t),p=ge(t,h),m=ye(p,jt(t));m&&n.appendChild(m)}catch{l.appendChild(Ht("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(bt(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=Z(h.root.id,h.board.id);const m=f("div","card-title");m.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(m,g),l.appendChild(p)}d.length===0&&l.appendChild(Ht("No boards yet — create one."))}catch{l.appendChild(Ht("Could not load boards."))}this.contentScroll.scrollTop=e??0}async listProjectBoards(t){const e=[];for(const n of t.docsRoots){const s=await J.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=St(a,"board");if(!r.ok){C(r.message);return}try{const c=await J.create(t,r.raw,ee(),e);await this.refreshContentIndex(),location.hash=Z(t,c)}catch{C("Could not create board")}}):_("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=St(c.value,"board");if(!p.ok){C(p.message),c.focus();return}try{const m=await J.create(t,p.raw,ee(),e);r(),await this.refreshContentIndex(),location.hash=Z(t,m)}catch{C("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=St(a,"directory");if(!r.ok){C(r.message);return}const c=e?`${e}/${r.slug}`:r.slug;try{await k.createDirectory(t,c),await this.refreshContentIndex()}catch{C("Could not create directory")}}):_("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=St(c.value,"directory");if(!p.ok){C(p.message),c.focus();return}const m=e?`${e}/${p.slug}`:p.slug;try{await k.createDirectory(t,m),r(),await this.refreshContentIndex()}catch{C("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{C("Could not create docs folder");return}}async createDocsFolder(t,e){try{await k.createDocsFolder(t,e),await this.refreshContentIndex(),C(`Created docs/ in ${e||"project root"}`)}catch{C("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=St(a.replace(/\.md$/i,""),"doc");if(!r.ok){C(r.message);return}const c=e?`${e}/${r.slug}.md`:`${r.slug}.md`;try{await k.writeFile(t,c,`# ${st(r.slug)}
50
+ `),await this.refreshContentIndex(),location.hash=O(t,c)}catch{C("Could not create doc")}}):_("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=St(c.value.replace(/\.md$/i,""),"doc");if(!p.ok){C(p.message),c.focus();return}const m=e?`${e}/${p.slug}.md`:`${p.slug}.md`;try{await k.writeFile(t,m,`# ${st(p.slug)}
51
+ `),r(),await this.refreshContentIndex(),location.hash=O(t,m)}catch{C("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){_("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}`:`capabilities/${l}`,p=`${h}/index.md`,m=`${h}/llms.txt`,g=st(l),y=`---
52
+ title: ${g}
53
+ summary:
54
+ tags:
55
+ kind:
56
+ ---
57
+
58
+ # ${g}
59
+
60
+ ## Purpose
61
+
62
+ ## When to use
63
+
64
+ ## Important files
65
+
66
+ ## Outputs
67
+ `,b=`# ${g}
68
+
69
+ Read index.md first for the human overview of this capability branch.
70
+
71
+ ## Purpose
72
+
73
+ Describe what this capability helps an LLM do.
74
+
75
+ ## Entry points
76
+
77
+ - Human entry: index.md
78
+ - Machine entry: llms.txt
79
+
80
+ ## Important files
81
+
82
+ List the files or subdirectories an LLM should inspect before acting.
83
+
84
+ ## Working rules
85
+
86
+ Record the constraints, tools, scripts, or workflows that matter for this capability.
87
+ `;try{await k.createDirectory(t,h),await k.writeFile(t,p,y),await k.writeFile(t,m,b),s(),await this.refreshContentIndex(),location.hash=Ft(t,p)}catch{C("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=O(t,l)}catch{C("Could not rename doc")}}):_("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 m=(l.value.trim()||s).replace(/\.md$/,"").replace(/\s+/g,"-").toLowerCase(),g=`${n}${m}.md`;if(g===e){c();return}try{await k.renameFile(t,e,g),c(),await this.refreshContentIndex(),location.hash=O(t,g)}catch{C("Could not rename doc")}};h.addEventListener("click",()=>void p()),l.addEventListener("keydown",m=>{m.stopPropagation(),m.key==="Enter"&&p()}),d.appendChild(h),r.append(l,d),l.focus()})}async moveDoc(t,e,n){const s=Xn(n,te(e));if(s!==e)try{const i=new Set(vt(await k.getTree(t)).map(c=>G(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===O(t,e)&&(location.hash=O(t,s)),C(`Moved ${te(e)}`)}catch{C("Could not move doc")}}async moveBoard(t,e,n){try{const s=await J.move(t,e,n),i=await this.updateBoardEmbedReferences(t,e,s);await this.refreshContentIndex(),location.hash===Z(t,e)&&(location.hash=Z(t,s)),C(i>0?`Moved ${te(e)} and updated ${i} embed${i===1?"":"s"}`:`Moved ${te(e)}`)}catch(s){C(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=bs(s);let a=0;for(const r of i){const c=await k.readFile(t,r.path),l=Sa(c,r.path,e,n);l!==c&&(await k.writeFile(t,r.path,l),a++)}return a}async moveDirectory(t,e,n){const s=te(e),i=Xn(n,s);if(i!==e)try{const a=await k.getTree(t),r=new Set(vt(a).map(p=>G(p.path))),c=ka(a,e),l=Ea(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,m]of d){const g=`${i}${p.slice(e.length)}`,y=Un(m,p,g,r);y!==m&&(await k.writeFile(t,g,y),h++)}for(const p of c){const m=`${i}${p.slice(e.length)}`;await this.rewriteMovedBoardDocumentId(t,p,m),h+=await this.updateBoardEmbedReferences(t,p,m)}await this.refreshContentIndex(),this.rewriteRouteAfterDirectoryMove(t,e,i),C(h>0?`Moved ${s} and updated ${h} embed${h===1?"":"s"}`:`Moved ${s}`)}catch{C("Could not move directory")}}promptRenameDirectory(t,e){const n=e.includes("/")?e.slice(0,e.lastIndexOf("/")+1):"",s=e.split("/").pop()??"";_("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(),C(`Renamed to ${h}`)}catch{C("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(),C(`Deleted ${n}`)}catch{C("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=O(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=Z(t,`${n}${c.slice(e.length)}`))}}async promptDeleteDoc(t,e){const n=e.split("/").pop()??e;_("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{C("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 J.load(t,e);if(!n){C("Board not found");return}_("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=St(a.value,"board");if(!d.ok){C(d.message),a.focus();return}try{const h=await J.rename(t,e,d.raw),p=await this.updateBoardEmbedReferences(t,e,h);i(),await this.refreshContentIndex(),location.hash===Z(t,e)&&(location.hash=Z(t,h)),p>0&&C(`Renamed board and updated ${p} embed${p===1?"":"s"}`)}catch(h){C(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){_("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 J.delete(t,e),s(),await this.refreshContentIndex(),location.hash=jt(t)}catch{C("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 ji(this.editorHost,{boardId:e,loadBoard:async s=>{const i=await k.getBoardWithRevision(t,s);return i||void 0},saveBoard:(s,i)=>k.saveBoard(t,s.id,s,i),deleteBoard:s=>J.delete(t,s),uploadImage:(s,i)=>J.uploadImage(t,s,i),cleanupUnusedAssets:s=>J.cleanupUnusedAssets(t,s),resolveAssetUrl:s=>k.assetUrl(t,s),initialRegion:n,onExit:()=>{this.pendingScrollRestore=this.lastNonBoardScrollTop,location.hash=this.lastNonBoardHash},onDeleted:()=>{location.hash=jt(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(Dn),e=t==="dark"||t==="light"?t:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";document.documentElement.setAttribute("data-theme",e)}toggleTheme(){var e;const t=ee()==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",t),localStorage.setItem(Dn,t),this.updateThemeButton(),(e=this.updateRenderedTheme)==null||e.call(this,t)}createTopbar(){const t=f("div","shell-topbar"),e=f("button","topbar-icon-btn");return e.innerHTML=V.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=`${V.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.hidden=!0,this.editBtn=f("button","btn topbar-edit"),this.editBtn.type="button",this.editBtn.innerHTML=`${V.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.editBtn,this.themeBtn),t}setSidebarCollapsed(t){this.layout.classList.toggle("sidebar-collapsed",t),localStorage.setItem(An,String(t))}setupSidebarResize(){this.sidebarResizeHandle&&this.sidebarResizeHandle.addEventListener("pointerdown",t=>{var r;if(this.layout.classList.contains("sidebar-collapsed"))return;t.preventDefault();const e=t.clientX,n=this.readSidebarWidth(),s=t.pointerId;(r=this.sidebarResizeHandle)==null||r.setPointerCapture(s),document.body.classList.add("sidebar-resizing");const i=c=>{const l=Oe(n+c.clientX-e);this.applySidebarWidth(l)},a=()=>{var c;(c=this.sidebarResizeHandle)==null||c.releasePointerCapture(s),document.body.classList.remove("sidebar-resizing"),window.removeEventListener("pointermove",i),window.removeEventListener("pointerup",a)};window.addEventListener("pointermove",i),window.addEventListener("pointerup",a)})}readSidebarWidth(){const t=Number(localStorage.getItem(Nn)??270);return Oe(t)}applySidebarWidth(t){const e=Oe(t);this.layout.style.setProperty("--sidebar-width",`${e}px`),localStorage.setItem(Nn,String(e))}setEditableFile(t){this.currentEditableFile=t,this.editBtn&&(this.editBtn.hidden=!t,this.editBtn.disabled=!t)}promptRemoveProject(t,e){_("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{C("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(){try{const t=new Set(this.allDocsRoots().map(l=>l.id)),e=await k.pickAndAddProject();if(e.cancelled)return;await this.refreshContentIndex();let n=e.addedProjectId?this.workspace.projects.find(l=>l.id===e.addedProjectId):void 0,s=n==null?void 0:n.docsRoots[0];if(n&&n.docsRoots.length===0){const l=await this.promptCreateProjectDocsRoot(n.id,n.label);if(!l){location.hash=Mt(n.id),C(`Added ${n.label}. Create docs/ later or switch to Raw view from the project menu.`);return}n=this.workspace.projects.find(d=>d.id===(n==null?void 0:n.id)),s=l}const i=this.allDocsRoots(),a=s??i.find(l=>!t.has(l.id));if(!a){C("No docs folders found under that project root.");return}const r=this.treesByRoot.get(a.id)??[],c=Ue(Xt(r));c?location.hash=O(a.id,c):location.hash=jt(a.id),C(`Added ${a.projectLabel}.`)}catch(t){C(t instanceof Error?t.message:"Could not add project root.")}}promptCreateProjectDocsRoot(t,e){return new Promise(n=>{_("Create docs folder",(s,i)=>{let a=!1;const r=m=>{a||(a=!0,i(),n(m))},c=document.createElement("p");c.textContent=`${e} does not have a docs/ folder yet. Create one at the project root now?`;const l=document.createElement("p");l.textContent="You can keep the repo in the workspace and switch to Raw view later if you prefer.";const d=f("div","modal-actions"),h=f("button","btn primary");h.textContent="Create docs/",h.addEventListener("click",()=>{h.disabled=!0,p.disabled=!0,this.ensureProjectDocsRoot(t).then(m=>{if(!m){h.disabled=!1,p.disabled=!1;return}r(m)})});const p=f("button","btn");p.textContent="Maybe later",p.addEventListener("click",()=>r(void 0)),d.append(h,p),s.append(c,l,d)})})}updateTopbarCart(t=!1){this.cartBtn&&(this.cartBtn.hidden=!0)}toggleCartPopover(){this.closeCartPopover()}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=ee()==="dark";this.themeBtn.innerHTML=t?V.sun:V.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=[...Jt(a),...Es(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}=ne(d),p=ys(d),m=h.title??fs(d)??st(c.name),g=h.summary??gs(p),y=l.startsWith("capabilities/")?"Capability":"Doc",b=l.startsWith("capabilities/")?Ft(i.id,l):O(i.id,l);s.push({title:m,path:`${i.projectLabel}/${i.displayPath}/${l}`,href:b,section:y,summary:g,body:p.map(x=>x.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=V.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=wa(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");On(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");On(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(mt).filter(Boolean),n=mt(t.join(" "));return this.searchIndex.map(s=>{const i=mt(s.title),a=mt(s.path),r=mt(s.summary);let c=Qt(i,e,n,10);c+=Qt(a,e,n,4),c+=Qt(r,e,n,3);let l,d=0;for(const p of s.chunks){const m=Qt(mt(p.heading),e,n,5),g=Qt(p.normalized,e,n,p.kind==="heading"?8:2),y=m+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?Ba(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.updateRenderedTheme=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 fe(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:Se(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:st(r[c]),href:Se(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":st(c)})}return n}function bt(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 Ht(o){const t=f("div","empty-note");return t.textContent=o,t}function zn(o,t,e,n){var s;return{path:`${o}:${t.branchPath}`,rootId:o,branchPath:t.branchPath,entryPath:t.entryPath,displayPath:t.routePath,title:n.title??fs(e)??Ee(t.entryPath),summary:n.summary??gs(ys(e)),kind:((s=n.kind)==null?void 0:s.trim())||void 0,tags:n.tags?n.tags.split(",").map(i=>i.trim()).filter(Boolean):[],md:e}}function ge(o,t){const e=[];function n(a){const c=[...Xt(a)].sort((l,d)=>{const h=l.type==="file"&&l.name==="index.md"?-1:0,p=d.type==="file"&&d.name==="index.md"?-1:0;return h!==p?h-p:l.type!==d.type?l.type==="dir"?-1:1:l.name.localeCompare(d.name)});for(const l of c)if(l.type==="file"){const d=l.name==="index.md"?"Overview":st(l.name);e.push({label:d,href:O(o,l.path)})}else n(l.children)}n(t);const s=vt(t).sort((a,r)=>a.path.localeCompare(r.path));if(s.length>0){e.push({label:"All Boards",href:jt(o)});for(const a of s){const r=G(a.path);e.push({label:st(r.split("/").pop()??r),href:Z(o,r)})}}const i=$t(t);if(i.length>0){e.push({label:"All Capabilities",href:ps(o)});for(const a of i)e.push({label:Ee(a.entryPath),href:Ft(o,a.entryPath)})}return e}function ye(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 ps(o){return`#/root/${encodeURIComponent(o)}/capabilities`}function Xt(o){return o.filter(t=>t.type==="file"?t.name.endsWith(".md"):t.name==="capabilities"||t.name==="assets"?!1:Xt(t.children).length>0).map(t=>t.type==="file"?t:{...t,children:Xt(t.children)})}function Jt(o){const t=[],e=n=>{for(const s of Xt(n))s.type==="file"?t.push(s):e(s.children)};return e(o),t}function O(o,t){return`#/root/${encodeURIComponent(o)}/docs/${encodeURIComponent(t)}`}function Ft(o,t){return`#/root/${encodeURIComponent(o)}/capabilities/${encodeURIComponent(qt(t))}`}function $t(o){const t=o.find(s=>s.type==="dir"&&s.name==="capabilities");if(!t||t.type!=="dir")return[];const e=[],n=s=>{for(const i of s){if(i.type==="file"){i.path.startsWith("capabilities/")&&i.name.endsWith(".md")&&!i.path.slice(13).includes("/")&&e.push({branchPath:i.path,entryPath:i.path,routePath:qt(i.path)});continue}const a=ba(i);a&&e.push({branchPath:i.path,entryPath:a.path,routePath:qt(i.path)}),n(i.children)}};return n(t.children),e.sort((s,i)=>s.branchPath.localeCompare(i.branchPath))}function pa(o,t){const e=t.replace(/^\/+|\/+$/g,""),n=e.startsWith("capabilities/")?e:`capabilities/${e}`;if(n.endsWith(".md"))return n;const s=$t(o).find(i=>i.branchPath===n||i.routePath===e);return(s==null?void 0:s.entryPath)??null}function Hn(o,t){const e=t.replace(/^\/+|\/+$/g,""),n=e.startsWith("capabilities/")?e:`capabilities/${e}`,s=$t(o).find(i=>i.branchPath===n||i.entryPath===n||i.routePath===e);return s||($t(o).filter(i=>n.startsWith(`${i.branchPath}/`)).sort((i,a)=>a.branchPath.length-i.branchPath.length)[0]??null)}function Ee(o){if(o.endsWith("/index.md")){const t=o.slice(0,-9);return st(t.split("/").pop()??t)}return st(o.split("/").pop()??o)}function qt(o){const t=o.replace(/^capabilities\//,"");return t.endsWith("/index.md")?t.slice(0,-9):t}function ua(o){return{branchPath:ma(o),entryPath:o,routePath:qt(o)}}function ma(o){return o.endsWith("/index.md")?o.slice(0,-9):o}function Fn(o,t){const e=us(o,t);return e?e.type==="file"?[e]:ms(e.children).sort(ya):[]}function be(o){return qt(o)||"index.md"}function fa(o){return o.endsWith(".md")?null:`${o}/llms.txt`}function ga(o){return/\.(md|txt|json|ya?ml|js|ts|mjs|cjs|sh|css|html)$/i.test(o)}function us(o,t){for(const e of o){if(e.path===t)return e;if(e.type==="dir"){const n=us(e.children,t);if(n)return n}}return null}function ms(o){const t=[];for(const e of o)e.type==="file"?t.push(e):t.push(...ms(e.children));return t}function ya(o,t){const e=jn(o.path),n=jn(t.path);if(e!==n)return e.localeCompare(n);const s=Wn(o.name),i=Wn(t.name);return s!==i?s?-1:1:o.path.localeCompare(t.path)}function jn(o){const t=o.lastIndexOf("/");return t===-1?"":o.slice(0,t)}function Wn(o){return/^readme\.(md|txt)$/i.test(o)}function ba(o){const t=o.children.find(e=>e.type==="file"&&e.name==="index.md");return t||(o.children.find(e=>e.type==="file"&&e.name.endsWith(".md"))??null)}function jt(o){return`#/root/${encodeURIComponent(o)}/boards`}function Z(o,t){return`#/root/${encodeURIComponent(o)}/boards/${encodeURIComponent(t)}`}function Mt(o){return`#/project/${encodeURIComponent(o)}`}function Se(o,t){return`#/root/${encodeURIComponent(o)}/directory/${encodeURIComponent(t)}`}function va(o){const t=o.match(/^#\/root\/([^/]+)/);return t?decodeURIComponent(t[1]):null}function fs(o){var t,e;return((e=(t=o.match(/^#\s+(.+)$/m))==null?void 0:t[1])==null?void 0:e.trim())??null}function wa(o){return[...new Set(o.trim().split(/\s+/).map(mt).filter(Boolean))]}function On(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(xa).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 xa(o){return o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function gs(o){var t;return((t=o.find(e=>e.kind==="text"&&e.text.length>0))==null?void 0:t.text.slice(0,180))??""}function ys(o){const e=o.replace(/^---[\s\S]*?---\s*/,"").split(`
88
+ `),n=[];let s="",i=[];const a=(c,l="text",d=s)=>{const h=_n(c);h&&n.push({heading:d,text:h,normalized:mt(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 m=d[1].length,g=(d[2]??"").toLowerCase(),y=new RegExp("^`{"+m+",}\\s*$"),b=[];for(c++;c<e.length&&!y.test(e[c]);)b.push(e[c]),c++;a(g==="board"?Ca(b.join(`
89
+ `)):b.join(`
90
+ `),g==="board"?"board":"code");continue}const h=l.match(/^(#{1,6})\s+(.+)$/);if(h){r(),s=_n(h[2]),a(s,"heading",s);continue}if(l.trim()===""||/^(-{3,}|\*{3,}|_{3,})\s*$/.test(l)){r();continue}if(Ia(l))continue;const p=l.replace(/^>\s?/,"").replace(/^\s*([-*+]|\d+\.)\s+/,"").replace(/^\[([ xX])\]\s+/,"").replace(/\|/g," ");i.push(p)}return r(),n}function Ca(o){return o.split(`
91
+ `).map(t=>t.replace(/#.*$/,"").trim()).filter(Boolean).map(t=>t.replace(/^(\w+)\s*:\s*/,"$1 ")).join(" ")}function bs(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 vt(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 ka(o,t){const e=t.replace(/^\/+|\/+$/g,"");return vt(o).map(n=>G(n.path)).filter(n=>n===e||n.startsWith(`${e}/`))}function Ea(o,t){const e=t.replace(/^\/+|\/+$/g,"");return bs(o).filter(n=>n.path.startsWith(`${e}/`))}function Un(o,t,e,n){if(t===e)return o;const s=o.split(`
92
+ `);let i=!1,a,r=!1;const c=s.map(l=>{if(!i){const m=l.match(/^(`{3,})\s*board\s*$/i);return m&&(i=!0,a=new RegExp("^`{"+m[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=vs(d[2]);if(!h.value)return l;const p=Ma(h.value,t,e,n);return p===h.value?l:(r=!0,`${d[1]}${p}${h.suffix}`)});return r?c.join(`
93
+ `):o}function Sa(o,t,e,n){const s=o.split(`
94
+ `);let i=!1,a,r=!1;const c=s.map(l=>{if(!i){const m=l.match(/^(`{3,})\s*board\s*$/i);return m&&(i=!0,a=new RegExp("^`{"+m[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=vs(d[2]);return!h.value||!re(h.value,t).includes(e)?l:(r=!0,`${d[1]}${Ta(h.value,t,e,n)}${h.suffix}`)});return r?c.join(`
95
+ `):o}function vs(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 Ta(o,t,e,n){const s=o.trim(),i=s.startsWith("/"),a=s.startsWith("./")||s.startsWith("../"),r=s.endsWith(".board.json"),c=re(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?ws(Ye(t,n)):n;return r&&!d.endsWith(".board.json")&&(d=`${d}.board.json`),d}function Ma(o,t,e,n){const s=o.trim(),i=s.startsWith("./")||s.startsWith("../"),a=re(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?Rs(s,t):c;if(!d)return o;let h=ws(Ye(e,d));return l&&!h.endsWith(".board.json")&&(h=`${h}.board.json`),h}function ws(o){return!o||o.startsWith("./")||o.startsWith("../")?o:`./${o}`}function _n(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 mt(o){return o.normalize("NFKD").replace(/[\u0300-\u036f]/g,"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function Qt(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 Ba(o,t){if(t.length===0)return o.slice(0,220);const e=mt(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 Ia(o){return/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(o)}function st(o){const t=o.replace(/\.md$/,"").replace(/[-_]/g," ");return t.charAt(0).toUpperCase()+t.slice(1)}function Ra(o){return o.trim().replace(/[\\/]+/g,"-").replace(/\s+/g,"-").replace(/[^a-z0-9-_]/gi,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").toLowerCase()}const La=new Set([".","..","assets","boards","capabilities","docs"]);function St(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=Ra(n);return s?s.length>64?{ok:!1,message:"Name is too long after formatting."}:La.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 te(o){const t=o.replace(/^\/+|\/+$/g,"");return t.split("/").pop()??t}function Xn(o,t){const e=o.replace(/^\/+|\/+$/g,""),n=t.replace(/^\/+|\/+$/g,"");return e?`${e}/${n}`:n}function $a(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]]}function Oe(o){return Math.max(la,Math.min(da,o))}const xs=document.getElementById("app");if(!xs)throw new Error("Missing #app root element");new ha(xs);