(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=re0?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;P0?-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;P0?-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.yd){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{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{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{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=re0?-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{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{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{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;Fi*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[(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)f+he)return[];w>m&&(m=w)}else{if(ws[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)(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{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)({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;fthis.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;ca.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.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;Es-a);for(let s=1;s.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({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;En[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{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"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[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='';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=`
${e.cellIndices.length} cell${e.cellIndices.length===1?"":"s"}
${n[e.id]?`
⚠ ${Ye(n[e.id])}
`:""} `,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;iS)):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.scoreS.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(ii||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;Lh/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(rr||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=ce0?-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;Gq[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;qA[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;AA[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;OO-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;Anew Promise(K=>setTimeout(K,A));et(M,`cellholder_${e}.step`);for(let A=0;AA.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{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=`${m.toFixed(0)} × ${f.toFixed(0)} mm footprint. Cells fit automatically.`);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=`${r}S ${s}P. ${m} cells. Footprint about ${v.toFixed(0)} × ${d.toFixed(0)} mm.`}}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=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();