tecton 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -131,7 +131,7 @@ jobs:
131
131
  with: { fetch-depth: 0 }
132
132
  - uses: actions/setup-node@v4
133
133
  with: { node-version: 20 }
134
- - uses: gaurav2180/tecton@v0.4.0
134
+ - uses: gaurav2180/tecton@v0.4.1
135
135
  ```
136
136
 
137
137
  The action compares the pull request with its base branch and does four things:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tecton",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Tecton: see every shift in your architecture before it becomes a crack. Architecture diagrams, before/after diffs and boundary rules for JS/TS codebases.",
5
5
  "homepage": "https://github.com/gaurav2180/tecton#readme",
6
6
  "repository": {
@@ -1,3 +1,3 @@
1
1
  // Generated by scripts/build.js from src/report/client/. Do not edit.
2
- (()=>{var xt="http://www.w3.org/2000/svg",$e=window.matchMedia("(prefers-reduced-motion: reduce)").matches,P=(e,s=document)=>s.querySelector(e),oe=(e,s=document)=>[...s.querySelectorAll(e)];function t(e,s,...a){let o=document.createElement(e);return Gt(o,s),_t(o,a),o}function v(e,s,...a){let o=document.createElementNS(xt,e);return Gt(o,s),_t(o,a),o}function Gt(e,s){if(s)for(let a of Object.keys(s)){let o=s[a];if(!(o==null||o===!1))if(a==="class")e.setAttribute("class",o);else if(a==="text")e.textContent=o;else if(a==="html")e.innerHTML=o;else if(a==="on")for(let n of Object.keys(o))e.addEventListener(n,o[n]);else a==="style"&&typeof o=="object"?Object.assign(e.style,o):a==="dataset"?Object.assign(e.dataset,o):e.setAttribute(a,o===!0?"":o)}}function _t(e,s){for(let a of s.flat(1/0))a==null||a===!1||e.appendChild(typeof a=="string"||typeof a=="number"?document.createTextNode(String(a)):a)}var qt='<rect class="pl" x="6" y="14" width="25" height="12" rx="3"/><rect class="pl-shift" x="33" y="9" width="25" height="12" rx="3"/><rect class="pl" x="25" y="28" width="14" height="30" rx="3"/>',ke={logo:'<circle cx="6" cy="6" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="12" cy="18" r="2.5"/><path d="M8 7.5l3 8M16 7.5l-3 8M8.5 6h7"/>',overview:'<rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/>',map:'<rect x="16" y="16" width="6" height="6" rx="1"/><rect x="2" y="16" width="6" height="6" rx="1"/><rect x="9" y="2" width="6" height="6" rx="1"/><path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3"/><path d="M12 12V8"/>',shield:'<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="m9 12 2 2 4-4"/>',compare:'<circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><path d="M13 6h3a2 2 0 0 1 2 2v7"/><path d="M11 18H8a2 2 0 0 1-2-2V9"/>',box:'<path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/>',pkg:'<path d="M16.5 9.4 7.55 4.24"/><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><path d="M3.29 7 12 12l8.71-5"/><path d="M12 22V12"/>',folder:'<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/>',search:'<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',sun:'<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>',moon:'<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>',monitor:'<rect width="20" height="14" x="2" y="3" rx="2"/><path d="M8 21h8M12 17v4"/>',x:'<path d="M18 6 6 18M6 6l12 12"/>',plus:'<path d="M5 12h14M12 5v14"/>',minus:'<path d="M5 12h14"/>',fit:'<path d="M8 3H5a2 2 0 0 0-2 2v3M21 8V5a2 2 0 0 0-2-2h-3M16 21h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/>',copy:'<rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',download:'<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/>',alert:'<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4M12 17h.01"/>',check:'<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',xcircle:'<circle cx="12" cy="12" r="10"/><path d="m15 9-6 6M9 9l6 6"/>',right:'<path d="m9 18 6-6-6-6"/>',arrowRight:'<path d="M5 12h14M12 5l7 7-7 7"/>',file:'<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>',branch:'<path d="M6 3v12"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>',menu:'<path d="M4 6h16M4 12h16M4 18h16"/>',cycle:'<path d="m17 2 4 4-4 4"/><path d="M3 11v-1a4 4 0 0 1 4-4h14"/><path d="m7 22-4-4 4-4"/><path d="M21 13v1a4 4 0 0 1-4 4H3"/>',image:'<rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21"/>',clock:'<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>',link:'<path d="M9 17H7A5 5 0 0 1 7 7h2M15 7h2a5 5 0 1 1 0 10h-2M8 12h8"/>',code:'<path d="m16 18 6-6-6-6M8 6l-6 6 6 6"/>',sparkle:'<path d="M9.94 14.06 2 22M12 2l1.8 5.2L19 9l-5.2 1.8L12 16l-1.8-5.2L5 9l5.2-1.8z"/>',layers:'<path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"/><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/>',server:'<rect width="20" height="8" x="2" y="2" rx="2"/><rect width="20" height="8" x="2" y="14" rx="2"/><path d="M6 6h.01M6 18h.01"/>',globe:'<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>',users:'<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/>',database:'<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/>',cloud:'<path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/>',terminal:'<path d="m4 17 6-6-6-6M12 19h8"/>',mail:'<rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>',phone:'<rect width="14" height="20" x="5" y="2" rx="2"/><path d="M12 18h.01"/>',filePlus:'<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4M9 15h6M12 12v6"/>'};ke.queue='<path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/>';ke.pencil='<path d="M21.17 6.81a2.82 2.82 0 0 0-3.99-3.99L3.84 16.17a2 2 0 0 0-.5.83l-1.32 4.35a.5.5 0 0 0 .62.62l4.35-1.32a2 2 0 0 0 .83-.5z"/>';ke.arrowLeft='<path d="M19 12H5M12 19l-7-7 7-7"/>';function $(e,s){let a=document.createElementNS(xt,"svg");return a.setAttribute("class",`i${s?` ${s}`:""}`),a.setAttribute("viewBox","0 0 24 24"),a.setAttribute("aria-hidden","true"),a.innerHTML=ke[e]||"",a}var Y=e=>e.startsWith("npm:")?e.slice(4):e,ee=(e,s,a)=>`${e.toLocaleString()} ${e===1?s:a||`${s}s`}`,ce=e=>String(e).replace(/[&<>"]/g,s=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[s]);function Qt(e){let s=new Date(e).getTime();if(!s)return"";let a=Math.round((Date.now()-s)/6e4);if(a<1)return"just now";if(a<60)return`${a} min ago`;let o=Math.round(a/60);return o<24?`${o} h ago`:new Date(e).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"})}var It={get(e){try{return localStorage.getItem(`tecton:${e}`)}catch{return null}},set(e,s){try{localStorage.setItem(`tecton:${e}`,s)}catch{}}};var x=JSON.parse(document.getElementById("data").textContent),Z=x.summary,be=Z.violations,M=x.hasBase,Oe=new Map(x.nodes.map(e=>[e.id,e])),Ue=new Map(x.edges.map(e=>[e.id,e])),lt=new Map(x.violations.map(e=>[e.id,e])),Ie={cur:new Map,base:new Map},Yt=(e,s,a)=>{e.has(s)||e.set(s,[]),e.get(s).push(a)};x.violations.forEach(e=>e.edges.forEach(s=>{e.status!=="fixed"&&Yt(Ie.cur,s,e),e.status!=="new"&&Yt(Ie.base,s,e)}));var Ce=M?be.newErrors>0:x.violations.some(e=>e.severity==="error"),Se=x.violations.filter(e=>e.status!=="fixed"),Ot=e=>e.status!=="same"||e.countBase!==e.countCur,Ms=e=>e.status==="added"?"added":e.status==="removed"?"removed":"changed",ze=x.nodes.filter(e=>!e.external),Ee=new Map(x.nodes.map(e=>[e.id,{uses:0,usedBy:0,viol:0}]));x.edges.forEach(e=>{e.status!=="removed"&&(Ee.get(e.from).uses++,Ee.get(e.to).usedBy++)});Se.forEach(e=>{(e.kind==="cycle"?e.members:[e.from]).forEach(a=>{Ee.has(a)&&Ee.get(a).viol++})});var xe=(x.rules||[]).map(e=>{let s=x.violations.filter(n=>n.rule===e.key),a={new:0,existing:0,fixed:0};s.forEach(n=>{a[n.status]++});let o;return a.new?o="new":a.existing?o="existing":a.fixed?o="fixed":o="pass",{...e,viols:s,n:a,state:o}}),Ne=[...ze.filter(e=>e.status!=="same").map(e=>({type:"node",id:e.id,kind:e.status,label:e.id,sub:ee(e.status==="added"?e.filesCur:e.filesBase,"file")})),...x.edges.filter(Ot).map(e=>({type:"edge",id:e.id,kind:Ms(e),label:`${Y(e.from)} \u2192 ${Y(e.to)}`,edge:e,viol:(Ie.cur.get(e.id)||[]).some(s=>s.status==="new")}))],Zt=x.files||{files:[],deps:[]},Kt={s:"same",a:"added",r:"removed"},Fe=Zt.files.map(([e,s,a,o],n)=>({i:n,path:e,module:s,status:Kt[a],edited:!!o,out:[],in:[]})),je=new Map(Fe.map(e=>[e.path,e]));Zt.deps.forEach(([e,s,a,o])=>{let n={from:Fe[e],to:Fe[s],status:Kt[a],line:o};Fe[e].out.push(n),Fe[s].in.push(n)});var Jt=e=>Fe.filter(s=>s.module===e),dt=new Set(x.nodes.filter(e=>e.touched).map(e=>e.id)),Ke=M&&dt.size>0,Ve=e=>e.status==="added"?"added":e.status==="removed"?"removed":e.edited?"edited":"same",Xt={added:0,removed:1,changed:2};Ne.sort((e,s)=>(s.viol?1:0)-(e.viol?1:0)||Xt[e.kind]-Xt[s.kind]||e.label.localeCompare(s.label));var Pe=[{id:"overview",title:"Overview",icon:"overview"},{id:"system",title:"Architecture",icon:"layers"},{id:"map",title:"Dependency map",icon:"map"},{id:"rules",title:"Rule checks",icon:"shield"},{id:"changes",title:"Changes",icon:"compare"},{id:"modules",title:"Modules",icon:"box"}],E={page:"overview",view:M?"diff":"cur",selected:null,focusOnly:!1,touchedOnly:!1};function He(e,s,a){let o=t("div",{class:"tabs",role:"group"}),n=t("span",{class:"ind"});o.appendChild(n);let i=e.map(l=>t("button",{"aria-pressed":String(l.value===s),dataset:{value:l.value},disabled:l.disabled,style:l.disabled?{opacity:".45",cursor:"not-allowed"}:null,on:{click:()=>{l.disabled||(d(l.value),a(l.value))}}},l.label,l.count!=null?t("span",{class:"c",text:l.count}):null));i.forEach(l=>o.appendChild(l));function p(){let l=i.find(c=>c.getAttribute("aria-pressed")==="true");!l||!l.offsetWidth||(n.style.left=`${l.offsetLeft}px`,n.style.width=`${l.offsetWidth}px`)}function d(l){i.forEach(c=>c.setAttribute("aria-pressed",String(c.dataset.value===l))),p()}return o._place=p,o._set=d,o}var et=()=>oe(".tabs").forEach(e=>e._place&&e._place());function de(e,s){return t("span",{class:`badge ${e}`,text:s})}function wt(e){return{new:de("critical","New break"),existing:de("serious","Failing"),fixed:de("good","Fixed"),pass:de("good","Passing")}[e]}function $t(e){return M?e.status==="new"?de(e.severity==="error"?"critical":"warn",e.severity==="error"?"New":"New warning"):e.status==="fixed"?de("good","Fixed"):de("neutral","Already there"):de(e.severity==="error"?"critical":"warn",e.severity==="error"?"Error":"Warning")}function he(e){return{added:de("add","Added"),removed:de("rem","Removed"),changed:de("chg","Changed"),edited:de("acc","Edited"),same:de("neutral","Unchanged")}[e]}function tt(e,s){return t("div",{class:"ev"},e.map(a=>t("div",{class:`ev-row ${s||""}`},t("code",{text:`${a.file}:${a.line}`}),t("span",{class:"to",text:`\u2192 ${a.spec}`}))))}function es(e,s){if($e||s===0){e.textContent=s.toLocaleString();return}let a=performance.now(),o=900,n=i=>{let p=Math.min(1,(i-a)/o);e.textContent=Math.round(s*(1-(1-p)**3)).toLocaleString(),p<1&&requestAnimationFrame(n)};requestAnimationFrame(n)}var Je=P("#tip");function Le(e,s){Je.innerHTML=s,Je.classList.add("show");let a=14,o=Je.getBoundingClientRect(),n=e.clientX+a,i=e.clientY+a;n+o.width>window.innerWidth-8&&(n=e.clientX-o.width-a),i+o.height>window.innerHeight-8&&(i=e.clientY-o.height-a),Je.style.left=`${n}px`,Je.style.top=`${i}px`}function me(){Je.classList.remove("show")}function Es(e){return Math.max(120,Math.round(e.length*7.3)+56)}function ts(e,s){let a=e.map(h=>h.id).sort(),o=h=>h.external?11:(h.filesBase!==h.filesCur?`${h.filesBase} \u2192 ${h.filesCur} files`:`${h.filesCur||h.filesBase||0} files`).length,n=new Map(e.map(h=>[h.id,Math.max(Es((h.label||h.id).replace(/^npm:/,"")),h.filesCur===void 0?0:Math.round(36+o(h)*6.4+16))])),i=new Map(a.map(h=>[h,[]]));for(let h of s)i.get(h.from).push(h);for(let h of i.values())h.sort((T,I)=>T.to<I.to?-1:1);let p=new Map,d=new Set,l=h=>{p.set(h,1);for(let T of i.get(h)){let I=p.get(T.to);I===1?d.add(T.id):I||l(T.to)}p.set(h,2)};for(let h of a)p.get(h)||l(h);let c=s.map(h=>d.has(h.id)?{id:h.id,u:h.to,v:h.from}:{id:h.id,u:h.from,v:h.to}),r=new Map(a.map(h=>[h,[]])),u=new Map(a.map(h=>[h,[]]));for(let h of c)r.get(h.v).push(h.u),u.get(h.u).push(h.v);let m=new Map(a.map(h=>[h,r.get(h).length])),g=[],f=a.filter(h=>m.get(h)===0);for(;f.length;){f.sort();let h=f.shift();g.push(h);for(let T of u.get(h))m.set(T,m.get(T)-1),m.get(T)===0&&f.push(T)}let y=new Map;for(let h of g)y.set(h,Math.max(0,...r.get(h).map(T=>y.get(T)+1)));for(let h of[...g].reverse())r.get(h).length===0&&u.get(h).length&&y.set(h,Math.min(...u.get(h).map(T=>y.get(T)))-1);let D=Math.min(0,...y.values());for(let h of a)y.set(h,y.get(h)-D);let F=new Map(y),ne=new Map,_=[];for(let h of c){let T=[h.u];for(let I=y.get(h.u)+1;I<y.get(h.v);I++){let A=`\0${h.id}#${I}`;F.set(A,I),n.set(A,14),T.push(A)}T.push(h.v),ne.set(h.id,T);for(let I=0;I+1<T.length;I++)_.push([T[I],T[I+1]])}let w=new Map([...F.keys()].map(h=>[h,[]])),z=new Map([...F.keys()].map(h=>[h,[]]));for(let[h,T]of _)z.get(h).push(T),w.get(T).push(h);let b=Math.max(0,...F.values())+1,S=Array.from({length:b},()=>[]),j=new Set,V=[...F.keys()].filter(h=>w.get(h).length===0).sort();for(;V.length;){let h=V.shift();if(!j.has(h)){j.add(h),S[F.get(h)].push(h);for(let T of[...z.get(h)].sort())j.has(T)||V.push(T)}}for(let h of[...F.keys()].sort())j.has(h)||S[F.get(h)].push(h);let ae=h=>{let T=0;for(let I=0;I+1<h.length;I++){let A=new Map(h[I+1].map((k,R)=>[k,R])),N=[];h[I].forEach((k,R)=>z.get(k).forEach(q=>N.push([R,A.get(q)])));for(let k=0;k<N.length;k++)for(let R=k+1;R<N.length;R++)(N[k][0]-N[R][0])*(N[k][1]-N[R][1])<0&&T++}return T},W=(h,T,I,A)=>{let N=new Map(h[A].map((R,q)=>[R,q])),k=new Map(h[T].map((R,q)=>{let pe=I.get(R).filter(ye=>N.has(ye));return[R,pe.length?pe.reduce((ye,De)=>ye+N.get(De),0)/pe.length:q]}));h[T]=[...h[T]].sort((R,q)=>k.get(R)-k.get(q)||h[T].indexOf(R)-h[T].indexOf(q))},X=S.map(h=>[...h]),B=ae(X);for(let h=0;h<16&&B>0;h++){if(h%2===0)for(let I=1;I<b;I++)W(S,I,w,I-1);else for(let I=b-2;I>=0;I--)W(S,I,z,I+1);let T=ae(S);T<B&&(B=T,X=S.map(I=>[...I]))}S=X;let H=new Map;for(let h of S){let T=0;for(let A of h)H.set(A,T+n.get(A)/2),T+=n.get(A)+36;let I=(T-36)/2;for(let A of h)H.set(A,H.get(A)-I)}let te=(h,T)=>{let I=(k,R)=>(n.get(k)+n.get(R))/2+(k.startsWith("\0")||R.startsWith("\0")?10:36),A=h.map(k=>T.get(k));for(let k=1;k<h.length;k++)A[k]=Math.max(A[k],A[k-1]+I(h[k-1],h[k]));let N=h.map(k=>T.get(k));for(let k=h.length-2;k>=0;k--)N[k]=Math.min(N[k],N[k+1]-I(h[k],h[k+1]));h.forEach((k,R)=>H.set(k,(A[R]+N[R])/2));for(let k=1;k<h.length;k++){let R=H.get(h[k-1])+I(h[k-1],h[k]);H.get(h[k])<R&&H.set(h[k],R)}};for(let h=0;h<10;h++){let T=h%2===0?S.map((I,A)=>A):S.map((I,A)=>S.length-1-A);for(let I of T){let A=h%2===0?w:z,N=new Map(S[I].map(k=>{let R=[...A.get(k),...h>5?(A===w?z:w).get(k):[]];return[k,R.length?R.reduce((q,pe)=>q+H.get(pe),0)/R.length:H.get(k)]}));te(S[I],N)}}let we=h=>h*132,G=Math.min(...[...H.entries()].map(([h,T])=>T-n.get(h)/2),0),L={};for(let h of a){let T=n.get(h);L[h]={x:H.get(h)-T/2-G,y:we(y.get(h)),w:T,h:46}}let Q=new Set(s.map(h=>`${h.from}\u2192${h.to}`)),le={};for(let h of s){let T=ne.get(h.id),I=T.map((A,N)=>{let k=H.get(A)-G,R=we(F.get(A));return N===0?[k,R+46]:N===T.length-1?[k,R]:[k,R+46/2]});if(d.has(h.id)&&I.reverse(),Q.has(`${h.to}\u2192${h.from}`)){let A=h.from<h.to?-7:7;I.forEach(N=>{N[0]+=A})}le[h.id]=I.map(([A,N])=>[Math.round(A*10)/10,Math.round(N*10)/10]),T=null}let J=Math.max(0,...Object.values(L).map(h=>h.x+h.w)),ue=Math.max(0,...Object.values(L).map(h=>h.y+h.h));return{pos:L,routes:le,width:J,height:ue,crossings:B}}function se(e){location.hash!==`#${e}`?location.hash=e:st(e)}var ss=!1;function st(e){let s=null;if(e.startsWith("module:")){try{s=decodeURIComponent(e.slice(7))}catch{s=null}let o=s&&Oe.get(s);e=o&&!o.external?"module":"modules"}e!=="module"&&!Pe.some(o=>o.id===e)&&(e="overview"),E.page=e;let a=e==="module"?s:Pe.find(o=>o.id===e).title;oe(".page").forEach(o=>o.classList.toggle("active",o.id===`page-${e}`)),oe(".nav a").forEach(o=>o.classList.toggle("active",o.dataset.page===(e==="module"?"modules":e))),P("#crumb-cur").textContent=e==="module"?`Modules / ${s}`:a,document.title=`${a} \xB7 ${x.project} \xB7 Tecton`,P("#content").scrollTop=0,me(),requestAnimationFrame(et),e==="overview"&&!ss&&(ss=!0,oe("[data-count]",P("#page-overview")).forEach(o=>es(o,Number(o.dataset.count)))),e!=="system"&&_e(),e==="system"&&(C.svg?(oe(".sys-tabs").forEach(o=>o._set&&o._set(E.view)),rt()):ct(),requestAnimationFrame(()=>{C.fitted||(C.fitted=Ge(!1))})),e==="module"&&kt(s),e==="map"&&requestAnimationFrame(()=>{O.fitted||(at(!1),O.fitted=!0),as()})}var re=x.system||{apps:[],stores:[],outside:[],links:[],hasUsers:!1,summary:null},ls={expanded:new Set,sel:null},Qe=[{key:"pages",title:"Pages",icon:"file",mono:!0},{key:"api",title:"Routes & API",icon:"code"},{key:"endpoints",title:"HTTP endpoints",icon:"code"},{key:"jobs",title:"Jobs & scripts",icon:"terminal",mono:!0},{key:"schedules",title:"Schedules",icon:"clock",mono:!0}],Nt=e=>e.kind==="Queue"?"queue":"database",ht=e=>({web:"globe",mobile:"phone",desktop:"monitor",server:"server"})[e.role]||"box",ns=e=>ie(e.status||"same");var pt=new Map(re.apps.map(e=>[e.id,e])),os=e=>e==="users"?"Users":(pt.get(e)||{}).name||e,Pt=new Map([...re.stores,...re.outside].map(e=>[e.id,e]));function Cs(){let e=re.links.filter(a=>a.kind==="app"),s=new Map(re.apps.map(a=>[a.id,["web","mobile","desktop"].includes(a.role)?0:1]));for(let a=0;a<4;a++)e.forEach(o=>{s.has(o.to)&&s.has(o.from)&&s.set(o.to,Math.max(s.get(o.to),s.get(o.from)+1))});return[...re.apps].sort((a,o)=>s.get(a.id)-s.get(o.id)||a.name.localeCompare(o.name))}var is=["var(--accent)","var(--chg)","var(--add)","var(--viol)","var(--warn)"];function Rt(e){let s=re.apps.findIndex(a=>a.id===e);return is[(s<0?0:s)%is.length]}var C={vb:{x:0,y:0,w:100,h:100},drag:null,dragMoved:!1,nodes:new Map,wires:[],model:null,fitted:!1},fe=8,ge=e=>Math.round(e/fe)*fe,qe=(e,s)=>e.length*s,Re=(e,s)=>e.length>s?`${e.slice(0,s-1)}\u2026`:e,Ss=e=>e.every(s=>s.status==="added")?"added":e.every(s=>s.status==="removed")?"removed":"same";function Ls(e){let s={pages:["page","pages"],api:["route","routes"],endpoints:["endpoint","endpoints"],jobs:["job","jobs"],schedules:["schedule","schedules"]};return Qe.map(a=>[a.key,(e.groups[a.key]||[]).filter(o=>o.status!=="removed").length]).filter(([,a])=>a).map(([a,o])=>`${o} ${s[a][o===1?0:1]}`).join(" \xB7 ")}function As(e){if(e.kind==="users")return"uses \xB7 HTTPS";if(e.kind==="app")return e.labels[0]||"HTTP";let s=Pt.get(e.to);return e.kind==="data"?e.labels.length?e.labels.join(" \xB7 "):s&&s.kind==="Queue"?"messages":s&&/SQL|Postgre|MySQL|SQLite|ORM|Prisma|Drizzle/i.test(`${s.name} ${s.via.join(" ")}`)?"reads & writes \xB7 SQL":"reads & writes":s&&s.id.startsWith("svc:")?"API \xB7 SDK":s&&s.id.startsWith("env:")?"HTTPS \xB7 env":"HTTPS"}function Bs(){let e=[],s=re.links.filter(n=>n.kind==="users");s.length&&e.push({id:"users",type:"person",name:"Users",kind:"Person",sub:"Browser & API clients",status:Ss(s),w:168,h:120});for(let n of re.apps){let i=Ls(n)||"No entry points found",p=n.tech.filter(l=>l.toLowerCase()!==n.framework.toLowerCase()).slice(0,4).join(" \xB7 "),d=ge(Math.max(248,64+qe(Re(n.name,26),8),32+qe(i,6.6),32+qe(p,6.3)));e.push({id:n.id,type:"app",name:Re(n.name,26),kind:`Container: ${n.framework}`,sub:i,tech:p,status:n.status||"same",w:d,h:p?128:112,ref:n,color:Rt(n.id)})}for(let n of re.stores){let i=n.kind==="Queue",p=ge(Math.max(i?192:176,44+qe(Re(n.name,24),7.6)));e.push({id:n.id,type:i?"queue":"db",name:Re(n.name,24),kind:i?"Queue":n.kind,sub:Re(n.via.join(", "),30),status:n.status||"same",w:p,h:i?72:104,ref:n})}for(let n of re.outside){let i=(n.hosts||[]).map(l=>typeof l=="string"?l:l.host),p=n.id.startsWith("env:")?`set by ${n.via[0]||"an env var"}`:i.length?Re(i.join(", "),30):n.via.length?Re(n.via.join(", "),30):"",d=ge(Math.max(208,56+qe(Re(n.name,26),7.8),32+qe(p,6.3)));e.push({id:n.id,type:"ext",name:Re(n.name,26),kind:`External \xB7 ${n.kind}`,sub:p,status:n.status||"same",w:d,h:80,ref:n,envOnly:n.id.startsWith("env:")})}let a=new Map(e.map(n=>[n.id,n])),o=re.links.filter(n=>a.has(n.from)&&a.has(n.to)).map(n=>({id:n.id,from:n.from,to:n.to,kind:n.kind,status:n.status||"same",label:As(n),link:n,async:n.kind==="data"&&a.get(n.to).type==="queue"}));return{nodes:e,edges:o,byId:a}}function Ts(e){let p=e.nodes.filter(L=>L.type==="app"),d=e.edges.filter(L=>L.kind==="app"),l=new Map(p.map(L=>[L.id,["web","mobile","desktop"].includes(L.ref.role)?0:1]));for(let L=0;L<4;L++)d.forEach(Q=>{l.has(Q.to)&&l.has(Q.from)&&l.set(Q.to,Math.max(l.get(Q.to),l.get(Q.from)+1))});let c=Math.min(...l.values());p.forEach(L=>l.set(L.id,l.get(L.id)-c));let r=4,u=p.slice().sort((L,Q)=>l.get(L.id)-l.get(Q.id)||L.name.localeCompare(Q.name)),m=[];for(let L=0;L<u.length;L+=r)m.push(u.slice(L,L+r));let g=e.nodes.filter(L=>L.type==="db"||L.type==="queue"),f=L=>L[0]&&L[0].type==="app"?144:64,y=L=>L.reduce((Q,le)=>Q+le.w,0)+f(L)*Math.max(0,L.length-1),D=Math.max(...m.map(y),y(g),320),F=e.byId.has("users"),ne=F?216:0,_=ne+48,w=(L,Q,le)=>{let J=le-y(L)/2,ue=Math.max(...L.map(h=>h.h));return L.forEach(h=>{h.x=ge(J),h.y=ge(Q+(ue-h.h)/2),J+=h.w+f(L)}),ue},z=48+D/2;if(m.forEach(L=>{_+=w(L,_,z)+104}),g.length){let L=Q=>{let le=e.edges.filter(J=>J.to===Q.id).map(J=>e.byId.get(J.from)).filter(J=>J&&J.x!=null);return le.length?le.reduce((J,ue)=>J+ue.x+ue.w/2,0)/le.length:z};g.sort((Q,le)=>L(Q)-L(le)||+(Q.type==="queue")-+(le.type==="queue")||Q.name.localeCompare(le.name)),_+=w(g,_,z)+0}else _-=104;let b=[...p,...g],S=ge(Math.min(...b.map(L=>L.x))-48),j=ge(Math.max(...b.map(L=>L.x+L.w))+48),V=ge(ne),ae=ge(_+48+40),W=b.length?{x:S,y:V,w:j-S,h:ae-V}:null;if(F){let L=e.byId.get("users"),Q=e.edges.filter(J=>J.from==="users").map(J=>e.byId.get(J.to)).filter(J=>J.x!=null),le=Q.length?Q.reduce((J,ue)=>J+ue.x+ue.w/2,0)/Q.length:z;L.x=ge(le-L.w/2),L.y=0}let X=e.nodes.filter(L=>L.type==="ext");if(X.length){let L=A=>{let N=e.edges.filter(k=>k.to===A.id).map(k=>e.byId.get(k.from)).filter(k=>k&&k.y!=null);return N.length?N.reduce((k,R)=>k+R.y+R.h/2,0)/N.length:0};X.sort((A,N)=>L(A)-L(N)||A.ref.kind.localeCompare(N.ref.kind)||A.name.localeCompare(N.name));let Q=40,le=W?W.y:0,J=W?W.h:600,ue=Math.max(4,Math.floor((J+Q)/(80+Q)),Math.min(8,Math.ceil(X.length/2))),h=Math.ceil(X.length/ue),T=Math.max(...X.map(A=>A.w)),I=(W?W.x+W.w:0)+176;for(let A=0;A<h;A++){let N=X.slice(A*ue,(A+1)*ue),k=N.reduce((q,pe)=>q+pe.h,0)+Q*(N.length-1),R=le+Math.max(0,(J-k)/2);N.forEach(q=>{q.x=ge(I+(T-q.w)/2),q.y=ge(R),R+=q.h+Q}),I+=T+96}}let B=e.nodes,H=Math.min(...B.map(L=>L.x),W?W.x:1/0),te=Math.min(...B.map(L=>L.y),W?W.y:1/0),we=Math.max(...B.map(L=>L.x+L.w),W?W.x+W.w:-1/0),G=Math.max(...B.map(L=>L.y+L.h),W?W.y+W.h:-1/0);return{boundary:W,bounds:{x:H,y:te,w:we-H,h:G-te}}}function Is(e,s){let o=s.bounds,n=ge(o.x-120),i=ge(o.y-120),p=Math.ceil((o.w+240)/fe)+1,d=Math.ceil((o.h+240)/fe)+1,l=new Uint8Array(p*d),c=(b,S)=>S*p+b;for(let b of e.nodes){let S=Math.floor((b.x-12-n)/fe)+1,j=Math.ceil((b.x+b.w+12-n)/fe)-1,V=Math.floor((b.y-12-i)/fe)+1,ae=Math.ceil((b.y+b.h+12-i)/fe)-1;for(let W=Math.max(0,V);W<=Math.min(d-1,ae);W++)for(let X=Math.max(0,S);X<=Math.min(p-1,j);X++)l[c(X,W)]=1}let r=new Uint8Array(p*d),u=new Int16Array(p*d),m=new Map(e.nodes.map((b,S)=>[b.id,S+1])),g=[[1,0],[0,1],[-1,0],[0,-1]],f={right:0,bottom:1,left:2,top:3},y=[];for(let b of e.edges){let S=e.byId.get(b.from),j=e.byId.get(b.to),V,ae;j.y>=S.y+S.h+24&&!(j.type==="ext"&&S.type!=="person")?(V="bottom",ae="top"):j.y+j.h+24<=S.y&&j.type!=="ext"?(V="top",ae="bottom"):j.x+j.w/2>=S.x+S.w/2?(V="right",ae="left"):(V="left",ae="right"),b.ss=V,b.ts=ae,y.push({e:b,node:S,side:V,other:j,end:"s"},{e:b,node:j,side:ae,other:S,end:"t"})}let D=new Map;y.forEach(b=>{let S=`${b.node.id}|${b.side}|${b.end}`;D.has(S)||D.set(S,[]),D.get(S).push(b)});for(let b of D.values()){let S=b[0].side==="top"||b[0].side==="bottom";b.sort((B,H)=>(S?B.other.x+B.other.w/2-(H.other.x+H.other.w/2):B.other.y+B.other.h/2-(H.other.y+H.other.h/2))||(B.e.id<H.e.id?-1:1));let j=b[0].node,V=S?j.w:j.h,ae=b[0].end==="s",W=ae?0:Math.min(V*.7,Math.max(0,(b.length-1)*24)),X=ae&&b.length?Math.max(-V*.25,Math.min(V*.25,(b.reduce((B,H)=>B+(S?H.other.x+H.other.w/2:H.other.y+H.other.h/2),0)/b.length-((S?j.x:j.y)+V/2))*.3)):0;b.forEach((B,H)=>{let te=ge((S?j.x:j.y)+V/2+X-W/2+(b.length>1&&W?W*H/(b.length-1):0)),we=B.side==="right"?[j.x+j.w,te]:B.side==="left"?[j.x,te]:B.side==="bottom"?[te,j.y+j.h]:[te,j.y],G=g[f[B.side]],L=[we[0]+G[0]*3*fe,we[1]+G[1]*3*fe];B.e[B.end==="s"?"P0":"P1"]=we,B.e[B.end==="s"?"Q0":"Q1"]=L})}let F=e.edges.slice().sort((b,S)=>Math.abs(b.Q0[0]-b.Q1[0])+Math.abs(b.Q0[1]-b.Q1[1])-(Math.abs(S.Q0[0]-S.Q1[0])+Math.abs(S.Q0[1]-S.Q1[1]))||(b.id<S.id?-1:1)),ne=6;for(let b of F){let S=Math.round((b.Q0[0]-n)/fe),j=Math.round((b.Q0[1]-i)/fe),V=Math.round((b.Q1[0]-n)/fe),ae=Math.round((b.Q1[1]-i)/fe),W=m.get(b.from),X=f[b.ss],B=(f[b.ts]+2)%4,H=p*d*4,te=new Float64Array(H).fill(1/0),we=new Int32Array(H).fill(-1),G=[],L=(I,A)=>{G.push([I,A]);let N=G.length-1;for(;N>0;){let k=N-1>>1;if(G[k][0]<=G[N][0])break;[G[k],G[N]]=[G[N],G[k]],N=k}},Q=()=>{let I=G[0],A=G.pop();if(G.length){G[0]=A;let N=0;for(;;){let k=2*N+1,R=k+1,q=N;if(k<G.length&&G[k][0]<G[q][0]&&(q=k),R<G.length&&G[R][0]<G[q][0]&&(q=R),q===N)break;[G[q],G[N]]=[G[N],G[q]],N=q}}return I},le=(I,A)=>Math.abs(I-V)+Math.abs(A-ae),J=c(S,j)<<2|X;te[J]=0,L(le(S,j),J);let ue=-1,h=0;for(;G.length&&h++<4e5;){let[I,A]=Q(),N=A>>2,k=A&3,R=N%p,q=(N-R)/p;if(R===V&&q===ae){ue=A;break}if(!(I>te[A]+le(R,q)+1e-6))for(let pe=0;pe<4;pe++){if(pe===(k+2)%4)continue;let ye=R+g[pe][0],De=q+g[pe][1];if(ye<0||De<0||ye>=p||De>=d)continue;let it=c(ye,De);if(l[it]&&!(ye===V&&De===ae))continue;let ks=pe%2===0?1:2,zt=u[it]===W,Vt=(zt?.7:1)+(pe!==k?ne:0)+(zt?0:r[it]&ks?4:r[it]?1.5:0);ye===V&&De===ae&&pe!==B&&(Vt+=ne);let bt=it<<2|pe,Tt=te[A]+Vt;Tt<te[bt]&&(te[bt]=Tt,we[bt]=A,L(Tt+le(ye,De),bt))}}let T;if(ue<0)T=[b.P0,b.Q0,[b.Q0[0],b.Q1[1]],b.Q1,b.P1];else{let I=[];for(let N=ue;N>=0;N=we[N])I.push(N);I.reverse();let A=null;for(let N of I){let k=N>>2,R=k%p,q=(k-R)/p;if(A){let pe=R!==A[0]?1:2;for(let ye of[c(R,q),c(A[0],A[1])])r[ye]|=pe,u[ye]||(u[ye]=W)}A=[R,q]}T=[b.P0,...I.map(N=>{let k=N>>2,R=k%p;return[n+R*fe,i+(k-R)/p*fe]}),b.P1]}b.pts=T.filter((I,A)=>A===0||A===T.length-1||!(T[A-1][0]===I[0]&&I[0]===T[A+1][0]||T[A-1][1]===I[1]&&I[1]===T[A+1][1]))}let _=e.nodes.map(b=>({x:b.x-4,y:b.y-4,w:b.w+8,h:b.h+8})),w=[],z=b=>[..._,...w].some(S=>b.x<S.x+S.w&&b.x+b.w>S.x&&b.y<S.y+S.h&&b.y+b.h>S.y);for(let b of F){let S=b.label.length*6.3+18,j=20,V=[];for(let B=0;B<b.pts.length-1;B++){let H=b.pts[B],te=b.pts[B+1];V.push({a:H,c:te,len:Math.abs(H[0]-te[0])+Math.abs(H[1]-te[1])})}let W=[...V.slice().reverse().filter(B=>B.len>=(B.a[1]===B.c[1]?S+16:j+24)),...V.slice().sort((B,H)=>H.len-B.len)],X=null;for(let B of W){for(let H of[.5,.3,.7,.18,.82]){let te=B.a[0]+(B.c[0]-B.a[0])*H,we=B.a[1]+(B.c[1]-B.a[1])*H,G={x:te-S/2,y:we-j/2,w:S,h:j};if(!z(G)){X=G;break}}if(X)break}if(!X&&W.length){let B=W[0];X={x:(B.a[0]+B.c[0])/2-S/2,y:(B.a[1]+B.c[1])/2-j/2,w:S,h:j}}X&&(w.push(X),b.lbl=X)}}function Os(e,s=10){if(e.length<2)return"";let a=`M${e[0][0]},${e[0][1]}`;for(let n=1;n<e.length-1;n++){let[i,p]=e[n-1],[d,l]=e[n],[c,r]=e[n+1],u=Math.min(s,Math.hypot(d-i,l-p)/2,Math.hypot(c-d,r-l)/2),m=d-Math.sign(d-i)*u,g=l-Math.sign(l-p)*u,f=d+Math.sign(c-d)*u,y=l+Math.sign(r-l)*u;a+=` L${m},${g} Q${d},${l} ${f},${y}`}let o=e[e.length-1];return`${a} L${o[0]},${o[1]}`}function Ns(e){let s=v("g",{class:`an t-${e.type}`,transform:`translate(${e.x},${e.y})`,dataset:{node:e.id}}),a=(d,l,c,r=.75)=>v("g",{class:"an-ico",transform:`translate(${l},${c}) scale(${r})`,html:ke[d]}),o=(d,l,c,r,u)=>v("text",{class:d,x:l,y:c,"text-anchor":u||"start"},r),{w:n,h:i}=e;e.type==="person"?s.append(v("rect",{class:"an-shape",x:0,y:40,width:n,height:i-40,rx:26}),v("circle",{class:"an-shape an-head",cx:n/2,cy:24,r:23}),o("an-name",n/2,80,e.name,"middle"),o("an-kind",n/2,96,`[${e.kind}]`,"middle"),o("an-sub",n/2,111,e.sub,"middle")):e.type==="app"?(s.style.setProperty("--app",e.color),s.append(v("rect",{class:"an-shape",width:n,height:i,rx:12}),v("rect",{class:"an-band",width:n,height:5,rx:2.5}),v("rect",{class:"an-ibox",x:16,y:18,width:30,height:30,rx:8}),a(ht(e.ref),22,24),o("an-name",56,32,e.name),o("an-kind",56,47,`[${e.kind}]`),v("line",{class:"an-rule",x1:16,x2:n-16,y1:64,y2:64}),o("an-sub",16,86,e.sub)),e.tech&&s.append(o("an-tech",16,110,e.tech))):e.type==="db"?s.append(v("path",{class:"an-shape",d:`M0,11 A${n/2},11 0 0 1 ${n},11 L${n},${i-11} A${n/2},11 0 0 1 0,${i-11} Z`}),v("ellipse",{class:"an-lid",cx:n/2,cy:11,rx:n/2,ry:11}),a("database",n/2-9,30),o("an-name",n/2,66,e.name,"middle"),o("an-kind",n/2,82,`[${e.kind}]`,"middle")):e.type==="queue"?s.append(v("path",{class:"an-shape",d:`M14,0 L${n-14},0 A14,${i/2} 0 0 1 ${n-14},${i} L14,${i} A14,${i/2} 0 0 1 14,0 Z`}),v("ellipse",{class:"an-lid",cx:n-14,cy:i/2,rx:14,ry:i/2}),a("queue",26,i/2-9),o("an-name",54,i/2-2,e.name),o("an-kind",54,i/2+14,`[${e.kind}${e.sub?` \xB7 ${e.sub}`:""}]`)):(s.append(v("rect",{class:`an-shape${e.envOnly?" env":""}`,width:n,height:i,rx:10}),a({Email:"mail","Web / HTTP":"globe"}[e.ref.kind]||"cloud",16,16),o("an-name",44,29,e.name),o("an-kind",16,52,`[${e.kind}]`)),e.sub&&s.append(o("an-sub mono",16,69,e.sub)));let p=(d,l,c)=>v("g",{class:`an-badge ${d}`,transform:`translate(${n-c-10},-9)`},v("rect",{width:c,height:17,rx:5}),v("text",{x:c/2,y:12,"text-anchor":"middle"},l));if(s.append(p("b-add","NEW",36),p("b-rem","GONE",40)),e.type!=="person"){s.setAttribute("tabindex",0),s.setAttribute("role","button"),s.setAttribute("aria-label",`${e.name}, ${e.kind}`);let d=()=>Ae(e.type==="app"?{type:"app",id:e.id}:{type:"svc",id:e.id});s.addEventListener("click",l=>{C.dragMoved||(l.stopPropagation(),d())}),s.addEventListener("keydown",l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),d())})}return s.addEventListener("pointerenter",()=>{C.drag||ut(e.id)}),s.addEventListener("pointerleave",()=>ut(null)),s.addEventListener("focus",()=>ut(e.id)),s.addEventListener("blur",()=>ut(null)),s}function Ps(e){let s=Bs(),a=Ts(s);Is(s,a),C.model=s,C.layout=a;let o=v("defs");o.innerHTML=[["line","--text-3"],["app","--accent"],["data","--text-2"],["add","--add"],["rem","--rem"],["hl","--accent"]].map(([l,c])=>`<marker id="aw-${l}" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="9" markerHeight="9" orient="auto-start-reverse" markerUnits="userSpaceOnUse"><path d="M1,1.5 L9,5 L1,8.5 Q2.5,5 1,1.5 z" style="fill: var(${c})"/></marker>`).join("")+'<filter id="an-shadow" x="-10%" y="-20%" width="120%" height="150%"><feDropShadow dx="0" dy="1.5" stdDeviation="2" flood-color="#101018" flood-opacity=".07"/></filter><pattern id="aw-dots" width="16" height="16" patternUnits="userSpaceOnUse"><circle cx="1" cy="1" r="1" style="fill: var(--dot)"/></pattern>',e.appendChild(o),e.appendChild(v("rect",{class:"arch-bg",x:-2e4,y:-2e4,width:4e4,height:4e4,fill:"url(#aw-dots)"}));let n=v("g",{id:"arch-world"});if(a.boundary){let l=a.boundary;n.append(v("g",{class:"arch-boundary"},v("rect",{x:l.x,y:l.y,width:l.w,height:l.h,rx:18}),v("g",{class:"an-ico",transform:`translate(${l.x+20},${l.y+l.h-33}) scale(0.7)`,html:ke.layers}),v("text",{class:"ab-name",x:l.x+44,y:l.y+l.h-20},x.project),v("text",{class:"ab-kind",x:l.x+56+qe(x.project,8.6),y:l.y+l.h-20},"[Software system \xB7 this repo]")))}let i=v("g"),p=v("g"),d=v("g");n.append(i,p,d),C.wires=[];for(let l of s.edges){let c=Os(l.pts),r=v("path",{class:"wl",d:c}),u=v("g",{class:`aw k-${l.kind}${l.async?" async":""}`,dataset:{wire:l.id}},r,v("path",{class:"whit",d:c}));if(!$e&&(l.kind==="app"||l.status==="added")){let f=v("circle",{class:"wdot",r:2.6}),y=v("animateMotion",{dur:`${Math.max(2,l.pts.reduce((D,F,ne)=>ne?D+Math.abs(F[0]-l.pts[ne-1][0])+Math.abs(F[1]-l.pts[ne-1][1]):0,0)/90).toFixed(2)}s`,repeatCount:"indefinite",path:c});f.appendChild(y),u.appendChild(f)}let m=null;l.lbl&&(m=v("g",{class:`aw-lbl k-${l.kind}`},v("rect",{x:l.lbl.x,y:l.lbl.y,width:l.lbl.w,height:l.lbl.h,rx:10}),v("text",{x:l.lbl.x+l.lbl.w/2,y:l.lbl.y+l.lbl.h/2+.5,"text-anchor":"middle","dominant-baseline":"central"},l.label)),d.appendChild(m));let g=()=>`<div class="tt">${ce(l.from==="users"?"Users":(s.byId.get(l.from)||{}).name||l.from)} <span class="faint">\u2192</span> ${ce((s.byId.get(l.to)||{}).name||l.to)}</div><div class="kv"><span>${ce(l.label)}</span><b>${l.link.count||""}</b></div>${M&&l.status!=="same"?`<div class="kv"><span>Status</span><b>${l.status==="added"?"New":"Removed"}</b></div>`:""}${l.link.evidence&&l.link.evidence[0]?`<div class="kv faint"><span class="mono-s">${ce(l.link.evidence[0].file)}:${l.link.evidence[0].line}</span></div>`:""}`;[u,m].filter(Boolean).forEach(f=>{f.addEventListener("pointermove",y=>{C.drag||Le(y,g())}),f.addEventListener("pointerleave",me)}),i.appendChild(u),C.wires.push({e:l,g:u,path:r,lbl:m})}C.nodes=new Map;for(let l of s.nodes){let c=Ns(l);p.appendChild(c),C.nodes.set(l.id,{n:l,el:c})}e.appendChild(n),e.addEventListener("click",()=>{C.dragMoved||_e()}),C.svg=e,C.world=n}function rt(){if(C.svg){for(let{n:e,el:s}of C.nodes.values()){let a=E.view==="diff"&&M?e.status:"same";s.setAttribute("class",`an t-${e.type} ${a}${ie(e.status)?"":" gone"}`)}for(let{e,g:s,path:a,lbl:o}of C.wires){let n=E.view==="diff"&&M?e.status:"same",i=`${n}${ie(e.status)?"":" gone"}`;s.setAttribute("class",`aw k-${e.kind}${e.async?" async":""} ${i}`),o&&o.setAttribute("class",`aw-lbl k-${e.kind} ${i}`),a.setAttribute("marker-end",`url(#aw-${n==="added"?"add":n==="removed"?"rem":e.kind==="app"?"app":e.kind==="data"?"data":"line"})`)}}}function ut(e){let s=P("#arch-card");if(!s||(rt(),s.classList.toggle("hl-on",!!e),!e))return;let a=new Set([e]);for(let{e:o,g:n,path:i,lbl:p}of C.wires){let d=o.from===e||o.to===e;n.classList.toggle("hl",d),p&&p.classList.toggle("hl",d),d&&(a.add(o.from),a.add(o.to),i.setAttribute("marker-end","url(#aw-hl)"))}for(let{n:o,el:n}of C.nodes.values())n.classList.toggle("hl",a.has(o.id))}function nt(){if(!C.svg)return;C.svg.setAttribute("viewBox",`${C.vb.x} ${C.vb.y} ${C.vb.w} ${C.vb.h}`);let e=P("#arch-stage").getBoundingClientRect(),s=P("#arch-pct");s&&e.width&&(s.textContent=`${Math.round(e.width/C.vb.w*100)}%`)}function Ge(e){let s=P("#arch-stage");if(!s||!C.layout)return!1;let a=s.getBoundingClientRect();if(!a.width||!a.height)return!1;let o=C.layout.bounds,n=40,i=Math.min(1.1,(a.width-n*2)/o.w,(a.height-n*2)/o.h),p=Math.max(i,a.width<640?.5:.2),d=p>i+1e-6,l=a.width/p,c=a.height/p,r=d?{x:o.x-n/p,y:o.y-n/p,w:l,h:c}:{x:o.x+o.w/2-l/2,y:o.y+o.h/2-c/2,w:l,h:c};if(!e||$e)return C.vb=r,nt(),!0;let u={...C.vb},m=performance.now(),g=f=>{let y=Math.min(1,(f-m)/320),D=1-(1-y)**3;for(let F of["x","y","w","h"])C.vb[F]=u[F]+(r[F]-u[F])*D;nt(),y<1&&requestAnimationFrame(g)};return requestAnimationFrame(g),!0}function Mt(e,s,a){let o=P("#arch-stage").getBoundingClientRect(),n=s??o.width/2,i=a??o.height/2,p=Math.min(8e3,Math.max(160,C.vb.w*e)),d=p/C.vb.w;C.vb.x+=n/o.width*C.vb.w*(1-d),C.vb.y+=i/o.height*C.vb.h*(1-d),C.vb.w=p,C.vb.h*=d,nt()}function Rs(e){let s=new Map,a=null;e.addEventListener("wheel",n=>{n.preventDefault();let i=e.getBoundingClientRect();n.ctrlKey||Math.abs(n.deltaY)>Math.abs(n.deltaX)*1.2||n.deltaMode?Mt(Math.exp(n.deltaY*(n.ctrlKey?.01:.0016)),n.clientX-i.left,n.clientY-i.top):(C.vb.x+=n.deltaX*C.vb.w/i.width,C.vb.y+=n.deltaY*C.vb.h/i.height,nt())},{passive:!1}),e.addEventListener("pointerdown",n=>{if(n.button===0){if(s.set(n.pointerId,[n.clientX,n.clientY]),s.size===2){let[i,p]=[...s.values()];a={d:Math.hypot(i[0]-p[0],i[1]-p[1]),w:C.vb.w},C.drag=null;return}C.drag={x:n.clientX,y:n.clientY,vx:C.vb.x,vy:C.vb.y},C.dragMoved=!1}}),e.addEventListener("pointermove",n=>{if(s.has(n.pointerId)&&s.set(n.pointerId,[n.clientX,n.clientY]),a&&s.size===2){let[l,c]=[...s.values()],r=e.getBoundingClientRect(),u=a.w*a.d/Math.max(20,Math.hypot(l[0]-c[0],l[1]-c[1]))/C.vb.w;Mt(u,(l[0]+c[0])/2-r.left,(l[1]+c[1])/2-r.top),C.dragMoved=!0;return}if(!C.drag)return;let i=n.clientX-C.drag.x,p=n.clientY-C.drag.y;if(!C.dragMoved&&Math.abs(i)+Math.abs(p)>4&&(C.dragMoved=!0,e.classList.add("dragging"),me(),ut(null)),!C.dragMoved)return;let d=e.getBoundingClientRect();C.vb.x=C.drag.vx-i*C.vb.w/d.width,C.vb.y=C.drag.vy-p*C.vb.h/d.height,nt()});let o=n=>{s.delete(n.pointerId),s.size<2&&(a=null),C.drag=null,e.classList.remove("dragging"),setTimeout(()=>{C.dragMoved=!1},0)};e.addEventListener("pointerup",o),e.addEventListener("pointercancel",o),e.addEventListener("pointerleave",n=>{C.drag&&o(n)})}function Ds(){let e=C.layout.bounds,s=40;Ft(C.svg,{x:e.x-s,y:e.y-s,w:e.w+s*2,h:e.h+s*2},`${x.project}-system-architecture.svg`,["whit","wdot","arch-bg"]),We("Architecture diagram exported as SVG","download")}function ct(){let e=P("#page-system"),s=C.svg&&C.fitted?{...C.vb}:null;e.innerHTML="",C.svg=null;let a=re.summary,o=He([{value:"diff",label:"Changes",disabled:!M},{value:"base",label:"Before",disabled:!M},{value:"cur",label:"After"}],E.view,m=>{E.view=m,Dt()});o.classList.add("sys-tabs");let n=m=>M&&(m.added||m.removed)?[m.added?t("span",{class:"chip add",text:`+${m.added}`}):null,m.removed?t("span",{class:"chip rem",text:`\u2212${m.removed}`}):null]:null,i=(m,g,f,y)=>t("div",{class:"sys-stat"},$(y),t("b",{class:"num",text:m}),t("span",{text:g}),n(f));if(e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Architecture"}),t("p",{text:"A container diagram drawn from your code: who uses the system, the apps in this repo, the data they keep and the outside systems they call."})),t("div",{class:"right"},o))),a&&e.append(t("div",{class:"sys-stats stagger"},i(a.apps.total,a.apps.total===1?"app":"apps",a.apps,"layers"),i(a.entry.total,"entry points",a.entry,"code"),i(a.stores.total,a.stores.total===1?"data store":"data stores",a.stores,"database"),i(a.outside.total,a.outside.total===1?"outside system":"outside systems",a.outside,"cloud"))),!re.apps.length){e.append(t("div",{class:"card"},t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("layers")),t("h4",{text:"No apps found"}),t("p",{text:"Tecton looks for package.json files to find the apps in a repo."}))));return}let p=v("svg",{id:"arch-svg",role:"img","aria-label":`Container diagram of ${x.project}`}),d=t("div",{id:"arch-stage"},p),l=(m,g,f)=>t("span",{class:"ak"},v("svg",{viewBox:"0 0 26 16","aria-hidden":"true"},f||v("g",{class:`aw ${m}`},v("path",{class:"wl",d:"M2,8 L24,8"}))),g),c=(m,g)=>v("path",{class:`ak-shape ${m}`,d:g}),r=t("div",{class:"arch-legend"},l("","Person",c("","M13,1.5 a3,3 0 1 1 0,6 a3,3 0 1 1 0,-6 M5,15 q0,-6 8,-6 q8,0 8,6 z")),l("","App (container)",c("","M3,3 h20 a2,2 0 0 1 2,2 v8 a2,2 0 0 1 -2,2 h-20 a2,2 0 0 1 -2,-2 v-8 a2,2 0 0 1 2,-2 z")),l("","Database",c("","M6,3 a7,2.5 0 0 1 14,0 v10 a7,2.5 0 0 1 -14,0 z M6,3 a7,2.5 0 0 0 14,0")),l("","Queue",c("","M5,3 h16 a3,5 0 0 1 0,10 h-16 a3,5 0 0 1 0,-10 z M21,3 a3,5 0 0 0 0,10")),l("","Outside system",c("ext","M2,3 h22 v10 h-22 z")),l("","This repo",c("bnd","M2,3 h22 v10 h-22 z")),t("span",{class:"ak-sep"}),l("k-app","calls"),l("k-data","reads / writes"),l("k-data async","async (queue)"),l("k-outside","outside call"),M?[l("added","new"),l("removed","removed")]:null),u=t("div",{class:"zoom glass"},t("button",{"aria-label":"Zoom in","data-tip":"Zoom in",on:{click:()=>Mt(1/1.3)}},$("plus")),t("button",{"aria-label":"Zoom out","data-tip":"Zoom out",on:{click:()=>Mt(1.3)}},$("minus")),t("button",{"aria-label":"Fit to screen","data-tip":"Fit to screen (F)",on:{click:()=>Ge(!0)}},$("fit")),t("button",{"aria-label":"Export SVG","data-tip":"Export as SVG",on:{click:Ds}},$("image")),t("div",{class:"pct",id:"arch-pct",text:"100%"}));e.append(t("div",{class:"card arch-card",id:"arch-card"},d,t("div",{class:"float br"},u),t("div",{class:"float bl"},t("div",{class:"arch-hint glass"},$("sparkle"),"Hover to trace \xB7 click for the exact lines \xB7 drag to pan"))),r),e.appendChild(t("p",{class:"faint sys-note",text:"Detected from package.json files, imports, route files and route definitions, queue names, cron schedules, URLs in the code and .env.example files."})),Ps(p),rt(),Rs(d),requestAnimationFrame(()=>{et(),s?(C.vb=s,nt()):C.fitted=Ge(!1)})}function Ae(e){ls.sel=e;let s=P("#sheet");s.innerHTML="";let a=t("div",{class:"drawer-b"}),o,n,i,p="",d=l=>t("div",{class:"ev"},l.map(c=>t("div",{class:"ev-row"},t("code",{text:`${c.file}:${c.line}`}),c.text?t("span",{class:"to",text:c.text}):null)));if(e.type==="app"){let l=pt.get(e.id);o=l.name,n=`${l.framework} app \xB7 ${l.root?`${l.root}/`:"repo root"}${l.pkgName&&l.pkgName!==l.name?` \xB7 package "${l.pkgName}"`:""}`,i=ht(l),a.append(t("div",{class:"kv-grid"},t("div",null,t("div",{class:"k",text:"Files"}),t("div",{class:"v",text:l.fileCount})),t("div",null,t("div",{class:"k",text:"Entry points"}),t("div",{class:"v",text:Qe.reduce((r,u)=>r+(l.groups[u.key]||[]).filter(m=>m.status!=="removed").length,0)})),t("div",null,t("div",{class:"k",text:"Modules"}),t("div",{class:"v",text:(l.modules||[]).length}))));let c=re.links.filter(r=>(r.from===l.id||r.to===l.id)&&ns(r));c.length&&a.append(t("div",null,t("div",{class:"sec-t",text:"Connections"}),t("div",{class:"pill-list"},c.map(r=>{let u=r.from===l.id?r.to:r.from,m=Pt.get(u);return t("button",{class:"pill-item",on:{click:()=>m?Ae({type:"svc",id:u}):pt.has(u)?Ae({type:"app",id:u}):null}},$(m?re.stores.includes(m)?Nt(m):"cloud":u==="users"?"users":"server","faint"),t("span",{class:"grow",text:`${r.from===l.id?"\u2192 ":"\u2190 "}${m?m.name:os(u)}`}),E.view==="diff"&&r.status!=="same"?he(r.status):null,t("span",{class:"faint",style:{fontSize:"12px"},text:r.labels[0]||""}))})))),l.tech.length&&a.append(t("div",null,t("div",{class:"sec-t",text:"Notable tech"}),t("div",{class:"sys-tech",style:{padding:0}},l.tech.map(r=>t("span",{class:"chip",text:r})))));for(let r of Qe){let u=(l.groups[r.key]||[]).filter(ns);u.length&&a.append(t("div",null,t("div",{class:"sec-t",text:`${r.title} \xB7 ${u.length}`}),t("div",{class:"pill-list"},u.map(m=>t("button",{class:"pill-item",title:`${m.file}:${m.line}`,on:{click:()=>Ae({type:"item",app:l.id,group:r.key,key:m.key})}},m.methods&&m.methods.length?m.methods.map(g=>t("span",{class:`meth m-${g.toLowerCase()}`,text:g})):$(r.icon,"faint"),t("span",{class:"grow mono-s",text:m.label}),m.human?t("span",{class:"faint",style:{fontSize:"12px"},text:m.human}):null,E.view==="diff"&&M&&m.status!=="same"?he(m.status):null)))))}}else if(e.type==="svc"){let l=Pt.get(e.id),c=re.stores.includes(l);o=l.name,n=`${l.kind}${l.via&&l.via.length?` \xB7 via ${l.via.join(", ")}`:""}`,i=c?Nt(l):l.kind==="Email"?"mail":"cloud",l.kind==="Set by env var"&&a.append(t("div",{class:"muted",text:`The address comes from ${l.via.join(", ")} at run time, so only its name is known. Check .env.example or your deploy settings for where it points.`})),l.status&&l.status!=="same"&&M&&a.append(t("div",null,he(l.status))),a.append(t("div",null,t("div",{class:"sec-t",text:"Used by"}),t("div",{class:"pill-list"},l.apps.map(r=>t("button",{class:"pill-item",on:{click:()=>Ae({type:"app",id:r})}},t("i",{class:"dot",style:{background:Rt(r)}}),t("span",{class:"grow",text:os(r)}),t("span",{class:"faint",style:{fontSize:"12px"},text:(pt.get(r)||{}).framework||""})))))),"hosts"in l&&l.hosts.length&&a.append(t("div",null,t("div",{class:"sec-t",text:"Hosts"}),t("div",{class:"file-list"},l.hosts.map(r=>t("div",{class:E.view==="diff"?r.status==="added"?"plus":r.status==="removed"?"minus":"":"",text:r.host}))))),a.append(t("div",null,t("div",{class:"sec-t",text:`Where the code uses it \xB7 ${l.evidence.length}${l.evidence.length>=25?"+":""}`}),d(l.evidence)))}else{let l=pt.get(e.app),c=Qe.find(g=>g.key===e.group),r=l.groups[e.group].find(g=>g.key===e.key);o=`${r.methods&&r.methods.length?`${r.methods.join(" / ")} `:""}${r.label}`,n=`${c.title.replace(/s$/,"")} in ${l.name}`,i=c.icon,r.status&&r.status!=="same"&&M&&a.append(t("div",null,he(r.status))),r.human&&a.append(t("div",{class:"callout info"},$("clock"),t("div",null,t("b",{text:`Runs ${r.human}`}),t("div",{class:"mono-s",text:r.label})))),a.append(t("div",null,t("div",{class:"sec-t",text:"Defined in"}),d([{file:r.file,line:r.line,text:r.cmd||null}])));let u=r.file,m=x.nodes.find(g=>g.files.some(f=>f.path===u));m&&a.append(t("button",{class:"btn",on:{click:()=>{_e(),ve({type:"node",id:m.id})}}},$("map"),`Show module \u201C${m.id}\u201D on the dependency map`))}s.append(t("div",{class:"drawer-h"},t("span",{class:`ico-box ${p}`},$(i)),t("div",{style:{minWidth:0}},t("h3",{text:o}),t("div",{class:"sub",text:n})),t("button",{class:"btn icon ghost","aria-label":"Close",style:{marginLeft:"auto"},on:{click:_e}},$("x"))),a),s.classList.add("open")}function _e(){let e=P("#sheet");e&&e.classList.remove("open"),ls.sel=null,U.file&&Be(null)}function Dt(){let e=P("#view-tabs");e&&e._set(E.view),Ye(),oe(".sys-tabs").forEach(s=>s._set&&s._set(E.view)),C.svg?rt():ct(),E.page==="module"&&kt(U.id)}function ds(){if(!re.apps.length)return null;let e=re.summary,s=t("div",{class:"glance"});re.hasUsers&&s.append(t("div",{class:"g-node users"},$("users"),"Users"),t("span",{class:"g-arrow"},$("arrowRight"))),Cs().forEach((o,n,i)=>{let p=Qe.map(d=>[d,(o.groups[d.key]||[]).filter(l=>l.status!=="removed").length]).filter(([,d])=>d);s.append(t("button",{class:"g-node g-app",style:{"--app":Rt(o.id)},on:{click:()=>{se("system"),setTimeout(()=>Ae({type:"app",id:o.id}),60)}}},t("span",{class:"ico-box app-ico"},$(ht(o))),t("span",null,t("b",{text:o.name}),t("span",{class:"faint",text:`${o.framework}${p.length?` \xB7 ${p.map(([d,l])=>`${l} ${d.title.toLowerCase().replace("routes & api","routes").replace("http endpoints","endpoints").replace("jobs & scripts","jobs").replace("schedules",l===1?"schedule":"schedules")}`).join(" \xB7 ")}`:""}`})))),n<i.length-1&&s.append(t("span",{class:"g-arrow"},$("arrowRight")))});let a=t("div",{class:"g-tail"},re.stores.filter(o=>o.status!=="removed").map(o=>t("span",{class:"chip"},$(Nt(o)),o.name)),t("span",{class:"chip"},$("cloud"),ee(e.outside.total,"outside service")),M&&e.outside.added?t("span",{class:"chip add",text:`+${e.outside.added} new ${e.outside.added===1?"service":"services"}`}):null,M&&e.entry.added?t("span",{class:"chip add",text:`+${e.entry.added} entry points`}):null);return t("div",{class:"card",style:{marginTop:"14px"}},t("div",{class:"card-h"},t("h3",{text:"Architecture"}),t("div",{class:"right"},t("button",{class:"link-btn",on:{click:()=>se("system")}},"Open diagram",$("right")))),t("div",{class:"card-b"},s,a))}var U={id:null,file:null,pending:null,onlyTouched:!1,els:null,rows:new Map,refresh:null},rs=250;function Me(e,s){U.pending=s||null;let a=`module:${encodeURIComponent(e)}`;location.hash!==`#${a}`?location.hash=a:st(a)}function Fs(e){if(!e.length)return"";let s=e[0].split("/").slice(0,-1);for(let a of e){let o=a.split("/"),n=0;for(;n<s.length&&n<o.length-1&&s[n]===o[n];)n++;s=s.slice(0,n)}return s.join("/")}var js=e=>e.from.module!==e.to.module?`${e.from.module}\u2192${e.to.module}`:null,mt=e=>{let s=js(e);return s&&ie(e.status)&&ot().get(s)||null},Et=e=>ie(e.status)&&(!U.onlyTouched||Ve(e)!=="same");function Hs(e,s,a){let o=new Map,n=new Set,i=(r,u,m)=>{let g=`${r}\u2192${u}`;o.has(g)||o.set(g,{id:g,from:r,to:u,deps:[]}),o.get(g).deps.push(m)};for(let r of s){for(let u of r.out)u.to.module===e?i(r.path,u.to.path,u):(n.add(u.to.module),i(r.path,`mod:${u.to.module}`,u));for(let u of r.in)u.from.module!==e&&(n.add(u.from.module),i(`mod:${u.from.module}`,r.path,u))}let p=(r,u)=>r.length*7.3>=u.length*6.4?r:r.padEnd(Math.ceil(u.length*6.4/7.3)," "),d=s.map(r=>{let u=a(r),m=u.includes("/")?u.slice(0,u.lastIndexOf("/")+1):"";return{id:r.path,name:u.split("/").pop(),meta:m,file:r}});[...n].sort().forEach(r=>d.push({id:`mod:${r}`,name:r,meta:"module",mod:r})),d.forEach(r=>{r.label=p(r.name,r.meta)});let l=[...o.values()].map(r=>{let u=r.deps.map(g=>g.status),m=u.every(g=>g==="added")?"added":u.every(g=>g==="removed")?"removed":"same";return{...r,status:m,countBase:r.deps.filter(g=>g.status!=="added").length,countCur:r.deps.filter(g=>g.status!=="removed").length}}),c=ts(d.map(r=>({id:r.id,label:r.label,external:!!r.mod})),l);return{nodes:d,edges:l,lay:c}}function Ws(e){if(e.mod)return`<div class="tt">${ce(e.name)}</div><div class="kv"><span>Another module</span><b></b></div><div class="kv faint"><span>Click to open its files</span></div>`;let s=e.file,a=Ve(s);return`<div class="tt">${ce(e.name)}${M&&a!=="same"?` <span class="badge ${a==="added"?"add":a==="removed"?"rem":"acc"}">${a[0].toUpperCase()}${a.slice(1)}</span>`:""}</div><div class="kv"><span class="mono-s">${ce(s.path)}</span></div><div class="kv"><span>Imports</span><b>${s.out.filter(o=>ie(o.status)).length}</b></div><div class="kv"><span>Imported by</span><b>${s.in.filter(o=>ie(o.status)).length}</b></div>`}function Us(e){let s=e.status==="removed"?e.countBase:e.countCur,a=n=>n.startsWith("mod:")?n.slice(4):n.split("/").pop(),o=[...new Set(e.deps.flatMap(n=>(mt(n)||[]).map(i=>i.rule)))];return`<div class="tt">${ce(a(e.from))} <span class="faint">\u2192</span> ${ce(a(e.to))}</div><div class="kv"><span>Imports</span><b>${e.status==="same"&&e.countBase!==e.countCur?`${e.countBase} \u2192 ${e.countCur}`:s}</b></div>`+(M&&e.status!=="same"?`<div class="kv"><span>Status</span><b>${e.status==="added"?"New":"Removed"}</b></div>`:"")+o.map(n=>`<div class="kv" style="color:var(--viol-text)"><span>\u26A0 ${ce(n)}</span></div>`).join("")}function zs(e,s){e.innerHTML="";let a=28,o=s.lay.width+a*2,n=s.lay.height+a*2,i=v("svg",{class:"fmap-svg",width:o,height:n,viewBox:`${-a} ${-a} ${o} ${n}`,role:"group","aria-label":"Files in this module and what they import"}),p=v("defs");p.innerHTML='<filter id="fm-shadow" x="-20%" y="-30%" width="140%" height="170%"><feDropShadow dx="0" dy="1" stdDeviation="1.5" flood-color="#101018" flood-opacity=".08"/></filter>'+["line","add","rem","viol","accent"].map(r=>`<marker id="fm-arr-${r}" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="10" markerHeight="10" orient="auto-start-reverse" markerUnits="userSpaceOnUse"><path d="M1,1.5 L9,5 L1,8.5 Q2.5,5 1,1.5 z" style="fill: var(--${r})"/></marker>`).join(""),i.appendChild(p);let d=v("g"),l=v("g");i.append(d,l);let c={nodes:new Map,edges:new Map};return s.edges.forEach(r=>{let u=Ct(s.lay.routes[r.id]),m=v("path",{class:"line",d:u}),g=v("g",{class:"edge"},v("path",{class:"glow",d:u}),m,v("path",{class:"hit",d:u}));g.addEventListener("pointermove",f=>Le(f,Us(r))),g.addEventListener("pointerleave",me),d.appendChild(g),c.edges.set(r.id,{e:r,el:g,line:m})}),s.nodes.forEach(r=>{let u=s.lay.pos[r.id],m=v("g",{class:`node${r.mod?" external":""}`,transform:`translate(${u.x},${u.y})`,tabindex:0,role:"button","aria-label":r.mod?`Open module ${r.name}`:`File ${r.file.path}`}),g=(y,D,F)=>v("g",{class:`nbadge ${y}`,transform:`translate(${u.w-F-8},-8)`},v("rect",{width:F,height:15,rx:4}),v("text",{x:F/2,y:10.5,"text-anchor":"middle"},D));m.append(v("rect",{class:"card-r",width:u.w,height:u.h,rx:r.mod?u.h/2:10}),v("g",{class:"n-ico",transform:`translate(12,${(u.h-16)/2}) scale(0.667)`,html:r.mod?ke.box:ke.file}),v("text",{class:"n-name",x:36,y:r.meta?20:u.h/2+4.5},r.name),r.meta?v("text",{class:"n-meta",x:36,y:35},r.meta):null,g("b-add","NEW",34),g("b-rem","GONE",38)),r.file&&r.file.edited&&r.file.status==="same"&&m.appendChild(v("circle",{class:"tdot",cx:u.w-11,cy:u.h/2,r:3.5}));let f=()=>r.mod?Me(r.mod):Be(U.file===r.id?null:r.id);m.addEventListener("click",y=>{y.stopPropagation(),f()}),m.addEventListener("keydown",y=>{(y.key==="Enter"||y.key===" ")&&(y.preventDefault(),f())}),m.addEventListener("pointermove",y=>Le(y,Ws(r))),m.addEventListener("pointerleave",me),l.appendChild(m),c.nodes.set(r.id,{x:r,el:m})}),i.addEventListener("click",()=>Be(null)),e.appendChild(i),c}function cs(){let e=U.els;if(!e)return;let s=U.file,a=d=>{let l=e.nodes.get(d).x;return l.mod?!0:Et(l.file)},o=new Set,n=new Set;for(let{e:d}of e.edges.values())ie(d.status)&&a(d.from)&&a(d.to)&&(o.add(d.id),[d.from,d.to].forEach(l=>{l.startsWith("mod:")&&n.add(l)}));let i=s?new Set([...o].filter(d=>{let l=e.edges.get(d).e;return l.from===s||l.to===s})):null,p=s?new Set([s,...[...i].flatMap(d=>{let l=e.edges.get(d).e;return[l.from,l.to]})]):null;for(let{e:d,el:l,line:c}of e.edges.values()){let r=o.has(d.id),u=E.view==="diff"?d.status:"same",m=r&&!(E.view==="diff"&&d.status==="removed")&&d.deps.some(f=>mt(f)),g=i&&i.has(d.id);l.setAttribute("class",`edge ${u}${m?" viol":""}${g?" sel":""}${r?"":" gone"}${i&&!g?" dim":""}`),c.setAttribute("marker-end",`url(#fm-arr-${g?"accent":m?"viol":u==="added"?"add":u==="removed"?"rem":"line"})`)}for(let{x:d,el:l}of e.nodes.values()){let c=d.mod?n.has(d.id):Et(d.file),r=d.file&&E.view==="diff"&&M?Ve(d.file):"same",u=r==="edited"?"same touched":r;l.setAttribute("class",`node${d.mod?" external":""} ${u}${s===d.id?" sel":""}${c?"":" gone"}${p&&!p.has(d.id)?" dim":""}`)}}function Be(e){if(U.file=e&&je.has(e)?e:null,cs(),U.rows.forEach((s,a)=>s.classList.toggle("sel",a===U.file)),me(),U.file){Vs(je.get(U.file));let s=U.rows.get(U.file),a=U.els&&U.els.nodes.get(U.file);a?a.el.scrollIntoView({block:"nearest",inline:"center",behavior:$e?"auto":"smooth"}):s&&s.scrollIntoView({block:"nearest"})}else{let s=P("#sheet");s&&s.classList.remove("open")}}function Vs(e){let s=P("#sheet");s.innerHTML="";let a=Ve(e),o=e.out.filter(c=>ie(c.status)).sort((c,r)=>+(c.to.module===e.module)-+(r.to.module===e.module)||c.to.path.localeCompare(r.to.path)),n=e.in.filter(c=>ie(c.status)).sort((c,r)=>+(c.from.module===e.module)-+(r.from.module===e.module)||c.from.path.localeCompare(r.from.path)),i=(c,r)=>{let u=r==="out"?c.to:c.from,m=u.module===e.module,g=mt(c);return t("button",{class:"pill-item",title:u.path,on:{click:()=>m?Be(u.path):Me(u.module,u.path)}},$("file","faint"),t("span",{class:"grow mono-s ell",text:m?u.path.split("/").pop():u.path}),m?null:t("span",{class:`chip${g?" viol":""}`,text:u.module}),E.view==="diff"&&M&&c.status!=="same"?he(c.status):null,t("span",{class:"faint mono-s",title:r==="out"?`line ${c.line} of this file`:`line ${c.line} of ${u.path}`,text:`:${c.line}`}))},p=[...new Set(o.flatMap(c=>(mt(c)||[]).map(r=>r.rule)))],d=[...new Set(o.filter(c=>c.to.module!==e.module).map(c=>c.to.module))],l=t("div",{class:"drawer-b"});M&&a!=="same"&&l.append(t("div",null,he(a)," ",t("span",{class:"chip",text:`module ${e.module}`}))),p.forEach(c=>l.append(t("div",{class:"callout"},$("alert"),t("div",null,t("b",{text:`An import here breaks \u201C${c}\u201D`}),t("div",{text:"The rule-breaking imports are marked in orange below."}))))),l.append(t("div",{class:"kv-grid"},t("div",null,t("div",{class:"k",text:"Imports"}),t("div",{class:"v",text:o.length})),t("div",null,t("div",{class:"k",text:"Imported by"}),t("div",{class:"v",text:n.length})),t("div",null,t("div",{class:"k",text:"Other modules"}),t("div",{class:"v",text:d.length})))),o.length&&l.append(t("div",null,t("div",{class:"sec-t",text:`Imports \xB7 ${o.length}`}),t("div",{class:"pill-list"},o.map(c=>i(c,"out"))))),n.length&&l.append(t("div",null,t("div",{class:"sec-t",text:`Imported by \xB7 ${n.length}`}),t("div",{class:"pill-list"},n.map(c=>i(c,"in"))))),!o.length&&!n.length&&l.append(t("div",{class:"muted",text:"This file does not import other files in the analysed code, and nothing imports it."})),s.append(t("div",{class:"drawer-h"},t("span",{class:`ico-box ${a==="added"?"add":a==="removed"?"rem":""}`},$("file")),t("div",{style:{minWidth:0}},t("h3",{text:e.path.split("/").pop()}),t("div",{class:"sub mono-s ell",title:e.path,text:e.path})),t("button",{class:"btn icon ghost","aria-label":"Close",style:{marginLeft:"auto"},on:{click:()=>Be(null)}},$("x"))),l),s.classList.add("open")}function kt(e){let s=P("#page-module");s.innerHTML="";let a=Oe.get(e),o=U.id===e?U.file:null;U.id=e,U.els=null,U.rows=new Map;let n=Jt(e),i=Fs(n.map(_=>_.path)),p=_=>i?_.path.slice(i.length+1):_.path,d=Ee.get(e),l=n.filter(_=>Ve(_)!=="same").length,c=He([{value:"diff",label:"Changes",disabled:!M},{value:"base",label:"Before",disabled:!M},{value:"cur",label:"After"}],E.view,_=>{E.view=_,Dt()}),r=n.filter(_=>ie(_.status)).length;s.append(t("div",{class:"page-head"},t("div",{style:{minWidth:0}},t("button",{class:"link-btn back",on:{click:()=>se("modules")}},$("arrowLeft"),"All modules"),t("h1",{class:"ell",text:e,title:e}),t("p",{text:`${ee(r,"file")}${i?` in ${i}/`:""} \xB7 uses ${ee(d.uses,"module")} \xB7 used by ${ee(d.usedBy,"module")}`})),t("div",{class:"right"},c,t("button",{class:"btn",on:{click:()=>ve({type:"node",id:e})}},$("map"),t("span",{class:"lbl-t",text:"Show on map"})))));let u=[M&&a.status!=="same"?he(a.status):null,M&&l?t("span",{class:"chip acc"},$("pencil"),`${l} ${l===1?"file":"files"} edited in this change`):null,d.viol?t("span",{class:"chip viol"},$("alert"),ee(d.viol,"rule break")):null].filter(Boolean);u.length&&s.append(t("div",{class:"chip-row"},u));let m=M&&l?t("label",{class:"switch"},t("input",{type:"checkbox",checked:U.onlyTouched,on:{change:_=>{U.onlyTouched=_.target.checked,U.refresh()}}}),"Only changed files"):null,g=(_,w)=>t("span",null,v("svg",{viewBox:"0 0 22 8"},v("g",{class:`edge ${_}`},v("path",{class:"line",d:"M1,4 L21,4"}))),w),f=t("div",{class:"fmap",id:"fmap"});s.append(t("div",{class:"card fmap-card"},t("div",{class:"card-h"},t("h3",{text:"How the files connect"}),t("div",{class:"right fmap-legend"},g("same","import"),M?g("added","new"):null,M?g("removed","removed"):null,g("viol","breaks a rule"),M&&l?t("span",null,t("i",{class:"tdot-key"}),"edited"):null)),f)),n.length>rs?f.append(t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("layers")),t("h4",{text:`${ee(n.length,"file")} is too many to draw clearly`}),t("p",{text:`The diagram is drawn for modules with up to ${rs} files. The table below lists every file, or split the module with "depth" or "modules" in tecton.config.json.`}))):n.length?U.els=zs(f,Hs(e,n,p)):f.append(t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("file")),t("h4",{text:"No files"}),t("p",{text:"This module has no files in the analysed code."})));let y=t("tbody"),D=()=>{y.innerHTML="",U.rows=new Map;let _=n.filter(Et).sort((w,z)=>p(w).localeCompare(p(z)));_.length||y.appendChild(t("tr",null,t("td",{colspan:5,class:"faint",text:"No files to show in this view."}))),_.forEach(w=>{let z=w.out.filter(B=>ie(B.status)),b=z.filter(B=>B.to.module===e).length,S=[...new Set(z.filter(B=>B.to.module!==e).map(B=>B.to.module))].sort(),j=w.in.filter(B=>ie(B.status)&&B.from.module!==e).length,V=p(w),ae=V.includes("/")?V.slice(0,V.lastIndexOf("/")+1):"",W=Ve(w),X=t("tr",{class:`click${w.path===U.file?" sel":""}`,tabindex:0,on:{click:()=>Be(U.file===w.path?null:w.path),keydown:B=>{B.key==="Enter"&&Be(w.path)}}},t("td",null,t("div",{class:"cell-mod mono-s"},$("file","faint"),t("span",{class:"ell"},ae?t("span",{class:"faint",text:ae}):null,V.split("/").pop()))),t("td",null,M&&E.view==="diff"&&W!=="same"?he(W):t("span",{class:"faint",text:"\u2014"})),t("td",{class:"r num",text:b}),t("td",null,S.length?t("div",{class:"chip-row tight"},S.slice(0,4).map(B=>{let H=z.some(te=>te.to.module===B&&mt(te));return t("button",{class:`chip mod${H?" viol":""}`,title:H?`Breaks a rule. Open ${B}`:`Open ${B}`,on:{click:te=>{te.stopPropagation(),Me(B)}}},B)}),S.length>4?t("span",{class:"faint",text:`+${S.length-4}`}):null):t("span",{class:"faint",text:"\u2014"})),t("td",{class:"r num",text:j}));U.rows.set(w.path,X),y.appendChild(X)})},F=t("tr",null,t("th",{text:"File"}),t("th",{text:"Change"}),t("th",{class:"r",text:"Imports here"}),t("th",{text:"Uses other modules"}),t("th",{class:"r",text:"Used from outside"}));s.append(t("div",{class:"toolbar",style:{marginTop:"14px"}},t("h3",{class:"toolbar-t",text:"Files"}),m),t("div",{class:"card"},t("div",{class:"tbl-wrap"},t("table",null,t("thead",null,F),y)))),U.refresh=()=>{D(),cs(),U.file&&!Et(je.get(U.file))&&Be(null)},D(),U.file=null;let ne=U.pending||o;U.pending=null,Be(ne&&je.has(ne)&&je.get(ne).module===e?ne:null)}var O={built:!1,animated:!1,vb:{x:0,y:0,w:100,h:100},edgeEls:new Map,nodeEls:new Map};function Ct(e){let s=`M${e[0][0]},${e[0][1]}`;for(let a=1;a<e.length;a++){let o=e[a-1],n=e[a],i=(n[1]-o[1])/2;s+=` C${o[0]},${o[1]+i} ${n[0]},${n[1]-i} ${n[0]},${n[1]}`}return s}function Gs(e){let s=[e[0]];for(let d=1;d<e.length;d++){let l=e[d-1],c=e[d],r=(c[1]-l[1])/2,u=[l[0],l[1]+r],m=[c[0],c[1]-r];for(let g=1;g<=16;g++){let f=g/16,y=1-f;s.push([y*y*y*l[0]+3*y*y*f*u[0]+3*y*f*f*m[0]+f*f*f*c[0],y*y*y*l[1]+3*y*y*f*u[1]+3*y*f*f*m[1]+f*f*f*c[1]])}}let a=0,o=[0];for(let d=1;d<s.length;d++)a+=Math.hypot(s[d][0]-s[d-1][0],s[d][1]-s[d-1][1]),o.push(a);let n=a/2,i=o.findIndex(d=>d>=n);i<1&&(i=1);let p=(n-o[i-1])/(o[i]-o[i-1]||1);return{len:a,mid:[s[i-1][0]+(s[i][0]-s[i-1][0])*p,s[i-1][1]+(s[i][1]-s[i-1][1])*p]}}function ps(){let e=P("#page-map"),s=He([{value:"diff",label:"Changes",disabled:!M},{value:"base",label:"Before",disabled:!M},{value:"cur",label:"After"}],E.view,m=>{E.view=m,Ye()});s.id="view-tabs";let a=t("label",{class:"switch glass",style:{display:M?"":"none"},title:"Show only dependencies that were added, removed or break a rule"},t("input",{type:"checkbox",id:"focus-sw",on:{change:m=>{if(E.focusOnly=m.target.checked,E.focusOnly){E.touchedOnly=!1;let g=P("#touched-sw");g&&(g.checked=!1),E.view!=="diff"&&(E.view="diff",s._set("diff"))}Ye()}}}),"Only changes"),o=Ke?t("label",{class:"switch glass",title:"Show only the modules whose files this change edits, and what they connect to"},t("input",{type:"checkbox",id:"touched-sw",on:{change:m=>{E.touchedOnly=m.target.checked,E.touchedOnly&&(E.focusOnly=!1,P("#focus-sw").checked=!1),Ye()}}}),t("i",{class:"tdot-key","aria-hidden":"true"}),"Only touched"):null,n=(m,g)=>t("span",null,v("svg",{viewBox:"0 0 22 8"},v("g",{class:`edge ${m}`},v("path",{class:"line",d:"M1,4 L21,4"}))),g),i=t("div",{class:"legend-float glass"},n("same","Unchanged"),M?n("added","New"):null,M?n("removed","Removed"):null,n("viol","Breaks a rule")),p=t("div",{class:"pct",id:"zoom-pct",text:"100%"}),d=t("div",{class:"zoom glass"},t("button",{"aria-label":"Zoom in","data-tip":"Zoom in",on:{click:()=>Ht(1/1.3)}},$("plus")),t("button",{"aria-label":"Zoom out","data-tip":"Zoom out",on:{click:()=>Ht(1.3)}},$("minus")),t("button",{"aria-label":"Fit to screen","data-tip":"Fit to screen (F)",on:{click:()=>at(!0)}},$("fit")),t("button",{"aria-label":"Export SVG","data-tip":"Export as SVG",on:{click:Lt}},$("image")),p),l=t("div",{class:"minimap glass",id:"minimap"}),c=v("svg",{id:"map-svg",role:"img","aria-label":"Module dependency map"}),r=t("div",{id:"stage"},c),u=t("aside",{class:"drawer",id:"drawer","aria-label":"Details"});e.append(t("div",{class:"card map-card"},r,t("div",{class:"float tl"},t("div",{class:"glass",style:{padding:"0",borderRadius:"11px"}},s),a,o,i),t("div",{class:"float br"},d),t("div",{class:"float bl"},l),u)),_s(c),Ks(l),Zs(r)}function _s(e){let s=v("defs");s.innerHTML='<filter id="nshadow" x="-20%" y="-30%" width="140%" height="170%"><feDropShadow dx="0" dy="1" stdDeviation="1.5" flood-color="#101018" flood-opacity=".08"/></filter><pattern id="dots" width="18" height="18" patternUnits="userSpaceOnUse"><circle cx="1" cy="1" r="1" style="fill: var(--dot)"/></pattern>',["line","add","rem","viol","accent"].forEach(d=>{let l=v("marker",{id:`arr-${d}`,viewBox:"0 0 10 10",refX:9,refY:5,markerWidth:10,markerHeight:10,orient:"auto-start-reverse",markerUnits:"userSpaceOnUse"});l.appendChild(v("path",{d:"M1,1.5 L9,5 L1,8.5 Q2.5,5 1,1.5 z",style:`fill: var(--${d})`})),s.appendChild(l)}),e.appendChild(s),e.appendChild(v("rect",{x:-2e4,y:-2e4,width:4e4,height:4e4,fill:"url(#dots)"}));let a=v("g",{id:"world"}),o=v("g"),n=v("g"),i=v("g");a.append(o,n,i),e.appendChild(a);let p=Math.max(1,x.height);x.edges.forEach((d,l)=>{let c=Ct(d.points),{len:r,mid:u}=Gs(d.points),m=v("g",{class:"edge",style:`--len:${Math.ceil(r)};--d:${d.points[0][1]/p*.6+.15}s`});m.appendChild(v("path",{class:"glow",d:c}));let g=v("path",{class:"line",d:c,id:`ep${l}`});if(m.appendChild(g),m.appendChild(v("path",{class:"hit",d:c})),(d.status==="added"||Ie.cur.has(d.id))&&!$e){let w=v("circle",{class:"flow",r:2.6}),z=v("animateMotion",{dur:`${Math.max(1.6,r/70).toFixed(2)}s`,repeatCount:"indefinite",rotate:"auto"});z.appendChild(v("mpath",{href:`#ep${l}`})),w.appendChild(z),m.appendChild(w)}o.appendChild(m);let y=v("g",{class:"edge"}),D=v("g",{class:"lbl",transform:`translate(${u[0].toFixed(1)},${u[1].toFixed(1)})`}),F=v("rect",{rx:8,height:16,y:-8}),ne=v("text",{"text-anchor":"middle","dominant-baseline":"central",y:.5});D.append(F,ne),y.appendChild(D),i.appendChild(y);let _=w=>{O.dragMoved||(w.stopPropagation(),Te({type:"edge",id:d.id}))};[m,y].forEach(w=>{w.addEventListener("click",_),w.addEventListener("pointermove",z=>{O.drag||Le(z,Qs(d))}),w.addEventListener("pointerleave",me)}),y.style.cursor="pointer",O.edgeEls.set(d.id,{g:m,line:g,lbl:y,lr:F,lt:ne})}),x.nodes.forEach((d,l)=>{let c=d.pos,r=v("g",{class:`node${d.external?" external":""}`,transform:`translate(${c.x},${c.y})`,tabindex:0,role:"button","aria-label":d.id}),u=v("g",{style:`--d:${c.y/p*.5+l%5*.03}s`});u.appendChild(v("rect",{class:"card-r",width:c.w,height:c.h,rx:d.external?c.h/2:10}));let m=v("g",{class:"n-ico",transform:`translate(12,${(c.h-16)/2}) scale(0.667)`,html:d.external?ke.pkg:ke.box});u.appendChild(m),u.appendChild(v("text",{class:"n-name",x:36,y:20},Y(d.id)));let g=v("text",{class:"n-meta",x:36,y:35});u.appendChild(g);let f=(y,D,F)=>v("g",{class:`nbadge ${y}`,transform:`translate(${c.w-F-8},-8)`},v("rect",{width:F,height:15,rx:4}),v("text",{x:F/2,y:10.5,"text-anchor":"middle"},D));u.appendChild(f("b-add","NEW",34)),u.appendChild(f("b-rem","GONE",38)),d.touched&&u.appendChild(v("circle",{class:"tdot",cx:c.w-11,cy:c.h/2,r:3.5})),r.appendChild(u),r.addEventListener("click",y=>{O.dragMoved||(y.stopPropagation(),Te({type:"node",id:d.id}))}),d.external||r.addEventListener("dblclick",y=>{y.stopPropagation(),Me(d.id)}),r.addEventListener("keydown",y=>{(y.key==="Enter"||y.key===" ")&&(y.preventDefault(),Te({type:"node",id:d.id}))}),r.addEventListener("pointermove",y=>{O.drag||Le(y,qs(d))}),r.addEventListener("pointerleave",me),n.appendChild(r),O.nodeEls.set(d.id,{g:r,inner:u,meta:g})}),e.addEventListener("click",()=>{!O.dragMoved&&E.selected&&Te(null)}),O.world=a,O.svg=e,O.built=!0,Ye()}function ie(e){return E.view==="diff"?!0:E.view==="base"?e!=="added":e!=="removed"}var ot=()=>E.view==="base"?Ie.base:Ie.cur;function Ye(){if(!O.built)return;let e=ot(),s=E.selected,a=null,o=null;if(s)if(a=new Set,o=new Set,s.type==="node")a.add(s.id),x.edges.forEach(i=>{(i.from===s.id||i.to===s.id)&&ie(i.status)&&(o.add(i.id),a.add(i.from),a.add(i.to))});else if(s.type==="edge"){let i=Ue.get(s.id);o.add(i.id),a.add(i.from),a.add(i.to)}else lt.get(s.id).edges.forEach(i=>{let p=Ue.get(i);p&&(o.add(i),a.add(p.from),a.add(p.to))});else E.focusOnly&&E.view==="diff"?(a=new Set,o=new Set,x.edges.forEach(i=>{(Ot(i)||e.has(i.id))&&(o.add(i.id),a.add(i.from),a.add(i.to))}),x.nodes.forEach(i=>{i.status!=="same"&&a.add(i.id)})):E.touchedOnly&&(a=new Set(dt),o=new Set,x.edges.forEach(i=>{ie(i.status)&&(dt.has(i.from)||dt.has(i.to))&&(o.add(i.id),a.add(i.from),a.add(i.to))}));let n=new Set;x.edges.forEach(i=>{let p=O.edgeEls.get(i.id),d=ie(i.status),l=E.view==="diff"?i.status:"same",c=e.has(i.id)&&d&&!(E.view==="diff"&&i.status==="removed");c&&(n.add(i.from),n.add(i.to));let r=s&&s.type==="edge"&&s.id===i.id,u=p.g.classList.contains("draw-in")?" draw-in":"",m=`edge ${l}${c?" viol":""}${r?" sel":""}${d?"":" gone"}${o&&!o.has(i.id)?" dim":""}`;p.g.setAttribute("class",m+u),p.lbl.setAttribute("class",m);let g=r?"accent":c?"viol":l==="added"?"add":l==="removed"?"rem":"line";p.line.setAttribute("marker-end",`url(#arr-${g})`);let f;E.view==="diff"?i.status==="added"?f=`+${i.countCur}`:i.status==="removed"?f=`\u2212${i.countBase}`:f=i.countBase===i.countCur?String(i.countCur):`${i.countBase}\u2192${i.countCur}`:f=String(E.view==="base"?i.countBase:i.countCur),c&&(f=`\u26A0 ${f}`),p.lt.textContent=f;let y=Math.max(20,f.length*6.3+12);p.lr.setAttribute("width",y),p.lr.setAttribute("x",-y/2)}),x.nodes.forEach(i=>{let p=O.nodeEls.get(i.id),d=ie(i.status),l=E.view==="diff"?i.status:"same",c=s&&s.type==="node"&&s.id===i.id;p.g.setAttribute("class",`node${i.external?" external":""} ${l}${n.has(i.id)?" inviol":""}${c?" sel":""}${d?"":" gone"}${a&&!a.has(i.id)?" dim":""}${i.touched&&E.view==="diff"?" touched":""}`);let r=E.view==="base"?i.filesBase:E.view==="cur"?i.filesCur:i.status==="removed"?i.filesBase:i.filesCur;p.meta.textContent=i.external?"npm package":E.view==="diff"&&i.status==="same"&&i.filesBase!==i.filesCur?`${i.filesBase} \u2192 ${i.filesCur} files`:ee(r,"file")}),ea(n),Ys()}function qs(e){let s=Ee.get(e.id);return`<div class="tt">${ce(Y(e.id))}${e.status!=="same"&&M?` <span class="badge ${e.status==="added"?"add":"rem"}">${e.status==="added"?"New":"Removed"}</span>`:""}</div>${e.external?'<div class="kv"><span>npm package</span><b></b></div>':`<div class="kv"><span>Files</span><b>${M&&e.filesBase!==e.filesCur?`${e.filesBase} \u2192 ${e.filesCur}`:e.status==="removed"?e.filesBase:e.filesCur}</b></div>`}<div class="kv"><span>Uses</span><b>${s.uses}</b></div><div class="kv"><span>Used by</span><b>${s.usedBy}</b></div>`+(e.touched&&M?`<div class="kv"><span>Files edited</span><b style="color:var(--accent-text)">${e.touched}</b></div>`:"")+(e.external?"":'<div class="kv faint"><span>Double-click to open its files</span></div>')+(s.viol?`<div class="kv"><span>Rule breaks</span><b style="color:var(--viol-text)">${s.viol}</b></div>`:"")}function Qs(e){let s=ot().get(e.id)||[],a=e.status==="removed"?e.countBase:e.countCur;return`<div class="tt">${ce(Y(e.from))} <span class="faint">\u2192</span> ${ce(Y(e.to))}</div><div class="kv"><span>Imports</span><b>${e.status==="same"&&e.countBase!==e.countCur?`${e.countBase} \u2192 ${e.countCur}`:a}</b></div>`+(M?`<div class="kv"><span>Status</span><b>${e.status==="added"?"New":e.status==="removed"?"Removed":"Unchanged"}</b></div>`:"")+s.map(o=>`<div class="kv" style="color:var(--viol-text)"><span>\u26A0 ${ce(o.rule)}</span></div>`).join("")}function Ys(){let e=P("#drawer");if(!e)return;let s=E.selected;if(!s){e.classList.remove("open");return}e.innerHTML="";let a=t("button",{class:"btn icon ghost","aria-label":"Close details",style:{marginLeft:"auto"},on:{click:()=>Te(null)}},$("x")),o=t("div",{class:"drawer-b"}),n;if(s.type==="node"){let i=Oe.get(s.id),p=Ee.get(i.id);n=t("div",{class:"drawer-h"},t("span",{class:`ico-box ${i.status==="added"&&M?"add":i.status==="removed"?"rem":""}`},$(i.external?"pkg":"box")),t("div",{style:{minWidth:0}},t("h3",{text:Y(i.id)}),t("div",{class:"sub"},i.external?"npm package":`${M?{added:"New module",removed:"Removed module",same:"Module"}[i.status]:"Module"} \xB7 ${ee(i.status==="removed"?i.filesBase:i.filesCur,"file")}`)),a),o.append(t("div",{class:"kv-grid"},t("div",null,t("div",{class:"k",text:"Uses"}),t("div",{class:"v",text:p.uses})),t("div",null,t("div",{class:"k",text:"Used by"}),t("div",{class:"v",text:p.usedBy})),t("div",null,t("div",{class:"k",text:"Rule breaks"}),t("div",{class:"v",style:p.viol?{color:"var(--viol-text)"}:null,text:p.viol})))),i.external||o.append(t("button",{class:"btn",on:{click:()=>Me(i.id)}},$("file"),"Open files and how they connect",i.touched&&M?t("span",{class:"chip acc",text:`${i.touched} edited`}):null));let d=x.edges.filter(c=>c.from===i.id&&ie(c.status)),l=x.edges.filter(c=>c.to===i.id&&ie(c.status));if([["Uses",d,"to"],["Used by",l,"from"]].forEach(([c,r,u])=>{r.length&&o.append(t("div",null,t("div",{class:"sec-t",text:`${c} \xB7 ${r.length}`}),t("div",{class:"pill-list"},r.map(m=>{let g=ot().get(m.id);return t("button",{class:"pill-item",on:{click:()=>Te({type:"edge",id:m.id})}},$(m[u].startsWith("npm:")?"pkg":"box","faint"),t("span",{class:"grow",text:Y(m[u])}),g?de("serious","Rule"):null,E.view==="diff"&&m.status!=="same"?he(m.status):null,t("span",{class:"faint num mono",style:{fontSize:"11.5px"},text:String(m.status==="removed"?m.countBase:m.countCur)}))}))))}),i.files.length){let c=i.files.filter(r=>!(E.view==="base"&&r.status==="added")&&!(E.view==="cur"&&r.status==="removed"));o.append(t("div",null,t("div",{class:"sec-t",text:`Files \xB7 ${c.length}`}),t("div",{class:"file-list"},c.slice(0,300).map(r=>{let u=E.view==="diff"&&r.status==="same"&&(je.get(r.path)||{}).edited,m=E.view==="diff"?r.status==="added"?"plus":r.status==="removed"?"minus":u?"edit":"":"";return t("div",{class:`${m} click`,role:"button",tabindex:0,title:"Open this file",on:{click:()=>Me(i.id,r.path),keydown:g=>{g.key==="Enter"&&Me(i.id,r.path)}},text:`${E.view==="diff"&&r.status==="added"?"+ ":E.view==="diff"&&r.status==="removed"?"\u2212 ":u?"~ ":""}${r.path}`})}))))}}else if(s.type==="edge"){let i=Ue.get(s.id),p=ot().get(i.id)||[];n=t("div",{class:"drawer-h"},t("span",{class:`ico-box ${p.length?"viol":i.status==="added"?"add":i.status==="removed"?"rem":""}`},$(p.length?"alert":"link")),t("div",{style:{minWidth:0}},t("h3",null,Y(i.from),t("span",{class:"arrow",text:" \u2192 "}),Y(i.to)),t("div",{class:"sub",text:`${M?{added:"New dependency",removed:"Removed dependency",same:"Dependency"}[i.status]:"Dependency"} \xB7 ${i.status==="same"&&i.countBase!==i.countCur?`imports ${i.countBase} \u2192 ${i.countCur}`:ee(i.status==="removed"?i.countBase:i.countCur,"import")}`})),a),p.forEach(d=>o.append(t("div",{class:"callout"},$("alert"),t("div",null,t("b",{text:`Breaks \u201C${d.rule}\u201D`}),d.message?t("div",{text:d.message}):null)))),o.append(t("div",{class:"pill-list"},[i.from,i.to].map(d=>t("button",{class:"pill-item",on:{click:()=>Te({type:"node",id:d})}},$(d.startsWith("npm:")?"pkg":"box","faint"),t("span",{class:"grow",text:Y(d)}),t("span",{class:"faint",style:{fontSize:"12px"},text:d===i.from?"imports":"is imported"}))))),i.addedImports&&i.addedImports.length&&o.append(t("div",null,t("div",{class:"sec-t",text:"Added in this change"}),tt(i.addedImports,"plus"))),o.append(t("div",null,t("div",{class:"sec-t",text:i.status==="removed"?"Where it used to happen":"Where it happens"}),tt(i.imports)))}else{let i=lt.get(s.id);n=t("div",{class:"drawer-h"},t("span",{class:"ico-box viol"},$(i.kind==="cycle"?"cycle":"alert")),t("div",{style:{minWidth:0}},t("h3",{text:i.rule}),t("div",{class:"sub",text:i.status==="new"?"New in this change":i.status==="fixed"?"Fixed by this change":M?"Already existed before this change":"Found in the current code"})),a),o.append(t("div",null,$t(i)," ",de(i.severity==="error"?"critical":"warn",i.severity==="error"?"Error":"Warning"))),i.message&&o.append(t("div",{class:"callout"},$("alert"),i.message)),o.append(t("div",{class:"muted",text:i.kind==="cycle"?`These modules depend on each other in a loop: ${i.members.map(Y).join(" \u21C4 ")}`:`${Y(i.from)} is not allowed to use ${Y(i.to)}.`})),o.append(t("div",null,t("div",{class:"sec-t",text:"Where it happens"}),tt(i.imports)))}e.append(n,o),e.classList.add("open")}function Te(e,s){E.selected=e&&E.selected&&E.selected.type===e.type&&E.selected.id===e.id&&!s?null:e;let a=E.selected;if(a&&M){let o=a.type==="node"?Oe.get(a.id):a.type==="edge"?Ue.get(a.id):null,n=a.type==="viol"?lt.get(a.id):null;E.view==="cur"&&(o&&o.status==="removed"||n&&n.status==="fixed")&&(E.view="diff"),E.view==="base"&&(o&&o.status==="added"||n&&n.status==="new")&&(E.view="diff");let i=P("#view-tabs");i&&i._set(E.view)}me(),Ye(),a&&s&&Xs()}function ve(e){se("map"),setTimeout(()=>Te(e,!0),30)}function ft(){let e=O.vb;O.svg.setAttribute("viewBox",`${e.x} ${e.y} ${e.w} ${e.h}`);let s=P("#stage").getBoundingClientRect(),a=P("#zoom-pct");a&&s.width&&(a.textContent=`${Math.round(s.width/e.w*100)}%`),Js()}function St(){return P("#stage").getBoundingClientRect()}function us(e,s,a,o,n,i){let p=St(),d=Math.max(1,p.width),l=Math.max(1,p.height),c=E.selected&&P("#drawer").classList.contains("open")&&d>700?Math.min(400,d):0,r=64,u=a-e+n*2,m=o-s+n*2+r,g=Math.max(u/(d-c),m/l,.55),f={w:d*g,h:l*g};f.x=(e+a)/2-(d-c)*g/2,f.y=(s+o)/2-f.h/2-r/2*g,hs(f,i)}var jt=null;function hs(e,s){if(cancelAnimationFrame(jt),!s||$e){Object.assign(O.vb,e),ft();return}let a={...O.vb},o=performance.now(),n=i=>{let p=Math.min(1,(i-o)/420),d=1-(1-p)**3;["x","y","w","h"].forEach(l=>{O.vb[l]=a[l]+(e[l]-a[l])*d}),ft(),p<1&&(jt=requestAnimationFrame(n))};jt=requestAnimationFrame(n)}function at(e){us(0,-10,x.width,x.height,48,e)}function Xs(){let e=E.selected;if(!e)return;let s=[];if(e.type==="node")s=[e.id],x.edges.forEach(p=>{(p.from===e.id||p.to===e.id)&&ie(p.status)&&s.push(p.from,p.to)});else if(e.type==="edge"){let p=Ue.get(e.id);s=[p.from,p.to]}else lt.get(e.id).edges.forEach(p=>{let d=Ue.get(p);d&&s.push(d.from,d.to)});let a=1/0,o=1/0,n=-1/0,i=-1/0;s.forEach(p=>{let d=Oe.get(p).pos;a=Math.min(a,d.x),o=Math.min(o,d.y),n=Math.max(n,d.x+d.w),i=Math.max(i,d.y+d.h)}),us(a,o,n,i,90,!0)}function Ht(e,s,a){let o=St();s==null&&(s=o.width/2,a=o.height/2);let n=O.vb,i=n.x+s/o.width*n.w,p=n.y+a/o.height*n.h,l=Math.min(Math.max(n.w*e,180),Math.max(x.width,x.height)*6+2400)/n.w;n.x=i-(i-n.x)*l,n.y=p-(p-n.y)*l,n.w*=l,n.h*=l,ft()}function Zs(e){e.addEventListener("wheel",s=>{s.preventDefault();let a=St();s.ctrlKey||Math.abs(s.deltaY)>Math.abs(s.deltaX)*1.2||s.deltaMode?Ht(Math.exp(s.deltaY*(s.ctrlKey?.01:.0016)),s.clientX-a.left,s.clientY-a.top):(O.vb.x+=s.deltaX*O.vb.w/a.width,O.vb.y+=s.deltaY*O.vb.h/a.height,ft())},{passive:!1}),e.addEventListener("pointerdown",s=>{s.button===0&&(O.drag={x:s.clientX,y:s.clientY,vx:O.vb.x,vy:O.vb.y},O.dragMoved=!1)}),window.addEventListener("pointermove",s=>{if(!O.drag)return;let a=s.clientX-O.drag.x,o=s.clientY-O.drag.y;if(!O.dragMoved&&Math.abs(a)+Math.abs(o)>4&&(O.dragMoved=!0,e.classList.add("dragging"),me()),!O.dragMoved)return;let n=St();O.vb.x=O.drag.vx-a*O.vb.w/n.width,O.vb.y=O.drag.vy-o*O.vb.h/n.height,ft()}),window.addEventListener("pointerup",()=>{O.drag=null,e.classList.remove("dragging"),setTimeout(()=>{O.dragMoved=!1},0)})}function Ks(e){let a=v("svg",{viewBox:`-20 -20 ${x.width+40} ${x.height+40}`,preserveAspectRatio:"xMidYMid meet"}),o=v("g");x.edges.forEach(d=>o.appendChild(v("path",{d:Ct(d.points),style:"fill:none;stroke:var(--border-strong);stroke-width:2","vector-effect":"non-scaling-stroke"}))),x.nodes.forEach(d=>{let l=v("rect",{class:"mn",x:d.pos.x,y:d.pos.y,width:d.pos.w,height:d.pos.h,rx:8,dataset:null});l.dataset.id=d.id,o.appendChild(l)});let n=v("rect",{class:"vp",rx:6});a.append(o,n),e.appendChild(a),O.mini={svg:a,vp:n,pad:20};let i=d=>{let l=a.getBoundingClientRect(),c=x.width+40,r=x.height+40,u=Math.max(c/l.width,r/l.height),m=(l.width*u-c)/2,g=(l.height*u-r)/2,f=(d.clientX-l.left)*u-m-20,y=(d.clientY-l.top)*u-g-20;hs({...O.vb,x:f-O.vb.w/2,y:y-O.vb.h/2},d.type==="click")},p=!1;e.addEventListener("pointerdown",d=>{d.stopPropagation(),p=!0,i(d)}),window.addEventListener("pointermove",d=>{p&&i(d)}),window.addEventListener("pointerup",()=>{p=!1})}function Js(){if(!O.mini)return;let e=O.vb,s=O.mini.vp;s.setAttribute("x",e.x),s.setAttribute("y",e.y),s.setAttribute("width",e.w),s.setAttribute("height",e.h)}function ea(e){O.mini&&oe("rect.mn",O.mini.svg).forEach(s=>{let a=Oe.get(s.dataset.id),o=E.view==="diff"?a.status:"same";s.setAttribute("class",`mn ${o}${e.has(a.id)?" inviol":""}`),s.style.opacity=ie(a.status)?"":"0"})}function as(){if(O.animated||$e){O.animated=!0;return}O.animated=!0,O.edgeEls.forEach(e=>e.g.classList.add("draw-in")),O.nodeEls.forEach(e=>e.inner.classList.add("pop-in")),oe(".lbl",O.world).forEach(e=>{e.style.opacity="0",e.style.transition="opacity .4s"}),setTimeout(()=>oe(".lbl",O.world).forEach(e=>{e.style.opacity=""}),900),setTimeout(()=>{O.edgeEls.forEach(e=>e.g.classList.remove("draw-in")),O.nodeEls.forEach(e=>e.inner.classList.remove("pop-in"))},1900)}function Ft(e,s,a,o){let n=e.cloneNode(!0);n.setAttribute("viewBox",`${s.x} ${s.y} ${s.w} ${s.h}`),n.setAttribute("width",Math.round(s.w)),n.setAttribute("height",Math.round(s.h)),n.setAttribute("xmlns",xt);let i=[e,...e.querySelectorAll("*")],p=[n,...n.querySelectorAll("*")],d=["fill","stroke","stroke-width","stroke-dasharray","stroke-linecap","opacity","font-family","font-size","font-weight","letter-spacing","display"],l=["gone",...o];i.forEach((u,m)=>{let g=getComputedStyle(u),f=p[m];if(u.classList&&l.some(y=>u.classList.contains(y))){f.setAttribute("data-drop","1");return}f.setAttribute("style",d.map(y=>`${y}:${g.getPropertyValue(y)}`).join(";")),f.removeAttribute("class")}),n.querySelectorAll("[data-drop]").forEach(u=>u.remove());let c=v("rect",{x:s.x,y:s.y,width:s.w,height:s.h,style:`fill:${getComputedStyle(document.body).backgroundColor}`});n.insertBefore(c,n.firstChild);let r=new Blob([`<?xml version="1.0" encoding="UTF-8"?>
3
- ${new XMLSerializer().serializeToString(n)}`],{type:"image/svg+xml"});Wt(r,a)}function Lt(){Ft(O.svg,{x:-32,y:-42,w:x.width+64,h:x.height+64+10},`${x.project}-dependency-map.svg`,["hit","flow"]),We("Map exported as SVG","download")}function Wt(e,s){let a=t("a",{href:URL.createObjectURL(e),download:s});document.body.appendChild(a),a.click(),a.remove(),setTimeout(()=>URL.revokeObjectURL(a.href),2e3)}function At(){let e=x.markdown||"",s=()=>We("PR summary copied as Markdown","copy");navigator.clipboard&&window.isSecureContext?navigator.clipboard.writeText(e).then(s,a):a();function a(){let o=t("textarea",{style:{position:"fixed",opacity:"0"}});o.value=e,document.body.appendChild(o),o.select();try{document.execCommand("copy"),s()}catch{We("Could not copy \u2014 use the JSON/Markdown output instead","alert")}o.remove()}}function ms(){let e=P("#page-overview"),s=be.newErrors+be.newWarnings,a=M?Ce?`This change breaks ${ee(be.newErrors,"architecture rule")}`:s?`No new errors, ${ee(be.newWarnings,"new warning")}`:"This change keeps the architecture clean":Ce?`${ee(Se.length,"rule break")} in this codebase`:"All architecture rules pass",o=M?Ce?"New dependencies cross boundaries your team set in tecton.config.json. CI will fail until they are removed or the rules are updated.":`Compared with ${Xe()}, nothing crosses a boundary you have set.${be.fixed?` It also fixes ${ee(be.fixed,"earlier rule break")}.`:""}`:"No git base was found, so this is a snapshot of the current code checked against your rules.",n=t("div",{class:`card hero ${Ce?"fail":"pass"}`},t("div",{class:"hero-icon"},$(Ce?"alert":"check")),t("div",null,t("h2",{text:a}),t("p",{text:o}),t("div",{class:"actions"},t("button",{class:"btn primary",on:{click:()=>se(Se.length?"rules":"map")}},$(Se.length?"shield":"map"),Se.length?"Review rule breaks":"Open the map"),t("button",{class:"btn",on:{click:()=>se("changes")}},$("compare"),"See all changes"))),t("div",{class:"big"},t("div",{class:"v num",dataset:{count:M?s:Se.length},text:"0"}),t("div",{class:"l",text:M?"new rule breaks":"rule breaks"}))),i=M?[Z.modules.added?t("span",{class:"chip add",text:`+${Z.modules.added} new`}):null,Z.modules.removed?t("span",{class:"chip rem",text:`\u2212${Z.modules.removed} gone`}):null]:[],p=M?[Z.deps.added?t("span",{class:"chip add",text:`+${Z.deps.added}`}):null,Z.deps.removed?t("span",{class:"chip rem",text:`\u2212${Z.deps.removed}`}):null,Z.deps.changed?t("span",{class:"chip chg",text:`${Z.deps.changed} changed`}):null]:[],d=[M&&Z.touched&&Z.touched.files?t("span",{class:"chip acc",text:`${Z.touched.files} edited`}):null,M&&Z.files.cur!==Z.files.base?t("span",{class:"chip",text:`${Z.files.cur-Z.files.base>0?"+":"\u2212"}${Math.abs(Z.files.cur-Z.files.base)} vs ${Xe()}`}):null],l=(w,z,b,S,j)=>t("div",{class:"card stat"},t("div",{class:"l"},$(z),w),t("div",{class:"v num",dataset:{count:b},text:"0"}),t("div",{class:"delta"},S.filter(Boolean).length?S:t("span",{class:"faint",text:j}))),c=t("div",{class:"grid stats stagger"},l("Modules","box",Z.modules.total,i,M?"No modules added or removed":"Current snapshot"),l("Dependencies","link",Z.deps.total,p,M?"No links changed":"Links between modules"),l("Rule breaks","shield",Se.length,[be.newErrors?t("span",{class:"chip viol",text:`${be.newErrors} new`}):null,be.existing?t("span",{class:"chip",text:`${be.existing} existing`}):null,be.fixed?t("span",{class:"chip add",text:`${be.fixed} fixed`}):null],`${xe.length} rules checked`),l("Files analysed","file",Z.files.cur,d,"JS / TS source files")),r=x.edges.filter(w=>w.status==="same"&&w.countBase===w.countCur).length,u=[{k:"Added",n:Z.deps.added,c:"var(--add)"},{k:"Removed",n:Z.deps.removed,c:"var(--rem)"},{k:"Import count changed",n:Z.deps.changed,c:"var(--chg)"},{k:"Unchanged",n:r,c:"var(--neutral-bar)"}],m=u.reduce((w,z)=>w+z.n,0)||1,g=t("div",{class:"card"},t("div",{class:"card-h"},t("h3",{text:"Dependency changes"}),t("div",{class:"right"},t("button",{class:"link-btn",on:{click:()=>se("changes")}},"View all",$("right")))),t("div",{class:"card-b",style:{paddingBottom:"6px"}},t("div",{class:"stackbar",role:"img","aria-label":u.map(w=>`${w.k}: ${w.n}`).join(", ")},u.filter(w=>w.n).map((w,z)=>t("span",{style:{width:`${w.n/m*100}%`,background:w.c,animationDelay:`${z*.08}s`},on:{pointermove:b=>Le(b,`<div class="tt">${ce(w.k)}</div><div class="kv"><span>Dependencies</span><b>${w.n}</b></div><div class="kv"><span>Share</span><b>${Math.round(w.n/m*100)}%</b></div>`),pointerleave:me}}))),t("div",{class:"legend-row"},u.map(w=>t("span",null,t("i",{class:"sw",style:{background:w.c}}),w.k,t("b",{class:"num",text:w.n}))))),t("div",{class:"list",style:{marginTop:"10px"}},Ne.length?Ne.slice(0,5).map(ta):t("div",{class:"card-b faint",text:M?"The structure did not change.":"No comparison available."}))),f=t("div",{class:"card"},t("div",{class:"card-h"},t("h3",{text:"Rule checks"}),t("div",{class:"right"},t("button",{class:"link-btn",on:{click:()=>se("rules")}},"Details",$("right")))),t("div",{class:"list",style:{marginTop:"12px"}},xe.length?xe.map(w=>t("button",{class:"row-btn",on:{click:()=>{se("rules"),gt(w.key)}}},t("span",{class:`ico-box ${w.state==="new"?"rem":w.state==="existing"?"viol":"good"}`},$(w.kind==="cycle"?"cycle":w.state==="pass"||w.state==="fixed"?"check":"alert")),t("span",{class:"main-t"},t("div",{class:"t1",text:w.key}),t("div",{class:"t2",text:Ut(w)})),wt(w.state))):t("div",{class:"card-b faint",text:'No rules yet. Run `tecton init` in your project to add some, like "components must not use db". Loops between modules are checked already.'}))),y=t("div",{class:"preview",id:"preview",role:"link",tabindex:0,"aria-label":"Open the architecture map",on:{click:()=>se("map"),keydown:w=>{w.key==="Enter"&&se("map")}}},t("button",{class:"btn open",tabindex:-1},"Open map",$("arrowRight"))),D=t("div",{class:"card"},t("div",{class:"card-h",style:{paddingBottom:"14px"}},t("h3",{text:"Architecture preview"}),t("div",{class:"right"},t("span",{class:"faint",style:{fontSize:"12.5px"},text:`${Z.modules.total} modules \xB7 ${Z.deps.total} links`}))),y),F=ze.slice().sort((w,z)=>Math.max(z.filesCur,z.filesBase)-Math.max(w.filesCur,w.filesBase)).slice(0,8),ne=Math.max(1,...F.map(w=>Math.max(w.filesCur,w.filesBase))),_=t("div",{class:"card"},t("div",{class:"card-h"},t("h3",{text:"Files per module"}),t("div",{class:"right"},t("button",{class:"link-btn",on:{click:()=>se("modules")}},"All modules",$("right")))),t("div",{class:"card-b"},t("div",{class:"bars"},F.map((w,z)=>{let b=w.status==="removed"?w.filesBase:w.filesCur;return t("div",{class:`bar-row ${w.status}`,on:{pointermove:S=>Le(S,`<div class="tt">${ce(w.id)}</div><div class="kv"><span>Files now</span><b>${w.filesCur}</b></div>${M?`<div class="kv"><span>Files before</span><b>${w.filesBase}</b></div>`:""}`),pointerleave:me}},t("span",{class:"n",text:w.id}),t("div",{class:"bar-track"},t("div",{class:"bar-fill",style:{width:`${Math.max(2,b/ne*100)}%`,animationDelay:`${z*.05}s`}})),t("span",{class:"num muted",style:{fontSize:"12.5px"},text:M&&w.filesBase!==w.filesCur?`${w.filesBase} \u2192 ${w.filesCur}`:String(b)}))}))));e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Overview"}),t("p",{text:M?`How ${x.curLabel} reshapes ${x.project} compared with ${Xe()}.`:`A snapshot of ${x.project}.`})),t("div",{class:"right"},t("button",{class:"btn",on:{click:()=>se("map")}},$("map"),"Open map"))),t("div",{class:"stagger"},n),c,ds(),t("div",{class:"grid two stagger",style:{marginTop:"14px"}},g,f),t("div",{class:"grid two stagger",style:{marginTop:"14px"}},D,_))}function ta(e){let s=e.edge,a=e.type==="node"?e.kind==="added"?"filePlus":"box":e.viol?"alert":"link",o=e.viol?"viol":e.kind==="added"?"add":e.kind==="removed"?"rem":"chg",n=e.type==="node"?`${e.kind==="added"?"New module":"Module removed"} \xB7 ${e.sub}`:s.status==="same"?`Imports ${s.countBase} \u2192 ${s.countCur}`:`${ee(s.status==="added"?s.countCur:s.countBase,"import")}${e.viol?" \xB7 breaks a rule":""}`;return t("button",{class:"row-btn",on:{click:()=>ve({type:e.type,id:e.id})}},t("span",{class:`ico-box ${o}`},$(a)),t("span",{class:"main-t"},t("div",{class:"t1",text:e.label}),t("div",{class:"t2",text:n})),he(e.kind),$("right","chev"))}function Ut(e){return Array.isArray(e.from)&&(e={...e,from:e.from.join(", ")}),e.kind==="cycle"?"No module may depend on itself through others":e.to?`${e.from} must not use ${e.to.map(Y).join(", ")}`:e.allow?e.allow.length?`${e.from} may only use ${e.allow.join(", ")}`:`${e.from} may not use other modules`:e.from||""}function fs(){let e=P("#page-rules"),s=xe.filter(n=>n.state==="new"||n.state==="existing").length;if(e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Rule checks"}),t("p",{text:`The boundaries set in tecton.config.json, checked against ${M?x.curLabel:"the current code"}.`})),t("div",{class:"right"},t("span",{class:"badge neutral plain",text:ee(xe.length,"rule")}),s?de("critical",`${s} failing`):null,de("good",`${xe.length-s} passing`)))),!xe.length){e.append(t("div",{class:"card"},t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("shield")),t("h4",{text:"No rules yet"}),t("p",null,"Run ",t("code",{text:"tecton init"})," to create a starter tecton.config.json, then describe which parts of the app may use which."))));return}let a=t("div",{class:"card",id:"rule-list"});xe.forEach(n=>{let i=t("div",{class:"rule-inner"},n.message?t("div",{class:"callout",style:{background:"var(--surface-2)",color:"var(--text-2)"}},$("sparkle"),n.message):null,n.viols.length?n.viols.map(d=>t("div",{class:"viol-card"},t("div",{class:"top"},$t(d),t("span",{text:d.kind==="cycle"?d.members.map(Y).join(" \u21C4 "):`${Y(d.from)} \u2192 ${Y(d.to)}`}),t("span",{class:"faint",style:{fontSize:"12.5px"},text:`\xB7 ${ee(d.count,d.kind==="cycle"?"link":"import")}`}),t("button",{class:"link-btn",style:{marginLeft:"auto"},on:{click:()=>ve({type:"viol",id:d.id})}},$("map"),"Show on map")),tt(d.imports.slice(0,8)),d.imports.length>8?t("div",{class:"faint",style:{fontSize:"12px",marginTop:"6px"},text:`+ ${d.imports.length-8} more`}):null)):t("div",{class:"faint",text:"Nothing breaks this rule."})),p=t("div",{class:"rule",dataset:{key:n.key}},t("button",{class:"rule-h","aria-expanded":"false",on:{click:d=>gs(d.currentTarget.parentNode)}},t("span",{class:`ico-box ${n.state==="new"?"rem":n.state==="existing"?"viol":"good"}`},$(n.kind==="cycle"?"cycle":n.state==="pass"||n.state==="fixed"?"check":"alert")),t("span",null,t("div",{class:"nm",text:n.key}),t("div",{class:"sub",text:n.severity==="error"?"Error \xB7 fails CI":"Warning \xB7 reported only"})),t("span",{class:"scope sub",text:Ut(n)}),t("span",{class:"cnt sub num",text:n.viols.length?ee(n.viols.filter(d=>d.status!=="fixed").length,"break"):"\u2014"}),wt(n.state),$("right","chev")),t("div",{class:"rule-body"},t("div",null,i)));a.appendChild(p)}),e.append(a);let o=xe.find(n=>n.state==="new")||xe.find(n=>n.state==="existing");o&&gt(o.key)}function gs(e,s){let a=s??!e.classList.contains("open");e.classList.toggle("open",a),P(".rule-h",e).setAttribute("aria-expanded",String(a))}function gt(e){let s=oe(".rule").find(a=>a.dataset.key===e);s&&(gs(s,!0),setTimeout(()=>s.scrollIntoView({behavior:$e?"auto":"smooth",block:"nearest"}),60))}var K={items:[],filtered:[],idx:0};function vs(){let e=[];Pe.forEach(s=>e.push({group:"Pages",label:s.title,icon:s.icon,run:()=>se(s.id)})),ze.forEach(s=>e.push({group:"Modules",label:s.id,hint:ee(s.status==="removed"?s.filesBase:s.filesCur,"file"),icon:"box",run:()=>ve({type:"node",id:s.id})})),x.edges.forEach(s=>e.push({group:"Dependencies",label:`${Y(s.from)} \u2192 ${Y(s.to)}`,hint:M&&s.status!=="same"?s.status==="added"?"new":"removed":ee(s.countCur||s.countBase,"import"),icon:"link",run:()=>ve({type:"edge",id:s.id})})),(x.system?x.system.apps:[]).forEach(s=>e.push({group:"Architecture",label:`${s.name} (${s.framework} app)`,icon:ht(s),run:()=>{se("system"),setTimeout(()=>Ae({type:"app",id:s.id}),60)}})),(x.system?[...x.system.stores,...x.system.outside]:[]).forEach(s=>e.push({group:"Architecture",label:s.name,hint:s.kind,icon:x.system.stores.includes(s)?"database":"cloud",run:()=>{se("system"),setTimeout(()=>Ae({type:"svc",id:s.id}),60)}})),Fe.slice(0,5e3).forEach(s=>e.push({group:"Files",label:s.path,hint:s.module,icon:"file",run:()=>Me(s.module,s.path)})),(x.system?x.system.apps:[]).forEach(s=>Qe.forEach(({key:a,icon:o})=>(s.groups[a]||[]).forEach(n=>e.push({group:"Entry points",label:`${n.methods&&n.methods.length?`${n.methods.join("/")} `:""}${n.label}`,hint:n.human?`${n.human} \xB7 ${s.name}`:s.name,icon:o,run:()=>{se("system"),setTimeout(()=>Ae({type:"item",app:s.id,group:a,key:n.key}),60)}})))),xe.forEach(s=>e.push({group:"Rules",label:s.key,hint:{new:"new break",existing:"failing",fixed:"fixed",pass:"passing"}[s.state],icon:"shield",run:()=>{se("rules"),setTimeout(()=>gt(s.key),50)}})),e.push({group:"Actions",label:"Copy PR summary (Markdown)",icon:"copy",run:At}),e.push({group:"Actions",label:"Export map as SVG",icon:"image",run:()=>{se("map"),setTimeout(Lt,80)}}),e.push({group:"Actions",label:"Download report data (JSON)",icon:"download",run:()=>{let{markdown:s,...a}=x;Wt(new Blob([JSON.stringify(a,null,2)],{type:"application/json"}),`${x.project}-tecton.json`),We("JSON downloaded","download")}}),e.push({group:"Actions",label:"Switch to light theme",icon:"sun",run:()=>Ze("light")}),e.push({group:"Actions",label:"Switch to dark theme",icon:"moon",run:()=>Ze("dark")}),e.push({group:"Actions",label:"Use system theme",icon:"monitor",run:()=>Ze("system")}),K.items=e}function sa(e,s){if(!s)return 1;let a=e.toLowerCase(),o=a.indexOf(s);if(o>=0)return 100-o;let n=0;for(let i of s){if(n=a.indexOf(i,n),n<0)return 0;n++}return 10}function yt(){let e=P("#palette-ov");e.innerHTML="";let s=t("input",{placeholder:"Search modules, files, rules, actions\u2026","aria-label":"Command palette search",autocomplete:"off"}),a=t("div",{class:"pal-list",role:"listbox"});e.append(t("div",{class:"palette",role:"dialog","aria-label":"Command palette"},t("div",{class:"pal-in"},$("search"),s,t("span",{class:"kbd",text:"Esc"})),a,t("div",{class:"pal-foot"},t("span",null,t("span",{class:"kbd",text:"\u2191\u2193"}),"navigate"),t("span",null,t("span",{class:"kbd",text:"\u21B5"}),"open"),t("span",null,t("span",{class:"kbd",text:"Esc"}),"close"))));let o=()=>{let p=s.value.trim().toLowerCase();K.filtered=K.items.map(c=>({it:c,sc:sa(`${c.label} ${c.group}`,p)})).filter(c=>c.sc>0).sort((c,r)=>p?r.sc-c.sc:0).map(c=>c.it),p||(K.filtered=K.items.filter(c=>c.group==="Pages"||c.group==="Actions"||c.group==="Rules"||c.group==="Architecture").concat(K.items.filter(c=>c.group==="Modules").slice(0,6)));let d=["Pages","Architecture","Rules","Modules","Files","Entry points","Dependencies","Actions"];if(K.filtered.sort((c,r)=>d.indexOf(c.group)-d.indexOf(r.group)),K.filtered=K.filtered.slice(0,60),K.idx=Math.min(K.idx,Math.max(0,K.filtered.length-1)),a.innerHTML="",!K.filtered.length){a.appendChild(t("div",{class:"pal-empty",text:"No results"}));return}let l=null;K.filtered.forEach((c,r)=>{c.group!==l&&(a.appendChild(t("div",{class:"pal-group",text:c.group})),l=c.group);let u=t("div",{class:`pal-item${r===K.idx?" on":""}`,role:"option","aria-selected":String(r===K.idx),on:{mousemove:()=>{K.idx!==r&&(K.idx=r,n())},click:()=>i(r)}},$(c.icon),t("span",{class:"grow",text:c.label}),c.hint?t("span",{class:"faint",style:{fontSize:"12px"},text:c.hint}):null,t("span",{class:"enter",text:"\u21B5"}));u.dataset.i=r,a.appendChild(u)})},n=()=>{oe(".pal-item",a).forEach(p=>{let d=Number(p.dataset.i)===K.idx;p.classList.toggle("on",d),p.setAttribute("aria-selected",String(d)),d&&p.scrollIntoView({block:"nearest"})})},i=p=>{let d=K.filtered[p];vt(),d&&d.run()};s.addEventListener("input",()=>{K.idx=0,o()}),s.addEventListener("keydown",p=>{p.key==="ArrowDown"&&(p.preventDefault(),K.idx=Math.min(K.filtered.length-1,K.idx+1),n()),p.key==="ArrowUp"&&(p.preventDefault(),K.idx=Math.max(0,K.idx-1),n()),p.key==="Enter"&&(p.preventDefault(),i(K.idx))}),e.onclick=p=>{p.target===e&&vt()},K.idx=0,o(),e.classList.add("open"),setTimeout(()=>s.focus(),10)}function vt(){P("#palette-ov").classList.remove("open")}function Ze(e){e==="light"||e==="dark"?document.documentElement.setAttribute("data-theme",e):document.documentElement.removeAttribute("data-theme"),It.set("theme",e),oe(".theme-seg button").forEach(s=>s.setAttribute("aria-pressed",String(s.dataset.mode===e)))}var ys=()=>It.get("theme")||"system";function We(e,s="check"){let a=t("div",{class:"toast",role:"status"},$(s),e);P("#toasts").appendChild(a),setTimeout(()=>{a.classList.add("out"),setTimeout(()=>a.remove(),260)},2600)}function aa(e){return e==="rules"?Se.length?t("span",{class:`count${Ce?" bad":""}`},Se.length):null:e==="changes"?M?t("span",{class:"count"},Ne.length):null:e==="system"?x.system&&M&&x.system.summary.entry.added+x.system.summary.outside.added+x.system.summary.stores.added+x.system.summary.apps.added?t("span",{class:"count",text:"new"}):null:e==="modules"?t("span",{class:"count"},ze.filter(s=>s.status!=="removed").length):null}function bs(){let e=P("#sidebar"),s=x.project.replace(/[^A-Za-z0-9]/g,"").slice(0,2).toUpperCase()||"AD";e.append(t("div",{class:"logo"},t("div",{class:"logo-mark","aria-hidden":"true"},v("svg",{viewBox:"0 0 64 64",html:qt})),t("b",{text:"tecton"}),t("span",{class:"ver",text:`v${x.version||"0"}`})),t("div",{class:"project"},t("div",{class:"name"},t("span",{class:"avatar",text:s}),t("span",{text:x.project,title:x.project})),t("div",{class:"compare"},$("branch"),t("span",{class:"ref",text:x.curLabel,title:x.curLabel}),M?[t("span",{class:"vs",text:"vs"}),t("span",{class:"ref",text:Xe(),title:x.baseLabel})]:[t("span"),t("span",{class:"faint",text:"snapshot only"})])),t("div",{class:"nav-label",text:"Report"}),t("nav",{class:"nav","aria-label":"Pages"},Pe.map(a=>t("a",{href:`#${a.id}`,dataset:{page:a.id}},$(a.icon),t("span",{text:a.title}),aa(a.id)))),t("div",{class:"side-foot"},t("div",{class:"theme-seg",role:"group","aria-label":"Theme"},[["system","monitor","System theme"],["light","sun","Light theme"],["dark","moon","Dark theme"]].map(([a,o,n])=>t("button",{dataset:{mode:a},"aria-label":n,title:n,on:{click:()=>Ze(a)}},$(o)))),t("div",{class:"gen"},$("clock"),t("span",{text:`Generated ${Qt(x.generatedAt)}`})))),oe(".nav a",e).forEach(a=>a.addEventListener("click",()=>Bt()))}function Xe(){return(x.baseLabel||"").replace(/\s*\(.*$/,"")}function na(){P("#sidebar").classList.add("open"),P("#scrim").classList.add("open")}function Bt(){P("#sidebar").classList.remove("open"),P("#scrim").classList.remove("open")}function xs(){P("#topbar").append(t("button",{class:"btn icon ghost menu-btn","aria-label":"Open menu",on:{click:na}},$("menu")),t("div",{class:"crumbs"},t("span",{class:"muted hide-sm",text:x.project}),t("span",{class:"sep hide-sm",text:"/"}),t("span",{class:"cur",id:"crumb-cur",text:"Overview"})),t("div",{class:"top-actions"},t("button",{class:"search-btn",on:{click:yt},"aria-label":"Search"},$("search"),t("span",{class:"lbl-t",text:"Search modules, rules\u2026"}),t("span",{class:"kbd",text:navigator.platform.includes("Mac")?"\u2318K":"Ctrl K"})),t("span",{class:`status-pill ${Ce?"fail":"pass"}`,title:Ce?"This change would fail the CI check":"This change passes the CI check"},t("span",{class:"pulse"}),t("span",{class:"lbl-t",text:Ce?"Check failing":"Check passing"})),t("button",{class:"btn",on:{click:At}},$("copy"),t("span",{class:"lbl-t",text:"Copy PR summary"}))))}function ws(){let e=P("#page-changes");if(e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Changes"}),t("p",{text:M?`Every module and dependency that differs from ${Xe()}.`:"Nothing to compare against \u2014 run Tecton inside a git repo with a main branch."})))),!M){e.append(t("div",{class:"card"},t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("compare")),t("h4",{text:"No comparison"}),t("p",{text:"Commit your code to git and create a main branch, or pass --base <branch>."}))));return}let s="all",a="",o=r=>Ne.filter(u=>r==="all"||u.kind===r).length,n=He([{value:"all",label:"All",count:o("all")},{value:"added",label:"Added",count:o("added")},{value:"removed",label:"Removed",count:o("removed")},{value:"changed",label:"Changed",count:o("changed")}],s,r=>{s=r,c()}),i=t("input",{type:"search",placeholder:"Filter by module\u2026","aria-label":"Filter changes",on:{input:r=>{a=r.target.value.toLowerCase(),c()}}}),p=t("tbody"),d=t("div",{class:"card"},t("div",{class:"tbl-wrap"},t("table",null,t("thead",null,t("tr",null,t("th",{text:"Change"}),t("th",{text:"What"}),t("th",{class:"r",text:"Imports"}),t("th",{text:"Rules"}),t("th"))),p))),l=t("div",{class:"empty-state",style:{display:"none"}},t("div",{class:"ico-box"},$("search")),t("h4",{text:"No matching changes"}),t("p",{text:"Try a different filter."}));d.appendChild(l);function c(){p.innerHTML="";let r=Ne.filter(u=>(s==="all"||u.kind===s)&&(!a||u.label.toLowerCase().includes(a)));r.forEach((u,m)=>{let g=u.edge,f=g?Ie.cur.get(g.id)||[]:[],y=t("tr",{class:"click enter",style:{animationDelay:`${Math.min(m,12)*.025}s`},on:{click:()=>ve({type:u.type,id:u.id})}},t("td",null,he(u.kind)),t("td",null,t("div",{class:"cell-mod"},t("span",{class:`ico-box ${u.viol?"viol":u.kind==="added"?"add":u.kind==="removed"?"rem":"chg"}`,style:{width:"26px",height:"26px"}},$(u.type==="node"?"box":"link")),u.type==="node"?t("span",null,u.label,t("span",{class:"faint",text:u.kind==="added"?" \xB7 new module":" \xB7 module removed"})):t("span",null,Y(g.from),t("span",{class:"arrow",text:" \u2192 "}),Y(g.to)))),t("td",{class:"r num mono"},u.type==="node"?t("span",{class:"faint",text:u.sub}):g.status==="same"?`${g.countBase} \u2192 ${g.countCur}`:g.status==="added"?`+${g.countCur}`:`\u2212${g.countBase}`),t("td",null,f.length?f.map(D=>t("span",{class:`badge ${D.status==="new"?D.severity==="error"?"critical":"warn":"neutral"}`,text:D.rule,style:{marginRight:"4px"}})):t("span",{class:"faint",text:"\u2014"})),t("td",{class:"r"},$("right","faint")));p.appendChild(y)}),l.style.display=r.length?"none":"block"}c(),e.append(t("div",{class:"toolbar"},n,t("label",{class:"input"},$("search"),i)),d)}function $s(){let e=P("#page-modules");e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Modules"}),t("p",{text:"Each folder Tecton treats as one part of the app, with how much it uses and is used. Open one to see its files."}))));let s={k:"files",dir:-1},a="",o=!1,n=x.nodes.map(f=>({n:f,...Ee.get(f.id),files:f.status==="removed"?f.filesBase:f.filesCur,edited:f.touched||0})),i=Math.max(1,...n.map(f=>f.files)),p=[["name","Module"],["status","Status"],["files","Files"],...Ke?[["edited","Edited"]]:[],["uses","Uses"],["usedBy","Used by"],["viol","Rule breaks"]],d=t("tr");p.forEach(([f,y])=>d.appendChild(t("th",{class:`sortable${f==="uses"||f==="usedBy"||f==="viol"||f==="edited"?" r":""}`,dataset:{k:f},on:{click:()=>{s={k:f,dir:s.k===f?-s.dir:f==="name"?1:-1},u()}}},y,t("span",{class:"sort"}))));let l=t("tbody"),c=t("input",{type:"search",placeholder:"Search modules\u2026","aria-label":"Search modules",on:{input:f=>{a=f.target.value.toLowerCase(),u()}}});function r(f,y){return y==="name"?f.n.id:y==="status"?f.n.status:f[y]}function u(){oe("th",d.parentNode||d).forEach(f=>{let y=P(".sort",f);y&&(y.textContent=f.dataset.k===s.k?s.dir>0?" \u2191":" \u2193":"")}),l.innerHTML="",n.filter(f=>(!a||f.n.id.toLowerCase().includes(a))&&(!o||f.edited)).sort((f,y)=>{let D=r(f,s.k),F=r(y,s.k);return(D>F?1:D<F?-1:0)*s.dir||f.n.id.localeCompare(y.n.id)}).forEach((f,y)=>{let D=f.n,F=()=>D.external?ve({type:"node",id:D.id}):Me(D.id);l.appendChild(t("tr",{class:"click enter",tabindex:0,style:{animationDelay:`${Math.min(y,12)*.02}s`},on:{click:F,keydown:ne=>{ne.key==="Enter"&&F()}}},t("td",null,t("div",{class:"cell-mod"},t("span",{class:`ico-box ${D.status==="added"?"add":D.status==="removed"?"rem":""}`,style:{width:"26px",height:"26px"}},$(D.external?"pkg":"box")),Y(D.id),D.external?t("span",{class:"faint",text:" \xB7 npm"}):null)),t("td",null,M&&D.status!=="same"?he(D.status):t("span",{class:"faint",text:D.external?"Package":"Unchanged"})),t("td",{class:"num"},D.external?t("span",{class:"faint",text:"\u2014"}):[t("span",{class:"mini-bar"},t("i",{style:{width:`${f.files/i*100}%`}})),M&&D.filesBase!==D.filesCur?`${D.filesBase} \u2192 ${D.filesCur}`:String(f.files)]),Ke?t("td",{class:"r num"},f.edited?t("span",{class:"chip acc",text:String(f.edited)}):t("span",{class:"faint",text:"0"})):null,t("td",{class:"r num",text:f.uses}),t("td",{class:"r num",text:f.usedBy}),t("td",{class:"r"},f.viol?de("serious",String(f.viol)):t("span",{class:"faint",text:"0"}))))})}let m=t("table",null,t("thead",null,d),l),g=Ke?t("label",{class:"switch"},t("input",{type:"checkbox",on:{change:f=>{o=f.target.checked,u()}}}),"Only modules this change touches"):null;e.append(t("div",{class:"toolbar"},t("label",{class:"input"},$("search"),c),g),t("div",{class:"card"},t("div",{class:"tbl-wrap"},m))),u()}window.addEventListener("hashchange",()=>st(location.hash.slice(1)));document.addEventListener("keydown",e=>{let s=/^(INPUT|TEXTAREA)$/.test(document.activeElement?.tagName);if((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="k"){e.preventDefault(),P("#palette-ov").classList.contains("open")?vt():yt();return}if(e.key==="Escape"){P("#palette-ov").classList.contains("open")?vt():P("#sheet")&&P("#sheet").classList.contains("open")?_e():E.selected?Te(null):Bt();return}s||(e.key==="/"&&(e.preventDefault(),yt()),E.page==="map"&&(e.key==="f"||e.key==="F")&&at(!0),E.page==="system"&&(e.key==="f"||e.key==="F")&&Ge(!0),/^[1-6]$/.test(e.key)&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&se(Pe[Number(e.key)-1].id))});bs();xs();ms();ps();ct();fs();ws();$s();vs();Ze(ys());P("#scrim").addEventListener("click",Bt);(()=>{let e=P("#preview");if(!e||!O.world)return;let s=30,a=v("svg",{viewBox:`${-s} ${-s} ${x.width+s*2} ${x.height+s*2}`,preserveAspectRatio:"xMidYMid meet","aria-hidden":"true"}),o=O.world.cloneNode(!0);o.removeAttribute("id"),oe("[id], [tabindex], [role], [aria-label]",o).forEach(n=>["id","tabindex","role","aria-label"].forEach(i=>n.removeAttribute(i))),a.appendChild(o),e.insertBefore(a,e.firstChild)})();window.addEventListener("resize",()=>{et(),E.page==="map"&&!E.selected&&at(!1),E.page==="system"&&Ge(!1)});st(location.hash.slice(1)||"overview");})();
2
+ (()=>{var xt="http://www.w3.org/2000/svg",$e=window.matchMedia("(prefers-reduced-motion: reduce)").matches,P=(e,s=document)=>s.querySelector(e),se=(e,s=document)=>[...s.querySelectorAll(e)];function t(e,s,...n){let i=document.createElement(e);return Gt(i,s),_t(i,n),i}function v(e,s,...n){let i=document.createElementNS(xt,e);return Gt(i,s),_t(i,n),i}function Gt(e,s){if(s)for(let n of Object.keys(s)){let i=s[n];if(!(i==null||i===!1))if(n==="class")e.setAttribute("class",i);else if(n==="text")e.textContent=i;else if(n==="html")e.innerHTML=i;else if(n==="on")for(let a of Object.keys(i))e.addEventListener(a,i[a]);else if(n==="style"&&typeof i=="object")for(let[a,o]of Object.entries(i))a.startsWith("--")?e.style.setProperty(a,o):e.style[a]=o;else n==="dataset"?Object.assign(e.dataset,i):e.setAttribute(n,i===!0?"":i)}}function _t(e,s){for(let n of s.flat(1/0))n==null||n===!1||e.appendChild(typeof n=="string"||typeof n=="number"?document.createTextNode(String(n)):n)}var Qt='<rect class="pl" x="6" y="14" width="25" height="12" rx="3"/><rect class="pl-shift" x="33" y="9" width="25" height="12" rx="3"/><rect class="pl" x="25" y="28" width="14" height="30" rx="3"/>',ke={logo:'<circle cx="6" cy="6" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="12" cy="18" r="2.5"/><path d="M8 7.5l3 8M16 7.5l-3 8M8.5 6h7"/>',overview:'<rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/>',map:'<rect x="16" y="16" width="6" height="6" rx="1"/><rect x="2" y="16" width="6" height="6" rx="1"/><rect x="9" y="2" width="6" height="6" rx="1"/><path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3"/><path d="M12 12V8"/>',shield:'<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="m9 12 2 2 4-4"/>',compare:'<circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><path d="M13 6h3a2 2 0 0 1 2 2v7"/><path d="M11 18H8a2 2 0 0 1-2-2V9"/>',box:'<path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/>',pkg:'<path d="M16.5 9.4 7.55 4.24"/><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><path d="M3.29 7 12 12l8.71-5"/><path d="M12 22V12"/>',folder:'<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/>',search:'<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',sun:'<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>',moon:'<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>',monitor:'<rect width="20" height="14" x="2" y="3" rx="2"/><path d="M8 21h8M12 17v4"/>',x:'<path d="M18 6 6 18M6 6l12 12"/>',plus:'<path d="M5 12h14M12 5v14"/>',minus:'<path d="M5 12h14"/>',fit:'<path d="M8 3H5a2 2 0 0 0-2 2v3M21 8V5a2 2 0 0 0-2-2h-3M16 21h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/>',copy:'<rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',download:'<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/>',alert:'<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4M12 17h.01"/>',check:'<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',xcircle:'<circle cx="12" cy="12" r="10"/><path d="m15 9-6 6M9 9l6 6"/>',right:'<path d="m9 18 6-6-6-6"/>',arrowRight:'<path d="M5 12h14M12 5l7 7-7 7"/>',file:'<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>',branch:'<path d="M6 3v12"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>',menu:'<path d="M4 6h16M4 12h16M4 18h16"/>',cycle:'<path d="m17 2 4 4-4 4"/><path d="M3 11v-1a4 4 0 0 1 4-4h14"/><path d="m7 22-4-4 4-4"/><path d="M21 13v1a4 4 0 0 1-4 4H3"/>',image:'<rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21"/>',clock:'<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>',link:'<path d="M9 17H7A5 5 0 0 1 7 7h2M15 7h2a5 5 0 1 1 0 10h-2M8 12h8"/>',code:'<path d="m16 18 6-6-6-6M8 6l-6 6 6 6"/>',sparkle:'<path d="M9.94 14.06 2 22M12 2l1.8 5.2L19 9l-5.2 1.8L12 16l-1.8-5.2L5 9l5.2-1.8z"/>',layers:'<path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"/><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/>',server:'<rect width="20" height="8" x="2" y="2" rx="2"/><rect width="20" height="8" x="2" y="14" rx="2"/><path d="M6 6h.01M6 18h.01"/>',globe:'<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>',users:'<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/>',database:'<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/>',cloud:'<path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/>',terminal:'<path d="m4 17 6-6-6-6M12 19h8"/>',mail:'<rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>',phone:'<rect width="14" height="20" x="5" y="2" rx="2"/><path d="M12 18h.01"/>',filePlus:'<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4M9 15h6M12 12v6"/>'};ke.queue='<path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/>';ke.pencil='<path d="M21.17 6.81a2.82 2.82 0 0 0-3.99-3.99L3.84 16.17a2 2 0 0 0-.5.83l-1.32 4.35a.5.5 0 0 0 .62.62l4.35-1.32a2 2 0 0 0 .83-.5z"/>';ke.arrowLeft='<path d="M19 12H5M12 19l-7-7 7-7"/>';function $(e,s){let n=document.createElementNS(xt,"svg");return n.setAttribute("class",`i${s?` ${s}`:""}`),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("aria-hidden","true"),n.innerHTML=ke[e]||"",n}var Y=e=>e.startsWith("npm:")?e.slice(4):e,ee=(e,s,n)=>`${e.toLocaleString()} ${e===1?s:n||`${s}s`}`,ce=e=>String(e).replace(/[&<>"]/g,s=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[s]);function qt(e){let s=new Date(e).getTime();if(!s)return"";let n=Math.round((Date.now()-s)/6e4);if(n<1)return"just now";if(n<60)return`${n} min ago`;let i=Math.round(n/60);return i<24?`${i} h ago`:new Date(e).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"})}var It={get(e){try{return localStorage.getItem(`tecton:${e}`)}catch{return null}},set(e,s){try{localStorage.setItem(`tecton:${e}`,s)}catch{}}};var x=JSON.parse(document.getElementById("data").textContent),Z=x.summary,be=Z.violations,M=x.hasBase,Oe=new Map(x.nodes.map(e=>[e.id,e])),Ue=new Map(x.edges.map(e=>[e.id,e])),lt=new Map(x.violations.map(e=>[e.id,e])),Ie={cur:new Map,base:new Map},Yt=(e,s,n)=>{e.has(s)||e.set(s,[]),e.get(s).push(n)};x.violations.forEach(e=>e.edges.forEach(s=>{e.status!=="fixed"&&Yt(Ie.cur,s,e),e.status!=="new"&&Yt(Ie.base,s,e)}));var Ce=M?be.newErrors>0:x.violations.some(e=>e.severity==="error"),Se=x.violations.filter(e=>e.status!=="fixed"),Ot=e=>e.status!=="same"||e.countBase!==e.countCur,Ms=e=>e.status==="added"?"added":e.status==="removed"?"removed":"changed",ze=x.nodes.filter(e=>!e.external),Ee=new Map(x.nodes.map(e=>[e.id,{uses:0,usedBy:0,viol:0}]));x.edges.forEach(e=>{e.status!=="removed"&&(Ee.get(e.from).uses++,Ee.get(e.to).usedBy++)});Se.forEach(e=>{(e.kind==="cycle"?e.members:[e.from]).forEach(n=>{Ee.has(n)&&Ee.get(n).viol++})});var xe=(x.rules||[]).map(e=>{let s=x.violations.filter(a=>a.rule===e.key),n={new:0,existing:0,fixed:0};s.forEach(a=>{n[a.status]++});let i;return n.new?i="new":n.existing?i="existing":n.fixed?i="fixed":i="pass",{...e,viols:s,n,state:i}}),Ne=[...ze.filter(e=>e.status!=="same").map(e=>({type:"node",id:e.id,kind:e.status,label:e.id,sub:ee(e.status==="added"?e.filesCur:e.filesBase,"file")})),...x.edges.filter(Ot).map(e=>({type:"edge",id:e.id,kind:Ms(e),label:`${Y(e.from)} \u2192 ${Y(e.to)}`,edge:e,viol:(Ie.cur.get(e.id)||[]).some(s=>s.status==="new")}))],Zt=x.files||{files:[],deps:[]},Kt={s:"same",a:"added",r:"removed"},Fe=Zt.files.map(([e,s,n,i],a)=>({i:a,path:e,module:s,status:Kt[n],edited:!!i,out:[],in:[]})),je=new Map(Fe.map(e=>[e.path,e]));Zt.deps.forEach(([e,s,n,i])=>{let a={from:Fe[e],to:Fe[s],status:Kt[n],line:i};Fe[e].out.push(a),Fe[s].in.push(a)});var Jt=e=>Fe.filter(s=>s.module===e),dt=new Set(x.nodes.filter(e=>e.touched).map(e=>e.id)),Ke=M&&dt.size>0,Ve=e=>e.status==="added"?"added":e.status==="removed"?"removed":e.edited?"edited":"same",Xt={added:0,removed:1,changed:2};Ne.sort((e,s)=>(s.viol?1:0)-(e.viol?1:0)||Xt[e.kind]-Xt[s.kind]||e.label.localeCompare(s.label));var Pe=[{id:"overview",title:"Overview",icon:"overview"},{id:"system",title:"Architecture",icon:"layers"},{id:"map",title:"Dependency map",icon:"map"},{id:"rules",title:"Rule checks",icon:"shield"},{id:"changes",title:"Changes",icon:"compare"},{id:"modules",title:"Modules",icon:"box"}],E={page:"overview",view:M?"diff":"cur",selected:null,focusOnly:!1,touchedOnly:!1};function He(e,s,n){let i=t("div",{class:"tabs",role:"group"}),a=t("span",{class:"ind"});i.appendChild(a);let o=e.map(l=>t("button",{"aria-pressed":String(l.value===s),dataset:{value:l.value},disabled:l.disabled,style:l.disabled?{opacity:".45",cursor:"not-allowed"}:null,on:{click:()=>{l.disabled||(d(l.value),n(l.value))}}},l.label,l.count!=null?t("span",{class:"c",text:l.count}):null));o.forEach(l=>i.appendChild(l));function p(){let l=o.find(c=>c.getAttribute("aria-pressed")==="true");!l||!l.offsetWidth||(a.style.left=`${l.offsetLeft}px`,a.style.width=`${l.offsetWidth}px`)}function d(l){o.forEach(c=>c.setAttribute("aria-pressed",String(c.dataset.value===l))),p()}return i._place=p,i._set=d,i}var et=()=>se(".tabs").forEach(e=>e._place&&e._place());function de(e,s){return t("span",{class:`badge ${e}`,text:s})}function wt(e){return{new:de("critical","New break"),existing:de("serious","Failing"),fixed:de("good","Fixed"),pass:de("good","Passing")}[e]}function $t(e){return M?e.status==="new"?de(e.severity==="error"?"critical":"warn",e.severity==="error"?"New":"New warning"):e.status==="fixed"?de("good","Fixed"):de("neutral","Already there"):de(e.severity==="error"?"critical":"warn",e.severity==="error"?"Error":"Warning")}function he(e){return{added:de("add","Added"),removed:de("rem","Removed"),changed:de("chg","Changed"),edited:de("acc","Edited"),same:de("neutral","Unchanged")}[e]}function tt(e,s){return t("div",{class:"ev"},e.map(n=>t("div",{class:`ev-row ${s||""}`},t("code",{text:`${n.file}:${n.line}`}),t("span",{class:"to",text:`\u2192 ${n.spec}`}))))}function es(e,s){if($e||s===0){e.textContent=s.toLocaleString();return}let n=performance.now(),i=900,a=o=>{let p=Math.min(1,(o-n)/i);e.textContent=Math.round(s*(1-(1-p)**3)).toLocaleString(),p<1&&requestAnimationFrame(a)};requestAnimationFrame(a)}var Je=P("#tip");function Le(e,s){Je.innerHTML=s,Je.classList.add("show");let n=14,i=Je.getBoundingClientRect(),a=e.clientX+n,o=e.clientY+n;a+i.width>window.innerWidth-8&&(a=e.clientX-i.width-n),o+i.height>window.innerHeight-8&&(o=e.clientY-i.height-n),Je.style.left=`${a}px`,Je.style.top=`${o}px`}function me(){Je.classList.remove("show")}function Es(e){return Math.max(120,Math.round(e.length*7.3)+56)}function ts(e,s){let n=e.map(h=>h.id).sort(),i=h=>h.external?11:(h.filesBase!==h.filesCur?`${h.filesBase} \u2192 ${h.filesCur} files`:`${h.filesCur||h.filesBase||0} files`).length,a=new Map(e.map(h=>[h.id,Math.max(Es((h.label||h.id).replace(/^npm:/,"")),h.filesCur===void 0?0:Math.round(36+i(h)*6.4+16))])),o=new Map(n.map(h=>[h,[]]));for(let h of s)o.get(h.from).push(h);for(let h of o.values())h.sort((T,I)=>T.to<I.to?-1:1);let p=new Map,d=new Set,l=h=>{p.set(h,1);for(let T of o.get(h)){let I=p.get(T.to);I===1?d.add(T.id):I||l(T.to)}p.set(h,2)};for(let h of n)p.get(h)||l(h);let c=s.map(h=>d.has(h.id)?{id:h.id,u:h.to,v:h.from}:{id:h.id,u:h.from,v:h.to}),r=new Map(n.map(h=>[h,[]])),u=new Map(n.map(h=>[h,[]]));for(let h of c)r.get(h.v).push(h.u),u.get(h.u).push(h.v);let m=new Map(n.map(h=>[h,r.get(h).length])),g=[],f=n.filter(h=>m.get(h)===0);for(;f.length;){f.sort();let h=f.shift();g.push(h);for(let T of u.get(h))m.set(T,m.get(T)-1),m.get(T)===0&&f.push(T)}let y=new Map;for(let h of g)y.set(h,Math.max(0,...r.get(h).map(T=>y.get(T)+1)));for(let h of[...g].reverse())r.get(h).length===0&&u.get(h).length&&y.set(h,Math.min(...u.get(h).map(T=>y.get(T)))-1);let D=Math.min(0,...y.values());for(let h of n)y.set(h,y.get(h)-D);let F=new Map(y),oe=new Map,_=[];for(let h of c){let T=[h.u];for(let I=y.get(h.u)+1;I<y.get(h.v);I++){let A=`\0${h.id}#${I}`;F.set(A,I),a.set(A,14),T.push(A)}T.push(h.v),oe.set(h.id,T);for(let I=0;I+1<T.length;I++)_.push([T[I],T[I+1]])}let w=new Map([...F.keys()].map(h=>[h,[]])),z=new Map([...F.keys()].map(h=>[h,[]]));for(let[h,T]of _)z.get(h).push(T),w.get(T).push(h);let b=Math.max(0,...F.values())+1,S=Array.from({length:b},()=>[]),j=new Set,V=[...F.keys()].filter(h=>w.get(h).length===0).sort();for(;V.length;){let h=V.shift();if(!j.has(h)){j.add(h),S[F.get(h)].push(h);for(let T of[...z.get(h)].sort())j.has(T)||V.push(T)}}for(let h of[...F.keys()].sort())j.has(h)||S[F.get(h)].push(h);let ne=h=>{let T=0;for(let I=0;I+1<h.length;I++){let A=new Map(h[I+1].map((k,R)=>[k,R])),N=[];h[I].forEach((k,R)=>z.get(k).forEach(Q=>N.push([R,A.get(Q)])));for(let k=0;k<N.length;k++)for(let R=k+1;R<N.length;R++)(N[k][0]-N[R][0])*(N[k][1]-N[R][1])<0&&T++}return T},W=(h,T,I,A)=>{let N=new Map(h[A].map((R,Q)=>[R,Q])),k=new Map(h[T].map((R,Q)=>{let pe=I.get(R).filter(ye=>N.has(ye));return[R,pe.length?pe.reduce((ye,De)=>ye+N.get(De),0)/pe.length:Q]}));h[T]=[...h[T]].sort((R,Q)=>k.get(R)-k.get(Q)||h[T].indexOf(R)-h[T].indexOf(Q))},X=S.map(h=>[...h]),B=ne(X);for(let h=0;h<16&&B>0;h++){if(h%2===0)for(let I=1;I<b;I++)W(S,I,w,I-1);else for(let I=b-2;I>=0;I--)W(S,I,z,I+1);let T=ne(S);T<B&&(B=T,X=S.map(I=>[...I]))}S=X;let H=new Map;for(let h of S){let T=0;for(let A of h)H.set(A,T+a.get(A)/2),T+=a.get(A)+36;let I=(T-36)/2;for(let A of h)H.set(A,H.get(A)-I)}let te=(h,T)=>{let I=(k,R)=>(a.get(k)+a.get(R))/2+(k.startsWith("\0")||R.startsWith("\0")?10:36),A=h.map(k=>T.get(k));for(let k=1;k<h.length;k++)A[k]=Math.max(A[k],A[k-1]+I(h[k-1],h[k]));let N=h.map(k=>T.get(k));for(let k=h.length-2;k>=0;k--)N[k]=Math.min(N[k],N[k+1]-I(h[k],h[k+1]));h.forEach((k,R)=>H.set(k,(A[R]+N[R])/2));for(let k=1;k<h.length;k++){let R=H.get(h[k-1])+I(h[k-1],h[k]);H.get(h[k])<R&&H.set(h[k],R)}};for(let h=0;h<10;h++){let T=h%2===0?S.map((I,A)=>A):S.map((I,A)=>S.length-1-A);for(let I of T){let A=h%2===0?w:z,N=new Map(S[I].map(k=>{let R=[...A.get(k),...h>5?(A===w?z:w).get(k):[]];return[k,R.length?R.reduce((Q,pe)=>Q+H.get(pe),0)/R.length:H.get(k)]}));te(S[I],N)}}let we=h=>h*132,G=Math.min(...[...H.entries()].map(([h,T])=>T-a.get(h)/2),0),L={};for(let h of n){let T=a.get(h);L[h]={x:H.get(h)-T/2-G,y:we(y.get(h)),w:T,h:46}}let q=new Set(s.map(h=>`${h.from}\u2192${h.to}`)),le={};for(let h of s){let T=oe.get(h.id),I=T.map((A,N)=>{let k=H.get(A)-G,R=we(F.get(A));return N===0?[k,R+46]:N===T.length-1?[k,R]:[k,R+46/2]});if(d.has(h.id)&&I.reverse(),q.has(`${h.to}\u2192${h.from}`)){let A=h.from<h.to?-7:7;I.forEach(N=>{N[0]+=A})}le[h.id]=I.map(([A,N])=>[Math.round(A*10)/10,Math.round(N*10)/10]),T=null}let J=Math.max(0,...Object.values(L).map(h=>h.x+h.w)),ue=Math.max(0,...Object.values(L).map(h=>h.y+h.h));return{pos:L,routes:le,width:J,height:ue,crossings:B}}function ae(e){location.hash!==`#${e}`?location.hash=e:st(e)}var ss=!1;function st(e){let s=null;if(e.startsWith("module:")){try{s=decodeURIComponent(e.slice(7))}catch{s=null}let i=s&&Oe.get(s);e=i&&!i.external?"module":"modules"}e!=="module"&&!Pe.some(i=>i.id===e)&&(e="overview"),E.page=e;let n=e==="module"?s:Pe.find(i=>i.id===e).title;se(".page").forEach(i=>i.classList.toggle("active",i.id===`page-${e}`)),se(".nav a").forEach(i=>i.classList.toggle("active",i.dataset.page===(e==="module"?"modules":e))),P("#crumb-cur").textContent=e==="module"?`Modules / ${s}`:n,document.title=`${n} \xB7 ${x.project} \xB7 Tecton`,P("#content").scrollTop=0,me(),requestAnimationFrame(et),e==="overview"&&!ss&&(ss=!0,se("[data-count]",P("#page-overview")).forEach(i=>es(i,Number(i.dataset.count)))),e!=="system"&&_e(),e==="system"&&(C.svg?(se(".sys-tabs").forEach(i=>i._set&&i._set(E.view)),rt()):ct(),requestAnimationFrame(()=>{C.fitted||(C.fitted=Ge(!1))})),e==="module"&&kt(s),e==="map"&&requestAnimationFrame(()=>{O.fitted||(at(!1),O.fitted=!0),as()})}var re=x.system||{apps:[],stores:[],outside:[],links:[],hasUsers:!1,summary:null},ls={expanded:new Set,sel:null},qe=[{key:"pages",title:"Pages",icon:"file",mono:!0},{key:"api",title:"Routes & API",icon:"code"},{key:"endpoints",title:"HTTP endpoints",icon:"code"},{key:"jobs",title:"Jobs & scripts",icon:"terminal",mono:!0},{key:"schedules",title:"Schedules",icon:"clock",mono:!0}],Nt=e=>e.kind==="Queue"?"queue":"database",ht=e=>({web:"globe",mobile:"phone",desktop:"monitor",server:"server"})[e.role]||"box",ns=e=>ie(e.status||"same");var pt=new Map(re.apps.map(e=>[e.id,e])),os=e=>e==="users"?"Users":(pt.get(e)||{}).name||e,Pt=new Map([...re.stores,...re.outside].map(e=>[e.id,e]));function Cs(){let e=re.links.filter(n=>n.kind==="app"),s=new Map(re.apps.map(n=>[n.id,["web","mobile","desktop"].includes(n.role)?0:1]));for(let n=0;n<4;n++)e.forEach(i=>{s.has(i.to)&&s.has(i.from)&&s.set(i.to,Math.max(s.get(i.to),s.get(i.from)+1))});return[...re.apps].sort((n,i)=>s.get(n.id)-s.get(i.id)||n.name.localeCompare(i.name))}var is=["var(--accent)","var(--chg)","var(--add)","var(--viol)","var(--warn)"];function Rt(e){let s=re.apps.findIndex(n=>n.id===e);return is[(s<0?0:s)%is.length]}var C={vb:{x:0,y:0,w:100,h:100},drag:null,dragMoved:!1,nodes:new Map,wires:[],model:null,fitted:!1},fe=8,ge=e=>Math.round(e/fe)*fe,Qe=(e,s)=>e.length*s,Re=(e,s)=>e.length>s?`${e.slice(0,s-1)}\u2026`:e,Ss=e=>e.every(s=>s.status==="added")?"added":e.every(s=>s.status==="removed")?"removed":"same";function Ls(e){let s={pages:["page","pages"],api:["route","routes"],endpoints:["endpoint","endpoints"],jobs:["job","jobs"],schedules:["schedule","schedules"]};return qe.map(n=>[n.key,(e.groups[n.key]||[]).filter(i=>i.status!=="removed").length]).filter(([,n])=>n).map(([n,i])=>`${i} ${s[n][i===1?0:1]}`).join(" \xB7 ")}function As(e){if(e.kind==="users")return"uses \xB7 HTTPS";if(e.kind==="app")return e.labels[0]||"HTTP";let s=Pt.get(e.to);return e.kind==="data"?e.labels.length?e.labels.join(" \xB7 "):s&&s.kind==="Queue"?"messages":s&&/SQL|Postgre|MySQL|SQLite|ORM|Prisma|Drizzle/i.test(`${s.name} ${s.via.join(" ")}`)?"reads & writes \xB7 SQL":"reads & writes":s&&s.id.startsWith("svc:")?"API \xB7 SDK":s&&s.id.startsWith("env:")?"HTTPS \xB7 env":"HTTPS"}function Bs(){let e=[],s=re.links.filter(a=>a.kind==="users");s.length&&e.push({id:"users",type:"person",name:"Users",kind:"Person",sub:"Browser & API clients",status:Ss(s),w:168,h:128});for(let a of re.apps){let o=Ls(a)||"No entry points found",p=a.tech.filter(l=>l.toLowerCase()!==a.framework.toLowerCase()).slice(0,4).join(" \xB7 "),d=ge(Math.max(248,64+Qe(Re(a.name,26),8),32+Qe(o,6.6),32+Qe(p,6.3)));e.push({id:a.id,type:"app",name:Re(a.name,26),kind:`Container: ${a.framework}`,sub:o,tech:p,status:a.status||"same",w:d,h:p?128:112,ref:a,color:Rt(a.id)})}for(let a of re.stores){let o=a.kind==="Queue",p=ge(Math.max(o?192:176,44+Qe(Re(a.name,24),7.6)));e.push({id:a.id,type:o?"queue":"db",name:Re(a.name,24),kind:o?"Queue":a.kind,sub:Re(a.via.join(", "),30),status:a.status||"same",w:p,h:o?72:104,ref:a})}for(let a of re.outside){let o=(a.hosts||[]).map(l=>typeof l=="string"?l:l.host),p=a.id.startsWith("env:")?`set by ${a.via[0]||"an env var"}`:o.length?Re(o.join(", "),30):a.via.length?Re(a.via.join(", "),30):"",d=ge(Math.max(208,56+Qe(Re(a.name,26),7.8),32+Qe(p,6.3)));e.push({id:a.id,type:"ext",name:Re(a.name,26),kind:`External \xB7 ${a.kind}`,sub:p,status:a.status||"same",w:d,h:80,ref:a,envOnly:a.id.startsWith("env:")})}let n=new Map(e.map(a=>[a.id,a])),i=re.links.filter(a=>n.has(a.from)&&n.has(a.to)).map(a=>({id:a.id,from:a.from,to:a.to,kind:a.kind,status:a.status||"same",label:As(a),link:a,async:a.kind==="data"&&n.get(a.to).type==="queue"}));return{nodes:e,edges:i,byId:n}}function Ts(e){let p=e.nodes.filter(L=>L.type==="app"),d=e.edges.filter(L=>L.kind==="app"),l=new Map(p.map(L=>[L.id,["web","mobile","desktop"].includes(L.ref.role)?0:1]));for(let L=0;L<4;L++)d.forEach(q=>{l.has(q.to)&&l.has(q.from)&&l.set(q.to,Math.max(l.get(q.to),l.get(q.from)+1))});let c=Math.min(...l.values());p.forEach(L=>l.set(L.id,l.get(L.id)-c));let r=4,u=p.slice().sort((L,q)=>l.get(L.id)-l.get(q.id)||L.name.localeCompare(q.name)),m=[];for(let L=0;L<u.length;L+=r)m.push(u.slice(L,L+r));let g=e.nodes.filter(L=>L.type==="db"||L.type==="queue"),f=L=>L[0]&&L[0].type==="app"?144:64,y=L=>L.reduce((q,le)=>q+le.w,0)+f(L)*Math.max(0,L.length-1),D=Math.max(...m.map(y),y(g),320),F=e.byId.has("users"),oe=F?e.byId.get("users").h+96:0,_=oe+48,w=(L,q,le)=>{let J=le-y(L)/2,ue=Math.max(...L.map(h=>h.h));return L.forEach(h=>{h.x=ge(J),h.y=ge(q+(ue-h.h)/2),J+=h.w+f(L)}),ue},z=48+D/2;if(m.forEach(L=>{_+=w(L,_,z)+104}),g.length){let L=q=>{let le=e.edges.filter(J=>J.to===q.id).map(J=>e.byId.get(J.from)).filter(J=>J&&J.x!=null);return le.length?le.reduce((J,ue)=>J+ue.x+ue.w/2,0)/le.length:z};g.sort((q,le)=>L(q)-L(le)||+(q.type==="queue")-+(le.type==="queue")||q.name.localeCompare(le.name)),_+=w(g,_,z)+0}else _-=104;let b=[...p,...g],S=ge(Math.min(...b.map(L=>L.x))-48),j=ge(Math.max(...b.map(L=>L.x+L.w))+48),V=ge(oe),ne=ge(_+48+40),W=b.length?{x:S,y:V,w:j-S,h:ne-V}:null;if(F){let L=e.byId.get("users"),q=e.edges.filter(J=>J.from==="users").map(J=>e.byId.get(J.to)).filter(J=>J.x!=null),le=q.length?q.reduce((J,ue)=>J+ue.x+ue.w/2,0)/q.length:z;L.x=ge(le-L.w/2),L.y=0}let X=e.nodes.filter(L=>L.type==="ext");if(X.length){let L=A=>{let N=e.edges.filter(k=>k.to===A.id).map(k=>e.byId.get(k.from)).filter(k=>k&&k.y!=null);return N.length?N.reduce((k,R)=>k+R.y+R.h/2,0)/N.length:0};X.sort((A,N)=>L(A)-L(N)||A.ref.kind.localeCompare(N.ref.kind)||A.name.localeCompare(N.name));let q=40,le=W?W.y:0,J=W?W.h:600,ue=Math.max(4,Math.floor((J+q)/(80+q)),Math.min(8,Math.ceil(X.length/2))),h=Math.ceil(X.length/ue),T=Math.max(...X.map(A=>A.w)),I=(W?W.x+W.w:0)+176;for(let A=0;A<h;A++){let N=X.slice(A*ue,(A+1)*ue),k=N.reduce((Q,pe)=>Q+pe.h,0)+q*(N.length-1),R=le+Math.max(0,(J-k)/2);N.forEach(Q=>{Q.x=ge(I+(T-Q.w)/2),Q.y=ge(R),R+=Q.h+q}),I+=T+96}}let B=e.nodes,H=Math.min(...B.map(L=>L.x),W?W.x:1/0),te=Math.min(...B.map(L=>L.y),W?W.y:1/0),we=Math.max(...B.map(L=>L.x+L.w),W?W.x+W.w:-1/0),G=Math.max(...B.map(L=>L.y+L.h),W?W.y+W.h:-1/0);return{boundary:W,bounds:{x:H,y:te,w:we-H,h:G-te}}}function Is(e,s){let i=s.bounds,a=ge(i.x-120),o=ge(i.y-120),p=Math.ceil((i.w+240)/fe)+1,d=Math.ceil((i.h+240)/fe)+1,l=new Uint8Array(p*d),c=(b,S)=>S*p+b;for(let b of e.nodes){let S=Math.floor((b.x-12-a)/fe)+1,j=Math.ceil((b.x+b.w+12-a)/fe)-1,V=Math.floor((b.y-12-o)/fe)+1,ne=Math.ceil((b.y+b.h+12-o)/fe)-1;for(let W=Math.max(0,V);W<=Math.min(d-1,ne);W++)for(let X=Math.max(0,S);X<=Math.min(p-1,j);X++)l[c(X,W)]=1}let r=new Uint8Array(p*d),u=new Int16Array(p*d),m=new Map(e.nodes.map((b,S)=>[b.id,S+1])),g=[[1,0],[0,1],[-1,0],[0,-1]],f={right:0,bottom:1,left:2,top:3},y=[];for(let b of e.edges){let S=e.byId.get(b.from),j=e.byId.get(b.to),V,ne;j.y>=S.y+S.h+24&&!(j.type==="ext"&&S.type!=="person")?(V="bottom",ne="top"):j.y+j.h+24<=S.y&&j.type!=="ext"?(V="top",ne="bottom"):j.x+j.w/2>=S.x+S.w/2?(V="right",ne="left"):(V="left",ne="right"),b.ss=V,b.ts=ne,y.push({e:b,node:S,side:V,other:j,end:"s"},{e:b,node:j,side:ne,other:S,end:"t"})}let D=new Map;y.forEach(b=>{let S=`${b.node.id}|${b.side}|${b.end}`;D.has(S)||D.set(S,[]),D.get(S).push(b)});for(let b of D.values()){let S=b[0].side==="top"||b[0].side==="bottom";b.sort((B,H)=>(S?B.other.x+B.other.w/2-(H.other.x+H.other.w/2):B.other.y+B.other.h/2-(H.other.y+H.other.h/2))||(B.e.id<H.e.id?-1:1));let j=b[0].node,V=S?j.w:j.h,ne=b[0].end==="s",W=ne?0:Math.min(V*.7,Math.max(0,(b.length-1)*24)),X=ne&&b.length?Math.max(-V*.25,Math.min(V*.25,(b.reduce((B,H)=>B+(S?H.other.x+H.other.w/2:H.other.y+H.other.h/2),0)/b.length-((S?j.x:j.y)+V/2))*.3)):0;b.forEach((B,H)=>{let te=ge((S?j.x:j.y)+V/2+X-W/2+(b.length>1&&W?W*H/(b.length-1):0)),we=B.side==="right"?[j.x+j.w,te]:B.side==="left"?[j.x,te]:B.side==="bottom"?[te,j.y+j.h]:[te,j.y],G=g[f[B.side]],L=[we[0]+G[0]*3*fe,we[1]+G[1]*3*fe];B.e[B.end==="s"?"P0":"P1"]=we,B.e[B.end==="s"?"Q0":"Q1"]=L})}let F=e.edges.slice().sort((b,S)=>Math.abs(b.Q0[0]-b.Q1[0])+Math.abs(b.Q0[1]-b.Q1[1])-(Math.abs(S.Q0[0]-S.Q1[0])+Math.abs(S.Q0[1]-S.Q1[1]))||(b.id<S.id?-1:1)),oe=6;for(let b of F){let S=Math.round((b.Q0[0]-a)/fe),j=Math.round((b.Q0[1]-o)/fe),V=Math.round((b.Q1[0]-a)/fe),ne=Math.round((b.Q1[1]-o)/fe),W=m.get(b.from),X=f[b.ss],B=(f[b.ts]+2)%4,H=p*d*4,te=new Float64Array(H).fill(1/0),we=new Int32Array(H).fill(-1),G=[],L=(I,A)=>{G.push([I,A]);let N=G.length-1;for(;N>0;){let k=N-1>>1;if(G[k][0]<=G[N][0])break;[G[k],G[N]]=[G[N],G[k]],N=k}},q=()=>{let I=G[0],A=G.pop();if(G.length){G[0]=A;let N=0;for(;;){let k=2*N+1,R=k+1,Q=N;if(k<G.length&&G[k][0]<G[Q][0]&&(Q=k),R<G.length&&G[R][0]<G[Q][0]&&(Q=R),Q===N)break;[G[Q],G[N]]=[G[N],G[Q]],N=Q}}return I},le=(I,A)=>Math.abs(I-V)+Math.abs(A-ne),J=c(S,j)<<2|X;te[J]=0,L(le(S,j),J);let ue=-1,h=0;for(;G.length&&h++<4e5;){let[I,A]=q(),N=A>>2,k=A&3,R=N%p,Q=(N-R)/p;if(R===V&&Q===ne){ue=A;break}if(!(I>te[A]+le(R,Q)+1e-6))for(let pe=0;pe<4;pe++){if(pe===(k+2)%4)continue;let ye=R+g[pe][0],De=Q+g[pe][1];if(ye<0||De<0||ye>=p||De>=d)continue;let it=c(ye,De);if(l[it]&&!(ye===V&&De===ne))continue;let ks=pe%2===0?1:2,zt=u[it]===W,Vt=(zt?.7:1)+(pe!==k?oe:0)+(zt?0:r[it]&ks?4:r[it]?1.5:0);ye===V&&De===ne&&pe!==B&&(Vt+=oe);let bt=it<<2|pe,Tt=te[A]+Vt;Tt<te[bt]&&(te[bt]=Tt,we[bt]=A,L(Tt+le(ye,De),bt))}}let T;if(ue<0)T=[b.P0,b.Q0,[b.Q0[0],b.Q1[1]],b.Q1,b.P1];else{let I=[];for(let N=ue;N>=0;N=we[N])I.push(N);I.reverse();let A=null;for(let N of I){let k=N>>2,R=k%p,Q=(k-R)/p;if(A){let pe=R!==A[0]?1:2;for(let ye of[c(R,Q),c(A[0],A[1])])r[ye]|=pe,u[ye]||(u[ye]=W)}A=[R,Q]}T=[b.P0,...I.map(N=>{let k=N>>2,R=k%p;return[a+R*fe,o+(k-R)/p*fe]}),b.P1]}b.pts=T.filter((I,A)=>A===0||A===T.length-1||!(T[A-1][0]===I[0]&&I[0]===T[A+1][0]||T[A-1][1]===I[1]&&I[1]===T[A+1][1]))}let _=e.nodes.map(b=>({x:b.x-4,y:b.y-4,w:b.w+8,h:b.h+8})),w=[],z=b=>[..._,...w].some(S=>b.x<S.x+S.w&&b.x+b.w>S.x&&b.y<S.y+S.h&&b.y+b.h>S.y);for(let b of F){let S=b.label.length*6.3+18,j=20,V=[];for(let B=0;B<b.pts.length-1;B++){let H=b.pts[B],te=b.pts[B+1];V.push({a:H,c:te,len:Math.abs(H[0]-te[0])+Math.abs(H[1]-te[1])})}let W=[...V.slice().reverse().filter(B=>B.len>=(B.a[1]===B.c[1]?S+16:j+24)),...V.slice().sort((B,H)=>H.len-B.len)],X=null;for(let B of W){for(let H of[.5,.3,.7,.18,.82]){let te=B.a[0]+(B.c[0]-B.a[0])*H,we=B.a[1]+(B.c[1]-B.a[1])*H,G={x:te-S/2,y:we-j/2,w:S,h:j};if(!z(G)){X=G;break}}if(X)break}if(!X&&W.length){let B=W[0];X={x:(B.a[0]+B.c[0])/2-S/2,y:(B.a[1]+B.c[1])/2-j/2,w:S,h:j}}X&&(w.push(X),b.lbl=X)}}function Os(e,s=10){if(e.length<2)return"";let n=`M${e[0][0]},${e[0][1]}`;for(let a=1;a<e.length-1;a++){let[o,p]=e[a-1],[d,l]=e[a],[c,r]=e[a+1],u=Math.min(s,Math.hypot(d-o,l-p)/2,Math.hypot(c-d,r-l)/2),m=d-Math.sign(d-o)*u,g=l-Math.sign(l-p)*u,f=d+Math.sign(c-d)*u,y=l+Math.sign(r-l)*u;n+=` L${m},${g} Q${d},${l} ${f},${y}`}let i=e[e.length-1];return`${n} L${i[0]},${i[1]}`}function Ns(e){let s=v("g",{class:`an t-${e.type}`,transform:`translate(${e.x},${e.y})`,dataset:{node:e.id}}),n=(d,l,c,r=.75)=>v("g",{class:"an-ico",transform:`translate(${l},${c}) scale(${r})`,html:ke[d]}),i=(d,l,c,r,u)=>v("text",{class:d,x:l,y:c,"text-anchor":u||"start"},r),{w:a,h:o}=e;e.type==="person"?s.append(v("path",{class:"an-shape",d:`M0,${o-12} V74 Q0,44 38,44 H${a-30-8} Q${a},44 ${a},74 V${o-12} Q${a},${o} ${a-12},${o} H12 Q0,${o} 0,${o-12} Z`}),v("circle",{class:"an-shape an-head",cx:a/2,cy:19,r:18}),i("an-name",a/2,80,e.name,"middle"),i("an-kind",a/2,97,`[${e.kind}]`,"middle"),i("an-sub",a/2,114,e.sub,"middle")):e.type==="app"?(s.style.setProperty("--app",e.color),s.append(v("rect",{class:"an-shape",width:a,height:o,rx:12}),v("rect",{class:"an-band",width:a,height:5,rx:2.5}),v("rect",{class:"an-ibox",x:16,y:18,width:30,height:30,rx:8}),n(ht(e.ref),22,24),i("an-name",56,32,e.name),i("an-kind",56,47,`[${e.kind}]`),v("line",{class:"an-rule",x1:16,x2:a-16,y1:64,y2:64}),i("an-sub",16,86,e.sub)),e.tech&&s.append(i("an-tech",16,110,e.tech))):e.type==="db"?s.append(v("path",{class:"an-shape",d:`M0,11 A${a/2},11 0 0 1 ${a},11 L${a},${o-11} A${a/2},11 0 0 1 0,${o-11} Z`}),v("ellipse",{class:"an-lid",cx:a/2,cy:11,rx:a/2,ry:11}),n("database",a/2-9,30),i("an-name",a/2,66,e.name,"middle"),i("an-kind",a/2,82,`[${e.kind}]`,"middle")):e.type==="queue"?s.append(v("path",{class:"an-shape",d:`M14,0 L${a-14},0 A14,${o/2} 0 0 1 ${a-14},${o} L14,${o} A14,${o/2} 0 0 1 14,0 Z`}),v("ellipse",{class:"an-lid",cx:a-14,cy:o/2,rx:14,ry:o/2}),n("queue",26,o/2-9),i("an-name",54,o/2-2,e.name),i("an-kind",54,o/2+14,`[${e.kind}${e.sub?` \xB7 ${e.sub}`:""}]`)):(s.append(v("rect",{class:`an-shape${e.envOnly?" env":""}`,width:a,height:o,rx:10}),n({Email:"mail","Web / HTTP":"globe"}[e.ref.kind]||"cloud",16,16),i("an-name",44,29,e.name),i("an-kind",16,52,`[${e.kind}]`)),e.sub&&s.append(i("an-sub mono",16,69,e.sub)));let p=(d,l,c)=>v("g",{class:`an-badge ${d}`,transform:`translate(${a-c-10},-9)`},v("rect",{width:c,height:17,rx:5}),v("text",{x:c/2,y:12,"text-anchor":"middle"},l));if(s.append(p("b-add","NEW",36),p("b-rem","GONE",40)),e.type!=="person"){s.setAttribute("tabindex",0),s.setAttribute("role","button"),s.setAttribute("aria-label",`${e.name}, ${e.kind}`);let d=()=>Ae(e.type==="app"?{type:"app",id:e.id}:{type:"svc",id:e.id});s.addEventListener("click",l=>{C.dragMoved||(l.stopPropagation(),d())}),s.addEventListener("keydown",l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),d())})}return s.addEventListener("pointerenter",()=>{C.drag||ut(e.id)}),s.addEventListener("pointerleave",()=>ut(null)),s.addEventListener("focus",()=>ut(e.id)),s.addEventListener("blur",()=>ut(null)),s}function Ps(e){let s=Bs(),n=Ts(s);Is(s,n),C.model=s,C.layout=n;let i=v("defs");i.innerHTML=[["line","--text-3"],["app","--accent"],["data","--text-2"],["add","--add"],["rem","--rem"],["hl","--accent"]].map(([l,c])=>`<marker id="aw-${l}" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="9" markerHeight="9" orient="auto-start-reverse" markerUnits="userSpaceOnUse"><path d="M1,1.5 L9,5 L1,8.5 Q2.5,5 1,1.5 z" style="fill: var(${c})"/></marker>`).join("")+'<filter id="an-shadow" x="-10%" y="-20%" width="120%" height="150%"><feDropShadow dx="0" dy="1.5" stdDeviation="2" flood-color="#101018" flood-opacity=".07"/></filter><pattern id="aw-dots" width="16" height="16" patternUnits="userSpaceOnUse"><circle cx="1" cy="1" r="1" style="fill: var(--dot)"/></pattern>',e.appendChild(i),e.appendChild(v("rect",{class:"arch-bg",x:-2e4,y:-2e4,width:4e4,height:4e4,fill:"url(#aw-dots)"}));let a=v("g",{id:"arch-world"});if(n.boundary){let l=n.boundary;a.append(v("g",{class:"arch-boundary"},v("rect",{x:l.x,y:l.y,width:l.w,height:l.h,rx:18}),v("g",{class:"an-ico",transform:`translate(${l.x+20},${l.y+l.h-33}) scale(0.7)`,html:ke.layers}),v("text",{class:"ab-name",x:l.x+44,y:l.y+l.h-20},x.project),v("text",{class:"ab-kind",x:l.x+56+Qe(x.project,8.6),y:l.y+l.h-20},"[Software system \xB7 this repo]")))}let o=v("g"),p=v("g"),d=v("g");a.append(o,p,d),C.wires=[];for(let l of s.edges){let c=Os(l.pts),r=v("path",{class:"wl",d:c}),u=v("g",{class:`aw k-${l.kind}${l.async?" async":""}`,dataset:{wire:l.id}},r,v("path",{class:"whit",d:c}));if(!$e&&(l.kind==="app"||l.status==="added")){let f=v("circle",{class:"wdot",r:2.6}),y=v("animateMotion",{dur:`${Math.max(2,l.pts.reduce((D,F,oe)=>oe?D+Math.abs(F[0]-l.pts[oe-1][0])+Math.abs(F[1]-l.pts[oe-1][1]):0,0)/90).toFixed(2)}s`,repeatCount:"indefinite",path:c});f.appendChild(y),u.appendChild(f)}let m=null;l.lbl&&(m=v("g",{class:`aw-lbl k-${l.kind}`},v("rect",{x:l.lbl.x,y:l.lbl.y,width:l.lbl.w,height:l.lbl.h,rx:10}),v("text",{x:l.lbl.x+l.lbl.w/2,y:l.lbl.y+l.lbl.h/2+.5,"text-anchor":"middle","dominant-baseline":"central"},l.label)),d.appendChild(m));let g=()=>`<div class="tt">${ce(l.from==="users"?"Users":(s.byId.get(l.from)||{}).name||l.from)} <span class="faint">\u2192</span> ${ce((s.byId.get(l.to)||{}).name||l.to)}</div><div class="kv"><span>${ce(l.label)}</span><b>${l.link.count||""}</b></div>${M&&l.status!=="same"?`<div class="kv"><span>Status</span><b>${l.status==="added"?"New":"Removed"}</b></div>`:""}${l.link.evidence&&l.link.evidence[0]?`<div class="kv faint"><span class="mono-s">${ce(l.link.evidence[0].file)}:${l.link.evidence[0].line}</span></div>`:""}`;[u,m].filter(Boolean).forEach(f=>{f.addEventListener("pointermove",y=>{C.drag||Le(y,g())}),f.addEventListener("pointerleave",me)}),o.appendChild(u),C.wires.push({e:l,g:u,path:r,lbl:m})}C.nodes=new Map;for(let l of s.nodes){let c=Ns(l);p.appendChild(c),C.nodes.set(l.id,{n:l,el:c})}e.appendChild(a),e.addEventListener("click",()=>{C.dragMoved||_e()}),C.svg=e,C.world=a}function rt(){if(C.svg){for(let{n:e,el:s}of C.nodes.values()){let n=E.view==="diff"&&M?e.status:"same";s.setAttribute("class",`an t-${e.type} ${n}${ie(e.status)?"":" gone"}`)}for(let{e,g:s,path:n,lbl:i}of C.wires){let a=E.view==="diff"&&M?e.status:"same",o=`${a}${ie(e.status)?"":" gone"}`;s.setAttribute("class",`aw k-${e.kind}${e.async?" async":""} ${o}`),i&&i.setAttribute("class",`aw-lbl k-${e.kind} ${o}`),n.setAttribute("marker-end",`url(#aw-${a==="added"?"add":a==="removed"?"rem":e.kind==="app"?"app":e.kind==="data"?"data":"line"})`)}}}function ut(e){let s=P("#arch-card");if(!s||(rt(),s.classList.toggle("hl-on",!!e),!e))return;let n=new Set([e]);for(let{e:i,g:a,path:o,lbl:p}of C.wires){let d=i.from===e||i.to===e;a.classList.toggle("hl",d),p&&p.classList.toggle("hl",d),d&&(n.add(i.from),n.add(i.to),o.setAttribute("marker-end","url(#aw-hl)"))}for(let{n:i,el:a}of C.nodes.values())a.classList.toggle("hl",n.has(i.id))}function nt(){if(!C.svg)return;C.svg.setAttribute("viewBox",`${C.vb.x} ${C.vb.y} ${C.vb.w} ${C.vb.h}`);let e=P("#arch-stage").getBoundingClientRect(),s=P("#arch-pct");s&&e.width&&(s.textContent=`${Math.round(e.width/C.vb.w*100)}%`)}function Ge(e){let s=P("#arch-stage");if(!s||!C.layout)return!1;let n=s.getBoundingClientRect();if(!n.width||!n.height)return!1;let i=C.layout.bounds,a=40,o=Math.min(1.1,(n.width-a*2)/i.w,(n.height-a*2)/i.h),p=Math.max(o,n.width<640?.5:.2),d=p>o+1e-6,l=n.width/p,c=n.height/p,r=d?{x:i.x-a/p,y:i.y-a/p,w:l,h:c}:{x:i.x+i.w/2-l/2,y:i.y+i.h/2-c/2,w:l,h:c};if(!e||$e)return C.vb=r,nt(),!0;let u={...C.vb},m=performance.now(),g=f=>{let y=Math.min(1,(f-m)/320),D=1-(1-y)**3;for(let F of["x","y","w","h"])C.vb[F]=u[F]+(r[F]-u[F])*D;nt(),y<1&&requestAnimationFrame(g)};return requestAnimationFrame(g),!0}function Mt(e,s,n){let i=P("#arch-stage").getBoundingClientRect(),a=s??i.width/2,o=n??i.height/2,p=Math.min(8e3,Math.max(160,C.vb.w*e)),d=p/C.vb.w;C.vb.x+=a/i.width*C.vb.w*(1-d),C.vb.y+=o/i.height*C.vb.h*(1-d),C.vb.w=p,C.vb.h*=d,nt()}function Rs(e){let s=new Map,n=null;e.addEventListener("wheel",a=>{a.preventDefault();let o=e.getBoundingClientRect();a.ctrlKey||Math.abs(a.deltaY)>Math.abs(a.deltaX)*1.2||a.deltaMode?Mt(Math.exp(a.deltaY*(a.ctrlKey?.01:.0016)),a.clientX-o.left,a.clientY-o.top):(C.vb.x+=a.deltaX*C.vb.w/o.width,C.vb.y+=a.deltaY*C.vb.h/o.height,nt())},{passive:!1}),e.addEventListener("pointerdown",a=>{if(a.button===0){if(s.set(a.pointerId,[a.clientX,a.clientY]),s.size===2){let[o,p]=[...s.values()];n={d:Math.hypot(o[0]-p[0],o[1]-p[1]),w:C.vb.w},C.drag=null;return}C.drag={x:a.clientX,y:a.clientY,vx:C.vb.x,vy:C.vb.y},C.dragMoved=!1}}),e.addEventListener("pointermove",a=>{if(s.has(a.pointerId)&&s.set(a.pointerId,[a.clientX,a.clientY]),n&&s.size===2){let[l,c]=[...s.values()],r=e.getBoundingClientRect(),u=n.w*n.d/Math.max(20,Math.hypot(l[0]-c[0],l[1]-c[1]))/C.vb.w;Mt(u,(l[0]+c[0])/2-r.left,(l[1]+c[1])/2-r.top),C.dragMoved=!0;return}if(!C.drag)return;let o=a.clientX-C.drag.x,p=a.clientY-C.drag.y;if(!C.dragMoved&&Math.abs(o)+Math.abs(p)>4&&(C.dragMoved=!0,e.classList.add("dragging"),me(),ut(null)),!C.dragMoved)return;let d=e.getBoundingClientRect();C.vb.x=C.drag.vx-o*C.vb.w/d.width,C.vb.y=C.drag.vy-p*C.vb.h/d.height,nt()});let i=a=>{s.delete(a.pointerId),s.size<2&&(n=null),C.drag=null,e.classList.remove("dragging"),setTimeout(()=>{C.dragMoved=!1},0)};e.addEventListener("pointerup",i),e.addEventListener("pointercancel",i),e.addEventListener("pointerleave",a=>{C.drag&&i(a)})}function Ds(){let e=C.layout.bounds,s=40;Ft(C.svg,{x:e.x-s,y:e.y-s,w:e.w+s*2,h:e.h+s*2},`${x.project}-system-architecture.svg`,["whit","wdot","arch-bg"]),We("Architecture diagram exported as SVG","download")}function ct(){let e=P("#page-system"),s=C.svg&&C.fitted?{...C.vb}:null;e.innerHTML="",C.svg=null;let n=re.summary,i=He([{value:"diff",label:"Changes",disabled:!M},{value:"base",label:"Before",disabled:!M},{value:"cur",label:"After"}],E.view,m=>{E.view=m,Dt()});i.classList.add("sys-tabs");let a=m=>M&&(m.added||m.removed)?[m.added?t("span",{class:"chip add",text:`+${m.added}`}):null,m.removed?t("span",{class:"chip rem",text:`\u2212${m.removed}`}):null]:null,o=(m,g,f,y)=>t("div",{class:"sys-stat"},$(y),t("b",{class:"num",text:m}),t("span",{text:g}),a(f));if(e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Architecture"}),t("p",{text:"A container diagram drawn from your code: who uses the system, the apps in this repo, the data they keep and the outside systems they call."})),t("div",{class:"right"},i))),n&&e.append(t("div",{class:"sys-stats stagger"},o(n.apps.total,n.apps.total===1?"app":"apps",n.apps,"layers"),o(n.entry.total,"entry points",n.entry,"code"),o(n.stores.total,n.stores.total===1?"data store":"data stores",n.stores,"database"),o(n.outside.total,n.outside.total===1?"outside system":"outside systems",n.outside,"cloud"))),!re.apps.length){e.append(t("div",{class:"card"},t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("layers")),t("h4",{text:"No apps found"}),t("p",{text:"Tecton looks for package.json files to find the apps in a repo."}))));return}let p=v("svg",{id:"arch-svg",role:"img","aria-label":`Container diagram of ${x.project}`}),d=t("div",{id:"arch-stage"},p),l=(m,g,f)=>t("span",{class:"ak"},v("svg",{viewBox:"0 0 26 16","aria-hidden":"true"},f||v("g",{class:`aw ${m}`},v("path",{class:"wl",d:"M2,8 L24,8"}))),g),c=(m,g)=>v("path",{class:`ak-shape ${m}`,d:g}),r=t("div",{class:"arch-legend"},l("","Person",c("","M13,1.5 a3,3 0 1 1 0,6 a3,3 0 1 1 0,-6 M5,15 q0,-6 8,-6 q8,0 8,6 z")),l("","App (container)",c("","M3,3 h20 a2,2 0 0 1 2,2 v8 a2,2 0 0 1 -2,2 h-20 a2,2 0 0 1 -2,-2 v-8 a2,2 0 0 1 2,-2 z")),l("","Database",c("","M6,3 a7,2.5 0 0 1 14,0 v10 a7,2.5 0 0 1 -14,0 z M6,3 a7,2.5 0 0 0 14,0")),l("","Queue",c("","M5,3 h16 a3,5 0 0 1 0,10 h-16 a3,5 0 0 1 0,-10 z M21,3 a3,5 0 0 0 0,10")),l("","Outside system",c("ext","M2,3 h22 v10 h-22 z")),l("","This repo",c("bnd","M2,3 h22 v10 h-22 z")),t("span",{class:"ak-sep"}),l("k-app","calls"),l("k-data","reads / writes"),l("k-data async","async (queue)"),l("k-outside","outside call"),M?[l("added","new"),l("removed","removed")]:null),u=t("div",{class:"zoom glass"},t("button",{"aria-label":"Zoom in","data-tip":"Zoom in",on:{click:()=>Mt(1/1.3)}},$("plus")),t("button",{"aria-label":"Zoom out","data-tip":"Zoom out",on:{click:()=>Mt(1.3)}},$("minus")),t("button",{"aria-label":"Fit to screen","data-tip":"Fit to screen (F)",on:{click:()=>Ge(!0)}},$("fit")),t("button",{"aria-label":"Export SVG","data-tip":"Export as SVG",on:{click:Ds}},$("image")),t("div",{class:"pct",id:"arch-pct",text:"100%"}));e.append(t("div",{class:"card arch-card",id:"arch-card"},d,t("div",{class:"float br"},u),t("div",{class:"float bl"},t("div",{class:"arch-hint glass"},$("sparkle"),"Hover to trace \xB7 click for the exact lines \xB7 drag to pan"))),r),e.appendChild(t("p",{class:"faint sys-note",text:"Detected from package.json files, imports, route files and route definitions, queue names, cron schedules, URLs in the code and .env.example files."})),Ps(p),rt(),Rs(d),requestAnimationFrame(()=>{et(),s?(C.vb=s,nt()):C.fitted=Ge(!1)})}function Ae(e){ls.sel=e;let s=P("#sheet");s.innerHTML="";let n=t("div",{class:"drawer-b"}),i,a,o,p="",d=l=>t("div",{class:"ev"},l.map(c=>t("div",{class:"ev-row"},t("code",{text:`${c.file}:${c.line}`}),c.text?t("span",{class:"to",text:c.text}):null)));if(e.type==="app"){let l=pt.get(e.id);i=l.name,a=`${l.framework} app \xB7 ${l.root?`${l.root}/`:"repo root"}${l.pkgName&&l.pkgName!==l.name?` \xB7 package "${l.pkgName}"`:""}`,o=ht(l),n.append(t("div",{class:"kv-grid"},t("div",null,t("div",{class:"k",text:"Files"}),t("div",{class:"v",text:l.fileCount})),t("div",null,t("div",{class:"k",text:"Entry points"}),t("div",{class:"v",text:qe.reduce((r,u)=>r+(l.groups[u.key]||[]).filter(m=>m.status!=="removed").length,0)})),t("div",null,t("div",{class:"k",text:"Modules"}),t("div",{class:"v",text:(l.modules||[]).length}))));let c=re.links.filter(r=>(r.from===l.id||r.to===l.id)&&ns(r));c.length&&n.append(t("div",null,t("div",{class:"sec-t",text:"Connections"}),t("div",{class:"pill-list"},c.map(r=>{let u=r.from===l.id?r.to:r.from,m=Pt.get(u);return t("button",{class:"pill-item",on:{click:()=>m?Ae({type:"svc",id:u}):pt.has(u)?Ae({type:"app",id:u}):null}},$(m?re.stores.includes(m)?Nt(m):"cloud":u==="users"?"users":"server","faint"),t("span",{class:"grow",text:`${r.from===l.id?"\u2192 ":"\u2190 "}${m?m.name:os(u)}`}),E.view==="diff"&&r.status!=="same"?he(r.status):null,t("span",{class:"faint",style:{fontSize:"12px"},text:r.labels[0]||""}))})))),l.tech.length&&n.append(t("div",null,t("div",{class:"sec-t",text:"Notable tech"}),t("div",{class:"sys-tech",style:{padding:0}},l.tech.map(r=>t("span",{class:"chip",text:r})))));for(let r of qe){let u=(l.groups[r.key]||[]).filter(ns);u.length&&n.append(t("div",null,t("div",{class:"sec-t",text:`${r.title} \xB7 ${u.length}`}),t("div",{class:"pill-list"},u.map(m=>t("button",{class:"pill-item",title:`${m.file}:${m.line}`,on:{click:()=>Ae({type:"item",app:l.id,group:r.key,key:m.key})}},m.methods&&m.methods.length?m.methods.map(g=>t("span",{class:`meth m-${g.toLowerCase()}`,text:g})):$(r.icon,"faint"),t("span",{class:"grow mono-s",text:m.label}),m.human?t("span",{class:"faint",style:{fontSize:"12px"},text:m.human}):null,E.view==="diff"&&M&&m.status!=="same"?he(m.status):null)))))}}else if(e.type==="svc"){let l=Pt.get(e.id),c=re.stores.includes(l);i=l.name,a=`${l.kind}${l.via&&l.via.length?` \xB7 via ${l.via.join(", ")}`:""}`,o=c?Nt(l):l.kind==="Email"?"mail":"cloud",l.kind==="Set by env var"&&n.append(t("div",{class:"muted",text:`The address comes from ${l.via.join(", ")} at run time, so only its name is known. Check .env.example or your deploy settings for where it points.`})),l.status&&l.status!=="same"&&M&&n.append(t("div",null,he(l.status))),n.append(t("div",null,t("div",{class:"sec-t",text:"Used by"}),t("div",{class:"pill-list"},l.apps.map(r=>t("button",{class:"pill-item",on:{click:()=>Ae({type:"app",id:r})}},t("i",{class:"dot",style:{background:Rt(r)}}),t("span",{class:"grow",text:os(r)}),t("span",{class:"faint",style:{fontSize:"12px"},text:(pt.get(r)||{}).framework||""})))))),"hosts"in l&&l.hosts.length&&n.append(t("div",null,t("div",{class:"sec-t",text:"Hosts"}),t("div",{class:"file-list"},l.hosts.map(r=>t("div",{class:E.view==="diff"?r.status==="added"?"plus":r.status==="removed"?"minus":"":"",text:r.host}))))),n.append(t("div",null,t("div",{class:"sec-t",text:`Where the code uses it \xB7 ${l.evidence.length}${l.evidence.length>=25?"+":""}`}),d(l.evidence)))}else{let l=pt.get(e.app),c=qe.find(g=>g.key===e.group),r=l.groups[e.group].find(g=>g.key===e.key);i=`${r.methods&&r.methods.length?`${r.methods.join(" / ")} `:""}${r.label}`,a=`${c.title.replace(/s$/,"")} in ${l.name}`,o=c.icon,r.status&&r.status!=="same"&&M&&n.append(t("div",null,he(r.status))),r.human&&n.append(t("div",{class:"callout info"},$("clock"),t("div",null,t("b",{text:`Runs ${r.human}`}),t("div",{class:"mono-s",text:r.label})))),n.append(t("div",null,t("div",{class:"sec-t",text:"Defined in"}),d([{file:r.file,line:r.line,text:r.cmd||null}])));let u=r.file,m=x.nodes.find(g=>g.files.some(f=>f.path===u));m&&n.append(t("button",{class:"btn",on:{click:()=>{_e(),ve({type:"node",id:m.id})}}},$("map"),`Show module \u201C${m.id}\u201D on the dependency map`))}s.append(t("div",{class:"drawer-h"},t("span",{class:`ico-box ${p}`},$(o)),t("div",{style:{minWidth:0}},t("h3",{text:i}),t("div",{class:"sub",text:a})),t("button",{class:"btn icon ghost","aria-label":"Close",style:{marginLeft:"auto"},on:{click:_e}},$("x"))),n),s.classList.add("open")}function _e(){let e=P("#sheet");e&&e.classList.remove("open"),ls.sel=null,U.file&&Be(null)}function Dt(){let e=P("#view-tabs");e&&e._set(E.view),Ye(),se(".sys-tabs").forEach(s=>s._set&&s._set(E.view)),C.svg?rt():ct(),E.page==="module"&&kt(U.id)}function ds(){if(!re.apps.length)return null;let e=re.summary,s=t("div",{class:"glance"});re.hasUsers&&s.append(t("div",{class:"g-node users"},$("users"),"Users"),t("span",{class:"g-arrow"},$("arrowRight"))),Cs().forEach((i,a,o)=>{let p=qe.map(d=>[d,(i.groups[d.key]||[]).filter(l=>l.status!=="removed").length]).filter(([,d])=>d);s.append(t("button",{class:"g-node g-app",style:{"--app":Rt(i.id)},on:{click:()=>{ae("system"),setTimeout(()=>Ae({type:"app",id:i.id}),60)}}},t("span",{class:"ico-box app-ico"},$(ht(i))),t("span",null,t("b",{text:i.name}),t("span",{class:"faint",text:`${i.framework}${p.length?` \xB7 ${p.map(([d,l])=>`${l} ${d.title.toLowerCase().replace("routes & api","routes").replace("http endpoints","endpoints").replace("jobs & scripts","jobs").replace("schedules",l===1?"schedule":"schedules")}`).join(" \xB7 ")}`:""}`})))),a<o.length-1&&s.append(t("span",{class:"g-arrow"},$("arrowRight")))});let n=t("div",{class:"g-tail"},re.stores.filter(i=>i.status!=="removed").map(i=>t("span",{class:"chip"},$(Nt(i)),i.name)),t("span",{class:"chip"},$("cloud"),ee(e.outside.total,"outside service")),M&&e.outside.added?t("span",{class:"chip add",text:`+${e.outside.added} new ${e.outside.added===1?"service":"services"}`}):null,M&&e.entry.added?t("span",{class:"chip add",text:`+${e.entry.added} entry points`}):null);return t("div",{class:"card",style:{marginTop:"14px"}},t("div",{class:"card-h"},t("h3",{text:"Architecture"}),t("div",{class:"right"},t("button",{class:"link-btn",on:{click:()=>ae("system")}},"Open diagram",$("right")))),t("div",{class:"card-b"},s,n))}var U={id:null,file:null,pending:null,onlyTouched:!1,els:null,rows:new Map,refresh:null},rs=250;function Me(e,s){U.pending=s||null;let n=`module:${encodeURIComponent(e)}`;location.hash!==`#${n}`?location.hash=n:st(n)}function Fs(e){if(!e.length)return"";let s=e[0].split("/").slice(0,-1);for(let n of e){let i=n.split("/"),a=0;for(;a<s.length&&a<i.length-1&&s[a]===i[a];)a++;s=s.slice(0,a)}return s.join("/")}var js=e=>e.from.module!==e.to.module?`${e.from.module}\u2192${e.to.module}`:null,mt=e=>{let s=js(e);return s&&ie(e.status)&&ot().get(s)||null},Et=e=>ie(e.status)&&(!U.onlyTouched||Ve(e)!=="same");function Hs(e,s,n){let i=new Map,a=new Set,o=(r,u,m)=>{let g=`${r}\u2192${u}`;i.has(g)||i.set(g,{id:g,from:r,to:u,deps:[]}),i.get(g).deps.push(m)};for(let r of s){for(let u of r.out)u.to.module===e?o(r.path,u.to.path,u):(a.add(u.to.module),o(r.path,`mod:${u.to.module}`,u));for(let u of r.in)u.from.module!==e&&(a.add(u.from.module),o(`mod:${u.from.module}`,r.path,u))}let p=(r,u)=>r.length*7.3>=u.length*6.4?r:r.padEnd(Math.ceil(u.length*6.4/7.3)," "),d=s.map(r=>{let u=n(r),m=u.includes("/")?u.slice(0,u.lastIndexOf("/")+1):"";return{id:r.path,name:u.split("/").pop(),meta:m,file:r}});[...a].sort().forEach(r=>d.push({id:`mod:${r}`,name:r,meta:"module",mod:r})),d.forEach(r=>{r.label=p(r.name,r.meta)});let l=[...i.values()].map(r=>{let u=r.deps.map(g=>g.status),m=u.every(g=>g==="added")?"added":u.every(g=>g==="removed")?"removed":"same";return{...r,status:m,countBase:r.deps.filter(g=>g.status!=="added").length,countCur:r.deps.filter(g=>g.status!=="removed").length}}),c=ts(d.map(r=>({id:r.id,label:r.label,external:!!r.mod})),l);return{nodes:d,edges:l,lay:c}}function Ws(e){if(e.mod)return`<div class="tt">${ce(e.name)}</div><div class="kv"><span>Another module</span><b></b></div><div class="kv faint"><span>Click to open its files</span></div>`;let s=e.file,n=Ve(s);return`<div class="tt">${ce(e.name)}${M&&n!=="same"?` <span class="badge ${n==="added"?"add":n==="removed"?"rem":"acc"}">${n[0].toUpperCase()}${n.slice(1)}</span>`:""}</div><div class="kv"><span class="mono-s">${ce(s.path)}</span></div><div class="kv"><span>Imports</span><b>${s.out.filter(i=>ie(i.status)).length}</b></div><div class="kv"><span>Imported by</span><b>${s.in.filter(i=>ie(i.status)).length}</b></div>`}function Us(e){let s=e.status==="removed"?e.countBase:e.countCur,n=a=>a.startsWith("mod:")?a.slice(4):a.split("/").pop(),i=[...new Set(e.deps.flatMap(a=>(mt(a)||[]).map(o=>o.rule)))];return`<div class="tt">${ce(n(e.from))} <span class="faint">\u2192</span> ${ce(n(e.to))}</div><div class="kv"><span>Imports</span><b>${e.status==="same"&&e.countBase!==e.countCur?`${e.countBase} \u2192 ${e.countCur}`:s}</b></div>`+(M&&e.status!=="same"?`<div class="kv"><span>Status</span><b>${e.status==="added"?"New":"Removed"}</b></div>`:"")+i.map(a=>`<div class="kv" style="color:var(--viol-text)"><span>\u26A0 ${ce(a)}</span></div>`).join("")}function zs(e,s){e.innerHTML="";let n=28,i=s.lay.width+n*2,a=s.lay.height+n*2,o=v("svg",{class:"fmap-svg",width:i,height:a,viewBox:`${-n} ${-n} ${i} ${a}`,role:"group","aria-label":"Files in this module and what they import"}),p=v("defs");p.innerHTML='<filter id="fm-shadow" x="-20%" y="-30%" width="140%" height="170%"><feDropShadow dx="0" dy="1" stdDeviation="1.5" flood-color="#101018" flood-opacity=".08"/></filter>'+["line","add","rem","viol","accent"].map(r=>`<marker id="fm-arr-${r}" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="10" markerHeight="10" orient="auto-start-reverse" markerUnits="userSpaceOnUse"><path d="M1,1.5 L9,5 L1,8.5 Q2.5,5 1,1.5 z" style="fill: var(--${r})"/></marker>`).join(""),o.appendChild(p);let d=v("g"),l=v("g");o.append(d,l);let c={nodes:new Map,edges:new Map};return s.edges.forEach(r=>{let u=Ct(s.lay.routes[r.id]),m=v("path",{class:"line",d:u}),g=v("g",{class:"edge"},v("path",{class:"glow",d:u}),m,v("path",{class:"hit",d:u}));g.addEventListener("pointermove",f=>Le(f,Us(r))),g.addEventListener("pointerleave",me),d.appendChild(g),c.edges.set(r.id,{e:r,el:g,line:m})}),s.nodes.forEach(r=>{let u=s.lay.pos[r.id],m=v("g",{class:`node${r.mod?" external":""}`,transform:`translate(${u.x},${u.y})`,tabindex:0,role:"button","aria-label":r.mod?`Open module ${r.name}`:`File ${r.file.path}`}),g=(y,D,F)=>v("g",{class:`nbadge ${y}`,transform:`translate(${u.w-F-8},-8)`},v("rect",{width:F,height:15,rx:4}),v("text",{x:F/2,y:10.5,"text-anchor":"middle"},D));m.append(v("rect",{class:"card-r",width:u.w,height:u.h,rx:r.mod?u.h/2:10}),v("g",{class:"n-ico",transform:`translate(12,${(u.h-16)/2}) scale(0.667)`,html:r.mod?ke.box:ke.file}),v("text",{class:"n-name",x:36,y:r.meta?20:u.h/2+4.5},r.name),r.meta?v("text",{class:"n-meta",x:36,y:35},r.meta):null,g("b-add","NEW",34),g("b-rem","GONE",38)),r.file&&r.file.edited&&r.file.status==="same"&&m.appendChild(v("circle",{class:"tdot",cx:u.w-11,cy:u.h/2,r:3.5}));let f=()=>r.mod?Me(r.mod):Be(U.file===r.id?null:r.id);m.addEventListener("click",y=>{y.stopPropagation(),f()}),m.addEventListener("keydown",y=>{(y.key==="Enter"||y.key===" ")&&(y.preventDefault(),f())}),m.addEventListener("pointermove",y=>Le(y,Ws(r))),m.addEventListener("pointerleave",me),l.appendChild(m),c.nodes.set(r.id,{x:r,el:m})}),o.addEventListener("click",()=>Be(null)),e.appendChild(o),c}function cs(){let e=U.els;if(!e)return;let s=U.file,n=d=>{let l=e.nodes.get(d).x;return l.mod?!0:Et(l.file)},i=new Set,a=new Set;for(let{e:d}of e.edges.values())ie(d.status)&&n(d.from)&&n(d.to)&&(i.add(d.id),[d.from,d.to].forEach(l=>{l.startsWith("mod:")&&a.add(l)}));let o=s?new Set([...i].filter(d=>{let l=e.edges.get(d).e;return l.from===s||l.to===s})):null,p=s?new Set([s,...[...o].flatMap(d=>{let l=e.edges.get(d).e;return[l.from,l.to]})]):null;for(let{e:d,el:l,line:c}of e.edges.values()){let r=i.has(d.id),u=E.view==="diff"?d.status:"same",m=r&&!(E.view==="diff"&&d.status==="removed")&&d.deps.some(f=>mt(f)),g=o&&o.has(d.id);l.setAttribute("class",`edge ${u}${m?" viol":""}${g?" sel":""}${r?"":" gone"}${o&&!g?" dim":""}`),c.setAttribute("marker-end",`url(#fm-arr-${g?"accent":m?"viol":u==="added"?"add":u==="removed"?"rem":"line"})`)}for(let{x:d,el:l}of e.nodes.values()){let c=d.mod?a.has(d.id):Et(d.file),r=d.file&&E.view==="diff"&&M?Ve(d.file):"same",u=r==="edited"?"same touched":r;l.setAttribute("class",`node${d.mod?" external":""} ${u}${s===d.id?" sel":""}${c?"":" gone"}${p&&!p.has(d.id)?" dim":""}`)}}function Be(e){if(U.file=e&&je.has(e)?e:null,cs(),U.rows.forEach((s,n)=>s.classList.toggle("sel",n===U.file)),me(),U.file){Vs(je.get(U.file));let s=U.rows.get(U.file),n=U.els&&U.els.nodes.get(U.file);n?n.el.scrollIntoView({block:"nearest",inline:"center",behavior:$e?"auto":"smooth"}):s&&s.scrollIntoView({block:"nearest"})}else{let s=P("#sheet");s&&s.classList.remove("open")}}function Vs(e){let s=P("#sheet");s.innerHTML="";let n=Ve(e),i=e.out.filter(c=>ie(c.status)).sort((c,r)=>+(c.to.module===e.module)-+(r.to.module===e.module)||c.to.path.localeCompare(r.to.path)),a=e.in.filter(c=>ie(c.status)).sort((c,r)=>+(c.from.module===e.module)-+(r.from.module===e.module)||c.from.path.localeCompare(r.from.path)),o=(c,r)=>{let u=r==="out"?c.to:c.from,m=u.module===e.module,g=mt(c);return t("button",{class:"pill-item",title:u.path,on:{click:()=>m?Be(u.path):Me(u.module,u.path)}},$("file","faint"),t("span",{class:"grow mono-s ell",text:m?u.path.split("/").pop():u.path}),m?null:t("span",{class:`chip${g?" viol":""}`,text:u.module}),E.view==="diff"&&M&&c.status!=="same"?he(c.status):null,t("span",{class:"faint mono-s",title:r==="out"?`line ${c.line} of this file`:`line ${c.line} of ${u.path}`,text:`:${c.line}`}))},p=[...new Set(i.flatMap(c=>(mt(c)||[]).map(r=>r.rule)))],d=[...new Set(i.filter(c=>c.to.module!==e.module).map(c=>c.to.module))],l=t("div",{class:"drawer-b"});M&&n!=="same"&&l.append(t("div",null,he(n)," ",t("span",{class:"chip",text:`module ${e.module}`}))),p.forEach(c=>l.append(t("div",{class:"callout"},$("alert"),t("div",null,t("b",{text:`An import here breaks \u201C${c}\u201D`}),t("div",{text:"The rule-breaking imports are marked in orange below."}))))),l.append(t("div",{class:"kv-grid"},t("div",null,t("div",{class:"k",text:"Imports"}),t("div",{class:"v",text:i.length})),t("div",null,t("div",{class:"k",text:"Imported by"}),t("div",{class:"v",text:a.length})),t("div",null,t("div",{class:"k",text:"Other modules"}),t("div",{class:"v",text:d.length})))),i.length&&l.append(t("div",null,t("div",{class:"sec-t",text:`Imports \xB7 ${i.length}`}),t("div",{class:"pill-list"},i.map(c=>o(c,"out"))))),a.length&&l.append(t("div",null,t("div",{class:"sec-t",text:`Imported by \xB7 ${a.length}`}),t("div",{class:"pill-list"},a.map(c=>o(c,"in"))))),!i.length&&!a.length&&l.append(t("div",{class:"muted",text:"This file does not import other files in the analysed code, and nothing imports it."})),s.append(t("div",{class:"drawer-h"},t("span",{class:`ico-box ${n==="added"?"add":n==="removed"?"rem":""}`},$("file")),t("div",{style:{minWidth:0}},t("h3",{text:e.path.split("/").pop()}),t("div",{class:"sub mono-s ell",title:e.path,text:e.path})),t("button",{class:"btn icon ghost","aria-label":"Close",style:{marginLeft:"auto"},on:{click:()=>Be(null)}},$("x"))),l),s.classList.add("open")}function kt(e){let s=P("#page-module");s.innerHTML="";let n=Oe.get(e),i=U.id===e?U.file:null;U.id=e,U.els=null,U.rows=new Map;let a=Jt(e),o=Fs(a.map(_=>_.path)),p=_=>o?_.path.slice(o.length+1):_.path,d=Ee.get(e),l=a.filter(_=>Ve(_)!=="same").length,c=He([{value:"diff",label:"Changes",disabled:!M},{value:"base",label:"Before",disabled:!M},{value:"cur",label:"After"}],E.view,_=>{E.view=_,Dt()}),r=a.filter(_=>ie(_.status)).length;s.append(t("div",{class:"page-head"},t("div",{style:{minWidth:0}},t("button",{class:"link-btn back",on:{click:()=>ae("modules")}},$("arrowLeft"),"All modules"),t("h1",{class:"ell",text:e,title:e}),t("p",{text:`${ee(r,"file")}${o?` in ${o}/`:""} \xB7 uses ${ee(d.uses,"module")} \xB7 used by ${ee(d.usedBy,"module")}`})),t("div",{class:"right"},c,t("button",{class:"btn",on:{click:()=>ve({type:"node",id:e})}},$("map"),t("span",{class:"lbl-t",text:"Show on map"})))));let u=[M&&n.status!=="same"?he(n.status):null,M&&l?t("span",{class:"chip acc"},$("pencil"),`${l} ${l===1?"file":"files"} edited in this change`):null,d.viol?t("span",{class:"chip viol"},$("alert"),ee(d.viol,"rule break")):null].filter(Boolean);u.length&&s.append(t("div",{class:"chip-row"},u));let m=M&&l?t("label",{class:"switch"},t("input",{type:"checkbox",checked:U.onlyTouched,on:{change:_=>{U.onlyTouched=_.target.checked,U.refresh()}}}),"Only changed files"):null,g=(_,w)=>t("span",null,v("svg",{viewBox:"0 0 22 8"},v("g",{class:`edge ${_}`},v("path",{class:"line",d:"M1,4 L21,4"}))),w),f=t("div",{class:"fmap",id:"fmap"});s.append(t("div",{class:"card fmap-card"},t("div",{class:"card-h"},t("h3",{text:"How the files connect"}),t("div",{class:"right fmap-legend"},g("same","import"),M?g("added","new"):null,M?g("removed","removed"):null,g("viol","breaks a rule"),M&&l?t("span",null,t("i",{class:"tdot-key"}),"edited"):null)),f)),a.length>rs?f.append(t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("layers")),t("h4",{text:`${ee(a.length,"file")} is too many to draw clearly`}),t("p",{text:`The diagram is drawn for modules with up to ${rs} files. The table below lists every file, or split the module with "depth" or "modules" in tecton.config.json.`}))):a.length?U.els=zs(f,Hs(e,a,p)):f.append(t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("file")),t("h4",{text:"No files"}),t("p",{text:"This module has no files in the analysed code."})));let y=t("tbody"),D=()=>{y.innerHTML="",U.rows=new Map;let _=a.filter(Et).sort((w,z)=>p(w).localeCompare(p(z)));_.length||y.appendChild(t("tr",null,t("td",{colspan:5,class:"faint",text:"No files to show in this view."}))),_.forEach(w=>{let z=w.out.filter(B=>ie(B.status)),b=z.filter(B=>B.to.module===e).length,S=[...new Set(z.filter(B=>B.to.module!==e).map(B=>B.to.module))].sort(),j=w.in.filter(B=>ie(B.status)&&B.from.module!==e).length,V=p(w),ne=V.includes("/")?V.slice(0,V.lastIndexOf("/")+1):"",W=Ve(w),X=t("tr",{class:`click${w.path===U.file?" sel":""}`,tabindex:0,on:{click:()=>Be(U.file===w.path?null:w.path),keydown:B=>{B.key==="Enter"&&Be(w.path)}}},t("td",null,t("div",{class:"cell-mod mono-s"},$("file","faint"),t("span",{class:"ell"},ne?t("span",{class:"faint",text:ne}):null,V.split("/").pop()))),t("td",null,M&&E.view==="diff"&&W!=="same"?he(W):t("span",{class:"faint",text:"\u2014"})),t("td",{class:"r num",text:b}),t("td",null,S.length?t("div",{class:"chip-row tight"},S.slice(0,4).map(B=>{let H=z.some(te=>te.to.module===B&&mt(te));return t("button",{class:`chip mod${H?" viol":""}`,title:H?`Breaks a rule. Open ${B}`:`Open ${B}`,on:{click:te=>{te.stopPropagation(),Me(B)}}},B)}),S.length>4?t("span",{class:"faint",text:`+${S.length-4}`}):null):t("span",{class:"faint",text:"\u2014"})),t("td",{class:"r num",text:j}));U.rows.set(w.path,X),y.appendChild(X)})},F=t("tr",null,t("th",{text:"File"}),t("th",{text:"Change"}),t("th",{class:"r",text:"Imports here"}),t("th",{text:"Uses other modules"}),t("th",{class:"r",text:"Used from outside"}));s.append(t("div",{class:"toolbar",style:{marginTop:"14px"}},t("h3",{class:"toolbar-t",text:"Files"}),m),t("div",{class:"card"},t("div",{class:"tbl-wrap"},t("table",null,t("thead",null,F),y)))),U.refresh=()=>{D(),cs(),U.file&&!Et(je.get(U.file))&&Be(null)},D(),U.file=null;let oe=U.pending||i;U.pending=null,Be(oe&&je.has(oe)&&je.get(oe).module===e?oe:null)}var O={built:!1,animated:!1,vb:{x:0,y:0,w:100,h:100},edgeEls:new Map,nodeEls:new Map};function Ct(e){let s=`M${e[0][0]},${e[0][1]}`;for(let n=1;n<e.length;n++){let i=e[n-1],a=e[n],o=(a[1]-i[1])/2;s+=` C${i[0]},${i[1]+o} ${a[0]},${a[1]-o} ${a[0]},${a[1]}`}return s}function Gs(e){let s=[e[0]];for(let d=1;d<e.length;d++){let l=e[d-1],c=e[d],r=(c[1]-l[1])/2,u=[l[0],l[1]+r],m=[c[0],c[1]-r];for(let g=1;g<=16;g++){let f=g/16,y=1-f;s.push([y*y*y*l[0]+3*y*y*f*u[0]+3*y*f*f*m[0]+f*f*f*c[0],y*y*y*l[1]+3*y*y*f*u[1]+3*y*f*f*m[1]+f*f*f*c[1]])}}let n=0,i=[0];for(let d=1;d<s.length;d++)n+=Math.hypot(s[d][0]-s[d-1][0],s[d][1]-s[d-1][1]),i.push(n);let a=n/2,o=i.findIndex(d=>d>=a);o<1&&(o=1);let p=(a-i[o-1])/(i[o]-i[o-1]||1);return{len:n,mid:[s[o-1][0]+(s[o][0]-s[o-1][0])*p,s[o-1][1]+(s[o][1]-s[o-1][1])*p]}}function ps(){let e=P("#page-map"),s=He([{value:"diff",label:"Changes",disabled:!M},{value:"base",label:"Before",disabled:!M},{value:"cur",label:"After"}],E.view,m=>{E.view=m,Ye()});s.id="view-tabs";let n=t("label",{class:"switch glass",style:{display:M?"":"none"},title:"Show only dependencies that were added, removed or break a rule"},t("input",{type:"checkbox",id:"focus-sw",on:{change:m=>{if(E.focusOnly=m.target.checked,E.focusOnly){E.touchedOnly=!1;let g=P("#touched-sw");g&&(g.checked=!1),E.view!=="diff"&&(E.view="diff",s._set("diff"))}Ye()}}}),"Only changes"),i=Ke?t("label",{class:"switch glass",title:"Show only the modules whose files this change edits, and what they connect to"},t("input",{type:"checkbox",id:"touched-sw",on:{change:m=>{E.touchedOnly=m.target.checked,E.touchedOnly&&(E.focusOnly=!1,P("#focus-sw").checked=!1),Ye()}}}),t("i",{class:"tdot-key","aria-hidden":"true"}),"Only touched"):null,a=(m,g)=>t("span",null,v("svg",{viewBox:"0 0 22 8"},v("g",{class:`edge ${m}`},v("path",{class:"line",d:"M1,4 L21,4"}))),g),o=t("div",{class:"legend-float glass"},a("same","Unchanged"),M?a("added","New"):null,M?a("removed","Removed"):null,a("viol","Breaks a rule")),p=t("div",{class:"pct",id:"zoom-pct",text:"100%"}),d=t("div",{class:"zoom glass"},t("button",{"aria-label":"Zoom in","data-tip":"Zoom in",on:{click:()=>Ht(1/1.3)}},$("plus")),t("button",{"aria-label":"Zoom out","data-tip":"Zoom out",on:{click:()=>Ht(1.3)}},$("minus")),t("button",{"aria-label":"Fit to screen","data-tip":"Fit to screen (F)",on:{click:()=>at(!0)}},$("fit")),t("button",{"aria-label":"Export SVG","data-tip":"Export as SVG",on:{click:Lt}},$("image")),p),l=t("div",{class:"minimap glass",id:"minimap"}),c=v("svg",{id:"map-svg",role:"img","aria-label":"Module dependency map"}),r=t("div",{id:"stage"},c),u=t("aside",{class:"drawer",id:"drawer","aria-label":"Details"});e.append(t("div",{class:"card map-card"},r,t("div",{class:"float tl"},t("div",{class:"glass",style:{padding:"0",borderRadius:"11px"}},s),n,i,o),t("div",{class:"float br"},d),t("div",{class:"float bl"},l),u)),_s(c),Ks(l),Zs(r)}function _s(e){let s=v("defs");s.innerHTML='<filter id="nshadow" x="-20%" y="-30%" width="140%" height="170%"><feDropShadow dx="0" dy="1" stdDeviation="1.5" flood-color="#101018" flood-opacity=".08"/></filter><pattern id="dots" width="18" height="18" patternUnits="userSpaceOnUse"><circle cx="1" cy="1" r="1" style="fill: var(--dot)"/></pattern>',["line","add","rem","viol","accent"].forEach(d=>{let l=v("marker",{id:`arr-${d}`,viewBox:"0 0 10 10",refX:9,refY:5,markerWidth:10,markerHeight:10,orient:"auto-start-reverse",markerUnits:"userSpaceOnUse"});l.appendChild(v("path",{d:"M1,1.5 L9,5 L1,8.5 Q2.5,5 1,1.5 z",style:`fill: var(--${d})`})),s.appendChild(l)}),e.appendChild(s),e.appendChild(v("rect",{x:-2e4,y:-2e4,width:4e4,height:4e4,fill:"url(#dots)"}));let n=v("g",{id:"world"}),i=v("g"),a=v("g"),o=v("g");n.append(i,a,o),e.appendChild(n);let p=Math.max(1,x.height);x.edges.forEach((d,l)=>{let c=Ct(d.points),{len:r,mid:u}=Gs(d.points),m=v("g",{class:"edge",style:`--len:${Math.ceil(r)};--d:${d.points[0][1]/p*.6+.15}s`});m.appendChild(v("path",{class:"glow",d:c}));let g=v("path",{class:"line",d:c,id:`ep${l}`});if(m.appendChild(g),m.appendChild(v("path",{class:"hit",d:c})),(d.status==="added"||Ie.cur.has(d.id))&&!$e){let w=v("circle",{class:"flow",r:2.6}),z=v("animateMotion",{dur:`${Math.max(1.6,r/70).toFixed(2)}s`,repeatCount:"indefinite",rotate:"auto"});z.appendChild(v("mpath",{href:`#ep${l}`})),w.appendChild(z),m.appendChild(w)}i.appendChild(m);let y=v("g",{class:"edge"}),D=v("g",{class:"lbl",transform:`translate(${u[0].toFixed(1)},${u[1].toFixed(1)})`}),F=v("rect",{rx:8,height:16,y:-8}),oe=v("text",{"text-anchor":"middle","dominant-baseline":"central",y:.5});D.append(F,oe),y.appendChild(D),o.appendChild(y);let _=w=>{O.dragMoved||(w.stopPropagation(),Te({type:"edge",id:d.id}))};[m,y].forEach(w=>{w.addEventListener("click",_),w.addEventListener("pointermove",z=>{O.drag||Le(z,qs(d))}),w.addEventListener("pointerleave",me)}),y.style.cursor="pointer",O.edgeEls.set(d.id,{g:m,line:g,lbl:y,lr:F,lt:oe})}),x.nodes.forEach((d,l)=>{let c=d.pos,r=v("g",{class:`node${d.external?" external":""}`,transform:`translate(${c.x},${c.y})`,tabindex:0,role:"button","aria-label":d.id}),u=v("g",{style:`--d:${c.y/p*.5+l%5*.03}s`});u.appendChild(v("rect",{class:"card-r",width:c.w,height:c.h,rx:d.external?c.h/2:10}));let m=v("g",{class:"n-ico",transform:`translate(12,${(c.h-16)/2}) scale(0.667)`,html:d.external?ke.pkg:ke.box});u.appendChild(m),u.appendChild(v("text",{class:"n-name",x:36,y:20},Y(d.id)));let g=v("text",{class:"n-meta",x:36,y:35});u.appendChild(g);let f=(y,D,F)=>v("g",{class:`nbadge ${y}`,transform:`translate(${c.w-F-8},-8)`},v("rect",{width:F,height:15,rx:4}),v("text",{x:F/2,y:10.5,"text-anchor":"middle"},D));u.appendChild(f("b-add","NEW",34)),u.appendChild(f("b-rem","GONE",38)),d.touched&&u.appendChild(v("circle",{class:"tdot",cx:c.w-11,cy:c.h/2,r:3.5})),r.appendChild(u),r.addEventListener("click",y=>{O.dragMoved||(y.stopPropagation(),Te({type:"node",id:d.id}))}),d.external||r.addEventListener("dblclick",y=>{y.stopPropagation(),Me(d.id)}),r.addEventListener("keydown",y=>{(y.key==="Enter"||y.key===" ")&&(y.preventDefault(),Te({type:"node",id:d.id}))}),r.addEventListener("pointermove",y=>{O.drag||Le(y,Qs(d))}),r.addEventListener("pointerleave",me),a.appendChild(r),O.nodeEls.set(d.id,{g:r,inner:u,meta:g})}),e.addEventListener("click",()=>{!O.dragMoved&&E.selected&&Te(null)}),O.world=n,O.svg=e,O.built=!0,Ye()}function ie(e){return E.view==="diff"?!0:E.view==="base"?e!=="added":e!=="removed"}var ot=()=>E.view==="base"?Ie.base:Ie.cur;function Ye(){if(!O.built)return;let e=ot(),s=E.selected,n=null,i=null;if(s)if(n=new Set,i=new Set,s.type==="node")n.add(s.id),x.edges.forEach(o=>{(o.from===s.id||o.to===s.id)&&ie(o.status)&&(i.add(o.id),n.add(o.from),n.add(o.to))});else if(s.type==="edge"){let o=Ue.get(s.id);i.add(o.id),n.add(o.from),n.add(o.to)}else lt.get(s.id).edges.forEach(o=>{let p=Ue.get(o);p&&(i.add(o),n.add(p.from),n.add(p.to))});else E.focusOnly&&E.view==="diff"?(n=new Set,i=new Set,x.edges.forEach(o=>{(Ot(o)||e.has(o.id))&&(i.add(o.id),n.add(o.from),n.add(o.to))}),x.nodes.forEach(o=>{o.status!=="same"&&n.add(o.id)})):E.touchedOnly&&(n=new Set(dt),i=new Set,x.edges.forEach(o=>{ie(o.status)&&(dt.has(o.from)||dt.has(o.to))&&(i.add(o.id),n.add(o.from),n.add(o.to))}));let a=new Set;x.edges.forEach(o=>{let p=O.edgeEls.get(o.id),d=ie(o.status),l=E.view==="diff"?o.status:"same",c=e.has(o.id)&&d&&!(E.view==="diff"&&o.status==="removed");c&&(a.add(o.from),a.add(o.to));let r=s&&s.type==="edge"&&s.id===o.id,u=p.g.classList.contains("draw-in")?" draw-in":"",m=`edge ${l}${c?" viol":""}${r?" sel":""}${d?"":" gone"}${i&&!i.has(o.id)?" dim":""}`;p.g.setAttribute("class",m+u),p.lbl.setAttribute("class",m);let g=r?"accent":c?"viol":l==="added"?"add":l==="removed"?"rem":"line";p.line.setAttribute("marker-end",`url(#arr-${g})`);let f;E.view==="diff"?o.status==="added"?f=`+${o.countCur}`:o.status==="removed"?f=`\u2212${o.countBase}`:f=o.countBase===o.countCur?String(o.countCur):`${o.countBase}\u2192${o.countCur}`:f=String(E.view==="base"?o.countBase:o.countCur),c&&(f=`\u26A0 ${f}`),p.lt.textContent=f;let y=Math.max(20,f.length*6.3+12);p.lr.setAttribute("width",y),p.lr.setAttribute("x",-y/2)}),x.nodes.forEach(o=>{let p=O.nodeEls.get(o.id),d=ie(o.status),l=E.view==="diff"?o.status:"same",c=s&&s.type==="node"&&s.id===o.id;p.g.setAttribute("class",`node${o.external?" external":""} ${l}${a.has(o.id)?" inviol":""}${c?" sel":""}${d?"":" gone"}${n&&!n.has(o.id)?" dim":""}${o.touched&&E.view==="diff"?" touched":""}`);let r=E.view==="base"?o.filesBase:E.view==="cur"?o.filesCur:o.status==="removed"?o.filesBase:o.filesCur;p.meta.textContent=o.external?"npm package":E.view==="diff"&&o.status==="same"&&o.filesBase!==o.filesCur?`${o.filesBase} \u2192 ${o.filesCur} files`:ee(r,"file")}),ea(a),Ys()}function Qs(e){let s=Ee.get(e.id);return`<div class="tt">${ce(Y(e.id))}${e.status!=="same"&&M?` <span class="badge ${e.status==="added"?"add":"rem"}">${e.status==="added"?"New":"Removed"}</span>`:""}</div>${e.external?'<div class="kv"><span>npm package</span><b></b></div>':`<div class="kv"><span>Files</span><b>${M&&e.filesBase!==e.filesCur?`${e.filesBase} \u2192 ${e.filesCur}`:e.status==="removed"?e.filesBase:e.filesCur}</b></div>`}<div class="kv"><span>Uses</span><b>${s.uses}</b></div><div class="kv"><span>Used by</span><b>${s.usedBy}</b></div>`+(e.touched&&M?`<div class="kv"><span>Files edited</span><b style="color:var(--accent-text)">${e.touched}</b></div>`:"")+(e.external?"":'<div class="kv faint"><span>Double-click to open its files</span></div>')+(s.viol?`<div class="kv"><span>Rule breaks</span><b style="color:var(--viol-text)">${s.viol}</b></div>`:"")}function qs(e){let s=ot().get(e.id)||[],n=e.status==="removed"?e.countBase:e.countCur;return`<div class="tt">${ce(Y(e.from))} <span class="faint">\u2192</span> ${ce(Y(e.to))}</div><div class="kv"><span>Imports</span><b>${e.status==="same"&&e.countBase!==e.countCur?`${e.countBase} \u2192 ${e.countCur}`:n}</b></div>`+(M?`<div class="kv"><span>Status</span><b>${e.status==="added"?"New":e.status==="removed"?"Removed":"Unchanged"}</b></div>`:"")+s.map(i=>`<div class="kv" style="color:var(--viol-text)"><span>\u26A0 ${ce(i.rule)}</span></div>`).join("")}function Ys(){let e=P("#drawer");if(!e)return;let s=E.selected;if(!s){e.classList.remove("open");return}e.innerHTML="";let n=t("button",{class:"btn icon ghost","aria-label":"Close details",style:{marginLeft:"auto"},on:{click:()=>Te(null)}},$("x")),i=t("div",{class:"drawer-b"}),a;if(s.type==="node"){let o=Oe.get(s.id),p=Ee.get(o.id);a=t("div",{class:"drawer-h"},t("span",{class:`ico-box ${o.status==="added"&&M?"add":o.status==="removed"?"rem":""}`},$(o.external?"pkg":"box")),t("div",{style:{minWidth:0}},t("h3",{text:Y(o.id)}),t("div",{class:"sub"},o.external?"npm package":`${M?{added:"New module",removed:"Removed module",same:"Module"}[o.status]:"Module"} \xB7 ${ee(o.status==="removed"?o.filesBase:o.filesCur,"file")}`)),n),i.append(t("div",{class:"kv-grid"},t("div",null,t("div",{class:"k",text:"Uses"}),t("div",{class:"v",text:p.uses})),t("div",null,t("div",{class:"k",text:"Used by"}),t("div",{class:"v",text:p.usedBy})),t("div",null,t("div",{class:"k",text:"Rule breaks"}),t("div",{class:"v",style:p.viol?{color:"var(--viol-text)"}:null,text:p.viol})))),o.external||i.append(t("button",{class:"btn",on:{click:()=>Me(o.id)}},$("file"),"Open files and how they connect",o.touched&&M?t("span",{class:"chip acc",text:`${o.touched} edited`}):null));let d=x.edges.filter(c=>c.from===o.id&&ie(c.status)),l=x.edges.filter(c=>c.to===o.id&&ie(c.status));if([["Uses",d,"to"],["Used by",l,"from"]].forEach(([c,r,u])=>{r.length&&i.append(t("div",null,t("div",{class:"sec-t",text:`${c} \xB7 ${r.length}`}),t("div",{class:"pill-list"},r.map(m=>{let g=ot().get(m.id);return t("button",{class:"pill-item",on:{click:()=>Te({type:"edge",id:m.id})}},$(m[u].startsWith("npm:")?"pkg":"box","faint"),t("span",{class:"grow",text:Y(m[u])}),g?de("serious","Rule"):null,E.view==="diff"&&m.status!=="same"?he(m.status):null,t("span",{class:"faint num mono",style:{fontSize:"11.5px"},text:String(m.status==="removed"?m.countBase:m.countCur)}))}))))}),o.files.length){let c=o.files.filter(r=>!(E.view==="base"&&r.status==="added")&&!(E.view==="cur"&&r.status==="removed"));i.append(t("div",null,t("div",{class:"sec-t",text:`Files \xB7 ${c.length}`}),t("div",{class:"file-list"},c.slice(0,300).map(r=>{let u=E.view==="diff"&&r.status==="same"&&(je.get(r.path)||{}).edited,m=E.view==="diff"?r.status==="added"?"plus":r.status==="removed"?"minus":u?"edit":"":"";return t("div",{class:`${m} click`,role:"button",tabindex:0,title:"Open this file",on:{click:()=>Me(o.id,r.path),keydown:g=>{g.key==="Enter"&&Me(o.id,r.path)}},text:`${E.view==="diff"&&r.status==="added"?"+ ":E.view==="diff"&&r.status==="removed"?"\u2212 ":u?"~ ":""}${r.path}`})}))))}}else if(s.type==="edge"){let o=Ue.get(s.id),p=ot().get(o.id)||[];a=t("div",{class:"drawer-h"},t("span",{class:`ico-box ${p.length?"viol":o.status==="added"?"add":o.status==="removed"?"rem":""}`},$(p.length?"alert":"link")),t("div",{style:{minWidth:0}},t("h3",null,Y(o.from),t("span",{class:"arrow",text:" \u2192 "}),Y(o.to)),t("div",{class:"sub",text:`${M?{added:"New dependency",removed:"Removed dependency",same:"Dependency"}[o.status]:"Dependency"} \xB7 ${o.status==="same"&&o.countBase!==o.countCur?`imports ${o.countBase} \u2192 ${o.countCur}`:ee(o.status==="removed"?o.countBase:o.countCur,"import")}`})),n),p.forEach(d=>i.append(t("div",{class:"callout"},$("alert"),t("div",null,t("b",{text:`Breaks \u201C${d.rule}\u201D`}),d.message?t("div",{text:d.message}):null)))),i.append(t("div",{class:"pill-list"},[o.from,o.to].map(d=>t("button",{class:"pill-item",on:{click:()=>Te({type:"node",id:d})}},$(d.startsWith("npm:")?"pkg":"box","faint"),t("span",{class:"grow",text:Y(d)}),t("span",{class:"faint",style:{fontSize:"12px"},text:d===o.from?"imports":"is imported"}))))),o.addedImports&&o.addedImports.length&&i.append(t("div",null,t("div",{class:"sec-t",text:"Added in this change"}),tt(o.addedImports,"plus"))),i.append(t("div",null,t("div",{class:"sec-t",text:o.status==="removed"?"Where it used to happen":"Where it happens"}),tt(o.imports)))}else{let o=lt.get(s.id);a=t("div",{class:"drawer-h"},t("span",{class:"ico-box viol"},$(o.kind==="cycle"?"cycle":"alert")),t("div",{style:{minWidth:0}},t("h3",{text:o.rule}),t("div",{class:"sub",text:o.status==="new"?"New in this change":o.status==="fixed"?"Fixed by this change":M?"Already existed before this change":"Found in the current code"})),n),i.append(t("div",null,$t(o)," ",de(o.severity==="error"?"critical":"warn",o.severity==="error"?"Error":"Warning"))),o.message&&i.append(t("div",{class:"callout"},$("alert"),o.message)),i.append(t("div",{class:"muted",text:o.kind==="cycle"?`These modules depend on each other in a loop: ${o.members.map(Y).join(" \u21C4 ")}`:`${Y(o.from)} is not allowed to use ${Y(o.to)}.`})),i.append(t("div",null,t("div",{class:"sec-t",text:"Where it happens"}),tt(o.imports)))}e.append(a,i),e.classList.add("open")}function Te(e,s){E.selected=e&&E.selected&&E.selected.type===e.type&&E.selected.id===e.id&&!s?null:e;let n=E.selected;if(n&&M){let i=n.type==="node"?Oe.get(n.id):n.type==="edge"?Ue.get(n.id):null,a=n.type==="viol"?lt.get(n.id):null;E.view==="cur"&&(i&&i.status==="removed"||a&&a.status==="fixed")&&(E.view="diff"),E.view==="base"&&(i&&i.status==="added"||a&&a.status==="new")&&(E.view="diff");let o=P("#view-tabs");o&&o._set(E.view)}me(),Ye(),n&&s&&Xs()}function ve(e){ae("map"),setTimeout(()=>Te(e,!0),30)}function ft(){let e=O.vb;O.svg.setAttribute("viewBox",`${e.x} ${e.y} ${e.w} ${e.h}`);let s=P("#stage").getBoundingClientRect(),n=P("#zoom-pct");n&&s.width&&(n.textContent=`${Math.round(s.width/e.w*100)}%`),Js()}function St(){return P("#stage").getBoundingClientRect()}function us(e,s,n,i,a,o){let p=St(),d=Math.max(1,p.width),l=Math.max(1,p.height),c=E.selected&&P("#drawer").classList.contains("open")&&d>700?Math.min(400,d):0,r=64,u=n-e+a*2,m=i-s+a*2+r,g=Math.max(u/(d-c),m/l,.55),f={w:d*g,h:l*g};f.x=(e+n)/2-(d-c)*g/2,f.y=(s+i)/2-f.h/2-r/2*g,hs(f,o)}var jt=null;function hs(e,s){if(cancelAnimationFrame(jt),!s||$e){Object.assign(O.vb,e),ft();return}let n={...O.vb},i=performance.now(),a=o=>{let p=Math.min(1,(o-i)/420),d=1-(1-p)**3;["x","y","w","h"].forEach(l=>{O.vb[l]=n[l]+(e[l]-n[l])*d}),ft(),p<1&&(jt=requestAnimationFrame(a))};jt=requestAnimationFrame(a)}function at(e){us(0,-10,x.width,x.height,48,e)}function Xs(){let e=E.selected;if(!e)return;let s=[];if(e.type==="node")s=[e.id],x.edges.forEach(p=>{(p.from===e.id||p.to===e.id)&&ie(p.status)&&s.push(p.from,p.to)});else if(e.type==="edge"){let p=Ue.get(e.id);s=[p.from,p.to]}else lt.get(e.id).edges.forEach(p=>{let d=Ue.get(p);d&&s.push(d.from,d.to)});let n=1/0,i=1/0,a=-1/0,o=-1/0;s.forEach(p=>{let d=Oe.get(p).pos;n=Math.min(n,d.x),i=Math.min(i,d.y),a=Math.max(a,d.x+d.w),o=Math.max(o,d.y+d.h)}),us(n,i,a,o,90,!0)}function Ht(e,s,n){let i=St();s==null&&(s=i.width/2,n=i.height/2);let a=O.vb,o=a.x+s/i.width*a.w,p=a.y+n/i.height*a.h,l=Math.min(Math.max(a.w*e,180),Math.max(x.width,x.height)*6+2400)/a.w;a.x=o-(o-a.x)*l,a.y=p-(p-a.y)*l,a.w*=l,a.h*=l,ft()}function Zs(e){e.addEventListener("wheel",s=>{s.preventDefault();let n=St();s.ctrlKey||Math.abs(s.deltaY)>Math.abs(s.deltaX)*1.2||s.deltaMode?Ht(Math.exp(s.deltaY*(s.ctrlKey?.01:.0016)),s.clientX-n.left,s.clientY-n.top):(O.vb.x+=s.deltaX*O.vb.w/n.width,O.vb.y+=s.deltaY*O.vb.h/n.height,ft())},{passive:!1}),e.addEventListener("pointerdown",s=>{s.button===0&&(O.drag={x:s.clientX,y:s.clientY,vx:O.vb.x,vy:O.vb.y},O.dragMoved=!1)}),window.addEventListener("pointermove",s=>{if(!O.drag)return;let n=s.clientX-O.drag.x,i=s.clientY-O.drag.y;if(!O.dragMoved&&Math.abs(n)+Math.abs(i)>4&&(O.dragMoved=!0,e.classList.add("dragging"),me()),!O.dragMoved)return;let a=St();O.vb.x=O.drag.vx-n*O.vb.w/a.width,O.vb.y=O.drag.vy-i*O.vb.h/a.height,ft()}),window.addEventListener("pointerup",()=>{O.drag=null,e.classList.remove("dragging"),setTimeout(()=>{O.dragMoved=!1},0)})}function Ks(e){let n=v("svg",{viewBox:`-20 -20 ${x.width+40} ${x.height+40}`,preserveAspectRatio:"xMidYMid meet"}),i=v("g");x.edges.forEach(d=>i.appendChild(v("path",{d:Ct(d.points),style:"fill:none;stroke:var(--border-strong);stroke-width:2","vector-effect":"non-scaling-stroke"}))),x.nodes.forEach(d=>{let l=v("rect",{class:"mn",x:d.pos.x,y:d.pos.y,width:d.pos.w,height:d.pos.h,rx:8,dataset:null});l.dataset.id=d.id,i.appendChild(l)});let a=v("rect",{class:"vp",rx:6});n.append(i,a),e.appendChild(n),O.mini={svg:n,vp:a,pad:20};let o=d=>{let l=n.getBoundingClientRect(),c=x.width+40,r=x.height+40,u=Math.max(c/l.width,r/l.height),m=(l.width*u-c)/2,g=(l.height*u-r)/2,f=(d.clientX-l.left)*u-m-20,y=(d.clientY-l.top)*u-g-20;hs({...O.vb,x:f-O.vb.w/2,y:y-O.vb.h/2},d.type==="click")},p=!1;e.addEventListener("pointerdown",d=>{d.stopPropagation(),p=!0,o(d)}),window.addEventListener("pointermove",d=>{p&&o(d)}),window.addEventListener("pointerup",()=>{p=!1})}function Js(){if(!O.mini)return;let e=O.vb,s=O.mini.vp;s.setAttribute("x",e.x),s.setAttribute("y",e.y),s.setAttribute("width",e.w),s.setAttribute("height",e.h)}function ea(e){O.mini&&se("rect.mn",O.mini.svg).forEach(s=>{let n=Oe.get(s.dataset.id),i=E.view==="diff"?n.status:"same";s.setAttribute("class",`mn ${i}${e.has(n.id)?" inviol":""}`),s.style.opacity=ie(n.status)?"":"0"})}function as(){if(O.animated||$e){O.animated=!0;return}O.animated=!0,O.edgeEls.forEach(e=>e.g.classList.add("draw-in")),O.nodeEls.forEach(e=>e.inner.classList.add("pop-in")),se(".lbl",O.world).forEach(e=>{e.style.opacity="0",e.style.transition="opacity .4s"}),setTimeout(()=>se(".lbl",O.world).forEach(e=>{e.style.opacity=""}),900),setTimeout(()=>{O.edgeEls.forEach(e=>e.g.classList.remove("draw-in")),O.nodeEls.forEach(e=>e.inner.classList.remove("pop-in"))},1900)}function Ft(e,s,n,i){let a=e.cloneNode(!0);a.setAttribute("viewBox",`${s.x} ${s.y} ${s.w} ${s.h}`),a.setAttribute("width",Math.round(s.w)),a.setAttribute("height",Math.round(s.h)),a.setAttribute("xmlns",xt);let o=[e,...e.querySelectorAll("*")],p=[a,...a.querySelectorAll("*")],d=["fill","stroke","stroke-width","stroke-dasharray","stroke-linecap","opacity","font-family","font-size","font-weight","letter-spacing","display"],l=["gone",...i];o.forEach((u,m)=>{let g=getComputedStyle(u),f=p[m];if(u.classList&&l.some(y=>u.classList.contains(y))){f.setAttribute("data-drop","1");return}f.setAttribute("style",d.map(y=>`${y}:${g.getPropertyValue(y)}`).join(";")),f.removeAttribute("class")}),a.querySelectorAll("[data-drop]").forEach(u=>u.remove());let c=v("rect",{x:s.x,y:s.y,width:s.w,height:s.h,style:`fill:${getComputedStyle(document.body).backgroundColor}`});a.insertBefore(c,a.firstChild);let r=new Blob([`<?xml version="1.0" encoding="UTF-8"?>
3
+ ${new XMLSerializer().serializeToString(a)}`],{type:"image/svg+xml"});Wt(r,n)}function Lt(){Ft(O.svg,{x:-32,y:-42,w:x.width+64,h:x.height+64+10},`${x.project}-dependency-map.svg`,["hit","flow"]),We("Map exported as SVG","download")}function Wt(e,s){let n=t("a",{href:URL.createObjectURL(e),download:s});document.body.appendChild(n),n.click(),n.remove(),setTimeout(()=>URL.revokeObjectURL(n.href),2e3)}function At(){let e=x.markdown||"",s=()=>We("PR summary copied as Markdown","copy");navigator.clipboard&&window.isSecureContext?navigator.clipboard.writeText(e).then(s,n):n();function n(){let i=t("textarea",{style:{position:"fixed",opacity:"0"}});i.value=e,document.body.appendChild(i),i.select();try{document.execCommand("copy"),s()}catch{We("Could not copy \u2014 use the JSON/Markdown output instead","alert")}i.remove()}}function ms(){let e=P("#page-overview"),s=be.newErrors+be.newWarnings,n=M?Ce?`This change breaks ${ee(be.newErrors,"architecture rule")}`:s?`No new errors, ${ee(be.newWarnings,"new warning")}`:"This change keeps the architecture clean":Ce?`${ee(Se.length,"rule break")} in this codebase`:"All architecture rules pass",i=M?Ce?"New dependencies cross boundaries your team set in tecton.config.json. CI will fail until they are removed or the rules are updated.":`Compared with ${Xe()}, nothing crosses a boundary you have set.${be.fixed?` It also fixes ${ee(be.fixed,"earlier rule break")}.`:""}`:"No git base was found, so this is a snapshot of the current code checked against your rules.",a=t("div",{class:`card hero ${Ce?"fail":"pass"}`},t("div",{class:"hero-icon"},$(Ce?"alert":"check")),t("div",null,t("h2",{text:n}),t("p",{text:i}),t("div",{class:"actions"},t("button",{class:"btn primary",on:{click:()=>ae(Se.length?"rules":"map")}},$(Se.length?"shield":"map"),Se.length?"Review rule breaks":"Open the map"),t("button",{class:"btn",on:{click:()=>ae("changes")}},$("compare"),"See all changes"))),t("div",{class:"big"},t("div",{class:"v num",dataset:{count:M?s:Se.length},text:"0"}),t("div",{class:"l",text:M?"new rule breaks":"rule breaks"}))),o=M?[Z.modules.added?t("span",{class:"chip add",text:`+${Z.modules.added} new`}):null,Z.modules.removed?t("span",{class:"chip rem",text:`\u2212${Z.modules.removed} gone`}):null]:[],p=M?[Z.deps.added?t("span",{class:"chip add",text:`+${Z.deps.added}`}):null,Z.deps.removed?t("span",{class:"chip rem",text:`\u2212${Z.deps.removed}`}):null,Z.deps.changed?t("span",{class:"chip chg",text:`${Z.deps.changed} changed`}):null]:[],d=[M&&Z.touched&&Z.touched.files?t("span",{class:"chip acc",text:`${Z.touched.files} edited`}):null,M&&Z.files.cur!==Z.files.base?t("span",{class:"chip",text:`${Z.files.cur-Z.files.base>0?"+":"\u2212"}${Math.abs(Z.files.cur-Z.files.base)} vs ${Xe()}`}):null],l=(w,z,b,S,j)=>t("div",{class:"card stat"},t("div",{class:"l"},$(z),w),t("div",{class:"v num",dataset:{count:b},text:"0"}),t("div",{class:"delta"},S.filter(Boolean).length?S:t("span",{class:"faint",text:j}))),c=t("div",{class:"grid stats stagger"},l("Modules","box",Z.modules.total,o,M?"No modules added or removed":"Current snapshot"),l("Dependencies","link",Z.deps.total,p,M?"No links changed":"Links between modules"),l("Rule breaks","shield",Se.length,[be.newErrors?t("span",{class:"chip viol",text:`${be.newErrors} new`}):null,be.existing?t("span",{class:"chip",text:`${be.existing} existing`}):null,be.fixed?t("span",{class:"chip add",text:`${be.fixed} fixed`}):null],`${xe.length} rules checked`),l("Files analysed","file",Z.files.cur,d,"JS / TS source files")),r=x.edges.filter(w=>w.status==="same"&&w.countBase===w.countCur).length,u=[{k:"Added",n:Z.deps.added,c:"var(--add)"},{k:"Removed",n:Z.deps.removed,c:"var(--rem)"},{k:"Import count changed",n:Z.deps.changed,c:"var(--chg)"},{k:"Unchanged",n:r,c:"var(--neutral-bar)"}],m=u.reduce((w,z)=>w+z.n,0)||1,g=t("div",{class:"card"},t("div",{class:"card-h"},t("h3",{text:"Dependency changes"}),t("div",{class:"right"},t("button",{class:"link-btn",on:{click:()=>ae("changes")}},"View all",$("right")))),t("div",{class:"card-b",style:{paddingBottom:"6px"}},t("div",{class:"stackbar",role:"img","aria-label":u.map(w=>`${w.k}: ${w.n}`).join(", ")},u.filter(w=>w.n).map((w,z)=>t("span",{style:{width:`${w.n/m*100}%`,background:w.c,animationDelay:`${z*.08}s`},on:{pointermove:b=>Le(b,`<div class="tt">${ce(w.k)}</div><div class="kv"><span>Dependencies</span><b>${w.n}</b></div><div class="kv"><span>Share</span><b>${Math.round(w.n/m*100)}%</b></div>`),pointerleave:me}}))),t("div",{class:"legend-row"},u.map(w=>t("span",null,t("i",{class:"sw",style:{background:w.c}}),w.k,t("b",{class:"num",text:w.n}))))),t("div",{class:"list",style:{marginTop:"10px"}},Ne.length?Ne.slice(0,5).map(ta):t("div",{class:"card-b faint",text:M?"The structure did not change.":"No comparison available."}))),f=t("div",{class:"card"},t("div",{class:"card-h"},t("h3",{text:"Rule checks"}),t("div",{class:"right"},t("button",{class:"link-btn",on:{click:()=>ae("rules")}},"Details",$("right")))),t("div",{class:"list",style:{marginTop:"12px"}},xe.length?xe.map(w=>t("button",{class:"row-btn",on:{click:()=>{ae("rules"),gt(w.key)}}},t("span",{class:`ico-box ${w.state==="new"?"rem":w.state==="existing"?"viol":"good"}`},$(w.kind==="cycle"?"cycle":w.state==="pass"||w.state==="fixed"?"check":"alert")),t("span",{class:"main-t"},t("div",{class:"t1",text:w.key}),t("div",{class:"t2",text:Ut(w)})),wt(w.state))):t("div",{class:"card-b faint",text:'No rules yet. Run `tecton init` in your project to add some, like "components must not use db". Loops between modules are checked already.'}))),y=t("div",{class:"preview",id:"preview",role:"link",tabindex:0,"aria-label":"Open the architecture map",on:{click:()=>ae("map"),keydown:w=>{w.key==="Enter"&&ae("map")}}},t("button",{class:"btn open",tabindex:-1},"Open map",$("arrowRight"))),D=t("div",{class:"card"},t("div",{class:"card-h",style:{paddingBottom:"14px"}},t("h3",{text:"Architecture preview"}),t("div",{class:"right"},t("span",{class:"faint",style:{fontSize:"12.5px"},text:`${Z.modules.total} modules \xB7 ${Z.deps.total} links`}))),y),F=ze.slice().sort((w,z)=>Math.max(z.filesCur,z.filesBase)-Math.max(w.filesCur,w.filesBase)).slice(0,8),oe=Math.max(1,...F.map(w=>Math.max(w.filesCur,w.filesBase))),_=t("div",{class:"card"},t("div",{class:"card-h"},t("h3",{text:"Files per module"}),t("div",{class:"right"},t("button",{class:"link-btn",on:{click:()=>ae("modules")}},"All modules",$("right")))),t("div",{class:"card-b"},t("div",{class:"bars"},F.map((w,z)=>{let b=w.status==="removed"?w.filesBase:w.filesCur;return t("div",{class:`bar-row ${w.status}`,on:{pointermove:S=>Le(S,`<div class="tt">${ce(w.id)}</div><div class="kv"><span>Files now</span><b>${w.filesCur}</b></div>${M?`<div class="kv"><span>Files before</span><b>${w.filesBase}</b></div>`:""}`),pointerleave:me}},t("span",{class:"n",text:w.id}),t("div",{class:"bar-track"},t("div",{class:"bar-fill",style:{width:`${Math.max(2,b/oe*100)}%`,animationDelay:`${z*.05}s`}})),t("span",{class:"num muted",style:{fontSize:"12.5px"},text:M&&w.filesBase!==w.filesCur?`${w.filesBase} \u2192 ${w.filesCur}`:String(b)}))}))));e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Overview"}),t("p",{text:M?`How ${x.curLabel} reshapes ${x.project} compared with ${Xe()}.`:`A snapshot of ${x.project}.`})),t("div",{class:"right"},t("button",{class:"btn",on:{click:()=>ae("map")}},$("map"),"Open map"))),t("div",{class:"stagger"},a),c,ds(),t("div",{class:"grid two stagger",style:{marginTop:"14px"}},g,f),t("div",{class:"grid two stagger",style:{marginTop:"14px"}},D,_))}function ta(e){let s=e.edge,n=e.type==="node"?e.kind==="added"?"filePlus":"box":e.viol?"alert":"link",i=e.viol?"viol":e.kind==="added"?"add":e.kind==="removed"?"rem":"chg",a=e.type==="node"?`${e.kind==="added"?"New module":"Module removed"} \xB7 ${e.sub}`:s.status==="same"?`Imports ${s.countBase} \u2192 ${s.countCur}`:`${ee(s.status==="added"?s.countCur:s.countBase,"import")}${e.viol?" \xB7 breaks a rule":""}`;return t("button",{class:"row-btn",on:{click:()=>ve({type:e.type,id:e.id})}},t("span",{class:`ico-box ${i}`},$(n)),t("span",{class:"main-t"},t("div",{class:"t1",text:e.label}),t("div",{class:"t2",text:a})),he(e.kind),$("right","chev"))}function Ut(e){return Array.isArray(e.from)&&(e={...e,from:e.from.join(", ")}),e.kind==="cycle"?"No module may depend on itself through others":e.to?`${e.from} must not use ${e.to.map(Y).join(", ")}`:e.allow?e.allow.length?`${e.from} may only use ${e.allow.join(", ")}`:`${e.from} may not use other modules`:e.from||""}function fs(){let e=P("#page-rules"),s=xe.filter(a=>a.state==="new"||a.state==="existing").length;if(e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Rule checks"}),t("p",{text:`The boundaries set in tecton.config.json, checked against ${M?x.curLabel:"the current code"}.`})),t("div",{class:"right"},t("span",{class:"badge neutral plain",text:ee(xe.length,"rule")}),s?de("critical",`${s} failing`):null,de("good",`${xe.length-s} passing`)))),!xe.length){e.append(t("div",{class:"card"},t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("shield")),t("h4",{text:"No rules yet"}),t("p",null,"Run ",t("code",{text:"tecton init"})," to create a starter tecton.config.json, then describe which parts of the app may use which."))));return}let n=t("div",{class:"card",id:"rule-list"});xe.forEach(a=>{let o=t("div",{class:"rule-inner"},a.message?t("div",{class:"callout",style:{background:"var(--surface-2)",color:"var(--text-2)"}},$("sparkle"),a.message):null,a.viols.length?a.viols.map(d=>t("div",{class:"viol-card"},t("div",{class:"top"},$t(d),t("span",{text:d.kind==="cycle"?d.members.map(Y).join(" \u21C4 "):`${Y(d.from)} \u2192 ${Y(d.to)}`}),t("span",{class:"faint",style:{fontSize:"12.5px"},text:`\xB7 ${ee(d.count,d.kind==="cycle"?"link":"import")}`}),t("button",{class:"link-btn",style:{marginLeft:"auto"},on:{click:()=>ve({type:"viol",id:d.id})}},$("map"),"Show on map")),tt(d.imports.slice(0,8)),d.imports.length>8?t("div",{class:"faint",style:{fontSize:"12px",marginTop:"6px"},text:`+ ${d.imports.length-8} more`}):null)):t("div",{class:"faint",text:"Nothing breaks this rule."})),p=t("div",{class:"rule",dataset:{key:a.key}},t("button",{class:"rule-h","aria-expanded":"false",on:{click:d=>gs(d.currentTarget.parentNode)}},t("span",{class:`ico-box ${a.state==="new"?"rem":a.state==="existing"?"viol":"good"}`},$(a.kind==="cycle"?"cycle":a.state==="pass"||a.state==="fixed"?"check":"alert")),t("span",null,t("div",{class:"nm",text:a.key}),t("div",{class:"sub",text:a.severity==="error"?"Error \xB7 fails CI":"Warning \xB7 reported only"})),t("span",{class:"scope sub",text:Ut(a)}),t("span",{class:"cnt sub num",text:a.viols.length?ee(a.viols.filter(d=>d.status!=="fixed").length,"break"):"\u2014"}),wt(a.state),$("right","chev")),t("div",{class:"rule-body"},t("div",null,o)));n.appendChild(p)}),e.append(n);let i=xe.find(a=>a.state==="new")||xe.find(a=>a.state==="existing");i&&gt(i.key)}function gs(e,s){let n=s??!e.classList.contains("open");e.classList.toggle("open",n),P(".rule-h",e).setAttribute("aria-expanded",String(n))}function gt(e){let s=se(".rule").find(n=>n.dataset.key===e);s&&(gs(s,!0),setTimeout(()=>s.scrollIntoView({behavior:$e?"auto":"smooth",block:"nearest"}),60))}var K={items:[],filtered:[],idx:0};function vs(){let e=[];Pe.forEach(s=>e.push({group:"Pages",label:s.title,icon:s.icon,run:()=>ae(s.id)})),ze.forEach(s=>e.push({group:"Modules",label:s.id,hint:ee(s.status==="removed"?s.filesBase:s.filesCur,"file"),icon:"box",run:()=>ve({type:"node",id:s.id})})),x.edges.forEach(s=>e.push({group:"Dependencies",label:`${Y(s.from)} \u2192 ${Y(s.to)}`,hint:M&&s.status!=="same"?s.status==="added"?"new":"removed":ee(s.countCur||s.countBase,"import"),icon:"link",run:()=>ve({type:"edge",id:s.id})})),(x.system?x.system.apps:[]).forEach(s=>e.push({group:"Architecture",label:`${s.name} (${s.framework} app)`,icon:ht(s),run:()=>{ae("system"),setTimeout(()=>Ae({type:"app",id:s.id}),60)}})),(x.system?[...x.system.stores,...x.system.outside]:[]).forEach(s=>e.push({group:"Architecture",label:s.name,hint:s.kind,icon:x.system.stores.includes(s)?"database":"cloud",run:()=>{ae("system"),setTimeout(()=>Ae({type:"svc",id:s.id}),60)}})),Fe.slice(0,5e3).forEach(s=>e.push({group:"Files",label:s.path,hint:s.module,icon:"file",run:()=>Me(s.module,s.path)})),(x.system?x.system.apps:[]).forEach(s=>qe.forEach(({key:n,icon:i})=>(s.groups[n]||[]).forEach(a=>e.push({group:"Entry points",label:`${a.methods&&a.methods.length?`${a.methods.join("/")} `:""}${a.label}`,hint:a.human?`${a.human} \xB7 ${s.name}`:s.name,icon:i,run:()=>{ae("system"),setTimeout(()=>Ae({type:"item",app:s.id,group:n,key:a.key}),60)}})))),xe.forEach(s=>e.push({group:"Rules",label:s.key,hint:{new:"new break",existing:"failing",fixed:"fixed",pass:"passing"}[s.state],icon:"shield",run:()=>{ae("rules"),setTimeout(()=>gt(s.key),50)}})),e.push({group:"Actions",label:"Copy PR summary (Markdown)",icon:"copy",run:At}),e.push({group:"Actions",label:"Export map as SVG",icon:"image",run:()=>{ae("map"),setTimeout(Lt,80)}}),e.push({group:"Actions",label:"Download report data (JSON)",icon:"download",run:()=>{let{markdown:s,...n}=x;Wt(new Blob([JSON.stringify(n,null,2)],{type:"application/json"}),`${x.project}-tecton.json`),We("JSON downloaded","download")}}),e.push({group:"Actions",label:"Switch to light theme",icon:"sun",run:()=>Ze("light")}),e.push({group:"Actions",label:"Switch to dark theme",icon:"moon",run:()=>Ze("dark")}),e.push({group:"Actions",label:"Use system theme",icon:"monitor",run:()=>Ze("system")}),K.items=e}function sa(e,s){if(!s)return 1;let n=e.toLowerCase(),i=n.indexOf(s);if(i>=0)return 100-i;let a=0;for(let o of s){if(a=n.indexOf(o,a),a<0)return 0;a++}return 10}function yt(){let e=P("#palette-ov");e.innerHTML="";let s=t("input",{placeholder:"Search modules, files, rules, actions\u2026","aria-label":"Command palette search",autocomplete:"off"}),n=t("div",{class:"pal-list",role:"listbox"});e.append(t("div",{class:"palette",role:"dialog","aria-label":"Command palette"},t("div",{class:"pal-in"},$("search"),s,t("span",{class:"kbd",text:"Esc"})),n,t("div",{class:"pal-foot"},t("span",null,t("span",{class:"kbd",text:"\u2191\u2193"}),"navigate"),t("span",null,t("span",{class:"kbd",text:"\u21B5"}),"open"),t("span",null,t("span",{class:"kbd",text:"Esc"}),"close"))));let i=()=>{let p=s.value.trim().toLowerCase();K.filtered=K.items.map(c=>({it:c,sc:sa(`${c.label} ${c.group}`,p)})).filter(c=>c.sc>0).sort((c,r)=>p?r.sc-c.sc:0).map(c=>c.it),p||(K.filtered=K.items.filter(c=>c.group==="Pages"||c.group==="Actions"||c.group==="Rules"||c.group==="Architecture").concat(K.items.filter(c=>c.group==="Modules").slice(0,6)));let d=["Pages","Architecture","Rules","Modules","Files","Entry points","Dependencies","Actions"];if(K.filtered.sort((c,r)=>d.indexOf(c.group)-d.indexOf(r.group)),K.filtered=K.filtered.slice(0,60),K.idx=Math.min(K.idx,Math.max(0,K.filtered.length-1)),n.innerHTML="",!K.filtered.length){n.appendChild(t("div",{class:"pal-empty",text:"No results"}));return}let l=null;K.filtered.forEach((c,r)=>{c.group!==l&&(n.appendChild(t("div",{class:"pal-group",text:c.group})),l=c.group);let u=t("div",{class:`pal-item${r===K.idx?" on":""}`,role:"option","aria-selected":String(r===K.idx),on:{mousemove:()=>{K.idx!==r&&(K.idx=r,a())},click:()=>o(r)}},$(c.icon),t("span",{class:"grow",text:c.label}),c.hint?t("span",{class:"faint",style:{fontSize:"12px"},text:c.hint}):null,t("span",{class:"enter",text:"\u21B5"}));u.dataset.i=r,n.appendChild(u)})},a=()=>{se(".pal-item",n).forEach(p=>{let d=Number(p.dataset.i)===K.idx;p.classList.toggle("on",d),p.setAttribute("aria-selected",String(d)),d&&p.scrollIntoView({block:"nearest"})})},o=p=>{let d=K.filtered[p];vt(),d&&d.run()};s.addEventListener("input",()=>{K.idx=0,i()}),s.addEventListener("keydown",p=>{p.key==="ArrowDown"&&(p.preventDefault(),K.idx=Math.min(K.filtered.length-1,K.idx+1),a()),p.key==="ArrowUp"&&(p.preventDefault(),K.idx=Math.max(0,K.idx-1),a()),p.key==="Enter"&&(p.preventDefault(),o(K.idx))}),e.onclick=p=>{p.target===e&&vt()},K.idx=0,i(),e.classList.add("open"),setTimeout(()=>s.focus(),10)}function vt(){P("#palette-ov").classList.remove("open")}function Ze(e){e==="light"||e==="dark"?document.documentElement.setAttribute("data-theme",e):document.documentElement.removeAttribute("data-theme"),It.set("theme",e),se(".theme-seg button").forEach(s=>s.setAttribute("aria-pressed",String(s.dataset.mode===e)))}var ys=()=>It.get("theme")||"system";function We(e,s="check"){let n=t("div",{class:"toast",role:"status"},$(s),e);P("#toasts").appendChild(n),setTimeout(()=>{n.classList.add("out"),setTimeout(()=>n.remove(),260)},2600)}function aa(e){return e==="rules"?Se.length?t("span",{class:`count${Ce?" bad":""}`},Se.length):null:e==="changes"?M?t("span",{class:"count"},Ne.length):null:e==="system"?x.system&&M&&x.system.summary.entry.added+x.system.summary.outside.added+x.system.summary.stores.added+x.system.summary.apps.added?t("span",{class:"count",text:"new"}):null:e==="modules"?t("span",{class:"count"},ze.filter(s=>s.status!=="removed").length):null}function bs(){let e=P("#sidebar"),s=x.project.replace(/[^A-Za-z0-9]/g,"").slice(0,2).toUpperCase()||"AD";e.append(t("div",{class:"logo"},t("div",{class:"logo-mark","aria-hidden":"true"},v("svg",{viewBox:"0 0 64 64",html:Qt})),t("b",{text:"tecton"}),t("span",{class:"ver",text:`v${x.version||"0"}`})),t("div",{class:"project"},t("div",{class:"name"},t("span",{class:"avatar",text:s}),t("span",{text:x.project,title:x.project})),t("div",{class:"compare"},$("branch"),t("span",{class:"ref",text:x.curLabel,title:x.curLabel}),M?[t("span",{class:"vs",text:"vs"}),t("span",{class:"ref",text:Xe(),title:x.baseLabel})]:[t("span"),t("span",{class:"faint",text:"snapshot only"})])),t("div",{class:"nav-label",text:"Report"}),t("nav",{class:"nav","aria-label":"Pages"},Pe.map(n=>t("a",{href:`#${n.id}`,dataset:{page:n.id}},$(n.icon),t("span",{text:n.title}),aa(n.id)))),t("div",{class:"side-foot"},t("div",{class:"theme-seg",role:"group","aria-label":"Theme"},[["system","monitor","System theme"],["light","sun","Light theme"],["dark","moon","Dark theme"]].map(([n,i,a])=>t("button",{dataset:{mode:n},"aria-label":a,title:a,on:{click:()=>Ze(n)}},$(i)))),t("div",{class:"gen"},$("clock"),t("span",{text:`Generated ${qt(x.generatedAt)}`})))),se(".nav a",e).forEach(n=>n.addEventListener("click",()=>Bt()))}function Xe(){return(x.baseLabel||"").replace(/\s*\(.*$/,"")}function na(){P("#sidebar").classList.add("open"),P("#scrim").classList.add("open")}function Bt(){P("#sidebar").classList.remove("open"),P("#scrim").classList.remove("open")}function xs(){P("#topbar").append(t("button",{class:"btn icon ghost menu-btn","aria-label":"Open menu",on:{click:na}},$("menu")),t("div",{class:"crumbs"},t("span",{class:"muted hide-sm",text:x.project}),t("span",{class:"sep hide-sm",text:"/"}),t("span",{class:"cur",id:"crumb-cur",text:"Overview"})),t("div",{class:"top-actions"},t("button",{class:"search-btn",on:{click:yt},"aria-label":"Search"},$("search"),t("span",{class:"lbl-t",text:"Search modules, rules\u2026"}),t("span",{class:"kbd",text:navigator.platform.includes("Mac")?"\u2318K":"Ctrl K"})),t("span",{class:`status-pill ${Ce?"fail":"pass"}`,title:Ce?"This change would fail the CI check":"This change passes the CI check"},t("span",{class:"pulse"}),t("span",{class:"lbl-t",text:Ce?"Check failing":"Check passing"})),t("button",{class:"btn",on:{click:At}},$("copy"),t("span",{class:"lbl-t",text:"Copy PR summary"}))))}function ws(){let e=P("#page-changes");if(e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Changes"}),t("p",{text:M?`Every module and dependency that differs from ${Xe()}.`:"Nothing to compare against \u2014 run Tecton inside a git repo with a main branch."})))),!M){e.append(t("div",{class:"card"},t("div",{class:"empty-state"},t("div",{class:"ico-box"},$("compare")),t("h4",{text:"No comparison"}),t("p",{text:"Commit your code to git and create a main branch, or pass --base <branch>."}))));return}let s="all",n="",i=r=>Ne.filter(u=>r==="all"||u.kind===r).length,a=He([{value:"all",label:"All",count:i("all")},{value:"added",label:"Added",count:i("added")},{value:"removed",label:"Removed",count:i("removed")},{value:"changed",label:"Changed",count:i("changed")}],s,r=>{s=r,c()}),o=t("input",{type:"search",placeholder:"Filter by module\u2026","aria-label":"Filter changes",on:{input:r=>{n=r.target.value.toLowerCase(),c()}}}),p=t("tbody"),d=t("div",{class:"card"},t("div",{class:"tbl-wrap"},t("table",null,t("thead",null,t("tr",null,t("th",{text:"Change"}),t("th",{text:"What"}),t("th",{class:"r",text:"Imports"}),t("th",{text:"Rules"}),t("th"))),p))),l=t("div",{class:"empty-state",style:{display:"none"}},t("div",{class:"ico-box"},$("search")),t("h4",{text:"No matching changes"}),t("p",{text:"Try a different filter."}));d.appendChild(l);function c(){p.innerHTML="";let r=Ne.filter(u=>(s==="all"||u.kind===s)&&(!n||u.label.toLowerCase().includes(n)));r.forEach((u,m)=>{let g=u.edge,f=g?Ie.cur.get(g.id)||[]:[],y=t("tr",{class:"click enter",style:{animationDelay:`${Math.min(m,12)*.025}s`},on:{click:()=>ve({type:u.type,id:u.id})}},t("td",null,he(u.kind)),t("td",null,t("div",{class:"cell-mod"},t("span",{class:`ico-box ${u.viol?"viol":u.kind==="added"?"add":u.kind==="removed"?"rem":"chg"}`,style:{width:"26px",height:"26px"}},$(u.type==="node"?"box":"link")),u.type==="node"?t("span",null,u.label,t("span",{class:"faint",text:u.kind==="added"?" \xB7 new module":" \xB7 module removed"})):t("span",null,Y(g.from),t("span",{class:"arrow",text:" \u2192 "}),Y(g.to)))),t("td",{class:"r num mono"},u.type==="node"?t("span",{class:"faint",text:u.sub}):g.status==="same"?`${g.countBase} \u2192 ${g.countCur}`:g.status==="added"?`+${g.countCur}`:`\u2212${g.countBase}`),t("td",null,f.length?f.map(D=>t("span",{class:`badge ${D.status==="new"?D.severity==="error"?"critical":"warn":"neutral"}`,text:D.rule,style:{marginRight:"4px"}})):t("span",{class:"faint",text:"\u2014"})),t("td",{class:"r"},$("right","faint")));p.appendChild(y)}),l.style.display=r.length?"none":"block"}c(),e.append(t("div",{class:"toolbar"},a,t("label",{class:"input"},$("search"),o)),d)}function $s(){let e=P("#page-modules");e.append(t("div",{class:"page-head"},t("div",null,t("h1",{text:"Modules"}),t("p",{text:"Each folder Tecton treats as one part of the app, with how much it uses and is used. Open one to see its files."}))));let s={k:"files",dir:-1},n="",i=!1,a=x.nodes.map(f=>({n:f,...Ee.get(f.id),files:f.status==="removed"?f.filesBase:f.filesCur,edited:f.touched||0})),o=Math.max(1,...a.map(f=>f.files)),p=[["name","Module"],["status","Status"],["files","Files"],...Ke?[["edited","Edited"]]:[],["uses","Uses"],["usedBy","Used by"],["viol","Rule breaks"]],d=t("tr");p.forEach(([f,y])=>d.appendChild(t("th",{class:`sortable${f==="uses"||f==="usedBy"||f==="viol"||f==="edited"?" r":""}`,dataset:{k:f},on:{click:()=>{s={k:f,dir:s.k===f?-s.dir:f==="name"?1:-1},u()}}},y,t("span",{class:"sort"}))));let l=t("tbody"),c=t("input",{type:"search",placeholder:"Search modules\u2026","aria-label":"Search modules",on:{input:f=>{n=f.target.value.toLowerCase(),u()}}});function r(f,y){return y==="name"?f.n.id:y==="status"?f.n.status:f[y]}function u(){se("th",d.parentNode||d).forEach(f=>{let y=P(".sort",f);y&&(y.textContent=f.dataset.k===s.k?s.dir>0?" \u2191":" \u2193":"")}),l.innerHTML="",a.filter(f=>(!n||f.n.id.toLowerCase().includes(n))&&(!i||f.edited)).sort((f,y)=>{let D=r(f,s.k),F=r(y,s.k);return(D>F?1:D<F?-1:0)*s.dir||f.n.id.localeCompare(y.n.id)}).forEach((f,y)=>{let D=f.n,F=()=>D.external?ve({type:"node",id:D.id}):Me(D.id);l.appendChild(t("tr",{class:"click enter",tabindex:0,style:{animationDelay:`${Math.min(y,12)*.02}s`},on:{click:F,keydown:oe=>{oe.key==="Enter"&&F()}}},t("td",null,t("div",{class:"cell-mod"},t("span",{class:`ico-box ${D.status==="added"?"add":D.status==="removed"?"rem":""}`,style:{width:"26px",height:"26px"}},$(D.external?"pkg":"box")),Y(D.id),D.external?t("span",{class:"faint",text:" \xB7 npm"}):null)),t("td",null,M&&D.status!=="same"?he(D.status):t("span",{class:"faint",text:D.external?"Package":"Unchanged"})),t("td",{class:"num"},D.external?t("span",{class:"faint",text:"\u2014"}):[t("span",{class:"mini-bar"},t("i",{style:{width:`${f.files/o*100}%`}})),M&&D.filesBase!==D.filesCur?`${D.filesBase} \u2192 ${D.filesCur}`:String(f.files)]),Ke?t("td",{class:"r num"},f.edited?t("span",{class:"chip acc",text:String(f.edited)}):t("span",{class:"faint",text:"0"})):null,t("td",{class:"r num",text:f.uses}),t("td",{class:"r num",text:f.usedBy}),t("td",{class:"r"},f.viol?de("serious",String(f.viol)):t("span",{class:"faint",text:"0"}))))})}let m=t("table",null,t("thead",null,d),l),g=Ke?t("label",{class:"switch"},t("input",{type:"checkbox",on:{change:f=>{i=f.target.checked,u()}}}),"Only modules this change touches"):null;e.append(t("div",{class:"toolbar"},t("label",{class:"input"},$("search"),c),g),t("div",{class:"card"},t("div",{class:"tbl-wrap"},m))),u()}window.addEventListener("hashchange",()=>st(location.hash.slice(1)));document.addEventListener("keydown",e=>{let s=/^(INPUT|TEXTAREA)$/.test(document.activeElement?.tagName);if((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="k"){e.preventDefault(),P("#palette-ov").classList.contains("open")?vt():yt();return}if(e.key==="Escape"){P("#palette-ov").classList.contains("open")?vt():P("#sheet")&&P("#sheet").classList.contains("open")?_e():E.selected?Te(null):Bt();return}s||(e.key==="/"&&(e.preventDefault(),yt()),E.page==="map"&&(e.key==="f"||e.key==="F")&&at(!0),E.page==="system"&&(e.key==="f"||e.key==="F")&&Ge(!0),/^[1-6]$/.test(e.key)&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&ae(Pe[Number(e.key)-1].id))});bs();xs();ms();ps();ct();fs();ws();$s();vs();Ze(ys());P("#scrim").addEventListener("click",Bt);(()=>{let e=P("#preview");if(!e||!O.world)return;let s=30,n=v("svg",{viewBox:`${-s} ${-s} ${x.width+s*2} ${x.height+s*2}`,preserveAspectRatio:"xMidYMid meet","aria-hidden":"true"}),i=O.world.cloneNode(!0);i.removeAttribute("id"),se("[id], [tabindex], [role], [aria-label]",i).forEach(o=>["id","tabindex","role","aria-label"].forEach(p=>o.removeAttribute(p)));let a=O.svg.querySelector("defs").cloneNode(!0);se("[id]",a).forEach(o=>o.setAttribute("id",`pv-${o.id}`)),se("[marker-end]",i).forEach(o=>o.setAttribute("marker-end",o.getAttribute("marker-end").replace("url(#","url(#pv-"))),n.append(a,i),e.insertBefore(n,e.firstChild)})();window.addEventListener("resize",()=>{et(),E.page==="map"&&!E.selected&&at(!1),E.page==="system"&&Ge(!1)});st(location.hash.slice(1)||"overview");})();
@@ -240,7 +240,8 @@ nav.nav { display: grid; gap: 2px; }
240
240
  .bar-row.added .bar-fill { background: var(--add); }
241
241
 
242
242
  .preview { position: relative; height: 260px; border-top: 1px solid var(--border); background-image: radial-gradient(var(--dot) 1px, transparent 1px); background-size: 16px 16px; border-radius: 0 0 var(--radius) var(--radius); overflow: hidden; cursor: pointer; }
243
- .preview svg { width: 100%; height: 100%; display: block; pointer-events: none; }
243
+ .preview > svg { width: 100%; height: 100%; display: block; pointer-events: none; }
244
+ .preview .node .card-r { filter: url(#pv-nshadow); }
244
245
  .preview .open { position: absolute; right: 12px; bottom: 12px; opacity: 0; transform: translateY(4px); transition: opacity .2s, transform .2s var(--ease); }
245
246
  .preview:hover .open { opacity: 1; transform: none; }
246
247