4;){const e=t.findIndex(t=>!t.live);if(e<0)break;clearTimeout(t[e].evict),t.splice(e,1)}}_warmScheduleEvict(t,e){if(clearTimeout(t.evict),!(t.dlg||t.vp&&"view"!==t.vp.mode))return;const i=t.freed,s=t.owner;t.evict=window.setTimeout(()=>{if(t.evict=0,t.freed!==i||t.owner!==s)return;var n;t.dlg=null,t.vp=(n=t.vp)&&"view"!==n.mode?{...n,mode:"view",zoom:n.snap?.space===n.space?n.snap.zoom:n.zoom,view:null,snap:null,tool:"draw",decorTool:"select",showHidden:!1,selId:null,rszSel:null,decorSel:null}:n,t.frameFingerprint="";const o=Kf.get(e);if(!t.live&&o&&o.length>1){const e=o.indexOf(t);e>=0&&o.splice(e,1)}},Xf+250)}_warmAdoptViewport(t){const e=this._warmVp;if(!e||this._warmSlot?.path!==location.pathname)return void(this._warmVp=null);const i=this._fixedFloorState();if(this._hashApplied||!this._model.find(t=>t.id===e.space)||"valid"===i.kind&&i.id!==e.space||this._hasFixedFloor&&"valid"!==i.kind)return void(this._warmVp=null);this._commitSpace(e.space,!0),this._navApplied=!0,this._adoptMode("view"!==e.mode&&this._canEdit&&!t.kiosk?e.mode:"view"),this._pendingNavMode="view"===e.mode||this._canEdit||t.kiosk?null:e.mode,this._zoom=e.zoom;const s=this._effectiveProjection(),n=s===e.projection&&this._labsIso===e.activeLabsIso;if(this._view=n&&e.view?{...e.view}:null,this._viewModeSnap=n&&e.snap?{...e.snap}:null,!n&&e.logicalCenter){const t="iso"===s?Qm([e.logicalCenter.x,e.logicalCenter.y],0):[e.logicalCenter.x,e.logicalCenter.y];this._applyView(e.zoom,t[0],t[1])}var o;this._tool="openwall"===(o=e.tool)||"closewall"===o?"boundary":"opening"===(o=function(t){return"partition"===t?"draw":t}(o))?"draw":"string"==typeof o&&lv.has(o)?o:"draw",this._decorTool=e.decorTool,this._showHidden=e.showHidden,this._showFar!==e.showFar&&(this._showFar=e.showFar,this._frame=null),this._selId=e.selId,this._rszSel=e.rszSel,this._decorSel=e.decorSel,this._warmVpArmed=!0}_warmPatch(t,e=!1){if(this._config?.kiosk)return;const i=Jf(this._config);if(!this._warmSlot||this._warmKey===i){if(!this._warmSlot){if(!e)return;const t=this.parentNode;this._warmKey=i,this._warmSlot={owner:this._warmGen,path:location.pathname,place:t?new WeakRef(t):null,idx:this._warmIdx(t),live:!0,hdrH:this._hdrH,stageH:0,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0};const s=Kf.get(i)||[];for(s.push(this._warmSlot),Kf.set(i,s),this._warmTrim(s);Kf.size>8;){const t=Kf.keys().next().value;if(void 0===t||t===i)break;for(const e of Kf.get(t)||[])clearTimeout(e.evict);Kf.delete(t)}}Object.assign(this._warmSlot,t)}}_warmViewportState(){const t=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:t,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(t),zoom:this._zoom,view:this._view?{...this._view}:null,snap:this._viewModeSnap?{...this._viewModeSnap}:null,tool:this._tool,decorTool:this._decorTool,showHidden:this._showHidden,showFar:this._showFar,selId:this._selId,rszSel:this._rszSel,decorSel:this._decorSel}}_warmDialogState(){const t=(t,e)=>({kind:t,space:this._space,mode:this._mode,data:e});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?t("openingInfo",this._openingInfo.id):this._infoCard?t("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:t("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:t("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:t("marker",this._markerDialog):this._openingDialog?t("opening",this._openingDialog):this._backdropDialog?t("backdrop",this._backdropDialog):this._decorShapeDialog?t("decorShape",this._decorShapeDialog):this._decorTextDialog?t("decorText",this._decorTextDialog):this._roomDialog?t("room",{editId:this._roomEditId,fill:this._roomFill,customFill:this._roomCustomFill,tempSrc:this._roomTempSrc,humSrc:this._roomHumSrc,srcOpen:this._roomSrcOpen,srcFilter:this._roomSrcFilter,nameScale:this._roomNameScale,labelScale:this._roomLabelScale,areaSel:this._areaSel,nameSel:this._nameSel,pendingSplit:this._pendingSplit,wallFaceBatch:this._wallFaceBatch,path:this._path}):this._spaceDialog?this._spaceDialog.busy?null:t("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const t={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices};if(this._warmRevivePending||(t.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const e=this.parentNode;t.place=e?new WeakRef(e):null,t.idx=this._warmIdx(e)}this._warmPatch(t)}_warmReviveDialog(){this._warmRevivePending=!1;const t=this._warmSlot;if(this._warmReviveTimer=void 0,!t||!t.dlg)return;const e=t.dlg,i=t.freed;if(t.dlg=null,t.freed=0,clearTimeout(t.evict),t.evict=0,i&&!(Date.now()-i>Xf)&&e.space===this._space&&e.mode===this._mode){switch(e.kind){case"space":this._spaceDialog={...e.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...e.data,busy:!1};break;case"settings":this._settingsDialog={...e.data,busy:!1};break;case"rules":this._rulesDialog={...e.data,busy:!1};break;case"opening":this._openingDialog={...e.data};break;case"backdrop":this._backdropDialog={...e.data};break;case"decorShape":this._decorShapeDialog={...e.data};break;case"decorText":{this._decorTextDialog={...e.data};const t=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:t,end:t};break}case"room":{const t=e.data;this._roomEditId=t.editId,this._roomFill=t.fill,this._roomCustomFill=t.customFill||null,this._roomTempSrc=t.tempSrc,this._roomHumSrc=t.humSrc,this._roomSrcOpen=t.srcOpen,this._roomSrcFilter=t.srcFilter,this._roomNameScale=t.nameScale,this._roomLabelScale=t.labelScale,this._areaSel=t.areaSel,this._nameSel=t.nameSel,this._pendingSplit=t.pendingSplit,this._wallFaceBatch=t.wallFaceBatch||null,this._path=t.path,this._wallFaceBatch&&(this._activeDraftId=this._wallFaceBatch.activeDraftId,this._draftSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const t=this._devices.find(t=>t.id===e.data);t&&(this._infoCard=t);break}case"openingInfo":{const t=(this._curSpaceCfg?.openings||[]).find(t=>t.id===e.data);t&&(this._openingInfo=t);break}}this.requestUpdate()}}_cacheSnapshot(){if(this._serverCfg)try{this._cfgContentFingerprint=Ad(this._serverCfg),this._layoutContentFingerprint=Ad(this._layout),this._virtualLights=function(t,e,i){if(t.configRev===i)return t;const s=new Set((Array.isArray(e?.markers)?e.markers:[]).filter(yn).map(t=>t.id));return{...t,configRev:i,off:new Set([...t.off].filter(t=>s.has(t)))}}(this._virtualLights,this._serverCfg,this._cfgRev),localStorage.setItem(Qf,JSON.stringify({config:this._serverCfg,rev:this._cfgRev,config_fingerprint:this._cfgContentFingerprint,layout:this._layout,layout_rev:this._layoutRev,layout_fingerprint:this._layoutContentFingerprint,virtual_lights:fn(this._virtualLights)}))}catch{}}_beginContinuityCandidate(t,e,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=e,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(t,i))}_continuityStageValid(){const t=this._stageEl;return!!t&&t.clientWidth>0&&t.clientHeight>0}_continuityAssetsReady(){if(!this._model.length)return!1;const t=this._model.length?this._spaceModel():null;return!t?.bg?.href||this._signer.isReady(this.hass,t.bg.href)}_initialSpaceSelection(t,e=this._loadOk){const i=this._fixedFloorState(t,e);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(t){const e=new Set(t.spaceIds.filter(t=>!!t));if(!e.size)return{id:null,source:"none"};const i=[["hash",!1===t.acceptHash?null:t.hashSpace],["current",t.preserveCurrent?t.currentSpace:null],["saved",t.savedSpace],["default",t.defaultSpace],["first",t.spaceIds[0]]];for(const[t,s]of i)if(s&&e.has(s))return{id:s,source:t};return{id:null,source:"none"}}({spaceIds:t.map(t=>t.id),hashSpace:this._hashSpace(),acceptHash:!this._hashApplied,currentSpace:this._space,preserveCurrent:this._hashApplied||this._navApplied||this._warmVpArmed,savedSpace:this._savedNav()?.space,defaultSpace:this._config?.default_floor})}_adoptInitialSpace(t,e=this._loadOk){const i=this._initialSpaceSelection(t,e);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(t,e=this._space){const i=$h(t),s=this._fixedFloorState(i,!0);if(this._hasFixedFloor&&"valid"!==s.kind)return"";const n=this._initialSpaceSelection(i,!0).id||(i.some(t=>t.id===e)?e:i[0]?.id);return i.find(t=>t.id===n)?.bg?.href||""}_visualFrameFingerprint(){const t=this._stageEl,e=t?[t.clientWidth,t.clientHeight]:[0,0];return zd([this._cfgRev,this._cfgContentFingerprint||Ad(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||Ad(this._layout),this._space,this._mode,this._view,e,this._glowScreenBlend?"screen":"normal",this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_settleContinuityFrame(){if(this._booting||!this._continuityStageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state)return void(this._continuityAssetsReady()&&(this._renderSnapshotAt=Date.now(),this._continuity.markCompleteFrame(this._visualFrameFingerprint())));if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const t=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==t)return this._stagedDeviceSnapshotToken=t,void this.requestUpdate();this._continuityPaintToken!==t&&(this._continuityPaintToken=t,this._continuity.candidateReady(t)&&this._continuity.commitAfterPaint(t,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(e=>{e&&t===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):t===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(t,e){this._signer.markLoaded(this.hass,t,e),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return U;const t="connection"===this._continuity.recoveryReason;return W`t.stopPropagation()}
@click=${t=>t.stopPropagation()}
@@ -4995,7 +4995,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1a3e44c4ae4f035729b63e78de9ab19d31dc
style="left:${r.toFixed(1)}%;top:${l.toFixed(1)}%"
@click=${t=>{t.stopPropagation(),this._fitAll()}}>
- `}_stageAspect(){const t=this._stageEl,e=this._baseVb();return t&&t.clientHeight?t.clientWidth/t.clientHeight:e[2]/e[3]}_viewOr(t){return this._view&&this._view.w?this._view:Ni(t,this._stageAspect())}_roomLabelReferenceViewWidth(t){if(!this._markup)return t.w;const e=this._stageEl,i=this.renderRoot.querySelector(".editorchrome");if(!e||e.clientWidth<=0||e.clientHeight<=0)return t.w;const s=e.clientHeight+(i?.getBoundingClientRect().height||0);return s<=0?t.w:this._viewForModeTarget(this._zoom,void 0,void 0,e.clientWidth,s).w}_screenToVb(t,e){const i=this._stageEl,s=this._viewOr(this._baseVb()),n=i?.clientWidth||1,o=i?.clientHeight||1;return[s.x+t/n*s.w,s.y+e/o*s.h]}_clampView(t,e){const i=(t,e,i,s)=>{const n=1*Math.max(e,s),o=i-n,a=i+s-e+n;return Math.max(Math.min(o,a),Math.min(Math.max(o,a),t))};return{w:t.w,h:t.h,x:i(t.x,t.w,e.x,e.w),y:i(t.y,t.h,e.y,e.h)}}_applyView(t,e,i){const s=this._baseVb(),n=Ni(s,this._stageAspect()),o=Math.min(_v.ZOOM_MAX,Math.max(_v.ZOOM_MIN,t)),a=n.w/o,r=n.h/o,l=this._viewOr(s),c=e??l.x+l.w/2,h=i??l.y+l.h/2,d=this._clampView({x:c-a/2,y:h-r/2,w:a,h:r},n);return!(this._view&&Math.abs(this._zoom-o)<1e-9&&Math.abs(this._view.x-d.x)<1e-6&&Math.abs(this._view.y-d.y)<1e-6&&Math.abs(this._view.w-d.w)<1e-6&&Math.abs(this._view.h-d.h)<1e-6)&&("opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=o,this._view=d,!0)}_bootWatch(){clearTimeout(this._bootTimer),this._bootStart=Date.now(),this._bootLastH=-1,this._bootLastChange=this._bootStart;const t=()=>{if(!this._booting)return;const e=Date.now(),i=this._stageEl?this._stageEl.clientHeight:0;i!==this._bootLastH&&(this._bootLastH=i,this._bootLastChange=e);const s=e-this._bootStart;s>=1200||s>=700&&i>0&&e-this._bootLastChange>=250?this._bootSettled():this._bootTimer=window.setTimeout(t,100)};this._bootTimer=window.setTimeout(t,100)}_bootSettled(){this._booting&&!this._bootSettling&&(this._bootSettling=!0,this._refitView(),this._bootSettleRaf=requestAnimationFrame(()=>{this._bootSettleRaf=0,this._finishBootSettled()}))}_finishBootSettled(){if(!this._booting)return;this._refitView(),this._booting=!1,this._bootSettling=!1;const t=this._stageEl?.clientHeight??0;!this._config?.kiosk&&t>0&&this._warmPatch({hdrH:this._hdrH,stageH:t,vp:this._warmViewportState()},!0),this._bootFading=!0,this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220),this._bootSoft=!0,clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},jf)}_bootSoftCancel(){this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoft=!1)}_beginResumeSettle(){this._booting||this._resumeSettling||(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0),this._viewportInvalidAt=0,this._beginContinuityCandidate("warm-resume",!1),this._loading?this.requestUpdate():this._loadFromServer())}_refitView(){if(this._modeTransitionBusy)return;const t=this._stageEl;if(!t||"visible"!==document.visibilityState||t.clientWidth<=0||t.clientHeight<=0)return void(this._viewportInvalidAt||(this._viewportInvalidAt=Date.now()));const e=[t.clientWidth,t.clientHeight],i=this._lastValidStageSize,s=!!i&&Math.abs(i[0]-e[0])<=.5&&Math.abs(i[1]-e[1])<=.5,n=this._viewportInvalidAt?Date.now()-this._viewportInvalidAt:0;if(this._viewportInvalidAt=0,!i)return this._lastValidStageSize=e,void(this._view||this._applyView(this._zoom));s?this._pendingRefitSize=null:(this._pendingRefitSize=e,this._refitRaf||(this._refitRaf=requestAnimationFrame(()=>{this._refitRaf=0;const t=this._pendingRefitSize;this._pendingRefitSize=null;const e=this._stageEl;if(!t||!e||e.clientWidth<=0||e.clientHeight<=0)return;if(Math.abs(e.clientWidth-t[0])>.5||Math.abs(e.clientHeight-t[1])>.5)return void this._refitView();const i=this._lastValidStageSize;if(i&&Math.abs(i[0]-t[0])<=.5&&Math.abs(i[1]-t[1])<=.5)return;this._lastValidStageSize=t;const s=this._view;n>=Cd?this._beginContinuityCandidate("stage-size-restored",!0,"stage-size"):this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._applyView(this._zoom,s?s.x+s.w/2:void 0,s?s.y+s.h/2:void 0)})))}_zoomAt(t,e,i){const s=this._stageEl;if(!s)return;const n=Ni(this._baseVb(),this._stageAspect()),o=Math.min(_v.ZOOM_MAX,Math.max(_v.ZOOM_MIN,i));"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1));const a=s.clientWidth,r=s.clientHeight,l=this._screenToVb(t,e),c=n.w/o,h=n.h/o;this._zoom=o,this._view=this._clampView({x:l[0]-t/a*c,y:l[1]-e/r*h,w:c,h:h},n)}_onWheel(t){const e=this._stageEl;if(!e)return;t.preventDefault();const i=e.getBoundingClientRect(),s=t.deltaY<0?1.15:1/1.15;this._zoomAt(t.clientX-i.left,t.clientY-i.top,this._zoom*s),this._saveZoom()}_stepZoom(t){const e=this._stageEl;e&&(this._zoomAt(e.clientWidth/2,e.clientHeight/2,this._zoom*(t>0?1.4:1/1.4)),this._saveZoom())}_resetZoom(){const t=this._baseVb();"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=1,this._view=Ni(t,this._stageAspect()),this._saveZoom()}_saveZoom(){if("view"===this._mode){this._zoomBySpace={...this._zoomBySpace,[this._space]:this._zoom};try{localStorage.setItem(tv,JSON.stringify(this._zoomBySpace))}catch{}}}_restoreZoom(){const t=this._zoomBySpace[this._space]||1;this._zoom=t;const e=this._stageEl;if(e&&e.clientHeight){const e=this._baseVb();return this._applyView(t,e[0]+e[2]/2,e[1]+e[3]/2),void this.requestUpdate()}this._view=null,requestAnimationFrame(()=>{if(!this._stageEl)return;const e=this._baseVb();this._applyView(t,e[0]+e[2]/2,e[1]+e[3]/2),this.requestUpdate()})}_stagePointerDown(t){if(this._vacFit)return;if(this._kiosk&&(this._cyclePausedUntil=Date.now()+6e4,0===this._pointers.size?(this._swipeStart={x:t.clientX,y:t.clientY,id:t.pointerId},t.target.closest?.(".dev, .roomlabel, .oplock")||(clearTimeout(this._kioskHoldTimer),this._kioskHoldTimer=window.setTimeout(()=>{this._kioskDialog=!0,this._swipeStart=null},3e3))):(this._swipeStart=null,clearTimeout(this._kioskHoldTimer))),this._drag)return;if(this._markup&&t.target.closest?.(".roomlabel, .rlhandle, .rszhandle, .dev, .oplock, .op-hit, button"))return;if("devices"===this._mode&&t.target.closest(".dev"))return;if("decor"===this._mode&&this._decorPointerDown(t))return;this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY});const e=this._viewOr(this._baseVb());if(1===this._pointers.size)this._panStart={sx:t.clientX,sy:t.clientY,vx:e.x,vy:e.y},this._panLock=null,this._suppressClick=!1;else if(2===this._pointers.size){this._cancelBoundaryAnchor(),"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const t=[...this._pointers.values()],e=Math.hypot(t[0].x-t[1].x,t[0].y-t[1].y);this._pinchStart={dist:e,zoom:this._zoom},this._panStart=null,this._panLock=null}}get _swipeZone(){return!this._hasFixedFloor&&this._kiosk&&this._zoom<=1.001&&this._model.length>1}_stagePointerMove(t){if(this._physicalRotate?.pid!==t.pointerId)if(this._physicalDrag?.pid!==t.pointerId)if(this._dtDrag?.pid!==t.pointerId)if(this._bdDrag?.pid!==t.pointerId){if(this._decorDraft?.pid===t.pointerId){const e=this._decorDraft;let i=this._decorSnap(this._svgPoint(t),t.pointerType);if(t.shiftKey&&("rect"===e.kind||"ellipse"===e.kind)){const t=i[0]-e.a[0],s=i[1]-e.a[1],n=Math.max(Math.abs(t),Math.abs(s));i=this._snap([e.a[0]+(t<0?-n:n),e.a[1]+(s<0?-n:n)])}return void(this._decorDraft={...e,b:i})}if(this._decorMove?.pid!==t.pointerId)if(this._pointers.has(t.pointerId)){if(this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY}),this._markup&&1===this._pointers.size&&this._markupMove(t),this._pinchStart&&this._pointers.size>=2){"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const t=[...this._pointers.values()],e=Math.hypot(t[0].x-t[1].x,t[0].y-t[1].y)/(this._pinchStart.dist||1),i=this._stageEl.getBoundingClientRect(),s=(t[0].x+t[1].x)/2-i.left,n=(t[0].y+t[1].y)/2-i.top;this._zoomAt(s,n,this._pinchStart.zoom*e),this._suppressClick=!0,this._saveZoom()}else if(this._panStart){const e=t.clientX-this._panStart.sx,i=t.clientY-this._panStart.sy;Math.abs(e)+Math.abs(i)>4&&(this._suppressClick=!0,clearTimeout(this._holdTimer),"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover()),null===this._panLock&&Math.abs(e)+Math.abs(i)>8&&(this._panLock=this._swipeZone&&Math.abs(e)>1.5*Math.abs(i)?"swipe":"pan");const s=this._stageEl;if("pan"===this._panLock&&s){const t=this._baseVb(),n=this._viewOr(t),o=Ni(t,this._stageAspect());this._view=this._clampView({x:this._panStart.vx-e/(s.clientWidth||1)*n.w,y:this._panStart.vy-i/(s.clientHeight||1)*n.h,w:n.w,h:n.h},o)}}}else this._markupMove(t);else this._decorMoveUpdate(t)}else this._bdMove(t);else this._dtMove(t);else this._physicalMove(t);else this._physicalRotateMove(t)}_stagePointerLeave(t){this._markup&&("opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover())}_stagePointerUp(t){if(this._kiosk){clearTimeout(this._kioskHoldTimer);const e=this._swipeStart;if(this._swipeStart=null,e&&e.id===t.pointerId){const i=t.clientX-e.x,s=t.clientY-e.y;if(Math.abs(i)+Math.abs(s)<8){const t=Date.now();t-this._lastTap<350&&this._resetZoom(),this._lastTap=t}const n="pan"===this._panLock?null:function(t,e,i,s,n,o=60){if(i>1.001||s.length<2)return null;if(Math.abs(t)t.id),this._space);n&&this._slideTo(n,i<0?"left":"right")&&(this._saveNav(),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._showKioskDots())}}if(this._physicalDrag?.pid===t.pointerId)return void this._physicalUp(t);if(this._physicalRotate?.pid===t.pointerId)return void this._physicalRotateUp(t);if(this._dtDrag?.pid===t.pointerId)return void this._dtUp();if(this._bdDrag?.pid===t.pointerId)return void this._bdUp();if(this._decorDraft?.pid===t.pointerId)return void this._decorCommitDraft();if(this._decorMove?.pid===t.pointerId)return this._decorMove.moved&&(this._recordGeometry(this._t("history.decor_move"),this._decorMove.before),this._saveConfig()),void(this._decorMove=null);const e=!!this._pinchStart||!!this._panStart;this._pointers.delete(t.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null,setTimeout(()=>this._suppressClick=!1,0)),e&&0===this._pointers.size&&this.requestUpdate()}_clickRoom(t){!this._suppressClick&&t.area&&dv("/config/areas/area/"+t.area)}_pointerDown(t,e){if("plan"===this._mode)return;if("view"===this._mode){this._holdFired=!1,clearTimeout(this._holdTimer);const i=t.pointerId,s=t.currentTarget;return void(this._holdTimer=window.setTimeout(()=>{this._holdFired=!0,this._interruptViewGesture(i,s),this._infoCard=e},600))}if("ha_disabled"===e.bindingStatus?.kind)return;t.preventDefault();const i=this._pos(e);this._drag={id:e.id,sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},uv(t),this._tip=null}_pointerMove(t,e){if(!this._drag||this._drag.id!==e.id)return;const i=this.renderRoot.querySelector(".stage");if(!i)return;const s=this._baseVb(),n=i.getBoundingClientRect(),o=this._viewOr(s),a=(t.clientX-this._drag.sx)/n.width*o.w,r=(t.clientY-this._drag.sy)/n.height*o.h;Math.abs(t.clientX-this._drag.sx)+Math.abs(t.clientY-this._drag.sy)>3&&(this._drag.moved=!0,clearTimeout(this._holdTimer));const l=Ih(this._drag.ox+a),c=Ih(this._drag.oy+r);this._savePos(e,l,c)}_pointerUp(t,e){if(clearTimeout(this._holdTimer),!this._drag||this._drag.id!==e.id)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&(this._selId=e.id,window.setTimeout(()=>this._drag=null,0))}_showToast(t){for(const t of this.renderRoot.querySelectorAll("hp-dialog"))t.closeTransientOverlays("toast");this._toast=t,clearTimeout(this._toastTimer),this._toastTimer=window.setTimeout(()=>{this._toast=""},3500)}_syncPointerHoverTargets(){const t=this._pointerModality.hoverEnabled;for(const e of this.renderRoot.querySelectorAll(nv))e.toggleAttribute("data-pointer-hover",t)}_syncPointerHoverSubtree(t){if(t.nodeType!==Node.ELEMENT_NODE)return;const e=t,i=this._pointerModality.hoverEnabled;e.matches(nv)&&e.toggleAttribute("data-pointer-hover",i);for(const t of e.querySelectorAll(nv))t.toggleAttribute("data-pointer-hover",i)}_clearTransientHover(t=!1){t&&this._pointerModality.suspend(),this._tip&&(this._tip=null),this._hoverRoom&&(this._hoverRoom=null)}_notePointer(t){this._boundaryPointerType=t.pointerType||"mouse";const e=this._pointerModality.modality,i=this._pointerModality.note(t);"touch"!==i&&"pen"!==i||e===i&&!this._tip&&!this._hoverRoom||this._clearTransientHover()}_guardTouchGesture(t){if(this._editorSecondary.handleOutsideDismiss(t))return;if("click"===t.type){if(!this._suppressClick&&!this._touchSequenceMultitouch&&Date.now()>this._touchClickBlockUntil)return;return t.preventDefault(),void t.stopImmediatePropagation()}const e=t;if(this._notePointer(e),"touch"===e.pointerType)if("pointerdown"!==t.type){if("pointermove"===t.type){const t=this._touchContacts.get(e.pointerId);if(!t)return;const i={...t,x:e.clientX,y:e.clientY};if(this._touchContacts.set(e.pointerId,i),this._touchSequenceMultitouch&&"view"===this._mode&&!this._vacFit&&this._pinchStart&&[...this._touchContacts.values()].every(t=>t.inStage)){this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY});const t=[...this._touchContacts.values()];if(t.length>=2&&this._stageEl){const[e,i]=t,s=Math.hypot(e.x-i.x,e.y-i.y)/(this._pinchStart.dist||1),n=this._stageEl.getBoundingClientRect();this._zoomAt((e.x+i.x)/2-n.left,(e.y+i.y)/2-n.top,this._pinchStart.zoom*s),this._saveZoom()}}return}if("pointerup"===t.type||"pointercancel"===t.type||"lostpointercapture"===t.type){if(this._clearTransientHover(),this._touchContacts.delete(e.pointerId),this._touchSequenceMultitouch){if(this._touchClickBlockUntil=Date.now()+500,this._pointers.delete(e.pointerId),!this._vacFit&&this._pointers.size>=2){const[t,e]=[...this._pointers.values()];this._pinchStart={dist:Math.hypot(t.x-e.x,t.y-e.y),zoom:this._zoom}}else this._pinchStart=null;0===this._pointers.size&&(this._panStart=null,this._panLock=null)}0===this._touchContacts.size&&(this._touchSequenceMultitouch=!1)}}else if(this._touchContacts.set(e.pointerId,{x:e.clientX,y:e.clientY,inStage:!!e.target?.closest?.(".stage")}),this._touchContacts.size>=2){this._clearTransientHover(),this._touchSequenceMultitouch=!0,this._touchClickBlockUntil=Number.POSITIVE_INFINITY,clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),this._swipeStart=null;const t=[...this._touchContacts.values()];if("view"===this._mode&&!this._vacFit&&t.every(t=>t.inStage)){this._pointers=new Map([...this._touchContacts].map(([t,e])=>[t,{x:e.x,y:e.y}]));const[e,i]=t;this._pinchStart={dist:Math.hypot(e.x-i.x,e.y-i.y),zoom:this._zoom},this._panStart=null,this._panLock=null}else this._vacFit&&(this._pointers.clear(),this._pinchStart=null,this._panStart=null,this._panLock=null)}}_showTip(t,e,i,s,n,o){this._notePointer(t),this._pointerModality.hoverEnabled&&(this._drag||(this._tip={x:t.clientX,y:t.clientY,title:e,meta:i,lqi:s,temp:n,hum:o}))}get _gridPitch(){return Dh}get _cellCm(){const t=Number(this._curSpaceCfg?.cell_cm);return Number.isFinite(t)&&t>0?t:5}_fmtLen(t,e){const i=function(t,e,i,s){return Math.hypot(e[0]-t[0],e[1]-t[1])/i*s}(t,e,this._gridPitch,this._cellCm);return li(i,"mi"===this.hass?.config?.unit_system?.length)}get _curSpaceCfg(){const t=this._rszPreview;return t&&t.space===this._space?t.sp:this._serverCfg?.spaces.find(t=>t.id===this._space)}get _renderCfg(){const t=this._rszPreview;return t&&this._serverCfg?{...this._serverCfg,spaces:this._serverCfg.spaces.map(e=>e.id===t.space?t.sp:e)}:this._serverCfg}get _spaceH(){return this._curSpaceCfg,ov}get _segments(){const t=this._curSpaceCfg,e=this._spaceH;return pi(t?.rooms||[]).map(t=>[t[0]*ov,t[1]*e,t[2]*ov,t[3]*e])}_savedNav(){if(this._hasFixedFloor)return null;try{return JSON.parse(localStorage.getItem(ev)||"null")}catch{return null}}_saveNav(){if(!this._hasFixedFloor)try{localStorage.setItem(ev,JSON.stringify({space:this._space}))}catch{}}_leaveCardRoute(){if(this._routeDepartureHandled)return;this._routeDepartureHandled=!0,"view"!==this._mode&&this._setMode("view",!1),this._pendingNavMode=null,this._geometryHistory.clear(),this._activeDraftId=null,this._resumeDraftBySpace={},this._draftSegmentCms=[],this._closingWallCm=null,this._drawWallField=null,this._showHidden=!1,this._tapConfirm=null,this._vacCalConfirm=null,this._decorEraseConfirm=null,this._openingInfo=null,this._closeInfoCard(),this._rulesDialog=null,this._alignDialog=null,this._backupImportDialog=null,this._backupExportDialog=null,this._settingsDialog=null,this._markerDialog=null,this._openingDialog=null,this._physicalDialog=null,this._wallDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._mergeDialog=null,this._roomDialog=!1,this._spaceDialog=null,this._importDialog=null;const t=this._warmSlot;t?.owner===this._warmGen&&(t.vp=this._warmViewportState(),t.dlg=null,t.frameFingerprint="",clearTimeout(t.evict),t.evict=0),this._saveNav()}_setMode(t,e=!0){this._endTabDrag(),this._pendingNavMode=null;const i=this._spaceModel();if(!i)return this._cancelModeTransition(!1),void(this._mode="view");if(this._kiosk&&"view"!==t)return;if(this._mode===t){if(!e&&"view"===t&&this._modeTransitionBusy){const e=this._currentModeVisual(t),i=this._modeTransitionTargetZoom,s=this._modeTransitionTargetCenterX,n=this._modeTransitionTargetCenterY;this._cancelModeTransition(!1),this._commitViewModeAtomic(e,i,s,n)}return}if(this._bootSoftCancel(),("plan"===t||"decor"===t)&&!this._norm)return void this._showToast(this._t("toast.markup_needs_server"));if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._clearTransientHover(!0),this._cancelDevicePressFeedback();const s=this._mode,n=this._effectiveProjection(),o=this._currentModeVisual(s),a=this._modeTransitionBusy,r=o&&"view"!==s&&"view"!==t?{...o,toolbarContentOpacity:this._reducedMotion?1:.35}:o;this._cancelModeTransition(!1),this._editorSecondary.closeForNavigation(),(this._decorMove||this._dtDrag||this._bdDrag)&&this._cancelDecorGesture();const l=!i.bg&&"view"===t!=("view"===s),c=a&&"view"===s&&"view"!==t?this._modeTransitionEditorCamera:null;let h=c?.zoom??(a?this._modeTransitionTargetZoom:this._zoom),d=c?c.centerX:a?this._modeTransitionTargetCenterX:r?.viewport.centerX,p=c?c.centerY:a?this._modeTransitionTargetCenterY:r?.viewport.centerY;if("view"===s&&"view"!==t&&!a){const e=this._view;if(this._viewModeSnap={space:this._space,zoom:this._zoom,cx:e?this._logicalViewCenter(n)?.x:void 0,cy:e?this._logicalViewCenter(n)?.y:void 0},"iso"===n){const e=this._logicalViewCenter("iso");d=e?.x,p=e?.y,this._view=null,this._mode=t,this._applyView(this._zoom,e?.x,e?.y)}l&&(h=1,d=void 0,p=void 0)}if("plan"===s&&this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._mode=t,this._editorChromeMode="view"===t?s:t,"view"===t){"view"===s||a||(this._modeTransitionEditorCamera={zoom:this._zoom,centerX:r?.viewport.centerX,centerY:r?.viewport.centerY});const t=this._viewModeSnap;if(t&&t.space===this._space){h=t.zoom;const e=this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat",i=null!=t.cx&&null!=t.cy&&"iso"===e?Qm([t.cx,t.cy],0):null;d=i?.[0]??t.cx,p=i?.[1]??t.cy}else t&&(h=this._zoomBySpace[this._space]||1,d=void 0,p=void 0)}else this._modeTransitionEditorCamera={zoom:h,centerX:d,centerY:p};this._modeTransitionTargetZoom=h,this._modeTransitionTargetCenterX=d,this._modeTransitionTargetCenterY=p,("iso"===n||"view"===t&&this._labsIso&&"iso"===this._viewPreference[this._space])&&(this._modeTransitionForceAtomic=!0);const u=++this._modeTransitionRequest;e?r?(this._modeTransitionPreparing=!0,this._modeTransitionVisual=r,this._prepareModeTransition(u,r,t,h,d,p)):(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._zoom=h,this._view=null,requestAnimationFrame(()=>{this.isConnected&&u===this._modeTransitionRequest&&this._mode===t&&(this._applyView(h,d,p),"view"===t&&(this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate())})):"view"===t&&this._commitViewModeAtomic(r,h,d,p),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._tool="draw",this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._selId=null,this._physicalSel=null,this._physicalDialog=null,this._physicalDrag=null,this._rszSel=null,this._rszDrag=null,this._rszLive=null,this._rszPreview=null,this._tip=null,this._hoverRoom=null,this._decorDraft=null,this._decorSel=null,this._decorMove=null,this._backdropDialog=null,this._decorTool="select",this._bdDrag=null,this._dtDrag=null,this._dtBox=null,"plan"===t&&(this._primeDrawWallField(),this._resumeLastDraft()),this._saveNav()}_primeDrawWallField(){null===this._drawWallField&&(this._drawWallField=gl(ll,this._imperial))}get _drawWallFieldValue(){return null===this._drawWallField?gl(ll,this._imperial):this._drawWallField}get _drawWallCm(){const t=Gf(this._drawWallFieldValue);if(null==t||t<=0)return null;const e=this._imperial?2.54*t:t,i="column"===this._tool?Wc:100;return e>=1&&e<=i?e:null}get _drawWallMaxCm(){return"column"===this._tool?Wc:100}_showPhysicalRange(t=this._drawWallMaxCm){this._showToast(this._t("toast.physical_range",{max:gl(t,this._imperial),unit:this._t(this._imperial?"wallthick.unit_in":"wallthick.unit_cm")}))}_draftSegmentCount(t=this._curSpaceCfg){return(t?.room_drafts||[]).reduce((t,e)=>t+(Array.isArray(e.segments)?e.segments.length:0),0)}_mergeSpacePartitions(t,e){const i=t?.partitions||[];if(i.length<2)return 0;const s=ag(i,{pitch:Ph,seedIds:e,geometry:lg(t,{excludeDraftId:this._activeDraftId})});return s.merged?(t.partitions=s.partitions,rg(t.openings,t.partitions,s.openingMoves,{coordScale:ov,cellCm:this._cellCm,gridPitch:this._gridPitch}),s.merged):0}_finishWallChain(){if("draw"!==this._tool||this._wallFaceBatch||this._roomDialog)return!0;const t=this._curSpaceCfg;if(!t||this._path.length<2)return this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._clearPlanSnapHover(),!0;const e=hu(this._path,cu(this._path.length-1,this._draftSegmentCms,this._drawWallCm,ll)),i=e.length;if((t.partitions||[]).length+i>cv)return this._showToast(this._t("toast.physical_limit")),!1;const s=this._geometrySnapshot();t.partitions||=[];const n=Date.now().toString(36),o=[],a=this._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this._activeDraftId):null,r=this._draftSegmentsForPath(this._path,a,e.map(t=>t.cm));for(let s=0;st.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this._t("history.wall_chain_finish"),s),delete this._resumeDraftBySpace[this._space],this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._clearPlanSnapHover(),!0}_activateMarkupTool(t){t!==this._tool&&(this._wallFaceBatch&&this._roomDialogCancel(),("draw"!==this._tool||this._finishWallChain())&&(this._cancelPath(),this._tool=t,"draw"===t&&this._resumeLastDraft(),"resize"===t&&(this._rszSel=null),"boundary"!==t&&"wallthick"!==t||(this._wallDialog=null)))}_limitReached(t){const e=this._curSpaceCfg;if(!e)return!0;const i="draft"===t?(e.room_drafts||[]).length>=200:"partition"===t?(e.partitions||[]).length>=cv:(e.wall_columns||[]).length>=500;return i&&this._showToast(this._t("toast.physical_limit")),i}_svgPoint(t){const e=this.renderRoot.querySelector(".stage").getBoundingClientRect();return this._screenToVb(t.clientX-e.left,t.clientY-e.top)}_snap(t){const e=this._gridPitch;return[Ih(ri(t[0],e)),Ih(ri(t[1],e))]}_snapDrawPoint(t,e=!1){const i=this._path[this._path.length-1],s=e&&i?function(t,e,i,s=1/0){if(!(i>0&&t?.every(Number.isFinite)&&e?.every(Number.isFinite)))return[e[0],e[1]];const n=e[0]-t[0],o=e[1]-t[1];if(Math.abs(n)+Math.abs(o)<=1e-12)return[t[0],t[1]];const a=Math.PI/4;let r=Math.atan2(o,n);r<0&&(r+=2*Math.PI);const l=Math.floor(r/a+.5)%8,[c,h]=[[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1],[0,-1],[1,-1]][l],d=c*c+h*h;let p=Math.max(0,Math.round((n*c+o*h)/(i*d)));if(Number.isFinite(s)&&s>=0){const e=(t,e)=>{if(!e)return 1/0;const n=e>0?s-t:t+s;return Math.max(0,Math.floor((n+1e-9*i)/i))};p=Math.min(p,e(t[0],c),e(t[1],h))}return[t[0]+c*p*i,t[1]+h*p*i]}(i,t,this._gridPitch,Mh):t;return this._snap(s)}_planSnapOpeningCuts(t,e){if(!this._openingsR.length)return[];const i=this._openingWallIndexFor(t,e).value,s=[];for(const e of this._roomWallOpeningInputs(this._openingsR,t)){const t=Oc(i,e);if(!t.negative&&!t.positive)continue;const n=e.angle*Math.PI/180,o=Math.cos(n)*e.length/2,a=Math.sin(n)*e.length/2;s.push([e.x-o,e.y-a,e.x+o,e.y+a])}return s}_planSnapGeometrySnapshot(){const t=this._spaceModel();if(!t)return{key:`${this._space}|empty`,value:{segments:[],endpoints:[]}};const e=[this._space,this._cfgEpoch,this._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this._planSnapGeometryCache?.key===e)return this._planSnapGeometryCache;const i=this._openCuts(),s=eu({space:t,activeDraftId:this._activeDraftId,roomCuts:[...i,...this._planSnapOpeningCuts(t,i)],partitionCuts:this._partitionOpeningCuts(t),epsilon:2e-4*this._gridPitch});return this._planSnapGeometryCache={key:e,value:s},this._planSnapGeometryCache}_hiddenWallDiagnosticSnapshot(){const t=this._spaceModel();if(!t)return{key:`${this._space}|hidden-empty`,value:{segments:[],endpoints:[]}};const e=["hidden",this._space,this._cfgEpoch,this._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this._hiddenWallDiagnosticCache?.key===e)return this._hiddenWallDiagnosticCache;const i=tu({space:t,activeDraftId:this._activeDraftId,epsilon:2e-4*this._gridPitch});return this._hiddenWallDiagnosticCache={key:e,value:i},this._hiddenWallDiagnosticCache}_planStructuralGeometrySnapshot(){const t=this._spaceModel();if(!t)return{key:`${this._space}|structural-empty`,value:{segments:[],endpoints:[]}};const e=["structural",this._space,this._cfgEpoch,this._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this._planStructuralGeometryCache?.key===e)return this._planStructuralGeometryCache;const i=eu({space:t,activeDraftId:this._activeDraftId,roomCuts:this._openCuts(),epsilon:2e-4*this._gridPitch});return this._planStructuralGeometryCache={key:e,value:i},this._planStructuralGeometryCache}_planSnapContextKey(t){const e=this._path[0],i=this._path[this._path.length-1];return[t,this._tool,this._path.length,e?`${e[0]},${e[1]}`:"",i?`${i[0]},${i[1]}`:""].join("|")}_resolvePlanDrawPoint(t,e){const i=this._planSnapGeometrySnapshot(),s=this._path[this._path.length-1],n="draw"===this._tool&&this._path.length>=3?[{point:this._path[0],key:"closure:first-point"}]:[],o={tolerance:this._cssPxToRender(12),distinguishTolerance:this._cssPxToRender(8),gridStep:this._gridPitch,excludePoints:s?[s]:[],extraEndpoints:n,epsilon:2e-4*this._gridPitch},a=e&&s?ru(i.value,t,{...o,anchor:s}):function(t,e,i){if(!(Up(e)&&i.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const s=i.epsilon??Gp,n=i.excludePoints||[],o=ou(nu(t,e,i),i.distinguishTolerance||0);if(o)return o;let a=null;for(const o of t.segments){const t=[o.a[0],o.a[1],o.b[0],o.b[1]],r=Ls([e[0],e[1]],t);if(r>i.tolerance)continue;const l=au(o,e,i.gridStep);!iu(l,n,s)&&su(r,o.key,a)&&(a={kind:"line",point:l,key:o.key,distance:r,segment:o})}return a?{kind:"resolved",candidate:a,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}(i.value,t,o),r="resolved"===a.kind?a.candidate:null,l=r?[...r.point]:this._snapDrawPoint(t,e),c=s?ua(s,l):l;return{point:c,candidate:r&&fi(c,r.point)?r:null,conflicts:"ambiguous"===a.kind?a.conflicts:[],ambiguous:"ambiguous"===a.kind,contextKey:this._planSnapContextKey(i.key)}}get _activePlanSnapCandidate(){if(!this._markup||"draw"!==this._tool)return null;const t=this._planSnapHover;if(!t)return null;const e=this._planSnapGeometrySnapshot();return t.contextKey===this._planSnapContextKey(e.key)?t.candidate:null}get _activePlanSnapConflicts(){if(!this._markup||"draw"!==this._tool)return[];const t=this._planSnapHover;if(!t)return[];const e=this._planSnapGeometrySnapshot();return t.contextKey===this._planSnapContextKey(e.key)?t.conflicts:[]}_clearPlanSnapHover(t=!0){this._planSnapHover=null,this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers([]),t&&(this._cursorPt=null)}_samePt(t,e){return fi(t,e)}_dropLegacySegments(){for(const t of this._serverCfg?.markers||[])"ripple"===t.display&&(t.display="icon_ripple");for(const t of this._serverCfg?.spaces||[]){delete t.segments;const e=new Set,i=t=>"string"==typeof t&&t.length>=1&&t.length<=64&&!e.has(t),s=t=>(e.add(t),!0),n=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(Number(t))&&Math.abs(Number(t))<=Sh);if(Array.isArray(t.partitions)&&(t.partitions=t.partitions.filter(t=>t&&i(t.id)&&n(t.a)&&n(t.b)&&Math.hypot(t.a[0]-t.b[0],t.a[1]-t.b[1])>1e-9&&s(t.id)).map(t=>({...t,cm:Math.max(1,Math.min(100,Number(t.cm)||15))})),t.partitions.length||delete t.partitions),Array.isArray(t.wall_columns)&&(t.wall_columns=t.wall_columns.filter(t=>t&&i(t.id)&&n(t.center)&&s(t.id)).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[Number(t.center[0]),Number(t.center[1])],cm:Gc(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:Uc(t.angle)}})),t.wall_columns.length||delete t.wall_columns),Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t&&i(t.id)&&Array.isArray(t.points)&&t.points.length>=2&&t.points.every(n)&&s(t.id)).map(t=>{const e=Ng(t);return{id:t.id,...e}}).filter(t=>t.points.length>=2),t.room_drafts.length||delete t.room_drafts),Array.isArray(t.walls)){const e=pd(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]);t.walls=Tl(t.walls,t.rooms||[],Ph,1,e),t.walls.length||delete t.walls}}}_rollbackRejectedPhysicalWrites(t){if(!this._serverCfg||!t.length)return!1;let e=!1;for(const[i]of t){const t=this._pendingPhysicalWrites.get(i);t&&(e=this._restoreGeometryStateInConfig(this._serverCfg,t.before)||e,this._pendingPhysicalWrites.delete(i))}return!!e&&(this._clearGeometryGesture(),this._geometryHistory.clear(),this._cfgEpoch++,this._modelCache=null,this._wallUnionCache=null,this._physicalBodiesCache=null,this._frame=null,this._regSignature="",this._cfgContentFingerprint=Ad(this._serverCfg),this._maybeRebuildDevices(),this.requestUpdate(),!0)}async _reloadRejectedPhysicalWrite(){const t=this._writeChain;await t.catch(()=>{}),await this._reloadConfigOnly(!0)}get _cfgWriting(){return this._writesPending>0}_writeConfig(){var t,e;this._writesPending++,this._writeChain=(t=this._writeChain,e=async()=>{if(!this._serverCfg)return;this._dropLegacySegments();const t=rl(Ur(this._serverCfg)),e=Ad(t),i=[...this._pendingPhysicalWrites.entries()];for(const[e,s]of i){const i=hm(t.spaces.find(t=>t.id===e));if(i===s.fingerprint)continue;let n=!1;try{n=this._checkSpacePhysicalGeometry(t,e).ok}catch{n=!1}if(!n)throw this._restoreGeometryStateLocal(s.before),this._pendingPhysicalWrites.delete(e),this._geometryHistory.clear(),this._showToast(this._t("toast.geometry_unsafe")),Object.assign(new Error("unsafe wall geometry"),{code:"geometry-unsafe"});s.fingerprint=i}let s;e!==Ad(this._serverCfg)&&(this._serverCfg=t),this._cfgContentFingerprint=e;try{s=await this.hass.callWS({type:"houseplan/config/set",config:t,expected_rev:this._cfgRev})}catch(t){if(!this._rollbackRejectedPhysicalWrites(i))throw t;const e=t&&"object"==typeof t?t:Object.assign(new Error(String(t)),{cause:t});throw e.physicalGeometryRolledBack=!0,e}this._cfgRev=s?.rev??this._cfgRev+1;for(const[t,e]of i)this._pendingPhysicalWrites.get(t)?.fingerprint===e.fingerprint&&this._pendingPhysicalWrites.delete(t)},t.catch(()=>{}).then(e));return this._writeChain.finally(()=>{this._writesPending--})}_saveConfig(){this._cfgEpoch++,this._saveConfigDebounced()}_geometrySnapshotFromConfig(t,e){const i=t?.spaces?.find(t=>t.id===e);if(!i)return null;const s=t=>JSON.parse(JSON.stringify(t)),n={};for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==i[t]&&(n[t]=i[t]);return{spaceId:e,rooms:s(i.rooms||[]),...Array.isArray(i.openings)?{openings:s(i.openings)}:{},...Array.isArray(i.walls)?{walls:s(i.walls)}:{},...Array.isArray(i.wall_segments)?{wall_segments:s(i.wall_segments)}:{},...Array.isArray(i.open_spans)?{open_spans:s(i.open_spans)}:{},...Array.isArray(i.room_drafts)?{room_drafts:s(i.room_drafts)}:{},...Array.isArray(i.partitions)?{partitions:s(i.partitions)}:{},...Array.isArray(i.wall_columns)?{wall_columns:s(i.wall_columns)}:{},...Array.isArray(i.decor)?{decor:s(i.decor)}:{},plan_transform:n}}_geometrySnapshot(t=this._space){return this._geometrySnapshotFromConfig(this._serverCfg,t)}_recordGeometry(t,e){if(!e)return;const i=this._geometrySnapshot(e.spaceId);i&&JSON.stringify(e)!==JSON.stringify(i)&&(this._geometryHistory.push({name:t,before:e,after:i}),this.requestUpdate())}_restoreGeometryStateInConfig(t,e,i=!1){const s=t?.spaces?.find(t=>t.id===e.spaceId);if(!s)return!1;const n=t=>JSON.parse(JSON.stringify(t)),o=new Map((s.rooms||[]).map(t=>[t.id,t]));if(s.rooms=n(e.rooms),i)for(const t of s.rooms){const e=o.get(t.id);!Array.isArray(t.wall_ids)&&Array.isArray(e?.wall_ids)&&e.wall_ids.length===t.poly?.length&&(t.wall_ids=n(e.wall_ids))}const a=(t,e)=>{void 0!==e?s[t]=n(e):i&&"wall_segments"===t||delete s[t]},r=new Map((s.openings||[]).map(t=>[t.id,t])),l=new Map((s.room_drafts||[]).map(t=>[t.id,t]));if(a("openings",e.openings),a("walls",e.walls),a("wall_segments",e.wall_segments),a("open_spans",e.open_spans),a("room_drafts",e.room_drafts),a("partitions",e.partitions),a("wall_columns",e.wall_columns),a("decor",e.decor),i){for(const t of s.openings||[]){const e=r.get(t.id);t.host||"wall"!==e?.host?.kind||(t.host=n(e.host))}for(const t of s.room_drafts||[]){const e=l.get(t.id);for(let i=0;i<(t.segments||[]).length;i++)!t.segments[i]?.id&&e?.segments?.[i]?.id&&(t.segments[i].id=e.segments[i].id)}}for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete s[t];return Object.assign(s,n(e.plan_transform||{})),!0}_restoreGeometryStateLocal(t){return!!this._restoreGeometryStateInConfig(this._serverCfg,t)&&(this._cfgEpoch++,this._modelCache=null,this._wallUnionCache=null,this._physicalBodiesCache=null,this._frame=null,this.requestUpdate(),!0)}_wallModelBlockerLabel(t){const e=t instanceof Pg?t.reason:"invalid-room";return this._t(`wall_model.reason.${e}`)}_commitPhysicalGeometry(t,e,i=[]){if(!e||!this._serverCfg)return!1;const s=this._serverCfg,n=this._geometrySnapshotFromConfig(s,e.spaceId),o=s.spaces.find(t=>t.id===e.spaceId);if(!o||hm(e)===hm(o))return!1;let a,r=!1;try{r=this._checkSpacePhysicalGeometry(s,e.spaceId).ok}catch{r=!1}if(!r)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this._showToast(this._t("toast.geometry_unsafe")),!1;let l=e;try{if(Number(s.model_version||0)<8){const t=JSON.parse(JSON.stringify(s));if(!this._restoreGeometryStateInConfig(t,e))throw new Pg("invalid-room",e.spaceId);const i=Zg(t).config;l=this._geometrySnapshotFromConfig(i,e.spaceId)||e;const o=JSON.parse(JSON.stringify(i));if(!n||!this._restoreGeometryStateInConfig(o,n,!0))throw new Pg("invalid-room",e.spaceId);const r=i.spaces.find(t=>t.id===e.spaceId),c=o.spaces.find(t=>t.id===e.spaceId),h=((t,e,i)=>{const s=new Map,n=new Map((t?.rooms||[]).map(t=>[t.id,t])),o=new Map((e||[]).map(t=>[t.id,t])),{rooms:a}=Yg(i,Vg(t));for(const t of a){const e=o.get(t.id),a=n.get(t.id),r=hi(e),l=hi((i.rooms||[]).find(e=>e.id===t.id)),c=hi(a);if(r&&l&&c&&r.length===l.length&&c.length===a?.wall_ids?.length&&t.poly.length===t.wall_ids.length)for(let e=0;e{const n=[];for(let o=0;oDg||Hg(r,i,s)>Dg)continue;const l=Lg(a,i,s),c=Lg(r,i,s);l<-Dg||c>1+Dg||c<=l+Dg||n.push({start:l,id:e[o]})}return n.sort((t,e)=>t.start-e.start)},n=i(c,a.wall_ids,r[e],r[(e+1)%r.length]),o=i(t.poly,t.wall_ids,l[e],l[(e+1)%l.length]);if(n.length&&n.length===o.length)for(let t=0;tt.id===e.spaceId),s=this._path.length>=2?this._path.map(t=>[t[0]/ov,t[1]/ov]):[];s.push(...i.map(t=>[t[0],t[1]])),c=Og(t)<=Og(l,s)&&this._checkSpacePhysicalGeometry(a,e.spaceId).ok}catch{c=!1}if(!c)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this._showToast(this._t("toast.geometry_unsafe")),!1;tm(s,a),this._recordGeometry(t,l);const h=s.spaces.find(t=>t.id===e.spaceId),d=this._pendingPhysicalWrites.get(e.spaceId);return this._pendingPhysicalWrites.set(e.spaceId,{before:d?.before||l,fingerprint:hm(h)}),this._saveConfig(),!0}_clearGeometryGesture(){this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!1),this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._roomDeleteDialog=null,this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._wallDialog=null,this._physicalDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._openingDialog=null,this._rszSel=null,this._rszDrag=null,this._rszPreview=null,this._rszLive=null,this._decorDraft=null,this._decorMove=null,this._dtDrag=null,this._bdDrag=null}_cancelBoundaryAnchor(){return!("boundary"!==this._tool||!this._openWallAnchor)&&(this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._clearPlanSnapHover(),this.requestUpdate(),!0)}_stagePointerCancel(t){if(clearTimeout(this._kioskHoldTimer),this._swipeStart?.id===t.pointerId&&(this._swipeStart=null),this._physicalDrag?.pid===t.pointerId||this._physicalRotate?.pid===t.pointerId)return void this._cancelPhysicalGesture();if(this._decorDraft?.pid===t.pointerId)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove?.pid===t.pointerId||this._dtDrag?.pid===t.pointerId||this._bdDrag?.pid===t.pointerId)return void this._cancelDecorGesture();this._cancelBoundaryAnchor(),"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const e=!!this._pinchStart||!!this._panStart;this._pointers.delete(t.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null),e&&0===this._pointers.size&&this.requestUpdate()}_applyGeometryState(t,e=!1){if(!this._canCommitSpace(t.spaceId))return!1;const i=this._geometrySnapshot(t.spaceId);if(!i||!this._restoreGeometryStateLocal(t))return!1;const s=this._serverCfg,n=hm(i)!==hm(t);if(n){let n=!1;try{const i=s?this._checkSpacePhysicalGeometry(s,t.spaceId):null;n=!!i?.ok||!(!e||"wall-degraded-extra"!==i?.reason)}catch{n=!1}if(!n)return this._restoreGeometryStateLocal(i),this._showToast(this._t("toast.geometry_unsafe")),!1}let o;try{o=Zg(s).config}catch(t){return this._restoreGeometryStateLocal(i),this._showToast(this._t("toast.wall_model_migration_blocked",{reason:this._wallModelBlockerLabel(t)})),!1}if(n){let n=!1;try{const i=o?this._checkSpacePhysicalGeometry(o,t.spaceId):null;n=!!i?.ok||!(!e||"wall-degraded-extra"!==i?.reason)}catch{n=!1}if(!n)return this._restoreGeometryStateLocal(i),this._showToast(this._t("toast.geometry_unsafe")),!1;tm(s,o);const a=s?.spaces.find(e=>e.id===t.spaceId),r=this._pendingPhysicalWrites.get(t.spaceId);this._pendingPhysicalWrites.set(t.spaceId,{before:r?.before||i,fingerprint:hm(a)})}else tm(s,o);return this._clearGeometryGesture(),this._space!==t.spaceId&&(this._commitSpace(t.spaceId),this._saveNav(),this._restoreZoom()),this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate(),!0}_roomAt(t){return this._spaceModel()?.rooms.find(e=>{const i=hi(e);return!!i&&wi(t,i)})}_overlapRoom(t){return this._spaceModel()?.rooms.find(e=>{const i=hi(e);return!!i&&Di(t,i)})}_pointInRoom(t,e){return e.poly?vi(t,e.poly):null!=e.x&&t[0]>=e.x&&t[0]<=e.x+e.w&&t[1]>=e.y&&t[1]<=e.y+e.h}_contourSelfIntersects(t){if(!Ia(t))return!0;const e=t.length,i=.001;for(let s=0;s=500)return this._showToast(this._t("toast.physical_limit")),!1;const t=this._curSpaceCfg;return!(!this._activeDraftId&&(t?.room_drafts||[]).length>=200||this._draftSegmentCount(t)>=2e3||(t?.partitions||[]).length+this._path.length>cv)||(this._showToast(this._t("toast.physical_limit")),!1)}_markupClick(t){if(this._vacFit)return;if(!this._markup)return;const e=this._spaceModel();if(!e)return void this._clearGeometryGesture();if(this._suppressClick)return;if(this._drag||this._rlResize)return;const i=t.composedPath?.()||[];if(i.some(t=>t?.classList?.contains?.("roomlabel")||t?.classList?.contains?.("rlhandle")))return;if(i.some(t=>t?.classList?.contains?.("physical-hit")))return void("boundary"===this._tool&&this._showToast(this._t("toast.boundary_blocked")));const s=this._svgPoint(t);if("select"===this._tool)return void(this._physicalSel=null);if("resize"===this._tool){if(this._rszDrag||i.some(t=>t?.classList?.contains?.("rszhandle")))return;const t=[...e.rooms].reverse().find(t=>this._pointInRoom(s,t));return void(this._rszSel=t?.id||null)}if("delroom"===this._tool)return void this._deleteRoomClick(s);if("opening"===this._tool)return void this._openingClick(s);if("merge"===this._tool)return void this._mergeClick(s);if("wallthick"===this._tool)return void this._wallThickClick(s);if("boundary"===this._tool)return void this._boundaryClick(s);if("split"===this._tool)return void this._splitClick(s);if("column"===this._tool)return void this._columnClick(s);this._wallRepairDiagnostic=null;const n=this._resolvePlanDrawPoint(s,t.shiftKey);if(n.ambiguous)return this._planSnapHover={contextKey:n.contextKey,candidate:null,conflicts:n.conflicts},this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers(n.conflicts),void this._showToast(this._t("toast.plan_snap_ambiguous"));let o=n.point;if(t.ctrlKey||t.metaKey){if(t.preventDefault(),this._path.length<3)return;o=ua(this._path[this._path.length-1],this._path[0])}if(!this._path.length){if(!t.shiftKey&&!n.candidate&&this._offerExistingWallFace(s))return;const e=this._draftEndAt(o);return e?(this._activeDraftId=e.draft.id,this._resumeDraftBySpace[this._space]=e.draft.id,this._path=e.reverse?[...e.draft.points].reverse().map(t=>[...t]):e.draft.points.map(t=>[...t]),void(this._draftSegmentCms=this._adoptDraftCms(this._path,e.reverse?[...e.draft.segments].reverse().map(t=>t.cm):e.draft.segments.map(t=>t.cm),e.draft.id))):(this._activeDraftId=null,this._draftSegmentCms=[],void(this._path=[o]))}const a=this._path[this._path.length-1];if(this._samePt(o,a))return;const r=this._draftEndAt(o,this._activeDraftId||void 0);if(r)return void this._mergeDraftEndpoint(r);if(!this._canAppendRoomDraftPoint())return;const l=this._drawWallCm;if(null==l)return void this._showPhysicalRange(100);const c=this._path.map(t=>[...t]);this._path=[...this._path,o],this._draftSegmentCms=[...this._draftSegmentCms,l],this._persistActiveDraftSegment(),this._offerWallFaces(c)}_draftEndAt(t,e){const i=this._spaceModel();if(!i)return null;const s=this._viewOr(this._baseVb()),n=Math.max(.15*this._gridPitch,this._stageEl?.clientWidth?s.w/this._stageEl.clientWidth*12:0);for(const s of i.room_drafts||[]){if(s.id===e)continue;if(s.points.length<2)continue;const i=s.points[0],o=s.points[s.points.length-1];if(Math.hypot(t[0]-o[0],t[1]-o[1])<=n)return{draft:s,reverse:!1};if(Math.hypot(t[0]-i[0],t[1]-i[1])<=n)return{draft:s,reverse:!0}}return null}_mergeDraftEndpoint(t){const e=this._curSpaceCfg;if(!e||!this._path.length)return;const i=this._path.map(t=>[...t]),s=this._wallGraphSources(i),n=Array.isArray(e.room_drafts)?e.room_drafts:[],o=this._activeDraftId?n.find(t=>t.id===this._activeDraftId):null,a=n.find(e=>e.id===t.draft.id);if(!a)return;const r=t.reverse?t.draft.points.map(t=>[...t]):[...t.draft.points].reverse().map(t=>[...t]),l=t.reverse?(a.segments||[]).map(t=>({...t})):[...a.segments||[]].reverse().map(t=>({...t})),c=this._path[this._path.length-1],h=this._samePt(c,r[0]),d=h?null:this._drawWallCm;if(!h&&null==d)return void this._showPhysicalRange(100);const p=this._draftSegmentsForPath(this._path,o,this._draftSegmentCms),u=[...this._path.map(t=>[...t]),...h?r.slice(1):r],_=[...p,...null==d?[]:[{cm:d}],...l],g=u.length>=4&&this._samePt(u[0],u[u.length-1]),m=u,f=_;if(m.length>500)return void this._showToast(this._t("toast.physical_limit"));const v=(o?.segments?.length||0)+(a.segments?.length||0);if(this._draftSegmentCount(e)-v+f.length>2e3)return void this._showToast(this._t("toast.physical_limit"));if(g){const t=m.slice(0,-1);if(this._contourSelfIntersects(t)||Ti(t)<=1e-6)return void this._showToast(this._t("toast.contour_cannot_close"));const e=this._overlapRoom(t);if(e)return void this._showToast(this._t("toast.room_overlap",{name:e.name||""}))}const y=this._geometrySnapshot(),b=this._activeDraftId||t.draft.id,w={...o||a,id:b,points:m.map(t=>[t[0]/ov,t[1]/ov]),segments:f};e.room_drafts=n.filter(e=>e.id!==t.draft.id&&(!this._activeDraftId||e.id!==this._activeDraftId)),e.room_drafts.push(w),this._activeDraftId=b,this._resumeDraftBySpace[this._space]=b,this._path=m,this._draftSegmentCms=this._adoptDraftCms(m,f.map(t=>Number(t.cm)),b),this._physicalSel=null,this._commitPhysicalGeometry(this._t("history.draft_merge"),y),null!=d&&this._offerWallFaces(i,i.length-1,s)}_adoptDraftCms(t,e,i){const s=Math.max(0,t.length-1),n=cu(s,e,this._drawWallCm,ll);return e.length!==s&&console.debug(`[houseplan] draft ${i??"?"}: восстановлено толщин ${s-e.length} (#234)`),n}_draftSegmentsForPath(t,e,i){const s=Array.isArray(e?.points)?e.points.map(t=>[Number(t?.[0])*ov,Number(t?.[1])*ov]):[],n=Array.isArray(e?.segments)?e.segments:[];return cu(Math.max(0,t.length-1),i,this._drawWallCm,ll).map((e,i)=>{const o=t[i],a=t[i+1],r=s.findIndex((t,e)=>{if(e+1>=s.length)return!1;const i=s[e+1];return this._samePt(o,t)&&this._samePt(a,i)||this._samePt(o,i)&&this._samePt(a,t)});return{...r>=0?n[r]:{},cm:e}})}_persistActiveDraftSegment(){if(this._path.length<2||!this._curSpaceCfg)return;const t=this._geometrySnapshot(),e=this._curSpaceCfg;e.room_drafts||=[],this._activeDraftId||(this._activeDraftId="draft-"+Date.now().toString(36)),this._resumeDraftBySpace[this._space]=this._activeDraftId;const i=e.room_drafts.findIndex(t=>t.id===this._activeDraftId),s={...i>=0?e.room_drafts[i]:{},id:this._activeDraftId,points:this._path.map(t=>[t[0]/ov,t[1]/ov]),segments:this._draftSegmentsForPath(this._path,i>=0?e.room_drafts[i]:null,this._draftSegmentCms)};i>=0?e.room_drafts[i]=s:e.room_drafts.push(s),this._commitPhysicalGeometry(this._t("history.draft_segment"),t)}_activeWallSourceKey(t){return`active:${this._activeDraftId||"session"}:${t}`}_wallGraphSources(t){const e=this._planStructuralGeometrySnapshot().value.segments.map(t=>({a:t.a,b:t.b,key:`static:${t.key}`}));for(let i=0;i+1t.key===i);if(s>=0){const[t]=this._wallFaceGraphCache.splice(s,1);return this._wallFaceGraphCache.push(t),t.value}const n=Iu(t,e);return this._wallFaceGraphCache.push({key:i,value:n}),this._wallFaceGraphCache.length>4&&this._wallFaceGraphCache.shift(),n}_offerWallFaces(t,e=this._path.length-2,i){if(this._path.length<2||this._wallFaceBatch||this._roomDialog)return;const s=this._spaceModel();if(!s)return;const n=this._activeWallSourceKey(e),o=2e-4*this._gridPitch;let a,r;try{const e=i||this._wallGraphSources(t);r=this._wallGraphSources(this._path),a=function(t,e,i){const s=new Set(t.faces.map(t=>t.key));return e.faces.filter(t=>!s.has(t.key)&&t.sourceKeys.includes(i))}(this._wallFaceGraph(e,o),this._wallFaceGraph(r,o),n)}catch{return}if(!a.length){const t=ju(r,{requiredSourceKey:n,maxDistance:ml(2,this._cellCm,this._gridPitch),gridStep:this._gridPitch,epsilon:o});return"ambiguous"===t.kind?(this._wallRepairDiagnostic=t.proposals[0]||null,void this._showToast(this._t("toast.wall_repair_ambiguous"))):void("repair"!==t.kind||this._overlapRoom(t.face.ring)||this._beginWallFaceBatch([{...t.face,repair:t.proposal}]))}for(const t of s.rooms){const e=hi(t);if(!t.id||!e)continue;const i=zi(e,this._path,.02*this._gridPitch);if(!i)continue;const[s,n]=i,o=Ti(s)>=Ti(n)?s:n,r=o===s?n:s,l=[...a].sort((t,e)=>Math.abs(t.area-Ti(r))-Math.abs(e.area-Ti(r))||t.key.localeCompare(e.key))[0];if(!l)return;return void this._beginWallFaceBatch([{...l,ring:r.map(t=>[t[0],t[1]]),split:{roomId:t.id,mainPoly:o,newPoly:r},consumeAllActive:!0}])}const l=a.filter(t=>!(t.ring.length<3||this._contourSelfIntersects(t.ring))&&!this._overlapRoom(t.ring));l.length&&this._beginWallFaceBatch(l)}_beginWallFaceBatch(t){this._wallRepairDiagnostic=null,this._wallFaceBatch={candidates:[...t].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key)),index:0,decisions:[],activePath:this._path.map(t=>[...t]),activeCms:[...this._draftSegmentCms],activeDraftId:this._activeDraftId},this._clearPlanSnapHover(),this._nameSel="",this._areaSel="",this._resetRoomDialogFields(),this._roomDialog=!0}_offerExistingWallFace(t){if(this._path.length||this._wallFaceBatch||this._roomDialog)return!1;const e=2e-4*this._gridPitch;try{let i,s=Au(this._wallFaceGraph(this._wallGraphSources([]),e),t,e);if(!s){const n=ju(this._wallGraphSources([]),{point:t,maxDistance:ml(2,this._cellCm,this._gridPitch),gridStep:this._gridPitch,epsilon:e});if("ambiguous"===n.kind)return this._wallRepairDiagnostic=n.proposals[0]||null,this._showToast(this._t("toast.wall_repair_ambiguous")),!0;if("repair"===n.kind)s=n.face,i=n.proposal;else if("none"===n.kind){const i=ju(this._wallGraphSources([]),{point:t,maxDistance:this._cssPxToRender(12),gridStep:this._gridPitch,epsilon:e});if("repair"===i.kind)return this._wallRepairDiagnostic=i.proposal,this._showToast(this._t("toast.wall_repair_too_large")),!0}}return!(!s||s.ring.length<3||this._contourSelfIntersects(s.ring)||this._overlapRoom(s.ring))&&(this._beginWallFaceBatch([{...s,existing:!i,repair:i}]),!0)}catch{return!1}}_columnClick(t){const e=this._snap(t),i=this._drawWallCm;if(null==i)return void this._showPhysicalRange(Wc);if(!this._curSpaceCfg||this._limitReached("column"))return;const s=this._spaceModel();if(!s)return;const n={id:"column-"+Date.now().toString(36),shape:"square",center:e,cm:Gc(i),angle:0},o=(s.wall_columns||[]).find(t=>ph(t,n,.02*this._gridPitch));if(o)return clearTimeout(this._duplicateColumnTimer),this._duplicateColumnId=o.id,this._duplicateColumnTimer=window.setTimeout(()=>{this._duplicateColumnId=null},900),void this._showToast(this._t("toast.column_duplicate"));const a=this._geometrySnapshot(),r=this._curSpaceCfg;r.wall_columns||=[],r.wall_columns.push({...n,center:[e[0]/ov,e[1]/ov]}),this._commitPhysicalGeometry(this._t("history.column_add"),a)}_openPhysicalDialog(t,e,i){const s=this._spaceModel();if(s)if("partition"===t){const i=s.partitions.find(t=>t.id===e);i&&(this._physicalDialog={kind:t,id:e,cm:gl(i.cm,this._imperial),length:this._fmtLen(i.a,i.b)})}else if("column"===t){const i=s.wall_columns.find(t=>t.id===e);i&&(this._physicalDialog={kind:t,id:e,cm:gl(i.cm,this._imperial),shape:i.shape,angle:this._angleField("square"===i.shape?Uc(i.angle):0)})}else{const n=s.room_drafts.find(t=>t.id===e),o=Math.max(0,Math.min(n?.segments.length?n.segments.length-1:0,i||0));n?.segments[o]&&(this._physicalDialog={kind:t,id:e,segment:o,cm:gl(n.segments[o].cm,this._imperial),length:this._fmtLen(n.points[o],n.points[o+1])})}}_physicalDown(t,e,i){const s=this._spaceModel();if(!s)return;t.stopPropagation(),uv(t);const n=this._svgPoint(t),o=[];for(const t of[...s.wall_columns].reverse())hh(n,Zc(t,this._cellCm,this._gridPitch))&&o.push({kind:"column",id:t.id});for(const t of[...s.partitions].reverse()){const e=Xc(t.a,t.b,t.cm,this._cellCm,this._gridPitch);e&&hh(n,e)&&o.push({kind:"partition",id:t.id})}o.some(t=>t.kind===e&&t.id===i)||o.unshift({kind:e,id:i});const a=o.map(t=>`${t.kind}:${t.id}`).sort().join("|"),r=performance.now(),l=this._physicalPickCycle,c=o.length>1&&l?.signature===a&&r-l.at>380&&r-l.at<=1200&&Math.hypot(t.clientX-l.x,t.clientY-l.y)<=10?(l.index+1)%o.length:Math.max(0,o.findIndex(t=>t.kind===e&&t.id===i));this._physicalPickCycle={signature:a,index:c,x:t.clientX,y:t.clientY,at:r},e=o[c].kind,i=o[c].id;const h="partition"===e?s.partitions.find(t=>t.id===i):s.wall_columns.find(t=>t.id===i);h&&(this._physicalSel={kind:e,id:i},this._physicalDrag={pid:t.pointerId,kind:e,id:i,start:this._svgPoint(t),startClient:[t.clientX,t.clientY],before:this._geometrySnapshot(),moved:!1,base:JSON.parse(JSON.stringify(h)),delta:[0,0]})}_clampPhysicalDelta(t,e,i){const s="partition"===t?[e.a,e.b]:[e.center],n=s.map(t=>t[0]),o=s.map(t=>t[1]);return[Math.max(-Sh*ov-Math.min(...n),Math.min(Sh*ov-Math.max(...n),i[0])),Math.max(-Sh*ov-Math.min(...o),Math.min(Sh*ov-Math.max(...o),i[1]))]}_physicalMove(t){const e=this._physicalDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._svgPoint(t),s="partition"===e.kind?e.base.a:e.base.center,n=this._snap([s[0]+i[0]-e.start[0],s[1]+i[1]-e.start[1]]),o=this._clampPhysicalDelta(e.kind,e.base,[n[0]-s[0],n[1]-s[1]]);this._physicalDrag={...e,delta:o,moved:e.moved||Math.hypot(t.clientX-e.startClient[0],t.clientY-e.startClient[1])>=5}}_physicalUp(t){const e=this._physicalDrag;if(!e||e.pid!==t.pointerId)return;if(t.stopPropagation(),this._physicalDrag=null,!e.moved)return void this._registerPhysicalTap(e.kind,e.id);const i=this._spaceModel();if(!this._curSpaceCfg||!i)return;const s=this._curSpaceCfg;if("partition"===e.kind){const t=(s.partitions||[]).find(t=>t.id===e.id),i=e.base;if(t){const n={...i,a:[i.a[0]+e.delta[0],i.a[1]+e.delta[1]],b:[i.b[0]+e.delta[0],i.b[1]+e.delta[1]]};t.a=[n.a[0]/ov,n.a[1]/ov],t.b=[n.b[0]/ov,n.b[1]/ov];for(const t of s.openings||[]){if("partition"!==t.host?.kind||t.host.id!==e.id)continue;const i=Np(t,[n],ov,this._cellCm,this._gridPitch).resolved;i&&Object.assign(t,jp(t,i,ov))}}}else{const t=(s.wall_columns||[]).find(t=>t.id===e.id),n=e.base,o={...n,center:[n.center[0]+e.delta[0],n.center[1]+e.delta[1]]};if(i.wall_columns.some(t=>t.id!==e.id&&ph(t,o,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"));t&&(t.center=[(n.center[0]+e.delta[0])/ov,(n.center[1]+e.delta[1])/ov])}this._commitPhysicalGeometry(this._t("history.physical_move"),e.before)}_registerPhysicalTap(t,e,i){const s=performance.now(),n=this._physicalLastTap?.kind===t&&this._physicalLastTap.id===e&&this._physicalLastTap.segment===i&&s-this._physicalLastTap.at<=360;this._physicalLastTap={kind:t,id:e,segment:i,at:s},n&&(this._physicalLastTap=null,this._openPhysicalDialog(t,e,i))}_cancelPhysicalGesture(){this._physicalDrag=null,this._physicalRotate=null,this.requestUpdate()}_physicalRotateDown(t,e){if("square"!==e.shape||!this._spaceModel())return;t.preventDefault(),t.stopPropagation(),uv(t);const i=this._svgPoint(t);this._physicalSel={kind:"column",id:e.id},this._physicalRotate={pid:t.pointerId,id:e.id,center:[...e.center],startAngle:180*Math.atan2(i[1]-e.center[1],i[0]-e.center[0])/Math.PI,baseAngle:Uc(e.angle),angle:Uc(e.angle),before:this._geometrySnapshot(),moved:!1}}_physicalRotateMove(t){const e=this._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation();const i=this._svgPoint(t),s=180*Math.atan2(i[1]-e.center[1],i[0]-e.center[0])/Math.PI,n=e.baseAngle+s-e.startAngle,o=Uc(t.shiftKey?n:5*Math.round(n/5));this._physicalRotate={...e,angle:o,moved:e.moved||Math.abs(n-e.baseAngle)>=.5}}_physicalRotateUp(t){const e=this._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation(),this._physicalRotate=null;const i=this._spaceModel();if(!e.moved||!this._curSpaceCfg||!i)return;const s=i.wall_columns.find(t=>t.id===e.id);if(!s||"square"!==s.shape)return;const n={...s,angle:e.angle};if(i.wall_columns.some(t=>t.id!==e.id&&ph(t,n,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"));const o=this._curSpaceCfg.wall_columns?.find(t=>t.id===e.id);o&&(o.angle=e.angle,this._commitPhysicalGeometry(this._t("history.physical_edit"),e.before))}_rszRooms(){const t=[],e=this._spaceModel();if(!e)return t;for(const i of e.rooms){const e=i.id?hi(i):null;e&&t.push({id:i.id,poly:e,wall_ids:Array.isArray(i.wall_ids)?[...i.wall_ids]:void 0})}return i=t,s=Math.max(1e-12,1e-12*this._gridPitch),i.map(t=>{if(!Array.isArray(t.wall_ids)||t.wall_ids.length!==t.poly.length)return{...t,poly:t.poly.map(t=>[...t])};const e=t.poly.map(t=>[...t]);let i=!0;for(;i&&e.length>3;){i=!1;for(let t=0;t0){e.splice(t,1),i=!0;break}}}return{...t,poly:e}});var i,s}_rszOpenings(){return this._openingsR.map(t=>({id:t.id,x:t.rx,y:t.ry,length:t.rlen,hosted:!!t.host,angle:t.angle,type:t.type}))}_rszObstacles(){const t=this._spaceModel();if(!t)return[];const e=[];for(const i of t.partitions||[])e.push({kind:"segment",a:[...i.a],b:[...i.b],half:ml(i.cm,this._cellCm,this._gridPitch)/2});for(const i of t.room_drafts||[])for(let t=0;t+1Array.isArray(t.a)&&Array.isArray(t.b)&&t.a.length>=2&&t.b.length>=2).map(t=>({wall:t,a:[t.a[0]*ov,t.a[1]*this._spaceH],b:[t.b[0]*ov,t.b[1]*this._spaceH]})),n=Math.abs(t[0]-e[0])<=.05*this._gridPitch?"v":Math.abs(t[1]-e[1])<=.05*this._gridPitch?"h":null,o=s.filter(i=>!!n&&("h"===n?!(Math.abs(i.a[1]-t[1])>.05*this._gridPitch||Math.abs(i.b[1]-t[1])>.05*this._gridPitch)&&Math.min(Math.max(t[0],e[0]),Math.max(i.a[0],i.b[0]))-Math.max(Math.min(t[0],e[0]),Math.min(i.a[0],i.b[0]))>.05*this._gridPitch:!(Math.abs(i.a[0]-t[0])>.05*this._gridPitch||Math.abs(i.b[0]-t[0])>.05*this._gridPitch)&&Math.min(Math.max(t[1],e[1]),Math.max(i.a[1],i.b[1]))-Math.max(Math.min(t[1],e[1]),Math.min(i.a[1],i.b[1]))>.05*this._gridPitch)),a=new Set(o.map(t=>Number(t.wall.cm)).filter(t=>t>0));return{minDim:this._cmToUnits(30),eps:.05*this._gridPitch,step:this._gridPitch,movingHalf:i>0?ml(i,this._cellCm,this._gridPitch)/2:0,obstacles:this._rszObstacles(),thicknessConflict:a.size>1}}_rszResolution(t,e,i){const s=this._rszDrag?.snap||i||this._rszSnapshot(),n=`${this._space}|${this._cellCm}|${this._gridPitch}|${s}`;this._rszEligibilityCache&&this._rszEligibilityCache.key===n||(this._rszEligibilityCache={key:n,values:new Map});const o=`${t}:${e}`,a=this._rszEligibilityCache.values.get(o);if(a)return a;const r=this._rszDrag?.rooms||this._rszRooms(),l=r.find(e=>e.id===t),c=l?.poly?.[e]||[0,0],h=l?.poly?.[(e+1)%(l?.poly?.length||1)]||[0,0],d=function(t,e,i,s,n){const{eps:o}=n,a=t.find(t=>t.id===i);if(!a||s<0||s>=(a.poly?.length||0)||a.poly.length<4||!Ia(a.poly))return{enabled:!1,reason:"invalid-geometry"};const r=a.poly[s],l=a.poly[(s+1)%a.poly.length],c=Ea(r,l,o);if(!c)return{enabled:!1,reason:"diagonal"};if(!Ha(a.poly,s,c,o))return{enabled:!1,reason:"side-angle"};if(n.thicknessConflict)return{enabled:!1,reason:"thickness-conflict"};for(const t of n.obstacles||[])if(Wa(t,r,l,n))return{enabled:!1,reason:"duplicate-physical-wall"};const h=Da(Sa(l,r)),d=[],p=new Set;let u=!1,_=!1;for(const e of t)if(e.id!==i)for(let t=0;t1||d.length>1)return{enabled:!1,reason:"multiple-rooms"};const g={[i]:s},m=[i];if(1===d.length){const t=d[0];if(!Ia(t.room.poly))return{enabled:!1,reason:"invalid-geometry"};if(!Ha(t.room.poly,t.edge,c,o))return{enabled:!1,reason:"side-angle"};m.push(t.room.id),g[t.room.id]=t.edge}const f=[];for(const t of e)if(!(Ta([t.x,t.y],r,l)>2*o)){if(t.hosted||t.length>h+2*o)return{enabled:!1,reason:"opening-conflict"};f.push(t.id)}const v=Object.fromEntries(m.map(e=>[e,t.find(t=>t.id===e).poly.length])),y=[];for(const e of m){const i=t.find(t=>t.id===e),s=g[e],n=(s-1+i.poly.length)%i.poly.length,a=(s+1)%i.poly.length,r=Ua(t,e,n,1,o),l=Ua(t,e,a,0,o);if(!r||!l)return{enabled:!1,reason:"partial-shared"};y.push(r,l)}const b={roomId:i,edge:s,a:[...r],b:[...l],n:Ra(a.poly,s),roomIds:m,edgeByRoom:g,topology:v,movingOpeningIds:f,sideOwnership:y};if(!Qa(t,e,b,0,n))return{enabled:!1,reason:"invalid-geometry"};const w=Math.abs(Number(n.step));if(Number.isFinite(w)&&w>o){const i=[-w,w];if(!i.some(i=>Qa(t,e,b,i,n))){if(!i.some(i=>Ya(Ja(t,e,b,i),b,o)))return{enabled:!1,reason:"partial-shared"};const s={...n,obstacles:[]};return i.some(i=>Qa(t,e,b,i,s))?{enabled:!1,reason:"duplicate-physical-wall"}:e.length&&i.some(e=>Qa(t,[],b,e,n))?{enabled:!1,reason:"opening-conflict"}:{enabled:!1,reason:"invalid-geometry"}}}return{enabled:!0,plan:b}}(r,this._rszDrag?.openings||this._rszOpenings(),t,e,this._rszOptsFor(c,h));return this._rszEligibilityCache.values.set(o,d),d}_rszSnapshot(){return JSON.stringify(this._geometrySnapshot()||{spaceId:this._space,rooms:[],openings:[],walls:[],open_spans:[]})}_rszApplyPreview(t,e){const i=this._rszDrag,s=this._serverCfg?.spaces.find(t=>t.id===this._space);if(!i||!s||!this._serverCfg)return{ok:!1,reason:"missing-context"};const n=JSON.parse(i.snap),o={...s,rooms:n.rooms,openings:n.openings||[]};for(const t of["walls","open_spans","room_drafts","partitions","wall_columns","decor"])void 0!==n[t]?o[t]=n[t]:delete o[t];for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==n.plan_transform?.[t]?o[t]=n.plan_transform[t]:delete o[t];const a=this._spaceH;for(const[e,i]of Object.entries(t)){const t=o.rooms.find(t=>t.id===e);t&&(t.poly=i.map(t=>[t[0]/ov,t[1]/a]),delete t.x,delete t.y,delete t.w,delete t.h)}for(const[t,i]of Object.entries(e)){const e=(o.openings||[]).find(e=>e.id===t);e&&(e.x=i[0]/ov,e.y=i[1]/a)}const r=[],l=[];for(const t of i.changed){const e=i.rooms.find(e=>e.id===t),s=o.rooms.find(e=>e.id===t);if(!e||!s?.poly)continue;const n=s.poly.map(t=>[t[0]*ov,t[1]*a]);if(e.poly.length===n.length)for(let t=0;t{a=!0});return{walls:a?(t||[]).map(t=>({...t})):r,rejected:a}}(o.walls,r,l,this._wallKeyPitch,ov,"fixed-topology");if(t.rejected)return{ok:!1,reason:"wall-metadata"};o.walls=t.walls}}const c=t=>t.map(t=>Number(t.cm)).sort((t,e)=>t-e),h=c(n.walls||[]),d=c(o.walls||[]);if(JSON.stringify(h)!==JSON.stringify(d))return{ok:!1,reason:"wall-metadata"};if((n.open_spans||[]).length!==(o.open_spans||[]).length)return{ok:!1,reason:"open-span-metadata"};const p=[];for(const t of o.rooms||[]){const e=hi(t);if(e&&!(e.length<2))for(let t=0;tJSON.stringify([t?.key,t?.cm,t?.a,t?.b]),_=new Map;for(const t of n.walls||[]){const e=u(t);_.set(e,(_.get(e)||0)+1)}const g=[];for(const t of o.walls||[]){const e=u(t),i=_.get(e)||0;i?_.set(e,i-1):g.push(t)}return zl(g,p,this._wallKeyPitch,ov,n.walls||[]).length?{ok:!1,reason:"wall-metadata"}:this._rszSpaceCandidateRenderable(this._space,o)?(this._rszPreview={space:this._space,sp:o},this._cfgEpoch++,{ok:!0}):{ok:!1,reason:"physical-geometry"}}_rszSpaceCandidateRenderable(t,e){if(!this._serverCfg)return!1;try{const i={...this._serverCfg,spaces:this._serverCfg.spaces.map(i=>i.id===t?e:i)};return this._checkSpacePhysicalGeometry(i,t).ok}catch{return!1}}_rszCandidateRenderable(t){return!!t&&t.space===this._space&&this._rszPreview===t&&this._rszSpaceCandidateRenderable(t.space,t.sp)}_rszEdgeDown(t,e,i){if("resize"!==this._tool||this._rszDrag)return;t.stopPropagation(),t.preventDefault();const s=this._rszRooms(),n=this._rszResolution(e,i);if(!n.enabled)return void this._showToast(this._rszReasonText(n.reason));uv(t);const o=n.plan,a=this._svgPoint(t);this._rszDrag={pid:t.pointerId,start:[a[0],a[1]],roomId:e,plan:o,opts:this._rszOptsFor(o.a,o.b),rooms:s,openings:this._rszOpenings(),snap:this._rszSnapshot(),moved:!1,d:0,changed:[...o.roomIds],rejectNotified:!1}}_rszReasonText(t){return this._t(`resize.disabled.${t}`)}_rszDisabledActivate(t,e){t.stopPropagation(),t.preventDefault(),this._showToast(this._rszReasonText(e))}_rszDisabledKey(t,e){"Enter"!==t.key&&" "!==t.key||this._rszDisabledActivate(t,e)}_rszMove(t){const e=this._rszDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._svgPoint(t),s=e.plan,n=(o=e.start,a=i,r=s.n,[o?.[0],o?.[1],a?.[0],a?.[1],r?.[0],r?.[1]].every(Number.isFinite)?(a[0]-o[0])*r[0]+(a[1]-o[1])*r[1]:0);var o,a,r;const l=this._snap([s.a[0]+s.n[0]*n,s.a[1]+s.n[1]*n]),c=(l[0]-s.a[0])*s.n[0]+(l[1]-s.a[1])*s.n[1];let h=function(t,e,i,s,n,o){if(!Number.isFinite(s)||Math.abs(s)<1e-9)return 0;const a=Math.sign(s),r=Math.abs(s),l=Math.max(Math.abs(n),1e-6);let c=tr.get(i);c&&c.opts===o||(c={opts:o,values:new Map},tr.set(i,c));const h=c.values;let d=0;for(let s=Math.min(l,r),n=0;n<4096&&s<=r+1e-9;n++,s=Math.min(r,s+l)){const n=a*s,c=`${n.toFixed(9)}|${l.toFixed(9)}`;let p=h.get(c);if(void 0===p&&(p=Qa(t,e,i,n,o),h.size<4096&&h.set(c,p)),!p)break;if(d=n,Math.abs(s-r)<=1e-9)break}return d}(e.rooms,e.openings,s,c,this._gridPitch,e.opts);if(h===e.d&&e.moved)return;const d=this._rszPreview,p=this._rszLive,u=e.d;let _=Ja(e.rooms,e.openings,s,h);if(!this._rszApplyPreview(_.polys,_.openings).ok)return this._rszPreview=d,this._rszLive=p,e.d=u,e.rejectNotified||(e.rejectNotified=!0,this._showToast(this._t("resize.preview_failed"))),void this.requestUpdate();e.moved=!0,e.changed=[...s.roomIds],e.d=h,this._rszLive=this._rszEdgeLabels(_,s),this.requestUpdate()}_rszUp(t){const e=this._rszDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._rszPreview,s=e.moved&&Math.abs(e.d)>1e-9,n=this._rszSnapshot()===e.snap,o=Qa(e.rooms,e.openings,e.plan,e.d,e.opts),a=this._rszCandidateRenderable(i);if(this._rszDrag=null,this._rszLive=null,this._rszPreview=null,!s||!i)return this._cfgEpoch++,void this.requestUpdate();if(!n||!o||!a)return this._cfgEpoch++,this._showToast(this._t("resize.commit_failed")),void this.requestUpdate();const r=JSON.parse(e.snap),l=this._curSpaceCfg;l&&(l.rooms=i.sp.rooms,l.openings=i.sp.openings,Array.isArray(i.sp.walls)&&(i.sp.walls.length?l.walls=i.sp.walls:delete l.walls),Array.isArray(i.sp.open_spans)&&i.sp.open_spans.length?l.open_spans=i.sp.open_spans:delete l.open_spans),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._commitPhysicalGeometry(this._t("history.resize_room"),r),this._rszEligibilityCache=null,this.requestUpdate()}_rszCancelDrag(){this._rszDrag&&(this._rszDrag=null,this._rszLive=null,this._rszPreview=null,this._cfgEpoch++,this.requestUpdate())}_rszPointerCancel(t){const e=this._rszDrag;e&&e.pid===t.pointerId&&(t.stopPropagation(),this._rszCancelDrag())}_rszEdgeLabels(t,e){const i=this._rszDrag,s=[],n=t.polys[e.roomId]||i.rooms.find(t=>t.id===e.roomId).poly,o=n.length,a=this._rszInnerSpanCms(e.roomId,n,t.polys);for(const t of function(t,e){const i=t.length;return[(e-1+i)%i,(e+1)%i]}(n,e.edge)){const e=n[t],i=n[(t+1)%o],r=a?.[t];s.push({kind:"length",x:(e[0]+i[0])/2,y:(e[1]+i[1])/2,text:null==r?this._fmtLen(e,i):li(r,"mi"===this.hass?.config?.unit_system?.length),edge:{a:[e[0],e[1]],b:[i[0],i[1]]}})}const r="mi"===this.hass?.config?.unit_system?.length,l=e.roomIds,c=this._spaceWalls,h=this._openPairs().flatMap(t=>t.segs),d=this._physicalBodiesR(),p=this._baseVb(),u=this._view&&this._view.w>0&&this._view.h>0?this._view:{x:p[0],y:p[1],w:p[2],h:p[3]},[_,g]=this._lastValidStageSize||[u.w,u.h],m={...u,stageWidth:Math.max(1,_),stageHeight:Math.max(1,g)},f=this._spaceModel(),v=this._config?.icon_size??2.5,y=f?Uh(v>8?2.5:v,f,u.w,this._kiosk?this._kioskScale.icon:1)*m.stageWidth/100:24,b=Math.max(10,.77*y),w=this._t("room.settings_short"),k=b*(1.457+.66*Math.max(1,w.length)*.42);for(const n of l){const o=t.polys[n]||i.rooms.find(t=>t.id===n).poly,a=c.length&&fc(Object.entries(t.polys).map(([t,e])=>({id:t,poly:e})),n,c,h,this._wallKeyPitch,this._cellCm,this._gridPitch,ov)||o,l=ir(d.length?rh(ah(a,d))*Math.pow(this._cellCm/this._gridPitch,2)/1e4:er(a,this._gridPitch,this._cellCm),r),p=nr({poly:o,edge:e.edgeByRoom[n],text:l,view:m,gearCenter:$i(o),gearWidthPx:k,gearHeightPx:b});s.push({kind:"area",roomId:n,x:p.anchor[0],y:p.anchor[1],text:l,placement:p})}return s}_rszInnerSpanCms(t,e,i){const s=Object.keys(i).length?Object.entries(i).map(([t,e])=>({id:t,poly:e})):this._spaceModel()?.rooms;if(!s?.length)return null;const n=this._spaceWalls;if(!n.length)return null;const o=function(t,e,i,s,n,o,a,r=1){const l=(t||[]).find(t=>t?.id===e),c=hi(l);if(!c||c.length<3)return null;const h=hc(t,e,i,s,n,o,a,r);if(!h)return c.map(()=>0);const d=4*Vl(n,r);return c.map((t,e)=>{const i=c[(e+1)%c.length],s=[(t[0]+i[0])/2,(t[1]+i[1])/2];for(let t=0;tt.segs),this._wallKeyPitch,this._cellCm,this._gridPitch,ov);if(!o||o.length!==e.length)return null;const a=this._cellCm/this._gridPitch;return e.map((t,i)=>function(t,e,i){const s=t?.length||0;if(s<3||!Array.isArray(i)||i.length!==s)return 0;const n=(Math.trunc(e)%s+s)%s,o=t[n],a=t[(n+1)%s],r=a[0]-o[0],l=a[1]-o[1],c=Math.hypot(r,l);if(!(c>0))return 0;const h=Math.max(0,Number(i[n])||0);if(!(h>0))return c;const d=[r/c,l/c],p=Yl(t,n),u=[o[0]+p[0]*h,o[1]+p[1]*h],_=e=>{const n=Math.max(0,Number(i[e])||0);if(!(n>0))return null;const a=t[e],r=t[(e+1)%s],l=r[0]-a[0],c=r[1]-a[1],h=Math.hypot(l,c);if(!(h>0))return null;const p=Yl(t,e),_=Xl(u,d,[a[0]+p[0]*n,a[1]+p[1]*n],[l/h,c/h]);return _?(_[0]-o[0])*d[0]+(_[1]-o[1])*d[1]:null},g=_((n-1+s)%s)??0,m=(_((n+1)%s)??c)-g;return m>0?m:0}(e,i,o)*a)}_renderResizeMeasurements(){if(!this._rszLive?.length)return U;const t=this._rszLive.filter(t=>"length"===t.kind),e=this._rszLive.filter(t=>"area"===t.kind);return j`
+ `}_stageAspect(){const t=this._stageEl,e=this._baseVb();return t&&t.clientHeight?t.clientWidth/t.clientHeight:e[2]/e[3]}_viewOr(t){return this._view&&this._view.w?this._view:Ni(t,this._stageAspect())}_roomLabelReferenceViewWidth(t){if(!this._markup)return t.w;const e=this._stageEl,i=this.renderRoot.querySelector(".editorchrome");if(!e||e.clientWidth<=0||e.clientHeight<=0)return t.w;const s=e.clientHeight+(i?.getBoundingClientRect().height||0);return s<=0?t.w:this._viewForModeTarget(this._zoom,void 0,void 0,e.clientWidth,s).w}_screenToVb(t,e){const i=this._stageEl,s=this._viewOr(this._baseVb()),n=i?.clientWidth||1,o=i?.clientHeight||1;return[s.x+t/n*s.w,s.y+e/o*s.h]}_clampView(t,e){const i=(t,e,i,s)=>{const n=1*Math.max(e,s),o=i-n,a=i+s-e+n;return Math.max(Math.min(o,a),Math.min(Math.max(o,a),t))};return{w:t.w,h:t.h,x:i(t.x,t.w,e.x,e.w),y:i(t.y,t.h,e.y,e.h)}}_applyView(t,e,i){const s=this._baseVb(),n=Ni(s,this._stageAspect()),o=Math.min(_v.ZOOM_MAX,Math.max(_v.ZOOM_MIN,t)),a=n.w/o,r=n.h/o,l=this._viewOr(s),c=e??l.x+l.w/2,h=i??l.y+l.h/2,d=this._clampView({x:c-a/2,y:h-r/2,w:a,h:r},n);return!(this._view&&Math.abs(this._zoom-o)<1e-9&&Math.abs(this._view.x-d.x)<1e-6&&Math.abs(this._view.y-d.y)<1e-6&&Math.abs(this._view.w-d.w)<1e-6&&Math.abs(this._view.h-d.h)<1e-6)&&("opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=o,this._view=d,!0)}_bootWatch(){clearTimeout(this._bootTimer),this._bootStart=Date.now(),this._bootLastH=-1,this._bootLastChange=this._bootStart;const t=()=>{if(!this._booting)return;const e=Date.now(),i=this._stageEl?this._stageEl.clientHeight:0;i!==this._bootLastH&&(this._bootLastH=i,this._bootLastChange=e);const s=e-this._bootStart;s>=1200||s>=700&&i>0&&e-this._bootLastChange>=250?this._bootSettled():this._bootTimer=window.setTimeout(t,100)};this._bootTimer=window.setTimeout(t,100)}_bootSettled(){this._booting&&!this._bootSettling&&(this._bootSettling=!0,this._refitView(),this._bootSettleRaf=requestAnimationFrame(()=>{this._bootSettleRaf=0,this._finishBootSettled()}))}_finishBootSettled(){if(!this._booting)return;this._refitView(),this._booting=!1,this._bootSettling=!1;const t=this._stageEl?.clientHeight??0;!this._config?.kiosk&&t>0&&this._warmPatch({hdrH:this._hdrH,stageH:t,vp:this._warmViewportState()},!0),this._bootFading=!0,this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220),this._bootSoft=!0,clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},jf)}_bootSoftCancel(){this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoft=!1)}_beginResumeSettle(){this._booting||this._resumeSettling||(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0),this._viewportInvalidAt=0,this._beginContinuityCandidate("warm-resume",!1),this._loading?this.requestUpdate():this._loadFromServer())}_refitView(){if(this._modeTransitionBusy)return;const t=this._stageEl;if(!t||"visible"!==document.visibilityState||t.clientWidth<=0||t.clientHeight<=0)return void(this._viewportInvalidAt||(this._viewportInvalidAt=Date.now()));const e=[t.clientWidth,t.clientHeight],i=this._lastValidStageSize,s=!!i&&Math.abs(i[0]-e[0])<=.5&&Math.abs(i[1]-e[1])<=.5,n=this._viewportInvalidAt?Date.now()-this._viewportInvalidAt:0;if(this._viewportInvalidAt=0,!i)return this._lastValidStageSize=e,void(this._view||this._applyView(this._zoom));s?this._pendingRefitSize=null:(this._pendingRefitSize=e,this._refitRaf||(this._refitRaf=requestAnimationFrame(()=>{this._refitRaf=0;const t=this._pendingRefitSize;this._pendingRefitSize=null;const e=this._stageEl;if(!t||!e||e.clientWidth<=0||e.clientHeight<=0)return;if(Math.abs(e.clientWidth-t[0])>.5||Math.abs(e.clientHeight-t[1])>.5)return void this._refitView();const i=this._lastValidStageSize;if(i&&Math.abs(i[0]-t[0])<=.5&&Math.abs(i[1]-t[1])<=.5)return;this._lastValidStageSize=t;const s=this._view;n>=Cd?this._beginContinuityCandidate("stage-size-restored",!0,"stage-size"):this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._applyView(this._zoom,s?s.x+s.w/2:void 0,s?s.y+s.h/2:void 0)})))}_zoomAt(t,e,i){const s=this._stageEl;if(!s)return;const n=Ni(this._baseVb(),this._stageAspect()),o=Math.min(_v.ZOOM_MAX,Math.max(_v.ZOOM_MIN,i));"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1));const a=s.clientWidth,r=s.clientHeight,l=this._screenToVb(t,e),c=n.w/o,h=n.h/o;this._zoom=o,this._view=this._clampView({x:l[0]-t/a*c,y:l[1]-e/r*h,w:c,h:h},n)}_onWheel(t){const e=this._stageEl;if(!e)return;t.preventDefault();const i=e.getBoundingClientRect(),s=t.deltaY<0?1.15:1/1.15;this._zoomAt(t.clientX-i.left,t.clientY-i.top,this._zoom*s),this._saveZoom()}_stepZoom(t){const e=this._stageEl;e&&(this._zoomAt(e.clientWidth/2,e.clientHeight/2,this._zoom*(t>0?1.4:1/1.4)),this._saveZoom())}_resetZoom(){const t=this._baseVb();"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=1,this._view=Ni(t,this._stageAspect()),this._saveZoom()}_saveZoom(){if("view"===this._mode){this._zoomBySpace={...this._zoomBySpace,[this._space]:this._zoom};try{localStorage.setItem(tv,JSON.stringify(this._zoomBySpace))}catch{}}}_restoreZoom(){const t=this._zoomBySpace[this._space]||1;this._zoom=t;const e=this._stageEl;if(e&&e.clientHeight){const e=this._baseVb();return this._applyView(t,e[0]+e[2]/2,e[1]+e[3]/2),void this.requestUpdate()}this._view=null,requestAnimationFrame(()=>{if(!this._stageEl)return;const e=this._baseVb();this._applyView(t,e[0]+e[2]/2,e[1]+e[3]/2),this.requestUpdate()})}_stagePointerDown(t){if(this._vacFit)return;if(this._kiosk&&(this._cyclePausedUntil=Date.now()+6e4,0===this._pointers.size?(this._swipeStart={x:t.clientX,y:t.clientY,id:t.pointerId},t.target.closest?.(".dev, .roomlabel, .oplock")||(clearTimeout(this._kioskHoldTimer),this._kioskHoldTimer=window.setTimeout(()=>{this._kioskDialog=!0,this._swipeStart=null},3e3))):(this._swipeStart=null,clearTimeout(this._kioskHoldTimer))),this._drag)return;if(this._markup&&t.target.closest?.(".roomlabel, .rlhandle, .rszhandle, .dev, .oplock, .op-hit, button"))return;if("devices"===this._mode&&t.target.closest(".dev"))return;if("decor"===this._mode&&this._decorPointerDown(t))return;this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY});const e=this._viewOr(this._baseVb());if(1===this._pointers.size)this._panStart={sx:t.clientX,sy:t.clientY,vx:e.x,vy:e.y},this._panLock=null,this._suppressClick=!1;else if(2===this._pointers.size){this._cancelBoundaryAnchor(),"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const t=[...this._pointers.values()],e=Math.hypot(t[0].x-t[1].x,t[0].y-t[1].y);this._pinchStart={dist:e,zoom:this._zoom},this._panStart=null,this._panLock=null}}get _swipeZone(){return!this._hasFixedFloor&&this._kiosk&&this._zoom<=1.001&&this._model.length>1}_stagePointerMove(t){if(this._physicalRotate?.pid!==t.pointerId)if(this._physicalDrag?.pid!==t.pointerId)if(this._dtDrag?.pid!==t.pointerId)if(this._bdDrag?.pid!==t.pointerId){if(this._decorDraft?.pid===t.pointerId){const e=this._decorDraft;let i=this._decorSnap(this._svgPoint(t),t.pointerType);if(t.shiftKey&&("rect"===e.kind||"ellipse"===e.kind)){const t=i[0]-e.a[0],s=i[1]-e.a[1],n=Math.max(Math.abs(t),Math.abs(s));i=this._snap([e.a[0]+(t<0?-n:n),e.a[1]+(s<0?-n:n)])}return void(this._decorDraft={...e,b:i})}if(this._decorMove?.pid!==t.pointerId)if(this._pointers.has(t.pointerId)){if(this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY}),this._markup&&1===this._pointers.size&&this._markupMove(t),this._pinchStart&&this._pointers.size>=2){"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const t=[...this._pointers.values()],e=Math.hypot(t[0].x-t[1].x,t[0].y-t[1].y)/(this._pinchStart.dist||1),i=this._stageEl.getBoundingClientRect(),s=(t[0].x+t[1].x)/2-i.left,n=(t[0].y+t[1].y)/2-i.top;this._zoomAt(s,n,this._pinchStart.zoom*e),this._suppressClick=!0,this._saveZoom()}else if(this._panStart){const e=t.clientX-this._panStart.sx,i=t.clientY-this._panStart.sy;Math.abs(e)+Math.abs(i)>4&&(this._suppressClick=!0,clearTimeout(this._holdTimer),"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover()),null===this._panLock&&Math.abs(e)+Math.abs(i)>8&&(this._panLock=this._swipeZone&&Math.abs(e)>1.5*Math.abs(i)?"swipe":"pan");const s=this._stageEl;if("pan"===this._panLock&&s){const t=this._baseVb(),n=this._viewOr(t),o=Ni(t,this._stageAspect());this._view=this._clampView({x:this._panStart.vx-e/(s.clientWidth||1)*n.w,y:this._panStart.vy-i/(s.clientHeight||1)*n.h,w:n.w,h:n.h},o)}}}else this._markupMove(t);else this._decorMoveUpdate(t)}else this._bdMove(t);else this._dtMove(t);else this._physicalMove(t);else this._physicalRotateMove(t)}_stagePointerLeave(t){this._markup&&("opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover())}_stagePointerUp(t){if(this._kiosk){clearTimeout(this._kioskHoldTimer);const e=this._swipeStart;if(this._swipeStart=null,e&&e.id===t.pointerId){const i=t.clientX-e.x,s=t.clientY-e.y;if(Math.abs(i)+Math.abs(s)<8){const t=Date.now();t-this._lastTap<350&&this._resetZoom(),this._lastTap=t}const n="pan"===this._panLock?null:function(t,e,i,s,n,o=60){if(i>1.001||s.length<2)return null;if(Math.abs(t)t.id),this._space);n&&this._slideTo(n,i<0?"left":"right")&&(this._saveNav(),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._showKioskDots())}}if(this._physicalDrag?.pid===t.pointerId)return void this._physicalUp(t);if(this._physicalRotate?.pid===t.pointerId)return void this._physicalRotateUp(t);if(this._dtDrag?.pid===t.pointerId)return void this._dtUp();if(this._bdDrag?.pid===t.pointerId)return void this._bdUp();if(this._decorDraft?.pid===t.pointerId)return void this._decorCommitDraft();if(this._decorMove?.pid===t.pointerId)return this._decorMove.moved&&(this._recordGeometry(this._t("history.decor_move"),this._decorMove.before),this._saveConfig()),void(this._decorMove=null);const e=!!this._pinchStart||!!this._panStart;this._pointers.delete(t.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null,setTimeout(()=>this._suppressClick=!1,0)),e&&0===this._pointers.size&&this.requestUpdate()}_clickRoom(t){!this._suppressClick&&t.area&&dv("/config/areas/area/"+t.area)}_pointerDown(t,e){if("plan"===this._mode)return;if("view"===this._mode){this._holdFired=!1,clearTimeout(this._holdTimer);const i=t.pointerId,s=t.currentTarget;return void(this._holdTimer=window.setTimeout(()=>{this._holdFired=!0,this._interruptViewGesture(i,s),this._infoCard=e},600))}if("ha_disabled"===e.bindingStatus?.kind)return;t.preventDefault();const i=this._pos(e);this._drag={id:e.id,sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},uv(t),this._tip=null}_pointerMove(t,e){if(!this._drag||this._drag.id!==e.id)return;const i=this.renderRoot.querySelector(".stage");if(!i)return;const s=this._baseVb(),n=i.getBoundingClientRect(),o=this._viewOr(s),a=(t.clientX-this._drag.sx)/n.width*o.w,r=(t.clientY-this._drag.sy)/n.height*o.h;Math.abs(t.clientX-this._drag.sx)+Math.abs(t.clientY-this._drag.sy)>3&&(this._drag.moved=!0,clearTimeout(this._holdTimer));const l=Ih(this._drag.ox+a),c=Ih(this._drag.oy+r);this._savePos(e,l,c)}_pointerUp(t,e){if(clearTimeout(this._holdTimer),!this._drag||this._drag.id!==e.id)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&(this._selId=e.id,window.setTimeout(()=>this._drag=null,0))}_showToast(t){for(const t of this.renderRoot.querySelectorAll("hp-dialog"))t.closeTransientOverlays("toast");this._toast=t,clearTimeout(this._toastTimer),this._toastTimer=window.setTimeout(()=>{this._toast=""},3500)}_syncPointerHoverTargets(){const t=this._pointerModality.hoverEnabled;for(const e of this.renderRoot.querySelectorAll(nv))e.toggleAttribute("data-pointer-hover",t)}_syncPointerHoverSubtree(t){if(t.nodeType!==Node.ELEMENT_NODE)return;const e=t,i=this._pointerModality.hoverEnabled;e.matches(nv)&&e.toggleAttribute("data-pointer-hover",i);for(const t of e.querySelectorAll(nv))t.toggleAttribute("data-pointer-hover",i)}_clearTransientHover(t=!1){t&&this._pointerModality.suspend(),this._tip&&(this._tip=null),this._hoverRoom&&(this._hoverRoom=null)}_notePointer(t){this._boundaryPointerType=t.pointerType||"mouse";const e=this._pointerModality.modality,i=this._pointerModality.note(t);"touch"!==i&&"pen"!==i||e===i&&!this._tip&&!this._hoverRoom||this._clearTransientHover()}_guardTouchGesture(t){if(this._editorSecondary.handleOutsideDismiss(t))return;if("click"===t.type){if(!this._suppressClick&&!this._touchSequenceMultitouch&&Date.now()>this._touchClickBlockUntil)return;return t.preventDefault(),void t.stopImmediatePropagation()}const e=t;if(this._notePointer(e),"touch"===e.pointerType)if("pointerdown"!==t.type){if("pointermove"===t.type){const t=this._touchContacts.get(e.pointerId);if(!t)return;const i={...t,x:e.clientX,y:e.clientY};if(this._touchContacts.set(e.pointerId,i),this._touchSequenceMultitouch&&"view"===this._mode&&!this._vacFit&&this._pinchStart&&[...this._touchContacts.values()].every(t=>t.inStage)){this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY});const t=[...this._touchContacts.values()];if(t.length>=2&&this._stageEl){const[e,i]=t,s=Math.hypot(e.x-i.x,e.y-i.y)/(this._pinchStart.dist||1),n=this._stageEl.getBoundingClientRect();this._zoomAt((e.x+i.x)/2-n.left,(e.y+i.y)/2-n.top,this._pinchStart.zoom*s),this._saveZoom()}}return}if("pointerup"===t.type||"pointercancel"===t.type||"lostpointercapture"===t.type){if(this._clearTransientHover(),this._touchContacts.delete(e.pointerId),this._touchSequenceMultitouch){if(this._touchClickBlockUntil=Date.now()+500,this._pointers.delete(e.pointerId),!this._vacFit&&this._pointers.size>=2){const[t,e]=[...this._pointers.values()];this._pinchStart={dist:Math.hypot(t.x-e.x,t.y-e.y),zoom:this._zoom}}else this._pinchStart=null;0===this._pointers.size&&(this._panStart=null,this._panLock=null)}0===this._touchContacts.size&&(this._touchSequenceMultitouch=!1)}}else if(this._touchContacts.set(e.pointerId,{x:e.clientX,y:e.clientY,inStage:!!e.target?.closest?.(".stage")}),this._touchContacts.size>=2){this._clearTransientHover(),this._touchSequenceMultitouch=!0,this._touchClickBlockUntil=Number.POSITIVE_INFINITY,clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),this._swipeStart=null;const t=[...this._touchContacts.values()];if("view"===this._mode&&!this._vacFit&&t.every(t=>t.inStage)){this._pointers=new Map([...this._touchContacts].map(([t,e])=>[t,{x:e.x,y:e.y}]));const[e,i]=t;this._pinchStart={dist:Math.hypot(e.x-i.x,e.y-i.y),zoom:this._zoom},this._panStart=null,this._panLock=null}else this._vacFit&&(this._pointers.clear(),this._pinchStart=null,this._panStart=null,this._panLock=null)}}_showTip(t,e,i,s,n,o){this._notePointer(t),this._pointerModality.hoverEnabled&&(this._drag||(this._tip={x:t.clientX,y:t.clientY,title:e,meta:i,lqi:s,temp:n,hum:o}))}get _gridPitch(){return Dh}get _cellCm(){const t=Number(this._curSpaceCfg?.cell_cm);return Number.isFinite(t)&&t>0?t:5}_fmtLen(t,e){const i=function(t,e,i,s){return Math.hypot(e[0]-t[0],e[1]-t[1])/i*s}(t,e,this._gridPitch,this._cellCm);return li(i,"mi"===this.hass?.config?.unit_system?.length)}get _curSpaceCfg(){const t=this._rszPreview;return t&&t.space===this._space?t.sp:this._serverCfg?.spaces.find(t=>t.id===this._space)}get _renderCfg(){const t=this._rszPreview;return t&&this._serverCfg?{...this._serverCfg,spaces:this._serverCfg.spaces.map(e=>e.id===t.space?t.sp:e)}:this._serverCfg}get _spaceH(){return this._curSpaceCfg,ov}get _segments(){const t=this._curSpaceCfg,e=this._spaceH;return pi(t?.rooms||[]).map(t=>[t[0]*ov,t[1]*e,t[2]*ov,t[3]*e])}_savedNav(){if(this._hasFixedFloor)return null;try{return JSON.parse(localStorage.getItem(ev)||"null")}catch{return null}}_saveNav(){if(!this._hasFixedFloor)try{localStorage.setItem(ev,JSON.stringify({space:this._space}))}catch{}}_leaveCardRoute(){if(this._routeDepartureHandled)return;this._routeDepartureHandled=!0,"view"!==this._mode&&this._setMode("view",!1),this._pendingNavMode=null,this._geometryHistory.clear(),this._activeDraftId=null,this._resumeDraftBySpace={},this._draftSegmentCms=[],this._closingWallCm=null,this._drawWallField=null,this._showHidden=!1,this._tapConfirm=null,this._vacCalConfirm=null,this._decorEraseConfirm=null,this._openingInfo=null,this._closeInfoCard(),this._rulesDialog=null,this._alignDialog=null,this._preflightClipboardFallback=null,this._backupImportDialog=null,this._backupExportDialog=null,this._settingsDialog=null,this._markerDialog=null,this._openingDialog=null,this._physicalDialog=null,this._wallDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._mergeDialog=null,this._roomDialog=!1,this._spaceDialog=null,this._importDialog=null;const t=this._warmSlot;t?.owner===this._warmGen&&(t.vp=this._warmViewportState(),t.dlg=null,t.frameFingerprint="",clearTimeout(t.evict),t.evict=0),this._saveNav()}_setMode(t,e=!0){this._endTabDrag(),this._pendingNavMode=null;const i=this._spaceModel();if(!i)return this._cancelModeTransition(!1),void(this._mode="view");if(this._kiosk&&"view"!==t)return;if(this._mode===t){if(!e&&"view"===t&&this._modeTransitionBusy){const e=this._currentModeVisual(t),i=this._modeTransitionTargetZoom,s=this._modeTransitionTargetCenterX,n=this._modeTransitionTargetCenterY;this._cancelModeTransition(!1),this._commitViewModeAtomic(e,i,s,n)}return}if(this._bootSoftCancel(),("plan"===t||"decor"===t)&&!this._norm)return void this._showToast(this._t("toast.markup_needs_server"));if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._clearTransientHover(!0),this._cancelDevicePressFeedback();const s=this._mode,n=this._effectiveProjection(),o=this._currentModeVisual(s),a=this._modeTransitionBusy,r=o&&"view"!==s&&"view"!==t?{...o,toolbarContentOpacity:this._reducedMotion?1:.35}:o;this._cancelModeTransition(!1),this._editorSecondary.closeForNavigation(),(this._decorMove||this._dtDrag||this._bdDrag)&&this._cancelDecorGesture();const l=!i.bg&&"view"===t!=("view"===s),c=a&&"view"===s&&"view"!==t?this._modeTransitionEditorCamera:null;let h=c?.zoom??(a?this._modeTransitionTargetZoom:this._zoom),d=c?c.centerX:a?this._modeTransitionTargetCenterX:r?.viewport.centerX,p=c?c.centerY:a?this._modeTransitionTargetCenterY:r?.viewport.centerY;if("view"===s&&"view"!==t&&!a){const e=this._view;if(this._viewModeSnap={space:this._space,zoom:this._zoom,cx:e?this._logicalViewCenter(n)?.x:void 0,cy:e?this._logicalViewCenter(n)?.y:void 0},"iso"===n){const e=this._logicalViewCenter("iso");d=e?.x,p=e?.y,this._view=null,this._mode=t,this._applyView(this._zoom,e?.x,e?.y)}l&&(h=1,d=void 0,p=void 0)}if("plan"===s&&this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._mode=t,this._editorChromeMode="view"===t?s:t,"view"===t){"view"===s||a||(this._modeTransitionEditorCamera={zoom:this._zoom,centerX:r?.viewport.centerX,centerY:r?.viewport.centerY});const t=this._viewModeSnap;if(t&&t.space===this._space){h=t.zoom;const e=this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat",i=null!=t.cx&&null!=t.cy&&"iso"===e?Qm([t.cx,t.cy],0):null;d=i?.[0]??t.cx,p=i?.[1]??t.cy}else t&&(h=this._zoomBySpace[this._space]||1,d=void 0,p=void 0)}else this._modeTransitionEditorCamera={zoom:h,centerX:d,centerY:p};this._modeTransitionTargetZoom=h,this._modeTransitionTargetCenterX=d,this._modeTransitionTargetCenterY=p,("iso"===n||"view"===t&&this._labsIso&&"iso"===this._viewPreference[this._space])&&(this._modeTransitionForceAtomic=!0);const u=++this._modeTransitionRequest;e?r?(this._modeTransitionPreparing=!0,this._modeTransitionVisual=r,this._prepareModeTransition(u,r,t,h,d,p)):(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._zoom=h,this._view=null,requestAnimationFrame(()=>{this.isConnected&&u===this._modeTransitionRequest&&this._mode===t&&(this._applyView(h,d,p),"view"===t&&(this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate())})):"view"===t&&this._commitViewModeAtomic(r,h,d,p),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._tool="draw",this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._selId=null,this._physicalSel=null,this._physicalDialog=null,this._physicalDrag=null,this._rszSel=null,this._rszDrag=null,this._rszLive=null,this._rszPreview=null,this._tip=null,this._hoverRoom=null,this._decorDraft=null,this._decorSel=null,this._decorMove=null,this._backdropDialog=null,this._decorTool="select",this._bdDrag=null,this._dtDrag=null,this._dtBox=null,"plan"===t&&(this._primeDrawWallField(),this._resumeLastDraft()),this._saveNav()}_primeDrawWallField(){null===this._drawWallField&&(this._drawWallField=gl(ll,this._imperial))}get _drawWallFieldValue(){return null===this._drawWallField?gl(ll,this._imperial):this._drawWallField}get _drawWallCm(){const t=Gf(this._drawWallFieldValue);if(null==t||t<=0)return null;const e=this._imperial?2.54*t:t,i="column"===this._tool?Wc:100;return e>=1&&e<=i?e:null}get _drawWallMaxCm(){return"column"===this._tool?Wc:100}_showPhysicalRange(t=this._drawWallMaxCm){this._showToast(this._t("toast.physical_range",{max:gl(t,this._imperial),unit:this._t(this._imperial?"wallthick.unit_in":"wallthick.unit_cm")}))}_draftSegmentCount(t=this._curSpaceCfg){return(t?.room_drafts||[]).reduce((t,e)=>t+(Array.isArray(e.segments)?e.segments.length:0),0)}_mergeSpacePartitions(t,e){const i=t?.partitions||[];if(i.length<2)return 0;const s=ag(i,{pitch:Ph,seedIds:e,geometry:lg(t,{excludeDraftId:this._activeDraftId})});return s.merged?(t.partitions=s.partitions,rg(t.openings,t.partitions,s.openingMoves,{coordScale:ov,cellCm:this._cellCm,gridPitch:this._gridPitch}),s.merged):0}_finishWallChain(){if("draw"!==this._tool||this._wallFaceBatch||this._roomDialog)return!0;const t=this._curSpaceCfg;if(!t||this._path.length<2)return this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._clearPlanSnapHover(),!0;const e=hu(this._path,cu(this._path.length-1,this._draftSegmentCms,this._drawWallCm,ll)),i=e.length;if((t.partitions||[]).length+i>cv)return this._showToast(this._t("toast.physical_limit")),!1;const s=this._geometrySnapshot();t.partitions||=[];const n=Date.now().toString(36),o=[],a=this._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this._activeDraftId):null,r=this._draftSegmentsForPath(this._path,a,e.map(t=>t.cm));for(let s=0;st.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this._t("history.wall_chain_finish"),s),delete this._resumeDraftBySpace[this._space],this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._clearPlanSnapHover(),!0}_activateMarkupTool(t){t!==this._tool&&(this._wallFaceBatch&&this._roomDialogCancel(),("draw"!==this._tool||this._finishWallChain())&&(this._cancelPath(),this._tool=t,"draw"===t&&this._resumeLastDraft(),"resize"===t&&(this._rszSel=null),"boundary"!==t&&"wallthick"!==t||(this._wallDialog=null)))}_limitReached(t){const e=this._curSpaceCfg;if(!e)return!0;const i="draft"===t?(e.room_drafts||[]).length>=200:"partition"===t?(e.partitions||[]).length>=cv:(e.wall_columns||[]).length>=500;return i&&this._showToast(this._t("toast.physical_limit")),i}_svgPoint(t){const e=this.renderRoot.querySelector(".stage").getBoundingClientRect();return this._screenToVb(t.clientX-e.left,t.clientY-e.top)}_snap(t){const e=this._gridPitch;return[Ih(ri(t[0],e)),Ih(ri(t[1],e))]}_snapDrawPoint(t,e=!1){const i=this._path[this._path.length-1],s=e&&i?function(t,e,i,s=1/0){if(!(i>0&&t?.every(Number.isFinite)&&e?.every(Number.isFinite)))return[e[0],e[1]];const n=e[0]-t[0],o=e[1]-t[1];if(Math.abs(n)+Math.abs(o)<=1e-12)return[t[0],t[1]];const a=Math.PI/4;let r=Math.atan2(o,n);r<0&&(r+=2*Math.PI);const l=Math.floor(r/a+.5)%8,[c,h]=[[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1],[0,-1],[1,-1]][l],d=c*c+h*h;let p=Math.max(0,Math.round((n*c+o*h)/(i*d)));if(Number.isFinite(s)&&s>=0){const e=(t,e)=>{if(!e)return 1/0;const n=e>0?s-t:t+s;return Math.max(0,Math.floor((n+1e-9*i)/i))};p=Math.min(p,e(t[0],c),e(t[1],h))}return[t[0]+c*p*i,t[1]+h*p*i]}(i,t,this._gridPitch,Mh):t;return this._snap(s)}_planSnapOpeningCuts(t,e){if(!this._openingsR.length)return[];const i=this._openingWallIndexFor(t,e).value,s=[];for(const e of this._roomWallOpeningInputs(this._openingsR,t)){const t=Oc(i,e);if(!t.negative&&!t.positive)continue;const n=e.angle*Math.PI/180,o=Math.cos(n)*e.length/2,a=Math.sin(n)*e.length/2;s.push([e.x-o,e.y-a,e.x+o,e.y+a])}return s}_planSnapGeometrySnapshot(){const t=this._spaceModel();if(!t)return{key:`${this._space}|empty`,value:{segments:[],endpoints:[]}};const e=[this._space,this._cfgEpoch,this._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this._planSnapGeometryCache?.key===e)return this._planSnapGeometryCache;const i=this._openCuts(),s=eu({space:t,activeDraftId:this._activeDraftId,roomCuts:[...i,...this._planSnapOpeningCuts(t,i)],partitionCuts:this._partitionOpeningCuts(t),epsilon:2e-4*this._gridPitch});return this._planSnapGeometryCache={key:e,value:s},this._planSnapGeometryCache}_hiddenWallDiagnosticSnapshot(){const t=this._spaceModel();if(!t)return{key:`${this._space}|hidden-empty`,value:{segments:[],endpoints:[]}};const e=["hidden",this._space,this._cfgEpoch,this._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this._hiddenWallDiagnosticCache?.key===e)return this._hiddenWallDiagnosticCache;const i=tu({space:t,activeDraftId:this._activeDraftId,epsilon:2e-4*this._gridPitch});return this._hiddenWallDiagnosticCache={key:e,value:i},this._hiddenWallDiagnosticCache}_planStructuralGeometrySnapshot(){const t=this._spaceModel();if(!t)return{key:`${this._space}|structural-empty`,value:{segments:[],endpoints:[]}};const e=["structural",this._space,this._cfgEpoch,this._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this._planStructuralGeometryCache?.key===e)return this._planStructuralGeometryCache;const i=eu({space:t,activeDraftId:this._activeDraftId,roomCuts:this._openCuts(),epsilon:2e-4*this._gridPitch});return this._planStructuralGeometryCache={key:e,value:i},this._planStructuralGeometryCache}_planSnapContextKey(t){const e=this._path[0],i=this._path[this._path.length-1];return[t,this._tool,this._path.length,e?`${e[0]},${e[1]}`:"",i?`${i[0]},${i[1]}`:""].join("|")}_resolvePlanDrawPoint(t,e){const i=this._planSnapGeometrySnapshot(),s=this._path[this._path.length-1],n="draw"===this._tool&&this._path.length>=3?[{point:this._path[0],key:"closure:first-point"}]:[],o={tolerance:this._cssPxToRender(12),distinguishTolerance:this._cssPxToRender(8),gridStep:this._gridPitch,excludePoints:s?[s]:[],extraEndpoints:n,epsilon:2e-4*this._gridPitch},a=e&&s?ru(i.value,t,{...o,anchor:s}):function(t,e,i){if(!(Up(e)&&i.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const s=i.epsilon??Gp,n=i.excludePoints||[],o=ou(nu(t,e,i),i.distinguishTolerance||0);if(o)return o;let a=null;for(const o of t.segments){const t=[o.a[0],o.a[1],o.b[0],o.b[1]],r=Ls([e[0],e[1]],t);if(r>i.tolerance)continue;const l=au(o,e,i.gridStep);!iu(l,n,s)&&su(r,o.key,a)&&(a={kind:"line",point:l,key:o.key,distance:r,segment:o})}return a?{kind:"resolved",candidate:a,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}(i.value,t,o),r="resolved"===a.kind?a.candidate:null,l=r?[...r.point]:this._snapDrawPoint(t,e),c=s?ua(s,l):l;return{point:c,candidate:r&&fi(c,r.point)?r:null,conflicts:"ambiguous"===a.kind?a.conflicts:[],ambiguous:"ambiguous"===a.kind,contextKey:this._planSnapContextKey(i.key)}}get _activePlanSnapCandidate(){if(!this._markup||"draw"!==this._tool)return null;const t=this._planSnapHover;if(!t)return null;const e=this._planSnapGeometrySnapshot();return t.contextKey===this._planSnapContextKey(e.key)?t.candidate:null}get _activePlanSnapConflicts(){if(!this._markup||"draw"!==this._tool)return[];const t=this._planSnapHover;if(!t)return[];const e=this._planSnapGeometrySnapshot();return t.contextKey===this._planSnapContextKey(e.key)?t.conflicts:[]}_clearPlanSnapHover(t=!0){this._planSnapHover=null,this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers([]),t&&(this._cursorPt=null)}_samePt(t,e){return fi(t,e)}_dropLegacySegments(){for(const t of this._serverCfg?.markers||[])"ripple"===t.display&&(t.display="icon_ripple");for(const t of this._serverCfg?.spaces||[]){delete t.segments;const e=new Set,i=t=>"string"==typeof t&&t.length>=1&&t.length<=64&&!e.has(t),s=t=>(e.add(t),!0),n=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(Number(t))&&Math.abs(Number(t))<=Sh);if(Array.isArray(t.partitions)&&(t.partitions=t.partitions.filter(t=>t&&i(t.id)&&n(t.a)&&n(t.b)&&Math.hypot(t.a[0]-t.b[0],t.a[1]-t.b[1])>1e-9&&s(t.id)).map(t=>({...t,cm:Math.max(1,Math.min(100,Number(t.cm)||15))})),t.partitions.length||delete t.partitions),Array.isArray(t.wall_columns)&&(t.wall_columns=t.wall_columns.filter(t=>t&&i(t.id)&&n(t.center)&&s(t.id)).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[Number(t.center[0]),Number(t.center[1])],cm:Gc(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:Uc(t.angle)}})),t.wall_columns.length||delete t.wall_columns),Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t&&i(t.id)&&Array.isArray(t.points)&&t.points.length>=2&&t.points.every(n)&&s(t.id)).map(t=>{const e=Ng(t);return{id:t.id,...e}}).filter(t=>t.points.length>=2),t.room_drafts.length||delete t.room_drafts),Array.isArray(t.walls)){const e=pd(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]);t.walls=Tl(t.walls,t.rooms||[],Ph,1,e),t.walls.length||delete t.walls}}}_rollbackRejectedPhysicalWrites(t){if(!this._serverCfg||!t.length)return!1;let e=!1;for(const[i]of t){const t=this._pendingPhysicalWrites.get(i);t&&(e=this._restoreGeometryStateInConfig(this._serverCfg,t.before)||e,this._pendingPhysicalWrites.delete(i))}return!!e&&(this._clearGeometryGesture(),this._geometryHistory.clear(),this._cfgEpoch++,this._modelCache=null,this._wallUnionCache=null,this._physicalBodiesCache=null,this._frame=null,this._regSignature="",this._cfgContentFingerprint=Ad(this._serverCfg),this._maybeRebuildDevices(),this.requestUpdate(),!0)}async _reloadRejectedPhysicalWrite(){const t=this._writeChain;await t.catch(()=>{}),await this._reloadConfigOnly(!0)}get _cfgWriting(){return this._writesPending>0}_writeConfig(){var t,e;this._writesPending++,this._writeChain=(t=this._writeChain,e=async()=>{if(!this._serverCfg)return;this._dropLegacySegments();const t=rl(Ur(this._serverCfg)),e=Ad(t),i=[...this._pendingPhysicalWrites.entries()];for(const[e,s]of i){const i=hm(t.spaces.find(t=>t.id===e));if(i===s.fingerprint)continue;let n=!1;try{n=this._checkSpacePhysicalGeometry(t,e).ok}catch{n=!1}if(!n)throw this._restoreGeometryStateLocal(s.before),this._pendingPhysicalWrites.delete(e),this._geometryHistory.clear(),this._showToast(this._t("toast.geometry_unsafe")),Object.assign(new Error("unsafe wall geometry"),{code:"geometry-unsafe"});s.fingerprint=i}let s;e!==Ad(this._serverCfg)&&(this._serverCfg=t),this._cfgContentFingerprint=e;try{s=await this.hass.callWS({type:"houseplan/config/set",config:t,expected_rev:this._cfgRev})}catch(t){if(!this._rollbackRejectedPhysicalWrites(i))throw t;const e=t&&"object"==typeof t?t:Object.assign(new Error(String(t)),{cause:t});throw e.physicalGeometryRolledBack=!0,e}this._cfgRev=s?.rev??this._cfgRev+1;for(const[t,e]of i)this._pendingPhysicalWrites.get(t)?.fingerprint===e.fingerprint&&this._pendingPhysicalWrites.delete(t)},t.catch(()=>{}).then(e));return this._writeChain.finally(()=>{this._writesPending--})}_saveConfig(){this._cfgEpoch++,this._saveConfigDebounced()}_geometrySnapshotFromConfig(t,e){const i=t?.spaces?.find(t=>t.id===e);if(!i)return null;const s=t=>JSON.parse(JSON.stringify(t)),n={};for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==i[t]&&(n[t]=i[t]);return{spaceId:e,rooms:s(i.rooms||[]),...Array.isArray(i.openings)?{openings:s(i.openings)}:{},...Array.isArray(i.walls)?{walls:s(i.walls)}:{},...Array.isArray(i.wall_segments)?{wall_segments:s(i.wall_segments)}:{},...Array.isArray(i.open_spans)?{open_spans:s(i.open_spans)}:{},...Array.isArray(i.room_drafts)?{room_drafts:s(i.room_drafts)}:{},...Array.isArray(i.partitions)?{partitions:s(i.partitions)}:{},...Array.isArray(i.wall_columns)?{wall_columns:s(i.wall_columns)}:{},...Array.isArray(i.decor)?{decor:s(i.decor)}:{},plan_transform:n}}_geometrySnapshot(t=this._space){return this._geometrySnapshotFromConfig(this._serverCfg,t)}_recordGeometry(t,e){if(!e)return;const i=this._geometrySnapshot(e.spaceId);i&&JSON.stringify(e)!==JSON.stringify(i)&&(this._geometryHistory.push({name:t,before:e,after:i}),this.requestUpdate())}_restoreGeometryStateInConfig(t,e,i=!1){const s=t?.spaces?.find(t=>t.id===e.spaceId);if(!s)return!1;const n=t=>JSON.parse(JSON.stringify(t)),o=new Map((s.rooms||[]).map(t=>[t.id,t]));if(s.rooms=n(e.rooms),i)for(const t of s.rooms){const e=o.get(t.id);!Array.isArray(t.wall_ids)&&Array.isArray(e?.wall_ids)&&e.wall_ids.length===t.poly?.length&&(t.wall_ids=n(e.wall_ids))}const a=(t,e)=>{void 0!==e?s[t]=n(e):i&&"wall_segments"===t||delete s[t]},r=new Map((s.openings||[]).map(t=>[t.id,t])),l=new Map((s.room_drafts||[]).map(t=>[t.id,t]));if(a("openings",e.openings),a("walls",e.walls),a("wall_segments",e.wall_segments),a("open_spans",e.open_spans),a("room_drafts",e.room_drafts),a("partitions",e.partitions),a("wall_columns",e.wall_columns),a("decor",e.decor),i){for(const t of s.openings||[]){const e=r.get(t.id);t.host||"wall"!==e?.host?.kind||(t.host=n(e.host))}for(const t of s.room_drafts||[]){const e=l.get(t.id);for(let i=0;i<(t.segments||[]).length;i++)!t.segments[i]?.id&&e?.segments?.[i]?.id&&(t.segments[i].id=e.segments[i].id)}}for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete s[t];return Object.assign(s,n(e.plan_transform||{})),!0}_restoreGeometryStateLocal(t){return!!this._restoreGeometryStateInConfig(this._serverCfg,t)&&(this._cfgEpoch++,this._modelCache=null,this._wallUnionCache=null,this._physicalBodiesCache=null,this._frame=null,this.requestUpdate(),!0)}_wallModelBlockerLabel(t){const e=t instanceof Pg?t.reason:"invalid-room";return this._t(`wall_model.reason.${e}`)}_commitPhysicalGeometry(t,e,i=[]){if(!e||!this._serverCfg)return!1;const s=this._serverCfg,n=this._geometrySnapshotFromConfig(s,e.spaceId),o=s.spaces.find(t=>t.id===e.spaceId);if(!o||hm(e)===hm(o))return!1;let a,r=!1;try{r=this._checkSpacePhysicalGeometry(s,e.spaceId).ok}catch{r=!1}if(!r)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this._showToast(this._t("toast.geometry_unsafe")),!1;let l=e;try{if(Number(s.model_version||0)<8){const t=JSON.parse(JSON.stringify(s));if(!this._restoreGeometryStateInConfig(t,e))throw new Pg("invalid-room",e.spaceId);const i=Zg(t).config;l=this._geometrySnapshotFromConfig(i,e.spaceId)||e;const o=JSON.parse(JSON.stringify(i));if(!n||!this._restoreGeometryStateInConfig(o,n,!0))throw new Pg("invalid-room",e.spaceId);const r=i.spaces.find(t=>t.id===e.spaceId),c=o.spaces.find(t=>t.id===e.spaceId),h=((t,e,i)=>{const s=new Map,n=new Map((t?.rooms||[]).map(t=>[t.id,t])),o=new Map((e||[]).map(t=>[t.id,t])),{rooms:a}=Yg(i,Vg(t));for(const t of a){const e=o.get(t.id),a=n.get(t.id),r=hi(e),l=hi((i.rooms||[]).find(e=>e.id===t.id)),c=hi(a);if(r&&l&&c&&r.length===l.length&&c.length===a?.wall_ids?.length&&t.poly.length===t.wall_ids.length)for(let e=0;e{const n=[];for(let o=0;oDg||Hg(r,i,s)>Dg)continue;const l=Lg(a,i,s),c=Lg(r,i,s);l<-Dg||c>1+Dg||c<=l+Dg||n.push({start:l,id:e[o]})}return n.sort((t,e)=>t.start-e.start)},n=i(c,a.wall_ids,r[e],r[(e+1)%r.length]),o=i(t.poly,t.wall_ids,l[e],l[(e+1)%l.length]);if(n.length&&n.length===o.length)for(let t=0;tt.id===e.spaceId),s=this._path.length>=2?this._path.map(t=>[t[0]/ov,t[1]/ov]):[];s.push(...i.map(t=>[t[0],t[1]])),c=Og(t)<=Og(l,s)&&this._checkSpacePhysicalGeometry(a,e.spaceId).ok}catch{c=!1}if(!c)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this._showToast(this._t("toast.geometry_unsafe")),!1;tm(s,a),this._recordGeometry(t,l);const h=s.spaces.find(t=>t.id===e.spaceId),d=this._pendingPhysicalWrites.get(e.spaceId);return this._pendingPhysicalWrites.set(e.spaceId,{before:d?.before||l,fingerprint:hm(h)}),this._saveConfig(),!0}_clearGeometryGesture(){this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!1),this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._roomDeleteDialog=null,this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._wallDialog=null,this._physicalDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._openingDialog=null,this._rszSel=null,this._rszDrag=null,this._rszPreview=null,this._rszLive=null,this._decorDraft=null,this._decorMove=null,this._dtDrag=null,this._bdDrag=null}_cancelBoundaryAnchor(){return!("boundary"!==this._tool||!this._openWallAnchor)&&(this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._clearPlanSnapHover(),this.requestUpdate(),!0)}_stagePointerCancel(t){if(clearTimeout(this._kioskHoldTimer),this._swipeStart?.id===t.pointerId&&(this._swipeStart=null),this._physicalDrag?.pid===t.pointerId||this._physicalRotate?.pid===t.pointerId)return void this._cancelPhysicalGesture();if(this._decorDraft?.pid===t.pointerId)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove?.pid===t.pointerId||this._dtDrag?.pid===t.pointerId||this._bdDrag?.pid===t.pointerId)return void this._cancelDecorGesture();this._cancelBoundaryAnchor(),"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const e=!!this._pinchStart||!!this._panStart;this._pointers.delete(t.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null),e&&0===this._pointers.size&&this.requestUpdate()}_applyGeometryState(t,e=!1){if(!this._canCommitSpace(t.spaceId))return!1;const i=this._geometrySnapshot(t.spaceId);if(!i||!this._restoreGeometryStateLocal(t))return!1;const s=this._serverCfg,n=hm(i)!==hm(t);if(n){let n=!1;try{const i=s?this._checkSpacePhysicalGeometry(s,t.spaceId):null;n=!!i?.ok||!(!e||"wall-degraded-extra"!==i?.reason)}catch{n=!1}if(!n)return this._restoreGeometryStateLocal(i),this._showToast(this._t("toast.geometry_unsafe")),!1}let o;try{o=Zg(s).config}catch(t){return this._restoreGeometryStateLocal(i),this._showToast(this._t("toast.wall_model_migration_blocked",{reason:this._wallModelBlockerLabel(t)})),!1}if(n){let n=!1;try{const i=o?this._checkSpacePhysicalGeometry(o,t.spaceId):null;n=!!i?.ok||!(!e||"wall-degraded-extra"!==i?.reason)}catch{n=!1}if(!n)return this._restoreGeometryStateLocal(i),this._showToast(this._t("toast.geometry_unsafe")),!1;tm(s,o);const a=s?.spaces.find(e=>e.id===t.spaceId),r=this._pendingPhysicalWrites.get(t.spaceId);this._pendingPhysicalWrites.set(t.spaceId,{before:r?.before||i,fingerprint:hm(a)})}else tm(s,o);return this._clearGeometryGesture(),this._space!==t.spaceId&&(this._commitSpace(t.spaceId),this._saveNav(),this._restoreZoom()),this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate(),!0}_roomAt(t){return this._spaceModel()?.rooms.find(e=>{const i=hi(e);return!!i&&wi(t,i)})}_overlapRoom(t){return this._spaceModel()?.rooms.find(e=>{const i=hi(e);return!!i&&Di(t,i)})}_pointInRoom(t,e){return e.poly?vi(t,e.poly):null!=e.x&&t[0]>=e.x&&t[0]<=e.x+e.w&&t[1]>=e.y&&t[1]<=e.y+e.h}_contourSelfIntersects(t){if(!Ia(t))return!0;const e=t.length,i=.001;for(let s=0;s=500)return this._showToast(this._t("toast.physical_limit")),!1;const t=this._curSpaceCfg;return!(!this._activeDraftId&&(t?.room_drafts||[]).length>=200||this._draftSegmentCount(t)>=2e3||(t?.partitions||[]).length+this._path.length>cv)||(this._showToast(this._t("toast.physical_limit")),!1)}_markupClick(t){if(this._vacFit)return;if(!this._markup)return;const e=this._spaceModel();if(!e)return void this._clearGeometryGesture();if(this._suppressClick)return;if(this._drag||this._rlResize)return;const i=t.composedPath?.()||[];if(i.some(t=>t?.classList?.contains?.("roomlabel")||t?.classList?.contains?.("rlhandle")))return;if(i.some(t=>t?.classList?.contains?.("physical-hit")))return void("boundary"===this._tool&&this._showToast(this._t("toast.boundary_blocked")));const s=this._svgPoint(t);if("select"===this._tool)return void(this._physicalSel=null);if("resize"===this._tool){if(this._rszDrag||i.some(t=>t?.classList?.contains?.("rszhandle")))return;const t=[...e.rooms].reverse().find(t=>this._pointInRoom(s,t));return void(this._rszSel=t?.id||null)}if("delroom"===this._tool)return void this._deleteRoomClick(s);if("opening"===this._tool)return void this._openingClick(s);if("merge"===this._tool)return void this._mergeClick(s);if("wallthick"===this._tool)return void this._wallThickClick(s);if("boundary"===this._tool)return void this._boundaryClick(s);if("split"===this._tool)return void this._splitClick(s);if("column"===this._tool)return void this._columnClick(s);this._wallRepairDiagnostic=null;const n=this._resolvePlanDrawPoint(s,t.shiftKey);if(n.ambiguous)return this._planSnapHover={contextKey:n.contextKey,candidate:null,conflicts:n.conflicts},this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers(n.conflicts),void this._showToast(this._t("toast.plan_snap_ambiguous"));let o=n.point;if(t.ctrlKey||t.metaKey){if(t.preventDefault(),this._path.length<3)return;o=ua(this._path[this._path.length-1],this._path[0])}if(!this._path.length){if(!t.shiftKey&&!n.candidate&&this._offerExistingWallFace(s))return;const e=this._draftEndAt(o);return e?(this._activeDraftId=e.draft.id,this._resumeDraftBySpace[this._space]=e.draft.id,this._path=e.reverse?[...e.draft.points].reverse().map(t=>[...t]):e.draft.points.map(t=>[...t]),void(this._draftSegmentCms=this._adoptDraftCms(this._path,e.reverse?[...e.draft.segments].reverse().map(t=>t.cm):e.draft.segments.map(t=>t.cm),e.draft.id))):(this._activeDraftId=null,this._draftSegmentCms=[],void(this._path=[o]))}const a=this._path[this._path.length-1];if(this._samePt(o,a))return;const r=this._draftEndAt(o,this._activeDraftId||void 0);if(r)return void this._mergeDraftEndpoint(r);if(!this._canAppendRoomDraftPoint())return;const l=this._drawWallCm;if(null==l)return void this._showPhysicalRange(100);const c=this._path.map(t=>[...t]);this._path=[...this._path,o],this._draftSegmentCms=[...this._draftSegmentCms,l],this._persistActiveDraftSegment(),this._offerWallFaces(c)}_draftEndAt(t,e){const i=this._spaceModel();if(!i)return null;const s=this._viewOr(this._baseVb()),n=Math.max(.15*this._gridPitch,this._stageEl?.clientWidth?s.w/this._stageEl.clientWidth*12:0);for(const s of i.room_drafts||[]){if(s.id===e)continue;if(s.points.length<2)continue;const i=s.points[0],o=s.points[s.points.length-1];if(Math.hypot(t[0]-o[0],t[1]-o[1])<=n)return{draft:s,reverse:!1};if(Math.hypot(t[0]-i[0],t[1]-i[1])<=n)return{draft:s,reverse:!0}}return null}_mergeDraftEndpoint(t){const e=this._curSpaceCfg;if(!e||!this._path.length)return;const i=this._path.map(t=>[...t]),s=this._wallGraphSources(i),n=Array.isArray(e.room_drafts)?e.room_drafts:[],o=this._activeDraftId?n.find(t=>t.id===this._activeDraftId):null,a=n.find(e=>e.id===t.draft.id);if(!a)return;const r=t.reverse?t.draft.points.map(t=>[...t]):[...t.draft.points].reverse().map(t=>[...t]),l=t.reverse?(a.segments||[]).map(t=>({...t})):[...a.segments||[]].reverse().map(t=>({...t})),c=this._path[this._path.length-1],h=this._samePt(c,r[0]),d=h?null:this._drawWallCm;if(!h&&null==d)return void this._showPhysicalRange(100);const p=this._draftSegmentsForPath(this._path,o,this._draftSegmentCms),u=[...this._path.map(t=>[...t]),...h?r.slice(1):r],_=[...p,...null==d?[]:[{cm:d}],...l],g=u.length>=4&&this._samePt(u[0],u[u.length-1]),m=u,f=_;if(m.length>500)return void this._showToast(this._t("toast.physical_limit"));const v=(o?.segments?.length||0)+(a.segments?.length||0);if(this._draftSegmentCount(e)-v+f.length>2e3)return void this._showToast(this._t("toast.physical_limit"));if(g){const t=m.slice(0,-1);if(this._contourSelfIntersects(t)||Ti(t)<=1e-6)return void this._showToast(this._t("toast.contour_cannot_close"));const e=this._overlapRoom(t);if(e)return void this._showToast(this._t("toast.room_overlap",{name:e.name||""}))}const y=this._geometrySnapshot(),b=this._activeDraftId||t.draft.id,w={...o||a,id:b,points:m.map(t=>[t[0]/ov,t[1]/ov]),segments:f};e.room_drafts=n.filter(e=>e.id!==t.draft.id&&(!this._activeDraftId||e.id!==this._activeDraftId)),e.room_drafts.push(w),this._activeDraftId=b,this._resumeDraftBySpace[this._space]=b,this._path=m,this._draftSegmentCms=this._adoptDraftCms(m,f.map(t=>Number(t.cm)),b),this._physicalSel=null,this._commitPhysicalGeometry(this._t("history.draft_merge"),y),null!=d&&this._offerWallFaces(i,i.length-1,s)}_adoptDraftCms(t,e,i){const s=Math.max(0,t.length-1),n=cu(s,e,this._drawWallCm,ll);return e.length!==s&&console.debug(`[houseplan] draft ${i??"?"}: восстановлено толщин ${s-e.length} (#234)`),n}_draftSegmentsForPath(t,e,i){const s=Array.isArray(e?.points)?e.points.map(t=>[Number(t?.[0])*ov,Number(t?.[1])*ov]):[],n=Array.isArray(e?.segments)?e.segments:[];return cu(Math.max(0,t.length-1),i,this._drawWallCm,ll).map((e,i)=>{const o=t[i],a=t[i+1],r=s.findIndex((t,e)=>{if(e+1>=s.length)return!1;const i=s[e+1];return this._samePt(o,t)&&this._samePt(a,i)||this._samePt(o,i)&&this._samePt(a,t)});return{...r>=0?n[r]:{},cm:e}})}_persistActiveDraftSegment(){if(this._path.length<2||!this._curSpaceCfg)return;const t=this._geometrySnapshot(),e=this._curSpaceCfg;e.room_drafts||=[],this._activeDraftId||(this._activeDraftId="draft-"+Date.now().toString(36)),this._resumeDraftBySpace[this._space]=this._activeDraftId;const i=e.room_drafts.findIndex(t=>t.id===this._activeDraftId),s={...i>=0?e.room_drafts[i]:{},id:this._activeDraftId,points:this._path.map(t=>[t[0]/ov,t[1]/ov]),segments:this._draftSegmentsForPath(this._path,i>=0?e.room_drafts[i]:null,this._draftSegmentCms)};i>=0?e.room_drafts[i]=s:e.room_drafts.push(s),this._commitPhysicalGeometry(this._t("history.draft_segment"),t)}_activeWallSourceKey(t){return`active:${this._activeDraftId||"session"}:${t}`}_wallGraphSources(t){const e=this._planStructuralGeometrySnapshot().value.segments.map(t=>({a:t.a,b:t.b,key:`static:${t.key}`}));for(let i=0;i+1t.key===i);if(s>=0){const[t]=this._wallFaceGraphCache.splice(s,1);return this._wallFaceGraphCache.push(t),t.value}const n=Iu(t,e);return this._wallFaceGraphCache.push({key:i,value:n}),this._wallFaceGraphCache.length>4&&this._wallFaceGraphCache.shift(),n}_offerWallFaces(t,e=this._path.length-2,i){if(this._path.length<2||this._wallFaceBatch||this._roomDialog)return;const s=this._spaceModel();if(!s)return;const n=this._activeWallSourceKey(e),o=2e-4*this._gridPitch;let a,r;try{const e=i||this._wallGraphSources(t);r=this._wallGraphSources(this._path),a=function(t,e,i){const s=new Set(t.faces.map(t=>t.key));return e.faces.filter(t=>!s.has(t.key)&&t.sourceKeys.includes(i))}(this._wallFaceGraph(e,o),this._wallFaceGraph(r,o),n)}catch{return}if(!a.length){const t=ju(r,{requiredSourceKey:n,maxDistance:ml(2,this._cellCm,this._gridPitch),gridStep:this._gridPitch,epsilon:o});return"ambiguous"===t.kind?(this._wallRepairDiagnostic=t.proposals[0]||null,void this._showToast(this._t("toast.wall_repair_ambiguous"))):void("repair"!==t.kind||this._overlapRoom(t.face.ring)||this._beginWallFaceBatch([{...t.face,repair:t.proposal}]))}for(const t of s.rooms){const e=hi(t);if(!t.id||!e)continue;const i=zi(e,this._path,.02*this._gridPitch);if(!i)continue;const[s,n]=i,o=Ti(s)>=Ti(n)?s:n,r=o===s?n:s,l=[...a].sort((t,e)=>Math.abs(t.area-Ti(r))-Math.abs(e.area-Ti(r))||t.key.localeCompare(e.key))[0];if(!l)return;return void this._beginWallFaceBatch([{...l,ring:r.map(t=>[t[0],t[1]]),split:{roomId:t.id,mainPoly:o,newPoly:r},consumeAllActive:!0}])}const l=a.filter(t=>!(t.ring.length<3||this._contourSelfIntersects(t.ring))&&!this._overlapRoom(t.ring));l.length&&this._beginWallFaceBatch(l)}_beginWallFaceBatch(t){this._wallRepairDiagnostic=null,this._wallFaceBatch={candidates:[...t].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key)),index:0,decisions:[],activePath:this._path.map(t=>[...t]),activeCms:[...this._draftSegmentCms],activeDraftId:this._activeDraftId},this._clearPlanSnapHover(),this._nameSel="",this._areaSel="",this._resetRoomDialogFields(),this._roomDialog=!0}_offerExistingWallFace(t){if(this._path.length||this._wallFaceBatch||this._roomDialog)return!1;const e=2e-4*this._gridPitch;try{let i,s=Au(this._wallFaceGraph(this._wallGraphSources([]),e),t,e);if(!s){const n=ju(this._wallGraphSources([]),{point:t,maxDistance:ml(2,this._cellCm,this._gridPitch),gridStep:this._gridPitch,epsilon:e});if("ambiguous"===n.kind)return this._wallRepairDiagnostic=n.proposals[0]||null,this._showToast(this._t("toast.wall_repair_ambiguous")),!0;if("repair"===n.kind)s=n.face,i=n.proposal;else if("none"===n.kind){const i=ju(this._wallGraphSources([]),{point:t,maxDistance:this._cssPxToRender(12),gridStep:this._gridPitch,epsilon:e});if("repair"===i.kind)return this._wallRepairDiagnostic=i.proposal,this._showToast(this._t("toast.wall_repair_too_large")),!0}}return!(!s||s.ring.length<3||this._contourSelfIntersects(s.ring)||this._overlapRoom(s.ring))&&(this._beginWallFaceBatch([{...s,existing:!i,repair:i}]),!0)}catch{return!1}}_columnClick(t){const e=this._snap(t),i=this._drawWallCm;if(null==i)return void this._showPhysicalRange(Wc);if(!this._curSpaceCfg||this._limitReached("column"))return;const s=this._spaceModel();if(!s)return;const n={id:"column-"+Date.now().toString(36),shape:"square",center:e,cm:Gc(i),angle:0},o=(s.wall_columns||[]).find(t=>ph(t,n,.02*this._gridPitch));if(o)return clearTimeout(this._duplicateColumnTimer),this._duplicateColumnId=o.id,this._duplicateColumnTimer=window.setTimeout(()=>{this._duplicateColumnId=null},900),void this._showToast(this._t("toast.column_duplicate"));const a=this._geometrySnapshot(),r=this._curSpaceCfg;r.wall_columns||=[],r.wall_columns.push({...n,center:[e[0]/ov,e[1]/ov]}),this._commitPhysicalGeometry(this._t("history.column_add"),a)}_openPhysicalDialog(t,e,i){const s=this._spaceModel();if(s)if("partition"===t){const i=s.partitions.find(t=>t.id===e);i&&(this._physicalDialog={kind:t,id:e,cm:gl(i.cm,this._imperial),length:this._fmtLen(i.a,i.b)})}else if("column"===t){const i=s.wall_columns.find(t=>t.id===e);i&&(this._physicalDialog={kind:t,id:e,cm:gl(i.cm,this._imperial),shape:i.shape,angle:this._angleField("square"===i.shape?Uc(i.angle):0)})}else{const n=s.room_drafts.find(t=>t.id===e),o=Math.max(0,Math.min(n?.segments.length?n.segments.length-1:0,i||0));n?.segments[o]&&(this._physicalDialog={kind:t,id:e,segment:o,cm:gl(n.segments[o].cm,this._imperial),length:this._fmtLen(n.points[o],n.points[o+1])})}}_physicalDown(t,e,i){const s=this._spaceModel();if(!s)return;t.stopPropagation(),uv(t);const n=this._svgPoint(t),o=[];for(const t of[...s.wall_columns].reverse())hh(n,Zc(t,this._cellCm,this._gridPitch))&&o.push({kind:"column",id:t.id});for(const t of[...s.partitions].reverse()){const e=Xc(t.a,t.b,t.cm,this._cellCm,this._gridPitch);e&&hh(n,e)&&o.push({kind:"partition",id:t.id})}o.some(t=>t.kind===e&&t.id===i)||o.unshift({kind:e,id:i});const a=o.map(t=>`${t.kind}:${t.id}`).sort().join("|"),r=performance.now(),l=this._physicalPickCycle,c=o.length>1&&l?.signature===a&&r-l.at>380&&r-l.at<=1200&&Math.hypot(t.clientX-l.x,t.clientY-l.y)<=10?(l.index+1)%o.length:Math.max(0,o.findIndex(t=>t.kind===e&&t.id===i));this._physicalPickCycle={signature:a,index:c,x:t.clientX,y:t.clientY,at:r},e=o[c].kind,i=o[c].id;const h="partition"===e?s.partitions.find(t=>t.id===i):s.wall_columns.find(t=>t.id===i);h&&(this._physicalSel={kind:e,id:i},this._physicalDrag={pid:t.pointerId,kind:e,id:i,start:this._svgPoint(t),startClient:[t.clientX,t.clientY],before:this._geometrySnapshot(),moved:!1,base:JSON.parse(JSON.stringify(h)),delta:[0,0]})}_clampPhysicalDelta(t,e,i){const s="partition"===t?[e.a,e.b]:[e.center],n=s.map(t=>t[0]),o=s.map(t=>t[1]);return[Math.max(-Sh*ov-Math.min(...n),Math.min(Sh*ov-Math.max(...n),i[0])),Math.max(-Sh*ov-Math.min(...o),Math.min(Sh*ov-Math.max(...o),i[1]))]}_physicalMove(t){const e=this._physicalDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._svgPoint(t),s="partition"===e.kind?e.base.a:e.base.center,n=this._snap([s[0]+i[0]-e.start[0],s[1]+i[1]-e.start[1]]),o=this._clampPhysicalDelta(e.kind,e.base,[n[0]-s[0],n[1]-s[1]]);this._physicalDrag={...e,delta:o,moved:e.moved||Math.hypot(t.clientX-e.startClient[0],t.clientY-e.startClient[1])>=5}}_physicalUp(t){const e=this._physicalDrag;if(!e||e.pid!==t.pointerId)return;if(t.stopPropagation(),this._physicalDrag=null,!e.moved)return void this._registerPhysicalTap(e.kind,e.id);const i=this._spaceModel();if(!this._curSpaceCfg||!i)return;const s=this._curSpaceCfg;if("partition"===e.kind){const t=(s.partitions||[]).find(t=>t.id===e.id),i=e.base;if(t){const n={...i,a:[i.a[0]+e.delta[0],i.a[1]+e.delta[1]],b:[i.b[0]+e.delta[0],i.b[1]+e.delta[1]]};t.a=[n.a[0]/ov,n.a[1]/ov],t.b=[n.b[0]/ov,n.b[1]/ov];for(const t of s.openings||[]){if("partition"!==t.host?.kind||t.host.id!==e.id)continue;const i=Np(t,[n],ov,this._cellCm,this._gridPitch).resolved;i&&Object.assign(t,jp(t,i,ov))}}}else{const t=(s.wall_columns||[]).find(t=>t.id===e.id),n=e.base,o={...n,center:[n.center[0]+e.delta[0],n.center[1]+e.delta[1]]};if(i.wall_columns.some(t=>t.id!==e.id&&ph(t,o,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"));t&&(t.center=[(n.center[0]+e.delta[0])/ov,(n.center[1]+e.delta[1])/ov])}this._commitPhysicalGeometry(this._t("history.physical_move"),e.before)}_registerPhysicalTap(t,e,i){const s=performance.now(),n=this._physicalLastTap?.kind===t&&this._physicalLastTap.id===e&&this._physicalLastTap.segment===i&&s-this._physicalLastTap.at<=360;this._physicalLastTap={kind:t,id:e,segment:i,at:s},n&&(this._physicalLastTap=null,this._openPhysicalDialog(t,e,i))}_cancelPhysicalGesture(){this._physicalDrag=null,this._physicalRotate=null,this.requestUpdate()}_physicalRotateDown(t,e){if("square"!==e.shape||!this._spaceModel())return;t.preventDefault(),t.stopPropagation(),uv(t);const i=this._svgPoint(t);this._physicalSel={kind:"column",id:e.id},this._physicalRotate={pid:t.pointerId,id:e.id,center:[...e.center],startAngle:180*Math.atan2(i[1]-e.center[1],i[0]-e.center[0])/Math.PI,baseAngle:Uc(e.angle),angle:Uc(e.angle),before:this._geometrySnapshot(),moved:!1}}_physicalRotateMove(t){const e=this._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation();const i=this._svgPoint(t),s=180*Math.atan2(i[1]-e.center[1],i[0]-e.center[0])/Math.PI,n=e.baseAngle+s-e.startAngle,o=Uc(t.shiftKey?n:5*Math.round(n/5));this._physicalRotate={...e,angle:o,moved:e.moved||Math.abs(n-e.baseAngle)>=.5}}_physicalRotateUp(t){const e=this._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation(),this._physicalRotate=null;const i=this._spaceModel();if(!e.moved||!this._curSpaceCfg||!i)return;const s=i.wall_columns.find(t=>t.id===e.id);if(!s||"square"!==s.shape)return;const n={...s,angle:e.angle};if(i.wall_columns.some(t=>t.id!==e.id&&ph(t,n,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"));const o=this._curSpaceCfg.wall_columns?.find(t=>t.id===e.id);o&&(o.angle=e.angle,this._commitPhysicalGeometry(this._t("history.physical_edit"),e.before))}_rszRooms(){const t=[],e=this._spaceModel();if(!e)return t;for(const i of e.rooms){const e=i.id?hi(i):null;e&&t.push({id:i.id,poly:e,wall_ids:Array.isArray(i.wall_ids)?[...i.wall_ids]:void 0})}return i=t,s=Math.max(1e-12,1e-12*this._gridPitch),i.map(t=>{if(!Array.isArray(t.wall_ids)||t.wall_ids.length!==t.poly.length)return{...t,poly:t.poly.map(t=>[...t])};const e=t.poly.map(t=>[...t]);let i=!0;for(;i&&e.length>3;){i=!1;for(let t=0;t0){e.splice(t,1),i=!0;break}}}return{...t,poly:e}});var i,s}_rszOpenings(){return this._openingsR.map(t=>({id:t.id,x:t.rx,y:t.ry,length:t.rlen,hosted:!!t.host,angle:t.angle,type:t.type}))}_rszObstacles(){const t=this._spaceModel();if(!t)return[];const e=[];for(const i of t.partitions||[])e.push({kind:"segment",a:[...i.a],b:[...i.b],half:ml(i.cm,this._cellCm,this._gridPitch)/2});for(const i of t.room_drafts||[])for(let t=0;t+1Array.isArray(t.a)&&Array.isArray(t.b)&&t.a.length>=2&&t.b.length>=2).map(t=>({wall:t,a:[t.a[0]*ov,t.a[1]*this._spaceH],b:[t.b[0]*ov,t.b[1]*this._spaceH]})),n=Math.abs(t[0]-e[0])<=.05*this._gridPitch?"v":Math.abs(t[1]-e[1])<=.05*this._gridPitch?"h":null,o=s.filter(i=>!!n&&("h"===n?!(Math.abs(i.a[1]-t[1])>.05*this._gridPitch||Math.abs(i.b[1]-t[1])>.05*this._gridPitch)&&Math.min(Math.max(t[0],e[0]),Math.max(i.a[0],i.b[0]))-Math.max(Math.min(t[0],e[0]),Math.min(i.a[0],i.b[0]))>.05*this._gridPitch:!(Math.abs(i.a[0]-t[0])>.05*this._gridPitch||Math.abs(i.b[0]-t[0])>.05*this._gridPitch)&&Math.min(Math.max(t[1],e[1]),Math.max(i.a[1],i.b[1]))-Math.max(Math.min(t[1],e[1]),Math.min(i.a[1],i.b[1]))>.05*this._gridPitch)),a=new Set(o.map(t=>Number(t.wall.cm)).filter(t=>t>0));return{minDim:this._cmToUnits(30),eps:.05*this._gridPitch,step:this._gridPitch,movingHalf:i>0?ml(i,this._cellCm,this._gridPitch)/2:0,obstacles:this._rszObstacles(),thicknessConflict:a.size>1}}_rszResolution(t,e,i){const s=this._rszDrag?.snap||i||this._rszSnapshot(),n=`${this._space}|${this._cellCm}|${this._gridPitch}|${s}`;this._rszEligibilityCache&&this._rszEligibilityCache.key===n||(this._rszEligibilityCache={key:n,values:new Map});const o=`${t}:${e}`,a=this._rszEligibilityCache.values.get(o);if(a)return a;const r=this._rszDrag?.rooms||this._rszRooms(),l=r.find(e=>e.id===t),c=l?.poly?.[e]||[0,0],h=l?.poly?.[(e+1)%(l?.poly?.length||1)]||[0,0],d=function(t,e,i,s,n){const{eps:o}=n,a=t.find(t=>t.id===i);if(!a||s<0||s>=(a.poly?.length||0)||a.poly.length<4||!Ia(a.poly))return{enabled:!1,reason:"invalid-geometry"};const r=a.poly[s],l=a.poly[(s+1)%a.poly.length],c=Ea(r,l,o);if(!c)return{enabled:!1,reason:"diagonal"};if(!Ha(a.poly,s,c,o))return{enabled:!1,reason:"side-angle"};if(n.thicknessConflict)return{enabled:!1,reason:"thickness-conflict"};for(const t of n.obstacles||[])if(Wa(t,r,l,n))return{enabled:!1,reason:"duplicate-physical-wall"};const h=Da(Sa(l,r)),d=[],p=new Set;let u=!1,_=!1;for(const e of t)if(e.id!==i)for(let t=0;t1||d.length>1)return{enabled:!1,reason:"multiple-rooms"};const g={[i]:s},m=[i];if(1===d.length){const t=d[0];if(!Ia(t.room.poly))return{enabled:!1,reason:"invalid-geometry"};if(!Ha(t.room.poly,t.edge,c,o))return{enabled:!1,reason:"side-angle"};m.push(t.room.id),g[t.room.id]=t.edge}const f=[];for(const t of e)if(!(Ta([t.x,t.y],r,l)>2*o)){if(t.hosted||t.length>h+2*o)return{enabled:!1,reason:"opening-conflict"};f.push(t.id)}const v=Object.fromEntries(m.map(e=>[e,t.find(t=>t.id===e).poly.length])),y=[];for(const e of m){const i=t.find(t=>t.id===e),s=g[e],n=(s-1+i.poly.length)%i.poly.length,a=(s+1)%i.poly.length,r=Ua(t,e,n,1,o),l=Ua(t,e,a,0,o);if(!r||!l)return{enabled:!1,reason:"partial-shared"};y.push(r,l)}const b={roomId:i,edge:s,a:[...r],b:[...l],n:Ra(a.poly,s),roomIds:m,edgeByRoom:g,topology:v,movingOpeningIds:f,sideOwnership:y};if(!Qa(t,e,b,0,n))return{enabled:!1,reason:"invalid-geometry"};const w=Math.abs(Number(n.step));if(Number.isFinite(w)&&w>o){const i=[-w,w];if(!i.some(i=>Qa(t,e,b,i,n))){if(!i.some(i=>Ya(Ja(t,e,b,i),b,o)))return{enabled:!1,reason:"partial-shared"};const s={...n,obstacles:[]};return i.some(i=>Qa(t,e,b,i,s))?{enabled:!1,reason:"duplicate-physical-wall"}:e.length&&i.some(e=>Qa(t,[],b,e,n))?{enabled:!1,reason:"opening-conflict"}:{enabled:!1,reason:"invalid-geometry"}}}return{enabled:!0,plan:b}}(r,this._rszDrag?.openings||this._rszOpenings(),t,e,this._rszOptsFor(c,h));return this._rszEligibilityCache.values.set(o,d),d}_rszSnapshot(){return JSON.stringify(this._geometrySnapshot()||{spaceId:this._space,rooms:[],openings:[],walls:[],open_spans:[]})}_rszApplyPreview(t,e){const i=this._rszDrag,s=this._serverCfg?.spaces.find(t=>t.id===this._space);if(!i||!s||!this._serverCfg)return{ok:!1,reason:"missing-context"};const n=JSON.parse(i.snap),o={...s,rooms:n.rooms,openings:n.openings||[]};for(const t of["walls","open_spans","room_drafts","partitions","wall_columns","decor"])void 0!==n[t]?o[t]=n[t]:delete o[t];for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==n.plan_transform?.[t]?o[t]=n.plan_transform[t]:delete o[t];const a=this._spaceH;for(const[e,i]of Object.entries(t)){const t=o.rooms.find(t=>t.id===e);t&&(t.poly=i.map(t=>[t[0]/ov,t[1]/a]),delete t.x,delete t.y,delete t.w,delete t.h)}for(const[t,i]of Object.entries(e)){const e=(o.openings||[]).find(e=>e.id===t);e&&(e.x=i[0]/ov,e.y=i[1]/a)}const r=[],l=[];for(const t of i.changed){const e=i.rooms.find(e=>e.id===t),s=o.rooms.find(e=>e.id===t);if(!e||!s?.poly)continue;const n=s.poly.map(t=>[t[0]*ov,t[1]*a]);if(e.poly.length===n.length)for(let t=0;t{a=!0});return{walls:a?(t||[]).map(t=>({...t})):r,rejected:a}}(o.walls,r,l,this._wallKeyPitch,ov,"fixed-topology");if(t.rejected)return{ok:!1,reason:"wall-metadata"};o.walls=t.walls}}const c=t=>t.map(t=>Number(t.cm)).sort((t,e)=>t-e),h=c(n.walls||[]),d=c(o.walls||[]);if(JSON.stringify(h)!==JSON.stringify(d))return{ok:!1,reason:"wall-metadata"};if((n.open_spans||[]).length!==(o.open_spans||[]).length)return{ok:!1,reason:"open-span-metadata"};const p=[];for(const t of o.rooms||[]){const e=hi(t);if(e&&!(e.length<2))for(let t=0;tJSON.stringify([t?.key,t?.cm,t?.a,t?.b]),_=new Map;for(const t of n.walls||[]){const e=u(t);_.set(e,(_.get(e)||0)+1)}const g=[];for(const t of o.walls||[]){const e=u(t),i=_.get(e)||0;i?_.set(e,i-1):g.push(t)}return zl(g,p,this._wallKeyPitch,ov,n.walls||[]).length?{ok:!1,reason:"wall-metadata"}:this._rszSpaceCandidateRenderable(this._space,o)?(this._rszPreview={space:this._space,sp:o},this._cfgEpoch++,{ok:!0}):{ok:!1,reason:"physical-geometry"}}_rszSpaceCandidateRenderable(t,e){if(!this._serverCfg)return!1;try{const i={...this._serverCfg,spaces:this._serverCfg.spaces.map(i=>i.id===t?e:i)};return this._checkSpacePhysicalGeometry(i,t).ok}catch{return!1}}_rszCandidateRenderable(t){return!!t&&t.space===this._space&&this._rszPreview===t&&this._rszSpaceCandidateRenderable(t.space,t.sp)}_rszEdgeDown(t,e,i){if("resize"!==this._tool||this._rszDrag)return;t.stopPropagation(),t.preventDefault();const s=this._rszRooms(),n=this._rszResolution(e,i);if(!n.enabled)return void this._showToast(this._rszReasonText(n.reason));uv(t);const o=n.plan,a=this._svgPoint(t);this._rszDrag={pid:t.pointerId,start:[a[0],a[1]],roomId:e,plan:o,opts:this._rszOptsFor(o.a,o.b),rooms:s,openings:this._rszOpenings(),snap:this._rszSnapshot(),moved:!1,d:0,changed:[...o.roomIds],rejectNotified:!1}}_rszReasonText(t){return this._t(`resize.disabled.${t}`)}_rszDisabledActivate(t,e){t.stopPropagation(),t.preventDefault(),this._showToast(this._rszReasonText(e))}_rszDisabledKey(t,e){"Enter"!==t.key&&" "!==t.key||this._rszDisabledActivate(t,e)}_rszMove(t){const e=this._rszDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._svgPoint(t),s=e.plan,n=(o=e.start,a=i,r=s.n,[o?.[0],o?.[1],a?.[0],a?.[1],r?.[0],r?.[1]].every(Number.isFinite)?(a[0]-o[0])*r[0]+(a[1]-o[1])*r[1]:0);var o,a,r;const l=this._snap([s.a[0]+s.n[0]*n,s.a[1]+s.n[1]*n]),c=(l[0]-s.a[0])*s.n[0]+(l[1]-s.a[1])*s.n[1];let h=function(t,e,i,s,n,o){if(!Number.isFinite(s)||Math.abs(s)<1e-9)return 0;const a=Math.sign(s),r=Math.abs(s),l=Math.max(Math.abs(n),1e-6);let c=tr.get(i);c&&c.opts===o||(c={opts:o,values:new Map},tr.set(i,c));const h=c.values;let d=0;for(let s=Math.min(l,r),n=0;n<4096&&s<=r+1e-9;n++,s=Math.min(r,s+l)){const n=a*s,c=`${n.toFixed(9)}|${l.toFixed(9)}`;let p=h.get(c);if(void 0===p&&(p=Qa(t,e,i,n,o),h.size<4096&&h.set(c,p)),!p)break;if(d=n,Math.abs(s-r)<=1e-9)break}return d}(e.rooms,e.openings,s,c,this._gridPitch,e.opts);if(h===e.d&&e.moved)return;const d=this._rszPreview,p=this._rszLive,u=e.d;let _=Ja(e.rooms,e.openings,s,h);if(!this._rszApplyPreview(_.polys,_.openings).ok)return this._rszPreview=d,this._rszLive=p,e.d=u,e.rejectNotified||(e.rejectNotified=!0,this._showToast(this._t("resize.preview_failed"))),void this.requestUpdate();e.moved=!0,e.changed=[...s.roomIds],e.d=h,this._rszLive=this._rszEdgeLabels(_,s),this.requestUpdate()}_rszUp(t){const e=this._rszDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._rszPreview,s=e.moved&&Math.abs(e.d)>1e-9,n=this._rszSnapshot()===e.snap,o=Qa(e.rooms,e.openings,e.plan,e.d,e.opts),a=this._rszCandidateRenderable(i);if(this._rszDrag=null,this._rszLive=null,this._rszPreview=null,!s||!i)return this._cfgEpoch++,void this.requestUpdate();if(!n||!o||!a)return this._cfgEpoch++,this._showToast(this._t("resize.commit_failed")),void this.requestUpdate();const r=JSON.parse(e.snap),l=this._curSpaceCfg;l&&(l.rooms=i.sp.rooms,l.openings=i.sp.openings,Array.isArray(i.sp.walls)&&(i.sp.walls.length?l.walls=i.sp.walls:delete l.walls),Array.isArray(i.sp.open_spans)&&i.sp.open_spans.length?l.open_spans=i.sp.open_spans:delete l.open_spans),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._commitPhysicalGeometry(this._t("history.resize_room"),r),this._rszEligibilityCache=null,this.requestUpdate()}_rszCancelDrag(){this._rszDrag&&(this._rszDrag=null,this._rszLive=null,this._rszPreview=null,this._cfgEpoch++,this.requestUpdate())}_rszPointerCancel(t){const e=this._rszDrag;e&&e.pid===t.pointerId&&(t.stopPropagation(),this._rszCancelDrag())}_rszEdgeLabels(t,e){const i=this._rszDrag,s=[],n=t.polys[e.roomId]||i.rooms.find(t=>t.id===e.roomId).poly,o=n.length,a=this._rszInnerSpanCms(e.roomId,n,t.polys);for(const t of function(t,e){const i=t.length;return[(e-1+i)%i,(e+1)%i]}(n,e.edge)){const e=n[t],i=n[(t+1)%o],r=a?.[t];s.push({kind:"length",x:(e[0]+i[0])/2,y:(e[1]+i[1])/2,text:null==r?this._fmtLen(e,i):li(r,"mi"===this.hass?.config?.unit_system?.length),edge:{a:[e[0],e[1]],b:[i[0],i[1]]}})}const r="mi"===this.hass?.config?.unit_system?.length,l=e.roomIds,c=this._spaceWalls,h=this._openPairs().flatMap(t=>t.segs),d=this._physicalBodiesR(),p=this._baseVb(),u=this._view&&this._view.w>0&&this._view.h>0?this._view:{x:p[0],y:p[1],w:p[2],h:p[3]},[_,g]=this._lastValidStageSize||[u.w,u.h],m={...u,stageWidth:Math.max(1,_),stageHeight:Math.max(1,g)},f=this._spaceModel(),v=this._config?.icon_size??2.5,y=f?Uh(v>8?2.5:v,f,u.w,this._kiosk?this._kioskScale.icon:1)*m.stageWidth/100:24,b=Math.max(10,.77*y),w=this._t("room.settings_short"),k=b*(1.457+.66*Math.max(1,w.length)*.42);for(const n of l){const o=t.polys[n]||i.rooms.find(t=>t.id===n).poly,a=c.length&&fc(Object.entries(t.polys).map(([t,e])=>({id:t,poly:e})),n,c,h,this._wallKeyPitch,this._cellCm,this._gridPitch,ov)||o,l=ir(d.length?rh(ah(a,d))*Math.pow(this._cellCm/this._gridPitch,2)/1e4:er(a,this._gridPitch,this._cellCm),r),p=nr({poly:o,edge:e.edgeByRoom[n],text:l,view:m,gearCenter:$i(o),gearWidthPx:k,gearHeightPx:b});s.push({kind:"area",roomId:n,x:p.anchor[0],y:p.anchor[1],text:l,placement:p})}return s}_rszInnerSpanCms(t,e,i){const s=Object.keys(i).length?Object.entries(i).map(([t,e])=>({id:t,poly:e})):this._spaceModel()?.rooms;if(!s?.length)return null;const n=this._spaceWalls;if(!n.length)return null;const o=function(t,e,i,s,n,o,a,r=1){const l=(t||[]).find(t=>t?.id===e),c=hi(l);if(!c||c.length<3)return null;const h=hc(t,e,i,s,n,o,a,r);if(!h)return c.map(()=>0);const d=4*Vl(n,r);return c.map((t,e)=>{const i=c[(e+1)%c.length],s=[(t[0]+i[0])/2,(t[1]+i[1])/2];for(let t=0;tt.segs),this._wallKeyPitch,this._cellCm,this._gridPitch,ov);if(!o||o.length!==e.length)return null;const a=this._cellCm/this._gridPitch;return e.map((t,i)=>function(t,e,i){const s=t?.length||0;if(s<3||!Array.isArray(i)||i.length!==s)return 0;const n=(Math.trunc(e)%s+s)%s,o=t[n],a=t[(n+1)%s],r=a[0]-o[0],l=a[1]-o[1],c=Math.hypot(r,l);if(!(c>0))return 0;const h=Math.max(0,Number(i[n])||0);if(!(h>0))return c;const d=[r/c,l/c],p=Yl(t,n),u=[o[0]+p[0]*h,o[1]+p[1]*h],_=e=>{const n=Math.max(0,Number(i[e])||0);if(!(n>0))return null;const a=t[e],r=t[(e+1)%s],l=r[0]-a[0],c=r[1]-a[1],h=Math.hypot(l,c);if(!(h>0))return null;const p=Yl(t,e),_=Xl(u,d,[a[0]+p[0]*n,a[1]+p[1]*n],[l/h,c/h]);return _?(_[0]-o[0])*d[0]+(_[1]-o[1])*d[1]:null},g=_((n-1+s)%s)??0,m=(_((n+1)%s)??c)-g;return m>0?m:0}(e,i,o)*a)}_renderResizeMeasurements(){if(!this._rszLive?.length)return U;const t=this._rszLive.filter(t=>"length"===t.kind),e=this._rszLive.filter(t=>"area"===t.kind);return j`
${t.map((t,e)=>j`