(function(){const o=document.createElement("link").relList;if(o&&o.supports&&o.supports("modulepreload"))return;for(const c of document.querySelectorAll('link[rel="modulepreload"]'))t(c);new MutationObserver(c=>{for(const s of c)if(s.type==="childList")for(const r of s.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&t(r)}).observe(document,{childList:!0,subtree:!0});function e(c){const s={};return c.integrity&&(s.integrity=c.integrity),c.referrerPolicy&&(s.referrerPolicy=c.referrerPolicy),c.crossOrigin==="use-credentials"?s.credentials="include":c.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function t(c){if(c.ep)return;c.ep=!0;const s=e(c);fetch(c.href,s)}})();const M={zoom:1,panX:0,panY:0,isDragging:!1,dragStartX:0,dragStartY:0,dragMoved:!1,lastMouseX:0,lastMouseY:0,currentPositions:[],currentCellSize:18,viewTransform:null},ke={key:null,positions:null};function ae(n,o="success"){const e=document.getElementById("previewStats");e&&(e.textContent=n,o==="error"?e.style.color="#ef4444":o==="success"?e.style.color="#10b981":e.style.color="#94a3b8")}function be(n,o="Generating 3D Model",e="Please be patient..."){const t=document.getElementById("loadingOverlay");if(!t)return;const c=document.getElementById("loadingText"),s=document.getElementById("loadingSubtext");c&&(c.textContent=o),s&&(s.textContent=e),n?(t.classList.add("active"),t.style.display="flex"):(t.classList.remove("active"),t.style.display="none")}function ze(){const n=document.getElementById("bmsHolesType").value,o=document.getElementById("bmsHoleDiameterGroup"),e=document.getElementById("tabDimensionsGroup");o.style.display=n==="halfcircles"||n==="fullcircles"?"block":"none",e.style.display=n==="tabs"?"grid":"none"}function ft(){document.querySelectorAll("select").forEach(o=>{const e=document.createElement("div");e.className="custom-select",o.parentNode.insertBefore(e,o),e.appendChild(o);const t=document.createElement("div");t.className="select-selected",t.textContent=o.options[o.selectedIndex].text,e.appendChild(t);const c=document.createElement("div");c.className="select-items",Array.from(o.options).forEach((s,r)=>{const u=document.createElement("div");u.textContent=s.text,u.dataset.value=s.value,r===o.selectedIndex&&(u.className="same-as-selected"),u.addEventListener("click",function(m){m.stopPropagation(),o.selectedIndex=r,t.textContent=this.textContent;const i=c.querySelector(".same-as-selected");i&&i.classList.remove("same-as-selected"),this.classList.add("same-as-selected"),t.click(),o.dispatchEvent(new Event("change"))}),c.appendChild(u)}),e.appendChild(c),t.addEventListener("click",function(s){s.stopPropagation(),Je(this),c.classList.toggle("show"),this.classList.toggle("select-arrow-active")})}),document.addEventListener("click",Je)}function Je(n){const o=document.querySelectorAll(".select-items"),e=document.querySelectorAll(".select-selected");o.forEach((t,c)=>{n!==e[c]&&(t.classList.remove("show"),e[c].classList.remove("select-arrow-active"))})}const pt={BASE_URL:"./",DEV:!1,MODE:"production",PROD:!0,SSR:!1},Ie={instance:null,initialized:!1};async function ct(){if(!Ie.initialized)try{const o=`${(typeof import.meta<"u"&&pt?"./":"/").replace(/\/?$/,"/")}vendor/opencascade.wasm.wasm`;Ie.instance=await opencascade({locateFile:()=>o}),Ie.initialized=!0,console.log("OpenCascade initialized successfully"),be(!1)}catch(n){console.error("Failed to initialize OpenCascade:",n),ae("Failed to initialize 3D engine. Please ensure opencascade.wasm.js and opencascade.wasm.wasm are in vendor/.","error"),be(!1)}}function ve(){const n=document.getElementById("preview");if(!n)return;const o=n.getContext("2d");o.clearRect(0,0,n.width,n.height),o.fillStyle="#1e293b",o.fillRect(0,0,n.width,n.height)}function Te(n,o){M.currentPositions=n,M.currentCellSize=o;const e=document.getElementById("preview");if(!e){console.error("Canvas element not found!");return}const t=e.getContext("2d");if(t.clearRect(0,0,e.width,e.height),t.fillStyle="#1e293b",t.fillRect(0,0,e.width,e.height),n.length===0)return;t.save(),t.translate(M.panX,M.panY),t.scale(M.zoom,M.zoom);const c=parseFloat(document.getElementById("spacing").value),s=document.getElementById("bmsHolesType").value,r=s!=="off",u=s==="tabs",m=s==="fullcircles",i=document.getElementById("roundedCorners").checked,f=parseFloat(document.getElementById("bmsHoleDiameter").value)||4,v=parseFloat(document.getElementById("ledgeWidth").value)||0,l=o/2,a=Math.min(...n.map(p=>p[0])),h=Math.min(...n.map(p=>p[1])),x=Math.max(...n.map(p=>p[0])),I=Math.max(...n.map(p=>p[1])),b=x-a+o+c*2,S=I-h+o+c*2,V=e.getBoundingClientRect(),H=V.width,K=V.height,T=80,R=(H-T*2)/b,O=(K-T*2)/S,g=Math.min(R,O),E=(H-b*g)/2,_=(K-S*g)/2;M.viewTransform={offsetX:E,offsetY:_,scale:g,minX:a,minY:h,spacing:c,r:l};const Q=M.zoom;if(i){const p=5*g,y=E,d=_,w=b*g,k=S*g;t.fillStyle="rgba(100, 149, 237, 0.15)",t.beginPath(),t.moveTo(y+p,d),t.lineTo(y+w-p,d),t.arcTo(y+w,d,y+w,d+p,p),t.lineTo(y+w,d+k-p),t.arcTo(y+w,d+k,y+w-p,d+k,p),t.lineTo(y+p,d+k),t.arcTo(y,d+k,y,d+k-p,p),t.lineTo(y,d+p),t.arcTo(y,d,y+p,d,p),t.closePath(),t.fill()}else t.fillStyle="rgba(100, 149, 237, 0.15)",t.fillRect(E,_,b*g,S*g);if(t.strokeStyle="#667eea",t.lineWidth=2/Q,i){const p=5*g,y=E,d=_,w=b*g,k=S*g;t.beginPath(),t.moveTo(y+p,d),t.lineTo(y+w-p,d),t.arcTo(y+w,d,y+w,d+p,p),t.lineTo(y+w,d+k-p),t.arcTo(y+w,d+k,y+w-p,d+k,p),t.lineTo(y+p,d+k),t.arcTo(y,d+k,y,d+k-p,p),t.lineTo(y,d+p),t.arcTo(y,d,y+p,d,p),t.closePath(),t.stroke()}else t.strokeRect(E,_,b*g,S*g);const fe=[];if(r){const p=h-l-c,y=I+l+c,d={};for(const[B,A]of n){const N=Math.round(A*1e3);d[N]||(d[N]=[]),d[N].push([B,A])}const w=Object.keys(d).map(Number).sort((B,A)=>B-A),k=w[w.length-1],q=w[0],le=w[0],de=w[w.length-1];d[k].sort((B,A)=>B[0]-A[0]),d[q].sort((B,A)=>B[0]-A[0]),d[k][0][1],d[q][0][1];let $,U;if(m){const B=d[le][0][1],A=d[de][0][1],N=d[le],j=d[de],P=(se,te,Z,ie)=>{const X=(Z+ie)/2,z=te0?G=re:D=re:z>0?D=re:G=re}const ce=(G+D)/2,oe=te+l*Math.sin(ce);return(se+2*oe)/3};N.length>=2&&($=P(p,B,N[0][0],N[1][0])),j.length>=2&&(U=P(y,A,j[0][0],j[1][0]))}else $=y,U=p;const ee=m?le:k,C=m?de:q;for(let B=0;B0?-Math.PI/2:0,X=Z>0?0:Math.PI/2;for(let oe=0;oe<80;oe++){const ne=(ie+X)/2,re=A-(j+l*Math.cos(ne)),ue=(N+l*Math.sin(ne)-se)*Z-re*Math.sqrt(3);if(Math.abs(ue)<1e-8)break;ue<0?Z>0?ie=ne:X=ne:Z>0?X=ne:ie=ne}const z=(ie+X)/2,G={x:j+l*Math.cos(z),y:N+l*Math.sin(z)},D={x:P-l*Math.cos(z),y:N+l*Math.sin(z)},ce=m?{apex:{x:A,y:se},left:G,right:D}:null;fe.push({x:A,y:te,diameter:f,isTab:!1,isFull:m,debugTri:ce})}for(let B=0;B0?-Math.PI/2:0,X=Z>0?0:Math.PI/2;for(let oe=0;oe<80;oe++){const ne=(ie+X)/2,re=A-(j+l*Math.cos(ne)),ue=(N+l*Math.sin(ne)-se)*Z-re*Math.sqrt(3);if(Math.abs(ue)<1e-8)break;ue<0?Z>0?ie=ne:X=ne:Z>0?X=ne:ie=ne}const z=(ie+X)/2,G={x:j+l*Math.cos(z),y:N+l*Math.sin(z)},D={x:P-l*Math.cos(z),y:N+l*Math.sin(z)},ce=m?{apex:{x:A,y:se},left:G,right:D}:null;fe.push({x:A,y:te,diameter:f,isTab:!1,isFull:m,debugTri:ce})}}t.fillStyle="#1e293b",t.strokeStyle="rgba(102, 126, 234, 0.8)",t.lineWidth=1.5/Q;for(const[p,y]of n){const d=(p-a+l+c)*g+E,w=(y-h+l+c)*g+_,k=l*g;if(t.beginPath(),t.arc(d,w,k,0,Math.PI*2),t.fill(),t.stroke(),v>0){const q=(l-v)*g;t.strokeStyle="rgba(255, 193, 7, 0.8)",t.setLineDash([3/Q,3/Q]),t.lineWidth=1/Q,t.beginPath(),t.arc(d,w,q,0,Math.PI*2),t.stroke(),t.setLineDash([]),t.strokeStyle="rgba(102, 126, 234, 0.8)",t.lineWidth=1.5/Q}}if(r&&fe.length>0)if(u){t.fillStyle="rgba(255, 193, 7, 0.5)",t.strokeStyle="rgba(255, 193, 7, 0.9)",t.lineWidth=1.5/Q;const p=parseFloat(document.getElementById("tabWidth").value)||4,y=parseFloat(document.getElementById("tabDepth").value)||1,d=p*g,w=y*g;for(const k of fe){const q=(k.x-a+l+c)*g+E;k.y>I?(t.fillRect(q-d/2,_+S*g-w,d,w),t.strokeRect(q-d/2,_+S*g-w,d,w)):(t.fillRect(q-d/2,_,d,w),t.strokeRect(q-d/2,_,d,w))}}else if(m){let p=null;for(const y of fe){const d=y.diameter/2*g,w=(y.x-a+l+c)*g+E,k=(y.y-h+l+c)*g+_;for(const[q,le]of n){const de=(q-a+l+c)*g+E,$=(le-h+l+c)*g+_,U=Math.sqrt((w-de)**2+(k-$)**2);if(UI){const w=3/Q;t.arc(y,_+S*g,d,Math.PI,0,!1),t.lineTo(y+d,_+S*g+w),t.lineTo(y-d,_+S*g+w)}else{const w=3/Q;t.arc(y,_,d,0,Math.PI,!1),t.lineTo(y-d,_-w),t.lineTo(y+d,_-w)}t.closePath(),t.fill()}t.globalCompositeOperation="source-over";for(const p of fe){const y=(p.x-a+l+c)*g+E,d=p.diameter/2*g;t.strokeStyle="rgba(16, 185, 129, 0.9)",t.lineWidth=1.5/Q,t.beginPath(),p.y>I?t.arc(y,_+S*g,d,Math.PI,0,!1):t.arc(y,_,d,0,Math.PI,!1),t.stroke()}t.restore()}t.strokeStyle="#94a3b8",t.fillStyle="#94a3b8",t.lineWidth=1/Q,t.font=`${12/Q}px Arial`,t.textAlign="center",t.textBaseline="middle";const Y=15/Q,W=5/Q,F=_+S*g+Y;t.setLineDash([2/Q,2/Q]),t.beginPath(),t.moveTo(E,_+S*g),t.lineTo(E,F+Y/2),t.stroke(),t.beginPath(),t.moveTo(E+b*g,_+S*g),t.lineTo(E+b*g,F+Y/2),t.stroke(),t.setLineDash([]),t.beginPath(),t.moveTo(E,F),t.lineTo(E+b*g,F),t.stroke(),t.beginPath(),t.moveTo(E,F),t.lineTo(E+W,F-W/2),t.lineTo(E+W,F+W/2),t.closePath(),t.fill(),t.beginPath(),t.moveTo(E+b*g,F),t.lineTo(E+b*g-W,F-W/2),t.lineTo(E+b*g-W,F+W/2),t.closePath(),t.fill(),t.fillText(`${b.toFixed(1)}mm`,E+b*g/2,F+Y);const L=E+b*g+Y;t.setLineDash([2/Q,2/Q]),t.beginPath(),t.moveTo(E+b*g,_),t.lineTo(L+Y/2,_),t.stroke(),t.beginPath(),t.moveTo(E+b*g,_+S*g),t.lineTo(L+Y/2,_+S*g),t.stroke(),t.setLineDash([]),t.beginPath(),t.moveTo(L,_),t.lineTo(L,_+S*g),t.stroke(),t.beginPath(),t.moveTo(L,_),t.lineTo(L-W/2,_+W),t.lineTo(L+W/2,_+W),t.closePath(),t.fill(),t.beginPath(),t.moveTo(L,_+S*g),t.lineTo(L-W/2,_+S*g-W),t.lineTo(L+W/2,_+S*g-W),t.closePath(),t.fill(),t.save(),t.translate(L+Y,_+S*g/2),t.rotate(-Math.PI/2),t.fillText(`${S.toFixed(1)}mm`,0,0),t.restore(),t.restore()}function rt(n,o,e,t){const c=[],s=t/2,r=s+e,u=s+e;for(let m=u;m+s+e<=o;m+=t+e)for(let i=r;i+s+e<=n;i+=t+e)c.push([i,m]);return c}function it(n,o,e,t){const c=[],s=t/2;let r=s+e,u=0;for(;r+s+e<=o;){const m=u%2===0?0:(t+e)/2;let i=s+e+m;for(;i+s+e<=n;)c.push([i,r]),i+=t+e;r+=Math.sqrt(3)*(s+e/2),u++}return c}function lt(n,o,e,t){const c=[],s=t/2;let r=s+e,u=0;for(;r+s+e<=n;){const m=u%2===0?0:(t+e)/2;let i=s+e+m;for(;i+s+e<=o;)c.push([r,i]),i+=t+e;r+=Math.sqrt(3)*(s+e/2),u++}return c}function gt(n,o,e,t,c){return n==="grid"?rt(o,e,t,c):n==="honeycomb"?it(o,e,t,c):lt(o,e,t,c)}function yt(n,o,e,t,c){const s=`${n}_${o}_${e}_${t}_${c}`;if(ke.key===s&&ke.positions)return ke.positions;const r=gt(c,n,o,e,t);return ke.key=s,ke.positions=r,r}function bt(n,o){const e=Ie.instance;if(!e||n.length===0)return null;const{cellSize:t,spacing:c,height:s,terminalDiameter:r,terminalDepth:u,coverThickness:m,ledgeWidth:i,roundedCorners:f,bmsHoles:v,useTabs:l,useFullCircles:a}=o,h=t/2,x=Math.min(...n.map(Y=>Y[0]))-h-c,I=Math.min(...n.map(Y=>Y[1]))-h-c,b=Math.max(...n.map(Y=>Y[0]))+h+c,S=Math.max(...n.map(Y=>Y[1]))+h+c,V=(x+b)/2,H=(I+S)/2,K=n.map(([Y,W])=>[Y-V,W-H]),T=b-x,R=S-I;performance.now();const O=Y=>{performance.now()};let E=new e.BRepPrimAPI_MakeBox(T,R,s).Shape();const _=new e.gp_Trsf;if(_.SetTranslation(new e.gp_Vec(-T/2,-R/2,0)),E=new e.BRepBuilderAPI_Transform(E,_,!1).Shape(),f)try{const W=(L,p)=>{const y={};let d=0;const w=new e.TopExp_Explorer(L,e.TopAbs_EDGE);for(w.Init(L,e.TopAbs_EDGE);w.More();w.Next()){const k=e.TopoDS.prototype.Edge(w.Current()),q=k.HashCode(1e8);y.hasOwnProperty(q)||(y[q]=d,p(d++,k))}return y},F=[];if(W(E,(L,p)=>{try{const y=new e.Bnd_Box;e.BRepBndLib.prototype.Add(p,y,!1);const d=y.CornerMin(),w=y.CornerMax(),k=Math.abs(w.X()-d.X()),q=Math.abs(w.Y()-d.Y()),le=Math.abs(w.Z()-d.Z());k<1&&q<1&&le>s*.8&&F.push(L)}catch{}}),F.length>0){const L=new e.BRepFilletAPI_MakeFillet(E);let p=0;W(E,(y,d)=>{if(F.includes(y))try{L.Add(5,d),p++}catch(w){console.error(` Failed to add edge ${y}:`,w.message)}}),p>0&&(E=new e.TopoDS_Solid(L.Shape()),console.log(" Applied rounded corners"),O("Rounded corners"))}else console.log(" No vertical edges found to fillet")}catch(Y){console.error(" Fillet operation failed:",Y.message),console.log(" Continuing without rounded corners")}const fe=i>0||m>0;if(fe){const Y=m,W=s-m,F=Math.max(.1,h-i),L=K.map(([w,k])=>{const q=new e.gp_Ax2(new e.gp_Pnt(w,k,Y),e.gp.prototype.DZ());return new e.BRepPrimAPI_MakeCylinder(q,h,W).Shape()});let p=L[0];for(let w=1;w{const q=new e.gp_Ax2(new e.gp_Pnt(w,k,0),e.gp.prototype.DZ());return new e.BRepPrimAPI_MakeCylinder(q,F,s).Shape()});let d=y[0];for(let w=1;w{const p=new e.gp_Ax2(new e.gp_Pnt(F,L,0),e.gp.prototype.DZ());return new e.BRepPrimAPI_MakeCylinder(p,h,s).Shape()});let W=Y[0];for(let F=1;F{const ee=Math.round(U*1e3);L[ee]||(L[ee]=[]),L[ee].push([$,U])});const p=Object.keys(L).map($=>parseInt($)).sort(($,U)=>U-$),y=p[0],d=p[p.length-1];if(a){const $=L[y][0][1],U=L[d][0][1],ee=R/2,C=-R/2,B=(A,N,j,P)=>{const se=(j+P)/2,te=N0?-Math.PI/2:0,ie=te>0?0:Math.PI/2;for(let G=0;G<80;G++){const D=(Z+ie)/2,ce=j+h*Math.cos(D),oe=N+h*Math.sin(D),ne=se-ce,me=(oe-A)*te-ne*Math.sqrt(3);if(Math.abs(me)<1e-8)break;me<0?te>0?Z=D:ie=D:te>0?ie=D:Z=D}const X=(Z+ie)/2,z=N+h*Math.sin(X);return(A+2*z)/3};W=B(ee,$,L[y][0][0],L[y][1][0]),F=B(C,U,L[d][0][0],L[d][1][0])}const w=L[y].sort(($,U)=>$[0]-U[0]),k=L[d].sort(($,U)=>$[0]-U[0]),q=[];for(let $=0;${const j=new e.BRepPrimAPI_MakeBox($,U,s).Shape(),P=new e.gp_Trsf;P.SetTranslation(new e.gp_Vec(A-$/2,ee-U,0));const se=new e.BRepBuilderAPI_Transform(j,P,!1);B.push(se.Shape())}),le.forEach(([A])=>{const j=new e.BRepPrimAPI_MakeBox($,U,s).Shape(),P=new e.gp_Trsf;P.SetTranslation(new e.gp_Vec(A-$/2,C,0));const se=new e.BRepBuilderAPI_Transform(j,P,!1);B.push(se.Shape())}),B.length>0)if(B.length===1)E=new e.BRepAlgoAPI_Cut(E,B[0]).Shape();else{let A=B[0];for(let N=1;N{const ee=new e.gp_Ax2(new e.gp_Pnt($,U,0),e.gp.prototype.DZ()),C=new e.BRepPrimAPI_MakeCylinder(ee,Y/2,s).Shape();E=new e.BRepAlgoAPI_Cut(E,C).Shape()});else{const $=de.map(([ee,C])=>{const B=new e.gp_Ax2(new e.gp_Pnt(ee,C,0),e.gp.prototype.DZ());return new e.BRepPrimAPI_MakeCylinder(B,Y/2,s).Shape()});let U=$[0];for(let ee=1;ee<$.length;ee++)U=new e.BRepAlgoAPI_Fuse(U,$[ee]).Shape();E=new e.BRepAlgoAPI_Cut(E,U).Shape()}O()}}if(K.length<=10)K.forEach(([Y,W])=>{const F=new e.gp_Ax2(new e.gp_Pnt(Y,W,s-u),e.gp.prototype.DZ()),L=new e.BRepPrimAPI_MakeCylinder(F,r/2,u).Shape();E=new e.BRepAlgoAPI_Cut(E,L).Shape()});else{const Y=K.map(([p,y])=>{const d=new e.gp_Ax2(new e.gp_Pnt(p,y,s-u),e.gp.prototype.DZ());return new e.BRepPrimAPI_MakeCylinder(d,r/2,u).Shape()}),W=30,F=[];for(let p=0;pu*180/Math.PI;return["0","ARC","8",s,"10",n.toFixed(4),"20",o.toFixed(4),"30","0.0","40",e.toFixed(4),"50",r(t).toFixed(4),"51",r(c).toFixed(4)]}function Mt(n,o,e,t,c){return["0","LINE","8",c,"10",n.toFixed(4),"20",o.toFixed(4),"30","0.0","11",e.toFixed(4),"21",t.toFixed(4),"31","0.0"]}const Re=2*Math.PI,he=1e-5,Be=n=>{const o=n%Re;return o<0?o+Re:o},Et=(n,o)=>{const e=Math.abs(Be(n)-Be(o));return e>Math.PI?Re-e:e};function St(n,o,e,t){const c=o[0]-n[0],s=o[1]-n[1],r=n[0]-e[0],u=n[1]-e[1],m=c*c+s*s;if(m[(T[0]-s)*l+(T[1]-r)*a,-(T[0]-s)*a+(T[1]-r)*l],x=h(n),I=h(o);let b=0,S=1;const V=I[0]-x[0],H=I[1]-x[1],K=[[-V,x[0]-0],[V,v-x[0]],[-H,x[1]- -c],[H,c-x[1]]];for(const[T,R]of K)if(Math.abs(T)S+he)return[];O>b&&(b=O)}else{if(Os[0]-r[0]),e=[];for(const s of o)e.length&&s[0]<=e[e.length-1][1]+he?e[e.length-1][1]=Math.max(e[e.length-1][1],s[1]):e.push([s[0],s[1]]);const t=[];let c=0;for(const[s,r]of e)s>c+he&&t.push([c,Math.min(s,1)]),c=Math.max(c,r);return c<1-he&&t.push([c,1]),t}function Tt(n,o){for(const e of o)if(Et(n,e)(s.has(i)||s.set(i,{pos:f,dirs:[]}),s.get(i));for(const i of n.padIndices){const f=o[i];f&&u(`c${i}`,f)}n.edges.forEach((i,f)=>{const v=o[i.from],l=o[i.to];if(!v||!l)return;const a=[{key:`c${i.from}`,pos:v},...i.waypoints.map((h,x)=>({key:`w${f}_${x}`,pos:h})),{key:`c${i.to}`,pos:l}];for(let h=1;h({key:i,...f}));for(const i of m){const[f,v]=i.pos;if(i.dirs.length===0){c.push(...xt(f,v,e,t));continue}const l=[];for(const h of i.dirs)l.push(Be(h-Math.PI/2)),l.push(Be(h+Math.PI/2));l.sort((h,x)=>h-x);const a=[];for(const h of l)(a.length===0||Math.abs(h-a[a.length-1])>he)&&a.push(h);for(let h=0;hthis.listeners.delete(n)},subscribeMutations(n){return this.mutationListeners.add(n),()=>this.mutationListeners.delete(n)},_emitMutation(n){this.mutationListeners.forEach(o=>o(n))},_notify(){this.listeners.forEach(n=>n())},getSnapshot(){return{activeId:this.activeId,list:this.list.map(n=>({id:n.id,name:n.name,color:n.color,cellIndices:Array.isArray(n.cellIndices)?[...n.cellIndices]:[],thickness:n.thickness}))}},replaceFromSnapshot(n){const o=n&&Array.isArray(n.list)?n.list:[];this.list=o.map((t,c)=>({id:typeof t.id=="string"&&t.id?t.id:`bb-${c+1}`,name:typeof t.name=="string"&&t.name?t.name:`Busbar ${c+1}`,color:typeof t.color=="string"&&t.color?t.color:Ce[c%Ce.length],cellIndices:Array.isArray(t.cellIndices)?t.cellIndices.map(s=>Number(s)).filter(s=>Number.isInteger(s)&&s>=0):[],thickness:Number.isFinite(Number(t.thickness))&&Number(t.thickness)>0?Number(t.thickness):1})),typeof(n==null?void 0:n.activeId)=="string"&&this.list.some(t=>t.id===n.activeId)?this.activeId=n.activeId:this.activeId=this.list.length?this.list[0].id:null,Xe=this.list.reduce((t,c)=>{const s=parseInt(String(c.id).replace(/^bb-/,""),10);return Number.isFinite(s)?Math.max(t,s):t},0)+1,De=this.list.length,this._emitMutation("replaceFromSnapshot"),this._notify()},add(){const n={id:"bb-"+Xe++,name:`Busbar ${this.list.length+1}`,color:Ce[De%Ce.length],cellIndices:[],thickness:1};return De++,this.list.push(n),this.activeId=n.id,this._emitMutation("add"),this._notify(),n},remove(n){this.list=this.list.filter(o=>o.id!==n),this.activeId===n&&(this.activeId=this.list.length?this.list[0].id:null),this._emitMutation("remove"),this._notify()},rename(n,o){const e=this.list.find(t=>t.id===n);e&&(e.name=o,this._emitMutation("rename"),this._notify())},setColor(n,o){const e=this.list.find(t=>t.id===n);e&&(e.color=o,this._emitMutation("setColor"),this._notify())},setThickness(n,o){const e=this.list.find(t=>t.id===n);e&&(e.thickness=o,this._emitMutation("setThickness"),this._notify())},setActive(n){this.activeId=n,this._emitMutation("setActive"),this._notify()},getActive(){return this.list.find(n=>n.id===this.activeId)||null},toggleCell(n){const o=this.getActive();if(!o)return!1;const e=o.cellIndices.indexOf(n);return e>=0?o.cellIndices.splice(e,1):o.cellIndices.push(n),this._emitMutation("toggleCell"),this._notify(),!0},clearAll(){this.list.length!==0&&(this.list=[],this.activeId=null,De=0,Xe=1,this._emitMutation("clearAll"),this._notify())}};function Ct(n,o,e,t){const c=[],s=(2*e+t)*1.3;for(let i=0;ir.set(i,[]));for(const[i,f]of c)r.get(i).push(f),r.get(f).push(i);const u=new Set,m=[];for(const i of n){if(u.has(i))continue;const f=[],v=[i];for(;v.length;){const l=v.pop();if(!u.has(l)){u.add(l),f.push(l);for(const a of r.get(l))v.push(a)}}m.push(f)}for(;m.length>1;){let i=null,f=1/0,v=-1,l=-1;for(let a=0;a!u.has(a)),i=Math.max(c,.3),f=t,v=[];for(const[l,a]of r){const h=o[l],x=o[a];if(qe(h,x,f,m,s,i))v.push({from:l,to:a,waypoints:[]});else{const I=At(h,x,f,m,s,i);if(I)v.push({from:l,to:a,waypoints:[I]});else return{padIndices:n.slice(),edges:v,blocked:{from:l,to:a,reason:"no clear route between these cells"}}}}return{padIndices:n.slice(),edges:v,blocked:null}}function tt(n,o){const e=parseInt(n.slice(1,3),16),t=parseInt(n.slice(3,5),16),c=parseInt(n.slice(5,7),16);return`rgba(${e},${t},${c},${o})`}function dt(n,o,e,t,c,s,r){const u=document.getElementById("preview");if(!u)return;const m=M.viewTransform;if(!m||n.length===0)return;const i=u.getContext("2d"),f=t/2,v=I=>(I-m.minX+f+s)*m.scale+m.offsetX,l=I=>(I-m.minY+f+s)*m.scale+m.offsetY,a=c*m.scale;i.save(),i.translate(M.panX,M.panY),i.scale(M.zoom,M.zoom);const h=M.zoom,x=2*Math.PI;n.forEach((I,b)=>{const S=o[b];if(!S||I.cellIndices.length===0)return;const V=I.id===r,H=V?.45:.3,K=tt(I.color,H);i.fillStyle=K,i.beginPath();for(const T of I.cellIndices){if(!e[T])continue;const[R,O]=e[T],g=v(R),E=l(O);i.moveTo(g+a,E),i.arc(g,E,a,0,x)}i.fill(),i.strokeStyle=K,i.lineWidth=2*a,i.lineJoin="round",i.lineCap="round";for(const T of S.edges){const R=[e[T.from],...T.waypoints,e[T.to]];for(let O=1;O=2){i.beginPath(),i.moveTo(v(R[0][0]),l(R[0][1]));for(let O=1;O"']/g,o=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[o])}function je(n={}){const o=document.getElementById("busbarList");if(o){if(o.innerHTML="",J.list.length===0){const e=document.createElement("div");e.className="busbar-empty",e.textContent='No busbars. Click "Add Busbar" then click cells in the preview.',o.appendChild(e);return}J.list.forEach(e=>{const t=document.createElement("div");t.className="busbar-row"+(e.id===J.activeId?" active":""),t.dataset.id=e.id,t.innerHTML=`
${e.cellIndices.length} cell${e.cellIndices.length===1?"":"s"}
${n[e.id]?`
⚠ ${nt(n[e.id])}
`:""} `,t.addEventListener("click",c=>{c.target.closest("input")||c.target.closest("button")||J.setActive(e.id)}),t.querySelector(".busbar-name").addEventListener("change",c=>{J.rename(e.id,c.target.value)}),t.querySelector(".busbar-thickness").addEventListener("change",c=>{const s=parseFloat(c.target.value);s>0&&J.setThickness(e.id,s)}),t.querySelector(".busbar-del").addEventListener("click",c=>{c.stopPropagation(),J.remove(e.id)}),o.appendChild(t)})}}function Lt(){const n=document.getElementById("addBusbarBtn");n&&n.addEventListener("click",()=>J.add())}let Le=[],Oe=null;function Fe(){if(!Oe)return;const{positions:n,cellSize:o,padRadius:e,spacing:t}=Oe;dt(J.list,Le,n,o,e,t,J.activeId)}function we(n=!1){n&&(M.zoom=1,M.panX=0,M.panY=0);const o=document.getElementById("previewStats"),e=(t,c)=>{o.textContent=t,o.style.color=c};try{const t=parseFloat(document.getElementById("xDim").value),c=parseFloat(document.getElementById("yDim").value),s=parseFloat(document.getElementById("spacing").value),r=parseFloat(document.getElementById("cellSize").value),u=document.getElementById("layoutType").value,m=parseFloat(document.getElementById("ledgeWidth").value)||0,i=parseFloat(document.getElementById("bmsHoleDiameter").value)||4,f=parseFloat(document.getElementById("coverThickness").value);if(!t||!c||!s||!r){e("Configure settings to see preview","#94a3b8");return}if(m>0&&m>=r){e(`Ledge width (${m}mm) must be less than cell diameter (${r}mm)!`,"#ef4444"),ve();return}const v=r+s*2;if(tt||r>c){e(`Cell diameter (${r}mm) larger than pack dimensions!`,"#ef4444"),ve();return}if(s<0){e("Cell spacing cannot be negative!","#ef4444"),ve();return}const l=yt(t,c,s,r,u);if(!l||l.length===0){e("No cells fit! Increase pack size or decrease cell size/spacing","#ef4444"),ve();return}if(document.getElementById("bmsHolesType").value!=="off"){if(i>r){e(`BMS hole (${i}mm) larger than cell (${r}mm)! Reduce hole size.`,"#ef4444"),ve();return}const g=r/2,E=i/2,_=g,Q=Math.min(...l.map(k=>k[1])),Y=Math.max(...l.map(k=>k[1]))+_+s,W=Q-_-s,F={};for(const[k,q]of l){const le=Math.round(q*1e3);F[le]||(F[le]=[]),F[le].push([k,q])}const L=Object.keys(F).map(Number).sort((k,q)=>k-q),p=L[L.length-1],y=L[0];F[p].sort((k,q)=>k[0]-q[0]),F[y].sort((k,q)=>k[0]-q[0]);const d=Y,w=W;for(let k=0;kr/2&&e(`Cover thickness (${f}mm) very large for cell size (${r}mm)`,"#f59e0b"),s<.5&&s>0&&e("Spacing < 0.5mm may be difficult to 3D print","#f59e0b"),l.length<2?e(`Only ${l.length} cell fits. Increase pack size for practical holder.`,"#f59e0b"):o.style.color="#10b981",Te(l,r);const x=r/2,I=Math.max(x-m,1),b=4;Le=J.list.map(g=>at(g.cellIndices,l,x,I,s,b)),Oe={positions:l,cellSize:r,padRadius:I,spacing:s},dt(J.list,Le,l,r,I,s,J.activeId);const S={};J.list.forEach((g,E)=>{const _=Le[E];_&&_.blocked&&(S[g.id]=_.blocked.reason)}),je(S);const V=Math.min(...l.map(g=>g[0])),H=Math.min(...l.map(g=>g[1])),K=Math.max(...l.map(g=>g[0])),T=Math.max(...l.map(g=>g[1])),R=K-V+r+s*2,O=T-H+r+s*2;l.length>=2&&(o.textContent=`${l.length} cells • ${R.toFixed(0)}×${O.toFixed(0)} mm`)}catch(t){console.error("Preview error:",t),e("Error: "+t.message,"#ef4444")}}async function Ft(){var o;const n=document.getElementById("layoutType").value;if(!(!Ie.initialized&&(ae("3D engine not ready. Please wait...","error"),await ct(),!Ie.initialized))){be(!0,"Generating 3D Model","Please be patient..."),await new Promise(e=>setTimeout(e,50));try{const e=parseFloat(document.getElementById("xDim").value),t=parseFloat(document.getElementById("yDim").value),c=parseFloat(document.getElementById("spacing").value),s=parseFloat(document.getElementById("cellSize").value),r=parseFloat(document.getElementById("ledgeWidth").value)||0,u=parseFloat(document.getElementById("bmsHoleDiameter").value)||4,m=parseFloat(document.getElementById("coverThickness").value),i=s/2,f=u/2;if(r>0&&r>=s){ae(`Ledge width (${r}mm) must be less than cell diameter (${s}mm)!`,"error"),be(!1);return}const v=s+c*2;if(ee||s>t){ae("Cell diameter is larger than pack dimensions!","error"),be(!1);return}if(c<0){ae("Cell spacing cannot be negative!","error"),be(!1);return}const l=parseFloat(document.getElementById("height").value),a=8,h=1,x=document.getElementById("roundedCorners").checked,I=document.getElementById("bmsHolesType").value,b=I!=="off",S=I==="tabs",V=I==="fullcircles",H=!1,K=!1;let T,R;switch(n){case"grid":T=rt(e,t,c,s),R="Grid Layout";break;case"honeycomb":T=it(e,t,c,s),R="Honeycomb Layout";break;case"vertical":T=lt(e,t,c,s),R="Vertical Honeycomb";break;default:ae("Invalid layout type","error");return}if(b&&V){const C=(X,z,G,D)=>{const ce=(G+D)/2,oe=z0?-Math.PI/2:0,re=oe>0?0:Math.PI/2;for(let Ee=0;Ee<80;Ee++){const Me=(ne+re)/2,Pe=ce-(G+i*Math.cos(Me)),Ve=(z+i*Math.sin(Me)-X)*oe-Pe*Math.sqrt(3);if(Math.abs(Ve)<1e-8)break;Ve<0?oe>0?ne=Me:re=Me:oe>0?re=Me:ne=Me}const me=(ne+re)/2,ue=z+i*Math.sin(me);return(X+2*ue)/3},B=Math.min(...T.map(X=>X[1])),A=Math.max(...T.map(X=>X[1])),N=B-i-c,j=A+i+c,P={};for(const[X,z]of T){const G=Math.round(z*1e3);P[G]||(P[G]=[]),P[G].push([X,z])}const se=Object.keys(P).map(Number).sort((X,z)=>X-z),te=se[0],Z=se[se.length-1];P[te].sort((X,z)=>X[0]-z[0]),P[Z].sort((X,z)=>X[0]-z[0]);const ie=[];for(let X=0;XD[1])),B=Math.max(...T.map(D=>D[1])),A=s/2,N=C-A-c,j=B+A+c,P={};for(const[D,ce]of T){const oe=Math.round(ce*1e3);P[oe]||(P[oe]=[]),P[oe].push([D,ce])}const se=Object.keys(P).map(Number).sort((D,ce)=>D-ce),te=se[se.length-1],Z=se[0];P[te].sort((D,ce)=>D[0]-ce[0]),P[Z].sort((D,ce)=>D[0]-ce[0]);const ie=P[te][0][1],X=P[Z][0][1];let z,G;K||(z=j,G=N);for(let D=0;Dat(C.cellIndices,T,i,Q,c,fe));for(let C=0;CC[0]))+Math.max(...T.map(C=>C[0])))/2,F=(Math.min(...T.map(C=>C[1]))+Math.max(...T.map(C=>C[1])))/2,L=T.map(([C,B])=>[C-W,B-F]),p=C=>(C||"").replace(/[^A-Za-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"busbar",y=C=>{const B=C.cellIndices;if(B.length===0)return null;if(B.length===1)return`single|${C.thickness.toFixed(2)}`;const A=B.map(j=>L[j]).filter(Boolean),N=[];for(let j=0;jj-P),`${A.length}|${C.thickness.toFixed(2)}|${N.map(j=>j.toFixed(3)).join(",")}`},d=((o=document.getElementById("busbarFormat"))==null?void 0:o.value)||"step",w=[],k=new Map;for(let C=0;Cnew Promise(B=>setTimeout(B,C));Qe(_,`cellholder_${n}.step`);for(let C=0;CC.cellIndices.length>0).length-w.length,$=w.length>0?`. ${w.length} unique ${d.toUpperCase()} busbar file${w.length===1?"":"s"}${de>0?` (${de} mirrored duplicate${de===1?"":"s"} skipped)`:""}`:"",U=S?"edge tabs":K?"circle offset":"semicircle offset",ee=H&&!S?" with filleted holes":"";ae(`${R} generated. ${T.length} cells (${U}${ee})${$}.`,"success")}catch(e){console.error("Generation error:",e),ae("Error: "+e.message,"error")}finally{be(!1)}}}const ut=1,Ue="#config=",Rt=new Set(["grid","honeycomb","vertical"]),Yt=new Set(["off","halfcircles","fullcircles","tabs"]),$t=new Set(["sp","mm"]),Xt=new Set(["step","dxf"]);function Nt(n){const o=new TextEncoder().encode(n);let e="";for(const t of o)e+=String.fromCharCode(t);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function Ht(n){const o=n.replace(/-/g,"+").replace(/_/g,"/"),e="=".repeat((4-o.length%4)%4),t=atob(o+e),c=new Uint8Array(t.length);for(let s=0;s{const m=Number(u);if(!Number.isInteger(m)||m<0)throw new Error(`Invalid busbar cell index at index ${o}`);return m});return{id:e,name:t,color:c,thickness:s,cellIndices:r}}function Ze(n){if(!n||typeof n!="object")throw new Error("Missing config object");const o=Number(n.v);if(!Number.isInteger(o))throw new Error("Missing schema version");if(o!==ut)throw new Error("Unsupported schema version");const e=n.pack,t=n.cell,c=n.bms,s=n.busbars;if(!e||!t||!c||!s)throw new Error("Missing required sections");const r=xe(e.mode,"pack.mode");if(!$t.has(r))throw new Error("Invalid pack mode");const u=xe(t.layoutType,"cell.layoutType");if(!Rt.has(u))throw new Error("Invalid layout type");const m=xe(c.type,"bms.type");if(!Yt.has(m))throw new Error("Invalid BMS type");const i=xe(s.format,"busbars.format");if(!Xt.has(i))throw new Error("Invalid busbar format");const f=Array.isArray(s.list)?s.list.map((l,a)=>zt(l,a)):(()=>{throw new Error("Invalid busbar list")})(),v=s.activeId==null?null:xe(s.activeId,"busbars.activeId");if(v!==null&&!f.some(l=>l.id===v))throw new Error("Active busbar id not found in list");return{v:o,pack:{mode:r,series:ge(Number(e.series),"pack.series"),parallel:ge(Number(e.parallel),"pack.parallel"),xDim:ge(Number(e.xDim),"pack.xDim"),yDim:ge(Number(e.yDim),"pack.yDim")},cell:{cellSize:ge(Number(t.cellSize),"cell.cellSize"),layoutType:u,spacing:ge(Number(t.spacing),"cell.spacing"),height:ge(Number(t.height),"cell.height"),coverThickness:ge(Number(t.coverThickness),"cell.coverThickness"),ledgeWidth:ge(Number(t.ledgeWidth),"cell.ledgeWidth"),roundedCorners:Wt(t.roundedCorners,"cell.roundedCorners")},bms:{type:m,holeDiameter:ge(Number(c.holeDiameter),"bms.holeDiameter"),tabWidth:ge(Number(c.tabWidth),"bms.tabWidth"),tabDepth:ge(Number(c.tabDepth),"bms.tabDepth")},busbars:{format:i,activeId:v,list:f}}}function ye(n,o=0){const e=document.getElementById(n);if(!e)return o;const t=Number(e.value);return Number.isFinite(t)?t:o}function Ne(n,o=""){const e=document.getElementById(n);return e&&typeof e.value=="string"?e.value:o}function qt(n,o=!1){const e=document.getElementById(n);return e?!!e.checked:o}async function ht(n){if(!(crypto!=null&&crypto.subtle))throw new Error("Web Crypto API is unavailable");const o=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(n)),e=new Uint8Array(o);return Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function Ot(n,o){const e=typeof n=="function"?n():"sp";return Ze({v:ut,pack:{mode:e,series:ye("series",1),parallel:ye("parallel",1),xDim:ye("xDim",150),yDim:ye("yDim",100)},cell:{cellSize:ye("cellSize",21.35),layoutType:Ne("layoutType","honeycomb"),spacing:ye("spacing",.6),height:ye("height",10),coverThickness:ye("coverThickness",.4),ledgeWidth:ye("ledgeWidth",2.75),roundedCorners:qt("roundedCorners",!0)},bms:{type:Ne("bmsHolesType","fullcircles"),holeDiameter:ye("bmsHoleDiameter",4),tabWidth:ye("tabWidth",4),tabDepth:ye("tabDepth",1)},busbars:{format:Ne("busbarFormat","step"),activeId:(o==null?void 0:o.activeId)??null,list:Array.isArray(o==null?void 0:o.list)?o.list:[]}})}async function Ut(n){const o=Ze(n),e=JSON.stringify(o),t=Nt(e),c=(await ht(e)).slice(0,16);return`${Ue}${t}_${c}`}async function Kt(n){if(!n||!n.startsWith(Ue))return{ok:!1,reason:"missing"};const o=n.slice(Ue.length),e=o.lastIndexOf("_");if(e<=0||e===o.length-1)return{ok:!1,reason:"format"};const t=o.slice(0,e),c=o.slice(e+1);if(!/^[0-9a-f]{16}$/i.test(c))return{ok:!1,reason:"checksum-format"};try{const s=Ht(t),r=(await ht(s)).slice(0,16);if(c.toLowerCase()!==r.toLowerCase())return{ok:!1,reason:"checksum-mismatch"};const u=JSON.parse(s);return{ok:!0,config:Ze(u)}}catch(s){return{ok:!1,reason:s instanceof Error?s.message:"decode-failed"}}}const Ae=4,jt=250;let Ke=null,_e=null,Ye=!1;function Zt(){const n=document.getElementById("preview");if(!n)return;const o=window.devicePixelRatio||1,e=n.getBoundingClientRect();n.width=e.width*o,n.height=e.height*o,n.getContext("2d").scale(o,o),n.style.width=e.width+"px",n.style.height=e.height+"px"}function $e(){const n=document.querySelector("[data-pack-mode]");return n&&n.dataset.mode||"sp"}function Gt(n){var s;const o=document.getElementById(n);if(!o)return;const e=o.closest(".custom-select");if(!e)return;const t=e.querySelector(".select-selected"),c=e.querySelectorAll(".select-items div");t&&(t.textContent=((s=o.options[o.selectedIndex])==null?void 0:s.text)||""),c.forEach(r=>{r.classList.toggle("same-as-selected",r.dataset.value===o.value)})}function pe(n,o){const e=document.getElementById(n);e&&(e.value=String(o))}function Vt(n,o){const e=document.getElementById(n);e&&(e.checked=!!o)}function He(n,o){const e=document.getElementById(n);e&&(e.value=String(o),Gt(n))}function mt(n,o={}){const{clearBusbars:e=!0,refresh:t=!0}=o;if(!Ke)return;const c=n==="mm"?"mm":"sp",{toggle:s,buttons:r,indicator:u,spFields:m,mmFields:i}=Ke;s.dataset.mode=c,r.forEach(f=>{const v=f.dataset.mode===c;f.classList.toggle("active",v),v&&u&&(u.style.left=f.offsetLeft+"px",u.style.width=f.offsetWidth+"px")}),m&&(m.hidden=c!=="sp"),i&&(i.hidden=c!=="mm"),t&&(Se(),we(!0)),e&&J.clearAll()}async function Ge(){if(!Ye)try{const n=Ot(()=>$e(),J.getSnapshot()),o=await Ut(n);window.location.hash!==o&&window.history.replaceState(null,"",o)}catch(n){console.error("Failed to sync URL hash:",n)}}function We(){Ye||(_e&&clearTimeout(_e),_e=setTimeout(()=>{_e=null,Ge()},jt))}function Jt(n){Ye=!0;try{pe("series",n.pack.series),pe("parallel",n.pack.parallel),pe("xDim",n.pack.xDim),pe("yDim",n.pack.yDim),pe("cellSize",n.cell.cellSize),He("layoutType",n.cell.layoutType),pe("spacing",n.cell.spacing),pe("height",n.cell.height),pe("coverThickness",n.cell.coverThickness),pe("ledgeWidth",n.cell.ledgeWidth),Vt("roundedCorners",n.cell.roundedCorners),He("bmsHolesType",n.bms.type),pe("bmsHoleDiameter",n.bms.holeDiameter),pe("tabWidth",n.bms.tabWidth),pe("tabDepth",n.bms.tabDepth),He("busbarFormat",n.busbars.format),mt(n.pack.mode,{clearBusbars:!1,refresh:!1}),ze(),Se(),n.pack.mode==="mm"&&(pe("xDim",n.pack.xDim),pe("yDim",n.pack.yDim)),J.replaceFromSnapshot({activeId:n.busbars.activeId,list:n.busbars.list}),je()}finally{Ye=!1}}async function Qt(){if(!window.location.hash||!window.location.hash.startsWith("#config="))return!1;const n=await Kt(window.location.hash);return n.ok?(Jt(n.config),!0):(ae("Shared URL is invalid or corrupted. Loaded default configuration.","error"),!1)}function en(){const n=document.getElementById("copyShareUrlBtn");n&&n.addEventListener("click",async()=>{var o;try{await Ge();const e=`${window.location.origin}${window.location.pathname}${window.location.hash}`;if(!((o=navigator.clipboard)!=null&&o.writeText))throw new Error("Clipboard API unavailable");await navigator.clipboard.writeText(e),ae("Share URL copied to clipboard.","success")}catch(e){console.error("Failed to copy share URL:",e),ae("Unable to copy URL automatically. Copy it from the address bar.","error")}})}function tn(){["series","parallel","xDim","yDim","height","cellSize","layoutType","spacing","coverThickness","ledgeWidth","roundedCorners","bmsHolesType","bmsHoleDiameter","tabWidth","tabDepth","busbarFormat"].forEach(o=>{const e=document.getElementById(o);e&&(e.addEventListener("input",We),e.addEventListener("change",We))}),J.subscribeMutations(We)}function Se(){const n=$e(),o=document.getElementById("xDim"),e=document.getElementById("yDim"),t=document.getElementById("packSummary");if(n==="mm"){const b=parseFloat(o.value)||0,S=parseFloat(e.value)||0;t&&(t.innerHTML=`${b.toFixed(0)} × ${S.toFixed(0)} mm footprint. Cells fit automatically.`);return}const c=Math.max(1,Math.round(parseFloat(document.getElementById("series").value)||1)),s=Math.max(1,Math.round(parseFloat(document.getElementById("parallel").value)||1)),r=parseFloat(document.getElementById("cellSize").value)||21.35,u=parseFloat(document.getElementById("spacing").value)||.6,m=document.getElementById("layoutType").value,i=r+u,f=Math.sqrt(3)/2*i,v=.02,l=b=>r+2*u+(b-1)*i+v,a=b=>r+2*u+(b-1)*f+v,h=b=>r+2*u+(b-1)*i+i/2+v;let x,I;if(m==="vertical"?(x=a(c),I=h(s)):m==="honeycomb"?(x=h(c),I=a(s)):(x=l(c),I=l(s)),o.value=x.toFixed(2),e.value=I.toFixed(2),t){const b=c*s;t.innerHTML=`${c}S ${s}P. ${b} cells. Footprint about ${x.toFixed(0)} × ${I.toFixed(0)} mm.`}}function nn(){["series","parallel"].forEach(s=>{const r=document.getElementById(s);r&&(r.addEventListener("input",()=>{Se(),we(!0)}),r.addEventListener("change",()=>J.clearAll()))}),["xDim","yDim"].forEach(s=>{const r=document.getElementById(s);r&&(r.addEventListener("input",()=>{$e()==="mm"&&(Se(),we(!0))}),r.addEventListener("change",()=>{$e()==="mm"&&J.clearAll()}))}),["spacing","cellSize","layoutType"].forEach(s=>{const r=document.getElementById(s);r&&r.addEventListener("change",()=>J.clearAll())}),["spacing","cellSize","layoutType","height","coverThickness"].forEach(s=>{const r=document.getElementById(s);if(!r)return;const u=()=>{Se(),we(!0)};r.addEventListener("input",u),r.addEventListener("change",u)}),["bmsHolesType","roundedCorners","bmsHoleDiameter","ledgeWidth","tabWidth","tabDepth"].forEach(s=>{const r=document.getElementById(s);r&&(r.addEventListener("input",()=>we(!1)),r.addEventListener("change",()=>we(!1)))})}function on(){const n=document.querySelector("[data-pack-mode]");if(!n)return;const o=Array.from(n.querySelectorAll(".seg")),e=n.querySelector(".seg-indicator"),t=document.querySelector(".pack-sp-fields"),c=document.querySelector(".pack-mm-fields"),s=r=>{!e||!r||(e.style.left=r.offsetLeft+"px",e.style.width=r.offsetWidth+"px")};Ke={toggle:n,buttons:o,indicator:e,spFields:t,mmFields:c},o.forEach(r=>r.addEventListener("click",()=>mt(r.dataset.mode))),requestAnimationFrame(()=>{const r=o.find(u=>u.classList.contains("active"))||o[0];r&&s(r)})}function sn(){M.currentPositions.length>0&&(Te(M.currentPositions,M.currentCellSize),Fe())}function cn(n,o){const e=M.viewTransform;if(!e)return null;const t=(n-M.panX)/M.zoom,c=(o-M.panY)/M.zoom,s=(t-e.offsetX)/e.scale+e.minX-e.r-e.spacing,r=(c-e.offsetY)/e.scale+e.minY-e.r-e.spacing;return[s,r]}function ot(n,o){if(!J.getActive())return;const t=cn(n,o);if(!t)return;const c=M.currentCellSize/2;let s=-1,r=c;M.currentPositions.forEach(([u,m],i)=>{const f=Math.hypot(t[0]-u,t[1]-m);f=0&&J.toggleCell(s)}function rn(){const n=document.getElementById("preview");if(!n)return;n.addEventListener("wheel",a=>{a.preventDefault();const h=.1,x=a.deltaY>0?-h:h,I=Math.max(.2,Math.min(5,M.zoom+x)),b=n.getBoundingClientRect(),S=a.clientX-b.left,V=a.clientY-b.top,H=I/M.zoom;M.panX=S-(S-M.panX)*H,M.panY=V-(V-M.panY)*H,M.zoom=I,sn()}),n.addEventListener("mousedown",a=>{M.isDragging=!0,M.dragStartX=a.clientX,M.dragStartY=a.clientY,M.dragMoved=!1,M.lastMouseX=a.clientX,M.lastMouseY=a.clientY,n.style.cursor="grabbing"}),n.addEventListener("mousemove",a=>{if(!M.isDragging)return;const h=a.clientX-M.dragStartX,x=a.clientY-M.dragStartY;(Math.abs(h)>Ae||Math.abs(x)>Ae)&&(M.dragMoved=!0);const I=a.clientX-M.lastMouseX,b=a.clientY-M.lastMouseY;M.panX+=I,M.panY+=b,M.lastMouseX=a.clientX,M.lastMouseY=a.clientY,M.currentPositions.length>0&&requestAnimationFrame(()=>{Te(M.currentPositions,M.currentCellSize),Fe()})}),n.addEventListener("mouseup",a=>{if(M.isDragging&&!M.dragMoved){const h=n.getBoundingClientRect();ot(a.clientX-h.left,a.clientY-h.top)}M.isDragging=!1,M.dragMoved=!1,n.style.cursor="grab"}),n.addEventListener("mouseleave",()=>{M.isDragging=!1,M.dragMoved=!1,n.style.cursor="grab"});let o=0,e=1,t=0,c=0,s=0,r=0,u=0,m=0,i=0,f=0,v=!1,l=!1;n.addEventListener("touchstart",a=>{if(a.preventDefault(),a.touches.length===1)l=!0,u=a.touches[0].clientX,m=a.touches[0].clientY,i=u,f=m,v=!1;else if(a.touches.length===2){l=!1;const h=a.touches[0],x=a.touches[1];o=Math.hypot(x.clientX-h.clientX,x.clientY-h.clientY),e=M.zoom,t=M.panX,c=M.panY;const I=n.getBoundingClientRect();s=(h.clientX+x.clientX)/2-I.left,r=(h.clientY+x.clientY)/2-I.top}}),n.addEventListener("touchmove",a=>{if(a.preventDefault(),a.touches.length===1&&l){const h=a.touches[0],x=h.clientX-i,I=h.clientY-f;(Math.abs(x)>Ae||Math.abs(I)>Ae)&&(v=!0),M.panX+=h.clientX-u,M.panY+=h.clientY-m,u=h.clientX,m=h.clientY,M.currentPositions.length>0&&requestAnimationFrame(()=>{Te(M.currentPositions,M.currentCellSize),Fe()})}else if(a.touches.length===2){const h=a.touches[0],x=a.touches[1],b=Math.hypot(x.clientX-h.clientX,x.clientY-h.clientY)/o,S=Math.max(.2,Math.min(5,e*b)),V=S/e;M.panX=s-(s-t)*V,M.panY=r-(r-c)*V,M.zoom=S,M.currentPositions.length>0&&requestAnimationFrame(()=>{Te(M.currentPositions,M.currentCellSize),Fe()})}}),n.addEventListener("touchend",a=>{if(a.preventDefault(),a.changedTouches.length>0&&l&&!v){const h=a.changedTouches[0],x=n.getBoundingClientRect();ot(h.clientX-x.left,h.clientY-x.top)}a.touches.length===0&&(l=!1,v=!1),a.touches.length<2&&(o=0)}),n.addEventListener("touchcancel",()=>{l=!1,v=!1,o=0}),n.style.cursor="grab"}function ln(){const n=document.querySelector("[data-tabs]");if(!n)return;const o=Array.from(n.querySelectorAll(".tab")),e=n.querySelector(".tab-indicator"),t=Array.from(document.querySelectorAll(".tab-panel")),c=r=>{!e||!r||(e.style.left=r.offsetLeft+"px",e.style.width=r.offsetWidth+"px")},s=r=>{for(const u of o){const m=u.dataset.panel===r;u.classList.toggle("active",m),u.setAttribute("aria-selected",m?"true":"false"),m&&c(u)}for(const u of t)u.classList.toggle("active",u.dataset.panel===r)};for(const r of o)r.addEventListener("click",()=>s(r.dataset.panel));requestAnimationFrame(()=>{const r=o.find(u=>u.classList.contains("active"))||o[0];r&&c(r)}),window.addEventListener("resize",()=>{const r=o.find(u=>u.classList.contains("active"));r&&c(r)})}async function st(){Zt(),ft(),ln(),on();const n=document.getElementById("bmsHolesType");n&&(n.addEventListener("change",ze),ze());const o=document.getElementById("generateBtn");o&&o.addEventListener("click",Ft),Lt(),je(),J.subscribe(()=>we(!1)),nn(),rn(),en(),tn(),await Qt()||Se(),await ct(),setTimeout(()=>{we(!0),Ge()},100)}document.readyState==="loading"?window.addEventListener("DOMContentLoaded",st):st();