Files
battery-builder/dist/assets/index-DwWFs8GA.js
2026-05-07 08:39:18 +02:00

27 lines
80 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))o(r);new MutationObserver(r=>{for(const s of r)if(s.type==="childList")for(const a of s.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&o(a)}).observe(document,{childList:!0,subtree:!0});function t(r){const s={};return r.integrity&&(s.integrity=r.integrity),r.referrerPolicy&&(s.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?s.credentials="include":r.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function o(r){if(r.ep)return;r.ep=!0;const s=t(r);fetch(r.href,s)}})();const B={zoom:1,panX:0,panY:0,isDragging:!1,dragStartX:0,dragStartY:0,dragMoved:!1,lastMouseX:0,lastMouseY:0,currentPositions:[],currentCellSize:18,viewTransform:null},_e={key:null,positions:null};function ae(e,n="success"){const t=document.getElementById("previewStats");t&&(t.textContent=e,n==="error"?t.style.color="#ef4444":n==="success"?t.style.color="#10b981":t.style.color="#94a3b8")}function be(e,n="Generating 3D Model",t="Please be patient..."){const o=document.getElementById("loadingOverlay");if(!o)return;const r=document.getElementById("loadingText"),s=document.getElementById("loadingSubtext");r&&(r.textContent=n),s&&(s.textContent=t),e?(o.classList.add("active"),o.style.display="flex"):(o.classList.remove("active"),o.style.display="none")}function Qe(){const e=document.getElementById("bmsHolesType").value,n=document.getElementById("bmsHoleDiameterGroup"),t=document.getElementById("tabDimensionsGroup"),o=document.getElementById("tabOverlapSideGroup");n.style.display=e==="halfcircles"||e==="fullcircles"?"block":"none",t.style.display=e==="tabs"?"grid":"none",o&&(o.style.display=e==="tabs"?"block":"none")}function Nt(){document.querySelectorAll("select").forEach(n=>{const t=document.createElement("div");t.className="custom-select",n.parentNode.insertBefore(t,n),t.appendChild(n);const o=document.createElement("div");o.className="select-selected",o.textContent=n.options[n.selectedIndex].text,t.appendChild(o);const r=document.createElement("div");r.className="select-items",Array.from(n.options).forEach((s,a)=>{const i=document.createElement("div");i.textContent=s.text,i.dataset.value=s.value,a===n.selectedIndex&&(i.className="same-as-selected"),i.addEventListener("click",function(u){u.stopPropagation(),n.selectedIndex=a,o.textContent=this.textContent;const c=r.querySelector(".same-as-selected");c&&c.classList.remove("same-as-selected"),this.classList.add("same-as-selected"),o.click(),n.dispatchEvent(new Event("change"))}),r.appendChild(i)}),t.appendChild(r),o.addEventListener("click",function(s){s.stopPropagation(),ut(this),r.classList.toggle("show"),this.classList.toggle("select-arrow-active")})}),document.addEventListener("click",ut)}function ut(e){const n=document.querySelectorAll(".select-items"),t=document.querySelectorAll(".select-selected");n.forEach((o,r)=>{e!==t[r]&&(o.classList.remove("show"),t[r].classList.remove("select-arrow-active"))})}const Yt={BASE_URL:"./",DEV:!1,MODE:"production",PROD:!0,SSR:!1},we={instance:null,initialized:!1};async function wt(){if(!we.initialized)try{const n=`${(typeof import.meta<"u"&&Yt?"./":"/").replace(/\/?$/,"/")}vendor/opencascade.wasm.wasm`;we.instance=await opencascade({locateFile:()=>n}),we.initialized=!0,console.log("OpenCascade initialized successfully"),be(!1)}catch(e){console.error("Failed to initialize OpenCascade:",e),ae("Failed to initialize 3D engine. Please ensure opencascade.wasm.js and opencascade.wasm.wasm are in vendor/.","error"),be(!1)}}function xt(e,n,t,o,r,s,a){e.strokeStyle="#94a3b8",e.fillStyle="#94a3b8",e.lineWidth=1/a,e.font=`${12/a}px Arial`,e.textAlign="center",e.textBaseline="middle";const i=15/a,u=5/a,c=t+r*s+i;e.setLineDash([2/a,2/a]),e.beginPath(),e.moveTo(n,t+r*s),e.lineTo(n,c+i/2),e.stroke(),e.beginPath(),e.moveTo(n+o*s,t+r*s),e.lineTo(n+o*s,c+i/2),e.stroke(),e.setLineDash([]),e.beginPath(),e.moveTo(n,c),e.lineTo(n+o*s,c),e.stroke(),e.beginPath(),e.moveTo(n,c),e.lineTo(n+u,c-u/2),e.lineTo(n+u,c+u/2),e.closePath(),e.fill(),e.beginPath(),e.moveTo(n+o*s,c),e.lineTo(n+o*s-u,c-u/2),e.lineTo(n+o*s-u,c+u/2),e.closePath(),e.fill(),e.fillText(`${o.toFixed(1)}mm`,n+o*s/2,c+i);const h=n+o*s+i;e.setLineDash([2/a,2/a]),e.beginPath(),e.moveTo(n+o*s,t),e.lineTo(h+i/2,t),e.stroke(),e.beginPath(),e.moveTo(n+o*s,t+r*s),e.lineTo(h+i/2,t+r*s),e.stroke(),e.setLineDash([]),e.beginPath(),e.moveTo(h,t),e.lineTo(h,t+r*s),e.stroke(),e.beginPath(),e.moveTo(h,t),e.lineTo(h-u/2,t+u),e.lineTo(h+u/2,t+u),e.closePath(),e.fill(),e.beginPath(),e.moveTo(h,t+r*s),e.lineTo(h-u/2,t+r*s-u),e.lineTo(h+u/2,t+r*s-u),e.closePath(),e.fill(),e.save(),e.translate(h+i,t+r*s/2),e.rotate(-Math.PI/2),e.fillText(`${r.toFixed(1)}mm`,0,0),e.restore()}function Pe(e="preview"){const n=document.getElementById(e);if(!n)return;const t=n.getContext("2d");t.save(),t.setTransform(1,0,0,1,0,0),t.clearRect(0,0,n.width,n.height),t.fillStyle="#1e293b",t.fillRect(0,0,n.width,n.height),t.restore()}function Ot(e){const n=document.getElementById("preview"),t=document.getElementById(e),o=B.viewTransform;if(!n||!t||!o)return;const r=t.getContext("2d");r.save(),r.setTransform(1,0,0,1,0,0),r.clearRect(0,0,t.width,t.height),r.translate(t.width,0),r.scale(-1,1),r.drawImage(n,0,0,t.width,t.height),r.restore();const s=B.panX+B.zoom*o.offsetX;B.panY+B.zoom*o.offsetY;const a=B.panX+B.zoom*(o.offsetX+o.packWidth*o.scale),i=B.panY+B.zoom*(o.offsetY+o.packHeight*o.scale);r.save(),r.setTransform(1,0,0,1,0,0),r.fillStyle="#1e293b",r.fillRect(0,Math.max(0,i),t.width,Math.max(0,t.height-i)),r.fillRect(0,0,Math.max(0,s),t.height),r.fillRect(Math.max(0,a),0,Math.max(0,t.width-a),t.height),r.restore(),r.save(),r.translate(B.panX,B.panY),r.scale(B.zoom,B.zoom),xt(r,o.offsetX,o.offsetY,o.packWidth,o.packHeight,o.scale,B.zoom),r.restore()}function zt(e,n){B.currentPositions=e,B.currentCellSize=n;const t=document.getElementById("preview");if(!t){console.error("Canvas element not found!");return}const o=t.getContext("2d");if(o.save(),o.setTransform(1,0,0,1,0,0),o.clearRect(0,0,t.width,t.height),o.fillStyle="#1e293b",o.fillRect(0,0,t.width,t.height),o.restore(),e.length===0)return;o.save(),o.translate(B.panX,B.panY),o.scale(B.zoom,B.zoom);const r=parseFloat(document.getElementById("spacing").value),s=document.getElementById("bmsHolesType").value,a=s!=="off",i=s==="tabs",u=s==="fullcircles",c=document.getElementById("roundedCorners").checked,h=parseFloat(document.getElementById("bmsHoleDiameter").value)||4,y=parseFloat(document.getElementById("ledgeWidth").value)||0,l=n/2,g=Math.min(...e.map(M=>M[0])),p=Math.min(...e.map(M=>M[1])),v=Math.max(...e.map(M=>M[0])),d=Math.max(...e.map(M=>M[1])),m=v-g+n+r*2,f=d-p+n+r*2,_=t.getBoundingClientRect(),D=_.width,T=_.height,I=80,E=(D-I*2)/m,w=(T-I*2)/f,S=Math.min(E,w),k=(D-m*S)/2,z=(T-f*S)/2;B.viewTransform={offsetX:k,offsetY:z,scale:S,minX:g,minY:p,spacing:r,r:l,packWidth:m,packHeight:f};const V=B.zoom;if(c){const M=5*S,b=k,x=z,C=m*S,F=f*S;o.fillStyle="rgba(100, 149, 237, 0.15)",o.beginPath(),o.moveTo(b+M,x),o.lineTo(b+C-M,x),o.arcTo(b+C,x,b+C,x+M,M),o.lineTo(b+C,x+F-M),o.arcTo(b+C,x+F,b+C-M,x+F,M),o.lineTo(b+M,x+F),o.arcTo(b,x+F,b,x+F-M,M),o.lineTo(b,x+M),o.arcTo(b,x,b+M,x,M),o.closePath(),o.fill()}else o.fillStyle="rgba(100, 149, 237, 0.15)",o.fillRect(k,z,m*S,f*S);if(o.strokeStyle="#667eea",o.lineWidth=2/V,c){const M=5*S,b=k,x=z,C=m*S,F=f*S;o.beginPath(),o.moveTo(b+M,x),o.lineTo(b+C-M,x),o.arcTo(b+C,x,b+C,x+M,M),o.lineTo(b+C,x+F-M),o.arcTo(b+C,x+F,b+C-M,x+F,M),o.lineTo(b+M,x+F),o.arcTo(b,x+F,b,x+F-M,M),o.lineTo(b,x+M),o.arcTo(b,x,b+M,x,M),o.closePath(),o.stroke()}else o.strokeRect(k,z,m*S,f*S);const $=[];if(a){const M=p-l-r,b=d+l+r,x={};for(const[P,R]of e){const L=Math.round(R*1e3);x[L]||(x[L]=[]),x[L].push([P,R])}const C=Object.keys(x).map(Number).sort((P,R)=>P-R),F=C[C.length-1],W=C[0],oe=C[0],j=C[C.length-1];x[F].sort((P,R)=>P[0]-R[0]),x[W].sort((P,R)=>P[0]-R[0]),x[F][0][1],x[W][0][1];let J,ne;if(u){const P=x[oe][0][1],R=x[j][0][1],L=x[oe],te=x[j],Z=(Q,re,se,A)=>{const K=(se+A)/2,H=re<Q?-1:1;let ie=-Math.PI/2*H,le=0;H<0&&(ie=0,le=Math.PI/2);for(let ee=0;ee<80;ee++){const O=(ie+le)/2,fe=se+l*Math.cos(O),G=re+l*Math.sin(O),ce=K-fe,q=(G-Q)*H-ce*Math.sqrt(3);if(Math.abs(q)<1e-8)break;q<0?H>0?ie=O:le=O:H>0?le=O:ie=O}const X=(ie+le)/2,ue=re+l*Math.sin(X);return(Q+2*ue)/3};L.length>=2&&(J=Z(M,P,L[0][0],L[1][0])),te.length>=2&&(ne=Z(b,R,te[0][0],te[1][0]))}else J=b,ne=M;const N=u?oe:F,Y=u?j:W;for(let P=0;P<x[N].length-1;P++){const R=(x[N][P][0]+x[N][P+1][0])/2,L=x[N][P][1],te=x[N][P][0],Z=x[N][P+1][0],Q=M,re=J,se=L<Q?-1:1;let A=se>0?-Math.PI/2:0,K=se>0?0:Math.PI/2;for(let ue=0;ue<80;ue++){const ee=(A+K)/2,O=R-(te+l*Math.cos(ee)),G=(L+l*Math.sin(ee)-Q)*se-O*Math.sqrt(3);if(Math.abs(G)<1e-8)break;G<0?se>0?A=ee:K=ee:se>0?K=ee:A=ee}const H=(A+K)/2,ie={x:te+l*Math.cos(H),y:L+l*Math.sin(H)},le={x:Z-l*Math.cos(H),y:L+l*Math.sin(H)},X=u?{apex:{x:R,y:Q},left:ie,right:le}:null;$.push({x:R,y:re,diameter:h,isTab:!1,isFull:u,debugTri:X})}for(let P=0;P<x[Y].length-1;P++){const R=(x[Y][P][0]+x[Y][P+1][0])/2,L=x[Y][P][1],te=x[Y][P][0],Z=x[Y][P+1][0],Q=b,re=ne,se=L<Q?-1:1;let A=se>0?-Math.PI/2:0,K=se>0?0:Math.PI/2;for(let ue=0;ue<80;ue++){const ee=(A+K)/2,O=R-(te+l*Math.cos(ee)),G=(L+l*Math.sin(ee)-Q)*se-O*Math.sqrt(3);if(Math.abs(G)<1e-8)break;G<0?se>0?A=ee:K=ee:se>0?K=ee:A=ee}const H=(A+K)/2,ie={x:te+l*Math.cos(H),y:L+l*Math.sin(H)},le={x:Z-l*Math.cos(H),y:L+l*Math.sin(H)},X=u?{apex:{x:R,y:Q},left:ie,right:le}:null;$.push({x:R,y:re,diameter:h,isTab:!1,isFull:u,debugTri:X})}}o.fillStyle="#1e293b",o.strokeStyle="rgba(102, 126, 234, 0.8)",o.lineWidth=1.5/V;for(const[M,b]of e){const x=(M-g+l+r)*S+k,C=(b-p+l+r)*S+z,F=l*S;if(o.beginPath(),o.arc(x,C,F,0,Math.PI*2),o.fill(),o.stroke(),y>0){const W=(l-y)*S;o.strokeStyle="rgba(255, 193, 7, 0.8)",o.setLineDash([3/V,3/V]),o.lineWidth=1/V,o.beginPath(),o.arc(x,C,W,0,Math.PI*2),o.stroke(),o.setLineDash([]),o.strokeStyle="rgba(102, 126, 234, 0.8)",o.lineWidth=1.5/V}}if(a&&$.length>0)if(i){o.fillStyle="rgba(255, 193, 7, 0.5)",o.strokeStyle="rgba(255, 193, 7, 0.9)",o.lineWidth=1.5/V;const b=(parseFloat(document.getElementById("tabWidth").value)||4)*S,x=28*S;for(const C of $){const F=(C.x-g+l+r)*S+k;C.y<p?(o.fillRect(F-b/2,z,b,x),o.strokeRect(F-b/2,z,b,x)):(o.fillRect(F-b/2,z+f*S-x,b,x),o.strokeRect(F-b/2,z+f*S-x,b,x))}}else if(u){let M=null;for(const b of $){const x=b.diameter/2*S,C=(b.x-g+l+r)*S+k,F=(b.y-p+l+r)*S+z;for(const[W,oe]of e){const j=(W-g+l+r)*S+k,J=(oe-p+l+r)*S+z,ne=Math.sqrt((C-j)**2+(F-J)**2);if(ne<x+l*S){M=`BMS hole too large, overlaps cell! Max diameter: ${((ne/S-l)*2).toFixed(1)}mm`;break}}if(M)break}if(M){o.restore(),B.currentPositions=[],o.clearRect(0,0,t.width,t.height),o.fillStyle="#1e293b",o.fillRect(0,0,t.width,t.height),ae(M,"error");return}for(const b of $){const x=(b.x-g+l+r)*S+k,C=(b.y-p+l+r)*S+z,F=b.diameter/2*S;o.save(),o.globalCompositeOperation="destination-out",o.fillStyle="black",o.beginPath(),o.arc(x,C,F,0,Math.PI*2),o.fill(),o.globalCompositeOperation="source-over",o.restore(),o.strokeStyle="rgba(16, 185, 129, 0.9)",o.lineWidth=1.5/V,o.beginPath(),o.arc(x,C,F,0,Math.PI*2),o.stroke()}}else{o.save(),o.globalCompositeOperation="destination-out";for(const M of $){const b=(M.x-g+l+r)*S+k,x=M.diameter/2*S;if(o.fillStyle="black",o.beginPath(),M.y>d){const C=3/V;o.arc(b,z+f*S,x,Math.PI,0,!1),o.lineTo(b+x,z+f*S+C),o.lineTo(b-x,z+f*S+C)}else{const C=3/V;o.arc(b,z,x,0,Math.PI,!1),o.lineTo(b-x,z-C),o.lineTo(b+x,z-C)}o.closePath(),o.fill()}o.globalCompositeOperation="source-over";for(const M of $){const b=(M.x-g+l+r)*S+k,x=M.diameter/2*S;o.strokeStyle="rgba(16, 185, 129, 0.9)",o.lineWidth=1.5/V,o.beginPath(),M.y>d?o.arc(b,z+f*S,x,Math.PI,0,!1):o.arc(b,z,x,0,Math.PI,!1),o.stroke()}o.restore()}xt(o,k,z,m,f,S,V),o.restore()}const Xt="modulepreload",Kt=function(e,n){return new URL(e,n).href},ht={},qt=function(n,t,o){let r=Promise.resolve();if(t&&t.length>0){const a=document.getElementsByTagName("link"),i=document.querySelector("meta[property=csp-nonce]"),u=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));r=Promise.allSettled(t.map(c=>{if(c=Kt(c,o),c in ht)return;ht[c]=!0;const h=c.endsWith(".css"),y=h?'[rel="stylesheet"]':"";if(!!o)for(let p=a.length-1;p>=0;p--){const v=a[p];if(v.href===c&&(!h||v.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${c}"]${y}`))return;const g=document.createElement("link");if(g.rel=h?"stylesheet":Xt,h||(g.as="script"),g.crossOrigin="",g.href=c,u&&g.setAttribute("nonce",u),document.head.appendChild(g),h)return new Promise((p,v)=>{g.addEventListener("load",p),g.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${c}`)))})}))}function s(a){const i=new Event("vite:preloadError",{cancelable:!0});if(i.payload=a,window.dispatchEvent(i),!i.defaultPrevented)throw a}return r.then(a=>{for(const i of a||[])i.status==="rejected"&&s(i.reason);return n().catch(s)})};function Et(e,n,t,o){const r=[],s=o/2,a=s+t,i=s+t;for(let u=i;u+s+t<=n;u+=o+t)for(let c=a;c+s+t<=e;c+=o+t)r.push([c,u]);return r}function St(e,n,t,o){const r=[],s=o/2;let a=s+t,i=0;for(;a+s+t<=n;){const u=i%2===0?0:(o+t)/2;let c=s+t+u;for(;c+s+t<=e;)r.push([c,a]),c+=o+t;a+=Math.sqrt(3)*(s+t/2),i++}return r}function Mt(e,n,t,o){const r=[],s=o/2;let a=s+t,i=0;for(;a+s+t<=e;){const u=i%2===0?0:(o+t)/2;let c=s+t+u;for(;c+s+t<=n;)r.push([a,c]),c+=o+t;a+=Math.sqrt(3)*(s+t/2),i++}return r}function Wt(e,n,t,o,r){return e==="grid"?Et(n,t,o,r):e==="honeycomb"?St(n,t,o,r):Mt(n,t,o,r)}function Ht(e,n,t,o,r){const s=`${e}_${n}_${t}_${o}_${r}`;if(_e.key===s&&_e.positions)return _e.positions;const a=Wt(r,e,n,t,o);return _e.key=s,_e.positions=a,a}function Ut(e,n){const t=we.instance;if(!t||e.length===0)return null;const{cellSize:o,spacing:r,height:s,terminalDiameter:a,terminalDepth:i,coverThickness:u,ledgeWidth:c,roundedCorners:h,bmsHoles:y,useTabs:l,useFullCircles:g}=n,p=o/2,v=Math.min(...e.map(M=>M[0]))-p-r,d=Math.min(...e.map(M=>M[1]))-p-r,m=Math.max(...e.map(M=>M[0]))+p+r,f=Math.max(...e.map(M=>M[1]))+p+r,_=(v+m)/2,D=(d+f)/2,T=e.map(([M,b])=>[M-_,b-D]),I=m-v,E=f-d;performance.now();const w=M=>{performance.now()};let k=new t.BRepPrimAPI_MakeBox(I,E,s).Shape();const z=new t.gp_Trsf;if(z.SetTranslation(new t.gp_Vec(-I/2,-E/2,0)),k=new t.BRepBuilderAPI_Transform(k,z,!1).Shape(),h)try{const b=(C,F)=>{const W={};let oe=0;const j=new t.TopExp_Explorer(C,t.TopAbs_EDGE);for(j.Init(C,t.TopAbs_EDGE);j.More();j.Next()){const J=t.TopoDS.prototype.Edge(j.Current()),ne=J.HashCode(1e8);W.hasOwnProperty(ne)||(W[ne]=oe,F(oe++,J))}return W},x=[];if(b(k,(C,F)=>{try{const W=new t.Bnd_Box;t.BRepBndLib.prototype.Add(F,W,!1);const oe=W.CornerMin(),j=W.CornerMax(),J=Math.abs(j.X()-oe.X()),ne=Math.abs(j.Y()-oe.Y()),N=Math.abs(j.Z()-oe.Z());J<1&&ne<1&&N>s*.8&&x.push(C)}catch{}}),x.length>0){const C=new t.BRepFilletAPI_MakeFillet(k);let F=0;b(k,(W,oe)=>{if(x.includes(W))try{C.Add(5,oe),F++}catch(j){console.error(` Failed to add edge ${W}:`,j.message)}}),F>0&&(k=new t.TopoDS_Solid(C.Shape()),console.log(" Applied rounded corners"),w("Rounded corners"))}else console.log(" No vertical edges found to fillet")}catch(M){console.error(" Fillet operation failed:",M.message),console.log(" Continuing without rounded corners")}const $=c>0||u>0;if($){const M=u,b=s-u,x=Math.max(.1,p-c),C=T.map(([j,J])=>{const ne=new t.gp_Ax2(new t.gp_Pnt(j,J,M),t.gp.prototype.DZ());return new t.BRepPrimAPI_MakeCylinder(ne,p,b).Shape()});let F=C[0];for(let j=1;j<C.length;j++)F=new t.BRepAlgoAPI_Fuse(F,C[j]).Shape();k=new t.BRepAlgoAPI_Cut(k,F).Shape();const W=T.map(([j,J])=>{const ne=new t.gp_Ax2(new t.gp_Pnt(j,J,0),t.gp.prototype.DZ());return new t.BRepPrimAPI_MakeCylinder(ne,x,s).Shape()});let oe=W[0];for(let j=1;j<W.length;j++)oe=new t.BRepAlgoAPI_Fuse(oe,W[j]).Shape();k=new t.BRepAlgoAPI_Cut(k,oe).Shape()}else{const M=T.map(([x,C])=>{const F=new t.gp_Ax2(new t.gp_Pnt(x,C,0),t.gp.prototype.DZ());return new t.BRepPrimAPI_MakeCylinder(F,p,s).Shape()});let b=M[0];for(let x=1;x<M.length;x++)b=new t.BRepAlgoAPI_Fuse(b,M[x]).Shape();k=new t.BRepAlgoAPI_Cut(k,b).Shape()}if(console.log(" Cell holes cut"+($?" (with integrated ledge)":"")),w(),y){const M=n.bmsHoleDiameter||4;let b,x;g?(b=null,x=null):(b=E/2,x=-E/2);const C={};T.forEach(([P,R])=>{const L=Math.round(R*1e3);C[L]||(C[L]=[]),C[L].push([P,R])});const F=Object.keys(C).map(P=>parseInt(P)).sort((P,R)=>R-P),W=F[0],oe=F[F.length-1];if(g){const P=C[W][0][1],R=C[oe][0][1],L=E/2,te=-E/2,Z=(Q,re,se,A)=>{const K=(se+A)/2,H=re<Q?-1:1;let ie=H>0?-Math.PI/2:0,le=H>0?0:Math.PI/2;for(let ee=0;ee<80;ee++){const O=(ie+le)/2,fe=se+p*Math.cos(O),G=re+p*Math.sin(O),ce=K-fe,q=(G-Q)*H-ce*Math.sqrt(3);if(Math.abs(q)<1e-8)break;q<0?H>0?ie=O:le=O:H>0?le=O:ie=O}const X=(ie+le)/2,ue=re+p*Math.sin(X);return(Q+2*ue)/3};b=Z(L,P,C[W][0][0],C[W][1][0]),x=Z(te,R,C[oe][0][0],C[oe][1][0])}const j=C[W].sort((P,R)=>P[0]-R[0]),J=C[oe].sort((P,R)=>P[0]-R[0]),ne=[];for(let P=0;P<j.length-1;P++){const R=(j[P][0]+j[P+1][0])/2;ne.push([R,b])}const N=[];for(let P=0;P<J.length-1;P++){const R=(J[P][0]+J[P+1][0])/2;N.push([R,x])}const Y=[...ne,...N];if(l){const P=n.tabWidth||M,R=28,L=E/2,te=-E/2,Z=[];if(ne.forEach(([Q])=>{const se=new t.BRepPrimAPI_MakeBox(P,R,s).Shape(),A=new t.gp_Trsf;A.SetTranslation(new t.gp_Vec(Q-P/2,L-R,0));const K=new t.BRepBuilderAPI_Transform(se,A,!1);Z.push(K.Shape())}),N.forEach(([Q])=>{const se=new t.BRepPrimAPI_MakeBox(P,R,s).Shape(),A=new t.gp_Trsf;A.SetTranslation(new t.gp_Vec(Q-P/2,te,0));const K=new t.BRepBuilderAPI_Transform(se,A,!1);Z.push(K.Shape())}),Z.length>0)if(Z.length===1)k=new t.BRepAlgoAPI_Cut(k,Z[0]).Shape();else{let Q=Z[0];for(let re=1;re<Z.length;re++)Q=new t.BRepAlgoAPI_Fuse(Q,Z[re]).Shape();k=new t.BRepAlgoAPI_Cut(k,Q).Shape()}w()}else{if(Y.length<=10)Y.forEach(([P,R])=>{const L=new t.gp_Ax2(new t.gp_Pnt(P,R,0),t.gp.prototype.DZ()),te=new t.BRepPrimAPI_MakeCylinder(L,M/2,s).Shape();k=new t.BRepAlgoAPI_Cut(k,te).Shape()});else{const P=Y.map(([L,te])=>{const Z=new t.gp_Ax2(new t.gp_Pnt(L,te,0),t.gp.prototype.DZ());return new t.BRepPrimAPI_MakeCylinder(Z,M/2,s).Shape()});let R=P[0];for(let L=1;L<P.length;L++)R=new t.BRepAlgoAPI_Fuse(R,P[L]).Shape();k=new t.BRepAlgoAPI_Cut(k,R).Shape()}w()}}if(T.length<=10)T.forEach(([M,b])=>{const x=new t.gp_Ax2(new t.gp_Pnt(M,b,s-i),t.gp.prototype.DZ()),C=new t.BRepPrimAPI_MakeCylinder(x,a/2,i).Shape();k=new t.BRepAlgoAPI_Cut(k,C).Shape()});else{const M=T.map(([F,W])=>{const oe=new t.gp_Ax2(new t.gp_Pnt(F,W,s-i),t.gp.prototype.DZ());return new t.BRepPrimAPI_MakeCylinder(oe,a/2,i).Shape()}),b=30,x=[];for(let F=0;F<M.length;F+=b){const W=Math.min(F+b,M.length);let oe=M[F];for(let j=F+1;j<W;j++)oe=new t.BRepAlgoAPI_Fuse(oe,M[j]).Shape();x.push(oe)}let C=x[0];for(let F=1;F<x.length;F++)C=new t.BRepAlgoAPI_Fuse(C,x[F]).Shape();k=new t.BRepAlgoAPI_Cut(k,C).Shape()}return console.log(" Terminal recesses cut"),w(),$&&console.log(" Ledge integrated into cell holes"),w(),w(),k}function jt(e,n){const t=we.instance;if(!t||!e)return null;try{const o=new t.STEPControl_Writer;o.Transfer(e,0),o.Write(n);const r=t.FS.readFile(n);return t.FS.unlink(n),r}catch(o){return console.error("STEP bytes error:",o),null}}function et(e,n){const t=we.instance;if(!(!t||!e))try{const o=new t.STEPControl_Writer;o.Transfer(e,0),o.Write(n);const r=t.FS.readFile(n),s=new Blob([r],{type:"application/step"}),a=URL.createObjectURL(s),i=document.createElement("a");i.href=a,i.download=n,document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(a),t.FS.unlink(n),ae(`Downloaded ${n} successfully!`,"success")}catch(o){console.error("STEP export error:",o),ae("Error exporting STEP file: "+o.message,"error")}}function Zt(){return["0","SECTION","2","HEADER","9","$ACADVER","1","AC1009","9","$INSUNITS","70","4","0","ENDSEC"]}function Gt(){return["0","SECTION","2","TABLES","0","TABLE","2","LAYER","70","1","0","LAYER","2","busbar","70","0","62","7","6","CONTINUOUS","0","ENDTAB","0","ENDSEC"]}function Vt(e,n,t,o){return["0","CIRCLE","8",o,"10",e.toFixed(4),"20",n.toFixed(4),"30","0.0","40",t.toFixed(4)]}function Jt(e,n,t,o,r,s){const a=i=>i*180/Math.PI;return["0","ARC","8",s,"10",e.toFixed(4),"20",n.toFixed(4),"30","0.0","40",t.toFixed(4),"50",a(o).toFixed(4),"51",a(r).toFixed(4)]}function De(e,n,t,o,r){return["0","LINE","8",r,"10",e.toFixed(4),"20",n.toFixed(4),"30","0.0","11",t.toFixed(4),"21",o.toFixed(4),"31","0.0"]}const We=2*Math.PI,he=1e-5,Fe=e=>{const n=e%We;return n<0?n+We:n},Qt=(e,n)=>{const t=Math.abs(Fe(e)-Fe(n));return t>Math.PI?We-t:t};function eo(e,n,t,o){const r=n[0]-e[0],s=n[1]-e[1],a=e[0]-t[0],i=e[1]-t[1],u=r*r+s*s;if(u<he)return[];const c=2*(a*r+i*s),h=a*a+i*i-o*o,y=c*c-4*u*h;if(y<=0)return[];const l=Math.sqrt(y),g=(-c-l)/(2*u),p=(-c+l)/(2*u),v=Math.max(0,g),d=Math.min(1,p);return d-v<he?[]:[[v,d]]}function ft(e,n,t,o,r){const s=t[0],a=t[1],i=o[0],u=o[1],c=i-s,h=u-a,y=Math.hypot(c,h);if(y<he)return[];const l=c/y,g=h/y,p=I=>[(I[0]-s)*l+(I[1]-a)*g,-(I[0]-s)*g+(I[1]-a)*l],v=p(e),d=p(n);let m=0,f=1;const _=d[0]-v[0],D=d[1]-v[1],T=[[-_,v[0]-0],[_,y-v[0]],[-D,v[1]- -r],[D,r-v[1]]];for(const[I,E]of T)if(Math.abs(I)<he){if(E<-he)return[]}else{const w=E/I;if(I<0){if(w>f+he)return[];w>m&&(m=w)}else{if(w<m-he)return[];w<f&&(f=w)}}return f-m<he?[]:[[m,f]]}function to(e){const n=e.slice().sort((s,a)=>s[0]-a[0]),t=[];for(const s of n)t.length&&s[0]<=t[t.length-1][1]+he?t[t.length-1][1]=Math.max(t[t.length-1][1],s[1]):t.push([s[0],s[1]]);const o=[];let r=0;for(const[s,a]of t)s>r+he&&o.push([r,Math.min(s,1)]),r=Math.max(r,a);return r<1-he&&o.push([r,1]),o}function oo(e,n){for(const t of n)if(Qt(e,t)<Math.PI/2-he)return!0;return!1}function at(e,n,t){const o="busbar",r=[...Zt(),...Gt(),"0","SECTION","2","ENTITIES"],s=Array.isArray(e.extraPads)?e.extraPads:[],a=Array.isArray(e.extraSegments)?e.extraSegments:[],i=Array.isArray(e.cutouts)?e.cutouts:[],u=new Map,c=[],h=(l,g,p=t)=>(u.has(l)?u.get(l).radius=Math.max(u.get(l).radius,p):u.set(l,{pos:g,dirs:[],radius:p}),u.get(l));for(const l of e.padIndices){const g=n[l];g&&h(`c${l}`,g,t)}for(const l of s)!(l!=null&&l.key)||!Array.isArray(l.pos)||h(l.key,l.pos,l.radius??t);e.edges.forEach((l,g)=>{const p=n[l.from],v=n[l.to];if(!p||!v)return;const d=[{key:`c${l.from}`,pos:p},...l.waypoints.map((m,f)=>({key:`w${g}_${f}`,pos:m})),{key:`c${l.to}`,pos:v}];for(let m=1;m<d.length-1;m++)h(d[m].key,d[m].pos,t);for(let m=0;m<d.length-1;m++){const f=d[m],_=d[m+1],D=_.pos[0]-f.pos[0],T=_.pos[1]-f.pos[1];if(Math.hypot(D,T)<he)continue;const E=Math.atan2(T,D);h(f.key,f.pos,t).dirs.push(E),h(_.key,_.pos,t).dirs.push(E+Math.PI),c.push({a:f.pos.slice(),b:_.pos.slice(),padKeyA:f.key,padKeyB:_.key,radius:t})}}),a.forEach((l,g)=>{if(!Array.isArray(l==null?void 0:l.from)||!Array.isArray(l==null?void 0:l.to))return;const p=l.fromKey||`extra_from_${g}`,v=l.toKey||`extra_to_${g}`,d=l.radius??t;h(p,l.from,d),h(v,l.to,d);const m=l.to[0]-l.from[0],f=l.to[1]-l.from[1];if(Math.hypot(m,f)<he)return;const D=Math.atan2(f,m);h(p,l.from,d).dirs.push(D),h(v,l.to,d).dirs.push(D+Math.PI),c.push({a:l.from.slice(),b:l.to.slice(),padKeyA:p,padKeyB:v,radius:d})});const y=Array.from(u.entries()).map(([l,g])=>({key:l,...g}));for(const l of y){const[g,p]=l.pos,v=l.radius??t;if(l.dirs.length===0){r.push(...Vt(g,p,v,o));continue}const d=[];for(const f of l.dirs)d.push(Fe(f-Math.PI/2)),d.push(Fe(f+Math.PI/2));d.sort((f,_)=>f-_);const m=[];for(const f of d)(m.length===0||Math.abs(f-m[m.length-1])>he)&&m.push(f);for(let f=0;f<m.length;f++){const _=m[f],D=m[(f+1)%m.length],T=f+1<m.length?D-_:We-_+D;if(T<he)continue;const I=Fe(_+T/2);if(oo(I,l.dirs))continue;const E=g+v*Math.cos(I),w=p+v*Math.sin(I);let S=!1;for(const k of c)if(!(k.padKeyA===l.key||k.padKeyB===l.key)&&ft([E,w],[E,w],k.a,k.b,k.radius??t).length){S=!0;break}if(!S)for(const k of y){if(k.key===l.key)continue;const z=E-k.pos[0],V=w-k.pos[1],$=k.radius??t;if(z*z+V*V<$*$-he){S=!0;break}}S||r.push(...Jt(g,p,v,_,D,o))}}for(let l=0;l<c.length;l++){const g=c[l],p=g.b[0]-g.a[0],v=g.b[1]-g.a[1],d=Math.hypot(p,v);if(d<he)continue;const m=g.radius??t,f=-v/d*m,_=p/d*m,D=[{p:[g.a[0]+f,g.a[1]+_],q:[g.b[0]+f,g.b[1]+_]},{p:[g.a[0]-f,g.a[1]-_],q:[g.b[0]-f,g.b[1]-_]}];for(const T of D){const I=[];for(let w=0;w<c.length;w++)w!==l&&I.push(...ft(T.p,T.q,c[w].a,c[w].b,c[w].radius??t));for(const w of y)w.key===g.padKeyA||w.key===g.padKeyB||I.push(...eo(T.p,T.q,w.pos,w.radius??t));const E=to(I);for(const[w,S]of E){if(S-w<.001)continue;const k=T.p[0]+w*(T.q[0]-T.p[0]),z=T.p[1]+w*(T.q[1]-T.p[1]),V=T.p[0]+S*(T.q[0]-T.p[0]),$=T.p[1]+S*(T.q[1]-T.p[1]);r.push(...De(k,z,V,$,o))}}}for(const l of i){const[g,p]=l.center,v=l.width/2,d=l.height/2,m=g-v,f=g+v,_=p-d,D=p+d;r.push(...De(m,_,f,_,o)),r.push(...De(f,_,f,D,o)),r.push(...De(f,D,m,D,o)),r.push(...De(m,D,m,_,o))}return r.push("0","ENDSEC","0","EOF"),r.join(`
`)+`
`}function It(e,n){const t=new Blob([e],{type:"application/dxf"}),o=URL.createObjectURL(t),r=document.createElement("a");r.href=o,r.download=n,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(o)}const Ce=["#ef4444","#f59e0b","#10b981","#3b82f6","#a855f7","#ec4899","#14b8a6","#f97316"];let Ge=1,Ne=0;const U={list:[],activeId:null,listeners:new Set,mutationListeners:new Set,subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)},subscribeMutations(e){return this.mutationListeners.add(e),()=>this.mutationListeners.delete(e)},_emitMutation(e){this.mutationListeners.forEach(n=>n(e))},_notify(){this.listeners.forEach(e=>e())},getSnapshot(){return{activeId:this.activeId,list:this.list.map(e=>({id:e.id,name:e.name,color:e.color,cellIndices:Array.isArray(e.cellIndices)?[...e.cellIndices]:[],thickness:e.thickness,overlapEnabled:e.overlapEnabled===!0,overlapSize:Number.isFinite(Number(e.overlapSize))&&Number(e.overlapSize)>0?Number(e.overlapSize):10,face:e.face==="bottom"?"bottom":"top"}))}},replaceFromSnapshot(e){const n=e&&Array.isArray(e.list)?e.list:[];this.list=n.map((o,r)=>({id:typeof o.id=="string"&&o.id?o.id:`bb-${r+1}`,name:typeof o.name=="string"&&o.name?o.name:`Busbar ${r+1}`,color:typeof o.color=="string"&&o.color?o.color:Ce[r%Ce.length],cellIndices:Array.isArray(o.cellIndices)?o.cellIndices.map(s=>Number(s)).filter(s=>Number.isInteger(s)&&s>=0):[],thickness:Number.isFinite(Number(o.thickness))&&Number(o.thickness)>0?Number(o.thickness):1,overlapEnabled:o.overlapEnabled===!0,overlapSize:Number.isFinite(Number(o.overlapSize))&&Number(o.overlapSize)>0?Number(o.overlapSize):10,face:o.face==="bottom"?"bottom":"top"})),typeof(e==null?void 0:e.activeId)=="string"&&this.list.some(o=>o.id===e.activeId)?this.activeId=e.activeId:this.activeId=this.list.length?this.list[0].id:null,Ge=this.list.reduce((o,r)=>{const s=parseInt(String(r.id).replace(/^bb-/,""),10);return Number.isFinite(s)?Math.max(o,s):o},0)+1,Ne=this.list.length,this._emitMutation("replaceFromSnapshot"),this._notify()},add(e="top"){const n=e==="bottom"?"top":"bottom",t=new Set(this.list.filter(a=>a.face===n).map(a=>a.color)),o=new Set(this.list.filter(a=>a.face===e).map(a=>a.color));let r=Ce.find(a=>!t.has(a)&&!o.has(a));r||(r=Ce.find(a=>!t.has(a))),r||(r=Ce[Ne%Ce.length]);const s={id:"bb-"+Ge++,name:`Busbar ${this.list.length+1}`,color:r,cellIndices:[],thickness:1,overlapEnabled:!1,overlapSize:10,face:e==="bottom"?"bottom":"top"};return Ne++,this.list.push(s),this.activeId=s.id,this._emitMutation("add"),this._notify(),s},remove(e){this.list=this.list.filter(n=>n.id!==e),this.activeId===e&&(this.activeId=this.list.length?this.list[0].id:null),this._emitMutation("remove"),this._notify()},rename(e,n){const t=this.list.find(o=>o.id===e);t&&(t.name=n,this._emitMutation("rename"),this._notify())},setColor(e,n){const t=this.list.find(o=>o.id===e);t&&(t.color=n,this._emitMutation("setColor"),this._notify())},setThickness(e,n){const t=this.list.find(o=>o.id===e);t&&(t.thickness=n,this._emitMutation("setThickness"),this._notify())},setOverlapEnabled(e,n){const t=this.list.find(o=>o.id===e);t&&(t.overlapEnabled=n===!0,this._emitMutation("setOverlapEnabled"),this._notify())},setOverlapSize(e,n){const t=this.list.find(o=>o.id===e);t&&Number.isFinite(Number(n))&&Number(n)>0&&(t.overlapSize=Number(n),this._emitMutation("setOverlapSize"),this._notify())},setFace(e,n){const t=this.list.find(o=>o.id===e);t&&(t.face=n==="bottom"?"bottom":"top",this._emitMutation("setFace"),this._notify())},setActive(e){this.activeId=e,this._emitMutation("setActive"),this._notify()},getActive(){return this.list.find(e=>e.id===this.activeId)||null},toggleCell(e){const n=this.getActive();if(!n)return!1;const t=n.cellIndices.indexOf(e);if(t>=0)n.cellIndices.splice(t,1);else{if(this.list.find(r=>r.id!==n.id&&(r.face||"top")===(n.face||"top")&&r.cellIndices.includes(e)))return!1;n.cellIndices.push(e)}return this._emitMutation("toggleCell"),this._notify(),!0},clearAll(){this.list.length!==0&&(this.list=[],this.activeId=null,Ne=0,Ge=1,this._emitMutation("clearAll"),this._notify())},clearAllCells(){this.list.every(e=>e.cellIndices.length===0)||(this.list.forEach(e=>{e.cellIndices=[]}),this._emitMutation("clearAllCells"),this._notify())}};function no(e,n,t,o){const r=[],s=(2*t+o)*1.3;for(let c=0;c<e.length;c++)for(let h=c+1;h<e.length;h++){const y=n[e[c]],l=n[e[h]];Math.hypot(y[0]-l[0],y[1]-l[1])<=s&&r.push([e[c],e[h]])}const a=new Map;e.forEach(c=>a.set(c,[]));for(const[c,h]of r)a.get(c).push(h),a.get(h).push(c);const i=new Set,u=[];for(const c of e){if(i.has(c))continue;const h=[],y=[c];for(;y.length;){const l=y.pop();if(!i.has(l)){i.add(l),h.push(l);for(const g of a.get(l))y.push(g)}}u.push(h)}for(;u.length>1;){let c=null,h=1/0,y=-1,l=-1;for(let g=0;g<u.length;g++)for(let p=g+1;p<u.length;p++)for(const v of u[g])for(const d of u[p]){const m=Math.hypot(n[v][0]-n[d][0],n[v][1]-n[d][1]);m<h&&(h=m,c=[v,d],y=g,l=p)}r.push(c),u[y]=u[y].concat(u[l]),u.splice(l,1)}return r}function so(e,n,t){const o=t[0]-n[0],r=t[1]-n[1],s=o*o+r*r;if(s===0)return Math.hypot(e[0]-n[0],e[1]-n[1]);const a=Math.max(0,Math.min(1,((e[0]-n[0])*o+(e[1]-n[1])*r)/s)),i=n[0]+a*o,u=n[1]+a*r;return Math.hypot(e[0]-i,e[1]-u)}function tt(e,n,t,o,r,s){const a=t+r+s;for(const i of o)if(so(i,e,n)<a)return!1;return!0}function ro(e,n,t,o,r,s){const a=(e[0]+n[0])/2,i=(e[1]+n[1])/2,u=n[0]-e[0],c=n[1]-e[1],h=Math.hypot(u,c);if(h===0)return null;const y=-c/h,l=u/h,g=t+r+s+1;for(let p=1;p<=10;p++)for(const v of[1,-1]){const d=p*g,m=[a+v*d*y,i+v*d*l];if(tt(e,m,t,o,r,s)&&tt(m,n,t,o,r,s))return m}return null}function ao(e,n,t,o){const r=1-o,s=r*r*e[0]+2*r*o*n[0]+o*o*t[0],a=r*r*e[1]+2*r*o*n[1]+o*o*t[1];return[s,a]}function io(e,n){if(!Array.isArray(e)||e.length<3)return e;const t=[e[0]],o=5,r=Math.max(.5,n*.65);for(let s=1;s<e.length-1;s++){const a=e[s-1],i=e[s],u=e[s+1],c=i[0]-a[0],h=i[1]-a[1],y=u[0]-i[0],l=u[1]-i[1],g=Math.hypot(c,h),p=Math.hypot(y,l);if(g<1e-6||p<1e-6){t.push(i);continue}const v=c/g,d=h/g,m=y/p,f=l/p;if(v*m+d*f>.985){t.push(i);continue}const D=Math.min(r,g*.35,p*.35);if(D<.25){t.push(i);continue}const T=[i[0]-v*D,i[1]-d*D],I=[i[0]+m*D,i[1]+f*D];t.push(T);for(let E=1;E<o;E++){const w=E/o;t.push(ao(T,i,I,w))}t.push(I)}return t.push(e[e.length-1]),t}function Pt(e){const t=new Map;for(const r of e){const s=r[1].toFixed(4);t.has(s)||t.set(s,[]),t.get(s).push(r[0])}let o=1/0;for(const r of t.values()){r.sort((s,a)=>s-a);for(let s=1;s<r.length;s++){const a=r[s]-r[s-1];a>.001&&(o=Math.min(o,a))}}return Number.isFinite(o)?o:0}function co(e,n,t){if(e.length<2)return{extraPads:[],extraSegments:[]};const o=e.map(m=>({index:m,pos:n[m]})).filter(m=>Array.isArray(m.pos)&&m.pos.length>=2);if(o.length!==e.length)return{extraPads:[],extraSegments:[]};const r=.001,s=Pt(n);if(s<=r)return{extraPads:[],extraSegments:[]};const a=Math.max(.5,s*.25),i=.001,u=(m,f)=>n.some(_=>{if(Math.abs(_[1]-m.pos[1])>i)return!1;const D=_[0]-m.pos[0];return f==="left"&&D>=-r||f==="right"&&D<=r?!1:Math.abs(Math.abs(D)-s)<=a}),c=new Map;for(const m of o){const f=m.pos[1].toFixed(4);c.has(f)||c.set(f,[]),c.get(f).push(m)}const h=[],y=[];for(const m of c.values())m.sort((f,_)=>f.pos[0]-_.pos[0]),h.push(m[0]),y.push(m[m.length-1]);const l=h.filter(m=>!u(m,"left")),g=y.filter(m=>!u(m,"right")),p=[],v=[],d=(m,f)=>{const _=f==="left"?-1:1,D=m.slice().sort((T,I)=>T.pos[1]-I.pos[1]);for(let T=0;T<D.length-1;T++){const I=D[T],E=D[T+1],w=Math.abs(I.pos[0]-E.pos[0]);if(w<.2)continue;const S=Math.max(.35,w*.24,t*.25),k=`boundary_round_${f}_${T}`,z=[(I.pos[0]+E.pos[0])/2+_*S,(I.pos[1]+E.pos[1])/2],V=Math.hypot(z[0]-I.pos[0],z[1]-I.pos[1]),$=Math.hypot(z[0]-E.pos[0],z[1]-E.pos[1]),M=Math.max(t*.75,V-t+t*.45,$-t+t*.45);p.push({key:k,pos:z,radius:M}),v.push({from:z,to:I.pos,fromKey:k,toKey:`c${I.index}`,radius:M}),v.push({from:z,to:E.pos,fromKey:k,toKey:`c${E.index}`,radius:M})}};return d(l,"left"),d(g,"right"),{extraPads:p,extraSegments:v}}function lo(e,n,t,o){if(e.length<2)return{extraPads:[],extraSegments:[]};const r=e.map(E=>({index:E,pos:n[E]})).filter(E=>Array.isArray(E.pos)&&E.pos.length>=2);if(r.length!==e.length)return{extraPads:[],extraSegments:[]};const s=.001,a=Pt(n);if(a<=s)return{extraPads:[],extraSegments:[]};const i=Math.max(.5,a*.25),u=.001,c=(E,w)=>n.some(S=>{if(Math.abs(S[1]-E.pos[1])>u)return!1;const k=S[0]-E.pos[0];return w==="left"&&k>=-s||w==="right"&&k<=s?!1:Math.abs(Math.abs(k)-a)<=i}),h=new Map;for(const E of r){const w=E.pos[1].toFixed(4);h.has(w)||h.set(w,[]),h.get(w).push(E)}const y=[],l=[];for(const E of h.values())E.sort((w,S)=>w.pos[0]-S.pos[0]),y.push(E[0]),l.push(E[E.length-1]);const g=y.filter(E=>!c(E,"left")),p=l.filter(E=>!c(E,"right"));let v=null,d=[];if(g.length>p.length&&g.length>0?(v="left",d=g):p.length>g.length&&p.length>0&&(v="right",d=p),!v||d.length===0)return{extraPads:[],extraSegments:[]};const m=Number.isFinite(Number(o))&&Number(o)>0?Number(o):10,f=v==="left"?-1:1,_=t==="honeycomb"?f<0?Math.min(...d.map(E=>E.pos[0]))-m:Math.max(...d.map(E=>E.pos[0]))+m:null,D=[],T=[],I=d.slice().sort((E,w)=>E.pos[1]-w.pos[1]).map((E,w)=>{const S=`edge_overlap_${w}`,k=[_??E.pos[0]+f*m,E.pos[1]];return D.push({key:S,pos:k}),T.push({from:k,to:E.pos,fromKey:S,toKey:`c${E.index}`}),{key:S,pos:k}});for(let E=0;E<I.length-1;E++){const w=I[E],S=I[E+1],k=d[E],z=d[E+1];T.push({from:w.pos,to:S.pos,fromKey:w.key,toKey:S.key});const V=`edge_overlap_fill_${E}`,$=[(w.pos[0]+S.pos[0]+k.pos[0]+z.pos[0])/4,(w.pos[1]+S.pos[1]+k.pos[1]+z.pos[1])/4];D.push({key:V,pos:$}),T.push({from:$,to:w.pos,fromKey:V,toKey:w.key}),T.push({from:$,to:S.pos,fromKey:V,toKey:S.key}),T.push({from:$,to:k.pos,fromKey:V,toKey:`c${k.index}`}),T.push({from:$,to:z.pos,fromKey:V,toKey:`c${z.index}`})}return{extraPads:D,extraSegments:T}}function mt(e,n,t){return t!==!0?[]:e.map(o=>n[o]).filter(o=>Array.isArray(o)&&o.length>=2).map(o=>({center:o.slice(),width:5,height:2}))}function Bt(e,n,t,o,r,s,a=null,i=!0,u="grid",c=10,h=!1){if(e.length===0)return{padIndices:[],edges:[],blocked:null,extraPads:[],extraSegments:[],cutouts:[]};if(e.length===1)return{padIndices:e.slice(),edges:[],blocked:null,extraPads:[],extraSegments:[],cutouts:mt(e,n,h)};const y=no(e,n,t,r),l=new Set(e),g=n.filter((T,I)=>!l.has(I)),p=Math.max(r,.3),v=o,d=[];for(const[T,I]of y){const E=n[T],w=n[I];if(tt(E,w,v,g,s,p))d.push({from:T,to:I,waypoints:[]});else{const S=ro(E,w,v,g,s,p);if(S)d.push({from:T,to:I,waypoints:[S]});else return{padIndices:e.slice(),edges:d,blocked:{from:T,to:I,reason:"no clear route between these cells"},extraPads:[],extraSegments:[],cutouts:[]}}}const m=d.map(T=>{const I=[n[T.from],...T.waypoints,n[T.to]],E=io(I,o);return{from:T.from,to:T.to,waypoints:E.slice(1,-1)}}),f=i?lo(e,n,u,c):{extraPads:[],extraSegments:[]},_=co(e,n,o),D=mt(e,n,h);return{padIndices:e.slice(),edges:m,blocked:null,extraPads:[...f.extraPads,..._.extraPads],extraSegments:[...f.extraSegments,..._.extraSegments],cutouts:D}}function uo(e,n){const t=parseInt(e.slice(1,3),16),o=parseInt(e.slice(3,5),16),r=parseInt(e.slice(5,7),16);return`rgba(${t},${o},${r},${n})`}function pt(e,n,t,o,r,s,a,i="preview",u=!1,c=!1){const h=document.getElementById(i);if(!h)return;const y=B.viewTransform;if(!y||e.length===0)return;const l=h.getContext("2d"),g=o/2,p=I=>(I-y.minX+g+s)*y.scale+y.offsetX,v=I=>(I-y.minY+g+s)*y.scale+y.offsetY,d=I=>(I??r)*y.scale,m=I=>Array.isArray(I==null?void 0:I.extraSegments)?I.extraSegments:[],f=I=>Array.isArray(I==null?void 0:I.extraPads)?I.extraPads:[],_=I=>Array.isArray(I==null?void 0:I.cutouts)?I.cutouts:[];l.save(),l.translate(B.panX,B.panY),l.scale(B.zoom,B.zoom);const D=B.zoom,T=(I,E=1)=>{l.save(),l.setTransform(1,0,0,1,0,0),l.globalAlpha=E,c&&(l.translate(h.width,0),l.scale(-1,1)),l.drawImage(I,0,0),l.restore()};e.forEach((I,E)=>{const w=n[E];if(!w||I.cellIndices.length===0)return;const S=!u&&I.id===a,k=u?.12:S?.45:.3,z=window.devicePixelRatio||1,V=document.createElement("canvas");V.width=h.width,V.height=h.height;const $=V.getContext("2d");$.scale(z,z),$.translate(B.panX,B.panY),$.scale(B.zoom,B.zoom);const M=document.createElement("canvas");M.width=h.width,M.height=h.height;const b=M.getContext("2d");b.scale(z,z),b.translate(B.panX,B.panY),b.scale(B.zoom,B.zoom);const x=I.color,C=`rgb(${parseInt(x.slice(1,3),16)},${parseInt(x.slice(3,5),16)},${parseInt(x.slice(5,7),16)})`,F=I.cellIndices,W=F.length,oe=(o+s)*1.3,j=(o+s)*1.5,J=[],ne=Array.from({length:W},()=>new Set);for(let N=0;N<W;N++)for(let Y=N+1;Y<W;Y++){const P=t[F[N]],R=t[F[Y]];if(!P||!R)continue;const L=Math.hypot(P[0]-R[0],P[1]-R[1]);L<=oe?(J.push([N,Y]),ne[N].add(Y),ne[Y].add(N)):L<=j&&(ne[N].add(Y),ne[Y].add(N))}$.strokeStyle=C,$.lineWidth=2*d(),$.lineCap="round",$.lineJoin="round";for(const[N,Y]of J){const P=t[F[N]],R=t[F[Y]];$.beginPath(),$.moveTo(p(P[0]),v(P[1])),$.lineTo(p(R[0]),v(R[1])),$.stroke()}for(const N of m(w))$.lineWidth=2*d(N.radius),$.beginPath(),$.moveTo(p(N.from[0]),v(N.from[1])),$.lineTo(p(N.to[0]),v(N.to[1])),$.stroke();$.fillStyle=C,$.beginPath();for(const N of F){const Y=t[N];if(!Y)continue;const P=d(),R=p(Y[0]),L=v(Y[1]);$.moveTo(R+P,L),$.arc(R,L,P,0,Math.PI*2)}for(const N of f(w)){const Y=d(N.radius),P=p(N.pos[0]),R=v(N.pos[1]);$.moveTo(P+Y,R),$.arc(P,R,Y,0,Math.PI*2)}$.fill(),$.fillStyle=C;for(let N=0;N<W;N++)for(const Y of ne[N])if(!(Y<=N))for(const P of ne[N]){if(P<=Y||!ne[Y].has(P))continue;const R=t[F[N]],L=t[F[Y]],te=t[F[P]];if(!R||!L||!te)continue;const Z=[(R[0]+L[0]+te[0])/3,(R[1]+L[1]+te[1])/3],Q=[R,L,te].map(re=>{const se=re[0]-Z[0],A=re[1]-Z[1],K=Math.hypot(se,A);if(K<1e-6||K<=r)return re;const H=r/K;return[re[0]-se*H,re[1]-A*H]});$.beginPath(),$.moveTo(p(Q[0][0]),v(Q[0][1])),$.quadraticCurveTo(p(Z[0]),v(Z[1]),p(Q[1][0]),v(Q[1][1])),$.quadraticCurveTo(p(Z[0]),v(Z[1]),p(Q[2][0]),v(Q[2][1])),$.quadraticCurveTo(p(Z[0]),v(Z[1]),p(Q[0][0]),v(Q[0][1])),$.closePath(),$.fill()}$.strokeStyle=C,$.lineWidth=2*d(),$.lineCap="round";for(const N of w.edges){if(N.waypoints.length===0)continue;const Y=[t[N.from],...N.waypoints,t[N.to]];if(!Y.some(P=>!P)){$.beginPath(),$.moveTo(p(Y[0][0]),v(Y[0][1]));for(let P=1;P<Y.length;P++)$.lineTo(p(Y[P][0]),v(Y[P][1]));$.stroke()}}$.save(),$.globalCompositeOperation="destination-out";for(const N of _(w)){const Y=N.width*y.scale,P=N.height*y.scale,R=p(N.center[0]),L=v(N.center[1]);$.fillRect(R-Y/2,L-P/2,Y,P)}if($.restore(),T(V,k),!u){b.strokeStyle=uo(I.color,S?1:.85),b.lineWidth=(S?2.5:1.5)/D;for(const N of I.cellIndices){if(!t[N])continue;const[Y,P]=t[N],R=p(Y),L=v(P);b.beginPath(),b.arc(R,L,d(),0,Math.PI*2),b.stroke()}}if(!u&&w.blocked){b.strokeStyle="#ef4444",b.lineWidth=3/D,b.setLineDash([8/D,5/D]);const N=t[w.blocked.from],Y=t[w.blocked.to];N&&Y&&(b.beginPath(),b.moveTo(p(N[0]),v(N[1])),b.lineTo(p(Y[0]),v(Y[1])),b.stroke()),b.setLineDash([])}T(M,1)}),l.restore()}function it(e,n,t,o,r){const s=we.instance;if(!s||e.padIndices.length===0)return null;const a=[],i=Array.isArray(e.extraPads)?e.extraPads:[],u=Array.isArray(e.extraSegments)?e.extraSegments:[],c=Array.isArray(e.cutouts)?e.cutouts:[];for(const y of e.padIndices){if(!n[y])continue;const[l,g]=n[y],p=new s.gp_Ax2(new s.gp_Pnt(l,g,o),s.gp.prototype.DZ());a.push(new s.BRepPrimAPI_MakeCylinder(p,t,r).Shape())}for(const y of i){const[l,g]=y.pos,p=y.radius??t,v=new s.gp_Ax2(new s.gp_Pnt(l,g,o),s.gp.prototype.DZ());a.push(new s.BRepPrimAPI_MakeCylinder(v,p,r).Shape())}for(const y of e.edges){const l=[n[y.from],...y.waypoints,n[y.to]];for(let g=1;g<l.length-1;g++){const[p,v]=l[g],d=new s.gp_Ax2(new s.gp_Pnt(p,v,o),s.gp.prototype.DZ());a.push(new s.BRepPrimAPI_MakeCylinder(d,t,r).Shape())}for(let g=0;g<l.length-1;g++){const[p,v]=l[g],[d,m]=l[g+1],f=d-p,_=m-v,D=Math.hypot(f,_);if(D<1e-6)continue;const T=Math.atan2(_,f),I=new s.BRepPrimAPI_MakeBox(D,2*t,r).Shape(),E=new s.gp_Trsf;E.SetTranslation(new s.gp_Vec(0,-t,0));let w=new s.BRepBuilderAPI_Transform(I,E,!1).Shape();const S=new s.gp_Trsf;S.SetRotation(new s.gp_Ax1(new s.gp_Pnt(0,0,0),s.gp.prototype.DZ()),T),w=new s.BRepBuilderAPI_Transform(w,S,!1).Shape();const k=new s.gp_Trsf;k.SetTranslation(new s.gp_Vec(p,v,o)),w=new s.BRepBuilderAPI_Transform(w,k,!1).Shape(),a.push(w)}}for(const y of u){const[l,g]=y.from,[p,v]=y.to,d=y.radius??t,m=p-l,f=v-g,_=Math.hypot(m,f);if(_<1e-6)continue;const D=Math.atan2(f,m),T=new s.BRepPrimAPI_MakeBox(_,2*d,r).Shape(),I=new s.gp_Trsf;I.SetTranslation(new s.gp_Vec(0,-d,0));let E=new s.BRepBuilderAPI_Transform(T,I,!1).Shape();const w=new s.gp_Trsf;w.SetRotation(new s.gp_Ax1(new s.gp_Pnt(0,0,0),s.gp.prototype.DZ()),D),E=new s.BRepBuilderAPI_Transform(E,w,!1).Shape();const S=new s.gp_Trsf;S.SetTranslation(new s.gp_Vec(l,g,o)),E=new s.BRepBuilderAPI_Transform(E,S,!1).Shape(),a.push(E)}if(a.length===0)return null;let h=a[0];for(let y=1;y<a.length;y++)h=new s.BRepAlgoAPI_Fuse(h,a[y]).Shape();for(const y of c){const[l,g]=y.center,p=y.width,v=y.height,d=new s.BRepPrimAPI_MakeBox(p,v,r).Shape(),m=new s.gp_Trsf;m.SetTranslation(new s.gp_Vec(l-p/2,g-v/2,o));const f=new s.BRepBuilderAPI_Transform(d,m,!1).Shape();h=new s.BRepAlgoAPI_Cut(h,f).Shape()}return h}function Ye(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}let $e="both",ot=null,Ve=null;function Tt(){var t;const e=document.getElementById("busbarList");if(!e)return;const n=((t=document.getElementById("busbarFormat"))==null?void 0:t.value)||"step";e.classList.toggle("busbar-list-dxf",n==="dxf")}const ho='<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v13M7 11l5 5 5-5"/><path d="M4 20h16"/></svg>';function fo(e,n){const t=document.createElement("div");return t.className="busbar-row"+(e.id===U.activeId?" active":""),t.dataset.id=e.id,t.innerHTML=`
<div class="busbar-header">
<label class="busbar-color-wrap" title="Busbar color">
<input class="busbar-color" type="color" value="${Ye(e.color)}" aria-label="Busbar color for ${Ye(e.name)}">
</label>
<input class="busbar-name" type="text" value="${Ye(e.name)}">
<button class="busbar-dl" title="Download this busbar">${ho}</button>
<button class="busbar-del" title="Delete">×</button>
</div>
<div class="busbar-meta">
<span class="busbar-count">${e.cellIndices.length} cell${e.cellIndices.length===1?"":"s"}</span>
<label class="busbar-overlap-label">
<input class="busbar-overlap" type="checkbox" ${e.overlapEnabled===!0?"checked":""}>
Overlap
</label>
<label class="busbar-overlap-size-label">Size
<input class="busbar-overlap-size" type="number" value="${e.overlapSize??10}" step="0.5" min="0.5" ${e.overlapEnabled===!0?"":"disabled"}>
</label>
<label class="busbar-thickness-label">Thickness
<input class="busbar-thickness" type="number" value="${e.thickness}" step="0.1" min="0.1">
</label>
</div>
${n[e.id]?`<div class="busbar-blocked">⚠ ${Ye(n[e.id])}</div>`:""}
`,t.addEventListener("click",o=>{o.target.closest("input")||o.target.closest("button")||U.setActive(e.id)}),t.querySelector(".busbar-name").addEventListener("change",o=>{U.rename(e.id,o.target.value)}),t.querySelector(".busbar-color").addEventListener("input",o=>{U.setColor(e.id,o.target.value)}),t.querySelector(".busbar-overlap").addEventListener("change",o=>{U.setOverlapEnabled(e.id,o.target.checked)}),t.querySelector(".busbar-overlap-size").addEventListener("change",o=>{const r=parseFloat(o.target.value);r>0&&U.setOverlapSize(e.id,r)}),t.querySelector(".busbar-thickness").addEventListener("change",o=>{const r=parseFloat(o.target.value);r>0&&U.setThickness(e.id,r)}),t.querySelector(".busbar-dl").addEventListener("click",o=>{o.stopPropagation(),ot&&ot(e.id)}),t.querySelector(".busbar-del").addEventListener("click",o=>{o.stopPropagation(),U.remove(e.id)}),t}function Ze(e={}){const n=document.getElementById("busbarList");if(!n)return;if(n.innerHTML="",Tt(),U.list.length===0){const o=document.createElement("div");o.className="busbar-empty",o.textContent="No busbars. Add a Top or Bottom busbar then click cells in the preview.",n.appendChild(o);return}const t=$e==="top"?["top"]:["top","bottom"];for(const o of t){const r=U.list.filter(i=>(i.face||"top")===o),s=document.createElement("div");s.className="busbar-face-section";const a=document.createElement("div");if(a.className="busbar-face-label",a.textContent=o==="top"?"Top Face":"Bottom Face",s.appendChild(a),r.length===0){const i=document.createElement("div");i.className="busbar-face-empty",i.textContent=`No ${o} busbars.`,s.appendChild(i)}else r.forEach(i=>s.appendChild(fo(i,e)));n.appendChild(s)}}function mo({onDownloadSingle:e,onDownloadAll:n,onFaceFilterChange:t}={}){ot=e??null,Ve=n??null;const o=document.getElementById("addTopBusbarBtn");o&&o.addEventListener("click",()=>U.add("top"));const r=document.getElementById("addBottomBusbarBtn");r&&r.addEventListener("click",()=>U.add("bottom"));const s=document.getElementById("bottomFaceWrap");document.querySelectorAll(".face-filter-btn").forEach(c=>{c.addEventListener("click",()=>{$e=c.dataset.filter,document.querySelectorAll(".face-filter-btn").forEach(h=>{h.classList.toggle("active",h.dataset.filter===$e)}),s&&(s.hidden=$e==="top"),t&&t($e),Ze()})});const a=document.getElementById("clearMarkingsBtn");a&&a.addEventListener("click",()=>{U.list.every(c=>c.cellIndices.length===0)||U.clearAllCells()});const i=document.getElementById("downloadAllBusbarsBtn");i&&i.addEventListener("click",()=>{Ve&&Ve()});const u=document.getElementById("busbarFormat");u&&u.addEventListener("change",Tt)}let Te=[],Le=null;function po(e,n,t){if(!Array.isArray(e)||e.length<2)return{top:[],bottom:[]};const o=new Map;for(const[c,h]of e){const y=h.toFixed(4);o.has(y)||o.set(y,[]),o.get(y).push([c,h])}const r=Array.from(o.keys()).sort((c,h)=>Number(c)-Number(h));if(r.length===0)return{top:[],bottom:[]};const s=(o.get(r[0])||[]).slice().sort((c,h)=>c[0]-h[0]),a=(o.get(r[r.length-1])||[]).slice().sort((c,h)=>c[0]-h[0]),i=Math.min(...e.map(([,c])=>c))-n-t,u=Math.max(...e.map(([,c])=>c))+n+t;return{top:s.slice(0,-1).map((c,h)=>({key:`top_${h}`,x:(c[0]+s[h+1][0])/2,y:i})),bottom:a.slice(0,-1).map((c,h)=>({key:`bottom_${h}`,x:(c[0]+a[h+1][0])/2,y:u}))}}function bo(e,n){const t=[],o=new Set,r=(s,a)=>{const i=`${s.toFixed(4)},${a.toFixed(4)}`;o.has(i)||(o.add(i),t.push([s,a]))};for(const s of(e==null?void 0:e.padIndices)||[]){const a=n[s];a&&r(a[0],a[1])}for(const s of(e==null?void 0:e.edges)||[]){const a=[n[s.from],...s.waypoints||[],n[s.to]].filter(Boolean);for(let i=0;i<a.length-1;i++){const u=a[i],c=a[i+1];r((u[0]+c[0])/2,(u[1]+c[1])/2)}}for(const s of(e==null?void 0:e.extraPads)||[])Array.isArray(s==null?void 0:s.pos)&&r(s.pos[0],s.pos[1]);for(const s of(e==null?void 0:e.extraSegments)||[])!Array.isArray(s==null?void 0:s.from)||!Array.isArray(s==null?void 0:s.to)||(r(s.from[0],s.from[1]),r(s.to[0],s.to[1]),r((s.from[0]+s.to[0])/2,(s.from[1]+s.to[1])/2));return t}function kt(e,n,t,o){const{enabled:r=!1,cellRadius:s,spacing:a,tabWidth:i,tabOverlapSide:u,overlapLength:c=28}=o;if(r!==!0||u!=="top"&&u!=="bottom")return;const h=po(t,s,a)[u];if(h.length===0)return;const y=u==="top"?1:-1,l=Math.max(i||0,s*2+a*2),g=c+s*2+a*2,p=Math.max((i||0)*.6,s*.75),v=Math.max(.05,((i||0)-.5)/2),d=[];for(let f=0;f<e.length;f++){e[f];const _=n[f];if(!_||_.blocked)continue;const D=bo(_,t);if(D.length===0)continue;const T=u==="top"?Math.min(...D.map(([,S])=>S)):Math.max(...D.map(([,S])=>S)),I=Math.max(s*1.1,a+s*.35),E=D.filter(([,S])=>u==="top"?S<=T+I:S>=T-I);if(E.length===0)continue;let w=null;for(const S of h)for(const k of E){const z=Math.abs(k[0]-S.x),V=Math.abs(S.y-k[1]);if(z>l||V>g)continue;const $=z*3+V,M={busbarIndex:f,geometry:_,anchor:k,score:$,tabKey:S.key,tab:S,deltaX:k[0]-S.x};(!w||M.score<w.score)&&(w=M)}w&&d.push(w)}const m=new Map;for(const f of d)m.has(f.tabKey)||m.set(f.tabKey,[]),m.get(f.tabKey).push(f);for(const f of d){const _=m.get(f.tabKey)||[],D=_.find(S=>S.deltaX<-p),T=_.find(S=>S.deltaX>p);if(D&&T)continue;const I=f.anchor.slice(),E=[f.tab.x,f.tab.y],w=[f.tab.x,f.tab.y+y*c];f.geometry.extraPads=Array.isArray(f.geometry.extraPads)?f.geometry.extraPads:[],f.geometry.extraPads.push({key:`bms_tab_anchor_${u}_${f.tabKey}`,pos:I,radius:v}),f.geometry.extraPads.push({key:`bms_tab_edge_${u}_${f.tabKey}`,pos:E,radius:v}),f.geometry.extraPads.push({key:`bms_tab_inner_${u}_${f.tabKey}`,pos:w,radius:v}),f.geometry.extraSegments=Array.isArray(f.geometry.extraSegments)?f.geometry.extraSegments:[],f.geometry.extraSegments.push({from:I,to:w,fromKey:`bms_tab_anchor_${u}_${f.tabKey}`,toKey:`bms_tab_inner_${u}_${f.tabKey}`,radius:v}),f.geometry.extraSegments.push({from:E,to:w,fromKey:`bms_tab_edge_${u}_${f.tabKey}`,toKey:`bms_tab_inner_${u}_${f.tabKey}`,radius:v})}}function Ct(e,n,t,o){zt(e,n);const r=U.list.map((i,u)=>({bb:i,geom:Te[u]})),s=r.filter(i=>(i.bb.face||"top")==="top"),a=r.filter(i=>(i.bb.face||"top")==="bottom");Ot("preview-bottom"),pt(s.map(i=>i.bb),s.map(i=>i.geom),e,n,t,o,U.activeId,"preview"),pt(a.map(i=>i.bb),a.map(i=>i.geom),e,n,t,o,U.activeId,"preview-bottom",!1,!0)}function At(){if(!Le)return;const{positions:e,cellSize:n,padRadius:t,spacing:o}=Le;Ct(e,n,t,o)}function Be(e=!1){var o,r,s,a;e&&(B.zoom=1,B.panX=0,B.panY=0);const n=document.getElementById("previewStats"),t=(i,u)=>{n.textContent=i,n.style.color=u};try{const i=parseFloat(document.getElementById("xDim").value),u=parseFloat(document.getElementById("yDim").value),c=parseFloat(document.getElementById("spacing").value),h=parseFloat(document.getElementById("cellSize").value),y=document.getElementById("layoutType").value,l=parseFloat(document.getElementById("ledgeWidth").value)||0,g=parseFloat(document.getElementById("bmsHoleDiameter").value)||4,p=parseFloat(document.getElementById("coverThickness").value);if(!i||!u||!c||!h){t("Configure settings to see preview","#94a3b8");return}if(l>0&&l>=h){t(`Ledge width (${l}mm) must be less than cell diameter (${h}mm)!`,"#ef4444"),Pe();return}const v=h+c*2;if(i<v||u<v){t(`Pack too small! Minimum: ${v.toFixed(1)}×${v.toFixed(1)} mm`,"#ef4444"),Pe();return}if(h>i||h>u){t(`Cell diameter (${h}mm) larger than pack dimensions!`,"#ef4444"),Pe();return}if(c<0){t("Cell spacing cannot be negative!","#ef4444"),Pe();return}const d=Ht(i,u,c,h,y);if(!d||d.length===0){t("No cells fit! Increase pack size or decrease cell size/spacing","#ef4444"),Pe();return}if(document.getElementById("bmsHolesType").value!=="off"){if(g>h){t(`BMS hole (${g}mm) larger than cell (${h}mm)! Reduce hole size.`,"#ef4444"),Pe();return}const b=h/2,x=g/2,C=b,F=Math.min(...d.map(L=>L[1])),oe=Math.max(...d.map(L=>L[1]))+C+c,j=F-C-c,J={};for(const[L,te]of d){const Z=Math.round(te*1e3);J[Z]||(J[Z]=[]),J[Z].push([L,te])}const ne=Object.keys(J).map(Number).sort((L,te)=>L-te),N=ne[ne.length-1],Y=ne[0];J[N].sort((L,te)=>L[0]-te[0]),J[Y].sort((L,te)=>L[0]-te[0]);const P=oe,R=j;for(let L=0;L<J[N].length-1;L++){const te=(J[N][L][0]+J[N][L+1][0])/2,Z=P;for(const[Q,re]of d){const se=Math.hypot(te-Q,Z-re),A=x+b;if(se<A){const K=(se-b)*2;t(`BMS hole overlaps cells! Max diameter: ${K.toFixed(1)}mm`,"#ef4444"),B.currentPositions=[],Pe();return}}}for(let L=0;L<J[Y].length-1;L++){const te=(J[Y][L][0]+J[Y][L+1][0])/2,Z=R;for(const[Q,re]of d){const se=Math.hypot(te-Q,Z-re),A=x+b;if(se<A){t("BMS hole overlaps cells! Reduce hole diameter.","#ef4444"),B.currentPositions=[],Pe();return}}}}p>h/2&&t(`Cover thickness (${p}mm) very large for cell size (${h}mm)`,"#f59e0b"),c<.5&&c>0&&t("Spacing < 0.5mm may be difficult to 3D print","#f59e0b"),d.length<2?t(`Only ${d.length} cell fits. Increase pack size for practical holder.`,"#f59e0b"):n.style.color="#10b981";const _=h/2,D=Math.max(_-l,1),T=4,I=((o=document.getElementById("busbarCellCutoutEnabled"))==null?void 0:o.checked)===!0,E={left:Math.min(...d.map(b=>b[0]))-_-c,right:Math.max(...d.map(b=>b[0]))+_+c,bottom:Math.min(...d.map(b=>b[1]))-_-c,top:Math.max(...d.map(b=>b[1]))+_+c};Te=U.list.map(b=>Bt(b.cellIndices,d,_,D,c,T,E,b.overlapEnabled!==!1,y,b.overlapSize,I)),kt(U.list,Te,d,{enabled:((r=document.getElementById("bmsHolesType"))==null?void 0:r.value)==="tabs",cellRadius:_,spacing:c,tabWidth:parseFloat((s=document.getElementById("tabWidth"))==null?void 0:s.value)||4,tabOverlapSide:((a=document.getElementById("tabOverlapSide"))==null?void 0:a.value)||"off",overlapLength:28}),Le={positions:d,cellSize:h,padRadius:D,spacing:c},Ct(d,h,D,c);const w={};U.list.forEach((b,x)=>{const C=Te[x];C&&C.blocked&&(w[b.id]=C.blocked.reason)}),Ze(w);const S=Math.min(...d.map(b=>b[0])),k=Math.min(...d.map(b=>b[1])),z=Math.max(...d.map(b=>b[0])),V=Math.max(...d.map(b=>b[1])),$=z-S+h+c*2,M=V-k+h+c*2;d.length>=2&&(n.textContent=`${d.length} cells • ${$.toFixed(0)}×${M.toFixed(0)} mm`)}catch(i){console.error("Preview error:",i),t("Error: "+i.message,"#ef4444")}}async function go(){var n,t,o;const e=document.getElementById("layoutType").value;if(!(!we.initialized&&(ae("3D engine not ready. Please wait...","error"),await wt(),!we.initialized))){be(!0,"Generating 3D Model","Please be patient..."),await new Promise(r=>setTimeout(r,50));try{const r=parseFloat(document.getElementById("xDim").value),s=parseFloat(document.getElementById("yDim").value),a=parseFloat(document.getElementById("spacing").value),i=parseFloat(document.getElementById("cellSize").value),u=parseFloat(document.getElementById("ledgeWidth").value)||0,c=parseFloat(document.getElementById("bmsHoleDiameter").value)||4,h=parseFloat(document.getElementById("coverThickness").value),y=i/2,l=c/2;if(u>0&&u>=i){ae(`Ledge width (${u}mm) must be less than cell diameter (${i}mm)!`,"error"),be(!1);return}const g=i+a*2;if(r<g||s<g){ae(`Pack too small! Minimum size: ${g.toFixed(1)}×${g.toFixed(1)} mm`,"error"),be(!1);return}if(i>r||i>s){ae("Cell diameter is larger than pack dimensions!","error"),be(!1);return}if(a<0){ae("Cell spacing cannot be negative!","error"),be(!1);return}const p=parseFloat(document.getElementById("height").value),v=8,d=1,m=document.getElementById("roundedCorners").checked,f=document.getElementById("bmsHolesType").value,_=f!=="off",D=f==="tabs",T=f==="fullcircles",I=!1,E=!1;let w,S;switch(e){case"grid":w=Et(r,s,a,i),S="Grid Layout";break;case"honeycomb":w=St(r,s,a,i),S="Honeycomb Layout";break;case"vertical":w=Mt(r,s,a,i),S="Vertical Honeycomb";break;default:ae("Invalid layout type","error");return}if(_&&T){const A=(G,ce,de,q)=>{const me=(de+q)/2,pe=ce<G?-1:1;let xe=pe>0?-Math.PI/2:0,Ee=pe>0?0:Math.PI/2;for(let Re=0;Re<80;Re++){const ke=(xe+Ee)/2,Rt=me-(de+y*Math.cos(ke)),dt=(ce+y*Math.sin(ke)-G)*pe-Rt*Math.sqrt(3);if(Math.abs(dt)<1e-8)break;dt<0?pe>0?xe=ke:Ee=ke:pe>0?Ee=ke:xe=ke}const Se=(xe+Ee)/2,Me=ce+y*Math.sin(Se);return(G+2*Me)/3},K=Math.min(...w.map(G=>G[1])),H=Math.max(...w.map(G=>G[1])),ie=K-y-a,le=H+y+a,X={};for(const[G,ce]of w){const de=Math.round(ce*1e3);X[de]||(X[de]=[]),X[de].push([G,ce])}const ue=Object.keys(X).map(Number).sort((G,ce)=>G-ce),ee=ue[0],O=ue[ue.length-1];X[ee].sort((G,ce)=>G[0]-ce[0]),X[O].sort((G,ce)=>G[0]-ce[0]);const fe=[];for(let G=0;G<X[ee].length-1;G++){const ce=X[ee][G][0],de=X[ee][G+1][0],q=X[ee][G][1];fe.push({hx:(ce+de)/2,hy:A(ie,q,ce,de)})}for(let G=0;G<X[O].length-1;G++){const ce=X[O][G][0],de=X[O][G+1][0],q=X[O][G][1];fe.push({hx:(ce+de)/2,hy:A(le,q,ce,de)})}for(const{hx:G,hy:ce}of fe){let de=1/0;for(const[q,me]of w){const pe=Math.hypot(G-q,ce-me);pe<de&&(de=pe)}if(de<l+y){const q=(de-y)*2;ae(`BMS hole too large, overlaps cell! Max diameter: ${q.toFixed(2)}mm`,"error"),be(!1);return}}}else if(_){const A=Math.min(...w.map(q=>q[1])),K=Math.max(...w.map(q=>q[1])),H=i/2,ie=A-H-a,le=K+H+a,X={};for(const[q,me]of w){const pe=Math.round(me*1e3);X[pe]||(X[pe]=[]),X[pe].push([q,me])}const ue=Object.keys(X).map(Number).sort((q,me)=>q-me),ee=ue[ue.length-1],O=ue[0];X[ee].sort((q,me)=>q[0]-me[0]),X[O].sort((q,me)=>q[0]-me[0]);const fe=X[ee][0][1],G=X[O][0][1];let ce,de;E||(ce=le,de=ie);for(let q=0;q<X[ee].length-1;q++){const me=(X[ee][q][0]+X[ee][q+1][0])/2,pe=ce,xe=[X[ee][q][0],X[ee][q][1]],Ee=[X[ee][q+1][0],X[ee][q+1][1]];for(const[Se,Me]of w){if(Se===xe[0]&&Me===xe[1]||Se===Ee[0]&&Me===Ee[1])continue;if(Math.hypot(me-Se,pe-Me)<l+y+u){ae(`BMS hole (${c}mm) collides with cell ledges! Reduce BMS hole size or increase spacing.`,"error"),be(!1);return}}}for(let q=0;q<X[O].length-1;q++){const me=(X[O][q][0]+X[O][q+1][0])/2,pe=de,xe=[X[O][q][0],X[O][q][1]],Ee=[X[O][q+1][0],X[O][q+1][1]];for(const[Se,Me]of w){if(Se===xe[0]&&Me===xe[1]||Se===Ee[0]&&Me===Ee[1])continue;if(Math.hypot(me-Se,pe-Me)<l+y+u){ae(`BMS hole (${c}mm) collides with cell ledges! Reduce BMS hole size or increase spacing.`,"error"),be(!1);return}}}}const k=parseFloat(document.getElementById("tabWidth").value)||4,z=parseFloat(document.getElementById("tabDepth").value)||1,V=((n=document.getElementById("tabOverlapSide"))==null?void 0:n.value)||"off",M=Ut(w,{cellSize:i,spacing:a,height:p,terminalDiameter:v,terminalDepth:d,coverThickness:h,roundedCorners:m,bmsHoles:_,ledgeWidth:u,filletBms:I,circleHoleOffset:E,useTabs:D,useFullCircles:T,bmsHoleDiameter:c,tabWidth:k,tabDepth:z,tabOverlapSide:V});if(!M){ae("Failed to create 3D model","error");return}const b=Math.max(y-u,1),x=v/2,C=((t=document.getElementById("busbarCellCutoutEnabled"))==null?void 0:t.checked)===!0,F={left:Math.min(...w.map(A=>A[0]))-y-a,right:Math.max(...w.map(A=>A[0]))+y+a,bottom:Math.min(...w.map(A=>A[1]))-y-a,top:Math.max(...w.map(A=>A[1]))+y+a},W=U.list.map(A=>Bt(A.cellIndices,w,y,b,a,x,F,A.overlapEnabled!==!1,e,A.overlapSize,C));kt(U.list,W,w,{enabled:f==="tabs",cellRadius:y,spacing:a,tabWidth:k,tabOverlapSide:V,overlapLength:28});for(let A=0;A<U.list.length;A++){const K=U.list[A],H=W[A];if(H.blocked){ae(`${K.name}: ${H.blocked.reason}. Cannot export.`,"error"),be(!1);return}}const oe=(Math.min(...w.map(A=>A[0]))+Math.max(...w.map(A=>A[0])))/2,j=(Math.min(...w.map(A=>A[1]))+Math.max(...w.map(A=>A[1])))/2,J=w.map(([A,K])=>[A-oe,K-j]),ne=A=>(A||"").replace(/[^A-Za-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"busbar",N=(A,K)=>{var ee;const H=A.cellIndices,ie=((ee=document.getElementById("busbarCellCutoutEnabled"))==null?void 0:ee.checked)===!0,le=(Array.isArray(K==null?void 0:K.extraSegments)?K.extraSegments:[]).filter(O=>String((O==null?void 0:O.fromKey)||"").startsWith("bms_tab_")||String((O==null?void 0:O.toKey)||"").startsWith("bms_tab_")).map(O=>`${O.from[0].toFixed(3)},${O.from[1].toFixed(3)}>${O.to[0].toFixed(3)},${O.to[1].toFixed(3)}`).sort().join(";");if(H.length===0)return null;if(H.length===1)return`single|${A.thickness.toFixed(2)}|ov:${A.overlapEnabled===!0?1:0}|os:${Number(A.overlapSize??10).toFixed(2)}|cc:${ie?1:0}|tabs:${le}`;const X=H.map(O=>J[O]).filter(Boolean),ue=[];for(let O=0;O<X.length;O++)for(let fe=O+1;fe<X.length;fe++)ue.push(Math.hypot(X[O][0]-X[fe][0],X[O][1]-X[fe][1]));return ue.sort((O,fe)=>O-fe),`${X.length}|${A.thickness.toFixed(2)}|ov:${A.overlapEnabled===!0?1:0}|os:${Number(A.overlapSize??10).toFixed(2)}|cc:${ie?1:0}|tabs:${le}|${ue.map(O=>O.toFixed(3)).join(",")}`},Y=((o=document.getElementById("busbarFormat"))==null?void 0:o.value)||"step",P=[],R=new Map;for(let A=0;A<U.list.length;A++){const K=U.list[A];if(K.cellIndices.length===0)continue;const H=N(K,W[A]);if(H&&R.has(H)){R.get(H).copies.push(K.name);continue}const ie={bb:K,geom:W[A],copies:[K.name],shape:null};Y==="step"&&(ie.shape=it(W[A],J,b,p,K.thickness),!ie.shape)||(P.push(ie),H&&R.set(H,ie))}const L=A=>new Promise(K=>setTimeout(K,A));et(M,`cellholder_${e}.step`);for(let A=0;A<P.length;A++){await L(250);const{bb:K,geom:H,shape:ie}=P[A],le=`busbar_${ne(K.name)}`;if(Y==="dxf"){const X=at(H,J,b);It(X,`${le}.dxf`)}else et(ie,`${le}.step`)}const Z=U.list.filter(A=>A.cellIndices.length>0).length-P.length,Q=P.length>0?`. ${P.length} unique ${Y.toUpperCase()} busbar file${P.length===1?"":"s"}${Z>0?` (${Z} mirrored duplicate${Z===1?"":"s"} skipped)`:""}`:"",re=D?"edge tabs":E?"circle offset":"semicircle offset",se=I&&!D?" with filleted holes":"";ae(`${S} generated. ${w.length} cells (${re}${se})${Q}.`,"success")}catch(r){console.error("Generation error:",r),ae("Error: "+r.message,"error")}finally{be(!1)}}}function _t(){var u;if(!Le||Te.length===0)return null;const{positions:e,padRadius:n}=Le,t=(Math.min(...e.map(c=>c[0]))+Math.max(...e.map(c=>c[0])))/2,o=(Math.min(...e.map(c=>c[1]))+Math.max(...e.map(c=>c[1])))/2,r=e.map(([c,h])=>[c-t,h-o]),s=parseFloat(document.getElementById("height").value),a=((u=document.getElementById("busbarFormat"))==null?void 0:u.value)||"step";return{centeredPositions:r,padRadius:n,height:s,busbarFormat:a,safeName:c=>(c||"").replace(/[^A-Za-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"busbar"}}async function yo(e){var a;const n=_t();if(!n){ae("Configure the layout first to enable busbar downloads.","error");return}const t=U.list.findIndex(i=>i.id===e);if(t<0)return;const o=U.list[t];if(o.cellIndices.length===0){ae(`${o.name} has no cells assigned.`,"error");return}const r=Te[t];if(!r||r.blocked){ae(`${o.name}: ${((a=r==null?void 0:r.blocked)==null?void 0:a.reason)??"geometry unavailable"}`,"error");return}if(n.busbarFormat==="step"&&!we.initialized){ae("3D engine not ready. Please wait.","error");return}const s=`busbar_${n.safeName(o.name)}`;be(!0,`Exporting ${o.name}`,""),await new Promise(i=>setTimeout(i,20));try{if(n.busbarFormat==="dxf"){const i=at(r,n.centeredPositions,n.padRadius);It(i,`${s}.dxf`)}else{const i=it(r,n.centeredPositions,n.padRadius,n.height,o.thickness);if(!i){ae(`Failed to build 3D shape for ${o.name}.`,"error");return}et(i,`${s}.step`)}}catch(i){ae(`Export error: ${i.message}`,"error")}finally{be(!1)}}async function vo(){const e=_t();if(!e){ae("Configure the layout first to enable busbar downloads.","error");return}const n=U.list.map((t,o)=>({bb:t,geom:Te[o],i:o})).filter(({bb:t,geom:o})=>t.cellIndices.length>0&&o&&!o.blocked);if(n.length===0){ae("No busbars with cells to export.","error");return}if(e.busbarFormat==="step"&&!we.initialized){ae("3D engine not ready. Please wait.","error");return}be(!0,"Building busbar ZIP","Please wait..."),await new Promise(t=>setTimeout(t,50));try{const{default:t}=await qt(async()=>{const{default:i}=await import("./jszip.min-BiHF8TMC.js").then(u=>u.j);return{default:i}},[],import.meta.url),o=new t;for(const{bb:i,geom:u}of n){const c=`busbar_${e.safeName(i.name)}`;if(e.busbarFormat==="dxf"){const h=at(u,e.centeredPositions,e.padRadius);o.file(`${c}.dxf`,h)}else{const h=it(u,e.centeredPositions,e.padRadius,e.height,i.thickness);if(!h)continue;const y=jt(h,`_zip_${c}.step`);y&&o.file(`${c}.step`,y)}}const r=await o.generateAsync({type:"blob",compression:"DEFLATE",compressionOptions:{level:6}}),s=URL.createObjectURL(r),a=document.createElement("a");a.href=s,a.download="busbars.zip",document.body.appendChild(a),a.click(),document.body.removeChild(a),URL.revokeObjectURL(s),ae(`Downloaded busbars.zip (${n.length} file${n.length===1?"":"s"}).`,"success")}catch(t){console.error("ZIP export error:",t),ae("ZIP export error: "+t.message,"error")}finally{be(!1)}}const Dt=2,nt="#config=",wo=new Set(["grid","honeycomb","vertical"]),xo=new Set(["off","halfcircles","fullcircles","tabs"]),Eo=new Set(["off","top","bottom","left","right"]);function $t(e){if(e==="top"||e==="bottom"||e==="off")return e;if(e==="left"||e==="right")return"off";throw new Error("Invalid tab overlap side")}const So=new Set(["sp","mm"]),Mo=new Set(["step","dxf"]);function Io(e){const n=new TextEncoder().encode(e);let t="";for(const o of n)t+=String.fromCharCode(o);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function Po(e){const n=e.replace(/-/g,"+").replace(/_/g,"/"),t="=".repeat((4-n.length%4)%4),o=atob(n+t),r=new Uint8Array(o.length);for(let s=0;s<o.length;s++)r[s]=o.charCodeAt(s);return new TextDecoder().decode(r)}function ye(e,n){if(!Number.isFinite(e))throw new Error(`Invalid number: ${n}`);return e}function Ie(e,n){if(typeof e!="string")throw new Error(`Invalid string: ${n}`);return e}function st(e,n){if(typeof e!="boolean")throw new Error(`Invalid boolean: ${n}`);return e}function Bo(e,n){if(!e||typeof e!="object")throw new Error(`Invalid busbar at index ${n}`);const t=Ie(e.id,`busbars.list[${n}].id`),o=Ie(e.name,`busbars.list[${n}].name`),r=Ie(e.color,`busbars.list[${n}].color`),s=ye(Number(e.thickness),`busbars.list[${n}].thickness`);if(s<=0)throw new Error(`Invalid busbar thickness at index ${n}`);if(!Array.isArray(e.cellIndices))throw new Error(`Invalid busbar cell index list at index ${n}`);const a=e.cellIndices.map(h=>{const y=Number(h);if(!Number.isInteger(y)||y<0)throw new Error(`Invalid busbar cell index at index ${n}`);return y}),i=e.face==="bottom"?"bottom":"top",u=e.overlapEnabled==null?!1:st(e.overlapEnabled,`busbars.list[${n}].overlapEnabled`),c=e.overlapSize==null?10:ye(Number(e.overlapSize),`busbars.list[${n}].overlapSize`);if(c<=0)throw new Error(`Invalid overlap size at index ${n}`);return{id:t,name:o,color:r,thickness:s,cellIndices:a,face:i,overlapEnabled:u,overlapSize:c}}function ct(e){if(!e||typeof e!="object")throw new Error("Missing config object");const n=Number(e.v);if(!Number.isInteger(n))throw new Error("Missing schema version");if(n!==Dt)throw new Error("Unsupported schema version");const t=e.pack,o=e.cell,r=e.bms,s=e.busbars;if(!t||!o||!r||!s)throw new Error("Missing required sections");const a=Ie(t.mode,"pack.mode");if(!So.has(a))throw new Error("Invalid pack mode");const i=Ie(o.layoutType,"cell.layoutType");if(!wo.has(i))throw new Error("Invalid layout type");const u=Ie(r.type,"bms.type");if(!xo.has(u))throw new Error("Invalid BMS type");const c=Ie(r.tabOverlapSide??"off","bms.tabOverlapSide");if(!Eo.has(c))throw new Error("Invalid tab overlap side");const h=$t(c),y=Ie(s.format,"busbars.format");if(!Mo.has(y))throw new Error("Invalid busbar format");const l=s.cellCutoutEnabled==null?!1:st(s.cellCutoutEnabled,"busbars.cellCutoutEnabled"),g=Array.isArray(s.list)?s.list.map((v,d)=>Bo(v,d)):(()=>{throw new Error("Invalid busbar list")})(),p=s.activeId==null?null:Ie(s.activeId,"busbars.activeId");if(p!==null&&!g.some(v=>v.id===p))throw new Error("Active busbar id not found in list");return{v:n,pack:{mode:a,series:ye(Number(t.series),"pack.series"),parallel:ye(Number(t.parallel),"pack.parallel"),xDim:ye(Number(t.xDim),"pack.xDim"),yDim:ye(Number(t.yDim),"pack.yDim")},cell:{cellSize:ye(Number(o.cellSize),"cell.cellSize"),layoutType:i,spacing:ye(Number(o.spacing),"cell.spacing"),height:ye(Number(o.height),"cell.height"),coverThickness:ye(Number(o.coverThickness),"cell.coverThickness"),ledgeWidth:ye(Number(o.ledgeWidth),"cell.ledgeWidth"),roundedCorners:st(o.roundedCorners,"cell.roundedCorners")},bms:{type:u,holeDiameter:ye(Number(r.holeDiameter),"bms.holeDiameter"),tabWidth:ye(Number(r.tabWidth),"bms.tabWidth"),tabDepth:ye(Number(r.tabDepth),"bms.tabDepth"),tabOverlapSide:h},busbars:{format:y,activeId:p,cellCutoutEnabled:l,list:g}}}function ve(e,n=0){const t=document.getElementById(e);if(!t)return n;const o=Number(t.value);return Number.isFinite(o)?o:n}function Oe(e,n=""){const t=document.getElementById(e);return t&&typeof t.value=="string"?t.value:n}function bt(e,n=!1){const t=document.getElementById(e);return t?!!t.checked:n}async function Ft(e){if(!(crypto!=null&&crypto.subtle))throw new Error("Web Crypto API is unavailable");const n=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e)),t=new Uint8Array(n);return Array.from(t).map(o=>o.toString(16).padStart(2,"0")).join("")}function To(e,n){const t=typeof e=="function"?e():"sp";return ct({v:Dt,pack:{mode:t,series:ve("series",1),parallel:ve("parallel",1),xDim:ve("xDim",150),yDim:ve("yDim",100)},cell:{cellSize:ve("cellSize",21.35),layoutType:Oe("layoutType","honeycomb"),spacing:ve("spacing",.6),height:ve("height",10),coverThickness:ve("coverThickness",.4),ledgeWidth:ve("ledgeWidth",2.75),roundedCorners:bt("roundedCorners",!0)},bms:{type:Oe("bmsHolesType","fullcircles"),holeDiameter:ve("bmsHoleDiameter",4),tabWidth:ve("tabWidth",4),tabDepth:ve("tabDepth",1),tabOverlapSide:$t(Oe("tabOverlapSide","off"))},busbars:{format:Oe("busbarFormat","step"),activeId:(n==null?void 0:n.activeId)??null,cellCutoutEnabled:bt("busbarCellCutoutEnabled",!1),list:Array.isArray(n==null?void 0:n.list)?n.list.map(o=>({...o,face:o.face==="bottom"?"bottom":"top"})):[]}})}async function ko(e){const n=ct(e),t=JSON.stringify(n),o=Io(t),r=(await Ft(t)).slice(0,16);return`${nt}${o}_${r}`}async function Co(e){if(!e||!e.startsWith(nt))return{ok:!1,reason:"missing"};const n=e.slice(nt.length),t=n.lastIndexOf("_");if(t<=0||t===n.length-1)return{ok:!1,reason:"format"};const o=n.slice(0,t),r=n.slice(t+1);if(!/^[0-9a-f]{16}$/i.test(r))return{ok:!1,reason:"checksum-format"};try{const s=Po(o),a=(await Ft(s)).slice(0,16);if(r.toLowerCase()!==a.toLowerCase())return{ok:!1,reason:"checksum-mismatch"};const i=JSON.parse(s);return{ok:!0,config:ct(i)}}catch(s){return{ok:!1,reason:s instanceof Error?s.message:"decode-failed"}}}const ze=4,Ao=250;let rt=null,Xe=null,He=!1;function Ue(e){const n=document.getElementById(e);if(!n)return;const t=window.devicePixelRatio||1,o=n.getBoundingClientRect();if(o.width===0||o.height===0)return;n.width=o.width*t,n.height=o.height*t,n.getContext("2d").scale(t,t)}function _o(){Ue("preview"),Ue("preview-bottom")}function je(){const e=document.querySelector("[data-pack-mode]");return e&&e.dataset.mode||"sp"}function Do(e){var s;const n=document.getElementById(e);if(!n)return;const t=n.closest(".custom-select");if(!t)return;const o=t.querySelector(".select-selected"),r=t.querySelectorAll(".select-items div");o&&(o.textContent=((s=n.options[n.selectedIndex])==null?void 0:s.text)||""),r.forEach(a=>{a.classList.toggle("same-as-selected",a.dataset.value===n.value)})}function ge(e,n){const t=document.getElementById(e);t&&(t.value=String(n))}function gt(e,n){const t=document.getElementById(e);t&&(t.checked=!!n)}function Ke(e,n){const t=document.getElementById(e);t&&(t.value=String(n),Do(e))}function Lt(e,n={}){const{clearBusbars:t=!0,refresh:o=!0}=n;if(!rt)return;const r=e==="mm"?"mm":"sp",{toggle:s,buttons:a,indicator:i,spFields:u,mmFields:c}=rt;s.dataset.mode=r,a.forEach(h=>{const y=h.dataset.mode===r;h.classList.toggle("active",y),y&&i&&(i.style.left=h.offsetLeft+"px",i.style.width=h.offsetWidth+"px")}),u&&(u.hidden=r!=="sp"),c&&(c.hidden=r!=="mm"),o&&(Ae(),Be(!0)),t&&U.clearAll()}async function lt(){if(!He)try{const e=To(()=>je(),U.getSnapshot()),n=await ko(e);window.location.hash!==n&&window.history.replaceState(null,"",n)}catch(e){console.error("Failed to sync URL hash:",e)}}function Je(){He||(Xe&&clearTimeout(Xe),Xe=setTimeout(()=>{Xe=null,lt()},Ao))}function $o(e){He=!0;try{ge("series",e.pack.series),ge("parallel",e.pack.parallel),ge("xDim",e.pack.xDim),ge("yDim",e.pack.yDim),ge("cellSize",e.cell.cellSize),Ke("layoutType",e.cell.layoutType),ge("spacing",e.cell.spacing),ge("height",e.cell.height),ge("coverThickness",e.cell.coverThickness),ge("ledgeWidth",e.cell.ledgeWidth),gt("roundedCorners",e.cell.roundedCorners),Ke("bmsHolesType",e.bms.type),ge("bmsHoleDiameter",e.bms.holeDiameter),ge("tabWidth",e.bms.tabWidth),ge("tabDepth",e.bms.tabDepth),Ke("tabOverlapSide",e.bms.tabOverlapSide||"off"),Ke("busbarFormat",e.busbars.format),gt("busbarCellCutoutEnabled",e.busbars.cellCutoutEnabled===!0),Lt(e.pack.mode,{clearBusbars:!1,refresh:!1}),Qe(),Ae(),e.pack.mode==="mm"&&(ge("xDim",e.pack.xDim),ge("yDim",e.pack.yDim)),U.replaceFromSnapshot({activeId:e.busbars.activeId,list:e.busbars.list}),Ze()}finally{He=!1}}async function Fo(){if(!window.location.hash||!window.location.hash.startsWith("#config="))return!1;const e=await Co(window.location.hash);return e.ok?($o(e.config),!0):(ae("Shared URL is invalid or corrupted. Loaded default configuration.","error"),!1)}function Lo(){const e=document.getElementById("copyShareUrlBtn");if(!e)return;const n=(e.textContent||"Copy Share URL").trim();let t=null;const o=(r,s)=>{t&&clearTimeout(t),e.classList.remove("is-success","is-error"),r&&e.classList.add(r),e.textContent=s,t=setTimeout(()=>{e.classList.remove("is-success","is-error"),e.textContent=n},2e3)};e.addEventListener("click",async()=>{var r;e.disabled=!0;try{await lt();const s=`${window.location.origin}${window.location.pathname}${window.location.hash}`;if(!((r=navigator.clipboard)!=null&&r.writeText))throw new Error("Clipboard API unavailable");await navigator.clipboard.writeText(s),o("is-success","✓ Copied")}catch(s){console.error("Failed to copy share URL:",s),o("is-error","Copy failed")}finally{e.disabled=!1}})}function Ro(){["series","parallel","xDim","yDim","height","cellSize","layoutType","spacing","coverThickness","ledgeWidth","roundedCorners","bmsHolesType","bmsHoleDiameter","tabWidth","tabDepth","tabOverlapSide","busbarFormat","busbarCellCutoutEnabled"].forEach(n=>{const t=document.getElementById(n);t&&(t.addEventListener("input",Je),t.addEventListener("change",Je))}),U.subscribeMutations(Je)}function Ae(){const e=je(),n=document.getElementById("xDim"),t=document.getElementById("yDim"),o=document.getElementById("packSummary");if(e==="mm"){const m=parseFloat(n.value)||0,f=parseFloat(t.value)||0;o&&(o.innerHTML=`<strong>${m.toFixed(0)} &times; ${f.toFixed(0)} mm</strong> <span class="muted">footprint. Cells fit automatically.</span>`);return}const r=Math.max(1,Math.round(parseFloat(document.getElementById("series").value)||1)),s=Math.max(1,Math.round(parseFloat(document.getElementById("parallel").value)||1)),a=parseFloat(document.getElementById("cellSize").value)||21.35,i=parseFloat(document.getElementById("spacing").value)||.6,u=document.getElementById("layoutType").value,c=a+i,h=Math.sqrt(3)/2*c,y=.02,l=m=>a+2*i+(m-1)*c+y,g=m=>a+2*i+(m-1)*h+y,p=m=>a+2*i+(m-1)*c+c/2+y;let v,d;if(u==="vertical"?(v=g(r),d=p(s)):u==="honeycomb"?(v=p(r),d=g(s)):(v=l(r),d=l(s)),n.value=v.toFixed(2),t.value=d.toFixed(2),o){const m=r*s;o.innerHTML=`<strong>${r}S ${s}P</strong>. ${m} cells. <span class="muted">Footprint about ${v.toFixed(0)} &times; ${d.toFixed(0)} mm.</span>`}}function No(){["series","parallel"].forEach(s=>{const a=document.getElementById(s);a&&(a.addEventListener("input",()=>{Ae(),Be(!0)}),a.addEventListener("change",()=>U.clearAll()))}),["xDim","yDim"].forEach(s=>{const a=document.getElementById(s);a&&(a.addEventListener("input",()=>{je()==="mm"&&(Ae(),Be(!0))}),a.addEventListener("change",()=>{je()==="mm"&&U.clearAll()}))}),["spacing","cellSize","layoutType"].forEach(s=>{const a=document.getElementById(s);a&&a.addEventListener("change",()=>U.clearAll())}),["spacing","cellSize","layoutType","height","coverThickness"].forEach(s=>{const a=document.getElementById(s);if(!a)return;const i=()=>{Ae(),Be(!0)};a.addEventListener("input",i),a.addEventListener("change",i)}),["bmsHolesType","roundedCorners","bmsHoleDiameter","ledgeWidth","tabWidth","tabDepth","tabOverlapSide","busbarCellCutoutEnabled"].forEach(s=>{const a=document.getElementById(s);a&&(a.addEventListener("input",()=>Be(!1)),a.addEventListener("change",()=>Be(!1)))})}function Yo(){const e=document.querySelector("[data-pack-mode]");if(!e)return;const n=Array.from(e.querySelectorAll(".seg")),t=e.querySelector(".seg-indicator"),o=document.querySelector(".pack-sp-fields"),r=document.querySelector(".pack-mm-fields"),s=a=>{!t||!a||(t.style.left=a.offsetLeft+"px",t.style.width=a.offsetWidth+"px")};rt={toggle:e,buttons:n,indicator:t,spFields:o,mmFields:r},n.forEach(a=>a.addEventListener("click",()=>Lt(a.dataset.mode))),requestAnimationFrame(()=>{const a=n.find(i=>i.classList.contains("active"))||n[0];a&&s(a)})}function qe(){B.currentPositions.length>0&&At()}function Oo(e,n){const t=B.viewTransform;if(!t)return null;const o=(e-B.panX)/B.zoom,r=(n-B.panY)/B.zoom,s=(o-t.offsetX)/t.scale+t.minX-t.r-t.spacing,a=(r-t.offsetY)/t.scale+t.minY-t.r-t.spacing;return[s,a]}function yt(e,n){if(!U.getActive())return;const o=Oo(e,n);if(!o)return;const r=B.currentCellSize/2;let s=-1,a=r;B.currentPositions.forEach(([i,u],c)=>{const h=Math.hypot(o[0]-i,o[1]-u);h<a&&(a=h,s=c)}),s>=0&&U.toggleCell(s)}function zo(){function e(t){const o=U.getActive();if(o&&(o.face||"top")!==t){const r=U.list.find(s=>(s.face||"top")===t);r&&U.setActive(r.id)}}function n(t,o){if(!t)return;t.style.cursor="grab",t.addEventListener("wheel",d=>{d.preventDefault();const m=.1,f=d.deltaY>0?-m:m,_=Math.max(.2,Math.min(5,B.zoom+f)),D=t.getBoundingClientRect(),T=d.clientX-D.left,I=d.clientY-D.top,E=_/B.zoom;B.panX=T-(T-B.panX)*E,B.panY=I-(I-B.panY)*E,B.zoom=_,qe()},{passive:!1}),t.addEventListener("mousedown",d=>{e(o),B.isDragging=!0,B.dragStartX=d.clientX,B.dragStartY=d.clientY,B.dragMoved=!1,B.lastMouseX=d.clientX,B.lastMouseY=d.clientY,t.style.cursor="grabbing"}),t.addEventListener("mousemove",d=>{if(!B.isDragging)return;const m=d.clientX-B.dragStartX,f=d.clientY-B.dragStartY;(Math.abs(m)>ze||Math.abs(f)>ze)&&(B.dragMoved=!0),B.panX+=d.clientX-B.lastMouseX,B.panY+=d.clientY-B.lastMouseY,B.lastMouseX=d.clientX,B.lastMouseY=d.clientY,B.currentPositions.length>0&&requestAnimationFrame(()=>qe())}),t.addEventListener("mouseup",d=>{if(B.isDragging&&!B.dragMoved){const m=t.getBoundingClientRect();yt(d.clientX-m.left,d.clientY-m.top)}B.isDragging=!1,B.dragMoved=!1,t.style.cursor="grab"}),t.addEventListener("mouseleave",()=>{t.style.cursor="grab"});let r=0,s=1,a=0,i=0,u=0,c=0,h=0,y=0,l=0,g=0,p=!1,v=!1;t.addEventListener("touchstart",d=>{if(d.preventDefault(),e(o),d.touches.length===1)v=!0,h=d.touches[0].clientX,y=d.touches[0].clientY,l=h,g=y,p=!1;else if(d.touches.length===2){v=!1;const m=d.touches[0],f=d.touches[1];r=Math.hypot(f.clientX-m.clientX,f.clientY-m.clientY),s=B.zoom,a=B.panX,i=B.panY;const _=t.getBoundingClientRect();u=(m.clientX+f.clientX)/2-_.left,c=(m.clientY+f.clientY)/2-_.top}},{passive:!1}),t.addEventListener("touchmove",d=>{if(d.preventDefault(),d.touches.length===1&&v){const m=d.touches[0],f=m.clientX-l,_=m.clientY-g;(Math.abs(f)>ze||Math.abs(_)>ze)&&(p=!0),B.panX+=m.clientX-h,B.panY+=m.clientY-y,h=m.clientX,y=m.clientY,B.currentPositions.length>0&&requestAnimationFrame(()=>qe())}else if(d.touches.length===2){const m=d.touches[0],f=d.touches[1],D=Math.hypot(f.clientX-m.clientX,f.clientY-m.clientY)/r,T=Math.max(.2,Math.min(5,s*D)),I=T/s;B.panX=u-(u-a)*I,B.panY=c-(c-i)*I,B.zoom=T,B.currentPositions.length>0&&requestAnimationFrame(()=>qe())}},{passive:!1}),t.addEventListener("touchend",d=>{if(d.preventDefault(),d.changedTouches.length>0&&v&&!p){const m=d.changedTouches[0],f=t.getBoundingClientRect();yt(m.clientX-f.left,m.clientY-f.top)}d.touches.length===0&&(v=!1,p=!1),d.touches.length<2&&(r=0)},{passive:!1}),t.addEventListener("touchcancel",()=>{v=!1,p=!1,r=0})}window.addEventListener("mouseup",()=>{var t,o;B.isDragging&&(B.isDragging=!1,B.dragMoved=!1,(t=document.getElementById("preview"))!=null&&t.style&&(document.getElementById("preview").style.cursor="grab"),(o=document.getElementById("preview-bottom"))!=null&&o.style&&(document.getElementById("preview-bottom").style.cursor="grab"))}),n(document.getElementById("preview"),"top"),n(document.getElementById("preview-bottom"),"bottom")}function Xo(){const e=document.querySelector("[data-tabs]");if(!e)return;const n=Array.from(e.querySelectorAll(".tab")),t=e.querySelector(".tab-indicator"),o=Array.from(document.querySelectorAll(".tab-panel")),r=a=>{!t||!a||(t.style.left=a.offsetLeft+"px",t.style.width=a.offsetWidth+"px")},s=a=>{for(const i of n){const u=i.dataset.panel===a;i.classList.toggle("active",u),i.setAttribute("aria-selected",u?"true":"false"),u&&r(i)}for(const i of o)i.classList.toggle("active",i.dataset.panel===a)};for(const a of n)a.addEventListener("click",()=>s(a.dataset.panel));requestAnimationFrame(()=>{const a=n.find(i=>i.classList.contains("active"))||n[0];a&&r(a)}),window.addEventListener("resize",()=>{const a=n.find(i=>i.classList.contains("active"));a&&r(a)})}async function vt(){_o(),Nt(),Xo(),Yo();const e=document.getElementById("bmsHolesType");e&&(e.addEventListener("change",Qe),Qe());const n=document.getElementById("generateBtn");n&&n.addEventListener("click",go),mo({onDownloadSingle:yo,onDownloadAll:vo,onFaceFilterChange(o){requestAnimationFrame(()=>requestAnimationFrame(()=>{Ue("preview"),o==="both"&&Ue("preview-bottom"),At()}))}}),Ze(),U.subscribe(()=>Be(!1)),No(),zo(),Lo(),Ro(),await Fo()||Ae(),await wt(),setTimeout(()=>{Be(!0),lt()},100)}document.readyState==="loading"?window.addEventListener("DOMContentLoaded",vt):vt();