Files
battery-builder/dist/assets/index-jBPW89B_.js

17 lines
54 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function(){const 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=te<se?-1:1;let G=-Math.PI/2*z,D=0;z<0&&(G=0,D=Math.PI/2);for(let ne=0;ne<80;ne++){const re=(G+D)/2,me=Z+l*Math.cos(re),ue=te+l*Math.sin(re),Ee=X-me,Pe=(ue-se)*z-Ee*Math.sqrt(3);if(Math.abs(Pe)<1e-8)break;Pe<0?z>0?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;B<d[ee].length-1;B++){const A=(d[ee][B][0]+d[ee][B+1][0])/2,N=d[ee][B][1],j=d[ee][B][0],P=d[ee][B+1][0],se=p,te=$,Z=N<se?-1:1;let ie=Z>0?-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;B<d[C].length-1;B++){const A=(d[C][B][0]+d[C][B+1][0])/2,N=d[C][B][1],j=d[C][B][0],P=d[C][B+1][0],se=y,te=U,Z=N<se?-1:1;let ie=Z>0?-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(U<d+l*g){p=`BMS hole too large, overlaps cell! Max diameter: ${((U/g-l)*2).toFixed(1)}mm`;break}}if(p)break}if(p){t.restore(),M.currentPositions=[],t.clearRect(0,0,e.width,e.height),t.fillStyle="#1e293b",t.fillRect(0,0,e.width,e.height),ae(p,"error");return}for(const y of fe){const d=(y.x-a+l+c)*g+E,w=(y.y-h+l+c)*g+_,k=y.diameter/2*g;t.save(),t.globalCompositeOperation="destination-out",t.fillStyle="black",t.beginPath(),t.arc(d,w,k,0,Math.PI*2),t.fill(),t.globalCompositeOperation="source-over",t.restore(),t.strokeStyle="rgba(16, 185, 129, 0.9)",t.lineWidth=1.5/Q,t.beginPath(),t.arc(d,w,k,0,Math.PI*2),t.stroke()}}else{t.save(),t.globalCompositeOperation="destination-out";for(const p of fe){const y=(p.x-a+l+c)*g+E,d=p.diameter/2*g;if(t.fillStyle="black",t.beginPath(),p.y>I){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<L.length;w++)p=new e.BRepAlgoAPI_Fuse(p,L[w]).Shape();E=new e.BRepAlgoAPI_Cut(E,p).Shape();const y=K.map(([w,k])=>{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<y.length;w++)d=new e.BRepAlgoAPI_Fuse(d,y[w]).Shape();E=new e.BRepAlgoAPI_Cut(E,d).Shape()}else{const Y=K.map(([F,L])=>{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<Y.length;F++)W=new e.BRepAlgoAPI_Fuse(W,Y[F]).Shape();E=new e.BRepAlgoAPI_Cut(E,W).Shape()}if(console.log(" Cell holes cut"+(fe?" (with integrated ledge)":"")),O(),v){const Y=o.bmsHoleDiameter||4;let W,F;a?(W=null,F=null):(W=R/2,F=-R/2);const L={};K.forEach(([$,U])=>{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=N<A?-1:1;let Z=te>0?-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;$<w.length-1;$++){const U=(w[$][0]+w[$+1][0])/2;q.push([U,W])}const le=[];for(let $=0;$<k.length-1;$++){const U=(k[$][0]+k[$+1][0])/2;le.push([U,F])}const de=[...q,...le];if(l){const $=o.tabWidth||Y,U=o.tabDepth||1,ee=R/2,C=-R/2,B=[];if(q.forEach(([A])=>{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<B.length;N++)A=new e.BRepAlgoAPI_Fuse(A,B[N]).Shape();E=new e.BRepAlgoAPI_Cut(E,A).Shape()}O()}else{if(de.length<=10)de.forEach(([$,U])=>{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;p<Y.length;p+=W){const y=Math.min(p+W,Y.length);let d=Y[p];for(let w=p+1;w<y;w++)d=new e.BRepAlgoAPI_Fuse(d,Y[w]).Shape();F.push(d)}let L=F[0];for(let p=1;p<F.length;p++)L=new e.BRepAlgoAPI_Fuse(L,F[p]).Shape();E=new e.BRepAlgoAPI_Cut(E,L).Shape()}return console.log(" Terminal recesses cut"),O(),fe&&console.log(" Ledge integrated into cell holes"),O(),O(),E}function Qe(n,o){const e=Ie.instance;if(!(!e||!n))try{const t=new e.STEPControl_Writer;t.Transfer(n,0),t.Write(o);const c=e.FS.readFile(o),s=new Blob([c],{type:"application/step"}),r=URL.createObjectURL(s),u=document.createElement("a");u.href=r,u.download=o,document.body.appendChild(u),u.click(),document.body.removeChild(u),URL.revokeObjectURL(r),e.FS.unlink(o),ae(`Downloaded ${o} successfully!`,"success")}catch(t){console.error("STEP export error:",t),ae("Error exporting STEP file: "+t.message,"error")}}function vt(){return["0","SECTION","2","HEADER","9","$ACADVER","1","AC1009","9","$INSUNITS","70","4","0","ENDSEC"]}function wt(){return["0","SECTION","2","TABLES","0","TABLE","2","LAYER","70","1","0","LAYER","2","busbar","70","0","62","7","6","CONTINUOUS","0","ENDTAB","0","ENDSEC"]}function xt(n,o,e,t){return["0","CIRCLE","8",t,"10",n.toFixed(4),"20",o.toFixed(4),"30","0.0","40",e.toFixed(4)]}function It(n,o,e,t,c,s){const r=u=>u*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<he)return[];const i=2*(r*c+u*s),f=r*r+u*u-t*t,v=i*i-4*m*f;if(v<=0)return[];const l=Math.sqrt(v),a=(-i-l)/(2*m),h=(-i+l)/(2*m),x=Math.max(0,a),I=Math.min(1,h);return I-x<he?[]:[[x,I]]}function et(n,o,e,t,c){const s=e[0],r=e[1],u=t[0],m=t[1],i=u-s,f=m-r,v=Math.hypot(i,f);if(v<he)return[];const l=i/v,a=f/v,h=T=>[(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)<he){if(R<-he)return[]}else{const O=R/T;if(T<0){if(O>S+he)return[];O>b&&(b=O)}else{if(O<b-he)return[];O<S&&(S=O)}}return S-b<he?[]:[[b,S]]}function kt(n){const o=n.slice().sort((s,r)=>s[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)<Math.PI/2-he)return!0;return!1}function Bt(n,o,e){const t="busbar",c=[...vt(),...wt(),"0","SECTION","2","ENTITIES"],s=new Map,r=[],u=(i,f)=>(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<a.length-1;h++)u(a[h].key,a[h].pos);for(let h=0;h<a.length-1;h++){const x=a[h],I=a[h+1],b=I.pos[0]-x.pos[0],S=I.pos[1]-x.pos[1];if(Math.hypot(b,S)<he)continue;const H=Math.atan2(S,b);u(x.key,x.pos).dirs.push(H),u(I.key,I.pos).dirs.push(H+Math.PI),r.push({a:x.pos.slice(),b:I.pos.slice(),padKeyA:x.key,padKeyB:I.key})}});const m=Array.from(s.entries()).map(([i,f])=>({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;h<a.length;h++){const x=a[h],I=a[(h+1)%a.length],b=h+1<a.length?I-x:Re-x+I;if(b<he)continue;const S=Be(x+b/2);if(Tt(S,i.dirs))continue;const V=f+e*Math.cos(S),H=v+e*Math.sin(S);let K=!1;for(const T of r)if(!(T.padKeyA===i.key||T.padKeyB===i.key)&&et([V,H],[V,H],T.a,T.b,e).length){K=!0;break}if(!K)for(const T of m){if(T.key===i.key)continue;const R=V-T.pos[0],O=H-T.pos[1];if(R*R+O*O<e*e-he){K=!0;break}}K||c.push(...It(f,v,e,x,I,t))}}for(let i=0;i<r.length;i++){const f=r[i],v=f.b[0]-f.a[0],l=f.b[1]-f.a[1],a=Math.hypot(v,l);if(a<he)continue;const h=-l/a*e,x=v/a*e,I=[{p:[f.a[0]+h,f.a[1]+x],q:[f.b[0]+h,f.b[1]+x]},{p:[f.a[0]-h,f.a[1]-x],q:[f.b[0]-h,f.b[1]-x]}];for(const b of I){const S=[];for(let H=0;H<r.length;H++)H!==i&&S.push(...et(b.p,b.q,r[H].a,r[H].b,e));for(const H of m)H.key===f.padKeyA||H.key===f.padKeyB||S.push(...St(b.p,b.q,H.pos,e));const V=kt(S);for(const[H,K]of V){if(K-H<.001)continue;const T=b.p[0]+H*(b.q[0]-b.p[0]),R=b.p[1]+H*(b.q[1]-b.p[1]),O=b.p[0]+K*(b.q[0]-b.p[0]),g=b.p[1]+K*(b.q[1]-b.p[1]);c.push(...Mt(T,R,O,g,t))}}}return c.push("0","ENDSEC","0","EOF"),c.join(`
`)+`
`}function Pt(n,o){const e=new Blob([n],{type:"application/dxf"}),t=URL.createObjectURL(e),c=document.createElement("a");c.href=t,c.download=o,document.body.appendChild(c),c.click(),document.body.removeChild(c),URL.revokeObjectURL(t)}const Ce=["#ef4444","#f59e0b","#10b981","#3b82f6","#a855f7","#ec4899","#14b8a6","#f97316"];let Xe=1,De=0;const J={list:[],activeId:null,listeners:new Set,mutationListeners:new Set,subscribe(n){return this.listeners.add(n),()=>this.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;i<n.length;i++)for(let f=i+1;f<n.length;f++){const v=o[n[i]],l=o[n[f]];Math.hypot(v[0]-l[0],v[1]-l[1])<=s&&c.push([n[i],n[f]])}const r=new Map;n.forEach(i=>r.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<m.length;a++)for(let h=a+1;h<m.length;h++)for(const x of m[a])for(const I of m[h]){const b=Math.hypot(o[x][0]-o[I][0],o[x][1]-o[I][1]);b<f&&(f=b,i=[x,I],v=a,l=h)}c.push(i),m[v]=m[v].concat(m[l]),m.splice(l,1)}return c}function Dt(n,o,e){const t=e[0]-o[0],c=e[1]-o[1],s=t*t+c*c;if(s===0)return Math.hypot(n[0]-o[0],n[1]-o[1]);const r=Math.max(0,Math.min(1,((n[0]-o[0])*t+(n[1]-o[1])*c)/s)),u=o[0]+r*t,m=o[1]+r*c;return Math.hypot(n[0]-u,n[1]-m)}function qe(n,o,e,t,c,s){const r=e+c+s;for(const u of t)if(Dt(u,n,o)<r)return!1;return!0}function At(n,o,e,t,c,s){const r=(n[0]+o[0])/2,u=(n[1]+o[1])/2,m=o[0]-n[0],i=o[1]-n[1],f=Math.hypot(m,i);if(f===0)return null;const v=-i/f,l=m/f,a=e+c+s+1;for(let h=1;h<=10;h++)for(const x of[1,-1]){const I=h*a,b=[r+x*I*v,u+x*I*l];if(qe(n,b,e,t,c,s)&&qe(b,o,e,t,c,s))return b}return null}function at(n,o,e,t,c,s){if(n.length===0)return{padIndices:[],edges:[],blocked:null};if(n.length===1)return{padIndices:n.slice(),edges:[],blocked:null};const r=Ct(n,o,e,c),u=new Set(n),m=o.filter((l,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<R.length-1;O++){const[g,E]=R[O],_=v(g),Q=l(E);i.fillStyle=K,i.beginPath(),i.moveTo(_+a,Q),i.arc(_,Q,a,0,x),i.fill()}if(R.length>=2){i.beginPath(),i.moveTo(v(R[0][0]),l(R[0][1]));for(let O=1;O<R.length;O++)i.lineTo(v(R[O][0]),l(R[O][1]));i.stroke()}}i.strokeStyle=tt(I.color,V?1:.85),i.lineWidth=(V?2.5:1.5)/h;for(const T of I.cellIndices){if(!e[T])continue;const[R,O]=e[T],g=v(R),E=l(O);i.beginPath(),i.arc(g,E,a,0,x),i.stroke()}if(S.blocked){i.strokeStyle="#ef4444",i.lineWidth=3/h,i.setLineDash([8/h,5/h]);const T=e[S.blocked.from],R=e[S.blocked.to];T&&R&&(i.beginPath(),i.moveTo(v(T[0]),l(T[1])),i.lineTo(v(R[0]),l(R[1])),i.stroke()),i.setLineDash([])}}),i.restore()}function _t(n,o,e,t,c){const s=Ie.instance;if(!s||n.padIndices.length===0)return null;const r=[];for(const m of n.padIndices){if(!o[m])continue;const[i,f]=o[m],v=new s.gp_Ax2(new s.gp_Pnt(i,f,t),s.gp.prototype.DZ());r.push(new s.BRepPrimAPI_MakeCylinder(v,e,c).Shape())}for(const m of n.edges){const i=[o[m.from],...m.waypoints,o[m.to]];for(let f=1;f<i.length-1;f++){const[v,l]=i[f],a=new s.gp_Ax2(new s.gp_Pnt(v,l,t),s.gp.prototype.DZ());r.push(new s.BRepPrimAPI_MakeCylinder(a,e,c).Shape())}for(let f=0;f<i.length-1;f++){const[v,l]=i[f],[a,h]=i[f+1],x=a-v,I=h-l,b=Math.hypot(x,I);if(b<1e-6)continue;const S=Math.atan2(I,x),V=new s.BRepPrimAPI_MakeBox(b,2*e,c).Shape(),H=new s.gp_Trsf;H.SetTranslation(new s.gp_Vec(0,-e,0));let K=new s.BRepBuilderAPI_Transform(V,H,!1).Shape();const T=new s.gp_Trsf;T.SetRotation(new s.gp_Ax1(new s.gp_Pnt(0,0,0),s.gp.prototype.DZ()),S),K=new s.BRepBuilderAPI_Transform(K,T,!1).Shape();const R=new s.gp_Trsf;R.SetTranslation(new s.gp_Vec(v,l,t)),K=new s.BRepBuilderAPI_Transform(K,R,!1).Shape(),r.push(K)}}if(r.length===0)return null;let u=r[0];for(let m=1;m<r.length;m++)u=new s.BRepAlgoAPI_Fuse(u,r[m]).Shape();return u}function nt(n){return n.replace(/[&<>"']/g,o=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[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=`
<div class="busbar-header">
<div class="busbar-swatch" style="background:${e.color}"></div>
<input class="busbar-name" type="text" value="${nt(e.name)}">
<button class="busbar-del" title="Delete">×</button>
</div>
<div class="busbar-meta">
<span class="busbar-count">${e.cellIndices.length} cell${e.cellIndices.length===1?"":"s"}</span>
<label class="busbar-thickness-label">Thickness
<input class="busbar-thickness" type="number" value="${e.thickness}" step="0.1" min="0.1">
</label>
</div>
${n[e.id]?`<div class="busbar-blocked">⚠ ${nt(n[e.id])}</div>`:""}
`,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(t<v||c<v){e(`Pack too small! Minimum: ${v.toFixed(1)}×${v.toFixed(1)} mm`,"#ef4444"),ve();return}if(r>t||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;k<F[p].length-1;k++){const q=(F[p][k][0]+F[p][k+1][0])/2,le=d;for(const[de,$]of l){const U=Math.hypot(q-de,le-$),ee=E+g;if(U<ee){const C=(U-g)*2;e(`BMS hole overlaps cells! Max diameter: ${C.toFixed(1)}mm`,"#ef4444"),M.currentPositions=[],ve();return}}}for(let k=0;k<F[y].length-1;k++){const q=(F[y][k][0]+F[y][k+1][0])/2,le=w;for(const[de,$]of l){const U=Math.hypot(q-de,le-$),ee=E+g;if(U<ee){e("BMS hole overlaps cells! Reduce hole diameter.","#ef4444"),M.currentPositions=[],ve();return}}}}f>r/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(e<v||t<v){ae(`Pack too small! Minimum size: ${v.toFixed(1)}×${v.toFixed(1)} mm`,"error"),be(!1);return}if(s>e||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=z<X?-1:1;let ne=oe>0?-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;X<P[te].length-1;X++){const z=P[te][X][0],G=P[te][X+1][0],D=P[te][X][1];ie.push({hx:(z+G)/2,hy:C(N,D,z,G)})}for(let X=0;X<P[Z].length-1;X++){const z=P[Z][X][0],G=P[Z][X+1][0],D=P[Z][X][1];ie.push({hx:(z+G)/2,hy:C(j,D,z,G)})}for(const{hx:X,hy:z}of ie){let G=1/0;for(const[D,ce]of T){const oe=Math.hypot(X-D,z-ce);oe<G&&(G=oe)}if(G<f+i){const D=(G-i)*2;ae(`BMS hole too large, overlaps cell! Max diameter: ${D.toFixed(2)}mm`,"error"),be(!1);return}}}else if(b){const C=Math.min(...T.map(D=>D[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;D<P[te].length-1;D++){const ce=(P[te][D][0]+P[te][D+1][0])/2,oe=z,ne=[P[te][D][0],P[te][D][1]],re=[P[te][D+1][0],P[te][D+1][1]];for(const[me,ue]of T){if(me===ne[0]&&ue===ne[1]||me===re[0]&&ue===re[1])continue;if(Math.hypot(ce-me,oe-ue)<f+i+r){ae(`BMS hole (${u}mm) collides with cell ledges! Reduce BMS hole size or increase spacing.`,"error"),be(!1);return}}}for(let D=0;D<P[Z].length-1;D++){const ce=(P[Z][D][0]+P[Z][D+1][0])/2,oe=G,ne=[P[Z][D][0],P[Z][D][1]],re=[P[Z][D+1][0],P[Z][D+1][1]];for(const[me,ue]of T){if(me===ne[0]&&ue===ne[1]||me===re[0]&&ue===re[1])continue;if(Math.hypot(ce-me,oe-ue)<f+i+r){ae(`BMS hole (${u}mm) collides with cell ledges! Reduce BMS hole size or increase spacing.`,"error"),be(!1);return}}}}const O=parseFloat(document.getElementById("tabWidth").value)||4,g=parseFloat(document.getElementById("tabDepth").value)||1,_=bt(T,{cellSize:s,spacing:c,height:l,terminalDiameter:a,terminalDepth:h,coverThickness:m,roundedCorners:x,bmsHoles:b,ledgeWidth:r,filletBms:H,circleHoleOffset:K,useTabs:S,useFullCircles:V,bmsHoleDiameter:u,tabWidth:O,tabDepth:g});if(!_){ae("Failed to create 3D model","error");return}const Q=Math.max(i-r,1),fe=a/2,Y=J.list.map(C=>at(C.cellIndices,T,i,Q,c,fe));for(let C=0;C<J.list.length;C++){const B=J.list[C],A=Y[C];if(A.blocked){ae(`${B.name}: ${A.blocked.reason}. Cannot export.`,"error"),be(!1);return}}const W=(Math.min(...T.map(C=>C[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;j<A.length;j++)for(let P=j+1;P<A.length;P++)N.push(Math.hypot(A[j][0]-A[P][0],A[j][1]-A[P][1]));return N.sort((j,P)=>j-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;C<J.list.length;C++){const B=J.list[C];if(B.cellIndices.length===0)continue;const A=y(B);if(A&&k.has(A)){k.get(A).copies.push(B.name);continue}const N={bb:B,geom:Y[C],copies:[B.name],shape:null};d==="step"&&(N.shape=_t(Y[C],L,Q,l,B.thickness),!N.shape)||(w.push(N),A&&k.set(A,N))}const q=C=>new Promise(B=>setTimeout(B,C));Qe(_,`cellholder_${n}.step`);for(let C=0;C<w.length;C++){await q(250);const{bb:B,geom:A,shape:N}=w[C],j=`busbar_${p(B.name)}`;if(d==="dxf"){const P=Bt(A,L,Q);Pt(P,`${j}.dxf`)}else Qe(N,`${j}.step`)}const de=J.list.filter(C=>C.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<t.length;s++)c[s]=t.charCodeAt(s);return new TextDecoder().decode(c)}function ge(n,o){if(!Number.isFinite(n))throw new Error(`Invalid number: ${o}`);return n}function xe(n,o){if(typeof n!="string")throw new Error(`Invalid string: ${o}`);return n}function Wt(n,o){if(typeof n!="boolean")throw new Error(`Invalid boolean: ${o}`);return n}function zt(n,o){if(!n||typeof n!="object")throw new Error(`Invalid busbar at index ${o}`);const e=xe(n.id,`busbars.list[${o}].id`),t=xe(n.name,`busbars.list[${o}].name`),c=xe(n.color,`busbars.list[${o}].color`),s=ge(Number(n.thickness),`busbars.list[${o}].thickness`);if(s<=0)throw new Error(`Invalid busbar thickness at index ${o}`);if(!Array.isArray(n.cellIndices))throw new Error(`Invalid busbar cell index list at index ${o}`);const r=n.cellIndices.map(u=>{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=`<strong>${b.toFixed(0)} &times; ${S.toFixed(0)} mm</strong> <span class="muted">footprint. Cells fit automatically.</span>`);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=`<strong>${c}S ${s}P</strong>. ${b} cells. <span class="muted">Footprint about ${x.toFixed(0)} &times; ${I.toFixed(0)} mm.</span>`}}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<r&&(r=f,s=i)}),s>=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();