diff --git a/custom_components/houseplan/frontend/houseplan-card.js b/custom_components/houseplan/frontend/houseplan-card.js index d6c333ba..a3322d42 100755 --- a/custom_components/houseplan/frontend/houseplan-card.js +++ b/custom_components/houseplan/frontend/houseplan-card.js @@ -1,4 +1,4 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4e36f45244a923a0f5aa01407a993";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),s=new WeakMap;let n=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const i=this.t;if(e&&void 0===t){const e=void 0!==i&&1===i.length;e&&(t=s.get(i)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&s.set(i,t))}return t}toString(){return this.cssText}};const o=(t,...e)=>{const s=1===t.length?t[0]:e.reduce((e,i,s)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+t[s+1],t[0]);return new n(s,t,i)},a=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return(t=>new n("string"==typeof t?t:t+"",void 0,i))(e)})(t):t,{is:r,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:p}=Object,u=globalThis,_=u.trustedTypes,m=_?_.emptyScript:"",g=u.reactiveElementPolyfillSupport,f=(t,e)=>t,v={toAttribute(t,e){switch(e){case Boolean:t=t?m:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let i=t;switch(e){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},y=(t,e)=>!r(t,e),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),u.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=b){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const i=Symbol(),s=this.getPropertyDescriptor(t,i,e);void 0!==s&&l(this.prototype,t,s)}}static getPropertyDescriptor(t,e,i){const{get:s,set:n}=c(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:s,set(e){const o=s?.call(this);n?.call(this,e),this.requestUpdate(t,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(f("elementProperties")))return;const t=p(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(f("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(f("properties"))){const t=this.properties,e=[...h(t),...d(t)];for(const i of e)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const i=this._$Eu(t,e);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const t of i)e.unshift(a(t))}else void 0!==t&&e.push(a(t));return e}static _$Eu(t,e){const i=e.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const i of e.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,s)=>{if(e)i.adoptedStyleSheets=s.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of s){const s=document.createElement("style"),n=t.litNonce;void 0!==n&&s.setAttribute("nonce",n),s.textContent=e.cssText,i.appendChild(s)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,i){this._$AK(t,i)}_$ET(t,e){const i=this.constructor.elementProperties.get(t),s=this.constructor._$Eu(t,i);if(void 0!==s&&!0===i.reflect){const n=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(e,i.type);this._$Em=t,null==n?this.removeAttribute(s):this.setAttribute(s,n),this._$Em=null}}_$AK(t,e){const i=this.constructor,s=i._$Eh.get(t);if(void 0!==s&&this._$Em!==s){const t=i.getPropertyOptions(s),n="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:v;this._$Em=s;const o=n.fromAttribute(e,t.type);this[s]=o??this._$Ej?.get(s)??o,this._$Em=null}}requestUpdate(t,e,i,s=!1,n){if(void 0!==t){const o=this.constructor;if(!1===s&&(n=this[t]),i??=o.getPropertyOptions(t),!((i.hasChanged??y)(n,e)||i.useDefault&&i.reflect&&n===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,i))))return;this.C(t,e,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:i,reflect:s,wrapped:n},o){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,o??e??this[t]),!0!==n||void 0!==o)||(this._$AL.has(t)||(this.hasUpdated||i||(e=void 0),this._$AL.set(t,e)),!0===s&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,i]of t){const{wrapped:t}=i,s=this[e];!0!==t||this._$AL.has(e)||void 0===s||this.C(e,void 0,i,s)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[f("elementProperties")]=new Map,w[f("finalized")]=new Map,g?.({ReactiveElement:w}),(u.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,x=t=>t,$=k.trustedTypes,S=$?$.createPolicy("lit-html",{createHTML:t=>t}):void 0,M="$lit$",C=`lit$${Math.random().toFixed(9).slice(2)}$`,D="?"+C,P=`<${D}>`,T=document,R=()=>T.createComment(""),I=t=>null===t||"object"!=typeof t&&"function"!=typeof t,A=Array.isArray,z="[ \t\n\f\r]",F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,E=/-->/g,N=/>/g,O=RegExp(`>|${z}(?:([^\\s"'>=/]+)(${z}*=${z}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,H=/"/g,B=/^(?:script|style|textarea|title)$/i,q=t=>(e,...i)=>({_$litType$:t,strings:e,values:i}),W=q(1),j=q(2),U=Symbol.for("lit-noChange"),G=Symbol.for("lit-nothing"),V=new WeakMap,K=T.createTreeWalker(T,129);function Y(t,e){if(!A(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(e):e}const J=(t,e)=>{const i=t.length-1,s=[];let n,o=2===e?"":3===e?"":"",a=F;for(let e=0;e"===l[0]?(a=n??F,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?O:'"'===l[3]?H:L):a===H||a===L?a=O:a===E||a===N?a=F:(a=O,n=void 0);const d=a===O&&t[e+1].startsWith("/>")?" ":"";o+=a===F?i+P:c>=0?(s.push(r),i.slice(0,c)+M+i.slice(c)+C+d):i+C+(-2===c?e:d)}return[Y(t,o+(t[i]||"")+(2===e?"":3===e?"":"")),s]};class X{constructor({strings:t,_$litType$:e},i){let s;this.parts=[];let n=0,o=0;const a=t.length-1,r=this.parts,[l,c]=J(t,e);if(this.el=X.createElement(l,i),K.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(s=K.nextNode())&&r.length0){s.textContent=$?$.emptyScript:"";for(let i=0;iA(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==G&&I(this._$AH)?this._$AA.nextSibling.data=t:this.T(T.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:i}=t,s="number"==typeof i?this._$AC(t):(void 0===i.el&&(i.el=X.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===s)this._$AH.p(e);else{const t=new Q(s,this),i=t.u(this.options);t.p(e),this.T(i),this._$AH=t}}_$AC(t){let e=V.get(t.strings);return void 0===e&&V.set(t.strings,e=new X(t)),e}k(t){A(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let i,s=0;for(const n of t)s===e.length?e.push(i=new tt(this.O(R()),this.O(R()),this,this.options)):i=e[s],i._$AI(n),s++;s2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=G}_$AI(t,e=this,i,s){const n=this.strings;let o=!1;if(void 0===n)t=Z(this,t,e,0),o=!I(t)||t!==this._$AH&&t!==U,o&&(this._$AH=t);else{const s=t;let a,r;for(t=n[0],a=0;a{const s=i?.renderBefore??e;let n=s._$litPart$;if(void 0===n){const t=i?.renderBefore??null;s._$litPart$=n=new tt(e.insertBefore(R(),t),t,void 0,i??{})}return n._$AI(t),n},ct=globalThis;let ht=class extends w{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=lt(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return U}};ht._$litElement$=!0,ht.finalized=!0,ct.litElementHydrateSupport?.({LitElement:ht});const dt=ct.litElementPolyfillSupport;dt?.({LitElement:ht}),(ct.litElementVersions??=[]).push("4.2.2");const pt=2,ut=t=>(...e)=>({_$litDirective$:t,values:e});let _t=class{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,i){this._$Ct=t,this._$AM=e,this._$Ci=i}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}};const mt={},gt=ut(class extends _t{constructor(){super(...arguments),this.ot=mt}render(t,e){return e()}update(t,[e,i]){if(Array.isArray(e)){if(Array.isArray(this.ot)&&this.ot.length===e.length&&e.every((t,e)=>t===this.ot[e]))return U}else if(this.ot===e)return U;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}}),{I:ft}=at,vt=t=>t,yt=()=>document.createComment(""),bt=(t,e,i)=>{const s=t._$AA.parentNode,n=void 0===e?t._$AB:e._$AA;if(void 0===i){const e=s.insertBefore(yt(),n),o=s.insertBefore(yt(),n);i=new ft(e,o,t,t.options)}else{const e=i._$AB.nextSibling,o=i._$AM,a=o!==t;if(a){let e;i._$AQ?.(t),i._$AM=t,void 0!==i._$AP&&(e=t._$AU)!==o._$AU&&i._$AP(e)}if(e!==n||a){let t=i._$AA;for(;t!==e;){const e=vt(t).nextSibling;vt(s).insertBefore(t,n),t=e}}}return i},wt=(t,e,i=t)=>(t._$AI(e,i),t),kt={},xt=(t,e=kt)=>t._$AH=e,$t=t=>{t._$AR(),t._$AA.remove()},St=(t,e,i)=>{const s=new Map;for(let n=e;n<=i;n++)s.set(t[n],n);return s},Mt=ut(class extends _t{constructor(t){if(super(t),t.type!==pt)throw Error("repeat() can only be used in text expressions")}dt(t,e,i){let s;void 0===i?i=e:void 0!==e&&(s=e);const n=[],o=[];let a=0;for(const e of t)n[a]=s?s(e,a):a,o[a]=i(e,a),a++;return{values:o,keys:n}}render(t,e,i){return this.dt(t,e,i).values}update(t,[e,i,s]){const n=(t=>t._$AH)(t),{values:o,keys:a}=this.dt(e,i,s);if(!Array.isArray(n))return this.ut=a,o;const r=this.ut??=[],l=[];let c,h,d=0,p=n.length-1,u=0,_=o.length-1;for(;d<=p&&u<=_;)if(null===n[d])d++;else if(null===n[p])p--;else if(r[d]===a[u])l[u]=wt(n[d],o[u]),d++,u++;else if(r[p]===a[_])l[_]=wt(n[p],o[_]),p--,_--;else if(r[d]===a[_])l[_]=wt(n[d],o[_]),bt(t,l[_+1],n[d]),d++,_--;else if(r[p]===a[u])l[u]=wt(n[p],o[u]),bt(t,n[d],n[p]),p--,u++;else if(void 0===c&&(c=St(a,u,_),h=St(r,d,p)),c.has(r[d]))if(c.has(r[p])){const e=h.get(a[u]),i=void 0!==e?n[e]:null;if(null===i){const e=bt(t,n[d]);wt(e,o[u]),l[u]=e}else l[u]=wt(i,o[u]),bt(t,n[d],i),n[e]=null;u++}else $t(n[p]),p--;else $t(n[d]),d++;for(;u<=_;){const e=bt(t,l[_+1]);wt(e,o[u]),l[u++]=e}for(;d<=p;){const t=n[d++];null!==t&&$t(t)}return this.ut=a,xt(t,l),U}}),Ct=new WeakMap;let Dt=0;class Pt extends ht{constructor(){super(...arguments),this.title="",this.icon="",this.wide=!1,this.dismissOnScrim=!1,this.hass=null,this._opener=null,this._focusRoot=null,this._useHaDialog=!1,this._closing=!1,this._overlays=[],this._titleId="hp-dialog-title-"+ ++Dt,this._focusInitial=()=>{const t=this._focusableElements(),e=t.find(t=>t.hasAttribute("autofocus"))||t[0]||(this._useHaDialog?null:this.renderRoot.querySelector(".close"))||this.renderRoot.querySelector(".surface")||this.renderRoot.querySelector("ha-dialog");e?.focus({preventScroll:!0})},this._requestClose=()=>{this._closing||(this._closing=!0,this.dispatchEvent(new CustomEvent("hp-close",{bubbles:!0,composed:!0})))},this._onKeyDown=t=>{if("Escape"===t.key){t.preventDefault(),t.stopImmediatePropagation(),this._pruneOverlays();const e=this._overlays[this._overlays.length-1];return e?void this._closeOverlay(e,"escape"):void this._requestClose()}if("Tab"!==t.key||this._useHaDialog)return;const e=this.renderRoot.querySelector(".close"),i=e?[e,...this._focusableElements()]:this._focusableElements();if(!i.length)return t.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const s=this._deepActiveElement(),n=i[0],o=i[i.length-1];!t.shiftKey||s!==n&&i.includes(s)?t.shiftKey||s!==o||(t.preventDefault(),n.focus()):(t.preventDefault(),o.focus())},this._onFallbackCancel=t=>{t.preventDefault(),this._requestClose()},this._onFallbackClick=t=>{this.dismissOnScrim&&t.target===t.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const t=this.getRootNode();this._focusRoot=t;const e=Ct.get(t)||{dialogs:new Set,opener:this._opener};e.dialogs.add(this),Ct.set(t,e),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const t=[...this._overlays];this._overlays=[];for(const e of t.reverse())e.close("disconnect");const e=this._focusRoot,i=this._opener;this._opener=null,this._focusRoot=null;const s=e?Ct.get(e):void 0;s?.dialogs.delete(this),super.disconnectedCallback(),e&&s&&requestAnimationFrame(()=>{const t=Ct.get(e);if(!t)return;if(!t.dialogs.size)return t.opener?.isConnected&&t.opener.focus({preventScroll:!0}),void Ct.delete(e);const s=i?.closest("hp-dialog");i?.isConnected&&s&&t.dialogs.has(s)&&i.focus({preventScroll:!0})})}firstUpdated(t){if(super.firstUpdated(t),!this._useHaDialog){const t=this.renderRoot.querySelector("dialog");t&&!t.open&&t.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let t=document.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t&&t!==document.body?t:null}_focusableElements(){const t=["[autofocus]","a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[contenteditable="true"]','[tabindex]:not([tabindex="-1"])'].join(","),e=[],i=new Set,s=n=>{if(!i.has(n)){if(i.add(n),n instanceof HTMLElement){if(n.matches(t)&&e.push(n),n instanceof HTMLSlotElement){for(const t of n.assignedNodes({flatten:!0}))s(t);return}if(n.shadowRoot){for(const t of n.shadowRoot.childNodes)s(t);return}}for(const t of n.childNodes)s(t)}};for(const t of this.childNodes)s(t);const n=this.overlayPortal();return n&&s(n),e.filter(t=>{let e=t;for(;e;){const t=getComputedStyle(e);if(e.hidden||e.inert||"true"===e.getAttribute("aria-hidden")||"none"===t.display||"hidden"===t.visibility)return!1;if(e=e.assignedSlot||e.parentElement||(e.getRootNode()instanceof ShadowRoot?e.getRootNode().host:null),e===this)break}return!0})}_pruneOverlays(){this._overlays=this._overlays.filter(t=>t.owner.isConnected)}_closeOverlay(t,e){const i=this._overlays.findIndex(e=>e.token===t.token);i>=0&&this._overlays.splice(i,1),t.close(e)}registerOverlay(t){this._pruneOverlays();const e=this._overlays.find(e=>e.owner===t.owner);e&&this._overlays.splice(this._overlays.indexOf(e),1);const i=t.group||"transient";for(const t of[...this._overlays].reverse())t.group===i&&this._closeOverlay(t,"exclusive");const s={...t,group:i,token:Symbol("hp-overlay")};this._overlays.push(s);let n=!1;return()=>{if(n)return;n=!0;const t=this._overlays.findIndex(t=>t.token===s.token);t>=0&&this._overlays.splice(t,1)}}closeTransientOverlays(t="outside"){this._pruneOverlays();const e=[...this._overlays].filter(t=>"transient"===(t.group||"transient"));for(const i of e.reverse())this._closeOverlay(i,t);return e.length>0}overlayPortal(){return this.renderRoot.querySelector(".overlay-portal")}render(){const t=W` +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="29ac1cf640f37bd2a809801d01750209abd89e2daef0881131c63e2d41c17bf7";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),s=new WeakMap;let n=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const i=this.t;if(e&&void 0===t){const e=void 0!==i&&1===i.length;e&&(t=s.get(i)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&s.set(i,t))}return t}toString(){return this.cssText}};const o=(t,...e)=>{const s=1===t.length?t[0]:e.reduce((e,i,s)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+t[s+1],t[0]);return new n(s,t,i)},a=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return(t=>new n("string"==typeof t?t:t+"",void 0,i))(e)})(t):t,{is:r,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:p}=Object,u=globalThis,_=u.trustedTypes,m=_?_.emptyScript:"",g=u.reactiveElementPolyfillSupport,f=(t,e)=>t,v={toAttribute(t,e){switch(e){case Boolean:t=t?m:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let i=t;switch(e){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},y=(t,e)=>!r(t,e),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),u.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=b){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const i=Symbol(),s=this.getPropertyDescriptor(t,i,e);void 0!==s&&l(this.prototype,t,s)}}static getPropertyDescriptor(t,e,i){const{get:s,set:n}=c(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:s,set(e){const o=s?.call(this);n?.call(this,e),this.requestUpdate(t,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(f("elementProperties")))return;const t=p(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(f("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(f("properties"))){const t=this.properties,e=[...h(t),...d(t)];for(const i of e)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const i=this._$Eu(t,e);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const t of i)e.unshift(a(t))}else void 0!==t&&e.push(a(t));return e}static _$Eu(t,e){const i=e.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const i of e.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,s)=>{if(e)i.adoptedStyleSheets=s.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of s){const s=document.createElement("style"),n=t.litNonce;void 0!==n&&s.setAttribute("nonce",n),s.textContent=e.cssText,i.appendChild(s)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,i){this._$AK(t,i)}_$ET(t,e){const i=this.constructor.elementProperties.get(t),s=this.constructor._$Eu(t,i);if(void 0!==s&&!0===i.reflect){const n=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(e,i.type);this._$Em=t,null==n?this.removeAttribute(s):this.setAttribute(s,n),this._$Em=null}}_$AK(t,e){const i=this.constructor,s=i._$Eh.get(t);if(void 0!==s&&this._$Em!==s){const t=i.getPropertyOptions(s),n="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:v;this._$Em=s;const o=n.fromAttribute(e,t.type);this[s]=o??this._$Ej?.get(s)??o,this._$Em=null}}requestUpdate(t,e,i,s=!1,n){if(void 0!==t){const o=this.constructor;if(!1===s&&(n=this[t]),i??=o.getPropertyOptions(t),!((i.hasChanged??y)(n,e)||i.useDefault&&i.reflect&&n===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,i))))return;this.C(t,e,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:i,reflect:s,wrapped:n},o){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,o??e??this[t]),!0!==n||void 0!==o)||(this._$AL.has(t)||(this.hasUpdated||i||(e=void 0),this._$AL.set(t,e)),!0===s&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,i]of t){const{wrapped:t}=i,s=this[e];!0!==t||this._$AL.has(e)||void 0===s||this.C(e,void 0,i,s)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[f("elementProperties")]=new Map,w[f("finalized")]=new Map,g?.({ReactiveElement:w}),(u.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,x=t=>t,$=k.trustedTypes,S=$?$.createPolicy("lit-html",{createHTML:t=>t}):void 0,M="$lit$",C=`lit$${Math.random().toFixed(9).slice(2)}$`,D="?"+C,P=`<${D}>`,T=document,R=()=>T.createComment(""),I=t=>null===t||"object"!=typeof t&&"function"!=typeof t,A=Array.isArray,z="[ \t\n\f\r]",F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,E=/-->/g,N=/>/g,O=RegExp(`>|${z}(?:([^\\s"'>=/]+)(${z}*=${z}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,H=/"/g,B=/^(?:script|style|textarea|title)$/i,q=t=>(e,...i)=>({_$litType$:t,strings:e,values:i}),W=q(1),j=q(2),U=Symbol.for("lit-noChange"),G=Symbol.for("lit-nothing"),V=new WeakMap,K=T.createTreeWalker(T,129);function Y(t,e){if(!A(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(e):e}const J=(t,e)=>{const i=t.length-1,s=[];let n,o=2===e?"":3===e?"":"",a=F;for(let e=0;e"===l[0]?(a=n??F,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?O:'"'===l[3]?H:L):a===H||a===L?a=O:a===E||a===N?a=F:(a=O,n=void 0);const d=a===O&&t[e+1].startsWith("/>")?" ":"";o+=a===F?i+P:c>=0?(s.push(r),i.slice(0,c)+M+i.slice(c)+C+d):i+C+(-2===c?e:d)}return[Y(t,o+(t[i]||"")+(2===e?"":3===e?"":"")),s]};class X{constructor({strings:t,_$litType$:e},i){let s;this.parts=[];let n=0,o=0;const a=t.length-1,r=this.parts,[l,c]=J(t,e);if(this.el=X.createElement(l,i),K.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(s=K.nextNode())&&r.length0){s.textContent=$?$.emptyScript:"";for(let i=0;iA(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==G&&I(this._$AH)?this._$AA.nextSibling.data=t:this.T(T.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:i}=t,s="number"==typeof i?this._$AC(t):(void 0===i.el&&(i.el=X.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===s)this._$AH.p(e);else{const t=new Q(s,this),i=t.u(this.options);t.p(e),this.T(i),this._$AH=t}}_$AC(t){let e=V.get(t.strings);return void 0===e&&V.set(t.strings,e=new X(t)),e}k(t){A(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let i,s=0;for(const n of t)s===e.length?e.push(i=new tt(this.O(R()),this.O(R()),this,this.options)):i=e[s],i._$AI(n),s++;s2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=G}_$AI(t,e=this,i,s){const n=this.strings;let o=!1;if(void 0===n)t=Z(this,t,e,0),o=!I(t)||t!==this._$AH&&t!==U,o&&(this._$AH=t);else{const s=t;let a,r;for(t=n[0],a=0;a{const s=i?.renderBefore??e;let n=s._$litPart$;if(void 0===n){const t=i?.renderBefore??null;s._$litPart$=n=new tt(e.insertBefore(R(),t),t,void 0,i??{})}return n._$AI(t),n},ct=globalThis;let ht=class extends w{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=lt(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return U}};ht._$litElement$=!0,ht.finalized=!0,ct.litElementHydrateSupport?.({LitElement:ht});const dt=ct.litElementPolyfillSupport;dt?.({LitElement:ht}),(ct.litElementVersions??=[]).push("4.2.2");const pt=2,ut=t=>(...e)=>({_$litDirective$:t,values:e});let _t=class{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,i){this._$Ct=t,this._$AM=e,this._$Ci=i}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}};const mt={},gt=ut(class extends _t{constructor(){super(...arguments),this.ot=mt}render(t,e){return e()}update(t,[e,i]){if(Array.isArray(e)){if(Array.isArray(this.ot)&&this.ot.length===e.length&&e.every((t,e)=>t===this.ot[e]))return U}else if(this.ot===e)return U;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}}),{I:ft}=at,vt=t=>t,yt=()=>document.createComment(""),bt=(t,e,i)=>{const s=t._$AA.parentNode,n=void 0===e?t._$AB:e._$AA;if(void 0===i){const e=s.insertBefore(yt(),n),o=s.insertBefore(yt(),n);i=new ft(e,o,t,t.options)}else{const e=i._$AB.nextSibling,o=i._$AM,a=o!==t;if(a){let e;i._$AQ?.(t),i._$AM=t,void 0!==i._$AP&&(e=t._$AU)!==o._$AU&&i._$AP(e)}if(e!==n||a){let t=i._$AA;for(;t!==e;){const e=vt(t).nextSibling;vt(s).insertBefore(t,n),t=e}}}return i},wt=(t,e,i=t)=>(t._$AI(e,i),t),kt={},xt=(t,e=kt)=>t._$AH=e,$t=t=>{t._$AR(),t._$AA.remove()},St=(t,e,i)=>{const s=new Map;for(let n=e;n<=i;n++)s.set(t[n],n);return s},Mt=ut(class extends _t{constructor(t){if(super(t),t.type!==pt)throw Error("repeat() can only be used in text expressions")}dt(t,e,i){let s;void 0===i?i=e:void 0!==e&&(s=e);const n=[],o=[];let a=0;for(const e of t)n[a]=s?s(e,a):a,o[a]=i(e,a),a++;return{values:o,keys:n}}render(t,e,i){return this.dt(t,e,i).values}update(t,[e,i,s]){const n=(t=>t._$AH)(t),{values:o,keys:a}=this.dt(e,i,s);if(!Array.isArray(n))return this.ut=a,o;const r=this.ut??=[],l=[];let c,h,d=0,p=n.length-1,u=0,_=o.length-1;for(;d<=p&&u<=_;)if(null===n[d])d++;else if(null===n[p])p--;else if(r[d]===a[u])l[u]=wt(n[d],o[u]),d++,u++;else if(r[p]===a[_])l[_]=wt(n[p],o[_]),p--,_--;else if(r[d]===a[_])l[_]=wt(n[d],o[_]),bt(t,l[_+1],n[d]),d++,_--;else if(r[p]===a[u])l[u]=wt(n[p],o[u]),bt(t,n[d],n[p]),p--,u++;else if(void 0===c&&(c=St(a,u,_),h=St(r,d,p)),c.has(r[d]))if(c.has(r[p])){const e=h.get(a[u]),i=void 0!==e?n[e]:null;if(null===i){const e=bt(t,n[d]);wt(e,o[u]),l[u]=e}else l[u]=wt(i,o[u]),bt(t,n[d],i),n[e]=null;u++}else $t(n[p]),p--;else $t(n[d]),d++;for(;u<=_;){const e=bt(t,l[_+1]);wt(e,o[u]),l[u++]=e}for(;d<=p;){const t=n[d++];null!==t&&$t(t)}return this.ut=a,xt(t,l),U}}),Ct=new WeakMap;let Dt=0;class Pt extends ht{constructor(){super(...arguments),this.title="",this.icon="",this.wide=!1,this.dismissOnScrim=!1,this.hass=null,this._opener=null,this._focusRoot=null,this._useHaDialog=!1,this._closing=!1,this._overlays=[],this._titleId="hp-dialog-title-"+ ++Dt,this._focusInitial=()=>{const t=this._focusableElements(),e=t.find(t=>t.hasAttribute("autofocus"))||t[0]||(this._useHaDialog?null:this.renderRoot.querySelector(".close"))||this.renderRoot.querySelector(".surface")||this.renderRoot.querySelector("ha-dialog");e?.focus({preventScroll:!0})},this._requestClose=()=>{this._closing||(this._closing=!0,this.dispatchEvent(new CustomEvent("hp-close",{bubbles:!0,composed:!0})))},this._onKeyDown=t=>{if("Escape"===t.key){t.preventDefault(),t.stopImmediatePropagation(),this._pruneOverlays();const e=this._overlays[this._overlays.length-1];return e?void this._closeOverlay(e,"escape"):void this._requestClose()}if("Tab"!==t.key||this._useHaDialog)return;const e=this.renderRoot.querySelector(".close"),i=e?[e,...this._focusableElements()]:this._focusableElements();if(!i.length)return t.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const s=this._deepActiveElement(),n=i[0],o=i[i.length-1];!t.shiftKey||s!==n&&i.includes(s)?t.shiftKey||s!==o||(t.preventDefault(),n.focus()):(t.preventDefault(),o.focus())},this._onFallbackCancel=t=>{t.preventDefault(),this._requestClose()},this._onFallbackClick=t=>{this.dismissOnScrim&&t.target===t.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const t=this.getRootNode();this._focusRoot=t;const e=Ct.get(t)||{dialogs:new Set,opener:this._opener};e.dialogs.add(this),Ct.set(t,e),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const t=[...this._overlays];this._overlays=[];for(const e of t.reverse())e.close("disconnect");const e=this._focusRoot,i=this._opener;this._opener=null,this._focusRoot=null;const s=e?Ct.get(e):void 0;s?.dialogs.delete(this),super.disconnectedCallback(),e&&s&&requestAnimationFrame(()=>{const t=Ct.get(e);if(!t)return;if(!t.dialogs.size)return t.opener?.isConnected&&t.opener.focus({preventScroll:!0}),void Ct.delete(e);const s=i?.closest("hp-dialog");i?.isConnected&&s&&t.dialogs.has(s)&&i.focus({preventScroll:!0})})}firstUpdated(t){if(super.firstUpdated(t),!this._useHaDialog){const t=this.renderRoot.querySelector("dialog");t&&!t.open&&t.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let t=document.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t&&t!==document.body?t:null}_focusableElements(){const t=["[autofocus]","a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[contenteditable="true"]','[tabindex]:not([tabindex="-1"])'].join(","),e=[],i=new Set,s=n=>{if(!i.has(n)){if(i.add(n),n instanceof HTMLElement){if(n.matches(t)&&e.push(n),n instanceof HTMLSlotElement){for(const t of n.assignedNodes({flatten:!0}))s(t);return}if(n.shadowRoot){for(const t of n.shadowRoot.childNodes)s(t);return}}for(const t of n.childNodes)s(t)}};for(const t of this.childNodes)s(t);const n=this.overlayPortal();return n&&s(n),e.filter(t=>{let e=t;for(;e;){const t=getComputedStyle(e);if(e.hidden||e.inert||"true"===e.getAttribute("aria-hidden")||"none"===t.display||"hidden"===t.visibility)return!1;if(e=e.assignedSlot||e.parentElement||(e.getRootNode()instanceof ShadowRoot?e.getRootNode().host:null),e===this)break}return!0})}_pruneOverlays(){this._overlays=this._overlays.filter(t=>t.owner.isConnected)}_closeOverlay(t,e){const i=this._overlays.findIndex(e=>e.token===t.token);i>=0&&this._overlays.splice(i,1),t.close(e)}registerOverlay(t){this._pruneOverlays();const e=this._overlays.find(e=>e.owner===t.owner);e&&this._overlays.splice(this._overlays.indexOf(e),1);const i=t.group||"transient";for(const t of[...this._overlays].reverse())t.group===i&&this._closeOverlay(t,"exclusive");const s={...t,group:i,token:Symbol("hp-overlay")};this._overlays.push(s);let n=!1;return()=>{if(n)return;n=!0;const t=this._overlays.findIndex(t=>t.token===s.token);t>=0&&this._overlays.splice(t,1)}}closeTransientOverlays(t="outside"){this._pruneOverlays();const e=[...this._overlays].filter(t=>"transient"===(t.group||"transient"));for(const i of e.reverse())this._closeOverlay(i,t);return e.length>0}overlayPortal(){return this.renderRoot.querySelector(".overlay-portal")}render(){const t=W` ${this.icon?W``:G} ${this.title} `;return this._useHaDialog?W`${t.visibleLabel}`:G}
${t?.content||G}
- `}afterRender(){const t=this.host.root();this._blocked&&(this._openGroupId?this.closeGroup(!1):"palette"===this._currentModel?.kind&&this._currentModel.dismiss?.()),this._syncGlobalDismissListener();const e=t.querySelector(".editor-secondary"),i=this._renderedContext,s=e?.dataset.contextId||"";if(s&&i&&s!==i&&!window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches&&(this._contentAnimation?.cancel(),this._contentAnimation=e?.querySelector(".editor-secondary-content")?.animate([{opacity:.35,transform:"translateY(-4px)"},{opacity:1,transform:"translateY(0)"}],{duration:100,easing:"ease-out"})),this._renderedContext=s,i&&s!==i&&this._focusOwned){const i=s?e?.querySelector('[tabindex="0"], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'):t.querySelector(".editbar-tools");i?.focus?.(),this._focusOwned=!!s}if("palette"===this._currentModel?.kind&&this._currentModel.launcherId){const e=[...t.querySelectorAll("[data-editor-palette]")].find(t=>t.dataset.editorPalette===this._currentModel?.launcherId);e&&null!==e.offsetParent||this._currentModel.dismiss?.()}if(!this._openGroupId)return;const n=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===this._openGroupId);n&&null!==n.offsetParent||this.closeGroup(!0)}handleOutsideDismiss(t){if(B_(t,t=>t.hasAttribute("data-editor-navigation")))return"pointerdown"===t.type?this.closeForNavigation():"click"===t.type&&this._dismissPointerTarget&&this._clearDismissClick(),!1;if("click"===t.type&&this._dismissPointerTarget){return!!(t.composedPath?.()||[t.target]).includes(this._dismissPointerTarget)&&(this._clearDismissClick(),t.preventDefault(),t.stopImmediatePropagation(),!0)}const e=this._openGroupId||this._blocked||"palette"!==this._currentModel?.kind?null:this._currentModel;if("pointerdown"===t.type&&(this._openGroupId||e)){const i=B_(t,t=>t.classList.contains("editor-secondary")),s=B_(t,t=>!!t.dataset.editorGroup),n=B_(t,t=>!!t.dataset.editorPalette),o=B_(t,t=>t.classList.contains("stage"));if(!(i||s||n||"stay-open-on-canvas"===e?.dismissPolicy&&o))return t.preventDefault(),t.stopImmediatePropagation(),this._dismissPointerTarget=t.target,clearTimeout(this._dismissTimer),this._dismissTimer=window.setTimeout(()=>{this._clearDismissClick()},800),this._openGroupId?this.closeGroup(!1):e?.dismiss?.(),this._syncGlobalDismissListener(),!0}return!1}_activateGroupItem(t,e,i){if(t.id!==this._openGroupId)return;const s=t.items.find(t=>t.id===e);if(!s||s.disabled)return;const n="toggle"===s.role&&"stay-open"===s.closePolicy,o=0===i.detail;n||(this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener()),s.invoke(),!n&&o&&this.host.updateComplete().then(()=>{const e=[...this.host.root().querySelectorAll("[data-editor-group]")].find(e=>e.dataset.editorGroup===t.id&&null!==e.offsetParent);e?.focus()})}_groupKeydown(t){if(!["ArrowLeft","ArrowRight","Home","End"].includes(t.key))return;const e=[...t.currentTarget.querySelectorAll(".editor-group-item:not([disabled])")];if(!e.length)return;t.preventDefault();const i=e.indexOf(this.host.root().activeElement),s="Home"===t.key?0:"End"===t.key?e.length-1:"ArrowLeft"===t.key?i<=0?e.length-1:i-1:(i+1)%e.length;e[s]?.focus()}_clearDismissClick(){this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}_syncGlobalDismissListener(){const t=!this._blocked&&"palette"===this._currentModel?.kind,e=!!this._openGroupId||t||!!this._dismissPointerTarget;e!==this._globalDismissListening&&(this._globalDismissListening=e,e?(window.addEventListener("pointerdown",this._globalDismissGuard,!0),window.addEventListener("click",this._globalDismissGuard,!0)):(window.removeEventListener("pointerdown",this._globalDismissGuard,!0),window.removeEventListener("click",this._globalDismissGuard,!0)))}}const W_=t=>t.stopPropagation(),j_=4.166666666666667e-9;function U_(t){return Number.isFinite(t)?Math.round(t/Ph)*Ph:t}const G_=(t,e,i,s)=>Math.hypot(i-t,s-e),V_=(t,e,i,s,n,o,a,r)=>Math.hypot(Math.max(Math.abs(n-t),Math.abs(n+a-(t+i))),Math.max(Math.abs(o-e),Math.abs(o+r-(e+s)))),K_=(t,e,i,s,n,o,a)=>{const r=Math.max(Number(s)||0,0)/2,l=Math.PI/180,c=Math.cos(i*l)*r,h=Math.sin(i*l)*r,d=Math.cos(a*l)*r,p=Math.sin(a*l)*r,u=Math.max(G_(t+c,e+h,n+d,o+p),G_(t-c,e-h,n-d,o-p)),_=Math.max(G_(t+c,e+h,n-d,o-p),G_(t-c,e-h,n+d,o+p));return Math.min(u,_)},Y_=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function J_(t,e){const i=JSON.parse(JSON.stringify(t||[])),s=JSON.parse(JSON.stringify(e||{}));let n=0,o=0,a=0,r=0,l="",c=0,h=0,d=0;const p=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=j_&&h++},u=(t,e)=>{p(t[0],e[0]),p(t[1],e[1])},_={};let m=5;for(const t of i){const e=Y_(t);null!=t?.id&&(_[String(t.id)]=e),e>m&&(m=e)}const g=(t,e,i,s=!1)=>{if(!(t>j_||s))return;n++,t>a&&(a=t);const o=t*Ch*e;o>r&&(r=o,l=i)};for(const t of i){const e=Y_(t),i=null!=t?.id?String(t.id):"";for(const s of t.rooms||[]){o++;let t=0;if(s.poly?.length)s.poly=s.poly.map(e=>{const i=[U_(e[0]),U_(e[1])];return t=Math.max(t,G_(e[0],e[1],i[0],i[1])),u(e,i),i});else if(null!=s.x&&null!=s.y){const e=s.x,i=s.y,n=s.w||0,o=s.h||0,a=U_(e+n),r=U_(i+o),l=U_(e),c=U_(i),h=Math.max(Ph,a-l),d=Math.max(Ph,r-c);t=V_(e,i,n,o,l,c,h,d),s.x=l,s.y=c,s.w=h,s.h=d,p(e,l),p(i,c),p(e+n,l+h),p(i+o,c+d)}g(t,e,i)}for(const s of t.room_drafts||[]){o++;let t=0;const n=s.points||[],a=n.map(e=>{const i=[U_(e[0]),U_(e[1])];return t=Math.max(t,G_(e[0],e[1],i[0],i[1])),i}),r=a.length?[a[0]]:[],l=a.length?[[n[0],a[0]]]:[],c=[];for(let t=0;t+1=2)for(const[t,e]of l)u(t,e);g(t,e,i)}if(Array.isArray(t.room_drafts)){const e=t.room_drafts.length;t.room_drafts=t.room_drafts.filter(t=>t.points?.length>=2),d+=e-t.room_drafts.length,t.room_drafts.length||delete t.room_drafts}for(const s of t.partitions||[]){o++;const n=[s.a[0],s.a[1]],a=[s.b[0],s.b[1]],r=[U_(n[0]),U_(n[1])],l=[U_(a[0]),U_(a[1])];let c=Math.max(G_(n[0],n[1],r[0],r[1]),G_(a[0],a[1],l[0],l[1]));const h=G_(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).every(t=>{const e=Number(t.length),i=Number(t.host.t),s=i*h;return Number.isFinite(e)&&e>0&&Number.isFinite(i)&&i>=0&&i<=1&&s-e/2>=-j_&&s+e/2<=h+j_});h>j_&&d?(s.a=r,s.b=l,u(n,r),u(a,l)):c=0,g(c,e,i)}for(const s of t.wall_columns||[]){o++;const t=[s.center[0],s.center[1]],n=[U_(t[0]),U_(t[1])],a=G_(t[0],t[1],n[0],n[1]);s.center=n,u(t,n),g(a,e,i)}for(const s of t.decor||[]){o++;let t=0;if("line"===s.kind){const e=[s.x1,s.y1],i=[s.x2,s.y2],n=[U_(e[0]),U_(e[1])],o=[U_(i[0]),U_(i[1])];t=Math.max(G_(e[0],e[1],n[0],n[1]),G_(i[0],i[1],o[0],o[1])),s.x1=n[0],s.y1=n[1],s.x2=o[0],s.y2=o[1],u(e,n),u(i,o)}else{const e=s.x,i=s.y,n=s.w,o=s.h,a=U_(e),r=U_(i);if(null!=s.w&&null!=s.h){const l=U_(e+n),c=U_(i+o),h=Math.max(Ph,l-a),d=Math.max(Ph,c-r);t=V_(e,i,n,o,a,r,h,d),s.w=h,s.h=d,p(e+n,a+h),p(i+o,r+d)}else t=G_(e,i,a,r);s.x=a,s.y=r,p(e,a),p(i,r)}g(t,e,i)}for(const s of t.openings||[]){if(o++,"partition"===s.host?.kind){const n=(t.partitions||[]).find(t=>t.id===s.host.id),o=Number(s.host.t);if(!n||!Number.isFinite(o)||o<0||o>1)continue;const a=n.b[0]-n.a[0],r=n.b[1]-n.a[1];if(Math.hypot(a,r)<=j_)continue;const l=n.a[0]+a*o,h=n.a[1]+r*o;let d=180*Math.atan2(r,a)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(s.angle),u=!(Number.isFinite(p)&&p===d),_=K_(s.x,s.y,Number.isFinite(p)?p:d,Number(s.length)||0,l,h,d);s.x=l,s.y=h,s.angle=d,u&&c++,g(_,e,i,u);continue}const n=ui([s.x,s.y],t.rooms||[],.025,{step:Ph,length:Number(s.length)||0});if(!n)continue;const a=Number(s.angle),r=!(Number.isFinite(a)&&a===n.angle),l=K_(s.x,s.y,Number.isFinite(a)?a:n.angle,Number(s.length)||0,n.x,n.y,n.angle);s.x=n.x,s.y=n.y,s.angle=n.angle,r&&c++,g(l,e,i,r)}}for(const[t,e]of Object.entries(s)){if(!e||"object"!=typeof e)continue;const i=e;if("number"!=typeof i.x||"number"!=typeof i.y)continue;o++;const n=U_(i.x),a=U_(i.y),r=G_(i.x,i.y,n,a);s[t]={...i,x:n,y:a},p(i.x,n),p(i.y,a);const l="string"==typeof i.s?i.s:"";g(r,_[l]??m,l)}return{spaces:i,layout:s,report:{moved:n,coordsCanonicalized:h,total:o,maxShift:a,maxShiftCm:r,maxSpace:l,rotated:c,removedDrafts:d},changed:n>0||h>0}}function X_(t,e){const i=e.base+t*e.span;return Math.min(1,Math.max(0,i))}const Z_=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Q_=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function tm(t,e,i){const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;if(o<=0)return Q_(t,e);let a=((t[0]-e[0])*s+(t[1]-e[1])*n)/o;return a=Math.max(0,Math.min(1,a)),Math.hypot(t[0]-(e[0]+s*a),t[1]-(e[1]+n*a))}function em(t,e,i,s,n){for(const s of e)if(s&&!i.has(s.id)&&Z_(s.a)&&Z_(s.b)&&(Q_(t,s.a)<=n||Q_(t,s.b)<=n))return!0;for(const e of s?.roomPolygons||[])for(let i=0;i0&&r>0))return null;if(Math.abs(n[0]/a*(o[1]/r)-n[1]/a*(o[0]/r))>i)return null;for(const[i,n]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(Q_(i,n)<=s)return[(i[0]+n[0])/2,(i[1]+n[1])/2];return null}function sm(t,e){const i=.05*(Number(e.pitch)>0?Number(e.pitch):1),s=new Map;let n=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&Z_(t.a)&&Z_(t.b));if(n.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const o=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let a=0;for(let t=0;tQ_(e,t.at)>i);let h=c[0]??r.a,d=c[c.length-1]??l.b;if(c.length<2&&(h=r.a,d=l.b),d[0]0?(d[0]-h[0])/u:0,m=u>0?(d[1]-h[1])/u:0,g=t=>u>0?((t[0]-h[0])*_+(t[1]-h[1])*m)/u:0;for(const t of[r,l]){const e=g(t.a),i=g(t.b)-e;for(const[n,o]of s)o.toId===t.id&&s.set(n,{fromId:o.fromId,toId:p.id,base:e+o.base*i,span:o.span*i});s.set(t.id,{fromId:t.id,toId:p.id,base:e,span:i})}o&&o.add(p.id),n=n.filter((e,i)=>i!==t.i&&i!==t.j),n.splice(t.i,0,p),a++}return{partitions:n,merged:a,openingMoves:[...s.values()]}}function nm(t,e,i,s){if(!t?.length||!i.length)return 0;const n=new Map(i.map(t=>[t.fromId,t]));let o=0;for(const i of t){const t=i?.host;if(!t||"partition"!==t.kind)continue;const a=n.get(t.id);if(!a)continue;i.host={...t,id:a.toId,t:X_(t.t,a)},o++;const r=$p(i,e,s.coordScale,s.cellCm,s.gridPitch).resolved;r&&Object.assign(i,Rp(i,r,s.coordScale))}return o}function om(t,e){const i=e?.excludeDraftId||null;return{roomPolygons:(t?.rooms||[]).map(t=>hi(t)).filter(t=>!!t),columns:t?.wall_columns||[],draftEnds:(t?.room_drafts||[]).flatMap(t=>{if(i&&t?.id===i)return[];const e=t?.points||[];return e.length?[e[0],e[e.length-1]]:[]})}}const am=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),rm=(t,e)=>t[0]-e[0]||t[1]-e[1],lm=(t,e,i,s)=>[t[0]+e*s,t[1]+i*s],cm=(t,e,i,s)=>(t[0]-e[0])*i+(t[1]-e[1])*s,hm=(t,e,i,s,n)=>{const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(!(r>n))return null;const l=o/r,c=a/r,h=e=>Math.abs((e[0]-t[0])*c-(e[1]-t[1])*l);if(h(i)>n||h(s)>n)return null;const d=cm(i,t,l,c),p=cm(s,t,l,c),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));return _-u>n?{lo:u,hi:_}:null},dm=(t,e,i)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>i,pm=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},um=(t,e,i,s)=>{const n=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(n,o);if(!(a>s))return!0;const r=n/a,l=o/a,c=gl(t.cm,i.cellCm,i.gridPitch)/2;return e.some(e=>{const n=e?.center;if(!am(n))return!0;const o=cm(n,t.a,r,l),h=Math.abs((n[0]-t.a[0])*l-(n[1]-t.a[1])*r),d=gl(Number(e.cm),i.cellCm,i.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||o>=-d-s&&o<=a+d+s&&h<=c+d+s})},_m=(t,e,i)=>{if(t.host){const s=$p(t,e,i.coordScale,i.cellCm,i.gridPitch).resolved;return s?{center:s.center,angle:s.angle,length:s.length}:null}const s=Number(t.x)*i.coordScale,n=Number(t.y)*i.coordScale,o=Number(t.angle),a=Number(t.length)*i.coordScale;return[s,n,o,a].every(Number.isFinite)&&a>0?{center:[s,n],angle:o,length:a}:null},mm=(t,e,i)=>{const s=t.angle*Math.PI/180,n=Math.cos(s),o=Math.sin(s),a=e.angle*Math.PI/180,r=Math.cos(a),l=Math.sin(a);if(Math.abs(n*l-o*r)>1e-6)return!1;const c=e.center[0]-t.center[0],h=e.center[1]-t.center[1];if(Math.abs(c*o-h*n)>i)return!1;const d=c*n+h*o;return Math.max(-t.length/2,d-e.length/2)({...t,a:[t.a[0]*e,t.a[1]*e],b:[t.b[0]*e,t.b[1]*e]}),fm=(t,e,i,s)=>{const n=`~r-${(t=>{let e=2166136261;for(let i=0;i>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${i[0].toFixed(9)},${i[1].toFixed(9)}`)}`,o=`${t.slice(0,Math.max(1,64-n.length))}${n}`;let a=o;for(let t=2;s.has(a);t++){const e=`-${t}`;a=`${o.slice(0,64-e.length)}${e}`}return s.add(a),a},vm=(t,e)=>{const i=[];for(const s of t){const t=i[i.length-1];!(t&&Math.abs(t.hi-s.lo)<=e&&t.safe===s.safe)||s.safe&&t.signature!==s.signature?i.push({lo:s.lo,hi:s.hi,a:s.a,b:s.b,safe:s.safe,signature:s.signature,roomIds:s.roomIds,finalCm:s.finalCm}):(t.hi=s.hi,t.b=s.b)}return i};function ym(t,e,i,s,n){const o=i||[],a=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l=Array.isArray(t?.room_drafts)?t.room_drafts:[],c={walls:o,partitions:a,openings:r,roomDrafts:l,partitionsReconciled:0,openingsRehosted:0,removedDrafts:0};if(!a.length&&!l.length)return c;const h=Math.max(2e-4*n.gridPitch,1e-9);let d=o,p=a,u=r;const _=dc(e.rooms,d,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),m=((t,e,i,s)=>{const n=new Map(t.map(t=>[t.id,t])),o=new Set;for(const t of e){if(!n.get(t.id)||!Array.isArray(t.points)||t.points.length<2||t.segments.length!==t.points.length-1)continue;let e=!0;for(let n=0;n+10)){e=!1;break}const l=Math.hypot(a[0]-o[0],a[1]-o[1]);if(!(l>s)){e=!1;break}const c=i.flatMap(t=>{const e=t.cm>0?t.cm:ll;if(t.open||"outer"!==t.kind&&"shared"!==t.kind||e+st.lo-e.lo||t.hi-e.hi);let h=0;for(const t of c){if(t.lo>h+s)break;if(h=Math.max(h,t.hi),h>=l-s)break}h!m.has(t.id));let f=0,v=0;const y=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...a].sort((t,e)=>t.id.localeCompare(e.id))){if(!p.some(e=>e.id===t.id))continue;if(!pm(t))continue;const i=y.get(t.id);if(!(i&&am(i.a)&&am(i.b)&&Number.isFinite(i.cm)&&i.cm>0))continue;const[o,a]=rm(i.a,i.b)<=0?[[i.a[0],i.a[1]],[i.b[0],i.b[1]]]:[[i.b[0],i.b[1]],[i.a[0],i.a[1]]],r=a[0]-o[0],l=a[1]-o[1],c=Math.hypot(r,l);if(!(c>h))continue;const _=r/c,g=l/c,b=dc(e.rooms,d,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),w=b.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=hm(o,a,t.a,t.b,h);return e?[{interval:t,range:e}]:[]});if(!w.length)continue;const k=u.filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).map(t=>({opening:t,resolved:$p(t,e.partitions,n.coordScale,n.cellCm,n.gridPitch).resolved}));if(k.some(t=>!t.resolved))continue;const x=[0,c];for(const{range:t}of w)x.push(t.lo,t.hi);const $=x.slice(),S=new Map;for(const{opening:t,resolved:e}of k){const i=cm(e.center,o,_,g),s={lo:i-e.length/2,hi:i+e.length/2};S.set(t.id,s),$.push(Math.max(0,s.lo),Math.min(c,s.hi))}const M=[...new Set($.filter(t=>Number.isFinite(t)&&t>=-h&&t<=c+h).map(t=>Math.max(0,Math.min(c,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),C=p.map(t=>gm(t,n.coordScale)).filter(t=>t.id!==i.id),D=e.room_drafts.filter(t=>!m.has(t.id)),P=[];for(let t=0;t+1h))continue;const r=lm(o,_,g,s),l=lm(o,_,g,a),c=w.filter(({range:t})=>t.lo<=s+h&&t.hi>=a-h).map(({interval:t})=>t),d=new Map;for(const t of c)d.set(t.roomId,t);const p=[...d.values()],u=new Set(p.map(t=>t.kind)),m=new Set(p.map(t=>t.cm>0?t.cm:ll)),f=p[0]?.kind,v=[...d.keys()].sort(),y=1===u.size&&1===m.size&&("outer"===f&&1===v.length||"shared"===f&&2===v.length),b={id:i.id,a:r,b:l,cm:i.cm},k=C.some(t=>!!hm(r,l,t.a,t.b,h)),x=D.some(t=>t.points.some((e,i)=>i+10?p[0].cm:ll:0,T=y?Math.max(S,i.cm):i.cm;P.push({lo:s,hi:a,a:r,b:l,safe:$,signature:$?`${f}|${v.join(",")}|${T}`:"",roomIds:v,roomCm:S,finalCm:T})}if(!P.some(t=>t.safe))continue;const T=new Map;for(const{opening:t,resolved:e}of k){const s=S.get(t.id),o=x.some(t=>t>s.lo+h&&tdm(t,s,h)),r=new Set(a.filter(t=>t.safe).map(t=>t.signature));if(!o&&a.length>0&&a.every(t=>t.safe)&&1===r.size&&Tp(e,b,h)){T.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=kp(i,n.cellCm,n.gridPitch),c={lo:s.lo-l,hi:s.hi+l};for(const t of P)dm(t,c,h)&&(t.safe=!1,t.signature="")}let R=!0;for(;R;){R=!1;for(const[t,e]of[...T.entries()]){const s=S.get(t),o=P.filter(t=>dm(t,s,h));if(o.length>0&&o.every(t=>t.safe)&&o.every(t=>t.signature===e.signature))continue;T.delete(t);const a=kp(i,n.cellCm,n.gridPitch),r={lo:s.lo-a,hi:s.hi+a};for(const t of P)dm(t,r,h)&&(t.safe=!1,t.signature="");R=!0}}const I=vm(P,h),A=I.filter(t=>t.safe),z=I.filter(t=>!t.safe);if(!A.length)continue;if(p.length-1+z.length>2e3)continue;let F=d;for(const t of A){const[e,s]=rm(i.a,i.b)<=0?[t.a,t.b]:[t.b,t.a];F=Fl(F,e,s,t.finalCm,n.pitch,n.coordScale)}if(F=uc(e.rooms,F,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),F.length>500)continue;const E=new Set(p.map(t=>t.id));E.delete(i.id);const N=z.map((t,e)=>{const s=[t.a[0]/n.coordScale,t.a[1]/n.coordScale],o=[t.b[0]/n.coordScale,t.b[1]/n.coordScale],a=0===e?i.id:fm(i.id,s,o,E);return E.add(a),{id:a,a:s,b:o,cm:i.cm}}),O=p.findIndex(t=>t.id===i.id),L=p.slice();L.splice(O,1,...N);const H=L.map(t=>gm(t,n.coordScale)),B=new Map;let q=!0;for(const{opening:t,resolved:e}of k){const i=T.get(t.id);if(i){const e=Rp(t,i.resolved,n.coordScale),{host:s,...o}=e;B.set(t.id,o);continue}const s=S.get(t.id),o=N[z.findIndex(t=>t.lo<=s.lo+h&&t.hi>=s.hi-h)],a=o&&H.find(t=>t.id===o.id);if(!o||!a){q=!1;break}const r=a.b[0]-a.a[0],l=a.b[1]-a.a[1],c=Math.hypot(r,l),d=cm(e.center,a.a,r/c,l/c),p={...Rp(t,e,n.coordScale),host:{kind:"partition",id:o.id,t:d/c}};if(!Sp(p,H,n.coordScale,n.cellCm,n.gridPitch).resolved){q=!1;break}B.set(t.id,p)}if(!q)continue;const W=u.map(t=>B.get(t.id)||t),j=[...T.keys()].map(t=>B.get(t)),U=j.map(t=>_m(t,H,n));if(U.some(t=>!t))continue;let G=!1;for(let t=0;tt.id));for(const t of W){if(V.has(t.id))continue;const e=_m(t,H,n);e&&U.some(t=>mm(t,e,h))&&(G=!0)}if(G)continue;const K=Fc(e.rooms,F,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale);[...T.entries()].every(([t,e])=>{const i=B.get(t),s=Oc(K,{x:i.x*n.coordScale,y:i.y*n.coordScale,angle:i.angle,length:i.length*n.coordScale},!0),o=[s.negative,s.positive].filter(t=>!!t?.full),a=e.signature.split("|")[1].split(","),r=new Set(o.map(t=>t.roomId));return o.length===a.length&&r.size===a.length&&a.every(t=>r.has(t))})&&(d=F,p=L,u=W,f+=A.length,v+=T.size)}return{walls:d,partitions:p,openings:u,roomDrafts:g,partitionsReconciled:f,openingsRehosted:v,removedDrafts:m.size}}const bm=t=>JSON.parse(JSON.stringify(t)),wm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),km=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function xm(t,e){let i=String(e??"");const s=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=new RegExp(`^${s}_(.+)_([0-9a-f]{8})$`);let o=0;for(;o<16;o++){const t=n.exec(i);if(!t)return{root:i,layers:o,bounded:!1};i=t[1]}return{root:i,layers:o,bounded:n.test(i)}}const $m=(t,e,i)=>{const s=t.get(e)||[];s.push(i),t.set(e,s)};const Sm=1e-9;class Mm extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const Cm=t=>JSON.parse(JSON.stringify(t)),Dm=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),Pm=t=>[Number(t[0]),Number(t[1])],Tm=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,Rm=(t,e)=>{const i=Tm(t),s=Tm(e);return iTm(t)<=Tm(e)?[Pm(t),Pm(e)]:[Pm(e),Pm(t)],Am=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),zm=t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],i=[];for(let s=1;s{const i=new Set,s=t=>{const e=Number(t);if(!Number.isFinite(e))return;const s=e/Ph;Math.abs(s-Math.round(s))>=Ur&&i.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of hi(e)||[])s(t[0]),s(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])s(t?.a?.[0]),s(t?.a?.[1]),s(t?.b?.[0]),s(t?.b?.[1]);for(const t of e)s(t?.[0]),s(t?.[1]);return i.size},Em=(t,e,i)=>{const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;return o>1e-18?((t[0]-e[0])*s+(t[1]-e[1])*n)/o:0},Nm=(t,e,i)=>{const s=Math.max(0,Math.min(1,Em(t,e,i)));return Math.hypot(t[0]-(e[0]+(i[0]-e[0])*s),t[1]-(e[1]+(i[1]-e[1])*s))},Om=(t,e,i,s,n=Sm)=>{const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(r<=n)return 0;const l=e=>Math.abs((e[0]-t[0])*a-(e[1]-t[1])*o)/r;if(l(i)>n||l(s)>n)return 0;const c=Em(i,t,e),h=Em(s,t,e);return Math.max(0,Math.min(1,Math.max(c,h))-Math.max(0,Math.min(c,h)))*r},Lm=t=>{const e=(new TextEncoder).encode(t),i=8*e.length,s=64*Math.ceil((e.length+9)/64),n=new Uint8Array(s);n.set(e),n[e.length]=128;const o=new DataView(n.buffer);o.setUint32(s-8,Math.floor(i/4294967296),!1),o.setUint32(s-4,i>>>0,!1);const a=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),l=new Uint32Array(64),c=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,n=c(i,17)^c(i,19)^i>>>10;l[t]=l[t-16]+s+l[t-7]+n>>>0}let[e,i,s,n,h,d,p,u]=r;for(let t=0;t<64;t++){const o=u+(c(h,6)^c(h,11)^c(h,25))+(h&d^~h&p)+a[t]+l[t]>>>0,r=e&i^e&s^i&s;u=p,p=d,d=h,h=n+o>>>0,n=s,s=i,i=e,e=o+((c(e,2)^c(e,13)^c(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+i>>>0,r[2]=r[2]+s>>>0,r[3]=r[3]+n>>>0,r[4]=r[4]+h>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+u>>>0}const h=new Uint8Array(32),d=new DataView(h.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let i=0,s=0,n="";for(const o of t)for(s=s<<8|o,i+=8;i>=5;)n+=e[s>>>i-5&31],i-=5;return i&&(n+=e[s<<5-i&31]),n},Bm=(t,e,i,s,n="")=>{const[o,a]=Im(e,i),r=`${t}|${Tm(o)}|${Tm(a)}|${[...s].sort().join(",")}${n}`;return`wall-${Hm(Lm(r)).slice(0,20)}`};let qm=0;const Wm=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),i=`wall-${e||Hm(Lm(`${Date.now()}|${qm++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(i))return i}throw new Mm("duplicate-id","id factory exhausted")},jm=t=>{const e=new Map;for(const i of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(i&&"string"==typeof i.id&&Dm(i.a)&&Dm(i.b)){if(e.has(i.id))throw new Mm("duplicate-id",i.id);e.set(i.id,i)}return e},Um=(t,e,i)=>{const s=(i,s)=>{const n=t[0]-i[0],o=t[1]-i[1];return Math.abs(e[0]-s[0]-n)<=Sm&&Math.abs(e[1]-s[1]-o)<=Sm?[n,o]:null};return s(i.a,i.b)||s(i.b,i.a)},Gm=(t,e)=>{const i=Array.isArray(t.rooms)?t.rooms:[],s=pd(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),n=s.length?s:ud(i,null,1,.04*Ph,!0),o=[];for(const t of i){const i=hi(t),s=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(i&&s.length===i.length)for(let t=0;tSm||Math.abs(s[1]-p[1])>Sm)){u=!1;break}p=s}const _=[];for(let t=0;t2)throw new Mm("third-owner",l);const m=d?h[c.parent[t]]:void 0;if("string"==typeof m&&m){const n=e.get(m);u||!n||Om(i,s,n.a,n.b)>Sm?p.preferredIds.add(m):p.positionalIds.add(m),p.preferredCarriers.set(m,{a:Pm(o[c.parent[t]]),b:Pm(o[(c.parent[t]+1)%o.length])})}const g=c.parent[t];p.parentKeys.add(wl(o[g],o[(g+1)%o.length],Ph));const f=[(i[0]+s[0])/2,(i[1]+s[1])/2];p.zeroWall||=a.some(t=>Nm(f,[t[0],t[1]],[t[2],t[3]])<=.04*Ph),_.push(l)}const m={...s};delete m.wall_ids,l.push({...m,poly:c.poly.map(t=>[t[0],t[1]]),wall_ids:_})}return{atoms:[...r.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:l}},Vm=(t,e,i,s,n)=>{const o=new Map([...i.values()].map(t=>[Rm(t.a,t.b),t])),a=(t=>{const e=new Map;for(const i of t)"wall"===i.host?.kind&&e.set(i.host.id,(e.get(i.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=n?.get(t.key);if(e){const s=i.get(e);if(!s)throw new Mm("duplicate-id",e);r.set(t,s);continue}if(t.preferredIds.size>1)throw new Mm("duplicate-id",[...t.preferredIds].sort().join(","));const s=[...t.preferredIds][0],l=s?i.get(s):void 0;if(l){r.set(t,l);continue}const c=s?t.preferredCarriers.get(s):void 0;if(s&&c){r.set(t,{id:s,a:c.a,b:c.b,cm:0});continue}const h=o.get(t.key);if(h){r.set(t,h);continue}const d=[...i.values()].filter(e=>Om(t.a,t.b,e.a,e.b)>Sm),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(a.get(e.id)||0)-(a.get(t.id)||0)||Am(e.a,e.b)-Am(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=i.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const i=l.get(e.id)||[];i.push(t),l.set(e.id,i)}for(const[t,e]of l){const s=i.get(t)||r.get(e[0]);if(!s)throw new Mm("duplicate-id",t);const n=[(s.a[0]+s.b[0])/2,(s.a[1]+s.b[1])/2];e.sort((t,e)=>{const i=Nm(n,t.a,t.b)<=Sm?0:1,o=Nm(n,e.a,e.b)<=Sm?0:1;if(i!==o)return i-o;return(Nm(s.a,t.a,t.b)<=Sm?0:1)-(Nm(s.a,e.a,e.b)<=Sm?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const c=(t=>{const e=new Set;for(const i of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(i)?i:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const i of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(i?.segments)?i.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(c.has(t.id))throw new Mm("duplicate-id",t.id);c.add(t.id)}const h=e.filter(t=>!t.id);if(s){const e=h.map(e=>{const[i,s]=Im(e.a,e.b),n=`${String(t.id||"")}|${Tm(i)}|${Tm(s)}|${[...e.owners].sort().join(",")}`,o=Hm(Lm(n));return{atom:e,seed:n,digest:o,base:`wall-${o.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),i=new Map;for(const t of e){const e=i.get(t.digest);if(e&&e!==t.seed)throw new Mm("duplicate-id",t.digest);i.set(t.digest,t.seed);let s=1,n=t.base;for(;c.has(n);)n=`${t.base}-${++s}`;t.atom.id=n,c.add(n)}}else for(const t of h)t.id=Wm(c),c.add(t.id)},Km=(t,e)=>{if("partition"===t.host?.kind)return null;const i=[Number(t.x),Number(t.y)];if(!i.every(Number.isFinite))return null;const s=e=>{if(!(Number(e.cm)>0))return!1;const s=Em(i,e.a,e.b),n=Am(e.a,e.b),o=Number(t.length)/2;return s>=-Sm&&s<=1+Sm&&Nm(i,e.a,e.b)<=.02*Ph&&Rl(e.a,e.b,Number(t.angle))&&Number.isFinite(o)&&o>=0&&s*n-o>=-Sm&&s*n+o<=n+Sm},n="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,o=n&&s(n)?[n]:e.filter(s);if(1!==o.length)return null;const a=o[0];return{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,Em(i,a.a,a.b)))}},Ym=(t,e,i)=>{const s=jm(t),{atoms:n,rooms:o}=Gm(t,s);Vm(t,n,s,e,i);const a=n.map(e=>{const i=e.id?s.get(e.id):void 0,n=((t,e,i)=>{if(e.zeroWall)return 0;const s=Array.isArray(t.walls)?t.walls:[],n=wl(e.a,e.b,Ph),o=s.filter(t=>Number(t.cm)>0&&(!(t.key!==n&&!e.parentKeys.has(t.key))||!(!Dm(t.a)||!Dm(t.b))&&Om(e.a,e.b,t.a,t.b)>=Am(e.a,e.b)-Sm)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(o.map(t=>t.toFixed(9))).size>1)throw new Mm("thickness-conflict",e.key);if(o.length)return o[0];const a=Pl(s,e.a,e.b,Ph,1);return a>0?a:Number(i?.cm)>0?Number(i.cm):0})(t,e,i);return{...i||{},id:e.id,a:[...e.a],b:[...e.b],cm:n}}),r=new Map(n.map(t=>[t.key,t.id]));for(const t of o)t.wall_ids=t.wall_ids.map(t=>r.get(t));t.rooms=o,t.wall_segments=a,t.walls=a.filter(t=>t.cm>0).map(t=>({key:wl(t.a,t.b,Ph),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e)=>{const i=new Set;for(const e of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&i.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[]){const n=Array.isArray(s.segments)?s.segments:[];for(let o=0;o{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;const i=Km(t,e);if(!i)throw new Mm("opening-host",t.id);t.host=i}})(t,a),a.reduce((t,e)=>t+(s.has(e.id)?0:1),0)};function Jm(t,e={}){const i=JSON.stringify(t),s=Cm(t);rl(s);let n=0;const o=Number(s?.model_version||0)<9;for(const t of Array.isArray(s?.spaces)?s.spaces:[]){const i=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0;n+=Ym(t,o,i)}return s.model_version=9,rl(s),{config:s,changed:i!==JSON.stringify(s),migratedSegments:n}}const Xm=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Zm(t,e){const i=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const s=new Map;for(const e of t)Xm(e)&&"string"==typeof e.id&&e.id&&s.set(e.id,e);const n=e.map((e,n)=>{if(Xm(e)&&"string"==typeof e.id&&e.id){const t=s.get(e.id);return t?i(t,e):Cm(e)}return n[e,e in t?i(t[e],s):Cm(s)]);for(const e of Object.keys(t))delete t[e];for(const[e,i]of s)t[e]=i;return t}return Cm(e)};return i(t,e)}const Qm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),tg=(t,e,i)=>Math.min(i,Math.max(e,t)),eg=t=>$h({spaces:[t]})[0],ig=(t,e,i)=>{const s=i>0?i:1,n=t=>`${(t[0]/s).toFixed(12)},${(t[1]/s).toFixed(12)}`,o=n(t),a=n(e);return o0?a:1,l=Math.max(s*r*.02,1e-9),c=[];for(const e of t||[])for(const t of hi(e)||[])c.push([t[0],t[1]]);const h=[];for(const t of i||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&h.push([t[0],t[1]],[t[2],t[3]]);const d=(t,e)=>e.some(e=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l),p=new Map;for(const a of t||[]){if(!a?.id)continue;const u=hc(t,a.id,e,i,s,n,o,r);if(u)for(let t=0;t0&&_>0&&a===m&&_!==a))continue;const g=u.poly[s],f=u.poly[(s+1)%u.poly.length],v=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(v>l&&v<.5*o-1e-9*o))continue;if(d(g,h)||d(f,h))continue;if(d(g,c)&&d(f,c))continue;const y=ig(g,f,r),b=p.get(y);b?b.targets.add(a):p.set(y,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([a])})}}}let u=e.slice();const _=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const i=[Number(t.a[0])*r,Number(t.a[1])*r],s=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...i,...s].every(Number.isFinite)&&(_(i,e.a)&&_(s,e.b)||_(i,e.b)&&_(s,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>ig(t.a,t.b,r).localeCompare(ig(e.a,e.b,r)))){const e=[...t.targets][0],i=u.filter(e=>m(e,t));if(new Set(i.map(t=>t.cm)).size>1)continue;let n=!1;u=u.map(i=>m(i,t)?(n=!0,i.cm===e?i:{...i,cm:e}):i),n||(u=Fl(u,t.a,t.b,e,s,r))}return u}const ng=t=>{const e=[];for(const i of t||[]){const t=hi(i);if(t?.length)for(let i=0;i"string"==typeof t?.id?t.id:"").filter(Boolean),h=new Set(c),d=new Map;for(const t of c){const e=xm("space",t);e.layers>0&&km("space",e.root)&&$m(d,e.root,t)}const p=new Map,u=new Map,_=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const i=new Map;for(const s of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof s?.id?s.id:"";if(!t)continue;const n=xm("room",t);n.layers>0&&km("room",n.root)&&$m(i,n.root,t),u.has(t)||u.set(t,e),_.has(t)||_.set(t,String(s.name||""));const o="string"==typeof s.area?s.area:"";if(o){const i=m.get(o)||[];i.push({spaceId:e,roomId:t}),m.set(o,i)}}p.set(e,i)}const g=new Set(u.keys()),f=new Map,v=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?v.set(t.id,t):f.set(t.id,t));const y={spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,positionsUnresolved:0,nestedRefsUnresolved:0,deadSpaceIds:[],orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0,removedPositions:[],liveMissingPositions:[],unverifiedPositions:[]},b=new Set,w=t=>h.has(t)?null:(()=>{const e=xm("space",t).root;if(!km("space",e))return null;const i=d.get(e)||[];return 1===i.length?i[0]:null})(),k=(t,e)=>{const i=xm("room",t).root;if(!km("room",i))return null;const s=p.get(e)?.get(i)||[];return 1===s.length?s[0]:null},x=t=>{const e=i.effectiveAreaByMarker?.[t]||"",s=e&&m.get(e)||[];return 1===s.length?s[0]:null},$=(t,e,i)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const s=e?k(t.room_id,e):null;s?(t.room_id=s,y.roomRefsRemapped++):i?(t.room_id=i.roomId,y.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const s=t.vacuum?.segment_map;if(s&&"object"==typeof s&&!Array.isArray(s))for(const t of Object.keys(s)){const i=s[t];if("string"!=typeof i||!i||g.has(i))continue;const n=e?k(i,e):null;n?(s[t]=n,y.roomRefsRemapped++):y.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const i="string"==typeof t.space?t.space:"",s=i&&!h.has(i),o=n[e],a="string"==typeof o?.s?o.s:"",r=a&&!h.has(a),l=!0===t.removed;let c=i&&h.has(i)?i:null,d=null,p=!1;if(s){const s=w(i);s?(t.space=s,c=s,p=!0,y.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,c=null,y.markersDetached++):(d=x(e),d?(t.space=d.spaceId,c=d.spaceId,y.spaceRefsRemapped++):(delete t.space,c=null,y.markersDetached++))}l&&!p||$(t,c,d),r&&p&&a===i&&c&&(n[e]={...o,s:c},y.positionsRemapped++,b.add(e))}for(const t of Object.keys(n)){if(b.has(t))continue;const e=n[t],i="string"==typeof e?.s?e.s:"";if(!i||h.has(i))continue;const s=w(i);if(s){if(t.startsWith("rl_")){const i=t.slice(3),o=k(i,s);if(o){const i=`rl_${o}`;wm(n,i)||(n[i]={...e,s:s}),delete n[t],y.roomRefsRemapped++,y.positionsRemapped++;continue}}n[t]={...e,s:s},y.positionsRemapped++}}const S=i.ownerRoster,M=!0===S?.authoritative,C=new Set(S?.deviceIds||[]),D=new Set(S?.entityIds||[]),P=new Set(Array.isArray(s.settings?.known_devices)?s.settings.known_devices.filter(t=>"string"==typeof t):[]),T=(t,e="")=>{const i=String(S?.names?.[t]||e||"").trim();return i&&i!==t?i:""},R=(t,e,i,s="",n)=>({id:t,spaceId:e,kind:i,name:T(t,s),...n?{reason:n}:{}}),I=t=>{"room_label"===t?y.orphanRoomLabelsRemoved++:"group"===t?y.orphanGroupPositionsRemoved++:y.orphanDevicePositionsRemoved++},A=new Set;for(const[t,e]of Object.entries(n)){const s="string"==typeof e?.s?e.s:"";if(!s||h.has(s))continue;let o,a;const r=f.get(t),l=v.get(t);if(r)o=R(t,s,"device",String(r.name||"")),a="live";else if(l)o=R(t,s,"device",String(l.name||"")),a="absent";else if(t.startsWith("rl_")){const e=t.slice(3);o=R(t,s,"room_label",_.get(e)||""),a=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);o=R(t,s,"group"),a=D.has(e)?"live":M?"absent":"unverified","unverified"===a&&(o.reason="registry_unavailable")}else C.has(t)?(o=R(t,s,"device"),a="live"):P.has(t)?(o=R(t,s,"device"),a=M?"absent":"unverified","unverified"===a&&(o.reason="registry_unavailable")):(o=R(t,s,"unknown","","unknown_owner"),a="unverified");if("absent"!==a){if("live"===a){if(y.liveMissingPositions.push(o),!0===i.removeLiveMissingPositions){delete n[t],y.liveMissingPositionsRemoved++,I(o.kind),y.removedPositions.push(o);continue}}else y.unverifiedPositions.push(o);y.positionsUnresolved++,A.add(s)}else delete n[t],I(o.kind),y.removedPositions.push(o)}return y.deadSpaceIds=[...A].sort((t,e)=>t.localeCompare(e)),{config:s,layout:n,report:y,changed:JSON.stringify(s)!==o||JSON.stringify(n)!==a}}(t,e,i),a=o.config,r=nl(a,o.layout);rl(a),al(o.layout);const l=JSON.stringify(t||{}),c=JSON.stringify(e||{}),h=Number.isInteger(Number(a.model_version))?Number(a.model_version):0,d=(t=>{let e=0,i=0,s=0;for(const i of t.markers||[]){if("ripple"===i.display&&(i.display="icon_ripple",e++),Array.isArray(i.controls)){const t="string"==typeof i.binding&&i.binding.startsWith("entity:")?i.binding.slice(7):"",s=t?i.controls.filter(e=>e!==t):i.controls;JSON.stringify(s)!==JSON.stringify(i.controls)&&(i.controls=s.length?s:null,e++)}const t=i.vacuum;t&&Qm(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const n of t.spaces||[]){const t=n.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,i++);for(const t of n.rooms||[]){const i=t.settings;"glow"===i?.fill_mode&&("boolean"!=typeof i.glow&&(i.glow=!0),delete i.fill_mode,e++,s++)}if(Qm(n,"segments")&&(delete n.segments,e++),Qm(n,"plan_scale")){const t=Number(n.plan_scale);Number.isFinite(t)&&t>=bh&&t<=wh&&(Qm(n,"plan_scale_x")||(n.plan_scale_x=t),Qm(n,"plan_scale_y")||(n.plan_scale_y=t),delete n.plan_scale,e++)}const o=Number(n.cell_cm);Qm(n,"cell_cm")&&(!Number.isFinite(o)||o<.1||o>1e3)&&(n.cell_cm=Number.isFinite(o)&&o>0?tg(o,.1,1e3):5,e++);const a=Number(n.cell_cm),r=Number.isFinite(a)&&a>0?a:5;for(const t of n.wall_columns||[])if("circle"===t.shape)Qm(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Qm(t,"angle")){const i=((Number(t.angle)||0)%90+90)%90;t.angle!==i&&(t.angle=i,e++)}for(const t of n.decor||[]){if(Qm(t,"width")){const i=Number(t.width);(Qm(t,"width_cm")||Number.isFinite(i))&&(Qm(t,"width_cm")||(t.width_cm=Number(tg(i/Dh*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Qm(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Qm(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(tg(es*is(t)/Dh*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Qm(t,"scale")||Qm(t,"size"))&&(delete t.scale,delete t.size,e++);let i=String(t.text??"");const s=[...i.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!Yi(t[1]));if(!(Qm(t,"entity")||Qm(t,"attr")||Qm(t,"unit")))continue;const n=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,a=s||n?"":Ji(t.entity,o);if(s||a){if(a){const e=i.indexOf("{}");i=e>=0?i.slice(0,e)+a+i.slice(e+2):`${i}${i?" ":""}${a}`,t.text=i}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:i,glowRooms:s}})(a);let p=d.total;const u=(_=a.spaces||[],JSON.parse(JSON.stringify(_)));var _;const m=J_(a.spaces||[],o.layout);let g=0,f=0,v=0,y="";const b=m.spaces.map(t=>{const e=function(t){const e=JSON.parse(JSON.stringify(t||{}));let i=Array.isArray(e.rooms)?e.rooms:[];const s=new Map;for(const t of i){const e=hi(t);if(e)for(let t=0;tt.key.localeCompare(e.key))){let e=null;for(const s of $a(t,i)){const t=r.get(_a(s.from));if(t&&t!==_a(s.to))continue;const n=wa(i,s);if(ka(i,n,s)){e=s,i=n;break}}e?(r.set(_a(e.from),_a(e.to)),n++,a=Math.max(a,Math.hypot(e.to[0]-e.from[0],e.to[1]-e.from[1]))):o++}e.rooms=i;for(const t of e.room_drafts||[]){if(!Array.isArray(t?.points)||t.points.length<2)continue;const e=t.points.map(t=>[...t]),i=e.slice(0,-1).flatMap((i,s)=>{const n=e[s+1],o=pa(i,n);return o?[{key:`${String(t.id||"")}:${s}`,a:[...i],b:[...n],axis:o.axis}]:[]});let s=e;for(const t of i){let e=null;for(const i of $a(t,[{poly:s}])){const t=s.map(t=>ba(t,i)),n=t.length>=4&&ma(t[0],t[t.length-1]),o=n?t.slice(0,-1):t;if(n?va(o):ya(o)){e=i,s=t;break}}e?(n++,a=Math.max(a,Math.hypot(e.to[0]-e.from[0],e.to[1]-e.from[1]))):o++}t.points=s}for(const t of e.partitions||[]){if(!Array.isArray(t?.a)||!Array.isArray(t?.b))continue;const i=pa(t.a,t.b);if(!i)continue;const s={key:String(t.id||ga(t.a,t.b)),a:[...t.a],b:[...t.b],axis:i.axis};let r=null;for(const i of $a(s,[{poly:[t.a,t.b]}])){const s=ba(t.a,i),n=ba(t.b,i),o=Math.hypot(n[0]-s[0],n[1]-s[1]);if(!(o>0))continue;const a=(e.openings||[]).filter(e=>"partition"===e?.host?.kind&&e.host.id===t.id).every(t=>{const e=Number(t.host.t),i=Number(t.length);return Number.isFinite(e)&&e>=0&&e<=1&&Number.isFinite(i)&&i>0&&e*o-i/2>=-1e-12&&e*o+i/2<=o+1e-12});if(a){r=i,t.a=s,t.b=n;break}}r?(n++,a=Math.max(a,Math.hypot(r.to[0]-r.from[0],r.to[1]-r.from[1]))):o++}return{space:e,report:{wallsStraightened:n,wallsStraightenSkipped:o,maxStraightenShift:a},changed:n>0}}(t);g+=e.report.wallsStraightened,f+=e.report.wallsStraightenSkipped;const i=Number(t?.cell_cm)>0?Number(t.cell_cm):5,s=e.report.maxStraightenShift/Ph*i;return s>v&&(v=s,y=String(t?.id||"")),e.space}),w=g?J_(b,m.layout):{...m,spaces:b};a.spaces=w.spaces;const k=g?{...m.report,moved:m.report.moved+w.report.moved,coordsCanonicalized:m.report.coordsCanonicalized+w.report.coordsCanonicalized,maxShift:Math.max(m.report.maxShift,w.report.maxShift),maxShiftCm:Math.max(m.report.maxShiftCm,w.report.maxShiftCm),maxSpace:w.report.maxShiftCm>m.report.maxShiftCm?w.report.maxSpace:m.report.maxSpace,rotated:m.report.rotated+w.report.rotated,removedDrafts:m.report.removedDrafts+w.report.removedDrafts}:{...m.report};let x=0,$=0,S=0,M=0,C=0,D=0,P=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),o=eg(e),r=eg(i);if(!o||!r)continue;const l=ng(o.rooms),c=ng(r.rooms),h=.02*Dh,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:wl(t.a,t.b,Ph),cm:0})),p=new Set(d.map(t=>t.key)),_=__(e,o.rooms,vh,h);$+=_.length;for(const t of _){const e=[t[0]/vh,t[1]/vh],i=[t[2]/vh,t[3]/vh],s=wl(e,i,Ph);p.has(s)||(p.add(s),d.push({key:s,a:e,b:i,cm:0}))}const m=d.length,g=Al(d,l,c,Ph,vh),f=(t,e,i)=>{const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;if(!(o>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const a=Math.max(0,Math.min(1,((t[0]-e[0])*s+(t[1]-e[1])*n)/o));return Math.hypot(t[0]-(e[0]+s*a),t[1]-(e[1]+n*a))},v=g.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*vh),i=t.b.map(t=>t*vh);return c.some(([t,s])=>f(e,t,s)<=4*h&&f(i,t,s)<=4*h)});S+=Math.max(0,m-v.length);const y=(i.wall_segments||[]).filter(t=>Number(t.cm)>0);i.wall_segments=[...y,...v.map(({key:t,...e})=>e)];const b=v.map(t=>[t.a[0]*vh,t.a[1]*vh,t.b[0]*vh,t.b[1]*vh]),w=Array.isArray(e.walls)?e.walls.length:0;let k=Al(e.walls,l,c,Ph,vh);k=sg(r.rooms,k,b,Ph,Number(i.cell_cm)>0?Number(i.cell_cm):5,Dh,vh),k=uc(r.rooms,k,b,Ph,Number(i.cell_cm)>0?Number(i.cell_cm):5,Dh,vh),k=Tl(k,i.rooms||[],Ph,1,b.map(t=>[t[0]/vh,t[1]/vh,t[2]/vh,t[3]/vh])),x+=Math.max(0,w-k.length),k.length?i.walls=k:delete i.walls;const R=sm(i.partitions||[],{pitch:Ph,geometry:om(i)});R.merged&&(M+=R.merged,i.partitions=R.partitions,nm(i.openings,i.partitions,R.openingMoves,{coordScale:vh,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,gridPitch:Dh}));const I=eg(i);if(I){const t=n(i,I,i.walls||[],b,{pitch:Ph,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,gridPitch:Dh,coordScale:vh});t.partitionsReconciled&&(C+=t.partitionsReconciled,D+=t.openingsRehosted,t.partitions.length?i.partitions=t.partitions:delete i.partitions,t.openings.length?i.openings=t.openings:delete i.openings,t.walls.length?i.walls=t.walls:delete i.walls),t.removedDrafts&&(P+=t.removedDrafts,t.roomDrafts.length?i.room_drafts=t.roomDrafts:delete i.room_drafts)}JSON.stringify({zero:(i.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:i.walls||[]})!==s&&T++}let R=0;h<=9&&(R=function(t){const e=Jm(t);return Zm(t,e.config),{...e,config:t}}(a).migratedSegments);const I=rl(a),A=al(w.layout),z=JSON.stringify(I)!==l||JSON.stringify(A)!==c;h<9&&z&&(I.model_version=9);const F=JSON.stringify(I)!==l||JSON.stringify(A)!==c,E=Number.isInteger(Number(I.model_version))?Number(I.model_version):h,N=F?k:{...k,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0,removedDrafts:0},O=F?o.report:{...o.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:I,layout:A,report:{...N,modelFrom:h,modelTo:E,migrated:F?p:0,glowSpacesMigrated:F?d.glowSpaces:0,glowRoomsMigrated:F?d.glowRooms:0,canonicalized:F?T:0,wallSegmentsMigrated:F?R:0,legacyZeroWallsMigrated:F?$:0,wallsMerged:F?x:0,spansMerged:F?S:0,partitionsMerged:F?M:0,partitionsReconciled:F?C:0,openingsRehosted:F?D:0,redundantDraftsRemoved:F?P:0,wallsStraightened:F?g:0,wallsStraightenSkipped:f,maxStraightenShiftCm:F?v:0,maxStraightenSpace:F?y:"",latticeCoordinatesCanonicalized:F?r.canonicalized:0,latticeCoordinatesFar:F?r.far:0,latticeMaxShift:F?r.maxShift:0,latticeMaxShiftCm:F?r.maxShiftCm:0,latticeSpaces:F?r.spaces:[],...O},changed:F}}function ag(t,e,i){const s=(t?.spaces||[]).find(t=>t?.id===i),n=new Set((s?.rooms||[]).map(t=>String(t?.id||"")).filter(Boolean)),o=[...new Set((t?.markers||[]).filter(t=>!0!==t?.removed&&"string"==typeof t?.id).filter(t=>t.space===i||"string"==typeof t.room_id&&n.has(t.room_id)||e?.[t.id]?.s===i).map(t=>t.id))].sort((t,e)=>t.localeCompare(e));return{markerIds:o,count:o.length}}function rg(t){return t instanceof Error?t.name||"Error":typeof t}function lg(t){return bd({id:t?.id??"",cell_cm:t?.cell_cm,rooms:t?.rooms||[],walls:t?.walls||[],wall_segments:t?.wall_segments||[],open_spans:t?.open_spans||[],openings:t?.openings||[],partitions:t?.partitions||[],room_drafts:t?.room_drafts||[],wall_columns:t?.wall_columns||[]})}function cg(t,e,i,s=Dh,n=1e3){return(Array.isArray(t?.openings)?t.openings:[]).flatMap(t=>{const o={...t,rx:Number(t.x)*n,ry:Number(t.y)*n,rlen:Number(t.length)*n};if(!t.host||"wall"===t.host.kind)return[o];const a=$p(t,e.partitions,n,i,s);return a.resolved?[{...t,rx:a.resolved.center[0],ry:a.resolved.center[1],rlen:a.resolved.length,angle:a.resolved.angle,partitionHost:a.resolved}]:[]})}function hg(t,e=()=>!0){return t.flatMap(t=>t.host&&t.partitionHost&&e(t)?[Cp(t.partitionHost)]:[])}function dg(t,e,i,s,n,o,a=Dh,r=1e3){const l=dc(e.rooms,[...i],s,n,o,a,r);return t.flatMap(t=>{const e={x:t.rx,y:t.ry,angle:Number(t.angle)||0,length:t.rlen};return t.host&&"wall"!==t.host.kind?t.partitionHost&&Tp(t.partitionHost,l,2e-4*a)?[e]:[]:[e]})}function pg(t,e){const i=Ph,s=Dh,n=vh,o=Number.isFinite(Number(e.cellCm))&&Number(e.cellCm)>0?Number(e.cellCm):5,a=Array.isArray(t?.walls)?t.walls:[],r=function(t,e,i=Dh,s=1e3){return ud(e.rooms,t?.open_spans,s,.02*i)}(t,e,s,n),l=function(t,e,i=Dh){if(!e.length)return[];const s=t.filter(t=>t?.id),n=.02*i,o=[];for(let t=0;t{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return h.some(t=>Ls(e,t)<4*n)}).map(t=>[...t]);d.length&&o.push({a:a,b:r,segs:d})}return o}(e.rooms,r,s).flatMap(t=>t.segs),c=cg(t,e,o,s,n),h=hg(c),d=eh(e,o,s,2e-4*s,h).all;return{space:e,walls:a,openCuts:l,openings:c,roomOpenings:dg(c,e,a,l,i,o,s,n),partitionCuts:h,physicalBodies:d,wallKeyPitch:i,cellCm:o,gridPitch:s,coordScale:n}}function ug(t,e,i){const s="string"==typeof t?.title?t.title.trim():"",n=null==t?.id?"":String(t.id).trim();return{spaceId:n,displayName:s||n||i(e+1)}}function _g(t,e={}){const i=(e.fingerprint||bd)(t),s=Array.isArray(t?.spaces)?t.spaces:[],n=e.fallbackSpaceName||(t=>`Space ${t}`),o=e.prepareSpace||pg,a=e.wallPass||Rc,r=e.floorPass||Pc,l=[];for(let e=0;e0||h.physicalBodies.length>0;if(!h.space.rooms.length&&!d){l.push({...c,status:"not-applicable"});continue}let p=null;if(d){try{p=a(h.space.rooms,h.walls,h.openCuts,h.roomOpenings,h.wallKeyPitch,h.cellCm,h.gridPitch,h.coordScale,h.physicalBodies)}catch(t){l.push({...c,status:"failed",reason:"wall-exception",detail:rg(t)});continue}if(null==p){l.push({...c,status:"failed",reason:"wall-null"});continue}if("degraded-extra"===p.status){l.push({...c,status:"failed",reason:"wall-degraded-extra"});continue}if("failed-core"===p.status){l.push({...c,status:"failed",reason:"wall-failed-core"});continue}}if(h.space.rooms.length&&null==p?.paperGeom){let t;try{t=r(h.space.rooms,h.walls,h.openCuts,h.wallKeyPitch,h.cellCm,h.gridPitch,h.coordScale)}catch(t){l.push({...c,status:"failed",reason:"floor-exception",detail:rg(t)});continue}if(null==t){l.push({...c,status:"failed",reason:"floor-null"});continue}}l.push({...c,status:"ok"})}const c=l.filter(t=>"failed"===t.status);return{fingerprint:i,spaces:l,failures:c,ok:0===c.length}}class mg{constructor(t=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(t))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(t){this._undo.push(t),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const t=this._undo.pop()??null;return t&&this._redo.push(t),t}redo(){const t=this._redo.pop()??null;return t&&this._undo.push(t),t}clear(){this._undo=[],this._redo=[]}}const gg=new WeakMap;const fg=(t,e,i)=>255===t[i+3]&&e.every((e,s)=>Math.abs(t[i+s]-e)<=2);async function vg(t){const e=t.defaultView;if(!e||!e.CSS?.supports?.("mix-blend-mode","screen"))return!1;const i=[128,32,16],s=[16,64,128],n=[9,19,29],o=`\n \n \n \n \n \n `,a=e.URL.createObjectURL(new Blob([o],{type:"image/svg+xml"}));try{const o=await new Promise((t,i)=>{const s=new e.Image,n=e.setTimeout(()=>i(new Error("SVG blend probe timeout")),1e3);s.onload=()=>{e.clearTimeout(n),t(s)},s.onerror=()=>{e.clearTimeout(n),i(new Error("SVG blend probe failed"))},s.src=a}),r=t.createElement("canvas");r.width=4,r.height=1;const l=r.getContext("2d",{willReadFrequently:!0});if(!l)return!1;l.drawImage(o,0,0,4,1);const c=l.getImageData(0,0,4,1).data;return fg(c,i,0)&&fg(c,function(t,e){return[0,1,2].map(i=>Math.round(255-(255-t[i])*(255-e[i])/255))}(i,s),4)&&fg(c,s,8)&&fg(c,n,12)}catch{return!1}finally{e.URL.revokeObjectURL(a)}}const yg={now:()=>performance.now(),requestFrame:t=>requestAnimationFrame(t),cancelFrame:t=>cancelAnimationFrame(t)},bg=t=>Math.max(0,Math.min(1,t)),wg=(t,e,i)=>t+(e-t)*i,kg=(t,e,i)=>{const s=1-t;return 3*s*s*t*e+3*s*t*t*i+t*t*t};function xg(t,e){return{centerX:t.x+t.w/2,centerY:t.y+t.h/2,pixelsPerUnit:e>0&&t.w>0?e/t.w:1,viewBox:{...t}}}function $g(t,e,i){const s=Math.max(1e-9,t.pixelsPerUnit),n=Math.max(1e-9,e/s),o=Math.max(1e-9,i/s);return{x:t.centerX-n/2,y:t.centerY-o/2,w:n,h:o}}function Sg(t){const e=t.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(e);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const s=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(e)?.[1];return s?[parseInt(s.slice(0,2),16),parseInt(s.slice(2,4),16),parseInt(s.slice(4,6),16),8===s.length?parseInt(s.slice(6,8),16)/255:1]:null}function Mg(t,e,i){const s=Sg(t),n=Sg(e);if(!s||!n)return i<.5?t:e;const o=bg(i);return`rgba(${Math.round(wg(s[0],n[0],o))}, ${Math.round(wg(s[1],n[1],o))}, ${Math.round(wg(s[2],n[2],o))}, ${wg(s[3],n[3],o).toFixed(3)})`}function Cg(t,e,i){const s=(t=>{const e=bg(t);if(0===e||1===e)return e;let i=0,s=1,n=e;for(let t=0;t<12;t++)n=(i+s)/2,kg(n,.2,.2){const e=this._state;if(!e||e.token!==n)return;const i=bg((t-e.startedAt)/e.duration);e.presented=i>=1?e.to:Cg(e.from,e.to,i),e.phase=i>=1?"settling":"running",this._hooks.frame(e),i<1?this._raf=this._clock.requestFrame(a):(this._raf=0,this._hooks.settled(e),this._state?.token===n&&(this._state=null))};return this._raf=this._clock.requestFrame(a),n}cancel(t=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const e=this._state;this._state=null,this._token++,e&&t&&(e.phase="settling",e.presented=e.to,this._hooks.frame(e),this._hooks.settled(e))}dispose(){this.cancel(!1)}}const Pg="houseplan_card_labs_v1",Tg=Object.freeze([Object.freeze({id:"iso",issue:89,since:"1.62.0",expires:"1.65.0",summary:"Volumetric plan renderer"})]);function Rg(t){const e=/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/.exec(String(t||"").trim());if(!e)return null;const i=e.slice(1).map(Number);return i.every(t=>Number.isSafeInteger(t))?i:null}function Ig(t,e){for(let i=0;i<3;i++)if(t[i]!==e[i])return t[i]t.split(",")).map(t=>t.trim()).filter(Boolean)}function Og(t,e,i,s=Tg){const n=function(t,e=Tg){const i=Rg(t),s=new Map;if(!i||!zg(e))return s;for(const t of e){const e=Rg(t.since),n=Rg(t.expires);Ig(i,e)>=0&&Ig(i,n)<0&&s.set(t.id,t)}return s}(i,s),o=new Set(zg(s)?s.map(t=>t.id):[]),a=new Set(function(t){if(!t)return[];try{const e=JSON.parse(t);return Array.isArray(e)?e.filter(t=>"string"==typeof t):[]}catch{return[]}}(e).filter(t=>n.has(t)));let r=!1;const l=t=>{if("off"===t)return a.clear(),void(r=!0);const e=t.startsWith("-"),i=e?t.slice(1):t;o.has(i)&&(r=!0,e||!n.has(i)?a.delete(i):a.add(i))};for(const e of Ng(new URLSearchParams(String(t.search||"").replace(/^\?/,""))))l(e);for(const e of Ng(Fg(t.hash)))l(e);const c=Object.freeze([...a].sort());return{active:c,space:Eg(t.hash),persist:r?JSON.stringify(c):void 0,knownUrlOperation:r}}let Lg={active:Object.freeze([]),space:""},Hg="",Bg=!1,qg="";const Wg=new Set;function jg(){if("undefined"==typeof window)return Lg;const t=Og(window.location,function(){try{return window.localStorage.getItem(Pg)}catch{return null}}(),Hg);void 0!==t.persist&&function(t){try{window.localStorage.setItem(Pg,t)}catch{}}(t.persist),Lg={active:t.active,space:t.space},window.__hpLabs=t.active;for(const t of Wg)t(Lg);return Lg}function Ug(){jg()}function Gg(t){return Hg=t,"undefined"==typeof window?Lg:(Bg||(Bg=!0,window.addEventListener("hashchange",Ug),window.addEventListener("popstate",Ug)),jg())}const Vg=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])});function Kg(t){return[t.rotDeg,t.tiltDeg,t.xyScale,t.zScale,t.origin[0],t.origin[1]].every(Number.isFinite)&&Math.abs(t.xyScale)>1e-12&&Math.abs(Math.cos(t.tiltDeg*Math.PI/180))>1e-12}function Yg(t,e,i=Vg){if(!(Kg(i)&&Number.isFinite(t[0])&&Number.isFinite(t[1])&&Number.isFinite(e)))throw new Error("invalid isometric projection input");const s=i.rotDeg*Math.PI/180,n=i.tiltDeg*Math.PI/180,o=t[0]-i.origin[0],a=t[1]-i.origin[1],r=(o*Math.cos(s)-a*Math.sin(s))*i.xyScale,l=(o*Math.sin(s)+a*Math.cos(s))*i.xyScale;return[i.origin[0]+r,i.origin[1]+l*Math.cos(n)-e*i.zScale*Math.sin(n)]}function Jg(t,e=Vg){if(!Kg(e)||!Number.isFinite(t[0])||!Number.isFinite(t[1]))throw new Error("invalid isometric projection input");const i=e.rotDeg*Math.PI/180,s=e.tiltDeg*Math.PI/180,n=(t[0]-e.origin[0])/e.xyScale,o=(t[1]-e.origin[1])/(e.xyScale*Math.cos(s));return[e.origin[0]+n*Math.cos(i)+o*Math.sin(i),e.origin[1]-n*Math.sin(i)+o*Math.cos(i)]}function Xg(t=Vg){return`matrix(${function(t=Vg){if(!Kg(t))throw new Error("invalid isometric camera");const e=t.rotDeg*Math.PI/180,i=t.tiltDeg*Math.PI/180,s=t.xyScale*Math.cos(e),n=-t.xyScale*Math.sin(e),o=t.xyScale*Math.sin(e)*Math.cos(i),a=t.xyScale*Math.cos(e)*Math.cos(i);return[s,o,n,a,t.origin[0]-s*t.origin[0]-n*t.origin[1],t.origin[1]-o*t.origin[0]-a*t.origin[1]]}(t).map(t=>Number(t.toFixed(12))).join(" ")})`}function Zg(t,e=Vg){const{rect:i,wallHeight:s}=t,n=t.openingHeight??s,o=t.floorDepth??0;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(s)||!Number.isFinite(n)||!Number.isFinite(o)||s<0||n<0||o<0)throw new Error("invalid isometric frame");const a=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],r=Math.max(s,n),l=a.flatMap(t=>[Yg(t,-o,e),Yg(t,r,e)]),c=l.map(t=>t[0]),h=l.map(t=>t[1]),d=Math.min(...c),p=Math.min(...h);return{x:d,y:p,w:Math.max(...c)-d,h:Math.max(...h)-p}}const Qg=t=>`${Number(t[0].toFixed(4))} ${Number(t[1].toFixed(4))}`;function tf(t){let e=0;for(let i=0;iArray.isArray(t)&&Number.isFinite(t[0])&&Number.isFinite(t[1])).map(t=>[Number(t[0]),Number(t[1])]),i=e[e.length-1];return e.length>1&&e[0][0]===i[0]&&e[0][1]===i[1]&&e.pop(),e}(t);if(i.length<3)return[];const s=!e;return tf(i)>0===s?i:[...i].reverse()}function sf(t,e,i){return t.length?`M ${t.map(t=>Qg(Yg(t,i,e))).join(" L ")} Z`:""}function nf(t,e,i){const s=e[1]-t[1],n=-(e[0]-t[0]),o=i.rotDeg*Math.PI/180;return s*Math.sin(o)+n*Math.cos(o)}function of(t,e,i=Vg){if(!Number.isFinite(e)||e<0)throw new Error("invalid floor edge height");const s=(t||[]).map(t=>(t||[]).map((t,e)=>function(t,e){const i=ef(t,e);if(!i.length)return i;let s=0;for(let t=1;t0)).filter(t=>t.length>=3&&Math.abs(tf(t))>=1e-9)).filter(t=>t.length&&tf(t[0])>0);s.sort((t,e)=>{const i=t[0][0],s=e[0][0];return i[0]-s[0]||i[1]-s[1]||Math.abs(tf(e[0]))-Math.abs(tf(t[0]))});const n=[],o=[];let a=0;for(let t=0;tt.depth-e.depth||t.component-e.component||t.edge-e.edge),{footprintPath:n.join(" "),sides:o,componentCount:s.length,edgeCount:a}}function af(t,e){return t^=Math.round(64*(Number.isFinite(e)?e:0)),Math.imul(t,16777619)>>>0}const rf=t=>t.every(Number.isFinite);function lf(t,e,i,s){const n=t[0]*i,o=t[1]*s,a=e*Math.PI/180;return[n*Math.cos(a)-o*Math.sin(a),n*Math.sin(a)+o*Math.cos(a)]}function cf(t,e,i,s,n,o,a){const r=t.flipH?-1:1,l="gate"===t.type?1:t.flipV?-1:1,c=(t.type,t.flipV,t.angle,t.face,{ox:0,oy:0}),h=function(t,e){return[t[0]+e[0],t[1]+e[1]]}([t.x+c.ox,t.y+c.oy],lf(i,t.angle,r,l));return{leaf:e,hinge:h,closedVector:lf(s,t.angle,r,l),quarterVector:lf([-s[1],s[0]],t.angle,r,l),turnDeg:n,bottom:o,top:a}}const hf=t=>`${Number(t[0].toFixed(4))} ${Number(t[1].toFixed(4))}`;function df(t,e,i=Vg){const s=Math.max(0,Math.min(1,Number.isFinite(e)?e:0));return t.leaves.map(e=>{const n=function(t,e){const i=t.turnDeg*e*Math.PI/180;return[t.hinge[0]+t.closedVector[0]*Math.cos(i)+t.quarterVector[0]*Math.sin(i),t.hinge[1]+t.closedVector[1]*Math.cos(i)+t.quarterVector[1]*Math.sin(i)]}(e,s),o=Yg(e.hinge,e.bottom,i),a=Yg(n,e.bottom,i),r=Yg(n,e.top,i),l=Yg(e.hinge,e.top,i);return{id:t.id,sourceIndex:t.sourceIndex,type:t.type,leaf:e.leaf,d:`M ${hf(o)} L ${hf(a)} L ${hf(r)} L ${hf(l)} Z`,shadowD:`M ${hf(Yg(e.hinge,0,i))} L ${hf(Yg(n,0,i))}`,depth:Math.max(o[1],a[1])}})}const pf={window:120,door:90,passage:90,gate:300};function uf(t){return pf[t]}function _f(t,e){const i=[t[0],t[1]],s=[e[0],e[1]];return function(t,e){return t[0]-e[0]||t[1]-e[1]}(i,s)<=0?{a:i,b:s}:{a:s,b:i}}function mf(t){const e=new Map;return t.forEach((t,i)=>{if(!t.kind||t.open)return;const s=_f(t.a,t.b);if(Math.hypot(s.b[0]-s.a[0],s.b[1]-s.a[1])<=1e-9)return;const n=function(t,e){const i=t=>(Math.abs(t)<=5e-10?0:Math.round(1e6*t)/1e6).toFixed(6);return`${i(t[0])},${i(t[1])}>${i(e[0])},${i(e[1])}`}(s.a,s.b),o=e.get(n);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,t.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(t.partitionHost&&(o.partitionHost&&o.partitionHost.id!==t.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=t.partitionHost));e.set(n,{segmentKey:n,a:s.a,b:s.b,physicalHalfWidth:Math.max(0,t.half||0),sourceOrder:i,...t.partitionHost?{partitionHost:t.partitionHost}:{}})}),[...e.values()]}function gf(t,e){if(Math.abs(t.distance-e.distance)>1e-9)return t.distance-e.distance;if(Math.abs(t.perpendicular-e.perpendicular)>1e-9)return t.perpendicular-e.perpendicular;return(t.target.segmentKeye.target.segmentKey?1:0)||t.target.sourceOrder-e.target.sourceOrder}function ff(t){const e=mf(t.intervals).map(e=>{const i=function(t,e){const i=e.b[0]-e.a[0],s=e.b[1]-e.a[1],n=Math.hypot(i,s),o=i/n,a=s/n,r=(t[0]-e.a[0])*o+(t[1]-e.a[1])*a,l=Math.max(0,Math.min(n,r)),c=e.a[0]+l*o,h=e.a[1]+l*a;return{along:l,length:n,x:c,y:h,distance:Math.hypot(t[0]-c,t[1]-h),perpendicular:Math.abs((t[0]-e.a[0])*a-(t[1]-e.a[1])*o)}}(t.pointer,e);return{target:e,...i,envelope:Math.max(t.baseTolerance,e.physicalHalfWidth+t.bodyPointerPadding)}}).filter(t=>t.distance<=t.envelope+1e-9).filter(e=>!function(t,e,i,s,n){const o=e.b[0]-e.a[0],a=e.b[1]-e.a[1],r=Math.hypot(o,a);if(!(r>1e-9))return!1;const l=o/r,c=a/r;for(const o of i){if(!o.open&&o.kind)continue;const i=_f(o.a,o.b),a=i.b[0]-i.a[0],r=i.b[1]-i.a[1],h=Math.hypot(a,r);if(!(h>1e-9))continue;const d=a/h,p=r/h;if(Math.abs(l*p-c*d)>1e-6)continue;if(Math.abs((i.a[0]-e.a[0])*c-(i.a[1]-e.a[1])*l)>n)continue;const u=(t[0]-i.a[0])*d+(t[1]-i.a[1])*p,_=1e-9;if(!(u<=_||u>=h-_)&&Math.abs((t[0]-i.a[0])*p-(t[1]-i.a[1])*d)<=s+1e-9)return!0}return!1}(t.pointer,e.target,t.intervals,e.envelope,Math.max(1e-9,Math.min(t.baseTolerance,.04*t.gridStep)))),i=e.filter(e=>!!e.target.partitionHost&&t.renderedLength+2*e.target.physicalHalfWidth>e.length+1e-9).sort(gf),s=e.filter(e=>!e.target.partitionHost||t.renderedLength+2*e.target.physicalHalfWidth<=e.length+1e-9).sort(gf);let n=s[0];if(!n)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=s.filter(t=>Math.abs(t.distance-n.distance)<=1e-9&&Math.abs(t.perpendicular-n.perpendicular)<=1e-9),a=o.filter(t=>t.target.partitionHost);if(a.length){if(1!==new Set(a.map(t=>t.target.partitionHost.id)).size||a.some(t=>t.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const t=a[0],e=t.target.b[0]-t.target.a[0],i=t.target.b[1]-t.target.a[1],s=Math.hypot(e,i),r=e/s,l=i/s,c=o.every(e=>{const i=e.target.b[0]-e.target.a[0],s=e.target.b[1]-e.target.a[1],n=Math.hypot(i,s),o=i/n,a=s/n,c=Math.abs(r*a-l*o)<=1e-6,h=Math.abs((e.target.a[0]-t.target.a[0])*l-(e.target.a[1]-t.target.a[1])*r);return c&&h<=1e-9});if(!c)return{candidate:null,jambBlockedTarget:null};n=t}if(n.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:r,length:l}=n,c=r.b[0]-r.a[0],h=r.b[1]-r.a[1],d=c/l,p=h/l,u=r.partitionHost?r.physicalHalfWidth:0,_=Math.min(Math.max(0,t.renderedLength)/2+u,l/2);let m=n.along;const g=Math.max(t.gridStep,1e-9),f=l/2;m=Math.abs(m-f)<=g/2?f:Math.round(m/g)*g,m=Math.max(_,Math.min(l-_,m));const v=r.a[0]+d*m,y=r.a[1]+p*m,b=Math.max(0,t.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),$=Math.max(0,l-k),S=[r.a[0]+d*(w-x/2),r.a[1]+p*(w-x/2)],M=[r.a[0]+d*(k+$/2),r.a[1]+p*(k+$/2)];let C=180*Math.atan2(h,c)/Math.PI;C>=90?C-=180:C<-90&&(C+=180);const D=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:t.preset.revision,geometryRevision:t.geometryRevision,pointer:[t.pointer[0],t.pointer[1]],type:t.preset.type,lengthCm:t.preset.lengthCm,flipH:t.preset.flipH,flipV:t.preset.flipV,x:v,y:y,angle:C,renderedLength:t.renderedLength,target:r,...r.partitionHost?{host:{...r.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:S},{distance:$,midpoint:M}],guide:D?{x:v,y:y,angle:C}:null}},jambBlockedTarget:null}}function vf(t,e,i,s,n=1e-6){return t.presetRevision===i&&t.geometryRevision===s&&Math.hypot(t.pointer[0]-e[0],t.pointer[1]-e[1])<=n}const yf=(t,e)=>t[0]*e[1]-t[1]*e[0],bf=(t,e)=>t[0]*e[0]+t[1]*e[1],wf=(t,e)=>[t[0]-e[0],t[1]-e[1]],kf=(t,e,i)=>[t[0]+e[0]*i,t[1]+e[1]*i];function xf(t,e,i){return Math.abs(yf(t,e))<=i}function $f(t,e,i){return Math.abs(yf(wf(t,e),i))}function Sf(t,e,i,s,n){const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(!(r>n&&i>0))return[];const l=[o/r,a/r];return function(t,e,i){const s=e.map(([e,i])=>[Math.max(0,Math.min(e,i)),Math.min(t,Math.max(e,i))]).filter(([t,e])=>e>t+i).sort((t,e)=>t[0]-e[0]||t[1]-e[1]),n=[];for(const t of s){const e=n[n.length-1];!e||t[0]>e[1]+i?n.push([...t]):e[1]=Math.max(e[1],t[1])}const o=[];let a=0;for(const[t,e]of n)t>a+i&&o.push([a,t]),a=Math.max(a,e);return t>a+i&&o.push([a,t]),o}(r,s.flatMap(e=>{const s=e.b[0]-e.a[0],o=e.b[1]-e.a[1],a=Math.hypot(s,o);if(!(a>n&&xf(l,[s/a,o/a],1e-6)))return[];if($f(e.a,t,l)>1.1*Math.max(i,n)||$f(e.b,t,l)>1.1*Math.max(i,n))return[];return[[bf(wf(e.a,t),l),bf(wf(e.b,t),l)]]}),n).flatMap(([e,s])=>{const n=Ol({a:kf(t,l,e),b:kf(t,l,s),halfDepth:i});return n?[n]:[]})}function Mf(t){const e=t.coordScale??1,i=Math.max(t.epsilon??2e-4*t.gridPitch,1e-9),s=[];for(const i of t.rooms||[]){if(!i?.id)continue;const n=hc(t.rooms,i.id,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e);if(!n||n.poly.length<3)continue;const o=Zl(n.poly,n.offsets);!o||o.length<3||s.push({roomId:i.id,profile:n,inner:o})}s.sort((t,e)=>t.roomId.localeCompare(e.roomId));const n=(t.roomOpenings||[]).map(t=>{const e=t.angle*Math.PI/180,i=[Math.cos(e),Math.sin(e)],s=Math.max(0,t.length)/2;return{a:kf([t.x,t.y],i,-s),b:kf([t.x,t.y],i,s)}}),o=[];for(const s of Ac(t.rooms,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e))for(const t of Sf(s.a,s.b,s.depthUnits/2,n,i))o.push({body:t});const a=new Map;for(const e of t.partitionCuts||[]){const t=a.get(e.hostId)||[];t.push(e),a.set(e.hostId,t)}for(const e of t.partitions||[]){const s=gl(e.cm,t.cellCm,t.gridPitch)/2;for(const t of Sf(e.a,e.b,s,a.get(e.id)||[],i))o.push({body:t,partitionId:e.id})}return{rooms:s,boundaries:o,epsilon:i}}function Cf(t,e,i,s){const n=t.profile.offsets[e];if(!(n>0))return null;const o=function(t,e){const i=t[e],s=t[(e+1)%t.length],n=s[0]-i[0],o=s[1]-i[1],a=Math.hypot(n,o)||1;return function(t){let e=0;for(let i=0;i=0?[-o/a,n/a]:[o/a,-n/a]}(t.profile.poly,e),a=kf(i.center,o,n),r=[];for(let e=0;es&&xf(i.axis,[l[0]/c,l[1]/c],1e-6)))continue;if($f(n,a,i.axis)>s||$f(o,a,i.axis)>s)continue;const h=bf(wf(n,a),i.axis),d=bf(wf(o,a),i.axis);r.push([Math.min(h,d),Math.max(h,d)])}const l=function(t,e){t.sort((t,e)=>t[0]-e[0]||t[1]-e[1]);const i=[];for(const s of t){const t=i[i.length-1];!t||s[0]>t[1]+e?i.push([...s]):t[1]=Math.max(t[1],s[1])}return i}(r,s).find(([t,e])=>t<=s&&e>=-s);if(!l)return null;const[c,h]=l,d=kf(a,i.axis,-i.half),p=kf(a,i.axis,i.half),u=Math.max(0,-i.half-c),_=Math.max(0,h-i.half),m=u>0?kf(a,i.axis,c):d,g=_>0?kf(a,i.axis,h):p,f=bf(o,i.normal)>=0?1:-1,v=(e,s,n)=>({from:e,to:s,label:[(e[0]+s[0])/2,(e[1]+s[1])/2],axis:i.axis,labelNormal:o,distance:n,roomId:t.roomId,roomSide:f,source:"room-face"});return{left:v(d,m,u),right:v(p,g,_)}}function Df(t){const e=kf(t.center,t.axis,-t.half),i=kf(t.center,t.axis,t.half),s=kf(t.center,t.axis,Math.min(-t.half,t.targetLo)),n=kf(t.center,t.axis,Math.max(t.half,t.targetHi)),o=(e,i)=>({from:e,to:i,label:[(e[0]+i[0])/2,(e[1]+i[1])/2],axis:t.axis,labelNormal:t.normal,distance:Math.hypot(i[0]-e[0],i[1]-e[1]),source:"host-end"});return[o(e,s),o(i,n)]}function Pf(t,e,i,s){const n=wf(i,e),o=bf(n,n);if(!(o>s*s))return Math.hypot(...wf(t,e))<=s;const a=bf(wf(t,e),n)/o;if(a<-s||a>1+s)return!1;const r=kf(e,n,Math.max(0,Math.min(1,a)));return Math.hypot(...wf(t,r))<=s}function Tf(t,e,i){let s=!1;for(let n=0,o=e.length-1;nt[1]!=c>t[1]&&t[0]<(l-a)*(t[1]-r)/(c-r)+a&&(s=!s)}return s}function Rf(t,e,i,s,n,o){const a=wf(s,i),r=yf(e,a);if(Math.abs(r)<=o)return null;const l=wf(i,t),c=yf(l,a)/r,h=yf(l,e)/r;return c<-o||c>n+o||h<-o||h>1+o?null:Math.max(0,Math.min(n,c))}function If(t,e,i){const s=Df(i),n="partition"===t.host?.kind?t.host.id:void 0;return[{base:s[0],direction:[-i.axis[0],-i.axis[1]]},{base:s[1],direction:i.axis}].map(({base:t,direction:i})=>{const s=t.distance,o=function(t,e,i,s,n,o){let a=null;for(const r of s)if(!n||r.partitionId!==n){if(Tf(t,r.body,o))return 0;for(let s=0;sbf(wf(t,n),i));return{center:n,axis:i,normal:s,half:Math.max(0,t.renderedLength)/2,targetLo:Math.min(...o),targetHi:Math.max(...o)}}(t),s=e.rooms.flatMap(t=>{const s=function(t,e,i){const{profile:s}=t;let n=null;for(let t=0;t0))continue;const o=s.poly[t],a=s.poly[(t+1)%s.poly.length],r=wf(a,o),l=Math.hypot(r[0],r[1]);if(!(l>i&&xf(e.axis,[r[0]/l,r[1]/l],1e-6)))continue;if($f(o,e.center,e.axis)>i||$f(a,e.center,e.axis)>i)continue;const c=bf(wf(o,e.center),e.axis),h=bf(wf(a,e.center),e.axis),d=Math.min(c,h),p=Math.max(c,h);if(d>-e.half+i||p0?d:p<0?-p:0);(!n||u2)return Df(i);if(s.length){const t=s.map(({room:t,edge:s})=>Cf(t,s,i,e.epsilon));if(t.some(t=>!t))return Df(i);const n=t;return[...n.map(t=>t.left),...n.map(t=>t.right)]}return If(t,e,i)}function zf(t){return!(!t.canEdit||t.kiosk||t.fixedFloor)&&("view"!==t.mode&&("mouse"===t.pointerType&&t.spaceCount>1))}const Ff="1.68.0-beta.3",Ef={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon"},Nf={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon"},Of=2e3,Lf=1e3,Hf=1500,Bf=t=>{const e=String(t??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e))return null;const i=Number(e);return Number.isFinite(i)?i:null},qf=(t,e)=>{if(!t.has(e))return{hit:!1};const i=t.get(e);return t.delete(e),t.set(e,i),{hit:!0,value:i}},Wf=(t,e,i,s)=>{for(t.delete(e),t.set(e,i);t.size>s;){const e=t.keys().next().value;if(void 0===e)break;t.delete(e)}},jf=new Map;let Uf=0;const Gf=t=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(t??{})}`;let Vf=1e4;const Kf="houseplan_card_layout_v1",Yf="houseplan_card_cfg_v1",Jf="houseplan_card_zoom_v1",Xf="houseplan_card_nav_v1",Zf="houseplan_card_kiosk_v1",Qf="houseplan_card_view_v1",tv="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",ev=1e3,iv=[[0,1],[45,.88],[70,.62],[86,.32],[100,0]],sv=(t,e)=>{const i=Math.min(t.x,e.x),s=Math.min(t.y,e.y);return{x:i,y:s,w:Math.max(t.x+t.w,e.x+e.w)-i,h:Math.max(t.y+t.h,e.y+e.h)-s}},nv=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),ov=2e3,av=(t,e,i)=>{const s=new Event(e,{bubbles:!0,composed:!0});s.detail=i??{},t.dispatchEvent(s)},rv=t=>{history.pushState(null,"",t),av(window,"location-changed",{replace:!1})},lv=(t,e)=>{let i,s=null;const n=(...n)=>{clearTimeout(i),s=n,i=window.setTimeout(()=>{i=void 0;const e=s;s=null,e&&t(...e)},e)};return n.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const e=s;s=null,e&&t(...e)},n.cancel=()=>{clearTimeout(i),i=void 0,s=null},n.pending=()=>void 0!==i,n},cv=t=>{try{t.target?.setPointerCapture?.(t.pointerId)}catch{}};class hv extends ht{constructor(){super(...arguments),this._space="f1",this._layout={},this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._serverCfg=null,this._cfgRev=0,this._cfgContentFingerprint="",this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._layoutRev=0,this._layoutContentFingerprint="",this._virtualLights=mn(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._tip=null,this._hoverRoom=null,this._pointerModality=new E_(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...Rr},this._decorDraft=null,this._decorMove=null,this._decorSel=null,this._decorEraseConfirm=null,this._decorTextDialog=null,this._decorShapeDialog=null,this._backdropDialog=null,this._decorTextSelection={start:0,end:0},this._furnPalette=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=t=>{this._reducedMotion=t.matches,this._cancelDevicePressFeedback(),t.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:t.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new Dg({frame:t=>this._applyModeTransitionFrame(t),settled:t=>this._settleModeTransition(t)}),this._editorSecondary=new q_({root:()=>this.renderRoot,requestUpdate:()=>this.requestUpdate(),updateComplete:()=>this.updateComplete,clearTip:()=>{this._tip=null}}),this._editorSecondaryCopy={groupActive:(t,e)=>this._t("editor.group_active",{group:t,item:e}),openGroup:t=>this._t("editor.open_group",{group:t}),disabledAction:(t,e)=>this._t("editor.disabled_action",{action:t,reason:e})},this._tool="draw",this._geometryHistory=new mg(50),this._wallDialog=null,this._drawWallField=null,this._activeDraftId=null,this._resumeDraftBySpace={},this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCache=null,this._isoGeometryCache=new Map,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._glowClipCache=new Map,this._glowGeometryWarnings=new Set,this._lightBarrierCache=null,this._glowFeatherUnits=null,this._glowRenderedSources=new Map,this._glowLastAppearance=new Map,this._glowEnteringSources=new Set,this._glowEnterRafs=new Map,this._glowFadeTimers=new Map,this._glowFeatherSuspendUntil=0,this._glowFeatherResumeTimer=0,this._glowSourceSeq=0,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszSel=null,this._rszDrag=null,this._rszEligibilityCache=null,this._rszPreview=null,this._rszLive=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._suppressClick=!1,this._touchContacts=new Map,this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:t=>this._guardTouchGesture(t)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._alignDialog=null,this._settingsDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=t=>this._onKey(t),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++Uf,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=t=>{if(this._continuity.visibility(t),this._dayCycleVisibility(t),"hidden"===t.kind)return this._clearTransientHover(!0),this._cancelDevicePressFeedback(),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,!t.long){const t=Date.now();let e=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+R_)>t||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,e=!0);return void(e&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._lastTap=0,this._onLabsSnapshot=t=>{const e=this._effectiveProjection();this._labs=t;const i=this._effectiveProjection();this._convertProjectionView(e,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const t=this._hashSpace();if(t&&this._model.find(e=>e.id===t)&&t!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(t),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._onHaRegistryUpdate=()=>{const t=An(this.hass);t.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=t.revision,this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,function(t){const e=Cn(t);e&&(Tn(t,e),Rn(t,e))}(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new xd(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=lv(()=>{if(this._serverStorage){const t=[...this._dirtyPos];this._dirtyPos.clear();for(const e of t){const t=ol(this._layout[e]);t&&(this._layout={...this._layout,[e]:t},this._sentPos.set(e,t),this.hass.callWS({type:"houseplan/layout/update",device_id:e,pos:t}).then(t=>this._noteLayoutRev(t)).catch(t=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))).finally(()=>{this._sentPos.get(e)===t&&this._sentPos.delete(e)}))}this._cacheSnapshot()}else this._layout=al(Gr(this._layout)),localStorage.setItem(Kf,JSON.stringify(this._layout))},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>{if(this._physicalDrag||this._physicalRotate)return void this._cancelPhysicalGesture();if(this._decorDraft)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove||this._dtDrag||this._bdDrag)return void this._cancelDecorGesture();if(this._rszDrag)return void this._rszCancelDrag();const t=this._geometryHistory.undo();t&&(this._applyGeometryState(t.before,!0)?this._showToast(this._t("history.undone",{name:t.name})):this._geometryHistory.clear())},this._redoGeometry=()=>{if(this._physicalDrag||this._physicalRotate)return void this._cancelPhysicalGesture();if(this._decorDraft)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove||this._dtDrag||this._bdDrag)return void this._cancelDecorGesture();if(this._rszDrag)return void this._rszCancelDrag();const t=this._geometryHistory.redo();t&&(this._applyGeometryState(t.after,!0)?this._showToast(this._t("history.redone",{name:t.name})):this._geometryHistory.clear())},this._saveConfigDebounced=lv(()=>{this._serverCfg&&this._writeConfig().catch(t=>{const e=!0===t?.physicalGeometryRolledBack;"geometry-unsafe"!==t?.code&&("wall_model_client_outdated"===t?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===t?.code?(this._showToast(this._t("toast.conflict")),e||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(t)})),e&&this._reloadRejectedPhysicalWrite())})},500),this._draftSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>{const t=this._physicalDialog,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=Bf(t.cm);if(null==s)return void this._showPhysicalRange("column"===t.kind?Wc:100,"column"===t.kind?1:0);const n=this._imperial?2.54*s:s,o="column"===t.kind?Wc:100,a="column"===t.kind?1:0;if(!Number.isFinite(n)||no)return void this._showPhysicalRange(o,a);if("column"===t.kind){const e=i.wall_columns.find(e=>e.id===t.id);if(!e)return;const s=Bf(t.angle||"0");if("circle"!==t.shape&&(null==s||s<0||s>=90))return void this._showToast(this._t("toast.physical_angle"));const o="circle"===t.shape?{id:t.id,shape:"circle",center:e.center,cm:n}:{id:t.id,shape:"square",center:e.center,cm:n,angle:s};if(i.wall_columns.some(e=>e.id!==t.id&&ph(e,o,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"))}const r=this._geometrySnapshot();if("partition"===t.kind){const i=(e.partitions||[]).find(e=>e.id===t.id);if(i&&0===n&&g_(e.openings,{kind:"partition",id:t.id}))return void this._showToast(this._t("toast.zero_wall_opening_conflict"));i&&(i.cm=n)}else if("column"===t.kind){const i=(e.wall_columns||[]).find(e=>e.id===t.id);i&&(i.cm=Uc(n),i.shape="circle"===t.shape?"circle":"square","square"===i.shape?i.angle=Bf(t.angle||"0"):delete i.angle)}else{const i=(e.room_drafts||[]).find(e=>e.id===t.id);i?.segments?.[t.segment||0]&&(i.segments[t.segment||0].cm=n)}const l=this._commitPhysicalGeometry(this._t("history.physical_edit"),r);this._physicalDialog=null,l||this.requestUpdate()},this._deletePhysicalSelection=()=>{const t=this._physicalSel,e=this._curSpaceCfg;if(!t||!e)return;if("draft"===t.kind)return void this._deleteDraftWhole();const i=this._geometrySnapshot();if("partition"===t.kind){const i=(e.openings||[]).filter(e=>"partition"===e.host?.kind&&e.host.id===t.id).sort((t,e)=>(t.host?.t||0)-(e.host?.t||0));if(i.length)return void(this._partitionDeleteDialog={id:t.id,openings:i.map(t=>JSON.parse(JSON.stringify(t)))})}const s="partition"===t.kind?"partitions":"column"===t.kind?"wall_columns":"room_drafts";e[s]=(e[s]||[]).filter(e=>e.id!==t.id),e[s].length||delete e[s],this._activeDraftId===t.id&&this._cancelPath(),this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._confirmPartitionDelete=()=>{const t=this._partitionDeleteDialog,e=this._curSpaceCfg;if(!t||!e)return;const i=this._geometrySnapshot();e.partitions=(e.partitions||[]).filter(e=>e.id!==t.id),e.partitions.length||delete e.partitions,e.openings=(e.openings||[]).filter(e=>"partition"!==e.host?.kind||e.host.id!==t.id),e.openings.length||delete e.openings,this._partitionDeleteDialog=null,this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._deleteDraftWhole=()=>{const t="draft"===this._physicalDialog?.kind?this._physicalDialog.id:"draft"===this._physicalSel?.kind?this._physicalSel.id:null,e=this._curSpaceCfg;if(!t||!e||!confirm(this._t("confirm.delete_draft")))return;const i=this._geometrySnapshot();e.room_drafts=(e.room_drafts||[]).filter(e=>e.id!==t),e.room_drafts.length||delete e.room_drafts,this._activeDraftId===t&&this._cancelPath(),this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._deleteDraftSegment=()=>{const t=this._physicalDialog,e=this._curSpaceCfg;if(!t||"draft"!==t.kind||!e)return;if(!confirm(this._t("confirm.delete_draft_segment")))return;const i=(e.room_drafts||[]).findIndex(e=>e.id===t.id);if(i<0)return;const s=e.room_drafts[i],n=Math.max(0,Math.min(s.segments.length-1,t.segment||0)),o=[],a=s.points.slice(0,n+1),r=s.points.slice(n+1);if(a.length>=2&&o.push({id:s.id,points:a,segments:s.segments.slice(0,n)}),r.length>=2&&o.push({id:o.length?`${s.id}-${Date.now().toString(36)}`:s.id,points:r,segments:s.segments.slice(n+1)}),2===o.length&&e.room_drafts.length>=200)return void this._showToast(this._t("toast.physical_limit"));const l=this._geometrySnapshot();e.room_drafts.splice(i,1,...o),e.room_drafts.length||delete e.room_drafts,this._activeDraftId===s.id&&this._cancelPath(),this._physicalDialog=null,this._physicalSel=o.length?{kind:"draft",id:o[0].id}:null,this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),l)},this._confirmRoomDelete=t=>{const e=this._roomDeleteDialog,i=this._curSpaceCfg,s=this._spaceModel();if(!e||!i||!s)return;const n=s.rooms.find(t=>t.id===e.roomId);if(!n)return void(this._roomDeleteDialog=null);const o=this._openCuts(),a=xu(dc(s.rooms,this._spaceWalls,o,this._wallKeyPitch,this._cellCm,this._gridPitch,ev).filter(t=>t.roomId===n.id),s.partitions,this._openingsR.map(t=>({...t,x:t.rx,y:t.ry})),.02*this._gridPitch),r=new Set(a.materialize.filter(t=>!t.reusePartitionId).map(t=>t.interval.key)).size;if(t&&(i.partitions||[]).length+r>ov)return void this._showToast(this._t("toast.physical_limit"));const l=this._geometrySnapshot(),c=pc(s.rooms,this._spaceWalls,o,this._wallKeyPitch,this._cellCm,this._gridPitch,ev);if(t){i.partitions||=[];const t=new Map,e=new Map,s=t=>{const e=(i.wall_segments||[]).find(e=>{const i=[Number(e.a?.[0])*ev,Number(e.a?.[1])*ev],s=[Number(e.b?.[0])*ev,Number(e.b?.[1])*ev];return this._samePt(t.a,i)&&this._samePt(t.b,s)||this._samePt(t.a,s)&&this._samePt(t.b,i)});return"string"==typeof e?.id&&e.id?e.id:null},n=Date.now().toString(36);for(const o of a.materialize){let a=o.reusePartitionId?i.partitions.find(t=>t.id===o.reusePartitionId):e.get(o.interval.key);a||(a={id:s(o.interval)||`partition-room-${n}-${e.size}`,a:[o.interval.a[0]/ev,o.interval.a[1]/ev],b:[o.interval.b[0]/ev,o.interval.b[1]/ev],cm:o.interval.cm},i.partitions.push(a),e.set(o.interval.key,a)),t.set(o.interval.key,a)}for(const e of i.openings||[]){const i=a.openingIntervals.get(e.id),s=i?t.get(i):null,n=this._openingsR.find(t=>t.id===e.id);if(!s||!n)continue;const o={a:[s.a[0]*ev,s.a[1]*ev],b:[s.b[0]*ev,s.b[1]*ev]};e.host={kind:"partition",id:s.id,t:$u([n.rx,n.ry],o)}}}else if(a.removeOpeningIds.length){const t=new Set(a.removeOpeningIds);i.openings=(i.openings||[]).filter(e=>!t.has(e.id)),i.openings.length||delete i.openings}i.rooms=i.rooms.filter(t=>t.id!==n.id),this._cfgEpoch++;const h=this._normalizeWalls(c,this._openCuts());h.length?i.walls=h:delete i.walls,this._roomDeleteDialog=null,this._commitPhysicalGeometry(this._t(t?"history.delete_room_keep_walls":"history.delete_room_with_walls"),l),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()},this._rebindPartitionOpening=()=>{const t=this._openingDialog;if(!t?.id)return;const e=t.id;this._activateMarkupTool("opening"),"opening"===this._tool&&(this._openingRebindId=e,this._openingPreset={type:t.type,lengthCm:t.lengthCm,flipH:t.flipH,flipV:t.flipV,revision:++this._openingPresetRevision},this._openingDialog=null,this._openingHoverCandidate=null)},this._keepClosedAsPartitions=()=>{if(this._wallFaceBatch)return void this._decideWallFace(!1);if(!this._contourClosed||this._pendingSplit||!this._curSpaceCfg)return;const t=this._curSpaceCfg,e=this._path.slice(0,-1);if((t.partitions||[]).length+e.length>ov)return void this._showToast(this._t("toast.physical_limit"));const i=this._geometrySnapshot(),s=Jp(e.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll);t.partitions||=[];const n=Date.now().toString(36),o=this._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this._activeDraftId):null,a=this._draftSegmentsForPath(this._path,o,s);for(let i=0;it.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this._t("history.contour_to_partitions"),i),this._roomDialog=!1,this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null},this._toggleServerPlans=async()=>{const t=this._spaceDialog;if(t)if(t.pickSaved)this._spaceDialog={...t,pickSaved:!1};else{this._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.hass.callWS({type:"houseplan/plans/list"}),e=this._spaceDialog;e&&(this._spaceDialog={...e,saved:t?.plans||[],savedBusy:!1})}catch(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,saved:[],savedBusy:!1}),this._showToast(this._t("toast.plans_list_failed",{err:this._errText(t)}))}}},this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const t=this._dayCycleState();if(!t)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const e=mr(t);e!==this._dayCycleClockKey&&(this._dayCycleClockKey=e,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(!this._norm)return;const t=this._glowRadiusCm,e=this._imperial?Math.round(t/30.48*10)/10:Math.round(t)/100;this._settingsDialog={colors:JSON.parse(JSON.stringify(this._fillColors)),glowRadius:e,bgColor:hs(this._settings,{bgColor:null})||null,northDeg:$r(this._settings,{}),bgMode:Sr(this._settings,{}),sunRays:Mr(this._settings,{}),busy:!1}},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._previewAlignDialog(!1),this._toggleOptimizeLivePositions=()=>{const t=this._alignDialog;t&&!t.busy&&t.report.liveMissingPositions.length&&this._previewAlignDialog(!t.removeLiveMissingPositions)},this._optimizeUndoBusy=!1,this._openBackupExport=()=>{this._settingsDialog=null,this._backupExportDialog={kind:"full",planOnly:!1,busy:!1,error:""}},this._openRulesDialog=()=>{if(!this._norm)return;const t=this._settings.icon_rules,e=(t&&t.length?t:Jt).map(t=>({...t}));this._rulesDialog={rules:e,test:"",busy:!1}},this._climateCache=null,this._gearPtCache=new WeakMap}get _canEdit(){return!!this._norm&&(!0===this._serverCanWrite||!1!==this._serverCanWrite&&!0===this.hass?.user?.is_admin)}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}_cssColor(t,e){const i=String(t||"").trim();if(!i)return e;const s=document.createElement("span");s.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(s);const n=getComputedStyle(s).color||e;return s.remove(),n}_currentModeVisual(t=this._mode){const e=this._modeTransition.presented||this._modeTransitionVisual;if(e)return{...e,viewport:{...e.viewport,viewBox:{...e.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const s=this.renderRoot.querySelector(".editorchrome"),n=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),a=this.renderRoot.querySelector(".hp-backdrop"),r=this.renderRoot.querySelector(".zoomwrap"),l=r?getComputedStyle(r).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:t,editorChromeHeight:"view"===t?0:s?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:xg(n,i.clientWidth),stageColor:getComputedStyle(i).backgroundColor||"rgb(255, 255, 255)",paperColor:o?getComputedStyle(o).fill:"rgb(255, 255, 255)",sceneBrightness:Number.isFinite(c)?c:1,architectureOpacity:"decor"===t?.35:1,backdropOpacity:a&&Number(getComputedStyle(a).opacity)||1,viewWeight:"view"===t?1:0,editorWeight:"view"===t?0:1,toolbarContentOpacity:"view"===t?0:1}}_viewForModeTarget(t,e,i,s,n){const o=Ni(this._baseVb(),s/Math.max(1,n)),a=Math.min(hv.ZOOM_MAX,Math.max(hv.ZOOM_MIN,t)),r=o.w/a,l=o.h/a,c=e??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-r/2,y:h-l/2,w:r,h:l},o)}_targetStageColor(t){return"view"!==t?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(t){return"view"===t&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(t){return 1}_applyModeTransitionFrame(t){t.targetMode===this._mode&&(this._modeTransitionVisual=t.presented,this._view={...t.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(t){if(t.targetMode!==this._mode)return;const e=this._modeTransitionRequest;this._view={...t.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[t.to.stageWidth,t.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._modeTransitionBusy||t.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-t.to.stageWidth)>.5||Math.abs(i.clientHeight-t.to.stageHeight)>.5)){const t=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,t?t.x+t.w/2:void 0,t?t.y+t.h/2:void 0),this.requestUpdate()}const s=this.renderRoot.activeElement;(!s||!s.isConnected||!!s.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(t=!0){const e=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(t),t&&e||(this._modeTransitionVisual=null)}_adoptMode(t){this._cancelModeTransition(!1),this._mode=t,"view"!==t&&(this._editorChromeMode=t)}_commitViewModeAtomic(t,e,i,s){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=e,t){const n=this._stageEl?.clientWidth||t.stageWidth,o=Math.max(1,t.stageHeight+t.editorChromeHeight);this._view=this._viewForModeTarget(e,i,s,n,o),this._lastValidStageSize=[n,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(t,e,i,s,n,o){this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._mode!==i)return void(t===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const a=this.renderRoot.querySelector(".editorchrome"),r=a?.querySelector(".editorchrome-inner"),l="view"===i?0:r?.scrollHeight||r?.getBoundingClientRect().height||0,c=Math.max(1,e.stageHeight+e.editorChromeHeight),h=Math.max(1,c-l),d=this._stageEl?.clientWidth||e.stageWidth;if(d<=0||h<=0)return this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._applyView(s,n,o),void this.requestUpdate();const p=this._viewForModeTarget(s,n,o,d,h),u={presentedMode:i,editorChromeHeight:l,stageWidth:d,stageHeight:h,viewport:xg(p,d),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const _=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(e,u,i,this._reducedMotion||_?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(t=this._model,e=this._loadOk){const i=this._config?.floor,s=function(t){if(!t.hasFloor)return{kind:"absent"};const e=t.floor;if("string"==typeof e)return e.length?t.spaceIds.includes(e)?{kind:"valid",id:e,source:"id"}:{kind:"invalid",reason:"unknown-id",value:e}:{kind:"invalid",reason:"empty-id",value:e};if("number"==typeof e){if(!Number.isFinite(e))return{kind:"invalid",reason:"non-finite-index",value:e};if(!Number.isInteger(e))return{kind:"invalid",reason:"fractional-index",value:e};if(e<0)return{kind:"invalid",reason:"negative-index",value:e};const i=t.spaceIds[e];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:e}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:e}}({spaceIds:t.map(t=>t.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||e?s:"number"==typeof i?"valid"===s.kind||"invalid"===s.kind&&"out-of-range-index"===s.reason?{kind:"pending",value:i}:s:"valid"===s.kind||"invalid"===s.kind&&"unknown-id"!==s.reason?s:{kind:"pending",value:i}}_canCommitSpace(t,e=!1){if(e||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===t}_commitSpace(t,e=!1){return!!this._canCommitSpace(t,e)&&(t!==this._space&&(this._clearTransientHover(!0),this._cancelDevicePressFeedback()),this._space=t,!0)}_slideTo(t,e){if(t===this._space)return!0;if(!this._canCommitSpace(t))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(t),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),i||(this._slide=e,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(t,e){zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:t.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(cv(t),this._tabDragRelease=t=>this._tabPointerUp(t),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:e,pointerId:t.pointerId,x:t.clientX,y:t.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(t,e,i){const s=this._model.map(t=>t.id),n=s.indexOf(i);if(n<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const a of o){const o=a.dataset.id||"";if(!o||o===i)continue;const r=a.getBoundingClientRect();if(tr.right||er.bottom)continue;const l=s.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,s;const n=this._tabDropTargetAt(t.clientX,t.clientY,e.id);e.moved&&e.targetId===n?.targetId&&e.placement===n?.placement||(this._tabDrag={...e,moved:!0,targetId:n?.targetId||null,placement:n?.placement||null})}_tabPointerUp(t){const e=this._tabDrag;if(e&&e.pointerId!==t.pointerId)return;const i="pointerup"===t.type&&e?.moved?this._tabDropTargetAt(t.clientX,t.clientY,e.id):null;"pointerup"===t.type&&e?.moved&&this._suppressNextTabClick(),this._endTabDrag(),e?.moved&&i&&this._commitTabOrder(e.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(t){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(t)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(t,e){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const s=this._model.map(t=>t.id),n=function(t,e,i){const s=t.indexOf(e),n=t.indexOf(i);if(s<0||n<0||s===n)return t;const o=t.slice();return o.splice(s,1),o.splice(n,0,e),o}(s,t,e);if(n===s)return;const o=new Map(this._devices.map(t=>[String(t.id),String(t.area||"")])),a=function(t,e,i,s=()=>""){if(!i)return[];const n=[];for(const o of t){if(!o||!0===o.removed)continue;const t="string"==typeof o.id?o.id:"";if(!t)continue;if("string"==typeof o.space&&o.space)continue;const a=("string"==typeof o.area?o.area:"")||s(t)||"";a&&e[a]||n.push({id:t,space:i})}return n}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),s[0]||"",t=>o.get(t)||"");if(a.length){const t=new Map(a.map(t=>[t.id,t.space]));for(const e of i.markers||[]){const i=t.get(String(e.id));i&&(e.space=i)}}i.spaces=function(t,e){const i=new Map(e.map((t,e)=>[t,e]));return t.map((t,e)=>({space:t,index:e})).sort((t,e)=>(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)||t.index-e.index).map(t=>t.space)}(i.spaces||[],n),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(t){if(this._endTabDrag(),t===this._space)return;const e=this._model.map(t=>t.id),i=e.indexOf(this._space),s=e.indexOf(t);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(t,i>=0&&s0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const t=this._model.map(t=>t.id),e=t.indexOf(this._space);this._slideTo(t[(e+1)%t.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}_newContinuityController(){return new yd(()=>{this._resumeSettling="steady"!==this._continuity.state,this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}get _labsIso(){return this._labs.active.includes("iso")}get _desiredProjection(){return"view"===this._mode&&this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat"}_saveViewPreference(){try{localStorage.setItem(Qf,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(t){const e=this._view;if(!e)return null;const i=[e.x+e.w/2,e.y+e.h/2],s="iso"===t?Jg(i):i;return{x:s[0],y:s[1]}}_convertProjectionView(t,e){if(t===e)return;const i=this._logicalViewCenter(t);this._view=null;const s=i?"iso"===e?Yg([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,s?.[0],s?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(t){if(!this._labsIso||"view"!==this._mode)return;const e=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:t},"iso"===t){const t=this._isoSceneKey();t&&this._isoFallback.delete(t)}this._saveViewPreference();const i=this._effectiveProjection();this._convertProjectionView(e,i)}_hashSpace(){return Eg(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const t=(e=this.ownerDocument,gg.get(e)?.resolved);var e;void 0!==t&&(this._glowScreenBlend=t),this._continuityUnsub?.(),this._continuityUnsub=fd(this.ownerDocument,this._pageVisibility),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(t=>{for(const e of t)for(const t of e.addedNodes)this._syncPointerHoverSubtree(t)}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),function(t){const e=gg.get(t);if(e)return e.promise;const i={promise:Promise.resolve(!1)};return i.promise=vg(t).catch(()=>!1).then(t=>(i.resolved=t,t)),gg.set(t,i),i.promise}(this.ownerDocument).then(t=>{t!==this._glowScreenBlend&&(this._glowScreenBlend=t,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>Is(this._serverCfg)),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(t,e){Wg.add(e);const i=Gg(t);return"undefined"==typeof window&&e(i),()=>{Wg.delete(e)}}(Ff,this._onLabsSnapshot),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Hf)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._vacRaf&&(cancelAnimationFrame(this._vacRaf),this._vacRaf=0),this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const t of this._activityRt.values())clearTimeout(t.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),this._modeTransition.dispose(),this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer);for(const t of this._glowFadeTimers.values())clearTimeout(t);for(const t of this._glowEnterRafs.values())cancelAnimationFrame(t);clearTimeout(this._glowFeatherResumeTimer),this._glowFeatherResumeTimer=0,this._glowFeatherSuspendUntil=0,this._glowFadeTimers.clear(),this._glowEnterRafs.clear(),this._glowEnteringSources.clear(),this._glowRenderedSources.clear(),this._glowLastAppearance.clear(),this._glowSourceSeq=0,this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._touchContacts.clear(),this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(t){if("Escape"===t.key&&this._vacFit)return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void t.stopPropagation();if("Escape"===t.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm=null);if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._settingsDialog)return void(this._settingsDialog=null);if(this._markerDialog)return void(this._markerDialog=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary.hasOpenGroup)return t.preventDefault(),void this._editorSecondary.closeGroup(!0)}const e=t.composedPath?.()||[t.target],i=e.some(t=>t?.matches?.('input, textarea, select, [contenteditable="true"]')),s=e.some(t=>t?.classList?.contains?.("editor-secondary")),n=t.ctrlKey||t.metaKey,o=t.key.toLowerCase(),a=/^[a-z]$/.test(o),r="z"===o||!a&&"KeyZ"===t.code,l="y"===o||!a&&"KeyY"===t.code,c=n&&(r&&t.shiftKey||l),h=n&&r&&!t.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;return c?(t.preventDefault(),void this._redoGeometry()):h?(t.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry()):"Delete"!==t.key&&"Backspace"!==t.key||!this._decorSel||i||s?void("Escape"===t.key&&(t.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._furnPalette=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(t.preventDefault(),void this._decorDeleteSel())}if(this._markup&&(!h&&!c||!i)){if(("Delete"===t.key||"Backspace"===t.key)&&this._physicalSel&&!i&&!s)return t.preventDefault(),void this._deletePhysicalSelection();if(c)return t.preventDefault(),void this._redoGeometry();if(h)return t.preventDefault(),this._rszDrag?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===t.key)return this._physicalDrag||this._physicalRotate?(t.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(t.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(t.preventDefault(),void this._finishWallChain()):this._physicalSel?(t.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(t.preventDefault(),this._rszDrag?void this._rszCancelDrag():void(this._rszSel?this._rszSel=null:this._tool="draw")):"split"===this._tool?(t.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(t.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(t.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(t.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length){if(this._contourClosed)return this._path=this._path.slice(0,-1),void(this._closingWallCm=null);if(this._activeDraftId&&this._path.length>1&&this._curSpaceCfg){const t=this._geometrySnapshot();this._path=this._path.slice(0,-1),this._draftSegmentCms=this._draftSegmentCms.slice(0,-1);const e=this._curSpaceCfg,i=(e.room_drafts||[]).findIndex(t=>t.id===this._activeDraftId);if(i>=0){const s=Array.isArray(e.room_drafts[i]?.segments)?e.room_drafts[i].segments:[];this._path.length<2?(e.room_drafts.splice(i,1),e.room_drafts.length||delete e.room_drafts,this._activeDraftId=null):e.room_drafts[i]={id:this._activeDraftId,points:this._path.map(t=>[t[0]/ev,t[1]/ev]),segments:this._draftSegmentCms.map((t,e)=>({...s[e]||{},cm:t}))},this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),t)}return}this._path=this._path.slice(0,-1)}}_undoActiveDraftPoint(){const t=this._activeDraftId,e=this._path[0]?[...this._path[0]]:null,i=this._geometryHistory.undo();if(!i)return void this._undoPoint();if(!this._applyGeometryState(i.before,!0))return void this._geometryHistory.clear();const s=t?this._spaceModel()?.room_drafts.find(e=>e.id===t):null;s?(this._activeDraftId=s.id,this._path=s.points.map(t=>[...t]),this._draftSegmentCms=this._adoptDraftCms(this._path,s.segments.map(t=>t.cm),s.id),this._resumeDraftBySpace[this._space]=s.id):(this._activeDraftId=null,this._path=e?[e]:[],this._draftSegmentCms=[],t&&this._resumeDraftBySpace[this._space]===t&&delete this._resumeDraftBySpace[this._space]),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:i.name}))}static getConfigElement(){return document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(t){for(const t of jf.values())for(const e of t)clearTimeout(e.evict);jf.clear(),Vf=t&&t>0?t:1e4}static _warmBootStats(){let t=0,e=0;const i=[];for(const s of jf.values())for(const n of s)t++,n.dlg&&(e++,i.push(n.dlg.kind));return{keys:jf.size,slots:t,dlgs:e,drafts:i}}setConfig(t){const e=this._config,i=!!e&&Object.prototype.hasOwnProperty.call(e,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...t};(i!==this._hasFixedFloor||e?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&t.default_floor&&this._commitSpace(t.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(Jf)||"{}")||{}}catch{this._zoomBySpace={}}try{const t=JSON.parse(localStorage.getItem(Qf)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(t).filter(t=>"flat"===t[1]||"iso"===t[1]))}catch{this._viewPreference={}}this._labs=Gg(Ff);try{const t=JSON.parse(localStorage.getItem(Zf)||"null");this._kioskScale={icon:Es(t?.icon),font:Es(t?.font)}}catch{}try{const t=JSON.parse(localStorage.getItem(Yf)||"null");t&&t.config&&Array.isArray(t.config.spaces)&&(this._serverCfg=t.config,this._cfgEpoch++,this._cfgRev=t.rev||0,this._cfgContentFingerprint=t.config_fingerprint||bd(t.config),this._layout=t.layout||{},this._layoutRev=t.layout_rev||0,this._layoutContentFingerprint=t.layout_fingerprint||bd(this._layout),this._virtualLights=mn(t.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1)}_warmAdopt(){if(this._config?.kiosk)return;const t=Gf(this._config);if(this._warmKey===t&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const e=this.parentNode,i=this._warmIdx(e),s=jf.get(t);if(!s||!s.length)return;const n=s.find(t=>t.owner===this._warmGen);if(n)return this._warmLongReturn=!!n.freed&&Date.now()-n.freed>=_d,clearTimeout(n.evict),n.evict=0,n.freed=0,n.live=!0,this._warmSlot=n,this._warmKey=t,n.frameFingerprint&&this._continuity.adoptCompleteFrame(n.frameFingerprint),void(!this._devices.length&&n.devices?.length&&(this._devices=[...n.devices]));const{slot:o,sure:a}=((t,e,i,s)=>{const n=t=>{const e=!!i&&t.place?.deref()===i;return e&&t.idx===s?4:t.live?0:e?3:2};let o=null,a=0,r=0,l=null;for(const i of t){if(i.owner===e)continue;l=i;const t=n(i);t<=0||(t>a?(o=i,a=t,r=1):t===a&&r++)}return!o||r>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(s,this._warmGen,e,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=_d,this._booting=!1,this._bootFading=!1,this._hdrH=o.hdrH,this._bootSoft=!0,this.isConnected&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Hf)),this._warmKey=t,a?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=e?new WeakRef(e):null,o.idx=i,o.live=!0,this._warmSlot=o,this._warmVp=o.vp,o.frameFingerprint&&this._continuity.adoptCompleteFrame(o.frameFingerprint),!this._devices.length&&o.devices?.length&&(this._devices=[...o.devices]),this._warmAdoptViewport(this._config)):(this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},s.push(this._warmSlot),this._warmTrim(s)))}_warmIdx(t){const e=t?.children;if(!e)return-1;for(let t=0;t4;){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=jf.get(e);if(!t.live&&o&&o.length>1){const e=o.indexOf(t);e>=0&&o.splice(e,1)}},Vf+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?Yg([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="opening"===(o=function(t){return"partition"===t?"draw":t}(o=e.tool))?"draw":"string"==typeof o&&nv.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=Gf(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=jf.get(i)||[];for(s.push(this._warmSlot),jf.set(i,s),this._warmTrim(s);jf.size>8;){const t=jf.keys().next().value;if(void 0===t||t===i)break;for(const e of jf.get(t)||[])clearTimeout(e.evict);jf.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>Vf)&&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=bd(this._serverCfg),this._layoutContentFingerprint=bd(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(Yf,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 wd([this._cfgRev,this._cfgContentFingerprint||bd(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||bd(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 G;const t="connection"===this._continuity.recoveryReason;return W`
`}afterRender(){const t=this.host.root();this._blocked&&(this._openGroupId?this.closeGroup(!1):"palette"===this._currentModel?.kind&&this._currentModel.dismiss?.()),this._syncGlobalDismissListener();const e=t.querySelector(".editor-secondary"),i=this._renderedContext,s=e?.dataset.contextId||"";if(s&&i&&s!==i&&!window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches&&(this._contentAnimation?.cancel(),this._contentAnimation=e?.querySelector(".editor-secondary-content")?.animate([{opacity:.35,transform:"translateY(-4px)"},{opacity:1,transform:"translateY(0)"}],{duration:100,easing:"ease-out"})),this._renderedContext=s,i&&s!==i&&this._focusOwned){const i=s?e?.querySelector('[tabindex="0"], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'):t.querySelector(".editbar-tools");i?.focus?.(),this._focusOwned=!!s}if("palette"===this._currentModel?.kind&&this._currentModel.launcherId){const e=[...t.querySelectorAll("[data-editor-palette]")].find(t=>t.dataset.editorPalette===this._currentModel?.launcherId);e&&null!==e.offsetParent||this._currentModel.dismiss?.()}if(!this._openGroupId)return;const n=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===this._openGroupId);n&&null!==n.offsetParent||this.closeGroup(!0)}handleOutsideDismiss(t){if(B_(t,t=>t.hasAttribute("data-editor-navigation")))return"pointerdown"===t.type?this.closeForNavigation():"click"===t.type&&this._dismissPointerTarget&&this._clearDismissClick(),!1;if("click"===t.type&&this._dismissPointerTarget){return!!(t.composedPath?.()||[t.target]).includes(this._dismissPointerTarget)&&(this._clearDismissClick(),t.preventDefault(),t.stopImmediatePropagation(),!0)}const e=this._openGroupId||this._blocked||"palette"!==this._currentModel?.kind?null:this._currentModel;if("pointerdown"===t.type&&(this._openGroupId||e)){const i=B_(t,t=>t.classList.contains("editor-secondary")),s=B_(t,t=>!!t.dataset.editorGroup),n=B_(t,t=>!!t.dataset.editorPalette),o=B_(t,t=>t.classList.contains("stage"));if(!(i||s||n||"stay-open-on-canvas"===e?.dismissPolicy&&o))return t.preventDefault(),t.stopImmediatePropagation(),this._dismissPointerTarget=t.target,clearTimeout(this._dismissTimer),this._dismissTimer=window.setTimeout(()=>{this._clearDismissClick()},800),this._openGroupId?this.closeGroup(!1):e?.dismiss?.(),this._syncGlobalDismissListener(),!0}return!1}_activateGroupItem(t,e,i){if(t.id!==this._openGroupId)return;const s=t.items.find(t=>t.id===e);if(!s||s.disabled)return;const n="toggle"===s.role&&"stay-open"===s.closePolicy,o=0===i.detail;n||(this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener()),s.invoke(),!n&&o&&this.host.updateComplete().then(()=>{const e=[...this.host.root().querySelectorAll("[data-editor-group]")].find(e=>e.dataset.editorGroup===t.id&&null!==e.offsetParent);e?.focus()})}_groupKeydown(t){if(!["ArrowLeft","ArrowRight","Home","End"].includes(t.key))return;const e=[...t.currentTarget.querySelectorAll(".editor-group-item:not([disabled])")];if(!e.length)return;t.preventDefault();const i=e.indexOf(this.host.root().activeElement),s="Home"===t.key?0:"End"===t.key?e.length-1:"ArrowLeft"===t.key?i<=0?e.length-1:i-1:(i+1)%e.length;e[s]?.focus()}_clearDismissClick(){this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}_syncGlobalDismissListener(){const t=!this._blocked&&"palette"===this._currentModel?.kind,e=!!this._openGroupId||t||!!this._dismissPointerTarget;e!==this._globalDismissListening&&(this._globalDismissListening=e,e?(window.addEventListener("pointerdown",this._globalDismissGuard,!0),window.addEventListener("click",this._globalDismissGuard,!0)):(window.removeEventListener("pointerdown",this._globalDismissGuard,!0),window.removeEventListener("click",this._globalDismissGuard,!0)))}}const W_=t=>t.stopPropagation(),j_=4.166666666666667e-9;function U_(t){return Number.isFinite(t)?Math.round(t/Ph)*Ph:t}const G_=(t,e,i,s)=>Math.hypot(i-t,s-e),V_=(t,e,i,s,n,o,a,r)=>Math.hypot(Math.max(Math.abs(n-t),Math.abs(n+a-(t+i))),Math.max(Math.abs(o-e),Math.abs(o+r-(e+s)))),K_=(t,e,i,s,n,o,a)=>{const r=Math.max(Number(s)||0,0)/2,l=Math.PI/180,c=Math.cos(i*l)*r,h=Math.sin(i*l)*r,d=Math.cos(a*l)*r,p=Math.sin(a*l)*r,u=Math.max(G_(t+c,e+h,n+d,o+p),G_(t-c,e-h,n-d,o-p)),_=Math.max(G_(t+c,e+h,n-d,o-p),G_(t-c,e-h,n+d,o+p));return Math.min(u,_)},Y_=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function J_(t,e){const i=JSON.parse(JSON.stringify(t||[])),s=JSON.parse(JSON.stringify(e||{}));let n=0,o=0,a=0,r=0,l="",c=0,h=0,d=0;const p=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=j_&&h++},u=(t,e)=>{p(t[0],e[0]),p(t[1],e[1])},_={};let m=5;for(const t of i){const e=Y_(t);null!=t?.id&&(_[String(t.id)]=e),e>m&&(m=e)}const g=(t,e,i,s=!1)=>{if(!(t>j_||s))return;n++,t>a&&(a=t);const o=t*Ch*e;o>r&&(r=o,l=i)};for(const t of i){const e=Y_(t),i=null!=t?.id?String(t.id):"";for(const s of t.rooms||[]){o++;let t=0;if(s.poly?.length)s.poly=s.poly.map(e=>{const i=[U_(e[0]),U_(e[1])];return t=Math.max(t,G_(e[0],e[1],i[0],i[1])),u(e,i),i});else if(null!=s.x&&null!=s.y){const e=s.x,i=s.y,n=s.w||0,o=s.h||0,a=U_(e+n),r=U_(i+o),l=U_(e),c=U_(i),h=Math.max(Ph,a-l),d=Math.max(Ph,r-c);t=V_(e,i,n,o,l,c,h,d),s.x=l,s.y=c,s.w=h,s.h=d,p(e,l),p(i,c),p(e+n,l+h),p(i+o,c+d)}g(t,e,i)}for(const s of t.room_drafts||[]){o++;let t=0;const n=s.points||[],a=n.map(e=>{const i=[U_(e[0]),U_(e[1])];return t=Math.max(t,G_(e[0],e[1],i[0],i[1])),i}),r=a.length?[a[0]]:[],l=a.length?[[n[0],a[0]]]:[],c=[];for(let t=0;t+1=2)for(const[t,e]of l)u(t,e);g(t,e,i)}if(Array.isArray(t.room_drafts)){const e=t.room_drafts.length;t.room_drafts=t.room_drafts.filter(t=>t.points?.length>=2),d+=e-t.room_drafts.length,t.room_drafts.length||delete t.room_drafts}for(const s of t.partitions||[]){o++;const n=[s.a[0],s.a[1]],a=[s.b[0],s.b[1]],r=[U_(n[0]),U_(n[1])],l=[U_(a[0]),U_(a[1])];let c=Math.max(G_(n[0],n[1],r[0],r[1]),G_(a[0],a[1],l[0],l[1]));const h=G_(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).every(t=>{const e=Number(t.length),i=Number(t.host.t),s=i*h;return Number.isFinite(e)&&e>0&&Number.isFinite(i)&&i>=0&&i<=1&&s-e/2>=-j_&&s+e/2<=h+j_});h>j_&&d?(s.a=r,s.b=l,u(n,r),u(a,l)):c=0,g(c,e,i)}for(const s of t.wall_columns||[]){o++;const t=[s.center[0],s.center[1]],n=[U_(t[0]),U_(t[1])],a=G_(t[0],t[1],n[0],n[1]);s.center=n,u(t,n),g(a,e,i)}for(const s of t.decor||[]){o++;let t=0;if("line"===s.kind){const e=[s.x1,s.y1],i=[s.x2,s.y2],n=[U_(e[0]),U_(e[1])],o=[U_(i[0]),U_(i[1])];t=Math.max(G_(e[0],e[1],n[0],n[1]),G_(i[0],i[1],o[0],o[1])),s.x1=n[0],s.y1=n[1],s.x2=o[0],s.y2=o[1],u(e,n),u(i,o)}else{const e=s.x,i=s.y,n=s.w,o=s.h,a=U_(e),r=U_(i);if(null!=s.w&&null!=s.h){const l=U_(e+n),c=U_(i+o),h=Math.max(Ph,l-a),d=Math.max(Ph,c-r);t=V_(e,i,n,o,a,r,h,d),s.w=h,s.h=d,p(e+n,a+h),p(i+o,r+d)}else t=G_(e,i,a,r);s.x=a,s.y=r,p(e,a),p(i,r)}g(t,e,i)}for(const s of t.openings||[]){if(o++,"partition"===s.host?.kind){const n=(t.partitions||[]).find(t=>t.id===s.host.id),o=Number(s.host.t);if(!n||!Number.isFinite(o)||o<0||o>1)continue;const a=n.b[0]-n.a[0],r=n.b[1]-n.a[1];if(Math.hypot(a,r)<=j_)continue;const l=n.a[0]+a*o,h=n.a[1]+r*o;let d=180*Math.atan2(r,a)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(s.angle),u=!(Number.isFinite(p)&&p===d),_=K_(s.x,s.y,Number.isFinite(p)?p:d,Number(s.length)||0,l,h,d);s.x=l,s.y=h,s.angle=d,u&&c++,g(_,e,i,u);continue}const n=ui([s.x,s.y],t.rooms||[],.025,{step:Ph,length:Number(s.length)||0});if(!n)continue;const a=Number(s.angle),r=!(Number.isFinite(a)&&a===n.angle),l=K_(s.x,s.y,Number.isFinite(a)?a:n.angle,Number(s.length)||0,n.x,n.y,n.angle);s.x=n.x,s.y=n.y,s.angle=n.angle,r&&c++,g(l,e,i,r)}}for(const[t,e]of Object.entries(s)){if(!e||"object"!=typeof e)continue;const i=e;if("number"!=typeof i.x||"number"!=typeof i.y)continue;o++;const n=U_(i.x),a=U_(i.y),r=G_(i.x,i.y,n,a);s[t]={...i,x:n,y:a},p(i.x,n),p(i.y,a);const l="string"==typeof i.s?i.s:"";g(r,_[l]??m,l)}return{spaces:i,layout:s,report:{moved:n,coordsCanonicalized:h,total:o,maxShift:a,maxShiftCm:r,maxSpace:l,rotated:c,removedDrafts:d},changed:n>0||h>0}}function X_(t,e){const i=e.base+t*e.span;return Math.min(1,Math.max(0,i))}const Z_=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Q_=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function tm(t,e,i){const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;if(o<=0)return Q_(t,e);let a=((t[0]-e[0])*s+(t[1]-e[1])*n)/o;return a=Math.max(0,Math.min(1,a)),Math.hypot(t[0]-(e[0]+s*a),t[1]-(e[1]+n*a))}function em(t,e,i,s,n){for(const s of e)if(s&&!i.has(s.id)&&Z_(s.a)&&Z_(s.b)&&(Q_(t,s.a)<=n||Q_(t,s.b)<=n))return!0;for(const e of s?.roomPolygons||[])for(let i=0;i0&&r>0))return null;if(Math.abs(n[0]/a*(o[1]/r)-n[1]/a*(o[0]/r))>i)return null;for(const[i,n]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(Q_(i,n)<=s)return[(i[0]+n[0])/2,(i[1]+n[1])/2];return null}function sm(t,e){const i=.05*(Number(e.pitch)>0?Number(e.pitch):1),s=new Map;let n=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&Z_(t.a)&&Z_(t.b));if(n.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const o=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let a=0;for(let t=0;tQ_(e,t.at)>i);let h=c[0]??r.a,d=c[c.length-1]??l.b;if(c.length<2&&(h=r.a,d=l.b),d[0]0?(d[0]-h[0])/u:0,m=u>0?(d[1]-h[1])/u:0,g=t=>u>0?((t[0]-h[0])*_+(t[1]-h[1])*m)/u:0;for(const t of[r,l]){const e=g(t.a),i=g(t.b)-e;for(const[n,o]of s)o.toId===t.id&&s.set(n,{fromId:o.fromId,toId:p.id,base:e+o.base*i,span:o.span*i});s.set(t.id,{fromId:t.id,toId:p.id,base:e,span:i})}o&&o.add(p.id),n=n.filter((e,i)=>i!==t.i&&i!==t.j),n.splice(t.i,0,p),a++}return{partitions:n,merged:a,openingMoves:[...s.values()]}}function nm(t,e,i,s){if(!t?.length||!i.length)return 0;const n=new Map(i.map(t=>[t.fromId,t]));let o=0;for(const i of t){const t=i?.host;if(!t||"partition"!==t.kind)continue;const a=n.get(t.id);if(!a)continue;i.host={...t,id:a.toId,t:X_(t.t,a)},o++;const r=$p(i,e,s.coordScale,s.cellCm,s.gridPitch).resolved;r&&Object.assign(i,Rp(i,r,s.coordScale))}return o}function om(t,e){const i=e?.excludeDraftId||null;return{roomPolygons:(t?.rooms||[]).map(t=>hi(t)).filter(t=>!!t),columns:t?.wall_columns||[],draftEnds:(t?.room_drafts||[]).flatMap(t=>{if(i&&t?.id===i)return[];const e=t?.points||[];return e.length?[e[0],e[e.length-1]]:[]})}}const am=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),rm=(t,e)=>t[0]-e[0]||t[1]-e[1],lm=(t,e,i,s)=>[t[0]+e*s,t[1]+i*s],cm=(t,e,i,s)=>(t[0]-e[0])*i+(t[1]-e[1])*s,hm=(t,e,i,s,n)=>{const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(!(r>n))return null;const l=o/r,c=a/r,h=e=>Math.abs((e[0]-t[0])*c-(e[1]-t[1])*l);if(h(i)>n||h(s)>n)return null;const d=cm(i,t,l,c),p=cm(s,t,l,c),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));return _-u>n?{lo:u,hi:_}:null},dm=(t,e,i)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>i,pm=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},um=(t,e,i,s)=>{const n=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(n,o);if(!(a>s))return!0;const r=n/a,l=o/a,c=gl(t.cm,i.cellCm,i.gridPitch)/2;return e.some(e=>{const n=e?.center;if(!am(n))return!0;const o=cm(n,t.a,r,l),h=Math.abs((n[0]-t.a[0])*l-(n[1]-t.a[1])*r),d=gl(Number(e.cm),i.cellCm,i.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||o>=-d-s&&o<=a+d+s&&h<=c+d+s})},_m=(t,e,i)=>{if(t.host){const s=$p(t,e,i.coordScale,i.cellCm,i.gridPitch).resolved;return s?{center:s.center,angle:s.angle,length:s.length}:null}const s=Number(t.x)*i.coordScale,n=Number(t.y)*i.coordScale,o=Number(t.angle),a=Number(t.length)*i.coordScale;return[s,n,o,a].every(Number.isFinite)&&a>0?{center:[s,n],angle:o,length:a}:null},mm=(t,e,i)=>{const s=t.angle*Math.PI/180,n=Math.cos(s),o=Math.sin(s),a=e.angle*Math.PI/180,r=Math.cos(a),l=Math.sin(a);if(Math.abs(n*l-o*r)>1e-6)return!1;const c=e.center[0]-t.center[0],h=e.center[1]-t.center[1];if(Math.abs(c*o-h*n)>i)return!1;const d=c*n+h*o;return Math.max(-t.length/2,d-e.length/2)({...t,a:[t.a[0]*e,t.a[1]*e],b:[t.b[0]*e,t.b[1]*e]}),fm=(t,e,i,s)=>{const n=`~r-${(t=>{let e=2166136261;for(let i=0;i>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${i[0].toFixed(9)},${i[1].toFixed(9)}`)}`,o=`${t.slice(0,Math.max(1,64-n.length))}${n}`;let a=o;for(let t=2;s.has(a);t++){const e=`-${t}`;a=`${o.slice(0,64-e.length)}${e}`}return s.add(a),a},vm=(t,e)=>{const i=[];for(const s of t){const t=i[i.length-1];!(t&&Math.abs(t.hi-s.lo)<=e&&t.safe===s.safe)||s.safe&&t.signature!==s.signature?i.push({lo:s.lo,hi:s.hi,a:s.a,b:s.b,safe:s.safe,signature:s.signature,roomIds:s.roomIds,finalCm:s.finalCm}):(t.hi=s.hi,t.b=s.b)}return i};function ym(t,e,i,s,n){const o=i||[],a=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l=Array.isArray(t?.room_drafts)?t.room_drafts:[],c={walls:o,partitions:a,openings:r,roomDrafts:l,partitionsReconciled:0,openingsRehosted:0,removedDrafts:0};if(!a.length&&!l.length)return c;const h=Math.max(2e-4*n.gridPitch,1e-9);let d=o,p=a,u=r;const _=dc(e.rooms,d,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),m=((t,e,i,s)=>{const n=new Map(t.map(t=>[t.id,t])),o=new Set;for(const t of e){if(!n.get(t.id)||!Array.isArray(t.points)||t.points.length<2||t.segments.length!==t.points.length-1)continue;let e=!0;for(let n=0;n+10)){e=!1;break}const l=Math.hypot(a[0]-o[0],a[1]-o[1]);if(!(l>s)){e=!1;break}const c=i.flatMap(t=>{const e=t.cm>0?t.cm:ll;if(t.open||"outer"!==t.kind&&"shared"!==t.kind||e+st.lo-e.lo||t.hi-e.hi);let h=0;for(const t of c){if(t.lo>h+s)break;if(h=Math.max(h,t.hi),h>=l-s)break}h!m.has(t.id));let f=0,v=0;const y=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...a].sort((t,e)=>t.id.localeCompare(e.id))){if(!p.some(e=>e.id===t.id))continue;if(!pm(t))continue;const i=y.get(t.id);if(!(i&&am(i.a)&&am(i.b)&&Number.isFinite(i.cm)&&i.cm>0))continue;const[o,a]=rm(i.a,i.b)<=0?[[i.a[0],i.a[1]],[i.b[0],i.b[1]]]:[[i.b[0],i.b[1]],[i.a[0],i.a[1]]],r=a[0]-o[0],l=a[1]-o[1],c=Math.hypot(r,l);if(!(c>h))continue;const _=r/c,g=l/c,b=dc(e.rooms,d,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),w=b.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=hm(o,a,t.a,t.b,h);return e?[{interval:t,range:e}]:[]});if(!w.length)continue;const k=u.filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).map(t=>({opening:t,resolved:$p(t,e.partitions,n.coordScale,n.cellCm,n.gridPitch).resolved}));if(k.some(t=>!t.resolved))continue;const x=[0,c];for(const{range:t}of w)x.push(t.lo,t.hi);const $=x.slice(),S=new Map;for(const{opening:t,resolved:e}of k){const i=cm(e.center,o,_,g),s={lo:i-e.length/2,hi:i+e.length/2};S.set(t.id,s),$.push(Math.max(0,s.lo),Math.min(c,s.hi))}const M=[...new Set($.filter(t=>Number.isFinite(t)&&t>=-h&&t<=c+h).map(t=>Math.max(0,Math.min(c,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),C=p.map(t=>gm(t,n.coordScale)).filter(t=>t.id!==i.id),D=e.room_drafts.filter(t=>!m.has(t.id)),P=[];for(let t=0;t+1h))continue;const r=lm(o,_,g,s),l=lm(o,_,g,a),c=w.filter(({range:t})=>t.lo<=s+h&&t.hi>=a-h).map(({interval:t})=>t),d=new Map;for(const t of c)d.set(t.roomId,t);const p=[...d.values()],u=new Set(p.map(t=>t.kind)),m=new Set(p.map(t=>t.cm>0?t.cm:ll)),f=p[0]?.kind,v=[...d.keys()].sort(),y=1===u.size&&1===m.size&&("outer"===f&&1===v.length||"shared"===f&&2===v.length),b={id:i.id,a:r,b:l,cm:i.cm},k=C.some(t=>!!hm(r,l,t.a,t.b,h)),x=D.some(t=>t.points.some((e,i)=>i+10?p[0].cm:ll:0,T=y?Math.max(S,i.cm):i.cm;P.push({lo:s,hi:a,a:r,b:l,safe:$,signature:$?`${f}|${v.join(",")}|${T}`:"",roomIds:v,roomCm:S,finalCm:T})}if(!P.some(t=>t.safe))continue;const T=new Map;for(const{opening:t,resolved:e}of k){const s=S.get(t.id),o=x.some(t=>t>s.lo+h&&tdm(t,s,h)),r=new Set(a.filter(t=>t.safe).map(t=>t.signature));if(!o&&a.length>0&&a.every(t=>t.safe)&&1===r.size&&Tp(e,b,h)){T.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=kp(i,n.cellCm,n.gridPitch),c={lo:s.lo-l,hi:s.hi+l};for(const t of P)dm(t,c,h)&&(t.safe=!1,t.signature="")}let R=!0;for(;R;){R=!1;for(const[t,e]of[...T.entries()]){const s=S.get(t),o=P.filter(t=>dm(t,s,h));if(o.length>0&&o.every(t=>t.safe)&&o.every(t=>t.signature===e.signature))continue;T.delete(t);const a=kp(i,n.cellCm,n.gridPitch),r={lo:s.lo-a,hi:s.hi+a};for(const t of P)dm(t,r,h)&&(t.safe=!1,t.signature="");R=!0}}const I=vm(P,h),A=I.filter(t=>t.safe),z=I.filter(t=>!t.safe);if(!A.length)continue;if(p.length-1+z.length>2e3)continue;let F=d;for(const t of A){const[e,s]=rm(i.a,i.b)<=0?[t.a,t.b]:[t.b,t.a];F=Fl(F,e,s,t.finalCm,n.pitch,n.coordScale)}if(F=uc(e.rooms,F,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),F.length>500)continue;const E=new Set(p.map(t=>t.id));E.delete(i.id);const N=z.map((t,e)=>{const s=[t.a[0]/n.coordScale,t.a[1]/n.coordScale],o=[t.b[0]/n.coordScale,t.b[1]/n.coordScale],a=0===e?i.id:fm(i.id,s,o,E);return E.add(a),{id:a,a:s,b:o,cm:i.cm}}),O=p.findIndex(t=>t.id===i.id),L=p.slice();L.splice(O,1,...N);const H=L.map(t=>gm(t,n.coordScale)),B=new Map;let q=!0;for(const{opening:t,resolved:e}of k){const i=T.get(t.id);if(i){const e=Rp(t,i.resolved,n.coordScale),{host:s,...o}=e;B.set(t.id,o);continue}const s=S.get(t.id),o=N[z.findIndex(t=>t.lo<=s.lo+h&&t.hi>=s.hi-h)],a=o&&H.find(t=>t.id===o.id);if(!o||!a){q=!1;break}const r=a.b[0]-a.a[0],l=a.b[1]-a.a[1],c=Math.hypot(r,l),d=cm(e.center,a.a,r/c,l/c),p={...Rp(t,e,n.coordScale),host:{kind:"partition",id:o.id,t:d/c}};if(!Sp(p,H,n.coordScale,n.cellCm,n.gridPitch).resolved){q=!1;break}B.set(t.id,p)}if(!q)continue;const W=u.map(t=>B.get(t.id)||t),j=[...T.keys()].map(t=>B.get(t)),U=j.map(t=>_m(t,H,n));if(U.some(t=>!t))continue;let G=!1;for(let t=0;tt.id));for(const t of W){if(V.has(t.id))continue;const e=_m(t,H,n);e&&U.some(t=>mm(t,e,h))&&(G=!0)}if(G)continue;const K=Fc(e.rooms,F,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale);[...T.entries()].every(([t,e])=>{const i=B.get(t),s=Oc(K,{x:i.x*n.coordScale,y:i.y*n.coordScale,angle:i.angle,length:i.length*n.coordScale},!0),o=[s.negative,s.positive].filter(t=>!!t?.full),a=e.signature.split("|")[1].split(","),r=new Set(o.map(t=>t.roomId));return o.length===a.length&&r.size===a.length&&a.every(t=>r.has(t))})&&(d=F,p=L,u=W,f+=A.length,v+=T.size)}return{walls:d,partitions:p,openings:u,roomDrafts:g,partitionsReconciled:f,openingsRehosted:v,removedDrafts:m.size}}const bm=t=>JSON.parse(JSON.stringify(t)),wm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),km=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function xm(t,e){let i=String(e??"");const s=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=new RegExp(`^${s}_(.+)_([0-9a-f]{8})$`);let o=0;for(;o<16;o++){const t=n.exec(i);if(!t)return{root:i,layers:o,bounded:!1};i=t[1]}return{root:i,layers:o,bounded:n.test(i)}}const $m=(t,e,i)=>{const s=t.get(e)||[];s.push(i),t.set(e,s)};const Sm=1e-9;class Mm extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const Cm=t=>JSON.parse(JSON.stringify(t)),Dm=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),Pm=t=>[Number(t[0]),Number(t[1])],Tm=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,Rm=(t,e)=>{const i=Tm(t),s=Tm(e);return iTm(t)<=Tm(e)?[Pm(t),Pm(e)]:[Pm(e),Pm(t)],Am=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),zm=t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],i=[];for(let s=1;s{const i=new Set,s=t=>{const e=Number(t);if(!Number.isFinite(e))return;const s=e/Ph;Math.abs(s-Math.round(s))>=Ur&&i.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of hi(e)||[])s(t[0]),s(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])s(t?.a?.[0]),s(t?.a?.[1]),s(t?.b?.[0]),s(t?.b?.[1]);for(const t of e)s(t?.[0]),s(t?.[1]);return i.size},Em=(t,e,i)=>{const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;return o>1e-18?((t[0]-e[0])*s+(t[1]-e[1])*n)/o:0},Nm=(t,e,i)=>{const s=Math.max(0,Math.min(1,Em(t,e,i)));return Math.hypot(t[0]-(e[0]+(i[0]-e[0])*s),t[1]-(e[1]+(i[1]-e[1])*s))},Om=(t,e,i,s,n=Sm)=>{const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(r<=n)return 0;const l=e=>Math.abs((e[0]-t[0])*a-(e[1]-t[1])*o)/r;if(l(i)>n||l(s)>n)return 0;const c=Em(i,t,e),h=Em(s,t,e);return Math.max(0,Math.min(1,Math.max(c,h))-Math.max(0,Math.min(c,h)))*r},Lm=t=>{const e=(new TextEncoder).encode(t),i=8*e.length,s=64*Math.ceil((e.length+9)/64),n=new Uint8Array(s);n.set(e),n[e.length]=128;const o=new DataView(n.buffer);o.setUint32(s-8,Math.floor(i/4294967296),!1),o.setUint32(s-4,i>>>0,!1);const a=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),l=new Uint32Array(64),c=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,n=c(i,17)^c(i,19)^i>>>10;l[t]=l[t-16]+s+l[t-7]+n>>>0}let[e,i,s,n,h,d,p,u]=r;for(let t=0;t<64;t++){const o=u+(c(h,6)^c(h,11)^c(h,25))+(h&d^~h&p)+a[t]+l[t]>>>0,r=e&i^e&s^i&s;u=p,p=d,d=h,h=n+o>>>0,n=s,s=i,i=e,e=o+((c(e,2)^c(e,13)^c(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+i>>>0,r[2]=r[2]+s>>>0,r[3]=r[3]+n>>>0,r[4]=r[4]+h>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+u>>>0}const h=new Uint8Array(32),d=new DataView(h.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let i=0,s=0,n="";for(const o of t)for(s=s<<8|o,i+=8;i>=5;)n+=e[s>>>i-5&31],i-=5;return i&&(n+=e[s<<5-i&31]),n},Bm=(t,e,i,s,n="")=>{const[o,a]=Im(e,i),r=`${t}|${Tm(o)}|${Tm(a)}|${[...s].sort().join(",")}${n}`;return`wall-${Hm(Lm(r)).slice(0,20)}`};let qm=0;const Wm=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),i=`wall-${e||Hm(Lm(`${Date.now()}|${qm++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(i))return i}throw new Mm("duplicate-id","id factory exhausted")},jm=t=>{const e=new Map;for(const i of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(i&&"string"==typeof i.id&&Dm(i.a)&&Dm(i.b)){if(e.has(i.id))throw new Mm("duplicate-id",i.id);e.set(i.id,i)}return e},Um=(t,e,i)=>{const s=(i,s)=>{const n=t[0]-i[0],o=t[1]-i[1];return Math.abs(e[0]-s[0]-n)<=Sm&&Math.abs(e[1]-s[1]-o)<=Sm?[n,o]:null};return s(i.a,i.b)||s(i.b,i.a)},Gm=(t,e)=>{const i=Array.isArray(t.rooms)?t.rooms:[],s=pd(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),n=s.length?s:ud(i,null,1,.04*Ph,!0),o=[];for(const t of i){const i=hi(t),s=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(i&&s.length===i.length)for(let t=0;t"partition"!==t.host?.kind&&[Number(t.x),Number(t.y)].every(Number.isFinite)&&Number.isFinite(Number(t.angle))&&Number(t.length)>0&&n.some(e=>Nm([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*Ph)):[],l=r.map(t=>{const e=Number(t.angle)*Math.PI/180,i=[Math.cos(e),Math.sin(e)],s=Number(t.length)/2,n=[Number(t.x),Number(t.y)];return{a:[n[0]-i[0]*s,n[1]-i[1]*s],b:[n[0]+i[0]*s,n[1]+i[1]*s]}}),c=(t,e)=>r.some(i=>{const s=[Number(i.x),Number(i.y)];if(!Rl(t,e,Number(i.angle)))return!1;if(Nm(s,t,e)>.02*Ph)return!1;const n=Am(t,e),o=Em(s,t,e)*n,a=Number(i.length)/2;return o+a>=-Sm&&o-a<=n+Sm}),h=new Map,d=[];for(const s of i){const r=String(s?.id||""),p=hi(s);if(!r||!p||p.length<3)throw new Mm("invalid-room",r);const u=ec(i,r,a,Ph,1,[...t.walls||[],...l]);if(!u||u.poly.length<3)throw new Mm("invalid-room",r);const _=Array.isArray(s.wall_ids)?s.wall_ids:[],m=_.length===p.length;let g=null,f=m;if(f)for(let t=0;tSm||Math.abs(s[1]-g[1])>Sm)){f=!1;break}g=s}const v=[];for(let t=0;t2)throw new Mm("third-owner",a);const d=m?_[u.parent[t]]:void 0;if("string"==typeof d&&d){const n=e.get(d);f||!n||Om(i,s,n.a,n.b)>Sm?l.preferredIds.add(d):l.positionalIds.add(d),l.preferredCarriers.set(d,{a:Pm(p[u.parent[t]]),b:Pm(p[(u.parent[t]+1)%p.length])})}const g=u.parent[t];l.parentKeys.add(wl(p[g],p[(g+1)%p.length],Ph));const y=[(i[0]+s[0])/2,(i[1]+s[1])/2],b=t=>t.some(t=>Nm(y,[t[0],t[1]],[t[2],t[3]])<=.04*Ph);l.zeroWall||=b(o)||b(n)&&!c(i,s),v.push(a)}const y={...s};delete y.wall_ids,d.push({...y,poly:u.poly.map(t=>[t[0],t[1]]),wall_ids:v})}return{atoms:[...h.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},Vm=(t,e,i,s,n)=>{const o=new Map([...i.values()].map(t=>[Rm(t.a,t.b),t])),a=(t=>{const e=new Map;for(const i of t)"wall"===i.host?.kind&&e.set(i.host.id,(e.get(i.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=n?.get(t.key);if(e){const s=i.get(e);if(!s)throw new Mm("duplicate-id",e);r.set(t,s);continue}if(t.preferredIds.size>1)throw new Mm("duplicate-id",[...t.preferredIds].sort().join(","));const s=[...t.preferredIds][0],l=s?i.get(s):void 0;if(l){r.set(t,l);continue}const c=s?t.preferredCarriers.get(s):void 0;if(s&&c){r.set(t,{id:s,a:c.a,b:c.b,cm:0});continue}const h=o.get(t.key);if(h){r.set(t,h);continue}const d=[...i.values()].filter(e=>Om(t.a,t.b,e.a,e.b)>Sm),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(a.get(e.id)||0)-(a.get(t.id)||0)||Am(e.a,e.b)-Am(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=i.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const i=l.get(e.id)||[];i.push(t),l.set(e.id,i)}for(const[t,e]of l){const s=i.get(t)||r.get(e[0]);if(!s)throw new Mm("duplicate-id",t);const n=[(s.a[0]+s.b[0])/2,(s.a[1]+s.b[1])/2];e.sort((t,e)=>{const i=Nm(n,t.a,t.b)<=Sm?0:1,o=Nm(n,e.a,e.b)<=Sm?0:1;if(i!==o)return i-o;return(Nm(s.a,t.a,t.b)<=Sm?0:1)-(Nm(s.a,e.a,e.b)<=Sm?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const c=(t=>{const e=new Set;for(const i of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(i)?i:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const i of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(i?.segments)?i.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(c.has(t.id))throw new Mm("duplicate-id",t.id);c.add(t.id)}const h=e.filter(t=>!t.id);if(s){const e=h.map(e=>{const[i,s]=Im(e.a,e.b),n=`${String(t.id||"")}|${Tm(i)}|${Tm(s)}|${[...e.owners].sort().join(",")}`,o=Hm(Lm(n));return{atom:e,seed:n,digest:o,base:`wall-${o.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),i=new Map;for(const t of e){const e=i.get(t.digest);if(e&&e!==t.seed)throw new Mm("duplicate-id",t.digest);i.set(t.digest,t.seed);let s=1,n=t.base;for(;c.has(n);)n=`${t.base}-${++s}`;t.atom.id=n,c.add(n)}}else for(const t of h)t.id=Wm(c),c.add(t.id)},Km=(t,e)=>{if("partition"===t.host?.kind)return null;const i=[Number(t.x),Number(t.y)];if(!i.every(Number.isFinite))return null;const s=e=>{if(!(Number(e.cm)>0))return!1;const s=Em(i,e.a,e.b),n=Am(e.a,e.b),o=Number(t.length)/2;return s>=-Sm&&s<=1+Sm&&Nm(i,e.a,e.b)<=.02*Ph&&Rl(e.a,e.b,Number(t.angle))&&Number.isFinite(o)&&o>=0&&s*n-o>=-Sm&&s*n+o<=n+Sm},n="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,o=n&&s(n)?[n]:e.filter(s);if(1!==o.length)return null;const a=o[0];return{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,Em(i,a.a,a.b)))}},Ym=(t,e)=>{const i=[Number(t.x),Number(t.y)];if(!i.every(Number.isFinite))return null;const s=Number(t.length)/2,n=e.filter(e=>{if(!(Number(e.cm)>0))return!1;const n=Em(i,e.a,e.b),o=Am(e.a,e.b);return n>=-Sm&&n<=1+Sm&&Nm(i,e.a,e.b)<=.02*Ph&&Rl(e.a,e.b,Number(t.angle))&&Number.isFinite(s)&&s>=0&&n*o-s>=-Sm&&n*o+s<=o+Sm}),o=e=>{if(!e.length)return null;const s="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null;return s||[...e].sort((t,e)=>Nm(i,t.a,t.b)-Nm(i,e.a,e.b)||Number(e.cm)-Number(t.cm)||(t.ide.id?1:0))[0]},a=e.filter(e=>Number(e.cm)>0&&Rl(e.a,e.b,Number(t.angle))&&Number.isFinite(s)&&s>=0&&Am(e.a,e.b)+Sm>=Number(t.length)),r=o(n)??o(a);return r?{kind:"wall",id:r.id,t:Math.max(0,Math.min(1,Em(i,r.a,r.b)))}:null},Jm=(t,e,i)=>{const s=jm(t),{atoms:n,rooms:o}=Gm(t,s);Vm(t,n,s,e,i);const a=n.map(e=>{const i=e.id?s.get(e.id):void 0,n=((t,e,i)=>{if(e.zeroWall)return 0;const s=Array.isArray(t.walls)?t.walls:[],n=wl(e.a,e.b,Ph),o=s.filter(t=>Number(t.cm)>0&&(!(t.key!==n&&!e.parentKeys.has(t.key))||!(!Dm(t.a)||!Dm(t.b))&&Om(e.a,e.b,t.a,t.b)>=Am(e.a,e.b)-Sm)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(o.map(t=>t.toFixed(9))).size>1)throw new Mm("thickness-conflict",e.key);if(o.length)return o[0];const a=Pl(s,e.a,e.b,Ph,1);return a>0?a:Number(i?.cm)>0?Number(i.cm):0})(t,e,i);return{...i||{},id:e.id,a:[...e.a],b:[...e.b],cm:n}}),r=new Map(n.map(t=>[t.key,t.id]));for(const t of o)t.wall_ids=t.wall_ids.map(t=>r.get(t));t.rooms=o,t.wall_segments=a,t.walls=a.filter(t=>t.cm>0).map(t=>({key:wl(t.a,t.b,Ph),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e)=>{const i=new Set;for(const e of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&i.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[]){const n=Array.isArray(s.segments)?s.segments:[];for(let o=0;o{const s=Array.isArray(t.openings)?t.openings:[];for(const t of s){if("partition"===t.host?.kind)continue;if(!t.host&&!i){const i=Km(t,e);i&&(t.host=i);continue}const s=Km(t,e)??(i?Ym(t,e):null);if(s)t.host=s;else{if(!i)throw new Mm("opening-host",t.id);delete t.host}}})(t,a,e),a.reduce((t,e)=>t+(s.has(e.id)?0:1),0)};function Xm(t,e={}){const i=JSON.stringify(t),s=Cm(t);rl(s);let n=0;const o=Number(s?.model_version||0)<9;for(const t of Array.isArray(s?.spaces)?s.spaces:[]){const i=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0;n+=Jm(t,o,i)}return s.model_version=9,rl(s),{config:s,changed:i!==JSON.stringify(s),migratedSegments:n}}const Zm=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Qm(t,e){const i=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const s=new Map;for(const e of t)Zm(e)&&"string"==typeof e.id&&e.id&&s.set(e.id,e);const n=e.map((e,n)=>{if(Zm(e)&&"string"==typeof e.id&&e.id){const t=s.get(e.id);return t?i(t,e):Cm(e)}return n[e,e in t?i(t[e],s):Cm(s)]);for(const e of Object.keys(t))delete t[e];for(const[e,i]of s)t[e]=i;return t}return Cm(e)};return i(t,e)}const tg=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),eg=(t,e,i)=>Math.min(i,Math.max(e,t)),ig=t=>$h({spaces:[t]})[0],sg=(t,e,i)=>{const s=i>0?i:1,n=t=>`${(t[0]/s).toFixed(12)},${(t[1]/s).toFixed(12)}`,o=n(t),a=n(e);return o0?a:1,l=Math.max(s*r*.02,1e-9),c=[];for(const e of t||[])for(const t of hi(e)||[])c.push([t[0],t[1]]);const h=[];for(const t of i||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&h.push([t[0],t[1]],[t[2],t[3]]);const d=(t,e)=>e.some(e=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l),p=new Map;for(const a of t||[]){if(!a?.id)continue;const u=hc(t,a.id,e,i,s,n,o,r);if(u)for(let t=0;t0&&_>0&&a===m&&_!==a))continue;const g=u.poly[s],f=u.poly[(s+1)%u.poly.length],v=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(v>l&&v<.5*o-1e-9*o))continue;if(d(g,h)||d(f,h))continue;if(d(g,c)&&d(f,c))continue;const y=sg(g,f,r),b=p.get(y);b?b.targets.add(a):p.set(y,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([a])})}}}let u=e.slice();const _=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const i=[Number(t.a[0])*r,Number(t.a[1])*r],s=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...i,...s].every(Number.isFinite)&&(_(i,e.a)&&_(s,e.b)||_(i,e.b)&&_(s,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>sg(t.a,t.b,r).localeCompare(sg(e.a,e.b,r)))){const e=[...t.targets][0],i=u.filter(e=>m(e,t));if(new Set(i.map(t=>t.cm)).size>1)continue;let n=!1;u=u.map(i=>m(i,t)?(n=!0,i.cm===e?i:{...i,cm:e}):i),n||(u=Fl(u,t.a,t.b,e,s,r))}return u}const og=t=>{const e=[];for(const i of t||[]){const t=hi(i);if(t?.length)for(let i=0;i"string"==typeof t?.id?t.id:"").filter(Boolean),h=new Set(c),d=new Map;for(const t of c){const e=xm("space",t);e.layers>0&&km("space",e.root)&&$m(d,e.root,t)}const p=new Map,u=new Map,_=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const i=new Map;for(const s of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof s?.id?s.id:"";if(!t)continue;const n=xm("room",t);n.layers>0&&km("room",n.root)&&$m(i,n.root,t),u.has(t)||u.set(t,e),_.has(t)||_.set(t,String(s.name||""));const o="string"==typeof s.area?s.area:"";if(o){const i=m.get(o)||[];i.push({spaceId:e,roomId:t}),m.set(o,i)}}p.set(e,i)}const g=new Set(u.keys()),f=new Map,v=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?v.set(t.id,t):f.set(t.id,t));const y={spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,positionsUnresolved:0,nestedRefsUnresolved:0,deadSpaceIds:[],orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0,removedPositions:[],liveMissingPositions:[],unverifiedPositions:[]},b=new Set,w=t=>h.has(t)?null:(()=>{const e=xm("space",t).root;if(!km("space",e))return null;const i=d.get(e)||[];return 1===i.length?i[0]:null})(),k=(t,e)=>{const i=xm("room",t).root;if(!km("room",i))return null;const s=p.get(e)?.get(i)||[];return 1===s.length?s[0]:null},x=t=>{const e=i.effectiveAreaByMarker?.[t]||"",s=e&&m.get(e)||[];return 1===s.length?s[0]:null},$=(t,e,i)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const s=e?k(t.room_id,e):null;s?(t.room_id=s,y.roomRefsRemapped++):i?(t.room_id=i.roomId,y.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const s=t.vacuum?.segment_map;if(s&&"object"==typeof s&&!Array.isArray(s))for(const t of Object.keys(s)){const i=s[t];if("string"!=typeof i||!i||g.has(i))continue;const n=e?k(i,e):null;n?(s[t]=n,y.roomRefsRemapped++):y.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const i="string"==typeof t.space?t.space:"",s=i&&!h.has(i),o=n[e],a="string"==typeof o?.s?o.s:"",r=a&&!h.has(a),l=!0===t.removed;let c=i&&h.has(i)?i:null,d=null,p=!1;if(s){const s=w(i);s?(t.space=s,c=s,p=!0,y.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,c=null,y.markersDetached++):(d=x(e),d?(t.space=d.spaceId,c=d.spaceId,y.spaceRefsRemapped++):(delete t.space,c=null,y.markersDetached++))}l&&!p||$(t,c,d),r&&p&&a===i&&c&&(n[e]={...o,s:c},y.positionsRemapped++,b.add(e))}for(const t of Object.keys(n)){if(b.has(t))continue;const e=n[t],i="string"==typeof e?.s?e.s:"";if(!i||h.has(i))continue;const s=w(i);if(s){if(t.startsWith("rl_")){const i=t.slice(3),o=k(i,s);if(o){const i=`rl_${o}`;wm(n,i)||(n[i]={...e,s:s}),delete n[t],y.roomRefsRemapped++,y.positionsRemapped++;continue}}n[t]={...e,s:s},y.positionsRemapped++}}const S=i.ownerRoster,M=!0===S?.authoritative,C=new Set(S?.deviceIds||[]),D=new Set(S?.entityIds||[]),P=new Set(Array.isArray(s.settings?.known_devices)?s.settings.known_devices.filter(t=>"string"==typeof t):[]),T=(t,e="")=>{const i=String(S?.names?.[t]||e||"").trim();return i&&i!==t?i:""},R=(t,e,i,s="",n)=>({id:t,spaceId:e,kind:i,name:T(t,s),...n?{reason:n}:{}}),I=t=>{"room_label"===t?y.orphanRoomLabelsRemoved++:"group"===t?y.orphanGroupPositionsRemoved++:y.orphanDevicePositionsRemoved++},A=new Set;for(const[t,e]of Object.entries(n)){const s="string"==typeof e?.s?e.s:"";if(!s||h.has(s))continue;let o,a;const r=f.get(t),l=v.get(t);if(r)o=R(t,s,"device",String(r.name||"")),a="live";else if(l)o=R(t,s,"device",String(l.name||"")),a="absent";else if(t.startsWith("rl_")){const e=t.slice(3);o=R(t,s,"room_label",_.get(e)||""),a=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);o=R(t,s,"group"),a=D.has(e)?"live":M?"absent":"unverified","unverified"===a&&(o.reason="registry_unavailable")}else C.has(t)?(o=R(t,s,"device"),a="live"):P.has(t)?(o=R(t,s,"device"),a=M?"absent":"unverified","unverified"===a&&(o.reason="registry_unavailable")):(o=R(t,s,"unknown","","unknown_owner"),a="unverified");if("absent"!==a){if("live"===a){if(y.liveMissingPositions.push(o),!0===i.removeLiveMissingPositions){delete n[t],y.liveMissingPositionsRemoved++,I(o.kind),y.removedPositions.push(o);continue}}else y.unverifiedPositions.push(o);y.positionsUnresolved++,A.add(s)}else delete n[t],I(o.kind),y.removedPositions.push(o)}return y.deadSpaceIds=[...A].sort((t,e)=>t.localeCompare(e)),{config:s,layout:n,report:y,changed:JSON.stringify(s)!==o||JSON.stringify(n)!==a}}(t,e,i),a=o.config,r=nl(a,o.layout);rl(a),al(o.layout);const l=JSON.stringify(t||{}),c=JSON.stringify(e||{}),h=Number.isInteger(Number(a.model_version))?Number(a.model_version):0,d=(t=>{let e=0,i=0,s=0;for(const i of t.markers||[]){if("ripple"===i.display&&(i.display="icon_ripple",e++),Array.isArray(i.controls)){const t="string"==typeof i.binding&&i.binding.startsWith("entity:")?i.binding.slice(7):"",s=t?i.controls.filter(e=>e!==t):i.controls;JSON.stringify(s)!==JSON.stringify(i.controls)&&(i.controls=s.length?s:null,e++)}const t=i.vacuum;t&&tg(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const n of t.spaces||[]){const t=n.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,i++);for(const t of n.rooms||[]){const i=t.settings;"glow"===i?.fill_mode&&("boolean"!=typeof i.glow&&(i.glow=!0),delete i.fill_mode,e++,s++)}if(tg(n,"segments")&&(delete n.segments,e++),tg(n,"plan_scale")){const t=Number(n.plan_scale);Number.isFinite(t)&&t>=bh&&t<=wh&&(tg(n,"plan_scale_x")||(n.plan_scale_x=t),tg(n,"plan_scale_y")||(n.plan_scale_y=t),delete n.plan_scale,e++)}const o=Number(n.cell_cm);tg(n,"cell_cm")&&(!Number.isFinite(o)||o<.1||o>1e3)&&(n.cell_cm=Number.isFinite(o)&&o>0?eg(o,.1,1e3):5,e++);const a=Number(n.cell_cm),r=Number.isFinite(a)&&a>0?a:5;for(const t of n.wall_columns||[])if("circle"===t.shape)tg(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&tg(t,"angle")){const i=((Number(t.angle)||0)%90+90)%90;t.angle!==i&&(t.angle=i,e++)}for(const t of n.decor||[]){if(tg(t,"width")){const i=Number(t.width);(tg(t,"width_cm")||Number.isFinite(i))&&(tg(t,"width_cm")||(t.width_cm=Number(eg(i/Dh*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(tg(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),tg(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(eg(es*is(t)/Dh*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(tg(t,"scale")||tg(t,"size"))&&(delete t.scale,delete t.size,e++);let i=String(t.text??"");const s=[...i.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!Yi(t[1]));if(!(tg(t,"entity")||tg(t,"attr")||tg(t,"unit")))continue;const n=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,a=s||n?"":Ji(t.entity,o);if(s||a){if(a){const e=i.indexOf("{}");i=e>=0?i.slice(0,e)+a+i.slice(e+2):`${i}${i?" ":""}${a}`,t.text=i}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:i,glowRooms:s}})(a);let p=d.total;const u=(_=a.spaces||[],JSON.parse(JSON.stringify(_)));var _;const m=J_(a.spaces||[],o.layout);let g=0,f=0,v=0,y="";const b=m.spaces.map(t=>{const e=function(t){const e=JSON.parse(JSON.stringify(t||{}));let i=Array.isArray(e.rooms)?e.rooms:[];const s=new Map;for(const t of i){const e=hi(t);if(e)for(let t=0;tt.key.localeCompare(e.key))){let e=null;for(const s of $a(t,i)){const t=r.get(_a(s.from));if(t&&t!==_a(s.to))continue;const n=wa(i,s);if(ka(i,n,s)){e=s,i=n;break}}e?(r.set(_a(e.from),_a(e.to)),n++,a=Math.max(a,Math.hypot(e.to[0]-e.from[0],e.to[1]-e.from[1]))):o++}e.rooms=i;for(const t of e.room_drafts||[]){if(!Array.isArray(t?.points)||t.points.length<2)continue;const e=t.points.map(t=>[...t]),i=e.slice(0,-1).flatMap((i,s)=>{const n=e[s+1],o=pa(i,n);return o?[{key:`${String(t.id||"")}:${s}`,a:[...i],b:[...n],axis:o.axis}]:[]});let s=e;for(const t of i){let e=null;for(const i of $a(t,[{poly:s}])){const t=s.map(t=>ba(t,i)),n=t.length>=4&&ma(t[0],t[t.length-1]),o=n?t.slice(0,-1):t;if(n?va(o):ya(o)){e=i,s=t;break}}e?(n++,a=Math.max(a,Math.hypot(e.to[0]-e.from[0],e.to[1]-e.from[1]))):o++}t.points=s}for(const t of e.partitions||[]){if(!Array.isArray(t?.a)||!Array.isArray(t?.b))continue;const i=pa(t.a,t.b);if(!i)continue;const s={key:String(t.id||ga(t.a,t.b)),a:[...t.a],b:[...t.b],axis:i.axis};let r=null;for(const i of $a(s,[{poly:[t.a,t.b]}])){const s=ba(t.a,i),n=ba(t.b,i),o=Math.hypot(n[0]-s[0],n[1]-s[1]);if(!(o>0))continue;const a=(e.openings||[]).filter(e=>"partition"===e?.host?.kind&&e.host.id===t.id).every(t=>{const e=Number(t.host.t),i=Number(t.length);return Number.isFinite(e)&&e>=0&&e<=1&&Number.isFinite(i)&&i>0&&e*o-i/2>=-1e-12&&e*o+i/2<=o+1e-12});if(a){r=i,t.a=s,t.b=n;break}}r?(n++,a=Math.max(a,Math.hypot(r.to[0]-r.from[0],r.to[1]-r.from[1]))):o++}return{space:e,report:{wallsStraightened:n,wallsStraightenSkipped:o,maxStraightenShift:a},changed:n>0}}(t);g+=e.report.wallsStraightened,f+=e.report.wallsStraightenSkipped;const i=Number(t?.cell_cm)>0?Number(t.cell_cm):5,s=e.report.maxStraightenShift/Ph*i;return s>v&&(v=s,y=String(t?.id||"")),e.space}),w=g?J_(b,m.layout):{...m,spaces:b};a.spaces=w.spaces;const k=g?{...m.report,moved:m.report.moved+w.report.moved,coordsCanonicalized:m.report.coordsCanonicalized+w.report.coordsCanonicalized,maxShift:Math.max(m.report.maxShift,w.report.maxShift),maxShiftCm:Math.max(m.report.maxShiftCm,w.report.maxShiftCm),maxSpace:w.report.maxShiftCm>m.report.maxShiftCm?w.report.maxSpace:m.report.maxSpace,rotated:m.report.rotated+w.report.rotated,removedDrafts:m.report.removedDrafts+w.report.removedDrafts}:{...m.report};let x=0,$=0,S=0,M=0,C=0,D=0,P=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),o=ig(e),r=ig(i);if(!o||!r)continue;const l=og(o.rooms),c=og(r.rooms),h=.02*Dh,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:wl(t.a,t.b,Ph),cm:0})),p=new Set(d.map(t=>t.key)),_=__(e,o.rooms,vh,h);$+=_.length;for(const t of _){const e=[t[0]/vh,t[1]/vh],i=[t[2]/vh,t[3]/vh],s=wl(e,i,Ph);p.has(s)||(p.add(s),d.push({key:s,a:e,b:i,cm:0}))}const m=d.length,g=Al(d,l,c,Ph,vh),f=(t,e,i)=>{const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;if(!(o>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const a=Math.max(0,Math.min(1,((t[0]-e[0])*s+(t[1]-e[1])*n)/o));return Math.hypot(t[0]-(e[0]+s*a),t[1]-(e[1]+n*a))},v=g.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*vh),i=t.b.map(t=>t*vh);return c.some(([t,s])=>f(e,t,s)<=4*h&&f(i,t,s)<=4*h)});S+=Math.max(0,m-v.length);const y=(i.wall_segments||[]).filter(t=>Number(t.cm)>0);i.wall_segments=[...y,...v.map(({key:t,...e})=>e)];const b=v.map(t=>[t.a[0]*vh,t.a[1]*vh,t.b[0]*vh,t.b[1]*vh]),w=Array.isArray(e.walls)?e.walls.length:0;let k=Al(e.walls,l,c,Ph,vh);k=ng(r.rooms,k,b,Ph,Number(i.cell_cm)>0?Number(i.cell_cm):5,Dh,vh),k=uc(r.rooms,k,b,Ph,Number(i.cell_cm)>0?Number(i.cell_cm):5,Dh,vh),k=Tl(k,i.rooms||[],Ph,1,b.map(t=>[t[0]/vh,t[1]/vh,t[2]/vh,t[3]/vh])),x+=Math.max(0,w-k.length),k.length?i.walls=k:delete i.walls;const R=sm(i.partitions||[],{pitch:Ph,geometry:om(i)});R.merged&&(M+=R.merged,i.partitions=R.partitions,nm(i.openings,i.partitions,R.openingMoves,{coordScale:vh,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,gridPitch:Dh}));const I=ig(i);if(I){const t=n(i,I,i.walls||[],b,{pitch:Ph,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,gridPitch:Dh,coordScale:vh});t.partitionsReconciled&&(C+=t.partitionsReconciled,D+=t.openingsRehosted,t.partitions.length?i.partitions=t.partitions:delete i.partitions,t.openings.length?i.openings=t.openings:delete i.openings,t.walls.length?i.walls=t.walls:delete i.walls),t.removedDrafts&&(P+=t.removedDrafts,t.roomDrafts.length?i.room_drafts=t.roomDrafts:delete i.room_drafts)}JSON.stringify({zero:(i.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:i.walls||[]})!==s&&T++}let R=0;h<=9&&(R=function(t){const e=Xm(t);return Qm(t,e.config),{...e,config:t}}(a).migratedSegments);const I=rl(a),A=al(w.layout),z=JSON.stringify(I)!==l||JSON.stringify(A)!==c;h<9&&z&&(I.model_version=9);const F=JSON.stringify(I)!==l||JSON.stringify(A)!==c,E=Number.isInteger(Number(I.model_version))?Number(I.model_version):h,N=F?k:{...k,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0,removedDrafts:0},O=F?o.report:{...o.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:I,layout:A,report:{...N,modelFrom:h,modelTo:E,migrated:F?p:0,glowSpacesMigrated:F?d.glowSpaces:0,glowRoomsMigrated:F?d.glowRooms:0,canonicalized:F?T:0,wallSegmentsMigrated:F?R:0,legacyZeroWallsMigrated:F?$:0,wallsMerged:F?x:0,spansMerged:F?S:0,partitionsMerged:F?M:0,partitionsReconciled:F?C:0,openingsRehosted:F?D:0,redundantDraftsRemoved:F?P:0,wallsStraightened:F?g:0,wallsStraightenSkipped:f,maxStraightenShiftCm:F?v:0,maxStraightenSpace:F?y:"",latticeCoordinatesCanonicalized:F?r.canonicalized:0,latticeCoordinatesFar:F?r.far:0,latticeMaxShift:F?r.maxShift:0,latticeMaxShiftCm:F?r.maxShiftCm:0,latticeSpaces:F?r.spaces:[],...O},changed:F}}function rg(t,e,i){const s=(t?.spaces||[]).find(t=>t?.id===i),n=new Set((s?.rooms||[]).map(t=>String(t?.id||"")).filter(Boolean)),o=[...new Set((t?.markers||[]).filter(t=>!0!==t?.removed&&"string"==typeof t?.id).filter(t=>t.space===i||"string"==typeof t.room_id&&n.has(t.room_id)||e?.[t.id]?.s===i).map(t=>t.id))].sort((t,e)=>t.localeCompare(e));return{markerIds:o,count:o.length}}function lg(t){return t instanceof Error?t.name||"Error":typeof t}function cg(t){return bd({id:t?.id??"",cell_cm:t?.cell_cm,rooms:t?.rooms||[],walls:t?.walls||[],wall_segments:t?.wall_segments||[],open_spans:t?.open_spans||[],openings:t?.openings||[],partitions:t?.partitions||[],room_drafts:t?.room_drafts||[],wall_columns:t?.wall_columns||[]})}function hg(t,e,i,s=Dh,n=1e3){return(Array.isArray(t?.openings)?t.openings:[]).flatMap(t=>{const o={...t,rx:Number(t.x)*n,ry:Number(t.y)*n,rlen:Number(t.length)*n};if(!t.host||"wall"===t.host.kind)return[o];const a=$p(t,e.partitions,n,i,s);return a.resolved?[{...t,rx:a.resolved.center[0],ry:a.resolved.center[1],rlen:a.resolved.length,angle:a.resolved.angle,partitionHost:a.resolved}]:[]})}function dg(t,e=()=>!0){return t.flatMap(t=>t.host&&t.partitionHost&&e(t)?[Cp(t.partitionHost)]:[])}function pg(t,e,i,s,n,o,a=Dh,r=1e3){const l=dc(e.rooms,[...i],s,n,o,a,r);return t.flatMap(t=>{const e={x:t.rx,y:t.ry,angle:Number(t.angle)||0,length:t.rlen};return t.host&&"wall"!==t.host.kind?t.partitionHost&&Tp(t.partitionHost,l,2e-4*a)?[e]:[]:[e]})}function ug(t,e){const i=Ph,s=Dh,n=vh,o=Number.isFinite(Number(e.cellCm))&&Number(e.cellCm)>0?Number(e.cellCm):5,a=Array.isArray(t?.walls)?t.walls:[],r=function(t,e,i=Dh,s=1e3){return ud(e.rooms,t?.open_spans,s,.02*i)}(t,e,s,n),l=function(t,e,i=Dh){if(!e.length)return[];const s=t.filter(t=>t?.id),n=.02*i,o=[];for(let t=0;t{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return h.some(t=>Ls(e,t)<4*n)}).map(t=>[...t]);d.length&&o.push({a:a,b:r,segs:d})}return o}(e.rooms,r,s).flatMap(t=>t.segs),c=hg(t,e,o,s,n),h=dg(c),d=eh(e,o,s,2e-4*s,h).all;return{space:e,walls:a,openCuts:l,openings:c,roomOpenings:pg(c,e,a,l,i,o,s,n),partitionCuts:h,physicalBodies:d,wallKeyPitch:i,cellCm:o,gridPitch:s,coordScale:n}}function _g(t,e,i){const s="string"==typeof t?.title?t.title.trim():"",n=null==t?.id?"":String(t.id).trim();return{spaceId:n,displayName:s||n||i(e+1)}}function mg(t,e={}){const i=(e.fingerprint||bd)(t),s=Array.isArray(t?.spaces)?t.spaces:[],n=e.fallbackSpaceName||(t=>`Space ${t}`),o=e.prepareSpace||ug,a=e.wallPass||Rc,r=e.floorPass||Pc,l=[];for(let e=0;e0||h.physicalBodies.length>0;if(!h.space.rooms.length&&!d){l.push({...c,status:"not-applicable"});continue}let p=null;if(d){try{p=a(h.space.rooms,h.walls,h.openCuts,h.roomOpenings,h.wallKeyPitch,h.cellCm,h.gridPitch,h.coordScale,h.physicalBodies)}catch(t){l.push({...c,status:"failed",reason:"wall-exception",detail:lg(t)});continue}if(null==p){l.push({...c,status:"failed",reason:"wall-null"});continue}if("degraded-extra"===p.status){l.push({...c,status:"failed",reason:"wall-degraded-extra"});continue}if("failed-core"===p.status){l.push({...c,status:"failed",reason:"wall-failed-core"});continue}}if(h.space.rooms.length&&null==p?.paperGeom){let t;try{t=r(h.space.rooms,h.walls,h.openCuts,h.wallKeyPitch,h.cellCm,h.gridPitch,h.coordScale)}catch(t){l.push({...c,status:"failed",reason:"floor-exception",detail:lg(t)});continue}if(null==t){l.push({...c,status:"failed",reason:"floor-null"});continue}}l.push({...c,status:"ok"})}const c=l.filter(t=>"failed"===t.status);return{fingerprint:i,spaces:l,failures:c,ok:0===c.length}}class gg{constructor(t=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(t))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(t){this._undo.push(t),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const t=this._undo.pop()??null;return t&&this._redo.push(t),t}redo(){const t=this._redo.pop()??null;return t&&this._undo.push(t),t}clear(){this._undo=[],this._redo=[]}}const fg=new WeakMap;const vg=(t,e,i)=>255===t[i+3]&&e.every((e,s)=>Math.abs(t[i+s]-e)<=2);async function yg(t){const e=t.defaultView;if(!e||!e.CSS?.supports?.("mix-blend-mode","screen"))return!1;const i=[128,32,16],s=[16,64,128],n=[9,19,29],o=`\n \n \n \n \n \n `,a=e.URL.createObjectURL(new Blob([o],{type:"image/svg+xml"}));try{const o=await new Promise((t,i)=>{const s=new e.Image,n=e.setTimeout(()=>i(new Error("SVG blend probe timeout")),1e3);s.onload=()=>{e.clearTimeout(n),t(s)},s.onerror=()=>{e.clearTimeout(n),i(new Error("SVG blend probe failed"))},s.src=a}),r=t.createElement("canvas");r.width=4,r.height=1;const l=r.getContext("2d",{willReadFrequently:!0});if(!l)return!1;l.drawImage(o,0,0,4,1);const c=l.getImageData(0,0,4,1).data;return vg(c,i,0)&&vg(c,function(t,e){return[0,1,2].map(i=>Math.round(255-(255-t[i])*(255-e[i])/255))}(i,s),4)&&vg(c,s,8)&&vg(c,n,12)}catch{return!1}finally{e.URL.revokeObjectURL(a)}}const bg={now:()=>performance.now(),requestFrame:t=>requestAnimationFrame(t),cancelFrame:t=>cancelAnimationFrame(t)},wg=t=>Math.max(0,Math.min(1,t)),kg=(t,e,i)=>t+(e-t)*i,xg=(t,e,i)=>{const s=1-t;return 3*s*s*t*e+3*s*t*t*i+t*t*t};function $g(t,e){return{centerX:t.x+t.w/2,centerY:t.y+t.h/2,pixelsPerUnit:e>0&&t.w>0?e/t.w:1,viewBox:{...t}}}function Sg(t,e,i){const s=Math.max(1e-9,t.pixelsPerUnit),n=Math.max(1e-9,e/s),o=Math.max(1e-9,i/s);return{x:t.centerX-n/2,y:t.centerY-o/2,w:n,h:o}}function Mg(t){const e=t.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(e);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const s=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(e)?.[1];return s?[parseInt(s.slice(0,2),16),parseInt(s.slice(2,4),16),parseInt(s.slice(4,6),16),8===s.length?parseInt(s.slice(6,8),16)/255:1]:null}function Cg(t,e,i){const s=Mg(t),n=Mg(e);if(!s||!n)return i<.5?t:e;const o=wg(i);return`rgba(${Math.round(kg(s[0],n[0],o))}, ${Math.round(kg(s[1],n[1],o))}, ${Math.round(kg(s[2],n[2],o))}, ${kg(s[3],n[3],o).toFixed(3)})`}function Dg(t,e,i){const s=(t=>{const e=wg(t);if(0===e||1===e)return e;let i=0,s=1,n=e;for(let t=0;t<12;t++)n=(i+s)/2,xg(n,.2,.2){const e=this._state;if(!e||e.token!==n)return;const i=wg((t-e.startedAt)/e.duration);e.presented=i>=1?e.to:Dg(e.from,e.to,i),e.phase=i>=1?"settling":"running",this._hooks.frame(e),i<1?this._raf=this._clock.requestFrame(a):(this._raf=0,this._hooks.settled(e),this._state?.token===n&&(this._state=null))};return this._raf=this._clock.requestFrame(a),n}cancel(t=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const e=this._state;this._state=null,this._token++,e&&t&&(e.phase="settling",e.presented=e.to,this._hooks.frame(e),this._hooks.settled(e))}dispose(){this.cancel(!1)}}const Tg="houseplan_card_labs_v1",Rg=Object.freeze([Object.freeze({id:"iso",issue:89,since:"1.62.0",expires:"1.65.0",summary:"Volumetric plan renderer"})]);function Ig(t){const e=/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/.exec(String(t||"").trim());if(!e)return null;const i=e.slice(1).map(Number);return i.every(t=>Number.isSafeInteger(t))?i:null}function Ag(t,e){for(let i=0;i<3;i++)if(t[i]!==e[i])return t[i]t.split(",")).map(t=>t.trim()).filter(Boolean)}function Lg(t,e,i,s=Rg){const n=function(t,e=Rg){const i=Ig(t),s=new Map;if(!i||!Fg(e))return s;for(const t of e){const e=Ig(t.since),n=Ig(t.expires);Ag(i,e)>=0&&Ag(i,n)<0&&s.set(t.id,t)}return s}(i,s),o=new Set(Fg(s)?s.map(t=>t.id):[]),a=new Set(function(t){if(!t)return[];try{const e=JSON.parse(t);return Array.isArray(e)?e.filter(t=>"string"==typeof t):[]}catch{return[]}}(e).filter(t=>n.has(t)));let r=!1;const l=t=>{if("off"===t)return a.clear(),void(r=!0);const e=t.startsWith("-"),i=e?t.slice(1):t;o.has(i)&&(r=!0,e||!n.has(i)?a.delete(i):a.add(i))};for(const e of Og(new URLSearchParams(String(t.search||"").replace(/^\?/,""))))l(e);for(const e of Og(Eg(t.hash)))l(e);const c=Object.freeze([...a].sort());return{active:c,space:Ng(t.hash),persist:r?JSON.stringify(c):void 0,knownUrlOperation:r}}let Hg={active:Object.freeze([]),space:""},Bg="",qg=!1,Wg="";const jg=new Set;function Ug(){if("undefined"==typeof window)return Hg;const t=Lg(window.location,function(){try{return window.localStorage.getItem(Tg)}catch{return null}}(),Bg);void 0!==t.persist&&function(t){try{window.localStorage.setItem(Tg,t)}catch{}}(t.persist),Hg={active:t.active,space:t.space},window.__hpLabs=t.active;for(const t of jg)t(Hg);return Hg}function Gg(){Ug()}function Vg(t){return Bg=t,"undefined"==typeof window?Hg:(qg||(qg=!0,window.addEventListener("hashchange",Gg),window.addEventListener("popstate",Gg)),Ug())}const Kg=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])});function Yg(t){return[t.rotDeg,t.tiltDeg,t.xyScale,t.zScale,t.origin[0],t.origin[1]].every(Number.isFinite)&&Math.abs(t.xyScale)>1e-12&&Math.abs(Math.cos(t.tiltDeg*Math.PI/180))>1e-12}function Jg(t,e,i=Kg){if(!(Yg(i)&&Number.isFinite(t[0])&&Number.isFinite(t[1])&&Number.isFinite(e)))throw new Error("invalid isometric projection input");const s=i.rotDeg*Math.PI/180,n=i.tiltDeg*Math.PI/180,o=t[0]-i.origin[0],a=t[1]-i.origin[1],r=(o*Math.cos(s)-a*Math.sin(s))*i.xyScale,l=(o*Math.sin(s)+a*Math.cos(s))*i.xyScale;return[i.origin[0]+r,i.origin[1]+l*Math.cos(n)-e*i.zScale*Math.sin(n)]}function Xg(t,e=Kg){if(!Yg(e)||!Number.isFinite(t[0])||!Number.isFinite(t[1]))throw new Error("invalid isometric projection input");const i=e.rotDeg*Math.PI/180,s=e.tiltDeg*Math.PI/180,n=(t[0]-e.origin[0])/e.xyScale,o=(t[1]-e.origin[1])/(e.xyScale*Math.cos(s));return[e.origin[0]+n*Math.cos(i)+o*Math.sin(i),e.origin[1]-n*Math.sin(i)+o*Math.cos(i)]}function Zg(t=Kg){return`matrix(${function(t=Kg){if(!Yg(t))throw new Error("invalid isometric camera");const e=t.rotDeg*Math.PI/180,i=t.tiltDeg*Math.PI/180,s=t.xyScale*Math.cos(e),n=-t.xyScale*Math.sin(e),o=t.xyScale*Math.sin(e)*Math.cos(i),a=t.xyScale*Math.cos(e)*Math.cos(i);return[s,o,n,a,t.origin[0]-s*t.origin[0]-n*t.origin[1],t.origin[1]-o*t.origin[0]-a*t.origin[1]]}(t).map(t=>Number(t.toFixed(12))).join(" ")})`}function Qg(t,e=Kg){const{rect:i,wallHeight:s}=t,n=t.openingHeight??s,o=t.floorDepth??0;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(s)||!Number.isFinite(n)||!Number.isFinite(o)||s<0||n<0||o<0)throw new Error("invalid isometric frame");const a=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],r=Math.max(s,n),l=a.flatMap(t=>[Jg(t,-o,e),Jg(t,r,e)]),c=l.map(t=>t[0]),h=l.map(t=>t[1]),d=Math.min(...c),p=Math.min(...h);return{x:d,y:p,w:Math.max(...c)-d,h:Math.max(...h)-p}}const tf=t=>`${Number(t[0].toFixed(4))} ${Number(t[1].toFixed(4))}`;function ef(t){let e=0;for(let i=0;iArray.isArray(t)&&Number.isFinite(t[0])&&Number.isFinite(t[1])).map(t=>[Number(t[0]),Number(t[1])]),i=e[e.length-1];return e.length>1&&e[0][0]===i[0]&&e[0][1]===i[1]&&e.pop(),e}(t);if(i.length<3)return[];const s=!e;return ef(i)>0===s?i:[...i].reverse()}function nf(t,e,i){return t.length?`M ${t.map(t=>tf(Jg(t,i,e))).join(" L ")} Z`:""}function of(t,e,i){const s=e[1]-t[1],n=-(e[0]-t[0]),o=i.rotDeg*Math.PI/180;return s*Math.sin(o)+n*Math.cos(o)}function af(t,e,i=Kg){if(!Number.isFinite(e)||e<0)throw new Error("invalid floor edge height");const s=(t||[]).map(t=>(t||[]).map((t,e)=>function(t,e){const i=sf(t,e);if(!i.length)return i;let s=0;for(let t=1;t0)).filter(t=>t.length>=3&&Math.abs(ef(t))>=1e-9)).filter(t=>t.length&&ef(t[0])>0);s.sort((t,e)=>{const i=t[0][0],s=e[0][0];return i[0]-s[0]||i[1]-s[1]||Math.abs(ef(e[0]))-Math.abs(ef(t[0]))});const n=[],o=[];let a=0;for(let t=0;tt.depth-e.depth||t.component-e.component||t.edge-e.edge),{footprintPath:n.join(" "),sides:o,componentCount:s.length,edgeCount:a}}function rf(t,e){return t^=Math.round(64*(Number.isFinite(e)?e:0)),Math.imul(t,16777619)>>>0}const lf=t=>t.every(Number.isFinite);function cf(t,e,i,s){const n=t[0]*i,o=t[1]*s,a=e*Math.PI/180;return[n*Math.cos(a)-o*Math.sin(a),n*Math.sin(a)+o*Math.cos(a)]}function hf(t,e,i,s,n,o,a){const r=t.flipH?-1:1,l="gate"===t.type?1:t.flipV?-1:1,c=(t.type,t.flipV,t.angle,t.face,{ox:0,oy:0}),h=function(t,e){return[t[0]+e[0],t[1]+e[1]]}([t.x+c.ox,t.y+c.oy],cf(i,t.angle,r,l));return{leaf:e,hinge:h,closedVector:cf(s,t.angle,r,l),quarterVector:cf([-s[1],s[0]],t.angle,r,l),turnDeg:n,bottom:o,top:a}}const df=t=>`${Number(t[0].toFixed(4))} ${Number(t[1].toFixed(4))}`;function pf(t,e,i=Kg){const s=Math.max(0,Math.min(1,Number.isFinite(e)?e:0));return t.leaves.map(e=>{const n=function(t,e){const i=t.turnDeg*e*Math.PI/180;return[t.hinge[0]+t.closedVector[0]*Math.cos(i)+t.quarterVector[0]*Math.sin(i),t.hinge[1]+t.closedVector[1]*Math.cos(i)+t.quarterVector[1]*Math.sin(i)]}(e,s),o=Jg(e.hinge,e.bottom,i),a=Jg(n,e.bottom,i),r=Jg(n,e.top,i),l=Jg(e.hinge,e.top,i);return{id:t.id,sourceIndex:t.sourceIndex,type:t.type,leaf:e.leaf,d:`M ${df(o)} L ${df(a)} L ${df(r)} L ${df(l)} Z`,shadowD:`M ${df(Jg(e.hinge,0,i))} L ${df(Jg(n,0,i))}`,depth:Math.max(o[1],a[1])}})}const uf={window:120,door:90,passage:90,gate:300};function _f(t){return uf[t]}function mf(t,e){const i=[t[0],t[1]],s=[e[0],e[1]];return function(t,e){return t[0]-e[0]||t[1]-e[1]}(i,s)<=0?{a:i,b:s}:{a:s,b:i}}function gf(t){const e=new Map;return t.forEach((t,i)=>{if(!t.kind||t.open)return;const s=mf(t.a,t.b);if(Math.hypot(s.b[0]-s.a[0],s.b[1]-s.a[1])<=1e-9)return;const n=function(t,e){const i=t=>(Math.abs(t)<=5e-10?0:Math.round(1e6*t)/1e6).toFixed(6);return`${i(t[0])},${i(t[1])}>${i(e[0])},${i(e[1])}`}(s.a,s.b),o=e.get(n);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,t.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(t.partitionHost&&(o.partitionHost&&o.partitionHost.id!==t.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=t.partitionHost));e.set(n,{segmentKey:n,a:s.a,b:s.b,physicalHalfWidth:Math.max(0,t.half||0),sourceOrder:i,...t.partitionHost?{partitionHost:t.partitionHost}:{}})}),[...e.values()]}function ff(t,e){if(Math.abs(t.distance-e.distance)>1e-9)return t.distance-e.distance;if(Math.abs(t.perpendicular-e.perpendicular)>1e-9)return t.perpendicular-e.perpendicular;return(t.target.segmentKeye.target.segmentKey?1:0)||t.target.sourceOrder-e.target.sourceOrder}function vf(t){const e=gf(t.intervals).map(e=>{const i=function(t,e){const i=e.b[0]-e.a[0],s=e.b[1]-e.a[1],n=Math.hypot(i,s),o=i/n,a=s/n,r=(t[0]-e.a[0])*o+(t[1]-e.a[1])*a,l=Math.max(0,Math.min(n,r)),c=e.a[0]+l*o,h=e.a[1]+l*a;return{along:l,length:n,x:c,y:h,distance:Math.hypot(t[0]-c,t[1]-h),perpendicular:Math.abs((t[0]-e.a[0])*a-(t[1]-e.a[1])*o)}}(t.pointer,e);return{target:e,...i,envelope:Math.max(t.baseTolerance,e.physicalHalfWidth+t.bodyPointerPadding)}}).filter(t=>t.distance<=t.envelope+1e-9).filter(e=>!function(t,e,i,s,n){const o=e.b[0]-e.a[0],a=e.b[1]-e.a[1],r=Math.hypot(o,a);if(!(r>1e-9))return!1;const l=o/r,c=a/r;for(const o of i){if(!o.open&&o.kind)continue;const i=mf(o.a,o.b),a=i.b[0]-i.a[0],r=i.b[1]-i.a[1],h=Math.hypot(a,r);if(!(h>1e-9))continue;const d=a/h,p=r/h;if(Math.abs(l*p-c*d)>1e-6)continue;if(Math.abs((i.a[0]-e.a[0])*c-(i.a[1]-e.a[1])*l)>n)continue;const u=(t[0]-i.a[0])*d+(t[1]-i.a[1])*p,_=1e-9;if(!(u<=_||u>=h-_)&&Math.abs((t[0]-i.a[0])*p-(t[1]-i.a[1])*d)<=s+1e-9)return!0}return!1}(t.pointer,e.target,t.intervals,e.envelope,Math.max(1e-9,Math.min(t.baseTolerance,.04*t.gridStep)))),i=e.filter(e=>!!e.target.partitionHost&&t.renderedLength+2*e.target.physicalHalfWidth>e.length+1e-9).sort(ff),s=e.filter(e=>!e.target.partitionHost||t.renderedLength+2*e.target.physicalHalfWidth<=e.length+1e-9).sort(ff);let n=s[0];if(!n)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=s.filter(t=>Math.abs(t.distance-n.distance)<=1e-9&&Math.abs(t.perpendicular-n.perpendicular)<=1e-9),a=o.filter(t=>t.target.partitionHost);if(a.length){if(1!==new Set(a.map(t=>t.target.partitionHost.id)).size||a.some(t=>t.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const t=a[0],e=t.target.b[0]-t.target.a[0],i=t.target.b[1]-t.target.a[1],s=Math.hypot(e,i),r=e/s,l=i/s,c=o.every(e=>{const i=e.target.b[0]-e.target.a[0],s=e.target.b[1]-e.target.a[1],n=Math.hypot(i,s),o=i/n,a=s/n,c=Math.abs(r*a-l*o)<=1e-6,h=Math.abs((e.target.a[0]-t.target.a[0])*l-(e.target.a[1]-t.target.a[1])*r);return c&&h<=1e-9});if(!c)return{candidate:null,jambBlockedTarget:null};n=t}if(n.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:r,length:l}=n,c=r.b[0]-r.a[0],h=r.b[1]-r.a[1],d=c/l,p=h/l,u=r.partitionHost?r.physicalHalfWidth:0,_=Math.min(Math.max(0,t.renderedLength)/2+u,l/2);let m=n.along;const g=Math.max(t.gridStep,1e-9),f=l/2;m=Math.abs(m-f)<=g/2?f:Math.round(m/g)*g,m=Math.max(_,Math.min(l-_,m));const v=r.a[0]+d*m,y=r.a[1]+p*m,b=Math.max(0,t.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),$=Math.max(0,l-k),S=[r.a[0]+d*(w-x/2),r.a[1]+p*(w-x/2)],M=[r.a[0]+d*(k+$/2),r.a[1]+p*(k+$/2)];let C=180*Math.atan2(h,c)/Math.PI;C>=90?C-=180:C<-90&&(C+=180);const D=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:t.preset.revision,geometryRevision:t.geometryRevision,pointer:[t.pointer[0],t.pointer[1]],type:t.preset.type,lengthCm:t.preset.lengthCm,flipH:t.preset.flipH,flipV:t.preset.flipV,x:v,y:y,angle:C,renderedLength:t.renderedLength,target:r,...r.partitionHost?{host:{...r.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:S},{distance:$,midpoint:M}],guide:D?{x:v,y:y,angle:C}:null}},jambBlockedTarget:null}}function yf(t,e,i,s,n=1e-6){return t.presetRevision===i&&t.geometryRevision===s&&Math.hypot(t.pointer[0]-e[0],t.pointer[1]-e[1])<=n}const bf=(t,e)=>t[0]*e[1]-t[1]*e[0],wf=(t,e)=>t[0]*e[0]+t[1]*e[1],kf=(t,e)=>[t[0]-e[0],t[1]-e[1]],xf=(t,e,i)=>[t[0]+e[0]*i,t[1]+e[1]*i];function $f(t,e,i){return Math.abs(bf(t,e))<=i}function Sf(t,e,i){return Math.abs(bf(kf(t,e),i))}function Mf(t,e,i,s,n){const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(!(r>n&&i>0))return[];const l=[o/r,a/r];return function(t,e,i){const s=e.map(([e,i])=>[Math.max(0,Math.min(e,i)),Math.min(t,Math.max(e,i))]).filter(([t,e])=>e>t+i).sort((t,e)=>t[0]-e[0]||t[1]-e[1]),n=[];for(const t of s){const e=n[n.length-1];!e||t[0]>e[1]+i?n.push([...t]):e[1]=Math.max(e[1],t[1])}const o=[];let a=0;for(const[t,e]of n)t>a+i&&o.push([a,t]),a=Math.max(a,e);return t>a+i&&o.push([a,t]),o}(r,s.flatMap(e=>{const s=e.b[0]-e.a[0],o=e.b[1]-e.a[1],a=Math.hypot(s,o);if(!(a>n&&$f(l,[s/a,o/a],1e-6)))return[];if(Sf(e.a,t,l)>1.1*Math.max(i,n)||Sf(e.b,t,l)>1.1*Math.max(i,n))return[];return[[wf(kf(e.a,t),l),wf(kf(e.b,t),l)]]}),n).flatMap(([e,s])=>{const n=Ol({a:xf(t,l,e),b:xf(t,l,s),halfDepth:i});return n?[n]:[]})}function Cf(t){const e=t.coordScale??1,i=Math.max(t.epsilon??2e-4*t.gridPitch,1e-9),s=[];for(const i of t.rooms||[]){if(!i?.id)continue;const n=hc(t.rooms,i.id,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e);if(!n||n.poly.length<3)continue;const o=Zl(n.poly,n.offsets);!o||o.length<3||s.push({roomId:i.id,profile:n,inner:o})}s.sort((t,e)=>t.roomId.localeCompare(e.roomId));const n=(t.roomOpenings||[]).map(t=>{const e=t.angle*Math.PI/180,i=[Math.cos(e),Math.sin(e)],s=Math.max(0,t.length)/2;return{a:xf([t.x,t.y],i,-s),b:xf([t.x,t.y],i,s)}}),o=[];for(const s of Ac(t.rooms,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e))for(const t of Mf(s.a,s.b,s.depthUnits/2,n,i))o.push({body:t});const a=new Map;for(const e of t.partitionCuts||[]){const t=a.get(e.hostId)||[];t.push(e),a.set(e.hostId,t)}for(const e of t.partitions||[]){const s=gl(e.cm,t.cellCm,t.gridPitch)/2;for(const t of Mf(e.a,e.b,s,a.get(e.id)||[],i))o.push({body:t,partitionId:e.id})}return{rooms:s,boundaries:o,epsilon:i}}function Df(t,e,i,s){const n=t.profile.offsets[e];if(!(n>0))return null;const o=function(t,e){const i=t[e],s=t[(e+1)%t.length],n=s[0]-i[0],o=s[1]-i[1],a=Math.hypot(n,o)||1;return function(t){let e=0;for(let i=0;i=0?[-o/a,n/a]:[o/a,-n/a]}(t.profile.poly,e),a=xf(i.center,o,n),r=[];for(let e=0;es&&$f(i.axis,[l[0]/c,l[1]/c],1e-6)))continue;if(Sf(n,a,i.axis)>s||Sf(o,a,i.axis)>s)continue;const h=wf(kf(n,a),i.axis),d=wf(kf(o,a),i.axis);r.push([Math.min(h,d),Math.max(h,d)])}const l=function(t,e){t.sort((t,e)=>t[0]-e[0]||t[1]-e[1]);const i=[];for(const s of t){const t=i[i.length-1];!t||s[0]>t[1]+e?i.push([...s]):t[1]=Math.max(t[1],s[1])}return i}(r,s).find(([t,e])=>t<=s&&e>=-s);if(!l)return null;const[c,h]=l,d=xf(a,i.axis,-i.half),p=xf(a,i.axis,i.half),u=Math.max(0,-i.half-c),_=Math.max(0,h-i.half),m=u>0?xf(a,i.axis,c):d,g=_>0?xf(a,i.axis,h):p,f=wf(o,i.normal)>=0?1:-1,v=(e,s,n)=>({from:e,to:s,label:[(e[0]+s[0])/2,(e[1]+s[1])/2],axis:i.axis,labelNormal:o,distance:n,roomId:t.roomId,roomSide:f,source:"room-face"});return{left:v(d,m,u),right:v(p,g,_)}}function Pf(t){const e=xf(t.center,t.axis,-t.half),i=xf(t.center,t.axis,t.half),s=xf(t.center,t.axis,Math.min(-t.half,t.targetLo)),n=xf(t.center,t.axis,Math.max(t.half,t.targetHi)),o=(e,i)=>({from:e,to:i,label:[(e[0]+i[0])/2,(e[1]+i[1])/2],axis:t.axis,labelNormal:t.normal,distance:Math.hypot(i[0]-e[0],i[1]-e[1]),source:"host-end"});return[o(e,s),o(i,n)]}function Tf(t,e,i,s){const n=kf(i,e),o=wf(n,n);if(!(o>s*s))return Math.hypot(...kf(t,e))<=s;const a=wf(kf(t,e),n)/o;if(a<-s||a>1+s)return!1;const r=xf(e,n,Math.max(0,Math.min(1,a)));return Math.hypot(...kf(t,r))<=s}function Rf(t,e,i){let s=!1;for(let n=0,o=e.length-1;nt[1]!=c>t[1]&&t[0]<(l-a)*(t[1]-r)/(c-r)+a&&(s=!s)}return s}function If(t,e,i,s,n,o){const a=kf(s,i),r=bf(e,a);if(Math.abs(r)<=o)return null;const l=kf(i,t),c=bf(l,a)/r,h=bf(l,e)/r;return c<-o||c>n+o||h<-o||h>1+o?null:Math.max(0,Math.min(n,c))}function Af(t,e,i){const s=Pf(i),n="partition"===t.host?.kind?t.host.id:void 0;return[{base:s[0],direction:[-i.axis[0],-i.axis[1]]},{base:s[1],direction:i.axis}].map(({base:t,direction:i})=>{const s=t.distance,o=function(t,e,i,s,n,o){let a=null;for(const r of s)if(!n||r.partitionId!==n){if(Rf(t,r.body,o))return 0;for(let s=0;swf(kf(t,n),i));return{center:n,axis:i,normal:s,half:Math.max(0,t.renderedLength)/2,targetLo:Math.min(...o),targetHi:Math.max(...o)}}(t),s=e.rooms.flatMap(t=>{const s=function(t,e,i){const{profile:s}=t;let n=null;for(let t=0;t0))continue;const o=s.poly[t],a=s.poly[(t+1)%s.poly.length],r=kf(a,o),l=Math.hypot(r[0],r[1]);if(!(l>i&&$f(e.axis,[r[0]/l,r[1]/l],1e-6)))continue;if(Sf(o,e.center,e.axis)>i||Sf(a,e.center,e.axis)>i)continue;const c=wf(kf(o,e.center),e.axis),h=wf(kf(a,e.center),e.axis),d=Math.min(c,h),p=Math.max(c,h);if(d>-e.half+i||p0?d:p<0?-p:0);(!n||u2)return Pf(i);if(s.length){const t=s.map(({room:t,edge:s})=>Df(t,s,i,e.epsilon));if(t.some(t=>!t))return Pf(i);const n=t;return[...n.map(t=>t.left),...n.map(t=>t.right)]}return Af(t,e,i)}function Ff(t){return!(!t.canEdit||t.kiosk||t.fixedFloor)&&("view"!==t.mode&&("mouse"===t.pointerType&&t.spaceCount>1))}const Ef="1.68.0-beta.3",Nf={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon"},Of={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon"},Lf=2e3,Hf=1e3,Bf=1500,qf=t=>{const e=String(t??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e))return null;const i=Number(e);return Number.isFinite(i)?i:null},Wf=(t,e)=>{if(!t.has(e))return{hit:!1};const i=t.get(e);return t.delete(e),t.set(e,i),{hit:!0,value:i}},jf=(t,e,i,s)=>{for(t.delete(e),t.set(e,i);t.size>s;){const e=t.keys().next().value;if(void 0===e)break;t.delete(e)}},Uf=new Map;let Gf=0;const Vf=t=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(t??{})}`;let Kf=1e4;const Yf="houseplan_card_layout_v1",Jf="houseplan_card_cfg_v1",Xf="houseplan_card_zoom_v1",Zf="houseplan_card_nav_v1",Qf="houseplan_card_kiosk_v1",tv="houseplan_card_view_v1",ev="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",iv=1e3,sv=[[0,1],[45,.88],[70,.62],[86,.32],[100,0]],nv=(t,e)=>{const i=Math.min(t.x,e.x),s=Math.min(t.y,e.y);return{x:i,y:s,w:Math.max(t.x+t.w,e.x+e.w)-i,h:Math.max(t.y+t.h,e.y+e.h)-s}},ov=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),av=2e3,rv=(t,e,i)=>{const s=new Event(e,{bubbles:!0,composed:!0});s.detail=i??{},t.dispatchEvent(s)},lv=t=>{history.pushState(null,"",t),rv(window,"location-changed",{replace:!1})},cv=(t,e)=>{let i,s=null;const n=(...n)=>{clearTimeout(i),s=n,i=window.setTimeout(()=>{i=void 0;const e=s;s=null,e&&t(...e)},e)};return n.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const e=s;s=null,e&&t(...e)},n.cancel=()=>{clearTimeout(i),i=void 0,s=null},n.pending=()=>void 0!==i,n},hv=t=>{try{t.target?.setPointerCapture?.(t.pointerId)}catch{}};class dv extends ht{constructor(){super(...arguments),this._space="f1",this._layout={},this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._serverCfg=null,this._cfgRev=0,this._cfgContentFingerprint="",this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._layoutRev=0,this._layoutContentFingerprint="",this._virtualLights=mn(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._tip=null,this._hoverRoom=null,this._pointerModality=new E_(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...Rr},this._decorDraft=null,this._decorMove=null,this._decorSel=null,this._decorEraseConfirm=null,this._decorTextDialog=null,this._decorShapeDialog=null,this._backdropDialog=null,this._decorTextSelection={start:0,end:0},this._furnPalette=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=t=>{this._reducedMotion=t.matches,this._cancelDevicePressFeedback(),t.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:t.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new Pg({frame:t=>this._applyModeTransitionFrame(t),settled:t=>this._settleModeTransition(t)}),this._editorSecondary=new q_({root:()=>this.renderRoot,requestUpdate:()=>this.requestUpdate(),updateComplete:()=>this.updateComplete,clearTip:()=>{this._tip=null}}),this._editorSecondaryCopy={groupActive:(t,e)=>this._t("editor.group_active",{group:t,item:e}),openGroup:t=>this._t("editor.open_group",{group:t}),disabledAction:(t,e)=>this._t("editor.disabled_action",{action:t,reason:e})},this._tool="draw",this._geometryHistory=new gg(50),this._wallDialog=null,this._drawWallField=null,this._activeDraftId=null,this._resumeDraftBySpace={},this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCache=null,this._isoGeometryCache=new Map,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._glowClipCache=new Map,this._glowGeometryWarnings=new Set,this._lightBarrierCache=null,this._glowFeatherUnits=null,this._glowRenderedSources=new Map,this._glowLastAppearance=new Map,this._glowEnteringSources=new Set,this._glowEnterRafs=new Map,this._glowFadeTimers=new Map,this._glowFeatherSuspendUntil=0,this._glowFeatherResumeTimer=0,this._glowSourceSeq=0,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszSel=null,this._rszDrag=null,this._rszEligibilityCache=null,this._rszPreview=null,this._rszLive=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._suppressClick=!1,this._touchContacts=new Map,this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:t=>this._guardTouchGesture(t)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._alignDialog=null,this._settingsDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=t=>this._onKey(t),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++Gf,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=t=>{if(this._continuity.visibility(t),this._dayCycleVisibility(t),"hidden"===t.kind)return this._clearTransientHover(!0),this._cancelDevicePressFeedback(),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,!t.long){const t=Date.now();let e=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+R_)>t||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,e=!0);return void(e&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._lastTap=0,this._onLabsSnapshot=t=>{const e=this._effectiveProjection();this._labs=t;const i=this._effectiveProjection();this._convertProjectionView(e,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const t=this._hashSpace();if(t&&this._model.find(e=>e.id===t)&&t!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(t),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._onHaRegistryUpdate=()=>{const t=An(this.hass);t.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=t.revision,this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,function(t){const e=Cn(t);e&&(Tn(t,e),Rn(t,e))}(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new xd(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=cv(()=>{if(this._serverStorage){const t=[...this._dirtyPos];this._dirtyPos.clear();for(const e of t){const t=ol(this._layout[e]);t&&(this._layout={...this._layout,[e]:t},this._sentPos.set(e,t),this.hass.callWS({type:"houseplan/layout/update",device_id:e,pos:t}).then(t=>this._noteLayoutRev(t)).catch(t=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))).finally(()=>{this._sentPos.get(e)===t&&this._sentPos.delete(e)}))}this._cacheSnapshot()}else this._layout=al(Gr(this._layout)),localStorage.setItem(Yf,JSON.stringify(this._layout))},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>{if(this._physicalDrag||this._physicalRotate)return void this._cancelPhysicalGesture();if(this._decorDraft)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove||this._dtDrag||this._bdDrag)return void this._cancelDecorGesture();if(this._rszDrag)return void this._rszCancelDrag();const t=this._geometryHistory.undo();t&&(this._applyGeometryState(t.before,!0)?this._showToast(this._t("history.undone",{name:t.name})):this._geometryHistory.clear())},this._redoGeometry=()=>{if(this._physicalDrag||this._physicalRotate)return void this._cancelPhysicalGesture();if(this._decorDraft)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove||this._dtDrag||this._bdDrag)return void this._cancelDecorGesture();if(this._rszDrag)return void this._rszCancelDrag();const t=this._geometryHistory.redo();t&&(this._applyGeometryState(t.after,!0)?this._showToast(this._t("history.redone",{name:t.name})):this._geometryHistory.clear())},this._saveConfigDebounced=cv(()=>{this._serverCfg&&this._writeConfig().catch(t=>{const e=!0===t?.physicalGeometryRolledBack;"geometry-unsafe"!==t?.code&&("wall_model_client_outdated"===t?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===t?.code?(this._showToast(this._t("toast.conflict")),e||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(t)})),e&&this._reloadRejectedPhysicalWrite())})},500),this._draftSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>{const t=this._physicalDialog,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=qf(t.cm);if(null==s)return void this._showPhysicalRange("column"===t.kind?Wc:100,"column"===t.kind?1:0);const n=this._imperial?2.54*s:s,o="column"===t.kind?Wc:100,a="column"===t.kind?1:0;if(!Number.isFinite(n)||no)return void this._showPhysicalRange(o,a);if("column"===t.kind){const e=i.wall_columns.find(e=>e.id===t.id);if(!e)return;const s=qf(t.angle||"0");if("circle"!==t.shape&&(null==s||s<0||s>=90))return void this._showToast(this._t("toast.physical_angle"));const o="circle"===t.shape?{id:t.id,shape:"circle",center:e.center,cm:n}:{id:t.id,shape:"square",center:e.center,cm:n,angle:s};if(i.wall_columns.some(e=>e.id!==t.id&&ph(e,o,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"))}const r=this._geometrySnapshot();if("partition"===t.kind){const i=(e.partitions||[]).find(e=>e.id===t.id);if(i&&0===n&&g_(e.openings,{kind:"partition",id:t.id}))return void this._showToast(this._t("toast.zero_wall_opening_conflict"));i&&(i.cm=n)}else if("column"===t.kind){const i=(e.wall_columns||[]).find(e=>e.id===t.id);i&&(i.cm=Uc(n),i.shape="circle"===t.shape?"circle":"square","square"===i.shape?i.angle=qf(t.angle||"0"):delete i.angle)}else{const i=(e.room_drafts||[]).find(e=>e.id===t.id);i?.segments?.[t.segment||0]&&(i.segments[t.segment||0].cm=n)}const l=this._commitPhysicalGeometry(this._t("history.physical_edit"),r);this._physicalDialog=null,l||this.requestUpdate()},this._deletePhysicalSelection=()=>{const t=this._physicalSel,e=this._curSpaceCfg;if(!t||!e)return;if("draft"===t.kind)return void this._deleteDraftWhole();const i=this._geometrySnapshot();if("partition"===t.kind){const i=(e.openings||[]).filter(e=>"partition"===e.host?.kind&&e.host.id===t.id).sort((t,e)=>(t.host?.t||0)-(e.host?.t||0));if(i.length)return void(this._partitionDeleteDialog={id:t.id,openings:i.map(t=>JSON.parse(JSON.stringify(t)))})}const s="partition"===t.kind?"partitions":"column"===t.kind?"wall_columns":"room_drafts";e[s]=(e[s]||[]).filter(e=>e.id!==t.id),e[s].length||delete e[s],this._activeDraftId===t.id&&this._cancelPath(),this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._confirmPartitionDelete=()=>{const t=this._partitionDeleteDialog,e=this._curSpaceCfg;if(!t||!e)return;const i=this._geometrySnapshot();e.partitions=(e.partitions||[]).filter(e=>e.id!==t.id),e.partitions.length||delete e.partitions,e.openings=(e.openings||[]).filter(e=>"partition"!==e.host?.kind||e.host.id!==t.id),e.openings.length||delete e.openings,this._partitionDeleteDialog=null,this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._deleteDraftWhole=()=>{const t="draft"===this._physicalDialog?.kind?this._physicalDialog.id:"draft"===this._physicalSel?.kind?this._physicalSel.id:null,e=this._curSpaceCfg;if(!t||!e||!confirm(this._t("confirm.delete_draft")))return;const i=this._geometrySnapshot();e.room_drafts=(e.room_drafts||[]).filter(e=>e.id!==t),e.room_drafts.length||delete e.room_drafts,this._activeDraftId===t&&this._cancelPath(),this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._deleteDraftSegment=()=>{const t=this._physicalDialog,e=this._curSpaceCfg;if(!t||"draft"!==t.kind||!e)return;if(!confirm(this._t("confirm.delete_draft_segment")))return;const i=(e.room_drafts||[]).findIndex(e=>e.id===t.id);if(i<0)return;const s=e.room_drafts[i],n=Math.max(0,Math.min(s.segments.length-1,t.segment||0)),o=[],a=s.points.slice(0,n+1),r=s.points.slice(n+1);if(a.length>=2&&o.push({id:s.id,points:a,segments:s.segments.slice(0,n)}),r.length>=2&&o.push({id:o.length?`${s.id}-${Date.now().toString(36)}`:s.id,points:r,segments:s.segments.slice(n+1)}),2===o.length&&e.room_drafts.length>=200)return void this._showToast(this._t("toast.physical_limit"));const l=this._geometrySnapshot();e.room_drafts.splice(i,1,...o),e.room_drafts.length||delete e.room_drafts,this._activeDraftId===s.id&&this._cancelPath(),this._physicalDialog=null,this._physicalSel=o.length?{kind:"draft",id:o[0].id}:null,this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),l)},this._confirmRoomDelete=t=>{const e=this._roomDeleteDialog,i=this._curSpaceCfg,s=this._spaceModel();if(!e||!i||!s)return;const n=s.rooms.find(t=>t.id===e.roomId);if(!n)return void(this._roomDeleteDialog=null);const o=this._openCuts(),a=xu(dc(s.rooms,this._spaceWalls,o,this._wallKeyPitch,this._cellCm,this._gridPitch,iv).filter(t=>t.roomId===n.id),s.partitions,this._openingsR.map(t=>({...t,x:t.rx,y:t.ry})),.02*this._gridPitch),r=new Set(a.materialize.filter(t=>!t.reusePartitionId).map(t=>t.interval.key)).size;if(t&&(i.partitions||[]).length+r>av)return void this._showToast(this._t("toast.physical_limit"));const l=this._geometrySnapshot(),c=pc(s.rooms,this._spaceWalls,o,this._wallKeyPitch,this._cellCm,this._gridPitch,iv);if(t){i.partitions||=[];const t=new Map,e=new Map,s=t=>{const e=(i.wall_segments||[]).find(e=>{const i=[Number(e.a?.[0])*iv,Number(e.a?.[1])*iv],s=[Number(e.b?.[0])*iv,Number(e.b?.[1])*iv];return this._samePt(t.a,i)&&this._samePt(t.b,s)||this._samePt(t.a,s)&&this._samePt(t.b,i)});return"string"==typeof e?.id&&e.id?e.id:null},n=Date.now().toString(36);for(const o of a.materialize){let a=o.reusePartitionId?i.partitions.find(t=>t.id===o.reusePartitionId):e.get(o.interval.key);a||(a={id:s(o.interval)||`partition-room-${n}-${e.size}`,a:[o.interval.a[0]/iv,o.interval.a[1]/iv],b:[o.interval.b[0]/iv,o.interval.b[1]/iv],cm:o.interval.cm},i.partitions.push(a),e.set(o.interval.key,a)),t.set(o.interval.key,a)}for(const e of i.openings||[]){const i=a.openingIntervals.get(e.id),s=i?t.get(i):null,n=this._openingsR.find(t=>t.id===e.id);if(!s||!n)continue;const o={a:[s.a[0]*iv,s.a[1]*iv],b:[s.b[0]*iv,s.b[1]*iv]};e.host={kind:"partition",id:s.id,t:$u([n.rx,n.ry],o)}}}else if(a.removeOpeningIds.length){const t=new Set(a.removeOpeningIds);i.openings=(i.openings||[]).filter(e=>!t.has(e.id)),i.openings.length||delete i.openings}i.rooms=i.rooms.filter(t=>t.id!==n.id),this._cfgEpoch++;const h=this._normalizeWalls(c,this._openCuts());h.length?i.walls=h:delete i.walls,this._roomDeleteDialog=null,this._commitPhysicalGeometry(this._t(t?"history.delete_room_keep_walls":"history.delete_room_with_walls"),l),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()},this._rebindPartitionOpening=()=>{const t=this._openingDialog;if(!t?.id)return;const e=t.id;this._activateMarkupTool("opening"),"opening"===this._tool&&(this._openingRebindId=e,this._openingPreset={type:t.type,lengthCm:t.lengthCm,flipH:t.flipH,flipV:t.flipV,revision:++this._openingPresetRevision},this._openingDialog=null,this._openingHoverCandidate=null)},this._keepClosedAsPartitions=()=>{if(this._wallFaceBatch)return void this._decideWallFace(!1);if(!this._contourClosed||this._pendingSplit||!this._curSpaceCfg)return;const t=this._curSpaceCfg,e=this._path.slice(0,-1);if((t.partitions||[]).length+e.length>av)return void this._showToast(this._t("toast.physical_limit"));const i=this._geometrySnapshot(),s=Jp(e.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll);t.partitions||=[];const n=Date.now().toString(36),o=this._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this._activeDraftId):null,a=this._draftSegmentsForPath(this._path,o,s);for(let i=0;it.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this._t("history.contour_to_partitions"),i),this._roomDialog=!1,this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null},this._toggleServerPlans=async()=>{const t=this._spaceDialog;if(t)if(t.pickSaved)this._spaceDialog={...t,pickSaved:!1};else{this._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.hass.callWS({type:"houseplan/plans/list"}),e=this._spaceDialog;e&&(this._spaceDialog={...e,saved:t?.plans||[],savedBusy:!1})}catch(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,saved:[],savedBusy:!1}),this._showToast(this._t("toast.plans_list_failed",{err:this._errText(t)}))}}},this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const t=this._dayCycleState();if(!t)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const e=mr(t);e!==this._dayCycleClockKey&&(this._dayCycleClockKey=e,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(!this._norm)return;const t=this._glowRadiusCm,e=this._imperial?Math.round(t/30.48*10)/10:Math.round(t)/100;this._settingsDialog={colors:JSON.parse(JSON.stringify(this._fillColors)),glowRadius:e,bgColor:hs(this._settings,{bgColor:null})||null,northDeg:$r(this._settings,{}),bgMode:Sr(this._settings,{}),sunRays:Mr(this._settings,{}),busy:!1}},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._previewAlignDialog(!1),this._toggleOptimizeLivePositions=()=>{const t=this._alignDialog;t&&!t.busy&&t.report.liveMissingPositions.length&&this._previewAlignDialog(!t.removeLiveMissingPositions)},this._optimizeUndoBusy=!1,this._openBackupExport=()=>{this._settingsDialog=null,this._backupExportDialog={kind:"full",planOnly:!1,busy:!1,error:""}},this._openRulesDialog=()=>{if(!this._norm)return;const t=this._settings.icon_rules,e=(t&&t.length?t:Jt).map(t=>({...t}));this._rulesDialog={rules:e,test:"",busy:!1}},this._climateCache=null,this._gearPtCache=new WeakMap}get _canEdit(){return!!this._norm&&(!0===this._serverCanWrite||!1!==this._serverCanWrite&&!0===this.hass?.user?.is_admin)}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}_cssColor(t,e){const i=String(t||"").trim();if(!i)return e;const s=document.createElement("span");s.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(s);const n=getComputedStyle(s).color||e;return s.remove(),n}_currentModeVisual(t=this._mode){const e=this._modeTransition.presented||this._modeTransitionVisual;if(e)return{...e,viewport:{...e.viewport,viewBox:{...e.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const s=this.renderRoot.querySelector(".editorchrome"),n=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),a=this.renderRoot.querySelector(".hp-backdrop"),r=this.renderRoot.querySelector(".zoomwrap"),l=r?getComputedStyle(r).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:t,editorChromeHeight:"view"===t?0:s?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:$g(n,i.clientWidth),stageColor:getComputedStyle(i).backgroundColor||"rgb(255, 255, 255)",paperColor:o?getComputedStyle(o).fill:"rgb(255, 255, 255)",sceneBrightness:Number.isFinite(c)?c:1,architectureOpacity:"decor"===t?.35:1,backdropOpacity:a&&Number(getComputedStyle(a).opacity)||1,viewWeight:"view"===t?1:0,editorWeight:"view"===t?0:1,toolbarContentOpacity:"view"===t?0:1}}_viewForModeTarget(t,e,i,s,n){const o=Ni(this._baseVb(),s/Math.max(1,n)),a=Math.min(dv.ZOOM_MAX,Math.max(dv.ZOOM_MIN,t)),r=o.w/a,l=o.h/a,c=e??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-r/2,y:h-l/2,w:r,h:l},o)}_targetStageColor(t){return"view"!==t?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(t){return"view"===t&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(t){return 1}_applyModeTransitionFrame(t){t.targetMode===this._mode&&(this._modeTransitionVisual=t.presented,this._view={...t.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(t){if(t.targetMode!==this._mode)return;const e=this._modeTransitionRequest;this._view={...t.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[t.to.stageWidth,t.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._modeTransitionBusy||t.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-t.to.stageWidth)>.5||Math.abs(i.clientHeight-t.to.stageHeight)>.5)){const t=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,t?t.x+t.w/2:void 0,t?t.y+t.h/2:void 0),this.requestUpdate()}const s=this.renderRoot.activeElement;(!s||!s.isConnected||!!s.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(t=!0){const e=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(t),t&&e||(this._modeTransitionVisual=null)}_adoptMode(t){this._cancelModeTransition(!1),this._mode=t,"view"!==t&&(this._editorChromeMode=t)}_commitViewModeAtomic(t,e,i,s){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=e,t){const n=this._stageEl?.clientWidth||t.stageWidth,o=Math.max(1,t.stageHeight+t.editorChromeHeight);this._view=this._viewForModeTarget(e,i,s,n,o),this._lastValidStageSize=[n,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(t,e,i,s,n,o){this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._mode!==i)return void(t===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const a=this.renderRoot.querySelector(".editorchrome"),r=a?.querySelector(".editorchrome-inner"),l="view"===i?0:r?.scrollHeight||r?.getBoundingClientRect().height||0,c=Math.max(1,e.stageHeight+e.editorChromeHeight),h=Math.max(1,c-l),d=this._stageEl?.clientWidth||e.stageWidth;if(d<=0||h<=0)return this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._applyView(s,n,o),void this.requestUpdate();const p=this._viewForModeTarget(s,n,o,d,h),u={presentedMode:i,editorChromeHeight:l,stageWidth:d,stageHeight:h,viewport:$g(p,d),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const _=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(e,u,i,this._reducedMotion||_?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(t=this._model,e=this._loadOk){const i=this._config?.floor,s=function(t){if(!t.hasFloor)return{kind:"absent"};const e=t.floor;if("string"==typeof e)return e.length?t.spaceIds.includes(e)?{kind:"valid",id:e,source:"id"}:{kind:"invalid",reason:"unknown-id",value:e}:{kind:"invalid",reason:"empty-id",value:e};if("number"==typeof e){if(!Number.isFinite(e))return{kind:"invalid",reason:"non-finite-index",value:e};if(!Number.isInteger(e))return{kind:"invalid",reason:"fractional-index",value:e};if(e<0)return{kind:"invalid",reason:"negative-index",value:e};const i=t.spaceIds[e];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:e}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:e}}({spaceIds:t.map(t=>t.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||e?s:"number"==typeof i?"valid"===s.kind||"invalid"===s.kind&&"out-of-range-index"===s.reason?{kind:"pending",value:i}:s:"valid"===s.kind||"invalid"===s.kind&&"unknown-id"!==s.reason?s:{kind:"pending",value:i}}_canCommitSpace(t,e=!1){if(e||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===t}_commitSpace(t,e=!1){return!!this._canCommitSpace(t,e)&&(t!==this._space&&(this._clearTransientHover(!0),this._cancelDevicePressFeedback()),this._space=t,!0)}_slideTo(t,e){if(t===this._space)return!0;if(!this._canCommitSpace(t))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(t),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),i||(this._slide=e,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return Ff({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(t,e){Ff({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:t.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(hv(t),this._tabDragRelease=t=>this._tabPointerUp(t),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:e,pointerId:t.pointerId,x:t.clientX,y:t.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(t,e,i){const s=this._model.map(t=>t.id),n=s.indexOf(i);if(n<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const a of o){const o=a.dataset.id||"";if(!o||o===i)continue;const r=a.getBoundingClientRect();if(tr.right||er.bottom)continue;const l=s.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,s;const n=this._tabDropTargetAt(t.clientX,t.clientY,e.id);e.moved&&e.targetId===n?.targetId&&e.placement===n?.placement||(this._tabDrag={...e,moved:!0,targetId:n?.targetId||null,placement:n?.placement||null})}_tabPointerUp(t){const e=this._tabDrag;if(e&&e.pointerId!==t.pointerId)return;const i="pointerup"===t.type&&e?.moved?this._tabDropTargetAt(t.clientX,t.clientY,e.id):null;"pointerup"===t.type&&e?.moved&&this._suppressNextTabClick(),this._endTabDrag(),e?.moved&&i&&this._commitTabOrder(e.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(t){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(t)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(t,e){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const s=this._model.map(t=>t.id),n=function(t,e,i){const s=t.indexOf(e),n=t.indexOf(i);if(s<0||n<0||s===n)return t;const o=t.slice();return o.splice(s,1),o.splice(n,0,e),o}(s,t,e);if(n===s)return;const o=new Map(this._devices.map(t=>[String(t.id),String(t.area||"")])),a=function(t,e,i,s=()=>""){if(!i)return[];const n=[];for(const o of t){if(!o||!0===o.removed)continue;const t="string"==typeof o.id?o.id:"";if(!t)continue;if("string"==typeof o.space&&o.space)continue;const a=("string"==typeof o.area?o.area:"")||s(t)||"";a&&e[a]||n.push({id:t,space:i})}return n}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),s[0]||"",t=>o.get(t)||"");if(a.length){const t=new Map(a.map(t=>[t.id,t.space]));for(const e of i.markers||[]){const i=t.get(String(e.id));i&&(e.space=i)}}i.spaces=function(t,e){const i=new Map(e.map((t,e)=>[t,e]));return t.map((t,e)=>({space:t,index:e})).sort((t,e)=>(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)||t.index-e.index).map(t=>t.space)}(i.spaces||[],n),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(t){if(this._endTabDrag(),t===this._space)return;const e=this._model.map(t=>t.id),i=e.indexOf(this._space),s=e.indexOf(t);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(t,i>=0&&s0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const t=this._model.map(t=>t.id),e=t.indexOf(this._space);this._slideTo(t[(e+1)%t.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}_newContinuityController(){return new yd(()=>{this._resumeSettling="steady"!==this._continuity.state,this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}get _labsIso(){return this._labs.active.includes("iso")}get _desiredProjection(){return"view"===this._mode&&this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat"}_saveViewPreference(){try{localStorage.setItem(tv,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(t){const e=this._view;if(!e)return null;const i=[e.x+e.w/2,e.y+e.h/2],s="iso"===t?Xg(i):i;return{x:s[0],y:s[1]}}_convertProjectionView(t,e){if(t===e)return;const i=this._logicalViewCenter(t);this._view=null;const s=i?"iso"===e?Jg([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,s?.[0],s?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(t){if(!this._labsIso||"view"!==this._mode)return;const e=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:t},"iso"===t){const t=this._isoSceneKey();t&&this._isoFallback.delete(t)}this._saveViewPreference();const i=this._effectiveProjection();this._convertProjectionView(e,i)}_hashSpace(){return Ng(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const t=(e=this.ownerDocument,fg.get(e)?.resolved);var e;void 0!==t&&(this._glowScreenBlend=t),this._continuityUnsub?.(),this._continuityUnsub=fd(this.ownerDocument,this._pageVisibility),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(t=>{for(const e of t)for(const t of e.addedNodes)this._syncPointerHoverSubtree(t)}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),function(t){const e=fg.get(t);if(e)return e.promise;const i={promise:Promise.resolve(!1)};return i.promise=yg(t).catch(()=>!1).then(t=>(i.resolved=t,t)),fg.set(t,i),i.promise}(this.ownerDocument).then(t=>{t!==this._glowScreenBlend&&(this._glowScreenBlend=t,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>Is(this._serverCfg)),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(t,e){jg.add(e);const i=Vg(t);return"undefined"==typeof window&&e(i),()=>{jg.delete(e)}}(Ef,this._onLabsSnapshot),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Bf)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._vacRaf&&(cancelAnimationFrame(this._vacRaf),this._vacRaf=0),this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const t of this._activityRt.values())clearTimeout(t.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),this._modeTransition.dispose(),this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer);for(const t of this._glowFadeTimers.values())clearTimeout(t);for(const t of this._glowEnterRafs.values())cancelAnimationFrame(t);clearTimeout(this._glowFeatherResumeTimer),this._glowFeatherResumeTimer=0,this._glowFeatherSuspendUntil=0,this._glowFadeTimers.clear(),this._glowEnterRafs.clear(),this._glowEnteringSources.clear(),this._glowRenderedSources.clear(),this._glowLastAppearance.clear(),this._glowSourceSeq=0,this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._touchContacts.clear(),this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(t){if("Escape"===t.key&&this._vacFit)return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void t.stopPropagation();if("Escape"===t.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm=null);if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._settingsDialog)return void(this._settingsDialog=null);if(this._markerDialog)return void(this._markerDialog=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary.hasOpenGroup)return t.preventDefault(),void this._editorSecondary.closeGroup(!0)}const e=t.composedPath?.()||[t.target],i=e.some(t=>t?.matches?.('input, textarea, select, [contenteditable="true"]')),s=e.some(t=>t?.classList?.contains?.("editor-secondary")),n=t.ctrlKey||t.metaKey,o=t.key.toLowerCase(),a=/^[a-z]$/.test(o),r="z"===o||!a&&"KeyZ"===t.code,l="y"===o||!a&&"KeyY"===t.code,c=n&&(r&&t.shiftKey||l),h=n&&r&&!t.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;return c?(t.preventDefault(),void this._redoGeometry()):h?(t.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry()):"Delete"!==t.key&&"Backspace"!==t.key||!this._decorSel||i||s?void("Escape"===t.key&&(t.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._furnPalette=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(t.preventDefault(),void this._decorDeleteSel())}if(this._markup&&(!h&&!c||!i)){if(("Delete"===t.key||"Backspace"===t.key)&&this._physicalSel&&!i&&!s)return t.preventDefault(),void this._deletePhysicalSelection();if(c)return t.preventDefault(),void this._redoGeometry();if(h)return t.preventDefault(),this._rszDrag?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===t.key)return this._physicalDrag||this._physicalRotate?(t.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(t.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(t.preventDefault(),void this._finishWallChain()):this._physicalSel?(t.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(t.preventDefault(),this._rszDrag?void this._rszCancelDrag():void(this._rszSel?this._rszSel=null:this._tool="draw")):"split"===this._tool?(t.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(t.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(t.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(t.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length){if(this._contourClosed)return this._path=this._path.slice(0,-1),void(this._closingWallCm=null);if(this._activeDraftId&&this._path.length>1&&this._curSpaceCfg){const t=this._geometrySnapshot();this._path=this._path.slice(0,-1),this._draftSegmentCms=this._draftSegmentCms.slice(0,-1);const e=this._curSpaceCfg,i=(e.room_drafts||[]).findIndex(t=>t.id===this._activeDraftId);if(i>=0){const s=Array.isArray(e.room_drafts[i]?.segments)?e.room_drafts[i].segments:[];this._path.length<2?(e.room_drafts.splice(i,1),e.room_drafts.length||delete e.room_drafts,this._activeDraftId=null):e.room_drafts[i]={id:this._activeDraftId,points:this._path.map(t=>[t[0]/iv,t[1]/iv]),segments:this._draftSegmentCms.map((t,e)=>({...s[e]||{},cm:t}))},this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),t)}return}this._path=this._path.slice(0,-1)}}_undoActiveDraftPoint(){const t=this._activeDraftId,e=this._path[0]?[...this._path[0]]:null,i=this._geometryHistory.undo();if(!i)return void this._undoPoint();if(!this._applyGeometryState(i.before,!0))return void this._geometryHistory.clear();const s=t?this._spaceModel()?.room_drafts.find(e=>e.id===t):null;s?(this._activeDraftId=s.id,this._path=s.points.map(t=>[...t]),this._draftSegmentCms=this._adoptDraftCms(this._path,s.segments.map(t=>t.cm),s.id),this._resumeDraftBySpace[this._space]=s.id):(this._activeDraftId=null,this._path=e?[e]:[],this._draftSegmentCms=[],t&&this._resumeDraftBySpace[this._space]===t&&delete this._resumeDraftBySpace[this._space]),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:i.name}))}static getConfigElement(){return document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(t){for(const t of Uf.values())for(const e of t)clearTimeout(e.evict);Uf.clear(),Kf=t&&t>0?t:1e4}static _warmBootStats(){let t=0,e=0;const i=[];for(const s of Uf.values())for(const n of s)t++,n.dlg&&(e++,i.push(n.dlg.kind));return{keys:Uf.size,slots:t,dlgs:e,drafts:i}}setConfig(t){const e=this._config,i=!!e&&Object.prototype.hasOwnProperty.call(e,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...t};(i!==this._hasFixedFloor||e?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&t.default_floor&&this._commitSpace(t.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(Xf)||"{}")||{}}catch{this._zoomBySpace={}}try{const t=JSON.parse(localStorage.getItem(tv)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(t).filter(t=>"flat"===t[1]||"iso"===t[1]))}catch{this._viewPreference={}}this._labs=Vg(Ef);try{const t=JSON.parse(localStorage.getItem(Qf)||"null");this._kioskScale={icon:Es(t?.icon),font:Es(t?.font)}}catch{}try{const t=JSON.parse(localStorage.getItem(Jf)||"null");t&&t.config&&Array.isArray(t.config.spaces)&&(this._serverCfg=t.config,this._cfgEpoch++,this._cfgRev=t.rev||0,this._cfgContentFingerprint=t.config_fingerprint||bd(t.config),this._layout=t.layout||{},this._layoutRev=t.layout_rev||0,this._layoutContentFingerprint=t.layout_fingerprint||bd(this._layout),this._virtualLights=mn(t.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1)}_warmAdopt(){if(this._config?.kiosk)return;const t=Vf(this._config);if(this._warmKey===t&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const e=this.parentNode,i=this._warmIdx(e),s=Uf.get(t);if(!s||!s.length)return;const n=s.find(t=>t.owner===this._warmGen);if(n)return this._warmLongReturn=!!n.freed&&Date.now()-n.freed>=_d,clearTimeout(n.evict),n.evict=0,n.freed=0,n.live=!0,this._warmSlot=n,this._warmKey=t,n.frameFingerprint&&this._continuity.adoptCompleteFrame(n.frameFingerprint),void(!this._devices.length&&n.devices?.length&&(this._devices=[...n.devices]));const{slot:o,sure:a}=((t,e,i,s)=>{const n=t=>{const e=!!i&&t.place?.deref()===i;return e&&t.idx===s?4:t.live?0:e?3:2};let o=null,a=0,r=0,l=null;for(const i of t){if(i.owner===e)continue;l=i;const t=n(i);t<=0||(t>a?(o=i,a=t,r=1):t===a&&r++)}return!o||r>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(s,this._warmGen,e,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=_d,this._booting=!1,this._bootFading=!1,this._hdrH=o.hdrH,this._bootSoft=!0,this.isConnected&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Bf)),this._warmKey=t,a?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=e?new WeakRef(e):null,o.idx=i,o.live=!0,this._warmSlot=o,this._warmVp=o.vp,o.frameFingerprint&&this._continuity.adoptCompleteFrame(o.frameFingerprint),!this._devices.length&&o.devices?.length&&(this._devices=[...o.devices]),this._warmAdoptViewport(this._config)):(this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},s.push(this._warmSlot),this._warmTrim(s)))}_warmIdx(t){const e=t?.children;if(!e)return-1;for(let t=0;t4;){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=Uf.get(e);if(!t.live&&o&&o.length>1){const e=o.indexOf(t);e>=0&&o.splice(e,1)}},Kf+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?Jg([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="opening"===(o=function(t){return"partition"===t?"draw":t}(o=e.tool))?"draw":"string"==typeof o&&ov.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=Vf(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=Uf.get(i)||[];for(s.push(this._warmSlot),Uf.set(i,s),this._warmTrim(s);Uf.size>8;){const t=Uf.keys().next().value;if(void 0===t||t===i)break;for(const e of Uf.get(t)||[])clearTimeout(e.evict);Uf.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>Kf)&&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=bd(this._serverCfg),this._layoutContentFingerprint=bd(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(Jf,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 wd([this._cfgRev,this._cfgContentFingerprint||bd(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||bd(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 G;const t="connection"===this._continuity.recoveryReason;return W`
t.stopPropagation()} @click=${t=>t.stopPropagation()} @@ -4974,8 +4974,8 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t(t?"continuity.restore_connection":"continuity.restore_plan")} ${"recovery-error"===this._continuity.state?W``:G} -
`}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(t=>({...t,...t.stage?{stage:[...t.stage]}:{}}))}getCardSize(){return 12}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const t=this._serverCfg?.spaces||[];let e=t.length+":";for(const i of t){e+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const t of i.rooms||[]){const i=t.poly?.[0],s=t.poly?.[t.poly.length-1];e+=(t.poly?.length||0)+"."+(t.id||"")+"."+(t.open_to||[]).join("+")+"."+(t.area||"")+"."+JSON.stringify(t.settings||0)+"."+(t.x??"")+","+(t.y??"")+","+(t.w??"")+","+(t.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(s?s[0]+"/"+s[1]:"")+";"}}return e}get _model(){if(!this._serverCfg)return[];const t=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===t)return this._modelCache.model;const e=this._buildModel();return this._modelCache={key:t,model:e},e}_buildModel(){if(!this._serverCfg)return[];const t=this._renderCfg;return $h(t).map((e,i)=>{const s=t.spaces[i]?.plan_url;return e.bg&&s?{...e,bg:{...e.bg,href:s}}:e})}_spaceModel(){return this._hasFixedFloor?$d(this._model,this._space):(t=this._model,e=this._space,t.find(t=>t.id===e)??t[0]);var t,e}_spaceModelById(t){return $d(this._model,t)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0;for(const t of this._pointers.keys())for(const e of this.renderRoot.querySelectorAll("*"))try{e.hasPointerCapture?.(t)&&e.releasePointerCapture(t)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._resumeDraftBySpace={},this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const t={};for(const e of this._model)for(const i of e.rooms)i.area&&(t[i.area]={space:e.id,room:i});return t}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._settings.filter_seeded?this._showHidden:!!this._settings.show_all}_toggleShowAll(){if(this._serverCfg){if(this._settings.filter_seeded)return this._showHidden=!this._showHidden,void this.requestUpdate();this._serverCfg={...this._serverCfg,settings:{...this._serverCfg.settings,show_all:!this._settings.show_all}},this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}}_seedHiddenDevices(){if(!this._serverCfg||!this._norm||!this._canEdit)return;const t=this._serverCfg,e=function(t){const e=t.hass,i=t.registry||An(e),s=Nn(e,i),n=On(e,i),{areaToSpace:o,markers:a,settings:r,excluded:l,iconRules:c}=t,h=!1!==r.group_lights,d=wo(a),p=yo(s,h).filter(t=>!ko(s,t.eid,d)),u=new Set(p.map(t=>t.area)),_=qn(s),m=Wn(a,n),g=new Set(a.map(t=>t.binding)),f=[];for(const t of Object.values(s.devices)){const n=t.area_id;if(!n||!o[n])continue;if("service"===t.entry_type)continue;if(g.has("device:"+t.id))continue;if("active"!==Bn(e,"device:"+t.id,i).kind)continue;const a=jn(s,t.id,_[t.id]||[],m);if(a.partial&&!a.entityIds.length)continue;const r=a.entityIds,d=Un(s,t,r);let p=l.has(d)||"Group"===t.model||/scene/i.test(t.model||"")||/bridge/i.test((t.model||"")+(t.name||""))||"myheat"===d&&!!t.via_device_id;if(!p&&h&&u.has(n)){const e=(t.name_by_user||t.name||"").trim();"mdi:lightbulb"===bo(s,e,t.model,r,c)&&(p=!0)}p&&f.push("device:"+t.id)}return f}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!e.length&&t.settings?.filter_seeded)return;t.markers=t.markers||[];const i=[];for(const s of e){const e="h"+s.slice(s.indexOf(":")+1);t.markers.push({id:e,binding:s,hidden:!0}),i.push(s.slice(s.indexOf(":")+1))}const s={...t.settings||{},filter_seeded:!0};delete s.show_all,i.length&&Array.isArray(s.new_device_ids)&&(s.new_device_ids=s.new_device_ids.filter(t=>!i.includes(t))),t.settings=s,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const t=this._settings.icon_rules;if(!t||!Array.isArray(t)||!t.length)return;const e=JSON.stringify(t);return e!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=e,this._rulesCompiled=Xt(t)),this._rulesCompiled}get _fillColors(){return ps(this._settings)}get _excluded(){const t=this._settings.exclude_integrations;return t?new Set(t):Yt}willUpdate(t){t.has("_serverCfg")&&this._cfgEpoch++,this._syncEmptySpaceState(),t.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._planHassMemo=null,this._hookConnection(),!this._loadOk&&!this._loading&&this._loadTries<8&&this._loadFromServer(),this._maybeRebuildDevices(),this._vacTick(),this._activityTick()),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._warmSnapshot(),this._dtMeasure();const t=this._stageEl;t&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>this._refitView()),this._roViewport.observe(t)),t&&this._booting&&!this._bootTimer&&this._bootWatch();const e=this.renderRoot.querySelector(".hdr");if(e&&t&&!this._roHdr){const i=()=>{const e=this.renderRoot.querySelector("ha-card");if(!e)return;const i=t.getBoundingClientRect().top-e.getBoundingClientRect().top,s=Math.min(Math.max(e.getBoundingClientRect().top,0),120),n=Math.round(i+s);n>=0&&n!==this._hdrH&&(this._hdrH=n),n>=0&&!this._booting&&!this._config?.kiosk&&t.clientHeight>0&&this._warmPatch({hdrH:n,stageH:t.clientHeight})};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(e),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(t&&!this._view&&this._refitView(),this._editorSecondary.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const t=function(t){const e=t?.floors;if(!e||"object"!=typeof e)return[];const i=[];for(const t of Object.values(e))t&&t.floor_id&&i.push({id:t.floor_id,name:t.name||t.floor_id,level:t.level??null});return i.sort((t,e)=>{const i=t.level??1e9,s=e.level??1e9;return i!==s?i-s:t.name.localeCompare(e.name)}),i}(this.hass);t.length?this._importDialog={floors:t.map(t=>({...t,checked:!0}))}:this._openSpaceDialog("create")}}_adoptStructuralResponses(t,e,i){const s=t?.config,n=s&&Array.isArray(s.spaces)?s:null,o=bd(n),a=o!==(this._cfgContentFingerprint||bd(this._serverCfg));if(a&&(this._geometryHistory.clear(),this._pendingPhysicalWrites.clear(),this._serverCfg&&this._clearGeometryGesture(),this._serverCfg=n,this._cfgContentFingerprint=o),this._cfgRev=t?.rev??this._cfgRev,t&&("virtual_lights"in t||"config"in t)){const e=gn(this._virtualLights,t.virtual_lights,this._cfgRev,"virtual_lights"in t);vn(e)!==vn(this._virtualLights)&&(this._virtualLights=e,this._capturedSnapshotVirtual="")}let r=!1;if(void 0!==e||void 0!==i){const t=i??e?.layout??{},s=bd(t);r=s!==(this._layoutContentFingerprint||bd(this._layout)),r&&(this._layout=t,this._layoutContentFingerprint=s),this._layoutRev=e?.rev??this._layoutRev}return this._canOptimizeUndo=!(!t?.can_optimize_undo&&!e?.can_optimize_undo),this._haIntegrationVersion="string"==typeof t?.integration_version?t.integration_version:this._haIntegrationVersion,this._undoKind=t?.undo_kind||e?.undo_kind||null,"boolean"==typeof t?.can_write&&(this._serverCanWrite=t.can_write),a&&this._continuity.note("config-candidate",{configRev:this._cfgRev}),r&&this._continuity.note("layout-candidate",{layoutRev:this._layoutRev}),{configChanged:a,layoutChanged:r}}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const t=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(t,!1),!0}async _loadFromServer(){this._loading=!0,this._loadTries++;const t=this._space,e=!!this._view;try{const[i,s]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]),n=i?.config&&Array.isArray(i.config.spaces)?i.config:null,o=bd(n)!==(this._cfgContentFingerprint||bd(this._serverCfg))||bd(s?.layout??{})!==(this._layoutContentFingerprint||bd(this._layout));if(o){if(!await this._signer.prepareImage(this.hass,this._candidateBackdrop(n)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0)}o&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),this._connectionWasLost=!1,this._serverStorage=!0,"boolean"==typeof i?.can_write&&(this._serverCanWrite=i.can_write),this._canOptimizeUndo=!(!i?.can_optimize_undo&&!s?.can_optimize_undo),this._haIntegrationVersion="string"==typeof i?.integration_version?i.integration_version:this._haIntegrationVersion,this._adoptStructuralResponses(i,s),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:e&&this._space===t||this._restoreZoom(),this._loadOk=!0,this.hass.callWS({type:"houseplan/trail/get"}).then(t=>{this._vacSrvTrails=t?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(t){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(Kf)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const t=this.hass?.connection;if(!t)return;if(t!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=t),this._liveSyncAttempt)return;const e=this._liveSyncGeneration,i=[],s=(s,n,o,a)=>{s()||i.push(async()=>{const i=await t.subscribeEvents(a,o);e===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===t&&!s()?n(i):i?.()})};if(s(()=>this._unsubCfg,t=>{this._unsubCfg=t},"houseplan_config_updated",t=>{const e=Number(t?.data?.rev??-1);e!==this._cfgRev&&this._reloadConfigOnly(!1,e)}),s(()=>this._unsubTrail,t=>{this._unsubTrail=t},"houseplan_trail_updated",async()=>{try{const t=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=t?.trails||{},this.requestUpdate()}catch{}}),s(()=>this._unsubLayout,t=>{this._unsubLayout=t},"houseplan_layout_updated",t=>this._onLayoutEvent(Number(t?.data?.rev??-1))),s(()=>this._unsubVirtual,t=>{this._unsubVirtual=t},"houseplan_virtual_light_updated",t=>{const e=wn(this._virtualLights,t?.data);e!==this._virtualLights&&(this._virtualLights=e,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const n=function(t){return Promise.allSettled(t.map(t=>Promise.resolve().then(t)))}(i).then(()=>{});this._liveSyncAttempt=n,n.finally(()=>{this._liveSyncAttempt===n&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(t=!1,e){if(!t){if(void 0!==e&&e<=this._cfgRev)return;if(this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(()=>this._reloadConfigOnly(!1,e),400))}this._beginContinuityCandidate("config-reload",!1);try{const t=await this.hass.callWS({type:"houseplan/config/get"}),e=t?.config&&Array.isArray(t.config.spaces)?t.config:null;if(bd(e)!==(this._cfgContentFingerprint||bd(this._serverCfg))&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(e)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0);const i=this._space;this._adoptStructuralResponses(t),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._space!==i&&this._restoreZoom(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}catch(t){this._showToast(this._t("toast.cfg_reload_failed",{err:this._errText(t)}))}finally{this._continuityDataReady=!0,this.requestUpdate()}}_scheduleLoadRetry(t=!1){if(void 0!==this._loadRetryTimer)return;const e=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!t&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},e)}_ensureHaRegistryAuthority(){const t=this.hass?.connection||null;t&&t!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=t,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._haRegistryRelease=In(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return An(this.hass)}get _planHass(){const t=this._haRegistry,e=Fn(this.hass,t),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===e)return i.active;const s=Nn(this.hass,t),n=On(this.hass,t);return this._planHassMemo={hass:this.hass,sig:e,active:s,full:n},s}_captureRenderDeviceSnapshot(){if(!this.hass)return;const t=Date.now(),e=[...this._activityRt.entries()].map(([e,i])=>`${e}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+R_)>t?1:0)).join("|"),i=vn(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===e)return;const s=this._planHass,n=new Map,o=new Map,a=new Set(["sun.sun"]);this._vacFit?.source&&a.add(this._vacFit.source);const r=new Set,l=new Set,c=t=>{if(!t)return;const e=t.indexOf(":");if(e<0)return void a.add(t);const i=t.slice(0,e),s=t.slice(e+1);"device"===i?r.add(s):"entity"===i&&a.add(s)};for(const t of this._model)for(const e of t.rooms)e.area&&l.add(e.area),c(e.settings?.temp_source),c(e.settings?.hum_source);for(const t of this._serverCfg?.spaces||[])for(const e of t.openings||[])for(const t of gi(e))a.add(t);for(const t of this._serverCfg?.spaces||[])for(const e of t.decor||[])if("text"===e.kind){for(const t of String(e.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const e=Yi(t[1]);e?.entity&&a.add(e.entity)}e.entity&&a.add(e.entity),o.set(`decor:${t.id}:${e.id}`,ts(e.text,e,s,t=>!!s.entities?.[t]&&!!s.states?.[t]&&!ko(s,t,wo(this._markers))))}const h=ho(s,this._devices,null,this._virtualLights);for(const t of this._devices){for(const e of[!1,!0])n.set(n_(t.id,e),t_(s,t,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:e,activityRuntime:this._activityRt.get(t.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(t)){const e=this._vacSource(t,s),i=e?Nd(s?.states?.[e]?.attributes):null,n=this._vacRt.get(t.id);o.set(`vacuum:${t.id}`,{source:e,telemetry:i,mapId:i?this._vacMapId(t,i,s):null,runtime:n?{trail:n.trail,lastTs:n.lastTs,moving:n.moving,jump:n.jump}:null,server:this._vacSrvTrails[t.id]||null})}}const d=s_({sourceSequence:this._hassSequence,hass:s,devices:this._devices,presentations:n,positions:(p=this._model.length>0,u=this._devices,_=t=>this._livePos(t),p?new Map(u.map(t=>[t.id,_(t)])):new Map),facts:o,entityIds:a,deviceIds:r,areaIds:l});var p,u,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=e,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(t){return Bn(this.hass,t,this._haRegistry)}houseplanDiagnostics(){const t=function(t){const e=An(t);return{access:e.access,authoritative:e.authoritative,revision:e.revision,lastSuccess:e.lastSuccess,error:e.error}}(this.hass),e={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const t of this._markers)t.removed||"virtual"===t.binding||e[this._bindingStatus(t.binding).kind]++;return{registry:{...t,lastSuccessAgeMs:t.lastSuccess?Math.max(0,Date.now()-t.lastSuccess):null},bindings:e}}_openBindingInHa(t){const[e,i]=t.split(":");if(i)if("device"!==e){if("entity"===e){const t=this._fullRegistryHass.entities?.[i];t?.device_id&&rv("/config/devices/device/"+encodeURIComponent(t.device_id))}}else rv("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(t){const[e,i]=t.split(":");return!!i&&("device"===e||"entity"===e&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const t=this._markerDialog;if(!t)return;const e="ha"===t.bindingMode?this._bindingStatus(t.binding):null,i=t.hideFromPlan||"ha_disabled"===e?.kind;i&&"ha_disabled"===e?.kind?this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===e?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...t,hideFromPlan:!i}}_hookConnection(){const t=this.hass?.connection;t&&t!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),t.addEventListener?.("ready",this._onConnReady),t.addEventListener?.("disconnected",this._onConnLost),t.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=t)}_display(t){return this._signer.display(this.hass,t)}_resign(){this._signer.resign(this.hass,Is(this._serverCfg))}_onLayoutEvent(t){t<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{t<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(t){const e=t?.rev;"number"==typeof e&&e>this._layoutRev&&(this._layoutRev=e)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const t=new Map;for(const e of this._dirtyPos)this._layout[e]&&t.set(e,this._layout[e]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[e,i]of this._sentPos)t.set(e,i);try{const e=await this.hass.callWS({type:"houseplan/layout/get"}),i={...e?.layout||{}};for(const[e,s]of t)i[e]=s;const s=bd(i);s!==(this._layoutContentFingerprint||bd(this._layout))&&(this._layout=i,this._layoutContentFingerprint=s),this._layoutRev=e?.rev??this._layoutRev,this._canOptimizeUndo=!!e?.can_optimize_undo,this._haIntegrationVersion="string"==typeof e?.integration_version?e.integration_version:this._haIntegrationVersion,this._undoKind=e?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_maybeRebuildDevices(){const t=this.hass;if(!t?.devices||!t?.entities||!t?.areas)return;const e=this._haRegistry,i=Fn(t,e)+":"+Object.keys(t.areas).length+":"+(this._norm?"n":"l")+":"+ra(t,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const s=new Map(this._devices.map(t=>[t.id,t.bindingStatus?.kind||"active"]));this._devices=So({hass:t,registry:e,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:t=>this._t(t),iconRules:this._iconRules});const n=this._markers.filter(t=>!t.removed&&"virtual"!==t.binding).map(t=>t.binding).sort(),o=e.revision+":"+n.join("|");if(e.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const s of n)i.set(s,Bn(t,s,e));!function(t){if("undefined"==typeof localStorage||!t.size)return;const e=Hn(),i=Date.now();for(const[s,n]of t)"active"===n.kind?e[s]={kind:"active",ts:i}:"ha_disabled"===n.kind&&(e[s]={kind:"ha_disabled",reason:n.reason,ts:i});const s=Object.fromEntries(Object.entries(e).sort((t,e)=>e[1].ts-t[1].ts).slice(0,1500));Mn=s;try{localStorage.setItem(Sn,JSON.stringify(s))}catch{}}(i),this._haBindingCacheKey=o}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),this._syncActivityRuntime();const a=new Set(this._devices.filter(t=>!t.hidden).map(t=>t.id));for(const t of this._vacRt.keys())a.has(t)||this._vacRt.delete(t);if(this._infoCard){const t=this._devices.find(t=>t.id===this._infoCard.id);this._infoCard=t&&"ha_disabled"!==t.bindingStatus?.kind?t:null}const r=this._devices.some(t=>"ha_disabled"===t.bindingStatus?.kind&&"ha_disabled"!==s.get(t.id));r&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(t=>t.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._drag&&"ha_disabled"===this._devices.find(t=>t.id===this._drag.id)?.bindingStatus?.kind&&(this._drag=null),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(av(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const t=this._devices.filter(t=>!t.marker&&!t.virtual).map(t=>t.id).sort(),e=t.join(",");if(e===this._newSyncKey)return;this._newSyncKey=e;const i=this._settings,{fresh:s,known:n}=function(t,e){if(!Array.isArray(e))return{fresh:[],known:[...t]};const i=new Set(e),s=t.filter(t=>!i.has(t));return{fresh:s,known:s.length?[...e,...s]:e}}(t,i.known_devices);if(!Array.isArray(i.known_devices)||s.length){const t=[...new Set([...i.new_device_ids||[],...s])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:n,new_device_ids:t}},this._saveConfig()}}get _newIds(){const t=this._settings.new_device_ids;return new Set(Array.isArray(t)?t:[])}_ackNewDevice(t){if(!this._newIds.has(t)||!this._serverCfg)return;const e=this._settings;this._serverCfg={...this._serverCfg,settings:{...e,new_device_ids:(e.new_device_ids||[]).filter(e=>e!==t)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(t){if(!t)return null;const e=[];for(const i of this._renderDevices){if(i.area!==t||i.virtual)continue;const s=_o(this._renderPlanHass,i.entities);null!=s&&e.push(s)}return Ei(e)}_roomBounds(t){if(t.poly&&t.poly.length){const e=t.poly.map(t=>t[0]),i=t.poly.map(t=>t[1]),s=Math.min(...e),n=Math.min(...i);return{x:s,y:n,w:Math.max(...e)-s,h:Math.max(...i)-n}}return{x:t.x??0,y:t.y??0,w:t.w??0,h:t.h??0}}_defaultPositions(){const t={},e=this._config?.icon_size??2.5;for(const i of this._model){const s=e/100*Uh(i)*1.3;for(const e of i.rooms){if(!e.area)continue;const n=this._devices.filter(t=>t.area===e.area&&t.space===i.id);if(!n.length)continue;const o=this._roomBounds(e),a=.1*Math.min(o.w,o.h),r=o.w-2*a,l=o.h-2*a,c=Math.max(1,Math.round(Math.sqrt(n.length*r/Math.max(l,1)))),h=Math.ceil(n.length/c),d=r/c,p=l/Math.max(h,1),u=n.map((t,e)=>({x:o.x+a+d*(e%c+.5),y:o.y+a+p*(Math.floor(e/c)+.5)}));Oi(u,o,s,.5*a),n.forEach((e,i)=>t[e.id]=Rh(u[i]))}}return t}_pos(t){const e=this._renderDeviceSnapshot?.positions.get(t.id);return e?{x:e.x,y:e.y}:this._livePos(t)}_livePos(t){const e=this._spaceModelById(t.space),i=this._layout[t.id];if(i)if(this._norm){if(i.s===t.space)return{x:i.x*ev,y:i.y*ev}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[t.id]?this._defPos[t.id]:e?Rh(jh(e)):{x:500,y:500}}_savePos(t,e,i){if(this._spaceModelById(t.space)){if(this._norm){const s=this._gridPitch,n=Math.round(e/s)*s,o=Math.round(i/s)*s,a=this._layout[t.id]?.k;this._layout={...this._layout,[t.id]:{s:t.space,x:Ah(n/ev),y:Ah(o/ev),...a?{k:a}:{}}}}else this._layout={...this._layout,[t.id]:{x:Math.round(e),y:Math.round(i)}};this._dirtyPos.add(t.id),this._persistLayout()}}_visualSamples(t){return Yu(this._renderPlanHass,t,this._renderDevices,void 0,this._fullRegistryHass).samples}_devicePresentation(t,e=!1!==this._config?.show_signal,i=!1){const s=i?null:this._renderDeviceSnapshot?.presentations.get(n_(t.id,e));return s||t_(this._renderPlanHass,t,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:e,designPreview:i,activityRuntime:this._activityRt.get(t.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(t){return this._devicePresentation(t).visual}_stateClass(t,e=this._deviceVisual(t)){const i=this._devicePresentation(t);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===e.status||e.activity,Qu({...i,visual:e}).join(" "))}_liveTemp(t){if(!this._config?.show_temperature)return null;if(!0===t.marker?.use_climate_temp){const e=go(this._renderPlanHass,t.entities);if(null!=e)return e}return"mdi:thermometer"!==t.icon&&"mdi:air-filter"!==t.icon?null:mo(this._renderPlanHass,t.entities)}_bindingEntities(t){if("virtual"===t||!t)return[];const e=this._bindingStatus(t);return"active"===e.kind?e.enabledEntityIds:e.allEntityIds}_bindingHasClimate(t){return this._bindingEntities(t).some(t=>t.startsWith("climate."))}_bindingHasAlarm(t){return this._bindingEntities(t).some(t=>{const e=this._planHass?.states?.[t]||this.hass?.states?.[t],i=this._fullRegistryHass.entities[t]||this.hass?.entities?.[t];return Bs(t.split(".")[0],e?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_liveHum(t){return this._config?.show_temperature&&t.primary&&fo(this.hass,t.primary)?vo(this.hass,t.entities):null}_deviceBindingActive(t,e=!0){if(t.virtual||"virtual"===t.bindingKind)return!0;if(!t.bindingKind||!t.bindingRef)return!1;const i=this._bindingStatus(`${t.bindingKind}:${t.bindingRef}`);return"active"===i.kind||(e&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(t){t?this._planEntityAvailable(t)?(this._nativeMoreInfoEntity=t,av(this,"hass-more-info",{entityId:t})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(t,e){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==t)for(const i of[e,this._stageEl])try{i?.hasPointerCapture?.(t)&&i.releasePointerCapture(t)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_ctxDevice(t,e){"view"===this._mode&&(t.preventDefault(),t.stopPropagation(),this._deviceBindingActive(e)&&(e.primary?this._openMoreInfo(e.primary):this._infoCard=e))}_clickDevice(t,e){if(t.stopPropagation(),this._drag?.moved||this._suppressClick||this._holdFired)return;if("plan"===this._mode)return;if("devices"===this._mode)return void this._openMarkerDialog(e);const i=this._devices.find(t=>t.id===e.id);if(!i)return;const s=pp(i.tapAction,i.primary?.split(".")[0]),n=(t,e)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:t,exec:e}:e()};if("toggle"===s){const t=this._toggleIntent(i);if(!t)return;if(!vp(t))return void this._showUnavailableToggleTargets(t);const e=t=>{const e=vp(t);if(!e)return;if("virtual-light"===e.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:e.markerId}).then(t=>{const e=wn(this._virtualLights,t);e!==this._virtualLights&&(this._virtualLights=e,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(t=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(t)})));const{command:s}=e;this._startDevicePressFeedback(i.id),this.hass.callService(s.domain,s.service,s.data).catch(t=>this._showToast(this._t("toast.error",{err:this._errText(t)})))},s=((o=t).targets.length?o.targets:o.skippedTargets).map(t=>t.name||t.entityId||t.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const n=this._toggleConfirmationLines(t);if(!n.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:s}),lines:n,initialIntent:t,deviceId:i.id,exec:()=>{const s=this._devices.find(t=>t.id===i.id),n=s?this._toggleIntent(s):null;n&&!vp(n)&&this._showUnavailableToggleTargets(n)||(n&&bp(t,n)?e(n):this._showToast(this._t("toast.tap_target_changed")))}}}else e(t);return}var o;if("info"===s)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===s){const t=i.marker?.tap_target||"",e=function(t){const e=String(t||"").split(".")[0];return"automation"===e?{domain:"automation",service:"trigger"}:"script"===e?{domain:"script",service:"turn_on"}:"scene"===e?{domain:"scene",service:"turn_on"}:null}(t),s=this.hass.states[t];if(!e||!s)return void this._showToast(this._t("toast.run_target_missing"));const o=s.attributes?.friendly_name||t;return void n(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(t)&&(this._startDevicePressFeedback(i.id),this.hass.callService(e.domain,e.service,{entity_id:t}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(t=>this._showToast(this._t("toast.error",{err:this._errText(t)}))))})}"more-info"===s&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(t){const e=function(t){if(!t||"group"!==t.kind||vp(t)||"configured-targets-missing"!==t.noneReason)return[];if(!t.skippedTargets.length||t.skippedTargets.some(t=>!yp.has(t.reason)&&"secure"!==t.reason))return[];const e=[],i=new Set;for(const s of t.skippedTargets){if(!yp.has(s.reason))continue;const t=String(s.name||s.entityId||s.ref||"").trim();t&&!i.has(t)&&(i.add(t),e.push(t))}return e}(t);return!!e.length&&(this._showToast(1===e.length?this._t("toast.toggle_target_unavailable",{name:e[0]}):this._t("toast.toggle_targets_unavailable",{names:e.join(", ")})),!0)}_keyDevice(t,e){"Enter"!==t.key&&" "!==t.key||"view"!==this._mode&&"devices"!==this._mode||(t.preventDefault(),this._clickDevice(t,e))}_startDevicePressFeedback(t){const e=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(e=>e.dataset.id===t),i=e?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const s=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),n=Number.isFinite(s)?Math.max(.95,Math.min(1,s)):1;this._devicePressAnimations.get(t)?.cancel();const o=this._reducedMotion?[{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"},{outlineColor:"var(--hp-accent, #3ea6ff)",outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"2px",offset:.5},{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"}]:[{scale:String(n)},{scale:"0.95",offset:.5},{scale:"1"}],a=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(t,a);const r=()=>{this._devicePressAnimations.get(t)===a&&this._devicePressAnimations.delete(t)};a.addEventListener("finish",r,{once:!0}),a.addEventListener("cancel",r,{once:!0})}_cancelDevicePressFeedback(){for(const t of this._devicePressAnimations.values())t.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const t=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(t=>t.dataset.id||""));for(const[e,i]of this._devicePressAnimations)t.has(e)||(i.cancel(),this._devicePressAnimations.delete(e))}_t(t,e){return la(ra(this.hass,this._config?.language),t,e)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex")}}_help(t){const e=`${t}.aria`,i=ra(this.hass,this._config?.language);return ca(i,t)&&ca(i,e)?W``:G}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(t){const e=[];for(const i of this._devices){if(i.space!==t.id||i.hidden)continue;const s=this._pos(i);e.push({minX:s.x,minY:s.y,maxX:s.x,maxY:s.y})}if(t.id===this._space){for(const t of this._openingsR){const i=Number(t.angle)*Math.PI/180,s=Math.cos(i)*t.rlen/2,n=Math.sin(i)*t.rlen/2,o=Eh([[t.rx-s,t.ry-n],[t.rx+s,t.ry+n]]);o&&e.push(o)}const i=this._decorH;for(const t of this._decorList){const s=Eh("line"===t.kind?[[t.x1*ev,t.y1*i],[t.x2*ev,t.y2*i]]:"text"===t.kind?[[t.x*ev,t.y*i]]:Lr({x:t.x*ev,y:t.y*i,w:t.w*ev,h:t.h*i,angle:t.angle}));s&&e.push(s)}for(const i of this._physicalBodiesR(t)){const t=Eh(i);t&&e.push(t)}}return Oh(t,e)}_frameOf(){const t=this._spaceModel();if(!t){this._frame=null;const t={x:0,y:0,w:ev,h:ev};return{rect:t,all:t,outliers:0}}const e=this._frame,i="view"!==this._mode;if(e&&e.id===t.id&&this._bdDrag)return e;if(e&&e.id===t.id&&e.model===t&&e.layout===this._layout&&e.devs===this._devices&&e.far===this._showFar&&e.grow===i)return e;const s=qh(this._contentItems(t));let n=s.all||Wh(t),o=this._showFar?n:s.core||Wh(t);return e&&e.id===t.id&&i&&e.grow&&(o=sv(e.rect,o),n=sv(e.all,n)),this._frame={id:t.id,model:t,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:n,outliers:s.outliers},this._frame}_isoSource(){const t=this._spaceModel();if(!t)return null;const e=this._spaceWalls,i=this._openCuts(),s=this._openingsR.map((t,e)=>({id:String(t.id||e),sourceIndex:e,type:t.type,x:t.rx,y:t.ry,angle:Number(t.angle)||0,length:t.rlen>0?t.rlen:900,flipH:!!t.flip_h,flipV:!!t.flip_v})),n=mh(64,this._cellCm),o=mh(10,this._cellCm),a=`${t.id}|${function(t){let e=2166136261;const i=t=>{if("number"!=typeof t)if("string"!=typeof t)if("boolean"!=typeof t)if(Array.isArray(t)){e=af(e,t.length);for(const e of t)i(e)}else{if(t&&"object"==typeof t){const e=t;for(const t of Object.keys(e).sort())i(t),i(e[t]);return}e=af(e,-1)}else e=af(e,t?1:0);else for(const i of t)e=af(e,i.codePointAt(0)||0);else e=af(e,t)};return i(t),e.toString(36)}({rooms:t.rooms,walls:e,openCuts:i,openings:s,partitions:t.partitions,roomDrafts:t.room_drafts,columns:t.wall_columns,cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,camera:Vg,wallHeight:n,floorEdgeHeight:o,algorithm:3})}`;return{key:a,build:()=>{const o=eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t)).all,a=this._roomWallOpeningInputs(this._openingsR,t),r=e.length||o.length?Rc(t.rooms,e,i,a,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,o):null;if(r&&("failed-core"===r.status||"not-applicable"===r.status))throw new Error("wall boolean geometry failed");const l=r?.paperGeom??Pc(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,ev);if(!l)throw new Error("floor boolean geometry failed");const c=r?.openingIndex||Fc(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,ev),h=s.map(t=>{const i=this._openingsR[t.sourceIndex],s="gate"===t.type?!t.flipV:t.flipV,o=i?.partitionHost?Dp(i.partitionHost,s):e.length||"gate"===t.type?Lc(c,{x:t.x,y:t.y,angle:t.angle,length:t.length,flip_v:s}):{ox:0,oy:0,cm:0,side:-1};return function(t,e=64){if(!(rf([t.x,t.y,t.angle,t.length,t.face.ox,t.face.oy,e])&&t.length>0&&e>0))throw new Error("invalid isometric opening input");const i=t.length/2;let s;if("passage"===t.type)s=[];else if("gate"===t.type){const n=10*t.face.side;s=[cf(t,0,[-i,0],[i,0],n,0,.88*e),cf(t,1,[i,0],[-i,0],-n,0,.88*e)]}else s="window"===t.type?[cf(t,0,[-i,0],[i,0],-90,.27*e,.78*e),cf(t,1,[i,0],[-i,0],90,.27*e,.78*e)]:[cf(t,0,[-i,0],[t.length,0],-90,0,.92*e)];return{id:t.id,sourceIndex:t.sourceIndex,type:t.type,leaves:Object.freeze(s.map(t=>Object.freeze(t)))}}({...t,face:o},n)});return{walls:r?.components.flatMap(t=>t.geom)||[],floor:l,openings:Object.freeze(h)}}}}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return`${this._space}|invalid`}}_isoScene(){const t=this._isoSource();if(!t)return null;const e=this._isoGeometryCache.get(t.key);if(e)return{key:t.key,...e};const i=this._frameOf().rect,s=t.build(),n=mh(64,this._cellCm),o=mh(10,this._cellCm),a=function(t){let e=1/0,i=1/0,s=-1/0,n=-1/0;for(const o of t)for(const t of o.leaves){const o=Math.hypot(t.closedVector[0],t.closedVector[1]);e=Math.min(e,t.hinge[0]-o),i=Math.min(i,t.hinge[1]-o),s=Math.max(s,t.hinge[0]+o),n=Math.max(n,t.hinge[1]+o)}return rf([e,i,s,n])?{x:e,y:i,w:s-e,h:n-i}:null}(s.openings),r=Zg({rect:a?sv(i,a):i,wallHeight:n,openingHeight:n,floorDepth:o}),l=function(t,e=Vg,i=64){if(!Number.isFinite(i)||i<0)throw new Error("invalid wall height");const s=[],n=[],o=[];let a=0;for(let r=0;r<(t||[]).length;r++){const l=t[r];for(let t=0;t<(l||[]).length;t++){const c=ef(l[t],t>0);if(!(c.length<3||Math.abs(tf(c))<1e-9)){s.push(sf(c,e,i)),a+=c.length;for(let s=0;st.depth-e.depth||t.polygon-e.polygon||t.ring-e.ring||t.edge-e.edge),{topPath:s.join(" "),sides:n,contactPath:o.join(" "),edgeCount:a}}(s.walls,Vg,n),c={geometry:l,floor:of(s.floor,o),openings:s.openings,frame:r};return Wf(this._isoGeometryCache,t.key,c,8),{key:t.key,...c}}_effectiveProjection(){if("iso"!==this._desiredProjection||!this._model.length)return"flat";const t=this._isoSceneKey()||`${this._space}|invalid`;if(this._isoFallback.has(t))return"flat";try{const t=this._isoScene();return t?(e="iso",i=t.key,s=this._isoFallback,"iso"===e&&i&&!s.has(i)?"iso":"flat"):"flat"}catch(e){if(!this._isoFallback.has(t)){this._isoFallback.add(t);const i=t.split("|");console.warn(`HOUSEPLAN ISO FALLBACK: #89, space ${this._space}, fingerprint ${i[i.length-1]}, ${e instanceof Error?e.message:"renderer error"}`)}return"flat"}var e,i,s}_scenePoint(t){return"iso"===this._renderProjection?Yg(t,0):t}_floorView(t){if("iso"!==this._renderProjection)return t;const e=Jg([t.x,t.y]),i=Jg([t.x+t.w,t.y+t.h]);return{x:e[0],y:e[1],w:i[0]-e[0],h:i[1]-e[1]}}_baseVb(){if("iso"===this._effectiveProjection()){if(!this._spaceDisplayForRender().showBorders){const t=Zg({rect:this._frameOf().rect,wallHeight:mh(64,this._cellCm)});return[t.x,t.y,t.w,t.h]}const t=this._isoScene()?.frame??this._frameOf().rect;return[t.x,t.y,t.w,t.h]}const t=this._frameOf().rect;return[t.x,t.y,t.w,t.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._showFar=!0,this._frame=null,this._resetZoom()}_fitAll(){this._showFar=!0,this._frame=null,this._resetZoom()}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?G:W`
+
`}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(t=>({...t,...t.stage?{stage:[...t.stage]}:{}}))}getCardSize(){return 12}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const t=this._serverCfg?.spaces||[];let e=t.length+":";for(const i of t){e+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const t of i.rooms||[]){const i=t.poly?.[0],s=t.poly?.[t.poly.length-1];e+=(t.poly?.length||0)+"."+(t.id||"")+"."+(t.open_to||[]).join("+")+"."+(t.area||"")+"."+JSON.stringify(t.settings||0)+"."+(t.x??"")+","+(t.y??"")+","+(t.w??"")+","+(t.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(s?s[0]+"/"+s[1]:"")+";"}}return e}get _model(){if(!this._serverCfg)return[];const t=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===t)return this._modelCache.model;const e=this._buildModel();return this._modelCache={key:t,model:e},e}_buildModel(){if(!this._serverCfg)return[];const t=this._renderCfg;return $h(t).map((e,i)=>{const s=t.spaces[i]?.plan_url;return e.bg&&s?{...e,bg:{...e.bg,href:s}}:e})}_spaceModel(){return this._hasFixedFloor?$d(this._model,this._space):(t=this._model,e=this._space,t.find(t=>t.id===e)??t[0]);var t,e}_spaceModelById(t){return $d(this._model,t)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0;for(const t of this._pointers.keys())for(const e of this.renderRoot.querySelectorAll("*"))try{e.hasPointerCapture?.(t)&&e.releasePointerCapture(t)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._resumeDraftBySpace={},this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const t={};for(const e of this._model)for(const i of e.rooms)i.area&&(t[i.area]={space:e.id,room:i});return t}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._settings.filter_seeded?this._showHidden:!!this._settings.show_all}_toggleShowAll(){if(this._serverCfg){if(this._settings.filter_seeded)return this._showHidden=!this._showHidden,void this.requestUpdate();this._serverCfg={...this._serverCfg,settings:{...this._serverCfg.settings,show_all:!this._settings.show_all}},this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}}_seedHiddenDevices(){if(!this._serverCfg||!this._norm||!this._canEdit)return;const t=this._serverCfg,e=function(t){const e=t.hass,i=t.registry||An(e),s=Nn(e,i),n=On(e,i),{areaToSpace:o,markers:a,settings:r,excluded:l,iconRules:c}=t,h=!1!==r.group_lights,d=wo(a),p=yo(s,h).filter(t=>!ko(s,t.eid,d)),u=new Set(p.map(t=>t.area)),_=qn(s),m=Wn(a,n),g=new Set(a.map(t=>t.binding)),f=[];for(const t of Object.values(s.devices)){const n=t.area_id;if(!n||!o[n])continue;if("service"===t.entry_type)continue;if(g.has("device:"+t.id))continue;if("active"!==Bn(e,"device:"+t.id,i).kind)continue;const a=jn(s,t.id,_[t.id]||[],m);if(a.partial&&!a.entityIds.length)continue;const r=a.entityIds,d=Un(s,t,r);let p=l.has(d)||"Group"===t.model||/scene/i.test(t.model||"")||/bridge/i.test((t.model||"")+(t.name||""))||"myheat"===d&&!!t.via_device_id;if(!p&&h&&u.has(n)){const e=(t.name_by_user||t.name||"").trim();"mdi:lightbulb"===bo(s,e,t.model,r,c)&&(p=!0)}p&&f.push("device:"+t.id)}return f}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!e.length&&t.settings?.filter_seeded)return;t.markers=t.markers||[];const i=[];for(const s of e){const e="h"+s.slice(s.indexOf(":")+1);t.markers.push({id:e,binding:s,hidden:!0}),i.push(s.slice(s.indexOf(":")+1))}const s={...t.settings||{},filter_seeded:!0};delete s.show_all,i.length&&Array.isArray(s.new_device_ids)&&(s.new_device_ids=s.new_device_ids.filter(t=>!i.includes(t))),t.settings=s,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const t=this._settings.icon_rules;if(!t||!Array.isArray(t)||!t.length)return;const e=JSON.stringify(t);return e!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=e,this._rulesCompiled=Xt(t)),this._rulesCompiled}get _fillColors(){return ps(this._settings)}get _excluded(){const t=this._settings.exclude_integrations;return t?new Set(t):Yt}willUpdate(t){t.has("_serverCfg")&&this._cfgEpoch++,this._syncEmptySpaceState(),t.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._planHassMemo=null,this._hookConnection(),!this._loadOk&&!this._loading&&this._loadTries<8&&this._loadFromServer(),this._maybeRebuildDevices(),this._vacTick(),this._activityTick()),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._warmSnapshot(),this._dtMeasure();const t=this._stageEl;t&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>this._refitView()),this._roViewport.observe(t)),t&&this._booting&&!this._bootTimer&&this._bootWatch();const e=this.renderRoot.querySelector(".hdr");if(e&&t&&!this._roHdr){const i=()=>{const e=this.renderRoot.querySelector("ha-card");if(!e)return;const i=t.getBoundingClientRect().top-e.getBoundingClientRect().top,s=Math.min(Math.max(e.getBoundingClientRect().top,0),120),n=Math.round(i+s);n>=0&&n!==this._hdrH&&(this._hdrH=n),n>=0&&!this._booting&&!this._config?.kiosk&&t.clientHeight>0&&this._warmPatch({hdrH:n,stageH:t.clientHeight})};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(e),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(t&&!this._view&&this._refitView(),this._editorSecondary.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const t=function(t){const e=t?.floors;if(!e||"object"!=typeof e)return[];const i=[];for(const t of Object.values(e))t&&t.floor_id&&i.push({id:t.floor_id,name:t.name||t.floor_id,level:t.level??null});return i.sort((t,e)=>{const i=t.level??1e9,s=e.level??1e9;return i!==s?i-s:t.name.localeCompare(e.name)}),i}(this.hass);t.length?this._importDialog={floors:t.map(t=>({...t,checked:!0}))}:this._openSpaceDialog("create")}}_adoptStructuralResponses(t,e,i){const s=t?.config,n=s&&Array.isArray(s.spaces)?s:null,o=bd(n),a=o!==(this._cfgContentFingerprint||bd(this._serverCfg));if(a&&(this._geometryHistory.clear(),this._pendingPhysicalWrites.clear(),this._serverCfg&&this._clearGeometryGesture(),this._serverCfg=n,this._cfgContentFingerprint=o),this._cfgRev=t?.rev??this._cfgRev,t&&("virtual_lights"in t||"config"in t)){const e=gn(this._virtualLights,t.virtual_lights,this._cfgRev,"virtual_lights"in t);vn(e)!==vn(this._virtualLights)&&(this._virtualLights=e,this._capturedSnapshotVirtual="")}let r=!1;if(void 0!==e||void 0!==i){const t=i??e?.layout??{},s=bd(t);r=s!==(this._layoutContentFingerprint||bd(this._layout)),r&&(this._layout=t,this._layoutContentFingerprint=s),this._layoutRev=e?.rev??this._layoutRev}return this._canOptimizeUndo=!(!t?.can_optimize_undo&&!e?.can_optimize_undo),this._haIntegrationVersion="string"==typeof t?.integration_version?t.integration_version:this._haIntegrationVersion,this._undoKind=t?.undo_kind||e?.undo_kind||null,"boolean"==typeof t?.can_write&&(this._serverCanWrite=t.can_write),a&&this._continuity.note("config-candidate",{configRev:this._cfgRev}),r&&this._continuity.note("layout-candidate",{layoutRev:this._layoutRev}),{configChanged:a,layoutChanged:r}}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const t=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(t,!1),!0}async _loadFromServer(){this._loading=!0,this._loadTries++;const t=this._space,e=!!this._view;try{const[i,s]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]),n=i?.config&&Array.isArray(i.config.spaces)?i.config:null,o=bd(n)!==(this._cfgContentFingerprint||bd(this._serverCfg))||bd(s?.layout??{})!==(this._layoutContentFingerprint||bd(this._layout));if(o){if(!await this._signer.prepareImage(this.hass,this._candidateBackdrop(n)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0)}o&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),this._connectionWasLost=!1,this._serverStorage=!0,"boolean"==typeof i?.can_write&&(this._serverCanWrite=i.can_write),this._canOptimizeUndo=!(!i?.can_optimize_undo&&!s?.can_optimize_undo),this._haIntegrationVersion="string"==typeof i?.integration_version?i.integration_version:this._haIntegrationVersion,this._adoptStructuralResponses(i,s),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:e&&this._space===t||this._restoreZoom(),this._loadOk=!0,this.hass.callWS({type:"houseplan/trail/get"}).then(t=>{this._vacSrvTrails=t?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(t){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(Yf)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const t=this.hass?.connection;if(!t)return;if(t!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=t),this._liveSyncAttempt)return;const e=this._liveSyncGeneration,i=[],s=(s,n,o,a)=>{s()||i.push(async()=>{const i=await t.subscribeEvents(a,o);e===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===t&&!s()?n(i):i?.()})};if(s(()=>this._unsubCfg,t=>{this._unsubCfg=t},"houseplan_config_updated",t=>{const e=Number(t?.data?.rev??-1);e!==this._cfgRev&&this._reloadConfigOnly(!1,e)}),s(()=>this._unsubTrail,t=>{this._unsubTrail=t},"houseplan_trail_updated",async()=>{try{const t=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=t?.trails||{},this.requestUpdate()}catch{}}),s(()=>this._unsubLayout,t=>{this._unsubLayout=t},"houseplan_layout_updated",t=>this._onLayoutEvent(Number(t?.data?.rev??-1))),s(()=>this._unsubVirtual,t=>{this._unsubVirtual=t},"houseplan_virtual_light_updated",t=>{const e=wn(this._virtualLights,t?.data);e!==this._virtualLights&&(this._virtualLights=e,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const n=function(t){return Promise.allSettled(t.map(t=>Promise.resolve().then(t)))}(i).then(()=>{});this._liveSyncAttempt=n,n.finally(()=>{this._liveSyncAttempt===n&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(t=!1,e){if(!t){if(void 0!==e&&e<=this._cfgRev)return;if(this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(()=>this._reloadConfigOnly(!1,e),400))}this._beginContinuityCandidate("config-reload",!1);try{const t=await this.hass.callWS({type:"houseplan/config/get"}),e=t?.config&&Array.isArray(t.config.spaces)?t.config:null;if(bd(e)!==(this._cfgContentFingerprint||bd(this._serverCfg))&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(e)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0);const i=this._space;this._adoptStructuralResponses(t),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._space!==i&&this._restoreZoom(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}catch(t){this._showToast(this._t("toast.cfg_reload_failed",{err:this._errText(t)}))}finally{this._continuityDataReady=!0,this.requestUpdate()}}_scheduleLoadRetry(t=!1){if(void 0!==this._loadRetryTimer)return;const e=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!t&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},e)}_ensureHaRegistryAuthority(){const t=this.hass?.connection||null;t&&t!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=t,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._haRegistryRelease=In(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return An(this.hass)}get _planHass(){const t=this._haRegistry,e=Fn(this.hass,t),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===e)return i.active;const s=Nn(this.hass,t),n=On(this.hass,t);return this._planHassMemo={hass:this.hass,sig:e,active:s,full:n},s}_captureRenderDeviceSnapshot(){if(!this.hass)return;const t=Date.now(),e=[...this._activityRt.entries()].map(([e,i])=>`${e}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+R_)>t?1:0)).join("|"),i=vn(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===e)return;const s=this._planHass,n=new Map,o=new Map,a=new Set(["sun.sun"]);this._vacFit?.source&&a.add(this._vacFit.source);const r=new Set,l=new Set,c=t=>{if(!t)return;const e=t.indexOf(":");if(e<0)return void a.add(t);const i=t.slice(0,e),s=t.slice(e+1);"device"===i?r.add(s):"entity"===i&&a.add(s)};for(const t of this._model)for(const e of t.rooms)e.area&&l.add(e.area),c(e.settings?.temp_source),c(e.settings?.hum_source);for(const t of this._serverCfg?.spaces||[])for(const e of t.openings||[])for(const t of gi(e))a.add(t);for(const t of this._serverCfg?.spaces||[])for(const e of t.decor||[])if("text"===e.kind){for(const t of String(e.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const e=Yi(t[1]);e?.entity&&a.add(e.entity)}e.entity&&a.add(e.entity),o.set(`decor:${t.id}:${e.id}`,ts(e.text,e,s,t=>!!s.entities?.[t]&&!!s.states?.[t]&&!ko(s,t,wo(this._markers))))}const h=ho(s,this._devices,null,this._virtualLights);for(const t of this._devices){for(const e of[!1,!0])n.set(n_(t.id,e),t_(s,t,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:e,activityRuntime:this._activityRt.get(t.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(t)){const e=this._vacSource(t,s),i=e?Nd(s?.states?.[e]?.attributes):null,n=this._vacRt.get(t.id);o.set(`vacuum:${t.id}`,{source:e,telemetry:i,mapId:i?this._vacMapId(t,i,s):null,runtime:n?{trail:n.trail,lastTs:n.lastTs,moving:n.moving,jump:n.jump}:null,server:this._vacSrvTrails[t.id]||null})}}const d=s_({sourceSequence:this._hassSequence,hass:s,devices:this._devices,presentations:n,positions:(p=this._model.length>0,u=this._devices,_=t=>this._livePos(t),p?new Map(u.map(t=>[t.id,_(t)])):new Map),facts:o,entityIds:a,deviceIds:r,areaIds:l});var p,u,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=e,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(t){return Bn(this.hass,t,this._haRegistry)}houseplanDiagnostics(){const t=function(t){const e=An(t);return{access:e.access,authoritative:e.authoritative,revision:e.revision,lastSuccess:e.lastSuccess,error:e.error}}(this.hass),e={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const t of this._markers)t.removed||"virtual"===t.binding||e[this._bindingStatus(t.binding).kind]++;return{registry:{...t,lastSuccessAgeMs:t.lastSuccess?Math.max(0,Date.now()-t.lastSuccess):null},bindings:e}}_openBindingInHa(t){const[e,i]=t.split(":");if(i)if("device"!==e){if("entity"===e){const t=this._fullRegistryHass.entities?.[i];t?.device_id&&lv("/config/devices/device/"+encodeURIComponent(t.device_id))}}else lv("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(t){const[e,i]=t.split(":");return!!i&&("device"===e||"entity"===e&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const t=this._markerDialog;if(!t)return;const e="ha"===t.bindingMode?this._bindingStatus(t.binding):null,i=t.hideFromPlan||"ha_disabled"===e?.kind;i&&"ha_disabled"===e?.kind?this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===e?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...t,hideFromPlan:!i}}_hookConnection(){const t=this.hass?.connection;t&&t!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),t.addEventListener?.("ready",this._onConnReady),t.addEventListener?.("disconnected",this._onConnLost),t.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=t)}_display(t){return this._signer.display(this.hass,t)}_resign(){this._signer.resign(this.hass,Is(this._serverCfg))}_onLayoutEvent(t){t<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{t<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(t){const e=t?.rev;"number"==typeof e&&e>this._layoutRev&&(this._layoutRev=e)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const t=new Map;for(const e of this._dirtyPos)this._layout[e]&&t.set(e,this._layout[e]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[e,i]of this._sentPos)t.set(e,i);try{const e=await this.hass.callWS({type:"houseplan/layout/get"}),i={...e?.layout||{}};for(const[e,s]of t)i[e]=s;const s=bd(i);s!==(this._layoutContentFingerprint||bd(this._layout))&&(this._layout=i,this._layoutContentFingerprint=s),this._layoutRev=e?.rev??this._layoutRev,this._canOptimizeUndo=!!e?.can_optimize_undo,this._haIntegrationVersion="string"==typeof e?.integration_version?e.integration_version:this._haIntegrationVersion,this._undoKind=e?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_maybeRebuildDevices(){const t=this.hass;if(!t?.devices||!t?.entities||!t?.areas)return;const e=this._haRegistry,i=Fn(t,e)+":"+Object.keys(t.areas).length+":"+(this._norm?"n":"l")+":"+ra(t,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const s=new Map(this._devices.map(t=>[t.id,t.bindingStatus?.kind||"active"]));this._devices=So({hass:t,registry:e,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:t=>this._t(t),iconRules:this._iconRules});const n=this._markers.filter(t=>!t.removed&&"virtual"!==t.binding).map(t=>t.binding).sort(),o=e.revision+":"+n.join("|");if(e.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const s of n)i.set(s,Bn(t,s,e));!function(t){if("undefined"==typeof localStorage||!t.size)return;const e=Hn(),i=Date.now();for(const[s,n]of t)"active"===n.kind?e[s]={kind:"active",ts:i}:"ha_disabled"===n.kind&&(e[s]={kind:"ha_disabled",reason:n.reason,ts:i});const s=Object.fromEntries(Object.entries(e).sort((t,e)=>e[1].ts-t[1].ts).slice(0,1500));Mn=s;try{localStorage.setItem(Sn,JSON.stringify(s))}catch{}}(i),this._haBindingCacheKey=o}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),this._syncActivityRuntime();const a=new Set(this._devices.filter(t=>!t.hidden).map(t=>t.id));for(const t of this._vacRt.keys())a.has(t)||this._vacRt.delete(t);if(this._infoCard){const t=this._devices.find(t=>t.id===this._infoCard.id);this._infoCard=t&&"ha_disabled"!==t.bindingStatus?.kind?t:null}const r=this._devices.some(t=>"ha_disabled"===t.bindingStatus?.kind&&"ha_disabled"!==s.get(t.id));r&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(t=>t.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._drag&&"ha_disabled"===this._devices.find(t=>t.id===this._drag.id)?.bindingStatus?.kind&&(this._drag=null),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(rv(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const t=this._devices.filter(t=>!t.marker&&!t.virtual).map(t=>t.id).sort(),e=t.join(",");if(e===this._newSyncKey)return;this._newSyncKey=e;const i=this._settings,{fresh:s,known:n}=function(t,e){if(!Array.isArray(e))return{fresh:[],known:[...t]};const i=new Set(e),s=t.filter(t=>!i.has(t));return{fresh:s,known:s.length?[...e,...s]:e}}(t,i.known_devices);if(!Array.isArray(i.known_devices)||s.length){const t=[...new Set([...i.new_device_ids||[],...s])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:n,new_device_ids:t}},this._saveConfig()}}get _newIds(){const t=this._settings.new_device_ids;return new Set(Array.isArray(t)?t:[])}_ackNewDevice(t){if(!this._newIds.has(t)||!this._serverCfg)return;const e=this._settings;this._serverCfg={...this._serverCfg,settings:{...e,new_device_ids:(e.new_device_ids||[]).filter(e=>e!==t)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(t){if(!t)return null;const e=[];for(const i of this._renderDevices){if(i.area!==t||i.virtual)continue;const s=_o(this._renderPlanHass,i.entities);null!=s&&e.push(s)}return Ei(e)}_roomBounds(t){if(t.poly&&t.poly.length){const e=t.poly.map(t=>t[0]),i=t.poly.map(t=>t[1]),s=Math.min(...e),n=Math.min(...i);return{x:s,y:n,w:Math.max(...e)-s,h:Math.max(...i)-n}}return{x:t.x??0,y:t.y??0,w:t.w??0,h:t.h??0}}_defaultPositions(){const t={},e=this._config?.icon_size??2.5;for(const i of this._model){const s=e/100*Uh(i)*1.3;for(const e of i.rooms){if(!e.area)continue;const n=this._devices.filter(t=>t.area===e.area&&t.space===i.id);if(!n.length)continue;const o=this._roomBounds(e),a=.1*Math.min(o.w,o.h),r=o.w-2*a,l=o.h-2*a,c=Math.max(1,Math.round(Math.sqrt(n.length*r/Math.max(l,1)))),h=Math.ceil(n.length/c),d=r/c,p=l/Math.max(h,1),u=n.map((t,e)=>({x:o.x+a+d*(e%c+.5),y:o.y+a+p*(Math.floor(e/c)+.5)}));Oi(u,o,s,.5*a),n.forEach((e,i)=>t[e.id]=Rh(u[i]))}}return t}_pos(t){const e=this._renderDeviceSnapshot?.positions.get(t.id);return e?{x:e.x,y:e.y}:this._livePos(t)}_livePos(t){const e=this._spaceModelById(t.space),i=this._layout[t.id];if(i)if(this._norm){if(i.s===t.space)return{x:i.x*iv,y:i.y*iv}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[t.id]?this._defPos[t.id]:e?Rh(jh(e)):{x:500,y:500}}_savePos(t,e,i){if(this._spaceModelById(t.space)){if(this._norm){const s=this._gridPitch,n=Math.round(e/s)*s,o=Math.round(i/s)*s,a=this._layout[t.id]?.k;this._layout={...this._layout,[t.id]:{s:t.space,x:Ah(n/iv),y:Ah(o/iv),...a?{k:a}:{}}}}else this._layout={...this._layout,[t.id]:{x:Math.round(e),y:Math.round(i)}};this._dirtyPos.add(t.id),this._persistLayout()}}_visualSamples(t){return Yu(this._renderPlanHass,t,this._renderDevices,void 0,this._fullRegistryHass).samples}_devicePresentation(t,e=!1!==this._config?.show_signal,i=!1){const s=i?null:this._renderDeviceSnapshot?.presentations.get(n_(t.id,e));return s||t_(this._renderPlanHass,t,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:e,designPreview:i,activityRuntime:this._activityRt.get(t.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(t){return this._devicePresentation(t).visual}_stateClass(t,e=this._deviceVisual(t)){const i=this._devicePresentation(t);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===e.status||e.activity,Qu({...i,visual:e}).join(" "))}_liveTemp(t){if(!this._config?.show_temperature)return null;if(!0===t.marker?.use_climate_temp){const e=go(this._renderPlanHass,t.entities);if(null!=e)return e}return"mdi:thermometer"!==t.icon&&"mdi:air-filter"!==t.icon?null:mo(this._renderPlanHass,t.entities)}_bindingEntities(t){if("virtual"===t||!t)return[];const e=this._bindingStatus(t);return"active"===e.kind?e.enabledEntityIds:e.allEntityIds}_bindingHasClimate(t){return this._bindingEntities(t).some(t=>t.startsWith("climate."))}_bindingHasAlarm(t){return this._bindingEntities(t).some(t=>{const e=this._planHass?.states?.[t]||this.hass?.states?.[t],i=this._fullRegistryHass.entities[t]||this.hass?.entities?.[t];return Bs(t.split(".")[0],e?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_liveHum(t){return this._config?.show_temperature&&t.primary&&fo(this.hass,t.primary)?vo(this.hass,t.entities):null}_deviceBindingActive(t,e=!0){if(t.virtual||"virtual"===t.bindingKind)return!0;if(!t.bindingKind||!t.bindingRef)return!1;const i=this._bindingStatus(`${t.bindingKind}:${t.bindingRef}`);return"active"===i.kind||(e&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(t){t?this._planEntityAvailable(t)?(this._nativeMoreInfoEntity=t,rv(this,"hass-more-info",{entityId:t})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(t,e){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==t)for(const i of[e,this._stageEl])try{i?.hasPointerCapture?.(t)&&i.releasePointerCapture(t)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_ctxDevice(t,e){"view"===this._mode&&(t.preventDefault(),t.stopPropagation(),this._deviceBindingActive(e)&&(e.primary?this._openMoreInfo(e.primary):this._infoCard=e))}_clickDevice(t,e){if(t.stopPropagation(),this._drag?.moved||this._suppressClick||this._holdFired)return;if("plan"===this._mode)return;if("devices"===this._mode)return void this._openMarkerDialog(e);const i=this._devices.find(t=>t.id===e.id);if(!i)return;const s=pp(i.tapAction,i.primary?.split(".")[0]),n=(t,e)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:t,exec:e}:e()};if("toggle"===s){const t=this._toggleIntent(i);if(!t)return;if(!vp(t))return void this._showUnavailableToggleTargets(t);const e=t=>{const e=vp(t);if(!e)return;if("virtual-light"===e.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:e.markerId}).then(t=>{const e=wn(this._virtualLights,t);e!==this._virtualLights&&(this._virtualLights=e,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(t=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(t)})));const{command:s}=e;this._startDevicePressFeedback(i.id),this.hass.callService(s.domain,s.service,s.data).catch(t=>this._showToast(this._t("toast.error",{err:this._errText(t)})))},s=((o=t).targets.length?o.targets:o.skippedTargets).map(t=>t.name||t.entityId||t.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const n=this._toggleConfirmationLines(t);if(!n.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:s}),lines:n,initialIntent:t,deviceId:i.id,exec:()=>{const s=this._devices.find(t=>t.id===i.id),n=s?this._toggleIntent(s):null;n&&!vp(n)&&this._showUnavailableToggleTargets(n)||(n&&bp(t,n)?e(n):this._showToast(this._t("toast.tap_target_changed")))}}}else e(t);return}var o;if("info"===s)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===s){const t=i.marker?.tap_target||"",e=function(t){const e=String(t||"").split(".")[0];return"automation"===e?{domain:"automation",service:"trigger"}:"script"===e?{domain:"script",service:"turn_on"}:"scene"===e?{domain:"scene",service:"turn_on"}:null}(t),s=this.hass.states[t];if(!e||!s)return void this._showToast(this._t("toast.run_target_missing"));const o=s.attributes?.friendly_name||t;return void n(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(t)&&(this._startDevicePressFeedback(i.id),this.hass.callService(e.domain,e.service,{entity_id:t}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(t=>this._showToast(this._t("toast.error",{err:this._errText(t)}))))})}"more-info"===s&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(t){const e=function(t){if(!t||"group"!==t.kind||vp(t)||"configured-targets-missing"!==t.noneReason)return[];if(!t.skippedTargets.length||t.skippedTargets.some(t=>!yp.has(t.reason)&&"secure"!==t.reason))return[];const e=[],i=new Set;for(const s of t.skippedTargets){if(!yp.has(s.reason))continue;const t=String(s.name||s.entityId||s.ref||"").trim();t&&!i.has(t)&&(i.add(t),e.push(t))}return e}(t);return!!e.length&&(this._showToast(1===e.length?this._t("toast.toggle_target_unavailable",{name:e[0]}):this._t("toast.toggle_targets_unavailable",{names:e.join(", ")})),!0)}_keyDevice(t,e){"Enter"!==t.key&&" "!==t.key||"view"!==this._mode&&"devices"!==this._mode||(t.preventDefault(),this._clickDevice(t,e))}_startDevicePressFeedback(t){const e=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(e=>e.dataset.id===t),i=e?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const s=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),n=Number.isFinite(s)?Math.max(.95,Math.min(1,s)):1;this._devicePressAnimations.get(t)?.cancel();const o=this._reducedMotion?[{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"},{outlineColor:"var(--hp-accent, #3ea6ff)",outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"2px",offset:.5},{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"}]:[{scale:String(n)},{scale:"0.95",offset:.5},{scale:"1"}],a=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(t,a);const r=()=>{this._devicePressAnimations.get(t)===a&&this._devicePressAnimations.delete(t)};a.addEventListener("finish",r,{once:!0}),a.addEventListener("cancel",r,{once:!0})}_cancelDevicePressFeedback(){for(const t of this._devicePressAnimations.values())t.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const t=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(t=>t.dataset.id||""));for(const[e,i]of this._devicePressAnimations)t.has(e)||(i.cancel(),this._devicePressAnimations.delete(e))}_t(t,e){return la(ra(this.hass,this._config?.language),t,e)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex")}}_help(t){const e=`${t}.aria`,i=ra(this.hass,this._config?.language);return ca(i,t)&&ca(i,e)?W``:G}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(t){const e=[];for(const i of this._devices){if(i.space!==t.id||i.hidden)continue;const s=this._pos(i);e.push({minX:s.x,minY:s.y,maxX:s.x,maxY:s.y})}if(t.id===this._space){for(const t of this._openingsR){const i=Number(t.angle)*Math.PI/180,s=Math.cos(i)*t.rlen/2,n=Math.sin(i)*t.rlen/2,o=Eh([[t.rx-s,t.ry-n],[t.rx+s,t.ry+n]]);o&&e.push(o)}const i=this._decorH;for(const t of this._decorList){const s=Eh("line"===t.kind?[[t.x1*iv,t.y1*i],[t.x2*iv,t.y2*i]]:"text"===t.kind?[[t.x*iv,t.y*i]]:Lr({x:t.x*iv,y:t.y*i,w:t.w*iv,h:t.h*i,angle:t.angle}));s&&e.push(s)}for(const i of this._physicalBodiesR(t)){const t=Eh(i);t&&e.push(t)}}return Oh(t,e)}_frameOf(){const t=this._spaceModel();if(!t){this._frame=null;const t={x:0,y:0,w:iv,h:iv};return{rect:t,all:t,outliers:0}}const e=this._frame,i="view"!==this._mode;if(e&&e.id===t.id&&this._bdDrag)return e;if(e&&e.id===t.id&&e.model===t&&e.layout===this._layout&&e.devs===this._devices&&e.far===this._showFar&&e.grow===i)return e;const s=qh(this._contentItems(t));let n=s.all||Wh(t),o=this._showFar?n:s.core||Wh(t);return e&&e.id===t.id&&i&&e.grow&&(o=nv(e.rect,o),n=nv(e.all,n)),this._frame={id:t.id,model:t,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:n,outliers:s.outliers},this._frame}_isoSource(){const t=this._spaceModel();if(!t)return null;const e=this._spaceWalls,i=this._openCuts(),s=this._openingsR.map((t,e)=>({id:String(t.id||e),sourceIndex:e,type:t.type,x:t.rx,y:t.ry,angle:Number(t.angle)||0,length:t.rlen>0?t.rlen:900,flipH:!!t.flip_h,flipV:!!t.flip_v})),n=mh(64,this._cellCm),o=mh(10,this._cellCm),a=`${t.id}|${function(t){let e=2166136261;const i=t=>{if("number"!=typeof t)if("string"!=typeof t)if("boolean"!=typeof t)if(Array.isArray(t)){e=rf(e,t.length);for(const e of t)i(e)}else{if(t&&"object"==typeof t){const e=t;for(const t of Object.keys(e).sort())i(t),i(e[t]);return}e=rf(e,-1)}else e=rf(e,t?1:0);else for(const i of t)e=rf(e,i.codePointAt(0)||0);else e=rf(e,t)};return i(t),e.toString(36)}({rooms:t.rooms,walls:e,openCuts:i,openings:s,partitions:t.partitions,roomDrafts:t.room_drafts,columns:t.wall_columns,cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,camera:Kg,wallHeight:n,floorEdgeHeight:o,algorithm:3})}`;return{key:a,build:()=>{const o=eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t)).all,a=this._roomWallOpeningInputs(this._openingsR,t),r=e.length||o.length?Rc(t.rooms,e,i,a,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,o):null;if(r&&("failed-core"===r.status||"not-applicable"===r.status))throw new Error("wall boolean geometry failed");const l=r?.paperGeom??Pc(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,iv);if(!l)throw new Error("floor boolean geometry failed");const c=r?.openingIndex||Fc(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,iv),h=s.map(t=>{const i=this._openingsR[t.sourceIndex],s="gate"===t.type?!t.flipV:t.flipV,o=i?.partitionHost?Dp(i.partitionHost,s):e.length||"gate"===t.type?Lc(c,{x:t.x,y:t.y,angle:t.angle,length:t.length,flip_v:s}):{ox:0,oy:0,cm:0,side:-1};return function(t,e=64){if(!(lf([t.x,t.y,t.angle,t.length,t.face.ox,t.face.oy,e])&&t.length>0&&e>0))throw new Error("invalid isometric opening input");const i=t.length/2;let s;if("passage"===t.type)s=[];else if("gate"===t.type){const n=10*t.face.side;s=[hf(t,0,[-i,0],[i,0],n,0,.88*e),hf(t,1,[i,0],[-i,0],-n,0,.88*e)]}else s="window"===t.type?[hf(t,0,[-i,0],[i,0],-90,.27*e,.78*e),hf(t,1,[i,0],[-i,0],90,.27*e,.78*e)]:[hf(t,0,[-i,0],[t.length,0],-90,0,.92*e)];return{id:t.id,sourceIndex:t.sourceIndex,type:t.type,leaves:Object.freeze(s.map(t=>Object.freeze(t)))}}({...t,face:o},n)});return{walls:r?.components.flatMap(t=>t.geom)||[],floor:l,openings:Object.freeze(h)}}}}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return`${this._space}|invalid`}}_isoScene(){const t=this._isoSource();if(!t)return null;const e=this._isoGeometryCache.get(t.key);if(e)return{key:t.key,...e};const i=this._frameOf().rect,s=t.build(),n=mh(64,this._cellCm),o=mh(10,this._cellCm),a=function(t){let e=1/0,i=1/0,s=-1/0,n=-1/0;for(const o of t)for(const t of o.leaves){const o=Math.hypot(t.closedVector[0],t.closedVector[1]);e=Math.min(e,t.hinge[0]-o),i=Math.min(i,t.hinge[1]-o),s=Math.max(s,t.hinge[0]+o),n=Math.max(n,t.hinge[1]+o)}return lf([e,i,s,n])?{x:e,y:i,w:s-e,h:n-i}:null}(s.openings),r=Qg({rect:a?nv(i,a):i,wallHeight:n,openingHeight:n,floorDepth:o}),l=function(t,e=Kg,i=64){if(!Number.isFinite(i)||i<0)throw new Error("invalid wall height");const s=[],n=[],o=[];let a=0;for(let r=0;r<(t||[]).length;r++){const l=t[r];for(let t=0;t<(l||[]).length;t++){const c=sf(l[t],t>0);if(!(c.length<3||Math.abs(ef(c))<1e-9)){s.push(nf(c,e,i)),a+=c.length;for(let s=0;st.depth-e.depth||t.polygon-e.polygon||t.ring-e.ring||t.edge-e.edge),{topPath:s.join(" "),sides:n,contactPath:o.join(" "),edgeCount:a}}(s.walls,Kg,n),c={geometry:l,floor:af(s.floor,o),openings:s.openings,frame:r};return jf(this._isoGeometryCache,t.key,c,8),{key:t.key,...c}}_effectiveProjection(){if("iso"!==this._desiredProjection||!this._model.length)return"flat";const t=this._isoSceneKey()||`${this._space}|invalid`;if(this._isoFallback.has(t))return"flat";try{const t=this._isoScene();return t?(e="iso",i=t.key,s=this._isoFallback,"iso"===e&&i&&!s.has(i)?"iso":"flat"):"flat"}catch(e){if(!this._isoFallback.has(t)){this._isoFallback.add(t);const i=t.split("|");console.warn(`HOUSEPLAN ISO FALLBACK: #89, space ${this._space}, fingerprint ${i[i.length-1]}, ${e instanceof Error?e.message:"renderer error"}`)}return"flat"}var e,i,s}_scenePoint(t){return"iso"===this._renderProjection?Jg(t,0):t}_floorView(t){if("iso"!==this._renderProjection)return t;const e=Xg([t.x,t.y]),i=Xg([t.x+t.w,t.y+t.h]);return{x:e[0],y:e[1],w:i[0]-e[0],h:i[1]-e[1]}}_baseVb(){if("iso"===this._effectiveProjection()){if(!this._spaceDisplayForRender().showBorders){const t=Qg({rect:this._frameOf().rect,wallHeight:mh(64,this._cellCm)});return[t.x,t.y,t.w,t.h]}const t=this._isoScene()?.frame??this._frameOf().rect;return[t.x,t.y,t.w,t.h]}const t=this._frameOf().rect;return[t.x,t.y,t.w,t.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._showFar=!0,this._frame=null,this._resetZoom()}_fitAll(){this._showFar=!0,this._frame=null,this._resetZoom()}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?G:W`
${this._t("canvas.far_objects",{n:this._outliers})} @@ -4983,7 +4983,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 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(hv.ZOOM_MAX,Math.max(hv.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},Hf)}_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>=_d?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(hv.ZOOM_MAX,Math.max(hv.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(Jf,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){"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&&rv("/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},cv(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(tv))e.toggleAttribute("data-pointer-hover",t)}_syncPointerHoverSubtree(t){if(t.nodeType!==Node.ELEMENT_NODE)return;const e=t,i=this._pointerModality.hoverEnabled;e.matches(tv)&&e.toggleAttribute("data-pointer-hover",i);for(const t of e.querySelectorAll(tv))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){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,ev}get _segments(){const t=this._curSpaceCfg,e=this._spaceH;return pi(t?.rooms||[]).map(t=>[t[0]*ev,t[1]*e,t[2]*ev,t[3]*e])}_savedNav(){if(this._hasFixedFloor)return null;try{return JSON.parse(localStorage.getItem(Xf)||"null")}catch{return null}}_saveNav(){if(!this._hasFixedFloor)try{localStorage.setItem(Xf,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?Yg([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._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=ml(ll,this._imperial))}get _drawWallFieldValue(){return null===this._drawWallField?ml(ll,this._imperial):this._drawWallField}get _drawWallCm(){const t=Bf(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>=("column"===this._tool?1:0)&&e<=i?e:null}get _drawWallMaxCm(){return"column"===this._tool?Wc:100}_showPhysicalRange(t=this._drawWallMaxCm,e=0){this._showToast(this._t("toast.physical_range",{min:ml(e,this._imperial),max:ml(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=sm(i,{pitch:Ph,seedIds:e,geometry:om(t,{excludeDraftId:this._activeDraftId})});return s.merged?(t.partitions=s.partitions,nm(t.openings,t.partitions,s.openingMoves,{coordScale:ev,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=Xp(this._path,Jp(this._path.length-1,this._draftSegmentCms,this._drawWallCm,ll)),i=e.length;if((t.partitions||[]).length+i>ov)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),"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>=ov:(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=qp({space:t,activeDraftId:this._activeDraftId,roomCuts: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=Bp({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=qp({space:t,activeDraftId:this._activeDraftId,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?Kp(i.value,t,{...o,anchor:s}):function(t,e,i){if(!(Ap(e)&&i.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const s=i.epsilon??Ip,n=i.excludePoints||[],o=Gp(Up(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=Vp(o,e,i.gridStep);!Wp(l,n,s)&&jp(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:Number.isFinite(Number(t.cm))?Math.max(0,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:Uc(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:Gc(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=zm(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=$d($h({spaces:[t]}),t.id),i=e?m_(t,e,ev,.02*Dh).contour.map(t=>t.map(t=>t/ev)):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,i),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=bd(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(Gr(this._serverCfg)),e=bd(t),i=[...this._pendingPhysicalWrites.entries()];for(const[e,s]of i){const i=lg(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!==bd(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 Mm?t.reason:"invalid-room";return this._t(`wall_model.reason.${e}`)}_hasLegacyZeroWallFields(t=this._serverCfg){return(t?.spaces||[]).some(t=>Array.isArray(t?.open_spans)&&t.open_spans.length>0||(t?.rooms||[]).some(t=>Array.isArray(t?.open_to)&&t.open_to.length>0))}_showWallModelMigrationBlocked(t){const e=this._hasLegacyZeroWallFields()?"toast.zero_wall_migration_blocked":"toast.wall_model_migration_blocked";this._showToast(this._t(e,{reason:this._wallModelBlockerLabel(t)}))}_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||lg(e)===lg(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)<9){const t=JSON.parse(JSON.stringify(s));if(!this._restoreGeometryStateInConfig(t,e))throw new Mm("invalid-room",e.spaceId);const i=Jm(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 Mm("invalid-room",e.spaceId);const r=i.spaces.find(t=>t.id===e.spaceId),c=o.spaces.find(t=>t.id===e.spaceId);if(!Array.isArray(n.wall_segments)&&JSON.stringify(e.rooms)===JSON.stringify(n.rooms))for(const t of c?.wall_segments||[])t.cm=Pl(n.walls,t.a,t.b,Ph,1);const 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}=Gm(i,jm(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;oSm||Nm(r,i,s)>Sm)continue;const l=Em(a,i,s),c=Em(r,i,s);l<-Sm||c>1+Sm||c<=l+Sm||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]/ev,t[1]/ev]):[];s.push(...i.map(t=>[t[0],t[1]])),c=Fm(t)<=Fm(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;Zm(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:lg(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._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}_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();"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=lg(i)!==lg(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=Jm(s).config}catch(t){return this._restoreGeometryStateLocal(i),this._showWallModelMigrationBlocked(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;Zm(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:lg(a)})}else Zm(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>ov)||(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;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("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],m=u.length>=4&&this._samePt(u[0],u[u.length-1]),g=u,f=_;if(g.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(m){const t=g.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:g.map(t=>[t[0]/ev,t[1]/ev]),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=g,this._draftSegmentCms=this._adoptDraftCms(g,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=Jp(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])*ev,Number(t?.[1])*ev]):[],n=Array.isArray(e?.segments)?e.segments:[];return Jp(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]/ev,t[1]/ev]),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=yu(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=Ru(r,{requiredSourceKey:n,maxDistance:gl(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(0===this._drawWallCm?"toast.zero_wall_ambiguous":"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=bu(this._wallFaceGraph(this._wallGraphSources([]),e),t,e);if(!s){const n=Ru(this._wallGraphSources([]),{point:t,maxDistance:gl(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(0===this._drawWallCm?"toast.zero_wall_ambiguous":"toast.wall_repair_ambiguous")),!0;if("repair"===n.kind)s=n.face,i=n.proposal;else if("none"===n.kind){const i=Ru(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,1);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:Uc(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]/ev,e[1]/ev]}),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:ml(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:ml(i.cm,this._imperial),shape:i.shape,angle:this._angleField("square"===i.shape?Gc(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:ml(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(),cv(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*ev-Math.min(...n),Math.min(Sh*ev-Math.max(...n),i[0])),Math.max(-Sh*ev-Math.min(...o),Math.min(Sh*ev-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]/ev,n.a[1]/ev],t.b=[n.b[0]/ev,n.b[1]/ev];for(const t of s.openings||[]){if("partition"!==t.host?.kind||t.host.id!==e.id)continue;const i=$p(t,[n],ev,this._cellCm,this._gridPitch).resolved;i&&Object.assign(t,Rp(t,i,ev))}}}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])/ev,(n.center[1]+e.delta[1])/ev])}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(),cv(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:Gc(e.angle),angle:Gc(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=Gc(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:gl(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]*ev,t.a[1]*this._spaceH],b:[t.b[0]*ev,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?gl(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 m={[i]:s},g=[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"};g.push(t.room.id),m[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(g.map(e=>[e,t.find(t=>t.id===e).poly.length])),y=[];for(const e of g){const i=t.find(t=>t.id===e),s=m[e],n=(s-1+i.poly.length)%i.poly.length,a=(s+1)%i.poly.length,r=Ga(t,e,n,1,o),l=Ga(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:g,edgeByRoom:m,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","wall_segments","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]/ev,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]/ev,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]*ev,t[1]*a]);if(e.poly.length!==n.length)continue;const c=Array.isArray(e.wall_ids)?e.wall_ids:[];for(let t=0;tt.id===i):null;s&&(s.a=[n[t][0]/ev,n[t][1]/ev],s.b=[n[(t+1)%n.length][0]/ev,n[(t+1)%n.length][1]/ev])}}if(r.length&&Array.isArray(o.walls)&&o.walls.length){const t=function(t,e,i,s,n=1,o="fixed-topology"){let a=!1;const r=Il(t,e,i,s,n,o,()=>{a=!0});return{walls:a?(t||[]).map(t=>({...t})):r,rejected:a}}(o.walls,r,l,this._wallKeyPitch,ev,"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"};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 m=[];for(const t of o.walls||[]){const e=u(t),i=_.get(e)||0;i?_.set(e,i-1):m.push(t)}return zl(m,p,this._wallKeyPitch,ev,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));cv(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.wall_segments)&&(l.wall_segments=i.sp.wall_segments)),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._openCuts(),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]},[_,m]=this._lastValidStageSize||[u.w,u.h],g={...u,stageWidth:Math.max(1,_),stageHeight:Math.max(1,m)},f=this._spaceModel(),v=this._config?.icon_size??2.5,y=f?Gh(v>8?2.5:v,f,u.w,this._kiosk?this._kioskScale.icon:1)*g.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,ev)||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:g,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;tfunction(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},m=_((n-1+s)%s)??0,g=(_((n+1)%s)??c)-m;return g>0?g:0}(e,i,o)*a)}_renderResizeMeasurements(){if(!this._rszLive?.length)return G;const t=this._rszLive.filter(t=>"length"===t.kind),e=this._rszLive.filter(t=>"area"===t.kind);return j``}_zeroWalls(){const t=this._spaceModel();return t?m_(this._curSpaceCfg,t,iv,.02*this._gridPitch):{style:d_(this._curSpaceCfg),lines:[],contour:[],barriers:[],transmissive:[]}}_openCuts(){return this._zeroWalls().contour}_deleteRoomClick(t){const e=this._spaceModel();if(!e)return;const i=[...e.rooms].reverse().find(e=>this._pointInRoom(t,e));i?i.id&&(this._roomDeleteDialog={roomId:i.id,name:i.name}):this._showToast(this._t("toast.delete_room_pick"))}get _wallKeyPitch(){return Ph}get _spaceWalls(){const t=this._curSpaceCfg?.walls;return Array.isArray(t)?t:[]}_cfgOpenCuts(){const t=this._curSpaceCfg,e=this._spaceModel();if(!t||!e)return[];const i=p_(t,1),s=__(t,e.rooms,iv,.02*this._gridPitch).map(t=>t.map(t=>t/iv)),n=new Set;return[...i,...s].filter(t=>{const e=t.map(t=>Number(t).toFixed(9)).join(","),i=[t[2],t[3],t[0],t[1]].map(t=>Number(t).toFixed(9)).join(","),s=e[t[0]/iv,t[1]/iv,t[2]/iv,t[3]/iv]))}_paperShapes(t){if(!this._spaceWalls.length)return di(t);const e=this._wallUnionGeometry();return e?.paperD?[{path:e.paperD}]:di(t)}_wallUnionGeometry(){const t=this._spaceModel();if(!t)return null;const e=this._spaceWalls,i=this._physicalBodiesR();if(!e.length&&!i.length)return null;const s=this._openCuts(),n=this._roomWallOpeningInputs(),o=`${this._space}|${this._cfgEpoch}|${t.rooms.length}`;return this._wallUnionCache&&this._wallUnionCache.key===o||(this._wallUnionCache={key:o,value:Ic(t.rooms,e,s,n,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,i)}),this._wallUnionCache.value}_thickWallCuts(){const t=this._spaceModel();if(!t)return[];const e=this._spaceWalls;if(!e.length)return[];const i=this._openCuts();return Ac(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,iv).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]])}_wallThickHit(t){const e=this._spaceModel();if(!e)return null;const i=6*this._gridPitch,s=this._openCuts();let n=null;const o=(t,e,s)=>{e>i||(!n||e0?t:0,n=Number.isFinite(e)&&e>0?e:5,o=Number.isFinite(i)&&i>0?i:0;return s>0?gl(s,n,o)/2:mh(1.5*o,n)}(t.cm,this._cellCm,this._gridPitch);let i="";for(const s of t.segs)i+=(i?" ":"")+Ul([[s[0],s[1]],[s[2],s[3]]],e,!1);return{segs:t.segs,open:t.open,d:i}}_wallThickClick(t){const e=this._wallThickHit(t);if(!e)return void this._showToast(this._t("toast.wallthick_pick"));const i=e.cm,s=this._viewOr(this._baseVb()),n=(e.a[0]+e.b[0])/2,o=(e.a[1]+e.b[1])/2;this._wallDialog={a:e.a,b:e.b,value:ml(i,this._imperial),roomId:e.roomId,source:e.source,sx:(n-s.x)/s.w*100,sy:(o-s.y)/s.h*100}}_wallThickApply(t){const e=this._wallDialog;if(!e)return;const i=this._curSpaceCfg,s=this._spaceModel();if(!i||!s)return;const n=e.value.trim(),o=n?qf(n):null;if(null==o)return void this._showPhysicalRange(100);const a=this._imperial?2.54*o:o;if(!Number.isFinite(a)||a<0||a>100)return void this._showPhysicalRange(100);if("room"!==e.source.kind){const t=this._geometrySnapshot();if("partition"===e.source.kind){const t=(i.partitions||[]).find(t=>t.id===e.source.id);if(!t)return;if(0===a&&g_(i.openings,{kind:"partition",id:t.id}))return void this._showToast(this._t("toast.zero_wall_opening_conflict"));t.cm=a}else{const t=(i.room_drafts||[]).find(t=>t.id===e.source.id),s=t?.segments?.[e.source.segment];if(!s)return;s.cm=a}this._wallDialog=null;return this._commitPhysicalGeometry(this._t("history.wall_thickness"),t)&&this._showToast(this._t("toast.wallthick_set")),void this.requestUpdate()}const r=this._geometrySnapshot(),l=a>0?a:null;if(0===a){const s=.02*this._gridPitch,n=[e.a[0],e.a[1],e.b[0],e.b[1]],o=(i.rooms||[]).find(t=>t.id===e.roomId),a=new Set(t&&o&&Array.isArray(o.wall_ids)?o.wall_ids:(i.wall_segments||[]).filter(t=>{const e=[Number(t.a?.[0])*iv,Number(t.a?.[1])*iv],i=[Number(t.b?.[0])*iv,Number(t.b?.[1])*iv];return Ls(e,n)<=s&&Ls(i,n)<=s}).map(t=>String(t.id))),r=(i.openings||[]).some(t=>{if("partition"===t.host?.kind)return!1;if("wall"===t.host?.kind&&a.has(t.host.id))return!0;if(t.host)return!1;const e=[Number(t.x)*iv,Number(t.y)*iv];return e.every(Number.isFinite)&&Ls(e,n)<=s});if(r)return void this._showToast(this._t("toast.zero_wall_opening_conflict"))}let c,h=this._openCuts();if(a>0&&h.length){const n=[];if(t&&e.roomId){const t=(i.rooms||[]).find(t=>t.id===e.roomId),o=new Set(Array.isArray(t?.wall_ids)?t.wall_ids:[]);for(const t of i.wall_segments||[])o.has(t.id)&&n.push([Number(t.a?.[0])*iv,Number(t.a?.[1])*iv,Number(t.b?.[0])*iv,Number(t.b?.[1])*iv]);if(!n.length){const t=s.rooms.find(t=>t.id===e.roomId),i=t?hi(t):null;for(let t=0;i&&t!n.some(e=>Ls([t[0],t[1]],e)<=o&&Ls([t[2],t[3]],e)<=o&&Ls([e[0],e[1]],t)<=o&&Ls([e[2],e[3]],t)<=o))}c=t&&e.roomId?El(i.walls,s.rooms,e.roomId,l,this._wallKeyPitch,h,iv):Fl(i.walls,e.a,e.b,l,this._wallKeyPitch,iv),c=this._normalizeWalls(c,h);for(const t of i.wall_segments||[])t.cm=Pl(c,t.a,t.b,Ph,1);c.length?i.walls=c:delete i.walls,this._wallDialog=null,this._commitPhysicalGeometry(this._t("history.wall_thickness"),r)&&this._showToast(this._t(0===a?"toast.wallthick_cleared":"toast.wallthick_set")),this.requestUpdate()}_wallHatchDefs(t){if(!this._spaceWalls.length&&!this._physicalBodiesR().length&&!this._markup)return j``;const e=pl(this._cellCm);return j` - `}_resolvedRoomFills(t,e){const i=new Map,s=new Map;for(const n of t.rooms){const t=this._roomDialog&&n.id===this._roomEditId?this._roomFill||e.fill:zs(e.fill,n),o=this._roomDialog&&n.id===this._roomEditId?this._roomCustomFill||e.customFill:ls(e.customFill,n),a=_s(t,"lqi"===t&&n.area?this._roomLqi(n.area):null,"light"===t?uo(ho(this._renderPlanHass,this._renderDevices,n,this._virtualLights)):"none","temp"===t?this._roomTemp(n):null,e.tempMin,e.tempMax,this._fillColors,o);i.set(n,a),n.id&&s.set(n.id,a)}return{byRoom:i,byId:s}}_spaceDisplayForRender(){const t=cs(this._curSpaceCfg),e=this._spaceDialog;return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,showBorders:e.showBorders,showNames:e.showNames,hideDecor:e.hideDecor,hideOpenings:e.hideOpenings,color:e.roomColor,opacity:e.roomOpacity,fill:e.fillMode,customFill:e.customFill?rs(e.customFill):as,glow:e.glowEnabled,tempMin:e.tempMin,tempMax:e.tempMax,showLqi:e.showLqi,cardFontScale:e.cardFontScale,labelTemp:e.labelTemp,labelHum:e.labelHum,labelLqi:e.labelLqi,labelLight:e.labelLight}:t}_openingWallIndexFor(t,e){const i=t.rooms.map(t=>`${t.id}:${t.poly?.map(t=>t.join(",")).join("/")||`${t.x},${t.y},${t.w},${t.h}`}`).join(";"),s=this._spaceWalls.map(t=>`${t.key}:${t.a?.join(",")||""}:${t.b?.join(",")||""}:${t.cm}`).join(";"),n=e.map(t=>t.join(",")).join(";"),o=[t.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,s,n].join("|");let a=this._openingWallIndexCache.get(o);return a||(a=Fc(t.rooms,this._spaceWalls,e,this._wallKeyPitch,this._cellCm,this._gridPitch,ev)),Wf(this._openingWallIndexCache,o,a,4),{key:o,value:a}}_renderOpeningTunnelFills(t,e,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return j``;if("glow-base"===i&&![...e.byRoom.values()].some(Boolean))return j``;const s=this._openCuts(),n=this._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),o=n.map(t=>`${t.x},${t.y},${t.angle},${t.length}`).join(";"),a=this._openingWallIndexFor(t,s),r=`${a.key}|${o}`;return this._openingTunnelCache&&this._openingTunnelCache.key===r||(this._openingTunnelCache={key:r,value:qc(a.value,n)}),a_({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:e.byId,idPrefix:`${t.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(t,e,i){const s=new Map,n=new Map,o=this._fillColors.glow_base;for(const a of t.rooms){const t=i.byRoom.get(a),r=Fs(e.glow,a)&&(!t||t.opacity<=0)?{color:o.c,opacity:o.a,mode:"glow"}:null;s.set(a,r),a.id&&n.set(a.id,r)}return{byRoom:s,byId:n}}_renderGlowBaseRooms(t,e){if(this._markup||![...e.byRoom.values()].some(Boolean))return j``;const i=new Map(t.rooms.map(t=>[t,hi(t)])),s=this._openCuts(),n=this._wallUnionGeometry()?.roomGeom,o=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",a=t.rooms.map(a=>{const r=e.byRoom.get(a)||null,l=i.get(a)||null;if(!r||!l)return G;const c=this._spaceWalls.length&&a.id&&fc(t.rooms,a.id,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,n)||l,h=Pi(c,t.rooms.filter(t=>t!==a).map(t=>i.get(t)).filter(t=>!!t)),d=this._cleanFloor(a,c,t).path;return d||h.length?j``}_resolvedRoomFills(t,e){const i=new Map,s=new Map;for(const n of t.rooms){const t=this._roomDialog&&n.id===this._roomEditId?this._roomFill||e.fill:zs(e.fill,n),o=this._roomDialog&&n.id===this._roomEditId?this._roomCustomFill||e.customFill:ls(e.customFill,n),a=_s(t,"lqi"===t&&n.area?this._roomLqi(n.area):null,"light"===t?uo(ho(this._renderPlanHass,this._renderDevices,n,this._virtualLights)):"none","temp"===t?this._roomTemp(n):null,e.tempMin,e.tempMax,this._fillColors,o);i.set(n,a),n.id&&s.set(n.id,a)}return{byRoom:i,byId:s}}_spaceDisplayForRender(){const t=cs(this._curSpaceCfg),e=this._spaceDialog;return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,showBorders:e.showBorders,showNames:e.showNames,hideDecor:e.hideDecor,hideOpenings:e.hideOpenings,color:e.roomColor,opacity:e.roomOpacity,fill:e.fillMode,customFill:e.customFill?rs(e.customFill):as,glow:e.glowEnabled,tempMin:e.tempMin,tempMax:e.tempMax,showLqi:e.showLqi,cardFontScale:e.cardFontScale,labelTemp:e.labelTemp,labelHum:e.labelHum,labelLqi:e.labelLqi,labelLight:e.labelLight}:t}_openingWallIndexFor(t,e){const i=t.rooms.map(t=>`${t.id}:${t.poly?.map(t=>t.join(",")).join("/")||`${t.x},${t.y},${t.w},${t.h}`}`).join(";"),s=this._spaceWalls.map(t=>`${t.key}:${t.a?.join(",")||""}:${t.b?.join(",")||""}:${t.cm}`).join(";"),n=e.map(t=>t.join(",")).join(";"),o=[t.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,s,n].join("|");let a=this._openingWallIndexCache.get(o);return a||(a=Fc(t.rooms,this._spaceWalls,e,this._wallKeyPitch,this._cellCm,this._gridPitch,iv)),jf(this._openingWallIndexCache,o,a,4),{key:o,value:a}}_renderOpeningTunnelFills(t,e,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return j``;if("glow-base"===i&&![...e.byRoom.values()].some(Boolean))return j``;const s=this._openCuts(),n=this._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),o=n.map(t=>`${t.x},${t.y},${t.angle},${t.length}`).join(";"),a=this._openingWallIndexFor(t,s),r=`${a.key}|${o}`;return this._openingTunnelCache&&this._openingTunnelCache.key===r||(this._openingTunnelCache={key:r,value:qc(a.value,n)}),a_({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:e.byId,idPrefix:`${t.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(t,e,i){const s=new Map,n=new Map,o=this._fillColors.glow_base;for(const a of t.rooms){const t=i.byRoom.get(a),r=Fs(e.glow,a)&&(!t||t.opacity<=0)?{color:o.c,opacity:o.a,mode:"glow"}:null;s.set(a,r),a.id&&n.set(a.id,r)}return{byRoom:s,byId:n}}_renderGlowBaseRooms(t,e){if(this._markup||![...e.byRoom.values()].some(Boolean))return j``;const i=new Map(t.rooms.map(t=>[t,hi(t)])),s=this._openCuts(),n=this._wallUnionGeometry()?.roomGeom,o=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",a=t.rooms.map(a=>{const r=e.byRoom.get(a)||null,l=i.get(a)||null;if(!r||!l)return G;const c=this._spaceWalls.length&&a.id&&fc(t.rooms,a.id,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,n)||l,h=Pi(c,t.rooms.filter(t=>t!==a).map(t=>i.get(t)).filter(t=>!!t)),d=this._cleanFloor(a,c,t).path;return d||h.length?j``:a.poly||c!==l?j``)} - `}_isoDecorationLayers(t){const e="undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("filter","blur(1px)"),i="function"==typeof matchMedia&&matchMedia("(forced-colors: active)").matches;return function(t){const e=!!t.showBorders;return{structural:e,panels:e&&!t.hideOpenings,shadows:e&&t.filtersSupported&&!t.forcedColors,materialNuance:e&&!t.forcedColors,floorSymbols:!t.hideOpenings&&!e}}({showBorders:t.showBorders,hideOpenings:t.hideOpenings,filtersSupported:e,forcedColors:i})}_isoOpeningPanels(t){if(!t.panels)return[];const e=this._isoScene();if(!e)return[];return e.openings.flatMap(t=>{const e=this._openingsR[t.sourceIndex];return e?df(t,this._openingAmt(e)):[]}).sort((t,e)=>t.depth-e.depth||t.sourceIndex-e.sourceIndex||t.leaf-e.leaf)}_renderIsoDefs(t,e){const i=_h(this._cellCm);return j` + `}_isoDecorationLayers(t){const e="undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("filter","blur(1px)"),i="function"==typeof matchMedia&&matchMedia("(forced-colors: active)").matches;return function(t){const e=!!t.showBorders;return{structural:e,panels:e&&!t.hideOpenings,shadows:e&&t.filtersSupported&&!t.forcedColors,materialNuance:e&&!t.forcedColors,floorSymbols:!t.hideOpenings&&!e}}({showBorders:t.showBorders,hideOpenings:t.hideOpenings,filtersSupported:e,forcedColors:i})}_isoOpeningPanels(t){if(!t.panels)return[];const e=this._isoScene();if(!e)return[];return e.openings.flatMap(t=>{const e=this._openingsR[t.sourceIndex];return e?pf(t,this._openingAmt(e)):[]}).sort((t,e)=>t.depth-e.depth||t.sourceIndex-e.sourceIndex||t.leaf-e.leaf)}_renderIsoDefs(t,e){const i=_h(this._cellCm);return j` ${"walls"===e&&t.materialNuance?j` @@ -5385,7 +5385,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${t.panels?j``:G} - `:j``}_roomHoverPaths(t){const e=this._hoverRoom;if("view"!==this._mode||!e||e.space!==t.id)return null;const i=t.rooms.find(t=>t===e.room||!!t.id&&t.id===e.room.id);if(!i)return null;const s=hi(i);if(!s)return null;const n=t.rooms.filter(t=>t!==i).map(t=>({room:t,poly:hi(t)})).filter(t=>!!t.poly),o=Pi(s,n.map(t=>t.poly)),a=this._openCuts(),r=.02*this._gridPitch,l=a.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return s.some((t,i)=>Ls(e,[t[0],t[1],...s[(i+1)%s.length]])<=4*r)}),c=this._spaceWalls,h=this._wallUnionGeometry()?.roomGeom,d=c.length&&i.id&&fc(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,h)||s,p=[{axis:s,face:d}];for(const e of o){const i=n.find(t=>t.poly===e)?.room;let s=e;if(c.length&&i?.id){const n=hc(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,ev);n&&(s=zc(n.poly,n.offsets)||e)}p.push({axis:e,face:s})}const u=this._roomWallOpeningInputs(this._openingsR,t).map(t=>{const e=t.angle*Math.PI/180,i=Math.cos(e)*t.length/2,s=Math.sin(e)*t.length/2;return[t.x-i,t.y-s,t.x+i,t.y+s]}),_=l.concat(u),m=p.map(({axis:t,face:e})=>{const i=_.map(i=>((t,e,i)=>{const s=t[2]-t[0],n=t[3]-t[1],o=Math.hypot(s,n);if(o.05)&&Ls([c,h],[i[0],i[1],s[0],s[1]])<=4*r){d=!0;break}}if(!d)return null;let p=null;for(let t=0;t.05)continue;const u=Ls([c,h],[e[0],e[1],s[0],s[1]]);(!p||u!!t);return i.length?Ps(e,i,r).map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" "):`M ${e.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return null;const g=t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`;return{fillD:[this._cleanFloor(i,d,t).path||g(d),...o.map(g)].join(" "),outlineD:m}}_renderRoomHoverFill(t){return t?j` + `:j``}_roomHoverPaths(t){const e=this._hoverRoom;if("view"!==this._mode||!e||e.space!==t.id)return null;const i=t.rooms.find(t=>t===e.room||!!t.id&&t.id===e.room.id);if(!i)return null;const s=hi(i);if(!s)return null;const n=t.rooms.filter(t=>t!==i).map(t=>({room:t,poly:hi(t)})).filter(t=>!!t.poly),o=Pi(s,n.map(t=>t.poly)),a=this._openCuts(),r=.02*this._gridPitch,l=a.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return s.some((t,i)=>Ls(e,[t[0],t[1],...s[(i+1)%s.length]])<=4*r)}),c=this._spaceWalls,h=this._wallUnionGeometry()?.roomGeom,d=c.length&&i.id&&fc(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,h)||s,p=[{axis:s,face:d}];for(const e of o){const i=n.find(t=>t.poly===e)?.room;let s=e;if(c.length&&i?.id){const n=hc(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,iv);n&&(s=zc(n.poly,n.offsets)||e)}p.push({axis:e,face:s})}const u=this._roomWallOpeningInputs(this._openingsR,t).map(t=>{const e=t.angle*Math.PI/180,i=Math.cos(e)*t.length/2,s=Math.sin(e)*t.length/2;return[t.x-i,t.y-s,t.x+i,t.y+s]}),_=l.concat(u),m=p.map(({axis:t,face:e})=>{const i=_.map(i=>((t,e,i)=>{const s=t[2]-t[0],n=t[3]-t[1],o=Math.hypot(s,n);if(o.05)&&Ls([c,h],[i[0],i[1],s[0],s[1]])<=4*r){d=!0;break}}if(!d)return null;let p=null;for(let t=0;t.05)continue;const u=Ls([c,h],[e[0],e[1],s[0],s[1]]);(!p||u!!t);return i.length?Ps(e,i,r).map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" "):`M ${e.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return null;const g=t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`;return{fillD:[this._cleanFloor(i,d,t).path||g(d),...o.map(g)].join(" "),outlineD:m}}_renderRoomHoverFill(t){return t?j` `:j``}_renderRoomHoverOutline(t){return t?j` @@ -5410,7 +5410,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4
-
`:W``}_openingAt(t){if(!this._openingsR.length)return null;const e=this._openingsR.flatMap(e=>{const i=e.angle*Math.PI/180,s=t[0]-e.rx,n=t[1]-e.ry,o=s*Math.cos(i)+n*Math.sin(i);return Math.abs(o)>e.rlen/2+mh(12,this._cellCm)?[]:[{o:e,localY:-s*Math.sin(i)+n*Math.cos(i)}]});if(!e.length)return null;const i=this._spaceModel();if(!i)return null;const s=this._openCuts(),n=this._openingWallIndexFor(i,s).value;return e.find(({o:t,localY:e})=>{const i="gate"===t.type?!t.flip_v:t.flip_v,s=t.partitionHost||this._spaceWalls.length||"gate"===t.type?this._openingFace(t,n,!!i):{ox:0,oy:0,cm:0,side:-1},o=Lu({type:t.type,length:t.rlen,angle:t.angle,amount:this._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this._cellCm,gridPitch:this._gridPitch,face:s});return Math.abs(e)<=o.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this._openingPreset;if("opening"!==this._tool||!e)return null;const i=this._spaceModel();if(!i)return null;const s=this._openCuts(),n=this._openingWallIndexFor(i,s),o=`${n.key}|partitions:${this._cfgEpoch}`;this._openingPlacementIntervalsCache&&this._openingPlacementIntervalsCache.key===o||(this._openingPlacementIntervalsCache={key:o,value:[...dc(i.rooms,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,ev),...Pp(i.partitions,this._cellCm,this._gridPitch)]}),this._openingDimensionContextCache&&this._openingDimensionContextCache.key===o||(this._openingDimensionContextCache={key:o,value:Mf({rooms:i.rooms,walls:this._spaceWalls,openCuts:s,partitions:i.partitions,roomOpenings:this._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(i),pitch:this._wallKeyPitch,cellCm:this._cellCm,gridPitch:this._gridPitch,coordScale:ev,epsilon:2e-4*this._gridPitch})});const a=ff({pointer:[t[0],t[1]],preset:e,geometryRevision:this._cfgEpoch,renderedLength:this._cmToUnits(e.lengthCm),intervals:this._openingPlacementIntervalsCache.value,baseTolerance:1.5*this._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this._pointerModality.modality||"pen"===this._pointerModality.modality?10:6),gridStep:this._gridPitch});this._openingJambBlockCm=a.jambBlockedTarget?a.jambBlockedTarget.physicalHalfWidth/this._gridPitch*this._cellCm:null;const r=a.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let c;if(r.host){const t=$p({id:"preview",type:r.type,x:r.x/ev,y:r.y/ev,angle:r.angle,length:r.renderedLength/ev,host:r.host},i.partitions,ev,this._cellCm,this._gridPitch).resolved;c=t?Dp(t,l):{ox:0,oy:0,cm:0,side:-1}}else c=Lc(n.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const h="mi"===this.hass?.config?.unit_system?.length,d=Af(r,this._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:li(t.distance/this._gridPitch*this._cellCm,h),dimension:t}));return{...r,face:c,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this._tool&&(this._openingPreset=function(t,e){return{type:t,lengthCm:uf(t),flipH:!1,flipV:!1,revision:e}}(t,++this._openingPresetRevision),this._openingHoverCandidate=null,this._cursorPt=null)}_clearOpeningPlacement(t){this._openingHoverCandidate=null,this._openingJambBlockCm=null,t&&(this._openingPreset=null,this._openingRebindId=null)}_openingClick(t){const e=this._spaceModel();if(!e)return;const i=this._openingRebindId?null:this._openingAt(t);if(i)return void this._editOpening(i);const s=this._openingPreset;if(!s)return;const n=this._openingHoverCandidate,o=n&&vf(n,[t[0],t[1]],s.revision,this._cfgEpoch)?n:this._resolveOpeningPlacement(t);if(!o){if(null!=this._openingJambBlockCm)return void this._showToast(this._t("opening.partition_jamb_margin",{distance:li(this._openingJambBlockCm,this._imperial)}));const i=1.5*this._gridPitch,s=ui(t,e.rooms,i);return s&&function(t,e,i,s,n){for(const o of s)if(!(Ls([t,e],o)>n)&&Rl([o[0],o[1]],[o[2],o[3]],i))return!0;return!1}(s.x,s.y,s.angle,this._openCuts(),i)?void this._showToast(this._t("toast.opening_on_zero_wall")):void this._showToast(this._t("toast.opening_no_wall"))}const a=this._openingRebindId?this._curSpaceCfg?.openings?.find(t=>t.id===this._openingRebindId):null;this._openingDialog={...a?{id:a.id,type:a.type,lengthCm:Math.round(a.length*ev/this._gridPitch*this._cellCm),lengthTouched:!1,contact:a.contact||"",lock:a.lock||"",invert:!!a.invert,flipH:!!a.flip_h,flipV:!!a.flip_v}:{type:o.type,lengthCm:o.lengthCm,contact:"",lock:"",invert:!1,flipH:o.flipH,flipV:o.flipV},...o.host?{host:o.host}:{},x:o.x,y:o.y,angle:o.angle},this._openingRebindId=null,this._openingHoverCandidate=null,this._cursorPt=null}_editOpening(t){this._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this._gridPitch*this._cellCm),lengthTouched:!1,contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,..."partition"===t.host?.kind?{host:{...t.host}}:{},x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this._mode&&this._spaceModel()&&"resize"!==this._tool){t.preventDefault(),t.stopPropagation();try{cv(t)}catch{}this._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this._opDrag.sx)+Math.abs(t.clientY-this._opDrag.sy)<=3)return;const i=this._spaceModel();if(!i)return;const s=this._svgPoint(t),n=this._curSpaceCfg,o=n?.openings?.find(t=>t.id===e.id);if(!o)return;if("partition"===o.host?.kind){const t=i.partitions.find(t=>t.id===o.host.id);if(!t)return;const e=t.b[0]-t.a[0],n=t.b[1]-t.a[1],a=Math.hypot(e,n);if(!(a>1e-9))return;const r=e/a,l=n/a;if(Math.abs((s[0]-t.a[0])*l-(s[1]-t.a[1])*r)>4*this._gridPitch)return;const c=o.length*ev/2+kp(t,this._cellCm,this._gridPitch);let h=(s[0]-t.a[0])*r+(s[1]-t.a[1])*l;if(h=Math.round(h/this._gridPitch)*this._gridPitch,h=Math.max(c,Math.min(a-c,h)),a<2*c-1e-9)return;const d=h/a,p=(t.a[0]+r*h)/ev,u=(t.a[1]+l*h)/this._spaceH;let _=180*Math.atan2(n,e)/Math.PI;_>=90?_-=180:_<-90&&(_+=180);const m=o.host.t!==d||o.x!==p||o.y!==u||o.angle!==_;return this._opDrag.moved=!0,m&&(this._opDrag.dirty=!0),o.host={...o.host,t:d},o.x=p,o.y=u,o.angle=_,this._opMeasure=null,m&&this._cfgEpoch++,void this.requestUpdate()}const a=ui(s,i.rooms,4*this._gridPitch);if(!a)return;this._opDrag.moved=!0;const r=this._opRuler(a,o.length*ev);this._opMeasure=r.measure;const l=r.x/ev,c=r.y/this._spaceH,h=o.x!==l||o.y!==c||o.angle!==a.angle;if(h&&(this._opDrag.dirty=!0),o.x=l,o.y=c,o.angle=a.angle,Number(this._serverCfg?.model_version||0)>=9){const t=Km(o,n?.wall_segments||[]);t?o.host=t:delete o.host}h&&this._cfgEpoch++,this.requestUpdate()}_opRuler(t,e){const i=this._spaceModel()?.rooms||[],s=this._gridPitch/2;let n=t.x,o=t.y,a=_i([n,o],t.angle,e,i,s);if(a&&a.centered&&(n!==a.wallCenter[0]||o!==a.wallCenter[1]))[n,o]=a.wallCenter,a=_i([n,o],t.angle,e,i,s);else if(a){const[r,l]=a.wallA,[c,h]=a.wallB,d=c-r,p=h-l,u=Math.hypot(d,p);if(u>0){const c=this._gridPitch,h=Math.min(e/2,u/2);let _=Math.round(((n-r)*d+(o-l)*p)/u/c)*c;_=Math.max(h,Math.min(u-h,_)),n=r+_/u*d,o=l+_/u*p,a=_i([n,o],t.angle,e,i,s)||a}}if(!a)return{x:n,y:o,angle:t.angle,measure:null};const r="mi"===this.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:li(t/this._gridPitch*this._cellCm,r)});return{x:n,y:o,angle:t.angle,measure:{labels:[l(a.sideA,a.midA),l(a.sideB,a.midB)],guide:a.centered?{x:a.wallCenter[0],y:a.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;const i=this._opDrag,s=i.moved;this._opMeasure=null,s&&i.dirty&&this._commitPhysicalGeometry(this._t("history.move_opening"),i.before),s?window.setTimeout(()=>this._opDrag=null,0):this._opDrag=null}_opClick(t,e){"plan"===this._mode&&"resize"===this._tool||(t.stopPropagation(),this._opDrag?.moved||"plan"===this._mode&&this._editOpening(e))}_saveOpening(){const t=this._openingDialog,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=this._geometrySnapshot(),n=this._spaceH,o=(e.openings||[]).find(e=>e.id===t.id),a={...o||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/ev,y:t.y/n,angle:t.angle,length:o&&!t.lengthTouched?o.length:this._cmToUnits(Math.max(20,t.lengthCm))/ev,...t.host?{host:{...t.host}}:{}};if("partition"===a.host?.kind){const t=Mp(o,a)?Sp(a,i.partitions,ev,this._cellCm,this._gridPitch):$p(a,i.partitions,ev,this._cellCm,this._gridPitch);if(!t.resolved){const e=i.partitions.find(t=>t.id===a.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=kp(e,this._cellCm,this._gridPitch);this._showToast(this._t("opening.partition_jamb_margin",{distance:li(t/this._gridPitch*this._cellCm,this._imperial)}))}else this._showToast(this._t("opening.partition_orphan"));return}const s=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===a.id)return[];const e=$p(t,i.partitions,ev,this._cellCm,this._gridPitch).resolved;return e?[e]:[]});if(function(t,e,i=1e-9){const s=t.length/(2*t.axis.length),n=t.t-s,o=t.t+s;return e.some(e=>{if(e.host.id!==t.host.id||e.opening.id===t.opening.id)return!1;const s=e.length/(2*e.axis.length);return Math.max(n,e.t-s)=9){const t=Km(a,e.wall_segments||[]);if(!t)return void this._showToast(this._t("toast.opening_no_wall"));a.host=t}else delete a.host;"passage"===t.type?(delete a.contact,delete a.lock,delete a.invert,delete a.flip_h,delete a.flip_v):(a.contact=t.contact||null,a.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,a.invert=t.invert||void 0,a.flip_h="gate"!==t.type&&t.flipH||void 0,a.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===a.id);r>=0?e.openings[r]=a:e.openings.push(a),this._commitPhysicalGeometry(this._t(t.id?"history.edit_opening":"history.add_opening"),s),this._openingDialog=null,this.requestUpdate()}_deleteOpening(){const t=this._openingDialog,e=this._curSpaceCfg;if(!t?.id||!e?.openings)return;const i=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this._t("history.delete_opening"),i),this._openingDialog=null,this.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.hass.states)){if(!this._openingEntityAvailable(e))continue;const i=e.split(".")[0];if("binary_sensor"!==i&&"cover"!==i)continue;const s=this.hass.states[e],n=["door","window","opening","garage_door","garage"].includes(s?.attributes?.device_class||"");("cover"!==i||n)&&t.push([e,s?.attributes?.friendly_name||e,n?0:1])}return t.sort((t,e)=>t[2]-e[2]||t[1].localeCompare(e[1])).map(([t,e])=>({value:t,label:e}))}_lockCandidates(){return Object.keys(this.hass.states).filter(t=>t.startsWith("lock.")&&this._openingEntityAvailable(t)).map(t=>({value:t,label:this.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this._openingDialog;if(!e)return;const i="contact"===t?!e.contactOpen:!e.lockOpen;this._openingDialog={...e,contactOpen:"contact"===t&&i,lockOpen:"lock"===t&&i}}_filterOpeningEntities(t,e){const i=this._openingDialog;i&&(this._openingDialog="contact"===t?{...i,contactFilter:e}:{...i,lockFilter:e})}_selectOpeningEntity(t,e){const i=this._openingDialog;i&&(this._openingDialog="contact"===t?{...i,contact:e,contactOpen:!1,contactFilter:""}:{...i,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this._spaceModel();if(!e)return;const i=e.rooms,s=[...i].reverse().find(e=>this._pointInRoom(t,e));if(!s?.id)return;const n=s.id;if(!this._mergeSel||this._mergeSel===n)return void(this._mergeSel=this._mergeSel===n?null:n);const o=i.find(t=>t.id===this._mergeSel),a=o?hi(o):null,r=hi(s),l=a&&r?function(t,e){if(!t||!e||t.length<3||e.length<3)return null;const i=si(Ri(t),Ri(e));if(1!==i.length)return null;if(1!==i[0].length)return null;const s=i[0][0].slice(0,-1).map(t=>[t[0],t[1]]);return s.length>=3?s:null}(a,r):null;if(!l)return this._showToast(this._t("toast.merge_not_adjacent")),void(this._mergeSel=null);this._mergeDialog={aId:this._mergeSel,bId:n,poly:l,pick:"a"},this._mergeSel=null}_commitMerge(){const t=this._mergeDialog,e=this._curSpaceCfg;if(!t||!e||!this._spaceModel())return;const i=this._geometrySnapshot(),s=this._spaceH,n="a"===t.pick?t.aId:t.bId,o="a"===t.pick?t.bId:t.aId,a=e.rooms.find(t=>t.id===n);if(!a)return void(this._mergeDialog=null);a.poly=t.poly.map(t=>[t[0]/ev,t[1]/s]),delete a.x,delete a.y,delete a.w,delete a.h,e.rooms=e.rooms.filter(t=>t.id!==o);const r=this._commitPhysicalGeometry(this._t("history.merge_rooms"),i);this._mergeDialog=null,this._regSignature="",this._maybeRebuildDevices(),r&&this._showToast(this._t("toast.rooms_merged",{name:a.name||""}))}_splitClick(t){const e=this._spaceModel();if(!e)return;const i=e.rooms;if(!this._splitSel){const e=[...i].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this._splitSel={roomId:e.id,pts:[]})}const s=i.find(t=>t.id===this._splitSel.roomId),n=s?hi(s):null;if(!s||!n)return void(this._splitSel=null);const o=.02*this._gridPitch,a=6*this._gridPitch,r=function(t,e){if(!e||e.length<2)return null;let i=null,s=1/0;for(let n=0;n=n)continue;n=_;const m=Math.sqrt(p),g=(i>0?Math.max(0,Math.min(m,Math.round(u*m/i)*i)):u*m)/m;s=[a+g*h,r+g*d]}return s}(r,n,this._gridPitch)||r,c=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=a?l:null,h=!!c&&bi(c,n,o),d=this._splitSel.pts;if(!d.length)return h?void(this._splitSel={...this._splitSel,pts:[c]}):void this._showToast(this._t("toast.split_pick_wall"));if(!h){const e=this._snap(t);return wi(e,n,o)?void(this._splitSel={...this._splitSel,pts:[...d,e]}):void this._showToast(this._t("toast.split_pick_inside"))}const p=zi(n,[...d,c],o);if(!p)return void this._showToast(this._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[u,_]=p,m=Ti(u)>=Ti(_)?u:_,g=m===u?_:u;this._pendingSplit={roomId:s.id,mainPoly:m,newPoly:g},this._cursorPt=null,this._nameSel="",this._areaSel="",this._roomDialog=!0}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])&&(null!=this._closingWallCm||!this._activeDraftId)}_markupMove(t){if(!this._markup)return;if("column"===this._tool)return void(this._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this._tool||"wallthick"===this._tool)return void(this._cursorPt=this._svgPoint(t));const e="draw"===this._tool&&!this._contourClosed,i="split"===this._tool&&!!this._splitSel?.pts?.length;if(!e&&!i)return;const s=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(s,t.shiftKey);return this._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this._path.length?void(this._cursorPt=e.point):void this._syncPlanSnapActiveMarker(e.candidate)}this._cursorPt=this._snap(s)}get _openingPreview(){const t=this._openingPreset;if("opening"!==this._tool||!t||!this._cursorPt)return null;const e=this._cursorPt,i=this._openingHoverCandidate;if(i&&vf(i,[e[0],e[1]],t.revision,this._cfgEpoch))return i;if(this._openingAt(e))return this._openingHoverCandidate=null,null;const s=this._resolveOpeningPlacement(e);return this._openingHoverCandidate=s,s}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){(this._areaSel||this._nameSel.trim())&&(this._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this._wallFaceBatch;if(!e)return;const i=e.candidates[e.index];if(!i)return;if(!t&&(i.existing||i.repair)&&1===e.candidates.length)return this._wallFaceBatch=null,this._roomDialog=!1,this._nameSel="",this._areaSel="",void this.requestUpdate();const s=t?{candidate:i,create:!0,name:this._nameSel.trim(),area:this._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:i,create:!1},n=[...e.decisions,s],o=e.index+1;if(o"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,n=.02*this._gridPitch,o=this._spaceModel();if(!o)return ll;for(const e of this._planSnapGeometrySnapshot().value.segments){if("room"===e.sourceKind||Ls(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>n)continue;if("partition"===e.sourceKind)return s(o.partitions.find(t=>t.id===e.sourceId)?.cm)??ll;const i=e.sourceId.lastIndexOf(":"),a=i>=0?e.sourceId.slice(0,i):e.sourceId,r=i>=0?Number(e.sourceId.slice(i+1)):-1;return s(o.room_drafts.find(t=>t.id===a)?.segments[r]?.cm)??ll}const a=Jp(Math.max(0,e.length-1),i,this._drawWallCm,ll);for(let i=0;i+1[...t]);if(!e?.sourceKey.startsWith("active:"))return i;const s=/:(\d+)$/.exec(e.sourceKey),n=s?Number(s[1])+("b"===e.endpoint?1:0):-1;return n>=0&&ne.key===t.sourceKey),o=s.find(e=>e.key===t.targetSourceKey);if(!n||!o)return!1;const a="a"===t.endpoint?n.a:n.b;return!(Math.hypot(a[0]-t.from[0],a[1]-t.from[1])>i)&&(!(Ls(t.to,[o.a[0],o.a[1],o.b[0],o.b[1]])>i)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const i=t.sourceKey.slice(17).split("|")[0];return!!i&&e.some(t=>"partition"===t.host?.kind&&t.host.id===i)}(t,this._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const i=this._curSpaceCfg;if(!i||!this._validateWallRepair(t,e.activePath))return!1;const s=e=>{e[0]=t.to[0]/ev,e[1]=t.to[1]/ev};if(t.sourceKey.startsWith("active:")){const n=/:(\d+)$/.exec(t.sourceKey),o=n?Number(n[1])+("b"===t.endpoint?1:0):-1;if(o<0||o>=e.activePath.length)return!1;e.activePath[o]=[...t.to];const a=(i.room_drafts||[]).find(t=>t.id===e.activeDraftId);return a?.points?.[o]&&s(a.points[o]),!0}if(!t.sourceKey.startsWith("static:"))return!1;const[n,o]=t.sourceKey.slice(7).split("|");if("partition"===n){const e=(i.partitions||[]).find(t=>t.id===o);if(!e)return!1;const n=[e.a[0]*ev,e.a[1]*ev],a=[e.b[0]*ev,e.b[1]*ev],r=Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this._gridPitch?e.a:Math.hypot(a[0]-t.from[0],a[1]-t.from[1])<=2e-4*this._gridPitch?e.b:null;return!!r&&(s(r),!0)}if("draft"===n){const e=o.lastIndexOf(":"),n=e>=0?o.slice(0,e):"",a=e>=0?Number(o.slice(e+1)):-1,r=(i.room_drafts||[]).find(t=>t.id===n);if(!r?.points?.[a]||!r?.points?.[a+1])return!1;const l=[a,a+1].find(e=>Math.hypot(r.points[e][0]*ev-t.from[0],r.points[e][1]*ev-t.from[1])<=2e-4*this._gridPitch);return null!=l&&(s(r.points[l]),!0)}return!1}_applyWallFaceBatch(){const t=this._wallFaceBatch,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=(t,e)=>{this._showToast(this._t(t,e)),this._roomDialogCancel()},n=t.decisions.filter(t=>t.create),o=n.map(t=>t.candidate.ring),a=i.rooms;for(let t=0;ti.id!==e&&!!hi(i)&&Di(o[t],hi(i)));if(i)return void s("toast.room_overlap",{name:i.name||""})}if((e.rooms||[]).length+n.length>400)return void s("toast.physical_limit");if(n.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void s("toast.contour_cannot_close");const r=n.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void s("toast.wall_repair_changed");const l=this._activePathWithRepair(t.activePath,r[0]),c=2e-4*this._gridPitch,h=new Map;for(let e=0;et.candidate.atomKeys)),e=n.some(t=>t.candidate.consumeAllActive);for(const i of vu(this._wallGraphSources(l),c)){const s=i.sourceKeys.find(t=>h.has(t));!s||e||t.has(i.key)||d.push({a:i.a,b:i.b,cm:h.get(s)})}}else d.push(...Xp(l,Jp(l.length-1,t.activeCms,this._drawWallCm,ll)));if((e.partitions||[]).length+d.length>ov)return void s("toast.physical_limit");const p=n.map(t=>t.candidate.ring.map(()=>"")),u=t.activeDraftId?(e.room_drafts||[]).find(e=>e.id===t.activeDraftId):null,_=this._draftSegmentsForPath(t.activePath,u,t.activeCms),m=(t,e)=>{const i=`${t[0].toFixed(9)},${t[1].toFixed(9)}`,s=`${e[0].toFixed(9)},${e[1].toFixed(9)}`;return i<=s?`${i}|${s}`:`${s}|${i}`};for(let e=0;e<_.length;e++){const i=_[e]?.id;if(!i)continue;const s=t.activePath[e],o=t.activePath[e+1],a=[s[0],s[1],o[0],o[1]],r=[];n.forEach((t,e)=>t.candidate.ring.forEach((i,s)=>{const n=t.candidate.ring[(s+1)%t.candidate.ring.length];Ls(i,a)<=c&&Ls(n,a)<=c&&r.push({kind:"room",owner:e,edge:s,a:i,b:n})})),d.forEach((t,e)=>{Ls(t.a,a)<=c&&Ls(t.b,a)<=c&&r.push({kind:"partition",owner:e,edge:0,a:t.a,b:t.b})});const l=[(s[0]+o[0])/2,(s[1]+o[1])/2];r.sort((t,e)=>{const i=[t.a[0],t.a[1],t.b[0],t.b[1]],n=[e.a[0],e.a[1],e.b[0],e.b[1]];return(Ls(l,i)<=c?0:1)-(Ls(l,n)<=c?0:1)||(Ls(s,i)<=c?0:1)-(Ls(s,n)<=c?0:1)||m(t.a,t.b).localeCompare(m(e.a,e.b))});const h=r[0];if(!h)continue;const u=m(h.a,h.b);for(const t of r)m(t.a,t.b)===u&&("room"===t.kind?p[t.owner][t.edge]=i:d[t.owner].id=i)}const g=this._geometrySnapshot();if(r[0]&&!this._applyWallRepair(r[0],t))return void s("toast.wall_repair_changed");const f=n.some(t=>!!t.candidate.split),v=f?pc(i.rooms,e.walls,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,ev):null,y=f&&Array.isArray(e.walls)?e.walls:null;for(const t of n){const i=t.candidate.split;if(!i)continue;const n=e.rooms.find(t=>t.id===i.roomId);if(!n)return void s("toast.contour_cannot_close");n.poly=i.mainPoly.map(t=>[t[0]/ev,t[1]/this._spaceH]),delete n.x,delete n.y,delete n.w,delete n.h}const b=Date.now().toString(36),w=[];if(n.forEach((t,i)=>{const s=t.area?this.hass.areas[t.area]?.name:"",n={id:`r${b}-${i}`,name:t.name||s||this._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/ev,t[1]/this._spaceH]),...p[i].some(Boolean)?{wall_ids:p[i]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(n),w.push({room:n,decision:t})}),t.activeDraftId&&Array.isArray(e.room_drafts)&&(e.room_drafts=e.room_drafts.filter(e=>e.id!==t.activeDraftId),e.room_drafts.length||delete e.room_drafts),d.length&&(e.partitions||=[],d.forEach((t,i)=>e.partitions.push({id:t.id||`partition-${b}-${i}`,a:[t.a[0]/ev,t.a[1]/ev],b:[t.b[0]/ev,t.b[1]/ev],cm:t.cm}))),f){const t=this._normalizeWalls(v,this._openCuts());t.length?e.walls=t:y?.length?e.walls=y:delete e.walls}if(w.length){this._cfgEpoch++;const i=this._openCuts(),s=this._spaceModel();if(!s)return;let n=e.walls;for(const{room:e,decision:o}of w){const a=o.candidate.ring,r=this._wallSourceCmAt(a[0],t.activePath,t.activeCms);n=Nl(n,s.rooms,e.id,r,this._wallKeyPitch,i,ev);for(const o of dc(s.rooms,n,i,this._wallKeyPitch,this._cellCm,this._gridPitch,ev)){if(o.roomId!==e.id||"outer"!==o.kind)continue;const i=[(o.a[0]+o.b[0])/2,(o.a[1]+o.b[1])/2];n=Fl(n,o.a,o.b,this._wallSourceCmAt(i,t.activePath,t.activeCms),this._wallKeyPitch,ev)}}const o=this._normalizeWalls(n,i);o.length?e.walls=o:delete e.walls}if(!this._commitPhysicalGeometry(this._t("history.wall_face_batch"),g))return;delete this._resumeDraftBySpace[this._space],this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._wallFaceBatch=null,this._roomDialog=!1,this._nameSel="",this._areaSel="",this._regSignature="",this._maybeRebuildDevices();const k=new Set(n.map(t=>t.area).filter(t=>!!t));if(k.size){const t={...this._layout};for(const e of this._devices){if(!k.has(e.area||"")||e.space!==this._space)continue;if(this._layout[e.id])continue;const i=this._defPos[e.id];i&&(t[e.id]={s:this._space,x:i.x/ev,y:i.y/ev},this._dirtyPos.add(e.id))}this._layout=t,this._persistLayout()}this._showToast(this._t(n.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:n.length}))}_commitRoom(){const t=this._curSpaceCfg,e=this._spaceModel();if(!t||!e)return;const i=this._geometrySnapshot(),s=this._spaceH,n=!!this._pendingSplit,o=n?pc(e.rooms,t.walls,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,ev):null,a=n&&Array.isArray(t.walls)?t.walls:null;let r;if(this._pendingSplit){const e=t.rooms.find(t=>t.id===this._pendingSplit.roomId);if(!e)return this._pendingSplit=null,this._splitSel=null,void(this._roomDialog=!1);e.poly=this._pendingSplit.mainPoly.map(t=>[t[0]/ev,t[1]/s]),delete e.x,delete e.y,delete e.w,delete e.h,r=this._pendingSplit.newPoly}else{if(!this._contourClosed)return;r=this._path.slice(0,-1)}const l=this._areaSel?this.hass.areas[this._areaSel]?.name:"",c={id:"r"+Date.now().toString(36),name:this._nameSel||l||this._t("room.default_name"),area:this._areaSel||null,poly:r.map(t=>[t[0]/ev,t[1]/s]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(!n&&this._activeDraftId){const e=Array.isArray(t.room_drafts)?t.room_drafts.find(t=>t.id===this._activeDraftId):null,i=Jp(r.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll),s=this._draftSegmentsForPath(this._path,e,i);s.length===r.length&&s.every(t=>!!t.id)&&(c.wall_ids=s.map(t=>t.id))}if(t.rooms.push(c),!n&&this._activeDraftId&&Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),n){const e=this._normalizeWalls(o,this._openCuts());e.length?t.walls=e:a?.length?t.walls=a:delete t.walls}if(!n){const e=Jp(r.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll),i=e[0];if(null!=i){this._cfgEpoch++;const s=this._openCuts(),n=this._spaceModel();if(!n)return;let o=Nl(t.walls,n.rooms,c.id,i,this._wallKeyPitch,s,ev);for(const t of dc(n.rooms,o,s,this._wallKeyPitch,this._cellCm,this._gridPitch,ev)){if(t.roomId!==c.id||"outer"!==t.kind)continue;const i=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],s=r.findIndex((t,e)=>{const s=r[(e+1)%r.length];return Ls(i,[t[0],t[1],s[0],s[1]])<=.02*this._gridPitch});s>=0&&(o=Fl(o,t.a,t.b,e[s],this._wallKeyPitch,ev))}o=this._normalizeWalls(o,s),o.length?t.walls=o:delete t.walls}}const h=this._commitPhysicalGeometry(this._t(n?"history.split_room":"history.add_room"),i);this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._pendingSplit=null,this._splitSel=null;const d=this._areaSel;if(this._areaSel="",this._nameSel="",this._roomDialog=!1,this._regSignature="",this._maybeRebuildDevices(),!h)return;let p=0;if(d){const t=ev,e={...this._layout};for(const i of this._devices){if(i.area!==d||i.space!==this._space)continue;if(p++,this._layout[i.id])continue;const s=this._defPos[i.id];s&&(e[i.id]={s:this._space,x:s.x/ev,y:s.y/t},this._dirtyPos.add(i.id))}this._layout=e,this._persistLayout()}const u=this._model.find(t=>t.id===this._space)?.rooms.length||0;this._showToast(d?this._t("toast.room_saved",{n:u,added:p}):this._t("toast.room_saved_no_area",{n:u}))}_cancelPath(){this._wallRepairDiagnostic=null,this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._clearPlanSnapHover(),this._roomDialog=!1,this._pendingSplit=null,this._wallFaceBatch=null,this._splitSel=null,this._mergeSel=null,this._mergeDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._clearOpeningPlacement(!0)}_resumeLastDraft(){const t=this._resumeDraftBySpace[this._space];if(!t)return;const e=this._spaceModel()?.room_drafts.find(e=>e.id===t);e?(this._activeDraftId=t,this._path=e.points.map(t=>[...t]),this._draftSegmentCms=this._adoptDraftCms(this._path,e.segments.map(t=>t.cm),e.id),this._clearPlanSnapHover()):delete this._resumeDraftBySpace[this._space]}_roomDialogCancel(){if(this._roomDialog=!1,this._roomEditId)return this._roomEditId=null,this._nameSel="",void(this._areaSel="");if(this._wallFaceBatch){const t=this._wallFaceBatch;return this._wallFaceBatch=null,this._path=t.activePath.map(t=>[...t]),this._draftSegmentCms=[...t.activeCms],this._activeDraftId=t.activeDraftId,this._nameSel="",this._areaSel="",void this.requestUpdate()}if(this._pendingSplit)return this._pendingSplit=null,void(this._splitSel=null);this._undoPoint()}get _freeAreas(){const t=new Set;for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area&&t.add(i.area);for(const e of this._wallFaceBatch?.decisions||[])e.create&&e.area&&t.add(e.area);return Object.values(this.hass?.areas||{}).filter(e=>!t.has(e.area_id)).sort((t,e)=>(t.name||"").localeCompare(e.name||""))}_openMarkerDialog(t){if(this._vacAllCamerasFor=null,this._vacAllCameraCache=null,t&&this._ackNewDevice(t.id),this._norm)if(t){const e=t.marker,i=Object.prototype.hasOwnProperty.call(e||{},"is_light"),s=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),n=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),o=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),a=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),r=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),l=ks(e?.glow_color),c=this._devicePresentation(t,!0).valueBadge,h=Wo(this._planHass,t,this._devices),d=jo(this._planHass,t,h);this._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:Bi(t.marker?.display),rippleColor:Rt(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:pp(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:a,originalTapAction:t.marker?.tap_action,tapHintAnnouncement:"",toggleEntity:e?.toggle_entity||"",toggleEntityTouched:!1,originalHasToggleEntity:r,originalToggleEntity:e?.toggle_entity,tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",controls:Zn(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:i,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:s,originalLightEntity:e?.light_entity,glowMode:null!=l?.bri?"fixed":l?"color":"auto",glowColor:l?.c||this._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(l?.bri??1))),glowColorDrafted:!!l,glowBrightnessDrafted:null!=l?.bri,glowTouched:!1,originalHasGlowColor:n&&(!!l||null===e?.glow_color),originalGlowColor:l||(null===e?.glow_color?null:void 0),valueBadgeEnabled:o?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||d,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:o,originalValueBadge:e?.value_badge,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:1.5,size:1,angle:0,tapAction:"info",tapActionTouched:!1,originalHasTapAction:!1,originalTapAction:void 0,tapHintAnnouncement:"",toggleEntity:"",toggleEntityTouched:!1,originalHasToggleEntity:!1,originalToggleEntity:void 0,tapTarget:"",tapConfirm:!1,runFilter:"",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,lightEntity:"",lightEntityTouched:!1,originalHasLightEntity:!1,originalLightEntity:void 0,glowMode:"auto",glowColor:this._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgePosition:"right",valueBadgeTouched:!1,originalHasValueBadge:!1,originalValueBadge:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};else this._showToast(this._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of Gi)for(const[i,s]of Object.entries(this.hass.states))i.startsWith(e+".")&&this._planEntityAvailable(i)&&t.push({value:i,label:s?.attributes?.friendly_name||i,sub:this._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=this._planHass,e=wo(this._markers),i=new Set(this._markers.filter(t=>t.removed).map(t=>t.binding)),s=new Set;for(const t of this._devices)t.id!==this._markerDialog?.devId&&("device"===t.bindingKind&&t.bindingRef&&s.add("device:"+t.bindingRef),"entity"===t.bindingKind&&t.bindingRef&&s.add("entity:"+t.bindingRef));const n=new Set;for(const t of this._devices)"device"===t.bindingKind&&t.name&&n.add(t.name.trim()+"|"+(t.area||""));const o=[];for(const e of Object.values(t.devices)){if("service"===e.entry_type)continue;const t="device:"+e.id;if(s.has(t))continue;const a=(e.name_by_user||e.name||e.id).trim();t!==this._markerDialog?.binding&&!i.has(t)&&n.has(a+"|"+(e.area_id||""))||o.push({value:t,label:a,sub:(e.model||this._t("marker.sub_device"))+("Group"===e.model?this._t("marker.sub_z2m_group"):"")})}const a=new Set(["group","template","derivative","min_max","threshold","integration","statistics","trend","utility_meter","tod","switch_as_x","schedule"]);for(const[n,r]of Object.entries(t.entities)){const l="entity:"+n;if(s.has(l))continue;if(ko(t,n,e)&&!i.has(l))continue;const c=a.has(r.platform),h="group"===r.platform;if(!c&&!h)continue;if(r.hidden&&!i.has(l))continue;const d=t.states[n];o.push({value:l,label:r.name||d?.attributes?.friendly_name||n,sub:n.split(".")[0]+" · "+("group"===r.platform?this._t("marker.sub_group"):this._t("marker.sub_helper"))})}if(this._markerDialog?.showEntities){const n=new Set(o.map(t=>t.value));for(const[a,r]of Object.entries(t.entities)){const l="entity:"+a;if(s.has(l)||n.has(l)||r.hidden&&!i.has(l))continue;const c=!!r.device_id&&e.devices.has(r.device_id);if(ko(t,a,e)&&!i.has(l)&&!c)continue;const h=t.states[a],d=r.name||h?.attributes?.friendly_name||a,p=r.device_id?t.devices[r.device_id]:null,u=p&&(p.name_by_user||p.name)||"";o.push({value:l,label:d,sub:a.split(".")[0]+" · "+this._t("marker.sub_entity")+(u?" · "+u:"")})}}const r=(this._markerDialog?.bindingFilter||"").toLowerCase().trim(),l=r?o.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(r)):o;return l.sort((t,e)=>t.label.localeCompare(e.label)),l.slice(0,200)}_physicalBodiesR(t=this._spaceModel()){if(!t)return[];const e=`${t.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===e)return this._physicalBodiesCache.all;const i=eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t));return this._physicalBodiesCache={key:e,...i},i.all}_rawPhysicalBodiesR(t=this._spaceModel()){if(!t)return[];this._physicalBodiesR(t);const e=this._physicalBodiesCache;return e?[...e.drafts,...e.partitions,...e.columns]:[]}_cleanFloor(t,e,i=this._spaceModel()){if(!i)return{floor:e,geom:null,path:"",area:rh([[[...e,e[0]]]])};const s=t.id||`#${i.rooms.indexOf(t)}`,n=`${i.id}|${this._cfgEpoch}|${s}`;if(!this._rszPreview){const t=qf(this._cleanFloorCache,n);if(t.hit)return t.value}const o=e.map(t=>t[0]),a=e.map(t=>t[1]),r=[Math.min(...o),Math.min(...a),Math.max(...o),Math.max(...a)],l=this._physicalBodiesR(i).filter(t=>{const e=t.map(t=>t[0]),i=t.map(t=>t[1]);return Math.max(...e)>=r[0]&&Math.min(...e)<=r[2]&&Math.max(...i)>=r[1]&&Math.min(...i)<=r[3]}),c=l.length?ah(e,l):null,h={floor:e,geom:c,path:c?Jc(c):"",area:rh(c||[[[...e,e[0]]]])};return this._rszPreview||Wf(this._cleanFloorCache,n,h,600),h}_autoIconForBinding(t){if("virtual"===t)return"mdi:map-marker";const[e,i]=t.split(":");if(!i)return"";const s=this._fullRegistryHass,n=this._bindingStatus(t),o="active"===n.kind?n.enabledEntityIds:n.allEntityIds;if("device"===e){const t=s.devices?.[i];if(!t)return"mdi:help-circle";const e=o;return e.some(t=>t.startsWith("lock."))?"mdi:lock":bo(s,t.name_by_user||t.name||"",t.model,e,this._iconRules)}if("entity"===e){const t=s.entities?.[i],e=this.hass.states?.[i],n=t?.name||e?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":bo(s,n,"",[i],this._iconRules)}return""}_allRoomsFlat(){const t=[];for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area?t.push({value:e.id+"#"+i.area,label:(e.title||e.id)+" · "+i.name}):i.id&&t.push({value:e.id+"#@"+i.id,label:(e.title||e.id)+" · "+i.name+" · "+this._t("marker.subarea")});return t}_errText(t){if(!t)return this._t("err.unknown");if("string"==typeof t)return t;if("invalid_passage_fields"===t.code){const e=String(t.message||t.error||"").match(/space=([^;]*);\s*opening=([^;]*);\s*fields=([^;]*)/);if(e){const t=this._serverCfg?.spaces?.find(t=>String(t.id)===e[1]),i={contact:"opening.contact_label",lock:"opening.lock_label",invert:"opening.invert",flip_h:"opening.flip_h",flip_v:"opening.flip_v"},s=e[3].split(",").filter(Boolean).map(t=>i[t]?this._t(i[t]):t).join(", ");return this._t("opening.invalid_passage_fields",{room:t?.title||e[1],fields:s})}}if("invalid_partition_opening_jamb_margin"===t.code){const e=String(t.message||t.error||"").match(/margin_cm=([^;]*)/),i=e?Number(e[1]):NaN;if(Number.isFinite(i))return this._t("opening.partition_jamb_margin",{distance:li(i,this._imperial)})}if(t.message)return t.message;if(t.error)return t.error;if(null!=t.code)return this._t("err.code",{code:t.code});try{return JSON.stringify(t)}catch{return String(t)}}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,i=this._t(t);if(i!==t)return i}return this._errText(t)}async _pickMarkerFiles(t){const e=t.target,i=e.files?[...e.files]:[];if(e.value="",!i.length||!this._markerDialog)return;const s=this._markerDialog.uploadId||this._markerDialog.devId||"new",n=[];for(const t of i)try{const e=new FormData;e.append("marker_id",s),e.append("file",t,t.name);const i=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error){const t={too_large:this._t("err.too_large",{mb:o.max_mb||50}),bad_ext:this._t("err.bad_ext"),unauthorized:this._t("err.unauthorized")};throw new Error(t[o.error]||o.error||"HTTP "+i.status)}n.push({name:o.name||t.name,url:o.url})}catch(e){this._showToast(this._t("toast.file_failed",{name:t.name,err:this._errText(e)}))}n.length&&this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:[...this._markerDialog.pdfs,...n]},this._showToast(this._t("toast.files_attached",{n:n.length})))}_removeMarkerPdf(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:this._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.lightEntityTouched?t.lightEntity&&(e.light_entity=t.lightEntity):t.originalHasLightEntity&&(e.light_entity=t.originalLightEntity??null),t.glowTouched){if("auto"!==t.glowMode){const i={c:Rt(t.glowColor,this._fillColors.glow_light.c)};"fixed"===t.glowMode&&(i.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=i}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}_markerTapActionFields(t){return t.tapActionTouched?{tap_action:t.tapAction||null}:t.originalHasTapAction?{tap_action:t.originalTapAction??null}:{}}_markerToggleEntityFields(t){return(e={touched:t.toggleEntityTouched,originalHas:t.originalHasToggleEntity,original:t.originalToggleEntity,value:t.toggleEntity}).touched?e.value?{toggle_entity:e.value}:{}:e.originalHas?{toggle_entity:e.original??null}:{};var e}async _saveMarker(){const t=this._markerDialog;if(!t||t.busy)return;const e=this._effectiveMarkerTapAction(t);if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return;if("virtual"===t.binding&&!t.name.trim())return void this._showToast(this._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this._showToast(this._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this._showToast(this._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this._bindingStatus(t.binding),i=t.devId?this._markers.find(e=>e.id===t.devId):null,s=!i||i.binding!==t.binding;if("active"!==e.kind&&s)return void this._showToast(this._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===i?.hidden&&!t.hideFromPlan)return this._markerDialog={...t,hideFromPlan:!0},void this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const i=this._serverCfg;if(!i)return;const s=i.markers||[],n=qs(t.room);let o=n?.space||null;const a=n?.area||null,r=n?.roomId||null,l=Fi(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),c=t.devId,h=c?this._devices.find(t=>t.id===c):null,d=n?.space||h?.space||null,p=d?this._spaceModelById(d):this._spaceModel();if(!p)return;const u=p.id;"virtual"!==t.binding||o||(o=u),this._markerDialog={...t,busy:!0};try{const n="virtual"===t.binding?[]:s.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=n.length>0,_=Zn(t.binding,t.controls,this._bindingEntities(t.binding)),m=s.find(t=>t.id===l||t.id===c)?.vacuum||null,g={id:l,vacuum:m,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===e&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:_.length?_:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=Bf(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};("virtual"===t.binding||t.room)&&(g.space=o,g.area=a,g.room_id=r);const f=h?.marker?.room_id??null,v=!!t.room&&null!=h&&(h.space!==o||h.area!==a||f!==r);let y=!1;const b=t.uploadId||c;if(b&&b!==l&&g.pdfs?.length)try{const t=await this.hass.callWS({type:"houseplan/files/migrate",from_id:b,to_id:l}),e=t?.mapping||{};g.pdfs=function(t,e,i,s){if(!e||!i||e===i)return t;const n="/files/"+e+"/",o="/files/"+i+"/";return t.map(t=>{if(!t.url.includes(n))return t;const e=t.url.split(n)[1]||"",[i,a]=[e.split("?")[0],e.includes("?")?"?"+e.split("?")[1]:""];if(s){const e=s[decodeURIComponent(i)]??s[i];return e?{...t,url:t.url.split(n+i)[0]+o+encodeURIComponent(e)+a}:t}return{...t,url:t.url.split(n).join(o)}})}(g.pdfs,b,l,e),y=Object.keys(e).length>0}catch(t){this._showToast(this._t("toast.files_migrate_failed",{err:this._errText(t)}))}i.markers=s,c&&c!==l&&(i.markers=function(t,e,i){if(!e||!i||e===i)return[...t];const s=`marker:${e}`,n=`marker:${i}`;return t.map(t=>{const e=Array.isArray(t.controls)?t.controls.map(t=>t===s?n:t):t.controls,i="derived_marker_state"===t.value_badge?.source?.kind&&t.value_badge.source.ref===s?{...t.value_badge,source:{...t.value_badge.source,ref:n}}:t.value_badge;return e===t.controls&&i===t.value_badge?t:{...t,controls:e,value_badge:i}})}(i.markers,c,l)),c&&c!==l&&"derived_marker_state"===g.value_badge?.source?.kind&&g.value_badge.source.ref===`marker:${c}`&&(g.value_badge.source={kind:"derived_marker_state",ref:`marker:${l}`}),i.markers=i.markers.filter(t=>t.id!==l&&t.id!==c&&("virtual"===g.binding||t.binding!==g.binding)),i.markers.push(g);let w=null;const k=c?this._layout[c]:null,x=k?{s:k.s||h?.space||this._space,x:k.x,y:k.y}:c&&h&&this._defPos[c]?this._normPos(h.space,this._defPos[c].x,this._defPos[c].y):null;if(!d&&x&&x.s===u)l===c&&this._layout[l]&&!v||(w={s:x.s,x:x.x,y:x.y},this._layout={...this._layout,[l]:w});else if(d||!this._layout[l]||v){let t=p.vb[0]+p.vb[2]/2,e=p.vb[1]+p.vb[3]/2;const i=r?p.rooms.find(t=>t.id===r):a?p.rooms.find(t=>t.area===a):void 0;i&&([t,e]=this._roomCenter(i)),w=this._normPos(u,t,e),this._layout={...this._layout,[l]:w}}if(await this._saveConfigNow(),w){const t=ol(w);this._layout={...this._layout,[l]:t},this._noteLayoutRev(await this.hass.callWS({type:"houseplan/layout/update",device_id:l,pos:t}))}const $=new Set(n);c&&c!==l&&$.add(c),$.delete(l);for(const t of $)delete this._layout[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{});y&&b&&await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:b}).catch(()=>{}),this._markerDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_saved"))}catch(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteMarker(){const t=this._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this._devices.find(e=>e.id===t.devId):null;if(!e)return;const i=t.name||this._t("device.fallback");if(!confirm(this._t("confirm.remove_marker",{name:i})))return;const s=this._serverCfg;s.markers=s.markers||[];const n=s.markers,o="virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"";if(!o)return;const a=function(t,e,i,s){const n=new Set([e]),o=t.filter(t=>{const o=t.id===e||!s&&t.binding===i;return o&&n.add(t.id),!o});return{markers:s?o:[...o,{id:e,binding:i,removed:!0,hidden:!0}],cleanupIds:n}}(s.markers,e.id,o,"virtual"===e.bindingKind);var r,l;s.markers=(r=a.markers,l=a.cleanupIds,r.map(t=>{if(!Array.isArray(t.controls))return t;const e=t.controls.filter(t=>!("string"==typeof t&&t.startsWith("marker:")&&l.has(t.slice(7))));return e.length===t.controls.length?t:{...t,controls:e.length?e:null}}));const c=a.cleanupIds;this._markerDialog={...t,busy:!0};try{await this._saveConfigNow();for(const t of c){delete this._layout[t],delete this._defPos[t],this._dirtyPos.delete(t),this._sentPos.delete(t);const e=this._activityRt.get(t);e&&clearTimeout(e.timer),this._activityRt.delete(t),this._vacRt.delete(t),delete this._vacSrvTrails[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{}),await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this._markerDialog=null,this._infoCard?.id===e.id&&this._closeInfoCard(),this._selId===e.id&&(this._selId=null),this._drag?.id===e.id&&(this._drag=null),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_removed"))}catch(t){this._serverCfg===s&&(s.markers=n),this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}_normPos(t,e,i){return{s:t,x:e/ev,y:i/ev}}_openSpaceDialog(t,e){if(this._serverStorage&&this._serverCfg)if("edit"===t){const i=this._serverCfg.spaces.find(t=>t.id===e);if(!i)return;const s=cs(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?rs(i.settings.custom_fill):null,o="none"===s.fill?{...n||as,a:0}:n;this._spaceDialog={mode:t,spaceId:e,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:s.showBorders,showNames:s.showNames,zeroWallStyle:d_(i),displayTouched:!0,hideDecor:s.hideDecor,hideOpenings:s.hideOpenings,roomColor:s.color,roomOpacity:s.opacity,fillMode:"none"===s.fill?"custom":s.fill,customFill:o,glowEnabled:s.glow,bgColor:s.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:$r({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:s.tempMin,tempMax:s.tempMax,showLqi:s.showLqi??this._config?.show_signal??!0,cardFontScale:s.cardFontScale,labelTemp:s.labelTemp,labelHum:s.labelHum,labelLqi:s.labelLqi,labelLight:s.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:fh(Number(i.cell_cm)>0?Number(i.cell_cm):5,this._imperial),cellCmTouched:!1,busy:!1}}else this._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...Sd(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ns,roomOpacity:os,fillMode:"custom",customFill:{...as,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:gh(this._imperial),cellCmInput:fh(gh(this._imperial),this._imperial),cellCmTouched:!1,busy:!1};else this._showToast(this._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,i=e.files?.[0];if(!i||!this._spaceDialog)return;const s={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[i.type]||(i.name.toLowerCase().endsWith(".svg")?"svg":"");if(!s)return void this._showToast(this._t("toast.plan_formats"));const n=new Uint8Array(await i.arrayBuffer());let o="";for(let t=0;t{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:1.414),e.onerror=()=>t(1.414),e.src=r});URL.revokeObjectURL(r),this._spaceDialog={...this._spaceDialog,planFile:{ext:s,b64:a,aspect:l,name:i.name}}}_useServerPlan(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this._display(t);if(e){const i=await new Promise(t=>{const i=new Image;i.onload=()=>t(i.naturalWidth&&i.naturalHeight?i.naturalWidth/i.naturalHeight:0),i.onerror=()=>t(0),i.src=e}),s=this._spaceDialog;return s&&s.planUrl===t&&Number.isFinite(i)&&i>0?(this._spaceDialog={...s,savedAspect:i},i):0}if(await new Promise(t=>setTimeout(t,150)),this._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this._t("confirm.delete_plan",{name:t})))try{await this.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this._spaceDialog;e?.saved&&(this._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this._showToast(this._t("toast.plan_delete_failed",{err:this._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return W`
${this._t("space.loading")}
`;const e=t.saved||[];if(!e.length)return W`
${this._t("space.no_saved")}
`;return W`
+
`:W``}_openingAt(t){if(!this._openingsR.length)return null;const e=this._openingsR.flatMap(e=>{const i=e.angle*Math.PI/180,s=t[0]-e.rx,n=t[1]-e.ry,o=s*Math.cos(i)+n*Math.sin(i);return Math.abs(o)>e.rlen/2+mh(12,this._cellCm)?[]:[{o:e,localY:-s*Math.sin(i)+n*Math.cos(i)}]});if(!e.length)return null;const i=this._spaceModel();if(!i)return null;const s=this._openCuts(),n=this._openingWallIndexFor(i,s).value;return e.find(({o:t,localY:e})=>{const i="gate"===t.type?!t.flip_v:t.flip_v,s=t.partitionHost||this._spaceWalls.length||"gate"===t.type?this._openingFace(t,n,!!i):{ox:0,oy:0,cm:0,side:-1},o=Lu({type:t.type,length:t.rlen,angle:t.angle,amount:this._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this._cellCm,gridPitch:this._gridPitch,face:s});return Math.abs(e)<=o.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this._openingPreset;if("opening"!==this._tool||!e)return null;const i=this._spaceModel();if(!i)return null;const s=this._openCuts(),n=this._openingWallIndexFor(i,s),o=`${n.key}|partitions:${this._cfgEpoch}`;this._openingPlacementIntervalsCache&&this._openingPlacementIntervalsCache.key===o||(this._openingPlacementIntervalsCache={key:o,value:[...dc(i.rooms,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,iv),...Pp(i.partitions,this._cellCm,this._gridPitch)]}),this._openingDimensionContextCache&&this._openingDimensionContextCache.key===o||(this._openingDimensionContextCache={key:o,value:Cf({rooms:i.rooms,walls:this._spaceWalls,openCuts:s,partitions:i.partitions,roomOpenings:this._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(i),pitch:this._wallKeyPitch,cellCm:this._cellCm,gridPitch:this._gridPitch,coordScale:iv,epsilon:2e-4*this._gridPitch})});const a=vf({pointer:[t[0],t[1]],preset:e,geometryRevision:this._cfgEpoch,renderedLength:this._cmToUnits(e.lengthCm),intervals:this._openingPlacementIntervalsCache.value,baseTolerance:1.5*this._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this._pointerModality.modality||"pen"===this._pointerModality.modality?10:6),gridStep:this._gridPitch});this._openingJambBlockCm=a.jambBlockedTarget?a.jambBlockedTarget.physicalHalfWidth/this._gridPitch*this._cellCm:null;const r=a.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let c;if(r.host){const t=$p({id:"preview",type:r.type,x:r.x/iv,y:r.y/iv,angle:r.angle,length:r.renderedLength/iv,host:r.host},i.partitions,iv,this._cellCm,this._gridPitch).resolved;c=t?Dp(t,l):{ox:0,oy:0,cm:0,side:-1}}else c=Lc(n.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const h="mi"===this.hass?.config?.unit_system?.length,d=zf(r,this._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:li(t.distance/this._gridPitch*this._cellCm,h),dimension:t}));return{...r,face:c,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this._tool&&(this._openingPreset=function(t,e){return{type:t,lengthCm:_f(t),flipH:!1,flipV:!1,revision:e}}(t,++this._openingPresetRevision),this._openingHoverCandidate=null,this._cursorPt=null)}_clearOpeningPlacement(t){this._openingHoverCandidate=null,this._openingJambBlockCm=null,t&&(this._openingPreset=null,this._openingRebindId=null)}_openingClick(t){const e=this._spaceModel();if(!e)return;const i=this._openingRebindId?null:this._openingAt(t);if(i)return void this._editOpening(i);const s=this._openingPreset;if(!s)return;const n=this._openingHoverCandidate,o=n&&yf(n,[t[0],t[1]],s.revision,this._cfgEpoch)?n:this._resolveOpeningPlacement(t);if(!o){if(null!=this._openingJambBlockCm)return void this._showToast(this._t("opening.partition_jamb_margin",{distance:li(this._openingJambBlockCm,this._imperial)}));const i=1.5*this._gridPitch,s=ui(t,e.rooms,i);return s&&function(t,e,i,s,n){for(const o of s)if(!(Ls([t,e],o)>n)&&Rl([o[0],o[1]],[o[2],o[3]],i))return!0;return!1}(s.x,s.y,s.angle,this._openCuts(),i)?void this._showToast(this._t("toast.opening_on_zero_wall")):void this._showToast(this._t("toast.opening_no_wall"))}const a=this._openingRebindId?this._curSpaceCfg?.openings?.find(t=>t.id===this._openingRebindId):null;this._openingDialog={...a?{id:a.id,type:a.type,lengthCm:Math.round(a.length*iv/this._gridPitch*this._cellCm),lengthTouched:!1,contact:a.contact||"",lock:a.lock||"",invert:!!a.invert,flipH:!!a.flip_h,flipV:!!a.flip_v}:{type:o.type,lengthCm:o.lengthCm,contact:"",lock:"",invert:!1,flipH:o.flipH,flipV:o.flipV},...o.host?{host:o.host}:{},x:o.x,y:o.y,angle:o.angle},this._openingRebindId=null,this._openingHoverCandidate=null,this._cursorPt=null}_editOpening(t){this._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this._gridPitch*this._cellCm),lengthTouched:!1,contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,..."partition"===t.host?.kind?{host:{...t.host}}:{},x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this._mode&&this._spaceModel()&&"resize"!==this._tool){t.preventDefault(),t.stopPropagation();try{hv(t)}catch{}this._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this._opDrag.sx)+Math.abs(t.clientY-this._opDrag.sy)<=3)return;const i=this._spaceModel();if(!i)return;const s=this._svgPoint(t),n=this._curSpaceCfg,o=n?.openings?.find(t=>t.id===e.id);if(!o)return;if("partition"===o.host?.kind){const t=i.partitions.find(t=>t.id===o.host.id);if(!t)return;const e=t.b[0]-t.a[0],n=t.b[1]-t.a[1],a=Math.hypot(e,n);if(!(a>1e-9))return;const r=e/a,l=n/a;if(Math.abs((s[0]-t.a[0])*l-(s[1]-t.a[1])*r)>4*this._gridPitch)return;const c=o.length*iv/2+kp(t,this._cellCm,this._gridPitch);let h=(s[0]-t.a[0])*r+(s[1]-t.a[1])*l;if(h=Math.round(h/this._gridPitch)*this._gridPitch,h=Math.max(c,Math.min(a-c,h)),a<2*c-1e-9)return;const d=h/a,p=(t.a[0]+r*h)/iv,u=(t.a[1]+l*h)/this._spaceH;let _=180*Math.atan2(n,e)/Math.PI;_>=90?_-=180:_<-90&&(_+=180);const m=o.host.t!==d||o.x!==p||o.y!==u||o.angle!==_;return this._opDrag.moved=!0,m&&(this._opDrag.dirty=!0),o.host={...o.host,t:d},o.x=p,o.y=u,o.angle=_,this._opMeasure=null,m&&this._cfgEpoch++,void this.requestUpdate()}const a=ui(s,i.rooms,4*this._gridPitch);if(!a)return;this._opDrag.moved=!0;const r=this._opRuler(a,o.length*iv);this._opMeasure=r.measure;const l=r.x/iv,c=r.y/this._spaceH,h=o.x!==l||o.y!==c||o.angle!==a.angle;if(h&&(this._opDrag.dirty=!0),o.x=l,o.y=c,o.angle=a.angle,Number(this._serverCfg?.model_version||0)>=9){const t=Km(o,n?.wall_segments||[]);t?o.host=t:delete o.host}h&&this._cfgEpoch++,this.requestUpdate()}_opRuler(t,e){const i=this._spaceModel()?.rooms||[],s=this._gridPitch/2;let n=t.x,o=t.y,a=_i([n,o],t.angle,e,i,s);if(a&&a.centered&&(n!==a.wallCenter[0]||o!==a.wallCenter[1]))[n,o]=a.wallCenter,a=_i([n,o],t.angle,e,i,s);else if(a){const[r,l]=a.wallA,[c,h]=a.wallB,d=c-r,p=h-l,u=Math.hypot(d,p);if(u>0){const c=this._gridPitch,h=Math.min(e/2,u/2);let _=Math.round(((n-r)*d+(o-l)*p)/u/c)*c;_=Math.max(h,Math.min(u-h,_)),n=r+_/u*d,o=l+_/u*p,a=_i([n,o],t.angle,e,i,s)||a}}if(!a)return{x:n,y:o,angle:t.angle,measure:null};const r="mi"===this.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:li(t/this._gridPitch*this._cellCm,r)});return{x:n,y:o,angle:t.angle,measure:{labels:[l(a.sideA,a.midA),l(a.sideB,a.midB)],guide:a.centered?{x:a.wallCenter[0],y:a.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;const i=this._opDrag,s=i.moved;this._opMeasure=null,s&&i.dirty&&this._commitPhysicalGeometry(this._t("history.move_opening"),i.before),s?window.setTimeout(()=>this._opDrag=null,0):this._opDrag=null}_opClick(t,e){"plan"===this._mode&&"resize"===this._tool||(t.stopPropagation(),this._opDrag?.moved||"plan"===this._mode&&this._editOpening(e))}_saveOpening(){const t=this._openingDialog,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=this._geometrySnapshot(),n=this._spaceH,o=(e.openings||[]).find(e=>e.id===t.id),a={...o||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/iv,y:t.y/n,angle:t.angle,length:o&&!t.lengthTouched?o.length:this._cmToUnits(Math.max(20,t.lengthCm))/iv,...t.host?{host:{...t.host}}:{}};if("partition"===a.host?.kind){const t=Mp(o,a)?Sp(a,i.partitions,iv,this._cellCm,this._gridPitch):$p(a,i.partitions,iv,this._cellCm,this._gridPitch);if(!t.resolved){const e=i.partitions.find(t=>t.id===a.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=kp(e,this._cellCm,this._gridPitch);this._showToast(this._t("opening.partition_jamb_margin",{distance:li(t/this._gridPitch*this._cellCm,this._imperial)}))}else this._showToast(this._t("opening.partition_orphan"));return}const s=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===a.id)return[];const e=$p(t,i.partitions,iv,this._cellCm,this._gridPitch).resolved;return e?[e]:[]});if(function(t,e,i=1e-9){const s=t.length/(2*t.axis.length),n=t.t-s,o=t.t+s;return e.some(e=>{if(e.host.id!==t.host.id||e.opening.id===t.opening.id)return!1;const s=e.length/(2*e.axis.length);return Math.max(n,e.t-s)=9){const t=Km(a,e.wall_segments||[]);if(!t)return void this._showToast(this._t("toast.opening_no_wall"));a.host=t}else delete a.host;"passage"===t.type?(delete a.contact,delete a.lock,delete a.invert,delete a.flip_h,delete a.flip_v):(a.contact=t.contact||null,a.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,a.invert=t.invert||void 0,a.flip_h="gate"!==t.type&&t.flipH||void 0,a.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===a.id);r>=0?e.openings[r]=a:e.openings.push(a),this._commitPhysicalGeometry(this._t(t.id?"history.edit_opening":"history.add_opening"),s),this._openingDialog=null,this.requestUpdate()}_deleteOpening(){const t=this._openingDialog,e=this._curSpaceCfg;if(!t?.id||!e?.openings)return;const i=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this._t("history.delete_opening"),i),this._openingDialog=null,this.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.hass.states)){if(!this._openingEntityAvailable(e))continue;const i=e.split(".")[0];if("binary_sensor"!==i&&"cover"!==i)continue;const s=this.hass.states[e],n=["door","window","opening","garage_door","garage"].includes(s?.attributes?.device_class||"");("cover"!==i||n)&&t.push([e,s?.attributes?.friendly_name||e,n?0:1])}return t.sort((t,e)=>t[2]-e[2]||t[1].localeCompare(e[1])).map(([t,e])=>({value:t,label:e}))}_lockCandidates(){return Object.keys(this.hass.states).filter(t=>t.startsWith("lock.")&&this._openingEntityAvailable(t)).map(t=>({value:t,label:this.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this._openingDialog;if(!e)return;const i="contact"===t?!e.contactOpen:!e.lockOpen;this._openingDialog={...e,contactOpen:"contact"===t&&i,lockOpen:"lock"===t&&i}}_filterOpeningEntities(t,e){const i=this._openingDialog;i&&(this._openingDialog="contact"===t?{...i,contactFilter:e}:{...i,lockFilter:e})}_selectOpeningEntity(t,e){const i=this._openingDialog;i&&(this._openingDialog="contact"===t?{...i,contact:e,contactOpen:!1,contactFilter:""}:{...i,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this._spaceModel();if(!e)return;const i=e.rooms,s=[...i].reverse().find(e=>this._pointInRoom(t,e));if(!s?.id)return;const n=s.id;if(!this._mergeSel||this._mergeSel===n)return void(this._mergeSel=this._mergeSel===n?null:n);const o=i.find(t=>t.id===this._mergeSel),a=o?hi(o):null,r=hi(s),l=a&&r?function(t,e){if(!t||!e||t.length<3||e.length<3)return null;const i=si(Ri(t),Ri(e));if(1!==i.length)return null;if(1!==i[0].length)return null;const s=i[0][0].slice(0,-1).map(t=>[t[0],t[1]]);return s.length>=3?s:null}(a,r):null;if(!l)return this._showToast(this._t("toast.merge_not_adjacent")),void(this._mergeSel=null);this._mergeDialog={aId:this._mergeSel,bId:n,poly:l,pick:"a"},this._mergeSel=null}_commitMerge(){const t=this._mergeDialog,e=this._curSpaceCfg;if(!t||!e||!this._spaceModel())return;const i=this._geometrySnapshot(),s=this._spaceH,n="a"===t.pick?t.aId:t.bId,o="a"===t.pick?t.bId:t.aId,a=e.rooms.find(t=>t.id===n);if(!a)return void(this._mergeDialog=null);a.poly=t.poly.map(t=>[t[0]/iv,t[1]/s]),delete a.x,delete a.y,delete a.w,delete a.h,e.rooms=e.rooms.filter(t=>t.id!==o);const r=this._commitPhysicalGeometry(this._t("history.merge_rooms"),i);this._mergeDialog=null,this._regSignature="",this._maybeRebuildDevices(),r&&this._showToast(this._t("toast.rooms_merged",{name:a.name||""}))}_splitClick(t){const e=this._spaceModel();if(!e)return;const i=e.rooms;if(!this._splitSel){const e=[...i].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this._splitSel={roomId:e.id,pts:[]})}const s=i.find(t=>t.id===this._splitSel.roomId),n=s?hi(s):null;if(!s||!n)return void(this._splitSel=null);const o=.02*this._gridPitch,a=6*this._gridPitch,r=function(t,e){if(!e||e.length<2)return null;let i=null,s=1/0;for(let n=0;n=n)continue;n=_;const m=Math.sqrt(p),g=(i>0?Math.max(0,Math.min(m,Math.round(u*m/i)*i)):u*m)/m;s=[a+g*h,r+g*d]}return s}(r,n,this._gridPitch)||r,c=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=a?l:null,h=!!c&&bi(c,n,o),d=this._splitSel.pts;if(!d.length)return h?void(this._splitSel={...this._splitSel,pts:[c]}):void this._showToast(this._t("toast.split_pick_wall"));if(!h){const e=this._snap(t);return wi(e,n,o)?void(this._splitSel={...this._splitSel,pts:[...d,e]}):void this._showToast(this._t("toast.split_pick_inside"))}const p=zi(n,[...d,c],o);if(!p)return void this._showToast(this._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[u,_]=p,m=Ti(u)>=Ti(_)?u:_,g=m===u?_:u;this._pendingSplit={roomId:s.id,mainPoly:m,newPoly:g},this._cursorPt=null,this._nameSel="",this._areaSel="",this._roomDialog=!0}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])&&(null!=this._closingWallCm||!this._activeDraftId)}_markupMove(t){if(!this._markup)return;if("column"===this._tool)return void(this._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this._tool||"wallthick"===this._tool)return void(this._cursorPt=this._svgPoint(t));const e="draw"===this._tool&&!this._contourClosed,i="split"===this._tool&&!!this._splitSel?.pts?.length;if(!e&&!i)return;const s=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(s,t.shiftKey);return this._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this._path.length?void(this._cursorPt=e.point):void this._syncPlanSnapActiveMarker(e.candidate)}this._cursorPt=this._snap(s)}get _openingPreview(){const t=this._openingPreset;if("opening"!==this._tool||!t||!this._cursorPt)return null;const e=this._cursorPt,i=this._openingHoverCandidate;if(i&&yf(i,[e[0],e[1]],t.revision,this._cfgEpoch))return i;if(this._openingAt(e))return this._openingHoverCandidate=null,null;const s=this._resolveOpeningPlacement(e);return this._openingHoverCandidate=s,s}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){(this._areaSel||this._nameSel.trim())&&(this._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this._wallFaceBatch;if(!e)return;const i=e.candidates[e.index];if(!i)return;if(!t&&(i.existing||i.repair)&&1===e.candidates.length)return this._wallFaceBatch=null,this._roomDialog=!1,this._nameSel="",this._areaSel="",void this.requestUpdate();const s=t?{candidate:i,create:!0,name:this._nameSel.trim(),area:this._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:i,create:!1},n=[...e.decisions,s],o=e.index+1;if(o"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,n=.02*this._gridPitch,o=this._spaceModel();if(!o)return ll;for(const e of this._planSnapGeometrySnapshot().value.segments){if("room"===e.sourceKind||Ls(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>n)continue;if("partition"===e.sourceKind)return s(o.partitions.find(t=>t.id===e.sourceId)?.cm)??ll;const i=e.sourceId.lastIndexOf(":"),a=i>=0?e.sourceId.slice(0,i):e.sourceId,r=i>=0?Number(e.sourceId.slice(i+1)):-1;return s(o.room_drafts.find(t=>t.id===a)?.segments[r]?.cm)??ll}const a=Jp(Math.max(0,e.length-1),i,this._drawWallCm,ll);for(let i=0;i+1[...t]);if(!e?.sourceKey.startsWith("active:"))return i;const s=/:(\d+)$/.exec(e.sourceKey),n=s?Number(s[1])+("b"===e.endpoint?1:0):-1;return n>=0&&ne.key===t.sourceKey),o=s.find(e=>e.key===t.targetSourceKey);if(!n||!o)return!1;const a="a"===t.endpoint?n.a:n.b;return!(Math.hypot(a[0]-t.from[0],a[1]-t.from[1])>i)&&(!(Ls(t.to,[o.a[0],o.a[1],o.b[0],o.b[1]])>i)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const i=t.sourceKey.slice(17).split("|")[0];return!!i&&e.some(t=>"partition"===t.host?.kind&&t.host.id===i)}(t,this._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const i=this._curSpaceCfg;if(!i||!this._validateWallRepair(t,e.activePath))return!1;const s=e=>{e[0]=t.to[0]/iv,e[1]=t.to[1]/iv};if(t.sourceKey.startsWith("active:")){const n=/:(\d+)$/.exec(t.sourceKey),o=n?Number(n[1])+("b"===t.endpoint?1:0):-1;if(o<0||o>=e.activePath.length)return!1;e.activePath[o]=[...t.to];const a=(i.room_drafts||[]).find(t=>t.id===e.activeDraftId);return a?.points?.[o]&&s(a.points[o]),!0}if(!t.sourceKey.startsWith("static:"))return!1;const[n,o]=t.sourceKey.slice(7).split("|");if("partition"===n){const e=(i.partitions||[]).find(t=>t.id===o);if(!e)return!1;const n=[e.a[0]*iv,e.a[1]*iv],a=[e.b[0]*iv,e.b[1]*iv],r=Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this._gridPitch?e.a:Math.hypot(a[0]-t.from[0],a[1]-t.from[1])<=2e-4*this._gridPitch?e.b:null;return!!r&&(s(r),!0)}if("draft"===n){const e=o.lastIndexOf(":"),n=e>=0?o.slice(0,e):"",a=e>=0?Number(o.slice(e+1)):-1,r=(i.room_drafts||[]).find(t=>t.id===n);if(!r?.points?.[a]||!r?.points?.[a+1])return!1;const l=[a,a+1].find(e=>Math.hypot(r.points[e][0]*iv-t.from[0],r.points[e][1]*iv-t.from[1])<=2e-4*this._gridPitch);return null!=l&&(s(r.points[l]),!0)}return!1}_applyWallFaceBatch(){const t=this._wallFaceBatch,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=(t,e)=>{this._showToast(this._t(t,e)),this._roomDialogCancel()},n=t.decisions.filter(t=>t.create),o=n.map(t=>t.candidate.ring),a=i.rooms;for(let t=0;ti.id!==e&&!!hi(i)&&Di(o[t],hi(i)));if(i)return void s("toast.room_overlap",{name:i.name||""})}if((e.rooms||[]).length+n.length>400)return void s("toast.physical_limit");if(n.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void s("toast.contour_cannot_close");const r=n.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void s("toast.wall_repair_changed");const l=this._activePathWithRepair(t.activePath,r[0]),c=2e-4*this._gridPitch,h=new Map;for(let e=0;et.candidate.atomKeys)),e=n.some(t=>t.candidate.consumeAllActive);for(const i of vu(this._wallGraphSources(l),c)){const s=i.sourceKeys.find(t=>h.has(t));!s||e||t.has(i.key)||d.push({a:i.a,b:i.b,cm:h.get(s)})}}else d.push(...Xp(l,Jp(l.length-1,t.activeCms,this._drawWallCm,ll)));if((e.partitions||[]).length+d.length>av)return void s("toast.physical_limit");const p=n.map(t=>t.candidate.ring.map(()=>"")),u=t.activeDraftId?(e.room_drafts||[]).find(e=>e.id===t.activeDraftId):null,_=this._draftSegmentsForPath(t.activePath,u,t.activeCms),m=(t,e)=>{const i=`${t[0].toFixed(9)},${t[1].toFixed(9)}`,s=`${e[0].toFixed(9)},${e[1].toFixed(9)}`;return i<=s?`${i}|${s}`:`${s}|${i}`};for(let e=0;e<_.length;e++){const i=_[e]?.id;if(!i)continue;const s=t.activePath[e],o=t.activePath[e+1],a=[s[0],s[1],o[0],o[1]],r=[];n.forEach((t,e)=>t.candidate.ring.forEach((i,s)=>{const n=t.candidate.ring[(s+1)%t.candidate.ring.length];Ls(i,a)<=c&&Ls(n,a)<=c&&r.push({kind:"room",owner:e,edge:s,a:i,b:n})})),d.forEach((t,e)=>{Ls(t.a,a)<=c&&Ls(t.b,a)<=c&&r.push({kind:"partition",owner:e,edge:0,a:t.a,b:t.b})});const l=[(s[0]+o[0])/2,(s[1]+o[1])/2];r.sort((t,e)=>{const i=[t.a[0],t.a[1],t.b[0],t.b[1]],n=[e.a[0],e.a[1],e.b[0],e.b[1]];return(Ls(l,i)<=c?0:1)-(Ls(l,n)<=c?0:1)||(Ls(s,i)<=c?0:1)-(Ls(s,n)<=c?0:1)||m(t.a,t.b).localeCompare(m(e.a,e.b))});const h=r[0];if(!h)continue;const u=m(h.a,h.b);for(const t of r)m(t.a,t.b)===u&&("room"===t.kind?p[t.owner][t.edge]=i:d[t.owner].id=i)}const g=this._geometrySnapshot();if(r[0]&&!this._applyWallRepair(r[0],t))return void s("toast.wall_repair_changed");const f=n.some(t=>!!t.candidate.split),v=f?pc(i.rooms,e.walls,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,iv):null,y=f&&Array.isArray(e.walls)?e.walls:null;for(const t of n){const i=t.candidate.split;if(!i)continue;const n=e.rooms.find(t=>t.id===i.roomId);if(!n)return void s("toast.contour_cannot_close");n.poly=i.mainPoly.map(t=>[t[0]/iv,t[1]/this._spaceH]),delete n.x,delete n.y,delete n.w,delete n.h}const b=Date.now().toString(36),w=[];if(n.forEach((t,i)=>{const s=t.area?this.hass.areas[t.area]?.name:"",n={id:`r${b}-${i}`,name:t.name||s||this._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/iv,t[1]/this._spaceH]),...p[i].some(Boolean)?{wall_ids:p[i]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(n),w.push({room:n,decision:t})}),t.activeDraftId&&Array.isArray(e.room_drafts)&&(e.room_drafts=e.room_drafts.filter(e=>e.id!==t.activeDraftId),e.room_drafts.length||delete e.room_drafts),d.length&&(e.partitions||=[],d.forEach((t,i)=>e.partitions.push({id:t.id||`partition-${b}-${i}`,a:[t.a[0]/iv,t.a[1]/iv],b:[t.b[0]/iv,t.b[1]/iv],cm:t.cm}))),f){const t=this._normalizeWalls(v,this._openCuts());t.length?e.walls=t:y?.length?e.walls=y:delete e.walls}if(w.length){this._cfgEpoch++;const i=this._openCuts(),s=this._spaceModel();if(!s)return;let n=e.walls;for(const{room:e,decision:o}of w){const a=o.candidate.ring,r=this._wallSourceCmAt(a[0],t.activePath,t.activeCms);n=Nl(n,s.rooms,e.id,r,this._wallKeyPitch,i,iv);for(const o of dc(s.rooms,n,i,this._wallKeyPitch,this._cellCm,this._gridPitch,iv)){if(o.roomId!==e.id||"outer"!==o.kind)continue;const i=[(o.a[0]+o.b[0])/2,(o.a[1]+o.b[1])/2];n=Fl(n,o.a,o.b,this._wallSourceCmAt(i,t.activePath,t.activeCms),this._wallKeyPitch,iv)}}const o=this._normalizeWalls(n,i);o.length?e.walls=o:delete e.walls}if(!this._commitPhysicalGeometry(this._t("history.wall_face_batch"),g))return;delete this._resumeDraftBySpace[this._space],this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._wallFaceBatch=null,this._roomDialog=!1,this._nameSel="",this._areaSel="",this._regSignature="",this._maybeRebuildDevices();const k=new Set(n.map(t=>t.area).filter(t=>!!t));if(k.size){const t={...this._layout};for(const e of this._devices){if(!k.has(e.area||"")||e.space!==this._space)continue;if(this._layout[e.id])continue;const i=this._defPos[e.id];i&&(t[e.id]={s:this._space,x:i.x/iv,y:i.y/iv},this._dirtyPos.add(e.id))}this._layout=t,this._persistLayout()}this._showToast(this._t(n.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:n.length}))}_commitRoom(){const t=this._curSpaceCfg,e=this._spaceModel();if(!t||!e)return;const i=this._geometrySnapshot(),s=this._spaceH,n=!!this._pendingSplit,o=n?pc(e.rooms,t.walls,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,iv):null,a=n&&Array.isArray(t.walls)?t.walls:null;let r;if(this._pendingSplit){const e=t.rooms.find(t=>t.id===this._pendingSplit.roomId);if(!e)return this._pendingSplit=null,this._splitSel=null,void(this._roomDialog=!1);e.poly=this._pendingSplit.mainPoly.map(t=>[t[0]/iv,t[1]/s]),delete e.x,delete e.y,delete e.w,delete e.h,r=this._pendingSplit.newPoly}else{if(!this._contourClosed)return;r=this._path.slice(0,-1)}const l=this._areaSel?this.hass.areas[this._areaSel]?.name:"",c={id:"r"+Date.now().toString(36),name:this._nameSel||l||this._t("room.default_name"),area:this._areaSel||null,poly:r.map(t=>[t[0]/iv,t[1]/s]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(!n&&this._activeDraftId){const e=Array.isArray(t.room_drafts)?t.room_drafts.find(t=>t.id===this._activeDraftId):null,i=Jp(r.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll),s=this._draftSegmentsForPath(this._path,e,i);s.length===r.length&&s.every(t=>!!t.id)&&(c.wall_ids=s.map(t=>t.id))}if(t.rooms.push(c),!n&&this._activeDraftId&&Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),n){const e=this._normalizeWalls(o,this._openCuts());e.length?t.walls=e:a?.length?t.walls=a:delete t.walls}if(!n){const e=Jp(r.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll),i=e[0];if(null!=i){this._cfgEpoch++;const s=this._openCuts(),n=this._spaceModel();if(!n)return;let o=Nl(t.walls,n.rooms,c.id,i,this._wallKeyPitch,s,iv);for(const t of dc(n.rooms,o,s,this._wallKeyPitch,this._cellCm,this._gridPitch,iv)){if(t.roomId!==c.id||"outer"!==t.kind)continue;const i=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],s=r.findIndex((t,e)=>{const s=r[(e+1)%r.length];return Ls(i,[t[0],t[1],s[0],s[1]])<=.02*this._gridPitch});s>=0&&(o=Fl(o,t.a,t.b,e[s],this._wallKeyPitch,iv))}o=this._normalizeWalls(o,s),o.length?t.walls=o:delete t.walls}}const h=this._commitPhysicalGeometry(this._t(n?"history.split_room":"history.add_room"),i);this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._pendingSplit=null,this._splitSel=null;const d=this._areaSel;if(this._areaSel="",this._nameSel="",this._roomDialog=!1,this._regSignature="",this._maybeRebuildDevices(),!h)return;let p=0;if(d){const t=iv,e={...this._layout};for(const i of this._devices){if(i.area!==d||i.space!==this._space)continue;if(p++,this._layout[i.id])continue;const s=this._defPos[i.id];s&&(e[i.id]={s:this._space,x:s.x/iv,y:s.y/t},this._dirtyPos.add(i.id))}this._layout=e,this._persistLayout()}const u=this._model.find(t=>t.id===this._space)?.rooms.length||0;this._showToast(d?this._t("toast.room_saved",{n:u,added:p}):this._t("toast.room_saved_no_area",{n:u}))}_cancelPath(){this._wallRepairDiagnostic=null,this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._clearPlanSnapHover(),this._roomDialog=!1,this._pendingSplit=null,this._wallFaceBatch=null,this._splitSel=null,this._mergeSel=null,this._mergeDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._clearOpeningPlacement(!0)}_resumeLastDraft(){const t=this._resumeDraftBySpace[this._space];if(!t)return;const e=this._spaceModel()?.room_drafts.find(e=>e.id===t);e?(this._activeDraftId=t,this._path=e.points.map(t=>[...t]),this._draftSegmentCms=this._adoptDraftCms(this._path,e.segments.map(t=>t.cm),e.id),this._clearPlanSnapHover()):delete this._resumeDraftBySpace[this._space]}_roomDialogCancel(){if(this._roomDialog=!1,this._roomEditId)return this._roomEditId=null,this._nameSel="",void(this._areaSel="");if(this._wallFaceBatch){const t=this._wallFaceBatch;return this._wallFaceBatch=null,this._path=t.activePath.map(t=>[...t]),this._draftSegmentCms=[...t.activeCms],this._activeDraftId=t.activeDraftId,this._nameSel="",this._areaSel="",void this.requestUpdate()}if(this._pendingSplit)return this._pendingSplit=null,void(this._splitSel=null);this._undoPoint()}get _freeAreas(){const t=new Set;for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area&&t.add(i.area);for(const e of this._wallFaceBatch?.decisions||[])e.create&&e.area&&t.add(e.area);return Object.values(this.hass?.areas||{}).filter(e=>!t.has(e.area_id)).sort((t,e)=>(t.name||"").localeCompare(e.name||""))}_openMarkerDialog(t){if(this._vacAllCamerasFor=null,this._vacAllCameraCache=null,t&&this._ackNewDevice(t.id),this._norm)if(t){const e=t.marker,i=Object.prototype.hasOwnProperty.call(e||{},"is_light"),s=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),n=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),o=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),a=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),r=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),l=ks(e?.glow_color),c=this._devicePresentation(t,!0).valueBadge,h=Wo(this._planHass,t,this._devices),d=jo(this._planHass,t,h);this._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:Bi(t.marker?.display),rippleColor:Rt(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:pp(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:a,originalTapAction:t.marker?.tap_action,tapHintAnnouncement:"",toggleEntity:e?.toggle_entity||"",toggleEntityTouched:!1,originalHasToggleEntity:r,originalToggleEntity:e?.toggle_entity,tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",controls:Zn(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:i,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:s,originalLightEntity:e?.light_entity,glowMode:null!=l?.bri?"fixed":l?"color":"auto",glowColor:l?.c||this._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(l?.bri??1))),glowColorDrafted:!!l,glowBrightnessDrafted:null!=l?.bri,glowTouched:!1,originalHasGlowColor:n&&(!!l||null===e?.glow_color),originalGlowColor:l||(null===e?.glow_color?null:void 0),valueBadgeEnabled:o?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||d,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:o,originalValueBadge:e?.value_badge,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:1.5,size:1,angle:0,tapAction:"info",tapActionTouched:!1,originalHasTapAction:!1,originalTapAction:void 0,tapHintAnnouncement:"",toggleEntity:"",toggleEntityTouched:!1,originalHasToggleEntity:!1,originalToggleEntity:void 0,tapTarget:"",tapConfirm:!1,runFilter:"",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,lightEntity:"",lightEntityTouched:!1,originalHasLightEntity:!1,originalLightEntity:void 0,glowMode:"auto",glowColor:this._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgePosition:"right",valueBadgeTouched:!1,originalHasValueBadge:!1,originalValueBadge:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};else this._showToast(this._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of Gi)for(const[i,s]of Object.entries(this.hass.states))i.startsWith(e+".")&&this._planEntityAvailable(i)&&t.push({value:i,label:s?.attributes?.friendly_name||i,sub:this._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=this._planHass,e=wo(this._markers),i=new Set(this._markers.filter(t=>t.removed).map(t=>t.binding)),s=new Set;for(const t of this._devices)t.id!==this._markerDialog?.devId&&("device"===t.bindingKind&&t.bindingRef&&s.add("device:"+t.bindingRef),"entity"===t.bindingKind&&t.bindingRef&&s.add("entity:"+t.bindingRef));const n=new Set;for(const t of this._devices)"device"===t.bindingKind&&t.name&&n.add(t.name.trim()+"|"+(t.area||""));const o=[];for(const e of Object.values(t.devices)){if("service"===e.entry_type)continue;const t="device:"+e.id;if(s.has(t))continue;const a=(e.name_by_user||e.name||e.id).trim();t!==this._markerDialog?.binding&&!i.has(t)&&n.has(a+"|"+(e.area_id||""))||o.push({value:t,label:a,sub:(e.model||this._t("marker.sub_device"))+("Group"===e.model?this._t("marker.sub_z2m_group"):"")})}const a=new Set(["group","template","derivative","min_max","threshold","integration","statistics","trend","utility_meter","tod","switch_as_x","schedule"]);for(const[n,r]of Object.entries(t.entities)){const l="entity:"+n;if(s.has(l))continue;if(ko(t,n,e)&&!i.has(l))continue;const c=a.has(r.platform),h="group"===r.platform;if(!c&&!h)continue;if(r.hidden&&!i.has(l))continue;const d=t.states[n];o.push({value:l,label:r.name||d?.attributes?.friendly_name||n,sub:n.split(".")[0]+" · "+("group"===r.platform?this._t("marker.sub_group"):this._t("marker.sub_helper"))})}if(this._markerDialog?.showEntities){const n=new Set(o.map(t=>t.value));for(const[a,r]of Object.entries(t.entities)){const l="entity:"+a;if(s.has(l)||n.has(l)||r.hidden&&!i.has(l))continue;const c=!!r.device_id&&e.devices.has(r.device_id);if(ko(t,a,e)&&!i.has(l)&&!c)continue;const h=t.states[a],d=r.name||h?.attributes?.friendly_name||a,p=r.device_id?t.devices[r.device_id]:null,u=p&&(p.name_by_user||p.name)||"";o.push({value:l,label:d,sub:a.split(".")[0]+" · "+this._t("marker.sub_entity")+(u?" · "+u:"")})}}const r=(this._markerDialog?.bindingFilter||"").toLowerCase().trim(),l=r?o.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(r)):o;return l.sort((t,e)=>t.label.localeCompare(e.label)),l.slice(0,200)}_physicalBodiesR(t=this._spaceModel()){if(!t)return[];const e=`${t.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===e)return this._physicalBodiesCache.all;const i=eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t));return this._physicalBodiesCache={key:e,...i},i.all}_rawPhysicalBodiesR(t=this._spaceModel()){if(!t)return[];this._physicalBodiesR(t);const e=this._physicalBodiesCache;return e?[...e.drafts,...e.partitions,...e.columns]:[]}_cleanFloor(t,e,i=this._spaceModel()){if(!i)return{floor:e,geom:null,path:"",area:rh([[[...e,e[0]]]])};const s=t.id||`#${i.rooms.indexOf(t)}`,n=`${i.id}|${this._cfgEpoch}|${s}`;if(!this._rszPreview){const t=Wf(this._cleanFloorCache,n);if(t.hit)return t.value}const o=e.map(t=>t[0]),a=e.map(t=>t[1]),r=[Math.min(...o),Math.min(...a),Math.max(...o),Math.max(...a)],l=this._physicalBodiesR(i).filter(t=>{const e=t.map(t=>t[0]),i=t.map(t=>t[1]);return Math.max(...e)>=r[0]&&Math.min(...e)<=r[2]&&Math.max(...i)>=r[1]&&Math.min(...i)<=r[3]}),c=l.length?ah(e,l):null,h={floor:e,geom:c,path:c?Jc(c):"",area:rh(c||[[[...e,e[0]]]])};return this._rszPreview||jf(this._cleanFloorCache,n,h,600),h}_autoIconForBinding(t){if("virtual"===t)return"mdi:map-marker";const[e,i]=t.split(":");if(!i)return"";const s=this._fullRegistryHass,n=this._bindingStatus(t),o="active"===n.kind?n.enabledEntityIds:n.allEntityIds;if("device"===e){const t=s.devices?.[i];if(!t)return"mdi:help-circle";const e=o;return e.some(t=>t.startsWith("lock."))?"mdi:lock":bo(s,t.name_by_user||t.name||"",t.model,e,this._iconRules)}if("entity"===e){const t=s.entities?.[i],e=this.hass.states?.[i],n=t?.name||e?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":bo(s,n,"",[i],this._iconRules)}return""}_allRoomsFlat(){const t=[];for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area?t.push({value:e.id+"#"+i.area,label:(e.title||e.id)+" · "+i.name}):i.id&&t.push({value:e.id+"#@"+i.id,label:(e.title||e.id)+" · "+i.name+" · "+this._t("marker.subarea")});return t}_errText(t){if(!t)return this._t("err.unknown");if("string"==typeof t)return t;if("invalid_passage_fields"===t.code){const e=String(t.message||t.error||"").match(/space=([^;]*);\s*opening=([^;]*);\s*fields=([^;]*)/);if(e){const t=this._serverCfg?.spaces?.find(t=>String(t.id)===e[1]),i={contact:"opening.contact_label",lock:"opening.lock_label",invert:"opening.invert",flip_h:"opening.flip_h",flip_v:"opening.flip_v"},s=e[3].split(",").filter(Boolean).map(t=>i[t]?this._t(i[t]):t).join(", ");return this._t("opening.invalid_passage_fields",{room:t?.title||e[1],fields:s})}}if("invalid_partition_opening_jamb_margin"===t.code){const e=String(t.message||t.error||"").match(/margin_cm=([^;]*)/),i=e?Number(e[1]):NaN;if(Number.isFinite(i))return this._t("opening.partition_jamb_margin",{distance:li(i,this._imperial)})}if(t.message)return t.message;if(t.error)return t.error;if(null!=t.code)return this._t("err.code",{code:t.code});try{return JSON.stringify(t)}catch{return String(t)}}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,i=this._t(t);if(i!==t)return i}return this._errText(t)}async _pickMarkerFiles(t){const e=t.target,i=e.files?[...e.files]:[];if(e.value="",!i.length||!this._markerDialog)return;const s=this._markerDialog.uploadId||this._markerDialog.devId||"new",n=[];for(const t of i)try{const e=new FormData;e.append("marker_id",s),e.append("file",t,t.name);const i=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error){const t={too_large:this._t("err.too_large",{mb:o.max_mb||50}),bad_ext:this._t("err.bad_ext"),unauthorized:this._t("err.unauthorized")};throw new Error(t[o.error]||o.error||"HTTP "+i.status)}n.push({name:o.name||t.name,url:o.url})}catch(e){this._showToast(this._t("toast.file_failed",{name:t.name,err:this._errText(e)}))}n.length&&this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:[...this._markerDialog.pdfs,...n]},this._showToast(this._t("toast.files_attached",{n:n.length})))}_removeMarkerPdf(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:this._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.lightEntityTouched?t.lightEntity&&(e.light_entity=t.lightEntity):t.originalHasLightEntity&&(e.light_entity=t.originalLightEntity??null),t.glowTouched){if("auto"!==t.glowMode){const i={c:Rt(t.glowColor,this._fillColors.glow_light.c)};"fixed"===t.glowMode&&(i.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=i}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}_markerTapActionFields(t){return t.tapActionTouched?{tap_action:t.tapAction||null}:t.originalHasTapAction?{tap_action:t.originalTapAction??null}:{}}_markerToggleEntityFields(t){return(e={touched:t.toggleEntityTouched,originalHas:t.originalHasToggleEntity,original:t.originalToggleEntity,value:t.toggleEntity}).touched?e.value?{toggle_entity:e.value}:{}:e.originalHas?{toggle_entity:e.original??null}:{};var e}async _saveMarker(){const t=this._markerDialog;if(!t||t.busy)return;const e=this._effectiveMarkerTapAction(t);if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return;if("virtual"===t.binding&&!t.name.trim())return void this._showToast(this._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this._showToast(this._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this._showToast(this._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this._bindingStatus(t.binding),i=t.devId?this._markers.find(e=>e.id===t.devId):null,s=!i||i.binding!==t.binding;if("active"!==e.kind&&s)return void this._showToast(this._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===i?.hidden&&!t.hideFromPlan)return this._markerDialog={...t,hideFromPlan:!0},void this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const i=this._serverCfg;if(!i)return;const s=i.markers||[],n=qs(t.room);let o=n?.space||null;const a=n?.area||null,r=n?.roomId||null,l=Fi(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),c=t.devId,h=c?this._devices.find(t=>t.id===c):null,d=n?.space||h?.space||null,p=d?this._spaceModelById(d):this._spaceModel();if(!p)return;const u=p.id;"virtual"!==t.binding||o||(o=u),this._markerDialog={...t,busy:!0};try{const n="virtual"===t.binding?[]:s.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=n.length>0,_=Zn(t.binding,t.controls,this._bindingEntities(t.binding)),m=s.find(t=>t.id===l||t.id===c)?.vacuum||null,g={id:l,vacuum:m,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===e&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:_.length?_:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=qf(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};("virtual"===t.binding||t.room)&&(g.space=o,g.area=a,g.room_id=r);const f=h?.marker?.room_id??null,v=!!t.room&&null!=h&&(h.space!==o||h.area!==a||f!==r);let y=!1;const b=t.uploadId||c;if(b&&b!==l&&g.pdfs?.length)try{const t=await this.hass.callWS({type:"houseplan/files/migrate",from_id:b,to_id:l}),e=t?.mapping||{};g.pdfs=function(t,e,i,s){if(!e||!i||e===i)return t;const n="/files/"+e+"/",o="/files/"+i+"/";return t.map(t=>{if(!t.url.includes(n))return t;const e=t.url.split(n)[1]||"",[i,a]=[e.split("?")[0],e.includes("?")?"?"+e.split("?")[1]:""];if(s){const e=s[decodeURIComponent(i)]??s[i];return e?{...t,url:t.url.split(n+i)[0]+o+encodeURIComponent(e)+a}:t}return{...t,url:t.url.split(n).join(o)}})}(g.pdfs,b,l,e),y=Object.keys(e).length>0}catch(t){this._showToast(this._t("toast.files_migrate_failed",{err:this._errText(t)}))}i.markers=s,c&&c!==l&&(i.markers=function(t,e,i){if(!e||!i||e===i)return[...t];const s=`marker:${e}`,n=`marker:${i}`;return t.map(t=>{const e=Array.isArray(t.controls)?t.controls.map(t=>t===s?n:t):t.controls,i="derived_marker_state"===t.value_badge?.source?.kind&&t.value_badge.source.ref===s?{...t.value_badge,source:{...t.value_badge.source,ref:n}}:t.value_badge;return e===t.controls&&i===t.value_badge?t:{...t,controls:e,value_badge:i}})}(i.markers,c,l)),c&&c!==l&&"derived_marker_state"===g.value_badge?.source?.kind&&g.value_badge.source.ref===`marker:${c}`&&(g.value_badge.source={kind:"derived_marker_state",ref:`marker:${l}`}),i.markers=i.markers.filter(t=>t.id!==l&&t.id!==c&&("virtual"===g.binding||t.binding!==g.binding)),i.markers.push(g);let w=null;const k=c?this._layout[c]:null,x=k?{s:k.s||h?.space||this._space,x:k.x,y:k.y}:c&&h&&this._defPos[c]?this._normPos(h.space,this._defPos[c].x,this._defPos[c].y):null;if(!d&&x&&x.s===u)l===c&&this._layout[l]&&!v||(w={s:x.s,x:x.x,y:x.y},this._layout={...this._layout,[l]:w});else if(d||!this._layout[l]||v){let t=p.vb[0]+p.vb[2]/2,e=p.vb[1]+p.vb[3]/2;const i=r?p.rooms.find(t=>t.id===r):a?p.rooms.find(t=>t.area===a):void 0;i&&([t,e]=this._roomCenter(i)),w=this._normPos(u,t,e),this._layout={...this._layout,[l]:w}}if(await this._saveConfigNow(),w){const t=ol(w);this._layout={...this._layout,[l]:t},this._noteLayoutRev(await this.hass.callWS({type:"houseplan/layout/update",device_id:l,pos:t}))}const $=new Set(n);c&&c!==l&&$.add(c),$.delete(l);for(const t of $)delete this._layout[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{});y&&b&&await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:b}).catch(()=>{}),this._markerDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_saved"))}catch(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteMarker(){const t=this._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this._devices.find(e=>e.id===t.devId):null;if(!e)return;const i=t.name||this._t("device.fallback");if(!confirm(this._t("confirm.remove_marker",{name:i})))return;const s=this._serverCfg;s.markers=s.markers||[];const n=s.markers,o="virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"";if(!o)return;const a=function(t,e,i,s){const n=new Set([e]),o=t.filter(t=>{const o=t.id===e||!s&&t.binding===i;return o&&n.add(t.id),!o});return{markers:s?o:[...o,{id:e,binding:i,removed:!0,hidden:!0}],cleanupIds:n}}(s.markers,e.id,o,"virtual"===e.bindingKind);var r,l;s.markers=(r=a.markers,l=a.cleanupIds,r.map(t=>{if(!Array.isArray(t.controls))return t;const e=t.controls.filter(t=>!("string"==typeof t&&t.startsWith("marker:")&&l.has(t.slice(7))));return e.length===t.controls.length?t:{...t,controls:e.length?e:null}}));const c=a.cleanupIds;this._markerDialog={...t,busy:!0};try{await this._saveConfigNow();for(const t of c){delete this._layout[t],delete this._defPos[t],this._dirtyPos.delete(t),this._sentPos.delete(t);const e=this._activityRt.get(t);e&&clearTimeout(e.timer),this._activityRt.delete(t),this._vacRt.delete(t),delete this._vacSrvTrails[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{}),await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this._markerDialog=null,this._infoCard?.id===e.id&&this._closeInfoCard(),this._selId===e.id&&(this._selId=null),this._drag?.id===e.id&&(this._drag=null),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_removed"))}catch(t){this._serverCfg===s&&(s.markers=n),this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}_normPos(t,e,i){return{s:t,x:e/iv,y:i/iv}}_openSpaceDialog(t,e){if(this._serverStorage&&this._serverCfg)if("edit"===t){const i=this._serverCfg.spaces.find(t=>t.id===e);if(!i)return;const s=cs(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?rs(i.settings.custom_fill):null,o="none"===s.fill?{...n||as,a:0}:n;this._spaceDialog={mode:t,spaceId:e,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:s.showBorders,showNames:s.showNames,zeroWallStyle:d_(i),displayTouched:!0,hideDecor:s.hideDecor,hideOpenings:s.hideOpenings,roomColor:s.color,roomOpacity:s.opacity,fillMode:"none"===s.fill?"custom":s.fill,customFill:o,glowEnabled:s.glow,bgColor:s.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:$r({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:s.tempMin,tempMax:s.tempMax,showLqi:s.showLqi??this._config?.show_signal??!0,cardFontScale:s.cardFontScale,labelTemp:s.labelTemp,labelHum:s.labelHum,labelLqi:s.labelLqi,labelLight:s.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:fh(Number(i.cell_cm)>0?Number(i.cell_cm):5,this._imperial),cellCmTouched:!1,busy:!1}}else this._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...Sd(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ns,roomOpacity:os,fillMode:"custom",customFill:{...as,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:gh(this._imperial),cellCmInput:fh(gh(this._imperial),this._imperial),cellCmTouched:!1,busy:!1};else this._showToast(this._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,i=e.files?.[0];if(!i||!this._spaceDialog)return;const s={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[i.type]||(i.name.toLowerCase().endsWith(".svg")?"svg":"");if(!s)return void this._showToast(this._t("toast.plan_formats"));const n=new Uint8Array(await i.arrayBuffer());let o="";for(let t=0;t{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:1.414),e.onerror=()=>t(1.414),e.src=r});URL.revokeObjectURL(r),this._spaceDialog={...this._spaceDialog,planFile:{ext:s,b64:a,aspect:l,name:i.name}}}_useServerPlan(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this._display(t);if(e){const i=await new Promise(t=>{const i=new Image;i.onload=()=>t(i.naturalWidth&&i.naturalHeight?i.naturalWidth/i.naturalHeight:0),i.onerror=()=>t(0),i.src=e}),s=this._spaceDialog;return s&&s.planUrl===t&&Number.isFinite(i)&&i>0?(this._spaceDialog={...s,savedAspect:i},i):0}if(await new Promise(t=>setTimeout(t,150)),this._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this._t("confirm.delete_plan",{name:t})))try{await this.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this._spaceDialog;e?.saved&&(this._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this._showToast(this._t("toast.plan_delete_failed",{err:this._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return W`
${this._t("space.loading")}
`;const e=t.saved||[];if(!e.length)return W`
${this._t("space.no_saved")}
`;return W`
${e.map(e=>W`
@@ -5427,7 +5427,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4
`)} -
`}async _saveSpaceDialog(){const t=this._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this._showToast(this._t("toast.plan_required"));const e="create"===t.mode&&0===(this._serverCfg?.spaces.length||0);this._spaceDialog={...t,busy:!0};try{const i="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let s=null;if("file"===t.source&&t.planFile){s={url:(await this.hass.callWS({type:"houseplan/plan/set",space_id:i,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let n=t.savedAspect||null;!s&&"file"===t.source&&t.planUrl&&!n&&this._aspectJob&&(n=await this._aspectJob||null);const o=this._serverCfg;let a;if("create"===t.mode)a={id:i,title:t.title.trim(),plan_url:null,view_box:[0,0,1,1],rooms:[]},o.spaces.push(a);else{if(a=o.spaces.find(t=>t.id===i),!a)throw new Error("space "+i+" is gone from the config");a.title=t.title.trim()}s?(a.plan_url=s.url,a.plan_aspect=s.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==a.plan_url&&(a.plan_url=t.planUrl,a.plan_aspect=n),"draw"===t.source&&(a.plan_url=null,a.plan_aspect=null,delete a.plan_x,delete a.plan_y,delete a.plan_scale,delete a.plan_scale_x,delete a.plan_scale_y,delete a.plan_angle),a.settings={...a.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):20,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):25,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},a.zero_wall_style=t.zeroWallStyle,a.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(Lf,t.cellCm)):5,await this._saveConfigNow(),this._spaceDialog=null,"create"===t.mode&&this._commitSpace(a.id),this._regSignature="",this._maybeRebuildDevices(),this._importQueue.length?this._openNextImport():e||this._importTotal>0?(this._importTotal=0,this._commitSpace(this._serverCfg.spaces[0]?.id||this._space),this._setMode("plan"),this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._showToast(this._t(e&&!this._importTotal?"toast.space_added_onboard":"import.done"))):(this._showToast("create"===t.mode?this._t("toast.space_added"):this._t("toast.space_saved")),"create"===t.mode&&("plan"!==this._mode?this._setMode("plan"):(this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._saveNav())))}catch(t){this._spaceDialog&&(this._spaceDialog={...this._spaceDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteSpace(){const t=this._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this._serverCfg;if(!e)return;const i=e.spaces.find(e=>e.id===t.spaceId),s=ag(e,this._layout||{},t.spaceId||""),n=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(!s.count||n){if(confirm(this._t("confirm.delete_space",{title:i.title}))){this._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._persistLayout.pending()&&this._persistLayout.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev}),[i,s]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._adoptStructuralResponses(i,s),this._cfgRev=e?.config_rev??this._cfgRev,this._layoutRev=e?.layout_rev??this._layoutRev,this._spaceDialog=null,this._space===t.spaceId&&this._commitSpace(this._serverCfg.spaces[0]?.id||""),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.space_deleted"))}catch(e){"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]);const i=this._serverCfg;if(this._spaceDialog&&i){const e=ag(i,this._layout||{},t.spaceId||""),s=1===i.spaces.length&&i.spaces[0]?.id===t.spaceId;this._spaceDialog={...this._spaceDialog,busy:!1,deleteBlockers:s?0:e.count}}this._showToast(this._t("toast.delete_failed",{err:this._errText(e)}))}}}else this._spaceDialog={...t,deleteBlockers:s.count}}async _saveConfigNow(){this._cfgEpoch++;try{await this._writeConfig()}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this._reloadConfigOnly(),t}}_startImport(){const t=this._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this._importDialog=null,e.length?(this._importQueue=e,this._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this._importQueue.shift();void 0!==t&&(this._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...Sd(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ns,roomOpacity:os,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:gh(this._imperial),cellCmInput:fh(gh(this._imperial),this._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this._spaceDialog=null,this._importQueue.length?this._openNextImport():this._importTotal>0&&this._model.length&&(this._importTotal=0,this._commitSpace(this._serverCfg.spaces[0]?.id||this._space),this._setMode("plan"),this._showToast(this._t("import.done")))}_renderImportDialog(){const t=this._importDialog,e=t.floors.filter(t=>t.checked).length;return W``}async _saveSpaceDialog(){const t=this._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this._showToast(this._t("toast.plan_required"));const e="create"===t.mode&&0===(this._serverCfg?.spaces.length||0);this._spaceDialog={...t,busy:!0};try{const i="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let s=null;if("file"===t.source&&t.planFile){s={url:(await this.hass.callWS({type:"houseplan/plan/set",space_id:i,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let n=t.savedAspect||null;!s&&"file"===t.source&&t.planUrl&&!n&&this._aspectJob&&(n=await this._aspectJob||null);const o=this._serverCfg;let a;if("create"===t.mode)a={id:i,title:t.title.trim(),plan_url:null,view_box:[0,0,1,1],rooms:[]},o.spaces.push(a);else{if(a=o.spaces.find(t=>t.id===i),!a)throw new Error("space "+i+" is gone from the config");a.title=t.title.trim()}s?(a.plan_url=s.url,a.plan_aspect=s.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==a.plan_url&&(a.plan_url=t.planUrl,a.plan_aspect=n),"draw"===t.source&&(a.plan_url=null,a.plan_aspect=null,delete a.plan_x,delete a.plan_y,delete a.plan_scale,delete a.plan_scale_x,delete a.plan_scale_y,delete a.plan_angle),a.settings={...a.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):20,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):25,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},a.zero_wall_style=t.zeroWallStyle,a.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(Hf,t.cellCm)):5,await this._saveConfigNow(),this._spaceDialog=null,"create"===t.mode&&this._commitSpace(a.id),this._regSignature="",this._maybeRebuildDevices(),this._importQueue.length?this._openNextImport():e||this._importTotal>0?(this._importTotal=0,this._commitSpace(this._serverCfg.spaces[0]?.id||this._space),this._setMode("plan"),this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._showToast(this._t(e&&!this._importTotal?"toast.space_added_onboard":"import.done"))):(this._showToast("create"===t.mode?this._t("toast.space_added"):this._t("toast.space_saved")),"create"===t.mode&&("plan"!==this._mode?this._setMode("plan"):(this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._saveNav())))}catch(t){this._spaceDialog&&(this._spaceDialog={...this._spaceDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteSpace(){const t=this._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this._serverCfg;if(!e)return;const i=e.spaces.find(e=>e.id===t.spaceId),s=rg(e,this._layout||{},t.spaceId||""),n=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(!s.count||n){if(confirm(this._t("confirm.delete_space",{title:i.title}))){this._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._persistLayout.pending()&&this._persistLayout.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev}),[i,s]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._adoptStructuralResponses(i,s),this._cfgRev=e?.config_rev??this._cfgRev,this._layoutRev=e?.layout_rev??this._layoutRev,this._spaceDialog=null,this._space===t.spaceId&&this._commitSpace(this._serverCfg.spaces[0]?.id||""),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.space_deleted"))}catch(e){"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]);const i=this._serverCfg;if(this._spaceDialog&&i){const e=rg(i,this._layout||{},t.spaceId||""),s=1===i.spaces.length&&i.spaces[0]?.id===t.spaceId;this._spaceDialog={...this._spaceDialog,busy:!1,deleteBlockers:s?0:e.count}}this._showToast(this._t("toast.delete_failed",{err:this._errText(e)}))}}}else this._spaceDialog={...t,deleteBlockers:s.count}}async _saveConfigNow(){this._cfgEpoch++;try{await this._writeConfig()}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this._reloadConfigOnly(),t}}_startImport(){const t=this._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this._importDialog=null,e.length?(this._importQueue=e,this._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this._importQueue.shift();void 0!==t&&(this._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...Sd(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ns,roomOpacity:os,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:gh(this._imperial),cellCmInput:fh(gh(this._imperial),this._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this._spaceDialog=null,this._importQueue.length?this._openNextImport():this._importTotal>0&&this._model.length&&(this._importTotal=0,this._commitSpace(this._serverCfg.spaces[0]?.id||this._space),this._setMode("plan"),this._showToast(this._t("import.done")))}_renderImportDialog(){const t=this._importDialog,e=t.floors.filter(t=>t.checked).length;return W`this._importDialog=null}>
${this._t("import.hint")}
@@ -5447,7 +5447,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t("import.start",{n:e})}
-
`}_sunGlobal(){const t=this._settingsDialog;return t?{...this._settings,north_deg:t.northDeg??void 0,bg_mode:t.bgMode,sun_rays:t.sunRays}:this._settings}_sunSpace(){const t=this._spaceDialog,e=this._curSpaceCfg?.settings||{};return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,north_deg:t.northDeg??void 0,bg_mode:t.bgMode??void 0,sun_rays:t.sunRays??void 0}:e}_effNorth(){return $r(this._sunGlobal(),this._sunSpace())}_effBgMode(){return Sr(this._sunGlobal(),this._sunSpace())}_dayCycleState(t=new Date){return(this._modeTransitionVisual?.viewWeight??("view"===this._mode?1:0))<=0||"daynight"!==this._effBgMode()?null:_r(this._renderPlanHass,t)}_syncDayCycleClock(){const t=this._dayCycleState();this._dayCycleClockKey=t?mr(t):"";const e="clock"===t?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;e&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!e&&this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(t){"hidden"!==t.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_effSunRays(){return Mr(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?Cr(this._renderPlanHass):null}_renderSunRays(t){const e=j``,i=this._modeTransitionVisual?.viewWeight??0;if(this._editing&&i<=0||!this._effSunRays())return this._sunFadeReset(),e;const s=this._effNorth(),n=null!==s?Cr(this._renderPlanHass):null;if(!n||n.elevation<=0)return this._sunFadeReset(),e;if(o=n.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return e;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const a=this._zeroWalls(),r=a.barriers.map(t=>t.join(",")).join(";"),l=`${t.id}|${n.azimuth}|${n.elevation}|${s}|${this._cfgEpoch}|${a.style}|${r}`;if(!this._sunRaysCache||this._sunRaysCache.key!==l){const e=t.rooms.map(t=>({id:t.id||"",poly:hi(t)})).filter(t=>!!t.id&&!!t.poly),i=this._openingsR.filter(t=>"window"===t.type&&"partition"!==t.host?.kind).map(t=>({id:t.id,x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),o=this._spaceWalls,r=this._openCuts(),c=this._openingWallIndexFor(t,r).value,h={},d={},p=this._wallUnionGeometry()?.roomGeom;if(o.length){for(const i of e){const e=fc(t.rooms,i.id,o,r,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,p);e&&(h[i.id]=e)}for(const t of i){const e=Lc(c,{x:t.x,y:t.y,angle:t.angle,length:t.length});e.cm>0&&(d[t.id]=gl(e.cm,this._cellCm,this._gridPitch))}}let u=kr(e,i,n.azimuth,n.elevation,s,o.length?h:void 0,o.length?d:void 0);const _=[...this._physicalBodiesR(t),...a.barriers.map(t=>[[t[0],t[1]],[t[2],t[3]]])];_.length&&(u=u.map(t=>{const e=function(t,e,i){return i>0?t.map(t=>function(t){const e=[...t].sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(e.length<=2)return e;const i=(t,e,i)=>(e[0]-t[0])*(i[1]-t[1])-(e[1]-t[1])*(i[0]-t[0]),s=[];for(const t of e){for(;s.length>=2&&i(s[s.length-2],s[s.length-1],t)<=0;)s.pop();s.push(t)}const n=[];for(let t=e.length-1;t>=0;t--){const s=e[t];for(;n.length>=2&&i(n[n.length-2],n[n.length-1],s)<=0;)n.pop();n.push(s)}return s.slice(0,-1).concat(n.slice(0,-1))}([...t,...t.map(t=>[t[0]+e[0]*i,t[1]+e[1]*i])])).filter(t=>t.length>=3):t}(_,t.dir,t.len),i=t.polys.map(t=>ah(t,e));return{...t,paths:i.map(Jc).filter(Boolean),polys:i.flatMap(ch)}}).filter(t=>t.paths?.length||t.polys.length)),this._sunRaysCache={key:l,rays:u,rims:u.map(t=>function(t,e=1e-4){const[i,s]=t.dir,n=-s,o=i,a=[];for(const r of[t.a,t.b]){const l=[];for(const a of t.polys)for(let t=0;te)continue;if(Math.abs((h[0]-r[0])*n+(h[1]-r[1])*o)>e)continue;const d=(c[0]-r[0])*i+(c[1]-r[1])*s,p=(h[0]-r[0])*i+(h[1]-r[1])*s;Math.abs(p-d)<=e||l.push(dt[0]-e[0]);const c=[];for(const t of l){const i=c[c.length-1];i&&t[0]<=i[1]+e?i[1]=Math.max(i[1],t[1]):c.push([t[0],t[1]])}for(const[t,e]of c)a.push([[r[0]+i*t,r[1]+s*t],[r[0]+i*e,r[1]+s*e]])}return a}(t))}}const c=this._sunRaysCache.rays,h=this._sunRaysCache.rims;if(!c.length)return e;const d=(p=function(t){const e=Math.min(90,Math.max(-90,Number(t)||0));let i=gr[gr.length-1][1];for(let t=1;t +
`}_sunGlobal(){const t=this._settingsDialog;return t?{...this._settings,north_deg:t.northDeg??void 0,bg_mode:t.bgMode,sun_rays:t.sunRays}:this._settings}_sunSpace(){const t=this._spaceDialog,e=this._curSpaceCfg?.settings||{};return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,north_deg:t.northDeg??void 0,bg_mode:t.bgMode??void 0,sun_rays:t.sunRays??void 0}:e}_effNorth(){return $r(this._sunGlobal(),this._sunSpace())}_effBgMode(){return Sr(this._sunGlobal(),this._sunSpace())}_dayCycleState(t=new Date){return(this._modeTransitionVisual?.viewWeight??("view"===this._mode?1:0))<=0||"daynight"!==this._effBgMode()?null:_r(this._renderPlanHass,t)}_syncDayCycleClock(){const t=this._dayCycleState();this._dayCycleClockKey=t?mr(t):"";const e="clock"===t?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;e&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!e&&this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(t){"hidden"!==t.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_effSunRays(){return Mr(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?Cr(this._renderPlanHass):null}_renderSunRays(t){const e=j``,i=this._modeTransitionVisual?.viewWeight??0;if(this._editing&&i<=0||!this._effSunRays())return this._sunFadeReset(),e;const s=this._effNorth(),n=null!==s?Cr(this._renderPlanHass):null;if(!n||n.elevation<=0)return this._sunFadeReset(),e;if(o=n.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return e;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const a=this._zeroWalls(),r=a.barriers.map(t=>t.join(",")).join(";"),l=`${t.id}|${n.azimuth}|${n.elevation}|${s}|${this._cfgEpoch}|${a.style}|${r}`;if(!this._sunRaysCache||this._sunRaysCache.key!==l){const e=t.rooms.map(t=>({id:t.id||"",poly:hi(t)})).filter(t=>!!t.id&&!!t.poly),i=this._openingsR.filter(t=>"window"===t.type&&"partition"!==t.host?.kind).map(t=>({id:t.id,x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),o=this._spaceWalls,r=this._openCuts(),c=this._openingWallIndexFor(t,r).value,h={},d={},p=this._wallUnionGeometry()?.roomGeom;if(o.length){for(const i of e){const e=fc(t.rooms,i.id,o,r,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,p);e&&(h[i.id]=e)}for(const t of i){const e=Lc(c,{x:t.x,y:t.y,angle:t.angle,length:t.length});e.cm>0&&(d[t.id]=gl(e.cm,this._cellCm,this._gridPitch))}}let u=kr(e,i,n.azimuth,n.elevation,s,o.length?h:void 0,o.length?d:void 0);const _=[...this._physicalBodiesR(t),...a.barriers.map(t=>[[t[0],t[1]],[t[2],t[3]]])];_.length&&(u=u.map(t=>{const e=function(t,e,i){return i>0?t.map(t=>function(t){const e=[...t].sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(e.length<=2)return e;const i=(t,e,i)=>(e[0]-t[0])*(i[1]-t[1])-(e[1]-t[1])*(i[0]-t[0]),s=[];for(const t of e){for(;s.length>=2&&i(s[s.length-2],s[s.length-1],t)<=0;)s.pop();s.push(t)}const n=[];for(let t=e.length-1;t>=0;t--){const s=e[t];for(;n.length>=2&&i(n[n.length-2],n[n.length-1],s)<=0;)n.pop();n.push(s)}return s.slice(0,-1).concat(n.slice(0,-1))}([...t,...t.map(t=>[t[0]+e[0]*i,t[1]+e[1]*i])])).filter(t=>t.length>=3):t}(_,t.dir,t.len),i=t.polys.map(t=>ah(t,e));return{...t,paths:i.map(Jc).filter(Boolean),polys:i.flatMap(ch)}}).filter(t=>t.paths?.length||t.polys.length)),this._sunRaysCache={key:l,rays:u,rims:u.map(t=>function(t,e=1e-4){const[i,s]=t.dir,n=-s,o=i,a=[];for(const r of[t.a,t.b]){const l=[];for(const a of t.polys)for(let t=0;te)continue;if(Math.abs((h[0]-r[0])*n+(h[1]-r[1])*o)>e)continue;const d=(c[0]-r[0])*i+(c[1]-r[1])*s,p=(h[0]-r[0])*i+(h[1]-r[1])*s;Math.abs(p-d)<=e||l.push(dt[0]-e[0]);const c=[];for(const t of l){const i=c[c.length-1];i&&t[0]<=i[1]+e?i[1]=Math.max(i[1],t[1]):c.push([t[0],t[1]])}for(const[t,e]of c)a.push([[r[0]+i*t,r[1]+s*t],[r[0]+i*e,r[1]+s*e]])}return a}(t))}}const c=this._sunRaysCache.rays,h=this._sunRaysCache.rims;if(!c.length)return e;const d=(p=function(t){const e=Math.min(90,Math.max(-90,Number(t)||0));let i=gr[gr.length-1][1];for(let t=1;t ${c.map((t,e)=>{const i=(t.a[0]+t.b[0])/2,s=(t.a[1]+t.b[1])/2,n=i+t.normal[0]*t.depth,o=s+t.normal[1]*t.depth;return j` ${u.map(([t,e])=>j`${this._t("gs.north_letter")} ${null===t?"—":t+"°"} - `}_stageBg(t){const e=this._settingsDialog,i=this._spaceDialog,s=e?e.bgColor||"":hs(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":t.bgColor||"")||s}_stageBgHex(){const t=this._stageEl;if(t){const e=getComputedStyle(t).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(e)return"#"+e.slice(1,4).map(t=>(+t).toString(16).padStart(2,"0")).join("")}return"#111111"}_preflightDiagnostics(t,e){const i=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:Ff,checkedAt:(new Date).toISOString(),preflightFingerprint:t.fingerprint,failures:t.failures.map(t=>({spaceId:t.spaceId,displayName:t.displayName,reason:t.reason,detail:t.detail??null,spaceGeometryFingerprint:i.has(t.spaceId)?lg(i.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this._reportedPreflightFingerprint||(this._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==Ff}async _copyPreflightDiagnostics(){const t=this._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this._preflightClipboardFallback=null,this._showToast(this._t("gs.preflight_copied"))}catch{this._preflightClipboardFallback=e}}_checkOptimizeGeometry(t){return _g(t,{fallbackSpaceName:t=>this._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometry(t,e){return function(t,e,i={}){const s=(Array.isArray(t?.spaces)?t.spaces:[]).find(t=>String(t?.id||"")===String(e||"")),n=lg(s);if(!s)return{spaceId:String(e||""),displayName:"",status:"failed",reason:"prepare-exception",fingerprint:n,ok:!1};const o=_g({...t,spaces:[s]},{...i,fingerprint:()=>n}).spaces[0]||{spaceId:String(e||""),displayName:"",status:"failed",reason:"prepare-exception"};return{...o,fingerprint:n,ok:"failed"!==o.status}}(t,e,{fallbackSpaceName:t=>this._t("gs.align_preflight_space",{n:String(t)})})}_optimizeReferenceContext(t){const e=this._haRegistry,i=this._fullRegistryHass,s={},n=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,i]of Object.entries(e.devices||{}))s[t]=n(i?.name_by_user,i?.name,i?.model);for(const[t,i]of Object.entries(e.entities||{}))s[`lg_${t}`]=n(this.hass?.states?.[t]?.attributes?.friendly_name,i?.name,i?.original_name);for(const t of this._devices)s[t.id]=n(t.name,s[t.id]);for(const t of this._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),o=e>0?t.binding.slice(0,e):"",a=e>0?t.binding.slice(e+1):"",r="device"===o?i?.devices?.[a]:"entity"===o?i?.entities?.[a]:null;s[t.id]=n(t.name,"device"===o?r?.name_by_user:null,r?.name,"entity"===o?this.hass?.states?.[a]?.attributes?.friendly_name:null,s[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this._devices.filter(t=>!t.virtual&&!!t.area).map(t=>[t.id,t.area])),ownerRoster:{authoritative:e.authoritative,deviceIds:Object.keys(e.devices||{}),entityIds:[...new Set([...Object.keys(e.entities||{}),...Object.keys(this.hass?.states||{})])],names:s},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this._norm||!this._serverCfg)return;const e=this._serverCfg.spaces||[];let i;try{i=og(this._serverCfg,this._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const s=i.changed?this._checkOptimizeGeometry(i.config):null;s&&this._reportPreflightFailure(s,i.config);const n=Math.ceil(10*i.report.maxShiftCm)/10,o=e.find(t=>null!=t?.id&&String(t.id)===i.report.maxSpace),a=e.length>1&&o?String(o.title||o.id):"";this._preflightClipboardFallback=null,this._alignDialog={report:i.report,config:i.config,layout:i.layout,cm:n,where:a,preflight:s,changed:i.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this._alignDialog;if(!t||t.busy||!this._serverCfg||!t.changed||!t.preflight?.ok)return;const e=bd(t.config);if(t.preflight.fingerprint!==e){const e=this._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this._alignDialog={...t,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/plan/optimize",config:t.config,layout:t.layout,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});this._serverCfg=t.config,this._layout=t.layout,this._geometryHistory.clear(),this._cfgRev=e?.config_rev??this._cfgRev+1,this._layoutRev=e?.layout_rev??this._layoutRev+1,this._canOptimizeUndo=!!e?.can_undo,this._undoKind=e?.can_undo?"optimize":null,this._dirtyPos.clear(),this._sentPos.clear(),this._cfgEpoch++,this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._cacheSnapshot(),this._alignDialog=null,this._preflightClipboardFallback=null,this.requestUpdate(),this._showToast(this._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.coordsCanonicalized+t.report.latticeCoordinatesCanonicalized+t.report.wallsMerged+t.report.spansMerged+t.report.partitionsMerged+t.report.partitionsReconciled+t.report.openingsRehosted+t.report.wallsStraightened),r:String(t.report.spaceRefsRemapped+t.report.roomRefsRemapped+t.report.positionsRemapped+t.report.markersDetached+t.report.orphanRoomLabelsRemoved+t.report.orphanDevicePositionsRemoved+t.report.orphanGroupPositionsRemoved)}))}catch(t){if(this._alignDialog&&(this._alignDialog={...this._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this._showToast(this._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _undoPlanOptimization(){if(!this._canOptimizeUndo||this._optimizeUndoBusy)return;const t=this._undoKind;this._clearGeometryGesture(),this._optimizeUndoBusy=!0,this.requestUpdate();try{await this.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});const[e,i]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._serverCfg=e?.config||this._serverCfg,this._cfgRev=e?.rev??this._cfgRev,this._layout=i?.layout||this._layout,this._geometryHistory.clear(),this._layoutRev=i?.rev??this._layoutRev,this._canOptimizeUndo=!1,this._undoKind=null,this._cfgEpoch++,this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._cacheSnapshot(),this.requestUpdate(),this._showToast(this._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this._canOptimizeUndo=!1,this._undoKind=null,this._showToast(this._t("toast.error",{err:this._errText(t)}))}finally{this._optimizeUndoBusy=!1,this.requestUpdate()}}async _runBackupExport(){const t=this._backupExportDialog;if(t&&!t.busy){this._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:Ff}),i=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),s=URL.createObjectURL(i),n=document.createElement("a");n.href=s,n.download=e.filename||`houseplan-${t.kind}.json`,n.style.display="none",document.body.append(n),n.click(),n.remove(),window.setTimeout(()=>URL.revokeObjectURL(s),0),this._backupExportDialog=null,this._showToast(this._t("backup.export_done"))}catch(t){this._backupExportDialog&&(this._backupExportDialog={...this._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,i=e.files?.[0];if(e.value="",i){this._settingsDialog=null,this._backupImportDialog={filename:i.name,size:i.size,token:"",preview:null,expectedConfigRev:this._cfgRev,expectedLayoutRev:this._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain,this._persistLayout.pending()&&this._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:i,headers:{"content-type":"application/json"}},s=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}}),n=await s.json().catch(()=>({}));if(!s.ok||n.error)throw Object.assign(new Error(n.message||n.error||`HTTP ${s.status}`),{code:n.error});this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,token:n.token,preview:n.preview,expectedConfigRev:n.expected_config_rev,expectedLayoutRev:n.expected_layout_rev,busy:!1})}catch(t){this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const i=await this.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,preview:{...e.preview,...i.preview},expectedConfigRev:i.expected_config_rev,expectedLayoutRev:i.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this._backupImportDialog={...t,busy:!0,error:""};const e=this._space;try{const i=await this.hass.callWS({type:"houseplan/import/apply",token:t.token,expected_config_rev:t.expectedConfigRev,expected_layout_rev:t.expectedLayoutRev,duplicate_policy:t.duplicatePolicy,confirm_missing_content:t.confirmMissing}),[s,n]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._adoptStructuralResponses(s,n),this._geometryHistory.clear(),this._dirtyPos.clear(),this._sentPos.clear(),this._defPos={},this._cfgEpoch++,this._modelCache=null,this._frame=null,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotConfigEpoch=-1,this._regSignature="",this._signer.invalidate(this.hass),this._resign(),this._maybeRebuildDevices();const o=this._serverCfg?.spaces||[],a="space"===i.kind&&i.space_id?i.space_id:o.some(t=>t.id===e)?e:o[0]?.id||this._space;this._hasFixedFloor?this._adoptInitialSpace(this._model,!0):this._commitSpace(a),this._backupImportDialog=null,this._cacheSnapshot(),this.requestUpdate();const r="space"===i.kind?t.preview.counts:i.counts;this._showToast(this._t("space"===i.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(i.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this._backupImportDialog?.token)try{const t=this._backupImportDialog,e=await this.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this._t("backup.revalidated")})}catch(e){t=e}this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this._backupExportDialog,e=(this._serverCfg?.spaces||[]).find(t=>t.id===this._space);return W``}_stageBg(t){const e=this._settingsDialog,i=this._spaceDialog,s=e?e.bgColor||"":hs(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":t.bgColor||"")||s}_stageBgHex(){const t=this._stageEl;if(t){const e=getComputedStyle(t).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(e)return"#"+e.slice(1,4).map(t=>(+t).toString(16).padStart(2,"0")).join("")}return"#111111"}_preflightDiagnostics(t,e){const i=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:Ef,checkedAt:(new Date).toISOString(),preflightFingerprint:t.fingerprint,failures:t.failures.map(t=>({spaceId:t.spaceId,displayName:t.displayName,reason:t.reason,detail:t.detail??null,spaceGeometryFingerprint:i.has(t.spaceId)?cg(i.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this._reportedPreflightFingerprint||(this._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==Ef}async _copyPreflightDiagnostics(){const t=this._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this._preflightClipboardFallback=null,this._showToast(this._t("gs.preflight_copied"))}catch{this._preflightClipboardFallback=e}}_checkOptimizeGeometry(t){return mg(t,{fallbackSpaceName:t=>this._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometry(t,e){return function(t,e,i={}){const s=(Array.isArray(t?.spaces)?t.spaces:[]).find(t=>String(t?.id||"")===String(e||"")),n=cg(s);if(!s)return{spaceId:String(e||""),displayName:"",status:"failed",reason:"prepare-exception",fingerprint:n,ok:!1};const o=mg({...t,spaces:[s]},{...i,fingerprint:()=>n}).spaces[0]||{spaceId:String(e||""),displayName:"",status:"failed",reason:"prepare-exception"};return{...o,fingerprint:n,ok:"failed"!==o.status}}(t,e,{fallbackSpaceName:t=>this._t("gs.align_preflight_space",{n:String(t)})})}_optimizeReferenceContext(t){const e=this._haRegistry,i=this._fullRegistryHass,s={},n=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,i]of Object.entries(e.devices||{}))s[t]=n(i?.name_by_user,i?.name,i?.model);for(const[t,i]of Object.entries(e.entities||{}))s[`lg_${t}`]=n(this.hass?.states?.[t]?.attributes?.friendly_name,i?.name,i?.original_name);for(const t of this._devices)s[t.id]=n(t.name,s[t.id]);for(const t of this._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),o=e>0?t.binding.slice(0,e):"",a=e>0?t.binding.slice(e+1):"",r="device"===o?i?.devices?.[a]:"entity"===o?i?.entities?.[a]:null;s[t.id]=n(t.name,"device"===o?r?.name_by_user:null,r?.name,"entity"===o?this.hass?.states?.[a]?.attributes?.friendly_name:null,s[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this._devices.filter(t=>!t.virtual&&!!t.area).map(t=>[t.id,t.area])),ownerRoster:{authoritative:e.authoritative,deviceIds:Object.keys(e.devices||{}),entityIds:[...new Set([...Object.keys(e.entities||{}),...Object.keys(this.hass?.states||{})])],names:s},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this._norm||!this._serverCfg)return;const e=this._serverCfg.spaces||[];let i;try{i=ag(this._serverCfg,this._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const s=i.changed?this._checkOptimizeGeometry(i.config):null;s&&this._reportPreflightFailure(s,i.config);const n=Math.ceil(10*i.report.maxShiftCm)/10,o=e.find(t=>null!=t?.id&&String(t.id)===i.report.maxSpace),a=e.length>1&&o?String(o.title||o.id):"";this._preflightClipboardFallback=null,this._alignDialog={report:i.report,config:i.config,layout:i.layout,cm:n,where:a,preflight:s,changed:i.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this._alignDialog;if(!t||t.busy||!this._serverCfg||!t.changed||!t.preflight?.ok)return;const e=bd(t.config);if(t.preflight.fingerprint!==e){const e=this._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this._alignDialog={...t,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/plan/optimize",config:t.config,layout:t.layout,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});this._serverCfg=t.config,this._layout=t.layout,this._geometryHistory.clear(),this._cfgRev=e?.config_rev??this._cfgRev+1,this._layoutRev=e?.layout_rev??this._layoutRev+1,this._canOptimizeUndo=!!e?.can_undo,this._undoKind=e?.can_undo?"optimize":null,this._dirtyPos.clear(),this._sentPos.clear(),this._cfgEpoch++,this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._cacheSnapshot(),this._alignDialog=null,this._preflightClipboardFallback=null,this.requestUpdate(),this._showToast(this._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.coordsCanonicalized+t.report.latticeCoordinatesCanonicalized+t.report.wallsMerged+t.report.spansMerged+t.report.partitionsMerged+t.report.partitionsReconciled+t.report.openingsRehosted+t.report.wallsStraightened),r:String(t.report.spaceRefsRemapped+t.report.roomRefsRemapped+t.report.positionsRemapped+t.report.markersDetached+t.report.orphanRoomLabelsRemoved+t.report.orphanDevicePositionsRemoved+t.report.orphanGroupPositionsRemoved)}))}catch(t){if(this._alignDialog&&(this._alignDialog={...this._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this._showToast(this._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _undoPlanOptimization(){if(!this._canOptimizeUndo||this._optimizeUndoBusy)return;const t=this._undoKind;this._clearGeometryGesture(),this._optimizeUndoBusy=!0,this.requestUpdate();try{await this.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});const[e,i]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._serverCfg=e?.config||this._serverCfg,this._cfgRev=e?.rev??this._cfgRev,this._layout=i?.layout||this._layout,this._geometryHistory.clear(),this._layoutRev=i?.rev??this._layoutRev,this._canOptimizeUndo=!1,this._undoKind=null,this._cfgEpoch++,this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._cacheSnapshot(),this.requestUpdate(),this._showToast(this._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this._canOptimizeUndo=!1,this._undoKind=null,this._showToast(this._t("toast.error",{err:this._errText(t)}))}finally{this._optimizeUndoBusy=!1,this.requestUpdate()}}async _runBackupExport(){const t=this._backupExportDialog;if(t&&!t.busy){this._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:Ef}),i=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),s=URL.createObjectURL(i),n=document.createElement("a");n.href=s,n.download=e.filename||`houseplan-${t.kind}.json`,n.style.display="none",document.body.append(n),n.click(),n.remove(),window.setTimeout(()=>URL.revokeObjectURL(s),0),this._backupExportDialog=null,this._showToast(this._t("backup.export_done"))}catch(t){this._backupExportDialog&&(this._backupExportDialog={...this._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,i=e.files?.[0];if(e.value="",i){this._settingsDialog=null,this._backupImportDialog={filename:i.name,size:i.size,token:"",preview:null,expectedConfigRev:this._cfgRev,expectedLayoutRev:this._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain,this._persistLayout.pending()&&this._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:i,headers:{"content-type":"application/json"}},s=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}}),n=await s.json().catch(()=>({}));if(!s.ok||n.error)throw Object.assign(new Error(n.message||n.error||`HTTP ${s.status}`),{code:n.error});this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,token:n.token,preview:n.preview,expectedConfigRev:n.expected_config_rev,expectedLayoutRev:n.expected_layout_rev,busy:!1})}catch(t){this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const i=await this.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,preview:{...e.preview,...i.preview},expectedConfigRev:i.expected_config_rev,expectedLayoutRev:i.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this._backupImportDialog={...t,busy:!0,error:""};const e=this._space;try{const i=await this.hass.callWS({type:"houseplan/import/apply",token:t.token,expected_config_rev:t.expectedConfigRev,expected_layout_rev:t.expectedLayoutRev,duplicate_policy:t.duplicatePolicy,confirm_missing_content:t.confirmMissing}),[s,n]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._adoptStructuralResponses(s,n),this._geometryHistory.clear(),this._dirtyPos.clear(),this._sentPos.clear(),this._defPos={},this._cfgEpoch++,this._modelCache=null,this._frame=null,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotConfigEpoch=-1,this._regSignature="",this._signer.invalidate(this.hass),this._resign(),this._maybeRebuildDevices();const o=this._serverCfg?.spaces||[],a="space"===i.kind&&i.space_id?i.space_id:o.some(t=>t.id===e)?e:o[0]?.id||this._space;this._hasFixedFloor?this._adoptInitialSpace(this._model,!0):this._commitSpace(a),this._backupImportDialog=null,this._cacheSnapshot(),this.requestUpdate();const r="space"===i.kind?t.preview.counts:i.counts;this._showToast(this._t("space"===i.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(i.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this._backupImportDialog?.token)try{const t=this._backupImportDialog,e=await this.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this._t("backup.revalidated")})}catch(e){t=e}this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this._backupExportDialog,e=(this._serverCfg?.spaces||[]).find(t=>t.id===this._space);return W`this._backupExportDialog=null}>
${this._t("backup.export_hint")}
@@ -5587,12 +5587,12 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 .pickerLabels=${this._colorPickerLabels} .color=${i.c} .opacity=${i.a} .showOpacity=${!0} @hp-color-opacity-change=${e=>{this._setFillColor(t,{c:e.detail.color,a:e.detail.opacity})}}> -
`}get _glowRadiusCm(){const t=Number(this._settings.glow_radius_cm);return Number.isFinite(t)&&t>0?t:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const t=this._glowRadiusCm;return this._imperial?String(Math.round(t/30.48*10)/10):String(t/100)}_glowTransition(t,e){let i=this._glowRenderedSources.get(t);if(e){const e=this._glowFadeTimers.get(t);if(null!=e&&(clearTimeout(e),this._glowFadeTimers.delete(t)),null==i){this._suspendGlowFeatherForTransition(),i=++this._glowSourceSeq,this._glowRenderedSources.set(t,i),this._glowEnteringSources.add(t);const e=requestAnimationFrame(()=>{this._glowEnterRafs.get(t)===e&&(this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(t,e)}return{domId:i,entering:this._glowEnteringSources.has(t),leaving:!1}}if(null==i)return null;const s=this._glowEnterRafs.get(t);if(null!=s&&cancelAnimationFrame(s),this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),!this._glowFadeTimers.has(t)){this._suspendGlowFeatherForTransition();const e=window.setTimeout(()=>{this._glowFadeTimers.get(t)===e&&(this._glowFadeTimers.delete(t),this._glowRenderedSources.delete(t),this._glowLastAppearance.delete(t),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(t,e)}return{domId:i,entering:!1,leaving:!0}}_suspendGlowFeatherForTransition(){if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;this._glowFeatherSuspendUntil=Math.max(this._glowFeatherSuspendUntil,Date.now()+500),clearTimeout(this._glowFeatherResumeTimer);const t=Math.max(0,this._glowFeatherSuspendUntil-Date.now())+17,e=()=>{this._glowFeatherResumeTimer=0,Date.now()=128){const t=this._glowGeometryWarnings.values().next().value;t&&this._glowGeometryWarnings.delete(t)}this._glowGeometryWarnings.add(n),console.warn(`HOUSEPLAN GLOW GEOMETRY FALLBACK: #218, space ${t}, room ${i}, phase ${s}`)}}_lightBarriers(t,e){const i=this._zeroWalls(),s=this._openCuts(),n=[...i.transmissive],o=Math.max(this._cmToUnits(10),.5*this._gridPitch),a=t=>e.some(e=>this._pointInRoom(t,e.r)),r=this._openingsR.filter(t=>{if("door"!==(e=String(t.type))&&"gate"!==e&&"passage"!==e)return!1;var e;const i=t.angle*Math.PI/180,s=-Math.sin(i),n=Math.cos(i);return a([t.rx+s*o,t.ry+n*o])&&a([t.rx-s*o,t.ry-n*o])}),l=this._roomWallOpeningInputs(r,t);for(const t of l){const e=t.angle*Math.PI/180,i=Math.cos(e)*t.length/2,s=Math.sin(e)*t.length/2;n.push([t.x-i,t.y-s,t.x+i,t.y+s])}const c=new Set(r.filter(t=>t.partitionHost).map(t=>t.id)),h=[t.id,this._cfgEpoch,this._cellCm,this._gridPitch,[...c].sort().join(",")].join("|");this._lightPhysicalBodiesCache?.key!==h&&(this._lightPhysicalBodiesCache={key:h,all:eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t,t=>c.has(t.id))).all});const d=this._lightPhysicalBodiesCache.all;let p=2166136261;const u=t=>{p^=Math.round(64*(Number.isFinite(t)?t:0)),p=Math.imul(p,16777619)>>>0},_=this._spaceWalls;u(this._cellCm),u(this._gridPitch),u(this._wallKeyPitch);for(const{poly:t}of e){u(t.length);for(const e of t)u(e[0]),u(e[1])}for(const t of n)for(const e of t)u(e);u("solid"===i.style?1:0);for(const t of i.barriers)for(const e of t)u(e);for(const t of d){u(t.length);for(const e of t)u(e[0]),u(e[1])}for(const t of _)u(t.cm),u(t.a?.[0]??0),u(t.a?.[1]??0),u(t.b?.[0]??0),u(t.b?.[1]??0);const m=p.toString(36),g=`${t.id}|${m}`;if(this._lightBarrierCache?.key===g)return this._lightBarrierCache.value;const f=.02*this._gridPitch,v=[],y=_.length||d.length?Rc(t.rooms,_,s,l,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,d):null;if(!y||"ok"!==y.status&&"degraded-extra"!==y.status)for(const t of d)v.push(...zu(t));else for(const t of y.components)for(const e of lh(t.geom))v.push(...zu(e));for(const{poly:t}of e)for(const e of n.length?Ps(t,n,f):zu(t))v.push(e);for(const t of i.barriers)v.push(t);const b={occluders:Au(v),floor:e.map(t=>t.poly),fingerprint:m,masonryGeometry:!y||"ok"!==y.status&&"degraded-extra"!==y.status?[]:y.components.flatMap(t=>t.geom),opaqueBodies:d};return this._lightBarrierCache={key:g,value:b},b}_renderGlowLayer(t,e){const i=this._fillColors,s=this._glowRadiusCm/this._cellCm*this._gridPitch,n=t.rooms.map(t=>({r:t,poly:hi(t)})).filter(t=>!!t.poly),o=n.filter(({r:t})=>Fs(e.glow,t));if(!o.length)return this._forgetGlowSpace(t.id),j``;const{occluders:a,floor:r,fingerprint:l,masonryGeometry:c,opaqueBodies:h}=this._lightBarriers(t,n),d=ho(this._renderPlanHass,this._renderDevices,null,this._virtualLights).filter(e=>e.device.space===t.id),p=new Map;for(const t of d){if(!t.device.id)continue;const e=p.get(t.device.id)||[];e.push(t),p.set(t.device.id,e)}const u=[],_=new Set;for(const e of this._renderDevices){if(e.space!==t.id)continue;const o=po(p.get(e.id)||[]);if(!o)continue;const d=`${t.id}|${e.id}`;_.add(d);const m=$s(o.passive?{state:o.on?"on":"off",attributes:{}}:this._renderPlanHass.states[o.eid],e.marker?.glow_color,i.glow_light.c),g=Number(e.marker?.glow_radius_cm),f=Number.isFinite(g)&&g>0?g/this._cellCm*this._gridPitch:s,v=this._pos(e);if(dh([v.x,v.y],c,h)){this._forgetGlowSource(d);continue}const y=this._glowTransition(d,!!m);if(!y)continue;m&&this._glowLastAppearance.set(d,{c:m.c,alpha:Ss(m.bri,i.glow_light.a)});const b=this._glowLastAppearance.get(d);if(!b)continue;let w=null;const k=`${t.id}|${l}|${v.x.toFixed(4)},${v.y.toFixed(4)}|${f.toFixed(4)}`,x=qf(this._glowClipCache,k);if(x.hit)w=x.value;else{const e=Nu([v.x,v.y],f,a,96);w={lit:e.length>=3?oh([e],r,{onBoundsFailure:({boundIndex:e,phase:i})=>{const s=n[e]?.r;this._warnGlowGeometryFallback(t.id,l,s?.id||`#${e}`,i)}}):[]},Wf(this._glowClipCache,k,w,256)}u.push({key:d,sourceEid:o.eid,domId:y.domId,entering:y.entering,leaving:y.leaving,pos:v,c:b.c,alpha:b.alpha,geometry:w,r:f})}const m=`${t.id}|`;for(const t of this._glowRenderedSources.keys())t.startsWith(m)&&!_.has(t)&&this._forgetGlowSource(t);if(!u.length)return j``;const g=this._spaceWalls,f=o.length===n.length?[]:this._openCuts(),v=this._wallUnionGeometry()?.roomGeom,y=o.length===n.length?null:o.map(({r:e,poly:i})=>{const s=g.length&&e.id&&fc(t.rooms,e.id,g,f,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,v)||i,o=this._cleanFloor(e,s,t).path,a=Pi(s,n.filter(t=>t.r!==e).map(t=>t.poly)),r=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z";return[o||r(s),...a.map(r)].join(" ")}),b=this._viewOr(this._baseVb()),w=this._stageEl?.clientWidth&&b.w?this._stageEl.clientWidth/b.w:1,k=1/(w>0?w:1),x=!this._pinchStart&&!this._panStart&&Date.now()>=this._glowFeatherSuspendUntil;(null==this._glowFeatherUnits||x)&&(this._glowFeatherUnits=k);const $=this._glowFeatherUnits??k,S=4*$,M=u.reduce((t,e)=>({x:Math.min(t.x,e.pos.x-e.r-S),y:Math.min(t.y,e.pos.y-e.r-S),maxX:Math.max(t.maxX,e.pos.x+e.r+S),maxY:Math.max(t.maxY,e.pos.y+e.r+S),w:0,h:0}),{x:1/0,y:1/0,maxX:-1/0,maxY:-1/0,w:0,h:0});return M.w=M.maxX-M.x,M.h=M.maxY-M.y,j` + `}get _glowRadiusCm(){const t=Number(this._settings.glow_radius_cm);return Number.isFinite(t)&&t>0?t:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const t=this._glowRadiusCm;return this._imperial?String(Math.round(t/30.48*10)/10):String(t/100)}_glowTransition(t,e){let i=this._glowRenderedSources.get(t);if(e){const e=this._glowFadeTimers.get(t);if(null!=e&&(clearTimeout(e),this._glowFadeTimers.delete(t)),null==i){this._suspendGlowFeatherForTransition(),i=++this._glowSourceSeq,this._glowRenderedSources.set(t,i),this._glowEnteringSources.add(t);const e=requestAnimationFrame(()=>{this._glowEnterRafs.get(t)===e&&(this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(t,e)}return{domId:i,entering:this._glowEnteringSources.has(t),leaving:!1}}if(null==i)return null;const s=this._glowEnterRafs.get(t);if(null!=s&&cancelAnimationFrame(s),this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),!this._glowFadeTimers.has(t)){this._suspendGlowFeatherForTransition();const e=window.setTimeout(()=>{this._glowFadeTimers.get(t)===e&&(this._glowFadeTimers.delete(t),this._glowRenderedSources.delete(t),this._glowLastAppearance.delete(t),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(t,e)}return{domId:i,entering:!1,leaving:!0}}_suspendGlowFeatherForTransition(){if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;this._glowFeatherSuspendUntil=Math.max(this._glowFeatherSuspendUntil,Date.now()+500),clearTimeout(this._glowFeatherResumeTimer);const t=Math.max(0,this._glowFeatherSuspendUntil-Date.now())+17,e=()=>{this._glowFeatherResumeTimer=0,Date.now()=128){const t=this._glowGeometryWarnings.values().next().value;t&&this._glowGeometryWarnings.delete(t)}this._glowGeometryWarnings.add(n),console.warn(`HOUSEPLAN GLOW GEOMETRY FALLBACK: #218, space ${t}, room ${i}, phase ${s}`)}}_lightBarriers(t,e){const i=this._zeroWalls(),s=this._openCuts(),n=[...i.transmissive],o=Math.max(this._cmToUnits(10),.5*this._gridPitch),a=t=>e.some(e=>this._pointInRoom(t,e.r)),r=this._openingsR.filter(t=>{if("door"!==(e=String(t.type))&&"gate"!==e&&"passage"!==e)return!1;var e;const i=t.angle*Math.PI/180,s=-Math.sin(i),n=Math.cos(i);return a([t.rx+s*o,t.ry+n*o])&&a([t.rx-s*o,t.ry-n*o])}),l=this._roomWallOpeningInputs(r,t);for(const t of l){const e=t.angle*Math.PI/180,i=Math.cos(e)*t.length/2,s=Math.sin(e)*t.length/2;n.push([t.x-i,t.y-s,t.x+i,t.y+s])}const c=new Set(r.filter(t=>t.partitionHost).map(t=>t.id)),h=[t.id,this._cfgEpoch,this._cellCm,this._gridPitch,[...c].sort().join(",")].join("|");this._lightPhysicalBodiesCache?.key!==h&&(this._lightPhysicalBodiesCache={key:h,all:eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t,t=>c.has(t.id))).all});const d=this._lightPhysicalBodiesCache.all;let p=2166136261;const u=t=>{p^=Math.round(64*(Number.isFinite(t)?t:0)),p=Math.imul(p,16777619)>>>0},_=this._spaceWalls;u(this._cellCm),u(this._gridPitch),u(this._wallKeyPitch);for(const{poly:t}of e){u(t.length);for(const e of t)u(e[0]),u(e[1])}for(const t of n)for(const e of t)u(e);u("solid"===i.style?1:0);for(const t of i.barriers)for(const e of t)u(e);for(const t of d){u(t.length);for(const e of t)u(e[0]),u(e[1])}for(const t of _)u(t.cm),u(t.a?.[0]??0),u(t.a?.[1]??0),u(t.b?.[0]??0),u(t.b?.[1]??0);const m=p.toString(36),g=`${t.id}|${m}`;if(this._lightBarrierCache?.key===g)return this._lightBarrierCache.value;const f=.02*this._gridPitch,v=[],y=_.length||d.length?Rc(t.rooms,_,s,l,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,d):null;if(!y||"ok"!==y.status&&"degraded-extra"!==y.status)for(const t of d)v.push(...zu(t));else for(const t of y.components)for(const e of lh(t.geom))v.push(...zu(e));for(const{poly:t}of e)for(const e of n.length?Ps(t,n,f):zu(t))v.push(e);for(const t of i.barriers)v.push(t);const b={occluders:Au(v),floor:e.map(t=>t.poly),fingerprint:m,masonryGeometry:!y||"ok"!==y.status&&"degraded-extra"!==y.status?[]:y.components.flatMap(t=>t.geom),opaqueBodies:d};return this._lightBarrierCache={key:g,value:b},b}_renderGlowLayer(t,e){const i=this._fillColors,s=this._glowRadiusCm/this._cellCm*this._gridPitch,n=t.rooms.map(t=>({r:t,poly:hi(t)})).filter(t=>!!t.poly),o=n.filter(({r:t})=>Fs(e.glow,t));if(!o.length)return this._forgetGlowSpace(t.id),j``;const{occluders:a,floor:r,fingerprint:l,masonryGeometry:c,opaqueBodies:h}=this._lightBarriers(t,n),d=ho(this._renderPlanHass,this._renderDevices,null,this._virtualLights).filter(e=>e.device.space===t.id),p=new Map;for(const t of d){if(!t.device.id)continue;const e=p.get(t.device.id)||[];e.push(t),p.set(t.device.id,e)}const u=[],_=new Set;for(const e of this._renderDevices){if(e.space!==t.id)continue;const o=po(p.get(e.id)||[]);if(!o)continue;const d=`${t.id}|${e.id}`;_.add(d);const m=$s(o.passive?{state:o.on?"on":"off",attributes:{}}:this._renderPlanHass.states[o.eid],e.marker?.glow_color,i.glow_light.c),g=Number(e.marker?.glow_radius_cm),f=Number.isFinite(g)&&g>0?g/this._cellCm*this._gridPitch:s,v=this._pos(e);if(dh([v.x,v.y],c,h)){this._forgetGlowSource(d);continue}const y=this._glowTransition(d,!!m);if(!y)continue;m&&this._glowLastAppearance.set(d,{c:m.c,alpha:Ss(m.bri,i.glow_light.a)});const b=this._glowLastAppearance.get(d);if(!b)continue;let w=null;const k=`${t.id}|${l}|${v.x.toFixed(4)},${v.y.toFixed(4)}|${f.toFixed(4)}`,x=Wf(this._glowClipCache,k);if(x.hit)w=x.value;else{const e=Nu([v.x,v.y],f,a,96);w={lit:e.length>=3?oh([e],r,{onBoundsFailure:({boundIndex:e,phase:i})=>{const s=n[e]?.r;this._warnGlowGeometryFallback(t.id,l,s?.id||`#${e}`,i)}}):[]},jf(this._glowClipCache,k,w,256)}u.push({key:d,sourceEid:o.eid,domId:y.domId,entering:y.entering,leaving:y.leaving,pos:v,c:b.c,alpha:b.alpha,geometry:w,r:f})}const m=`${t.id}|`;for(const t of this._glowRenderedSources.keys())t.startsWith(m)&&!_.has(t)&&this._forgetGlowSource(t);if(!u.length)return j``;const g=this._spaceWalls,f=o.length===n.length?[]:this._openCuts(),v=this._wallUnionGeometry()?.roomGeom,y=o.length===n.length?null:o.map(({r:e,poly:i})=>{const s=g.length&&e.id&&fc(t.rooms,e.id,g,f,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,v)||i,o=this._cleanFloor(e,s,t).path,a=Pi(s,n.filter(t=>t.r!==e).map(t=>t.poly)),r=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z";return[o||r(s),...a.map(r)].join(" ")}),b=this._viewOr(this._baseVb()),w=this._stageEl?.clientWidth&&b.w?this._stageEl.clientWidth/b.w:1,k=1/(w>0?w:1),x=!this._pinchStart&&!this._panStart&&Date.now()>=this._glowFeatherSuspendUntil;(null==this._glowFeatherUnits||x)&&(this._glowFeatherUnits=k);const $=this._glowFeatherUnits??k,S=4*$,M=u.reduce((t,e)=>({x:Math.min(t.x,e.pos.x-e.r-S),y:Math.min(t.y,e.pos.y-e.r-S),maxX:Math.max(t.maxX,e.pos.x+e.r+S),maxY:Math.max(t.maxY,e.pos.y+e.r+S),w:0,h:0}),{x:1/0,y:1/0,maxX:-1/0,maxY:-1/0,w:0,h:0});return M.w=M.maxX-M.x,M.h=M.maxY-M.y,j` ${Mt(u,t=>t.key,t=>{const e=t.domId,i=t.geometry;return j` ${""} - ${iv.map(([e,i])=>j` + ${sv.map(([e,i])=>j` `)} @@ -5729,7 +5729,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t("gs.glow_radius")} {const e=Bf(t.target.value);null!=e&&e>0&&(this._settingsDialog={...this._settingsDialog,glowRadius:e})}} /> + @input=${t=>{const e=qf(t.target.value);null!=e&&e>0&&(this._settingsDialog={...this._settingsDialog,glowRadius:e})}} /> ${this._imperial?this._t("gs.unit_ft"):this._t("gs.unit_m")} @@ -5804,7 +5804,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 `:G} -
${this._t("gs.about_version",{v:Ff})}
+
${this._t("gs.about_version",{v:Ef})}
${this._t("gs.about_github")} @@ -5861,7 +5861,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${t.busy?"…":this._t("btn.save")} -
`}_saveKioskScale(t){this._kioskScale={...this._kioskScale,...t};try{localStorage.setItem(Zf,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const t=this._kioskScale,e=(e,i)=>W` +
`}_saveKioskScale(t){this._kioskScale={...this._kioskScale,...t};try{localStorage.setItem(Qf,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const t=this._kioskScale,e=(e,i)=>W`
${this._rangeInput(50,300,5,Math.round(100*t[e]),t=>this._saveKioskScale({[e]:t/100}))} ${Math.round(100*t[e])}% @@ -5918,7 +5918,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._spaceDialog?this._renderSpaceDialog():G} ${this._importDialog?this._renderImportDialog():G} ${this._toast?W``:G} - `;const s=this._spaceModel();if(!s)return G;const n="valid"===i.kind?[s]:t,o=s.vb,a=this._effectiveProjection();this._renderProjection=a,this._labs.active.length&&function(t){Hg||Gg(t);const e=Lg,i=e.active.join(",");if(!i||i===qg)return;qg=i;const s=new Map(Tg.map(t=>[t.id,t])),n=e.active.map(t=>{const e=s.get(t);return`${t} (#${e.issue}, expires ${e.expires})`}).join(", ");console.info(`HOUSEPLAN LABS: ${n}`)}(Ff);const r="iso"===a,l="devices"===this._mode&&this._showAll,c=this._renderDevices.filter(t=>t.space===s.id&&(!t.hidden||l)),h=this._renderDeviceSnapshot,d=this._spaceDisplayForRender(),p=r?this._isoDecorationLayers(d):null,u=p?this._isoOpeningPanels(p):[],_=this._resolvedRoomFills(s,d),m=this._resolvedGlowBase(s,d,_),g=d.showLqi??this._config.show_signal??!0,f=this._config.icon_size??2.5,v=f>8?2.5:f,y=o_(v),b=this._viewOr(this._baseVb()),w=this._floorView(b),k=this._editing?"":this._stageBg(d),x=this._opMeasureView,$=this._decorMeasure,S=this._bdLive,M=this._furnLive,C="view"===this._mode?this._editorChromeMode:this._mode,D=this._roomHoverPaths(s),P=s.bg?this._display(s.bg.href):"",T=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null,R=this._modeTransitionVisual,I=this._dayCycleState(),A=R?.viewWeight??("view"===this._mode?1:0),z=this._modeTransition.state?.from.presentedMode,F=!this._markup||!!R&&("view"===R.presentedMode||"devices"===R.presentedMode||"view"===z||"devices"===z),E=R?.stageColor||k,N=R?.sceneBrightness??1;return W` + `;const s=this._spaceModel();if(!s)return G;const n="valid"===i.kind?[s]:t,o=s.vb,a=this._effectiveProjection();this._renderProjection=a,this._labs.active.length&&function(t){Bg||Vg(t);const e=Hg,i=e.active.join(",");if(!i||i===Wg)return;Wg=i;const s=new Map(Rg.map(t=>[t.id,t])),n=e.active.map(t=>{const e=s.get(t);return`${t} (#${e.issue}, expires ${e.expires})`}).join(", ");console.info(`HOUSEPLAN LABS: ${n}`)}(Ef);const r="iso"===a,l="devices"===this._mode&&this._showAll,c=this._renderDevices.filter(t=>t.space===s.id&&(!t.hidden||l)),h=this._renderDeviceSnapshot,d=this._spaceDisplayForRender(),p=r?this._isoDecorationLayers(d):null,u=p?this._isoOpeningPanels(p):[],_=this._resolvedRoomFills(s,d),m=this._resolvedGlowBase(s,d,_),g=d.showLqi??this._config.show_signal??!0,f=this._config.icon_size??2.5,v=f>8?2.5:f,y=o_(v),b=this._viewOr(this._baseVb()),w=this._floorView(b),k=this._editing?"":this._stageBg(d),x=this._opMeasureView,$=this._decorMeasure,S=this._bdLive,M=this._furnLive,C="view"===this._mode?this._editorChromeMode:this._mode,D=this._roomHoverPaths(s),P=s.bg?this._display(s.bg.href):"",T=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null,R=this._modeTransitionVisual,I=this._dayCycleState(),A=R?.viewWeight??("view"===this._mode?1:0),z=this._modeTransition.state?.from.presentedMode,F=!this._markup||!!R&&("view"===R.presentedMode||"devices"===R.presentedMode||"view"===z||"devices"===z),E=R?.stageColor||k,N=R?.sceneBrightness??1;return W` + transform=${p?.structural?Zg():G}> ${""} ${this._wallHatchDefs(d.color)}${j`${this._paperShapes(s.rooms).map(t=>"path"in t?j``:"poly"in t?j``:j``)}`} ${this._editing?this._renderMarkupDefs(o):G} @@ -6039,7 +6039,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 transform=${s.bg.angle?`rotate(${s.bg.angle} ${s.bg.x+s.bg.w/2} ${s.bg.y+s.bg.h/2})`:G} @dblclick=${t=>this._openBackdropDialog(t)} preserveAspectRatio="none" />`:G} - ${(()=>{const t=this._openCuts(),e=new Map,i=t=>(e.has(t)||e.set(t,hi(t)),e.get(t));return s.rooms.filter(t=>t.area||"view"===this._mode||this._markup||d.showBorders).map(e=>{let n="room "+(s.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||e.id!==this._mergeSel&&e.id!==this._splitSel?.roomId||(n+=" picked");let o="";const a=zs(d.fill,e);if(!this._markup&&(d.showBorders||"none"!==a)){n+=" styled";const t=[];t.push(`--room-stroke:${d.color}`,`--room-stroke-op:${d.showBorders?d.opacity:0}`);const i=_.byRoom.get(e)||null;i?(n+=" filled",t.push(`--room-fill:${i.color}`,`--room-fill-op:${i.opacity}`)):t.push("--room-fill:transparent","--room-fill-op:0"),o=t.join(";")}let r;const l=t=>{"view"===this._mode&&(void 0===r&&(r=this._roomArea(e)),this._showTip(t,e.name||this._t("room.unnamed"),r?this._t("tip.area",{value:r}):"",g?this._roomLqi(e.area):null,this._roomTemp(e),this._roomHum(e)))},c=i(e),h=this._markup&&(e.id===this._mergeSel||e.id===this._splitSel?.roomId),p=c&&!h?t.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return c.some((t,i)=>Ls(e,[t[0],t[1],...c[(i+1)%c.length]])<=.08*this._gridPitch)}):[],u=h?[]:this._thickWallCuts(),m=p.concat(u);m.length&&(n+=" noedge");const f=this._spaceWalls,v=f.length&&e.id&&c&&fc(s.rooms,e.id,f,t,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,this._wallUnionGeometry()?.roomGeom)||c,y=v?Pi(v,(b=e,s.rooms.filter(t=>t!==b).map(i).filter(Boolean))):[];var b;const w=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",k=v?this._cleanFloor(e,v,s).path:"",x=e.id||G,$=e.area||G,S=k&&v?j`{const t=this._openCuts(),e=new Map,i=t=>(e.has(t)||e.set(t,hi(t)),e.get(t));return s.rooms.filter(t=>t.area||"view"===this._mode||this._markup||d.showBorders).map(e=>{let n="room "+(s.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||e.id!==this._mergeSel&&e.id!==this._splitSel?.roomId||(n+=" picked");let o="";const a=zs(d.fill,e);if(!this._markup&&(d.showBorders||"none"!==a)){n+=" styled";const t=[];t.push(`--room-stroke:${d.color}`,`--room-stroke-op:${d.showBorders?d.opacity:0}`);const i=_.byRoom.get(e)||null;i?(n+=" filled",t.push(`--room-fill:${i.color}`,`--room-fill-op:${i.opacity}`)):t.push("--room-fill:transparent","--room-fill-op:0"),o=t.join(";")}let r;const l=t=>{"view"===this._mode&&(void 0===r&&(r=this._roomArea(e)),this._showTip(t,e.name||this._t("room.unnamed"),r?this._t("tip.area",{value:r}):"",g?this._roomLqi(e.area):null,this._roomTemp(e),this._roomHum(e)))},c=i(e),h=this._markup&&(e.id===this._mergeSel||e.id===this._splitSel?.roomId),p=c&&!h?t.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return c.some((t,i)=>Ls(e,[t[0],t[1],...c[(i+1)%c.length]])<=.08*this._gridPitch)}):[],u=h?[]:this._thickWallCuts(),m=p.concat(u);m.length&&(n+=" noedge");const f=this._spaceWalls,v=f.length&&e.id&&c&&fc(s.rooms,e.id,f,t,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,this._wallUnionGeometry()?.roomGeom)||c,y=v?Pi(v,(b=e,s.rooms.filter(t=>t!==b).map(i).filter(Boolean))):[];var b;const w=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",k=v?this._cleanFloor(e,v,s).path:"",x=e.id||G,$=e.area||G,S=k&&v?j`{this._notePointer(t),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:s.id,room:e})}} @@ -6333,7 +6333,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 @pointercancel=${e=>this._pointerUp(e,t)} > ${Ko(r,{newDevice:this._newIds.has(t.id),newDeviceTitle:this._t("device.new"),disabledTitle:r.haDisabled?h:""})} -
`}_roomArea(t){const e=hi(t);if(!e)return null;const i=this._spaceModel();if(!i)return null;const s=this._spaceWalls,n=s.length&&t.id&&fc(i.rooms,t.id,s,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,ev,this._wallUnionGeometry()?.roomGeom)||e,o=this._cleanFloor(t,n),a=this._cellCm/this._gridPitch;return ir(o.area*a*a/1e4,"mi"===this._renderPlanHass?.config?.unit_system?.length)}_roomTemp(t){const e=t.settings?.temp_source;return e?Mo(this._renderPlanHass,e,"temp",this._markers):t.area?this._climate().get(t.area)?.temp??null:null}_roomHum(t){const e=t.settings?.hum_source;return e?Mo(this._renderPlanHass,e,"hum",this._markers):t.area?this._climate().get(t.area)?.hum??null:null}_climate(){const t=this._serverCfg?.markers,e=this._renderPlanHass,i=this._climateCache;if(i&&i.h===e&&i.r===this._iconRules&&i.mk===t)return i.m;const s=function(t,e,i){const s=new Map;if(!t?.entities)return s;const n=wo(i),o=new Set;for(const t of i||[]){if(t?.removed||!0!==t?.use_climate_temp)continue;const e=(t.binding||"").indexOf(":");e>0&&o.add(t.binding.slice(e+1))}const a=new Map;for(const[e,i]of Object.entries(t.entities)){if(i.device_id&&n.devices.has(i.device_id)&&!n.liveEntities.has(e)||!i.device_id&&n.entities.has(e)&&!n.liveEntities.has(e))continue;const s=i.device_id?t.devices?.[i.device_id]:null,r=i.area_id||s?.area_id||null;if(!r)continue;if(i.entity_category)continue;if(!(o.size>0&&e.startsWith("climate.")&&(o.has(e)||i.device_id&&o.has(i.device_id)))){if(Yt.has(i.platform))continue;if(Co.test(e))continue}let l=a.get(r);l||(l=new Map,a.set(r,l));const c=i.device_id||e;let h=l.get(c);if(!h){const n=t.states?.[e];h={name:(s?s.name_by_user||s.name:i.name||n?.attributes?.friendly_name||e)||e,model:s?.model,ents:[]},l.set(c,h)}h.ents.push(e)}for(const[i,n]of a){const a=[],r=[];for(const[i,s]of n){const n=bo(t,s.name,s.model,s.ents,e),l="mdi:thermometer"===n||"mdi:air-filter"===n;if(l){const e=mo(t,s.ents);null!=e&&a.push(e)}if(o.size>0&&(o.has(i)||s.ents.some(t=>o.has(t)))){const e=go(t,s.ents);null!=e&&a.push(e)}if(l||"mdi:water-percent"===n){const e=vo(t,s.ents);null!=e&&r.push(e)}}(a.length||r.length)&&s.set(i,{temp:a.length?Math.round(a.reduce((t,e)=>t+e,0)/a.length*10)/10:null,hum:r.length?Math.round(r.reduce((t,e)=>t+e,0)/r.length):null})}return s}(e,this._iconRules,t);return this._climateCache={h:e,r:this._iconRules,mk:t,m:s},s}_resetRoomDialogFields(){this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1}_openRoomEdit(t){if(!t.id)return;this._roomEditId=t.id,this._nameSel=t.name||"",this._areaSel=t.area||"",this._roomFill="glow"===t.settings?.fill_mode?"":t.settings?.fill_mode||"";const e=t.settings?.custom_fill;this._roomCustomFill=e&&"object"==typeof e?rs(e,cs(this._curSpaceCfg).customFill):null,this._roomTempSrc=t.settings?.temp_source||"",this._roomHumSrc=t.settings?.hum_source||"",this._roomNameScale=Es(t.settings?.name_scale),this._roomLabelScale=Es(t.settings?.label_scale),this._roomSrcOpen=null,this._roomSrcFilter="",this._roomDialog=!0}_roomSettingsFromDialog(){const t={};return this._roomFill&&(t.fill_mode=this._roomFill),this._roomCustomFill&&(t.custom_fill=this._roomCustomFill),this._roomTempSrc&&(t.temp_source=this._roomTempSrc),this._roomHumSrc&&(t.hum_source=this._roomHumSrc),1!==this._roomNameScale&&(t.name_scale=this._roomNameScale),1!==this._roomLabelScale&&(t.label_scale=this._roomLabelScale),Object.keys(t).length?t:null}_saveRoomEdit(){const t=this._curSpaceCfg,e=t?.rooms.find(t=>t.id===this._roomEditId);if(!e)return this._roomDialog=!1,void(this._roomEditId=null);e.name=this._nameSel.trim()||e.name,e.area=this._areaSel||null;const i=e.settings||{},s={...i};this._roomFill?s.fill_mode=this._roomFill:delete s.fill_mode,this._roomCustomFill?s.custom_fill=this._roomCustomFill:delete s.custom_fill,"glow"===i.fill_mode&&"boolean"!=typeof i.glow&&(s.glow=!0),this._roomTempSrc?s.temp_source=this._roomTempSrc:delete s.temp_source,this._roomHumSrc?s.hum_source=this._roomHumSrc:delete s.hum_source,1!==this._roomNameScale?s.name_scale=this._roomNameScale:delete s.name_scale,1!==this._roomLabelScale?s.label_scale=this._roomLabelScale:delete s.label_scale,Object.keys(s).length?e.settings=s:delete e.settings,this._saveConfig(),this._roomDialog=!1,this._roomEditId=null,this._nameSel="",this._areaSel="",this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate(),this._showToast(this._t("toast.room_updated"))}_roomSrcCandidates(){const t=this._planHass,e=wo(this._markers),i=this._roomSrcFilter.trim().toLowerCase(),s=[];for(const n of Object.values(t.devices)){if("service"===n.entry_type)continue;if(e.devices.has(n.id))continue;const t=(n.name_by_user||n.name||n.id).trim();i&&!t.toLowerCase().includes(i)||s.push({value:"device:"+n.id,label:t,sub:n.model||this._t("marker.sub_device")})}for(const[n,o]of Object.entries(t.entities)){if(!n.startsWith("sensor.")||o.hidden)continue;if(ko(t,n,e))continue;const a=o.name||t.states[n]?.attributes?.friendly_name||n;i&&!(a+" "+n).toLowerCase().includes(i)||s.push({value:"entity:"+n,label:a,sub:n})}return s.sort((t,e)=>t.label.localeCompare(e.label)),s.slice(0,200)}_roomSrcLabel(t){const e=t.indexOf(":"),i=t.slice(0,e),s=t.slice(e+1);return"device"===i?this._fullRegistryHass.devices[s]?.name_by_user||this._fullRegistryHass.devices[s]?.name||s:this._fullRegistryHass.entities[s]?.name||this.hass.states[s]?.attributes?.friendly_name||s}_labelPos(t,e){const i=this._layout["rl_"+(t.id||"")];if(i&&i.s===e)return{x:i.x*ev,y:i.y*ev};const s=this._snap(this._roomCenter(t));return{x:s[0],y:s[1]}}_labelDown(t,e,i){if("plan"!==this._mode)return;t.preventDefault(),t.stopPropagation();const s=this._labelPos(e,i);this._drag={id:"rl_"+(e.id||""),sx:t.clientX,sy:t.clientY,ox:s.x,oy:s.y,moved:!1},cv(t),this._tip=null}_labelMove(t,e,i){const s="rl_"+(e.id||"");if(!this._drag||this._drag.id!==s)return;const n=this._stageEl;if(!n)return;const o=this._spaceModelById(i);if(!o)return;const a=o.vb,r=n.getBoundingClientRect(),l=this._viewOr(a),c=(t.clientX-this._drag.sx)/r.width*l.w,h=(t.clientY-this._drag.sy)/r.height*l.h;Math.abs(t.clientX-this._drag.sx)+Math.abs(t.clientY-this._drag.sy)>3&&(this._drag.moved=!0);const d=Ih(this._drag.ox+c),p=Ih(this._drag.oy+h);this._savePos({id:s,space:i},d,p)}_labelUp(t){const e="rl_"+(t.id||"");if(!this._drag||this._drag.id!==e)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&window.setTimeout(()=>this._drag=null,0)}_labelScale(t){const e=this._layout["rl_"+(t.id||"")]?.k;return"number"==typeof e&&Number.isFinite(e)?Math.min(3,Math.max(.5,e)):1}_rlResizeDown(t,e,i){if("plan"!==this._mode)return;t.preventDefault(),t.stopPropagation();const s=t.target.closest(".roomlabel");if(!s)return;const n=s.getBoundingClientRect(),o=n.left+n.width/2,a=n.top+n.height/2,r=Math.max(8,Math.hypot(t.clientX-o,t.clientY-a));this._rlResize={id:"rl_"+(e.id||""),space:i,k0:this._labelScale(e),cx:o,cy:a,d0:r},cv(t)}_rlResizeMove(t){const e=this._rlResize;if(!e)return;t.stopPropagation();const i=Math.max(8,Math.hypot(t.clientX-e.cx,t.clientY-e.cy)),s=Math.min(3,Math.max(.5,e.k0*(i/e.d0))),n=this._layout[e.id];if(n)this._layout={...this._layout,[e.id]:{...n,k:s}};else{const t=e.id.slice(3),i=this._spaceModelById(e.space);if(!i)return;const n=i.rooms.find(e=>e.id===t);if(!n)return;const o=this._labelPos(n,e.space);this._layout={...this._layout,[e.id]:{s:e.space,x:o.x/ev,y:o.y/ev,k:s}}}this._dirtyPos.add(e.id)}_rlResizeUp(){this._rlResize&&(this._rlResize=null,this._persistLayout())}_renderRoomGear(t,e,i){if(!t.id)return G;let s=null;if(t.poly?(s=this._gearPtCache.get(t.poly)||null,s||(s=$i(t.poly),this._gearPtCache.set(t.poly,s))):null!=t.x&&null!=t.y&&(s=[t.x+(t.w||0)/2,t.y+(t.h||0)/2]),!s)return G;const n=(s[0]-i.x)/i.w*100,o=(s[1]-i.y)/i.h*100;return W` - `}_renderOpeningDialog(){const t=this._openingDialog,e=this._spaceModel()?.partitions||[],i=t.id?this._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,s={id:t.id||"preview",type:t.type,x:t.x/ev,y:t.y/this._spaceH,angle:t.angle,length:i&&!t.lengthTouched?i.length:this._cmToUnits(Math.max(20,t.lengthCm))/ev,...t.host?{host:t.host}:{}},n=Mp(i,s),o=t.host?n?Sp(s,e,ev,this._cellCm,this._gridPitch):$p(s,e,ev,this._cellCm,this._gridPitch):null,a="does-not-fit-jamb"===o?.reason,r=t.host?e.find(e=>e.id===t.host.id):null,l=r?li(r.cm/2,this._imperial):"",c=!!t.host&&!o?.resolved&&!a,h="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",d=(e,i)=>{const s="contact"===e?t.contact:t.lock,n="contact"===e?!!t.contactOpen:!!t.lockOpen,o="contact"===e?t.contactFilter||"":t.lockFilter||"",a=i.find(t=>t.value===s),r=a?.label||this.hass.states[s]?.attributes?.friendly_name||this._fullRegistryHass.entities[s]?.name||s,l=function(t,e,i=200){const s=e.trim().toLowerCase();return(s?t.filter(t=>t.label.toLowerCase().includes(s)||t.value.toLowerCase().includes(s)):t).slice(0,Math.max(0,i))}(i,o);return W` + `}_renderOpeningDialog(){const t=this._openingDialog,e=this._spaceModel()?.partitions||[],i=t.id?this._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,s={id:t.id||"preview",type:t.type,x:t.x/iv,y:t.y/this._spaceH,angle:t.angle,length:i&&!t.lengthTouched?i.length:this._cmToUnits(Math.max(20,t.lengthCm))/iv,...t.host?{host:t.host}:{}},n=Mp(i,s),o=t.host?n?Sp(s,e,iv,this._cellCm,this._gridPitch):$p(s,e,iv,this._cellCm,this._gridPitch):null,a="does-not-fit-jamb"===o?.reason,r=t.host?e.find(e=>e.id===t.host.id):null,l=r?li(r.cm/2,this._imperial):"",c=!!t.host&&!o?.resolved&&!a,h="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",d=(e,i)=>{const s="contact"===e?t.contact:t.lock,n="contact"===e?!!t.contactOpen:!!t.lockOpen,o="contact"===e?t.contactFilter||"":t.lockFilter||"",a=i.find(t=>t.value===s),r=a?.label||this.hass.states[s]?.attributes?.friendly_name||this._fullRegistryHass.entities[s]?.name||s,l=function(t,e,i=200){const s=e.trim().toLowerCase();return(s?t.filter(t=>t.label.toLowerCase().includes(s)||t.value.toLowerCase().includes(s)):t).slice(0,Math.max(0,i))}(i,o);return W` `:G} - `}_markerValueBadgeFields(t){return(e={touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition}).touched?{value_badge:{enabled:e.enabled,source:e.source,position:e.position}}:e.originalHas?{value_badge:e.original}:{};var e}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=qs(t.room),i=Fi(t.binding,t.devId,()=>"__hp_device_preview__"),s=this._markers.find(e=>e.id===i||e.id===t.devId),n=Zn(t.binding,t.controls,this._bindingEntities(t.binding)),o=this._effectiveStoredTapAction(t),a={id:i,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===o&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:n.length?n:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=Bf(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:s?.vacuum||null};return("virtual"===t.binding||t.room)&&(a.space=e?.space||("virtual"===t.binding?this._space:null),a.area=e?.area||null,a.room_id=e?.roomId||null),a}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const i=`${this._haRegistry.revision}\n${bd(this._markers)}\n${JSON.stringify(e)}`;if(this._markerPreviewMemo?.key===i)return this._markerPreviewMemo.device;const s=function(t){const{marker:e,siblingMarkers:i=[],...s}=t;return So({...s,markers:[...i.filter(t=>t.id!==e.id),e]}).find(t=>t.id===e.id)||null}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||this._space,loc:t=>this._t(t),iconRules:this._iconRules});return this._markerPreviewMemo={key:i,device:s},s}_markerPreviewDevices(t){const e=this._markerPreviewDevicesMemo;if(e?.base===this._devices&&e.preview===t)return e.devices;const i=[...this._devices.filter(e=>e.id!==t.id),t];return this._markerPreviewDevicesMemo={base:this._devices,preview:t,devices:i},i}_toggleIntent(t,e=this._devices){return gp({hass:this._planHass,registryHass:this._fullRegistryHass,devices:e,device:t,virtualLights:this._virtualLights})}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const i=this._markerPreviewDevices(e);return this._toggleIntent(e,i)}_toggleStateText(t,e){const i=this._planHass?.states?.[t]||this.hass?.states?.[t];try{return i&&"function"==typeof this.hass?.formatEntityState?this.hass.formatEntityState(i):e}catch{return e}}_toggleConfirmationStateText(t){const e=String(t.state||"unknown"),i=t.entityId?this._toggleStateText(t.entityId,e):e;if(i.trim().toLocaleLowerCase()!==e.trim().toLocaleLowerCase())return i;const s={on:"confirm.state_on",off:"confirm.state_off",open:"confirm.state_open",closed:"confirm.state_closed",opening:"confirm.state_opening",closing:"confirm.state_closing",unknown:"confirm.state_unknown"}[e];return s?this._t(s):e.replaceAll("_"," ").replaceAll("-"," ")}_toggleConfirmationLines(t){const e={"turn-on":"confirm.state_on","turn-off":"confirm.state_off",open:"confirm.state_open",close:"confirm.state_closed",stop:"confirm.state_stopped"};return function(t,e){if(!vp(t)||!t.nextEffect||!t.targets.length)return[];const i="group"===t.kind,s=i?t.targets.filter(t=>"on"===t.state).length:0,n=i?0===s?e.groupAllOff():e.groupCurrent(s,t.targets.length):e.state(t.targets[0]);let o;return o="toggle"===t.nextEffect?e.expectedByHa():i&&"turn-on"===t.nextEffect?e.groupAllOn():i&&"turn-off"===t.nextEffect?e.groupAllOff():e.effect(t.nextEffect),[e.current(n),e.expected(o),...t.skippedTargets.length?[e.unavailable(t.skippedTargets.length)]:[]]}(t,{state:t=>this._toggleConfirmationStateText(t),current:t=>this._t("confirm.current_state",{state:t}),expected:t=>this._t("confirm.expected_state",{state:t}),groupCurrent:(t,e)=>this._t("confirm.group_current",{on:t,total:e}),groupAllOn:()=>this._t("confirm.group_all_on"),groupAllOff:()=>this._t("confirm.group_all_off"),unavailable:t=>this._t("confirm.unavailable_targets",{count:t}),effect:t=>this._t(e[t]),expectedByHa:()=>this._t("confirm.expected_by_ha")})}_toggleHintLines(t){if(!t)return[];const e=t=>this._t(`marker.toggle_effect_${t.replace("-","_")}`),i=t=>this._t(`marker.toggle_skip_${t.replace("-","_")}`);return function(t,e){const i=t.targets[0]||t.skippedTargets[0],s=[];return"group"===t.kind?t.targets.length&&s.push(e.group(t.targets)):i&&s.push(e.single(i)),t.nextEffect&&t.targets.length&&s.push("group"===t.kind?e.groupCurrentNext(t.targets,t.nextEffect):e.currentNext(t.targets[0],t.nextEffect)),t.skippedTargets.length&&s.push(e.skipped(t.skippedTargets)),!t.command&&t.noneReason&&s.push(e.none(t.noneReason)),s}(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),i=t.name||e;return this._t("marker.toggle_hint_single",{name:i,id:e})},group:t=>this._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,i)=>"virtual-light"===t.via?this._t("marker.virtual_light_current",{state:this._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(i)}):this._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(i)}),groupCurrentNext:(t,i)=>this._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(i)}),skipped:t=>this._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${i(t.reason)})`}).join(", ")}),none:t=>this._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:pp(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),i=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},s="toggle"===i.tapAction?this._toggleHintLines(this._toggleIntentForDialog(i)).join(" "):"";return{...i,tapHintAnnouncement:s}}_valueBadgeForBinding(t,e){const i={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},s=this._markerPreviewDevice(i);if(!s)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const n=[...this._devices.filter(t=>t.id!==s.id),s],o=Wo(this._planHass,s,n),a=jo(this._planHass,s,o);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!a,valueBadgeSource:a,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const i={...e,hidden:!1};return po(ho(this._planHass,[...this._devices.filter(t=>t.id!==i.id),i],null,this._virtualLights).filter(t=>t.device.id===i.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},i=this._markerPreviewDevice(e);return!!i&&lo(this._planHass,{...i})}_setMarkerLightRole(t){const e=this._markerDialog;e&&(this._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this._planEntityAvailable(t)};const e=t.slice(7),i=this._markers.find(t=>t.id===e),s=this._devices.find(t=>t.id===e);if(!i||i.removed||!0!==i.is_light)return{label:this._t("marker.control_missing_label"),sub:`${this._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const n=this._serverCfg?.spaces.find(t=>t.id===(s?.space||i.space)),o=!!s&&to(s).length>0;return{label:i.name||s?.name||e,sub:[n?.title||s?.space||i.space,i.room_id||s?.area,o?"":this._t("marker.control_passive")].filter(Boolean).join(" · "),icon:i.icon||s?.icon||"mdi:lightbulb-outline",warning:!0===i.hidden||!0===s?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this._t("marker.value_badge_state",{name:t.label});const i=this.hass.states[e.entity_id]?.attributes?.friendly_name||this._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this._t(`marker.value_badge_attr_${e.attribute}`,{name:i})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",i=[],s=new Set;for(const t of this._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this._bindingStatus(t.binding).kind)continue;const n=this._devices.find(e=>e.id===t.id);if(!n||n.hidden)continue;const o=this._controlRefInfo(`marker:${t.id}`);for(const t of to(n))s.add(t);i.push({value:`marker:${t.id}`,label:o.label,sub:o.sub,icon:o.icon,search:`${o.label} ${o.sub} ${t.id} ${to(n).join(" ")}`.toLowerCase()})}const n=Object.keys(this.hass.states||{}).filter(e=>Ms(e)&&!s.has(e)&&Xn(t.binding,[e],this._bindingEntities(t.binding)).length>0&&this._planEntityAvailable(e)).map(t=>{const e=this._controlRefInfo(t);return{value:t,label:e.label,sub:t,icon:e.icon,search:`${e.label} ${t}`.toLowerCase()}}),o=t.controlsFilter.trim().toLowerCase();return[...i,...n].filter(e=>!t.controls.includes(e.value)&&(!o||e.search.includes(o))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const i=this._markerDraft(t)?.id||t.devId||"";if(!i)return void this._showToast(this._t("toast.marker_binding_required"));const s=e.slice(7),n=this._markerDraft(t);if(function(t,e,i){if(!e||e===i)return!0;const s=new Map;for(const e of t)s.set(e.id,(e.controls||[]).filter(t=>"string"==typeof t&&t.startsWith("marker:")).map(t=>t.slice(7)));const n=new Set,o=[i];for(;o.length;){const t=o.pop();if(t===e)return!0;n.has(t)||(n.add(t),o.push(...s.get(t)||[]))}return!1}(n?[...this._markers.filter(t=>t.id!==i),n]:this._markers,i,s))return void this._showToast(this._t("toast.marker_control_cycle"))}this._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this._markerDialog;if(!e)return;if("auto"===t)return void(this._markerDialog={...e,glowMode:t,glowTouched:!0});const i=this._markerSpatialSource(e),s=xs(i?this._planHass.states[i.eid]:void 0,null,this._fillColors.glow_light.c),n=!e.glowColorDrafted,o="fixed"===t&&!e.glowBrightnessDrafted;this._markerDialog={...e,glowMode:t,glowColor:n?s.c:e.glowColor,glowBrightness:o?Math.max(1,Math.round(100*s.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderMarkerDialog(){const t=this._markerDialog,e="virtual"===t.bindingMode,i=this._bindingCandidates();this._bindingEntities(t.binding);const s=e?null:this._bindingStatus(t.binding),n=!e&&this._bindingHasHaPage(t.binding),o=this._markerPreviewDevice(t),a=this._effectiveMarkerTapAction(t,o),r=o?cs(this._serverCfg?.spaces.find(t=>t.id===o.space)):null,l=o?this._markerPreviewDevices(o):this._devices,c="toggle"===a&&o?this._toggleIntent(o,l):null,h=this._toggleHintLines(c),d=o?t_(this._planHass,o,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:r?.showLqi??!1!==this._config?.show_signal,designPreview:!0,activityRuntime:this._activityRt.get(o.id),lightDevices:l,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}):null,p=o?Wo(this._planHass,o,l):[],u=o?jo(this._planHass,o,p):null,_=t.valueBadgeTouched?t.valueBadgeEnabled:!!d?.valueBadge,m=t.valueBadgeTouched?t.valueBadgeSource:d?.valueBadge?.source||t.valueBadgeSource,g=t.valueBadgeTouched?t.valueBadgePosition:d?.valueBadge?.position||t.valueBadgePosition,f=Ao(m),v=!!m&&!p.some(t=>t.key===f),y=p.find(t=>t.key===f),b=d?.valueSource?d.valueSource.attribute?`attr:${d.valueSource.eid}:${d.valueSource.attribute}`:`state:${d.valueSource.eid}`:"",w=this._markerAutoHasSpatialSource(t),k=!!o&&function(t,e){return io(t,e).some(t=>!!t.eid)}(this._planHass,{...o}),x=function(t,e,i,s){const n="always"===t||"auto"===t&&e,o=n&&!i;return{sourceExists:n,fromSourceEnabled:n&&i,manualEnabled:n,radiusEnabled:n,passive:o,effectiveMode:o&&"auto"===s?"fixed":s}}(t.lightRole,w,k,t.glowMode),$=!x.sourceExists,S=!x.fromSourceEnabled,M=x.passive,C=x.effectiveMode,D="never"===t.lightRole?this._t("marker.glow_disabled_never"):"auto"!==t.lightRole||w?M?this._t("marker.glow_passive_hint"):this._t("marker.glow_disabled_no_entity"):this._t("marker.glow_disabled_auto"),P=o?to(o):[],T=o&&eo(o)||"",R=!!t.lightEntity&&!P.includes(t.lightEntity),I=o?rp(o):[],A=!!t.toggleEntity&&!I.includes(t.toggleEntity),z="toggle"===a?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,F=z?[...z.targets,...z.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",E=(()=>{if(e)return null;const s=i.find(e=>e.value===t.binding);if(s)return s.label;const[n,o]=t.binding.split(":");return"device"===n?this._fullRegistryHass.devices[o]?.name_by_user||this._fullRegistryHass.devices[o]?.name||o:this._fullRegistryHass.entities[o]?.name||this.hass.states[o]?.attributes?.friendly_name||o})();return W``}_markerValueBadgeFields(t){return(e={touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition}).touched?{value_badge:{enabled:e.enabled,source:e.source,position:e.position}}:e.originalHas?{value_badge:e.original}:{};var e}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=qs(t.room),i=Fi(t.binding,t.devId,()=>"__hp_device_preview__"),s=this._markers.find(e=>e.id===i||e.id===t.devId),n=Zn(t.binding,t.controls,this._bindingEntities(t.binding)),o=this._effectiveStoredTapAction(t),a={id:i,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===o&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:n.length?n:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=qf(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:s?.vacuum||null};return("virtual"===t.binding||t.room)&&(a.space=e?.space||("virtual"===t.binding?this._space:null),a.area=e?.area||null,a.room_id=e?.roomId||null),a}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const i=`${this._haRegistry.revision}\n${bd(this._markers)}\n${JSON.stringify(e)}`;if(this._markerPreviewMemo?.key===i)return this._markerPreviewMemo.device;const s=function(t){const{marker:e,siblingMarkers:i=[],...s}=t;return So({...s,markers:[...i.filter(t=>t.id!==e.id),e]}).find(t=>t.id===e.id)||null}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||this._space,loc:t=>this._t(t),iconRules:this._iconRules});return this._markerPreviewMemo={key:i,device:s},s}_markerPreviewDevices(t){const e=this._markerPreviewDevicesMemo;if(e?.base===this._devices&&e.preview===t)return e.devices;const i=[...this._devices.filter(e=>e.id!==t.id),t];return this._markerPreviewDevicesMemo={base:this._devices,preview:t,devices:i},i}_toggleIntent(t,e=this._devices){return gp({hass:this._planHass,registryHass:this._fullRegistryHass,devices:e,device:t,virtualLights:this._virtualLights})}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const i=this._markerPreviewDevices(e);return this._toggleIntent(e,i)}_toggleStateText(t,e){const i=this._planHass?.states?.[t]||this.hass?.states?.[t];try{return i&&"function"==typeof this.hass?.formatEntityState?this.hass.formatEntityState(i):e}catch{return e}}_toggleConfirmationStateText(t){const e=String(t.state||"unknown"),i=t.entityId?this._toggleStateText(t.entityId,e):e;if(i.trim().toLocaleLowerCase()!==e.trim().toLocaleLowerCase())return i;const s={on:"confirm.state_on",off:"confirm.state_off",open:"confirm.state_open",closed:"confirm.state_closed",opening:"confirm.state_opening",closing:"confirm.state_closing",unknown:"confirm.state_unknown"}[e];return s?this._t(s):e.replaceAll("_"," ").replaceAll("-"," ")}_toggleConfirmationLines(t){const e={"turn-on":"confirm.state_on","turn-off":"confirm.state_off",open:"confirm.state_open",close:"confirm.state_closed",stop:"confirm.state_stopped"};return function(t,e){if(!vp(t)||!t.nextEffect||!t.targets.length)return[];const i="group"===t.kind,s=i?t.targets.filter(t=>"on"===t.state).length:0,n=i?0===s?e.groupAllOff():e.groupCurrent(s,t.targets.length):e.state(t.targets[0]);let o;return o="toggle"===t.nextEffect?e.expectedByHa():i&&"turn-on"===t.nextEffect?e.groupAllOn():i&&"turn-off"===t.nextEffect?e.groupAllOff():e.effect(t.nextEffect),[e.current(n),e.expected(o),...t.skippedTargets.length?[e.unavailable(t.skippedTargets.length)]:[]]}(t,{state:t=>this._toggleConfirmationStateText(t),current:t=>this._t("confirm.current_state",{state:t}),expected:t=>this._t("confirm.expected_state",{state:t}),groupCurrent:(t,e)=>this._t("confirm.group_current",{on:t,total:e}),groupAllOn:()=>this._t("confirm.group_all_on"),groupAllOff:()=>this._t("confirm.group_all_off"),unavailable:t=>this._t("confirm.unavailable_targets",{count:t}),effect:t=>this._t(e[t]),expectedByHa:()=>this._t("confirm.expected_by_ha")})}_toggleHintLines(t){if(!t)return[];const e=t=>this._t(`marker.toggle_effect_${t.replace("-","_")}`),i=t=>this._t(`marker.toggle_skip_${t.replace("-","_")}`);return function(t,e){const i=t.targets[0]||t.skippedTargets[0],s=[];return"group"===t.kind?t.targets.length&&s.push(e.group(t.targets)):i&&s.push(e.single(i)),t.nextEffect&&t.targets.length&&s.push("group"===t.kind?e.groupCurrentNext(t.targets,t.nextEffect):e.currentNext(t.targets[0],t.nextEffect)),t.skippedTargets.length&&s.push(e.skipped(t.skippedTargets)),!t.command&&t.noneReason&&s.push(e.none(t.noneReason)),s}(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),i=t.name||e;return this._t("marker.toggle_hint_single",{name:i,id:e})},group:t=>this._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,i)=>"virtual-light"===t.via?this._t("marker.virtual_light_current",{state:this._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(i)}):this._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(i)}),groupCurrentNext:(t,i)=>this._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(i)}),skipped:t=>this._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${i(t.reason)})`}).join(", ")}),none:t=>this._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:pp(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),i=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},s="toggle"===i.tapAction?this._toggleHintLines(this._toggleIntentForDialog(i)).join(" "):"";return{...i,tapHintAnnouncement:s}}_valueBadgeForBinding(t,e){const i={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},s=this._markerPreviewDevice(i);if(!s)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const n=[...this._devices.filter(t=>t.id!==s.id),s],o=Wo(this._planHass,s,n),a=jo(this._planHass,s,o);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!a,valueBadgeSource:a,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const i={...e,hidden:!1};return po(ho(this._planHass,[...this._devices.filter(t=>t.id!==i.id),i],null,this._virtualLights).filter(t=>t.device.id===i.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},i=this._markerPreviewDevice(e);return!!i&&lo(this._planHass,{...i})}_setMarkerLightRole(t){const e=this._markerDialog;e&&(this._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this._planEntityAvailable(t)};const e=t.slice(7),i=this._markers.find(t=>t.id===e),s=this._devices.find(t=>t.id===e);if(!i||i.removed||!0!==i.is_light)return{label:this._t("marker.control_missing_label"),sub:`${this._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const n=this._serverCfg?.spaces.find(t=>t.id===(s?.space||i.space)),o=!!s&&to(s).length>0;return{label:i.name||s?.name||e,sub:[n?.title||s?.space||i.space,i.room_id||s?.area,o?"":this._t("marker.control_passive")].filter(Boolean).join(" · "),icon:i.icon||s?.icon||"mdi:lightbulb-outline",warning:!0===i.hidden||!0===s?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this._t("marker.value_badge_state",{name:t.label});const i=this.hass.states[e.entity_id]?.attributes?.friendly_name||this._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this._t(`marker.value_badge_attr_${e.attribute}`,{name:i})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",i=[],s=new Set;for(const t of this._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this._bindingStatus(t.binding).kind)continue;const n=this._devices.find(e=>e.id===t.id);if(!n||n.hidden)continue;const o=this._controlRefInfo(`marker:${t.id}`);for(const t of to(n))s.add(t);i.push({value:`marker:${t.id}`,label:o.label,sub:o.sub,icon:o.icon,search:`${o.label} ${o.sub} ${t.id} ${to(n).join(" ")}`.toLowerCase()})}const n=Object.keys(this.hass.states||{}).filter(e=>Ms(e)&&!s.has(e)&&Xn(t.binding,[e],this._bindingEntities(t.binding)).length>0&&this._planEntityAvailable(e)).map(t=>{const e=this._controlRefInfo(t);return{value:t,label:e.label,sub:t,icon:e.icon,search:`${e.label} ${t}`.toLowerCase()}}),o=t.controlsFilter.trim().toLowerCase();return[...i,...n].filter(e=>!t.controls.includes(e.value)&&(!o||e.search.includes(o))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const i=this._markerDraft(t)?.id||t.devId||"";if(!i)return void this._showToast(this._t("toast.marker_binding_required"));const s=e.slice(7),n=this._markerDraft(t);if(function(t,e,i){if(!e||e===i)return!0;const s=new Map;for(const e of t)s.set(e.id,(e.controls||[]).filter(t=>"string"==typeof t&&t.startsWith("marker:")).map(t=>t.slice(7)));const n=new Set,o=[i];for(;o.length;){const t=o.pop();if(t===e)return!0;n.has(t)||(n.add(t),o.push(...s.get(t)||[]))}return!1}(n?[...this._markers.filter(t=>t.id!==i),n]:this._markers,i,s))return void this._showToast(this._t("toast.marker_control_cycle"))}this._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this._markerDialog;if(!e)return;if("auto"===t)return void(this._markerDialog={...e,glowMode:t,glowTouched:!0});const i=this._markerSpatialSource(e),s=xs(i?this._planHass.states[i.eid]:void 0,null,this._fillColors.glow_light.c),n=!e.glowColorDrafted,o="fixed"===t&&!e.glowBrightnessDrafted;this._markerDialog={...e,glowMode:t,glowColor:n?s.c:e.glowColor,glowBrightness:o?Math.max(1,Math.round(100*s.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderMarkerDialog(){const t=this._markerDialog,e="virtual"===t.bindingMode,i=this._bindingCandidates();this._bindingEntities(t.binding);const s=e?null:this._bindingStatus(t.binding),n=!e&&this._bindingHasHaPage(t.binding),o=this._markerPreviewDevice(t),a=this._effectiveMarkerTapAction(t,o),r=o?cs(this._serverCfg?.spaces.find(t=>t.id===o.space)):null,l=o?this._markerPreviewDevices(o):this._devices,c="toggle"===a&&o?this._toggleIntent(o,l):null,h=this._toggleHintLines(c),d=o?t_(this._planHass,o,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:r?.showLqi??!1!==this._config?.show_signal,designPreview:!0,activityRuntime:this._activityRt.get(o.id),lightDevices:l,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}):null,p=o?Wo(this._planHass,o,l):[],u=o?jo(this._planHass,o,p):null,_=t.valueBadgeTouched?t.valueBadgeEnabled:!!d?.valueBadge,m=t.valueBadgeTouched?t.valueBadgeSource:d?.valueBadge?.source||t.valueBadgeSource,g=t.valueBadgeTouched?t.valueBadgePosition:d?.valueBadge?.position||t.valueBadgePosition,f=Ao(m),v=!!m&&!p.some(t=>t.key===f),y=p.find(t=>t.key===f),b=d?.valueSource?d.valueSource.attribute?`attr:${d.valueSource.eid}:${d.valueSource.attribute}`:`state:${d.valueSource.eid}`:"",w=this._markerAutoHasSpatialSource(t),k=!!o&&function(t,e){return io(t,e).some(t=>!!t.eid)}(this._planHass,{...o}),x=function(t,e,i,s){const n="always"===t||"auto"===t&&e,o=n&&!i;return{sourceExists:n,fromSourceEnabled:n&&i,manualEnabled:n,radiusEnabled:n,passive:o,effectiveMode:o&&"auto"===s?"fixed":s}}(t.lightRole,w,k,t.glowMode),$=!x.sourceExists,S=!x.fromSourceEnabled,M=x.passive,C=x.effectiveMode,D="never"===t.lightRole?this._t("marker.glow_disabled_never"):"auto"!==t.lightRole||w?M?this._t("marker.glow_passive_hint"):this._t("marker.glow_disabled_no_entity"):this._t("marker.glow_disabled_auto"),P=o?to(o):[],T=o&&eo(o)||"",R=!!t.lightEntity&&!P.includes(t.lightEntity),I=o?rp(o):[],A=!!t.toggleEntity&&!I.includes(t.toggleEntity),z="toggle"===a?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,F=z?[...z.targets,...z.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",E=(()=>{if(e)return null;const s=i.find(e=>e.value===t.binding);if(s)return s.label;const[n,o]=t.binding.split(":");return"device"===n?this._fullRegistryHass.devices[o]?.name_by_user||this._fullRegistryHass.devices[o]?.name||o:this._fullRegistryHass.entities[o]?.name||this.hass.states[o]?.attributes?.friendly_name||o})();return W`this._markerDialog=null}>
@@ -7098,10 +7098,10 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 -

${this._t(Nf[t.display])}

+

${this._t(Of[t.display])}

${"static_icon"===t.display&&this._bindingHasAlarm(t.binding)?W`
${this._t("marker.static_alarm_warning")} @@ -7278,9 +7278,9 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4
{const i=e.target.value,s=Bf(i),n=null==s?null:(o=s,this._imperial?o*uh:o);var o;this._spaceDialog={...t,cellCmInput:i,cellCmTouched:!0,cellCm:null!=n&&n>0?Math.max(.1,Math.min(Lf,n)):t.cellCm}}} /> + @input=${e=>{const i=e.target.value,s=qf(i),n=null==s?null:(o=s,this._imperial?o*uh:o);var o;this._spaceDialog={...t,cellCmInput:i,cellCmTouched:!0,cellCm:null!=n&&n>0?Math.max(.1,Math.min(Hf,n)):t.cellCm}}} /> ${this._t(this._imperial?"space.scale_unit_imperial":"space.scale_unit")}
@@ -7375,10 +7375,10 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t(i)} ${"temp"===e&&"temp"===t.fillMode?W` {const i=Bf(e.target.value);null!=i&&(this._spaceDialog={...t,tempMin:i})}} /> + @input=${e=>{const i=qf(e.target.value);null!=i&&(this._spaceDialog={...t,tempMin:i})}} /> – {const i=Bf(e.target.value);null!=i&&(this._spaceDialog={...t,tempMax:i})}} /> + @input=${e=>{const i=qf(e.target.value);null!=i&&(this._spaceDialog={...t,tempMax:i})}} /> °C `:G} @@ -7535,4 +7535,4 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t("btn.save")} `}
- `}}hv.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_hoverRoom:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_wallDialog:{state:!0},_drawWallField:{state:!0},_activeDraftId:{state:!0},_physicalSel:{state:!0},_physicalDialog:{state:!0},_partitionDeleteDialog:{state:!0},_roomDeleteDialog:{state:!0},_physicalDrag:{state:!0},_physicalRotate:{state:!0},_duplicateColumnId:{state:!0},_rszSel:{state:!0},_rszLive:{state:!0},_opMeasure:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingPreset:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorEraseConfirm:{state:!0},_decorTextDialog:{state:!0},_decorShapeDialog:{state:!0},_backdropDialog:{state:!0},_furnPalette:{state:!0},_bdDrag:{state:!0},_dtBox:{state:!0},_dtDrag:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_vacAllCamerasFor:{state:!0},_vacCalConfirm:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomCustomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_alignDialog:{state:!0},_preflightClipboardFallback:{state:!0},_backupExportDialog:{state:!0},_backupImportDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},hv.ZOOM_MAX=8,hv.ZOOM_MIN=1/3,hv.styles=[Kt,H_],customElements.get("houseplan-card")||customElements.define("houseplan-card",hv),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info(`%c HOUSEPLAN-CARD %c v${Ff} `,"background:#3ea6ff;color:#04121f;font-weight:700",""); + `}}dv.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_hoverRoom:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_wallDialog:{state:!0},_drawWallField:{state:!0},_activeDraftId:{state:!0},_physicalSel:{state:!0},_physicalDialog:{state:!0},_partitionDeleteDialog:{state:!0},_roomDeleteDialog:{state:!0},_physicalDrag:{state:!0},_physicalRotate:{state:!0},_duplicateColumnId:{state:!0},_rszSel:{state:!0},_rszLive:{state:!0},_opMeasure:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingPreset:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorEraseConfirm:{state:!0},_decorTextDialog:{state:!0},_decorShapeDialog:{state:!0},_backdropDialog:{state:!0},_furnPalette:{state:!0},_bdDrag:{state:!0},_dtBox:{state:!0},_dtDrag:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_vacAllCamerasFor:{state:!0},_vacCalConfirm:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomCustomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_alignDialog:{state:!0},_preflightClipboardFallback:{state:!0},_backupExportDialog:{state:!0},_backupImportDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},dv.ZOOM_MAX=8,dv.ZOOM_MIN=1/3,dv.styles=[Kt,H_],customElements.get("houseplan-card")||customElements.define("houseplan-card",dv),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info(`%c HOUSEPLAN-CARD %c v${Ef} `,"background:#3ea6ff;color:#04121f;font-weight:700",""); diff --git a/custom_components/houseplan/validation.py b/custom_components/houseplan/validation.py index b80b9ce4..5431e513 100644 --- a/custom_components/houseplan/validation.py +++ b/custom_components/houseplan/validation.py @@ -1831,7 +1831,10 @@ def _config_wall_segment_invariants(value: dict) -> dict: for opening in space.get("openings", []): host = opening.get("host") if host is None: - raise vol.Invalid("v8+ opening requires an explicit host") + # #316 §3.3: a degraded migration may leave a contour opening + # unhosted. It is inert (no body/tunnel/cut) and excluded from + # the interval checks; a later edit can re-place it. + continue if host["kind"] == "partition": if host["id"] not in partitions: raise vol.Invalid("partition opening host must exist in the same space") diff --git a/custom_components/houseplan/wall_segment_model.py b/custom_components/houseplan/wall_segment_model.py index 5d027613..f6ab2782 100644 --- a/custom_components/houseplan/wall_segment_model.py +++ b/custom_components/houseplan/wall_segment_model.py @@ -225,6 +225,53 @@ def _atomize( global_breaks.extend((segment[:2], segment[2:])) zero_segments = canonical_zero_segments + legacy_segments + # #316 §3.1: a legacy open_spans/open_to cut never zeroes the atom that + # carries an existing contour opening; its edges become atom boundaries so + # the zero run continues on both sides of the opening. + legacy_era_openings: list[dict[str, Any]] = [] + if legacy_segments: + for opening in space.get("openings") or []: + if not isinstance(opening, dict): + continue + host = opening.get("host") + if isinstance(host, dict) and host.get("kind") == "partition": + continue + try: + centre = [float(opening["x"]), float(opening["y"])] + angle = float(opening["angle"]) + half = float(opening["length"]) / 2 + except (KeyError, TypeError, ValueError): + continue + if half <= 0: + continue + # Only an opening that actually stands on a legacy cut changes the + # atomization; unrelated openings must not churn the catalogue. + if not any( + _distance_to_segment(centre, cut[:2], cut[2:]) <= GRID_STEP_N * 0.04 + for cut in legacy_segments + ): + continue + legacy_era_openings.append( + {"centre": centre, "angle": angle, "half": half} + ) + direction = (math.cos(math.radians(angle)), math.sin(math.radians(angle))) + global_breaks.extend(( + [centre[0] - direction[0] * half, centre[1] - direction[1] * half], + [centre[0] + direction[0] * half, centre[1] + direction[1] * half], + )) + + def _atom_carries_opening(a: list[float], b: list[float]) -> bool: + for entry in legacy_era_openings: + if not _angle_matches(a, b, entry["angle"]): + continue + if _distance_to_segment(entry["centre"], a, b) > GRID_STEP_N * 0.02: + continue + span = _length(a, b) + tc = _project_t(entry["centre"], a, b) * span + if tc + entry["half"] >= -EPS and tc - entry["half"] <= span + EPS: + return True + return False + for wall in space.get("walls") or []: if isinstance(wall, dict) and isinstance(wall.get("a"), list) and isinstance(wall.get("b"), list): global_breaks.extend((wall["a"], wall["b"])) @@ -301,9 +348,14 @@ def _atomize( parent_index = parents[index] atom["parent_keys"].add(_wall_key(original[parent_index], original[(parent_index + 1) % len(original)])) midpoint = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2] - atom["zero_wall"] = atom["zero_wall"] or any( + covered_by = lambda cuts: any( _distance_to_segment(midpoint, cut[:2], cut[2:]) <= GRID_STEP_N * 0.04 - for cut in zero_segments + for cut in cuts + ) + # Canonical cm:0 atoms stay zero; a LEGACY cut spares the atom + # that carries an opening (#316 §3.1). + atom["zero_wall"] = atom["zero_wall"] or covered_by(canonical_zero_segments) or ( + covered_by(legacy_segments) and not _atom_carries_opening(a, b) ) if indexed_lineage and isinstance(old_ids[parent_index], str) and old_ids[parent_index]: previous = old.get(old_ids[parent_index]) @@ -478,7 +530,9 @@ def _angle_matches(a: list[float], b: list[float], angle: float) -> bool: return difference <= 8 -def _host_openings(space: dict[str, Any], segments: list[dict[str, Any]]) -> None: +def _host_openings( + space: dict[str, Any], segments: list[dict[str, Any]], initial_migration: bool, +) -> None: for opening in space.get("openings") or []: host = opening.get("host") if isinstance(host, dict) and host.get("kind") == "partition": @@ -487,6 +541,10 @@ def _host_openings(space: dict[str, Any], segments: list[dict[str, Any]]) -> Non centre = [float(opening["x"]), float(opening["y"])] angle, half = float(opening["angle"]), float(opening["length"]) / 2 except (KeyError, TypeError, ValueError): + if initial_migration: + # #316 §3.4: the initial migration never throws over an opening. + opening.pop("host", None) + continue raise WallSegmentMigrationError("opening-host", str(opening.get("id", ""))) from None def eligible(segment: dict[str, Any]) -> bool: @@ -501,19 +559,52 @@ def _host_openings(space: dict[str, Any], segments: list[dict[str, Any]]) -> Non and half >= 0 and t * span - half >= -EPS and t * span + half <= span + EPS) + def materialize(carrier: dict[str, Any]) -> None: + opening["host"] = { + "kind": "wall", "id": carrier["id"], + "t": max(0.0, min(1.0, _project_t(centre, carrier["a"], carrier["b"]))), + } + current = None if isinstance(host, dict) and host.get("kind") == "wall": current = next((segment for segment in segments if segment["id"] == host.get("id")), None) candidates = [current] if current is not None and eligible(current) else [ segment for segment in segments if eligible(segment) ] - if len(candidates) != 1: + if len(candidates) == 1: + materialize(candidates[0]) + continue + # #316 §3.3: an unhosted opening is a valid degraded v9 state. A later + # write keeps it, may self-heal it, and never fails over it. + if host is None and not initial_migration: + continue + if not initial_migration: raise WallSegmentMigrationError("opening-host", str(opening.get("id", ""))) - carrier = candidates[0] - opening["host"] = { - "kind": "wall", "id": carrier["id"], - "t": max(0.0, min(1.0, _project_t(centre, carrier["a"], carrier["b"]))), - } + + def pick(pool: list[dict[str, Any]]) -> dict[str, Any] | None: + if not pool: + return None + if current is not None and any(item is current for item in pool): + return current + return sorted(pool, key=lambda segment: ( + _distance_to_segment(centre, segment["a"], segment["b"]), + -float(segment.get("cm", 0)), + str(segment.get("id", "")), + ))[0] + + # #316 §3.2 tie-break, then the §3.3 degraded pool (angle- and + # capacity-compatible positive walls at any distance, nearest first). + degraded = [segment for segment in segments if ( + float(segment.get("cm", 0)) > 0 + and _angle_matches(segment["a"], segment["b"], angle) + and half >= 0 + and _length(segment["a"], segment["b"]) + EPS >= half * 2 + )] + carrier = pick([segment for segment in segments if eligible(segment)]) or pick(degraded) + if carrier is not None: + materialize(carrier) + else: + opening.pop("host", None) def _migrate_space(space: dict[str, Any], initial_migration: bool) -> int: @@ -579,7 +670,7 @@ def _migrate_space(space: dict[str, Any], initial_migration: bool) -> int: else: segment["id"] = _fresh_wall_segment_id(draft_used) draft_used.add(segment["id"]) - _host_openings(space, segments) + _host_openings(space, segments, initial_migration) return sum(1 for segment in segments if segment["id"] not in old) diff --git a/demo/golden/harness.mjs b/demo/golden/harness.mjs index 7d75c9a8..332cff8a 100644 --- a/demo/golden/harness.mjs +++ b/demo/golden/harness.mjs @@ -23,6 +23,9 @@ const wallKeyRoundtripFixture = JSON.parse(readFileSync( const coincidentPartitionFixture = JSON.parse(readFileSync( new URL('../../test/fixtures/276-coincident-partition.json', import.meta.url), 'utf8', )); +const spanOverDoorFixture = JSON.parse(readFileSync( + new URL('../../test/fixtures/316-span-over-door-migrated.json', import.meta.url), 'utf8', +)); const wallUnionIsolationFixture = JSON.parse(readFileSync( new URL('../../test/fixtures/278-wall-union-isolation.json', import.meta.url), 'utf8', )); @@ -79,6 +82,15 @@ async function stableEnvironment(page, scenario) { /** Apply every data-only scenario override before the fixture crosses into the browser. */ export function prepareGoldenFixture(scenario) { const fixture = fixtureFor(scenario); + if (scenario.spanOverDoor) { + // #316 §3.1: the scene renders the MIGRATED document — the door keeps its + // carrying atom while the former span is zero (dashed) on both sides. The + // fixture is produced by the real writer and pinned byte-for-byte by the + // wall-segment-model unit test, so it cannot drift from the migration. + const migrated = structuredClone(spanOverDoorFixture.migrated); + fixture.config.model_version = migrated.model_version; + fixture.config.spaces.push(...migrated.spaces); + } if (scenario.coincidentPartition) { const state = scenario.coincidentPartition; if (!['before', 'thin', 'thick', 'virtual'].includes(state)) diff --git a/demo/golden/matrix.mjs b/demo/golden/matrix.mjs index 80ee04c2..110d09df 100644 --- a/demo/golden/matrix.mjs +++ b/demo/golden/matrix.mjs @@ -1,7 +1,7 @@ import { fixtureWallKey } from '../fixtures/visual-matrix.mjs'; /** Data-only HP-QA-01 capture matrix. Bump when framing or scenarios change. */ -export const GOLDEN_MATRIX_VERSION = 46; +export const GOLDEN_MATRIX_VERSION = 47; const stage = { capture: 'stage', threshold: { maxChannelDelta: 10, maxDiffRatio: 0.0005 } }; const page = { capture: 'page', threshold: { maxChannelDelta: 10, maxDiffRatio: 0.0008 } }; @@ -185,6 +185,11 @@ export const GOLDEN_SCENARIOS = Object.freeze([ { id: 'coincident-partition-virtual-dark', fixture: 'visual', space: 'golden-coincident-partition', coincidentPartition: 'virtual', mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage }, + // #316 §3.1: a legacy span over a wall with a door — after the migration the + // door keeps its carrying atom while the border is zero on both sides. + { id: 'span-over-door-migrated-dark', fixture: 'visual', + space: 'golden-span-over-door', spanOverDoor: true, + mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage }, { id: 'split-corner-wall-before-dark', fixture: 'visual', space: 'golden-corner-split', cornerSplitWall: 'before', mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage }, { id: 'split-corner-wall-thin-dark', fixture: 'visual', space: 'golden-corner-split', diff --git a/demo/smoke_zero_wall_migration_unblocked.mjs b/demo/smoke_zero_wall_migration_unblocked.mjs new file mode 100644 index 00000000..041bab3d --- /dev/null +++ b/demo/smoke_zero_wall_migration_unblocked.mjs @@ -0,0 +1,67 @@ +/** Issue #316: a legacy opening/zero-wall conflict in ANY space must not block + * drawing in another (empty) space — the migration auto-resolves it (§3). */ +import { launch, checkAll, finish } from './serve.mjs'; + +const { page, browser } = await launch({ width: 1000, height: 820 }, 1); + +const out = await page.evaluate(async () => { + const result = {}; + const card = window.__card; + const update = async () => { card.requestUpdate(); await card.updateComplete; }; + const toasts = []; + const origToast = card._showToast.bind(card); + card._showToast = (text) => { toasts.push(String(text)); }; + + // Space B replays the #316 report: a room, a legacy open_span along its top + // wall and a door standing inside that former "border". + const spaceB = { + id: 'B', title: 'B', cell_cm: 5, view_box: [0, 0, 1, 0.7], + rooms: [{ id: 'rB', poly: [[0.2, 0.2], [0.6, 0.2], [0.6, 0.5], [0.2, 0.5]] }], + walls: [{ key: '', a: [0.2, 0.2], b: [0.6, 0.2], cm: 15 }], + open_spans: [{ a: [0.2, 0.2], b: [0.6, 0.2] }], + openings: [{ id: 'op1', type: 'door', x: 0.4, y: 0.2, angle: 0, length: 0.09, cm: 90 }], + }; + const spaceA = { id: 'A', title: 'A', cell_cm: 5, view_box: [0, 0, 1, 0.7], rooms: [] }; + card._serverCfg = { spaces: [spaceA, spaceB], markers: [], settings: {} }; + const sent = []; + const baseCall = card.hass.callWS.bind(card.hass); + card.hass = { ...card.hass, callWS: async (message) => { + if (message.type === 'houseplan/config/set') { + sent.push(structuredClone(message)); + return { ok: true, rev: (message.expected_rev ?? 0) + 1 }; + } + return baseCall(message); + } }; + card._space = 'A'; card._layout = {}; + card._cfgEpoch++; card._modelCache = null; card._frame = null; + card._setMode('plan'); card._tool = 'draw'; card._drawWallField = '20'; + card._path = []; await update(); + + // The two clicks of the Walls tool: a first draft segment is committed. + const before = card._geometrySnapshotFromConfig(card._serverCfg, 'A'); + const fresh = card._serverCfg.spaces.find((space) => space.id === 'A'); + fresh.room_drafts = [{ id: 'd1', points: [[0.24, 0.24], [0.48, 0.24]], + segments: [{ cm: 20 }] }]; + result.commitSucceeds = card._commitPhysicalGeometry('draw', before) === true; + result.noMigrationToast = !toasts.some((text) => /не преобразовано|not converted/i.test(text)); + + // The auto-resolution kept the door on a real wall and zeroed the border on + // both sides of it (§3.1) inside the migrated candidate. + const migratedB = card._serverCfg.spaces.find((space) => space.id === 'B'); + const top = (migratedB.wall_segments || []) + .filter((s) => Math.abs(s.a[1] - 0.2) < 1e-9 && Math.abs(s.b[1] - 0.2) < 1e-9) + .sort((x, y) => x.a[0] - y.a[0]); + result.doorKeepsItsWall = top.length === 3 + && top[0].cm === 0 && top[1].cm > 0 && top[2].cm === 0 + && migratedB.openings[0]?.host?.id === top[1].id; + result.legacyFieldsGone = !('open_spans' in migratedB) + && (migratedB.rooms || []).every((room) => !('open_to' in room)); + result.draftSurvives = (card._serverCfg.spaces.find((s) => s.id === 'A') + .room_drafts || []).length === 1; + + card._showToast = origToast; + return result; +}); + +checkAll(out); +await finish(browser); diff --git a/dist/houseplan-card.js b/dist/houseplan-card.js index d6c333ba..a3322d42 100755 --- a/dist/houseplan-card.js +++ b/dist/houseplan-card.js @@ -1,4 +1,4 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4e36f45244a923a0f5aa01407a993";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),s=new WeakMap;let n=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const i=this.t;if(e&&void 0===t){const e=void 0!==i&&1===i.length;e&&(t=s.get(i)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&s.set(i,t))}return t}toString(){return this.cssText}};const o=(t,...e)=>{const s=1===t.length?t[0]:e.reduce((e,i,s)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+t[s+1],t[0]);return new n(s,t,i)},a=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return(t=>new n("string"==typeof t?t:t+"",void 0,i))(e)})(t):t,{is:r,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:p}=Object,u=globalThis,_=u.trustedTypes,m=_?_.emptyScript:"",g=u.reactiveElementPolyfillSupport,f=(t,e)=>t,v={toAttribute(t,e){switch(e){case Boolean:t=t?m:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let i=t;switch(e){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},y=(t,e)=>!r(t,e),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),u.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=b){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const i=Symbol(),s=this.getPropertyDescriptor(t,i,e);void 0!==s&&l(this.prototype,t,s)}}static getPropertyDescriptor(t,e,i){const{get:s,set:n}=c(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:s,set(e){const o=s?.call(this);n?.call(this,e),this.requestUpdate(t,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(f("elementProperties")))return;const t=p(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(f("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(f("properties"))){const t=this.properties,e=[...h(t),...d(t)];for(const i of e)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const i=this._$Eu(t,e);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const t of i)e.unshift(a(t))}else void 0!==t&&e.push(a(t));return e}static _$Eu(t,e){const i=e.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const i of e.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,s)=>{if(e)i.adoptedStyleSheets=s.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of s){const s=document.createElement("style"),n=t.litNonce;void 0!==n&&s.setAttribute("nonce",n),s.textContent=e.cssText,i.appendChild(s)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,i){this._$AK(t,i)}_$ET(t,e){const i=this.constructor.elementProperties.get(t),s=this.constructor._$Eu(t,i);if(void 0!==s&&!0===i.reflect){const n=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(e,i.type);this._$Em=t,null==n?this.removeAttribute(s):this.setAttribute(s,n),this._$Em=null}}_$AK(t,e){const i=this.constructor,s=i._$Eh.get(t);if(void 0!==s&&this._$Em!==s){const t=i.getPropertyOptions(s),n="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:v;this._$Em=s;const o=n.fromAttribute(e,t.type);this[s]=o??this._$Ej?.get(s)??o,this._$Em=null}}requestUpdate(t,e,i,s=!1,n){if(void 0!==t){const o=this.constructor;if(!1===s&&(n=this[t]),i??=o.getPropertyOptions(t),!((i.hasChanged??y)(n,e)||i.useDefault&&i.reflect&&n===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,i))))return;this.C(t,e,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:i,reflect:s,wrapped:n},o){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,o??e??this[t]),!0!==n||void 0!==o)||(this._$AL.has(t)||(this.hasUpdated||i||(e=void 0),this._$AL.set(t,e)),!0===s&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,i]of t){const{wrapped:t}=i,s=this[e];!0!==t||this._$AL.has(e)||void 0===s||this.C(e,void 0,i,s)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[f("elementProperties")]=new Map,w[f("finalized")]=new Map,g?.({ReactiveElement:w}),(u.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,x=t=>t,$=k.trustedTypes,S=$?$.createPolicy("lit-html",{createHTML:t=>t}):void 0,M="$lit$",C=`lit$${Math.random().toFixed(9).slice(2)}$`,D="?"+C,P=`<${D}>`,T=document,R=()=>T.createComment(""),I=t=>null===t||"object"!=typeof t&&"function"!=typeof t,A=Array.isArray,z="[ \t\n\f\r]",F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,E=/-->/g,N=/>/g,O=RegExp(`>|${z}(?:([^\\s"'>=/]+)(${z}*=${z}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,H=/"/g,B=/^(?:script|style|textarea|title)$/i,q=t=>(e,...i)=>({_$litType$:t,strings:e,values:i}),W=q(1),j=q(2),U=Symbol.for("lit-noChange"),G=Symbol.for("lit-nothing"),V=new WeakMap,K=T.createTreeWalker(T,129);function Y(t,e){if(!A(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(e):e}const J=(t,e)=>{const i=t.length-1,s=[];let n,o=2===e?"":3===e?"":"",a=F;for(let e=0;e"===l[0]?(a=n??F,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?O:'"'===l[3]?H:L):a===H||a===L?a=O:a===E||a===N?a=F:(a=O,n=void 0);const d=a===O&&t[e+1].startsWith("/>")?" ":"";o+=a===F?i+P:c>=0?(s.push(r),i.slice(0,c)+M+i.slice(c)+C+d):i+C+(-2===c?e:d)}return[Y(t,o+(t[i]||"")+(2===e?"":3===e?"":"")),s]};class X{constructor({strings:t,_$litType$:e},i){let s;this.parts=[];let n=0,o=0;const a=t.length-1,r=this.parts,[l,c]=J(t,e);if(this.el=X.createElement(l,i),K.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(s=K.nextNode())&&r.length0){s.textContent=$?$.emptyScript:"";for(let i=0;iA(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==G&&I(this._$AH)?this._$AA.nextSibling.data=t:this.T(T.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:i}=t,s="number"==typeof i?this._$AC(t):(void 0===i.el&&(i.el=X.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===s)this._$AH.p(e);else{const t=new Q(s,this),i=t.u(this.options);t.p(e),this.T(i),this._$AH=t}}_$AC(t){let e=V.get(t.strings);return void 0===e&&V.set(t.strings,e=new X(t)),e}k(t){A(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let i,s=0;for(const n of t)s===e.length?e.push(i=new tt(this.O(R()),this.O(R()),this,this.options)):i=e[s],i._$AI(n),s++;s2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=G}_$AI(t,e=this,i,s){const n=this.strings;let o=!1;if(void 0===n)t=Z(this,t,e,0),o=!I(t)||t!==this._$AH&&t!==U,o&&(this._$AH=t);else{const s=t;let a,r;for(t=n[0],a=0;a{const s=i?.renderBefore??e;let n=s._$litPart$;if(void 0===n){const t=i?.renderBefore??null;s._$litPart$=n=new tt(e.insertBefore(R(),t),t,void 0,i??{})}return n._$AI(t),n},ct=globalThis;let ht=class extends w{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=lt(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return U}};ht._$litElement$=!0,ht.finalized=!0,ct.litElementHydrateSupport?.({LitElement:ht});const dt=ct.litElementPolyfillSupport;dt?.({LitElement:ht}),(ct.litElementVersions??=[]).push("4.2.2");const pt=2,ut=t=>(...e)=>({_$litDirective$:t,values:e});let _t=class{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,i){this._$Ct=t,this._$AM=e,this._$Ci=i}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}};const mt={},gt=ut(class extends _t{constructor(){super(...arguments),this.ot=mt}render(t,e){return e()}update(t,[e,i]){if(Array.isArray(e)){if(Array.isArray(this.ot)&&this.ot.length===e.length&&e.every((t,e)=>t===this.ot[e]))return U}else if(this.ot===e)return U;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}}),{I:ft}=at,vt=t=>t,yt=()=>document.createComment(""),bt=(t,e,i)=>{const s=t._$AA.parentNode,n=void 0===e?t._$AB:e._$AA;if(void 0===i){const e=s.insertBefore(yt(),n),o=s.insertBefore(yt(),n);i=new ft(e,o,t,t.options)}else{const e=i._$AB.nextSibling,o=i._$AM,a=o!==t;if(a){let e;i._$AQ?.(t),i._$AM=t,void 0!==i._$AP&&(e=t._$AU)!==o._$AU&&i._$AP(e)}if(e!==n||a){let t=i._$AA;for(;t!==e;){const e=vt(t).nextSibling;vt(s).insertBefore(t,n),t=e}}}return i},wt=(t,e,i=t)=>(t._$AI(e,i),t),kt={},xt=(t,e=kt)=>t._$AH=e,$t=t=>{t._$AR(),t._$AA.remove()},St=(t,e,i)=>{const s=new Map;for(let n=e;n<=i;n++)s.set(t[n],n);return s},Mt=ut(class extends _t{constructor(t){if(super(t),t.type!==pt)throw Error("repeat() can only be used in text expressions")}dt(t,e,i){let s;void 0===i?i=e:void 0!==e&&(s=e);const n=[],o=[];let a=0;for(const e of t)n[a]=s?s(e,a):a,o[a]=i(e,a),a++;return{values:o,keys:n}}render(t,e,i){return this.dt(t,e,i).values}update(t,[e,i,s]){const n=(t=>t._$AH)(t),{values:o,keys:a}=this.dt(e,i,s);if(!Array.isArray(n))return this.ut=a,o;const r=this.ut??=[],l=[];let c,h,d=0,p=n.length-1,u=0,_=o.length-1;for(;d<=p&&u<=_;)if(null===n[d])d++;else if(null===n[p])p--;else if(r[d]===a[u])l[u]=wt(n[d],o[u]),d++,u++;else if(r[p]===a[_])l[_]=wt(n[p],o[_]),p--,_--;else if(r[d]===a[_])l[_]=wt(n[d],o[_]),bt(t,l[_+1],n[d]),d++,_--;else if(r[p]===a[u])l[u]=wt(n[p],o[u]),bt(t,n[d],n[p]),p--,u++;else if(void 0===c&&(c=St(a,u,_),h=St(r,d,p)),c.has(r[d]))if(c.has(r[p])){const e=h.get(a[u]),i=void 0!==e?n[e]:null;if(null===i){const e=bt(t,n[d]);wt(e,o[u]),l[u]=e}else l[u]=wt(i,o[u]),bt(t,n[d],i),n[e]=null;u++}else $t(n[p]),p--;else $t(n[d]),d++;for(;u<=_;){const e=bt(t,l[_+1]);wt(e,o[u]),l[u++]=e}for(;d<=p;){const t=n[d++];null!==t&&$t(t)}return this.ut=a,xt(t,l),U}}),Ct=new WeakMap;let Dt=0;class Pt extends ht{constructor(){super(...arguments),this.title="",this.icon="",this.wide=!1,this.dismissOnScrim=!1,this.hass=null,this._opener=null,this._focusRoot=null,this._useHaDialog=!1,this._closing=!1,this._overlays=[],this._titleId="hp-dialog-title-"+ ++Dt,this._focusInitial=()=>{const t=this._focusableElements(),e=t.find(t=>t.hasAttribute("autofocus"))||t[0]||(this._useHaDialog?null:this.renderRoot.querySelector(".close"))||this.renderRoot.querySelector(".surface")||this.renderRoot.querySelector("ha-dialog");e?.focus({preventScroll:!0})},this._requestClose=()=>{this._closing||(this._closing=!0,this.dispatchEvent(new CustomEvent("hp-close",{bubbles:!0,composed:!0})))},this._onKeyDown=t=>{if("Escape"===t.key){t.preventDefault(),t.stopImmediatePropagation(),this._pruneOverlays();const e=this._overlays[this._overlays.length-1];return e?void this._closeOverlay(e,"escape"):void this._requestClose()}if("Tab"!==t.key||this._useHaDialog)return;const e=this.renderRoot.querySelector(".close"),i=e?[e,...this._focusableElements()]:this._focusableElements();if(!i.length)return t.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const s=this._deepActiveElement(),n=i[0],o=i[i.length-1];!t.shiftKey||s!==n&&i.includes(s)?t.shiftKey||s!==o||(t.preventDefault(),n.focus()):(t.preventDefault(),o.focus())},this._onFallbackCancel=t=>{t.preventDefault(),this._requestClose()},this._onFallbackClick=t=>{this.dismissOnScrim&&t.target===t.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const t=this.getRootNode();this._focusRoot=t;const e=Ct.get(t)||{dialogs:new Set,opener:this._opener};e.dialogs.add(this),Ct.set(t,e),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const t=[...this._overlays];this._overlays=[];for(const e of t.reverse())e.close("disconnect");const e=this._focusRoot,i=this._opener;this._opener=null,this._focusRoot=null;const s=e?Ct.get(e):void 0;s?.dialogs.delete(this),super.disconnectedCallback(),e&&s&&requestAnimationFrame(()=>{const t=Ct.get(e);if(!t)return;if(!t.dialogs.size)return t.opener?.isConnected&&t.opener.focus({preventScroll:!0}),void Ct.delete(e);const s=i?.closest("hp-dialog");i?.isConnected&&s&&t.dialogs.has(s)&&i.focus({preventScroll:!0})})}firstUpdated(t){if(super.firstUpdated(t),!this._useHaDialog){const t=this.renderRoot.querySelector("dialog");t&&!t.open&&t.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let t=document.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t&&t!==document.body?t:null}_focusableElements(){const t=["[autofocus]","a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[contenteditable="true"]','[tabindex]:not([tabindex="-1"])'].join(","),e=[],i=new Set,s=n=>{if(!i.has(n)){if(i.add(n),n instanceof HTMLElement){if(n.matches(t)&&e.push(n),n instanceof HTMLSlotElement){for(const t of n.assignedNodes({flatten:!0}))s(t);return}if(n.shadowRoot){for(const t of n.shadowRoot.childNodes)s(t);return}}for(const t of n.childNodes)s(t)}};for(const t of this.childNodes)s(t);const n=this.overlayPortal();return n&&s(n),e.filter(t=>{let e=t;for(;e;){const t=getComputedStyle(e);if(e.hidden||e.inert||"true"===e.getAttribute("aria-hidden")||"none"===t.display||"hidden"===t.visibility)return!1;if(e=e.assignedSlot||e.parentElement||(e.getRootNode()instanceof ShadowRoot?e.getRootNode().host:null),e===this)break}return!0})}_pruneOverlays(){this._overlays=this._overlays.filter(t=>t.owner.isConnected)}_closeOverlay(t,e){const i=this._overlays.findIndex(e=>e.token===t.token);i>=0&&this._overlays.splice(i,1),t.close(e)}registerOverlay(t){this._pruneOverlays();const e=this._overlays.find(e=>e.owner===t.owner);e&&this._overlays.splice(this._overlays.indexOf(e),1);const i=t.group||"transient";for(const t of[...this._overlays].reverse())t.group===i&&this._closeOverlay(t,"exclusive");const s={...t,group:i,token:Symbol("hp-overlay")};this._overlays.push(s);let n=!1;return()=>{if(n)return;n=!0;const t=this._overlays.findIndex(t=>t.token===s.token);t>=0&&this._overlays.splice(t,1)}}closeTransientOverlays(t="outside"){this._pruneOverlays();const e=[...this._overlays].filter(t=>"transient"===(t.group||"transient"));for(const i of e.reverse())this._closeOverlay(i,t);return e.length>0}overlayPortal(){return this.renderRoot.querySelector(".overlay-portal")}render(){const t=W` +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="29ac1cf640f37bd2a809801d01750209abd89e2daef0881131c63e2d41c17bf7";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),s=new WeakMap;let n=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const i=this.t;if(e&&void 0===t){const e=void 0!==i&&1===i.length;e&&(t=s.get(i)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&s.set(i,t))}return t}toString(){return this.cssText}};const o=(t,...e)=>{const s=1===t.length?t[0]:e.reduce((e,i,s)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+t[s+1],t[0]);return new n(s,t,i)},a=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return(t=>new n("string"==typeof t?t:t+"",void 0,i))(e)})(t):t,{is:r,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:p}=Object,u=globalThis,_=u.trustedTypes,m=_?_.emptyScript:"",g=u.reactiveElementPolyfillSupport,f=(t,e)=>t,v={toAttribute(t,e){switch(e){case Boolean:t=t?m:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let i=t;switch(e){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},y=(t,e)=>!r(t,e),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),u.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=b){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const i=Symbol(),s=this.getPropertyDescriptor(t,i,e);void 0!==s&&l(this.prototype,t,s)}}static getPropertyDescriptor(t,e,i){const{get:s,set:n}=c(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:s,set(e){const o=s?.call(this);n?.call(this,e),this.requestUpdate(t,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(f("elementProperties")))return;const t=p(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(f("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(f("properties"))){const t=this.properties,e=[...h(t),...d(t)];for(const i of e)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const i=this._$Eu(t,e);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const t of i)e.unshift(a(t))}else void 0!==t&&e.push(a(t));return e}static _$Eu(t,e){const i=e.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const i of e.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,s)=>{if(e)i.adoptedStyleSheets=s.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of s){const s=document.createElement("style"),n=t.litNonce;void 0!==n&&s.setAttribute("nonce",n),s.textContent=e.cssText,i.appendChild(s)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,i){this._$AK(t,i)}_$ET(t,e){const i=this.constructor.elementProperties.get(t),s=this.constructor._$Eu(t,i);if(void 0!==s&&!0===i.reflect){const n=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(e,i.type);this._$Em=t,null==n?this.removeAttribute(s):this.setAttribute(s,n),this._$Em=null}}_$AK(t,e){const i=this.constructor,s=i._$Eh.get(t);if(void 0!==s&&this._$Em!==s){const t=i.getPropertyOptions(s),n="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:v;this._$Em=s;const o=n.fromAttribute(e,t.type);this[s]=o??this._$Ej?.get(s)??o,this._$Em=null}}requestUpdate(t,e,i,s=!1,n){if(void 0!==t){const o=this.constructor;if(!1===s&&(n=this[t]),i??=o.getPropertyOptions(t),!((i.hasChanged??y)(n,e)||i.useDefault&&i.reflect&&n===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,i))))return;this.C(t,e,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:i,reflect:s,wrapped:n},o){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,o??e??this[t]),!0!==n||void 0!==o)||(this._$AL.has(t)||(this.hasUpdated||i||(e=void 0),this._$AL.set(t,e)),!0===s&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,i]of t){const{wrapped:t}=i,s=this[e];!0!==t||this._$AL.has(e)||void 0===s||this.C(e,void 0,i,s)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[f("elementProperties")]=new Map,w[f("finalized")]=new Map,g?.({ReactiveElement:w}),(u.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,x=t=>t,$=k.trustedTypes,S=$?$.createPolicy("lit-html",{createHTML:t=>t}):void 0,M="$lit$",C=`lit$${Math.random().toFixed(9).slice(2)}$`,D="?"+C,P=`<${D}>`,T=document,R=()=>T.createComment(""),I=t=>null===t||"object"!=typeof t&&"function"!=typeof t,A=Array.isArray,z="[ \t\n\f\r]",F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,E=/-->/g,N=/>/g,O=RegExp(`>|${z}(?:([^\\s"'>=/]+)(${z}*=${z}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,H=/"/g,B=/^(?:script|style|textarea|title)$/i,q=t=>(e,...i)=>({_$litType$:t,strings:e,values:i}),W=q(1),j=q(2),U=Symbol.for("lit-noChange"),G=Symbol.for("lit-nothing"),V=new WeakMap,K=T.createTreeWalker(T,129);function Y(t,e){if(!A(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(e):e}const J=(t,e)=>{const i=t.length-1,s=[];let n,o=2===e?"":3===e?"":"",a=F;for(let e=0;e"===l[0]?(a=n??F,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?O:'"'===l[3]?H:L):a===H||a===L?a=O:a===E||a===N?a=F:(a=O,n=void 0);const d=a===O&&t[e+1].startsWith("/>")?" ":"";o+=a===F?i+P:c>=0?(s.push(r),i.slice(0,c)+M+i.slice(c)+C+d):i+C+(-2===c?e:d)}return[Y(t,o+(t[i]||"")+(2===e?"":3===e?"":"")),s]};class X{constructor({strings:t,_$litType$:e},i){let s;this.parts=[];let n=0,o=0;const a=t.length-1,r=this.parts,[l,c]=J(t,e);if(this.el=X.createElement(l,i),K.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(s=K.nextNode())&&r.length0){s.textContent=$?$.emptyScript:"";for(let i=0;iA(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==G&&I(this._$AH)?this._$AA.nextSibling.data=t:this.T(T.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:i}=t,s="number"==typeof i?this._$AC(t):(void 0===i.el&&(i.el=X.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===s)this._$AH.p(e);else{const t=new Q(s,this),i=t.u(this.options);t.p(e),this.T(i),this._$AH=t}}_$AC(t){let e=V.get(t.strings);return void 0===e&&V.set(t.strings,e=new X(t)),e}k(t){A(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let i,s=0;for(const n of t)s===e.length?e.push(i=new tt(this.O(R()),this.O(R()),this,this.options)):i=e[s],i._$AI(n),s++;s2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=G}_$AI(t,e=this,i,s){const n=this.strings;let o=!1;if(void 0===n)t=Z(this,t,e,0),o=!I(t)||t!==this._$AH&&t!==U,o&&(this._$AH=t);else{const s=t;let a,r;for(t=n[0],a=0;a{const s=i?.renderBefore??e;let n=s._$litPart$;if(void 0===n){const t=i?.renderBefore??null;s._$litPart$=n=new tt(e.insertBefore(R(),t),t,void 0,i??{})}return n._$AI(t),n},ct=globalThis;let ht=class extends w{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=lt(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return U}};ht._$litElement$=!0,ht.finalized=!0,ct.litElementHydrateSupport?.({LitElement:ht});const dt=ct.litElementPolyfillSupport;dt?.({LitElement:ht}),(ct.litElementVersions??=[]).push("4.2.2");const pt=2,ut=t=>(...e)=>({_$litDirective$:t,values:e});let _t=class{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,i){this._$Ct=t,this._$AM=e,this._$Ci=i}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}};const mt={},gt=ut(class extends _t{constructor(){super(...arguments),this.ot=mt}render(t,e){return e()}update(t,[e,i]){if(Array.isArray(e)){if(Array.isArray(this.ot)&&this.ot.length===e.length&&e.every((t,e)=>t===this.ot[e]))return U}else if(this.ot===e)return U;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}}),{I:ft}=at,vt=t=>t,yt=()=>document.createComment(""),bt=(t,e,i)=>{const s=t._$AA.parentNode,n=void 0===e?t._$AB:e._$AA;if(void 0===i){const e=s.insertBefore(yt(),n),o=s.insertBefore(yt(),n);i=new ft(e,o,t,t.options)}else{const e=i._$AB.nextSibling,o=i._$AM,a=o!==t;if(a){let e;i._$AQ?.(t),i._$AM=t,void 0!==i._$AP&&(e=t._$AU)!==o._$AU&&i._$AP(e)}if(e!==n||a){let t=i._$AA;for(;t!==e;){const e=vt(t).nextSibling;vt(s).insertBefore(t,n),t=e}}}return i},wt=(t,e,i=t)=>(t._$AI(e,i),t),kt={},xt=(t,e=kt)=>t._$AH=e,$t=t=>{t._$AR(),t._$AA.remove()},St=(t,e,i)=>{const s=new Map;for(let n=e;n<=i;n++)s.set(t[n],n);return s},Mt=ut(class extends _t{constructor(t){if(super(t),t.type!==pt)throw Error("repeat() can only be used in text expressions")}dt(t,e,i){let s;void 0===i?i=e:void 0!==e&&(s=e);const n=[],o=[];let a=0;for(const e of t)n[a]=s?s(e,a):a,o[a]=i(e,a),a++;return{values:o,keys:n}}render(t,e,i){return this.dt(t,e,i).values}update(t,[e,i,s]){const n=(t=>t._$AH)(t),{values:o,keys:a}=this.dt(e,i,s);if(!Array.isArray(n))return this.ut=a,o;const r=this.ut??=[],l=[];let c,h,d=0,p=n.length-1,u=0,_=o.length-1;for(;d<=p&&u<=_;)if(null===n[d])d++;else if(null===n[p])p--;else if(r[d]===a[u])l[u]=wt(n[d],o[u]),d++,u++;else if(r[p]===a[_])l[_]=wt(n[p],o[_]),p--,_--;else if(r[d]===a[_])l[_]=wt(n[d],o[_]),bt(t,l[_+1],n[d]),d++,_--;else if(r[p]===a[u])l[u]=wt(n[p],o[u]),bt(t,n[d],n[p]),p--,u++;else if(void 0===c&&(c=St(a,u,_),h=St(r,d,p)),c.has(r[d]))if(c.has(r[p])){const e=h.get(a[u]),i=void 0!==e?n[e]:null;if(null===i){const e=bt(t,n[d]);wt(e,o[u]),l[u]=e}else l[u]=wt(i,o[u]),bt(t,n[d],i),n[e]=null;u++}else $t(n[p]),p--;else $t(n[d]),d++;for(;u<=_;){const e=bt(t,l[_+1]);wt(e,o[u]),l[u++]=e}for(;d<=p;){const t=n[d++];null!==t&&$t(t)}return this.ut=a,xt(t,l),U}}),Ct=new WeakMap;let Dt=0;class Pt extends ht{constructor(){super(...arguments),this.title="",this.icon="",this.wide=!1,this.dismissOnScrim=!1,this.hass=null,this._opener=null,this._focusRoot=null,this._useHaDialog=!1,this._closing=!1,this._overlays=[],this._titleId="hp-dialog-title-"+ ++Dt,this._focusInitial=()=>{const t=this._focusableElements(),e=t.find(t=>t.hasAttribute("autofocus"))||t[0]||(this._useHaDialog?null:this.renderRoot.querySelector(".close"))||this.renderRoot.querySelector(".surface")||this.renderRoot.querySelector("ha-dialog");e?.focus({preventScroll:!0})},this._requestClose=()=>{this._closing||(this._closing=!0,this.dispatchEvent(new CustomEvent("hp-close",{bubbles:!0,composed:!0})))},this._onKeyDown=t=>{if("Escape"===t.key){t.preventDefault(),t.stopImmediatePropagation(),this._pruneOverlays();const e=this._overlays[this._overlays.length-1];return e?void this._closeOverlay(e,"escape"):void this._requestClose()}if("Tab"!==t.key||this._useHaDialog)return;const e=this.renderRoot.querySelector(".close"),i=e?[e,...this._focusableElements()]:this._focusableElements();if(!i.length)return t.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const s=this._deepActiveElement(),n=i[0],o=i[i.length-1];!t.shiftKey||s!==n&&i.includes(s)?t.shiftKey||s!==o||(t.preventDefault(),n.focus()):(t.preventDefault(),o.focus())},this._onFallbackCancel=t=>{t.preventDefault(),this._requestClose()},this._onFallbackClick=t=>{this.dismissOnScrim&&t.target===t.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const t=this.getRootNode();this._focusRoot=t;const e=Ct.get(t)||{dialogs:new Set,opener:this._opener};e.dialogs.add(this),Ct.set(t,e),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const t=[...this._overlays];this._overlays=[];for(const e of t.reverse())e.close("disconnect");const e=this._focusRoot,i=this._opener;this._opener=null,this._focusRoot=null;const s=e?Ct.get(e):void 0;s?.dialogs.delete(this),super.disconnectedCallback(),e&&s&&requestAnimationFrame(()=>{const t=Ct.get(e);if(!t)return;if(!t.dialogs.size)return t.opener?.isConnected&&t.opener.focus({preventScroll:!0}),void Ct.delete(e);const s=i?.closest("hp-dialog");i?.isConnected&&s&&t.dialogs.has(s)&&i.focus({preventScroll:!0})})}firstUpdated(t){if(super.firstUpdated(t),!this._useHaDialog){const t=this.renderRoot.querySelector("dialog");t&&!t.open&&t.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let t=document.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t&&t!==document.body?t:null}_focusableElements(){const t=["[autofocus]","a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[contenteditable="true"]','[tabindex]:not([tabindex="-1"])'].join(","),e=[],i=new Set,s=n=>{if(!i.has(n)){if(i.add(n),n instanceof HTMLElement){if(n.matches(t)&&e.push(n),n instanceof HTMLSlotElement){for(const t of n.assignedNodes({flatten:!0}))s(t);return}if(n.shadowRoot){for(const t of n.shadowRoot.childNodes)s(t);return}}for(const t of n.childNodes)s(t)}};for(const t of this.childNodes)s(t);const n=this.overlayPortal();return n&&s(n),e.filter(t=>{let e=t;for(;e;){const t=getComputedStyle(e);if(e.hidden||e.inert||"true"===e.getAttribute("aria-hidden")||"none"===t.display||"hidden"===t.visibility)return!1;if(e=e.assignedSlot||e.parentElement||(e.getRootNode()instanceof ShadowRoot?e.getRootNode().host:null),e===this)break}return!0})}_pruneOverlays(){this._overlays=this._overlays.filter(t=>t.owner.isConnected)}_closeOverlay(t,e){const i=this._overlays.findIndex(e=>e.token===t.token);i>=0&&this._overlays.splice(i,1),t.close(e)}registerOverlay(t){this._pruneOverlays();const e=this._overlays.find(e=>e.owner===t.owner);e&&this._overlays.splice(this._overlays.indexOf(e),1);const i=t.group||"transient";for(const t of[...this._overlays].reverse())t.group===i&&this._closeOverlay(t,"exclusive");const s={...t,group:i,token:Symbol("hp-overlay")};this._overlays.push(s);let n=!1;return()=>{if(n)return;n=!0;const t=this._overlays.findIndex(t=>t.token===s.token);t>=0&&this._overlays.splice(t,1)}}closeTransientOverlays(t="outside"){this._pruneOverlays();const e=[...this._overlays].filter(t=>"transient"===(t.group||"transient"));for(const i of e.reverse())this._closeOverlay(i,t);return e.length>0}overlayPortal(){return this.renderRoot.querySelector(".overlay-portal")}render(){const t=W` ${this.icon?W``:G} ${this.title} `;return this._useHaDialog?W`${t.visibleLabel}`:G}
${t?.content||G}
- `}afterRender(){const t=this.host.root();this._blocked&&(this._openGroupId?this.closeGroup(!1):"palette"===this._currentModel?.kind&&this._currentModel.dismiss?.()),this._syncGlobalDismissListener();const e=t.querySelector(".editor-secondary"),i=this._renderedContext,s=e?.dataset.contextId||"";if(s&&i&&s!==i&&!window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches&&(this._contentAnimation?.cancel(),this._contentAnimation=e?.querySelector(".editor-secondary-content")?.animate([{opacity:.35,transform:"translateY(-4px)"},{opacity:1,transform:"translateY(0)"}],{duration:100,easing:"ease-out"})),this._renderedContext=s,i&&s!==i&&this._focusOwned){const i=s?e?.querySelector('[tabindex="0"], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'):t.querySelector(".editbar-tools");i?.focus?.(),this._focusOwned=!!s}if("palette"===this._currentModel?.kind&&this._currentModel.launcherId){const e=[...t.querySelectorAll("[data-editor-palette]")].find(t=>t.dataset.editorPalette===this._currentModel?.launcherId);e&&null!==e.offsetParent||this._currentModel.dismiss?.()}if(!this._openGroupId)return;const n=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===this._openGroupId);n&&null!==n.offsetParent||this.closeGroup(!0)}handleOutsideDismiss(t){if(B_(t,t=>t.hasAttribute("data-editor-navigation")))return"pointerdown"===t.type?this.closeForNavigation():"click"===t.type&&this._dismissPointerTarget&&this._clearDismissClick(),!1;if("click"===t.type&&this._dismissPointerTarget){return!!(t.composedPath?.()||[t.target]).includes(this._dismissPointerTarget)&&(this._clearDismissClick(),t.preventDefault(),t.stopImmediatePropagation(),!0)}const e=this._openGroupId||this._blocked||"palette"!==this._currentModel?.kind?null:this._currentModel;if("pointerdown"===t.type&&(this._openGroupId||e)){const i=B_(t,t=>t.classList.contains("editor-secondary")),s=B_(t,t=>!!t.dataset.editorGroup),n=B_(t,t=>!!t.dataset.editorPalette),o=B_(t,t=>t.classList.contains("stage"));if(!(i||s||n||"stay-open-on-canvas"===e?.dismissPolicy&&o))return t.preventDefault(),t.stopImmediatePropagation(),this._dismissPointerTarget=t.target,clearTimeout(this._dismissTimer),this._dismissTimer=window.setTimeout(()=>{this._clearDismissClick()},800),this._openGroupId?this.closeGroup(!1):e?.dismiss?.(),this._syncGlobalDismissListener(),!0}return!1}_activateGroupItem(t,e,i){if(t.id!==this._openGroupId)return;const s=t.items.find(t=>t.id===e);if(!s||s.disabled)return;const n="toggle"===s.role&&"stay-open"===s.closePolicy,o=0===i.detail;n||(this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener()),s.invoke(),!n&&o&&this.host.updateComplete().then(()=>{const e=[...this.host.root().querySelectorAll("[data-editor-group]")].find(e=>e.dataset.editorGroup===t.id&&null!==e.offsetParent);e?.focus()})}_groupKeydown(t){if(!["ArrowLeft","ArrowRight","Home","End"].includes(t.key))return;const e=[...t.currentTarget.querySelectorAll(".editor-group-item:not([disabled])")];if(!e.length)return;t.preventDefault();const i=e.indexOf(this.host.root().activeElement),s="Home"===t.key?0:"End"===t.key?e.length-1:"ArrowLeft"===t.key?i<=0?e.length-1:i-1:(i+1)%e.length;e[s]?.focus()}_clearDismissClick(){this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}_syncGlobalDismissListener(){const t=!this._blocked&&"palette"===this._currentModel?.kind,e=!!this._openGroupId||t||!!this._dismissPointerTarget;e!==this._globalDismissListening&&(this._globalDismissListening=e,e?(window.addEventListener("pointerdown",this._globalDismissGuard,!0),window.addEventListener("click",this._globalDismissGuard,!0)):(window.removeEventListener("pointerdown",this._globalDismissGuard,!0),window.removeEventListener("click",this._globalDismissGuard,!0)))}}const W_=t=>t.stopPropagation(),j_=4.166666666666667e-9;function U_(t){return Number.isFinite(t)?Math.round(t/Ph)*Ph:t}const G_=(t,e,i,s)=>Math.hypot(i-t,s-e),V_=(t,e,i,s,n,o,a,r)=>Math.hypot(Math.max(Math.abs(n-t),Math.abs(n+a-(t+i))),Math.max(Math.abs(o-e),Math.abs(o+r-(e+s)))),K_=(t,e,i,s,n,o,a)=>{const r=Math.max(Number(s)||0,0)/2,l=Math.PI/180,c=Math.cos(i*l)*r,h=Math.sin(i*l)*r,d=Math.cos(a*l)*r,p=Math.sin(a*l)*r,u=Math.max(G_(t+c,e+h,n+d,o+p),G_(t-c,e-h,n-d,o-p)),_=Math.max(G_(t+c,e+h,n-d,o-p),G_(t-c,e-h,n+d,o+p));return Math.min(u,_)},Y_=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function J_(t,e){const i=JSON.parse(JSON.stringify(t||[])),s=JSON.parse(JSON.stringify(e||{}));let n=0,o=0,a=0,r=0,l="",c=0,h=0,d=0;const p=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=j_&&h++},u=(t,e)=>{p(t[0],e[0]),p(t[1],e[1])},_={};let m=5;for(const t of i){const e=Y_(t);null!=t?.id&&(_[String(t.id)]=e),e>m&&(m=e)}const g=(t,e,i,s=!1)=>{if(!(t>j_||s))return;n++,t>a&&(a=t);const o=t*Ch*e;o>r&&(r=o,l=i)};for(const t of i){const e=Y_(t),i=null!=t?.id?String(t.id):"";for(const s of t.rooms||[]){o++;let t=0;if(s.poly?.length)s.poly=s.poly.map(e=>{const i=[U_(e[0]),U_(e[1])];return t=Math.max(t,G_(e[0],e[1],i[0],i[1])),u(e,i),i});else if(null!=s.x&&null!=s.y){const e=s.x,i=s.y,n=s.w||0,o=s.h||0,a=U_(e+n),r=U_(i+o),l=U_(e),c=U_(i),h=Math.max(Ph,a-l),d=Math.max(Ph,r-c);t=V_(e,i,n,o,l,c,h,d),s.x=l,s.y=c,s.w=h,s.h=d,p(e,l),p(i,c),p(e+n,l+h),p(i+o,c+d)}g(t,e,i)}for(const s of t.room_drafts||[]){o++;let t=0;const n=s.points||[],a=n.map(e=>{const i=[U_(e[0]),U_(e[1])];return t=Math.max(t,G_(e[0],e[1],i[0],i[1])),i}),r=a.length?[a[0]]:[],l=a.length?[[n[0],a[0]]]:[],c=[];for(let t=0;t+1=2)for(const[t,e]of l)u(t,e);g(t,e,i)}if(Array.isArray(t.room_drafts)){const e=t.room_drafts.length;t.room_drafts=t.room_drafts.filter(t=>t.points?.length>=2),d+=e-t.room_drafts.length,t.room_drafts.length||delete t.room_drafts}for(const s of t.partitions||[]){o++;const n=[s.a[0],s.a[1]],a=[s.b[0],s.b[1]],r=[U_(n[0]),U_(n[1])],l=[U_(a[0]),U_(a[1])];let c=Math.max(G_(n[0],n[1],r[0],r[1]),G_(a[0],a[1],l[0],l[1]));const h=G_(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).every(t=>{const e=Number(t.length),i=Number(t.host.t),s=i*h;return Number.isFinite(e)&&e>0&&Number.isFinite(i)&&i>=0&&i<=1&&s-e/2>=-j_&&s+e/2<=h+j_});h>j_&&d?(s.a=r,s.b=l,u(n,r),u(a,l)):c=0,g(c,e,i)}for(const s of t.wall_columns||[]){o++;const t=[s.center[0],s.center[1]],n=[U_(t[0]),U_(t[1])],a=G_(t[0],t[1],n[0],n[1]);s.center=n,u(t,n),g(a,e,i)}for(const s of t.decor||[]){o++;let t=0;if("line"===s.kind){const e=[s.x1,s.y1],i=[s.x2,s.y2],n=[U_(e[0]),U_(e[1])],o=[U_(i[0]),U_(i[1])];t=Math.max(G_(e[0],e[1],n[0],n[1]),G_(i[0],i[1],o[0],o[1])),s.x1=n[0],s.y1=n[1],s.x2=o[0],s.y2=o[1],u(e,n),u(i,o)}else{const e=s.x,i=s.y,n=s.w,o=s.h,a=U_(e),r=U_(i);if(null!=s.w&&null!=s.h){const l=U_(e+n),c=U_(i+o),h=Math.max(Ph,l-a),d=Math.max(Ph,c-r);t=V_(e,i,n,o,a,r,h,d),s.w=h,s.h=d,p(e+n,a+h),p(i+o,r+d)}else t=G_(e,i,a,r);s.x=a,s.y=r,p(e,a),p(i,r)}g(t,e,i)}for(const s of t.openings||[]){if(o++,"partition"===s.host?.kind){const n=(t.partitions||[]).find(t=>t.id===s.host.id),o=Number(s.host.t);if(!n||!Number.isFinite(o)||o<0||o>1)continue;const a=n.b[0]-n.a[0],r=n.b[1]-n.a[1];if(Math.hypot(a,r)<=j_)continue;const l=n.a[0]+a*o,h=n.a[1]+r*o;let d=180*Math.atan2(r,a)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(s.angle),u=!(Number.isFinite(p)&&p===d),_=K_(s.x,s.y,Number.isFinite(p)?p:d,Number(s.length)||0,l,h,d);s.x=l,s.y=h,s.angle=d,u&&c++,g(_,e,i,u);continue}const n=ui([s.x,s.y],t.rooms||[],.025,{step:Ph,length:Number(s.length)||0});if(!n)continue;const a=Number(s.angle),r=!(Number.isFinite(a)&&a===n.angle),l=K_(s.x,s.y,Number.isFinite(a)?a:n.angle,Number(s.length)||0,n.x,n.y,n.angle);s.x=n.x,s.y=n.y,s.angle=n.angle,r&&c++,g(l,e,i,r)}}for(const[t,e]of Object.entries(s)){if(!e||"object"!=typeof e)continue;const i=e;if("number"!=typeof i.x||"number"!=typeof i.y)continue;o++;const n=U_(i.x),a=U_(i.y),r=G_(i.x,i.y,n,a);s[t]={...i,x:n,y:a},p(i.x,n),p(i.y,a);const l="string"==typeof i.s?i.s:"";g(r,_[l]??m,l)}return{spaces:i,layout:s,report:{moved:n,coordsCanonicalized:h,total:o,maxShift:a,maxShiftCm:r,maxSpace:l,rotated:c,removedDrafts:d},changed:n>0||h>0}}function X_(t,e){const i=e.base+t*e.span;return Math.min(1,Math.max(0,i))}const Z_=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Q_=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function tm(t,e,i){const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;if(o<=0)return Q_(t,e);let a=((t[0]-e[0])*s+(t[1]-e[1])*n)/o;return a=Math.max(0,Math.min(1,a)),Math.hypot(t[0]-(e[0]+s*a),t[1]-(e[1]+n*a))}function em(t,e,i,s,n){for(const s of e)if(s&&!i.has(s.id)&&Z_(s.a)&&Z_(s.b)&&(Q_(t,s.a)<=n||Q_(t,s.b)<=n))return!0;for(const e of s?.roomPolygons||[])for(let i=0;i0&&r>0))return null;if(Math.abs(n[0]/a*(o[1]/r)-n[1]/a*(o[0]/r))>i)return null;for(const[i,n]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(Q_(i,n)<=s)return[(i[0]+n[0])/2,(i[1]+n[1])/2];return null}function sm(t,e){const i=.05*(Number(e.pitch)>0?Number(e.pitch):1),s=new Map;let n=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&Z_(t.a)&&Z_(t.b));if(n.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const o=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let a=0;for(let t=0;tQ_(e,t.at)>i);let h=c[0]??r.a,d=c[c.length-1]??l.b;if(c.length<2&&(h=r.a,d=l.b),d[0]0?(d[0]-h[0])/u:0,m=u>0?(d[1]-h[1])/u:0,g=t=>u>0?((t[0]-h[0])*_+(t[1]-h[1])*m)/u:0;for(const t of[r,l]){const e=g(t.a),i=g(t.b)-e;for(const[n,o]of s)o.toId===t.id&&s.set(n,{fromId:o.fromId,toId:p.id,base:e+o.base*i,span:o.span*i});s.set(t.id,{fromId:t.id,toId:p.id,base:e,span:i})}o&&o.add(p.id),n=n.filter((e,i)=>i!==t.i&&i!==t.j),n.splice(t.i,0,p),a++}return{partitions:n,merged:a,openingMoves:[...s.values()]}}function nm(t,e,i,s){if(!t?.length||!i.length)return 0;const n=new Map(i.map(t=>[t.fromId,t]));let o=0;for(const i of t){const t=i?.host;if(!t||"partition"!==t.kind)continue;const a=n.get(t.id);if(!a)continue;i.host={...t,id:a.toId,t:X_(t.t,a)},o++;const r=$p(i,e,s.coordScale,s.cellCm,s.gridPitch).resolved;r&&Object.assign(i,Rp(i,r,s.coordScale))}return o}function om(t,e){const i=e?.excludeDraftId||null;return{roomPolygons:(t?.rooms||[]).map(t=>hi(t)).filter(t=>!!t),columns:t?.wall_columns||[],draftEnds:(t?.room_drafts||[]).flatMap(t=>{if(i&&t?.id===i)return[];const e=t?.points||[];return e.length?[e[0],e[e.length-1]]:[]})}}const am=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),rm=(t,e)=>t[0]-e[0]||t[1]-e[1],lm=(t,e,i,s)=>[t[0]+e*s,t[1]+i*s],cm=(t,e,i,s)=>(t[0]-e[0])*i+(t[1]-e[1])*s,hm=(t,e,i,s,n)=>{const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(!(r>n))return null;const l=o/r,c=a/r,h=e=>Math.abs((e[0]-t[0])*c-(e[1]-t[1])*l);if(h(i)>n||h(s)>n)return null;const d=cm(i,t,l,c),p=cm(s,t,l,c),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));return _-u>n?{lo:u,hi:_}:null},dm=(t,e,i)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>i,pm=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},um=(t,e,i,s)=>{const n=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(n,o);if(!(a>s))return!0;const r=n/a,l=o/a,c=gl(t.cm,i.cellCm,i.gridPitch)/2;return e.some(e=>{const n=e?.center;if(!am(n))return!0;const o=cm(n,t.a,r,l),h=Math.abs((n[0]-t.a[0])*l-(n[1]-t.a[1])*r),d=gl(Number(e.cm),i.cellCm,i.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||o>=-d-s&&o<=a+d+s&&h<=c+d+s})},_m=(t,e,i)=>{if(t.host){const s=$p(t,e,i.coordScale,i.cellCm,i.gridPitch).resolved;return s?{center:s.center,angle:s.angle,length:s.length}:null}const s=Number(t.x)*i.coordScale,n=Number(t.y)*i.coordScale,o=Number(t.angle),a=Number(t.length)*i.coordScale;return[s,n,o,a].every(Number.isFinite)&&a>0?{center:[s,n],angle:o,length:a}:null},mm=(t,e,i)=>{const s=t.angle*Math.PI/180,n=Math.cos(s),o=Math.sin(s),a=e.angle*Math.PI/180,r=Math.cos(a),l=Math.sin(a);if(Math.abs(n*l-o*r)>1e-6)return!1;const c=e.center[0]-t.center[0],h=e.center[1]-t.center[1];if(Math.abs(c*o-h*n)>i)return!1;const d=c*n+h*o;return Math.max(-t.length/2,d-e.length/2)({...t,a:[t.a[0]*e,t.a[1]*e],b:[t.b[0]*e,t.b[1]*e]}),fm=(t,e,i,s)=>{const n=`~r-${(t=>{let e=2166136261;for(let i=0;i>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${i[0].toFixed(9)},${i[1].toFixed(9)}`)}`,o=`${t.slice(0,Math.max(1,64-n.length))}${n}`;let a=o;for(let t=2;s.has(a);t++){const e=`-${t}`;a=`${o.slice(0,64-e.length)}${e}`}return s.add(a),a},vm=(t,e)=>{const i=[];for(const s of t){const t=i[i.length-1];!(t&&Math.abs(t.hi-s.lo)<=e&&t.safe===s.safe)||s.safe&&t.signature!==s.signature?i.push({lo:s.lo,hi:s.hi,a:s.a,b:s.b,safe:s.safe,signature:s.signature,roomIds:s.roomIds,finalCm:s.finalCm}):(t.hi=s.hi,t.b=s.b)}return i};function ym(t,e,i,s,n){const o=i||[],a=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l=Array.isArray(t?.room_drafts)?t.room_drafts:[],c={walls:o,partitions:a,openings:r,roomDrafts:l,partitionsReconciled:0,openingsRehosted:0,removedDrafts:0};if(!a.length&&!l.length)return c;const h=Math.max(2e-4*n.gridPitch,1e-9);let d=o,p=a,u=r;const _=dc(e.rooms,d,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),m=((t,e,i,s)=>{const n=new Map(t.map(t=>[t.id,t])),o=new Set;for(const t of e){if(!n.get(t.id)||!Array.isArray(t.points)||t.points.length<2||t.segments.length!==t.points.length-1)continue;let e=!0;for(let n=0;n+10)){e=!1;break}const l=Math.hypot(a[0]-o[0],a[1]-o[1]);if(!(l>s)){e=!1;break}const c=i.flatMap(t=>{const e=t.cm>0?t.cm:ll;if(t.open||"outer"!==t.kind&&"shared"!==t.kind||e+st.lo-e.lo||t.hi-e.hi);let h=0;for(const t of c){if(t.lo>h+s)break;if(h=Math.max(h,t.hi),h>=l-s)break}h!m.has(t.id));let f=0,v=0;const y=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...a].sort((t,e)=>t.id.localeCompare(e.id))){if(!p.some(e=>e.id===t.id))continue;if(!pm(t))continue;const i=y.get(t.id);if(!(i&&am(i.a)&&am(i.b)&&Number.isFinite(i.cm)&&i.cm>0))continue;const[o,a]=rm(i.a,i.b)<=0?[[i.a[0],i.a[1]],[i.b[0],i.b[1]]]:[[i.b[0],i.b[1]],[i.a[0],i.a[1]]],r=a[0]-o[0],l=a[1]-o[1],c=Math.hypot(r,l);if(!(c>h))continue;const _=r/c,g=l/c,b=dc(e.rooms,d,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),w=b.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=hm(o,a,t.a,t.b,h);return e?[{interval:t,range:e}]:[]});if(!w.length)continue;const k=u.filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).map(t=>({opening:t,resolved:$p(t,e.partitions,n.coordScale,n.cellCm,n.gridPitch).resolved}));if(k.some(t=>!t.resolved))continue;const x=[0,c];for(const{range:t}of w)x.push(t.lo,t.hi);const $=x.slice(),S=new Map;for(const{opening:t,resolved:e}of k){const i=cm(e.center,o,_,g),s={lo:i-e.length/2,hi:i+e.length/2};S.set(t.id,s),$.push(Math.max(0,s.lo),Math.min(c,s.hi))}const M=[...new Set($.filter(t=>Number.isFinite(t)&&t>=-h&&t<=c+h).map(t=>Math.max(0,Math.min(c,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),C=p.map(t=>gm(t,n.coordScale)).filter(t=>t.id!==i.id),D=e.room_drafts.filter(t=>!m.has(t.id)),P=[];for(let t=0;t+1h))continue;const r=lm(o,_,g,s),l=lm(o,_,g,a),c=w.filter(({range:t})=>t.lo<=s+h&&t.hi>=a-h).map(({interval:t})=>t),d=new Map;for(const t of c)d.set(t.roomId,t);const p=[...d.values()],u=new Set(p.map(t=>t.kind)),m=new Set(p.map(t=>t.cm>0?t.cm:ll)),f=p[0]?.kind,v=[...d.keys()].sort(),y=1===u.size&&1===m.size&&("outer"===f&&1===v.length||"shared"===f&&2===v.length),b={id:i.id,a:r,b:l,cm:i.cm},k=C.some(t=>!!hm(r,l,t.a,t.b,h)),x=D.some(t=>t.points.some((e,i)=>i+10?p[0].cm:ll:0,T=y?Math.max(S,i.cm):i.cm;P.push({lo:s,hi:a,a:r,b:l,safe:$,signature:$?`${f}|${v.join(",")}|${T}`:"",roomIds:v,roomCm:S,finalCm:T})}if(!P.some(t=>t.safe))continue;const T=new Map;for(const{opening:t,resolved:e}of k){const s=S.get(t.id),o=x.some(t=>t>s.lo+h&&tdm(t,s,h)),r=new Set(a.filter(t=>t.safe).map(t=>t.signature));if(!o&&a.length>0&&a.every(t=>t.safe)&&1===r.size&&Tp(e,b,h)){T.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=kp(i,n.cellCm,n.gridPitch),c={lo:s.lo-l,hi:s.hi+l};for(const t of P)dm(t,c,h)&&(t.safe=!1,t.signature="")}let R=!0;for(;R;){R=!1;for(const[t,e]of[...T.entries()]){const s=S.get(t),o=P.filter(t=>dm(t,s,h));if(o.length>0&&o.every(t=>t.safe)&&o.every(t=>t.signature===e.signature))continue;T.delete(t);const a=kp(i,n.cellCm,n.gridPitch),r={lo:s.lo-a,hi:s.hi+a};for(const t of P)dm(t,r,h)&&(t.safe=!1,t.signature="");R=!0}}const I=vm(P,h),A=I.filter(t=>t.safe),z=I.filter(t=>!t.safe);if(!A.length)continue;if(p.length-1+z.length>2e3)continue;let F=d;for(const t of A){const[e,s]=rm(i.a,i.b)<=0?[t.a,t.b]:[t.b,t.a];F=Fl(F,e,s,t.finalCm,n.pitch,n.coordScale)}if(F=uc(e.rooms,F,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),F.length>500)continue;const E=new Set(p.map(t=>t.id));E.delete(i.id);const N=z.map((t,e)=>{const s=[t.a[0]/n.coordScale,t.a[1]/n.coordScale],o=[t.b[0]/n.coordScale,t.b[1]/n.coordScale],a=0===e?i.id:fm(i.id,s,o,E);return E.add(a),{id:a,a:s,b:o,cm:i.cm}}),O=p.findIndex(t=>t.id===i.id),L=p.slice();L.splice(O,1,...N);const H=L.map(t=>gm(t,n.coordScale)),B=new Map;let q=!0;for(const{opening:t,resolved:e}of k){const i=T.get(t.id);if(i){const e=Rp(t,i.resolved,n.coordScale),{host:s,...o}=e;B.set(t.id,o);continue}const s=S.get(t.id),o=N[z.findIndex(t=>t.lo<=s.lo+h&&t.hi>=s.hi-h)],a=o&&H.find(t=>t.id===o.id);if(!o||!a){q=!1;break}const r=a.b[0]-a.a[0],l=a.b[1]-a.a[1],c=Math.hypot(r,l),d=cm(e.center,a.a,r/c,l/c),p={...Rp(t,e,n.coordScale),host:{kind:"partition",id:o.id,t:d/c}};if(!Sp(p,H,n.coordScale,n.cellCm,n.gridPitch).resolved){q=!1;break}B.set(t.id,p)}if(!q)continue;const W=u.map(t=>B.get(t.id)||t),j=[...T.keys()].map(t=>B.get(t)),U=j.map(t=>_m(t,H,n));if(U.some(t=>!t))continue;let G=!1;for(let t=0;tt.id));for(const t of W){if(V.has(t.id))continue;const e=_m(t,H,n);e&&U.some(t=>mm(t,e,h))&&(G=!0)}if(G)continue;const K=Fc(e.rooms,F,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale);[...T.entries()].every(([t,e])=>{const i=B.get(t),s=Oc(K,{x:i.x*n.coordScale,y:i.y*n.coordScale,angle:i.angle,length:i.length*n.coordScale},!0),o=[s.negative,s.positive].filter(t=>!!t?.full),a=e.signature.split("|")[1].split(","),r=new Set(o.map(t=>t.roomId));return o.length===a.length&&r.size===a.length&&a.every(t=>r.has(t))})&&(d=F,p=L,u=W,f+=A.length,v+=T.size)}return{walls:d,partitions:p,openings:u,roomDrafts:g,partitionsReconciled:f,openingsRehosted:v,removedDrafts:m.size}}const bm=t=>JSON.parse(JSON.stringify(t)),wm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),km=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function xm(t,e){let i=String(e??"");const s=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=new RegExp(`^${s}_(.+)_([0-9a-f]{8})$`);let o=0;for(;o<16;o++){const t=n.exec(i);if(!t)return{root:i,layers:o,bounded:!1};i=t[1]}return{root:i,layers:o,bounded:n.test(i)}}const $m=(t,e,i)=>{const s=t.get(e)||[];s.push(i),t.set(e,s)};const Sm=1e-9;class Mm extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const Cm=t=>JSON.parse(JSON.stringify(t)),Dm=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),Pm=t=>[Number(t[0]),Number(t[1])],Tm=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,Rm=(t,e)=>{const i=Tm(t),s=Tm(e);return iTm(t)<=Tm(e)?[Pm(t),Pm(e)]:[Pm(e),Pm(t)],Am=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),zm=t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],i=[];for(let s=1;s{const i=new Set,s=t=>{const e=Number(t);if(!Number.isFinite(e))return;const s=e/Ph;Math.abs(s-Math.round(s))>=Ur&&i.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of hi(e)||[])s(t[0]),s(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])s(t?.a?.[0]),s(t?.a?.[1]),s(t?.b?.[0]),s(t?.b?.[1]);for(const t of e)s(t?.[0]),s(t?.[1]);return i.size},Em=(t,e,i)=>{const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;return o>1e-18?((t[0]-e[0])*s+(t[1]-e[1])*n)/o:0},Nm=(t,e,i)=>{const s=Math.max(0,Math.min(1,Em(t,e,i)));return Math.hypot(t[0]-(e[0]+(i[0]-e[0])*s),t[1]-(e[1]+(i[1]-e[1])*s))},Om=(t,e,i,s,n=Sm)=>{const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(r<=n)return 0;const l=e=>Math.abs((e[0]-t[0])*a-(e[1]-t[1])*o)/r;if(l(i)>n||l(s)>n)return 0;const c=Em(i,t,e),h=Em(s,t,e);return Math.max(0,Math.min(1,Math.max(c,h))-Math.max(0,Math.min(c,h)))*r},Lm=t=>{const e=(new TextEncoder).encode(t),i=8*e.length,s=64*Math.ceil((e.length+9)/64),n=new Uint8Array(s);n.set(e),n[e.length]=128;const o=new DataView(n.buffer);o.setUint32(s-8,Math.floor(i/4294967296),!1),o.setUint32(s-4,i>>>0,!1);const a=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),l=new Uint32Array(64),c=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,n=c(i,17)^c(i,19)^i>>>10;l[t]=l[t-16]+s+l[t-7]+n>>>0}let[e,i,s,n,h,d,p,u]=r;for(let t=0;t<64;t++){const o=u+(c(h,6)^c(h,11)^c(h,25))+(h&d^~h&p)+a[t]+l[t]>>>0,r=e&i^e&s^i&s;u=p,p=d,d=h,h=n+o>>>0,n=s,s=i,i=e,e=o+((c(e,2)^c(e,13)^c(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+i>>>0,r[2]=r[2]+s>>>0,r[3]=r[3]+n>>>0,r[4]=r[4]+h>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+u>>>0}const h=new Uint8Array(32),d=new DataView(h.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let i=0,s=0,n="";for(const o of t)for(s=s<<8|o,i+=8;i>=5;)n+=e[s>>>i-5&31],i-=5;return i&&(n+=e[s<<5-i&31]),n},Bm=(t,e,i,s,n="")=>{const[o,a]=Im(e,i),r=`${t}|${Tm(o)}|${Tm(a)}|${[...s].sort().join(",")}${n}`;return`wall-${Hm(Lm(r)).slice(0,20)}`};let qm=0;const Wm=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),i=`wall-${e||Hm(Lm(`${Date.now()}|${qm++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(i))return i}throw new Mm("duplicate-id","id factory exhausted")},jm=t=>{const e=new Map;for(const i of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(i&&"string"==typeof i.id&&Dm(i.a)&&Dm(i.b)){if(e.has(i.id))throw new Mm("duplicate-id",i.id);e.set(i.id,i)}return e},Um=(t,e,i)=>{const s=(i,s)=>{const n=t[0]-i[0],o=t[1]-i[1];return Math.abs(e[0]-s[0]-n)<=Sm&&Math.abs(e[1]-s[1]-o)<=Sm?[n,o]:null};return s(i.a,i.b)||s(i.b,i.a)},Gm=(t,e)=>{const i=Array.isArray(t.rooms)?t.rooms:[],s=pd(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),n=s.length?s:ud(i,null,1,.04*Ph,!0),o=[];for(const t of i){const i=hi(t),s=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(i&&s.length===i.length)for(let t=0;tSm||Math.abs(s[1]-p[1])>Sm)){u=!1;break}p=s}const _=[];for(let t=0;t2)throw new Mm("third-owner",l);const m=d?h[c.parent[t]]:void 0;if("string"==typeof m&&m){const n=e.get(m);u||!n||Om(i,s,n.a,n.b)>Sm?p.preferredIds.add(m):p.positionalIds.add(m),p.preferredCarriers.set(m,{a:Pm(o[c.parent[t]]),b:Pm(o[(c.parent[t]+1)%o.length])})}const g=c.parent[t];p.parentKeys.add(wl(o[g],o[(g+1)%o.length],Ph));const f=[(i[0]+s[0])/2,(i[1]+s[1])/2];p.zeroWall||=a.some(t=>Nm(f,[t[0],t[1]],[t[2],t[3]])<=.04*Ph),_.push(l)}const m={...s};delete m.wall_ids,l.push({...m,poly:c.poly.map(t=>[t[0],t[1]]),wall_ids:_})}return{atoms:[...r.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:l}},Vm=(t,e,i,s,n)=>{const o=new Map([...i.values()].map(t=>[Rm(t.a,t.b),t])),a=(t=>{const e=new Map;for(const i of t)"wall"===i.host?.kind&&e.set(i.host.id,(e.get(i.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=n?.get(t.key);if(e){const s=i.get(e);if(!s)throw new Mm("duplicate-id",e);r.set(t,s);continue}if(t.preferredIds.size>1)throw new Mm("duplicate-id",[...t.preferredIds].sort().join(","));const s=[...t.preferredIds][0],l=s?i.get(s):void 0;if(l){r.set(t,l);continue}const c=s?t.preferredCarriers.get(s):void 0;if(s&&c){r.set(t,{id:s,a:c.a,b:c.b,cm:0});continue}const h=o.get(t.key);if(h){r.set(t,h);continue}const d=[...i.values()].filter(e=>Om(t.a,t.b,e.a,e.b)>Sm),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(a.get(e.id)||0)-(a.get(t.id)||0)||Am(e.a,e.b)-Am(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=i.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const i=l.get(e.id)||[];i.push(t),l.set(e.id,i)}for(const[t,e]of l){const s=i.get(t)||r.get(e[0]);if(!s)throw new Mm("duplicate-id",t);const n=[(s.a[0]+s.b[0])/2,(s.a[1]+s.b[1])/2];e.sort((t,e)=>{const i=Nm(n,t.a,t.b)<=Sm?0:1,o=Nm(n,e.a,e.b)<=Sm?0:1;if(i!==o)return i-o;return(Nm(s.a,t.a,t.b)<=Sm?0:1)-(Nm(s.a,e.a,e.b)<=Sm?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const c=(t=>{const e=new Set;for(const i of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(i)?i:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const i of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(i?.segments)?i.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(c.has(t.id))throw new Mm("duplicate-id",t.id);c.add(t.id)}const h=e.filter(t=>!t.id);if(s){const e=h.map(e=>{const[i,s]=Im(e.a,e.b),n=`${String(t.id||"")}|${Tm(i)}|${Tm(s)}|${[...e.owners].sort().join(",")}`,o=Hm(Lm(n));return{atom:e,seed:n,digest:o,base:`wall-${o.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),i=new Map;for(const t of e){const e=i.get(t.digest);if(e&&e!==t.seed)throw new Mm("duplicate-id",t.digest);i.set(t.digest,t.seed);let s=1,n=t.base;for(;c.has(n);)n=`${t.base}-${++s}`;t.atom.id=n,c.add(n)}}else for(const t of h)t.id=Wm(c),c.add(t.id)},Km=(t,e)=>{if("partition"===t.host?.kind)return null;const i=[Number(t.x),Number(t.y)];if(!i.every(Number.isFinite))return null;const s=e=>{if(!(Number(e.cm)>0))return!1;const s=Em(i,e.a,e.b),n=Am(e.a,e.b),o=Number(t.length)/2;return s>=-Sm&&s<=1+Sm&&Nm(i,e.a,e.b)<=.02*Ph&&Rl(e.a,e.b,Number(t.angle))&&Number.isFinite(o)&&o>=0&&s*n-o>=-Sm&&s*n+o<=n+Sm},n="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,o=n&&s(n)?[n]:e.filter(s);if(1!==o.length)return null;const a=o[0];return{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,Em(i,a.a,a.b)))}},Ym=(t,e,i)=>{const s=jm(t),{atoms:n,rooms:o}=Gm(t,s);Vm(t,n,s,e,i);const a=n.map(e=>{const i=e.id?s.get(e.id):void 0,n=((t,e,i)=>{if(e.zeroWall)return 0;const s=Array.isArray(t.walls)?t.walls:[],n=wl(e.a,e.b,Ph),o=s.filter(t=>Number(t.cm)>0&&(!(t.key!==n&&!e.parentKeys.has(t.key))||!(!Dm(t.a)||!Dm(t.b))&&Om(e.a,e.b,t.a,t.b)>=Am(e.a,e.b)-Sm)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(o.map(t=>t.toFixed(9))).size>1)throw new Mm("thickness-conflict",e.key);if(o.length)return o[0];const a=Pl(s,e.a,e.b,Ph,1);return a>0?a:Number(i?.cm)>0?Number(i.cm):0})(t,e,i);return{...i||{},id:e.id,a:[...e.a],b:[...e.b],cm:n}}),r=new Map(n.map(t=>[t.key,t.id]));for(const t of o)t.wall_ids=t.wall_ids.map(t=>r.get(t));t.rooms=o,t.wall_segments=a,t.walls=a.filter(t=>t.cm>0).map(t=>({key:wl(t.a,t.b,Ph),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e)=>{const i=new Set;for(const e of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&i.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[]){const n=Array.isArray(s.segments)?s.segments:[];for(let o=0;o{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;const i=Km(t,e);if(!i)throw new Mm("opening-host",t.id);t.host=i}})(t,a),a.reduce((t,e)=>t+(s.has(e.id)?0:1),0)};function Jm(t,e={}){const i=JSON.stringify(t),s=Cm(t);rl(s);let n=0;const o=Number(s?.model_version||0)<9;for(const t of Array.isArray(s?.spaces)?s.spaces:[]){const i=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0;n+=Ym(t,o,i)}return s.model_version=9,rl(s),{config:s,changed:i!==JSON.stringify(s),migratedSegments:n}}const Xm=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Zm(t,e){const i=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const s=new Map;for(const e of t)Xm(e)&&"string"==typeof e.id&&e.id&&s.set(e.id,e);const n=e.map((e,n)=>{if(Xm(e)&&"string"==typeof e.id&&e.id){const t=s.get(e.id);return t?i(t,e):Cm(e)}return n[e,e in t?i(t[e],s):Cm(s)]);for(const e of Object.keys(t))delete t[e];for(const[e,i]of s)t[e]=i;return t}return Cm(e)};return i(t,e)}const Qm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),tg=(t,e,i)=>Math.min(i,Math.max(e,t)),eg=t=>$h({spaces:[t]})[0],ig=(t,e,i)=>{const s=i>0?i:1,n=t=>`${(t[0]/s).toFixed(12)},${(t[1]/s).toFixed(12)}`,o=n(t),a=n(e);return o0?a:1,l=Math.max(s*r*.02,1e-9),c=[];for(const e of t||[])for(const t of hi(e)||[])c.push([t[0],t[1]]);const h=[];for(const t of i||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&h.push([t[0],t[1]],[t[2],t[3]]);const d=(t,e)=>e.some(e=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l),p=new Map;for(const a of t||[]){if(!a?.id)continue;const u=hc(t,a.id,e,i,s,n,o,r);if(u)for(let t=0;t0&&_>0&&a===m&&_!==a))continue;const g=u.poly[s],f=u.poly[(s+1)%u.poly.length],v=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(v>l&&v<.5*o-1e-9*o))continue;if(d(g,h)||d(f,h))continue;if(d(g,c)&&d(f,c))continue;const y=ig(g,f,r),b=p.get(y);b?b.targets.add(a):p.set(y,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([a])})}}}let u=e.slice();const _=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const i=[Number(t.a[0])*r,Number(t.a[1])*r],s=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...i,...s].every(Number.isFinite)&&(_(i,e.a)&&_(s,e.b)||_(i,e.b)&&_(s,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>ig(t.a,t.b,r).localeCompare(ig(e.a,e.b,r)))){const e=[...t.targets][0],i=u.filter(e=>m(e,t));if(new Set(i.map(t=>t.cm)).size>1)continue;let n=!1;u=u.map(i=>m(i,t)?(n=!0,i.cm===e?i:{...i,cm:e}):i),n||(u=Fl(u,t.a,t.b,e,s,r))}return u}const ng=t=>{const e=[];for(const i of t||[]){const t=hi(i);if(t?.length)for(let i=0;i"string"==typeof t?.id?t.id:"").filter(Boolean),h=new Set(c),d=new Map;for(const t of c){const e=xm("space",t);e.layers>0&&km("space",e.root)&&$m(d,e.root,t)}const p=new Map,u=new Map,_=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const i=new Map;for(const s of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof s?.id?s.id:"";if(!t)continue;const n=xm("room",t);n.layers>0&&km("room",n.root)&&$m(i,n.root,t),u.has(t)||u.set(t,e),_.has(t)||_.set(t,String(s.name||""));const o="string"==typeof s.area?s.area:"";if(o){const i=m.get(o)||[];i.push({spaceId:e,roomId:t}),m.set(o,i)}}p.set(e,i)}const g=new Set(u.keys()),f=new Map,v=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?v.set(t.id,t):f.set(t.id,t));const y={spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,positionsUnresolved:0,nestedRefsUnresolved:0,deadSpaceIds:[],orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0,removedPositions:[],liveMissingPositions:[],unverifiedPositions:[]},b=new Set,w=t=>h.has(t)?null:(()=>{const e=xm("space",t).root;if(!km("space",e))return null;const i=d.get(e)||[];return 1===i.length?i[0]:null})(),k=(t,e)=>{const i=xm("room",t).root;if(!km("room",i))return null;const s=p.get(e)?.get(i)||[];return 1===s.length?s[0]:null},x=t=>{const e=i.effectiveAreaByMarker?.[t]||"",s=e&&m.get(e)||[];return 1===s.length?s[0]:null},$=(t,e,i)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const s=e?k(t.room_id,e):null;s?(t.room_id=s,y.roomRefsRemapped++):i?(t.room_id=i.roomId,y.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const s=t.vacuum?.segment_map;if(s&&"object"==typeof s&&!Array.isArray(s))for(const t of Object.keys(s)){const i=s[t];if("string"!=typeof i||!i||g.has(i))continue;const n=e?k(i,e):null;n?(s[t]=n,y.roomRefsRemapped++):y.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const i="string"==typeof t.space?t.space:"",s=i&&!h.has(i),o=n[e],a="string"==typeof o?.s?o.s:"",r=a&&!h.has(a),l=!0===t.removed;let c=i&&h.has(i)?i:null,d=null,p=!1;if(s){const s=w(i);s?(t.space=s,c=s,p=!0,y.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,c=null,y.markersDetached++):(d=x(e),d?(t.space=d.spaceId,c=d.spaceId,y.spaceRefsRemapped++):(delete t.space,c=null,y.markersDetached++))}l&&!p||$(t,c,d),r&&p&&a===i&&c&&(n[e]={...o,s:c},y.positionsRemapped++,b.add(e))}for(const t of Object.keys(n)){if(b.has(t))continue;const e=n[t],i="string"==typeof e?.s?e.s:"";if(!i||h.has(i))continue;const s=w(i);if(s){if(t.startsWith("rl_")){const i=t.slice(3),o=k(i,s);if(o){const i=`rl_${o}`;wm(n,i)||(n[i]={...e,s:s}),delete n[t],y.roomRefsRemapped++,y.positionsRemapped++;continue}}n[t]={...e,s:s},y.positionsRemapped++}}const S=i.ownerRoster,M=!0===S?.authoritative,C=new Set(S?.deviceIds||[]),D=new Set(S?.entityIds||[]),P=new Set(Array.isArray(s.settings?.known_devices)?s.settings.known_devices.filter(t=>"string"==typeof t):[]),T=(t,e="")=>{const i=String(S?.names?.[t]||e||"").trim();return i&&i!==t?i:""},R=(t,e,i,s="",n)=>({id:t,spaceId:e,kind:i,name:T(t,s),...n?{reason:n}:{}}),I=t=>{"room_label"===t?y.orphanRoomLabelsRemoved++:"group"===t?y.orphanGroupPositionsRemoved++:y.orphanDevicePositionsRemoved++},A=new Set;for(const[t,e]of Object.entries(n)){const s="string"==typeof e?.s?e.s:"";if(!s||h.has(s))continue;let o,a;const r=f.get(t),l=v.get(t);if(r)o=R(t,s,"device",String(r.name||"")),a="live";else if(l)o=R(t,s,"device",String(l.name||"")),a="absent";else if(t.startsWith("rl_")){const e=t.slice(3);o=R(t,s,"room_label",_.get(e)||""),a=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);o=R(t,s,"group"),a=D.has(e)?"live":M?"absent":"unverified","unverified"===a&&(o.reason="registry_unavailable")}else C.has(t)?(o=R(t,s,"device"),a="live"):P.has(t)?(o=R(t,s,"device"),a=M?"absent":"unverified","unverified"===a&&(o.reason="registry_unavailable")):(o=R(t,s,"unknown","","unknown_owner"),a="unverified");if("absent"!==a){if("live"===a){if(y.liveMissingPositions.push(o),!0===i.removeLiveMissingPositions){delete n[t],y.liveMissingPositionsRemoved++,I(o.kind),y.removedPositions.push(o);continue}}else y.unverifiedPositions.push(o);y.positionsUnresolved++,A.add(s)}else delete n[t],I(o.kind),y.removedPositions.push(o)}return y.deadSpaceIds=[...A].sort((t,e)=>t.localeCompare(e)),{config:s,layout:n,report:y,changed:JSON.stringify(s)!==o||JSON.stringify(n)!==a}}(t,e,i),a=o.config,r=nl(a,o.layout);rl(a),al(o.layout);const l=JSON.stringify(t||{}),c=JSON.stringify(e||{}),h=Number.isInteger(Number(a.model_version))?Number(a.model_version):0,d=(t=>{let e=0,i=0,s=0;for(const i of t.markers||[]){if("ripple"===i.display&&(i.display="icon_ripple",e++),Array.isArray(i.controls)){const t="string"==typeof i.binding&&i.binding.startsWith("entity:")?i.binding.slice(7):"",s=t?i.controls.filter(e=>e!==t):i.controls;JSON.stringify(s)!==JSON.stringify(i.controls)&&(i.controls=s.length?s:null,e++)}const t=i.vacuum;t&&Qm(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const n of t.spaces||[]){const t=n.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,i++);for(const t of n.rooms||[]){const i=t.settings;"glow"===i?.fill_mode&&("boolean"!=typeof i.glow&&(i.glow=!0),delete i.fill_mode,e++,s++)}if(Qm(n,"segments")&&(delete n.segments,e++),Qm(n,"plan_scale")){const t=Number(n.plan_scale);Number.isFinite(t)&&t>=bh&&t<=wh&&(Qm(n,"plan_scale_x")||(n.plan_scale_x=t),Qm(n,"plan_scale_y")||(n.plan_scale_y=t),delete n.plan_scale,e++)}const o=Number(n.cell_cm);Qm(n,"cell_cm")&&(!Number.isFinite(o)||o<.1||o>1e3)&&(n.cell_cm=Number.isFinite(o)&&o>0?tg(o,.1,1e3):5,e++);const a=Number(n.cell_cm),r=Number.isFinite(a)&&a>0?a:5;for(const t of n.wall_columns||[])if("circle"===t.shape)Qm(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Qm(t,"angle")){const i=((Number(t.angle)||0)%90+90)%90;t.angle!==i&&(t.angle=i,e++)}for(const t of n.decor||[]){if(Qm(t,"width")){const i=Number(t.width);(Qm(t,"width_cm")||Number.isFinite(i))&&(Qm(t,"width_cm")||(t.width_cm=Number(tg(i/Dh*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Qm(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Qm(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(tg(es*is(t)/Dh*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Qm(t,"scale")||Qm(t,"size"))&&(delete t.scale,delete t.size,e++);let i=String(t.text??"");const s=[...i.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!Yi(t[1]));if(!(Qm(t,"entity")||Qm(t,"attr")||Qm(t,"unit")))continue;const n=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,a=s||n?"":Ji(t.entity,o);if(s||a){if(a){const e=i.indexOf("{}");i=e>=0?i.slice(0,e)+a+i.slice(e+2):`${i}${i?" ":""}${a}`,t.text=i}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:i,glowRooms:s}})(a);let p=d.total;const u=(_=a.spaces||[],JSON.parse(JSON.stringify(_)));var _;const m=J_(a.spaces||[],o.layout);let g=0,f=0,v=0,y="";const b=m.spaces.map(t=>{const e=function(t){const e=JSON.parse(JSON.stringify(t||{}));let i=Array.isArray(e.rooms)?e.rooms:[];const s=new Map;for(const t of i){const e=hi(t);if(e)for(let t=0;tt.key.localeCompare(e.key))){let e=null;for(const s of $a(t,i)){const t=r.get(_a(s.from));if(t&&t!==_a(s.to))continue;const n=wa(i,s);if(ka(i,n,s)){e=s,i=n;break}}e?(r.set(_a(e.from),_a(e.to)),n++,a=Math.max(a,Math.hypot(e.to[0]-e.from[0],e.to[1]-e.from[1]))):o++}e.rooms=i;for(const t of e.room_drafts||[]){if(!Array.isArray(t?.points)||t.points.length<2)continue;const e=t.points.map(t=>[...t]),i=e.slice(0,-1).flatMap((i,s)=>{const n=e[s+1],o=pa(i,n);return o?[{key:`${String(t.id||"")}:${s}`,a:[...i],b:[...n],axis:o.axis}]:[]});let s=e;for(const t of i){let e=null;for(const i of $a(t,[{poly:s}])){const t=s.map(t=>ba(t,i)),n=t.length>=4&&ma(t[0],t[t.length-1]),o=n?t.slice(0,-1):t;if(n?va(o):ya(o)){e=i,s=t;break}}e?(n++,a=Math.max(a,Math.hypot(e.to[0]-e.from[0],e.to[1]-e.from[1]))):o++}t.points=s}for(const t of e.partitions||[]){if(!Array.isArray(t?.a)||!Array.isArray(t?.b))continue;const i=pa(t.a,t.b);if(!i)continue;const s={key:String(t.id||ga(t.a,t.b)),a:[...t.a],b:[...t.b],axis:i.axis};let r=null;for(const i of $a(s,[{poly:[t.a,t.b]}])){const s=ba(t.a,i),n=ba(t.b,i),o=Math.hypot(n[0]-s[0],n[1]-s[1]);if(!(o>0))continue;const a=(e.openings||[]).filter(e=>"partition"===e?.host?.kind&&e.host.id===t.id).every(t=>{const e=Number(t.host.t),i=Number(t.length);return Number.isFinite(e)&&e>=0&&e<=1&&Number.isFinite(i)&&i>0&&e*o-i/2>=-1e-12&&e*o+i/2<=o+1e-12});if(a){r=i,t.a=s,t.b=n;break}}r?(n++,a=Math.max(a,Math.hypot(r.to[0]-r.from[0],r.to[1]-r.from[1]))):o++}return{space:e,report:{wallsStraightened:n,wallsStraightenSkipped:o,maxStraightenShift:a},changed:n>0}}(t);g+=e.report.wallsStraightened,f+=e.report.wallsStraightenSkipped;const i=Number(t?.cell_cm)>0?Number(t.cell_cm):5,s=e.report.maxStraightenShift/Ph*i;return s>v&&(v=s,y=String(t?.id||"")),e.space}),w=g?J_(b,m.layout):{...m,spaces:b};a.spaces=w.spaces;const k=g?{...m.report,moved:m.report.moved+w.report.moved,coordsCanonicalized:m.report.coordsCanonicalized+w.report.coordsCanonicalized,maxShift:Math.max(m.report.maxShift,w.report.maxShift),maxShiftCm:Math.max(m.report.maxShiftCm,w.report.maxShiftCm),maxSpace:w.report.maxShiftCm>m.report.maxShiftCm?w.report.maxSpace:m.report.maxSpace,rotated:m.report.rotated+w.report.rotated,removedDrafts:m.report.removedDrafts+w.report.removedDrafts}:{...m.report};let x=0,$=0,S=0,M=0,C=0,D=0,P=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),o=eg(e),r=eg(i);if(!o||!r)continue;const l=ng(o.rooms),c=ng(r.rooms),h=.02*Dh,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:wl(t.a,t.b,Ph),cm:0})),p=new Set(d.map(t=>t.key)),_=__(e,o.rooms,vh,h);$+=_.length;for(const t of _){const e=[t[0]/vh,t[1]/vh],i=[t[2]/vh,t[3]/vh],s=wl(e,i,Ph);p.has(s)||(p.add(s),d.push({key:s,a:e,b:i,cm:0}))}const m=d.length,g=Al(d,l,c,Ph,vh),f=(t,e,i)=>{const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;if(!(o>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const a=Math.max(0,Math.min(1,((t[0]-e[0])*s+(t[1]-e[1])*n)/o));return Math.hypot(t[0]-(e[0]+s*a),t[1]-(e[1]+n*a))},v=g.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*vh),i=t.b.map(t=>t*vh);return c.some(([t,s])=>f(e,t,s)<=4*h&&f(i,t,s)<=4*h)});S+=Math.max(0,m-v.length);const y=(i.wall_segments||[]).filter(t=>Number(t.cm)>0);i.wall_segments=[...y,...v.map(({key:t,...e})=>e)];const b=v.map(t=>[t.a[0]*vh,t.a[1]*vh,t.b[0]*vh,t.b[1]*vh]),w=Array.isArray(e.walls)?e.walls.length:0;let k=Al(e.walls,l,c,Ph,vh);k=sg(r.rooms,k,b,Ph,Number(i.cell_cm)>0?Number(i.cell_cm):5,Dh,vh),k=uc(r.rooms,k,b,Ph,Number(i.cell_cm)>0?Number(i.cell_cm):5,Dh,vh),k=Tl(k,i.rooms||[],Ph,1,b.map(t=>[t[0]/vh,t[1]/vh,t[2]/vh,t[3]/vh])),x+=Math.max(0,w-k.length),k.length?i.walls=k:delete i.walls;const R=sm(i.partitions||[],{pitch:Ph,geometry:om(i)});R.merged&&(M+=R.merged,i.partitions=R.partitions,nm(i.openings,i.partitions,R.openingMoves,{coordScale:vh,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,gridPitch:Dh}));const I=eg(i);if(I){const t=n(i,I,i.walls||[],b,{pitch:Ph,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,gridPitch:Dh,coordScale:vh});t.partitionsReconciled&&(C+=t.partitionsReconciled,D+=t.openingsRehosted,t.partitions.length?i.partitions=t.partitions:delete i.partitions,t.openings.length?i.openings=t.openings:delete i.openings,t.walls.length?i.walls=t.walls:delete i.walls),t.removedDrafts&&(P+=t.removedDrafts,t.roomDrafts.length?i.room_drafts=t.roomDrafts:delete i.room_drafts)}JSON.stringify({zero:(i.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:i.walls||[]})!==s&&T++}let R=0;h<=9&&(R=function(t){const e=Jm(t);return Zm(t,e.config),{...e,config:t}}(a).migratedSegments);const I=rl(a),A=al(w.layout),z=JSON.stringify(I)!==l||JSON.stringify(A)!==c;h<9&&z&&(I.model_version=9);const F=JSON.stringify(I)!==l||JSON.stringify(A)!==c,E=Number.isInteger(Number(I.model_version))?Number(I.model_version):h,N=F?k:{...k,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0,removedDrafts:0},O=F?o.report:{...o.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:I,layout:A,report:{...N,modelFrom:h,modelTo:E,migrated:F?p:0,glowSpacesMigrated:F?d.glowSpaces:0,glowRoomsMigrated:F?d.glowRooms:0,canonicalized:F?T:0,wallSegmentsMigrated:F?R:0,legacyZeroWallsMigrated:F?$:0,wallsMerged:F?x:0,spansMerged:F?S:0,partitionsMerged:F?M:0,partitionsReconciled:F?C:0,openingsRehosted:F?D:0,redundantDraftsRemoved:F?P:0,wallsStraightened:F?g:0,wallsStraightenSkipped:f,maxStraightenShiftCm:F?v:0,maxStraightenSpace:F?y:"",latticeCoordinatesCanonicalized:F?r.canonicalized:0,latticeCoordinatesFar:F?r.far:0,latticeMaxShift:F?r.maxShift:0,latticeMaxShiftCm:F?r.maxShiftCm:0,latticeSpaces:F?r.spaces:[],...O},changed:F}}function ag(t,e,i){const s=(t?.spaces||[]).find(t=>t?.id===i),n=new Set((s?.rooms||[]).map(t=>String(t?.id||"")).filter(Boolean)),o=[...new Set((t?.markers||[]).filter(t=>!0!==t?.removed&&"string"==typeof t?.id).filter(t=>t.space===i||"string"==typeof t.room_id&&n.has(t.room_id)||e?.[t.id]?.s===i).map(t=>t.id))].sort((t,e)=>t.localeCompare(e));return{markerIds:o,count:o.length}}function rg(t){return t instanceof Error?t.name||"Error":typeof t}function lg(t){return bd({id:t?.id??"",cell_cm:t?.cell_cm,rooms:t?.rooms||[],walls:t?.walls||[],wall_segments:t?.wall_segments||[],open_spans:t?.open_spans||[],openings:t?.openings||[],partitions:t?.partitions||[],room_drafts:t?.room_drafts||[],wall_columns:t?.wall_columns||[]})}function cg(t,e,i,s=Dh,n=1e3){return(Array.isArray(t?.openings)?t.openings:[]).flatMap(t=>{const o={...t,rx:Number(t.x)*n,ry:Number(t.y)*n,rlen:Number(t.length)*n};if(!t.host||"wall"===t.host.kind)return[o];const a=$p(t,e.partitions,n,i,s);return a.resolved?[{...t,rx:a.resolved.center[0],ry:a.resolved.center[1],rlen:a.resolved.length,angle:a.resolved.angle,partitionHost:a.resolved}]:[]})}function hg(t,e=()=>!0){return t.flatMap(t=>t.host&&t.partitionHost&&e(t)?[Cp(t.partitionHost)]:[])}function dg(t,e,i,s,n,o,a=Dh,r=1e3){const l=dc(e.rooms,[...i],s,n,o,a,r);return t.flatMap(t=>{const e={x:t.rx,y:t.ry,angle:Number(t.angle)||0,length:t.rlen};return t.host&&"wall"!==t.host.kind?t.partitionHost&&Tp(t.partitionHost,l,2e-4*a)?[e]:[]:[e]})}function pg(t,e){const i=Ph,s=Dh,n=vh,o=Number.isFinite(Number(e.cellCm))&&Number(e.cellCm)>0?Number(e.cellCm):5,a=Array.isArray(t?.walls)?t.walls:[],r=function(t,e,i=Dh,s=1e3){return ud(e.rooms,t?.open_spans,s,.02*i)}(t,e,s,n),l=function(t,e,i=Dh){if(!e.length)return[];const s=t.filter(t=>t?.id),n=.02*i,o=[];for(let t=0;t{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return h.some(t=>Ls(e,t)<4*n)}).map(t=>[...t]);d.length&&o.push({a:a,b:r,segs:d})}return o}(e.rooms,r,s).flatMap(t=>t.segs),c=cg(t,e,o,s,n),h=hg(c),d=eh(e,o,s,2e-4*s,h).all;return{space:e,walls:a,openCuts:l,openings:c,roomOpenings:dg(c,e,a,l,i,o,s,n),partitionCuts:h,physicalBodies:d,wallKeyPitch:i,cellCm:o,gridPitch:s,coordScale:n}}function ug(t,e,i){const s="string"==typeof t?.title?t.title.trim():"",n=null==t?.id?"":String(t.id).trim();return{spaceId:n,displayName:s||n||i(e+1)}}function _g(t,e={}){const i=(e.fingerprint||bd)(t),s=Array.isArray(t?.spaces)?t.spaces:[],n=e.fallbackSpaceName||(t=>`Space ${t}`),o=e.prepareSpace||pg,a=e.wallPass||Rc,r=e.floorPass||Pc,l=[];for(let e=0;e0||h.physicalBodies.length>0;if(!h.space.rooms.length&&!d){l.push({...c,status:"not-applicable"});continue}let p=null;if(d){try{p=a(h.space.rooms,h.walls,h.openCuts,h.roomOpenings,h.wallKeyPitch,h.cellCm,h.gridPitch,h.coordScale,h.physicalBodies)}catch(t){l.push({...c,status:"failed",reason:"wall-exception",detail:rg(t)});continue}if(null==p){l.push({...c,status:"failed",reason:"wall-null"});continue}if("degraded-extra"===p.status){l.push({...c,status:"failed",reason:"wall-degraded-extra"});continue}if("failed-core"===p.status){l.push({...c,status:"failed",reason:"wall-failed-core"});continue}}if(h.space.rooms.length&&null==p?.paperGeom){let t;try{t=r(h.space.rooms,h.walls,h.openCuts,h.wallKeyPitch,h.cellCm,h.gridPitch,h.coordScale)}catch(t){l.push({...c,status:"failed",reason:"floor-exception",detail:rg(t)});continue}if(null==t){l.push({...c,status:"failed",reason:"floor-null"});continue}}l.push({...c,status:"ok"})}const c=l.filter(t=>"failed"===t.status);return{fingerprint:i,spaces:l,failures:c,ok:0===c.length}}class mg{constructor(t=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(t))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(t){this._undo.push(t),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const t=this._undo.pop()??null;return t&&this._redo.push(t),t}redo(){const t=this._redo.pop()??null;return t&&this._undo.push(t),t}clear(){this._undo=[],this._redo=[]}}const gg=new WeakMap;const fg=(t,e,i)=>255===t[i+3]&&e.every((e,s)=>Math.abs(t[i+s]-e)<=2);async function vg(t){const e=t.defaultView;if(!e||!e.CSS?.supports?.("mix-blend-mode","screen"))return!1;const i=[128,32,16],s=[16,64,128],n=[9,19,29],o=`\n \n \n \n \n \n `,a=e.URL.createObjectURL(new Blob([o],{type:"image/svg+xml"}));try{const o=await new Promise((t,i)=>{const s=new e.Image,n=e.setTimeout(()=>i(new Error("SVG blend probe timeout")),1e3);s.onload=()=>{e.clearTimeout(n),t(s)},s.onerror=()=>{e.clearTimeout(n),i(new Error("SVG blend probe failed"))},s.src=a}),r=t.createElement("canvas");r.width=4,r.height=1;const l=r.getContext("2d",{willReadFrequently:!0});if(!l)return!1;l.drawImage(o,0,0,4,1);const c=l.getImageData(0,0,4,1).data;return fg(c,i,0)&&fg(c,function(t,e){return[0,1,2].map(i=>Math.round(255-(255-t[i])*(255-e[i])/255))}(i,s),4)&&fg(c,s,8)&&fg(c,n,12)}catch{return!1}finally{e.URL.revokeObjectURL(a)}}const yg={now:()=>performance.now(),requestFrame:t=>requestAnimationFrame(t),cancelFrame:t=>cancelAnimationFrame(t)},bg=t=>Math.max(0,Math.min(1,t)),wg=(t,e,i)=>t+(e-t)*i,kg=(t,e,i)=>{const s=1-t;return 3*s*s*t*e+3*s*t*t*i+t*t*t};function xg(t,e){return{centerX:t.x+t.w/2,centerY:t.y+t.h/2,pixelsPerUnit:e>0&&t.w>0?e/t.w:1,viewBox:{...t}}}function $g(t,e,i){const s=Math.max(1e-9,t.pixelsPerUnit),n=Math.max(1e-9,e/s),o=Math.max(1e-9,i/s);return{x:t.centerX-n/2,y:t.centerY-o/2,w:n,h:o}}function Sg(t){const e=t.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(e);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const s=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(e)?.[1];return s?[parseInt(s.slice(0,2),16),parseInt(s.slice(2,4),16),parseInt(s.slice(4,6),16),8===s.length?parseInt(s.slice(6,8),16)/255:1]:null}function Mg(t,e,i){const s=Sg(t),n=Sg(e);if(!s||!n)return i<.5?t:e;const o=bg(i);return`rgba(${Math.round(wg(s[0],n[0],o))}, ${Math.round(wg(s[1],n[1],o))}, ${Math.round(wg(s[2],n[2],o))}, ${wg(s[3],n[3],o).toFixed(3)})`}function Cg(t,e,i){const s=(t=>{const e=bg(t);if(0===e||1===e)return e;let i=0,s=1,n=e;for(let t=0;t<12;t++)n=(i+s)/2,kg(n,.2,.2){const e=this._state;if(!e||e.token!==n)return;const i=bg((t-e.startedAt)/e.duration);e.presented=i>=1?e.to:Cg(e.from,e.to,i),e.phase=i>=1?"settling":"running",this._hooks.frame(e),i<1?this._raf=this._clock.requestFrame(a):(this._raf=0,this._hooks.settled(e),this._state?.token===n&&(this._state=null))};return this._raf=this._clock.requestFrame(a),n}cancel(t=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const e=this._state;this._state=null,this._token++,e&&t&&(e.phase="settling",e.presented=e.to,this._hooks.frame(e),this._hooks.settled(e))}dispose(){this.cancel(!1)}}const Pg="houseplan_card_labs_v1",Tg=Object.freeze([Object.freeze({id:"iso",issue:89,since:"1.62.0",expires:"1.65.0",summary:"Volumetric plan renderer"})]);function Rg(t){const e=/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/.exec(String(t||"").trim());if(!e)return null;const i=e.slice(1).map(Number);return i.every(t=>Number.isSafeInteger(t))?i:null}function Ig(t,e){for(let i=0;i<3;i++)if(t[i]!==e[i])return t[i]t.split(",")).map(t=>t.trim()).filter(Boolean)}function Og(t,e,i,s=Tg){const n=function(t,e=Tg){const i=Rg(t),s=new Map;if(!i||!zg(e))return s;for(const t of e){const e=Rg(t.since),n=Rg(t.expires);Ig(i,e)>=0&&Ig(i,n)<0&&s.set(t.id,t)}return s}(i,s),o=new Set(zg(s)?s.map(t=>t.id):[]),a=new Set(function(t){if(!t)return[];try{const e=JSON.parse(t);return Array.isArray(e)?e.filter(t=>"string"==typeof t):[]}catch{return[]}}(e).filter(t=>n.has(t)));let r=!1;const l=t=>{if("off"===t)return a.clear(),void(r=!0);const e=t.startsWith("-"),i=e?t.slice(1):t;o.has(i)&&(r=!0,e||!n.has(i)?a.delete(i):a.add(i))};for(const e of Ng(new URLSearchParams(String(t.search||"").replace(/^\?/,""))))l(e);for(const e of Ng(Fg(t.hash)))l(e);const c=Object.freeze([...a].sort());return{active:c,space:Eg(t.hash),persist:r?JSON.stringify(c):void 0,knownUrlOperation:r}}let Lg={active:Object.freeze([]),space:""},Hg="",Bg=!1,qg="";const Wg=new Set;function jg(){if("undefined"==typeof window)return Lg;const t=Og(window.location,function(){try{return window.localStorage.getItem(Pg)}catch{return null}}(),Hg);void 0!==t.persist&&function(t){try{window.localStorage.setItem(Pg,t)}catch{}}(t.persist),Lg={active:t.active,space:t.space},window.__hpLabs=t.active;for(const t of Wg)t(Lg);return Lg}function Ug(){jg()}function Gg(t){return Hg=t,"undefined"==typeof window?Lg:(Bg||(Bg=!0,window.addEventListener("hashchange",Ug),window.addEventListener("popstate",Ug)),jg())}const Vg=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])});function Kg(t){return[t.rotDeg,t.tiltDeg,t.xyScale,t.zScale,t.origin[0],t.origin[1]].every(Number.isFinite)&&Math.abs(t.xyScale)>1e-12&&Math.abs(Math.cos(t.tiltDeg*Math.PI/180))>1e-12}function Yg(t,e,i=Vg){if(!(Kg(i)&&Number.isFinite(t[0])&&Number.isFinite(t[1])&&Number.isFinite(e)))throw new Error("invalid isometric projection input");const s=i.rotDeg*Math.PI/180,n=i.tiltDeg*Math.PI/180,o=t[0]-i.origin[0],a=t[1]-i.origin[1],r=(o*Math.cos(s)-a*Math.sin(s))*i.xyScale,l=(o*Math.sin(s)+a*Math.cos(s))*i.xyScale;return[i.origin[0]+r,i.origin[1]+l*Math.cos(n)-e*i.zScale*Math.sin(n)]}function Jg(t,e=Vg){if(!Kg(e)||!Number.isFinite(t[0])||!Number.isFinite(t[1]))throw new Error("invalid isometric projection input");const i=e.rotDeg*Math.PI/180,s=e.tiltDeg*Math.PI/180,n=(t[0]-e.origin[0])/e.xyScale,o=(t[1]-e.origin[1])/(e.xyScale*Math.cos(s));return[e.origin[0]+n*Math.cos(i)+o*Math.sin(i),e.origin[1]-n*Math.sin(i)+o*Math.cos(i)]}function Xg(t=Vg){return`matrix(${function(t=Vg){if(!Kg(t))throw new Error("invalid isometric camera");const e=t.rotDeg*Math.PI/180,i=t.tiltDeg*Math.PI/180,s=t.xyScale*Math.cos(e),n=-t.xyScale*Math.sin(e),o=t.xyScale*Math.sin(e)*Math.cos(i),a=t.xyScale*Math.cos(e)*Math.cos(i);return[s,o,n,a,t.origin[0]-s*t.origin[0]-n*t.origin[1],t.origin[1]-o*t.origin[0]-a*t.origin[1]]}(t).map(t=>Number(t.toFixed(12))).join(" ")})`}function Zg(t,e=Vg){const{rect:i,wallHeight:s}=t,n=t.openingHeight??s,o=t.floorDepth??0;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(s)||!Number.isFinite(n)||!Number.isFinite(o)||s<0||n<0||o<0)throw new Error("invalid isometric frame");const a=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],r=Math.max(s,n),l=a.flatMap(t=>[Yg(t,-o,e),Yg(t,r,e)]),c=l.map(t=>t[0]),h=l.map(t=>t[1]),d=Math.min(...c),p=Math.min(...h);return{x:d,y:p,w:Math.max(...c)-d,h:Math.max(...h)-p}}const Qg=t=>`${Number(t[0].toFixed(4))} ${Number(t[1].toFixed(4))}`;function tf(t){let e=0;for(let i=0;iArray.isArray(t)&&Number.isFinite(t[0])&&Number.isFinite(t[1])).map(t=>[Number(t[0]),Number(t[1])]),i=e[e.length-1];return e.length>1&&e[0][0]===i[0]&&e[0][1]===i[1]&&e.pop(),e}(t);if(i.length<3)return[];const s=!e;return tf(i)>0===s?i:[...i].reverse()}function sf(t,e,i){return t.length?`M ${t.map(t=>Qg(Yg(t,i,e))).join(" L ")} Z`:""}function nf(t,e,i){const s=e[1]-t[1],n=-(e[0]-t[0]),o=i.rotDeg*Math.PI/180;return s*Math.sin(o)+n*Math.cos(o)}function of(t,e,i=Vg){if(!Number.isFinite(e)||e<0)throw new Error("invalid floor edge height");const s=(t||[]).map(t=>(t||[]).map((t,e)=>function(t,e){const i=ef(t,e);if(!i.length)return i;let s=0;for(let t=1;t0)).filter(t=>t.length>=3&&Math.abs(tf(t))>=1e-9)).filter(t=>t.length&&tf(t[0])>0);s.sort((t,e)=>{const i=t[0][0],s=e[0][0];return i[0]-s[0]||i[1]-s[1]||Math.abs(tf(e[0]))-Math.abs(tf(t[0]))});const n=[],o=[];let a=0;for(let t=0;tt.depth-e.depth||t.component-e.component||t.edge-e.edge),{footprintPath:n.join(" "),sides:o,componentCount:s.length,edgeCount:a}}function af(t,e){return t^=Math.round(64*(Number.isFinite(e)?e:0)),Math.imul(t,16777619)>>>0}const rf=t=>t.every(Number.isFinite);function lf(t,e,i,s){const n=t[0]*i,o=t[1]*s,a=e*Math.PI/180;return[n*Math.cos(a)-o*Math.sin(a),n*Math.sin(a)+o*Math.cos(a)]}function cf(t,e,i,s,n,o,a){const r=t.flipH?-1:1,l="gate"===t.type?1:t.flipV?-1:1,c=(t.type,t.flipV,t.angle,t.face,{ox:0,oy:0}),h=function(t,e){return[t[0]+e[0],t[1]+e[1]]}([t.x+c.ox,t.y+c.oy],lf(i,t.angle,r,l));return{leaf:e,hinge:h,closedVector:lf(s,t.angle,r,l),quarterVector:lf([-s[1],s[0]],t.angle,r,l),turnDeg:n,bottom:o,top:a}}const hf=t=>`${Number(t[0].toFixed(4))} ${Number(t[1].toFixed(4))}`;function df(t,e,i=Vg){const s=Math.max(0,Math.min(1,Number.isFinite(e)?e:0));return t.leaves.map(e=>{const n=function(t,e){const i=t.turnDeg*e*Math.PI/180;return[t.hinge[0]+t.closedVector[0]*Math.cos(i)+t.quarterVector[0]*Math.sin(i),t.hinge[1]+t.closedVector[1]*Math.cos(i)+t.quarterVector[1]*Math.sin(i)]}(e,s),o=Yg(e.hinge,e.bottom,i),a=Yg(n,e.bottom,i),r=Yg(n,e.top,i),l=Yg(e.hinge,e.top,i);return{id:t.id,sourceIndex:t.sourceIndex,type:t.type,leaf:e.leaf,d:`M ${hf(o)} L ${hf(a)} L ${hf(r)} L ${hf(l)} Z`,shadowD:`M ${hf(Yg(e.hinge,0,i))} L ${hf(Yg(n,0,i))}`,depth:Math.max(o[1],a[1])}})}const pf={window:120,door:90,passage:90,gate:300};function uf(t){return pf[t]}function _f(t,e){const i=[t[0],t[1]],s=[e[0],e[1]];return function(t,e){return t[0]-e[0]||t[1]-e[1]}(i,s)<=0?{a:i,b:s}:{a:s,b:i}}function mf(t){const e=new Map;return t.forEach((t,i)=>{if(!t.kind||t.open)return;const s=_f(t.a,t.b);if(Math.hypot(s.b[0]-s.a[0],s.b[1]-s.a[1])<=1e-9)return;const n=function(t,e){const i=t=>(Math.abs(t)<=5e-10?0:Math.round(1e6*t)/1e6).toFixed(6);return`${i(t[0])},${i(t[1])}>${i(e[0])},${i(e[1])}`}(s.a,s.b),o=e.get(n);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,t.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(t.partitionHost&&(o.partitionHost&&o.partitionHost.id!==t.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=t.partitionHost));e.set(n,{segmentKey:n,a:s.a,b:s.b,physicalHalfWidth:Math.max(0,t.half||0),sourceOrder:i,...t.partitionHost?{partitionHost:t.partitionHost}:{}})}),[...e.values()]}function gf(t,e){if(Math.abs(t.distance-e.distance)>1e-9)return t.distance-e.distance;if(Math.abs(t.perpendicular-e.perpendicular)>1e-9)return t.perpendicular-e.perpendicular;return(t.target.segmentKeye.target.segmentKey?1:0)||t.target.sourceOrder-e.target.sourceOrder}function ff(t){const e=mf(t.intervals).map(e=>{const i=function(t,e){const i=e.b[0]-e.a[0],s=e.b[1]-e.a[1],n=Math.hypot(i,s),o=i/n,a=s/n,r=(t[0]-e.a[0])*o+(t[1]-e.a[1])*a,l=Math.max(0,Math.min(n,r)),c=e.a[0]+l*o,h=e.a[1]+l*a;return{along:l,length:n,x:c,y:h,distance:Math.hypot(t[0]-c,t[1]-h),perpendicular:Math.abs((t[0]-e.a[0])*a-(t[1]-e.a[1])*o)}}(t.pointer,e);return{target:e,...i,envelope:Math.max(t.baseTolerance,e.physicalHalfWidth+t.bodyPointerPadding)}}).filter(t=>t.distance<=t.envelope+1e-9).filter(e=>!function(t,e,i,s,n){const o=e.b[0]-e.a[0],a=e.b[1]-e.a[1],r=Math.hypot(o,a);if(!(r>1e-9))return!1;const l=o/r,c=a/r;for(const o of i){if(!o.open&&o.kind)continue;const i=_f(o.a,o.b),a=i.b[0]-i.a[0],r=i.b[1]-i.a[1],h=Math.hypot(a,r);if(!(h>1e-9))continue;const d=a/h,p=r/h;if(Math.abs(l*p-c*d)>1e-6)continue;if(Math.abs((i.a[0]-e.a[0])*c-(i.a[1]-e.a[1])*l)>n)continue;const u=(t[0]-i.a[0])*d+(t[1]-i.a[1])*p,_=1e-9;if(!(u<=_||u>=h-_)&&Math.abs((t[0]-i.a[0])*p-(t[1]-i.a[1])*d)<=s+1e-9)return!0}return!1}(t.pointer,e.target,t.intervals,e.envelope,Math.max(1e-9,Math.min(t.baseTolerance,.04*t.gridStep)))),i=e.filter(e=>!!e.target.partitionHost&&t.renderedLength+2*e.target.physicalHalfWidth>e.length+1e-9).sort(gf),s=e.filter(e=>!e.target.partitionHost||t.renderedLength+2*e.target.physicalHalfWidth<=e.length+1e-9).sort(gf);let n=s[0];if(!n)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=s.filter(t=>Math.abs(t.distance-n.distance)<=1e-9&&Math.abs(t.perpendicular-n.perpendicular)<=1e-9),a=o.filter(t=>t.target.partitionHost);if(a.length){if(1!==new Set(a.map(t=>t.target.partitionHost.id)).size||a.some(t=>t.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const t=a[0],e=t.target.b[0]-t.target.a[0],i=t.target.b[1]-t.target.a[1],s=Math.hypot(e,i),r=e/s,l=i/s,c=o.every(e=>{const i=e.target.b[0]-e.target.a[0],s=e.target.b[1]-e.target.a[1],n=Math.hypot(i,s),o=i/n,a=s/n,c=Math.abs(r*a-l*o)<=1e-6,h=Math.abs((e.target.a[0]-t.target.a[0])*l-(e.target.a[1]-t.target.a[1])*r);return c&&h<=1e-9});if(!c)return{candidate:null,jambBlockedTarget:null};n=t}if(n.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:r,length:l}=n,c=r.b[0]-r.a[0],h=r.b[1]-r.a[1],d=c/l,p=h/l,u=r.partitionHost?r.physicalHalfWidth:0,_=Math.min(Math.max(0,t.renderedLength)/2+u,l/2);let m=n.along;const g=Math.max(t.gridStep,1e-9),f=l/2;m=Math.abs(m-f)<=g/2?f:Math.round(m/g)*g,m=Math.max(_,Math.min(l-_,m));const v=r.a[0]+d*m,y=r.a[1]+p*m,b=Math.max(0,t.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),$=Math.max(0,l-k),S=[r.a[0]+d*(w-x/2),r.a[1]+p*(w-x/2)],M=[r.a[0]+d*(k+$/2),r.a[1]+p*(k+$/2)];let C=180*Math.atan2(h,c)/Math.PI;C>=90?C-=180:C<-90&&(C+=180);const D=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:t.preset.revision,geometryRevision:t.geometryRevision,pointer:[t.pointer[0],t.pointer[1]],type:t.preset.type,lengthCm:t.preset.lengthCm,flipH:t.preset.flipH,flipV:t.preset.flipV,x:v,y:y,angle:C,renderedLength:t.renderedLength,target:r,...r.partitionHost?{host:{...r.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:S},{distance:$,midpoint:M}],guide:D?{x:v,y:y,angle:C}:null}},jambBlockedTarget:null}}function vf(t,e,i,s,n=1e-6){return t.presetRevision===i&&t.geometryRevision===s&&Math.hypot(t.pointer[0]-e[0],t.pointer[1]-e[1])<=n}const yf=(t,e)=>t[0]*e[1]-t[1]*e[0],bf=(t,e)=>t[0]*e[0]+t[1]*e[1],wf=(t,e)=>[t[0]-e[0],t[1]-e[1]],kf=(t,e,i)=>[t[0]+e[0]*i,t[1]+e[1]*i];function xf(t,e,i){return Math.abs(yf(t,e))<=i}function $f(t,e,i){return Math.abs(yf(wf(t,e),i))}function Sf(t,e,i,s,n){const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(!(r>n&&i>0))return[];const l=[o/r,a/r];return function(t,e,i){const s=e.map(([e,i])=>[Math.max(0,Math.min(e,i)),Math.min(t,Math.max(e,i))]).filter(([t,e])=>e>t+i).sort((t,e)=>t[0]-e[0]||t[1]-e[1]),n=[];for(const t of s){const e=n[n.length-1];!e||t[0]>e[1]+i?n.push([...t]):e[1]=Math.max(e[1],t[1])}const o=[];let a=0;for(const[t,e]of n)t>a+i&&o.push([a,t]),a=Math.max(a,e);return t>a+i&&o.push([a,t]),o}(r,s.flatMap(e=>{const s=e.b[0]-e.a[0],o=e.b[1]-e.a[1],a=Math.hypot(s,o);if(!(a>n&&xf(l,[s/a,o/a],1e-6)))return[];if($f(e.a,t,l)>1.1*Math.max(i,n)||$f(e.b,t,l)>1.1*Math.max(i,n))return[];return[[bf(wf(e.a,t),l),bf(wf(e.b,t),l)]]}),n).flatMap(([e,s])=>{const n=Ol({a:kf(t,l,e),b:kf(t,l,s),halfDepth:i});return n?[n]:[]})}function Mf(t){const e=t.coordScale??1,i=Math.max(t.epsilon??2e-4*t.gridPitch,1e-9),s=[];for(const i of t.rooms||[]){if(!i?.id)continue;const n=hc(t.rooms,i.id,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e);if(!n||n.poly.length<3)continue;const o=Zl(n.poly,n.offsets);!o||o.length<3||s.push({roomId:i.id,profile:n,inner:o})}s.sort((t,e)=>t.roomId.localeCompare(e.roomId));const n=(t.roomOpenings||[]).map(t=>{const e=t.angle*Math.PI/180,i=[Math.cos(e),Math.sin(e)],s=Math.max(0,t.length)/2;return{a:kf([t.x,t.y],i,-s),b:kf([t.x,t.y],i,s)}}),o=[];for(const s of Ac(t.rooms,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e))for(const t of Sf(s.a,s.b,s.depthUnits/2,n,i))o.push({body:t});const a=new Map;for(const e of t.partitionCuts||[]){const t=a.get(e.hostId)||[];t.push(e),a.set(e.hostId,t)}for(const e of t.partitions||[]){const s=gl(e.cm,t.cellCm,t.gridPitch)/2;for(const t of Sf(e.a,e.b,s,a.get(e.id)||[],i))o.push({body:t,partitionId:e.id})}return{rooms:s,boundaries:o,epsilon:i}}function Cf(t,e,i,s){const n=t.profile.offsets[e];if(!(n>0))return null;const o=function(t,e){const i=t[e],s=t[(e+1)%t.length],n=s[0]-i[0],o=s[1]-i[1],a=Math.hypot(n,o)||1;return function(t){let e=0;for(let i=0;i=0?[-o/a,n/a]:[o/a,-n/a]}(t.profile.poly,e),a=kf(i.center,o,n),r=[];for(let e=0;es&&xf(i.axis,[l[0]/c,l[1]/c],1e-6)))continue;if($f(n,a,i.axis)>s||$f(o,a,i.axis)>s)continue;const h=bf(wf(n,a),i.axis),d=bf(wf(o,a),i.axis);r.push([Math.min(h,d),Math.max(h,d)])}const l=function(t,e){t.sort((t,e)=>t[0]-e[0]||t[1]-e[1]);const i=[];for(const s of t){const t=i[i.length-1];!t||s[0]>t[1]+e?i.push([...s]):t[1]=Math.max(t[1],s[1])}return i}(r,s).find(([t,e])=>t<=s&&e>=-s);if(!l)return null;const[c,h]=l,d=kf(a,i.axis,-i.half),p=kf(a,i.axis,i.half),u=Math.max(0,-i.half-c),_=Math.max(0,h-i.half),m=u>0?kf(a,i.axis,c):d,g=_>0?kf(a,i.axis,h):p,f=bf(o,i.normal)>=0?1:-1,v=(e,s,n)=>({from:e,to:s,label:[(e[0]+s[0])/2,(e[1]+s[1])/2],axis:i.axis,labelNormal:o,distance:n,roomId:t.roomId,roomSide:f,source:"room-face"});return{left:v(d,m,u),right:v(p,g,_)}}function Df(t){const e=kf(t.center,t.axis,-t.half),i=kf(t.center,t.axis,t.half),s=kf(t.center,t.axis,Math.min(-t.half,t.targetLo)),n=kf(t.center,t.axis,Math.max(t.half,t.targetHi)),o=(e,i)=>({from:e,to:i,label:[(e[0]+i[0])/2,(e[1]+i[1])/2],axis:t.axis,labelNormal:t.normal,distance:Math.hypot(i[0]-e[0],i[1]-e[1]),source:"host-end"});return[o(e,s),o(i,n)]}function Pf(t,e,i,s){const n=wf(i,e),o=bf(n,n);if(!(o>s*s))return Math.hypot(...wf(t,e))<=s;const a=bf(wf(t,e),n)/o;if(a<-s||a>1+s)return!1;const r=kf(e,n,Math.max(0,Math.min(1,a)));return Math.hypot(...wf(t,r))<=s}function Tf(t,e,i){let s=!1;for(let n=0,o=e.length-1;nt[1]!=c>t[1]&&t[0]<(l-a)*(t[1]-r)/(c-r)+a&&(s=!s)}return s}function Rf(t,e,i,s,n,o){const a=wf(s,i),r=yf(e,a);if(Math.abs(r)<=o)return null;const l=wf(i,t),c=yf(l,a)/r,h=yf(l,e)/r;return c<-o||c>n+o||h<-o||h>1+o?null:Math.max(0,Math.min(n,c))}function If(t,e,i){const s=Df(i),n="partition"===t.host?.kind?t.host.id:void 0;return[{base:s[0],direction:[-i.axis[0],-i.axis[1]]},{base:s[1],direction:i.axis}].map(({base:t,direction:i})=>{const s=t.distance,o=function(t,e,i,s,n,o){let a=null;for(const r of s)if(!n||r.partitionId!==n){if(Tf(t,r.body,o))return 0;for(let s=0;sbf(wf(t,n),i));return{center:n,axis:i,normal:s,half:Math.max(0,t.renderedLength)/2,targetLo:Math.min(...o),targetHi:Math.max(...o)}}(t),s=e.rooms.flatMap(t=>{const s=function(t,e,i){const{profile:s}=t;let n=null;for(let t=0;t0))continue;const o=s.poly[t],a=s.poly[(t+1)%s.poly.length],r=wf(a,o),l=Math.hypot(r[0],r[1]);if(!(l>i&&xf(e.axis,[r[0]/l,r[1]/l],1e-6)))continue;if($f(o,e.center,e.axis)>i||$f(a,e.center,e.axis)>i)continue;const c=bf(wf(o,e.center),e.axis),h=bf(wf(a,e.center),e.axis),d=Math.min(c,h),p=Math.max(c,h);if(d>-e.half+i||p0?d:p<0?-p:0);(!n||u2)return Df(i);if(s.length){const t=s.map(({room:t,edge:s})=>Cf(t,s,i,e.epsilon));if(t.some(t=>!t))return Df(i);const n=t;return[...n.map(t=>t.left),...n.map(t=>t.right)]}return If(t,e,i)}function zf(t){return!(!t.canEdit||t.kiosk||t.fixedFloor)&&("view"!==t.mode&&("mouse"===t.pointerType&&t.spaceCount>1))}const Ff="1.68.0-beta.3",Ef={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon"},Nf={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon"},Of=2e3,Lf=1e3,Hf=1500,Bf=t=>{const e=String(t??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e))return null;const i=Number(e);return Number.isFinite(i)?i:null},qf=(t,e)=>{if(!t.has(e))return{hit:!1};const i=t.get(e);return t.delete(e),t.set(e,i),{hit:!0,value:i}},Wf=(t,e,i,s)=>{for(t.delete(e),t.set(e,i);t.size>s;){const e=t.keys().next().value;if(void 0===e)break;t.delete(e)}},jf=new Map;let Uf=0;const Gf=t=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(t??{})}`;let Vf=1e4;const Kf="houseplan_card_layout_v1",Yf="houseplan_card_cfg_v1",Jf="houseplan_card_zoom_v1",Xf="houseplan_card_nav_v1",Zf="houseplan_card_kiosk_v1",Qf="houseplan_card_view_v1",tv="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",ev=1e3,iv=[[0,1],[45,.88],[70,.62],[86,.32],[100,0]],sv=(t,e)=>{const i=Math.min(t.x,e.x),s=Math.min(t.y,e.y);return{x:i,y:s,w:Math.max(t.x+t.w,e.x+e.w)-i,h:Math.max(t.y+t.h,e.y+e.h)-s}},nv=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),ov=2e3,av=(t,e,i)=>{const s=new Event(e,{bubbles:!0,composed:!0});s.detail=i??{},t.dispatchEvent(s)},rv=t=>{history.pushState(null,"",t),av(window,"location-changed",{replace:!1})},lv=(t,e)=>{let i,s=null;const n=(...n)=>{clearTimeout(i),s=n,i=window.setTimeout(()=>{i=void 0;const e=s;s=null,e&&t(...e)},e)};return n.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const e=s;s=null,e&&t(...e)},n.cancel=()=>{clearTimeout(i),i=void 0,s=null},n.pending=()=>void 0!==i,n},cv=t=>{try{t.target?.setPointerCapture?.(t.pointerId)}catch{}};class hv extends ht{constructor(){super(...arguments),this._space="f1",this._layout={},this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._serverCfg=null,this._cfgRev=0,this._cfgContentFingerprint="",this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._layoutRev=0,this._layoutContentFingerprint="",this._virtualLights=mn(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._tip=null,this._hoverRoom=null,this._pointerModality=new E_(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...Rr},this._decorDraft=null,this._decorMove=null,this._decorSel=null,this._decorEraseConfirm=null,this._decorTextDialog=null,this._decorShapeDialog=null,this._backdropDialog=null,this._decorTextSelection={start:0,end:0},this._furnPalette=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=t=>{this._reducedMotion=t.matches,this._cancelDevicePressFeedback(),t.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:t.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new Dg({frame:t=>this._applyModeTransitionFrame(t),settled:t=>this._settleModeTransition(t)}),this._editorSecondary=new q_({root:()=>this.renderRoot,requestUpdate:()=>this.requestUpdate(),updateComplete:()=>this.updateComplete,clearTip:()=>{this._tip=null}}),this._editorSecondaryCopy={groupActive:(t,e)=>this._t("editor.group_active",{group:t,item:e}),openGroup:t=>this._t("editor.open_group",{group:t}),disabledAction:(t,e)=>this._t("editor.disabled_action",{action:t,reason:e})},this._tool="draw",this._geometryHistory=new mg(50),this._wallDialog=null,this._drawWallField=null,this._activeDraftId=null,this._resumeDraftBySpace={},this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCache=null,this._isoGeometryCache=new Map,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._glowClipCache=new Map,this._glowGeometryWarnings=new Set,this._lightBarrierCache=null,this._glowFeatherUnits=null,this._glowRenderedSources=new Map,this._glowLastAppearance=new Map,this._glowEnteringSources=new Set,this._glowEnterRafs=new Map,this._glowFadeTimers=new Map,this._glowFeatherSuspendUntil=0,this._glowFeatherResumeTimer=0,this._glowSourceSeq=0,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszSel=null,this._rszDrag=null,this._rszEligibilityCache=null,this._rszPreview=null,this._rszLive=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._suppressClick=!1,this._touchContacts=new Map,this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:t=>this._guardTouchGesture(t)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._alignDialog=null,this._settingsDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=t=>this._onKey(t),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++Uf,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=t=>{if(this._continuity.visibility(t),this._dayCycleVisibility(t),"hidden"===t.kind)return this._clearTransientHover(!0),this._cancelDevicePressFeedback(),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,!t.long){const t=Date.now();let e=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+R_)>t||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,e=!0);return void(e&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._lastTap=0,this._onLabsSnapshot=t=>{const e=this._effectiveProjection();this._labs=t;const i=this._effectiveProjection();this._convertProjectionView(e,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const t=this._hashSpace();if(t&&this._model.find(e=>e.id===t)&&t!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(t),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._onHaRegistryUpdate=()=>{const t=An(this.hass);t.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=t.revision,this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,function(t){const e=Cn(t);e&&(Tn(t,e),Rn(t,e))}(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new xd(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=lv(()=>{if(this._serverStorage){const t=[...this._dirtyPos];this._dirtyPos.clear();for(const e of t){const t=ol(this._layout[e]);t&&(this._layout={...this._layout,[e]:t},this._sentPos.set(e,t),this.hass.callWS({type:"houseplan/layout/update",device_id:e,pos:t}).then(t=>this._noteLayoutRev(t)).catch(t=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))).finally(()=>{this._sentPos.get(e)===t&&this._sentPos.delete(e)}))}this._cacheSnapshot()}else this._layout=al(Gr(this._layout)),localStorage.setItem(Kf,JSON.stringify(this._layout))},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>{if(this._physicalDrag||this._physicalRotate)return void this._cancelPhysicalGesture();if(this._decorDraft)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove||this._dtDrag||this._bdDrag)return void this._cancelDecorGesture();if(this._rszDrag)return void this._rszCancelDrag();const t=this._geometryHistory.undo();t&&(this._applyGeometryState(t.before,!0)?this._showToast(this._t("history.undone",{name:t.name})):this._geometryHistory.clear())},this._redoGeometry=()=>{if(this._physicalDrag||this._physicalRotate)return void this._cancelPhysicalGesture();if(this._decorDraft)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove||this._dtDrag||this._bdDrag)return void this._cancelDecorGesture();if(this._rszDrag)return void this._rszCancelDrag();const t=this._geometryHistory.redo();t&&(this._applyGeometryState(t.after,!0)?this._showToast(this._t("history.redone",{name:t.name})):this._geometryHistory.clear())},this._saveConfigDebounced=lv(()=>{this._serverCfg&&this._writeConfig().catch(t=>{const e=!0===t?.physicalGeometryRolledBack;"geometry-unsafe"!==t?.code&&("wall_model_client_outdated"===t?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===t?.code?(this._showToast(this._t("toast.conflict")),e||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(t)})),e&&this._reloadRejectedPhysicalWrite())})},500),this._draftSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>{const t=this._physicalDialog,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=Bf(t.cm);if(null==s)return void this._showPhysicalRange("column"===t.kind?Wc:100,"column"===t.kind?1:0);const n=this._imperial?2.54*s:s,o="column"===t.kind?Wc:100,a="column"===t.kind?1:0;if(!Number.isFinite(n)||no)return void this._showPhysicalRange(o,a);if("column"===t.kind){const e=i.wall_columns.find(e=>e.id===t.id);if(!e)return;const s=Bf(t.angle||"0");if("circle"!==t.shape&&(null==s||s<0||s>=90))return void this._showToast(this._t("toast.physical_angle"));const o="circle"===t.shape?{id:t.id,shape:"circle",center:e.center,cm:n}:{id:t.id,shape:"square",center:e.center,cm:n,angle:s};if(i.wall_columns.some(e=>e.id!==t.id&&ph(e,o,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"))}const r=this._geometrySnapshot();if("partition"===t.kind){const i=(e.partitions||[]).find(e=>e.id===t.id);if(i&&0===n&&g_(e.openings,{kind:"partition",id:t.id}))return void this._showToast(this._t("toast.zero_wall_opening_conflict"));i&&(i.cm=n)}else if("column"===t.kind){const i=(e.wall_columns||[]).find(e=>e.id===t.id);i&&(i.cm=Uc(n),i.shape="circle"===t.shape?"circle":"square","square"===i.shape?i.angle=Bf(t.angle||"0"):delete i.angle)}else{const i=(e.room_drafts||[]).find(e=>e.id===t.id);i?.segments?.[t.segment||0]&&(i.segments[t.segment||0].cm=n)}const l=this._commitPhysicalGeometry(this._t("history.physical_edit"),r);this._physicalDialog=null,l||this.requestUpdate()},this._deletePhysicalSelection=()=>{const t=this._physicalSel,e=this._curSpaceCfg;if(!t||!e)return;if("draft"===t.kind)return void this._deleteDraftWhole();const i=this._geometrySnapshot();if("partition"===t.kind){const i=(e.openings||[]).filter(e=>"partition"===e.host?.kind&&e.host.id===t.id).sort((t,e)=>(t.host?.t||0)-(e.host?.t||0));if(i.length)return void(this._partitionDeleteDialog={id:t.id,openings:i.map(t=>JSON.parse(JSON.stringify(t)))})}const s="partition"===t.kind?"partitions":"column"===t.kind?"wall_columns":"room_drafts";e[s]=(e[s]||[]).filter(e=>e.id!==t.id),e[s].length||delete e[s],this._activeDraftId===t.id&&this._cancelPath(),this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._confirmPartitionDelete=()=>{const t=this._partitionDeleteDialog,e=this._curSpaceCfg;if(!t||!e)return;const i=this._geometrySnapshot();e.partitions=(e.partitions||[]).filter(e=>e.id!==t.id),e.partitions.length||delete e.partitions,e.openings=(e.openings||[]).filter(e=>"partition"!==e.host?.kind||e.host.id!==t.id),e.openings.length||delete e.openings,this._partitionDeleteDialog=null,this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._deleteDraftWhole=()=>{const t="draft"===this._physicalDialog?.kind?this._physicalDialog.id:"draft"===this._physicalSel?.kind?this._physicalSel.id:null,e=this._curSpaceCfg;if(!t||!e||!confirm(this._t("confirm.delete_draft")))return;const i=this._geometrySnapshot();e.room_drafts=(e.room_drafts||[]).filter(e=>e.id!==t),e.room_drafts.length||delete e.room_drafts,this._activeDraftId===t&&this._cancelPath(),this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._deleteDraftSegment=()=>{const t=this._physicalDialog,e=this._curSpaceCfg;if(!t||"draft"!==t.kind||!e)return;if(!confirm(this._t("confirm.delete_draft_segment")))return;const i=(e.room_drafts||[]).findIndex(e=>e.id===t.id);if(i<0)return;const s=e.room_drafts[i],n=Math.max(0,Math.min(s.segments.length-1,t.segment||0)),o=[],a=s.points.slice(0,n+1),r=s.points.slice(n+1);if(a.length>=2&&o.push({id:s.id,points:a,segments:s.segments.slice(0,n)}),r.length>=2&&o.push({id:o.length?`${s.id}-${Date.now().toString(36)}`:s.id,points:r,segments:s.segments.slice(n+1)}),2===o.length&&e.room_drafts.length>=200)return void this._showToast(this._t("toast.physical_limit"));const l=this._geometrySnapshot();e.room_drafts.splice(i,1,...o),e.room_drafts.length||delete e.room_drafts,this._activeDraftId===s.id&&this._cancelPath(),this._physicalDialog=null,this._physicalSel=o.length?{kind:"draft",id:o[0].id}:null,this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),l)},this._confirmRoomDelete=t=>{const e=this._roomDeleteDialog,i=this._curSpaceCfg,s=this._spaceModel();if(!e||!i||!s)return;const n=s.rooms.find(t=>t.id===e.roomId);if(!n)return void(this._roomDeleteDialog=null);const o=this._openCuts(),a=xu(dc(s.rooms,this._spaceWalls,o,this._wallKeyPitch,this._cellCm,this._gridPitch,ev).filter(t=>t.roomId===n.id),s.partitions,this._openingsR.map(t=>({...t,x:t.rx,y:t.ry})),.02*this._gridPitch),r=new Set(a.materialize.filter(t=>!t.reusePartitionId).map(t=>t.interval.key)).size;if(t&&(i.partitions||[]).length+r>ov)return void this._showToast(this._t("toast.physical_limit"));const l=this._geometrySnapshot(),c=pc(s.rooms,this._spaceWalls,o,this._wallKeyPitch,this._cellCm,this._gridPitch,ev);if(t){i.partitions||=[];const t=new Map,e=new Map,s=t=>{const e=(i.wall_segments||[]).find(e=>{const i=[Number(e.a?.[0])*ev,Number(e.a?.[1])*ev],s=[Number(e.b?.[0])*ev,Number(e.b?.[1])*ev];return this._samePt(t.a,i)&&this._samePt(t.b,s)||this._samePt(t.a,s)&&this._samePt(t.b,i)});return"string"==typeof e?.id&&e.id?e.id:null},n=Date.now().toString(36);for(const o of a.materialize){let a=o.reusePartitionId?i.partitions.find(t=>t.id===o.reusePartitionId):e.get(o.interval.key);a||(a={id:s(o.interval)||`partition-room-${n}-${e.size}`,a:[o.interval.a[0]/ev,o.interval.a[1]/ev],b:[o.interval.b[0]/ev,o.interval.b[1]/ev],cm:o.interval.cm},i.partitions.push(a),e.set(o.interval.key,a)),t.set(o.interval.key,a)}for(const e of i.openings||[]){const i=a.openingIntervals.get(e.id),s=i?t.get(i):null,n=this._openingsR.find(t=>t.id===e.id);if(!s||!n)continue;const o={a:[s.a[0]*ev,s.a[1]*ev],b:[s.b[0]*ev,s.b[1]*ev]};e.host={kind:"partition",id:s.id,t:$u([n.rx,n.ry],o)}}}else if(a.removeOpeningIds.length){const t=new Set(a.removeOpeningIds);i.openings=(i.openings||[]).filter(e=>!t.has(e.id)),i.openings.length||delete i.openings}i.rooms=i.rooms.filter(t=>t.id!==n.id),this._cfgEpoch++;const h=this._normalizeWalls(c,this._openCuts());h.length?i.walls=h:delete i.walls,this._roomDeleteDialog=null,this._commitPhysicalGeometry(this._t(t?"history.delete_room_keep_walls":"history.delete_room_with_walls"),l),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()},this._rebindPartitionOpening=()=>{const t=this._openingDialog;if(!t?.id)return;const e=t.id;this._activateMarkupTool("opening"),"opening"===this._tool&&(this._openingRebindId=e,this._openingPreset={type:t.type,lengthCm:t.lengthCm,flipH:t.flipH,flipV:t.flipV,revision:++this._openingPresetRevision},this._openingDialog=null,this._openingHoverCandidate=null)},this._keepClosedAsPartitions=()=>{if(this._wallFaceBatch)return void this._decideWallFace(!1);if(!this._contourClosed||this._pendingSplit||!this._curSpaceCfg)return;const t=this._curSpaceCfg,e=this._path.slice(0,-1);if((t.partitions||[]).length+e.length>ov)return void this._showToast(this._t("toast.physical_limit"));const i=this._geometrySnapshot(),s=Jp(e.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll);t.partitions||=[];const n=Date.now().toString(36),o=this._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this._activeDraftId):null,a=this._draftSegmentsForPath(this._path,o,s);for(let i=0;it.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this._t("history.contour_to_partitions"),i),this._roomDialog=!1,this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null},this._toggleServerPlans=async()=>{const t=this._spaceDialog;if(t)if(t.pickSaved)this._spaceDialog={...t,pickSaved:!1};else{this._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.hass.callWS({type:"houseplan/plans/list"}),e=this._spaceDialog;e&&(this._spaceDialog={...e,saved:t?.plans||[],savedBusy:!1})}catch(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,saved:[],savedBusy:!1}),this._showToast(this._t("toast.plans_list_failed",{err:this._errText(t)}))}}},this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const t=this._dayCycleState();if(!t)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const e=mr(t);e!==this._dayCycleClockKey&&(this._dayCycleClockKey=e,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(!this._norm)return;const t=this._glowRadiusCm,e=this._imperial?Math.round(t/30.48*10)/10:Math.round(t)/100;this._settingsDialog={colors:JSON.parse(JSON.stringify(this._fillColors)),glowRadius:e,bgColor:hs(this._settings,{bgColor:null})||null,northDeg:$r(this._settings,{}),bgMode:Sr(this._settings,{}),sunRays:Mr(this._settings,{}),busy:!1}},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._previewAlignDialog(!1),this._toggleOptimizeLivePositions=()=>{const t=this._alignDialog;t&&!t.busy&&t.report.liveMissingPositions.length&&this._previewAlignDialog(!t.removeLiveMissingPositions)},this._optimizeUndoBusy=!1,this._openBackupExport=()=>{this._settingsDialog=null,this._backupExportDialog={kind:"full",planOnly:!1,busy:!1,error:""}},this._openRulesDialog=()=>{if(!this._norm)return;const t=this._settings.icon_rules,e=(t&&t.length?t:Jt).map(t=>({...t}));this._rulesDialog={rules:e,test:"",busy:!1}},this._climateCache=null,this._gearPtCache=new WeakMap}get _canEdit(){return!!this._norm&&(!0===this._serverCanWrite||!1!==this._serverCanWrite&&!0===this.hass?.user?.is_admin)}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}_cssColor(t,e){const i=String(t||"").trim();if(!i)return e;const s=document.createElement("span");s.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(s);const n=getComputedStyle(s).color||e;return s.remove(),n}_currentModeVisual(t=this._mode){const e=this._modeTransition.presented||this._modeTransitionVisual;if(e)return{...e,viewport:{...e.viewport,viewBox:{...e.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const s=this.renderRoot.querySelector(".editorchrome"),n=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),a=this.renderRoot.querySelector(".hp-backdrop"),r=this.renderRoot.querySelector(".zoomwrap"),l=r?getComputedStyle(r).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:t,editorChromeHeight:"view"===t?0:s?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:xg(n,i.clientWidth),stageColor:getComputedStyle(i).backgroundColor||"rgb(255, 255, 255)",paperColor:o?getComputedStyle(o).fill:"rgb(255, 255, 255)",sceneBrightness:Number.isFinite(c)?c:1,architectureOpacity:"decor"===t?.35:1,backdropOpacity:a&&Number(getComputedStyle(a).opacity)||1,viewWeight:"view"===t?1:0,editorWeight:"view"===t?0:1,toolbarContentOpacity:"view"===t?0:1}}_viewForModeTarget(t,e,i,s,n){const o=Ni(this._baseVb(),s/Math.max(1,n)),a=Math.min(hv.ZOOM_MAX,Math.max(hv.ZOOM_MIN,t)),r=o.w/a,l=o.h/a,c=e??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-r/2,y:h-l/2,w:r,h:l},o)}_targetStageColor(t){return"view"!==t?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(t){return"view"===t&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(t){return 1}_applyModeTransitionFrame(t){t.targetMode===this._mode&&(this._modeTransitionVisual=t.presented,this._view={...t.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(t){if(t.targetMode!==this._mode)return;const e=this._modeTransitionRequest;this._view={...t.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[t.to.stageWidth,t.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._modeTransitionBusy||t.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-t.to.stageWidth)>.5||Math.abs(i.clientHeight-t.to.stageHeight)>.5)){const t=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,t?t.x+t.w/2:void 0,t?t.y+t.h/2:void 0),this.requestUpdate()}const s=this.renderRoot.activeElement;(!s||!s.isConnected||!!s.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(t=!0){const e=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(t),t&&e||(this._modeTransitionVisual=null)}_adoptMode(t){this._cancelModeTransition(!1),this._mode=t,"view"!==t&&(this._editorChromeMode=t)}_commitViewModeAtomic(t,e,i,s){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=e,t){const n=this._stageEl?.clientWidth||t.stageWidth,o=Math.max(1,t.stageHeight+t.editorChromeHeight);this._view=this._viewForModeTarget(e,i,s,n,o),this._lastValidStageSize=[n,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(t,e,i,s,n,o){this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._mode!==i)return void(t===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const a=this.renderRoot.querySelector(".editorchrome"),r=a?.querySelector(".editorchrome-inner"),l="view"===i?0:r?.scrollHeight||r?.getBoundingClientRect().height||0,c=Math.max(1,e.stageHeight+e.editorChromeHeight),h=Math.max(1,c-l),d=this._stageEl?.clientWidth||e.stageWidth;if(d<=0||h<=0)return this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._applyView(s,n,o),void this.requestUpdate();const p=this._viewForModeTarget(s,n,o,d,h),u={presentedMode:i,editorChromeHeight:l,stageWidth:d,stageHeight:h,viewport:xg(p,d),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const _=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(e,u,i,this._reducedMotion||_?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(t=this._model,e=this._loadOk){const i=this._config?.floor,s=function(t){if(!t.hasFloor)return{kind:"absent"};const e=t.floor;if("string"==typeof e)return e.length?t.spaceIds.includes(e)?{kind:"valid",id:e,source:"id"}:{kind:"invalid",reason:"unknown-id",value:e}:{kind:"invalid",reason:"empty-id",value:e};if("number"==typeof e){if(!Number.isFinite(e))return{kind:"invalid",reason:"non-finite-index",value:e};if(!Number.isInteger(e))return{kind:"invalid",reason:"fractional-index",value:e};if(e<0)return{kind:"invalid",reason:"negative-index",value:e};const i=t.spaceIds[e];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:e}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:e}}({spaceIds:t.map(t=>t.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||e?s:"number"==typeof i?"valid"===s.kind||"invalid"===s.kind&&"out-of-range-index"===s.reason?{kind:"pending",value:i}:s:"valid"===s.kind||"invalid"===s.kind&&"unknown-id"!==s.reason?s:{kind:"pending",value:i}}_canCommitSpace(t,e=!1){if(e||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===t}_commitSpace(t,e=!1){return!!this._canCommitSpace(t,e)&&(t!==this._space&&(this._clearTransientHover(!0),this._cancelDevicePressFeedback()),this._space=t,!0)}_slideTo(t,e){if(t===this._space)return!0;if(!this._canCommitSpace(t))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(t),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),i||(this._slide=e,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(t,e){zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:t.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(cv(t),this._tabDragRelease=t=>this._tabPointerUp(t),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:e,pointerId:t.pointerId,x:t.clientX,y:t.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(t,e,i){const s=this._model.map(t=>t.id),n=s.indexOf(i);if(n<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const a of o){const o=a.dataset.id||"";if(!o||o===i)continue;const r=a.getBoundingClientRect();if(tr.right||er.bottom)continue;const l=s.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,s;const n=this._tabDropTargetAt(t.clientX,t.clientY,e.id);e.moved&&e.targetId===n?.targetId&&e.placement===n?.placement||(this._tabDrag={...e,moved:!0,targetId:n?.targetId||null,placement:n?.placement||null})}_tabPointerUp(t){const e=this._tabDrag;if(e&&e.pointerId!==t.pointerId)return;const i="pointerup"===t.type&&e?.moved?this._tabDropTargetAt(t.clientX,t.clientY,e.id):null;"pointerup"===t.type&&e?.moved&&this._suppressNextTabClick(),this._endTabDrag(),e?.moved&&i&&this._commitTabOrder(e.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(t){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(t)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(t,e){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const s=this._model.map(t=>t.id),n=function(t,e,i){const s=t.indexOf(e),n=t.indexOf(i);if(s<0||n<0||s===n)return t;const o=t.slice();return o.splice(s,1),o.splice(n,0,e),o}(s,t,e);if(n===s)return;const o=new Map(this._devices.map(t=>[String(t.id),String(t.area||"")])),a=function(t,e,i,s=()=>""){if(!i)return[];const n=[];for(const o of t){if(!o||!0===o.removed)continue;const t="string"==typeof o.id?o.id:"";if(!t)continue;if("string"==typeof o.space&&o.space)continue;const a=("string"==typeof o.area?o.area:"")||s(t)||"";a&&e[a]||n.push({id:t,space:i})}return n}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),s[0]||"",t=>o.get(t)||"");if(a.length){const t=new Map(a.map(t=>[t.id,t.space]));for(const e of i.markers||[]){const i=t.get(String(e.id));i&&(e.space=i)}}i.spaces=function(t,e){const i=new Map(e.map((t,e)=>[t,e]));return t.map((t,e)=>({space:t,index:e})).sort((t,e)=>(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)||t.index-e.index).map(t=>t.space)}(i.spaces||[],n),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(t){if(this._endTabDrag(),t===this._space)return;const e=this._model.map(t=>t.id),i=e.indexOf(this._space),s=e.indexOf(t);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(t,i>=0&&s0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const t=this._model.map(t=>t.id),e=t.indexOf(this._space);this._slideTo(t[(e+1)%t.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}_newContinuityController(){return new yd(()=>{this._resumeSettling="steady"!==this._continuity.state,this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}get _labsIso(){return this._labs.active.includes("iso")}get _desiredProjection(){return"view"===this._mode&&this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat"}_saveViewPreference(){try{localStorage.setItem(Qf,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(t){const e=this._view;if(!e)return null;const i=[e.x+e.w/2,e.y+e.h/2],s="iso"===t?Jg(i):i;return{x:s[0],y:s[1]}}_convertProjectionView(t,e){if(t===e)return;const i=this._logicalViewCenter(t);this._view=null;const s=i?"iso"===e?Yg([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,s?.[0],s?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(t){if(!this._labsIso||"view"!==this._mode)return;const e=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:t},"iso"===t){const t=this._isoSceneKey();t&&this._isoFallback.delete(t)}this._saveViewPreference();const i=this._effectiveProjection();this._convertProjectionView(e,i)}_hashSpace(){return Eg(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const t=(e=this.ownerDocument,gg.get(e)?.resolved);var e;void 0!==t&&(this._glowScreenBlend=t),this._continuityUnsub?.(),this._continuityUnsub=fd(this.ownerDocument,this._pageVisibility),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(t=>{for(const e of t)for(const t of e.addedNodes)this._syncPointerHoverSubtree(t)}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),function(t){const e=gg.get(t);if(e)return e.promise;const i={promise:Promise.resolve(!1)};return i.promise=vg(t).catch(()=>!1).then(t=>(i.resolved=t,t)),gg.set(t,i),i.promise}(this.ownerDocument).then(t=>{t!==this._glowScreenBlend&&(this._glowScreenBlend=t,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>Is(this._serverCfg)),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(t,e){Wg.add(e);const i=Gg(t);return"undefined"==typeof window&&e(i),()=>{Wg.delete(e)}}(Ff,this._onLabsSnapshot),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Hf)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._vacRaf&&(cancelAnimationFrame(this._vacRaf),this._vacRaf=0),this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const t of this._activityRt.values())clearTimeout(t.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),this._modeTransition.dispose(),this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer);for(const t of this._glowFadeTimers.values())clearTimeout(t);for(const t of this._glowEnterRafs.values())cancelAnimationFrame(t);clearTimeout(this._glowFeatherResumeTimer),this._glowFeatherResumeTimer=0,this._glowFeatherSuspendUntil=0,this._glowFadeTimers.clear(),this._glowEnterRafs.clear(),this._glowEnteringSources.clear(),this._glowRenderedSources.clear(),this._glowLastAppearance.clear(),this._glowSourceSeq=0,this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._touchContacts.clear(),this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(t){if("Escape"===t.key&&this._vacFit)return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void t.stopPropagation();if("Escape"===t.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm=null);if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._settingsDialog)return void(this._settingsDialog=null);if(this._markerDialog)return void(this._markerDialog=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary.hasOpenGroup)return t.preventDefault(),void this._editorSecondary.closeGroup(!0)}const e=t.composedPath?.()||[t.target],i=e.some(t=>t?.matches?.('input, textarea, select, [contenteditable="true"]')),s=e.some(t=>t?.classList?.contains?.("editor-secondary")),n=t.ctrlKey||t.metaKey,o=t.key.toLowerCase(),a=/^[a-z]$/.test(o),r="z"===o||!a&&"KeyZ"===t.code,l="y"===o||!a&&"KeyY"===t.code,c=n&&(r&&t.shiftKey||l),h=n&&r&&!t.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;return c?(t.preventDefault(),void this._redoGeometry()):h?(t.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry()):"Delete"!==t.key&&"Backspace"!==t.key||!this._decorSel||i||s?void("Escape"===t.key&&(t.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._furnPalette=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(t.preventDefault(),void this._decorDeleteSel())}if(this._markup&&(!h&&!c||!i)){if(("Delete"===t.key||"Backspace"===t.key)&&this._physicalSel&&!i&&!s)return t.preventDefault(),void this._deletePhysicalSelection();if(c)return t.preventDefault(),void this._redoGeometry();if(h)return t.preventDefault(),this._rszDrag?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===t.key)return this._physicalDrag||this._physicalRotate?(t.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(t.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(t.preventDefault(),void this._finishWallChain()):this._physicalSel?(t.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(t.preventDefault(),this._rszDrag?void this._rszCancelDrag():void(this._rszSel?this._rszSel=null:this._tool="draw")):"split"===this._tool?(t.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(t.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(t.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(t.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length){if(this._contourClosed)return this._path=this._path.slice(0,-1),void(this._closingWallCm=null);if(this._activeDraftId&&this._path.length>1&&this._curSpaceCfg){const t=this._geometrySnapshot();this._path=this._path.slice(0,-1),this._draftSegmentCms=this._draftSegmentCms.slice(0,-1);const e=this._curSpaceCfg,i=(e.room_drafts||[]).findIndex(t=>t.id===this._activeDraftId);if(i>=0){const s=Array.isArray(e.room_drafts[i]?.segments)?e.room_drafts[i].segments:[];this._path.length<2?(e.room_drafts.splice(i,1),e.room_drafts.length||delete e.room_drafts,this._activeDraftId=null):e.room_drafts[i]={id:this._activeDraftId,points:this._path.map(t=>[t[0]/ev,t[1]/ev]),segments:this._draftSegmentCms.map((t,e)=>({...s[e]||{},cm:t}))},this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),t)}return}this._path=this._path.slice(0,-1)}}_undoActiveDraftPoint(){const t=this._activeDraftId,e=this._path[0]?[...this._path[0]]:null,i=this._geometryHistory.undo();if(!i)return void this._undoPoint();if(!this._applyGeometryState(i.before,!0))return void this._geometryHistory.clear();const s=t?this._spaceModel()?.room_drafts.find(e=>e.id===t):null;s?(this._activeDraftId=s.id,this._path=s.points.map(t=>[...t]),this._draftSegmentCms=this._adoptDraftCms(this._path,s.segments.map(t=>t.cm),s.id),this._resumeDraftBySpace[this._space]=s.id):(this._activeDraftId=null,this._path=e?[e]:[],this._draftSegmentCms=[],t&&this._resumeDraftBySpace[this._space]===t&&delete this._resumeDraftBySpace[this._space]),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:i.name}))}static getConfigElement(){return document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(t){for(const t of jf.values())for(const e of t)clearTimeout(e.evict);jf.clear(),Vf=t&&t>0?t:1e4}static _warmBootStats(){let t=0,e=0;const i=[];for(const s of jf.values())for(const n of s)t++,n.dlg&&(e++,i.push(n.dlg.kind));return{keys:jf.size,slots:t,dlgs:e,drafts:i}}setConfig(t){const e=this._config,i=!!e&&Object.prototype.hasOwnProperty.call(e,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...t};(i!==this._hasFixedFloor||e?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&t.default_floor&&this._commitSpace(t.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(Jf)||"{}")||{}}catch{this._zoomBySpace={}}try{const t=JSON.parse(localStorage.getItem(Qf)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(t).filter(t=>"flat"===t[1]||"iso"===t[1]))}catch{this._viewPreference={}}this._labs=Gg(Ff);try{const t=JSON.parse(localStorage.getItem(Zf)||"null");this._kioskScale={icon:Es(t?.icon),font:Es(t?.font)}}catch{}try{const t=JSON.parse(localStorage.getItem(Yf)||"null");t&&t.config&&Array.isArray(t.config.spaces)&&(this._serverCfg=t.config,this._cfgEpoch++,this._cfgRev=t.rev||0,this._cfgContentFingerprint=t.config_fingerprint||bd(t.config),this._layout=t.layout||{},this._layoutRev=t.layout_rev||0,this._layoutContentFingerprint=t.layout_fingerprint||bd(this._layout),this._virtualLights=mn(t.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1)}_warmAdopt(){if(this._config?.kiosk)return;const t=Gf(this._config);if(this._warmKey===t&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const e=this.parentNode,i=this._warmIdx(e),s=jf.get(t);if(!s||!s.length)return;const n=s.find(t=>t.owner===this._warmGen);if(n)return this._warmLongReturn=!!n.freed&&Date.now()-n.freed>=_d,clearTimeout(n.evict),n.evict=0,n.freed=0,n.live=!0,this._warmSlot=n,this._warmKey=t,n.frameFingerprint&&this._continuity.adoptCompleteFrame(n.frameFingerprint),void(!this._devices.length&&n.devices?.length&&(this._devices=[...n.devices]));const{slot:o,sure:a}=((t,e,i,s)=>{const n=t=>{const e=!!i&&t.place?.deref()===i;return e&&t.idx===s?4:t.live?0:e?3:2};let o=null,a=0,r=0,l=null;for(const i of t){if(i.owner===e)continue;l=i;const t=n(i);t<=0||(t>a?(o=i,a=t,r=1):t===a&&r++)}return!o||r>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(s,this._warmGen,e,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=_d,this._booting=!1,this._bootFading=!1,this._hdrH=o.hdrH,this._bootSoft=!0,this.isConnected&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Hf)),this._warmKey=t,a?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=e?new WeakRef(e):null,o.idx=i,o.live=!0,this._warmSlot=o,this._warmVp=o.vp,o.frameFingerprint&&this._continuity.adoptCompleteFrame(o.frameFingerprint),!this._devices.length&&o.devices?.length&&(this._devices=[...o.devices]),this._warmAdoptViewport(this._config)):(this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},s.push(this._warmSlot),this._warmTrim(s)))}_warmIdx(t){const e=t?.children;if(!e)return-1;for(let t=0;t4;){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=jf.get(e);if(!t.live&&o&&o.length>1){const e=o.indexOf(t);e>=0&&o.splice(e,1)}},Vf+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?Yg([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="opening"===(o=function(t){return"partition"===t?"draw":t}(o=e.tool))?"draw":"string"==typeof o&&nv.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=Gf(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=jf.get(i)||[];for(s.push(this._warmSlot),jf.set(i,s),this._warmTrim(s);jf.size>8;){const t=jf.keys().next().value;if(void 0===t||t===i)break;for(const e of jf.get(t)||[])clearTimeout(e.evict);jf.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>Vf)&&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=bd(this._serverCfg),this._layoutContentFingerprint=bd(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(Yf,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 wd([this._cfgRev,this._cfgContentFingerprint||bd(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||bd(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 G;const t="connection"===this._continuity.recoveryReason;return W`
`}afterRender(){const t=this.host.root();this._blocked&&(this._openGroupId?this.closeGroup(!1):"palette"===this._currentModel?.kind&&this._currentModel.dismiss?.()),this._syncGlobalDismissListener();const e=t.querySelector(".editor-secondary"),i=this._renderedContext,s=e?.dataset.contextId||"";if(s&&i&&s!==i&&!window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches&&(this._contentAnimation?.cancel(),this._contentAnimation=e?.querySelector(".editor-secondary-content")?.animate([{opacity:.35,transform:"translateY(-4px)"},{opacity:1,transform:"translateY(0)"}],{duration:100,easing:"ease-out"})),this._renderedContext=s,i&&s!==i&&this._focusOwned){const i=s?e?.querySelector('[tabindex="0"], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'):t.querySelector(".editbar-tools");i?.focus?.(),this._focusOwned=!!s}if("palette"===this._currentModel?.kind&&this._currentModel.launcherId){const e=[...t.querySelectorAll("[data-editor-palette]")].find(t=>t.dataset.editorPalette===this._currentModel?.launcherId);e&&null!==e.offsetParent||this._currentModel.dismiss?.()}if(!this._openGroupId)return;const n=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===this._openGroupId);n&&null!==n.offsetParent||this.closeGroup(!0)}handleOutsideDismiss(t){if(B_(t,t=>t.hasAttribute("data-editor-navigation")))return"pointerdown"===t.type?this.closeForNavigation():"click"===t.type&&this._dismissPointerTarget&&this._clearDismissClick(),!1;if("click"===t.type&&this._dismissPointerTarget){return!!(t.composedPath?.()||[t.target]).includes(this._dismissPointerTarget)&&(this._clearDismissClick(),t.preventDefault(),t.stopImmediatePropagation(),!0)}const e=this._openGroupId||this._blocked||"palette"!==this._currentModel?.kind?null:this._currentModel;if("pointerdown"===t.type&&(this._openGroupId||e)){const i=B_(t,t=>t.classList.contains("editor-secondary")),s=B_(t,t=>!!t.dataset.editorGroup),n=B_(t,t=>!!t.dataset.editorPalette),o=B_(t,t=>t.classList.contains("stage"));if(!(i||s||n||"stay-open-on-canvas"===e?.dismissPolicy&&o))return t.preventDefault(),t.stopImmediatePropagation(),this._dismissPointerTarget=t.target,clearTimeout(this._dismissTimer),this._dismissTimer=window.setTimeout(()=>{this._clearDismissClick()},800),this._openGroupId?this.closeGroup(!1):e?.dismiss?.(),this._syncGlobalDismissListener(),!0}return!1}_activateGroupItem(t,e,i){if(t.id!==this._openGroupId)return;const s=t.items.find(t=>t.id===e);if(!s||s.disabled)return;const n="toggle"===s.role&&"stay-open"===s.closePolicy,o=0===i.detail;n||(this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener()),s.invoke(),!n&&o&&this.host.updateComplete().then(()=>{const e=[...this.host.root().querySelectorAll("[data-editor-group]")].find(e=>e.dataset.editorGroup===t.id&&null!==e.offsetParent);e?.focus()})}_groupKeydown(t){if(!["ArrowLeft","ArrowRight","Home","End"].includes(t.key))return;const e=[...t.currentTarget.querySelectorAll(".editor-group-item:not([disabled])")];if(!e.length)return;t.preventDefault();const i=e.indexOf(this.host.root().activeElement),s="Home"===t.key?0:"End"===t.key?e.length-1:"ArrowLeft"===t.key?i<=0?e.length-1:i-1:(i+1)%e.length;e[s]?.focus()}_clearDismissClick(){this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}_syncGlobalDismissListener(){const t=!this._blocked&&"palette"===this._currentModel?.kind,e=!!this._openGroupId||t||!!this._dismissPointerTarget;e!==this._globalDismissListening&&(this._globalDismissListening=e,e?(window.addEventListener("pointerdown",this._globalDismissGuard,!0),window.addEventListener("click",this._globalDismissGuard,!0)):(window.removeEventListener("pointerdown",this._globalDismissGuard,!0),window.removeEventListener("click",this._globalDismissGuard,!0)))}}const W_=t=>t.stopPropagation(),j_=4.166666666666667e-9;function U_(t){return Number.isFinite(t)?Math.round(t/Ph)*Ph:t}const G_=(t,e,i,s)=>Math.hypot(i-t,s-e),V_=(t,e,i,s,n,o,a,r)=>Math.hypot(Math.max(Math.abs(n-t),Math.abs(n+a-(t+i))),Math.max(Math.abs(o-e),Math.abs(o+r-(e+s)))),K_=(t,e,i,s,n,o,a)=>{const r=Math.max(Number(s)||0,0)/2,l=Math.PI/180,c=Math.cos(i*l)*r,h=Math.sin(i*l)*r,d=Math.cos(a*l)*r,p=Math.sin(a*l)*r,u=Math.max(G_(t+c,e+h,n+d,o+p),G_(t-c,e-h,n-d,o-p)),_=Math.max(G_(t+c,e+h,n-d,o-p),G_(t-c,e-h,n+d,o+p));return Math.min(u,_)},Y_=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function J_(t,e){const i=JSON.parse(JSON.stringify(t||[])),s=JSON.parse(JSON.stringify(e||{}));let n=0,o=0,a=0,r=0,l="",c=0,h=0,d=0;const p=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=j_&&h++},u=(t,e)=>{p(t[0],e[0]),p(t[1],e[1])},_={};let m=5;for(const t of i){const e=Y_(t);null!=t?.id&&(_[String(t.id)]=e),e>m&&(m=e)}const g=(t,e,i,s=!1)=>{if(!(t>j_||s))return;n++,t>a&&(a=t);const o=t*Ch*e;o>r&&(r=o,l=i)};for(const t of i){const e=Y_(t),i=null!=t?.id?String(t.id):"";for(const s of t.rooms||[]){o++;let t=0;if(s.poly?.length)s.poly=s.poly.map(e=>{const i=[U_(e[0]),U_(e[1])];return t=Math.max(t,G_(e[0],e[1],i[0],i[1])),u(e,i),i});else if(null!=s.x&&null!=s.y){const e=s.x,i=s.y,n=s.w||0,o=s.h||0,a=U_(e+n),r=U_(i+o),l=U_(e),c=U_(i),h=Math.max(Ph,a-l),d=Math.max(Ph,r-c);t=V_(e,i,n,o,l,c,h,d),s.x=l,s.y=c,s.w=h,s.h=d,p(e,l),p(i,c),p(e+n,l+h),p(i+o,c+d)}g(t,e,i)}for(const s of t.room_drafts||[]){o++;let t=0;const n=s.points||[],a=n.map(e=>{const i=[U_(e[0]),U_(e[1])];return t=Math.max(t,G_(e[0],e[1],i[0],i[1])),i}),r=a.length?[a[0]]:[],l=a.length?[[n[0],a[0]]]:[],c=[];for(let t=0;t+1=2)for(const[t,e]of l)u(t,e);g(t,e,i)}if(Array.isArray(t.room_drafts)){const e=t.room_drafts.length;t.room_drafts=t.room_drafts.filter(t=>t.points?.length>=2),d+=e-t.room_drafts.length,t.room_drafts.length||delete t.room_drafts}for(const s of t.partitions||[]){o++;const n=[s.a[0],s.a[1]],a=[s.b[0],s.b[1]],r=[U_(n[0]),U_(n[1])],l=[U_(a[0]),U_(a[1])];let c=Math.max(G_(n[0],n[1],r[0],r[1]),G_(a[0],a[1],l[0],l[1]));const h=G_(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).every(t=>{const e=Number(t.length),i=Number(t.host.t),s=i*h;return Number.isFinite(e)&&e>0&&Number.isFinite(i)&&i>=0&&i<=1&&s-e/2>=-j_&&s+e/2<=h+j_});h>j_&&d?(s.a=r,s.b=l,u(n,r),u(a,l)):c=0,g(c,e,i)}for(const s of t.wall_columns||[]){o++;const t=[s.center[0],s.center[1]],n=[U_(t[0]),U_(t[1])],a=G_(t[0],t[1],n[0],n[1]);s.center=n,u(t,n),g(a,e,i)}for(const s of t.decor||[]){o++;let t=0;if("line"===s.kind){const e=[s.x1,s.y1],i=[s.x2,s.y2],n=[U_(e[0]),U_(e[1])],o=[U_(i[0]),U_(i[1])];t=Math.max(G_(e[0],e[1],n[0],n[1]),G_(i[0],i[1],o[0],o[1])),s.x1=n[0],s.y1=n[1],s.x2=o[0],s.y2=o[1],u(e,n),u(i,o)}else{const e=s.x,i=s.y,n=s.w,o=s.h,a=U_(e),r=U_(i);if(null!=s.w&&null!=s.h){const l=U_(e+n),c=U_(i+o),h=Math.max(Ph,l-a),d=Math.max(Ph,c-r);t=V_(e,i,n,o,a,r,h,d),s.w=h,s.h=d,p(e+n,a+h),p(i+o,r+d)}else t=G_(e,i,a,r);s.x=a,s.y=r,p(e,a),p(i,r)}g(t,e,i)}for(const s of t.openings||[]){if(o++,"partition"===s.host?.kind){const n=(t.partitions||[]).find(t=>t.id===s.host.id),o=Number(s.host.t);if(!n||!Number.isFinite(o)||o<0||o>1)continue;const a=n.b[0]-n.a[0],r=n.b[1]-n.a[1];if(Math.hypot(a,r)<=j_)continue;const l=n.a[0]+a*o,h=n.a[1]+r*o;let d=180*Math.atan2(r,a)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(s.angle),u=!(Number.isFinite(p)&&p===d),_=K_(s.x,s.y,Number.isFinite(p)?p:d,Number(s.length)||0,l,h,d);s.x=l,s.y=h,s.angle=d,u&&c++,g(_,e,i,u);continue}const n=ui([s.x,s.y],t.rooms||[],.025,{step:Ph,length:Number(s.length)||0});if(!n)continue;const a=Number(s.angle),r=!(Number.isFinite(a)&&a===n.angle),l=K_(s.x,s.y,Number.isFinite(a)?a:n.angle,Number(s.length)||0,n.x,n.y,n.angle);s.x=n.x,s.y=n.y,s.angle=n.angle,r&&c++,g(l,e,i,r)}}for(const[t,e]of Object.entries(s)){if(!e||"object"!=typeof e)continue;const i=e;if("number"!=typeof i.x||"number"!=typeof i.y)continue;o++;const n=U_(i.x),a=U_(i.y),r=G_(i.x,i.y,n,a);s[t]={...i,x:n,y:a},p(i.x,n),p(i.y,a);const l="string"==typeof i.s?i.s:"";g(r,_[l]??m,l)}return{spaces:i,layout:s,report:{moved:n,coordsCanonicalized:h,total:o,maxShift:a,maxShiftCm:r,maxSpace:l,rotated:c,removedDrafts:d},changed:n>0||h>0}}function X_(t,e){const i=e.base+t*e.span;return Math.min(1,Math.max(0,i))}const Z_=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Q_=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function tm(t,e,i){const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;if(o<=0)return Q_(t,e);let a=((t[0]-e[0])*s+(t[1]-e[1])*n)/o;return a=Math.max(0,Math.min(1,a)),Math.hypot(t[0]-(e[0]+s*a),t[1]-(e[1]+n*a))}function em(t,e,i,s,n){for(const s of e)if(s&&!i.has(s.id)&&Z_(s.a)&&Z_(s.b)&&(Q_(t,s.a)<=n||Q_(t,s.b)<=n))return!0;for(const e of s?.roomPolygons||[])for(let i=0;i0&&r>0))return null;if(Math.abs(n[0]/a*(o[1]/r)-n[1]/a*(o[0]/r))>i)return null;for(const[i,n]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(Q_(i,n)<=s)return[(i[0]+n[0])/2,(i[1]+n[1])/2];return null}function sm(t,e){const i=.05*(Number(e.pitch)>0?Number(e.pitch):1),s=new Map;let n=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&Z_(t.a)&&Z_(t.b));if(n.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const o=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let a=0;for(let t=0;tQ_(e,t.at)>i);let h=c[0]??r.a,d=c[c.length-1]??l.b;if(c.length<2&&(h=r.a,d=l.b),d[0]0?(d[0]-h[0])/u:0,m=u>0?(d[1]-h[1])/u:0,g=t=>u>0?((t[0]-h[0])*_+(t[1]-h[1])*m)/u:0;for(const t of[r,l]){const e=g(t.a),i=g(t.b)-e;for(const[n,o]of s)o.toId===t.id&&s.set(n,{fromId:o.fromId,toId:p.id,base:e+o.base*i,span:o.span*i});s.set(t.id,{fromId:t.id,toId:p.id,base:e,span:i})}o&&o.add(p.id),n=n.filter((e,i)=>i!==t.i&&i!==t.j),n.splice(t.i,0,p),a++}return{partitions:n,merged:a,openingMoves:[...s.values()]}}function nm(t,e,i,s){if(!t?.length||!i.length)return 0;const n=new Map(i.map(t=>[t.fromId,t]));let o=0;for(const i of t){const t=i?.host;if(!t||"partition"!==t.kind)continue;const a=n.get(t.id);if(!a)continue;i.host={...t,id:a.toId,t:X_(t.t,a)},o++;const r=$p(i,e,s.coordScale,s.cellCm,s.gridPitch).resolved;r&&Object.assign(i,Rp(i,r,s.coordScale))}return o}function om(t,e){const i=e?.excludeDraftId||null;return{roomPolygons:(t?.rooms||[]).map(t=>hi(t)).filter(t=>!!t),columns:t?.wall_columns||[],draftEnds:(t?.room_drafts||[]).flatMap(t=>{if(i&&t?.id===i)return[];const e=t?.points||[];return e.length?[e[0],e[e.length-1]]:[]})}}const am=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),rm=(t,e)=>t[0]-e[0]||t[1]-e[1],lm=(t,e,i,s)=>[t[0]+e*s,t[1]+i*s],cm=(t,e,i,s)=>(t[0]-e[0])*i+(t[1]-e[1])*s,hm=(t,e,i,s,n)=>{const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(!(r>n))return null;const l=o/r,c=a/r,h=e=>Math.abs((e[0]-t[0])*c-(e[1]-t[1])*l);if(h(i)>n||h(s)>n)return null;const d=cm(i,t,l,c),p=cm(s,t,l,c),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));return _-u>n?{lo:u,hi:_}:null},dm=(t,e,i)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>i,pm=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},um=(t,e,i,s)=>{const n=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(n,o);if(!(a>s))return!0;const r=n/a,l=o/a,c=gl(t.cm,i.cellCm,i.gridPitch)/2;return e.some(e=>{const n=e?.center;if(!am(n))return!0;const o=cm(n,t.a,r,l),h=Math.abs((n[0]-t.a[0])*l-(n[1]-t.a[1])*r),d=gl(Number(e.cm),i.cellCm,i.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||o>=-d-s&&o<=a+d+s&&h<=c+d+s})},_m=(t,e,i)=>{if(t.host){const s=$p(t,e,i.coordScale,i.cellCm,i.gridPitch).resolved;return s?{center:s.center,angle:s.angle,length:s.length}:null}const s=Number(t.x)*i.coordScale,n=Number(t.y)*i.coordScale,o=Number(t.angle),a=Number(t.length)*i.coordScale;return[s,n,o,a].every(Number.isFinite)&&a>0?{center:[s,n],angle:o,length:a}:null},mm=(t,e,i)=>{const s=t.angle*Math.PI/180,n=Math.cos(s),o=Math.sin(s),a=e.angle*Math.PI/180,r=Math.cos(a),l=Math.sin(a);if(Math.abs(n*l-o*r)>1e-6)return!1;const c=e.center[0]-t.center[0],h=e.center[1]-t.center[1];if(Math.abs(c*o-h*n)>i)return!1;const d=c*n+h*o;return Math.max(-t.length/2,d-e.length/2)({...t,a:[t.a[0]*e,t.a[1]*e],b:[t.b[0]*e,t.b[1]*e]}),fm=(t,e,i,s)=>{const n=`~r-${(t=>{let e=2166136261;for(let i=0;i>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${i[0].toFixed(9)},${i[1].toFixed(9)}`)}`,o=`${t.slice(0,Math.max(1,64-n.length))}${n}`;let a=o;for(let t=2;s.has(a);t++){const e=`-${t}`;a=`${o.slice(0,64-e.length)}${e}`}return s.add(a),a},vm=(t,e)=>{const i=[];for(const s of t){const t=i[i.length-1];!(t&&Math.abs(t.hi-s.lo)<=e&&t.safe===s.safe)||s.safe&&t.signature!==s.signature?i.push({lo:s.lo,hi:s.hi,a:s.a,b:s.b,safe:s.safe,signature:s.signature,roomIds:s.roomIds,finalCm:s.finalCm}):(t.hi=s.hi,t.b=s.b)}return i};function ym(t,e,i,s,n){const o=i||[],a=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l=Array.isArray(t?.room_drafts)?t.room_drafts:[],c={walls:o,partitions:a,openings:r,roomDrafts:l,partitionsReconciled:0,openingsRehosted:0,removedDrafts:0};if(!a.length&&!l.length)return c;const h=Math.max(2e-4*n.gridPitch,1e-9);let d=o,p=a,u=r;const _=dc(e.rooms,d,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),m=((t,e,i,s)=>{const n=new Map(t.map(t=>[t.id,t])),o=new Set;for(const t of e){if(!n.get(t.id)||!Array.isArray(t.points)||t.points.length<2||t.segments.length!==t.points.length-1)continue;let e=!0;for(let n=0;n+10)){e=!1;break}const l=Math.hypot(a[0]-o[0],a[1]-o[1]);if(!(l>s)){e=!1;break}const c=i.flatMap(t=>{const e=t.cm>0?t.cm:ll;if(t.open||"outer"!==t.kind&&"shared"!==t.kind||e+st.lo-e.lo||t.hi-e.hi);let h=0;for(const t of c){if(t.lo>h+s)break;if(h=Math.max(h,t.hi),h>=l-s)break}h!m.has(t.id));let f=0,v=0;const y=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...a].sort((t,e)=>t.id.localeCompare(e.id))){if(!p.some(e=>e.id===t.id))continue;if(!pm(t))continue;const i=y.get(t.id);if(!(i&&am(i.a)&&am(i.b)&&Number.isFinite(i.cm)&&i.cm>0))continue;const[o,a]=rm(i.a,i.b)<=0?[[i.a[0],i.a[1]],[i.b[0],i.b[1]]]:[[i.b[0],i.b[1]],[i.a[0],i.a[1]]],r=a[0]-o[0],l=a[1]-o[1],c=Math.hypot(r,l);if(!(c>h))continue;const _=r/c,g=l/c,b=dc(e.rooms,d,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),w=b.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=hm(o,a,t.a,t.b,h);return e?[{interval:t,range:e}]:[]});if(!w.length)continue;const k=u.filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).map(t=>({opening:t,resolved:$p(t,e.partitions,n.coordScale,n.cellCm,n.gridPitch).resolved}));if(k.some(t=>!t.resolved))continue;const x=[0,c];for(const{range:t}of w)x.push(t.lo,t.hi);const $=x.slice(),S=new Map;for(const{opening:t,resolved:e}of k){const i=cm(e.center,o,_,g),s={lo:i-e.length/2,hi:i+e.length/2};S.set(t.id,s),$.push(Math.max(0,s.lo),Math.min(c,s.hi))}const M=[...new Set($.filter(t=>Number.isFinite(t)&&t>=-h&&t<=c+h).map(t=>Math.max(0,Math.min(c,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),C=p.map(t=>gm(t,n.coordScale)).filter(t=>t.id!==i.id),D=e.room_drafts.filter(t=>!m.has(t.id)),P=[];for(let t=0;t+1h))continue;const r=lm(o,_,g,s),l=lm(o,_,g,a),c=w.filter(({range:t})=>t.lo<=s+h&&t.hi>=a-h).map(({interval:t})=>t),d=new Map;for(const t of c)d.set(t.roomId,t);const p=[...d.values()],u=new Set(p.map(t=>t.kind)),m=new Set(p.map(t=>t.cm>0?t.cm:ll)),f=p[0]?.kind,v=[...d.keys()].sort(),y=1===u.size&&1===m.size&&("outer"===f&&1===v.length||"shared"===f&&2===v.length),b={id:i.id,a:r,b:l,cm:i.cm},k=C.some(t=>!!hm(r,l,t.a,t.b,h)),x=D.some(t=>t.points.some((e,i)=>i+10?p[0].cm:ll:0,T=y?Math.max(S,i.cm):i.cm;P.push({lo:s,hi:a,a:r,b:l,safe:$,signature:$?`${f}|${v.join(",")}|${T}`:"",roomIds:v,roomCm:S,finalCm:T})}if(!P.some(t=>t.safe))continue;const T=new Map;for(const{opening:t,resolved:e}of k){const s=S.get(t.id),o=x.some(t=>t>s.lo+h&&tdm(t,s,h)),r=new Set(a.filter(t=>t.safe).map(t=>t.signature));if(!o&&a.length>0&&a.every(t=>t.safe)&&1===r.size&&Tp(e,b,h)){T.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=kp(i,n.cellCm,n.gridPitch),c={lo:s.lo-l,hi:s.hi+l};for(const t of P)dm(t,c,h)&&(t.safe=!1,t.signature="")}let R=!0;for(;R;){R=!1;for(const[t,e]of[...T.entries()]){const s=S.get(t),o=P.filter(t=>dm(t,s,h));if(o.length>0&&o.every(t=>t.safe)&&o.every(t=>t.signature===e.signature))continue;T.delete(t);const a=kp(i,n.cellCm,n.gridPitch),r={lo:s.lo-a,hi:s.hi+a};for(const t of P)dm(t,r,h)&&(t.safe=!1,t.signature="");R=!0}}const I=vm(P,h),A=I.filter(t=>t.safe),z=I.filter(t=>!t.safe);if(!A.length)continue;if(p.length-1+z.length>2e3)continue;let F=d;for(const t of A){const[e,s]=rm(i.a,i.b)<=0?[t.a,t.b]:[t.b,t.a];F=Fl(F,e,s,t.finalCm,n.pitch,n.coordScale)}if(F=uc(e.rooms,F,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale),F.length>500)continue;const E=new Set(p.map(t=>t.id));E.delete(i.id);const N=z.map((t,e)=>{const s=[t.a[0]/n.coordScale,t.a[1]/n.coordScale],o=[t.b[0]/n.coordScale,t.b[1]/n.coordScale],a=0===e?i.id:fm(i.id,s,o,E);return E.add(a),{id:a,a:s,b:o,cm:i.cm}}),O=p.findIndex(t=>t.id===i.id),L=p.slice();L.splice(O,1,...N);const H=L.map(t=>gm(t,n.coordScale)),B=new Map;let q=!0;for(const{opening:t,resolved:e}of k){const i=T.get(t.id);if(i){const e=Rp(t,i.resolved,n.coordScale),{host:s,...o}=e;B.set(t.id,o);continue}const s=S.get(t.id),o=N[z.findIndex(t=>t.lo<=s.lo+h&&t.hi>=s.hi-h)],a=o&&H.find(t=>t.id===o.id);if(!o||!a){q=!1;break}const r=a.b[0]-a.a[0],l=a.b[1]-a.a[1],c=Math.hypot(r,l),d=cm(e.center,a.a,r/c,l/c),p={...Rp(t,e,n.coordScale),host:{kind:"partition",id:o.id,t:d/c}};if(!Sp(p,H,n.coordScale,n.cellCm,n.gridPitch).resolved){q=!1;break}B.set(t.id,p)}if(!q)continue;const W=u.map(t=>B.get(t.id)||t),j=[...T.keys()].map(t=>B.get(t)),U=j.map(t=>_m(t,H,n));if(U.some(t=>!t))continue;let G=!1;for(let t=0;tt.id));for(const t of W){if(V.has(t.id))continue;const e=_m(t,H,n);e&&U.some(t=>mm(t,e,h))&&(G=!0)}if(G)continue;const K=Fc(e.rooms,F,s,n.pitch,n.cellCm,n.gridPitch,n.coordScale);[...T.entries()].every(([t,e])=>{const i=B.get(t),s=Oc(K,{x:i.x*n.coordScale,y:i.y*n.coordScale,angle:i.angle,length:i.length*n.coordScale},!0),o=[s.negative,s.positive].filter(t=>!!t?.full),a=e.signature.split("|")[1].split(","),r=new Set(o.map(t=>t.roomId));return o.length===a.length&&r.size===a.length&&a.every(t=>r.has(t))})&&(d=F,p=L,u=W,f+=A.length,v+=T.size)}return{walls:d,partitions:p,openings:u,roomDrafts:g,partitionsReconciled:f,openingsRehosted:v,removedDrafts:m.size}}const bm=t=>JSON.parse(JSON.stringify(t)),wm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),km=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function xm(t,e){let i=String(e??"");const s=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=new RegExp(`^${s}_(.+)_([0-9a-f]{8})$`);let o=0;for(;o<16;o++){const t=n.exec(i);if(!t)return{root:i,layers:o,bounded:!1};i=t[1]}return{root:i,layers:o,bounded:n.test(i)}}const $m=(t,e,i)=>{const s=t.get(e)||[];s.push(i),t.set(e,s)};const Sm=1e-9;class Mm extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const Cm=t=>JSON.parse(JSON.stringify(t)),Dm=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),Pm=t=>[Number(t[0]),Number(t[1])],Tm=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,Rm=(t,e)=>{const i=Tm(t),s=Tm(e);return iTm(t)<=Tm(e)?[Pm(t),Pm(e)]:[Pm(e),Pm(t)],Am=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),zm=t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],i=[];for(let s=1;s{const i=new Set,s=t=>{const e=Number(t);if(!Number.isFinite(e))return;const s=e/Ph;Math.abs(s-Math.round(s))>=Ur&&i.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of hi(e)||[])s(t[0]),s(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])s(t?.a?.[0]),s(t?.a?.[1]),s(t?.b?.[0]),s(t?.b?.[1]);for(const t of e)s(t?.[0]),s(t?.[1]);return i.size},Em=(t,e,i)=>{const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;return o>1e-18?((t[0]-e[0])*s+(t[1]-e[1])*n)/o:0},Nm=(t,e,i)=>{const s=Math.max(0,Math.min(1,Em(t,e,i)));return Math.hypot(t[0]-(e[0]+(i[0]-e[0])*s),t[1]-(e[1]+(i[1]-e[1])*s))},Om=(t,e,i,s,n=Sm)=>{const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(r<=n)return 0;const l=e=>Math.abs((e[0]-t[0])*a-(e[1]-t[1])*o)/r;if(l(i)>n||l(s)>n)return 0;const c=Em(i,t,e),h=Em(s,t,e);return Math.max(0,Math.min(1,Math.max(c,h))-Math.max(0,Math.min(c,h)))*r},Lm=t=>{const e=(new TextEncoder).encode(t),i=8*e.length,s=64*Math.ceil((e.length+9)/64),n=new Uint8Array(s);n.set(e),n[e.length]=128;const o=new DataView(n.buffer);o.setUint32(s-8,Math.floor(i/4294967296),!1),o.setUint32(s-4,i>>>0,!1);const a=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),l=new Uint32Array(64),c=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,n=c(i,17)^c(i,19)^i>>>10;l[t]=l[t-16]+s+l[t-7]+n>>>0}let[e,i,s,n,h,d,p,u]=r;for(let t=0;t<64;t++){const o=u+(c(h,6)^c(h,11)^c(h,25))+(h&d^~h&p)+a[t]+l[t]>>>0,r=e&i^e&s^i&s;u=p,p=d,d=h,h=n+o>>>0,n=s,s=i,i=e,e=o+((c(e,2)^c(e,13)^c(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+i>>>0,r[2]=r[2]+s>>>0,r[3]=r[3]+n>>>0,r[4]=r[4]+h>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+u>>>0}const h=new Uint8Array(32),d=new DataView(h.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let i=0,s=0,n="";for(const o of t)for(s=s<<8|o,i+=8;i>=5;)n+=e[s>>>i-5&31],i-=5;return i&&(n+=e[s<<5-i&31]),n},Bm=(t,e,i,s,n="")=>{const[o,a]=Im(e,i),r=`${t}|${Tm(o)}|${Tm(a)}|${[...s].sort().join(",")}${n}`;return`wall-${Hm(Lm(r)).slice(0,20)}`};let qm=0;const Wm=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),i=`wall-${e||Hm(Lm(`${Date.now()}|${qm++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(i))return i}throw new Mm("duplicate-id","id factory exhausted")},jm=t=>{const e=new Map;for(const i of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(i&&"string"==typeof i.id&&Dm(i.a)&&Dm(i.b)){if(e.has(i.id))throw new Mm("duplicate-id",i.id);e.set(i.id,i)}return e},Um=(t,e,i)=>{const s=(i,s)=>{const n=t[0]-i[0],o=t[1]-i[1];return Math.abs(e[0]-s[0]-n)<=Sm&&Math.abs(e[1]-s[1]-o)<=Sm?[n,o]:null};return s(i.a,i.b)||s(i.b,i.a)},Gm=(t,e)=>{const i=Array.isArray(t.rooms)?t.rooms:[],s=pd(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),n=s.length?s:ud(i,null,1,.04*Ph,!0),o=[];for(const t of i){const i=hi(t),s=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(i&&s.length===i.length)for(let t=0;t"partition"!==t.host?.kind&&[Number(t.x),Number(t.y)].every(Number.isFinite)&&Number.isFinite(Number(t.angle))&&Number(t.length)>0&&n.some(e=>Nm([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*Ph)):[],l=r.map(t=>{const e=Number(t.angle)*Math.PI/180,i=[Math.cos(e),Math.sin(e)],s=Number(t.length)/2,n=[Number(t.x),Number(t.y)];return{a:[n[0]-i[0]*s,n[1]-i[1]*s],b:[n[0]+i[0]*s,n[1]+i[1]*s]}}),c=(t,e)=>r.some(i=>{const s=[Number(i.x),Number(i.y)];if(!Rl(t,e,Number(i.angle)))return!1;if(Nm(s,t,e)>.02*Ph)return!1;const n=Am(t,e),o=Em(s,t,e)*n,a=Number(i.length)/2;return o+a>=-Sm&&o-a<=n+Sm}),h=new Map,d=[];for(const s of i){const r=String(s?.id||""),p=hi(s);if(!r||!p||p.length<3)throw new Mm("invalid-room",r);const u=ec(i,r,a,Ph,1,[...t.walls||[],...l]);if(!u||u.poly.length<3)throw new Mm("invalid-room",r);const _=Array.isArray(s.wall_ids)?s.wall_ids:[],m=_.length===p.length;let g=null,f=m;if(f)for(let t=0;tSm||Math.abs(s[1]-g[1])>Sm)){f=!1;break}g=s}const v=[];for(let t=0;t2)throw new Mm("third-owner",a);const d=m?_[u.parent[t]]:void 0;if("string"==typeof d&&d){const n=e.get(d);f||!n||Om(i,s,n.a,n.b)>Sm?l.preferredIds.add(d):l.positionalIds.add(d),l.preferredCarriers.set(d,{a:Pm(p[u.parent[t]]),b:Pm(p[(u.parent[t]+1)%p.length])})}const g=u.parent[t];l.parentKeys.add(wl(p[g],p[(g+1)%p.length],Ph));const y=[(i[0]+s[0])/2,(i[1]+s[1])/2],b=t=>t.some(t=>Nm(y,[t[0],t[1]],[t[2],t[3]])<=.04*Ph);l.zeroWall||=b(o)||b(n)&&!c(i,s),v.push(a)}const y={...s};delete y.wall_ids,d.push({...y,poly:u.poly.map(t=>[t[0],t[1]]),wall_ids:v})}return{atoms:[...h.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},Vm=(t,e,i,s,n)=>{const o=new Map([...i.values()].map(t=>[Rm(t.a,t.b),t])),a=(t=>{const e=new Map;for(const i of t)"wall"===i.host?.kind&&e.set(i.host.id,(e.get(i.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=n?.get(t.key);if(e){const s=i.get(e);if(!s)throw new Mm("duplicate-id",e);r.set(t,s);continue}if(t.preferredIds.size>1)throw new Mm("duplicate-id",[...t.preferredIds].sort().join(","));const s=[...t.preferredIds][0],l=s?i.get(s):void 0;if(l){r.set(t,l);continue}const c=s?t.preferredCarriers.get(s):void 0;if(s&&c){r.set(t,{id:s,a:c.a,b:c.b,cm:0});continue}const h=o.get(t.key);if(h){r.set(t,h);continue}const d=[...i.values()].filter(e=>Om(t.a,t.b,e.a,e.b)>Sm),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(a.get(e.id)||0)-(a.get(t.id)||0)||Am(e.a,e.b)-Am(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=i.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const i=l.get(e.id)||[];i.push(t),l.set(e.id,i)}for(const[t,e]of l){const s=i.get(t)||r.get(e[0]);if(!s)throw new Mm("duplicate-id",t);const n=[(s.a[0]+s.b[0])/2,(s.a[1]+s.b[1])/2];e.sort((t,e)=>{const i=Nm(n,t.a,t.b)<=Sm?0:1,o=Nm(n,e.a,e.b)<=Sm?0:1;if(i!==o)return i-o;return(Nm(s.a,t.a,t.b)<=Sm?0:1)-(Nm(s.a,e.a,e.b)<=Sm?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const c=(t=>{const e=new Set;for(const i of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(i)?i:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const i of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(i?.segments)?i.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(c.has(t.id))throw new Mm("duplicate-id",t.id);c.add(t.id)}const h=e.filter(t=>!t.id);if(s){const e=h.map(e=>{const[i,s]=Im(e.a,e.b),n=`${String(t.id||"")}|${Tm(i)}|${Tm(s)}|${[...e.owners].sort().join(",")}`,o=Hm(Lm(n));return{atom:e,seed:n,digest:o,base:`wall-${o.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),i=new Map;for(const t of e){const e=i.get(t.digest);if(e&&e!==t.seed)throw new Mm("duplicate-id",t.digest);i.set(t.digest,t.seed);let s=1,n=t.base;for(;c.has(n);)n=`${t.base}-${++s}`;t.atom.id=n,c.add(n)}}else for(const t of h)t.id=Wm(c),c.add(t.id)},Km=(t,e)=>{if("partition"===t.host?.kind)return null;const i=[Number(t.x),Number(t.y)];if(!i.every(Number.isFinite))return null;const s=e=>{if(!(Number(e.cm)>0))return!1;const s=Em(i,e.a,e.b),n=Am(e.a,e.b),o=Number(t.length)/2;return s>=-Sm&&s<=1+Sm&&Nm(i,e.a,e.b)<=.02*Ph&&Rl(e.a,e.b,Number(t.angle))&&Number.isFinite(o)&&o>=0&&s*n-o>=-Sm&&s*n+o<=n+Sm},n="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,o=n&&s(n)?[n]:e.filter(s);if(1!==o.length)return null;const a=o[0];return{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,Em(i,a.a,a.b)))}},Ym=(t,e)=>{const i=[Number(t.x),Number(t.y)];if(!i.every(Number.isFinite))return null;const s=Number(t.length)/2,n=e.filter(e=>{if(!(Number(e.cm)>0))return!1;const n=Em(i,e.a,e.b),o=Am(e.a,e.b);return n>=-Sm&&n<=1+Sm&&Nm(i,e.a,e.b)<=.02*Ph&&Rl(e.a,e.b,Number(t.angle))&&Number.isFinite(s)&&s>=0&&n*o-s>=-Sm&&n*o+s<=o+Sm}),o=e=>{if(!e.length)return null;const s="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null;return s||[...e].sort((t,e)=>Nm(i,t.a,t.b)-Nm(i,e.a,e.b)||Number(e.cm)-Number(t.cm)||(t.ide.id?1:0))[0]},a=e.filter(e=>Number(e.cm)>0&&Rl(e.a,e.b,Number(t.angle))&&Number.isFinite(s)&&s>=0&&Am(e.a,e.b)+Sm>=Number(t.length)),r=o(n)??o(a);return r?{kind:"wall",id:r.id,t:Math.max(0,Math.min(1,Em(i,r.a,r.b)))}:null},Jm=(t,e,i)=>{const s=jm(t),{atoms:n,rooms:o}=Gm(t,s);Vm(t,n,s,e,i);const a=n.map(e=>{const i=e.id?s.get(e.id):void 0,n=((t,e,i)=>{if(e.zeroWall)return 0;const s=Array.isArray(t.walls)?t.walls:[],n=wl(e.a,e.b,Ph),o=s.filter(t=>Number(t.cm)>0&&(!(t.key!==n&&!e.parentKeys.has(t.key))||!(!Dm(t.a)||!Dm(t.b))&&Om(e.a,e.b,t.a,t.b)>=Am(e.a,e.b)-Sm)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(o.map(t=>t.toFixed(9))).size>1)throw new Mm("thickness-conflict",e.key);if(o.length)return o[0];const a=Pl(s,e.a,e.b,Ph,1);return a>0?a:Number(i?.cm)>0?Number(i.cm):0})(t,e,i);return{...i||{},id:e.id,a:[...e.a],b:[...e.b],cm:n}}),r=new Map(n.map(t=>[t.key,t.id]));for(const t of o)t.wall_ids=t.wall_ids.map(t=>r.get(t));t.rooms=o,t.wall_segments=a,t.walls=a.filter(t=>t.cm>0).map(t=>({key:wl(t.a,t.b,Ph),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e)=>{const i=new Set;for(const e of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&i.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[]){const n=Array.isArray(s.segments)?s.segments:[];for(let o=0;o{const s=Array.isArray(t.openings)?t.openings:[];for(const t of s){if("partition"===t.host?.kind)continue;if(!t.host&&!i){const i=Km(t,e);i&&(t.host=i);continue}const s=Km(t,e)??(i?Ym(t,e):null);if(s)t.host=s;else{if(!i)throw new Mm("opening-host",t.id);delete t.host}}})(t,a,e),a.reduce((t,e)=>t+(s.has(e.id)?0:1),0)};function Xm(t,e={}){const i=JSON.stringify(t),s=Cm(t);rl(s);let n=0;const o=Number(s?.model_version||0)<9;for(const t of Array.isArray(s?.spaces)?s.spaces:[]){const i=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0;n+=Jm(t,o,i)}return s.model_version=9,rl(s),{config:s,changed:i!==JSON.stringify(s),migratedSegments:n}}const Zm=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Qm(t,e){const i=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const s=new Map;for(const e of t)Zm(e)&&"string"==typeof e.id&&e.id&&s.set(e.id,e);const n=e.map((e,n)=>{if(Zm(e)&&"string"==typeof e.id&&e.id){const t=s.get(e.id);return t?i(t,e):Cm(e)}return n[e,e in t?i(t[e],s):Cm(s)]);for(const e of Object.keys(t))delete t[e];for(const[e,i]of s)t[e]=i;return t}return Cm(e)};return i(t,e)}const tg=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),eg=(t,e,i)=>Math.min(i,Math.max(e,t)),ig=t=>$h({spaces:[t]})[0],sg=(t,e,i)=>{const s=i>0?i:1,n=t=>`${(t[0]/s).toFixed(12)},${(t[1]/s).toFixed(12)}`,o=n(t),a=n(e);return o0?a:1,l=Math.max(s*r*.02,1e-9),c=[];for(const e of t||[])for(const t of hi(e)||[])c.push([t[0],t[1]]);const h=[];for(const t of i||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&h.push([t[0],t[1]],[t[2],t[3]]);const d=(t,e)=>e.some(e=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l),p=new Map;for(const a of t||[]){if(!a?.id)continue;const u=hc(t,a.id,e,i,s,n,o,r);if(u)for(let t=0;t0&&_>0&&a===m&&_!==a))continue;const g=u.poly[s],f=u.poly[(s+1)%u.poly.length],v=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(v>l&&v<.5*o-1e-9*o))continue;if(d(g,h)||d(f,h))continue;if(d(g,c)&&d(f,c))continue;const y=sg(g,f,r),b=p.get(y);b?b.targets.add(a):p.set(y,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([a])})}}}let u=e.slice();const _=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const i=[Number(t.a[0])*r,Number(t.a[1])*r],s=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...i,...s].every(Number.isFinite)&&(_(i,e.a)&&_(s,e.b)||_(i,e.b)&&_(s,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>sg(t.a,t.b,r).localeCompare(sg(e.a,e.b,r)))){const e=[...t.targets][0],i=u.filter(e=>m(e,t));if(new Set(i.map(t=>t.cm)).size>1)continue;let n=!1;u=u.map(i=>m(i,t)?(n=!0,i.cm===e?i:{...i,cm:e}):i),n||(u=Fl(u,t.a,t.b,e,s,r))}return u}const og=t=>{const e=[];for(const i of t||[]){const t=hi(i);if(t?.length)for(let i=0;i"string"==typeof t?.id?t.id:"").filter(Boolean),h=new Set(c),d=new Map;for(const t of c){const e=xm("space",t);e.layers>0&&km("space",e.root)&&$m(d,e.root,t)}const p=new Map,u=new Map,_=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const i=new Map;for(const s of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof s?.id?s.id:"";if(!t)continue;const n=xm("room",t);n.layers>0&&km("room",n.root)&&$m(i,n.root,t),u.has(t)||u.set(t,e),_.has(t)||_.set(t,String(s.name||""));const o="string"==typeof s.area?s.area:"";if(o){const i=m.get(o)||[];i.push({spaceId:e,roomId:t}),m.set(o,i)}}p.set(e,i)}const g=new Set(u.keys()),f=new Map,v=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?v.set(t.id,t):f.set(t.id,t));const y={spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,positionsUnresolved:0,nestedRefsUnresolved:0,deadSpaceIds:[],orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0,removedPositions:[],liveMissingPositions:[],unverifiedPositions:[]},b=new Set,w=t=>h.has(t)?null:(()=>{const e=xm("space",t).root;if(!km("space",e))return null;const i=d.get(e)||[];return 1===i.length?i[0]:null})(),k=(t,e)=>{const i=xm("room",t).root;if(!km("room",i))return null;const s=p.get(e)?.get(i)||[];return 1===s.length?s[0]:null},x=t=>{const e=i.effectiveAreaByMarker?.[t]||"",s=e&&m.get(e)||[];return 1===s.length?s[0]:null},$=(t,e,i)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const s=e?k(t.room_id,e):null;s?(t.room_id=s,y.roomRefsRemapped++):i?(t.room_id=i.roomId,y.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const s=t.vacuum?.segment_map;if(s&&"object"==typeof s&&!Array.isArray(s))for(const t of Object.keys(s)){const i=s[t];if("string"!=typeof i||!i||g.has(i))continue;const n=e?k(i,e):null;n?(s[t]=n,y.roomRefsRemapped++):y.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const i="string"==typeof t.space?t.space:"",s=i&&!h.has(i),o=n[e],a="string"==typeof o?.s?o.s:"",r=a&&!h.has(a),l=!0===t.removed;let c=i&&h.has(i)?i:null,d=null,p=!1;if(s){const s=w(i);s?(t.space=s,c=s,p=!0,y.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,c=null,y.markersDetached++):(d=x(e),d?(t.space=d.spaceId,c=d.spaceId,y.spaceRefsRemapped++):(delete t.space,c=null,y.markersDetached++))}l&&!p||$(t,c,d),r&&p&&a===i&&c&&(n[e]={...o,s:c},y.positionsRemapped++,b.add(e))}for(const t of Object.keys(n)){if(b.has(t))continue;const e=n[t],i="string"==typeof e?.s?e.s:"";if(!i||h.has(i))continue;const s=w(i);if(s){if(t.startsWith("rl_")){const i=t.slice(3),o=k(i,s);if(o){const i=`rl_${o}`;wm(n,i)||(n[i]={...e,s:s}),delete n[t],y.roomRefsRemapped++,y.positionsRemapped++;continue}}n[t]={...e,s:s},y.positionsRemapped++}}const S=i.ownerRoster,M=!0===S?.authoritative,C=new Set(S?.deviceIds||[]),D=new Set(S?.entityIds||[]),P=new Set(Array.isArray(s.settings?.known_devices)?s.settings.known_devices.filter(t=>"string"==typeof t):[]),T=(t,e="")=>{const i=String(S?.names?.[t]||e||"").trim();return i&&i!==t?i:""},R=(t,e,i,s="",n)=>({id:t,spaceId:e,kind:i,name:T(t,s),...n?{reason:n}:{}}),I=t=>{"room_label"===t?y.orphanRoomLabelsRemoved++:"group"===t?y.orphanGroupPositionsRemoved++:y.orphanDevicePositionsRemoved++},A=new Set;for(const[t,e]of Object.entries(n)){const s="string"==typeof e?.s?e.s:"";if(!s||h.has(s))continue;let o,a;const r=f.get(t),l=v.get(t);if(r)o=R(t,s,"device",String(r.name||"")),a="live";else if(l)o=R(t,s,"device",String(l.name||"")),a="absent";else if(t.startsWith("rl_")){const e=t.slice(3);o=R(t,s,"room_label",_.get(e)||""),a=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);o=R(t,s,"group"),a=D.has(e)?"live":M?"absent":"unverified","unverified"===a&&(o.reason="registry_unavailable")}else C.has(t)?(o=R(t,s,"device"),a="live"):P.has(t)?(o=R(t,s,"device"),a=M?"absent":"unverified","unverified"===a&&(o.reason="registry_unavailable")):(o=R(t,s,"unknown","","unknown_owner"),a="unverified");if("absent"!==a){if("live"===a){if(y.liveMissingPositions.push(o),!0===i.removeLiveMissingPositions){delete n[t],y.liveMissingPositionsRemoved++,I(o.kind),y.removedPositions.push(o);continue}}else y.unverifiedPositions.push(o);y.positionsUnresolved++,A.add(s)}else delete n[t],I(o.kind),y.removedPositions.push(o)}return y.deadSpaceIds=[...A].sort((t,e)=>t.localeCompare(e)),{config:s,layout:n,report:y,changed:JSON.stringify(s)!==o||JSON.stringify(n)!==a}}(t,e,i),a=o.config,r=nl(a,o.layout);rl(a),al(o.layout);const l=JSON.stringify(t||{}),c=JSON.stringify(e||{}),h=Number.isInteger(Number(a.model_version))?Number(a.model_version):0,d=(t=>{let e=0,i=0,s=0;for(const i of t.markers||[]){if("ripple"===i.display&&(i.display="icon_ripple",e++),Array.isArray(i.controls)){const t="string"==typeof i.binding&&i.binding.startsWith("entity:")?i.binding.slice(7):"",s=t?i.controls.filter(e=>e!==t):i.controls;JSON.stringify(s)!==JSON.stringify(i.controls)&&(i.controls=s.length?s:null,e++)}const t=i.vacuum;t&&tg(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const n of t.spaces||[]){const t=n.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,i++);for(const t of n.rooms||[]){const i=t.settings;"glow"===i?.fill_mode&&("boolean"!=typeof i.glow&&(i.glow=!0),delete i.fill_mode,e++,s++)}if(tg(n,"segments")&&(delete n.segments,e++),tg(n,"plan_scale")){const t=Number(n.plan_scale);Number.isFinite(t)&&t>=bh&&t<=wh&&(tg(n,"plan_scale_x")||(n.plan_scale_x=t),tg(n,"plan_scale_y")||(n.plan_scale_y=t),delete n.plan_scale,e++)}const o=Number(n.cell_cm);tg(n,"cell_cm")&&(!Number.isFinite(o)||o<.1||o>1e3)&&(n.cell_cm=Number.isFinite(o)&&o>0?eg(o,.1,1e3):5,e++);const a=Number(n.cell_cm),r=Number.isFinite(a)&&a>0?a:5;for(const t of n.wall_columns||[])if("circle"===t.shape)tg(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&tg(t,"angle")){const i=((Number(t.angle)||0)%90+90)%90;t.angle!==i&&(t.angle=i,e++)}for(const t of n.decor||[]){if(tg(t,"width")){const i=Number(t.width);(tg(t,"width_cm")||Number.isFinite(i))&&(tg(t,"width_cm")||(t.width_cm=Number(eg(i/Dh*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(tg(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),tg(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(eg(es*is(t)/Dh*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(tg(t,"scale")||tg(t,"size"))&&(delete t.scale,delete t.size,e++);let i=String(t.text??"");const s=[...i.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!Yi(t[1]));if(!(tg(t,"entity")||tg(t,"attr")||tg(t,"unit")))continue;const n=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,a=s||n?"":Ji(t.entity,o);if(s||a){if(a){const e=i.indexOf("{}");i=e>=0?i.slice(0,e)+a+i.slice(e+2):`${i}${i?" ":""}${a}`,t.text=i}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:i,glowRooms:s}})(a);let p=d.total;const u=(_=a.spaces||[],JSON.parse(JSON.stringify(_)));var _;const m=J_(a.spaces||[],o.layout);let g=0,f=0,v=0,y="";const b=m.spaces.map(t=>{const e=function(t){const e=JSON.parse(JSON.stringify(t||{}));let i=Array.isArray(e.rooms)?e.rooms:[];const s=new Map;for(const t of i){const e=hi(t);if(e)for(let t=0;tt.key.localeCompare(e.key))){let e=null;for(const s of $a(t,i)){const t=r.get(_a(s.from));if(t&&t!==_a(s.to))continue;const n=wa(i,s);if(ka(i,n,s)){e=s,i=n;break}}e?(r.set(_a(e.from),_a(e.to)),n++,a=Math.max(a,Math.hypot(e.to[0]-e.from[0],e.to[1]-e.from[1]))):o++}e.rooms=i;for(const t of e.room_drafts||[]){if(!Array.isArray(t?.points)||t.points.length<2)continue;const e=t.points.map(t=>[...t]),i=e.slice(0,-1).flatMap((i,s)=>{const n=e[s+1],o=pa(i,n);return o?[{key:`${String(t.id||"")}:${s}`,a:[...i],b:[...n],axis:o.axis}]:[]});let s=e;for(const t of i){let e=null;for(const i of $a(t,[{poly:s}])){const t=s.map(t=>ba(t,i)),n=t.length>=4&&ma(t[0],t[t.length-1]),o=n?t.slice(0,-1):t;if(n?va(o):ya(o)){e=i,s=t;break}}e?(n++,a=Math.max(a,Math.hypot(e.to[0]-e.from[0],e.to[1]-e.from[1]))):o++}t.points=s}for(const t of e.partitions||[]){if(!Array.isArray(t?.a)||!Array.isArray(t?.b))continue;const i=pa(t.a,t.b);if(!i)continue;const s={key:String(t.id||ga(t.a,t.b)),a:[...t.a],b:[...t.b],axis:i.axis};let r=null;for(const i of $a(s,[{poly:[t.a,t.b]}])){const s=ba(t.a,i),n=ba(t.b,i),o=Math.hypot(n[0]-s[0],n[1]-s[1]);if(!(o>0))continue;const a=(e.openings||[]).filter(e=>"partition"===e?.host?.kind&&e.host.id===t.id).every(t=>{const e=Number(t.host.t),i=Number(t.length);return Number.isFinite(e)&&e>=0&&e<=1&&Number.isFinite(i)&&i>0&&e*o-i/2>=-1e-12&&e*o+i/2<=o+1e-12});if(a){r=i,t.a=s,t.b=n;break}}r?(n++,a=Math.max(a,Math.hypot(r.to[0]-r.from[0],r.to[1]-r.from[1]))):o++}return{space:e,report:{wallsStraightened:n,wallsStraightenSkipped:o,maxStraightenShift:a},changed:n>0}}(t);g+=e.report.wallsStraightened,f+=e.report.wallsStraightenSkipped;const i=Number(t?.cell_cm)>0?Number(t.cell_cm):5,s=e.report.maxStraightenShift/Ph*i;return s>v&&(v=s,y=String(t?.id||"")),e.space}),w=g?J_(b,m.layout):{...m,spaces:b};a.spaces=w.spaces;const k=g?{...m.report,moved:m.report.moved+w.report.moved,coordsCanonicalized:m.report.coordsCanonicalized+w.report.coordsCanonicalized,maxShift:Math.max(m.report.maxShift,w.report.maxShift),maxShiftCm:Math.max(m.report.maxShiftCm,w.report.maxShiftCm),maxSpace:w.report.maxShiftCm>m.report.maxShiftCm?w.report.maxSpace:m.report.maxSpace,rotated:m.report.rotated+w.report.rotated,removedDrafts:m.report.removedDrafts+w.report.removedDrafts}:{...m.report};let x=0,$=0,S=0,M=0,C=0,D=0,P=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),o=ig(e),r=ig(i);if(!o||!r)continue;const l=og(o.rooms),c=og(r.rooms),h=.02*Dh,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:wl(t.a,t.b,Ph),cm:0})),p=new Set(d.map(t=>t.key)),_=__(e,o.rooms,vh,h);$+=_.length;for(const t of _){const e=[t[0]/vh,t[1]/vh],i=[t[2]/vh,t[3]/vh],s=wl(e,i,Ph);p.has(s)||(p.add(s),d.push({key:s,a:e,b:i,cm:0}))}const m=d.length,g=Al(d,l,c,Ph,vh),f=(t,e,i)=>{const s=i[0]-e[0],n=i[1]-e[1],o=s*s+n*n;if(!(o>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const a=Math.max(0,Math.min(1,((t[0]-e[0])*s+(t[1]-e[1])*n)/o));return Math.hypot(t[0]-(e[0]+s*a),t[1]-(e[1]+n*a))},v=g.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*vh),i=t.b.map(t=>t*vh);return c.some(([t,s])=>f(e,t,s)<=4*h&&f(i,t,s)<=4*h)});S+=Math.max(0,m-v.length);const y=(i.wall_segments||[]).filter(t=>Number(t.cm)>0);i.wall_segments=[...y,...v.map(({key:t,...e})=>e)];const b=v.map(t=>[t.a[0]*vh,t.a[1]*vh,t.b[0]*vh,t.b[1]*vh]),w=Array.isArray(e.walls)?e.walls.length:0;let k=Al(e.walls,l,c,Ph,vh);k=ng(r.rooms,k,b,Ph,Number(i.cell_cm)>0?Number(i.cell_cm):5,Dh,vh),k=uc(r.rooms,k,b,Ph,Number(i.cell_cm)>0?Number(i.cell_cm):5,Dh,vh),k=Tl(k,i.rooms||[],Ph,1,b.map(t=>[t[0]/vh,t[1]/vh,t[2]/vh,t[3]/vh])),x+=Math.max(0,w-k.length),k.length?i.walls=k:delete i.walls;const R=sm(i.partitions||[],{pitch:Ph,geometry:om(i)});R.merged&&(M+=R.merged,i.partitions=R.partitions,nm(i.openings,i.partitions,R.openingMoves,{coordScale:vh,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,gridPitch:Dh}));const I=ig(i);if(I){const t=n(i,I,i.walls||[],b,{pitch:Ph,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,gridPitch:Dh,coordScale:vh});t.partitionsReconciled&&(C+=t.partitionsReconciled,D+=t.openingsRehosted,t.partitions.length?i.partitions=t.partitions:delete i.partitions,t.openings.length?i.openings=t.openings:delete i.openings,t.walls.length?i.walls=t.walls:delete i.walls),t.removedDrafts&&(P+=t.removedDrafts,t.roomDrafts.length?i.room_drafts=t.roomDrafts:delete i.room_drafts)}JSON.stringify({zero:(i.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:i.walls||[]})!==s&&T++}let R=0;h<=9&&(R=function(t){const e=Xm(t);return Qm(t,e.config),{...e,config:t}}(a).migratedSegments);const I=rl(a),A=al(w.layout),z=JSON.stringify(I)!==l||JSON.stringify(A)!==c;h<9&&z&&(I.model_version=9);const F=JSON.stringify(I)!==l||JSON.stringify(A)!==c,E=Number.isInteger(Number(I.model_version))?Number(I.model_version):h,N=F?k:{...k,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0,removedDrafts:0},O=F?o.report:{...o.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:I,layout:A,report:{...N,modelFrom:h,modelTo:E,migrated:F?p:0,glowSpacesMigrated:F?d.glowSpaces:0,glowRoomsMigrated:F?d.glowRooms:0,canonicalized:F?T:0,wallSegmentsMigrated:F?R:0,legacyZeroWallsMigrated:F?$:0,wallsMerged:F?x:0,spansMerged:F?S:0,partitionsMerged:F?M:0,partitionsReconciled:F?C:0,openingsRehosted:F?D:0,redundantDraftsRemoved:F?P:0,wallsStraightened:F?g:0,wallsStraightenSkipped:f,maxStraightenShiftCm:F?v:0,maxStraightenSpace:F?y:"",latticeCoordinatesCanonicalized:F?r.canonicalized:0,latticeCoordinatesFar:F?r.far:0,latticeMaxShift:F?r.maxShift:0,latticeMaxShiftCm:F?r.maxShiftCm:0,latticeSpaces:F?r.spaces:[],...O},changed:F}}function rg(t,e,i){const s=(t?.spaces||[]).find(t=>t?.id===i),n=new Set((s?.rooms||[]).map(t=>String(t?.id||"")).filter(Boolean)),o=[...new Set((t?.markers||[]).filter(t=>!0!==t?.removed&&"string"==typeof t?.id).filter(t=>t.space===i||"string"==typeof t.room_id&&n.has(t.room_id)||e?.[t.id]?.s===i).map(t=>t.id))].sort((t,e)=>t.localeCompare(e));return{markerIds:o,count:o.length}}function lg(t){return t instanceof Error?t.name||"Error":typeof t}function cg(t){return bd({id:t?.id??"",cell_cm:t?.cell_cm,rooms:t?.rooms||[],walls:t?.walls||[],wall_segments:t?.wall_segments||[],open_spans:t?.open_spans||[],openings:t?.openings||[],partitions:t?.partitions||[],room_drafts:t?.room_drafts||[],wall_columns:t?.wall_columns||[]})}function hg(t,e,i,s=Dh,n=1e3){return(Array.isArray(t?.openings)?t.openings:[]).flatMap(t=>{const o={...t,rx:Number(t.x)*n,ry:Number(t.y)*n,rlen:Number(t.length)*n};if(!t.host||"wall"===t.host.kind)return[o];const a=$p(t,e.partitions,n,i,s);return a.resolved?[{...t,rx:a.resolved.center[0],ry:a.resolved.center[1],rlen:a.resolved.length,angle:a.resolved.angle,partitionHost:a.resolved}]:[]})}function dg(t,e=()=>!0){return t.flatMap(t=>t.host&&t.partitionHost&&e(t)?[Cp(t.partitionHost)]:[])}function pg(t,e,i,s,n,o,a=Dh,r=1e3){const l=dc(e.rooms,[...i],s,n,o,a,r);return t.flatMap(t=>{const e={x:t.rx,y:t.ry,angle:Number(t.angle)||0,length:t.rlen};return t.host&&"wall"!==t.host.kind?t.partitionHost&&Tp(t.partitionHost,l,2e-4*a)?[e]:[]:[e]})}function ug(t,e){const i=Ph,s=Dh,n=vh,o=Number.isFinite(Number(e.cellCm))&&Number(e.cellCm)>0?Number(e.cellCm):5,a=Array.isArray(t?.walls)?t.walls:[],r=function(t,e,i=Dh,s=1e3){return ud(e.rooms,t?.open_spans,s,.02*i)}(t,e,s,n),l=function(t,e,i=Dh){if(!e.length)return[];const s=t.filter(t=>t?.id),n=.02*i,o=[];for(let t=0;t{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return h.some(t=>Ls(e,t)<4*n)}).map(t=>[...t]);d.length&&o.push({a:a,b:r,segs:d})}return o}(e.rooms,r,s).flatMap(t=>t.segs),c=hg(t,e,o,s,n),h=dg(c),d=eh(e,o,s,2e-4*s,h).all;return{space:e,walls:a,openCuts:l,openings:c,roomOpenings:pg(c,e,a,l,i,o,s,n),partitionCuts:h,physicalBodies:d,wallKeyPitch:i,cellCm:o,gridPitch:s,coordScale:n}}function _g(t,e,i){const s="string"==typeof t?.title?t.title.trim():"",n=null==t?.id?"":String(t.id).trim();return{spaceId:n,displayName:s||n||i(e+1)}}function mg(t,e={}){const i=(e.fingerprint||bd)(t),s=Array.isArray(t?.spaces)?t.spaces:[],n=e.fallbackSpaceName||(t=>`Space ${t}`),o=e.prepareSpace||ug,a=e.wallPass||Rc,r=e.floorPass||Pc,l=[];for(let e=0;e0||h.physicalBodies.length>0;if(!h.space.rooms.length&&!d){l.push({...c,status:"not-applicable"});continue}let p=null;if(d){try{p=a(h.space.rooms,h.walls,h.openCuts,h.roomOpenings,h.wallKeyPitch,h.cellCm,h.gridPitch,h.coordScale,h.physicalBodies)}catch(t){l.push({...c,status:"failed",reason:"wall-exception",detail:lg(t)});continue}if(null==p){l.push({...c,status:"failed",reason:"wall-null"});continue}if("degraded-extra"===p.status){l.push({...c,status:"failed",reason:"wall-degraded-extra"});continue}if("failed-core"===p.status){l.push({...c,status:"failed",reason:"wall-failed-core"});continue}}if(h.space.rooms.length&&null==p?.paperGeom){let t;try{t=r(h.space.rooms,h.walls,h.openCuts,h.wallKeyPitch,h.cellCm,h.gridPitch,h.coordScale)}catch(t){l.push({...c,status:"failed",reason:"floor-exception",detail:lg(t)});continue}if(null==t){l.push({...c,status:"failed",reason:"floor-null"});continue}}l.push({...c,status:"ok"})}const c=l.filter(t=>"failed"===t.status);return{fingerprint:i,spaces:l,failures:c,ok:0===c.length}}class gg{constructor(t=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(t))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(t){this._undo.push(t),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const t=this._undo.pop()??null;return t&&this._redo.push(t),t}redo(){const t=this._redo.pop()??null;return t&&this._undo.push(t),t}clear(){this._undo=[],this._redo=[]}}const fg=new WeakMap;const vg=(t,e,i)=>255===t[i+3]&&e.every((e,s)=>Math.abs(t[i+s]-e)<=2);async function yg(t){const e=t.defaultView;if(!e||!e.CSS?.supports?.("mix-blend-mode","screen"))return!1;const i=[128,32,16],s=[16,64,128],n=[9,19,29],o=`\n \n \n \n \n \n `,a=e.URL.createObjectURL(new Blob([o],{type:"image/svg+xml"}));try{const o=await new Promise((t,i)=>{const s=new e.Image,n=e.setTimeout(()=>i(new Error("SVG blend probe timeout")),1e3);s.onload=()=>{e.clearTimeout(n),t(s)},s.onerror=()=>{e.clearTimeout(n),i(new Error("SVG blend probe failed"))},s.src=a}),r=t.createElement("canvas");r.width=4,r.height=1;const l=r.getContext("2d",{willReadFrequently:!0});if(!l)return!1;l.drawImage(o,0,0,4,1);const c=l.getImageData(0,0,4,1).data;return vg(c,i,0)&&vg(c,function(t,e){return[0,1,2].map(i=>Math.round(255-(255-t[i])*(255-e[i])/255))}(i,s),4)&&vg(c,s,8)&&vg(c,n,12)}catch{return!1}finally{e.URL.revokeObjectURL(a)}}const bg={now:()=>performance.now(),requestFrame:t=>requestAnimationFrame(t),cancelFrame:t=>cancelAnimationFrame(t)},wg=t=>Math.max(0,Math.min(1,t)),kg=(t,e,i)=>t+(e-t)*i,xg=(t,e,i)=>{const s=1-t;return 3*s*s*t*e+3*s*t*t*i+t*t*t};function $g(t,e){return{centerX:t.x+t.w/2,centerY:t.y+t.h/2,pixelsPerUnit:e>0&&t.w>0?e/t.w:1,viewBox:{...t}}}function Sg(t,e,i){const s=Math.max(1e-9,t.pixelsPerUnit),n=Math.max(1e-9,e/s),o=Math.max(1e-9,i/s);return{x:t.centerX-n/2,y:t.centerY-o/2,w:n,h:o}}function Mg(t){const e=t.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(e);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const s=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(e)?.[1];return s?[parseInt(s.slice(0,2),16),parseInt(s.slice(2,4),16),parseInt(s.slice(4,6),16),8===s.length?parseInt(s.slice(6,8),16)/255:1]:null}function Cg(t,e,i){const s=Mg(t),n=Mg(e);if(!s||!n)return i<.5?t:e;const o=wg(i);return`rgba(${Math.round(kg(s[0],n[0],o))}, ${Math.round(kg(s[1],n[1],o))}, ${Math.round(kg(s[2],n[2],o))}, ${kg(s[3],n[3],o).toFixed(3)})`}function Dg(t,e,i){const s=(t=>{const e=wg(t);if(0===e||1===e)return e;let i=0,s=1,n=e;for(let t=0;t<12;t++)n=(i+s)/2,xg(n,.2,.2){const e=this._state;if(!e||e.token!==n)return;const i=wg((t-e.startedAt)/e.duration);e.presented=i>=1?e.to:Dg(e.from,e.to,i),e.phase=i>=1?"settling":"running",this._hooks.frame(e),i<1?this._raf=this._clock.requestFrame(a):(this._raf=0,this._hooks.settled(e),this._state?.token===n&&(this._state=null))};return this._raf=this._clock.requestFrame(a),n}cancel(t=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const e=this._state;this._state=null,this._token++,e&&t&&(e.phase="settling",e.presented=e.to,this._hooks.frame(e),this._hooks.settled(e))}dispose(){this.cancel(!1)}}const Tg="houseplan_card_labs_v1",Rg=Object.freeze([Object.freeze({id:"iso",issue:89,since:"1.62.0",expires:"1.65.0",summary:"Volumetric plan renderer"})]);function Ig(t){const e=/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/.exec(String(t||"").trim());if(!e)return null;const i=e.slice(1).map(Number);return i.every(t=>Number.isSafeInteger(t))?i:null}function Ag(t,e){for(let i=0;i<3;i++)if(t[i]!==e[i])return t[i]t.split(",")).map(t=>t.trim()).filter(Boolean)}function Lg(t,e,i,s=Rg){const n=function(t,e=Rg){const i=Ig(t),s=new Map;if(!i||!Fg(e))return s;for(const t of e){const e=Ig(t.since),n=Ig(t.expires);Ag(i,e)>=0&&Ag(i,n)<0&&s.set(t.id,t)}return s}(i,s),o=new Set(Fg(s)?s.map(t=>t.id):[]),a=new Set(function(t){if(!t)return[];try{const e=JSON.parse(t);return Array.isArray(e)?e.filter(t=>"string"==typeof t):[]}catch{return[]}}(e).filter(t=>n.has(t)));let r=!1;const l=t=>{if("off"===t)return a.clear(),void(r=!0);const e=t.startsWith("-"),i=e?t.slice(1):t;o.has(i)&&(r=!0,e||!n.has(i)?a.delete(i):a.add(i))};for(const e of Og(new URLSearchParams(String(t.search||"").replace(/^\?/,""))))l(e);for(const e of Og(Eg(t.hash)))l(e);const c=Object.freeze([...a].sort());return{active:c,space:Ng(t.hash),persist:r?JSON.stringify(c):void 0,knownUrlOperation:r}}let Hg={active:Object.freeze([]),space:""},Bg="",qg=!1,Wg="";const jg=new Set;function Ug(){if("undefined"==typeof window)return Hg;const t=Lg(window.location,function(){try{return window.localStorage.getItem(Tg)}catch{return null}}(),Bg);void 0!==t.persist&&function(t){try{window.localStorage.setItem(Tg,t)}catch{}}(t.persist),Hg={active:t.active,space:t.space},window.__hpLabs=t.active;for(const t of jg)t(Hg);return Hg}function Gg(){Ug()}function Vg(t){return Bg=t,"undefined"==typeof window?Hg:(qg||(qg=!0,window.addEventListener("hashchange",Gg),window.addEventListener("popstate",Gg)),Ug())}const Kg=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])});function Yg(t){return[t.rotDeg,t.tiltDeg,t.xyScale,t.zScale,t.origin[0],t.origin[1]].every(Number.isFinite)&&Math.abs(t.xyScale)>1e-12&&Math.abs(Math.cos(t.tiltDeg*Math.PI/180))>1e-12}function Jg(t,e,i=Kg){if(!(Yg(i)&&Number.isFinite(t[0])&&Number.isFinite(t[1])&&Number.isFinite(e)))throw new Error("invalid isometric projection input");const s=i.rotDeg*Math.PI/180,n=i.tiltDeg*Math.PI/180,o=t[0]-i.origin[0],a=t[1]-i.origin[1],r=(o*Math.cos(s)-a*Math.sin(s))*i.xyScale,l=(o*Math.sin(s)+a*Math.cos(s))*i.xyScale;return[i.origin[0]+r,i.origin[1]+l*Math.cos(n)-e*i.zScale*Math.sin(n)]}function Xg(t,e=Kg){if(!Yg(e)||!Number.isFinite(t[0])||!Number.isFinite(t[1]))throw new Error("invalid isometric projection input");const i=e.rotDeg*Math.PI/180,s=e.tiltDeg*Math.PI/180,n=(t[0]-e.origin[0])/e.xyScale,o=(t[1]-e.origin[1])/(e.xyScale*Math.cos(s));return[e.origin[0]+n*Math.cos(i)+o*Math.sin(i),e.origin[1]-n*Math.sin(i)+o*Math.cos(i)]}function Zg(t=Kg){return`matrix(${function(t=Kg){if(!Yg(t))throw new Error("invalid isometric camera");const e=t.rotDeg*Math.PI/180,i=t.tiltDeg*Math.PI/180,s=t.xyScale*Math.cos(e),n=-t.xyScale*Math.sin(e),o=t.xyScale*Math.sin(e)*Math.cos(i),a=t.xyScale*Math.cos(e)*Math.cos(i);return[s,o,n,a,t.origin[0]-s*t.origin[0]-n*t.origin[1],t.origin[1]-o*t.origin[0]-a*t.origin[1]]}(t).map(t=>Number(t.toFixed(12))).join(" ")})`}function Qg(t,e=Kg){const{rect:i,wallHeight:s}=t,n=t.openingHeight??s,o=t.floorDepth??0;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(s)||!Number.isFinite(n)||!Number.isFinite(o)||s<0||n<0||o<0)throw new Error("invalid isometric frame");const a=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],r=Math.max(s,n),l=a.flatMap(t=>[Jg(t,-o,e),Jg(t,r,e)]),c=l.map(t=>t[0]),h=l.map(t=>t[1]),d=Math.min(...c),p=Math.min(...h);return{x:d,y:p,w:Math.max(...c)-d,h:Math.max(...h)-p}}const tf=t=>`${Number(t[0].toFixed(4))} ${Number(t[1].toFixed(4))}`;function ef(t){let e=0;for(let i=0;iArray.isArray(t)&&Number.isFinite(t[0])&&Number.isFinite(t[1])).map(t=>[Number(t[0]),Number(t[1])]),i=e[e.length-1];return e.length>1&&e[0][0]===i[0]&&e[0][1]===i[1]&&e.pop(),e}(t);if(i.length<3)return[];const s=!e;return ef(i)>0===s?i:[...i].reverse()}function nf(t,e,i){return t.length?`M ${t.map(t=>tf(Jg(t,i,e))).join(" L ")} Z`:""}function of(t,e,i){const s=e[1]-t[1],n=-(e[0]-t[0]),o=i.rotDeg*Math.PI/180;return s*Math.sin(o)+n*Math.cos(o)}function af(t,e,i=Kg){if(!Number.isFinite(e)||e<0)throw new Error("invalid floor edge height");const s=(t||[]).map(t=>(t||[]).map((t,e)=>function(t,e){const i=sf(t,e);if(!i.length)return i;let s=0;for(let t=1;t0)).filter(t=>t.length>=3&&Math.abs(ef(t))>=1e-9)).filter(t=>t.length&&ef(t[0])>0);s.sort((t,e)=>{const i=t[0][0],s=e[0][0];return i[0]-s[0]||i[1]-s[1]||Math.abs(ef(e[0]))-Math.abs(ef(t[0]))});const n=[],o=[];let a=0;for(let t=0;tt.depth-e.depth||t.component-e.component||t.edge-e.edge),{footprintPath:n.join(" "),sides:o,componentCount:s.length,edgeCount:a}}function rf(t,e){return t^=Math.round(64*(Number.isFinite(e)?e:0)),Math.imul(t,16777619)>>>0}const lf=t=>t.every(Number.isFinite);function cf(t,e,i,s){const n=t[0]*i,o=t[1]*s,a=e*Math.PI/180;return[n*Math.cos(a)-o*Math.sin(a),n*Math.sin(a)+o*Math.cos(a)]}function hf(t,e,i,s,n,o,a){const r=t.flipH?-1:1,l="gate"===t.type?1:t.flipV?-1:1,c=(t.type,t.flipV,t.angle,t.face,{ox:0,oy:0}),h=function(t,e){return[t[0]+e[0],t[1]+e[1]]}([t.x+c.ox,t.y+c.oy],cf(i,t.angle,r,l));return{leaf:e,hinge:h,closedVector:cf(s,t.angle,r,l),quarterVector:cf([-s[1],s[0]],t.angle,r,l),turnDeg:n,bottom:o,top:a}}const df=t=>`${Number(t[0].toFixed(4))} ${Number(t[1].toFixed(4))}`;function pf(t,e,i=Kg){const s=Math.max(0,Math.min(1,Number.isFinite(e)?e:0));return t.leaves.map(e=>{const n=function(t,e){const i=t.turnDeg*e*Math.PI/180;return[t.hinge[0]+t.closedVector[0]*Math.cos(i)+t.quarterVector[0]*Math.sin(i),t.hinge[1]+t.closedVector[1]*Math.cos(i)+t.quarterVector[1]*Math.sin(i)]}(e,s),o=Jg(e.hinge,e.bottom,i),a=Jg(n,e.bottom,i),r=Jg(n,e.top,i),l=Jg(e.hinge,e.top,i);return{id:t.id,sourceIndex:t.sourceIndex,type:t.type,leaf:e.leaf,d:`M ${df(o)} L ${df(a)} L ${df(r)} L ${df(l)} Z`,shadowD:`M ${df(Jg(e.hinge,0,i))} L ${df(Jg(n,0,i))}`,depth:Math.max(o[1],a[1])}})}const uf={window:120,door:90,passage:90,gate:300};function _f(t){return uf[t]}function mf(t,e){const i=[t[0],t[1]],s=[e[0],e[1]];return function(t,e){return t[0]-e[0]||t[1]-e[1]}(i,s)<=0?{a:i,b:s}:{a:s,b:i}}function gf(t){const e=new Map;return t.forEach((t,i)=>{if(!t.kind||t.open)return;const s=mf(t.a,t.b);if(Math.hypot(s.b[0]-s.a[0],s.b[1]-s.a[1])<=1e-9)return;const n=function(t,e){const i=t=>(Math.abs(t)<=5e-10?0:Math.round(1e6*t)/1e6).toFixed(6);return`${i(t[0])},${i(t[1])}>${i(e[0])},${i(e[1])}`}(s.a,s.b),o=e.get(n);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,t.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(t.partitionHost&&(o.partitionHost&&o.partitionHost.id!==t.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=t.partitionHost));e.set(n,{segmentKey:n,a:s.a,b:s.b,physicalHalfWidth:Math.max(0,t.half||0),sourceOrder:i,...t.partitionHost?{partitionHost:t.partitionHost}:{}})}),[...e.values()]}function ff(t,e){if(Math.abs(t.distance-e.distance)>1e-9)return t.distance-e.distance;if(Math.abs(t.perpendicular-e.perpendicular)>1e-9)return t.perpendicular-e.perpendicular;return(t.target.segmentKeye.target.segmentKey?1:0)||t.target.sourceOrder-e.target.sourceOrder}function vf(t){const e=gf(t.intervals).map(e=>{const i=function(t,e){const i=e.b[0]-e.a[0],s=e.b[1]-e.a[1],n=Math.hypot(i,s),o=i/n,a=s/n,r=(t[0]-e.a[0])*o+(t[1]-e.a[1])*a,l=Math.max(0,Math.min(n,r)),c=e.a[0]+l*o,h=e.a[1]+l*a;return{along:l,length:n,x:c,y:h,distance:Math.hypot(t[0]-c,t[1]-h),perpendicular:Math.abs((t[0]-e.a[0])*a-(t[1]-e.a[1])*o)}}(t.pointer,e);return{target:e,...i,envelope:Math.max(t.baseTolerance,e.physicalHalfWidth+t.bodyPointerPadding)}}).filter(t=>t.distance<=t.envelope+1e-9).filter(e=>!function(t,e,i,s,n){const o=e.b[0]-e.a[0],a=e.b[1]-e.a[1],r=Math.hypot(o,a);if(!(r>1e-9))return!1;const l=o/r,c=a/r;for(const o of i){if(!o.open&&o.kind)continue;const i=mf(o.a,o.b),a=i.b[0]-i.a[0],r=i.b[1]-i.a[1],h=Math.hypot(a,r);if(!(h>1e-9))continue;const d=a/h,p=r/h;if(Math.abs(l*p-c*d)>1e-6)continue;if(Math.abs((i.a[0]-e.a[0])*c-(i.a[1]-e.a[1])*l)>n)continue;const u=(t[0]-i.a[0])*d+(t[1]-i.a[1])*p,_=1e-9;if(!(u<=_||u>=h-_)&&Math.abs((t[0]-i.a[0])*p-(t[1]-i.a[1])*d)<=s+1e-9)return!0}return!1}(t.pointer,e.target,t.intervals,e.envelope,Math.max(1e-9,Math.min(t.baseTolerance,.04*t.gridStep)))),i=e.filter(e=>!!e.target.partitionHost&&t.renderedLength+2*e.target.physicalHalfWidth>e.length+1e-9).sort(ff),s=e.filter(e=>!e.target.partitionHost||t.renderedLength+2*e.target.physicalHalfWidth<=e.length+1e-9).sort(ff);let n=s[0];if(!n)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=s.filter(t=>Math.abs(t.distance-n.distance)<=1e-9&&Math.abs(t.perpendicular-n.perpendicular)<=1e-9),a=o.filter(t=>t.target.partitionHost);if(a.length){if(1!==new Set(a.map(t=>t.target.partitionHost.id)).size||a.some(t=>t.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const t=a[0],e=t.target.b[0]-t.target.a[0],i=t.target.b[1]-t.target.a[1],s=Math.hypot(e,i),r=e/s,l=i/s,c=o.every(e=>{const i=e.target.b[0]-e.target.a[0],s=e.target.b[1]-e.target.a[1],n=Math.hypot(i,s),o=i/n,a=s/n,c=Math.abs(r*a-l*o)<=1e-6,h=Math.abs((e.target.a[0]-t.target.a[0])*l-(e.target.a[1]-t.target.a[1])*r);return c&&h<=1e-9});if(!c)return{candidate:null,jambBlockedTarget:null};n=t}if(n.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:r,length:l}=n,c=r.b[0]-r.a[0],h=r.b[1]-r.a[1],d=c/l,p=h/l,u=r.partitionHost?r.physicalHalfWidth:0,_=Math.min(Math.max(0,t.renderedLength)/2+u,l/2);let m=n.along;const g=Math.max(t.gridStep,1e-9),f=l/2;m=Math.abs(m-f)<=g/2?f:Math.round(m/g)*g,m=Math.max(_,Math.min(l-_,m));const v=r.a[0]+d*m,y=r.a[1]+p*m,b=Math.max(0,t.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),$=Math.max(0,l-k),S=[r.a[0]+d*(w-x/2),r.a[1]+p*(w-x/2)],M=[r.a[0]+d*(k+$/2),r.a[1]+p*(k+$/2)];let C=180*Math.atan2(h,c)/Math.PI;C>=90?C-=180:C<-90&&(C+=180);const D=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:t.preset.revision,geometryRevision:t.geometryRevision,pointer:[t.pointer[0],t.pointer[1]],type:t.preset.type,lengthCm:t.preset.lengthCm,flipH:t.preset.flipH,flipV:t.preset.flipV,x:v,y:y,angle:C,renderedLength:t.renderedLength,target:r,...r.partitionHost?{host:{...r.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:S},{distance:$,midpoint:M}],guide:D?{x:v,y:y,angle:C}:null}},jambBlockedTarget:null}}function yf(t,e,i,s,n=1e-6){return t.presetRevision===i&&t.geometryRevision===s&&Math.hypot(t.pointer[0]-e[0],t.pointer[1]-e[1])<=n}const bf=(t,e)=>t[0]*e[1]-t[1]*e[0],wf=(t,e)=>t[0]*e[0]+t[1]*e[1],kf=(t,e)=>[t[0]-e[0],t[1]-e[1]],xf=(t,e,i)=>[t[0]+e[0]*i,t[1]+e[1]*i];function $f(t,e,i){return Math.abs(bf(t,e))<=i}function Sf(t,e,i){return Math.abs(bf(kf(t,e),i))}function Mf(t,e,i,s,n){const o=e[0]-t[0],a=e[1]-t[1],r=Math.hypot(o,a);if(!(r>n&&i>0))return[];const l=[o/r,a/r];return function(t,e,i){const s=e.map(([e,i])=>[Math.max(0,Math.min(e,i)),Math.min(t,Math.max(e,i))]).filter(([t,e])=>e>t+i).sort((t,e)=>t[0]-e[0]||t[1]-e[1]),n=[];for(const t of s){const e=n[n.length-1];!e||t[0]>e[1]+i?n.push([...t]):e[1]=Math.max(e[1],t[1])}const o=[];let a=0;for(const[t,e]of n)t>a+i&&o.push([a,t]),a=Math.max(a,e);return t>a+i&&o.push([a,t]),o}(r,s.flatMap(e=>{const s=e.b[0]-e.a[0],o=e.b[1]-e.a[1],a=Math.hypot(s,o);if(!(a>n&&$f(l,[s/a,o/a],1e-6)))return[];if(Sf(e.a,t,l)>1.1*Math.max(i,n)||Sf(e.b,t,l)>1.1*Math.max(i,n))return[];return[[wf(kf(e.a,t),l),wf(kf(e.b,t),l)]]}),n).flatMap(([e,s])=>{const n=Ol({a:xf(t,l,e),b:xf(t,l,s),halfDepth:i});return n?[n]:[]})}function Cf(t){const e=t.coordScale??1,i=Math.max(t.epsilon??2e-4*t.gridPitch,1e-9),s=[];for(const i of t.rooms||[]){if(!i?.id)continue;const n=hc(t.rooms,i.id,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e);if(!n||n.poly.length<3)continue;const o=Zl(n.poly,n.offsets);!o||o.length<3||s.push({roomId:i.id,profile:n,inner:o})}s.sort((t,e)=>t.roomId.localeCompare(e.roomId));const n=(t.roomOpenings||[]).map(t=>{const e=t.angle*Math.PI/180,i=[Math.cos(e),Math.sin(e)],s=Math.max(0,t.length)/2;return{a:xf([t.x,t.y],i,-s),b:xf([t.x,t.y],i,s)}}),o=[];for(const s of Ac(t.rooms,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e))for(const t of Mf(s.a,s.b,s.depthUnits/2,n,i))o.push({body:t});const a=new Map;for(const e of t.partitionCuts||[]){const t=a.get(e.hostId)||[];t.push(e),a.set(e.hostId,t)}for(const e of t.partitions||[]){const s=gl(e.cm,t.cellCm,t.gridPitch)/2;for(const t of Mf(e.a,e.b,s,a.get(e.id)||[],i))o.push({body:t,partitionId:e.id})}return{rooms:s,boundaries:o,epsilon:i}}function Df(t,e,i,s){const n=t.profile.offsets[e];if(!(n>0))return null;const o=function(t,e){const i=t[e],s=t[(e+1)%t.length],n=s[0]-i[0],o=s[1]-i[1],a=Math.hypot(n,o)||1;return function(t){let e=0;for(let i=0;i=0?[-o/a,n/a]:[o/a,-n/a]}(t.profile.poly,e),a=xf(i.center,o,n),r=[];for(let e=0;es&&$f(i.axis,[l[0]/c,l[1]/c],1e-6)))continue;if(Sf(n,a,i.axis)>s||Sf(o,a,i.axis)>s)continue;const h=wf(kf(n,a),i.axis),d=wf(kf(o,a),i.axis);r.push([Math.min(h,d),Math.max(h,d)])}const l=function(t,e){t.sort((t,e)=>t[0]-e[0]||t[1]-e[1]);const i=[];for(const s of t){const t=i[i.length-1];!t||s[0]>t[1]+e?i.push([...s]):t[1]=Math.max(t[1],s[1])}return i}(r,s).find(([t,e])=>t<=s&&e>=-s);if(!l)return null;const[c,h]=l,d=xf(a,i.axis,-i.half),p=xf(a,i.axis,i.half),u=Math.max(0,-i.half-c),_=Math.max(0,h-i.half),m=u>0?xf(a,i.axis,c):d,g=_>0?xf(a,i.axis,h):p,f=wf(o,i.normal)>=0?1:-1,v=(e,s,n)=>({from:e,to:s,label:[(e[0]+s[0])/2,(e[1]+s[1])/2],axis:i.axis,labelNormal:o,distance:n,roomId:t.roomId,roomSide:f,source:"room-face"});return{left:v(d,m,u),right:v(p,g,_)}}function Pf(t){const e=xf(t.center,t.axis,-t.half),i=xf(t.center,t.axis,t.half),s=xf(t.center,t.axis,Math.min(-t.half,t.targetLo)),n=xf(t.center,t.axis,Math.max(t.half,t.targetHi)),o=(e,i)=>({from:e,to:i,label:[(e[0]+i[0])/2,(e[1]+i[1])/2],axis:t.axis,labelNormal:t.normal,distance:Math.hypot(i[0]-e[0],i[1]-e[1]),source:"host-end"});return[o(e,s),o(i,n)]}function Tf(t,e,i,s){const n=kf(i,e),o=wf(n,n);if(!(o>s*s))return Math.hypot(...kf(t,e))<=s;const a=wf(kf(t,e),n)/o;if(a<-s||a>1+s)return!1;const r=xf(e,n,Math.max(0,Math.min(1,a)));return Math.hypot(...kf(t,r))<=s}function Rf(t,e,i){let s=!1;for(let n=0,o=e.length-1;nt[1]!=c>t[1]&&t[0]<(l-a)*(t[1]-r)/(c-r)+a&&(s=!s)}return s}function If(t,e,i,s,n,o){const a=kf(s,i),r=bf(e,a);if(Math.abs(r)<=o)return null;const l=kf(i,t),c=bf(l,a)/r,h=bf(l,e)/r;return c<-o||c>n+o||h<-o||h>1+o?null:Math.max(0,Math.min(n,c))}function Af(t,e,i){const s=Pf(i),n="partition"===t.host?.kind?t.host.id:void 0;return[{base:s[0],direction:[-i.axis[0],-i.axis[1]]},{base:s[1],direction:i.axis}].map(({base:t,direction:i})=>{const s=t.distance,o=function(t,e,i,s,n,o){let a=null;for(const r of s)if(!n||r.partitionId!==n){if(Rf(t,r.body,o))return 0;for(let s=0;swf(kf(t,n),i));return{center:n,axis:i,normal:s,half:Math.max(0,t.renderedLength)/2,targetLo:Math.min(...o),targetHi:Math.max(...o)}}(t),s=e.rooms.flatMap(t=>{const s=function(t,e,i){const{profile:s}=t;let n=null;for(let t=0;t0))continue;const o=s.poly[t],a=s.poly[(t+1)%s.poly.length],r=kf(a,o),l=Math.hypot(r[0],r[1]);if(!(l>i&&$f(e.axis,[r[0]/l,r[1]/l],1e-6)))continue;if(Sf(o,e.center,e.axis)>i||Sf(a,e.center,e.axis)>i)continue;const c=wf(kf(o,e.center),e.axis),h=wf(kf(a,e.center),e.axis),d=Math.min(c,h),p=Math.max(c,h);if(d>-e.half+i||p0?d:p<0?-p:0);(!n||u2)return Pf(i);if(s.length){const t=s.map(({room:t,edge:s})=>Df(t,s,i,e.epsilon));if(t.some(t=>!t))return Pf(i);const n=t;return[...n.map(t=>t.left),...n.map(t=>t.right)]}return Af(t,e,i)}function Ff(t){return!(!t.canEdit||t.kiosk||t.fixedFloor)&&("view"!==t.mode&&("mouse"===t.pointerType&&t.spaceCount>1))}const Ef="1.68.0-beta.3",Nf={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon"},Of={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon"},Lf=2e3,Hf=1e3,Bf=1500,qf=t=>{const e=String(t??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e))return null;const i=Number(e);return Number.isFinite(i)?i:null},Wf=(t,e)=>{if(!t.has(e))return{hit:!1};const i=t.get(e);return t.delete(e),t.set(e,i),{hit:!0,value:i}},jf=(t,e,i,s)=>{for(t.delete(e),t.set(e,i);t.size>s;){const e=t.keys().next().value;if(void 0===e)break;t.delete(e)}},Uf=new Map;let Gf=0;const Vf=t=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(t??{})}`;let Kf=1e4;const Yf="houseplan_card_layout_v1",Jf="houseplan_card_cfg_v1",Xf="houseplan_card_zoom_v1",Zf="houseplan_card_nav_v1",Qf="houseplan_card_kiosk_v1",tv="houseplan_card_view_v1",ev="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",iv=1e3,sv=[[0,1],[45,.88],[70,.62],[86,.32],[100,0]],nv=(t,e)=>{const i=Math.min(t.x,e.x),s=Math.min(t.y,e.y);return{x:i,y:s,w:Math.max(t.x+t.w,e.x+e.w)-i,h:Math.max(t.y+t.h,e.y+e.h)-s}},ov=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),av=2e3,rv=(t,e,i)=>{const s=new Event(e,{bubbles:!0,composed:!0});s.detail=i??{},t.dispatchEvent(s)},lv=t=>{history.pushState(null,"",t),rv(window,"location-changed",{replace:!1})},cv=(t,e)=>{let i,s=null;const n=(...n)=>{clearTimeout(i),s=n,i=window.setTimeout(()=>{i=void 0;const e=s;s=null,e&&t(...e)},e)};return n.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const e=s;s=null,e&&t(...e)},n.cancel=()=>{clearTimeout(i),i=void 0,s=null},n.pending=()=>void 0!==i,n},hv=t=>{try{t.target?.setPointerCapture?.(t.pointerId)}catch{}};class dv extends ht{constructor(){super(...arguments),this._space="f1",this._layout={},this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._serverCfg=null,this._cfgRev=0,this._cfgContentFingerprint="",this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._layoutRev=0,this._layoutContentFingerprint="",this._virtualLights=mn(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._tip=null,this._hoverRoom=null,this._pointerModality=new E_(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...Rr},this._decorDraft=null,this._decorMove=null,this._decorSel=null,this._decorEraseConfirm=null,this._decorTextDialog=null,this._decorShapeDialog=null,this._backdropDialog=null,this._decorTextSelection={start:0,end:0},this._furnPalette=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=t=>{this._reducedMotion=t.matches,this._cancelDevicePressFeedback(),t.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:t.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new Pg({frame:t=>this._applyModeTransitionFrame(t),settled:t=>this._settleModeTransition(t)}),this._editorSecondary=new q_({root:()=>this.renderRoot,requestUpdate:()=>this.requestUpdate(),updateComplete:()=>this.updateComplete,clearTip:()=>{this._tip=null}}),this._editorSecondaryCopy={groupActive:(t,e)=>this._t("editor.group_active",{group:t,item:e}),openGroup:t=>this._t("editor.open_group",{group:t}),disabledAction:(t,e)=>this._t("editor.disabled_action",{action:t,reason:e})},this._tool="draw",this._geometryHistory=new gg(50),this._wallDialog=null,this._drawWallField=null,this._activeDraftId=null,this._resumeDraftBySpace={},this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCache=null,this._isoGeometryCache=new Map,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._glowClipCache=new Map,this._glowGeometryWarnings=new Set,this._lightBarrierCache=null,this._glowFeatherUnits=null,this._glowRenderedSources=new Map,this._glowLastAppearance=new Map,this._glowEnteringSources=new Set,this._glowEnterRafs=new Map,this._glowFadeTimers=new Map,this._glowFeatherSuspendUntil=0,this._glowFeatherResumeTimer=0,this._glowSourceSeq=0,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszSel=null,this._rszDrag=null,this._rszEligibilityCache=null,this._rszPreview=null,this._rszLive=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._suppressClick=!1,this._touchContacts=new Map,this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:t=>this._guardTouchGesture(t)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._alignDialog=null,this._settingsDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=t=>this._onKey(t),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++Gf,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=t=>{if(this._continuity.visibility(t),this._dayCycleVisibility(t),"hidden"===t.kind)return this._clearTransientHover(!0),this._cancelDevicePressFeedback(),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,!t.long){const t=Date.now();let e=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+R_)>t||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,e=!0);return void(e&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._lastTap=0,this._onLabsSnapshot=t=>{const e=this._effectiveProjection();this._labs=t;const i=this._effectiveProjection();this._convertProjectionView(e,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const t=this._hashSpace();if(t&&this._model.find(e=>e.id===t)&&t!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(t),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._onHaRegistryUpdate=()=>{const t=An(this.hass);t.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=t.revision,this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,function(t){const e=Cn(t);e&&(Tn(t,e),Rn(t,e))}(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new xd(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=cv(()=>{if(this._serverStorage){const t=[...this._dirtyPos];this._dirtyPos.clear();for(const e of t){const t=ol(this._layout[e]);t&&(this._layout={...this._layout,[e]:t},this._sentPos.set(e,t),this.hass.callWS({type:"houseplan/layout/update",device_id:e,pos:t}).then(t=>this._noteLayoutRev(t)).catch(t=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))).finally(()=>{this._sentPos.get(e)===t&&this._sentPos.delete(e)}))}this._cacheSnapshot()}else this._layout=al(Gr(this._layout)),localStorage.setItem(Yf,JSON.stringify(this._layout))},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>{if(this._physicalDrag||this._physicalRotate)return void this._cancelPhysicalGesture();if(this._decorDraft)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove||this._dtDrag||this._bdDrag)return void this._cancelDecorGesture();if(this._rszDrag)return void this._rszCancelDrag();const t=this._geometryHistory.undo();t&&(this._applyGeometryState(t.before,!0)?this._showToast(this._t("history.undone",{name:t.name})):this._geometryHistory.clear())},this._redoGeometry=()=>{if(this._physicalDrag||this._physicalRotate)return void this._cancelPhysicalGesture();if(this._decorDraft)return this._decorDraft=null,void this.requestUpdate();if(this._decorMove||this._dtDrag||this._bdDrag)return void this._cancelDecorGesture();if(this._rszDrag)return void this._rszCancelDrag();const t=this._geometryHistory.redo();t&&(this._applyGeometryState(t.after,!0)?this._showToast(this._t("history.redone",{name:t.name})):this._geometryHistory.clear())},this._saveConfigDebounced=cv(()=>{this._serverCfg&&this._writeConfig().catch(t=>{const e=!0===t?.physicalGeometryRolledBack;"geometry-unsafe"!==t?.code&&("wall_model_client_outdated"===t?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===t?.code?(this._showToast(this._t("toast.conflict")),e||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(t)})),e&&this._reloadRejectedPhysicalWrite())})},500),this._draftSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>{const t=this._physicalDialog,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=qf(t.cm);if(null==s)return void this._showPhysicalRange("column"===t.kind?Wc:100,"column"===t.kind?1:0);const n=this._imperial?2.54*s:s,o="column"===t.kind?Wc:100,a="column"===t.kind?1:0;if(!Number.isFinite(n)||no)return void this._showPhysicalRange(o,a);if("column"===t.kind){const e=i.wall_columns.find(e=>e.id===t.id);if(!e)return;const s=qf(t.angle||"0");if("circle"!==t.shape&&(null==s||s<0||s>=90))return void this._showToast(this._t("toast.physical_angle"));const o="circle"===t.shape?{id:t.id,shape:"circle",center:e.center,cm:n}:{id:t.id,shape:"square",center:e.center,cm:n,angle:s};if(i.wall_columns.some(e=>e.id!==t.id&&ph(e,o,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"))}const r=this._geometrySnapshot();if("partition"===t.kind){const i=(e.partitions||[]).find(e=>e.id===t.id);if(i&&0===n&&g_(e.openings,{kind:"partition",id:t.id}))return void this._showToast(this._t("toast.zero_wall_opening_conflict"));i&&(i.cm=n)}else if("column"===t.kind){const i=(e.wall_columns||[]).find(e=>e.id===t.id);i&&(i.cm=Uc(n),i.shape="circle"===t.shape?"circle":"square","square"===i.shape?i.angle=qf(t.angle||"0"):delete i.angle)}else{const i=(e.room_drafts||[]).find(e=>e.id===t.id);i?.segments?.[t.segment||0]&&(i.segments[t.segment||0].cm=n)}const l=this._commitPhysicalGeometry(this._t("history.physical_edit"),r);this._physicalDialog=null,l||this.requestUpdate()},this._deletePhysicalSelection=()=>{const t=this._physicalSel,e=this._curSpaceCfg;if(!t||!e)return;if("draft"===t.kind)return void this._deleteDraftWhole();const i=this._geometrySnapshot();if("partition"===t.kind){const i=(e.openings||[]).filter(e=>"partition"===e.host?.kind&&e.host.id===t.id).sort((t,e)=>(t.host?.t||0)-(e.host?.t||0));if(i.length)return void(this._partitionDeleteDialog={id:t.id,openings:i.map(t=>JSON.parse(JSON.stringify(t)))})}const s="partition"===t.kind?"partitions":"column"===t.kind?"wall_columns":"room_drafts";e[s]=(e[s]||[]).filter(e=>e.id!==t.id),e[s].length||delete e[s],this._activeDraftId===t.id&&this._cancelPath(),this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._confirmPartitionDelete=()=>{const t=this._partitionDeleteDialog,e=this._curSpaceCfg;if(!t||!e)return;const i=this._geometrySnapshot();e.partitions=(e.partitions||[]).filter(e=>e.id!==t.id),e.partitions.length||delete e.partitions,e.openings=(e.openings||[]).filter(e=>"partition"!==e.host?.kind||e.host.id!==t.id),e.openings.length||delete e.openings,this._partitionDeleteDialog=null,this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._deleteDraftWhole=()=>{const t="draft"===this._physicalDialog?.kind?this._physicalDialog.id:"draft"===this._physicalSel?.kind?this._physicalSel.id:null,e=this._curSpaceCfg;if(!t||!e||!confirm(this._t("confirm.delete_draft")))return;const i=this._geometrySnapshot();e.room_drafts=(e.room_drafts||[]).filter(e=>e.id!==t),e.room_drafts.length||delete e.room_drafts,this._activeDraftId===t&&this._cancelPath(),this._physicalSel=null,this._physicalDialog=null,this._commitPhysicalGeometry(this._t("history.physical_delete"),i)},this._deleteDraftSegment=()=>{const t=this._physicalDialog,e=this._curSpaceCfg;if(!t||"draft"!==t.kind||!e)return;if(!confirm(this._t("confirm.delete_draft_segment")))return;const i=(e.room_drafts||[]).findIndex(e=>e.id===t.id);if(i<0)return;const s=e.room_drafts[i],n=Math.max(0,Math.min(s.segments.length-1,t.segment||0)),o=[],a=s.points.slice(0,n+1),r=s.points.slice(n+1);if(a.length>=2&&o.push({id:s.id,points:a,segments:s.segments.slice(0,n)}),r.length>=2&&o.push({id:o.length?`${s.id}-${Date.now().toString(36)}`:s.id,points:r,segments:s.segments.slice(n+1)}),2===o.length&&e.room_drafts.length>=200)return void this._showToast(this._t("toast.physical_limit"));const l=this._geometrySnapshot();e.room_drafts.splice(i,1,...o),e.room_drafts.length||delete e.room_drafts,this._activeDraftId===s.id&&this._cancelPath(),this._physicalDialog=null,this._physicalSel=o.length?{kind:"draft",id:o[0].id}:null,this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),l)},this._confirmRoomDelete=t=>{const e=this._roomDeleteDialog,i=this._curSpaceCfg,s=this._spaceModel();if(!e||!i||!s)return;const n=s.rooms.find(t=>t.id===e.roomId);if(!n)return void(this._roomDeleteDialog=null);const o=this._openCuts(),a=xu(dc(s.rooms,this._spaceWalls,o,this._wallKeyPitch,this._cellCm,this._gridPitch,iv).filter(t=>t.roomId===n.id),s.partitions,this._openingsR.map(t=>({...t,x:t.rx,y:t.ry})),.02*this._gridPitch),r=new Set(a.materialize.filter(t=>!t.reusePartitionId).map(t=>t.interval.key)).size;if(t&&(i.partitions||[]).length+r>av)return void this._showToast(this._t("toast.physical_limit"));const l=this._geometrySnapshot(),c=pc(s.rooms,this._spaceWalls,o,this._wallKeyPitch,this._cellCm,this._gridPitch,iv);if(t){i.partitions||=[];const t=new Map,e=new Map,s=t=>{const e=(i.wall_segments||[]).find(e=>{const i=[Number(e.a?.[0])*iv,Number(e.a?.[1])*iv],s=[Number(e.b?.[0])*iv,Number(e.b?.[1])*iv];return this._samePt(t.a,i)&&this._samePt(t.b,s)||this._samePt(t.a,s)&&this._samePt(t.b,i)});return"string"==typeof e?.id&&e.id?e.id:null},n=Date.now().toString(36);for(const o of a.materialize){let a=o.reusePartitionId?i.partitions.find(t=>t.id===o.reusePartitionId):e.get(o.interval.key);a||(a={id:s(o.interval)||`partition-room-${n}-${e.size}`,a:[o.interval.a[0]/iv,o.interval.a[1]/iv],b:[o.interval.b[0]/iv,o.interval.b[1]/iv],cm:o.interval.cm},i.partitions.push(a),e.set(o.interval.key,a)),t.set(o.interval.key,a)}for(const e of i.openings||[]){const i=a.openingIntervals.get(e.id),s=i?t.get(i):null,n=this._openingsR.find(t=>t.id===e.id);if(!s||!n)continue;const o={a:[s.a[0]*iv,s.a[1]*iv],b:[s.b[0]*iv,s.b[1]*iv]};e.host={kind:"partition",id:s.id,t:$u([n.rx,n.ry],o)}}}else if(a.removeOpeningIds.length){const t=new Set(a.removeOpeningIds);i.openings=(i.openings||[]).filter(e=>!t.has(e.id)),i.openings.length||delete i.openings}i.rooms=i.rooms.filter(t=>t.id!==n.id),this._cfgEpoch++;const h=this._normalizeWalls(c,this._openCuts());h.length?i.walls=h:delete i.walls,this._roomDeleteDialog=null,this._commitPhysicalGeometry(this._t(t?"history.delete_room_keep_walls":"history.delete_room_with_walls"),l),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()},this._rebindPartitionOpening=()=>{const t=this._openingDialog;if(!t?.id)return;const e=t.id;this._activateMarkupTool("opening"),"opening"===this._tool&&(this._openingRebindId=e,this._openingPreset={type:t.type,lengthCm:t.lengthCm,flipH:t.flipH,flipV:t.flipV,revision:++this._openingPresetRevision},this._openingDialog=null,this._openingHoverCandidate=null)},this._keepClosedAsPartitions=()=>{if(this._wallFaceBatch)return void this._decideWallFace(!1);if(!this._contourClosed||this._pendingSplit||!this._curSpaceCfg)return;const t=this._curSpaceCfg,e=this._path.slice(0,-1);if((t.partitions||[]).length+e.length>av)return void this._showToast(this._t("toast.physical_limit"));const i=this._geometrySnapshot(),s=Jp(e.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll);t.partitions||=[];const n=Date.now().toString(36),o=this._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this._activeDraftId):null,a=this._draftSegmentsForPath(this._path,o,s);for(let i=0;it.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this._t("history.contour_to_partitions"),i),this._roomDialog=!1,this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null},this._toggleServerPlans=async()=>{const t=this._spaceDialog;if(t)if(t.pickSaved)this._spaceDialog={...t,pickSaved:!1};else{this._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.hass.callWS({type:"houseplan/plans/list"}),e=this._spaceDialog;e&&(this._spaceDialog={...e,saved:t?.plans||[],savedBusy:!1})}catch(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,saved:[],savedBusy:!1}),this._showToast(this._t("toast.plans_list_failed",{err:this._errText(t)}))}}},this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const t=this._dayCycleState();if(!t)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const e=mr(t);e!==this._dayCycleClockKey&&(this._dayCycleClockKey=e,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(!this._norm)return;const t=this._glowRadiusCm,e=this._imperial?Math.round(t/30.48*10)/10:Math.round(t)/100;this._settingsDialog={colors:JSON.parse(JSON.stringify(this._fillColors)),glowRadius:e,bgColor:hs(this._settings,{bgColor:null})||null,northDeg:$r(this._settings,{}),bgMode:Sr(this._settings,{}),sunRays:Mr(this._settings,{}),busy:!1}},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._previewAlignDialog(!1),this._toggleOptimizeLivePositions=()=>{const t=this._alignDialog;t&&!t.busy&&t.report.liveMissingPositions.length&&this._previewAlignDialog(!t.removeLiveMissingPositions)},this._optimizeUndoBusy=!1,this._openBackupExport=()=>{this._settingsDialog=null,this._backupExportDialog={kind:"full",planOnly:!1,busy:!1,error:""}},this._openRulesDialog=()=>{if(!this._norm)return;const t=this._settings.icon_rules,e=(t&&t.length?t:Jt).map(t=>({...t}));this._rulesDialog={rules:e,test:"",busy:!1}},this._climateCache=null,this._gearPtCache=new WeakMap}get _canEdit(){return!!this._norm&&(!0===this._serverCanWrite||!1!==this._serverCanWrite&&!0===this.hass?.user?.is_admin)}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}_cssColor(t,e){const i=String(t||"").trim();if(!i)return e;const s=document.createElement("span");s.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(s);const n=getComputedStyle(s).color||e;return s.remove(),n}_currentModeVisual(t=this._mode){const e=this._modeTransition.presented||this._modeTransitionVisual;if(e)return{...e,viewport:{...e.viewport,viewBox:{...e.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const s=this.renderRoot.querySelector(".editorchrome"),n=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),a=this.renderRoot.querySelector(".hp-backdrop"),r=this.renderRoot.querySelector(".zoomwrap"),l=r?getComputedStyle(r).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:t,editorChromeHeight:"view"===t?0:s?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:$g(n,i.clientWidth),stageColor:getComputedStyle(i).backgroundColor||"rgb(255, 255, 255)",paperColor:o?getComputedStyle(o).fill:"rgb(255, 255, 255)",sceneBrightness:Number.isFinite(c)?c:1,architectureOpacity:"decor"===t?.35:1,backdropOpacity:a&&Number(getComputedStyle(a).opacity)||1,viewWeight:"view"===t?1:0,editorWeight:"view"===t?0:1,toolbarContentOpacity:"view"===t?0:1}}_viewForModeTarget(t,e,i,s,n){const o=Ni(this._baseVb(),s/Math.max(1,n)),a=Math.min(dv.ZOOM_MAX,Math.max(dv.ZOOM_MIN,t)),r=o.w/a,l=o.h/a,c=e??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-r/2,y:h-l/2,w:r,h:l},o)}_targetStageColor(t){return"view"!==t?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(t){return"view"===t&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(t){return 1}_applyModeTransitionFrame(t){t.targetMode===this._mode&&(this._modeTransitionVisual=t.presented,this._view={...t.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(t){if(t.targetMode!==this._mode)return;const e=this._modeTransitionRequest;this._view={...t.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[t.to.stageWidth,t.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._modeTransitionBusy||t.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-t.to.stageWidth)>.5||Math.abs(i.clientHeight-t.to.stageHeight)>.5)){const t=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,t?t.x+t.w/2:void 0,t?t.y+t.h/2:void 0),this.requestUpdate()}const s=this.renderRoot.activeElement;(!s||!s.isConnected||!!s.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(t=!0){const e=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(t),t&&e||(this._modeTransitionVisual=null)}_adoptMode(t){this._cancelModeTransition(!1),this._mode=t,"view"!==t&&(this._editorChromeMode=t)}_commitViewModeAtomic(t,e,i,s){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=e,t){const n=this._stageEl?.clientWidth||t.stageWidth,o=Math.max(1,t.stageHeight+t.editorChromeHeight);this._view=this._viewForModeTarget(e,i,s,n,o),this._lastValidStageSize=[n,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(t,e,i,s,n,o){this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._mode!==i)return void(t===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const a=this.renderRoot.querySelector(".editorchrome"),r=a?.querySelector(".editorchrome-inner"),l="view"===i?0:r?.scrollHeight||r?.getBoundingClientRect().height||0,c=Math.max(1,e.stageHeight+e.editorChromeHeight),h=Math.max(1,c-l),d=this._stageEl?.clientWidth||e.stageWidth;if(d<=0||h<=0)return this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._applyView(s,n,o),void this.requestUpdate();const p=this._viewForModeTarget(s,n,o,d,h),u={presentedMode:i,editorChromeHeight:l,stageWidth:d,stageHeight:h,viewport:$g(p,d),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const _=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(e,u,i,this._reducedMotion||_?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(t=this._model,e=this._loadOk){const i=this._config?.floor,s=function(t){if(!t.hasFloor)return{kind:"absent"};const e=t.floor;if("string"==typeof e)return e.length?t.spaceIds.includes(e)?{kind:"valid",id:e,source:"id"}:{kind:"invalid",reason:"unknown-id",value:e}:{kind:"invalid",reason:"empty-id",value:e};if("number"==typeof e){if(!Number.isFinite(e))return{kind:"invalid",reason:"non-finite-index",value:e};if(!Number.isInteger(e))return{kind:"invalid",reason:"fractional-index",value:e};if(e<0)return{kind:"invalid",reason:"negative-index",value:e};const i=t.spaceIds[e];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:e}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:e}}({spaceIds:t.map(t=>t.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||e?s:"number"==typeof i?"valid"===s.kind||"invalid"===s.kind&&"out-of-range-index"===s.reason?{kind:"pending",value:i}:s:"valid"===s.kind||"invalid"===s.kind&&"unknown-id"!==s.reason?s:{kind:"pending",value:i}}_canCommitSpace(t,e=!1){if(e||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===t}_commitSpace(t,e=!1){return!!this._canCommitSpace(t,e)&&(t!==this._space&&(this._clearTransientHover(!0),this._cancelDevicePressFeedback()),this._space=t,!0)}_slideTo(t,e){if(t===this._space)return!0;if(!this._canCommitSpace(t))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(t),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),i||(this._slide=e,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return Ff({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(t,e){Ff({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:t.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(hv(t),this._tabDragRelease=t=>this._tabPointerUp(t),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:e,pointerId:t.pointerId,x:t.clientX,y:t.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(t,e,i){const s=this._model.map(t=>t.id),n=s.indexOf(i);if(n<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const a of o){const o=a.dataset.id||"";if(!o||o===i)continue;const r=a.getBoundingClientRect();if(tr.right||er.bottom)continue;const l=s.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,s;const n=this._tabDropTargetAt(t.clientX,t.clientY,e.id);e.moved&&e.targetId===n?.targetId&&e.placement===n?.placement||(this._tabDrag={...e,moved:!0,targetId:n?.targetId||null,placement:n?.placement||null})}_tabPointerUp(t){const e=this._tabDrag;if(e&&e.pointerId!==t.pointerId)return;const i="pointerup"===t.type&&e?.moved?this._tabDropTargetAt(t.clientX,t.clientY,e.id):null;"pointerup"===t.type&&e?.moved&&this._suppressNextTabClick(),this._endTabDrag(),e?.moved&&i&&this._commitTabOrder(e.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(t){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(t)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(t,e){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const s=this._model.map(t=>t.id),n=function(t,e,i){const s=t.indexOf(e),n=t.indexOf(i);if(s<0||n<0||s===n)return t;const o=t.slice();return o.splice(s,1),o.splice(n,0,e),o}(s,t,e);if(n===s)return;const o=new Map(this._devices.map(t=>[String(t.id),String(t.area||"")])),a=function(t,e,i,s=()=>""){if(!i)return[];const n=[];for(const o of t){if(!o||!0===o.removed)continue;const t="string"==typeof o.id?o.id:"";if(!t)continue;if("string"==typeof o.space&&o.space)continue;const a=("string"==typeof o.area?o.area:"")||s(t)||"";a&&e[a]||n.push({id:t,space:i})}return n}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),s[0]||"",t=>o.get(t)||"");if(a.length){const t=new Map(a.map(t=>[t.id,t.space]));for(const e of i.markers||[]){const i=t.get(String(e.id));i&&(e.space=i)}}i.spaces=function(t,e){const i=new Map(e.map((t,e)=>[t,e]));return t.map((t,e)=>({space:t,index:e})).sort((t,e)=>(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)||t.index-e.index).map(t=>t.space)}(i.spaces||[],n),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(t){if(this._endTabDrag(),t===this._space)return;const e=this._model.map(t=>t.id),i=e.indexOf(this._space),s=e.indexOf(t);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(t,i>=0&&s0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const t=this._model.map(t=>t.id),e=t.indexOf(this._space);this._slideTo(t[(e+1)%t.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}_newContinuityController(){return new yd(()=>{this._resumeSettling="steady"!==this._continuity.state,this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}get _labsIso(){return this._labs.active.includes("iso")}get _desiredProjection(){return"view"===this._mode&&this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat"}_saveViewPreference(){try{localStorage.setItem(tv,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(t){const e=this._view;if(!e)return null;const i=[e.x+e.w/2,e.y+e.h/2],s="iso"===t?Xg(i):i;return{x:s[0],y:s[1]}}_convertProjectionView(t,e){if(t===e)return;const i=this._logicalViewCenter(t);this._view=null;const s=i?"iso"===e?Jg([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,s?.[0],s?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(t){if(!this._labsIso||"view"!==this._mode)return;const e=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:t},"iso"===t){const t=this._isoSceneKey();t&&this._isoFallback.delete(t)}this._saveViewPreference();const i=this._effectiveProjection();this._convertProjectionView(e,i)}_hashSpace(){return Ng(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const t=(e=this.ownerDocument,fg.get(e)?.resolved);var e;void 0!==t&&(this._glowScreenBlend=t),this._continuityUnsub?.(),this._continuityUnsub=fd(this.ownerDocument,this._pageVisibility),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(t=>{for(const e of t)for(const t of e.addedNodes)this._syncPointerHoverSubtree(t)}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),function(t){const e=fg.get(t);if(e)return e.promise;const i={promise:Promise.resolve(!1)};return i.promise=yg(t).catch(()=>!1).then(t=>(i.resolved=t,t)),fg.set(t,i),i.promise}(this.ownerDocument).then(t=>{t!==this._glowScreenBlend&&(this._glowScreenBlend=t,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>Is(this._serverCfg)),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(t,e){jg.add(e);const i=Vg(t);return"undefined"==typeof window&&e(i),()=>{jg.delete(e)}}(Ef,this._onLabsSnapshot),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Bf)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._vacRaf&&(cancelAnimationFrame(this._vacRaf),this._vacRaf=0),this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const t of this._activityRt.values())clearTimeout(t.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),this._modeTransition.dispose(),this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer);for(const t of this._glowFadeTimers.values())clearTimeout(t);for(const t of this._glowEnterRafs.values())cancelAnimationFrame(t);clearTimeout(this._glowFeatherResumeTimer),this._glowFeatherResumeTimer=0,this._glowFeatherSuspendUntil=0,this._glowFadeTimers.clear(),this._glowEnterRafs.clear(),this._glowEnteringSources.clear(),this._glowRenderedSources.clear(),this._glowLastAppearance.clear(),this._glowSourceSeq=0,this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._touchContacts.clear(),this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(t){if("Escape"===t.key&&this._vacFit)return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void t.stopPropagation();if("Escape"===t.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm=null);if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._settingsDialog)return void(this._settingsDialog=null);if(this._markerDialog)return void(this._markerDialog=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary.hasOpenGroup)return t.preventDefault(),void this._editorSecondary.closeGroup(!0)}const e=t.composedPath?.()||[t.target],i=e.some(t=>t?.matches?.('input, textarea, select, [contenteditable="true"]')),s=e.some(t=>t?.classList?.contains?.("editor-secondary")),n=t.ctrlKey||t.metaKey,o=t.key.toLowerCase(),a=/^[a-z]$/.test(o),r="z"===o||!a&&"KeyZ"===t.code,l="y"===o||!a&&"KeyY"===t.code,c=n&&(r&&t.shiftKey||l),h=n&&r&&!t.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;return c?(t.preventDefault(),void this._redoGeometry()):h?(t.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry()):"Delete"!==t.key&&"Backspace"!==t.key||!this._decorSel||i||s?void("Escape"===t.key&&(t.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._furnPalette=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(t.preventDefault(),void this._decorDeleteSel())}if(this._markup&&(!h&&!c||!i)){if(("Delete"===t.key||"Backspace"===t.key)&&this._physicalSel&&!i&&!s)return t.preventDefault(),void this._deletePhysicalSelection();if(c)return t.preventDefault(),void this._redoGeometry();if(h)return t.preventDefault(),this._rszDrag?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===t.key)return this._physicalDrag||this._physicalRotate?(t.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(t.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(t.preventDefault(),void this._finishWallChain()):this._physicalSel?(t.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(t.preventDefault(),this._rszDrag?void this._rszCancelDrag():void(this._rszSel?this._rszSel=null:this._tool="draw")):"split"===this._tool?(t.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(t.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(t.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(t.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length){if(this._contourClosed)return this._path=this._path.slice(0,-1),void(this._closingWallCm=null);if(this._activeDraftId&&this._path.length>1&&this._curSpaceCfg){const t=this._geometrySnapshot();this._path=this._path.slice(0,-1),this._draftSegmentCms=this._draftSegmentCms.slice(0,-1);const e=this._curSpaceCfg,i=(e.room_drafts||[]).findIndex(t=>t.id===this._activeDraftId);if(i>=0){const s=Array.isArray(e.room_drafts[i]?.segments)?e.room_drafts[i].segments:[];this._path.length<2?(e.room_drafts.splice(i,1),e.room_drafts.length||delete e.room_drafts,this._activeDraftId=null):e.room_drafts[i]={id:this._activeDraftId,points:this._path.map(t=>[t[0]/iv,t[1]/iv]),segments:this._draftSegmentCms.map((t,e)=>({...s[e]||{},cm:t}))},this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),t)}return}this._path=this._path.slice(0,-1)}}_undoActiveDraftPoint(){const t=this._activeDraftId,e=this._path[0]?[...this._path[0]]:null,i=this._geometryHistory.undo();if(!i)return void this._undoPoint();if(!this._applyGeometryState(i.before,!0))return void this._geometryHistory.clear();const s=t?this._spaceModel()?.room_drafts.find(e=>e.id===t):null;s?(this._activeDraftId=s.id,this._path=s.points.map(t=>[...t]),this._draftSegmentCms=this._adoptDraftCms(this._path,s.segments.map(t=>t.cm),s.id),this._resumeDraftBySpace[this._space]=s.id):(this._activeDraftId=null,this._path=e?[e]:[],this._draftSegmentCms=[],t&&this._resumeDraftBySpace[this._space]===t&&delete this._resumeDraftBySpace[this._space]),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:i.name}))}static getConfigElement(){return document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(t){for(const t of Uf.values())for(const e of t)clearTimeout(e.evict);Uf.clear(),Kf=t&&t>0?t:1e4}static _warmBootStats(){let t=0,e=0;const i=[];for(const s of Uf.values())for(const n of s)t++,n.dlg&&(e++,i.push(n.dlg.kind));return{keys:Uf.size,slots:t,dlgs:e,drafts:i}}setConfig(t){const e=this._config,i=!!e&&Object.prototype.hasOwnProperty.call(e,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...t};(i!==this._hasFixedFloor||e?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&t.default_floor&&this._commitSpace(t.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(Xf)||"{}")||{}}catch{this._zoomBySpace={}}try{const t=JSON.parse(localStorage.getItem(tv)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(t).filter(t=>"flat"===t[1]||"iso"===t[1]))}catch{this._viewPreference={}}this._labs=Vg(Ef);try{const t=JSON.parse(localStorage.getItem(Qf)||"null");this._kioskScale={icon:Es(t?.icon),font:Es(t?.font)}}catch{}try{const t=JSON.parse(localStorage.getItem(Jf)||"null");t&&t.config&&Array.isArray(t.config.spaces)&&(this._serverCfg=t.config,this._cfgEpoch++,this._cfgRev=t.rev||0,this._cfgContentFingerprint=t.config_fingerprint||bd(t.config),this._layout=t.layout||{},this._layoutRev=t.layout_rev||0,this._layoutContentFingerprint=t.layout_fingerprint||bd(this._layout),this._virtualLights=mn(t.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1)}_warmAdopt(){if(this._config?.kiosk)return;const t=Vf(this._config);if(this._warmKey===t&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const e=this.parentNode,i=this._warmIdx(e),s=Uf.get(t);if(!s||!s.length)return;const n=s.find(t=>t.owner===this._warmGen);if(n)return this._warmLongReturn=!!n.freed&&Date.now()-n.freed>=_d,clearTimeout(n.evict),n.evict=0,n.freed=0,n.live=!0,this._warmSlot=n,this._warmKey=t,n.frameFingerprint&&this._continuity.adoptCompleteFrame(n.frameFingerprint),void(!this._devices.length&&n.devices?.length&&(this._devices=[...n.devices]));const{slot:o,sure:a}=((t,e,i,s)=>{const n=t=>{const e=!!i&&t.place?.deref()===i;return e&&t.idx===s?4:t.live?0:e?3:2};let o=null,a=0,r=0,l=null;for(const i of t){if(i.owner===e)continue;l=i;const t=n(i);t<=0||(t>a?(o=i,a=t,r=1):t===a&&r++)}return!o||r>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(s,this._warmGen,e,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=_d,this._booting=!1,this._bootFading=!1,this._hdrH=o.hdrH,this._bootSoft=!0,this.isConnected&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Bf)),this._warmKey=t,a?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=e?new WeakRef(e):null,o.idx=i,o.live=!0,this._warmSlot=o,this._warmVp=o.vp,o.frameFingerprint&&this._continuity.adoptCompleteFrame(o.frameFingerprint),!this._devices.length&&o.devices?.length&&(this._devices=[...o.devices]),this._warmAdoptViewport(this._config)):(this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},s.push(this._warmSlot),this._warmTrim(s)))}_warmIdx(t){const e=t?.children;if(!e)return-1;for(let t=0;t4;){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=Uf.get(e);if(!t.live&&o&&o.length>1){const e=o.indexOf(t);e>=0&&o.splice(e,1)}},Kf+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?Jg([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="opening"===(o=function(t){return"partition"===t?"draw":t}(o=e.tool))?"draw":"string"==typeof o&&ov.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=Vf(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=Uf.get(i)||[];for(s.push(this._warmSlot),Uf.set(i,s),this._warmTrim(s);Uf.size>8;){const t=Uf.keys().next().value;if(void 0===t||t===i)break;for(const e of Uf.get(t)||[])clearTimeout(e.evict);Uf.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>Kf)&&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=bd(this._serverCfg),this._layoutContentFingerprint=bd(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(Jf,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 wd([this._cfgRev,this._cfgContentFingerprint||bd(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||bd(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 G;const t="connection"===this._continuity.recoveryReason;return W`
t.stopPropagation()} @click=${t=>t.stopPropagation()} @@ -4974,8 +4974,8 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t(t?"continuity.restore_connection":"continuity.restore_plan")} ${"recovery-error"===this._continuity.state?W``:G} -
`}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(t=>({...t,...t.stage?{stage:[...t.stage]}:{}}))}getCardSize(){return 12}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const t=this._serverCfg?.spaces||[];let e=t.length+":";for(const i of t){e+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const t of i.rooms||[]){const i=t.poly?.[0],s=t.poly?.[t.poly.length-1];e+=(t.poly?.length||0)+"."+(t.id||"")+"."+(t.open_to||[]).join("+")+"."+(t.area||"")+"."+JSON.stringify(t.settings||0)+"."+(t.x??"")+","+(t.y??"")+","+(t.w??"")+","+(t.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(s?s[0]+"/"+s[1]:"")+";"}}return e}get _model(){if(!this._serverCfg)return[];const t=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===t)return this._modelCache.model;const e=this._buildModel();return this._modelCache={key:t,model:e},e}_buildModel(){if(!this._serverCfg)return[];const t=this._renderCfg;return $h(t).map((e,i)=>{const s=t.spaces[i]?.plan_url;return e.bg&&s?{...e,bg:{...e.bg,href:s}}:e})}_spaceModel(){return this._hasFixedFloor?$d(this._model,this._space):(t=this._model,e=this._space,t.find(t=>t.id===e)??t[0]);var t,e}_spaceModelById(t){return $d(this._model,t)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0;for(const t of this._pointers.keys())for(const e of this.renderRoot.querySelectorAll("*"))try{e.hasPointerCapture?.(t)&&e.releasePointerCapture(t)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._resumeDraftBySpace={},this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const t={};for(const e of this._model)for(const i of e.rooms)i.area&&(t[i.area]={space:e.id,room:i});return t}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._settings.filter_seeded?this._showHidden:!!this._settings.show_all}_toggleShowAll(){if(this._serverCfg){if(this._settings.filter_seeded)return this._showHidden=!this._showHidden,void this.requestUpdate();this._serverCfg={...this._serverCfg,settings:{...this._serverCfg.settings,show_all:!this._settings.show_all}},this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}}_seedHiddenDevices(){if(!this._serverCfg||!this._norm||!this._canEdit)return;const t=this._serverCfg,e=function(t){const e=t.hass,i=t.registry||An(e),s=Nn(e,i),n=On(e,i),{areaToSpace:o,markers:a,settings:r,excluded:l,iconRules:c}=t,h=!1!==r.group_lights,d=wo(a),p=yo(s,h).filter(t=>!ko(s,t.eid,d)),u=new Set(p.map(t=>t.area)),_=qn(s),m=Wn(a,n),g=new Set(a.map(t=>t.binding)),f=[];for(const t of Object.values(s.devices)){const n=t.area_id;if(!n||!o[n])continue;if("service"===t.entry_type)continue;if(g.has("device:"+t.id))continue;if("active"!==Bn(e,"device:"+t.id,i).kind)continue;const a=jn(s,t.id,_[t.id]||[],m);if(a.partial&&!a.entityIds.length)continue;const r=a.entityIds,d=Un(s,t,r);let p=l.has(d)||"Group"===t.model||/scene/i.test(t.model||"")||/bridge/i.test((t.model||"")+(t.name||""))||"myheat"===d&&!!t.via_device_id;if(!p&&h&&u.has(n)){const e=(t.name_by_user||t.name||"").trim();"mdi:lightbulb"===bo(s,e,t.model,r,c)&&(p=!0)}p&&f.push("device:"+t.id)}return f}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!e.length&&t.settings?.filter_seeded)return;t.markers=t.markers||[];const i=[];for(const s of e){const e="h"+s.slice(s.indexOf(":")+1);t.markers.push({id:e,binding:s,hidden:!0}),i.push(s.slice(s.indexOf(":")+1))}const s={...t.settings||{},filter_seeded:!0};delete s.show_all,i.length&&Array.isArray(s.new_device_ids)&&(s.new_device_ids=s.new_device_ids.filter(t=>!i.includes(t))),t.settings=s,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const t=this._settings.icon_rules;if(!t||!Array.isArray(t)||!t.length)return;const e=JSON.stringify(t);return e!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=e,this._rulesCompiled=Xt(t)),this._rulesCompiled}get _fillColors(){return ps(this._settings)}get _excluded(){const t=this._settings.exclude_integrations;return t?new Set(t):Yt}willUpdate(t){t.has("_serverCfg")&&this._cfgEpoch++,this._syncEmptySpaceState(),t.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._planHassMemo=null,this._hookConnection(),!this._loadOk&&!this._loading&&this._loadTries<8&&this._loadFromServer(),this._maybeRebuildDevices(),this._vacTick(),this._activityTick()),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._warmSnapshot(),this._dtMeasure();const t=this._stageEl;t&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>this._refitView()),this._roViewport.observe(t)),t&&this._booting&&!this._bootTimer&&this._bootWatch();const e=this.renderRoot.querySelector(".hdr");if(e&&t&&!this._roHdr){const i=()=>{const e=this.renderRoot.querySelector("ha-card");if(!e)return;const i=t.getBoundingClientRect().top-e.getBoundingClientRect().top,s=Math.min(Math.max(e.getBoundingClientRect().top,0),120),n=Math.round(i+s);n>=0&&n!==this._hdrH&&(this._hdrH=n),n>=0&&!this._booting&&!this._config?.kiosk&&t.clientHeight>0&&this._warmPatch({hdrH:n,stageH:t.clientHeight})};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(e),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(t&&!this._view&&this._refitView(),this._editorSecondary.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const t=function(t){const e=t?.floors;if(!e||"object"!=typeof e)return[];const i=[];for(const t of Object.values(e))t&&t.floor_id&&i.push({id:t.floor_id,name:t.name||t.floor_id,level:t.level??null});return i.sort((t,e)=>{const i=t.level??1e9,s=e.level??1e9;return i!==s?i-s:t.name.localeCompare(e.name)}),i}(this.hass);t.length?this._importDialog={floors:t.map(t=>({...t,checked:!0}))}:this._openSpaceDialog("create")}}_adoptStructuralResponses(t,e,i){const s=t?.config,n=s&&Array.isArray(s.spaces)?s:null,o=bd(n),a=o!==(this._cfgContentFingerprint||bd(this._serverCfg));if(a&&(this._geometryHistory.clear(),this._pendingPhysicalWrites.clear(),this._serverCfg&&this._clearGeometryGesture(),this._serverCfg=n,this._cfgContentFingerprint=o),this._cfgRev=t?.rev??this._cfgRev,t&&("virtual_lights"in t||"config"in t)){const e=gn(this._virtualLights,t.virtual_lights,this._cfgRev,"virtual_lights"in t);vn(e)!==vn(this._virtualLights)&&(this._virtualLights=e,this._capturedSnapshotVirtual="")}let r=!1;if(void 0!==e||void 0!==i){const t=i??e?.layout??{},s=bd(t);r=s!==(this._layoutContentFingerprint||bd(this._layout)),r&&(this._layout=t,this._layoutContentFingerprint=s),this._layoutRev=e?.rev??this._layoutRev}return this._canOptimizeUndo=!(!t?.can_optimize_undo&&!e?.can_optimize_undo),this._haIntegrationVersion="string"==typeof t?.integration_version?t.integration_version:this._haIntegrationVersion,this._undoKind=t?.undo_kind||e?.undo_kind||null,"boolean"==typeof t?.can_write&&(this._serverCanWrite=t.can_write),a&&this._continuity.note("config-candidate",{configRev:this._cfgRev}),r&&this._continuity.note("layout-candidate",{layoutRev:this._layoutRev}),{configChanged:a,layoutChanged:r}}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const t=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(t,!1),!0}async _loadFromServer(){this._loading=!0,this._loadTries++;const t=this._space,e=!!this._view;try{const[i,s]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]),n=i?.config&&Array.isArray(i.config.spaces)?i.config:null,o=bd(n)!==(this._cfgContentFingerprint||bd(this._serverCfg))||bd(s?.layout??{})!==(this._layoutContentFingerprint||bd(this._layout));if(o){if(!await this._signer.prepareImage(this.hass,this._candidateBackdrop(n)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0)}o&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),this._connectionWasLost=!1,this._serverStorage=!0,"boolean"==typeof i?.can_write&&(this._serverCanWrite=i.can_write),this._canOptimizeUndo=!(!i?.can_optimize_undo&&!s?.can_optimize_undo),this._haIntegrationVersion="string"==typeof i?.integration_version?i.integration_version:this._haIntegrationVersion,this._adoptStructuralResponses(i,s),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:e&&this._space===t||this._restoreZoom(),this._loadOk=!0,this.hass.callWS({type:"houseplan/trail/get"}).then(t=>{this._vacSrvTrails=t?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(t){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(Kf)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const t=this.hass?.connection;if(!t)return;if(t!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=t),this._liveSyncAttempt)return;const e=this._liveSyncGeneration,i=[],s=(s,n,o,a)=>{s()||i.push(async()=>{const i=await t.subscribeEvents(a,o);e===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===t&&!s()?n(i):i?.()})};if(s(()=>this._unsubCfg,t=>{this._unsubCfg=t},"houseplan_config_updated",t=>{const e=Number(t?.data?.rev??-1);e!==this._cfgRev&&this._reloadConfigOnly(!1,e)}),s(()=>this._unsubTrail,t=>{this._unsubTrail=t},"houseplan_trail_updated",async()=>{try{const t=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=t?.trails||{},this.requestUpdate()}catch{}}),s(()=>this._unsubLayout,t=>{this._unsubLayout=t},"houseplan_layout_updated",t=>this._onLayoutEvent(Number(t?.data?.rev??-1))),s(()=>this._unsubVirtual,t=>{this._unsubVirtual=t},"houseplan_virtual_light_updated",t=>{const e=wn(this._virtualLights,t?.data);e!==this._virtualLights&&(this._virtualLights=e,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const n=function(t){return Promise.allSettled(t.map(t=>Promise.resolve().then(t)))}(i).then(()=>{});this._liveSyncAttempt=n,n.finally(()=>{this._liveSyncAttempt===n&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(t=!1,e){if(!t){if(void 0!==e&&e<=this._cfgRev)return;if(this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(()=>this._reloadConfigOnly(!1,e),400))}this._beginContinuityCandidate("config-reload",!1);try{const t=await this.hass.callWS({type:"houseplan/config/get"}),e=t?.config&&Array.isArray(t.config.spaces)?t.config:null;if(bd(e)!==(this._cfgContentFingerprint||bd(this._serverCfg))&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(e)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0);const i=this._space;this._adoptStructuralResponses(t),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._space!==i&&this._restoreZoom(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}catch(t){this._showToast(this._t("toast.cfg_reload_failed",{err:this._errText(t)}))}finally{this._continuityDataReady=!0,this.requestUpdate()}}_scheduleLoadRetry(t=!1){if(void 0!==this._loadRetryTimer)return;const e=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!t&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},e)}_ensureHaRegistryAuthority(){const t=this.hass?.connection||null;t&&t!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=t,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._haRegistryRelease=In(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return An(this.hass)}get _planHass(){const t=this._haRegistry,e=Fn(this.hass,t),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===e)return i.active;const s=Nn(this.hass,t),n=On(this.hass,t);return this._planHassMemo={hass:this.hass,sig:e,active:s,full:n},s}_captureRenderDeviceSnapshot(){if(!this.hass)return;const t=Date.now(),e=[...this._activityRt.entries()].map(([e,i])=>`${e}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+R_)>t?1:0)).join("|"),i=vn(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===e)return;const s=this._planHass,n=new Map,o=new Map,a=new Set(["sun.sun"]);this._vacFit?.source&&a.add(this._vacFit.source);const r=new Set,l=new Set,c=t=>{if(!t)return;const e=t.indexOf(":");if(e<0)return void a.add(t);const i=t.slice(0,e),s=t.slice(e+1);"device"===i?r.add(s):"entity"===i&&a.add(s)};for(const t of this._model)for(const e of t.rooms)e.area&&l.add(e.area),c(e.settings?.temp_source),c(e.settings?.hum_source);for(const t of this._serverCfg?.spaces||[])for(const e of t.openings||[])for(const t of gi(e))a.add(t);for(const t of this._serverCfg?.spaces||[])for(const e of t.decor||[])if("text"===e.kind){for(const t of String(e.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const e=Yi(t[1]);e?.entity&&a.add(e.entity)}e.entity&&a.add(e.entity),o.set(`decor:${t.id}:${e.id}`,ts(e.text,e,s,t=>!!s.entities?.[t]&&!!s.states?.[t]&&!ko(s,t,wo(this._markers))))}const h=ho(s,this._devices,null,this._virtualLights);for(const t of this._devices){for(const e of[!1,!0])n.set(n_(t.id,e),t_(s,t,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:e,activityRuntime:this._activityRt.get(t.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(t)){const e=this._vacSource(t,s),i=e?Nd(s?.states?.[e]?.attributes):null,n=this._vacRt.get(t.id);o.set(`vacuum:${t.id}`,{source:e,telemetry:i,mapId:i?this._vacMapId(t,i,s):null,runtime:n?{trail:n.trail,lastTs:n.lastTs,moving:n.moving,jump:n.jump}:null,server:this._vacSrvTrails[t.id]||null})}}const d=s_({sourceSequence:this._hassSequence,hass:s,devices:this._devices,presentations:n,positions:(p=this._model.length>0,u=this._devices,_=t=>this._livePos(t),p?new Map(u.map(t=>[t.id,_(t)])):new Map),facts:o,entityIds:a,deviceIds:r,areaIds:l});var p,u,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=e,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(t){return Bn(this.hass,t,this._haRegistry)}houseplanDiagnostics(){const t=function(t){const e=An(t);return{access:e.access,authoritative:e.authoritative,revision:e.revision,lastSuccess:e.lastSuccess,error:e.error}}(this.hass),e={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const t of this._markers)t.removed||"virtual"===t.binding||e[this._bindingStatus(t.binding).kind]++;return{registry:{...t,lastSuccessAgeMs:t.lastSuccess?Math.max(0,Date.now()-t.lastSuccess):null},bindings:e}}_openBindingInHa(t){const[e,i]=t.split(":");if(i)if("device"!==e){if("entity"===e){const t=this._fullRegistryHass.entities?.[i];t?.device_id&&rv("/config/devices/device/"+encodeURIComponent(t.device_id))}}else rv("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(t){const[e,i]=t.split(":");return!!i&&("device"===e||"entity"===e&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const t=this._markerDialog;if(!t)return;const e="ha"===t.bindingMode?this._bindingStatus(t.binding):null,i=t.hideFromPlan||"ha_disabled"===e?.kind;i&&"ha_disabled"===e?.kind?this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===e?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...t,hideFromPlan:!i}}_hookConnection(){const t=this.hass?.connection;t&&t!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),t.addEventListener?.("ready",this._onConnReady),t.addEventListener?.("disconnected",this._onConnLost),t.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=t)}_display(t){return this._signer.display(this.hass,t)}_resign(){this._signer.resign(this.hass,Is(this._serverCfg))}_onLayoutEvent(t){t<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{t<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(t){const e=t?.rev;"number"==typeof e&&e>this._layoutRev&&(this._layoutRev=e)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const t=new Map;for(const e of this._dirtyPos)this._layout[e]&&t.set(e,this._layout[e]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[e,i]of this._sentPos)t.set(e,i);try{const e=await this.hass.callWS({type:"houseplan/layout/get"}),i={...e?.layout||{}};for(const[e,s]of t)i[e]=s;const s=bd(i);s!==(this._layoutContentFingerprint||bd(this._layout))&&(this._layout=i,this._layoutContentFingerprint=s),this._layoutRev=e?.rev??this._layoutRev,this._canOptimizeUndo=!!e?.can_optimize_undo,this._haIntegrationVersion="string"==typeof e?.integration_version?e.integration_version:this._haIntegrationVersion,this._undoKind=e?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_maybeRebuildDevices(){const t=this.hass;if(!t?.devices||!t?.entities||!t?.areas)return;const e=this._haRegistry,i=Fn(t,e)+":"+Object.keys(t.areas).length+":"+(this._norm?"n":"l")+":"+ra(t,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const s=new Map(this._devices.map(t=>[t.id,t.bindingStatus?.kind||"active"]));this._devices=So({hass:t,registry:e,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:t=>this._t(t),iconRules:this._iconRules});const n=this._markers.filter(t=>!t.removed&&"virtual"!==t.binding).map(t=>t.binding).sort(),o=e.revision+":"+n.join("|");if(e.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const s of n)i.set(s,Bn(t,s,e));!function(t){if("undefined"==typeof localStorage||!t.size)return;const e=Hn(),i=Date.now();for(const[s,n]of t)"active"===n.kind?e[s]={kind:"active",ts:i}:"ha_disabled"===n.kind&&(e[s]={kind:"ha_disabled",reason:n.reason,ts:i});const s=Object.fromEntries(Object.entries(e).sort((t,e)=>e[1].ts-t[1].ts).slice(0,1500));Mn=s;try{localStorage.setItem(Sn,JSON.stringify(s))}catch{}}(i),this._haBindingCacheKey=o}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),this._syncActivityRuntime();const a=new Set(this._devices.filter(t=>!t.hidden).map(t=>t.id));for(const t of this._vacRt.keys())a.has(t)||this._vacRt.delete(t);if(this._infoCard){const t=this._devices.find(t=>t.id===this._infoCard.id);this._infoCard=t&&"ha_disabled"!==t.bindingStatus?.kind?t:null}const r=this._devices.some(t=>"ha_disabled"===t.bindingStatus?.kind&&"ha_disabled"!==s.get(t.id));r&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(t=>t.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._drag&&"ha_disabled"===this._devices.find(t=>t.id===this._drag.id)?.bindingStatus?.kind&&(this._drag=null),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(av(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const t=this._devices.filter(t=>!t.marker&&!t.virtual).map(t=>t.id).sort(),e=t.join(",");if(e===this._newSyncKey)return;this._newSyncKey=e;const i=this._settings,{fresh:s,known:n}=function(t,e){if(!Array.isArray(e))return{fresh:[],known:[...t]};const i=new Set(e),s=t.filter(t=>!i.has(t));return{fresh:s,known:s.length?[...e,...s]:e}}(t,i.known_devices);if(!Array.isArray(i.known_devices)||s.length){const t=[...new Set([...i.new_device_ids||[],...s])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:n,new_device_ids:t}},this._saveConfig()}}get _newIds(){const t=this._settings.new_device_ids;return new Set(Array.isArray(t)?t:[])}_ackNewDevice(t){if(!this._newIds.has(t)||!this._serverCfg)return;const e=this._settings;this._serverCfg={...this._serverCfg,settings:{...e,new_device_ids:(e.new_device_ids||[]).filter(e=>e!==t)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(t){if(!t)return null;const e=[];for(const i of this._renderDevices){if(i.area!==t||i.virtual)continue;const s=_o(this._renderPlanHass,i.entities);null!=s&&e.push(s)}return Ei(e)}_roomBounds(t){if(t.poly&&t.poly.length){const e=t.poly.map(t=>t[0]),i=t.poly.map(t=>t[1]),s=Math.min(...e),n=Math.min(...i);return{x:s,y:n,w:Math.max(...e)-s,h:Math.max(...i)-n}}return{x:t.x??0,y:t.y??0,w:t.w??0,h:t.h??0}}_defaultPositions(){const t={},e=this._config?.icon_size??2.5;for(const i of this._model){const s=e/100*Uh(i)*1.3;for(const e of i.rooms){if(!e.area)continue;const n=this._devices.filter(t=>t.area===e.area&&t.space===i.id);if(!n.length)continue;const o=this._roomBounds(e),a=.1*Math.min(o.w,o.h),r=o.w-2*a,l=o.h-2*a,c=Math.max(1,Math.round(Math.sqrt(n.length*r/Math.max(l,1)))),h=Math.ceil(n.length/c),d=r/c,p=l/Math.max(h,1),u=n.map((t,e)=>({x:o.x+a+d*(e%c+.5),y:o.y+a+p*(Math.floor(e/c)+.5)}));Oi(u,o,s,.5*a),n.forEach((e,i)=>t[e.id]=Rh(u[i]))}}return t}_pos(t){const e=this._renderDeviceSnapshot?.positions.get(t.id);return e?{x:e.x,y:e.y}:this._livePos(t)}_livePos(t){const e=this._spaceModelById(t.space),i=this._layout[t.id];if(i)if(this._norm){if(i.s===t.space)return{x:i.x*ev,y:i.y*ev}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[t.id]?this._defPos[t.id]:e?Rh(jh(e)):{x:500,y:500}}_savePos(t,e,i){if(this._spaceModelById(t.space)){if(this._norm){const s=this._gridPitch,n=Math.round(e/s)*s,o=Math.round(i/s)*s,a=this._layout[t.id]?.k;this._layout={...this._layout,[t.id]:{s:t.space,x:Ah(n/ev),y:Ah(o/ev),...a?{k:a}:{}}}}else this._layout={...this._layout,[t.id]:{x:Math.round(e),y:Math.round(i)}};this._dirtyPos.add(t.id),this._persistLayout()}}_visualSamples(t){return Yu(this._renderPlanHass,t,this._renderDevices,void 0,this._fullRegistryHass).samples}_devicePresentation(t,e=!1!==this._config?.show_signal,i=!1){const s=i?null:this._renderDeviceSnapshot?.presentations.get(n_(t.id,e));return s||t_(this._renderPlanHass,t,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:e,designPreview:i,activityRuntime:this._activityRt.get(t.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(t){return this._devicePresentation(t).visual}_stateClass(t,e=this._deviceVisual(t)){const i=this._devicePresentation(t);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===e.status||e.activity,Qu({...i,visual:e}).join(" "))}_liveTemp(t){if(!this._config?.show_temperature)return null;if(!0===t.marker?.use_climate_temp){const e=go(this._renderPlanHass,t.entities);if(null!=e)return e}return"mdi:thermometer"!==t.icon&&"mdi:air-filter"!==t.icon?null:mo(this._renderPlanHass,t.entities)}_bindingEntities(t){if("virtual"===t||!t)return[];const e=this._bindingStatus(t);return"active"===e.kind?e.enabledEntityIds:e.allEntityIds}_bindingHasClimate(t){return this._bindingEntities(t).some(t=>t.startsWith("climate."))}_bindingHasAlarm(t){return this._bindingEntities(t).some(t=>{const e=this._planHass?.states?.[t]||this.hass?.states?.[t],i=this._fullRegistryHass.entities[t]||this.hass?.entities?.[t];return Bs(t.split(".")[0],e?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_liveHum(t){return this._config?.show_temperature&&t.primary&&fo(this.hass,t.primary)?vo(this.hass,t.entities):null}_deviceBindingActive(t,e=!0){if(t.virtual||"virtual"===t.bindingKind)return!0;if(!t.bindingKind||!t.bindingRef)return!1;const i=this._bindingStatus(`${t.bindingKind}:${t.bindingRef}`);return"active"===i.kind||(e&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(t){t?this._planEntityAvailable(t)?(this._nativeMoreInfoEntity=t,av(this,"hass-more-info",{entityId:t})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(t,e){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==t)for(const i of[e,this._stageEl])try{i?.hasPointerCapture?.(t)&&i.releasePointerCapture(t)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_ctxDevice(t,e){"view"===this._mode&&(t.preventDefault(),t.stopPropagation(),this._deviceBindingActive(e)&&(e.primary?this._openMoreInfo(e.primary):this._infoCard=e))}_clickDevice(t,e){if(t.stopPropagation(),this._drag?.moved||this._suppressClick||this._holdFired)return;if("plan"===this._mode)return;if("devices"===this._mode)return void this._openMarkerDialog(e);const i=this._devices.find(t=>t.id===e.id);if(!i)return;const s=pp(i.tapAction,i.primary?.split(".")[0]),n=(t,e)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:t,exec:e}:e()};if("toggle"===s){const t=this._toggleIntent(i);if(!t)return;if(!vp(t))return void this._showUnavailableToggleTargets(t);const e=t=>{const e=vp(t);if(!e)return;if("virtual-light"===e.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:e.markerId}).then(t=>{const e=wn(this._virtualLights,t);e!==this._virtualLights&&(this._virtualLights=e,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(t=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(t)})));const{command:s}=e;this._startDevicePressFeedback(i.id),this.hass.callService(s.domain,s.service,s.data).catch(t=>this._showToast(this._t("toast.error",{err:this._errText(t)})))},s=((o=t).targets.length?o.targets:o.skippedTargets).map(t=>t.name||t.entityId||t.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const n=this._toggleConfirmationLines(t);if(!n.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:s}),lines:n,initialIntent:t,deviceId:i.id,exec:()=>{const s=this._devices.find(t=>t.id===i.id),n=s?this._toggleIntent(s):null;n&&!vp(n)&&this._showUnavailableToggleTargets(n)||(n&&bp(t,n)?e(n):this._showToast(this._t("toast.tap_target_changed")))}}}else e(t);return}var o;if("info"===s)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===s){const t=i.marker?.tap_target||"",e=function(t){const e=String(t||"").split(".")[0];return"automation"===e?{domain:"automation",service:"trigger"}:"script"===e?{domain:"script",service:"turn_on"}:"scene"===e?{domain:"scene",service:"turn_on"}:null}(t),s=this.hass.states[t];if(!e||!s)return void this._showToast(this._t("toast.run_target_missing"));const o=s.attributes?.friendly_name||t;return void n(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(t)&&(this._startDevicePressFeedback(i.id),this.hass.callService(e.domain,e.service,{entity_id:t}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(t=>this._showToast(this._t("toast.error",{err:this._errText(t)}))))})}"more-info"===s&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(t){const e=function(t){if(!t||"group"!==t.kind||vp(t)||"configured-targets-missing"!==t.noneReason)return[];if(!t.skippedTargets.length||t.skippedTargets.some(t=>!yp.has(t.reason)&&"secure"!==t.reason))return[];const e=[],i=new Set;for(const s of t.skippedTargets){if(!yp.has(s.reason))continue;const t=String(s.name||s.entityId||s.ref||"").trim();t&&!i.has(t)&&(i.add(t),e.push(t))}return e}(t);return!!e.length&&(this._showToast(1===e.length?this._t("toast.toggle_target_unavailable",{name:e[0]}):this._t("toast.toggle_targets_unavailable",{names:e.join(", ")})),!0)}_keyDevice(t,e){"Enter"!==t.key&&" "!==t.key||"view"!==this._mode&&"devices"!==this._mode||(t.preventDefault(),this._clickDevice(t,e))}_startDevicePressFeedback(t){const e=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(e=>e.dataset.id===t),i=e?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const s=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),n=Number.isFinite(s)?Math.max(.95,Math.min(1,s)):1;this._devicePressAnimations.get(t)?.cancel();const o=this._reducedMotion?[{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"},{outlineColor:"var(--hp-accent, #3ea6ff)",outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"2px",offset:.5},{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"}]:[{scale:String(n)},{scale:"0.95",offset:.5},{scale:"1"}],a=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(t,a);const r=()=>{this._devicePressAnimations.get(t)===a&&this._devicePressAnimations.delete(t)};a.addEventListener("finish",r,{once:!0}),a.addEventListener("cancel",r,{once:!0})}_cancelDevicePressFeedback(){for(const t of this._devicePressAnimations.values())t.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const t=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(t=>t.dataset.id||""));for(const[e,i]of this._devicePressAnimations)t.has(e)||(i.cancel(),this._devicePressAnimations.delete(e))}_t(t,e){return la(ra(this.hass,this._config?.language),t,e)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex")}}_help(t){const e=`${t}.aria`,i=ra(this.hass,this._config?.language);return ca(i,t)&&ca(i,e)?W``:G}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(t){const e=[];for(const i of this._devices){if(i.space!==t.id||i.hidden)continue;const s=this._pos(i);e.push({minX:s.x,minY:s.y,maxX:s.x,maxY:s.y})}if(t.id===this._space){for(const t of this._openingsR){const i=Number(t.angle)*Math.PI/180,s=Math.cos(i)*t.rlen/2,n=Math.sin(i)*t.rlen/2,o=Eh([[t.rx-s,t.ry-n],[t.rx+s,t.ry+n]]);o&&e.push(o)}const i=this._decorH;for(const t of this._decorList){const s=Eh("line"===t.kind?[[t.x1*ev,t.y1*i],[t.x2*ev,t.y2*i]]:"text"===t.kind?[[t.x*ev,t.y*i]]:Lr({x:t.x*ev,y:t.y*i,w:t.w*ev,h:t.h*i,angle:t.angle}));s&&e.push(s)}for(const i of this._physicalBodiesR(t)){const t=Eh(i);t&&e.push(t)}}return Oh(t,e)}_frameOf(){const t=this._spaceModel();if(!t){this._frame=null;const t={x:0,y:0,w:ev,h:ev};return{rect:t,all:t,outliers:0}}const e=this._frame,i="view"!==this._mode;if(e&&e.id===t.id&&this._bdDrag)return e;if(e&&e.id===t.id&&e.model===t&&e.layout===this._layout&&e.devs===this._devices&&e.far===this._showFar&&e.grow===i)return e;const s=qh(this._contentItems(t));let n=s.all||Wh(t),o=this._showFar?n:s.core||Wh(t);return e&&e.id===t.id&&i&&e.grow&&(o=sv(e.rect,o),n=sv(e.all,n)),this._frame={id:t.id,model:t,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:n,outliers:s.outliers},this._frame}_isoSource(){const t=this._spaceModel();if(!t)return null;const e=this._spaceWalls,i=this._openCuts(),s=this._openingsR.map((t,e)=>({id:String(t.id||e),sourceIndex:e,type:t.type,x:t.rx,y:t.ry,angle:Number(t.angle)||0,length:t.rlen>0?t.rlen:900,flipH:!!t.flip_h,flipV:!!t.flip_v})),n=mh(64,this._cellCm),o=mh(10,this._cellCm),a=`${t.id}|${function(t){let e=2166136261;const i=t=>{if("number"!=typeof t)if("string"!=typeof t)if("boolean"!=typeof t)if(Array.isArray(t)){e=af(e,t.length);for(const e of t)i(e)}else{if(t&&"object"==typeof t){const e=t;for(const t of Object.keys(e).sort())i(t),i(e[t]);return}e=af(e,-1)}else e=af(e,t?1:0);else for(const i of t)e=af(e,i.codePointAt(0)||0);else e=af(e,t)};return i(t),e.toString(36)}({rooms:t.rooms,walls:e,openCuts:i,openings:s,partitions:t.partitions,roomDrafts:t.room_drafts,columns:t.wall_columns,cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,camera:Vg,wallHeight:n,floorEdgeHeight:o,algorithm:3})}`;return{key:a,build:()=>{const o=eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t)).all,a=this._roomWallOpeningInputs(this._openingsR,t),r=e.length||o.length?Rc(t.rooms,e,i,a,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,o):null;if(r&&("failed-core"===r.status||"not-applicable"===r.status))throw new Error("wall boolean geometry failed");const l=r?.paperGeom??Pc(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,ev);if(!l)throw new Error("floor boolean geometry failed");const c=r?.openingIndex||Fc(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,ev),h=s.map(t=>{const i=this._openingsR[t.sourceIndex],s="gate"===t.type?!t.flipV:t.flipV,o=i?.partitionHost?Dp(i.partitionHost,s):e.length||"gate"===t.type?Lc(c,{x:t.x,y:t.y,angle:t.angle,length:t.length,flip_v:s}):{ox:0,oy:0,cm:0,side:-1};return function(t,e=64){if(!(rf([t.x,t.y,t.angle,t.length,t.face.ox,t.face.oy,e])&&t.length>0&&e>0))throw new Error("invalid isometric opening input");const i=t.length/2;let s;if("passage"===t.type)s=[];else if("gate"===t.type){const n=10*t.face.side;s=[cf(t,0,[-i,0],[i,0],n,0,.88*e),cf(t,1,[i,0],[-i,0],-n,0,.88*e)]}else s="window"===t.type?[cf(t,0,[-i,0],[i,0],-90,.27*e,.78*e),cf(t,1,[i,0],[-i,0],90,.27*e,.78*e)]:[cf(t,0,[-i,0],[t.length,0],-90,0,.92*e)];return{id:t.id,sourceIndex:t.sourceIndex,type:t.type,leaves:Object.freeze(s.map(t=>Object.freeze(t)))}}({...t,face:o},n)});return{walls:r?.components.flatMap(t=>t.geom)||[],floor:l,openings:Object.freeze(h)}}}}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return`${this._space}|invalid`}}_isoScene(){const t=this._isoSource();if(!t)return null;const e=this._isoGeometryCache.get(t.key);if(e)return{key:t.key,...e};const i=this._frameOf().rect,s=t.build(),n=mh(64,this._cellCm),o=mh(10,this._cellCm),a=function(t){let e=1/0,i=1/0,s=-1/0,n=-1/0;for(const o of t)for(const t of o.leaves){const o=Math.hypot(t.closedVector[0],t.closedVector[1]);e=Math.min(e,t.hinge[0]-o),i=Math.min(i,t.hinge[1]-o),s=Math.max(s,t.hinge[0]+o),n=Math.max(n,t.hinge[1]+o)}return rf([e,i,s,n])?{x:e,y:i,w:s-e,h:n-i}:null}(s.openings),r=Zg({rect:a?sv(i,a):i,wallHeight:n,openingHeight:n,floorDepth:o}),l=function(t,e=Vg,i=64){if(!Number.isFinite(i)||i<0)throw new Error("invalid wall height");const s=[],n=[],o=[];let a=0;for(let r=0;r<(t||[]).length;r++){const l=t[r];for(let t=0;t<(l||[]).length;t++){const c=ef(l[t],t>0);if(!(c.length<3||Math.abs(tf(c))<1e-9)){s.push(sf(c,e,i)),a+=c.length;for(let s=0;st.depth-e.depth||t.polygon-e.polygon||t.ring-e.ring||t.edge-e.edge),{topPath:s.join(" "),sides:n,contactPath:o.join(" "),edgeCount:a}}(s.walls,Vg,n),c={geometry:l,floor:of(s.floor,o),openings:s.openings,frame:r};return Wf(this._isoGeometryCache,t.key,c,8),{key:t.key,...c}}_effectiveProjection(){if("iso"!==this._desiredProjection||!this._model.length)return"flat";const t=this._isoSceneKey()||`${this._space}|invalid`;if(this._isoFallback.has(t))return"flat";try{const t=this._isoScene();return t?(e="iso",i=t.key,s=this._isoFallback,"iso"===e&&i&&!s.has(i)?"iso":"flat"):"flat"}catch(e){if(!this._isoFallback.has(t)){this._isoFallback.add(t);const i=t.split("|");console.warn(`HOUSEPLAN ISO FALLBACK: #89, space ${this._space}, fingerprint ${i[i.length-1]}, ${e instanceof Error?e.message:"renderer error"}`)}return"flat"}var e,i,s}_scenePoint(t){return"iso"===this._renderProjection?Yg(t,0):t}_floorView(t){if("iso"!==this._renderProjection)return t;const e=Jg([t.x,t.y]),i=Jg([t.x+t.w,t.y+t.h]);return{x:e[0],y:e[1],w:i[0]-e[0],h:i[1]-e[1]}}_baseVb(){if("iso"===this._effectiveProjection()){if(!this._spaceDisplayForRender().showBorders){const t=Zg({rect:this._frameOf().rect,wallHeight:mh(64,this._cellCm)});return[t.x,t.y,t.w,t.h]}const t=this._isoScene()?.frame??this._frameOf().rect;return[t.x,t.y,t.w,t.h]}const t=this._frameOf().rect;return[t.x,t.y,t.w,t.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._showFar=!0,this._frame=null,this._resetZoom()}_fitAll(){this._showFar=!0,this._frame=null,this._resetZoom()}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?G:W`
+
`}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(t=>({...t,...t.stage?{stage:[...t.stage]}:{}}))}getCardSize(){return 12}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const t=this._serverCfg?.spaces||[];let e=t.length+":";for(const i of t){e+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const t of i.rooms||[]){const i=t.poly?.[0],s=t.poly?.[t.poly.length-1];e+=(t.poly?.length||0)+"."+(t.id||"")+"."+(t.open_to||[]).join("+")+"."+(t.area||"")+"."+JSON.stringify(t.settings||0)+"."+(t.x??"")+","+(t.y??"")+","+(t.w??"")+","+(t.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(s?s[0]+"/"+s[1]:"")+";"}}return e}get _model(){if(!this._serverCfg)return[];const t=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===t)return this._modelCache.model;const e=this._buildModel();return this._modelCache={key:t,model:e},e}_buildModel(){if(!this._serverCfg)return[];const t=this._renderCfg;return $h(t).map((e,i)=>{const s=t.spaces[i]?.plan_url;return e.bg&&s?{...e,bg:{...e.bg,href:s}}:e})}_spaceModel(){return this._hasFixedFloor?$d(this._model,this._space):(t=this._model,e=this._space,t.find(t=>t.id===e)??t[0]);var t,e}_spaceModelById(t){return $d(this._model,t)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0;for(const t of this._pointers.keys())for(const e of this.renderRoot.querySelectorAll("*"))try{e.hasPointerCapture?.(t)&&e.releasePointerCapture(t)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._resumeDraftBySpace={},this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const t={};for(const e of this._model)for(const i of e.rooms)i.area&&(t[i.area]={space:e.id,room:i});return t}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._settings.filter_seeded?this._showHidden:!!this._settings.show_all}_toggleShowAll(){if(this._serverCfg){if(this._settings.filter_seeded)return this._showHidden=!this._showHidden,void this.requestUpdate();this._serverCfg={...this._serverCfg,settings:{...this._serverCfg.settings,show_all:!this._settings.show_all}},this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}}_seedHiddenDevices(){if(!this._serverCfg||!this._norm||!this._canEdit)return;const t=this._serverCfg,e=function(t){const e=t.hass,i=t.registry||An(e),s=Nn(e,i),n=On(e,i),{areaToSpace:o,markers:a,settings:r,excluded:l,iconRules:c}=t,h=!1!==r.group_lights,d=wo(a),p=yo(s,h).filter(t=>!ko(s,t.eid,d)),u=new Set(p.map(t=>t.area)),_=qn(s),m=Wn(a,n),g=new Set(a.map(t=>t.binding)),f=[];for(const t of Object.values(s.devices)){const n=t.area_id;if(!n||!o[n])continue;if("service"===t.entry_type)continue;if(g.has("device:"+t.id))continue;if("active"!==Bn(e,"device:"+t.id,i).kind)continue;const a=jn(s,t.id,_[t.id]||[],m);if(a.partial&&!a.entityIds.length)continue;const r=a.entityIds,d=Un(s,t,r);let p=l.has(d)||"Group"===t.model||/scene/i.test(t.model||"")||/bridge/i.test((t.model||"")+(t.name||""))||"myheat"===d&&!!t.via_device_id;if(!p&&h&&u.has(n)){const e=(t.name_by_user||t.name||"").trim();"mdi:lightbulb"===bo(s,e,t.model,r,c)&&(p=!0)}p&&f.push("device:"+t.id)}return f}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!e.length&&t.settings?.filter_seeded)return;t.markers=t.markers||[];const i=[];for(const s of e){const e="h"+s.slice(s.indexOf(":")+1);t.markers.push({id:e,binding:s,hidden:!0}),i.push(s.slice(s.indexOf(":")+1))}const s={...t.settings||{},filter_seeded:!0};delete s.show_all,i.length&&Array.isArray(s.new_device_ids)&&(s.new_device_ids=s.new_device_ids.filter(t=>!i.includes(t))),t.settings=s,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const t=this._settings.icon_rules;if(!t||!Array.isArray(t)||!t.length)return;const e=JSON.stringify(t);return e!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=e,this._rulesCompiled=Xt(t)),this._rulesCompiled}get _fillColors(){return ps(this._settings)}get _excluded(){const t=this._settings.exclude_integrations;return t?new Set(t):Yt}willUpdate(t){t.has("_serverCfg")&&this._cfgEpoch++,this._syncEmptySpaceState(),t.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._planHassMemo=null,this._hookConnection(),!this._loadOk&&!this._loading&&this._loadTries<8&&this._loadFromServer(),this._maybeRebuildDevices(),this._vacTick(),this._activityTick()),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._warmSnapshot(),this._dtMeasure();const t=this._stageEl;t&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>this._refitView()),this._roViewport.observe(t)),t&&this._booting&&!this._bootTimer&&this._bootWatch();const e=this.renderRoot.querySelector(".hdr");if(e&&t&&!this._roHdr){const i=()=>{const e=this.renderRoot.querySelector("ha-card");if(!e)return;const i=t.getBoundingClientRect().top-e.getBoundingClientRect().top,s=Math.min(Math.max(e.getBoundingClientRect().top,0),120),n=Math.round(i+s);n>=0&&n!==this._hdrH&&(this._hdrH=n),n>=0&&!this._booting&&!this._config?.kiosk&&t.clientHeight>0&&this._warmPatch({hdrH:n,stageH:t.clientHeight})};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(e),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(t&&!this._view&&this._refitView(),this._editorSecondary.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const t=function(t){const e=t?.floors;if(!e||"object"!=typeof e)return[];const i=[];for(const t of Object.values(e))t&&t.floor_id&&i.push({id:t.floor_id,name:t.name||t.floor_id,level:t.level??null});return i.sort((t,e)=>{const i=t.level??1e9,s=e.level??1e9;return i!==s?i-s:t.name.localeCompare(e.name)}),i}(this.hass);t.length?this._importDialog={floors:t.map(t=>({...t,checked:!0}))}:this._openSpaceDialog("create")}}_adoptStructuralResponses(t,e,i){const s=t?.config,n=s&&Array.isArray(s.spaces)?s:null,o=bd(n),a=o!==(this._cfgContentFingerprint||bd(this._serverCfg));if(a&&(this._geometryHistory.clear(),this._pendingPhysicalWrites.clear(),this._serverCfg&&this._clearGeometryGesture(),this._serverCfg=n,this._cfgContentFingerprint=o),this._cfgRev=t?.rev??this._cfgRev,t&&("virtual_lights"in t||"config"in t)){const e=gn(this._virtualLights,t.virtual_lights,this._cfgRev,"virtual_lights"in t);vn(e)!==vn(this._virtualLights)&&(this._virtualLights=e,this._capturedSnapshotVirtual="")}let r=!1;if(void 0!==e||void 0!==i){const t=i??e?.layout??{},s=bd(t);r=s!==(this._layoutContentFingerprint||bd(this._layout)),r&&(this._layout=t,this._layoutContentFingerprint=s),this._layoutRev=e?.rev??this._layoutRev}return this._canOptimizeUndo=!(!t?.can_optimize_undo&&!e?.can_optimize_undo),this._haIntegrationVersion="string"==typeof t?.integration_version?t.integration_version:this._haIntegrationVersion,this._undoKind=t?.undo_kind||e?.undo_kind||null,"boolean"==typeof t?.can_write&&(this._serverCanWrite=t.can_write),a&&this._continuity.note("config-candidate",{configRev:this._cfgRev}),r&&this._continuity.note("layout-candidate",{layoutRev:this._layoutRev}),{configChanged:a,layoutChanged:r}}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const t=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(t,!1),!0}async _loadFromServer(){this._loading=!0,this._loadTries++;const t=this._space,e=!!this._view;try{const[i,s]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]),n=i?.config&&Array.isArray(i.config.spaces)?i.config:null,o=bd(n)!==(this._cfgContentFingerprint||bd(this._serverCfg))||bd(s?.layout??{})!==(this._layoutContentFingerprint||bd(this._layout));if(o){if(!await this._signer.prepareImage(this.hass,this._candidateBackdrop(n)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0)}o&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),this._connectionWasLost=!1,this._serverStorage=!0,"boolean"==typeof i?.can_write&&(this._serverCanWrite=i.can_write),this._canOptimizeUndo=!(!i?.can_optimize_undo&&!s?.can_optimize_undo),this._haIntegrationVersion="string"==typeof i?.integration_version?i.integration_version:this._haIntegrationVersion,this._adoptStructuralResponses(i,s),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:e&&this._space===t||this._restoreZoom(),this._loadOk=!0,this.hass.callWS({type:"houseplan/trail/get"}).then(t=>{this._vacSrvTrails=t?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(t){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(Yf)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const t=this.hass?.connection;if(!t)return;if(t!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=t),this._liveSyncAttempt)return;const e=this._liveSyncGeneration,i=[],s=(s,n,o,a)=>{s()||i.push(async()=>{const i=await t.subscribeEvents(a,o);e===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===t&&!s()?n(i):i?.()})};if(s(()=>this._unsubCfg,t=>{this._unsubCfg=t},"houseplan_config_updated",t=>{const e=Number(t?.data?.rev??-1);e!==this._cfgRev&&this._reloadConfigOnly(!1,e)}),s(()=>this._unsubTrail,t=>{this._unsubTrail=t},"houseplan_trail_updated",async()=>{try{const t=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=t?.trails||{},this.requestUpdate()}catch{}}),s(()=>this._unsubLayout,t=>{this._unsubLayout=t},"houseplan_layout_updated",t=>this._onLayoutEvent(Number(t?.data?.rev??-1))),s(()=>this._unsubVirtual,t=>{this._unsubVirtual=t},"houseplan_virtual_light_updated",t=>{const e=wn(this._virtualLights,t?.data);e!==this._virtualLights&&(this._virtualLights=e,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const n=function(t){return Promise.allSettled(t.map(t=>Promise.resolve().then(t)))}(i).then(()=>{});this._liveSyncAttempt=n,n.finally(()=>{this._liveSyncAttempt===n&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(t=!1,e){if(!t){if(void 0!==e&&e<=this._cfgRev)return;if(this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(()=>this._reloadConfigOnly(!1,e),400))}this._beginContinuityCandidate("config-reload",!1);try{const t=await this.hass.callWS({type:"houseplan/config/get"}),e=t?.config&&Array.isArray(t.config.spaces)?t.config:null;if(bd(e)!==(this._cfgContentFingerprint||bd(this._serverCfg))&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(e)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0);const i=this._space;this._adoptStructuralResponses(t),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._space!==i&&this._restoreZoom(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}catch(t){this._showToast(this._t("toast.cfg_reload_failed",{err:this._errText(t)}))}finally{this._continuityDataReady=!0,this.requestUpdate()}}_scheduleLoadRetry(t=!1){if(void 0!==this._loadRetryTimer)return;const e=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!t&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},e)}_ensureHaRegistryAuthority(){const t=this.hass?.connection||null;t&&t!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=t,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._haRegistryRelease=In(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return An(this.hass)}get _planHass(){const t=this._haRegistry,e=Fn(this.hass,t),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===e)return i.active;const s=Nn(this.hass,t),n=On(this.hass,t);return this._planHassMemo={hass:this.hass,sig:e,active:s,full:n},s}_captureRenderDeviceSnapshot(){if(!this.hass)return;const t=Date.now(),e=[...this._activityRt.entries()].map(([e,i])=>`${e}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+R_)>t?1:0)).join("|"),i=vn(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===e)return;const s=this._planHass,n=new Map,o=new Map,a=new Set(["sun.sun"]);this._vacFit?.source&&a.add(this._vacFit.source);const r=new Set,l=new Set,c=t=>{if(!t)return;const e=t.indexOf(":");if(e<0)return void a.add(t);const i=t.slice(0,e),s=t.slice(e+1);"device"===i?r.add(s):"entity"===i&&a.add(s)};for(const t of this._model)for(const e of t.rooms)e.area&&l.add(e.area),c(e.settings?.temp_source),c(e.settings?.hum_source);for(const t of this._serverCfg?.spaces||[])for(const e of t.openings||[])for(const t of gi(e))a.add(t);for(const t of this._serverCfg?.spaces||[])for(const e of t.decor||[])if("text"===e.kind){for(const t of String(e.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const e=Yi(t[1]);e?.entity&&a.add(e.entity)}e.entity&&a.add(e.entity),o.set(`decor:${t.id}:${e.id}`,ts(e.text,e,s,t=>!!s.entities?.[t]&&!!s.states?.[t]&&!ko(s,t,wo(this._markers))))}const h=ho(s,this._devices,null,this._virtualLights);for(const t of this._devices){for(const e of[!1,!0])n.set(n_(t.id,e),t_(s,t,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:e,activityRuntime:this._activityRt.get(t.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(t)){const e=this._vacSource(t,s),i=e?Nd(s?.states?.[e]?.attributes):null,n=this._vacRt.get(t.id);o.set(`vacuum:${t.id}`,{source:e,telemetry:i,mapId:i?this._vacMapId(t,i,s):null,runtime:n?{trail:n.trail,lastTs:n.lastTs,moving:n.moving,jump:n.jump}:null,server:this._vacSrvTrails[t.id]||null})}}const d=s_({sourceSequence:this._hassSequence,hass:s,devices:this._devices,presentations:n,positions:(p=this._model.length>0,u=this._devices,_=t=>this._livePos(t),p?new Map(u.map(t=>[t.id,_(t)])):new Map),facts:o,entityIds:a,deviceIds:r,areaIds:l});var p,u,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=e,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(t){return Bn(this.hass,t,this._haRegistry)}houseplanDiagnostics(){const t=function(t){const e=An(t);return{access:e.access,authoritative:e.authoritative,revision:e.revision,lastSuccess:e.lastSuccess,error:e.error}}(this.hass),e={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const t of this._markers)t.removed||"virtual"===t.binding||e[this._bindingStatus(t.binding).kind]++;return{registry:{...t,lastSuccessAgeMs:t.lastSuccess?Math.max(0,Date.now()-t.lastSuccess):null},bindings:e}}_openBindingInHa(t){const[e,i]=t.split(":");if(i)if("device"!==e){if("entity"===e){const t=this._fullRegistryHass.entities?.[i];t?.device_id&&lv("/config/devices/device/"+encodeURIComponent(t.device_id))}}else lv("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(t){const[e,i]=t.split(":");return!!i&&("device"===e||"entity"===e&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const t=this._markerDialog;if(!t)return;const e="ha"===t.bindingMode?this._bindingStatus(t.binding):null,i=t.hideFromPlan||"ha_disabled"===e?.kind;i&&"ha_disabled"===e?.kind?this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===e?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...t,hideFromPlan:!i}}_hookConnection(){const t=this.hass?.connection;t&&t!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),t.addEventListener?.("ready",this._onConnReady),t.addEventListener?.("disconnected",this._onConnLost),t.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=t)}_display(t){return this._signer.display(this.hass,t)}_resign(){this._signer.resign(this.hass,Is(this._serverCfg))}_onLayoutEvent(t){t<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{t<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(t){const e=t?.rev;"number"==typeof e&&e>this._layoutRev&&(this._layoutRev=e)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const t=new Map;for(const e of this._dirtyPos)this._layout[e]&&t.set(e,this._layout[e]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[e,i]of this._sentPos)t.set(e,i);try{const e=await this.hass.callWS({type:"houseplan/layout/get"}),i={...e?.layout||{}};for(const[e,s]of t)i[e]=s;const s=bd(i);s!==(this._layoutContentFingerprint||bd(this._layout))&&(this._layout=i,this._layoutContentFingerprint=s),this._layoutRev=e?.rev??this._layoutRev,this._canOptimizeUndo=!!e?.can_optimize_undo,this._haIntegrationVersion="string"==typeof e?.integration_version?e.integration_version:this._haIntegrationVersion,this._undoKind=e?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_maybeRebuildDevices(){const t=this.hass;if(!t?.devices||!t?.entities||!t?.areas)return;const e=this._haRegistry,i=Fn(t,e)+":"+Object.keys(t.areas).length+":"+(this._norm?"n":"l")+":"+ra(t,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const s=new Map(this._devices.map(t=>[t.id,t.bindingStatus?.kind||"active"]));this._devices=So({hass:t,registry:e,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:t=>this._t(t),iconRules:this._iconRules});const n=this._markers.filter(t=>!t.removed&&"virtual"!==t.binding).map(t=>t.binding).sort(),o=e.revision+":"+n.join("|");if(e.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const s of n)i.set(s,Bn(t,s,e));!function(t){if("undefined"==typeof localStorage||!t.size)return;const e=Hn(),i=Date.now();for(const[s,n]of t)"active"===n.kind?e[s]={kind:"active",ts:i}:"ha_disabled"===n.kind&&(e[s]={kind:"ha_disabled",reason:n.reason,ts:i});const s=Object.fromEntries(Object.entries(e).sort((t,e)=>e[1].ts-t[1].ts).slice(0,1500));Mn=s;try{localStorage.setItem(Sn,JSON.stringify(s))}catch{}}(i),this._haBindingCacheKey=o}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),this._syncActivityRuntime();const a=new Set(this._devices.filter(t=>!t.hidden).map(t=>t.id));for(const t of this._vacRt.keys())a.has(t)||this._vacRt.delete(t);if(this._infoCard){const t=this._devices.find(t=>t.id===this._infoCard.id);this._infoCard=t&&"ha_disabled"!==t.bindingStatus?.kind?t:null}const r=this._devices.some(t=>"ha_disabled"===t.bindingStatus?.kind&&"ha_disabled"!==s.get(t.id));r&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(t=>t.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._drag&&"ha_disabled"===this._devices.find(t=>t.id===this._drag.id)?.bindingStatus?.kind&&(this._drag=null),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(rv(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const t=this._devices.filter(t=>!t.marker&&!t.virtual).map(t=>t.id).sort(),e=t.join(",");if(e===this._newSyncKey)return;this._newSyncKey=e;const i=this._settings,{fresh:s,known:n}=function(t,e){if(!Array.isArray(e))return{fresh:[],known:[...t]};const i=new Set(e),s=t.filter(t=>!i.has(t));return{fresh:s,known:s.length?[...e,...s]:e}}(t,i.known_devices);if(!Array.isArray(i.known_devices)||s.length){const t=[...new Set([...i.new_device_ids||[],...s])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:n,new_device_ids:t}},this._saveConfig()}}get _newIds(){const t=this._settings.new_device_ids;return new Set(Array.isArray(t)?t:[])}_ackNewDevice(t){if(!this._newIds.has(t)||!this._serverCfg)return;const e=this._settings;this._serverCfg={...this._serverCfg,settings:{...e,new_device_ids:(e.new_device_ids||[]).filter(e=>e!==t)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(t){if(!t)return null;const e=[];for(const i of this._renderDevices){if(i.area!==t||i.virtual)continue;const s=_o(this._renderPlanHass,i.entities);null!=s&&e.push(s)}return Ei(e)}_roomBounds(t){if(t.poly&&t.poly.length){const e=t.poly.map(t=>t[0]),i=t.poly.map(t=>t[1]),s=Math.min(...e),n=Math.min(...i);return{x:s,y:n,w:Math.max(...e)-s,h:Math.max(...i)-n}}return{x:t.x??0,y:t.y??0,w:t.w??0,h:t.h??0}}_defaultPositions(){const t={},e=this._config?.icon_size??2.5;for(const i of this._model){const s=e/100*Uh(i)*1.3;for(const e of i.rooms){if(!e.area)continue;const n=this._devices.filter(t=>t.area===e.area&&t.space===i.id);if(!n.length)continue;const o=this._roomBounds(e),a=.1*Math.min(o.w,o.h),r=o.w-2*a,l=o.h-2*a,c=Math.max(1,Math.round(Math.sqrt(n.length*r/Math.max(l,1)))),h=Math.ceil(n.length/c),d=r/c,p=l/Math.max(h,1),u=n.map((t,e)=>({x:o.x+a+d*(e%c+.5),y:o.y+a+p*(Math.floor(e/c)+.5)}));Oi(u,o,s,.5*a),n.forEach((e,i)=>t[e.id]=Rh(u[i]))}}return t}_pos(t){const e=this._renderDeviceSnapshot?.positions.get(t.id);return e?{x:e.x,y:e.y}:this._livePos(t)}_livePos(t){const e=this._spaceModelById(t.space),i=this._layout[t.id];if(i)if(this._norm){if(i.s===t.space)return{x:i.x*iv,y:i.y*iv}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[t.id]?this._defPos[t.id]:e?Rh(jh(e)):{x:500,y:500}}_savePos(t,e,i){if(this._spaceModelById(t.space)){if(this._norm){const s=this._gridPitch,n=Math.round(e/s)*s,o=Math.round(i/s)*s,a=this._layout[t.id]?.k;this._layout={...this._layout,[t.id]:{s:t.space,x:Ah(n/iv),y:Ah(o/iv),...a?{k:a}:{}}}}else this._layout={...this._layout,[t.id]:{x:Math.round(e),y:Math.round(i)}};this._dirtyPos.add(t.id),this._persistLayout()}}_visualSamples(t){return Yu(this._renderPlanHass,t,this._renderDevices,void 0,this._fullRegistryHass).samples}_devicePresentation(t,e=!1!==this._config?.show_signal,i=!1){const s=i?null:this._renderDeviceSnapshot?.presentations.get(n_(t.id,e));return s||t_(this._renderPlanHass,t,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:e,designPreview:i,activityRuntime:this._activityRt.get(t.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(t){return this._devicePresentation(t).visual}_stateClass(t,e=this._deviceVisual(t)){const i=this._devicePresentation(t);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===e.status||e.activity,Qu({...i,visual:e}).join(" "))}_liveTemp(t){if(!this._config?.show_temperature)return null;if(!0===t.marker?.use_climate_temp){const e=go(this._renderPlanHass,t.entities);if(null!=e)return e}return"mdi:thermometer"!==t.icon&&"mdi:air-filter"!==t.icon?null:mo(this._renderPlanHass,t.entities)}_bindingEntities(t){if("virtual"===t||!t)return[];const e=this._bindingStatus(t);return"active"===e.kind?e.enabledEntityIds:e.allEntityIds}_bindingHasClimate(t){return this._bindingEntities(t).some(t=>t.startsWith("climate."))}_bindingHasAlarm(t){return this._bindingEntities(t).some(t=>{const e=this._planHass?.states?.[t]||this.hass?.states?.[t],i=this._fullRegistryHass.entities[t]||this.hass?.entities?.[t];return Bs(t.split(".")[0],e?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_liveHum(t){return this._config?.show_temperature&&t.primary&&fo(this.hass,t.primary)?vo(this.hass,t.entities):null}_deviceBindingActive(t,e=!0){if(t.virtual||"virtual"===t.bindingKind)return!0;if(!t.bindingKind||!t.bindingRef)return!1;const i=this._bindingStatus(`${t.bindingKind}:${t.bindingRef}`);return"active"===i.kind||(e&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(t){t?this._planEntityAvailable(t)?(this._nativeMoreInfoEntity=t,rv(this,"hass-more-info",{entityId:t})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(t,e){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==t)for(const i of[e,this._stageEl])try{i?.hasPointerCapture?.(t)&&i.releasePointerCapture(t)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_ctxDevice(t,e){"view"===this._mode&&(t.preventDefault(),t.stopPropagation(),this._deviceBindingActive(e)&&(e.primary?this._openMoreInfo(e.primary):this._infoCard=e))}_clickDevice(t,e){if(t.stopPropagation(),this._drag?.moved||this._suppressClick||this._holdFired)return;if("plan"===this._mode)return;if("devices"===this._mode)return void this._openMarkerDialog(e);const i=this._devices.find(t=>t.id===e.id);if(!i)return;const s=pp(i.tapAction,i.primary?.split(".")[0]),n=(t,e)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:t,exec:e}:e()};if("toggle"===s){const t=this._toggleIntent(i);if(!t)return;if(!vp(t))return void this._showUnavailableToggleTargets(t);const e=t=>{const e=vp(t);if(!e)return;if("virtual-light"===e.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:e.markerId}).then(t=>{const e=wn(this._virtualLights,t);e!==this._virtualLights&&(this._virtualLights=e,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(t=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(t)})));const{command:s}=e;this._startDevicePressFeedback(i.id),this.hass.callService(s.domain,s.service,s.data).catch(t=>this._showToast(this._t("toast.error",{err:this._errText(t)})))},s=((o=t).targets.length?o.targets:o.skippedTargets).map(t=>t.name||t.entityId||t.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const n=this._toggleConfirmationLines(t);if(!n.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:s}),lines:n,initialIntent:t,deviceId:i.id,exec:()=>{const s=this._devices.find(t=>t.id===i.id),n=s?this._toggleIntent(s):null;n&&!vp(n)&&this._showUnavailableToggleTargets(n)||(n&&bp(t,n)?e(n):this._showToast(this._t("toast.tap_target_changed")))}}}else e(t);return}var o;if("info"===s)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===s){const t=i.marker?.tap_target||"",e=function(t){const e=String(t||"").split(".")[0];return"automation"===e?{domain:"automation",service:"trigger"}:"script"===e?{domain:"script",service:"turn_on"}:"scene"===e?{domain:"scene",service:"turn_on"}:null}(t),s=this.hass.states[t];if(!e||!s)return void this._showToast(this._t("toast.run_target_missing"));const o=s.attributes?.friendly_name||t;return void n(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(t)&&(this._startDevicePressFeedback(i.id),this.hass.callService(e.domain,e.service,{entity_id:t}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(t=>this._showToast(this._t("toast.error",{err:this._errText(t)}))))})}"more-info"===s&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(t){const e=function(t){if(!t||"group"!==t.kind||vp(t)||"configured-targets-missing"!==t.noneReason)return[];if(!t.skippedTargets.length||t.skippedTargets.some(t=>!yp.has(t.reason)&&"secure"!==t.reason))return[];const e=[],i=new Set;for(const s of t.skippedTargets){if(!yp.has(s.reason))continue;const t=String(s.name||s.entityId||s.ref||"").trim();t&&!i.has(t)&&(i.add(t),e.push(t))}return e}(t);return!!e.length&&(this._showToast(1===e.length?this._t("toast.toggle_target_unavailable",{name:e[0]}):this._t("toast.toggle_targets_unavailable",{names:e.join(", ")})),!0)}_keyDevice(t,e){"Enter"!==t.key&&" "!==t.key||"view"!==this._mode&&"devices"!==this._mode||(t.preventDefault(),this._clickDevice(t,e))}_startDevicePressFeedback(t){const e=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(e=>e.dataset.id===t),i=e?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const s=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),n=Number.isFinite(s)?Math.max(.95,Math.min(1,s)):1;this._devicePressAnimations.get(t)?.cancel();const o=this._reducedMotion?[{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"},{outlineColor:"var(--hp-accent, #3ea6ff)",outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"2px",offset:.5},{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"}]:[{scale:String(n)},{scale:"0.95",offset:.5},{scale:"1"}],a=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(t,a);const r=()=>{this._devicePressAnimations.get(t)===a&&this._devicePressAnimations.delete(t)};a.addEventListener("finish",r,{once:!0}),a.addEventListener("cancel",r,{once:!0})}_cancelDevicePressFeedback(){for(const t of this._devicePressAnimations.values())t.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const t=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(t=>t.dataset.id||""));for(const[e,i]of this._devicePressAnimations)t.has(e)||(i.cancel(),this._devicePressAnimations.delete(e))}_t(t,e){return la(ra(this.hass,this._config?.language),t,e)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex")}}_help(t){const e=`${t}.aria`,i=ra(this.hass,this._config?.language);return ca(i,t)&&ca(i,e)?W``:G}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(t){const e=[];for(const i of this._devices){if(i.space!==t.id||i.hidden)continue;const s=this._pos(i);e.push({minX:s.x,minY:s.y,maxX:s.x,maxY:s.y})}if(t.id===this._space){for(const t of this._openingsR){const i=Number(t.angle)*Math.PI/180,s=Math.cos(i)*t.rlen/2,n=Math.sin(i)*t.rlen/2,o=Eh([[t.rx-s,t.ry-n],[t.rx+s,t.ry+n]]);o&&e.push(o)}const i=this._decorH;for(const t of this._decorList){const s=Eh("line"===t.kind?[[t.x1*iv,t.y1*i],[t.x2*iv,t.y2*i]]:"text"===t.kind?[[t.x*iv,t.y*i]]:Lr({x:t.x*iv,y:t.y*i,w:t.w*iv,h:t.h*i,angle:t.angle}));s&&e.push(s)}for(const i of this._physicalBodiesR(t)){const t=Eh(i);t&&e.push(t)}}return Oh(t,e)}_frameOf(){const t=this._spaceModel();if(!t){this._frame=null;const t={x:0,y:0,w:iv,h:iv};return{rect:t,all:t,outliers:0}}const e=this._frame,i="view"!==this._mode;if(e&&e.id===t.id&&this._bdDrag)return e;if(e&&e.id===t.id&&e.model===t&&e.layout===this._layout&&e.devs===this._devices&&e.far===this._showFar&&e.grow===i)return e;const s=qh(this._contentItems(t));let n=s.all||Wh(t),o=this._showFar?n:s.core||Wh(t);return e&&e.id===t.id&&i&&e.grow&&(o=nv(e.rect,o),n=nv(e.all,n)),this._frame={id:t.id,model:t,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:n,outliers:s.outliers},this._frame}_isoSource(){const t=this._spaceModel();if(!t)return null;const e=this._spaceWalls,i=this._openCuts(),s=this._openingsR.map((t,e)=>({id:String(t.id||e),sourceIndex:e,type:t.type,x:t.rx,y:t.ry,angle:Number(t.angle)||0,length:t.rlen>0?t.rlen:900,flipH:!!t.flip_h,flipV:!!t.flip_v})),n=mh(64,this._cellCm),o=mh(10,this._cellCm),a=`${t.id}|${function(t){let e=2166136261;const i=t=>{if("number"!=typeof t)if("string"!=typeof t)if("boolean"!=typeof t)if(Array.isArray(t)){e=rf(e,t.length);for(const e of t)i(e)}else{if(t&&"object"==typeof t){const e=t;for(const t of Object.keys(e).sort())i(t),i(e[t]);return}e=rf(e,-1)}else e=rf(e,t?1:0);else for(const i of t)e=rf(e,i.codePointAt(0)||0);else e=rf(e,t)};return i(t),e.toString(36)}({rooms:t.rooms,walls:e,openCuts:i,openings:s,partitions:t.partitions,roomDrafts:t.room_drafts,columns:t.wall_columns,cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,camera:Kg,wallHeight:n,floorEdgeHeight:o,algorithm:3})}`;return{key:a,build:()=>{const o=eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t)).all,a=this._roomWallOpeningInputs(this._openingsR,t),r=e.length||o.length?Rc(t.rooms,e,i,a,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,o):null;if(r&&("failed-core"===r.status||"not-applicable"===r.status))throw new Error("wall boolean geometry failed");const l=r?.paperGeom??Pc(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,iv);if(!l)throw new Error("floor boolean geometry failed");const c=r?.openingIndex||Fc(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,iv),h=s.map(t=>{const i=this._openingsR[t.sourceIndex],s="gate"===t.type?!t.flipV:t.flipV,o=i?.partitionHost?Dp(i.partitionHost,s):e.length||"gate"===t.type?Lc(c,{x:t.x,y:t.y,angle:t.angle,length:t.length,flip_v:s}):{ox:0,oy:0,cm:0,side:-1};return function(t,e=64){if(!(lf([t.x,t.y,t.angle,t.length,t.face.ox,t.face.oy,e])&&t.length>0&&e>0))throw new Error("invalid isometric opening input");const i=t.length/2;let s;if("passage"===t.type)s=[];else if("gate"===t.type){const n=10*t.face.side;s=[hf(t,0,[-i,0],[i,0],n,0,.88*e),hf(t,1,[i,0],[-i,0],-n,0,.88*e)]}else s="window"===t.type?[hf(t,0,[-i,0],[i,0],-90,.27*e,.78*e),hf(t,1,[i,0],[-i,0],90,.27*e,.78*e)]:[hf(t,0,[-i,0],[t.length,0],-90,0,.92*e)];return{id:t.id,sourceIndex:t.sourceIndex,type:t.type,leaves:Object.freeze(s.map(t=>Object.freeze(t)))}}({...t,face:o},n)});return{walls:r?.components.flatMap(t=>t.geom)||[],floor:l,openings:Object.freeze(h)}}}}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return`${this._space}|invalid`}}_isoScene(){const t=this._isoSource();if(!t)return null;const e=this._isoGeometryCache.get(t.key);if(e)return{key:t.key,...e};const i=this._frameOf().rect,s=t.build(),n=mh(64,this._cellCm),o=mh(10,this._cellCm),a=function(t){let e=1/0,i=1/0,s=-1/0,n=-1/0;for(const o of t)for(const t of o.leaves){const o=Math.hypot(t.closedVector[0],t.closedVector[1]);e=Math.min(e,t.hinge[0]-o),i=Math.min(i,t.hinge[1]-o),s=Math.max(s,t.hinge[0]+o),n=Math.max(n,t.hinge[1]+o)}return lf([e,i,s,n])?{x:e,y:i,w:s-e,h:n-i}:null}(s.openings),r=Qg({rect:a?nv(i,a):i,wallHeight:n,openingHeight:n,floorDepth:o}),l=function(t,e=Kg,i=64){if(!Number.isFinite(i)||i<0)throw new Error("invalid wall height");const s=[],n=[],o=[];let a=0;for(let r=0;r<(t||[]).length;r++){const l=t[r];for(let t=0;t<(l||[]).length;t++){const c=sf(l[t],t>0);if(!(c.length<3||Math.abs(ef(c))<1e-9)){s.push(nf(c,e,i)),a+=c.length;for(let s=0;st.depth-e.depth||t.polygon-e.polygon||t.ring-e.ring||t.edge-e.edge),{topPath:s.join(" "),sides:n,contactPath:o.join(" "),edgeCount:a}}(s.walls,Kg,n),c={geometry:l,floor:af(s.floor,o),openings:s.openings,frame:r};return jf(this._isoGeometryCache,t.key,c,8),{key:t.key,...c}}_effectiveProjection(){if("iso"!==this._desiredProjection||!this._model.length)return"flat";const t=this._isoSceneKey()||`${this._space}|invalid`;if(this._isoFallback.has(t))return"flat";try{const t=this._isoScene();return t?(e="iso",i=t.key,s=this._isoFallback,"iso"===e&&i&&!s.has(i)?"iso":"flat"):"flat"}catch(e){if(!this._isoFallback.has(t)){this._isoFallback.add(t);const i=t.split("|");console.warn(`HOUSEPLAN ISO FALLBACK: #89, space ${this._space}, fingerprint ${i[i.length-1]}, ${e instanceof Error?e.message:"renderer error"}`)}return"flat"}var e,i,s}_scenePoint(t){return"iso"===this._renderProjection?Jg(t,0):t}_floorView(t){if("iso"!==this._renderProjection)return t;const e=Xg([t.x,t.y]),i=Xg([t.x+t.w,t.y+t.h]);return{x:e[0],y:e[1],w:i[0]-e[0],h:i[1]-e[1]}}_baseVb(){if("iso"===this._effectiveProjection()){if(!this._spaceDisplayForRender().showBorders){const t=Qg({rect:this._frameOf().rect,wallHeight:mh(64,this._cellCm)});return[t.x,t.y,t.w,t.h]}const t=this._isoScene()?.frame??this._frameOf().rect;return[t.x,t.y,t.w,t.h]}const t=this._frameOf().rect;return[t.x,t.y,t.w,t.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._showFar=!0,this._frame=null,this._resetZoom()}_fitAll(){this._showFar=!0,this._frame=null,this._resetZoom()}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?G:W`
${this._t("canvas.far_objects",{n:this._outliers})} @@ -4983,7 +4983,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 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(hv.ZOOM_MAX,Math.max(hv.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},Hf)}_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>=_d?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(hv.ZOOM_MAX,Math.max(hv.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(Jf,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){"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&&rv("/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},cv(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(tv))e.toggleAttribute("data-pointer-hover",t)}_syncPointerHoverSubtree(t){if(t.nodeType!==Node.ELEMENT_NODE)return;const e=t,i=this._pointerModality.hoverEnabled;e.matches(tv)&&e.toggleAttribute("data-pointer-hover",i);for(const t of e.querySelectorAll(tv))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){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,ev}get _segments(){const t=this._curSpaceCfg,e=this._spaceH;return pi(t?.rooms||[]).map(t=>[t[0]*ev,t[1]*e,t[2]*ev,t[3]*e])}_savedNav(){if(this._hasFixedFloor)return null;try{return JSON.parse(localStorage.getItem(Xf)||"null")}catch{return null}}_saveNav(){if(!this._hasFixedFloor)try{localStorage.setItem(Xf,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?Yg([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._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=ml(ll,this._imperial))}get _drawWallFieldValue(){return null===this._drawWallField?ml(ll,this._imperial):this._drawWallField}get _drawWallCm(){const t=Bf(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>=("column"===this._tool?1:0)&&e<=i?e:null}get _drawWallMaxCm(){return"column"===this._tool?Wc:100}_showPhysicalRange(t=this._drawWallMaxCm,e=0){this._showToast(this._t("toast.physical_range",{min:ml(e,this._imperial),max:ml(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=sm(i,{pitch:Ph,seedIds:e,geometry:om(t,{excludeDraftId:this._activeDraftId})});return s.merged?(t.partitions=s.partitions,nm(t.openings,t.partitions,s.openingMoves,{coordScale:ev,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=Xp(this._path,Jp(this._path.length-1,this._draftSegmentCms,this._drawWallCm,ll)),i=e.length;if((t.partitions||[]).length+i>ov)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),"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>=ov:(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=qp({space:t,activeDraftId:this._activeDraftId,roomCuts: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=Bp({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=qp({space:t,activeDraftId:this._activeDraftId,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?Kp(i.value,t,{...o,anchor:s}):function(t,e,i){if(!(Ap(e)&&i.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const s=i.epsilon??Ip,n=i.excludePoints||[],o=Gp(Up(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=Vp(o,e,i.gridStep);!Wp(l,n,s)&&jp(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:Number.isFinite(Number(t.cm))?Math.max(0,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:Uc(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:Gc(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=zm(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=$d($h({spaces:[t]}),t.id),i=e?m_(t,e,ev,.02*Dh).contour.map(t=>t.map(t=>t/ev)):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,i),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=bd(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(Gr(this._serverCfg)),e=bd(t),i=[...this._pendingPhysicalWrites.entries()];for(const[e,s]of i){const i=lg(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!==bd(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 Mm?t.reason:"invalid-room";return this._t(`wall_model.reason.${e}`)}_hasLegacyZeroWallFields(t=this._serverCfg){return(t?.spaces||[]).some(t=>Array.isArray(t?.open_spans)&&t.open_spans.length>0||(t?.rooms||[]).some(t=>Array.isArray(t?.open_to)&&t.open_to.length>0))}_showWallModelMigrationBlocked(t){const e=this._hasLegacyZeroWallFields()?"toast.zero_wall_migration_blocked":"toast.wall_model_migration_blocked";this._showToast(this._t(e,{reason:this._wallModelBlockerLabel(t)}))}_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||lg(e)===lg(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)<9){const t=JSON.parse(JSON.stringify(s));if(!this._restoreGeometryStateInConfig(t,e))throw new Mm("invalid-room",e.spaceId);const i=Jm(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 Mm("invalid-room",e.spaceId);const r=i.spaces.find(t=>t.id===e.spaceId),c=o.spaces.find(t=>t.id===e.spaceId);if(!Array.isArray(n.wall_segments)&&JSON.stringify(e.rooms)===JSON.stringify(n.rooms))for(const t of c?.wall_segments||[])t.cm=Pl(n.walls,t.a,t.b,Ph,1);const 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}=Gm(i,jm(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;oSm||Nm(r,i,s)>Sm)continue;const l=Em(a,i,s),c=Em(r,i,s);l<-Sm||c>1+Sm||c<=l+Sm||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]/ev,t[1]/ev]):[];s.push(...i.map(t=>[t[0],t[1]])),c=Fm(t)<=Fm(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;Zm(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:lg(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._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}_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();"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=lg(i)!==lg(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=Jm(s).config}catch(t){return this._restoreGeometryStateLocal(i),this._showWallModelMigrationBlocked(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;Zm(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:lg(a)})}else Zm(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>ov)||(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;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("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],m=u.length>=4&&this._samePt(u[0],u[u.length-1]),g=u,f=_;if(g.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(m){const t=g.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:g.map(t=>[t[0]/ev,t[1]/ev]),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=g,this._draftSegmentCms=this._adoptDraftCms(g,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=Jp(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])*ev,Number(t?.[1])*ev]):[],n=Array.isArray(e?.segments)?e.segments:[];return Jp(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]/ev,t[1]/ev]),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=yu(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=Ru(r,{requiredSourceKey:n,maxDistance:gl(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(0===this._drawWallCm?"toast.zero_wall_ambiguous":"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=bu(this._wallFaceGraph(this._wallGraphSources([]),e),t,e);if(!s){const n=Ru(this._wallGraphSources([]),{point:t,maxDistance:gl(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(0===this._drawWallCm?"toast.zero_wall_ambiguous":"toast.wall_repair_ambiguous")),!0;if("repair"===n.kind)s=n.face,i=n.proposal;else if("none"===n.kind){const i=Ru(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,1);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:Uc(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]/ev,e[1]/ev]}),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:ml(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:ml(i.cm,this._imperial),shape:i.shape,angle:this._angleField("square"===i.shape?Gc(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:ml(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(),cv(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*ev-Math.min(...n),Math.min(Sh*ev-Math.max(...n),i[0])),Math.max(-Sh*ev-Math.min(...o),Math.min(Sh*ev-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]/ev,n.a[1]/ev],t.b=[n.b[0]/ev,n.b[1]/ev];for(const t of s.openings||[]){if("partition"!==t.host?.kind||t.host.id!==e.id)continue;const i=$p(t,[n],ev,this._cellCm,this._gridPitch).resolved;i&&Object.assign(t,Rp(t,i,ev))}}}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])/ev,(n.center[1]+e.delta[1])/ev])}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(),cv(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:Gc(e.angle),angle:Gc(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=Gc(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:gl(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]*ev,t.a[1]*this._spaceH],b:[t.b[0]*ev,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?gl(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 m={[i]:s},g=[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"};g.push(t.room.id),m[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(g.map(e=>[e,t.find(t=>t.id===e).poly.length])),y=[];for(const e of g){const i=t.find(t=>t.id===e),s=m[e],n=(s-1+i.poly.length)%i.poly.length,a=(s+1)%i.poly.length,r=Ga(t,e,n,1,o),l=Ga(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:g,edgeByRoom:m,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","wall_segments","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]/ev,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]/ev,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]*ev,t[1]*a]);if(e.poly.length!==n.length)continue;const c=Array.isArray(e.wall_ids)?e.wall_ids:[];for(let t=0;tt.id===i):null;s&&(s.a=[n[t][0]/ev,n[t][1]/ev],s.b=[n[(t+1)%n.length][0]/ev,n[(t+1)%n.length][1]/ev])}}if(r.length&&Array.isArray(o.walls)&&o.walls.length){const t=function(t,e,i,s,n=1,o="fixed-topology"){let a=!1;const r=Il(t,e,i,s,n,o,()=>{a=!0});return{walls:a?(t||[]).map(t=>({...t})):r,rejected:a}}(o.walls,r,l,this._wallKeyPitch,ev,"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"};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 m=[];for(const t of o.walls||[]){const e=u(t),i=_.get(e)||0;i?_.set(e,i-1):m.push(t)}return zl(m,p,this._wallKeyPitch,ev,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));cv(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.wall_segments)&&(l.wall_segments=i.sp.wall_segments)),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._openCuts(),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]},[_,m]=this._lastValidStageSize||[u.w,u.h],g={...u,stageWidth:Math.max(1,_),stageHeight:Math.max(1,m)},f=this._spaceModel(),v=this._config?.icon_size??2.5,y=f?Gh(v>8?2.5:v,f,u.w,this._kiosk?this._kioskScale.icon:1)*g.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,ev)||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:g,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;tfunction(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},m=_((n-1+s)%s)??0,g=(_((n+1)%s)??c)-m;return g>0?g:0}(e,i,o)*a)}_renderResizeMeasurements(){if(!this._rszLive?.length)return G;const t=this._rszLive.filter(t=>"length"===t.kind),e=this._rszLive.filter(t=>"area"===t.kind);return j``}_zeroWalls(){const t=this._spaceModel();return t?m_(this._curSpaceCfg,t,iv,.02*this._gridPitch):{style:d_(this._curSpaceCfg),lines:[],contour:[],barriers:[],transmissive:[]}}_openCuts(){return this._zeroWalls().contour}_deleteRoomClick(t){const e=this._spaceModel();if(!e)return;const i=[...e.rooms].reverse().find(e=>this._pointInRoom(t,e));i?i.id&&(this._roomDeleteDialog={roomId:i.id,name:i.name}):this._showToast(this._t("toast.delete_room_pick"))}get _wallKeyPitch(){return Ph}get _spaceWalls(){const t=this._curSpaceCfg?.walls;return Array.isArray(t)?t:[]}_cfgOpenCuts(){const t=this._curSpaceCfg,e=this._spaceModel();if(!t||!e)return[];const i=p_(t,1),s=__(t,e.rooms,iv,.02*this._gridPitch).map(t=>t.map(t=>t/iv)),n=new Set;return[...i,...s].filter(t=>{const e=t.map(t=>Number(t).toFixed(9)).join(","),i=[t[2],t[3],t[0],t[1]].map(t=>Number(t).toFixed(9)).join(","),s=e[t[0]/iv,t[1]/iv,t[2]/iv,t[3]/iv]))}_paperShapes(t){if(!this._spaceWalls.length)return di(t);const e=this._wallUnionGeometry();return e?.paperD?[{path:e.paperD}]:di(t)}_wallUnionGeometry(){const t=this._spaceModel();if(!t)return null;const e=this._spaceWalls,i=this._physicalBodiesR();if(!e.length&&!i.length)return null;const s=this._openCuts(),n=this._roomWallOpeningInputs(),o=`${this._space}|${this._cfgEpoch}|${t.rooms.length}`;return this._wallUnionCache&&this._wallUnionCache.key===o||(this._wallUnionCache={key:o,value:Ic(t.rooms,e,s,n,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,i)}),this._wallUnionCache.value}_thickWallCuts(){const t=this._spaceModel();if(!t)return[];const e=this._spaceWalls;if(!e.length)return[];const i=this._openCuts();return Ac(t.rooms,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,iv).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]])}_wallThickHit(t){const e=this._spaceModel();if(!e)return null;const i=6*this._gridPitch,s=this._openCuts();let n=null;const o=(t,e,s)=>{e>i||(!n||e0?t:0,n=Number.isFinite(e)&&e>0?e:5,o=Number.isFinite(i)&&i>0?i:0;return s>0?gl(s,n,o)/2:mh(1.5*o,n)}(t.cm,this._cellCm,this._gridPitch);let i="";for(const s of t.segs)i+=(i?" ":"")+Ul([[s[0],s[1]],[s[2],s[3]]],e,!1);return{segs:t.segs,open:t.open,d:i}}_wallThickClick(t){const e=this._wallThickHit(t);if(!e)return void this._showToast(this._t("toast.wallthick_pick"));const i=e.cm,s=this._viewOr(this._baseVb()),n=(e.a[0]+e.b[0])/2,o=(e.a[1]+e.b[1])/2;this._wallDialog={a:e.a,b:e.b,value:ml(i,this._imperial),roomId:e.roomId,source:e.source,sx:(n-s.x)/s.w*100,sy:(o-s.y)/s.h*100}}_wallThickApply(t){const e=this._wallDialog;if(!e)return;const i=this._curSpaceCfg,s=this._spaceModel();if(!i||!s)return;const n=e.value.trim(),o=n?qf(n):null;if(null==o)return void this._showPhysicalRange(100);const a=this._imperial?2.54*o:o;if(!Number.isFinite(a)||a<0||a>100)return void this._showPhysicalRange(100);if("room"!==e.source.kind){const t=this._geometrySnapshot();if("partition"===e.source.kind){const t=(i.partitions||[]).find(t=>t.id===e.source.id);if(!t)return;if(0===a&&g_(i.openings,{kind:"partition",id:t.id}))return void this._showToast(this._t("toast.zero_wall_opening_conflict"));t.cm=a}else{const t=(i.room_drafts||[]).find(t=>t.id===e.source.id),s=t?.segments?.[e.source.segment];if(!s)return;s.cm=a}this._wallDialog=null;return this._commitPhysicalGeometry(this._t("history.wall_thickness"),t)&&this._showToast(this._t("toast.wallthick_set")),void this.requestUpdate()}const r=this._geometrySnapshot(),l=a>0?a:null;if(0===a){const s=.02*this._gridPitch,n=[e.a[0],e.a[1],e.b[0],e.b[1]],o=(i.rooms||[]).find(t=>t.id===e.roomId),a=new Set(t&&o&&Array.isArray(o.wall_ids)?o.wall_ids:(i.wall_segments||[]).filter(t=>{const e=[Number(t.a?.[0])*iv,Number(t.a?.[1])*iv],i=[Number(t.b?.[0])*iv,Number(t.b?.[1])*iv];return Ls(e,n)<=s&&Ls(i,n)<=s}).map(t=>String(t.id))),r=(i.openings||[]).some(t=>{if("partition"===t.host?.kind)return!1;if("wall"===t.host?.kind&&a.has(t.host.id))return!0;if(t.host)return!1;const e=[Number(t.x)*iv,Number(t.y)*iv];return e.every(Number.isFinite)&&Ls(e,n)<=s});if(r)return void this._showToast(this._t("toast.zero_wall_opening_conflict"))}let c,h=this._openCuts();if(a>0&&h.length){const n=[];if(t&&e.roomId){const t=(i.rooms||[]).find(t=>t.id===e.roomId),o=new Set(Array.isArray(t?.wall_ids)?t.wall_ids:[]);for(const t of i.wall_segments||[])o.has(t.id)&&n.push([Number(t.a?.[0])*iv,Number(t.a?.[1])*iv,Number(t.b?.[0])*iv,Number(t.b?.[1])*iv]);if(!n.length){const t=s.rooms.find(t=>t.id===e.roomId),i=t?hi(t):null;for(let t=0;i&&t!n.some(e=>Ls([t[0],t[1]],e)<=o&&Ls([t[2],t[3]],e)<=o&&Ls([e[0],e[1]],t)<=o&&Ls([e[2],e[3]],t)<=o))}c=t&&e.roomId?El(i.walls,s.rooms,e.roomId,l,this._wallKeyPitch,h,iv):Fl(i.walls,e.a,e.b,l,this._wallKeyPitch,iv),c=this._normalizeWalls(c,h);for(const t of i.wall_segments||[])t.cm=Pl(c,t.a,t.b,Ph,1);c.length?i.walls=c:delete i.walls,this._wallDialog=null,this._commitPhysicalGeometry(this._t("history.wall_thickness"),r)&&this._showToast(this._t(0===a?"toast.wallthick_cleared":"toast.wallthick_set")),this.requestUpdate()}_wallHatchDefs(t){if(!this._spaceWalls.length&&!this._physicalBodiesR().length&&!this._markup)return j``;const e=pl(this._cellCm);return j` - `}_resolvedRoomFills(t,e){const i=new Map,s=new Map;for(const n of t.rooms){const t=this._roomDialog&&n.id===this._roomEditId?this._roomFill||e.fill:zs(e.fill,n),o=this._roomDialog&&n.id===this._roomEditId?this._roomCustomFill||e.customFill:ls(e.customFill,n),a=_s(t,"lqi"===t&&n.area?this._roomLqi(n.area):null,"light"===t?uo(ho(this._renderPlanHass,this._renderDevices,n,this._virtualLights)):"none","temp"===t?this._roomTemp(n):null,e.tempMin,e.tempMax,this._fillColors,o);i.set(n,a),n.id&&s.set(n.id,a)}return{byRoom:i,byId:s}}_spaceDisplayForRender(){const t=cs(this._curSpaceCfg),e=this._spaceDialog;return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,showBorders:e.showBorders,showNames:e.showNames,hideDecor:e.hideDecor,hideOpenings:e.hideOpenings,color:e.roomColor,opacity:e.roomOpacity,fill:e.fillMode,customFill:e.customFill?rs(e.customFill):as,glow:e.glowEnabled,tempMin:e.tempMin,tempMax:e.tempMax,showLqi:e.showLqi,cardFontScale:e.cardFontScale,labelTemp:e.labelTemp,labelHum:e.labelHum,labelLqi:e.labelLqi,labelLight:e.labelLight}:t}_openingWallIndexFor(t,e){const i=t.rooms.map(t=>`${t.id}:${t.poly?.map(t=>t.join(",")).join("/")||`${t.x},${t.y},${t.w},${t.h}`}`).join(";"),s=this._spaceWalls.map(t=>`${t.key}:${t.a?.join(",")||""}:${t.b?.join(",")||""}:${t.cm}`).join(";"),n=e.map(t=>t.join(",")).join(";"),o=[t.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,s,n].join("|");let a=this._openingWallIndexCache.get(o);return a||(a=Fc(t.rooms,this._spaceWalls,e,this._wallKeyPitch,this._cellCm,this._gridPitch,ev)),Wf(this._openingWallIndexCache,o,a,4),{key:o,value:a}}_renderOpeningTunnelFills(t,e,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return j``;if("glow-base"===i&&![...e.byRoom.values()].some(Boolean))return j``;const s=this._openCuts(),n=this._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),o=n.map(t=>`${t.x},${t.y},${t.angle},${t.length}`).join(";"),a=this._openingWallIndexFor(t,s),r=`${a.key}|${o}`;return this._openingTunnelCache&&this._openingTunnelCache.key===r||(this._openingTunnelCache={key:r,value:qc(a.value,n)}),a_({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:e.byId,idPrefix:`${t.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(t,e,i){const s=new Map,n=new Map,o=this._fillColors.glow_base;for(const a of t.rooms){const t=i.byRoom.get(a),r=Fs(e.glow,a)&&(!t||t.opacity<=0)?{color:o.c,opacity:o.a,mode:"glow"}:null;s.set(a,r),a.id&&n.set(a.id,r)}return{byRoom:s,byId:n}}_renderGlowBaseRooms(t,e){if(this._markup||![...e.byRoom.values()].some(Boolean))return j``;const i=new Map(t.rooms.map(t=>[t,hi(t)])),s=this._openCuts(),n=this._wallUnionGeometry()?.roomGeom,o=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",a=t.rooms.map(a=>{const r=e.byRoom.get(a)||null,l=i.get(a)||null;if(!r||!l)return G;const c=this._spaceWalls.length&&a.id&&fc(t.rooms,a.id,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,n)||l,h=Pi(c,t.rooms.filter(t=>t!==a).map(t=>i.get(t)).filter(t=>!!t)),d=this._cleanFloor(a,c,t).path;return d||h.length?j``}_resolvedRoomFills(t,e){const i=new Map,s=new Map;for(const n of t.rooms){const t=this._roomDialog&&n.id===this._roomEditId?this._roomFill||e.fill:zs(e.fill,n),o=this._roomDialog&&n.id===this._roomEditId?this._roomCustomFill||e.customFill:ls(e.customFill,n),a=_s(t,"lqi"===t&&n.area?this._roomLqi(n.area):null,"light"===t?uo(ho(this._renderPlanHass,this._renderDevices,n,this._virtualLights)):"none","temp"===t?this._roomTemp(n):null,e.tempMin,e.tempMax,this._fillColors,o);i.set(n,a),n.id&&s.set(n.id,a)}return{byRoom:i,byId:s}}_spaceDisplayForRender(){const t=cs(this._curSpaceCfg),e=this._spaceDialog;return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,showBorders:e.showBorders,showNames:e.showNames,hideDecor:e.hideDecor,hideOpenings:e.hideOpenings,color:e.roomColor,opacity:e.roomOpacity,fill:e.fillMode,customFill:e.customFill?rs(e.customFill):as,glow:e.glowEnabled,tempMin:e.tempMin,tempMax:e.tempMax,showLqi:e.showLqi,cardFontScale:e.cardFontScale,labelTemp:e.labelTemp,labelHum:e.labelHum,labelLqi:e.labelLqi,labelLight:e.labelLight}:t}_openingWallIndexFor(t,e){const i=t.rooms.map(t=>`${t.id}:${t.poly?.map(t=>t.join(",")).join("/")||`${t.x},${t.y},${t.w},${t.h}`}`).join(";"),s=this._spaceWalls.map(t=>`${t.key}:${t.a?.join(",")||""}:${t.b?.join(",")||""}:${t.cm}`).join(";"),n=e.map(t=>t.join(",")).join(";"),o=[t.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,s,n].join("|");let a=this._openingWallIndexCache.get(o);return a||(a=Fc(t.rooms,this._spaceWalls,e,this._wallKeyPitch,this._cellCm,this._gridPitch,iv)),jf(this._openingWallIndexCache,o,a,4),{key:o,value:a}}_renderOpeningTunnelFills(t,e,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return j``;if("glow-base"===i&&![...e.byRoom.values()].some(Boolean))return j``;const s=this._openCuts(),n=this._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),o=n.map(t=>`${t.x},${t.y},${t.angle},${t.length}`).join(";"),a=this._openingWallIndexFor(t,s),r=`${a.key}|${o}`;return this._openingTunnelCache&&this._openingTunnelCache.key===r||(this._openingTunnelCache={key:r,value:qc(a.value,n)}),a_({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:e.byId,idPrefix:`${t.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(t,e,i){const s=new Map,n=new Map,o=this._fillColors.glow_base;for(const a of t.rooms){const t=i.byRoom.get(a),r=Fs(e.glow,a)&&(!t||t.opacity<=0)?{color:o.c,opacity:o.a,mode:"glow"}:null;s.set(a,r),a.id&&n.set(a.id,r)}return{byRoom:s,byId:n}}_renderGlowBaseRooms(t,e){if(this._markup||![...e.byRoom.values()].some(Boolean))return j``;const i=new Map(t.rooms.map(t=>[t,hi(t)])),s=this._openCuts(),n=this._wallUnionGeometry()?.roomGeom,o=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",a=t.rooms.map(a=>{const r=e.byRoom.get(a)||null,l=i.get(a)||null;if(!r||!l)return G;const c=this._spaceWalls.length&&a.id&&fc(t.rooms,a.id,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,n)||l,h=Pi(c,t.rooms.filter(t=>t!==a).map(t=>i.get(t)).filter(t=>!!t)),d=this._cleanFloor(a,c,t).path;return d||h.length?j``:a.poly||c!==l?j``)} - `}_isoDecorationLayers(t){const e="undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("filter","blur(1px)"),i="function"==typeof matchMedia&&matchMedia("(forced-colors: active)").matches;return function(t){const e=!!t.showBorders;return{structural:e,panels:e&&!t.hideOpenings,shadows:e&&t.filtersSupported&&!t.forcedColors,materialNuance:e&&!t.forcedColors,floorSymbols:!t.hideOpenings&&!e}}({showBorders:t.showBorders,hideOpenings:t.hideOpenings,filtersSupported:e,forcedColors:i})}_isoOpeningPanels(t){if(!t.panels)return[];const e=this._isoScene();if(!e)return[];return e.openings.flatMap(t=>{const e=this._openingsR[t.sourceIndex];return e?df(t,this._openingAmt(e)):[]}).sort((t,e)=>t.depth-e.depth||t.sourceIndex-e.sourceIndex||t.leaf-e.leaf)}_renderIsoDefs(t,e){const i=_h(this._cellCm);return j` + `}_isoDecorationLayers(t){const e="undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("filter","blur(1px)"),i="function"==typeof matchMedia&&matchMedia("(forced-colors: active)").matches;return function(t){const e=!!t.showBorders;return{structural:e,panels:e&&!t.hideOpenings,shadows:e&&t.filtersSupported&&!t.forcedColors,materialNuance:e&&!t.forcedColors,floorSymbols:!t.hideOpenings&&!e}}({showBorders:t.showBorders,hideOpenings:t.hideOpenings,filtersSupported:e,forcedColors:i})}_isoOpeningPanels(t){if(!t.panels)return[];const e=this._isoScene();if(!e)return[];return e.openings.flatMap(t=>{const e=this._openingsR[t.sourceIndex];return e?pf(t,this._openingAmt(e)):[]}).sort((t,e)=>t.depth-e.depth||t.sourceIndex-e.sourceIndex||t.leaf-e.leaf)}_renderIsoDefs(t,e){const i=_h(this._cellCm);return j` ${"walls"===e&&t.materialNuance?j` @@ -5385,7 +5385,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${t.panels?j``:G} - `:j``}_roomHoverPaths(t){const e=this._hoverRoom;if("view"!==this._mode||!e||e.space!==t.id)return null;const i=t.rooms.find(t=>t===e.room||!!t.id&&t.id===e.room.id);if(!i)return null;const s=hi(i);if(!s)return null;const n=t.rooms.filter(t=>t!==i).map(t=>({room:t,poly:hi(t)})).filter(t=>!!t.poly),o=Pi(s,n.map(t=>t.poly)),a=this._openCuts(),r=.02*this._gridPitch,l=a.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return s.some((t,i)=>Ls(e,[t[0],t[1],...s[(i+1)%s.length]])<=4*r)}),c=this._spaceWalls,h=this._wallUnionGeometry()?.roomGeom,d=c.length&&i.id&&fc(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,h)||s,p=[{axis:s,face:d}];for(const e of o){const i=n.find(t=>t.poly===e)?.room;let s=e;if(c.length&&i?.id){const n=hc(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,ev);n&&(s=zc(n.poly,n.offsets)||e)}p.push({axis:e,face:s})}const u=this._roomWallOpeningInputs(this._openingsR,t).map(t=>{const e=t.angle*Math.PI/180,i=Math.cos(e)*t.length/2,s=Math.sin(e)*t.length/2;return[t.x-i,t.y-s,t.x+i,t.y+s]}),_=l.concat(u),m=p.map(({axis:t,face:e})=>{const i=_.map(i=>((t,e,i)=>{const s=t[2]-t[0],n=t[3]-t[1],o=Math.hypot(s,n);if(o.05)&&Ls([c,h],[i[0],i[1],s[0],s[1]])<=4*r){d=!0;break}}if(!d)return null;let p=null;for(let t=0;t.05)continue;const u=Ls([c,h],[e[0],e[1],s[0],s[1]]);(!p||u!!t);return i.length?Ps(e,i,r).map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" "):`M ${e.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return null;const g=t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`;return{fillD:[this._cleanFloor(i,d,t).path||g(d),...o.map(g)].join(" "),outlineD:m}}_renderRoomHoverFill(t){return t?j` + `:j``}_roomHoverPaths(t){const e=this._hoverRoom;if("view"!==this._mode||!e||e.space!==t.id)return null;const i=t.rooms.find(t=>t===e.room||!!t.id&&t.id===e.room.id);if(!i)return null;const s=hi(i);if(!s)return null;const n=t.rooms.filter(t=>t!==i).map(t=>({room:t,poly:hi(t)})).filter(t=>!!t.poly),o=Pi(s,n.map(t=>t.poly)),a=this._openCuts(),r=.02*this._gridPitch,l=a.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return s.some((t,i)=>Ls(e,[t[0],t[1],...s[(i+1)%s.length]])<=4*r)}),c=this._spaceWalls,h=this._wallUnionGeometry()?.roomGeom,d=c.length&&i.id&&fc(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,h)||s,p=[{axis:s,face:d}];for(const e of o){const i=n.find(t=>t.poly===e)?.room;let s=e;if(c.length&&i?.id){const n=hc(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,iv);n&&(s=zc(n.poly,n.offsets)||e)}p.push({axis:e,face:s})}const u=this._roomWallOpeningInputs(this._openingsR,t).map(t=>{const e=t.angle*Math.PI/180,i=Math.cos(e)*t.length/2,s=Math.sin(e)*t.length/2;return[t.x-i,t.y-s,t.x+i,t.y+s]}),_=l.concat(u),m=p.map(({axis:t,face:e})=>{const i=_.map(i=>((t,e,i)=>{const s=t[2]-t[0],n=t[3]-t[1],o=Math.hypot(s,n);if(o.05)&&Ls([c,h],[i[0],i[1],s[0],s[1]])<=4*r){d=!0;break}}if(!d)return null;let p=null;for(let t=0;t.05)continue;const u=Ls([c,h],[e[0],e[1],s[0],s[1]]);(!p||u!!t);return i.length?Ps(e,i,r).map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" "):`M ${e.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return null;const g=t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`;return{fillD:[this._cleanFloor(i,d,t).path||g(d),...o.map(g)].join(" "),outlineD:m}}_renderRoomHoverFill(t){return t?j` `:j``}_renderRoomHoverOutline(t){return t?j` @@ -5410,7 +5410,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4
-
`:W``}_openingAt(t){if(!this._openingsR.length)return null;const e=this._openingsR.flatMap(e=>{const i=e.angle*Math.PI/180,s=t[0]-e.rx,n=t[1]-e.ry,o=s*Math.cos(i)+n*Math.sin(i);return Math.abs(o)>e.rlen/2+mh(12,this._cellCm)?[]:[{o:e,localY:-s*Math.sin(i)+n*Math.cos(i)}]});if(!e.length)return null;const i=this._spaceModel();if(!i)return null;const s=this._openCuts(),n=this._openingWallIndexFor(i,s).value;return e.find(({o:t,localY:e})=>{const i="gate"===t.type?!t.flip_v:t.flip_v,s=t.partitionHost||this._spaceWalls.length||"gate"===t.type?this._openingFace(t,n,!!i):{ox:0,oy:0,cm:0,side:-1},o=Lu({type:t.type,length:t.rlen,angle:t.angle,amount:this._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this._cellCm,gridPitch:this._gridPitch,face:s});return Math.abs(e)<=o.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this._openingPreset;if("opening"!==this._tool||!e)return null;const i=this._spaceModel();if(!i)return null;const s=this._openCuts(),n=this._openingWallIndexFor(i,s),o=`${n.key}|partitions:${this._cfgEpoch}`;this._openingPlacementIntervalsCache&&this._openingPlacementIntervalsCache.key===o||(this._openingPlacementIntervalsCache={key:o,value:[...dc(i.rooms,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,ev),...Pp(i.partitions,this._cellCm,this._gridPitch)]}),this._openingDimensionContextCache&&this._openingDimensionContextCache.key===o||(this._openingDimensionContextCache={key:o,value:Mf({rooms:i.rooms,walls:this._spaceWalls,openCuts:s,partitions:i.partitions,roomOpenings:this._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(i),pitch:this._wallKeyPitch,cellCm:this._cellCm,gridPitch:this._gridPitch,coordScale:ev,epsilon:2e-4*this._gridPitch})});const a=ff({pointer:[t[0],t[1]],preset:e,geometryRevision:this._cfgEpoch,renderedLength:this._cmToUnits(e.lengthCm),intervals:this._openingPlacementIntervalsCache.value,baseTolerance:1.5*this._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this._pointerModality.modality||"pen"===this._pointerModality.modality?10:6),gridStep:this._gridPitch});this._openingJambBlockCm=a.jambBlockedTarget?a.jambBlockedTarget.physicalHalfWidth/this._gridPitch*this._cellCm:null;const r=a.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let c;if(r.host){const t=$p({id:"preview",type:r.type,x:r.x/ev,y:r.y/ev,angle:r.angle,length:r.renderedLength/ev,host:r.host},i.partitions,ev,this._cellCm,this._gridPitch).resolved;c=t?Dp(t,l):{ox:0,oy:0,cm:0,side:-1}}else c=Lc(n.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const h="mi"===this.hass?.config?.unit_system?.length,d=Af(r,this._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:li(t.distance/this._gridPitch*this._cellCm,h),dimension:t}));return{...r,face:c,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this._tool&&(this._openingPreset=function(t,e){return{type:t,lengthCm:uf(t),flipH:!1,flipV:!1,revision:e}}(t,++this._openingPresetRevision),this._openingHoverCandidate=null,this._cursorPt=null)}_clearOpeningPlacement(t){this._openingHoverCandidate=null,this._openingJambBlockCm=null,t&&(this._openingPreset=null,this._openingRebindId=null)}_openingClick(t){const e=this._spaceModel();if(!e)return;const i=this._openingRebindId?null:this._openingAt(t);if(i)return void this._editOpening(i);const s=this._openingPreset;if(!s)return;const n=this._openingHoverCandidate,o=n&&vf(n,[t[0],t[1]],s.revision,this._cfgEpoch)?n:this._resolveOpeningPlacement(t);if(!o){if(null!=this._openingJambBlockCm)return void this._showToast(this._t("opening.partition_jamb_margin",{distance:li(this._openingJambBlockCm,this._imperial)}));const i=1.5*this._gridPitch,s=ui(t,e.rooms,i);return s&&function(t,e,i,s,n){for(const o of s)if(!(Ls([t,e],o)>n)&&Rl([o[0],o[1]],[o[2],o[3]],i))return!0;return!1}(s.x,s.y,s.angle,this._openCuts(),i)?void this._showToast(this._t("toast.opening_on_zero_wall")):void this._showToast(this._t("toast.opening_no_wall"))}const a=this._openingRebindId?this._curSpaceCfg?.openings?.find(t=>t.id===this._openingRebindId):null;this._openingDialog={...a?{id:a.id,type:a.type,lengthCm:Math.round(a.length*ev/this._gridPitch*this._cellCm),lengthTouched:!1,contact:a.contact||"",lock:a.lock||"",invert:!!a.invert,flipH:!!a.flip_h,flipV:!!a.flip_v}:{type:o.type,lengthCm:o.lengthCm,contact:"",lock:"",invert:!1,flipH:o.flipH,flipV:o.flipV},...o.host?{host:o.host}:{},x:o.x,y:o.y,angle:o.angle},this._openingRebindId=null,this._openingHoverCandidate=null,this._cursorPt=null}_editOpening(t){this._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this._gridPitch*this._cellCm),lengthTouched:!1,contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,..."partition"===t.host?.kind?{host:{...t.host}}:{},x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this._mode&&this._spaceModel()&&"resize"!==this._tool){t.preventDefault(),t.stopPropagation();try{cv(t)}catch{}this._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this._opDrag.sx)+Math.abs(t.clientY-this._opDrag.sy)<=3)return;const i=this._spaceModel();if(!i)return;const s=this._svgPoint(t),n=this._curSpaceCfg,o=n?.openings?.find(t=>t.id===e.id);if(!o)return;if("partition"===o.host?.kind){const t=i.partitions.find(t=>t.id===o.host.id);if(!t)return;const e=t.b[0]-t.a[0],n=t.b[1]-t.a[1],a=Math.hypot(e,n);if(!(a>1e-9))return;const r=e/a,l=n/a;if(Math.abs((s[0]-t.a[0])*l-(s[1]-t.a[1])*r)>4*this._gridPitch)return;const c=o.length*ev/2+kp(t,this._cellCm,this._gridPitch);let h=(s[0]-t.a[0])*r+(s[1]-t.a[1])*l;if(h=Math.round(h/this._gridPitch)*this._gridPitch,h=Math.max(c,Math.min(a-c,h)),a<2*c-1e-9)return;const d=h/a,p=(t.a[0]+r*h)/ev,u=(t.a[1]+l*h)/this._spaceH;let _=180*Math.atan2(n,e)/Math.PI;_>=90?_-=180:_<-90&&(_+=180);const m=o.host.t!==d||o.x!==p||o.y!==u||o.angle!==_;return this._opDrag.moved=!0,m&&(this._opDrag.dirty=!0),o.host={...o.host,t:d},o.x=p,o.y=u,o.angle=_,this._opMeasure=null,m&&this._cfgEpoch++,void this.requestUpdate()}const a=ui(s,i.rooms,4*this._gridPitch);if(!a)return;this._opDrag.moved=!0;const r=this._opRuler(a,o.length*ev);this._opMeasure=r.measure;const l=r.x/ev,c=r.y/this._spaceH,h=o.x!==l||o.y!==c||o.angle!==a.angle;if(h&&(this._opDrag.dirty=!0),o.x=l,o.y=c,o.angle=a.angle,Number(this._serverCfg?.model_version||0)>=9){const t=Km(o,n?.wall_segments||[]);t?o.host=t:delete o.host}h&&this._cfgEpoch++,this.requestUpdate()}_opRuler(t,e){const i=this._spaceModel()?.rooms||[],s=this._gridPitch/2;let n=t.x,o=t.y,a=_i([n,o],t.angle,e,i,s);if(a&&a.centered&&(n!==a.wallCenter[0]||o!==a.wallCenter[1]))[n,o]=a.wallCenter,a=_i([n,o],t.angle,e,i,s);else if(a){const[r,l]=a.wallA,[c,h]=a.wallB,d=c-r,p=h-l,u=Math.hypot(d,p);if(u>0){const c=this._gridPitch,h=Math.min(e/2,u/2);let _=Math.round(((n-r)*d+(o-l)*p)/u/c)*c;_=Math.max(h,Math.min(u-h,_)),n=r+_/u*d,o=l+_/u*p,a=_i([n,o],t.angle,e,i,s)||a}}if(!a)return{x:n,y:o,angle:t.angle,measure:null};const r="mi"===this.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:li(t/this._gridPitch*this._cellCm,r)});return{x:n,y:o,angle:t.angle,measure:{labels:[l(a.sideA,a.midA),l(a.sideB,a.midB)],guide:a.centered?{x:a.wallCenter[0],y:a.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;const i=this._opDrag,s=i.moved;this._opMeasure=null,s&&i.dirty&&this._commitPhysicalGeometry(this._t("history.move_opening"),i.before),s?window.setTimeout(()=>this._opDrag=null,0):this._opDrag=null}_opClick(t,e){"plan"===this._mode&&"resize"===this._tool||(t.stopPropagation(),this._opDrag?.moved||"plan"===this._mode&&this._editOpening(e))}_saveOpening(){const t=this._openingDialog,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=this._geometrySnapshot(),n=this._spaceH,o=(e.openings||[]).find(e=>e.id===t.id),a={...o||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/ev,y:t.y/n,angle:t.angle,length:o&&!t.lengthTouched?o.length:this._cmToUnits(Math.max(20,t.lengthCm))/ev,...t.host?{host:{...t.host}}:{}};if("partition"===a.host?.kind){const t=Mp(o,a)?Sp(a,i.partitions,ev,this._cellCm,this._gridPitch):$p(a,i.partitions,ev,this._cellCm,this._gridPitch);if(!t.resolved){const e=i.partitions.find(t=>t.id===a.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=kp(e,this._cellCm,this._gridPitch);this._showToast(this._t("opening.partition_jamb_margin",{distance:li(t/this._gridPitch*this._cellCm,this._imperial)}))}else this._showToast(this._t("opening.partition_orphan"));return}const s=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===a.id)return[];const e=$p(t,i.partitions,ev,this._cellCm,this._gridPitch).resolved;return e?[e]:[]});if(function(t,e,i=1e-9){const s=t.length/(2*t.axis.length),n=t.t-s,o=t.t+s;return e.some(e=>{if(e.host.id!==t.host.id||e.opening.id===t.opening.id)return!1;const s=e.length/(2*e.axis.length);return Math.max(n,e.t-s)=9){const t=Km(a,e.wall_segments||[]);if(!t)return void this._showToast(this._t("toast.opening_no_wall"));a.host=t}else delete a.host;"passage"===t.type?(delete a.contact,delete a.lock,delete a.invert,delete a.flip_h,delete a.flip_v):(a.contact=t.contact||null,a.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,a.invert=t.invert||void 0,a.flip_h="gate"!==t.type&&t.flipH||void 0,a.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===a.id);r>=0?e.openings[r]=a:e.openings.push(a),this._commitPhysicalGeometry(this._t(t.id?"history.edit_opening":"history.add_opening"),s),this._openingDialog=null,this.requestUpdate()}_deleteOpening(){const t=this._openingDialog,e=this._curSpaceCfg;if(!t?.id||!e?.openings)return;const i=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this._t("history.delete_opening"),i),this._openingDialog=null,this.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.hass.states)){if(!this._openingEntityAvailable(e))continue;const i=e.split(".")[0];if("binary_sensor"!==i&&"cover"!==i)continue;const s=this.hass.states[e],n=["door","window","opening","garage_door","garage"].includes(s?.attributes?.device_class||"");("cover"!==i||n)&&t.push([e,s?.attributes?.friendly_name||e,n?0:1])}return t.sort((t,e)=>t[2]-e[2]||t[1].localeCompare(e[1])).map(([t,e])=>({value:t,label:e}))}_lockCandidates(){return Object.keys(this.hass.states).filter(t=>t.startsWith("lock.")&&this._openingEntityAvailable(t)).map(t=>({value:t,label:this.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this._openingDialog;if(!e)return;const i="contact"===t?!e.contactOpen:!e.lockOpen;this._openingDialog={...e,contactOpen:"contact"===t&&i,lockOpen:"lock"===t&&i}}_filterOpeningEntities(t,e){const i=this._openingDialog;i&&(this._openingDialog="contact"===t?{...i,contactFilter:e}:{...i,lockFilter:e})}_selectOpeningEntity(t,e){const i=this._openingDialog;i&&(this._openingDialog="contact"===t?{...i,contact:e,contactOpen:!1,contactFilter:""}:{...i,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this._spaceModel();if(!e)return;const i=e.rooms,s=[...i].reverse().find(e=>this._pointInRoom(t,e));if(!s?.id)return;const n=s.id;if(!this._mergeSel||this._mergeSel===n)return void(this._mergeSel=this._mergeSel===n?null:n);const o=i.find(t=>t.id===this._mergeSel),a=o?hi(o):null,r=hi(s),l=a&&r?function(t,e){if(!t||!e||t.length<3||e.length<3)return null;const i=si(Ri(t),Ri(e));if(1!==i.length)return null;if(1!==i[0].length)return null;const s=i[0][0].slice(0,-1).map(t=>[t[0],t[1]]);return s.length>=3?s:null}(a,r):null;if(!l)return this._showToast(this._t("toast.merge_not_adjacent")),void(this._mergeSel=null);this._mergeDialog={aId:this._mergeSel,bId:n,poly:l,pick:"a"},this._mergeSel=null}_commitMerge(){const t=this._mergeDialog,e=this._curSpaceCfg;if(!t||!e||!this._spaceModel())return;const i=this._geometrySnapshot(),s=this._spaceH,n="a"===t.pick?t.aId:t.bId,o="a"===t.pick?t.bId:t.aId,a=e.rooms.find(t=>t.id===n);if(!a)return void(this._mergeDialog=null);a.poly=t.poly.map(t=>[t[0]/ev,t[1]/s]),delete a.x,delete a.y,delete a.w,delete a.h,e.rooms=e.rooms.filter(t=>t.id!==o);const r=this._commitPhysicalGeometry(this._t("history.merge_rooms"),i);this._mergeDialog=null,this._regSignature="",this._maybeRebuildDevices(),r&&this._showToast(this._t("toast.rooms_merged",{name:a.name||""}))}_splitClick(t){const e=this._spaceModel();if(!e)return;const i=e.rooms;if(!this._splitSel){const e=[...i].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this._splitSel={roomId:e.id,pts:[]})}const s=i.find(t=>t.id===this._splitSel.roomId),n=s?hi(s):null;if(!s||!n)return void(this._splitSel=null);const o=.02*this._gridPitch,a=6*this._gridPitch,r=function(t,e){if(!e||e.length<2)return null;let i=null,s=1/0;for(let n=0;n=n)continue;n=_;const m=Math.sqrt(p),g=(i>0?Math.max(0,Math.min(m,Math.round(u*m/i)*i)):u*m)/m;s=[a+g*h,r+g*d]}return s}(r,n,this._gridPitch)||r,c=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=a?l:null,h=!!c&&bi(c,n,o),d=this._splitSel.pts;if(!d.length)return h?void(this._splitSel={...this._splitSel,pts:[c]}):void this._showToast(this._t("toast.split_pick_wall"));if(!h){const e=this._snap(t);return wi(e,n,o)?void(this._splitSel={...this._splitSel,pts:[...d,e]}):void this._showToast(this._t("toast.split_pick_inside"))}const p=zi(n,[...d,c],o);if(!p)return void this._showToast(this._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[u,_]=p,m=Ti(u)>=Ti(_)?u:_,g=m===u?_:u;this._pendingSplit={roomId:s.id,mainPoly:m,newPoly:g},this._cursorPt=null,this._nameSel="",this._areaSel="",this._roomDialog=!0}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])&&(null!=this._closingWallCm||!this._activeDraftId)}_markupMove(t){if(!this._markup)return;if("column"===this._tool)return void(this._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this._tool||"wallthick"===this._tool)return void(this._cursorPt=this._svgPoint(t));const e="draw"===this._tool&&!this._contourClosed,i="split"===this._tool&&!!this._splitSel?.pts?.length;if(!e&&!i)return;const s=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(s,t.shiftKey);return this._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this._path.length?void(this._cursorPt=e.point):void this._syncPlanSnapActiveMarker(e.candidate)}this._cursorPt=this._snap(s)}get _openingPreview(){const t=this._openingPreset;if("opening"!==this._tool||!t||!this._cursorPt)return null;const e=this._cursorPt,i=this._openingHoverCandidate;if(i&&vf(i,[e[0],e[1]],t.revision,this._cfgEpoch))return i;if(this._openingAt(e))return this._openingHoverCandidate=null,null;const s=this._resolveOpeningPlacement(e);return this._openingHoverCandidate=s,s}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){(this._areaSel||this._nameSel.trim())&&(this._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this._wallFaceBatch;if(!e)return;const i=e.candidates[e.index];if(!i)return;if(!t&&(i.existing||i.repair)&&1===e.candidates.length)return this._wallFaceBatch=null,this._roomDialog=!1,this._nameSel="",this._areaSel="",void this.requestUpdate();const s=t?{candidate:i,create:!0,name:this._nameSel.trim(),area:this._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:i,create:!1},n=[...e.decisions,s],o=e.index+1;if(o"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,n=.02*this._gridPitch,o=this._spaceModel();if(!o)return ll;for(const e of this._planSnapGeometrySnapshot().value.segments){if("room"===e.sourceKind||Ls(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>n)continue;if("partition"===e.sourceKind)return s(o.partitions.find(t=>t.id===e.sourceId)?.cm)??ll;const i=e.sourceId.lastIndexOf(":"),a=i>=0?e.sourceId.slice(0,i):e.sourceId,r=i>=0?Number(e.sourceId.slice(i+1)):-1;return s(o.room_drafts.find(t=>t.id===a)?.segments[r]?.cm)??ll}const a=Jp(Math.max(0,e.length-1),i,this._drawWallCm,ll);for(let i=0;i+1[...t]);if(!e?.sourceKey.startsWith("active:"))return i;const s=/:(\d+)$/.exec(e.sourceKey),n=s?Number(s[1])+("b"===e.endpoint?1:0):-1;return n>=0&&ne.key===t.sourceKey),o=s.find(e=>e.key===t.targetSourceKey);if(!n||!o)return!1;const a="a"===t.endpoint?n.a:n.b;return!(Math.hypot(a[0]-t.from[0],a[1]-t.from[1])>i)&&(!(Ls(t.to,[o.a[0],o.a[1],o.b[0],o.b[1]])>i)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const i=t.sourceKey.slice(17).split("|")[0];return!!i&&e.some(t=>"partition"===t.host?.kind&&t.host.id===i)}(t,this._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const i=this._curSpaceCfg;if(!i||!this._validateWallRepair(t,e.activePath))return!1;const s=e=>{e[0]=t.to[0]/ev,e[1]=t.to[1]/ev};if(t.sourceKey.startsWith("active:")){const n=/:(\d+)$/.exec(t.sourceKey),o=n?Number(n[1])+("b"===t.endpoint?1:0):-1;if(o<0||o>=e.activePath.length)return!1;e.activePath[o]=[...t.to];const a=(i.room_drafts||[]).find(t=>t.id===e.activeDraftId);return a?.points?.[o]&&s(a.points[o]),!0}if(!t.sourceKey.startsWith("static:"))return!1;const[n,o]=t.sourceKey.slice(7).split("|");if("partition"===n){const e=(i.partitions||[]).find(t=>t.id===o);if(!e)return!1;const n=[e.a[0]*ev,e.a[1]*ev],a=[e.b[0]*ev,e.b[1]*ev],r=Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this._gridPitch?e.a:Math.hypot(a[0]-t.from[0],a[1]-t.from[1])<=2e-4*this._gridPitch?e.b:null;return!!r&&(s(r),!0)}if("draft"===n){const e=o.lastIndexOf(":"),n=e>=0?o.slice(0,e):"",a=e>=0?Number(o.slice(e+1)):-1,r=(i.room_drafts||[]).find(t=>t.id===n);if(!r?.points?.[a]||!r?.points?.[a+1])return!1;const l=[a,a+1].find(e=>Math.hypot(r.points[e][0]*ev-t.from[0],r.points[e][1]*ev-t.from[1])<=2e-4*this._gridPitch);return null!=l&&(s(r.points[l]),!0)}return!1}_applyWallFaceBatch(){const t=this._wallFaceBatch,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=(t,e)=>{this._showToast(this._t(t,e)),this._roomDialogCancel()},n=t.decisions.filter(t=>t.create),o=n.map(t=>t.candidate.ring),a=i.rooms;for(let t=0;ti.id!==e&&!!hi(i)&&Di(o[t],hi(i)));if(i)return void s("toast.room_overlap",{name:i.name||""})}if((e.rooms||[]).length+n.length>400)return void s("toast.physical_limit");if(n.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void s("toast.contour_cannot_close");const r=n.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void s("toast.wall_repair_changed");const l=this._activePathWithRepair(t.activePath,r[0]),c=2e-4*this._gridPitch,h=new Map;for(let e=0;et.candidate.atomKeys)),e=n.some(t=>t.candidate.consumeAllActive);for(const i of vu(this._wallGraphSources(l),c)){const s=i.sourceKeys.find(t=>h.has(t));!s||e||t.has(i.key)||d.push({a:i.a,b:i.b,cm:h.get(s)})}}else d.push(...Xp(l,Jp(l.length-1,t.activeCms,this._drawWallCm,ll)));if((e.partitions||[]).length+d.length>ov)return void s("toast.physical_limit");const p=n.map(t=>t.candidate.ring.map(()=>"")),u=t.activeDraftId?(e.room_drafts||[]).find(e=>e.id===t.activeDraftId):null,_=this._draftSegmentsForPath(t.activePath,u,t.activeCms),m=(t,e)=>{const i=`${t[0].toFixed(9)},${t[1].toFixed(9)}`,s=`${e[0].toFixed(9)},${e[1].toFixed(9)}`;return i<=s?`${i}|${s}`:`${s}|${i}`};for(let e=0;e<_.length;e++){const i=_[e]?.id;if(!i)continue;const s=t.activePath[e],o=t.activePath[e+1],a=[s[0],s[1],o[0],o[1]],r=[];n.forEach((t,e)=>t.candidate.ring.forEach((i,s)=>{const n=t.candidate.ring[(s+1)%t.candidate.ring.length];Ls(i,a)<=c&&Ls(n,a)<=c&&r.push({kind:"room",owner:e,edge:s,a:i,b:n})})),d.forEach((t,e)=>{Ls(t.a,a)<=c&&Ls(t.b,a)<=c&&r.push({kind:"partition",owner:e,edge:0,a:t.a,b:t.b})});const l=[(s[0]+o[0])/2,(s[1]+o[1])/2];r.sort((t,e)=>{const i=[t.a[0],t.a[1],t.b[0],t.b[1]],n=[e.a[0],e.a[1],e.b[0],e.b[1]];return(Ls(l,i)<=c?0:1)-(Ls(l,n)<=c?0:1)||(Ls(s,i)<=c?0:1)-(Ls(s,n)<=c?0:1)||m(t.a,t.b).localeCompare(m(e.a,e.b))});const h=r[0];if(!h)continue;const u=m(h.a,h.b);for(const t of r)m(t.a,t.b)===u&&("room"===t.kind?p[t.owner][t.edge]=i:d[t.owner].id=i)}const g=this._geometrySnapshot();if(r[0]&&!this._applyWallRepair(r[0],t))return void s("toast.wall_repair_changed");const f=n.some(t=>!!t.candidate.split),v=f?pc(i.rooms,e.walls,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,ev):null,y=f&&Array.isArray(e.walls)?e.walls:null;for(const t of n){const i=t.candidate.split;if(!i)continue;const n=e.rooms.find(t=>t.id===i.roomId);if(!n)return void s("toast.contour_cannot_close");n.poly=i.mainPoly.map(t=>[t[0]/ev,t[1]/this._spaceH]),delete n.x,delete n.y,delete n.w,delete n.h}const b=Date.now().toString(36),w=[];if(n.forEach((t,i)=>{const s=t.area?this.hass.areas[t.area]?.name:"",n={id:`r${b}-${i}`,name:t.name||s||this._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/ev,t[1]/this._spaceH]),...p[i].some(Boolean)?{wall_ids:p[i]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(n),w.push({room:n,decision:t})}),t.activeDraftId&&Array.isArray(e.room_drafts)&&(e.room_drafts=e.room_drafts.filter(e=>e.id!==t.activeDraftId),e.room_drafts.length||delete e.room_drafts),d.length&&(e.partitions||=[],d.forEach((t,i)=>e.partitions.push({id:t.id||`partition-${b}-${i}`,a:[t.a[0]/ev,t.a[1]/ev],b:[t.b[0]/ev,t.b[1]/ev],cm:t.cm}))),f){const t=this._normalizeWalls(v,this._openCuts());t.length?e.walls=t:y?.length?e.walls=y:delete e.walls}if(w.length){this._cfgEpoch++;const i=this._openCuts(),s=this._spaceModel();if(!s)return;let n=e.walls;for(const{room:e,decision:o}of w){const a=o.candidate.ring,r=this._wallSourceCmAt(a[0],t.activePath,t.activeCms);n=Nl(n,s.rooms,e.id,r,this._wallKeyPitch,i,ev);for(const o of dc(s.rooms,n,i,this._wallKeyPitch,this._cellCm,this._gridPitch,ev)){if(o.roomId!==e.id||"outer"!==o.kind)continue;const i=[(o.a[0]+o.b[0])/2,(o.a[1]+o.b[1])/2];n=Fl(n,o.a,o.b,this._wallSourceCmAt(i,t.activePath,t.activeCms),this._wallKeyPitch,ev)}}const o=this._normalizeWalls(n,i);o.length?e.walls=o:delete e.walls}if(!this._commitPhysicalGeometry(this._t("history.wall_face_batch"),g))return;delete this._resumeDraftBySpace[this._space],this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._wallFaceBatch=null,this._roomDialog=!1,this._nameSel="",this._areaSel="",this._regSignature="",this._maybeRebuildDevices();const k=new Set(n.map(t=>t.area).filter(t=>!!t));if(k.size){const t={...this._layout};for(const e of this._devices){if(!k.has(e.area||"")||e.space!==this._space)continue;if(this._layout[e.id])continue;const i=this._defPos[e.id];i&&(t[e.id]={s:this._space,x:i.x/ev,y:i.y/ev},this._dirtyPos.add(e.id))}this._layout=t,this._persistLayout()}this._showToast(this._t(n.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:n.length}))}_commitRoom(){const t=this._curSpaceCfg,e=this._spaceModel();if(!t||!e)return;const i=this._geometrySnapshot(),s=this._spaceH,n=!!this._pendingSplit,o=n?pc(e.rooms,t.walls,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,ev):null,a=n&&Array.isArray(t.walls)?t.walls:null;let r;if(this._pendingSplit){const e=t.rooms.find(t=>t.id===this._pendingSplit.roomId);if(!e)return this._pendingSplit=null,this._splitSel=null,void(this._roomDialog=!1);e.poly=this._pendingSplit.mainPoly.map(t=>[t[0]/ev,t[1]/s]),delete e.x,delete e.y,delete e.w,delete e.h,r=this._pendingSplit.newPoly}else{if(!this._contourClosed)return;r=this._path.slice(0,-1)}const l=this._areaSel?this.hass.areas[this._areaSel]?.name:"",c={id:"r"+Date.now().toString(36),name:this._nameSel||l||this._t("room.default_name"),area:this._areaSel||null,poly:r.map(t=>[t[0]/ev,t[1]/s]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(!n&&this._activeDraftId){const e=Array.isArray(t.room_drafts)?t.room_drafts.find(t=>t.id===this._activeDraftId):null,i=Jp(r.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll),s=this._draftSegmentsForPath(this._path,e,i);s.length===r.length&&s.every(t=>!!t.id)&&(c.wall_ids=s.map(t=>t.id))}if(t.rooms.push(c),!n&&this._activeDraftId&&Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),n){const e=this._normalizeWalls(o,this._openCuts());e.length?t.walls=e:a?.length?t.walls=a:delete t.walls}if(!n){const e=Jp(r.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll),i=e[0];if(null!=i){this._cfgEpoch++;const s=this._openCuts(),n=this._spaceModel();if(!n)return;let o=Nl(t.walls,n.rooms,c.id,i,this._wallKeyPitch,s,ev);for(const t of dc(n.rooms,o,s,this._wallKeyPitch,this._cellCm,this._gridPitch,ev)){if(t.roomId!==c.id||"outer"!==t.kind)continue;const i=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],s=r.findIndex((t,e)=>{const s=r[(e+1)%r.length];return Ls(i,[t[0],t[1],s[0],s[1]])<=.02*this._gridPitch});s>=0&&(o=Fl(o,t.a,t.b,e[s],this._wallKeyPitch,ev))}o=this._normalizeWalls(o,s),o.length?t.walls=o:delete t.walls}}const h=this._commitPhysicalGeometry(this._t(n?"history.split_room":"history.add_room"),i);this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._pendingSplit=null,this._splitSel=null;const d=this._areaSel;if(this._areaSel="",this._nameSel="",this._roomDialog=!1,this._regSignature="",this._maybeRebuildDevices(),!h)return;let p=0;if(d){const t=ev,e={...this._layout};for(const i of this._devices){if(i.area!==d||i.space!==this._space)continue;if(p++,this._layout[i.id])continue;const s=this._defPos[i.id];s&&(e[i.id]={s:this._space,x:s.x/ev,y:s.y/t},this._dirtyPos.add(i.id))}this._layout=e,this._persistLayout()}const u=this._model.find(t=>t.id===this._space)?.rooms.length||0;this._showToast(d?this._t("toast.room_saved",{n:u,added:p}):this._t("toast.room_saved_no_area",{n:u}))}_cancelPath(){this._wallRepairDiagnostic=null,this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._clearPlanSnapHover(),this._roomDialog=!1,this._pendingSplit=null,this._wallFaceBatch=null,this._splitSel=null,this._mergeSel=null,this._mergeDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._clearOpeningPlacement(!0)}_resumeLastDraft(){const t=this._resumeDraftBySpace[this._space];if(!t)return;const e=this._spaceModel()?.room_drafts.find(e=>e.id===t);e?(this._activeDraftId=t,this._path=e.points.map(t=>[...t]),this._draftSegmentCms=this._adoptDraftCms(this._path,e.segments.map(t=>t.cm),e.id),this._clearPlanSnapHover()):delete this._resumeDraftBySpace[this._space]}_roomDialogCancel(){if(this._roomDialog=!1,this._roomEditId)return this._roomEditId=null,this._nameSel="",void(this._areaSel="");if(this._wallFaceBatch){const t=this._wallFaceBatch;return this._wallFaceBatch=null,this._path=t.activePath.map(t=>[...t]),this._draftSegmentCms=[...t.activeCms],this._activeDraftId=t.activeDraftId,this._nameSel="",this._areaSel="",void this.requestUpdate()}if(this._pendingSplit)return this._pendingSplit=null,void(this._splitSel=null);this._undoPoint()}get _freeAreas(){const t=new Set;for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area&&t.add(i.area);for(const e of this._wallFaceBatch?.decisions||[])e.create&&e.area&&t.add(e.area);return Object.values(this.hass?.areas||{}).filter(e=>!t.has(e.area_id)).sort((t,e)=>(t.name||"").localeCompare(e.name||""))}_openMarkerDialog(t){if(this._vacAllCamerasFor=null,this._vacAllCameraCache=null,t&&this._ackNewDevice(t.id),this._norm)if(t){const e=t.marker,i=Object.prototype.hasOwnProperty.call(e||{},"is_light"),s=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),n=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),o=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),a=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),r=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),l=ks(e?.glow_color),c=this._devicePresentation(t,!0).valueBadge,h=Wo(this._planHass,t,this._devices),d=jo(this._planHass,t,h);this._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:Bi(t.marker?.display),rippleColor:Rt(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:pp(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:a,originalTapAction:t.marker?.tap_action,tapHintAnnouncement:"",toggleEntity:e?.toggle_entity||"",toggleEntityTouched:!1,originalHasToggleEntity:r,originalToggleEntity:e?.toggle_entity,tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",controls:Zn(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:i,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:s,originalLightEntity:e?.light_entity,glowMode:null!=l?.bri?"fixed":l?"color":"auto",glowColor:l?.c||this._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(l?.bri??1))),glowColorDrafted:!!l,glowBrightnessDrafted:null!=l?.bri,glowTouched:!1,originalHasGlowColor:n&&(!!l||null===e?.glow_color),originalGlowColor:l||(null===e?.glow_color?null:void 0),valueBadgeEnabled:o?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||d,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:o,originalValueBadge:e?.value_badge,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:1.5,size:1,angle:0,tapAction:"info",tapActionTouched:!1,originalHasTapAction:!1,originalTapAction:void 0,tapHintAnnouncement:"",toggleEntity:"",toggleEntityTouched:!1,originalHasToggleEntity:!1,originalToggleEntity:void 0,tapTarget:"",tapConfirm:!1,runFilter:"",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,lightEntity:"",lightEntityTouched:!1,originalHasLightEntity:!1,originalLightEntity:void 0,glowMode:"auto",glowColor:this._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgePosition:"right",valueBadgeTouched:!1,originalHasValueBadge:!1,originalValueBadge:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};else this._showToast(this._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of Gi)for(const[i,s]of Object.entries(this.hass.states))i.startsWith(e+".")&&this._planEntityAvailable(i)&&t.push({value:i,label:s?.attributes?.friendly_name||i,sub:this._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=this._planHass,e=wo(this._markers),i=new Set(this._markers.filter(t=>t.removed).map(t=>t.binding)),s=new Set;for(const t of this._devices)t.id!==this._markerDialog?.devId&&("device"===t.bindingKind&&t.bindingRef&&s.add("device:"+t.bindingRef),"entity"===t.bindingKind&&t.bindingRef&&s.add("entity:"+t.bindingRef));const n=new Set;for(const t of this._devices)"device"===t.bindingKind&&t.name&&n.add(t.name.trim()+"|"+(t.area||""));const o=[];for(const e of Object.values(t.devices)){if("service"===e.entry_type)continue;const t="device:"+e.id;if(s.has(t))continue;const a=(e.name_by_user||e.name||e.id).trim();t!==this._markerDialog?.binding&&!i.has(t)&&n.has(a+"|"+(e.area_id||""))||o.push({value:t,label:a,sub:(e.model||this._t("marker.sub_device"))+("Group"===e.model?this._t("marker.sub_z2m_group"):"")})}const a=new Set(["group","template","derivative","min_max","threshold","integration","statistics","trend","utility_meter","tod","switch_as_x","schedule"]);for(const[n,r]of Object.entries(t.entities)){const l="entity:"+n;if(s.has(l))continue;if(ko(t,n,e)&&!i.has(l))continue;const c=a.has(r.platform),h="group"===r.platform;if(!c&&!h)continue;if(r.hidden&&!i.has(l))continue;const d=t.states[n];o.push({value:l,label:r.name||d?.attributes?.friendly_name||n,sub:n.split(".")[0]+" · "+("group"===r.platform?this._t("marker.sub_group"):this._t("marker.sub_helper"))})}if(this._markerDialog?.showEntities){const n=new Set(o.map(t=>t.value));for(const[a,r]of Object.entries(t.entities)){const l="entity:"+a;if(s.has(l)||n.has(l)||r.hidden&&!i.has(l))continue;const c=!!r.device_id&&e.devices.has(r.device_id);if(ko(t,a,e)&&!i.has(l)&&!c)continue;const h=t.states[a],d=r.name||h?.attributes?.friendly_name||a,p=r.device_id?t.devices[r.device_id]:null,u=p&&(p.name_by_user||p.name)||"";o.push({value:l,label:d,sub:a.split(".")[0]+" · "+this._t("marker.sub_entity")+(u?" · "+u:"")})}}const r=(this._markerDialog?.bindingFilter||"").toLowerCase().trim(),l=r?o.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(r)):o;return l.sort((t,e)=>t.label.localeCompare(e.label)),l.slice(0,200)}_physicalBodiesR(t=this._spaceModel()){if(!t)return[];const e=`${t.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===e)return this._physicalBodiesCache.all;const i=eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t));return this._physicalBodiesCache={key:e,...i},i.all}_rawPhysicalBodiesR(t=this._spaceModel()){if(!t)return[];this._physicalBodiesR(t);const e=this._physicalBodiesCache;return e?[...e.drafts,...e.partitions,...e.columns]:[]}_cleanFloor(t,e,i=this._spaceModel()){if(!i)return{floor:e,geom:null,path:"",area:rh([[[...e,e[0]]]])};const s=t.id||`#${i.rooms.indexOf(t)}`,n=`${i.id}|${this._cfgEpoch}|${s}`;if(!this._rszPreview){const t=qf(this._cleanFloorCache,n);if(t.hit)return t.value}const o=e.map(t=>t[0]),a=e.map(t=>t[1]),r=[Math.min(...o),Math.min(...a),Math.max(...o),Math.max(...a)],l=this._physicalBodiesR(i).filter(t=>{const e=t.map(t=>t[0]),i=t.map(t=>t[1]);return Math.max(...e)>=r[0]&&Math.min(...e)<=r[2]&&Math.max(...i)>=r[1]&&Math.min(...i)<=r[3]}),c=l.length?ah(e,l):null,h={floor:e,geom:c,path:c?Jc(c):"",area:rh(c||[[[...e,e[0]]]])};return this._rszPreview||Wf(this._cleanFloorCache,n,h,600),h}_autoIconForBinding(t){if("virtual"===t)return"mdi:map-marker";const[e,i]=t.split(":");if(!i)return"";const s=this._fullRegistryHass,n=this._bindingStatus(t),o="active"===n.kind?n.enabledEntityIds:n.allEntityIds;if("device"===e){const t=s.devices?.[i];if(!t)return"mdi:help-circle";const e=o;return e.some(t=>t.startsWith("lock."))?"mdi:lock":bo(s,t.name_by_user||t.name||"",t.model,e,this._iconRules)}if("entity"===e){const t=s.entities?.[i],e=this.hass.states?.[i],n=t?.name||e?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":bo(s,n,"",[i],this._iconRules)}return""}_allRoomsFlat(){const t=[];for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area?t.push({value:e.id+"#"+i.area,label:(e.title||e.id)+" · "+i.name}):i.id&&t.push({value:e.id+"#@"+i.id,label:(e.title||e.id)+" · "+i.name+" · "+this._t("marker.subarea")});return t}_errText(t){if(!t)return this._t("err.unknown");if("string"==typeof t)return t;if("invalid_passage_fields"===t.code){const e=String(t.message||t.error||"").match(/space=([^;]*);\s*opening=([^;]*);\s*fields=([^;]*)/);if(e){const t=this._serverCfg?.spaces?.find(t=>String(t.id)===e[1]),i={contact:"opening.contact_label",lock:"opening.lock_label",invert:"opening.invert",flip_h:"opening.flip_h",flip_v:"opening.flip_v"},s=e[3].split(",").filter(Boolean).map(t=>i[t]?this._t(i[t]):t).join(", ");return this._t("opening.invalid_passage_fields",{room:t?.title||e[1],fields:s})}}if("invalid_partition_opening_jamb_margin"===t.code){const e=String(t.message||t.error||"").match(/margin_cm=([^;]*)/),i=e?Number(e[1]):NaN;if(Number.isFinite(i))return this._t("opening.partition_jamb_margin",{distance:li(i,this._imperial)})}if(t.message)return t.message;if(t.error)return t.error;if(null!=t.code)return this._t("err.code",{code:t.code});try{return JSON.stringify(t)}catch{return String(t)}}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,i=this._t(t);if(i!==t)return i}return this._errText(t)}async _pickMarkerFiles(t){const e=t.target,i=e.files?[...e.files]:[];if(e.value="",!i.length||!this._markerDialog)return;const s=this._markerDialog.uploadId||this._markerDialog.devId||"new",n=[];for(const t of i)try{const e=new FormData;e.append("marker_id",s),e.append("file",t,t.name);const i=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error){const t={too_large:this._t("err.too_large",{mb:o.max_mb||50}),bad_ext:this._t("err.bad_ext"),unauthorized:this._t("err.unauthorized")};throw new Error(t[o.error]||o.error||"HTTP "+i.status)}n.push({name:o.name||t.name,url:o.url})}catch(e){this._showToast(this._t("toast.file_failed",{name:t.name,err:this._errText(e)}))}n.length&&this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:[...this._markerDialog.pdfs,...n]},this._showToast(this._t("toast.files_attached",{n:n.length})))}_removeMarkerPdf(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:this._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.lightEntityTouched?t.lightEntity&&(e.light_entity=t.lightEntity):t.originalHasLightEntity&&(e.light_entity=t.originalLightEntity??null),t.glowTouched){if("auto"!==t.glowMode){const i={c:Rt(t.glowColor,this._fillColors.glow_light.c)};"fixed"===t.glowMode&&(i.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=i}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}_markerTapActionFields(t){return t.tapActionTouched?{tap_action:t.tapAction||null}:t.originalHasTapAction?{tap_action:t.originalTapAction??null}:{}}_markerToggleEntityFields(t){return(e={touched:t.toggleEntityTouched,originalHas:t.originalHasToggleEntity,original:t.originalToggleEntity,value:t.toggleEntity}).touched?e.value?{toggle_entity:e.value}:{}:e.originalHas?{toggle_entity:e.original??null}:{};var e}async _saveMarker(){const t=this._markerDialog;if(!t||t.busy)return;const e=this._effectiveMarkerTapAction(t);if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return;if("virtual"===t.binding&&!t.name.trim())return void this._showToast(this._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this._showToast(this._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this._showToast(this._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this._bindingStatus(t.binding),i=t.devId?this._markers.find(e=>e.id===t.devId):null,s=!i||i.binding!==t.binding;if("active"!==e.kind&&s)return void this._showToast(this._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===i?.hidden&&!t.hideFromPlan)return this._markerDialog={...t,hideFromPlan:!0},void this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const i=this._serverCfg;if(!i)return;const s=i.markers||[],n=qs(t.room);let o=n?.space||null;const a=n?.area||null,r=n?.roomId||null,l=Fi(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),c=t.devId,h=c?this._devices.find(t=>t.id===c):null,d=n?.space||h?.space||null,p=d?this._spaceModelById(d):this._spaceModel();if(!p)return;const u=p.id;"virtual"!==t.binding||o||(o=u),this._markerDialog={...t,busy:!0};try{const n="virtual"===t.binding?[]:s.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=n.length>0,_=Zn(t.binding,t.controls,this._bindingEntities(t.binding)),m=s.find(t=>t.id===l||t.id===c)?.vacuum||null,g={id:l,vacuum:m,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===e&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:_.length?_:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=Bf(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};("virtual"===t.binding||t.room)&&(g.space=o,g.area=a,g.room_id=r);const f=h?.marker?.room_id??null,v=!!t.room&&null!=h&&(h.space!==o||h.area!==a||f!==r);let y=!1;const b=t.uploadId||c;if(b&&b!==l&&g.pdfs?.length)try{const t=await this.hass.callWS({type:"houseplan/files/migrate",from_id:b,to_id:l}),e=t?.mapping||{};g.pdfs=function(t,e,i,s){if(!e||!i||e===i)return t;const n="/files/"+e+"/",o="/files/"+i+"/";return t.map(t=>{if(!t.url.includes(n))return t;const e=t.url.split(n)[1]||"",[i,a]=[e.split("?")[0],e.includes("?")?"?"+e.split("?")[1]:""];if(s){const e=s[decodeURIComponent(i)]??s[i];return e?{...t,url:t.url.split(n+i)[0]+o+encodeURIComponent(e)+a}:t}return{...t,url:t.url.split(n).join(o)}})}(g.pdfs,b,l,e),y=Object.keys(e).length>0}catch(t){this._showToast(this._t("toast.files_migrate_failed",{err:this._errText(t)}))}i.markers=s,c&&c!==l&&(i.markers=function(t,e,i){if(!e||!i||e===i)return[...t];const s=`marker:${e}`,n=`marker:${i}`;return t.map(t=>{const e=Array.isArray(t.controls)?t.controls.map(t=>t===s?n:t):t.controls,i="derived_marker_state"===t.value_badge?.source?.kind&&t.value_badge.source.ref===s?{...t.value_badge,source:{...t.value_badge.source,ref:n}}:t.value_badge;return e===t.controls&&i===t.value_badge?t:{...t,controls:e,value_badge:i}})}(i.markers,c,l)),c&&c!==l&&"derived_marker_state"===g.value_badge?.source?.kind&&g.value_badge.source.ref===`marker:${c}`&&(g.value_badge.source={kind:"derived_marker_state",ref:`marker:${l}`}),i.markers=i.markers.filter(t=>t.id!==l&&t.id!==c&&("virtual"===g.binding||t.binding!==g.binding)),i.markers.push(g);let w=null;const k=c?this._layout[c]:null,x=k?{s:k.s||h?.space||this._space,x:k.x,y:k.y}:c&&h&&this._defPos[c]?this._normPos(h.space,this._defPos[c].x,this._defPos[c].y):null;if(!d&&x&&x.s===u)l===c&&this._layout[l]&&!v||(w={s:x.s,x:x.x,y:x.y},this._layout={...this._layout,[l]:w});else if(d||!this._layout[l]||v){let t=p.vb[0]+p.vb[2]/2,e=p.vb[1]+p.vb[3]/2;const i=r?p.rooms.find(t=>t.id===r):a?p.rooms.find(t=>t.area===a):void 0;i&&([t,e]=this._roomCenter(i)),w=this._normPos(u,t,e),this._layout={...this._layout,[l]:w}}if(await this._saveConfigNow(),w){const t=ol(w);this._layout={...this._layout,[l]:t},this._noteLayoutRev(await this.hass.callWS({type:"houseplan/layout/update",device_id:l,pos:t}))}const $=new Set(n);c&&c!==l&&$.add(c),$.delete(l);for(const t of $)delete this._layout[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{});y&&b&&await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:b}).catch(()=>{}),this._markerDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_saved"))}catch(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteMarker(){const t=this._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this._devices.find(e=>e.id===t.devId):null;if(!e)return;const i=t.name||this._t("device.fallback");if(!confirm(this._t("confirm.remove_marker",{name:i})))return;const s=this._serverCfg;s.markers=s.markers||[];const n=s.markers,o="virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"";if(!o)return;const a=function(t,e,i,s){const n=new Set([e]),o=t.filter(t=>{const o=t.id===e||!s&&t.binding===i;return o&&n.add(t.id),!o});return{markers:s?o:[...o,{id:e,binding:i,removed:!0,hidden:!0}],cleanupIds:n}}(s.markers,e.id,o,"virtual"===e.bindingKind);var r,l;s.markers=(r=a.markers,l=a.cleanupIds,r.map(t=>{if(!Array.isArray(t.controls))return t;const e=t.controls.filter(t=>!("string"==typeof t&&t.startsWith("marker:")&&l.has(t.slice(7))));return e.length===t.controls.length?t:{...t,controls:e.length?e:null}}));const c=a.cleanupIds;this._markerDialog={...t,busy:!0};try{await this._saveConfigNow();for(const t of c){delete this._layout[t],delete this._defPos[t],this._dirtyPos.delete(t),this._sentPos.delete(t);const e=this._activityRt.get(t);e&&clearTimeout(e.timer),this._activityRt.delete(t),this._vacRt.delete(t),delete this._vacSrvTrails[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{}),await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this._markerDialog=null,this._infoCard?.id===e.id&&this._closeInfoCard(),this._selId===e.id&&(this._selId=null),this._drag?.id===e.id&&(this._drag=null),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_removed"))}catch(t){this._serverCfg===s&&(s.markers=n),this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}_normPos(t,e,i){return{s:t,x:e/ev,y:i/ev}}_openSpaceDialog(t,e){if(this._serverStorage&&this._serverCfg)if("edit"===t){const i=this._serverCfg.spaces.find(t=>t.id===e);if(!i)return;const s=cs(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?rs(i.settings.custom_fill):null,o="none"===s.fill?{...n||as,a:0}:n;this._spaceDialog={mode:t,spaceId:e,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:s.showBorders,showNames:s.showNames,zeroWallStyle:d_(i),displayTouched:!0,hideDecor:s.hideDecor,hideOpenings:s.hideOpenings,roomColor:s.color,roomOpacity:s.opacity,fillMode:"none"===s.fill?"custom":s.fill,customFill:o,glowEnabled:s.glow,bgColor:s.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:$r({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:s.tempMin,tempMax:s.tempMax,showLqi:s.showLqi??this._config?.show_signal??!0,cardFontScale:s.cardFontScale,labelTemp:s.labelTemp,labelHum:s.labelHum,labelLqi:s.labelLqi,labelLight:s.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:fh(Number(i.cell_cm)>0?Number(i.cell_cm):5,this._imperial),cellCmTouched:!1,busy:!1}}else this._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...Sd(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ns,roomOpacity:os,fillMode:"custom",customFill:{...as,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:gh(this._imperial),cellCmInput:fh(gh(this._imperial),this._imperial),cellCmTouched:!1,busy:!1};else this._showToast(this._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,i=e.files?.[0];if(!i||!this._spaceDialog)return;const s={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[i.type]||(i.name.toLowerCase().endsWith(".svg")?"svg":"");if(!s)return void this._showToast(this._t("toast.plan_formats"));const n=new Uint8Array(await i.arrayBuffer());let o="";for(let t=0;t{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:1.414),e.onerror=()=>t(1.414),e.src=r});URL.revokeObjectURL(r),this._spaceDialog={...this._spaceDialog,planFile:{ext:s,b64:a,aspect:l,name:i.name}}}_useServerPlan(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this._display(t);if(e){const i=await new Promise(t=>{const i=new Image;i.onload=()=>t(i.naturalWidth&&i.naturalHeight?i.naturalWidth/i.naturalHeight:0),i.onerror=()=>t(0),i.src=e}),s=this._spaceDialog;return s&&s.planUrl===t&&Number.isFinite(i)&&i>0?(this._spaceDialog={...s,savedAspect:i},i):0}if(await new Promise(t=>setTimeout(t,150)),this._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this._t("confirm.delete_plan",{name:t})))try{await this.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this._spaceDialog;e?.saved&&(this._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this._showToast(this._t("toast.plan_delete_failed",{err:this._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return W`
${this._t("space.loading")}
`;const e=t.saved||[];if(!e.length)return W`
${this._t("space.no_saved")}
`;return W`
+
`:W``}_openingAt(t){if(!this._openingsR.length)return null;const e=this._openingsR.flatMap(e=>{const i=e.angle*Math.PI/180,s=t[0]-e.rx,n=t[1]-e.ry,o=s*Math.cos(i)+n*Math.sin(i);return Math.abs(o)>e.rlen/2+mh(12,this._cellCm)?[]:[{o:e,localY:-s*Math.sin(i)+n*Math.cos(i)}]});if(!e.length)return null;const i=this._spaceModel();if(!i)return null;const s=this._openCuts(),n=this._openingWallIndexFor(i,s).value;return e.find(({o:t,localY:e})=>{const i="gate"===t.type?!t.flip_v:t.flip_v,s=t.partitionHost||this._spaceWalls.length||"gate"===t.type?this._openingFace(t,n,!!i):{ox:0,oy:0,cm:0,side:-1},o=Lu({type:t.type,length:t.rlen,angle:t.angle,amount:this._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this._cellCm,gridPitch:this._gridPitch,face:s});return Math.abs(e)<=o.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this._openingPreset;if("opening"!==this._tool||!e)return null;const i=this._spaceModel();if(!i)return null;const s=this._openCuts(),n=this._openingWallIndexFor(i,s),o=`${n.key}|partitions:${this._cfgEpoch}`;this._openingPlacementIntervalsCache&&this._openingPlacementIntervalsCache.key===o||(this._openingPlacementIntervalsCache={key:o,value:[...dc(i.rooms,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,iv),...Pp(i.partitions,this._cellCm,this._gridPitch)]}),this._openingDimensionContextCache&&this._openingDimensionContextCache.key===o||(this._openingDimensionContextCache={key:o,value:Cf({rooms:i.rooms,walls:this._spaceWalls,openCuts:s,partitions:i.partitions,roomOpenings:this._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(i),pitch:this._wallKeyPitch,cellCm:this._cellCm,gridPitch:this._gridPitch,coordScale:iv,epsilon:2e-4*this._gridPitch})});const a=vf({pointer:[t[0],t[1]],preset:e,geometryRevision:this._cfgEpoch,renderedLength:this._cmToUnits(e.lengthCm),intervals:this._openingPlacementIntervalsCache.value,baseTolerance:1.5*this._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this._pointerModality.modality||"pen"===this._pointerModality.modality?10:6),gridStep:this._gridPitch});this._openingJambBlockCm=a.jambBlockedTarget?a.jambBlockedTarget.physicalHalfWidth/this._gridPitch*this._cellCm:null;const r=a.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let c;if(r.host){const t=$p({id:"preview",type:r.type,x:r.x/iv,y:r.y/iv,angle:r.angle,length:r.renderedLength/iv,host:r.host},i.partitions,iv,this._cellCm,this._gridPitch).resolved;c=t?Dp(t,l):{ox:0,oy:0,cm:0,side:-1}}else c=Lc(n.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const h="mi"===this.hass?.config?.unit_system?.length,d=zf(r,this._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:li(t.distance/this._gridPitch*this._cellCm,h),dimension:t}));return{...r,face:c,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this._tool&&(this._openingPreset=function(t,e){return{type:t,lengthCm:_f(t),flipH:!1,flipV:!1,revision:e}}(t,++this._openingPresetRevision),this._openingHoverCandidate=null,this._cursorPt=null)}_clearOpeningPlacement(t){this._openingHoverCandidate=null,this._openingJambBlockCm=null,t&&(this._openingPreset=null,this._openingRebindId=null)}_openingClick(t){const e=this._spaceModel();if(!e)return;const i=this._openingRebindId?null:this._openingAt(t);if(i)return void this._editOpening(i);const s=this._openingPreset;if(!s)return;const n=this._openingHoverCandidate,o=n&&yf(n,[t[0],t[1]],s.revision,this._cfgEpoch)?n:this._resolveOpeningPlacement(t);if(!o){if(null!=this._openingJambBlockCm)return void this._showToast(this._t("opening.partition_jamb_margin",{distance:li(this._openingJambBlockCm,this._imperial)}));const i=1.5*this._gridPitch,s=ui(t,e.rooms,i);return s&&function(t,e,i,s,n){for(const o of s)if(!(Ls([t,e],o)>n)&&Rl([o[0],o[1]],[o[2],o[3]],i))return!0;return!1}(s.x,s.y,s.angle,this._openCuts(),i)?void this._showToast(this._t("toast.opening_on_zero_wall")):void this._showToast(this._t("toast.opening_no_wall"))}const a=this._openingRebindId?this._curSpaceCfg?.openings?.find(t=>t.id===this._openingRebindId):null;this._openingDialog={...a?{id:a.id,type:a.type,lengthCm:Math.round(a.length*iv/this._gridPitch*this._cellCm),lengthTouched:!1,contact:a.contact||"",lock:a.lock||"",invert:!!a.invert,flipH:!!a.flip_h,flipV:!!a.flip_v}:{type:o.type,lengthCm:o.lengthCm,contact:"",lock:"",invert:!1,flipH:o.flipH,flipV:o.flipV},...o.host?{host:o.host}:{},x:o.x,y:o.y,angle:o.angle},this._openingRebindId=null,this._openingHoverCandidate=null,this._cursorPt=null}_editOpening(t){this._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this._gridPitch*this._cellCm),lengthTouched:!1,contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,..."partition"===t.host?.kind?{host:{...t.host}}:{},x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this._mode&&this._spaceModel()&&"resize"!==this._tool){t.preventDefault(),t.stopPropagation();try{hv(t)}catch{}this._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this._opDrag.sx)+Math.abs(t.clientY-this._opDrag.sy)<=3)return;const i=this._spaceModel();if(!i)return;const s=this._svgPoint(t),n=this._curSpaceCfg,o=n?.openings?.find(t=>t.id===e.id);if(!o)return;if("partition"===o.host?.kind){const t=i.partitions.find(t=>t.id===o.host.id);if(!t)return;const e=t.b[0]-t.a[0],n=t.b[1]-t.a[1],a=Math.hypot(e,n);if(!(a>1e-9))return;const r=e/a,l=n/a;if(Math.abs((s[0]-t.a[0])*l-(s[1]-t.a[1])*r)>4*this._gridPitch)return;const c=o.length*iv/2+kp(t,this._cellCm,this._gridPitch);let h=(s[0]-t.a[0])*r+(s[1]-t.a[1])*l;if(h=Math.round(h/this._gridPitch)*this._gridPitch,h=Math.max(c,Math.min(a-c,h)),a<2*c-1e-9)return;const d=h/a,p=(t.a[0]+r*h)/iv,u=(t.a[1]+l*h)/this._spaceH;let _=180*Math.atan2(n,e)/Math.PI;_>=90?_-=180:_<-90&&(_+=180);const m=o.host.t!==d||o.x!==p||o.y!==u||o.angle!==_;return this._opDrag.moved=!0,m&&(this._opDrag.dirty=!0),o.host={...o.host,t:d},o.x=p,o.y=u,o.angle=_,this._opMeasure=null,m&&this._cfgEpoch++,void this.requestUpdate()}const a=ui(s,i.rooms,4*this._gridPitch);if(!a)return;this._opDrag.moved=!0;const r=this._opRuler(a,o.length*iv);this._opMeasure=r.measure;const l=r.x/iv,c=r.y/this._spaceH,h=o.x!==l||o.y!==c||o.angle!==a.angle;if(h&&(this._opDrag.dirty=!0),o.x=l,o.y=c,o.angle=a.angle,Number(this._serverCfg?.model_version||0)>=9){const t=Km(o,n?.wall_segments||[]);t?o.host=t:delete o.host}h&&this._cfgEpoch++,this.requestUpdate()}_opRuler(t,e){const i=this._spaceModel()?.rooms||[],s=this._gridPitch/2;let n=t.x,o=t.y,a=_i([n,o],t.angle,e,i,s);if(a&&a.centered&&(n!==a.wallCenter[0]||o!==a.wallCenter[1]))[n,o]=a.wallCenter,a=_i([n,o],t.angle,e,i,s);else if(a){const[r,l]=a.wallA,[c,h]=a.wallB,d=c-r,p=h-l,u=Math.hypot(d,p);if(u>0){const c=this._gridPitch,h=Math.min(e/2,u/2);let _=Math.round(((n-r)*d+(o-l)*p)/u/c)*c;_=Math.max(h,Math.min(u-h,_)),n=r+_/u*d,o=l+_/u*p,a=_i([n,o],t.angle,e,i,s)||a}}if(!a)return{x:n,y:o,angle:t.angle,measure:null};const r="mi"===this.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:li(t/this._gridPitch*this._cellCm,r)});return{x:n,y:o,angle:t.angle,measure:{labels:[l(a.sideA,a.midA),l(a.sideB,a.midB)],guide:a.centered?{x:a.wallCenter[0],y:a.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;const i=this._opDrag,s=i.moved;this._opMeasure=null,s&&i.dirty&&this._commitPhysicalGeometry(this._t("history.move_opening"),i.before),s?window.setTimeout(()=>this._opDrag=null,0):this._opDrag=null}_opClick(t,e){"plan"===this._mode&&"resize"===this._tool||(t.stopPropagation(),this._opDrag?.moved||"plan"===this._mode&&this._editOpening(e))}_saveOpening(){const t=this._openingDialog,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=this._geometrySnapshot(),n=this._spaceH,o=(e.openings||[]).find(e=>e.id===t.id),a={...o||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/iv,y:t.y/n,angle:t.angle,length:o&&!t.lengthTouched?o.length:this._cmToUnits(Math.max(20,t.lengthCm))/iv,...t.host?{host:{...t.host}}:{}};if("partition"===a.host?.kind){const t=Mp(o,a)?Sp(a,i.partitions,iv,this._cellCm,this._gridPitch):$p(a,i.partitions,iv,this._cellCm,this._gridPitch);if(!t.resolved){const e=i.partitions.find(t=>t.id===a.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=kp(e,this._cellCm,this._gridPitch);this._showToast(this._t("opening.partition_jamb_margin",{distance:li(t/this._gridPitch*this._cellCm,this._imperial)}))}else this._showToast(this._t("opening.partition_orphan"));return}const s=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===a.id)return[];const e=$p(t,i.partitions,iv,this._cellCm,this._gridPitch).resolved;return e?[e]:[]});if(function(t,e,i=1e-9){const s=t.length/(2*t.axis.length),n=t.t-s,o=t.t+s;return e.some(e=>{if(e.host.id!==t.host.id||e.opening.id===t.opening.id)return!1;const s=e.length/(2*e.axis.length);return Math.max(n,e.t-s)=9){const t=Km(a,e.wall_segments||[]);if(!t)return void this._showToast(this._t("toast.opening_no_wall"));a.host=t}else delete a.host;"passage"===t.type?(delete a.contact,delete a.lock,delete a.invert,delete a.flip_h,delete a.flip_v):(a.contact=t.contact||null,a.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,a.invert=t.invert||void 0,a.flip_h="gate"!==t.type&&t.flipH||void 0,a.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===a.id);r>=0?e.openings[r]=a:e.openings.push(a),this._commitPhysicalGeometry(this._t(t.id?"history.edit_opening":"history.add_opening"),s),this._openingDialog=null,this.requestUpdate()}_deleteOpening(){const t=this._openingDialog,e=this._curSpaceCfg;if(!t?.id||!e?.openings)return;const i=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this._t("history.delete_opening"),i),this._openingDialog=null,this.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.hass.states)){if(!this._openingEntityAvailable(e))continue;const i=e.split(".")[0];if("binary_sensor"!==i&&"cover"!==i)continue;const s=this.hass.states[e],n=["door","window","opening","garage_door","garage"].includes(s?.attributes?.device_class||"");("cover"!==i||n)&&t.push([e,s?.attributes?.friendly_name||e,n?0:1])}return t.sort((t,e)=>t[2]-e[2]||t[1].localeCompare(e[1])).map(([t,e])=>({value:t,label:e}))}_lockCandidates(){return Object.keys(this.hass.states).filter(t=>t.startsWith("lock.")&&this._openingEntityAvailable(t)).map(t=>({value:t,label:this.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this._openingDialog;if(!e)return;const i="contact"===t?!e.contactOpen:!e.lockOpen;this._openingDialog={...e,contactOpen:"contact"===t&&i,lockOpen:"lock"===t&&i}}_filterOpeningEntities(t,e){const i=this._openingDialog;i&&(this._openingDialog="contact"===t?{...i,contactFilter:e}:{...i,lockFilter:e})}_selectOpeningEntity(t,e){const i=this._openingDialog;i&&(this._openingDialog="contact"===t?{...i,contact:e,contactOpen:!1,contactFilter:""}:{...i,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this._spaceModel();if(!e)return;const i=e.rooms,s=[...i].reverse().find(e=>this._pointInRoom(t,e));if(!s?.id)return;const n=s.id;if(!this._mergeSel||this._mergeSel===n)return void(this._mergeSel=this._mergeSel===n?null:n);const o=i.find(t=>t.id===this._mergeSel),a=o?hi(o):null,r=hi(s),l=a&&r?function(t,e){if(!t||!e||t.length<3||e.length<3)return null;const i=si(Ri(t),Ri(e));if(1!==i.length)return null;if(1!==i[0].length)return null;const s=i[0][0].slice(0,-1).map(t=>[t[0],t[1]]);return s.length>=3?s:null}(a,r):null;if(!l)return this._showToast(this._t("toast.merge_not_adjacent")),void(this._mergeSel=null);this._mergeDialog={aId:this._mergeSel,bId:n,poly:l,pick:"a"},this._mergeSel=null}_commitMerge(){const t=this._mergeDialog,e=this._curSpaceCfg;if(!t||!e||!this._spaceModel())return;const i=this._geometrySnapshot(),s=this._spaceH,n="a"===t.pick?t.aId:t.bId,o="a"===t.pick?t.bId:t.aId,a=e.rooms.find(t=>t.id===n);if(!a)return void(this._mergeDialog=null);a.poly=t.poly.map(t=>[t[0]/iv,t[1]/s]),delete a.x,delete a.y,delete a.w,delete a.h,e.rooms=e.rooms.filter(t=>t.id!==o);const r=this._commitPhysicalGeometry(this._t("history.merge_rooms"),i);this._mergeDialog=null,this._regSignature="",this._maybeRebuildDevices(),r&&this._showToast(this._t("toast.rooms_merged",{name:a.name||""}))}_splitClick(t){const e=this._spaceModel();if(!e)return;const i=e.rooms;if(!this._splitSel){const e=[...i].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this._splitSel={roomId:e.id,pts:[]})}const s=i.find(t=>t.id===this._splitSel.roomId),n=s?hi(s):null;if(!s||!n)return void(this._splitSel=null);const o=.02*this._gridPitch,a=6*this._gridPitch,r=function(t,e){if(!e||e.length<2)return null;let i=null,s=1/0;for(let n=0;n=n)continue;n=_;const m=Math.sqrt(p),g=(i>0?Math.max(0,Math.min(m,Math.round(u*m/i)*i)):u*m)/m;s=[a+g*h,r+g*d]}return s}(r,n,this._gridPitch)||r,c=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=a?l:null,h=!!c&&bi(c,n,o),d=this._splitSel.pts;if(!d.length)return h?void(this._splitSel={...this._splitSel,pts:[c]}):void this._showToast(this._t("toast.split_pick_wall"));if(!h){const e=this._snap(t);return wi(e,n,o)?void(this._splitSel={...this._splitSel,pts:[...d,e]}):void this._showToast(this._t("toast.split_pick_inside"))}const p=zi(n,[...d,c],o);if(!p)return void this._showToast(this._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[u,_]=p,m=Ti(u)>=Ti(_)?u:_,g=m===u?_:u;this._pendingSplit={roomId:s.id,mainPoly:m,newPoly:g},this._cursorPt=null,this._nameSel="",this._areaSel="",this._roomDialog=!0}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])&&(null!=this._closingWallCm||!this._activeDraftId)}_markupMove(t){if(!this._markup)return;if("column"===this._tool)return void(this._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this._tool||"wallthick"===this._tool)return void(this._cursorPt=this._svgPoint(t));const e="draw"===this._tool&&!this._contourClosed,i="split"===this._tool&&!!this._splitSel?.pts?.length;if(!e&&!i)return;const s=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(s,t.shiftKey);return this._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this._path.length?void(this._cursorPt=e.point):void this._syncPlanSnapActiveMarker(e.candidate)}this._cursorPt=this._snap(s)}get _openingPreview(){const t=this._openingPreset;if("opening"!==this._tool||!t||!this._cursorPt)return null;const e=this._cursorPt,i=this._openingHoverCandidate;if(i&&yf(i,[e[0],e[1]],t.revision,this._cfgEpoch))return i;if(this._openingAt(e))return this._openingHoverCandidate=null,null;const s=this._resolveOpeningPlacement(e);return this._openingHoverCandidate=s,s}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){(this._areaSel||this._nameSel.trim())&&(this._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this._wallFaceBatch;if(!e)return;const i=e.candidates[e.index];if(!i)return;if(!t&&(i.existing||i.repair)&&1===e.candidates.length)return this._wallFaceBatch=null,this._roomDialog=!1,this._nameSel="",this._areaSel="",void this.requestUpdate();const s=t?{candidate:i,create:!0,name:this._nameSel.trim(),area:this._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:i,create:!1},n=[...e.decisions,s],o=e.index+1;if(o"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,n=.02*this._gridPitch,o=this._spaceModel();if(!o)return ll;for(const e of this._planSnapGeometrySnapshot().value.segments){if("room"===e.sourceKind||Ls(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>n)continue;if("partition"===e.sourceKind)return s(o.partitions.find(t=>t.id===e.sourceId)?.cm)??ll;const i=e.sourceId.lastIndexOf(":"),a=i>=0?e.sourceId.slice(0,i):e.sourceId,r=i>=0?Number(e.sourceId.slice(i+1)):-1;return s(o.room_drafts.find(t=>t.id===a)?.segments[r]?.cm)??ll}const a=Jp(Math.max(0,e.length-1),i,this._drawWallCm,ll);for(let i=0;i+1[...t]);if(!e?.sourceKey.startsWith("active:"))return i;const s=/:(\d+)$/.exec(e.sourceKey),n=s?Number(s[1])+("b"===e.endpoint?1:0):-1;return n>=0&&ne.key===t.sourceKey),o=s.find(e=>e.key===t.targetSourceKey);if(!n||!o)return!1;const a="a"===t.endpoint?n.a:n.b;return!(Math.hypot(a[0]-t.from[0],a[1]-t.from[1])>i)&&(!(Ls(t.to,[o.a[0],o.a[1],o.b[0],o.b[1]])>i)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const i=t.sourceKey.slice(17).split("|")[0];return!!i&&e.some(t=>"partition"===t.host?.kind&&t.host.id===i)}(t,this._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const i=this._curSpaceCfg;if(!i||!this._validateWallRepair(t,e.activePath))return!1;const s=e=>{e[0]=t.to[0]/iv,e[1]=t.to[1]/iv};if(t.sourceKey.startsWith("active:")){const n=/:(\d+)$/.exec(t.sourceKey),o=n?Number(n[1])+("b"===t.endpoint?1:0):-1;if(o<0||o>=e.activePath.length)return!1;e.activePath[o]=[...t.to];const a=(i.room_drafts||[]).find(t=>t.id===e.activeDraftId);return a?.points?.[o]&&s(a.points[o]),!0}if(!t.sourceKey.startsWith("static:"))return!1;const[n,o]=t.sourceKey.slice(7).split("|");if("partition"===n){const e=(i.partitions||[]).find(t=>t.id===o);if(!e)return!1;const n=[e.a[0]*iv,e.a[1]*iv],a=[e.b[0]*iv,e.b[1]*iv],r=Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this._gridPitch?e.a:Math.hypot(a[0]-t.from[0],a[1]-t.from[1])<=2e-4*this._gridPitch?e.b:null;return!!r&&(s(r),!0)}if("draft"===n){const e=o.lastIndexOf(":"),n=e>=0?o.slice(0,e):"",a=e>=0?Number(o.slice(e+1)):-1,r=(i.room_drafts||[]).find(t=>t.id===n);if(!r?.points?.[a]||!r?.points?.[a+1])return!1;const l=[a,a+1].find(e=>Math.hypot(r.points[e][0]*iv-t.from[0],r.points[e][1]*iv-t.from[1])<=2e-4*this._gridPitch);return null!=l&&(s(r.points[l]),!0)}return!1}_applyWallFaceBatch(){const t=this._wallFaceBatch,e=this._curSpaceCfg,i=this._spaceModel();if(!t||!e||!i)return;const s=(t,e)=>{this._showToast(this._t(t,e)),this._roomDialogCancel()},n=t.decisions.filter(t=>t.create),o=n.map(t=>t.candidate.ring),a=i.rooms;for(let t=0;ti.id!==e&&!!hi(i)&&Di(o[t],hi(i)));if(i)return void s("toast.room_overlap",{name:i.name||""})}if((e.rooms||[]).length+n.length>400)return void s("toast.physical_limit");if(n.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void s("toast.contour_cannot_close");const r=n.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void s("toast.wall_repair_changed");const l=this._activePathWithRepair(t.activePath,r[0]),c=2e-4*this._gridPitch,h=new Map;for(let e=0;et.candidate.atomKeys)),e=n.some(t=>t.candidate.consumeAllActive);for(const i of vu(this._wallGraphSources(l),c)){const s=i.sourceKeys.find(t=>h.has(t));!s||e||t.has(i.key)||d.push({a:i.a,b:i.b,cm:h.get(s)})}}else d.push(...Xp(l,Jp(l.length-1,t.activeCms,this._drawWallCm,ll)));if((e.partitions||[]).length+d.length>av)return void s("toast.physical_limit");const p=n.map(t=>t.candidate.ring.map(()=>"")),u=t.activeDraftId?(e.room_drafts||[]).find(e=>e.id===t.activeDraftId):null,_=this._draftSegmentsForPath(t.activePath,u,t.activeCms),m=(t,e)=>{const i=`${t[0].toFixed(9)},${t[1].toFixed(9)}`,s=`${e[0].toFixed(9)},${e[1].toFixed(9)}`;return i<=s?`${i}|${s}`:`${s}|${i}`};for(let e=0;e<_.length;e++){const i=_[e]?.id;if(!i)continue;const s=t.activePath[e],o=t.activePath[e+1],a=[s[0],s[1],o[0],o[1]],r=[];n.forEach((t,e)=>t.candidate.ring.forEach((i,s)=>{const n=t.candidate.ring[(s+1)%t.candidate.ring.length];Ls(i,a)<=c&&Ls(n,a)<=c&&r.push({kind:"room",owner:e,edge:s,a:i,b:n})})),d.forEach((t,e)=>{Ls(t.a,a)<=c&&Ls(t.b,a)<=c&&r.push({kind:"partition",owner:e,edge:0,a:t.a,b:t.b})});const l=[(s[0]+o[0])/2,(s[1]+o[1])/2];r.sort((t,e)=>{const i=[t.a[0],t.a[1],t.b[0],t.b[1]],n=[e.a[0],e.a[1],e.b[0],e.b[1]];return(Ls(l,i)<=c?0:1)-(Ls(l,n)<=c?0:1)||(Ls(s,i)<=c?0:1)-(Ls(s,n)<=c?0:1)||m(t.a,t.b).localeCompare(m(e.a,e.b))});const h=r[0];if(!h)continue;const u=m(h.a,h.b);for(const t of r)m(t.a,t.b)===u&&("room"===t.kind?p[t.owner][t.edge]=i:d[t.owner].id=i)}const g=this._geometrySnapshot();if(r[0]&&!this._applyWallRepair(r[0],t))return void s("toast.wall_repair_changed");const f=n.some(t=>!!t.candidate.split),v=f?pc(i.rooms,e.walls,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,iv):null,y=f&&Array.isArray(e.walls)?e.walls:null;for(const t of n){const i=t.candidate.split;if(!i)continue;const n=e.rooms.find(t=>t.id===i.roomId);if(!n)return void s("toast.contour_cannot_close");n.poly=i.mainPoly.map(t=>[t[0]/iv,t[1]/this._spaceH]),delete n.x,delete n.y,delete n.w,delete n.h}const b=Date.now().toString(36),w=[];if(n.forEach((t,i)=>{const s=t.area?this.hass.areas[t.area]?.name:"",n={id:`r${b}-${i}`,name:t.name||s||this._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/iv,t[1]/this._spaceH]),...p[i].some(Boolean)?{wall_ids:p[i]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(n),w.push({room:n,decision:t})}),t.activeDraftId&&Array.isArray(e.room_drafts)&&(e.room_drafts=e.room_drafts.filter(e=>e.id!==t.activeDraftId),e.room_drafts.length||delete e.room_drafts),d.length&&(e.partitions||=[],d.forEach((t,i)=>e.partitions.push({id:t.id||`partition-${b}-${i}`,a:[t.a[0]/iv,t.a[1]/iv],b:[t.b[0]/iv,t.b[1]/iv],cm:t.cm}))),f){const t=this._normalizeWalls(v,this._openCuts());t.length?e.walls=t:y?.length?e.walls=y:delete e.walls}if(w.length){this._cfgEpoch++;const i=this._openCuts(),s=this._spaceModel();if(!s)return;let n=e.walls;for(const{room:e,decision:o}of w){const a=o.candidate.ring,r=this._wallSourceCmAt(a[0],t.activePath,t.activeCms);n=Nl(n,s.rooms,e.id,r,this._wallKeyPitch,i,iv);for(const o of dc(s.rooms,n,i,this._wallKeyPitch,this._cellCm,this._gridPitch,iv)){if(o.roomId!==e.id||"outer"!==o.kind)continue;const i=[(o.a[0]+o.b[0])/2,(o.a[1]+o.b[1])/2];n=Fl(n,o.a,o.b,this._wallSourceCmAt(i,t.activePath,t.activeCms),this._wallKeyPitch,iv)}}const o=this._normalizeWalls(n,i);o.length?e.walls=o:delete e.walls}if(!this._commitPhysicalGeometry(this._t("history.wall_face_batch"),g))return;delete this._resumeDraftBySpace[this._space],this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._wallFaceBatch=null,this._roomDialog=!1,this._nameSel="",this._areaSel="",this._regSignature="",this._maybeRebuildDevices();const k=new Set(n.map(t=>t.area).filter(t=>!!t));if(k.size){const t={...this._layout};for(const e of this._devices){if(!k.has(e.area||"")||e.space!==this._space)continue;if(this._layout[e.id])continue;const i=this._defPos[e.id];i&&(t[e.id]={s:this._space,x:i.x/iv,y:i.y/iv},this._dirtyPos.add(e.id))}this._layout=t,this._persistLayout()}this._showToast(this._t(n.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:n.length}))}_commitRoom(){const t=this._curSpaceCfg,e=this._spaceModel();if(!t||!e)return;const i=this._geometrySnapshot(),s=this._spaceH,n=!!this._pendingSplit,o=n?pc(e.rooms,t.walls,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,iv):null,a=n&&Array.isArray(t.walls)?t.walls:null;let r;if(this._pendingSplit){const e=t.rooms.find(t=>t.id===this._pendingSplit.roomId);if(!e)return this._pendingSplit=null,this._splitSel=null,void(this._roomDialog=!1);e.poly=this._pendingSplit.mainPoly.map(t=>[t[0]/iv,t[1]/s]),delete e.x,delete e.y,delete e.w,delete e.h,r=this._pendingSplit.newPoly}else{if(!this._contourClosed)return;r=this._path.slice(0,-1)}const l=this._areaSel?this.hass.areas[this._areaSel]?.name:"",c={id:"r"+Date.now().toString(36),name:this._nameSel||l||this._t("room.default_name"),area:this._areaSel||null,poly:r.map(t=>[t[0]/iv,t[1]/s]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(!n&&this._activeDraftId){const e=Array.isArray(t.room_drafts)?t.room_drafts.find(t=>t.id===this._activeDraftId):null,i=Jp(r.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll),s=this._draftSegmentsForPath(this._path,e,i);s.length===r.length&&s.every(t=>!!t.id)&&(c.wall_ids=s.map(t=>t.id))}if(t.rooms.push(c),!n&&this._activeDraftId&&Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),n){const e=this._normalizeWalls(o,this._openCuts());e.length?t.walls=e:a?.length?t.walls=a:delete t.walls}if(!n){const e=Jp(r.length,[...this._draftSegmentCms,this._closingWallCm??void 0],this._drawWallCm,ll),i=e[0];if(null!=i){this._cfgEpoch++;const s=this._openCuts(),n=this._spaceModel();if(!n)return;let o=Nl(t.walls,n.rooms,c.id,i,this._wallKeyPitch,s,iv);for(const t of dc(n.rooms,o,s,this._wallKeyPitch,this._cellCm,this._gridPitch,iv)){if(t.roomId!==c.id||"outer"!==t.kind)continue;const i=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],s=r.findIndex((t,e)=>{const s=r[(e+1)%r.length];return Ls(i,[t[0],t[1],s[0],s[1]])<=.02*this._gridPitch});s>=0&&(o=Fl(o,t.a,t.b,e[s],this._wallKeyPitch,iv))}o=this._normalizeWalls(o,s),o.length?t.walls=o:delete t.walls}}const h=this._commitPhysicalGeometry(this._t(n?"history.split_room":"history.add_room"),i);this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._pendingSplit=null,this._splitSel=null;const d=this._areaSel;if(this._areaSel="",this._nameSel="",this._roomDialog=!1,this._regSignature="",this._maybeRebuildDevices(),!h)return;let p=0;if(d){const t=iv,e={...this._layout};for(const i of this._devices){if(i.area!==d||i.space!==this._space)continue;if(p++,this._layout[i.id])continue;const s=this._defPos[i.id];s&&(e[i.id]={s:this._space,x:s.x/iv,y:s.y/t},this._dirtyPos.add(i.id))}this._layout=e,this._persistLayout()}const u=this._model.find(t=>t.id===this._space)?.rooms.length||0;this._showToast(d?this._t("toast.room_saved",{n:u,added:p}):this._t("toast.room_saved_no_area",{n:u}))}_cancelPath(){this._wallRepairDiagnostic=null,this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._clearPlanSnapHover(),this._roomDialog=!1,this._pendingSplit=null,this._wallFaceBatch=null,this._splitSel=null,this._mergeSel=null,this._mergeDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._clearOpeningPlacement(!0)}_resumeLastDraft(){const t=this._resumeDraftBySpace[this._space];if(!t)return;const e=this._spaceModel()?.room_drafts.find(e=>e.id===t);e?(this._activeDraftId=t,this._path=e.points.map(t=>[...t]),this._draftSegmentCms=this._adoptDraftCms(this._path,e.segments.map(t=>t.cm),e.id),this._clearPlanSnapHover()):delete this._resumeDraftBySpace[this._space]}_roomDialogCancel(){if(this._roomDialog=!1,this._roomEditId)return this._roomEditId=null,this._nameSel="",void(this._areaSel="");if(this._wallFaceBatch){const t=this._wallFaceBatch;return this._wallFaceBatch=null,this._path=t.activePath.map(t=>[...t]),this._draftSegmentCms=[...t.activeCms],this._activeDraftId=t.activeDraftId,this._nameSel="",this._areaSel="",void this.requestUpdate()}if(this._pendingSplit)return this._pendingSplit=null,void(this._splitSel=null);this._undoPoint()}get _freeAreas(){const t=new Set;for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area&&t.add(i.area);for(const e of this._wallFaceBatch?.decisions||[])e.create&&e.area&&t.add(e.area);return Object.values(this.hass?.areas||{}).filter(e=>!t.has(e.area_id)).sort((t,e)=>(t.name||"").localeCompare(e.name||""))}_openMarkerDialog(t){if(this._vacAllCamerasFor=null,this._vacAllCameraCache=null,t&&this._ackNewDevice(t.id),this._norm)if(t){const e=t.marker,i=Object.prototype.hasOwnProperty.call(e||{},"is_light"),s=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),n=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),o=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),a=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),r=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),l=ks(e?.glow_color),c=this._devicePresentation(t,!0).valueBadge,h=Wo(this._planHass,t,this._devices),d=jo(this._planHass,t,h);this._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:Bi(t.marker?.display),rippleColor:Rt(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:pp(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:a,originalTapAction:t.marker?.tap_action,tapHintAnnouncement:"",toggleEntity:e?.toggle_entity||"",toggleEntityTouched:!1,originalHasToggleEntity:r,originalToggleEntity:e?.toggle_entity,tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",controls:Zn(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:i,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:s,originalLightEntity:e?.light_entity,glowMode:null!=l?.bri?"fixed":l?"color":"auto",glowColor:l?.c||this._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(l?.bri??1))),glowColorDrafted:!!l,glowBrightnessDrafted:null!=l?.bri,glowTouched:!1,originalHasGlowColor:n&&(!!l||null===e?.glow_color),originalGlowColor:l||(null===e?.glow_color?null:void 0),valueBadgeEnabled:o?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||d,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:o,originalValueBadge:e?.value_badge,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:1.5,size:1,angle:0,tapAction:"info",tapActionTouched:!1,originalHasTapAction:!1,originalTapAction:void 0,tapHintAnnouncement:"",toggleEntity:"",toggleEntityTouched:!1,originalHasToggleEntity:!1,originalToggleEntity:void 0,tapTarget:"",tapConfirm:!1,runFilter:"",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,lightEntity:"",lightEntityTouched:!1,originalHasLightEntity:!1,originalLightEntity:void 0,glowMode:"auto",glowColor:this._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgePosition:"right",valueBadgeTouched:!1,originalHasValueBadge:!1,originalValueBadge:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};else this._showToast(this._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of Gi)for(const[i,s]of Object.entries(this.hass.states))i.startsWith(e+".")&&this._planEntityAvailable(i)&&t.push({value:i,label:s?.attributes?.friendly_name||i,sub:this._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=this._planHass,e=wo(this._markers),i=new Set(this._markers.filter(t=>t.removed).map(t=>t.binding)),s=new Set;for(const t of this._devices)t.id!==this._markerDialog?.devId&&("device"===t.bindingKind&&t.bindingRef&&s.add("device:"+t.bindingRef),"entity"===t.bindingKind&&t.bindingRef&&s.add("entity:"+t.bindingRef));const n=new Set;for(const t of this._devices)"device"===t.bindingKind&&t.name&&n.add(t.name.trim()+"|"+(t.area||""));const o=[];for(const e of Object.values(t.devices)){if("service"===e.entry_type)continue;const t="device:"+e.id;if(s.has(t))continue;const a=(e.name_by_user||e.name||e.id).trim();t!==this._markerDialog?.binding&&!i.has(t)&&n.has(a+"|"+(e.area_id||""))||o.push({value:t,label:a,sub:(e.model||this._t("marker.sub_device"))+("Group"===e.model?this._t("marker.sub_z2m_group"):"")})}const a=new Set(["group","template","derivative","min_max","threshold","integration","statistics","trend","utility_meter","tod","switch_as_x","schedule"]);for(const[n,r]of Object.entries(t.entities)){const l="entity:"+n;if(s.has(l))continue;if(ko(t,n,e)&&!i.has(l))continue;const c=a.has(r.platform),h="group"===r.platform;if(!c&&!h)continue;if(r.hidden&&!i.has(l))continue;const d=t.states[n];o.push({value:l,label:r.name||d?.attributes?.friendly_name||n,sub:n.split(".")[0]+" · "+("group"===r.platform?this._t("marker.sub_group"):this._t("marker.sub_helper"))})}if(this._markerDialog?.showEntities){const n=new Set(o.map(t=>t.value));for(const[a,r]of Object.entries(t.entities)){const l="entity:"+a;if(s.has(l)||n.has(l)||r.hidden&&!i.has(l))continue;const c=!!r.device_id&&e.devices.has(r.device_id);if(ko(t,a,e)&&!i.has(l)&&!c)continue;const h=t.states[a],d=r.name||h?.attributes?.friendly_name||a,p=r.device_id?t.devices[r.device_id]:null,u=p&&(p.name_by_user||p.name)||"";o.push({value:l,label:d,sub:a.split(".")[0]+" · "+this._t("marker.sub_entity")+(u?" · "+u:"")})}}const r=(this._markerDialog?.bindingFilter||"").toLowerCase().trim(),l=r?o.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(r)):o;return l.sort((t,e)=>t.label.localeCompare(e.label)),l.slice(0,200)}_physicalBodiesR(t=this._spaceModel()){if(!t)return[];const e=`${t.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===e)return this._physicalBodiesCache.all;const i=eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t));return this._physicalBodiesCache={key:e,...i},i.all}_rawPhysicalBodiesR(t=this._spaceModel()){if(!t)return[];this._physicalBodiesR(t);const e=this._physicalBodiesCache;return e?[...e.drafts,...e.partitions,...e.columns]:[]}_cleanFloor(t,e,i=this._spaceModel()){if(!i)return{floor:e,geom:null,path:"",area:rh([[[...e,e[0]]]])};const s=t.id||`#${i.rooms.indexOf(t)}`,n=`${i.id}|${this._cfgEpoch}|${s}`;if(!this._rszPreview){const t=Wf(this._cleanFloorCache,n);if(t.hit)return t.value}const o=e.map(t=>t[0]),a=e.map(t=>t[1]),r=[Math.min(...o),Math.min(...a),Math.max(...o),Math.max(...a)],l=this._physicalBodiesR(i).filter(t=>{const e=t.map(t=>t[0]),i=t.map(t=>t[1]);return Math.max(...e)>=r[0]&&Math.min(...e)<=r[2]&&Math.max(...i)>=r[1]&&Math.min(...i)<=r[3]}),c=l.length?ah(e,l):null,h={floor:e,geom:c,path:c?Jc(c):"",area:rh(c||[[[...e,e[0]]]])};return this._rszPreview||jf(this._cleanFloorCache,n,h,600),h}_autoIconForBinding(t){if("virtual"===t)return"mdi:map-marker";const[e,i]=t.split(":");if(!i)return"";const s=this._fullRegistryHass,n=this._bindingStatus(t),o="active"===n.kind?n.enabledEntityIds:n.allEntityIds;if("device"===e){const t=s.devices?.[i];if(!t)return"mdi:help-circle";const e=o;return e.some(t=>t.startsWith("lock."))?"mdi:lock":bo(s,t.name_by_user||t.name||"",t.model,e,this._iconRules)}if("entity"===e){const t=s.entities?.[i],e=this.hass.states?.[i],n=t?.name||e?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":bo(s,n,"",[i],this._iconRules)}return""}_allRoomsFlat(){const t=[];for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area?t.push({value:e.id+"#"+i.area,label:(e.title||e.id)+" · "+i.name}):i.id&&t.push({value:e.id+"#@"+i.id,label:(e.title||e.id)+" · "+i.name+" · "+this._t("marker.subarea")});return t}_errText(t){if(!t)return this._t("err.unknown");if("string"==typeof t)return t;if("invalid_passage_fields"===t.code){const e=String(t.message||t.error||"").match(/space=([^;]*);\s*opening=([^;]*);\s*fields=([^;]*)/);if(e){const t=this._serverCfg?.spaces?.find(t=>String(t.id)===e[1]),i={contact:"opening.contact_label",lock:"opening.lock_label",invert:"opening.invert",flip_h:"opening.flip_h",flip_v:"opening.flip_v"},s=e[3].split(",").filter(Boolean).map(t=>i[t]?this._t(i[t]):t).join(", ");return this._t("opening.invalid_passage_fields",{room:t?.title||e[1],fields:s})}}if("invalid_partition_opening_jamb_margin"===t.code){const e=String(t.message||t.error||"").match(/margin_cm=([^;]*)/),i=e?Number(e[1]):NaN;if(Number.isFinite(i))return this._t("opening.partition_jamb_margin",{distance:li(i,this._imperial)})}if(t.message)return t.message;if(t.error)return t.error;if(null!=t.code)return this._t("err.code",{code:t.code});try{return JSON.stringify(t)}catch{return String(t)}}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,i=this._t(t);if(i!==t)return i}return this._errText(t)}async _pickMarkerFiles(t){const e=t.target,i=e.files?[...e.files]:[];if(e.value="",!i.length||!this._markerDialog)return;const s=this._markerDialog.uploadId||this._markerDialog.devId||"new",n=[];for(const t of i)try{const e=new FormData;e.append("marker_id",s),e.append("file",t,t.name);const i=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error){const t={too_large:this._t("err.too_large",{mb:o.max_mb||50}),bad_ext:this._t("err.bad_ext"),unauthorized:this._t("err.unauthorized")};throw new Error(t[o.error]||o.error||"HTTP "+i.status)}n.push({name:o.name||t.name,url:o.url})}catch(e){this._showToast(this._t("toast.file_failed",{name:t.name,err:this._errText(e)}))}n.length&&this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:[...this._markerDialog.pdfs,...n]},this._showToast(this._t("toast.files_attached",{n:n.length})))}_removeMarkerPdf(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:this._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.lightEntityTouched?t.lightEntity&&(e.light_entity=t.lightEntity):t.originalHasLightEntity&&(e.light_entity=t.originalLightEntity??null),t.glowTouched){if("auto"!==t.glowMode){const i={c:Rt(t.glowColor,this._fillColors.glow_light.c)};"fixed"===t.glowMode&&(i.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=i}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}_markerTapActionFields(t){return t.tapActionTouched?{tap_action:t.tapAction||null}:t.originalHasTapAction?{tap_action:t.originalTapAction??null}:{}}_markerToggleEntityFields(t){return(e={touched:t.toggleEntityTouched,originalHas:t.originalHasToggleEntity,original:t.originalToggleEntity,value:t.toggleEntity}).touched?e.value?{toggle_entity:e.value}:{}:e.originalHas?{toggle_entity:e.original??null}:{};var e}async _saveMarker(){const t=this._markerDialog;if(!t||t.busy)return;const e=this._effectiveMarkerTapAction(t);if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return;if("virtual"===t.binding&&!t.name.trim())return void this._showToast(this._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this._showToast(this._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this._showToast(this._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this._bindingStatus(t.binding),i=t.devId?this._markers.find(e=>e.id===t.devId):null,s=!i||i.binding!==t.binding;if("active"!==e.kind&&s)return void this._showToast(this._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===i?.hidden&&!t.hideFromPlan)return this._markerDialog={...t,hideFromPlan:!0},void this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const i=this._serverCfg;if(!i)return;const s=i.markers||[],n=qs(t.room);let o=n?.space||null;const a=n?.area||null,r=n?.roomId||null,l=Fi(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),c=t.devId,h=c?this._devices.find(t=>t.id===c):null,d=n?.space||h?.space||null,p=d?this._spaceModelById(d):this._spaceModel();if(!p)return;const u=p.id;"virtual"!==t.binding||o||(o=u),this._markerDialog={...t,busy:!0};try{const n="virtual"===t.binding?[]:s.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=n.length>0,_=Zn(t.binding,t.controls,this._bindingEntities(t.binding)),m=s.find(t=>t.id===l||t.id===c)?.vacuum||null,g={id:l,vacuum:m,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===e&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:_.length?_:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=qf(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};("virtual"===t.binding||t.room)&&(g.space=o,g.area=a,g.room_id=r);const f=h?.marker?.room_id??null,v=!!t.room&&null!=h&&(h.space!==o||h.area!==a||f!==r);let y=!1;const b=t.uploadId||c;if(b&&b!==l&&g.pdfs?.length)try{const t=await this.hass.callWS({type:"houseplan/files/migrate",from_id:b,to_id:l}),e=t?.mapping||{};g.pdfs=function(t,e,i,s){if(!e||!i||e===i)return t;const n="/files/"+e+"/",o="/files/"+i+"/";return t.map(t=>{if(!t.url.includes(n))return t;const e=t.url.split(n)[1]||"",[i,a]=[e.split("?")[0],e.includes("?")?"?"+e.split("?")[1]:""];if(s){const e=s[decodeURIComponent(i)]??s[i];return e?{...t,url:t.url.split(n+i)[0]+o+encodeURIComponent(e)+a}:t}return{...t,url:t.url.split(n).join(o)}})}(g.pdfs,b,l,e),y=Object.keys(e).length>0}catch(t){this._showToast(this._t("toast.files_migrate_failed",{err:this._errText(t)}))}i.markers=s,c&&c!==l&&(i.markers=function(t,e,i){if(!e||!i||e===i)return[...t];const s=`marker:${e}`,n=`marker:${i}`;return t.map(t=>{const e=Array.isArray(t.controls)?t.controls.map(t=>t===s?n:t):t.controls,i="derived_marker_state"===t.value_badge?.source?.kind&&t.value_badge.source.ref===s?{...t.value_badge,source:{...t.value_badge.source,ref:n}}:t.value_badge;return e===t.controls&&i===t.value_badge?t:{...t,controls:e,value_badge:i}})}(i.markers,c,l)),c&&c!==l&&"derived_marker_state"===g.value_badge?.source?.kind&&g.value_badge.source.ref===`marker:${c}`&&(g.value_badge.source={kind:"derived_marker_state",ref:`marker:${l}`}),i.markers=i.markers.filter(t=>t.id!==l&&t.id!==c&&("virtual"===g.binding||t.binding!==g.binding)),i.markers.push(g);let w=null;const k=c?this._layout[c]:null,x=k?{s:k.s||h?.space||this._space,x:k.x,y:k.y}:c&&h&&this._defPos[c]?this._normPos(h.space,this._defPos[c].x,this._defPos[c].y):null;if(!d&&x&&x.s===u)l===c&&this._layout[l]&&!v||(w={s:x.s,x:x.x,y:x.y},this._layout={...this._layout,[l]:w});else if(d||!this._layout[l]||v){let t=p.vb[0]+p.vb[2]/2,e=p.vb[1]+p.vb[3]/2;const i=r?p.rooms.find(t=>t.id===r):a?p.rooms.find(t=>t.area===a):void 0;i&&([t,e]=this._roomCenter(i)),w=this._normPos(u,t,e),this._layout={...this._layout,[l]:w}}if(await this._saveConfigNow(),w){const t=ol(w);this._layout={...this._layout,[l]:t},this._noteLayoutRev(await this.hass.callWS({type:"houseplan/layout/update",device_id:l,pos:t}))}const $=new Set(n);c&&c!==l&&$.add(c),$.delete(l);for(const t of $)delete this._layout[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{});y&&b&&await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:b}).catch(()=>{}),this._markerDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_saved"))}catch(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteMarker(){const t=this._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this._devices.find(e=>e.id===t.devId):null;if(!e)return;const i=t.name||this._t("device.fallback");if(!confirm(this._t("confirm.remove_marker",{name:i})))return;const s=this._serverCfg;s.markers=s.markers||[];const n=s.markers,o="virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"";if(!o)return;const a=function(t,e,i,s){const n=new Set([e]),o=t.filter(t=>{const o=t.id===e||!s&&t.binding===i;return o&&n.add(t.id),!o});return{markers:s?o:[...o,{id:e,binding:i,removed:!0,hidden:!0}],cleanupIds:n}}(s.markers,e.id,o,"virtual"===e.bindingKind);var r,l;s.markers=(r=a.markers,l=a.cleanupIds,r.map(t=>{if(!Array.isArray(t.controls))return t;const e=t.controls.filter(t=>!("string"==typeof t&&t.startsWith("marker:")&&l.has(t.slice(7))));return e.length===t.controls.length?t:{...t,controls:e.length?e:null}}));const c=a.cleanupIds;this._markerDialog={...t,busy:!0};try{await this._saveConfigNow();for(const t of c){delete this._layout[t],delete this._defPos[t],this._dirtyPos.delete(t),this._sentPos.delete(t);const e=this._activityRt.get(t);e&&clearTimeout(e.timer),this._activityRt.delete(t),this._vacRt.delete(t),delete this._vacSrvTrails[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{}),await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this._markerDialog=null,this._infoCard?.id===e.id&&this._closeInfoCard(),this._selId===e.id&&(this._selId=null),this._drag?.id===e.id&&(this._drag=null),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_removed"))}catch(t){this._serverCfg===s&&(s.markers=n),this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}_normPos(t,e,i){return{s:t,x:e/iv,y:i/iv}}_openSpaceDialog(t,e){if(this._serverStorage&&this._serverCfg)if("edit"===t){const i=this._serverCfg.spaces.find(t=>t.id===e);if(!i)return;const s=cs(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?rs(i.settings.custom_fill):null,o="none"===s.fill?{...n||as,a:0}:n;this._spaceDialog={mode:t,spaceId:e,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:s.showBorders,showNames:s.showNames,zeroWallStyle:d_(i),displayTouched:!0,hideDecor:s.hideDecor,hideOpenings:s.hideOpenings,roomColor:s.color,roomOpacity:s.opacity,fillMode:"none"===s.fill?"custom":s.fill,customFill:o,glowEnabled:s.glow,bgColor:s.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:$r({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:s.tempMin,tempMax:s.tempMax,showLqi:s.showLqi??this._config?.show_signal??!0,cardFontScale:s.cardFontScale,labelTemp:s.labelTemp,labelHum:s.labelHum,labelLqi:s.labelLqi,labelLight:s.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:fh(Number(i.cell_cm)>0?Number(i.cell_cm):5,this._imperial),cellCmTouched:!1,busy:!1}}else this._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...Sd(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ns,roomOpacity:os,fillMode:"custom",customFill:{...as,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:gh(this._imperial),cellCmInput:fh(gh(this._imperial),this._imperial),cellCmTouched:!1,busy:!1};else this._showToast(this._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,i=e.files?.[0];if(!i||!this._spaceDialog)return;const s={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[i.type]||(i.name.toLowerCase().endsWith(".svg")?"svg":"");if(!s)return void this._showToast(this._t("toast.plan_formats"));const n=new Uint8Array(await i.arrayBuffer());let o="";for(let t=0;t{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:1.414),e.onerror=()=>t(1.414),e.src=r});URL.revokeObjectURL(r),this._spaceDialog={...this._spaceDialog,planFile:{ext:s,b64:a,aspect:l,name:i.name}}}_useServerPlan(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this._display(t);if(e){const i=await new Promise(t=>{const i=new Image;i.onload=()=>t(i.naturalWidth&&i.naturalHeight?i.naturalWidth/i.naturalHeight:0),i.onerror=()=>t(0),i.src=e}),s=this._spaceDialog;return s&&s.planUrl===t&&Number.isFinite(i)&&i>0?(this._spaceDialog={...s,savedAspect:i},i):0}if(await new Promise(t=>setTimeout(t,150)),this._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this._t("confirm.delete_plan",{name:t})))try{await this.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this._spaceDialog;e?.saved&&(this._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this._showToast(this._t("toast.plan_delete_failed",{err:this._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return W`
${this._t("space.loading")}
`;const e=t.saved||[];if(!e.length)return W`
${this._t("space.no_saved")}
`;return W`
${e.map(e=>W`
@@ -5427,7 +5427,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4
`)} -
`}async _saveSpaceDialog(){const t=this._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this._showToast(this._t("toast.plan_required"));const e="create"===t.mode&&0===(this._serverCfg?.spaces.length||0);this._spaceDialog={...t,busy:!0};try{const i="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let s=null;if("file"===t.source&&t.planFile){s={url:(await this.hass.callWS({type:"houseplan/plan/set",space_id:i,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let n=t.savedAspect||null;!s&&"file"===t.source&&t.planUrl&&!n&&this._aspectJob&&(n=await this._aspectJob||null);const o=this._serverCfg;let a;if("create"===t.mode)a={id:i,title:t.title.trim(),plan_url:null,view_box:[0,0,1,1],rooms:[]},o.spaces.push(a);else{if(a=o.spaces.find(t=>t.id===i),!a)throw new Error("space "+i+" is gone from the config");a.title=t.title.trim()}s?(a.plan_url=s.url,a.plan_aspect=s.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==a.plan_url&&(a.plan_url=t.planUrl,a.plan_aspect=n),"draw"===t.source&&(a.plan_url=null,a.plan_aspect=null,delete a.plan_x,delete a.plan_y,delete a.plan_scale,delete a.plan_scale_x,delete a.plan_scale_y,delete a.plan_angle),a.settings={...a.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):20,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):25,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},a.zero_wall_style=t.zeroWallStyle,a.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(Lf,t.cellCm)):5,await this._saveConfigNow(),this._spaceDialog=null,"create"===t.mode&&this._commitSpace(a.id),this._regSignature="",this._maybeRebuildDevices(),this._importQueue.length?this._openNextImport():e||this._importTotal>0?(this._importTotal=0,this._commitSpace(this._serverCfg.spaces[0]?.id||this._space),this._setMode("plan"),this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._showToast(this._t(e&&!this._importTotal?"toast.space_added_onboard":"import.done"))):(this._showToast("create"===t.mode?this._t("toast.space_added"):this._t("toast.space_saved")),"create"===t.mode&&("plan"!==this._mode?this._setMode("plan"):(this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._saveNav())))}catch(t){this._spaceDialog&&(this._spaceDialog={...this._spaceDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteSpace(){const t=this._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this._serverCfg;if(!e)return;const i=e.spaces.find(e=>e.id===t.spaceId),s=ag(e,this._layout||{},t.spaceId||""),n=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(!s.count||n){if(confirm(this._t("confirm.delete_space",{title:i.title}))){this._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._persistLayout.pending()&&this._persistLayout.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev}),[i,s]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._adoptStructuralResponses(i,s),this._cfgRev=e?.config_rev??this._cfgRev,this._layoutRev=e?.layout_rev??this._layoutRev,this._spaceDialog=null,this._space===t.spaceId&&this._commitSpace(this._serverCfg.spaces[0]?.id||""),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.space_deleted"))}catch(e){"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]);const i=this._serverCfg;if(this._spaceDialog&&i){const e=ag(i,this._layout||{},t.spaceId||""),s=1===i.spaces.length&&i.spaces[0]?.id===t.spaceId;this._spaceDialog={...this._spaceDialog,busy:!1,deleteBlockers:s?0:e.count}}this._showToast(this._t("toast.delete_failed",{err:this._errText(e)}))}}}else this._spaceDialog={...t,deleteBlockers:s.count}}async _saveConfigNow(){this._cfgEpoch++;try{await this._writeConfig()}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this._reloadConfigOnly(),t}}_startImport(){const t=this._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this._importDialog=null,e.length?(this._importQueue=e,this._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this._importQueue.shift();void 0!==t&&(this._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...Sd(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ns,roomOpacity:os,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:gh(this._imperial),cellCmInput:fh(gh(this._imperial),this._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this._spaceDialog=null,this._importQueue.length?this._openNextImport():this._importTotal>0&&this._model.length&&(this._importTotal=0,this._commitSpace(this._serverCfg.spaces[0]?.id||this._space),this._setMode("plan"),this._showToast(this._t("import.done")))}_renderImportDialog(){const t=this._importDialog,e=t.floors.filter(t=>t.checked).length;return W``}async _saveSpaceDialog(){const t=this._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this._showToast(this._t("toast.plan_required"));const e="create"===t.mode&&0===(this._serverCfg?.spaces.length||0);this._spaceDialog={...t,busy:!0};try{const i="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let s=null;if("file"===t.source&&t.planFile){s={url:(await this.hass.callWS({type:"houseplan/plan/set",space_id:i,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let n=t.savedAspect||null;!s&&"file"===t.source&&t.planUrl&&!n&&this._aspectJob&&(n=await this._aspectJob||null);const o=this._serverCfg;let a;if("create"===t.mode)a={id:i,title:t.title.trim(),plan_url:null,view_box:[0,0,1,1],rooms:[]},o.spaces.push(a);else{if(a=o.spaces.find(t=>t.id===i),!a)throw new Error("space "+i+" is gone from the config");a.title=t.title.trim()}s?(a.plan_url=s.url,a.plan_aspect=s.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==a.plan_url&&(a.plan_url=t.planUrl,a.plan_aspect=n),"draw"===t.source&&(a.plan_url=null,a.plan_aspect=null,delete a.plan_x,delete a.plan_y,delete a.plan_scale,delete a.plan_scale_x,delete a.plan_scale_y,delete a.plan_angle),a.settings={...a.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):20,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):25,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},a.zero_wall_style=t.zeroWallStyle,a.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(Hf,t.cellCm)):5,await this._saveConfigNow(),this._spaceDialog=null,"create"===t.mode&&this._commitSpace(a.id),this._regSignature="",this._maybeRebuildDevices(),this._importQueue.length?this._openNextImport():e||this._importTotal>0?(this._importTotal=0,this._commitSpace(this._serverCfg.spaces[0]?.id||this._space),this._setMode("plan"),this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._showToast(this._t(e&&!this._importTotal?"toast.space_added_onboard":"import.done"))):(this._showToast("create"===t.mode?this._t("toast.space_added"):this._t("toast.space_saved")),"create"===t.mode&&("plan"!==this._mode?this._setMode("plan"):(this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._saveNav())))}catch(t){this._spaceDialog&&(this._spaceDialog={...this._spaceDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteSpace(){const t=this._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this._serverCfg;if(!e)return;const i=e.spaces.find(e=>e.id===t.spaceId),s=rg(e,this._layout||{},t.spaceId||""),n=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(!s.count||n){if(confirm(this._t("confirm.delete_space",{title:i.title}))){this._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._persistLayout.pending()&&this._persistLayout.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev}),[i,s]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._adoptStructuralResponses(i,s),this._cfgRev=e?.config_rev??this._cfgRev,this._layoutRev=e?.layout_rev??this._layoutRev,this._spaceDialog=null,this._space===t.spaceId&&this._commitSpace(this._serverCfg.spaces[0]?.id||""),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.space_deleted"))}catch(e){"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]);const i=this._serverCfg;if(this._spaceDialog&&i){const e=rg(i,this._layout||{},t.spaceId||""),s=1===i.spaces.length&&i.spaces[0]?.id===t.spaceId;this._spaceDialog={...this._spaceDialog,busy:!1,deleteBlockers:s?0:e.count}}this._showToast(this._t("toast.delete_failed",{err:this._errText(e)}))}}}else this._spaceDialog={...t,deleteBlockers:s.count}}async _saveConfigNow(){this._cfgEpoch++;try{await this._writeConfig()}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this._reloadConfigOnly(),t}}_startImport(){const t=this._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this._importDialog=null,e.length?(this._importQueue=e,this._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this._importQueue.shift();void 0!==t&&(this._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...Sd(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ns,roomOpacity:os,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:gh(this._imperial),cellCmInput:fh(gh(this._imperial),this._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this._spaceDialog=null,this._importQueue.length?this._openNextImport():this._importTotal>0&&this._model.length&&(this._importTotal=0,this._commitSpace(this._serverCfg.spaces[0]?.id||this._space),this._setMode("plan"),this._showToast(this._t("import.done")))}_renderImportDialog(){const t=this._importDialog,e=t.floors.filter(t=>t.checked).length;return W`this._importDialog=null}>
${this._t("import.hint")}
@@ -5447,7 +5447,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t("import.start",{n:e})}
-
`}_sunGlobal(){const t=this._settingsDialog;return t?{...this._settings,north_deg:t.northDeg??void 0,bg_mode:t.bgMode,sun_rays:t.sunRays}:this._settings}_sunSpace(){const t=this._spaceDialog,e=this._curSpaceCfg?.settings||{};return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,north_deg:t.northDeg??void 0,bg_mode:t.bgMode??void 0,sun_rays:t.sunRays??void 0}:e}_effNorth(){return $r(this._sunGlobal(),this._sunSpace())}_effBgMode(){return Sr(this._sunGlobal(),this._sunSpace())}_dayCycleState(t=new Date){return(this._modeTransitionVisual?.viewWeight??("view"===this._mode?1:0))<=0||"daynight"!==this._effBgMode()?null:_r(this._renderPlanHass,t)}_syncDayCycleClock(){const t=this._dayCycleState();this._dayCycleClockKey=t?mr(t):"";const e="clock"===t?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;e&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!e&&this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(t){"hidden"!==t.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_effSunRays(){return Mr(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?Cr(this._renderPlanHass):null}_renderSunRays(t){const e=j``,i=this._modeTransitionVisual?.viewWeight??0;if(this._editing&&i<=0||!this._effSunRays())return this._sunFadeReset(),e;const s=this._effNorth(),n=null!==s?Cr(this._renderPlanHass):null;if(!n||n.elevation<=0)return this._sunFadeReset(),e;if(o=n.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return e;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const a=this._zeroWalls(),r=a.barriers.map(t=>t.join(",")).join(";"),l=`${t.id}|${n.azimuth}|${n.elevation}|${s}|${this._cfgEpoch}|${a.style}|${r}`;if(!this._sunRaysCache||this._sunRaysCache.key!==l){const e=t.rooms.map(t=>({id:t.id||"",poly:hi(t)})).filter(t=>!!t.id&&!!t.poly),i=this._openingsR.filter(t=>"window"===t.type&&"partition"!==t.host?.kind).map(t=>({id:t.id,x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),o=this._spaceWalls,r=this._openCuts(),c=this._openingWallIndexFor(t,r).value,h={},d={},p=this._wallUnionGeometry()?.roomGeom;if(o.length){for(const i of e){const e=fc(t.rooms,i.id,o,r,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,p);e&&(h[i.id]=e)}for(const t of i){const e=Lc(c,{x:t.x,y:t.y,angle:t.angle,length:t.length});e.cm>0&&(d[t.id]=gl(e.cm,this._cellCm,this._gridPitch))}}let u=kr(e,i,n.azimuth,n.elevation,s,o.length?h:void 0,o.length?d:void 0);const _=[...this._physicalBodiesR(t),...a.barriers.map(t=>[[t[0],t[1]],[t[2],t[3]]])];_.length&&(u=u.map(t=>{const e=function(t,e,i){return i>0?t.map(t=>function(t){const e=[...t].sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(e.length<=2)return e;const i=(t,e,i)=>(e[0]-t[0])*(i[1]-t[1])-(e[1]-t[1])*(i[0]-t[0]),s=[];for(const t of e){for(;s.length>=2&&i(s[s.length-2],s[s.length-1],t)<=0;)s.pop();s.push(t)}const n=[];for(let t=e.length-1;t>=0;t--){const s=e[t];for(;n.length>=2&&i(n[n.length-2],n[n.length-1],s)<=0;)n.pop();n.push(s)}return s.slice(0,-1).concat(n.slice(0,-1))}([...t,...t.map(t=>[t[0]+e[0]*i,t[1]+e[1]*i])])).filter(t=>t.length>=3):t}(_,t.dir,t.len),i=t.polys.map(t=>ah(t,e));return{...t,paths:i.map(Jc).filter(Boolean),polys:i.flatMap(ch)}}).filter(t=>t.paths?.length||t.polys.length)),this._sunRaysCache={key:l,rays:u,rims:u.map(t=>function(t,e=1e-4){const[i,s]=t.dir,n=-s,o=i,a=[];for(const r of[t.a,t.b]){const l=[];for(const a of t.polys)for(let t=0;te)continue;if(Math.abs((h[0]-r[0])*n+(h[1]-r[1])*o)>e)continue;const d=(c[0]-r[0])*i+(c[1]-r[1])*s,p=(h[0]-r[0])*i+(h[1]-r[1])*s;Math.abs(p-d)<=e||l.push(dt[0]-e[0]);const c=[];for(const t of l){const i=c[c.length-1];i&&t[0]<=i[1]+e?i[1]=Math.max(i[1],t[1]):c.push([t[0],t[1]])}for(const[t,e]of c)a.push([[r[0]+i*t,r[1]+s*t],[r[0]+i*e,r[1]+s*e]])}return a}(t))}}const c=this._sunRaysCache.rays,h=this._sunRaysCache.rims;if(!c.length)return e;const d=(p=function(t){const e=Math.min(90,Math.max(-90,Number(t)||0));let i=gr[gr.length-1][1];for(let t=1;t +
`}_sunGlobal(){const t=this._settingsDialog;return t?{...this._settings,north_deg:t.northDeg??void 0,bg_mode:t.bgMode,sun_rays:t.sunRays}:this._settings}_sunSpace(){const t=this._spaceDialog,e=this._curSpaceCfg?.settings||{};return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,north_deg:t.northDeg??void 0,bg_mode:t.bgMode??void 0,sun_rays:t.sunRays??void 0}:e}_effNorth(){return $r(this._sunGlobal(),this._sunSpace())}_effBgMode(){return Sr(this._sunGlobal(),this._sunSpace())}_dayCycleState(t=new Date){return(this._modeTransitionVisual?.viewWeight??("view"===this._mode?1:0))<=0||"daynight"!==this._effBgMode()?null:_r(this._renderPlanHass,t)}_syncDayCycleClock(){const t=this._dayCycleState();this._dayCycleClockKey=t?mr(t):"";const e="clock"===t?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;e&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!e&&this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(t){"hidden"!==t.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_effSunRays(){return Mr(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?Cr(this._renderPlanHass):null}_renderSunRays(t){const e=j``,i=this._modeTransitionVisual?.viewWeight??0;if(this._editing&&i<=0||!this._effSunRays())return this._sunFadeReset(),e;const s=this._effNorth(),n=null!==s?Cr(this._renderPlanHass):null;if(!n||n.elevation<=0)return this._sunFadeReset(),e;if(o=n.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return e;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const a=this._zeroWalls(),r=a.barriers.map(t=>t.join(",")).join(";"),l=`${t.id}|${n.azimuth}|${n.elevation}|${s}|${this._cfgEpoch}|${a.style}|${r}`;if(!this._sunRaysCache||this._sunRaysCache.key!==l){const e=t.rooms.map(t=>({id:t.id||"",poly:hi(t)})).filter(t=>!!t.id&&!!t.poly),i=this._openingsR.filter(t=>"window"===t.type&&"partition"!==t.host?.kind).map(t=>({id:t.id,x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),o=this._spaceWalls,r=this._openCuts(),c=this._openingWallIndexFor(t,r).value,h={},d={},p=this._wallUnionGeometry()?.roomGeom;if(o.length){for(const i of e){const e=fc(t.rooms,i.id,o,r,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,p);e&&(h[i.id]=e)}for(const t of i){const e=Lc(c,{x:t.x,y:t.y,angle:t.angle,length:t.length});e.cm>0&&(d[t.id]=gl(e.cm,this._cellCm,this._gridPitch))}}let u=kr(e,i,n.azimuth,n.elevation,s,o.length?h:void 0,o.length?d:void 0);const _=[...this._physicalBodiesR(t),...a.barriers.map(t=>[[t[0],t[1]],[t[2],t[3]]])];_.length&&(u=u.map(t=>{const e=function(t,e,i){return i>0?t.map(t=>function(t){const e=[...t].sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(e.length<=2)return e;const i=(t,e,i)=>(e[0]-t[0])*(i[1]-t[1])-(e[1]-t[1])*(i[0]-t[0]),s=[];for(const t of e){for(;s.length>=2&&i(s[s.length-2],s[s.length-1],t)<=0;)s.pop();s.push(t)}const n=[];for(let t=e.length-1;t>=0;t--){const s=e[t];for(;n.length>=2&&i(n[n.length-2],n[n.length-1],s)<=0;)n.pop();n.push(s)}return s.slice(0,-1).concat(n.slice(0,-1))}([...t,...t.map(t=>[t[0]+e[0]*i,t[1]+e[1]*i])])).filter(t=>t.length>=3):t}(_,t.dir,t.len),i=t.polys.map(t=>ah(t,e));return{...t,paths:i.map(Jc).filter(Boolean),polys:i.flatMap(ch)}}).filter(t=>t.paths?.length||t.polys.length)),this._sunRaysCache={key:l,rays:u,rims:u.map(t=>function(t,e=1e-4){const[i,s]=t.dir,n=-s,o=i,a=[];for(const r of[t.a,t.b]){const l=[];for(const a of t.polys)for(let t=0;te)continue;if(Math.abs((h[0]-r[0])*n+(h[1]-r[1])*o)>e)continue;const d=(c[0]-r[0])*i+(c[1]-r[1])*s,p=(h[0]-r[0])*i+(h[1]-r[1])*s;Math.abs(p-d)<=e||l.push(dt[0]-e[0]);const c=[];for(const t of l){const i=c[c.length-1];i&&t[0]<=i[1]+e?i[1]=Math.max(i[1],t[1]):c.push([t[0],t[1]])}for(const[t,e]of c)a.push([[r[0]+i*t,r[1]+s*t],[r[0]+i*e,r[1]+s*e]])}return a}(t))}}const c=this._sunRaysCache.rays,h=this._sunRaysCache.rims;if(!c.length)return e;const d=(p=function(t){const e=Math.min(90,Math.max(-90,Number(t)||0));let i=gr[gr.length-1][1];for(let t=1;t ${c.map((t,e)=>{const i=(t.a[0]+t.b[0])/2,s=(t.a[1]+t.b[1])/2,n=i+t.normal[0]*t.depth,o=s+t.normal[1]*t.depth;return j` ${u.map(([t,e])=>j`${this._t("gs.north_letter")} ${null===t?"—":t+"°"} - `}_stageBg(t){const e=this._settingsDialog,i=this._spaceDialog,s=e?e.bgColor||"":hs(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":t.bgColor||"")||s}_stageBgHex(){const t=this._stageEl;if(t){const e=getComputedStyle(t).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(e)return"#"+e.slice(1,4).map(t=>(+t).toString(16).padStart(2,"0")).join("")}return"#111111"}_preflightDiagnostics(t,e){const i=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:Ff,checkedAt:(new Date).toISOString(),preflightFingerprint:t.fingerprint,failures:t.failures.map(t=>({spaceId:t.spaceId,displayName:t.displayName,reason:t.reason,detail:t.detail??null,spaceGeometryFingerprint:i.has(t.spaceId)?lg(i.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this._reportedPreflightFingerprint||(this._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==Ff}async _copyPreflightDiagnostics(){const t=this._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this._preflightClipboardFallback=null,this._showToast(this._t("gs.preflight_copied"))}catch{this._preflightClipboardFallback=e}}_checkOptimizeGeometry(t){return _g(t,{fallbackSpaceName:t=>this._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometry(t,e){return function(t,e,i={}){const s=(Array.isArray(t?.spaces)?t.spaces:[]).find(t=>String(t?.id||"")===String(e||"")),n=lg(s);if(!s)return{spaceId:String(e||""),displayName:"",status:"failed",reason:"prepare-exception",fingerprint:n,ok:!1};const o=_g({...t,spaces:[s]},{...i,fingerprint:()=>n}).spaces[0]||{spaceId:String(e||""),displayName:"",status:"failed",reason:"prepare-exception"};return{...o,fingerprint:n,ok:"failed"!==o.status}}(t,e,{fallbackSpaceName:t=>this._t("gs.align_preflight_space",{n:String(t)})})}_optimizeReferenceContext(t){const e=this._haRegistry,i=this._fullRegistryHass,s={},n=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,i]of Object.entries(e.devices||{}))s[t]=n(i?.name_by_user,i?.name,i?.model);for(const[t,i]of Object.entries(e.entities||{}))s[`lg_${t}`]=n(this.hass?.states?.[t]?.attributes?.friendly_name,i?.name,i?.original_name);for(const t of this._devices)s[t.id]=n(t.name,s[t.id]);for(const t of this._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),o=e>0?t.binding.slice(0,e):"",a=e>0?t.binding.slice(e+1):"",r="device"===o?i?.devices?.[a]:"entity"===o?i?.entities?.[a]:null;s[t.id]=n(t.name,"device"===o?r?.name_by_user:null,r?.name,"entity"===o?this.hass?.states?.[a]?.attributes?.friendly_name:null,s[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this._devices.filter(t=>!t.virtual&&!!t.area).map(t=>[t.id,t.area])),ownerRoster:{authoritative:e.authoritative,deviceIds:Object.keys(e.devices||{}),entityIds:[...new Set([...Object.keys(e.entities||{}),...Object.keys(this.hass?.states||{})])],names:s},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this._norm||!this._serverCfg)return;const e=this._serverCfg.spaces||[];let i;try{i=og(this._serverCfg,this._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const s=i.changed?this._checkOptimizeGeometry(i.config):null;s&&this._reportPreflightFailure(s,i.config);const n=Math.ceil(10*i.report.maxShiftCm)/10,o=e.find(t=>null!=t?.id&&String(t.id)===i.report.maxSpace),a=e.length>1&&o?String(o.title||o.id):"";this._preflightClipboardFallback=null,this._alignDialog={report:i.report,config:i.config,layout:i.layout,cm:n,where:a,preflight:s,changed:i.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this._alignDialog;if(!t||t.busy||!this._serverCfg||!t.changed||!t.preflight?.ok)return;const e=bd(t.config);if(t.preflight.fingerprint!==e){const e=this._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this._alignDialog={...t,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/plan/optimize",config:t.config,layout:t.layout,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});this._serverCfg=t.config,this._layout=t.layout,this._geometryHistory.clear(),this._cfgRev=e?.config_rev??this._cfgRev+1,this._layoutRev=e?.layout_rev??this._layoutRev+1,this._canOptimizeUndo=!!e?.can_undo,this._undoKind=e?.can_undo?"optimize":null,this._dirtyPos.clear(),this._sentPos.clear(),this._cfgEpoch++,this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._cacheSnapshot(),this._alignDialog=null,this._preflightClipboardFallback=null,this.requestUpdate(),this._showToast(this._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.coordsCanonicalized+t.report.latticeCoordinatesCanonicalized+t.report.wallsMerged+t.report.spansMerged+t.report.partitionsMerged+t.report.partitionsReconciled+t.report.openingsRehosted+t.report.wallsStraightened),r:String(t.report.spaceRefsRemapped+t.report.roomRefsRemapped+t.report.positionsRemapped+t.report.markersDetached+t.report.orphanRoomLabelsRemoved+t.report.orphanDevicePositionsRemoved+t.report.orphanGroupPositionsRemoved)}))}catch(t){if(this._alignDialog&&(this._alignDialog={...this._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this._showToast(this._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _undoPlanOptimization(){if(!this._canOptimizeUndo||this._optimizeUndoBusy)return;const t=this._undoKind;this._clearGeometryGesture(),this._optimizeUndoBusy=!0,this.requestUpdate();try{await this.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});const[e,i]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._serverCfg=e?.config||this._serverCfg,this._cfgRev=e?.rev??this._cfgRev,this._layout=i?.layout||this._layout,this._geometryHistory.clear(),this._layoutRev=i?.rev??this._layoutRev,this._canOptimizeUndo=!1,this._undoKind=null,this._cfgEpoch++,this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._cacheSnapshot(),this.requestUpdate(),this._showToast(this._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this._canOptimizeUndo=!1,this._undoKind=null,this._showToast(this._t("toast.error",{err:this._errText(t)}))}finally{this._optimizeUndoBusy=!1,this.requestUpdate()}}async _runBackupExport(){const t=this._backupExportDialog;if(t&&!t.busy){this._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:Ff}),i=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),s=URL.createObjectURL(i),n=document.createElement("a");n.href=s,n.download=e.filename||`houseplan-${t.kind}.json`,n.style.display="none",document.body.append(n),n.click(),n.remove(),window.setTimeout(()=>URL.revokeObjectURL(s),0),this._backupExportDialog=null,this._showToast(this._t("backup.export_done"))}catch(t){this._backupExportDialog&&(this._backupExportDialog={...this._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,i=e.files?.[0];if(e.value="",i){this._settingsDialog=null,this._backupImportDialog={filename:i.name,size:i.size,token:"",preview:null,expectedConfigRev:this._cfgRev,expectedLayoutRev:this._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain,this._persistLayout.pending()&&this._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:i,headers:{"content-type":"application/json"}},s=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}}),n=await s.json().catch(()=>({}));if(!s.ok||n.error)throw Object.assign(new Error(n.message||n.error||`HTTP ${s.status}`),{code:n.error});this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,token:n.token,preview:n.preview,expectedConfigRev:n.expected_config_rev,expectedLayoutRev:n.expected_layout_rev,busy:!1})}catch(t){this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const i=await this.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,preview:{...e.preview,...i.preview},expectedConfigRev:i.expected_config_rev,expectedLayoutRev:i.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this._backupImportDialog={...t,busy:!0,error:""};const e=this._space;try{const i=await this.hass.callWS({type:"houseplan/import/apply",token:t.token,expected_config_rev:t.expectedConfigRev,expected_layout_rev:t.expectedLayoutRev,duplicate_policy:t.duplicatePolicy,confirm_missing_content:t.confirmMissing}),[s,n]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._adoptStructuralResponses(s,n),this._geometryHistory.clear(),this._dirtyPos.clear(),this._sentPos.clear(),this._defPos={},this._cfgEpoch++,this._modelCache=null,this._frame=null,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotConfigEpoch=-1,this._regSignature="",this._signer.invalidate(this.hass),this._resign(),this._maybeRebuildDevices();const o=this._serverCfg?.spaces||[],a="space"===i.kind&&i.space_id?i.space_id:o.some(t=>t.id===e)?e:o[0]?.id||this._space;this._hasFixedFloor?this._adoptInitialSpace(this._model,!0):this._commitSpace(a),this._backupImportDialog=null,this._cacheSnapshot(),this.requestUpdate();const r="space"===i.kind?t.preview.counts:i.counts;this._showToast(this._t("space"===i.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(i.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this._backupImportDialog?.token)try{const t=this._backupImportDialog,e=await this.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this._t("backup.revalidated")})}catch(e){t=e}this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this._backupExportDialog,e=(this._serverCfg?.spaces||[]).find(t=>t.id===this._space);return W``}_stageBg(t){const e=this._settingsDialog,i=this._spaceDialog,s=e?e.bgColor||"":hs(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":t.bgColor||"")||s}_stageBgHex(){const t=this._stageEl;if(t){const e=getComputedStyle(t).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(e)return"#"+e.slice(1,4).map(t=>(+t).toString(16).padStart(2,"0")).join("")}return"#111111"}_preflightDiagnostics(t,e){const i=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:Ef,checkedAt:(new Date).toISOString(),preflightFingerprint:t.fingerprint,failures:t.failures.map(t=>({spaceId:t.spaceId,displayName:t.displayName,reason:t.reason,detail:t.detail??null,spaceGeometryFingerprint:i.has(t.spaceId)?cg(i.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this._reportedPreflightFingerprint||(this._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==Ef}async _copyPreflightDiagnostics(){const t=this._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this._preflightClipboardFallback=null,this._showToast(this._t("gs.preflight_copied"))}catch{this._preflightClipboardFallback=e}}_checkOptimizeGeometry(t){return mg(t,{fallbackSpaceName:t=>this._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometry(t,e){return function(t,e,i={}){const s=(Array.isArray(t?.spaces)?t.spaces:[]).find(t=>String(t?.id||"")===String(e||"")),n=cg(s);if(!s)return{spaceId:String(e||""),displayName:"",status:"failed",reason:"prepare-exception",fingerprint:n,ok:!1};const o=mg({...t,spaces:[s]},{...i,fingerprint:()=>n}).spaces[0]||{spaceId:String(e||""),displayName:"",status:"failed",reason:"prepare-exception"};return{...o,fingerprint:n,ok:"failed"!==o.status}}(t,e,{fallbackSpaceName:t=>this._t("gs.align_preflight_space",{n:String(t)})})}_optimizeReferenceContext(t){const e=this._haRegistry,i=this._fullRegistryHass,s={},n=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,i]of Object.entries(e.devices||{}))s[t]=n(i?.name_by_user,i?.name,i?.model);for(const[t,i]of Object.entries(e.entities||{}))s[`lg_${t}`]=n(this.hass?.states?.[t]?.attributes?.friendly_name,i?.name,i?.original_name);for(const t of this._devices)s[t.id]=n(t.name,s[t.id]);for(const t of this._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),o=e>0?t.binding.slice(0,e):"",a=e>0?t.binding.slice(e+1):"",r="device"===o?i?.devices?.[a]:"entity"===o?i?.entities?.[a]:null;s[t.id]=n(t.name,"device"===o?r?.name_by_user:null,r?.name,"entity"===o?this.hass?.states?.[a]?.attributes?.friendly_name:null,s[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this._devices.filter(t=>!t.virtual&&!!t.area).map(t=>[t.id,t.area])),ownerRoster:{authoritative:e.authoritative,deviceIds:Object.keys(e.devices||{}),entityIds:[...new Set([...Object.keys(e.entities||{}),...Object.keys(this.hass?.states||{})])],names:s},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this._norm||!this._serverCfg)return;const e=this._serverCfg.spaces||[];let i;try{i=ag(this._serverCfg,this._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const s=i.changed?this._checkOptimizeGeometry(i.config):null;s&&this._reportPreflightFailure(s,i.config);const n=Math.ceil(10*i.report.maxShiftCm)/10,o=e.find(t=>null!=t?.id&&String(t.id)===i.report.maxSpace),a=e.length>1&&o?String(o.title||o.id):"";this._preflightClipboardFallback=null,this._alignDialog={report:i.report,config:i.config,layout:i.layout,cm:n,where:a,preflight:s,changed:i.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this._alignDialog;if(!t||t.busy||!this._serverCfg||!t.changed||!t.preflight?.ok)return;const e=bd(t.config);if(t.preflight.fingerprint!==e){const e=this._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this._alignDialog={...t,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/plan/optimize",config:t.config,layout:t.layout,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});this._serverCfg=t.config,this._layout=t.layout,this._geometryHistory.clear(),this._cfgRev=e?.config_rev??this._cfgRev+1,this._layoutRev=e?.layout_rev??this._layoutRev+1,this._canOptimizeUndo=!!e?.can_undo,this._undoKind=e?.can_undo?"optimize":null,this._dirtyPos.clear(),this._sentPos.clear(),this._cfgEpoch++,this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._cacheSnapshot(),this._alignDialog=null,this._preflightClipboardFallback=null,this.requestUpdate(),this._showToast(this._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.coordsCanonicalized+t.report.latticeCoordinatesCanonicalized+t.report.wallsMerged+t.report.spansMerged+t.report.partitionsMerged+t.report.partitionsReconciled+t.report.openingsRehosted+t.report.wallsStraightened),r:String(t.report.spaceRefsRemapped+t.report.roomRefsRemapped+t.report.positionsRemapped+t.report.markersDetached+t.report.orphanRoomLabelsRemoved+t.report.orphanDevicePositionsRemoved+t.report.orphanGroupPositionsRemoved)}))}catch(t){if(this._alignDialog&&(this._alignDialog={...this._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this._showToast(this._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _undoPlanOptimization(){if(!this._canOptimizeUndo||this._optimizeUndoBusy)return;const t=this._undoKind;this._clearGeometryGesture(),this._optimizeUndoBusy=!0,this.requestUpdate();try{await this.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});const[e,i]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._serverCfg=e?.config||this._serverCfg,this._cfgRev=e?.rev??this._cfgRev,this._layout=i?.layout||this._layout,this._geometryHistory.clear(),this._layoutRev=i?.rev??this._layoutRev,this._canOptimizeUndo=!1,this._undoKind=null,this._cfgEpoch++,this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._cacheSnapshot(),this.requestUpdate(),this._showToast(this._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this._canOptimizeUndo=!1,this._undoKind=null,this._showToast(this._t("toast.error",{err:this._errText(t)}))}finally{this._optimizeUndoBusy=!1,this.requestUpdate()}}async _runBackupExport(){const t=this._backupExportDialog;if(t&&!t.busy){this._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:Ef}),i=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),s=URL.createObjectURL(i),n=document.createElement("a");n.href=s,n.download=e.filename||`houseplan-${t.kind}.json`,n.style.display="none",document.body.append(n),n.click(),n.remove(),window.setTimeout(()=>URL.revokeObjectURL(s),0),this._backupExportDialog=null,this._showToast(this._t("backup.export_done"))}catch(t){this._backupExportDialog&&(this._backupExportDialog={...this._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,i=e.files?.[0];if(e.value="",i){this._settingsDialog=null,this._backupImportDialog={filename:i.name,size:i.size,token:"",preview:null,expectedConfigRev:this._cfgRev,expectedLayoutRev:this._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain,this._persistLayout.pending()&&this._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:i,headers:{"content-type":"application/json"}},s=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}}),n=await s.json().catch(()=>({}));if(!s.ok||n.error)throw Object.assign(new Error(n.message||n.error||`HTTP ${s.status}`),{code:n.error});this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,token:n.token,preview:n.preview,expectedConfigRev:n.expected_config_rev,expectedLayoutRev:n.expected_layout_rev,busy:!1})}catch(t){this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const i=await this.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,preview:{...e.preview,...i.preview},expectedConfigRev:i.expected_config_rev,expectedLayoutRev:i.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this._backupImportDialog={...t,busy:!0,error:""};const e=this._space;try{const i=await this.hass.callWS({type:"houseplan/import/apply",token:t.token,expected_config_rev:t.expectedConfigRev,expected_layout_rev:t.expectedLayoutRev,duplicate_policy:t.duplicatePolicy,confirm_missing_content:t.confirmMissing}),[s,n]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._adoptStructuralResponses(s,n),this._geometryHistory.clear(),this._dirtyPos.clear(),this._sentPos.clear(),this._defPos={},this._cfgEpoch++,this._modelCache=null,this._frame=null,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotConfigEpoch=-1,this._regSignature="",this._signer.invalidate(this.hass),this._resign(),this._maybeRebuildDevices();const o=this._serverCfg?.spaces||[],a="space"===i.kind&&i.space_id?i.space_id:o.some(t=>t.id===e)?e:o[0]?.id||this._space;this._hasFixedFloor?this._adoptInitialSpace(this._model,!0):this._commitSpace(a),this._backupImportDialog=null,this._cacheSnapshot(),this.requestUpdate();const r="space"===i.kind?t.preview.counts:i.counts;this._showToast(this._t("space"===i.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(i.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this._backupImportDialog?.token)try{const t=this._backupImportDialog,e=await this.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this._t("backup.revalidated")})}catch(e){t=e}this._backupImportDialog&&(this._backupImportDialog={...this._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this._backupExportDialog,e=(this._serverCfg?.spaces||[]).find(t=>t.id===this._space);return W`this._backupExportDialog=null}>
${this._t("backup.export_hint")}
@@ -5587,12 +5587,12 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 .pickerLabels=${this._colorPickerLabels} .color=${i.c} .opacity=${i.a} .showOpacity=${!0} @hp-color-opacity-change=${e=>{this._setFillColor(t,{c:e.detail.color,a:e.detail.opacity})}}> -
`}get _glowRadiusCm(){const t=Number(this._settings.glow_radius_cm);return Number.isFinite(t)&&t>0?t:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const t=this._glowRadiusCm;return this._imperial?String(Math.round(t/30.48*10)/10):String(t/100)}_glowTransition(t,e){let i=this._glowRenderedSources.get(t);if(e){const e=this._glowFadeTimers.get(t);if(null!=e&&(clearTimeout(e),this._glowFadeTimers.delete(t)),null==i){this._suspendGlowFeatherForTransition(),i=++this._glowSourceSeq,this._glowRenderedSources.set(t,i),this._glowEnteringSources.add(t);const e=requestAnimationFrame(()=>{this._glowEnterRafs.get(t)===e&&(this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(t,e)}return{domId:i,entering:this._glowEnteringSources.has(t),leaving:!1}}if(null==i)return null;const s=this._glowEnterRafs.get(t);if(null!=s&&cancelAnimationFrame(s),this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),!this._glowFadeTimers.has(t)){this._suspendGlowFeatherForTransition();const e=window.setTimeout(()=>{this._glowFadeTimers.get(t)===e&&(this._glowFadeTimers.delete(t),this._glowRenderedSources.delete(t),this._glowLastAppearance.delete(t),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(t,e)}return{domId:i,entering:!1,leaving:!0}}_suspendGlowFeatherForTransition(){if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;this._glowFeatherSuspendUntil=Math.max(this._glowFeatherSuspendUntil,Date.now()+500),clearTimeout(this._glowFeatherResumeTimer);const t=Math.max(0,this._glowFeatherSuspendUntil-Date.now())+17,e=()=>{this._glowFeatherResumeTimer=0,Date.now()=128){const t=this._glowGeometryWarnings.values().next().value;t&&this._glowGeometryWarnings.delete(t)}this._glowGeometryWarnings.add(n),console.warn(`HOUSEPLAN GLOW GEOMETRY FALLBACK: #218, space ${t}, room ${i}, phase ${s}`)}}_lightBarriers(t,e){const i=this._zeroWalls(),s=this._openCuts(),n=[...i.transmissive],o=Math.max(this._cmToUnits(10),.5*this._gridPitch),a=t=>e.some(e=>this._pointInRoom(t,e.r)),r=this._openingsR.filter(t=>{if("door"!==(e=String(t.type))&&"gate"!==e&&"passage"!==e)return!1;var e;const i=t.angle*Math.PI/180,s=-Math.sin(i),n=Math.cos(i);return a([t.rx+s*o,t.ry+n*o])&&a([t.rx-s*o,t.ry-n*o])}),l=this._roomWallOpeningInputs(r,t);for(const t of l){const e=t.angle*Math.PI/180,i=Math.cos(e)*t.length/2,s=Math.sin(e)*t.length/2;n.push([t.x-i,t.y-s,t.x+i,t.y+s])}const c=new Set(r.filter(t=>t.partitionHost).map(t=>t.id)),h=[t.id,this._cfgEpoch,this._cellCm,this._gridPitch,[...c].sort().join(",")].join("|");this._lightPhysicalBodiesCache?.key!==h&&(this._lightPhysicalBodiesCache={key:h,all:eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t,t=>c.has(t.id))).all});const d=this._lightPhysicalBodiesCache.all;let p=2166136261;const u=t=>{p^=Math.round(64*(Number.isFinite(t)?t:0)),p=Math.imul(p,16777619)>>>0},_=this._spaceWalls;u(this._cellCm),u(this._gridPitch),u(this._wallKeyPitch);for(const{poly:t}of e){u(t.length);for(const e of t)u(e[0]),u(e[1])}for(const t of n)for(const e of t)u(e);u("solid"===i.style?1:0);for(const t of i.barriers)for(const e of t)u(e);for(const t of d){u(t.length);for(const e of t)u(e[0]),u(e[1])}for(const t of _)u(t.cm),u(t.a?.[0]??0),u(t.a?.[1]??0),u(t.b?.[0]??0),u(t.b?.[1]??0);const m=p.toString(36),g=`${t.id}|${m}`;if(this._lightBarrierCache?.key===g)return this._lightBarrierCache.value;const f=.02*this._gridPitch,v=[],y=_.length||d.length?Rc(t.rooms,_,s,l,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,d):null;if(!y||"ok"!==y.status&&"degraded-extra"!==y.status)for(const t of d)v.push(...zu(t));else for(const t of y.components)for(const e of lh(t.geom))v.push(...zu(e));for(const{poly:t}of e)for(const e of n.length?Ps(t,n,f):zu(t))v.push(e);for(const t of i.barriers)v.push(t);const b={occluders:Au(v),floor:e.map(t=>t.poly),fingerprint:m,masonryGeometry:!y||"ok"!==y.status&&"degraded-extra"!==y.status?[]:y.components.flatMap(t=>t.geom),opaqueBodies:d};return this._lightBarrierCache={key:g,value:b},b}_renderGlowLayer(t,e){const i=this._fillColors,s=this._glowRadiusCm/this._cellCm*this._gridPitch,n=t.rooms.map(t=>({r:t,poly:hi(t)})).filter(t=>!!t.poly),o=n.filter(({r:t})=>Fs(e.glow,t));if(!o.length)return this._forgetGlowSpace(t.id),j``;const{occluders:a,floor:r,fingerprint:l,masonryGeometry:c,opaqueBodies:h}=this._lightBarriers(t,n),d=ho(this._renderPlanHass,this._renderDevices,null,this._virtualLights).filter(e=>e.device.space===t.id),p=new Map;for(const t of d){if(!t.device.id)continue;const e=p.get(t.device.id)||[];e.push(t),p.set(t.device.id,e)}const u=[],_=new Set;for(const e of this._renderDevices){if(e.space!==t.id)continue;const o=po(p.get(e.id)||[]);if(!o)continue;const d=`${t.id}|${e.id}`;_.add(d);const m=$s(o.passive?{state:o.on?"on":"off",attributes:{}}:this._renderPlanHass.states[o.eid],e.marker?.glow_color,i.glow_light.c),g=Number(e.marker?.glow_radius_cm),f=Number.isFinite(g)&&g>0?g/this._cellCm*this._gridPitch:s,v=this._pos(e);if(dh([v.x,v.y],c,h)){this._forgetGlowSource(d);continue}const y=this._glowTransition(d,!!m);if(!y)continue;m&&this._glowLastAppearance.set(d,{c:m.c,alpha:Ss(m.bri,i.glow_light.a)});const b=this._glowLastAppearance.get(d);if(!b)continue;let w=null;const k=`${t.id}|${l}|${v.x.toFixed(4)},${v.y.toFixed(4)}|${f.toFixed(4)}`,x=qf(this._glowClipCache,k);if(x.hit)w=x.value;else{const e=Nu([v.x,v.y],f,a,96);w={lit:e.length>=3?oh([e],r,{onBoundsFailure:({boundIndex:e,phase:i})=>{const s=n[e]?.r;this._warnGlowGeometryFallback(t.id,l,s?.id||`#${e}`,i)}}):[]},Wf(this._glowClipCache,k,w,256)}u.push({key:d,sourceEid:o.eid,domId:y.domId,entering:y.entering,leaving:y.leaving,pos:v,c:b.c,alpha:b.alpha,geometry:w,r:f})}const m=`${t.id}|`;for(const t of this._glowRenderedSources.keys())t.startsWith(m)&&!_.has(t)&&this._forgetGlowSource(t);if(!u.length)return j``;const g=this._spaceWalls,f=o.length===n.length?[]:this._openCuts(),v=this._wallUnionGeometry()?.roomGeom,y=o.length===n.length?null:o.map(({r:e,poly:i})=>{const s=g.length&&e.id&&fc(t.rooms,e.id,g,f,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,v)||i,o=this._cleanFloor(e,s,t).path,a=Pi(s,n.filter(t=>t.r!==e).map(t=>t.poly)),r=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z";return[o||r(s),...a.map(r)].join(" ")}),b=this._viewOr(this._baseVb()),w=this._stageEl?.clientWidth&&b.w?this._stageEl.clientWidth/b.w:1,k=1/(w>0?w:1),x=!this._pinchStart&&!this._panStart&&Date.now()>=this._glowFeatherSuspendUntil;(null==this._glowFeatherUnits||x)&&(this._glowFeatherUnits=k);const $=this._glowFeatherUnits??k,S=4*$,M=u.reduce((t,e)=>({x:Math.min(t.x,e.pos.x-e.r-S),y:Math.min(t.y,e.pos.y-e.r-S),maxX:Math.max(t.maxX,e.pos.x+e.r+S),maxY:Math.max(t.maxY,e.pos.y+e.r+S),w:0,h:0}),{x:1/0,y:1/0,maxX:-1/0,maxY:-1/0,w:0,h:0});return M.w=M.maxX-M.x,M.h=M.maxY-M.y,j` + `}get _glowRadiusCm(){const t=Number(this._settings.glow_radius_cm);return Number.isFinite(t)&&t>0?t:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const t=this._glowRadiusCm;return this._imperial?String(Math.round(t/30.48*10)/10):String(t/100)}_glowTransition(t,e){let i=this._glowRenderedSources.get(t);if(e){const e=this._glowFadeTimers.get(t);if(null!=e&&(clearTimeout(e),this._glowFadeTimers.delete(t)),null==i){this._suspendGlowFeatherForTransition(),i=++this._glowSourceSeq,this._glowRenderedSources.set(t,i),this._glowEnteringSources.add(t);const e=requestAnimationFrame(()=>{this._glowEnterRafs.get(t)===e&&(this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(t,e)}return{domId:i,entering:this._glowEnteringSources.has(t),leaving:!1}}if(null==i)return null;const s=this._glowEnterRafs.get(t);if(null!=s&&cancelAnimationFrame(s),this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),!this._glowFadeTimers.has(t)){this._suspendGlowFeatherForTransition();const e=window.setTimeout(()=>{this._glowFadeTimers.get(t)===e&&(this._glowFadeTimers.delete(t),this._glowRenderedSources.delete(t),this._glowLastAppearance.delete(t),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(t,e)}return{domId:i,entering:!1,leaving:!0}}_suspendGlowFeatherForTransition(){if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;this._glowFeatherSuspendUntil=Math.max(this._glowFeatherSuspendUntil,Date.now()+500),clearTimeout(this._glowFeatherResumeTimer);const t=Math.max(0,this._glowFeatherSuspendUntil-Date.now())+17,e=()=>{this._glowFeatherResumeTimer=0,Date.now()=128){const t=this._glowGeometryWarnings.values().next().value;t&&this._glowGeometryWarnings.delete(t)}this._glowGeometryWarnings.add(n),console.warn(`HOUSEPLAN GLOW GEOMETRY FALLBACK: #218, space ${t}, room ${i}, phase ${s}`)}}_lightBarriers(t,e){const i=this._zeroWalls(),s=this._openCuts(),n=[...i.transmissive],o=Math.max(this._cmToUnits(10),.5*this._gridPitch),a=t=>e.some(e=>this._pointInRoom(t,e.r)),r=this._openingsR.filter(t=>{if("door"!==(e=String(t.type))&&"gate"!==e&&"passage"!==e)return!1;var e;const i=t.angle*Math.PI/180,s=-Math.sin(i),n=Math.cos(i);return a([t.rx+s*o,t.ry+n*o])&&a([t.rx-s*o,t.ry-n*o])}),l=this._roomWallOpeningInputs(r,t);for(const t of l){const e=t.angle*Math.PI/180,i=Math.cos(e)*t.length/2,s=Math.sin(e)*t.length/2;n.push([t.x-i,t.y-s,t.x+i,t.y+s])}const c=new Set(r.filter(t=>t.partitionHost).map(t=>t.id)),h=[t.id,this._cfgEpoch,this._cellCm,this._gridPitch,[...c].sort().join(",")].join("|");this._lightPhysicalBodiesCache?.key!==h&&(this._lightPhysicalBodiesCache={key:h,all:eh(t,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(t,t=>c.has(t.id))).all});const d=this._lightPhysicalBodiesCache.all;let p=2166136261;const u=t=>{p^=Math.round(64*(Number.isFinite(t)?t:0)),p=Math.imul(p,16777619)>>>0},_=this._spaceWalls;u(this._cellCm),u(this._gridPitch),u(this._wallKeyPitch);for(const{poly:t}of e){u(t.length);for(const e of t)u(e[0]),u(e[1])}for(const t of n)for(const e of t)u(e);u("solid"===i.style?1:0);for(const t of i.barriers)for(const e of t)u(e);for(const t of d){u(t.length);for(const e of t)u(e[0]),u(e[1])}for(const t of _)u(t.cm),u(t.a?.[0]??0),u(t.a?.[1]??0),u(t.b?.[0]??0),u(t.b?.[1]??0);const m=p.toString(36),g=`${t.id}|${m}`;if(this._lightBarrierCache?.key===g)return this._lightBarrierCache.value;const f=.02*this._gridPitch,v=[],y=_.length||d.length?Rc(t.rooms,_,s,l,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,d):null;if(!y||"ok"!==y.status&&"degraded-extra"!==y.status)for(const t of d)v.push(...zu(t));else for(const t of y.components)for(const e of lh(t.geom))v.push(...zu(e));for(const{poly:t}of e)for(const e of n.length?Ps(t,n,f):zu(t))v.push(e);for(const t of i.barriers)v.push(t);const b={occluders:Au(v),floor:e.map(t=>t.poly),fingerprint:m,masonryGeometry:!y||"ok"!==y.status&&"degraded-extra"!==y.status?[]:y.components.flatMap(t=>t.geom),opaqueBodies:d};return this._lightBarrierCache={key:g,value:b},b}_renderGlowLayer(t,e){const i=this._fillColors,s=this._glowRadiusCm/this._cellCm*this._gridPitch,n=t.rooms.map(t=>({r:t,poly:hi(t)})).filter(t=>!!t.poly),o=n.filter(({r:t})=>Fs(e.glow,t));if(!o.length)return this._forgetGlowSpace(t.id),j``;const{occluders:a,floor:r,fingerprint:l,masonryGeometry:c,opaqueBodies:h}=this._lightBarriers(t,n),d=ho(this._renderPlanHass,this._renderDevices,null,this._virtualLights).filter(e=>e.device.space===t.id),p=new Map;for(const t of d){if(!t.device.id)continue;const e=p.get(t.device.id)||[];e.push(t),p.set(t.device.id,e)}const u=[],_=new Set;for(const e of this._renderDevices){if(e.space!==t.id)continue;const o=po(p.get(e.id)||[]);if(!o)continue;const d=`${t.id}|${e.id}`;_.add(d);const m=$s(o.passive?{state:o.on?"on":"off",attributes:{}}:this._renderPlanHass.states[o.eid],e.marker?.glow_color,i.glow_light.c),g=Number(e.marker?.glow_radius_cm),f=Number.isFinite(g)&&g>0?g/this._cellCm*this._gridPitch:s,v=this._pos(e);if(dh([v.x,v.y],c,h)){this._forgetGlowSource(d);continue}const y=this._glowTransition(d,!!m);if(!y)continue;m&&this._glowLastAppearance.set(d,{c:m.c,alpha:Ss(m.bri,i.glow_light.a)});const b=this._glowLastAppearance.get(d);if(!b)continue;let w=null;const k=`${t.id}|${l}|${v.x.toFixed(4)},${v.y.toFixed(4)}|${f.toFixed(4)}`,x=Wf(this._glowClipCache,k);if(x.hit)w=x.value;else{const e=Nu([v.x,v.y],f,a,96);w={lit:e.length>=3?oh([e],r,{onBoundsFailure:({boundIndex:e,phase:i})=>{const s=n[e]?.r;this._warnGlowGeometryFallback(t.id,l,s?.id||`#${e}`,i)}}):[]},jf(this._glowClipCache,k,w,256)}u.push({key:d,sourceEid:o.eid,domId:y.domId,entering:y.entering,leaving:y.leaving,pos:v,c:b.c,alpha:b.alpha,geometry:w,r:f})}const m=`${t.id}|`;for(const t of this._glowRenderedSources.keys())t.startsWith(m)&&!_.has(t)&&this._forgetGlowSource(t);if(!u.length)return j``;const g=this._spaceWalls,f=o.length===n.length?[]:this._openCuts(),v=this._wallUnionGeometry()?.roomGeom,y=o.length===n.length?null:o.map(({r:e,poly:i})=>{const s=g.length&&e.id&&fc(t.rooms,e.id,g,f,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,v)||i,o=this._cleanFloor(e,s,t).path,a=Pi(s,n.filter(t=>t.r!==e).map(t=>t.poly)),r=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z";return[o||r(s),...a.map(r)].join(" ")}),b=this._viewOr(this._baseVb()),w=this._stageEl?.clientWidth&&b.w?this._stageEl.clientWidth/b.w:1,k=1/(w>0?w:1),x=!this._pinchStart&&!this._panStart&&Date.now()>=this._glowFeatherSuspendUntil;(null==this._glowFeatherUnits||x)&&(this._glowFeatherUnits=k);const $=this._glowFeatherUnits??k,S=4*$,M=u.reduce((t,e)=>({x:Math.min(t.x,e.pos.x-e.r-S),y:Math.min(t.y,e.pos.y-e.r-S),maxX:Math.max(t.maxX,e.pos.x+e.r+S),maxY:Math.max(t.maxY,e.pos.y+e.r+S),w:0,h:0}),{x:1/0,y:1/0,maxX:-1/0,maxY:-1/0,w:0,h:0});return M.w=M.maxX-M.x,M.h=M.maxY-M.y,j` ${Mt(u,t=>t.key,t=>{const e=t.domId,i=t.geometry;return j` ${""} - ${iv.map(([e,i])=>j` + ${sv.map(([e,i])=>j` `)} @@ -5729,7 +5729,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t("gs.glow_radius")} {const e=Bf(t.target.value);null!=e&&e>0&&(this._settingsDialog={...this._settingsDialog,glowRadius:e})}} /> + @input=${t=>{const e=qf(t.target.value);null!=e&&e>0&&(this._settingsDialog={...this._settingsDialog,glowRadius:e})}} /> ${this._imperial?this._t("gs.unit_ft"):this._t("gs.unit_m")} @@ -5804,7 +5804,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 `:G} -
${this._t("gs.about_version",{v:Ff})}
+
${this._t("gs.about_version",{v:Ef})}
${this._t("gs.about_github")} @@ -5861,7 +5861,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${t.busy?"…":this._t("btn.save")} - `}_saveKioskScale(t){this._kioskScale={...this._kioskScale,...t};try{localStorage.setItem(Zf,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const t=this._kioskScale,e=(e,i)=>W` + `}_saveKioskScale(t){this._kioskScale={...this._kioskScale,...t};try{localStorage.setItem(Qf,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const t=this._kioskScale,e=(e,i)=>W`
${this._rangeInput(50,300,5,Math.round(100*t[e]),t=>this._saveKioskScale({[e]:t/100}))} ${Math.round(100*t[e])}% @@ -5918,7 +5918,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._spaceDialog?this._renderSpaceDialog():G} ${this._importDialog?this._renderImportDialog():G} ${this._toast?W``:G} - `;const s=this._spaceModel();if(!s)return G;const n="valid"===i.kind?[s]:t,o=s.vb,a=this._effectiveProjection();this._renderProjection=a,this._labs.active.length&&function(t){Hg||Gg(t);const e=Lg,i=e.active.join(",");if(!i||i===qg)return;qg=i;const s=new Map(Tg.map(t=>[t.id,t])),n=e.active.map(t=>{const e=s.get(t);return`${t} (#${e.issue}, expires ${e.expires})`}).join(", ");console.info(`HOUSEPLAN LABS: ${n}`)}(Ff);const r="iso"===a,l="devices"===this._mode&&this._showAll,c=this._renderDevices.filter(t=>t.space===s.id&&(!t.hidden||l)),h=this._renderDeviceSnapshot,d=this._spaceDisplayForRender(),p=r?this._isoDecorationLayers(d):null,u=p?this._isoOpeningPanels(p):[],_=this._resolvedRoomFills(s,d),m=this._resolvedGlowBase(s,d,_),g=d.showLqi??this._config.show_signal??!0,f=this._config.icon_size??2.5,v=f>8?2.5:f,y=o_(v),b=this._viewOr(this._baseVb()),w=this._floorView(b),k=this._editing?"":this._stageBg(d),x=this._opMeasureView,$=this._decorMeasure,S=this._bdLive,M=this._furnLive,C="view"===this._mode?this._editorChromeMode:this._mode,D=this._roomHoverPaths(s),P=s.bg?this._display(s.bg.href):"",T=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null,R=this._modeTransitionVisual,I=this._dayCycleState(),A=R?.viewWeight??("view"===this._mode?1:0),z=this._modeTransition.state?.from.presentedMode,F=!this._markup||!!R&&("view"===R.presentedMode||"devices"===R.presentedMode||"view"===z||"devices"===z),E=R?.stageColor||k,N=R?.sceneBrightness??1;return W` + `;const s=this._spaceModel();if(!s)return G;const n="valid"===i.kind?[s]:t,o=s.vb,a=this._effectiveProjection();this._renderProjection=a,this._labs.active.length&&function(t){Bg||Vg(t);const e=Hg,i=e.active.join(",");if(!i||i===Wg)return;Wg=i;const s=new Map(Rg.map(t=>[t.id,t])),n=e.active.map(t=>{const e=s.get(t);return`${t} (#${e.issue}, expires ${e.expires})`}).join(", ");console.info(`HOUSEPLAN LABS: ${n}`)}(Ef);const r="iso"===a,l="devices"===this._mode&&this._showAll,c=this._renderDevices.filter(t=>t.space===s.id&&(!t.hidden||l)),h=this._renderDeviceSnapshot,d=this._spaceDisplayForRender(),p=r?this._isoDecorationLayers(d):null,u=p?this._isoOpeningPanels(p):[],_=this._resolvedRoomFills(s,d),m=this._resolvedGlowBase(s,d,_),g=d.showLqi??this._config.show_signal??!0,f=this._config.icon_size??2.5,v=f>8?2.5:f,y=o_(v),b=this._viewOr(this._baseVb()),w=this._floorView(b),k=this._editing?"":this._stageBg(d),x=this._opMeasureView,$=this._decorMeasure,S=this._bdLive,M=this._furnLive,C="view"===this._mode?this._editorChromeMode:this._mode,D=this._roomHoverPaths(s),P=s.bg?this._display(s.bg.href):"",T=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null,R=this._modeTransitionVisual,I=this._dayCycleState(),A=R?.viewWeight??("view"===this._mode?1:0),z=this._modeTransition.state?.from.presentedMode,F=!this._markup||!!R&&("view"===R.presentedMode||"devices"===R.presentedMode||"view"===z||"devices"===z),E=R?.stageColor||k,N=R?.sceneBrightness??1;return W` + transform=${p?.structural?Zg():G}> ${""} ${this._wallHatchDefs(d.color)}${j`${this._paperShapes(s.rooms).map(t=>"path"in t?j``:"poly"in t?j``:j``)}`} ${this._editing?this._renderMarkupDefs(o):G} @@ -6039,7 +6039,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 transform=${s.bg.angle?`rotate(${s.bg.angle} ${s.bg.x+s.bg.w/2} ${s.bg.y+s.bg.h/2})`:G} @dblclick=${t=>this._openBackdropDialog(t)} preserveAspectRatio="none" />`:G} - ${(()=>{const t=this._openCuts(),e=new Map,i=t=>(e.has(t)||e.set(t,hi(t)),e.get(t));return s.rooms.filter(t=>t.area||"view"===this._mode||this._markup||d.showBorders).map(e=>{let n="room "+(s.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||e.id!==this._mergeSel&&e.id!==this._splitSel?.roomId||(n+=" picked");let o="";const a=zs(d.fill,e);if(!this._markup&&(d.showBorders||"none"!==a)){n+=" styled";const t=[];t.push(`--room-stroke:${d.color}`,`--room-stroke-op:${d.showBorders?d.opacity:0}`);const i=_.byRoom.get(e)||null;i?(n+=" filled",t.push(`--room-fill:${i.color}`,`--room-fill-op:${i.opacity}`)):t.push("--room-fill:transparent","--room-fill-op:0"),o=t.join(";")}let r;const l=t=>{"view"===this._mode&&(void 0===r&&(r=this._roomArea(e)),this._showTip(t,e.name||this._t("room.unnamed"),r?this._t("tip.area",{value:r}):"",g?this._roomLqi(e.area):null,this._roomTemp(e),this._roomHum(e)))},c=i(e),h=this._markup&&(e.id===this._mergeSel||e.id===this._splitSel?.roomId),p=c&&!h?t.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return c.some((t,i)=>Ls(e,[t[0],t[1],...c[(i+1)%c.length]])<=.08*this._gridPitch)}):[],u=h?[]:this._thickWallCuts(),m=p.concat(u);m.length&&(n+=" noedge");const f=this._spaceWalls,v=f.length&&e.id&&c&&fc(s.rooms,e.id,f,t,this._wallKeyPitch,this._cellCm,this._gridPitch,ev,this._wallUnionGeometry()?.roomGeom)||c,y=v?Pi(v,(b=e,s.rooms.filter(t=>t!==b).map(i).filter(Boolean))):[];var b;const w=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",k=v?this._cleanFloor(e,v,s).path:"",x=e.id||G,$=e.area||G,S=k&&v?j`{const t=this._openCuts(),e=new Map,i=t=>(e.has(t)||e.set(t,hi(t)),e.get(t));return s.rooms.filter(t=>t.area||"view"===this._mode||this._markup||d.showBorders).map(e=>{let n="room "+(s.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||e.id!==this._mergeSel&&e.id!==this._splitSel?.roomId||(n+=" picked");let o="";const a=zs(d.fill,e);if(!this._markup&&(d.showBorders||"none"!==a)){n+=" styled";const t=[];t.push(`--room-stroke:${d.color}`,`--room-stroke-op:${d.showBorders?d.opacity:0}`);const i=_.byRoom.get(e)||null;i?(n+=" filled",t.push(`--room-fill:${i.color}`,`--room-fill-op:${i.opacity}`)):t.push("--room-fill:transparent","--room-fill-op:0"),o=t.join(";")}let r;const l=t=>{"view"===this._mode&&(void 0===r&&(r=this._roomArea(e)),this._showTip(t,e.name||this._t("room.unnamed"),r?this._t("tip.area",{value:r}):"",g?this._roomLqi(e.area):null,this._roomTemp(e),this._roomHum(e)))},c=i(e),h=this._markup&&(e.id===this._mergeSel||e.id===this._splitSel?.roomId),p=c&&!h?t.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return c.some((t,i)=>Ls(e,[t[0],t[1],...c[(i+1)%c.length]])<=.08*this._gridPitch)}):[],u=h?[]:this._thickWallCuts(),m=p.concat(u);m.length&&(n+=" noedge");const f=this._spaceWalls,v=f.length&&e.id&&c&&fc(s.rooms,e.id,f,t,this._wallKeyPitch,this._cellCm,this._gridPitch,iv,this._wallUnionGeometry()?.roomGeom)||c,y=v?Pi(v,(b=e,s.rooms.filter(t=>t!==b).map(i).filter(Boolean))):[];var b;const w=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",k=v?this._cleanFloor(e,v,s).path:"",x=e.id||G,$=e.area||G,S=k&&v?j`{this._notePointer(t),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:s.id,room:e})}} @@ -6333,7 +6333,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 @pointercancel=${e=>this._pointerUp(e,t)} > ${Ko(r,{newDevice:this._newIds.has(t.id),newDeviceTitle:this._t("device.new"),disabledTitle:r.haDisabled?h:""})} -
`}_roomArea(t){const e=hi(t);if(!e)return null;const i=this._spaceModel();if(!i)return null;const s=this._spaceWalls,n=s.length&&t.id&&fc(i.rooms,t.id,s,this._openCuts(),this._wallKeyPitch,this._cellCm,this._gridPitch,ev,this._wallUnionGeometry()?.roomGeom)||e,o=this._cleanFloor(t,n),a=this._cellCm/this._gridPitch;return ir(o.area*a*a/1e4,"mi"===this._renderPlanHass?.config?.unit_system?.length)}_roomTemp(t){const e=t.settings?.temp_source;return e?Mo(this._renderPlanHass,e,"temp",this._markers):t.area?this._climate().get(t.area)?.temp??null:null}_roomHum(t){const e=t.settings?.hum_source;return e?Mo(this._renderPlanHass,e,"hum",this._markers):t.area?this._climate().get(t.area)?.hum??null:null}_climate(){const t=this._serverCfg?.markers,e=this._renderPlanHass,i=this._climateCache;if(i&&i.h===e&&i.r===this._iconRules&&i.mk===t)return i.m;const s=function(t,e,i){const s=new Map;if(!t?.entities)return s;const n=wo(i),o=new Set;for(const t of i||[]){if(t?.removed||!0!==t?.use_climate_temp)continue;const e=(t.binding||"").indexOf(":");e>0&&o.add(t.binding.slice(e+1))}const a=new Map;for(const[e,i]of Object.entries(t.entities)){if(i.device_id&&n.devices.has(i.device_id)&&!n.liveEntities.has(e)||!i.device_id&&n.entities.has(e)&&!n.liveEntities.has(e))continue;const s=i.device_id?t.devices?.[i.device_id]:null,r=i.area_id||s?.area_id||null;if(!r)continue;if(i.entity_category)continue;if(!(o.size>0&&e.startsWith("climate.")&&(o.has(e)||i.device_id&&o.has(i.device_id)))){if(Yt.has(i.platform))continue;if(Co.test(e))continue}let l=a.get(r);l||(l=new Map,a.set(r,l));const c=i.device_id||e;let h=l.get(c);if(!h){const n=t.states?.[e];h={name:(s?s.name_by_user||s.name:i.name||n?.attributes?.friendly_name||e)||e,model:s?.model,ents:[]},l.set(c,h)}h.ents.push(e)}for(const[i,n]of a){const a=[],r=[];for(const[i,s]of n){const n=bo(t,s.name,s.model,s.ents,e),l="mdi:thermometer"===n||"mdi:air-filter"===n;if(l){const e=mo(t,s.ents);null!=e&&a.push(e)}if(o.size>0&&(o.has(i)||s.ents.some(t=>o.has(t)))){const e=go(t,s.ents);null!=e&&a.push(e)}if(l||"mdi:water-percent"===n){const e=vo(t,s.ents);null!=e&&r.push(e)}}(a.length||r.length)&&s.set(i,{temp:a.length?Math.round(a.reduce((t,e)=>t+e,0)/a.length*10)/10:null,hum:r.length?Math.round(r.reduce((t,e)=>t+e,0)/r.length):null})}return s}(e,this._iconRules,t);return this._climateCache={h:e,r:this._iconRules,mk:t,m:s},s}_resetRoomDialogFields(){this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1}_openRoomEdit(t){if(!t.id)return;this._roomEditId=t.id,this._nameSel=t.name||"",this._areaSel=t.area||"",this._roomFill="glow"===t.settings?.fill_mode?"":t.settings?.fill_mode||"";const e=t.settings?.custom_fill;this._roomCustomFill=e&&"object"==typeof e?rs(e,cs(this._curSpaceCfg).customFill):null,this._roomTempSrc=t.settings?.temp_source||"",this._roomHumSrc=t.settings?.hum_source||"",this._roomNameScale=Es(t.settings?.name_scale),this._roomLabelScale=Es(t.settings?.label_scale),this._roomSrcOpen=null,this._roomSrcFilter="",this._roomDialog=!0}_roomSettingsFromDialog(){const t={};return this._roomFill&&(t.fill_mode=this._roomFill),this._roomCustomFill&&(t.custom_fill=this._roomCustomFill),this._roomTempSrc&&(t.temp_source=this._roomTempSrc),this._roomHumSrc&&(t.hum_source=this._roomHumSrc),1!==this._roomNameScale&&(t.name_scale=this._roomNameScale),1!==this._roomLabelScale&&(t.label_scale=this._roomLabelScale),Object.keys(t).length?t:null}_saveRoomEdit(){const t=this._curSpaceCfg,e=t?.rooms.find(t=>t.id===this._roomEditId);if(!e)return this._roomDialog=!1,void(this._roomEditId=null);e.name=this._nameSel.trim()||e.name,e.area=this._areaSel||null;const i=e.settings||{},s={...i};this._roomFill?s.fill_mode=this._roomFill:delete s.fill_mode,this._roomCustomFill?s.custom_fill=this._roomCustomFill:delete s.custom_fill,"glow"===i.fill_mode&&"boolean"!=typeof i.glow&&(s.glow=!0),this._roomTempSrc?s.temp_source=this._roomTempSrc:delete s.temp_source,this._roomHumSrc?s.hum_source=this._roomHumSrc:delete s.hum_source,1!==this._roomNameScale?s.name_scale=this._roomNameScale:delete s.name_scale,1!==this._roomLabelScale?s.label_scale=this._roomLabelScale:delete s.label_scale,Object.keys(s).length?e.settings=s:delete e.settings,this._saveConfig(),this._roomDialog=!1,this._roomEditId=null,this._nameSel="",this._areaSel="",this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate(),this._showToast(this._t("toast.room_updated"))}_roomSrcCandidates(){const t=this._planHass,e=wo(this._markers),i=this._roomSrcFilter.trim().toLowerCase(),s=[];for(const n of Object.values(t.devices)){if("service"===n.entry_type)continue;if(e.devices.has(n.id))continue;const t=(n.name_by_user||n.name||n.id).trim();i&&!t.toLowerCase().includes(i)||s.push({value:"device:"+n.id,label:t,sub:n.model||this._t("marker.sub_device")})}for(const[n,o]of Object.entries(t.entities)){if(!n.startsWith("sensor.")||o.hidden)continue;if(ko(t,n,e))continue;const a=o.name||t.states[n]?.attributes?.friendly_name||n;i&&!(a+" "+n).toLowerCase().includes(i)||s.push({value:"entity:"+n,label:a,sub:n})}return s.sort((t,e)=>t.label.localeCompare(e.label)),s.slice(0,200)}_roomSrcLabel(t){const e=t.indexOf(":"),i=t.slice(0,e),s=t.slice(e+1);return"device"===i?this._fullRegistryHass.devices[s]?.name_by_user||this._fullRegistryHass.devices[s]?.name||s:this._fullRegistryHass.entities[s]?.name||this.hass.states[s]?.attributes?.friendly_name||s}_labelPos(t,e){const i=this._layout["rl_"+(t.id||"")];if(i&&i.s===e)return{x:i.x*ev,y:i.y*ev};const s=this._snap(this._roomCenter(t));return{x:s[0],y:s[1]}}_labelDown(t,e,i){if("plan"!==this._mode)return;t.preventDefault(),t.stopPropagation();const s=this._labelPos(e,i);this._drag={id:"rl_"+(e.id||""),sx:t.clientX,sy:t.clientY,ox:s.x,oy:s.y,moved:!1},cv(t),this._tip=null}_labelMove(t,e,i){const s="rl_"+(e.id||"");if(!this._drag||this._drag.id!==s)return;const n=this._stageEl;if(!n)return;const o=this._spaceModelById(i);if(!o)return;const a=o.vb,r=n.getBoundingClientRect(),l=this._viewOr(a),c=(t.clientX-this._drag.sx)/r.width*l.w,h=(t.clientY-this._drag.sy)/r.height*l.h;Math.abs(t.clientX-this._drag.sx)+Math.abs(t.clientY-this._drag.sy)>3&&(this._drag.moved=!0);const d=Ih(this._drag.ox+c),p=Ih(this._drag.oy+h);this._savePos({id:s,space:i},d,p)}_labelUp(t){const e="rl_"+(t.id||"");if(!this._drag||this._drag.id!==e)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&window.setTimeout(()=>this._drag=null,0)}_labelScale(t){const e=this._layout["rl_"+(t.id||"")]?.k;return"number"==typeof e&&Number.isFinite(e)?Math.min(3,Math.max(.5,e)):1}_rlResizeDown(t,e,i){if("plan"!==this._mode)return;t.preventDefault(),t.stopPropagation();const s=t.target.closest(".roomlabel");if(!s)return;const n=s.getBoundingClientRect(),o=n.left+n.width/2,a=n.top+n.height/2,r=Math.max(8,Math.hypot(t.clientX-o,t.clientY-a));this._rlResize={id:"rl_"+(e.id||""),space:i,k0:this._labelScale(e),cx:o,cy:a,d0:r},cv(t)}_rlResizeMove(t){const e=this._rlResize;if(!e)return;t.stopPropagation();const i=Math.max(8,Math.hypot(t.clientX-e.cx,t.clientY-e.cy)),s=Math.min(3,Math.max(.5,e.k0*(i/e.d0))),n=this._layout[e.id];if(n)this._layout={...this._layout,[e.id]:{...n,k:s}};else{const t=e.id.slice(3),i=this._spaceModelById(e.space);if(!i)return;const n=i.rooms.find(e=>e.id===t);if(!n)return;const o=this._labelPos(n,e.space);this._layout={...this._layout,[e.id]:{s:e.space,x:o.x/ev,y:o.y/ev,k:s}}}this._dirtyPos.add(e.id)}_rlResizeUp(){this._rlResize&&(this._rlResize=null,this._persistLayout())}_renderRoomGear(t,e,i){if(!t.id)return G;let s=null;if(t.poly?(s=this._gearPtCache.get(t.poly)||null,s||(s=$i(t.poly),this._gearPtCache.set(t.poly,s))):null!=t.x&&null!=t.y&&(s=[t.x+(t.w||0)/2,t.y+(t.h||0)/2]),!s)return G;const n=(s[0]-i.x)/i.w*100,o=(s[1]-i.y)/i.h*100;return W` - `}_renderOpeningDialog(){const t=this._openingDialog,e=this._spaceModel()?.partitions||[],i=t.id?this._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,s={id:t.id||"preview",type:t.type,x:t.x/ev,y:t.y/this._spaceH,angle:t.angle,length:i&&!t.lengthTouched?i.length:this._cmToUnits(Math.max(20,t.lengthCm))/ev,...t.host?{host:t.host}:{}},n=Mp(i,s),o=t.host?n?Sp(s,e,ev,this._cellCm,this._gridPitch):$p(s,e,ev,this._cellCm,this._gridPitch):null,a="does-not-fit-jamb"===o?.reason,r=t.host?e.find(e=>e.id===t.host.id):null,l=r?li(r.cm/2,this._imperial):"",c=!!t.host&&!o?.resolved&&!a,h="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",d=(e,i)=>{const s="contact"===e?t.contact:t.lock,n="contact"===e?!!t.contactOpen:!!t.lockOpen,o="contact"===e?t.contactFilter||"":t.lockFilter||"",a=i.find(t=>t.value===s),r=a?.label||this.hass.states[s]?.attributes?.friendly_name||this._fullRegistryHass.entities[s]?.name||s,l=function(t,e,i=200){const s=e.trim().toLowerCase();return(s?t.filter(t=>t.label.toLowerCase().includes(s)||t.value.toLowerCase().includes(s)):t).slice(0,Math.max(0,i))}(i,o);return W` + `}_renderOpeningDialog(){const t=this._openingDialog,e=this._spaceModel()?.partitions||[],i=t.id?this._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,s={id:t.id||"preview",type:t.type,x:t.x/iv,y:t.y/this._spaceH,angle:t.angle,length:i&&!t.lengthTouched?i.length:this._cmToUnits(Math.max(20,t.lengthCm))/iv,...t.host?{host:t.host}:{}},n=Mp(i,s),o=t.host?n?Sp(s,e,iv,this._cellCm,this._gridPitch):$p(s,e,iv,this._cellCm,this._gridPitch):null,a="does-not-fit-jamb"===o?.reason,r=t.host?e.find(e=>e.id===t.host.id):null,l=r?li(r.cm/2,this._imperial):"",c=!!t.host&&!o?.resolved&&!a,h="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",d=(e,i)=>{const s="contact"===e?t.contact:t.lock,n="contact"===e?!!t.contactOpen:!!t.lockOpen,o="contact"===e?t.contactFilter||"":t.lockFilter||"",a=i.find(t=>t.value===s),r=a?.label||this.hass.states[s]?.attributes?.friendly_name||this._fullRegistryHass.entities[s]?.name||s,l=function(t,e,i=200){const s=e.trim().toLowerCase();return(s?t.filter(t=>t.label.toLowerCase().includes(s)||t.value.toLowerCase().includes(s)):t).slice(0,Math.max(0,i))}(i,o);return W` `:G} - `}_markerValueBadgeFields(t){return(e={touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition}).touched?{value_badge:{enabled:e.enabled,source:e.source,position:e.position}}:e.originalHas?{value_badge:e.original}:{};var e}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=qs(t.room),i=Fi(t.binding,t.devId,()=>"__hp_device_preview__"),s=this._markers.find(e=>e.id===i||e.id===t.devId),n=Zn(t.binding,t.controls,this._bindingEntities(t.binding)),o=this._effectiveStoredTapAction(t),a={id:i,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===o&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:n.length?n:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=Bf(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:s?.vacuum||null};return("virtual"===t.binding||t.room)&&(a.space=e?.space||("virtual"===t.binding?this._space:null),a.area=e?.area||null,a.room_id=e?.roomId||null),a}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const i=`${this._haRegistry.revision}\n${bd(this._markers)}\n${JSON.stringify(e)}`;if(this._markerPreviewMemo?.key===i)return this._markerPreviewMemo.device;const s=function(t){const{marker:e,siblingMarkers:i=[],...s}=t;return So({...s,markers:[...i.filter(t=>t.id!==e.id),e]}).find(t=>t.id===e.id)||null}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||this._space,loc:t=>this._t(t),iconRules:this._iconRules});return this._markerPreviewMemo={key:i,device:s},s}_markerPreviewDevices(t){const e=this._markerPreviewDevicesMemo;if(e?.base===this._devices&&e.preview===t)return e.devices;const i=[...this._devices.filter(e=>e.id!==t.id),t];return this._markerPreviewDevicesMemo={base:this._devices,preview:t,devices:i},i}_toggleIntent(t,e=this._devices){return gp({hass:this._planHass,registryHass:this._fullRegistryHass,devices:e,device:t,virtualLights:this._virtualLights})}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const i=this._markerPreviewDevices(e);return this._toggleIntent(e,i)}_toggleStateText(t,e){const i=this._planHass?.states?.[t]||this.hass?.states?.[t];try{return i&&"function"==typeof this.hass?.formatEntityState?this.hass.formatEntityState(i):e}catch{return e}}_toggleConfirmationStateText(t){const e=String(t.state||"unknown"),i=t.entityId?this._toggleStateText(t.entityId,e):e;if(i.trim().toLocaleLowerCase()!==e.trim().toLocaleLowerCase())return i;const s={on:"confirm.state_on",off:"confirm.state_off",open:"confirm.state_open",closed:"confirm.state_closed",opening:"confirm.state_opening",closing:"confirm.state_closing",unknown:"confirm.state_unknown"}[e];return s?this._t(s):e.replaceAll("_"," ").replaceAll("-"," ")}_toggleConfirmationLines(t){const e={"turn-on":"confirm.state_on","turn-off":"confirm.state_off",open:"confirm.state_open",close:"confirm.state_closed",stop:"confirm.state_stopped"};return function(t,e){if(!vp(t)||!t.nextEffect||!t.targets.length)return[];const i="group"===t.kind,s=i?t.targets.filter(t=>"on"===t.state).length:0,n=i?0===s?e.groupAllOff():e.groupCurrent(s,t.targets.length):e.state(t.targets[0]);let o;return o="toggle"===t.nextEffect?e.expectedByHa():i&&"turn-on"===t.nextEffect?e.groupAllOn():i&&"turn-off"===t.nextEffect?e.groupAllOff():e.effect(t.nextEffect),[e.current(n),e.expected(o),...t.skippedTargets.length?[e.unavailable(t.skippedTargets.length)]:[]]}(t,{state:t=>this._toggleConfirmationStateText(t),current:t=>this._t("confirm.current_state",{state:t}),expected:t=>this._t("confirm.expected_state",{state:t}),groupCurrent:(t,e)=>this._t("confirm.group_current",{on:t,total:e}),groupAllOn:()=>this._t("confirm.group_all_on"),groupAllOff:()=>this._t("confirm.group_all_off"),unavailable:t=>this._t("confirm.unavailable_targets",{count:t}),effect:t=>this._t(e[t]),expectedByHa:()=>this._t("confirm.expected_by_ha")})}_toggleHintLines(t){if(!t)return[];const e=t=>this._t(`marker.toggle_effect_${t.replace("-","_")}`),i=t=>this._t(`marker.toggle_skip_${t.replace("-","_")}`);return function(t,e){const i=t.targets[0]||t.skippedTargets[0],s=[];return"group"===t.kind?t.targets.length&&s.push(e.group(t.targets)):i&&s.push(e.single(i)),t.nextEffect&&t.targets.length&&s.push("group"===t.kind?e.groupCurrentNext(t.targets,t.nextEffect):e.currentNext(t.targets[0],t.nextEffect)),t.skippedTargets.length&&s.push(e.skipped(t.skippedTargets)),!t.command&&t.noneReason&&s.push(e.none(t.noneReason)),s}(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),i=t.name||e;return this._t("marker.toggle_hint_single",{name:i,id:e})},group:t=>this._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,i)=>"virtual-light"===t.via?this._t("marker.virtual_light_current",{state:this._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(i)}):this._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(i)}),groupCurrentNext:(t,i)=>this._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(i)}),skipped:t=>this._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${i(t.reason)})`}).join(", ")}),none:t=>this._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:pp(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),i=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},s="toggle"===i.tapAction?this._toggleHintLines(this._toggleIntentForDialog(i)).join(" "):"";return{...i,tapHintAnnouncement:s}}_valueBadgeForBinding(t,e){const i={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},s=this._markerPreviewDevice(i);if(!s)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const n=[...this._devices.filter(t=>t.id!==s.id),s],o=Wo(this._planHass,s,n),a=jo(this._planHass,s,o);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!a,valueBadgeSource:a,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const i={...e,hidden:!1};return po(ho(this._planHass,[...this._devices.filter(t=>t.id!==i.id),i],null,this._virtualLights).filter(t=>t.device.id===i.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},i=this._markerPreviewDevice(e);return!!i&&lo(this._planHass,{...i})}_setMarkerLightRole(t){const e=this._markerDialog;e&&(this._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this._planEntityAvailable(t)};const e=t.slice(7),i=this._markers.find(t=>t.id===e),s=this._devices.find(t=>t.id===e);if(!i||i.removed||!0!==i.is_light)return{label:this._t("marker.control_missing_label"),sub:`${this._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const n=this._serverCfg?.spaces.find(t=>t.id===(s?.space||i.space)),o=!!s&&to(s).length>0;return{label:i.name||s?.name||e,sub:[n?.title||s?.space||i.space,i.room_id||s?.area,o?"":this._t("marker.control_passive")].filter(Boolean).join(" · "),icon:i.icon||s?.icon||"mdi:lightbulb-outline",warning:!0===i.hidden||!0===s?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this._t("marker.value_badge_state",{name:t.label});const i=this.hass.states[e.entity_id]?.attributes?.friendly_name||this._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this._t(`marker.value_badge_attr_${e.attribute}`,{name:i})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",i=[],s=new Set;for(const t of this._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this._bindingStatus(t.binding).kind)continue;const n=this._devices.find(e=>e.id===t.id);if(!n||n.hidden)continue;const o=this._controlRefInfo(`marker:${t.id}`);for(const t of to(n))s.add(t);i.push({value:`marker:${t.id}`,label:o.label,sub:o.sub,icon:o.icon,search:`${o.label} ${o.sub} ${t.id} ${to(n).join(" ")}`.toLowerCase()})}const n=Object.keys(this.hass.states||{}).filter(e=>Ms(e)&&!s.has(e)&&Xn(t.binding,[e],this._bindingEntities(t.binding)).length>0&&this._planEntityAvailable(e)).map(t=>{const e=this._controlRefInfo(t);return{value:t,label:e.label,sub:t,icon:e.icon,search:`${e.label} ${t}`.toLowerCase()}}),o=t.controlsFilter.trim().toLowerCase();return[...i,...n].filter(e=>!t.controls.includes(e.value)&&(!o||e.search.includes(o))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const i=this._markerDraft(t)?.id||t.devId||"";if(!i)return void this._showToast(this._t("toast.marker_binding_required"));const s=e.slice(7),n=this._markerDraft(t);if(function(t,e,i){if(!e||e===i)return!0;const s=new Map;for(const e of t)s.set(e.id,(e.controls||[]).filter(t=>"string"==typeof t&&t.startsWith("marker:")).map(t=>t.slice(7)));const n=new Set,o=[i];for(;o.length;){const t=o.pop();if(t===e)return!0;n.has(t)||(n.add(t),o.push(...s.get(t)||[]))}return!1}(n?[...this._markers.filter(t=>t.id!==i),n]:this._markers,i,s))return void this._showToast(this._t("toast.marker_control_cycle"))}this._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this._markerDialog;if(!e)return;if("auto"===t)return void(this._markerDialog={...e,glowMode:t,glowTouched:!0});const i=this._markerSpatialSource(e),s=xs(i?this._planHass.states[i.eid]:void 0,null,this._fillColors.glow_light.c),n=!e.glowColorDrafted,o="fixed"===t&&!e.glowBrightnessDrafted;this._markerDialog={...e,glowMode:t,glowColor:n?s.c:e.glowColor,glowBrightness:o?Math.max(1,Math.round(100*s.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderMarkerDialog(){const t=this._markerDialog,e="virtual"===t.bindingMode,i=this._bindingCandidates();this._bindingEntities(t.binding);const s=e?null:this._bindingStatus(t.binding),n=!e&&this._bindingHasHaPage(t.binding),o=this._markerPreviewDevice(t),a=this._effectiveMarkerTapAction(t,o),r=o?cs(this._serverCfg?.spaces.find(t=>t.id===o.space)):null,l=o?this._markerPreviewDevices(o):this._devices,c="toggle"===a&&o?this._toggleIntent(o,l):null,h=this._toggleHintLines(c),d=o?t_(this._planHass,o,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:r?.showLqi??!1!==this._config?.show_signal,designPreview:!0,activityRuntime:this._activityRt.get(o.id),lightDevices:l,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}):null,p=o?Wo(this._planHass,o,l):[],u=o?jo(this._planHass,o,p):null,_=t.valueBadgeTouched?t.valueBadgeEnabled:!!d?.valueBadge,m=t.valueBadgeTouched?t.valueBadgeSource:d?.valueBadge?.source||t.valueBadgeSource,g=t.valueBadgeTouched?t.valueBadgePosition:d?.valueBadge?.position||t.valueBadgePosition,f=Ao(m),v=!!m&&!p.some(t=>t.key===f),y=p.find(t=>t.key===f),b=d?.valueSource?d.valueSource.attribute?`attr:${d.valueSource.eid}:${d.valueSource.attribute}`:`state:${d.valueSource.eid}`:"",w=this._markerAutoHasSpatialSource(t),k=!!o&&function(t,e){return io(t,e).some(t=>!!t.eid)}(this._planHass,{...o}),x=function(t,e,i,s){const n="always"===t||"auto"===t&&e,o=n&&!i;return{sourceExists:n,fromSourceEnabled:n&&i,manualEnabled:n,radiusEnabled:n,passive:o,effectiveMode:o&&"auto"===s?"fixed":s}}(t.lightRole,w,k,t.glowMode),$=!x.sourceExists,S=!x.fromSourceEnabled,M=x.passive,C=x.effectiveMode,D="never"===t.lightRole?this._t("marker.glow_disabled_never"):"auto"!==t.lightRole||w?M?this._t("marker.glow_passive_hint"):this._t("marker.glow_disabled_no_entity"):this._t("marker.glow_disabled_auto"),P=o?to(o):[],T=o&&eo(o)||"",R=!!t.lightEntity&&!P.includes(t.lightEntity),I=o?rp(o):[],A=!!t.toggleEntity&&!I.includes(t.toggleEntity),z="toggle"===a?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,F=z?[...z.targets,...z.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",E=(()=>{if(e)return null;const s=i.find(e=>e.value===t.binding);if(s)return s.label;const[n,o]=t.binding.split(":");return"device"===n?this._fullRegistryHass.devices[o]?.name_by_user||this._fullRegistryHass.devices[o]?.name||o:this._fullRegistryHass.entities[o]?.name||this.hass.states[o]?.attributes?.friendly_name||o})();return W``}_markerValueBadgeFields(t){return(e={touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition}).touched?{value_badge:{enabled:e.enabled,source:e.source,position:e.position}}:e.originalHas?{value_badge:e.original}:{};var e}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=qs(t.room),i=Fi(t.binding,t.devId,()=>"__hp_device_preview__"),s=this._markers.find(e=>e.id===i||e.id===t.devId),n=Zn(t.binding,t.controls,this._bindingEntities(t.binding)),o=this._effectiveStoredTapAction(t),a={id:i,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===o&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:n.length?n:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=qf(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:s?.vacuum||null};return("virtual"===t.binding||t.room)&&(a.space=e?.space||("virtual"===t.binding?this._space:null),a.area=e?.area||null,a.room_id=e?.roomId||null),a}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const i=`${this._haRegistry.revision}\n${bd(this._markers)}\n${JSON.stringify(e)}`;if(this._markerPreviewMemo?.key===i)return this._markerPreviewMemo.device;const s=function(t){const{marker:e,siblingMarkers:i=[],...s}=t;return So({...s,markers:[...i.filter(t=>t.id!==e.id),e]}).find(t=>t.id===e.id)||null}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||this._space,loc:t=>this._t(t),iconRules:this._iconRules});return this._markerPreviewMemo={key:i,device:s},s}_markerPreviewDevices(t){const e=this._markerPreviewDevicesMemo;if(e?.base===this._devices&&e.preview===t)return e.devices;const i=[...this._devices.filter(e=>e.id!==t.id),t];return this._markerPreviewDevicesMemo={base:this._devices,preview:t,devices:i},i}_toggleIntent(t,e=this._devices){return gp({hass:this._planHass,registryHass:this._fullRegistryHass,devices:e,device:t,virtualLights:this._virtualLights})}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const i=this._markerPreviewDevices(e);return this._toggleIntent(e,i)}_toggleStateText(t,e){const i=this._planHass?.states?.[t]||this.hass?.states?.[t];try{return i&&"function"==typeof this.hass?.formatEntityState?this.hass.formatEntityState(i):e}catch{return e}}_toggleConfirmationStateText(t){const e=String(t.state||"unknown"),i=t.entityId?this._toggleStateText(t.entityId,e):e;if(i.trim().toLocaleLowerCase()!==e.trim().toLocaleLowerCase())return i;const s={on:"confirm.state_on",off:"confirm.state_off",open:"confirm.state_open",closed:"confirm.state_closed",opening:"confirm.state_opening",closing:"confirm.state_closing",unknown:"confirm.state_unknown"}[e];return s?this._t(s):e.replaceAll("_"," ").replaceAll("-"," ")}_toggleConfirmationLines(t){const e={"turn-on":"confirm.state_on","turn-off":"confirm.state_off",open:"confirm.state_open",close:"confirm.state_closed",stop:"confirm.state_stopped"};return function(t,e){if(!vp(t)||!t.nextEffect||!t.targets.length)return[];const i="group"===t.kind,s=i?t.targets.filter(t=>"on"===t.state).length:0,n=i?0===s?e.groupAllOff():e.groupCurrent(s,t.targets.length):e.state(t.targets[0]);let o;return o="toggle"===t.nextEffect?e.expectedByHa():i&&"turn-on"===t.nextEffect?e.groupAllOn():i&&"turn-off"===t.nextEffect?e.groupAllOff():e.effect(t.nextEffect),[e.current(n),e.expected(o),...t.skippedTargets.length?[e.unavailable(t.skippedTargets.length)]:[]]}(t,{state:t=>this._toggleConfirmationStateText(t),current:t=>this._t("confirm.current_state",{state:t}),expected:t=>this._t("confirm.expected_state",{state:t}),groupCurrent:(t,e)=>this._t("confirm.group_current",{on:t,total:e}),groupAllOn:()=>this._t("confirm.group_all_on"),groupAllOff:()=>this._t("confirm.group_all_off"),unavailable:t=>this._t("confirm.unavailable_targets",{count:t}),effect:t=>this._t(e[t]),expectedByHa:()=>this._t("confirm.expected_by_ha")})}_toggleHintLines(t){if(!t)return[];const e=t=>this._t(`marker.toggle_effect_${t.replace("-","_")}`),i=t=>this._t(`marker.toggle_skip_${t.replace("-","_")}`);return function(t,e){const i=t.targets[0]||t.skippedTargets[0],s=[];return"group"===t.kind?t.targets.length&&s.push(e.group(t.targets)):i&&s.push(e.single(i)),t.nextEffect&&t.targets.length&&s.push("group"===t.kind?e.groupCurrentNext(t.targets,t.nextEffect):e.currentNext(t.targets[0],t.nextEffect)),t.skippedTargets.length&&s.push(e.skipped(t.skippedTargets)),!t.command&&t.noneReason&&s.push(e.none(t.noneReason)),s}(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),i=t.name||e;return this._t("marker.toggle_hint_single",{name:i,id:e})},group:t=>this._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,i)=>"virtual-light"===t.via?this._t("marker.virtual_light_current",{state:this._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(i)}):this._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(i)}),groupCurrentNext:(t,i)=>this._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(i)}),skipped:t=>this._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${i(t.reason)})`}).join(", ")}),none:t=>this._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:pp(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),i=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},s="toggle"===i.tapAction?this._toggleHintLines(this._toggleIntentForDialog(i)).join(" "):"";return{...i,tapHintAnnouncement:s}}_valueBadgeForBinding(t,e){const i={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},s=this._markerPreviewDevice(i);if(!s)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const n=[...this._devices.filter(t=>t.id!==s.id),s],o=Wo(this._planHass,s,n),a=jo(this._planHass,s,o);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!a,valueBadgeSource:a,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const i={...e,hidden:!1};return po(ho(this._planHass,[...this._devices.filter(t=>t.id!==i.id),i],null,this._virtualLights).filter(t=>t.device.id===i.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},i=this._markerPreviewDevice(e);return!!i&&lo(this._planHass,{...i})}_setMarkerLightRole(t){const e=this._markerDialog;e&&(this._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this._planEntityAvailable(t)};const e=t.slice(7),i=this._markers.find(t=>t.id===e),s=this._devices.find(t=>t.id===e);if(!i||i.removed||!0!==i.is_light)return{label:this._t("marker.control_missing_label"),sub:`${this._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const n=this._serverCfg?.spaces.find(t=>t.id===(s?.space||i.space)),o=!!s&&to(s).length>0;return{label:i.name||s?.name||e,sub:[n?.title||s?.space||i.space,i.room_id||s?.area,o?"":this._t("marker.control_passive")].filter(Boolean).join(" · "),icon:i.icon||s?.icon||"mdi:lightbulb-outline",warning:!0===i.hidden||!0===s?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this._t("marker.value_badge_state",{name:t.label});const i=this.hass.states[e.entity_id]?.attributes?.friendly_name||this._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this._t(`marker.value_badge_attr_${e.attribute}`,{name:i})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",i=[],s=new Set;for(const t of this._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this._bindingStatus(t.binding).kind)continue;const n=this._devices.find(e=>e.id===t.id);if(!n||n.hidden)continue;const o=this._controlRefInfo(`marker:${t.id}`);for(const t of to(n))s.add(t);i.push({value:`marker:${t.id}`,label:o.label,sub:o.sub,icon:o.icon,search:`${o.label} ${o.sub} ${t.id} ${to(n).join(" ")}`.toLowerCase()})}const n=Object.keys(this.hass.states||{}).filter(e=>Ms(e)&&!s.has(e)&&Xn(t.binding,[e],this._bindingEntities(t.binding)).length>0&&this._planEntityAvailable(e)).map(t=>{const e=this._controlRefInfo(t);return{value:t,label:e.label,sub:t,icon:e.icon,search:`${e.label} ${t}`.toLowerCase()}}),o=t.controlsFilter.trim().toLowerCase();return[...i,...n].filter(e=>!t.controls.includes(e.value)&&(!o||e.search.includes(o))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const i=this._markerDraft(t)?.id||t.devId||"";if(!i)return void this._showToast(this._t("toast.marker_binding_required"));const s=e.slice(7),n=this._markerDraft(t);if(function(t,e,i){if(!e||e===i)return!0;const s=new Map;for(const e of t)s.set(e.id,(e.controls||[]).filter(t=>"string"==typeof t&&t.startsWith("marker:")).map(t=>t.slice(7)));const n=new Set,o=[i];for(;o.length;){const t=o.pop();if(t===e)return!0;n.has(t)||(n.add(t),o.push(...s.get(t)||[]))}return!1}(n?[...this._markers.filter(t=>t.id!==i),n]:this._markers,i,s))return void this._showToast(this._t("toast.marker_control_cycle"))}this._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this._markerDialog;if(!e)return;if("auto"===t)return void(this._markerDialog={...e,glowMode:t,glowTouched:!0});const i=this._markerSpatialSource(e),s=xs(i?this._planHass.states[i.eid]:void 0,null,this._fillColors.glow_light.c),n=!e.glowColorDrafted,o="fixed"===t&&!e.glowBrightnessDrafted;this._markerDialog={...e,glowMode:t,glowColor:n?s.c:e.glowColor,glowBrightness:o?Math.max(1,Math.round(100*s.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderMarkerDialog(){const t=this._markerDialog,e="virtual"===t.bindingMode,i=this._bindingCandidates();this._bindingEntities(t.binding);const s=e?null:this._bindingStatus(t.binding),n=!e&&this._bindingHasHaPage(t.binding),o=this._markerPreviewDevice(t),a=this._effectiveMarkerTapAction(t,o),r=o?cs(this._serverCfg?.spaces.find(t=>t.id===o.space)):null,l=o?this._markerPreviewDevices(o):this._devices,c="toggle"===a&&o?this._toggleIntent(o,l):null,h=this._toggleHintLines(c),d=o?t_(this._planHass,o,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:r?.showLqi??!1!==this._config?.show_signal,designPreview:!0,activityRuntime:this._activityRt.get(o.id),lightDevices:l,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}):null,p=o?Wo(this._planHass,o,l):[],u=o?jo(this._planHass,o,p):null,_=t.valueBadgeTouched?t.valueBadgeEnabled:!!d?.valueBadge,m=t.valueBadgeTouched?t.valueBadgeSource:d?.valueBadge?.source||t.valueBadgeSource,g=t.valueBadgeTouched?t.valueBadgePosition:d?.valueBadge?.position||t.valueBadgePosition,f=Ao(m),v=!!m&&!p.some(t=>t.key===f),y=p.find(t=>t.key===f),b=d?.valueSource?d.valueSource.attribute?`attr:${d.valueSource.eid}:${d.valueSource.attribute}`:`state:${d.valueSource.eid}`:"",w=this._markerAutoHasSpatialSource(t),k=!!o&&function(t,e){return io(t,e).some(t=>!!t.eid)}(this._planHass,{...o}),x=function(t,e,i,s){const n="always"===t||"auto"===t&&e,o=n&&!i;return{sourceExists:n,fromSourceEnabled:n&&i,manualEnabled:n,radiusEnabled:n,passive:o,effectiveMode:o&&"auto"===s?"fixed":s}}(t.lightRole,w,k,t.glowMode),$=!x.sourceExists,S=!x.fromSourceEnabled,M=x.passive,C=x.effectiveMode,D="never"===t.lightRole?this._t("marker.glow_disabled_never"):"auto"!==t.lightRole||w?M?this._t("marker.glow_passive_hint"):this._t("marker.glow_disabled_no_entity"):this._t("marker.glow_disabled_auto"),P=o?to(o):[],T=o&&eo(o)||"",R=!!t.lightEntity&&!P.includes(t.lightEntity),I=o?rp(o):[],A=!!t.toggleEntity&&!I.includes(t.toggleEntity),z="toggle"===a?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,F=z?[...z.targets,...z.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",E=(()=>{if(e)return null;const s=i.find(e=>e.value===t.binding);if(s)return s.label;const[n,o]=t.binding.split(":");return"device"===n?this._fullRegistryHass.devices[o]?.name_by_user||this._fullRegistryHass.devices[o]?.name||o:this._fullRegistryHass.entities[o]?.name||this.hass.states[o]?.attributes?.friendly_name||o})();return W`this._markerDialog=null}>
@@ -7098,10 +7098,10 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 -

${this._t(Nf[t.display])}

+

${this._t(Of[t.display])}

${"static_icon"===t.display&&this._bindingHasAlarm(t.binding)?W`
${this._t("marker.static_alarm_warning")} @@ -7278,9 +7278,9 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4
{const i=e.target.value,s=Bf(i),n=null==s?null:(o=s,this._imperial?o*uh:o);var o;this._spaceDialog={...t,cellCmInput:i,cellCmTouched:!0,cellCm:null!=n&&n>0?Math.max(.1,Math.min(Lf,n)):t.cellCm}}} /> + @input=${e=>{const i=e.target.value,s=qf(i),n=null==s?null:(o=s,this._imperial?o*uh:o);var o;this._spaceDialog={...t,cellCmInput:i,cellCmTouched:!0,cellCm:null!=n&&n>0?Math.max(.1,Math.min(Hf,n)):t.cellCm}}} /> ${this._t(this._imperial?"space.scale_unit_imperial":"space.scale_unit")}
@@ -7375,10 +7375,10 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t(i)} ${"temp"===e&&"temp"===t.fillMode?W` {const i=Bf(e.target.value);null!=i&&(this._spaceDialog={...t,tempMin:i})}} /> + @input=${e=>{const i=qf(e.target.value);null!=i&&(this._spaceDialog={...t,tempMin:i})}} /> – {const i=Bf(e.target.value);null!=i&&(this._spaceDialog={...t,tempMax:i})}} /> + @input=${e=>{const i=qf(e.target.value);null!=i&&(this._spaceDialog={...t,tempMax:i})}} /> °C `:G} @@ -7535,4 +7535,4 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="cdbf6c9487767779ce784762ee48b32c7be4 ${this._t("btn.save")} `}
- `}}hv.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_hoverRoom:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_wallDialog:{state:!0},_drawWallField:{state:!0},_activeDraftId:{state:!0},_physicalSel:{state:!0},_physicalDialog:{state:!0},_partitionDeleteDialog:{state:!0},_roomDeleteDialog:{state:!0},_physicalDrag:{state:!0},_physicalRotate:{state:!0},_duplicateColumnId:{state:!0},_rszSel:{state:!0},_rszLive:{state:!0},_opMeasure:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingPreset:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorEraseConfirm:{state:!0},_decorTextDialog:{state:!0},_decorShapeDialog:{state:!0},_backdropDialog:{state:!0},_furnPalette:{state:!0},_bdDrag:{state:!0},_dtBox:{state:!0},_dtDrag:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_vacAllCamerasFor:{state:!0},_vacCalConfirm:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomCustomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_alignDialog:{state:!0},_preflightClipboardFallback:{state:!0},_backupExportDialog:{state:!0},_backupImportDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},hv.ZOOM_MAX=8,hv.ZOOM_MIN=1/3,hv.styles=[Kt,H_],customElements.get("houseplan-card")||customElements.define("houseplan-card",hv),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info(`%c HOUSEPLAN-CARD %c v${Ff} `,"background:#3ea6ff;color:#04121f;font-weight:700",""); + `}}dv.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_tapConfirm:{state:!0},hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_hoverRoom:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_wallDialog:{state:!0},_drawWallField:{state:!0},_activeDraftId:{state:!0},_physicalSel:{state:!0},_physicalDialog:{state:!0},_partitionDeleteDialog:{state:!0},_roomDeleteDialog:{state:!0},_physicalDrag:{state:!0},_physicalRotate:{state:!0},_duplicateColumnId:{state:!0},_rszSel:{state:!0},_rszLive:{state:!0},_opMeasure:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingPreset:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorEraseConfirm:{state:!0},_decorTextDialog:{state:!0},_decorShapeDialog:{state:!0},_backdropDialog:{state:!0},_furnPalette:{state:!0},_bdDrag:{state:!0},_dtBox:{state:!0},_dtDrag:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_vacAllCamerasFor:{state:!0},_vacCalConfirm:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomCustomFill:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_alignDialog:{state:!0},_preflightClipboardFallback:{state:!0},_backupExportDialog:{state:!0},_backupImportDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},dv.ZOOM_MAX=8,dv.ZOOM_MIN=1/3,dv.styles=[Kt,H_],customElements.get("houseplan-card")||customElements.define("houseplan-card",dv),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info(`%c HOUSEPLAN-CARD %c v${Ef} `,"background:#3ea6ff;color:#04121f;font-weight:700",""); diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 73a82c58..5c123836 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -7,6 +7,12 @@ example one that still carried an orphan legacy border) instead of demanding a card update that was already installed ([#319](https://github.com/Matysh/houseplan-card/issues/319)). +- Drawing works again everywhere: converting a plan to the new wall model no + longer stops on a legacy border/opening conflict. A door standing inside a + former «border» keeps its real wall (the gap continues on both sides), an + ambiguous carrier is resolved deterministically, and an opening with no + usable wall at all is kept as data — inert until you re-place it + ([#316](https://github.com/Matysh/houseplan-card/issues/316)). ## v1.68.0-beta.3 — 2026-08-26 diff --git a/docs/CHANGELOG.ru.md b/docs/CHANGELOG.ru.md index f2f6da67..73514cd3 100755 --- a/docs/CHANGELOG.ru.md +++ b/docs/CHANGELOG.ru.md @@ -13,6 +13,12 @@ документа (например, с осиротевшей легаси-границей) вместо требования обновить уже обновлённую карточку ([#319](https://github.com/Matysh/houseplan-card/issues/319)). +- Рисование снова работает везде: преобразование плана к новой модели стен + больше не останавливается на конфликте легаси-границы с проёмом. Дверь + внутри бывшей «границы» сохраняет настоящую стену (разрыв продолжается по + обе стороны), неоднозначный носитель выбирается детерминированно, а проём + вовсе без пригодной стены сохраняется в данных — бездействует, пока его не + переставят ([#316](https://github.com/Matysh/houseplan-card/issues/316)). ## v1.68.0-beta.3 — 2026-08-26 diff --git a/docs/CONFIG-COMPATIBILITY.md b/docs/CONFIG-COMPATIBILITY.md index 9e1067e1..377502d7 100644 --- a/docs/CONFIG-COMPATIBILITY.md +++ b/docs/CONFIG-COMPATIBILITY.md @@ -90,9 +90,16 @@ transmit Glow and sunlight, while solid zero walls are exact line barriers. documents only. Explicit valid spans win; `open_to` expands to the full proven shared boundary only when spans are absent. The first structural write, confirmed **Optimize plans**, or import into a current target atomizes that -geometry into stable `wall_segments[].cm=0`, preserves surviving IDs, verifies -that no opening would acquire a zero host, and then removes both legacy fields -in one transaction. A conflict rejects the complete candidate. Presentation, +geometry into stable `wall_segments[].cm=0`, preserves surviving IDs, and then +removes both legacy fields in one transaction. An opening never blocks that +migration (#316): the atom carrying an existing opening keeps its positive +thickness (the zero run continues on both sides), an ambiguous carrier is +resolved deterministically (current host, then distance, thicker cm, smaller +id), and an opening with no usable carrier at all persists **unhosted** — a +valid degraded v9 state that is inert in the physics (no body, tunnel or cut), +renders by its own `x/y`, survives later writes untouched and may be re-placed +in the editor. Post-migration structural writes keep the fail-closed refusal +for an opening that LOST its carrier. Presentation, marker and ordinary space-settings writes do not trigger the migration. There is deliberately no provenance flag. Existing v8 `cm:0` and atoms derived diff --git a/docs/images/screenshots.json b/docs/images/screenshots.json index b14cb57b..ee9ad8f6 100644 --- a/docs/images/screenshots.json +++ b/docs/images/screenshots.json @@ -2,7 +2,7 @@ "version": 1, "fixture": "synthetic-only", "chromium": "151.0.7922.34", - "sourceFingerprint": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceFingerprint": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "captureScriptSha256": "ce2e9542fed9dade3085be87d16f69adb2ac8262893ad78ad966b1b9673f2983", "command": "npm run build && node demo/docs/capture.mjs", "scenarios": { @@ -14,7 +14,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "9190bd86a07b0cb0502019d76d3286c0542181e1b4a4f862077d9cefa120613c" }, "view-touch": { @@ -25,7 +25,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "cfa2f77eb68df69ae9fc9b51ffe2f14df01f7b74444fd2b038cadc1e9dfee22b" }, "space-create": { @@ -36,7 +36,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "a86d4211af24923d5048e9094d0d35f9b28129394d00cd72582a8f8c2dd7ff75" }, "room-contour-close": { @@ -47,7 +47,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "c7effd4ccd19bcaff9138458583368aaab488dcb6fc7ea5ab766383cb5377ac4" }, "plan-context-tray": { @@ -58,7 +58,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "af1194f073f00b03af02b949a072cffb21bfd29995aa65a067eaaaec74ef8490" }, "device-editor": { @@ -69,7 +69,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "36ed21b66920ff2de9e3346cf6f27c67e64a9f81692599b9c70d8373f5eb7241" }, "device-display-preview": { @@ -80,7 +80,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "7151c96dc048381f7a7070ecb85a82a890b2f4c703628f14fa472eb8dacbf3dc" }, "background-editor": { @@ -91,7 +91,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "9f08f3f3711b100d68fb1a05af269e43e47d8f8d12c0cbe4f9ab557138722989" }, "room-card": { @@ -102,7 +102,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "66d8b0a509909822ff6b891a483bad9d2c72b20f08e287355883aa5205c6cee0" }, "device-info": { @@ -113,7 +113,7 @@ }, "theme": "dark", "language": "en", - "sourceSha256": "4e7b4a7dc71cb9f1bb89caddbac0e70fee49088369165368845fcf1988867577", + "sourceSha256": "1f20c9d64ca59363be3909accd069595b4fe18404ee7a28a5db479dac605661a", "imageSha256": "83620033bb66edf7c804619261e4a62327049c178267f0837bd997627ffdc003" } } diff --git a/scripts/config-field-registry.mjs b/scripts/config-field-registry.mjs index bdb92d86..447d1acd 100644 --- a/scripts/config-field-registry.mjs +++ b/scripts/config-field-registry.mjs @@ -292,13 +292,13 @@ export const CONFIG_FIELD_REGISTRY = Object.freeze([ selector: { path: ['spaces', '*', 'openings', '*', 'host', 'kind'], equals: 'wall' }, storage: 'House Plan server config', type: "{ kind: 'wall'; id: string; t: number }", - default: 'required for contour openings in model v8', + default: 'materialized by migration (#316 §3); may persist unhosted after degraded migration', level: 'opening', ui: 'internal opening ownership', runtime: 'binds an opening to a stable contour-wall segment', introduced: 'model v8 / issue #282', status: 'current', - migration: 'materialize only when exactly one carrier is proven', + migration: 'auto-resolved per #316 §3.1-3.3; unhosted is the degraded terminal state', compatibility: 'legacy unhosted openings remain readable before migration', }, { diff --git a/scripts/mutation-gate.mjs b/scripts/mutation-gate.mjs index 8c6e0681..78e1aae8 100644 --- a/scripts/mutation-gate.mjs +++ b/scripts/mutation-gate.mjs @@ -2257,6 +2257,35 @@ export const MUTANTS = [ replace: " const spacesById = new Map(((this._serverCfg as any)?.spaces || [])", }], }, + { + id: 'span-cut-erases-the-door-wall', + // #316 §3.1: легаси-кат обязан щадить атом, несущий проём — иначе дверь + // остаётся на нулевой стене и миграция деградирует без нужды. + guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs ' + + '&& node --test --test-name-pattern="keeps its wall through a legacy span cut" ' + + 'test/wall-segment-model.test.mjs', + because: 'дверь внутри бывшей «границы» стояла в настоящей стене — занулять её атом значит переписать план (#316)', + patches: [{ + file: 'src/wall-segment-model.ts', + find: " atom.zeroWall ||= coveredBy(canonicalZeroCuts)\n || (coveredBy(legacyCuts) && !atomCarriesOpening(a, b));", + replace: " atom.zeroWall ||= coveredBy(canonicalZeroCuts) || coveredBy(legacyCuts);", + }], + }, + { + id: 'migration-throws-over-an-opening-again', + // #316 §3.4: initial migration никогда не кидает opening-host — реверт + // возвращает глобальный блокер рисования beta.3. + guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs ' + + '&& node --test --test-name-pattern="migrates unhosted instead of blocking" ' + + 'test/wall-segment-model.test.mjs ' + + '&& node demo/smoke_zero_wall_migration_unblocked.mjs', + because: 'один конфликтный проём снова заблокировал бы структурные записи во всех пространствах (#316)', + patches: [{ + file: 'src/wall-segment-model.ts', + find: " if (initialMigration) { delete opening.host; continue; }", + replace: " if (initialMigration) throw new WallSegmentModelError('opening-host', opening.id);", + }], + }, { id: 'preflight-fallback-survives-dialog-close', // CODE-REVIEW-295-r1 M2: инлайн-фолбэк живёт одно показание диалога; diff --git a/src/wall-segment-model.ts b/src/wall-segment-model.ts index 494e9a04..d6d4d804 100644 --- a/src/wall-segment-model.ts +++ b/src/wall-segment-model.ts @@ -332,13 +332,54 @@ const buildAtoms = ( } } const cuts = [...canonicalZeroCuts, ...legacyCuts]; + // #316 §3.1: a legacy open_spans/open_to cut never zeroes the atom that + // carries an existing contour opening — if a door stands inside a former + // "border", the wall under it was real and stays real. The zero run + // continues on both sides, so the opening's edges become atom boundaries. + const legacyEraOpenings: OpeningCfg[] = legacyCuts.length + ? ((Array.isArray(space.openings) ? space.openings : []) as OpeningCfg[]) + .filter((opening) => opening.host?.kind !== 'partition' + && [Number(opening.x), Number(opening.y)].every(Number.isFinite) + && Number.isFinite(Number(opening.angle)) + && Number(opening.length) > 0 + // Only an opening that actually stands on a legacy cut changes the + // atomization; unrelated openings must not churn the catalogue. + && legacyCuts.some((cut) => distanceToSegment( + [Number(opening.x), Number(opening.y)], + [cut[0], cut[1]], [cut[2], cut[3]], + ) <= GRID_STEP_N * 0.04)) + : []; + const openingEdgeBreaks: WallEntry[] = legacyEraOpenings.map((opening) => { + const rad = (Number(opening.angle) * Math.PI) / 180; + const dir = [Math.cos(rad), Math.sin(rad)]; + const half = Number(opening.length) / 2; + const centre = [Number(opening.x), Number(opening.y)]; + return { + a: [centre[0] - dir[0] * half, centre[1] - dir[1] * half], + b: [centre[0] + dir[0] * half, centre[1] + dir[1] * half], + } as WallEntry; + }); + const atomCarriesOpening = (a: number[], b: number[]): boolean => ( + legacyEraOpenings.some((opening) => { + const centre = [Number(opening.x), Number(opening.y)]; + if (!wallAngleMatches(a, b, Number(opening.angle))) return false; + if (distanceToSegment(centre, a, b) > GRID_STEP_N * 0.02) return false; + const span = lengthOf(a, b); + const tc = projectT(centre, a, b) * span; + const half = Number(opening.length) / 2; + return tc + half >= -EPS && tc - half <= span + EPS; + }) + ); const byKey = new Map(); const nextRooms: any[] = []; for (const rawRoom of rooms) { const id = String(rawRoom?.id || ''); const original = roomPoly(rawRoom); if (!id || !original || original.length < 3) throw new WallSegmentModelError('invalid-room', id); - const atomic = atomicPolyForRoom(rooms, id, cuts, GRID_STEP_N, 1, space.walls || []); + const atomic = atomicPolyForRoom( + rooms, id, cuts, GRID_STEP_N, 1, + [...(space.walls || []), ...openingEdgeBreaks], + ); if (!atomic || atomic.poly.length < 3) throw new WallSegmentModelError('invalid-room', id); const oldIds = Array.isArray(rawRoom.wall_ids) ? rawRoom.wall_ids : []; const indexedLineageIsValid = oldIds.length === original.length; @@ -399,9 +440,13 @@ const buildAtoms = ( original[parent], original[(parent + 1) % original.length], GRID_STEP_N, )); const midpoint = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2]; - atom.zeroWall ||= cuts.some((cut) => distanceToSegment( + const coveredBy = (list: number[][]): boolean => list.some((cut) => distanceToSegment( midpoint, [cut[0], cut[1]], [cut[2], cut[3]], ) <= GRID_STEP_N * 0.04); + // Canonical cm:0 atoms stay zero; a LEGACY cut spares the atom that + // carries an opening (#316 §3.1). + atom.zeroWall ||= coveredBy(canonicalZeroCuts) + || (coveredBy(legacyCuts) && !atomCarriesOpening(a, b)); wallIds.push(key); // replaced with stable ids after lineage resolution } // Re-add the owned field last on every pass. Several legacy maintenance @@ -614,13 +659,74 @@ export const resolveRoomOpeningHost = ( }; }; -const hostRoomOpenings = (space: any, segments: readonly WallSegmentEntry[]): void => { +/** #316 §3.2/§3.3: deterministic migration-time host resolution. Returns null + * only when the space has no usable carrier at all — the opening then persists + * unhosted (§3.3) instead of blocking the migration. */ +const migrateRoomOpeningHost = ( + opening: OpeningCfg, segments: readonly WallSegmentEntry[], +): WallOpeningHost | null => { + const centre = [Number(opening.x), Number(opening.y)]; + if (!centre.every(Number.isFinite)) return null; + const half = Number(opening.length) / 2; + const eligible = segments.filter((segment) => { + if (!(Number(segment.cm) > 0)) return false; + const t = projectT(centre, segment.a, segment.b); + const span = lengthOf(segment.a, segment.b); + return t >= -EPS && t <= 1 + EPS + && distanceToSegment(centre, segment.a, segment.b) <= GRID_STEP_N * 0.02 + && wallAngleMatches(segment.a, segment.b, Number(opening.angle)) + && Number.isFinite(half) && half >= 0 + && t * span - half >= -EPS && t * span + half <= span + EPS; + }); + // §3.2 tie-break: current host → distance → thicker cm → smaller id. + const pick = (candidates: readonly WallSegmentEntry[]): WallSegmentEntry | null => { + if (!candidates.length) return null; + const current = opening.host?.kind === 'wall' + ? candidates.find((segment) => segment.id === opening.host!.id) : null; + if (current) return current; + return [...candidates].sort((x, y) => ( + distanceToSegment(centre, x.a, x.b) - distanceToSegment(centre, y.a, y.b) + || Number(y.cm) - Number(x.cm) + || (x.id < y.id ? -1 : x.id > y.id ? 1 : 0) + ))[0]; + }; + // §3.3 degraded pool: angle- and capacity-compatible positive walls at any + // distance, nearest first. + const degraded = segments.filter((segment) => ( + Number(segment.cm) > 0 + && wallAngleMatches(segment.a, segment.b, Number(opening.angle)) + && Number.isFinite(half) && half >= 0 + && lengthOf(segment.a, segment.b) + EPS >= Number(opening.length) + )); + const host = pick(eligible) ?? pick(degraded); + if (!host) return null; + return { + kind: 'wall', id: host.id, + t: Math.max(0, Math.min(1, projectT(centre, host.a, host.b))), + }; +}; + +const hostRoomOpenings = ( + space: any, segments: readonly WallSegmentEntry[], initialMigration: boolean, +): void => { const openings: OpeningCfg[] = Array.isArray(space.openings) ? space.openings : []; for (const opening of openings) { if (opening.host?.kind === 'partition') continue; - const host = resolveRoomOpeningHost(opening, segments); - if (!host) throw new WallSegmentModelError('opening-host', opening.id); - opening.host = host; + // #316 §3.3: an unhosted opening is a valid degraded v9 state — inert in + // the physics, rendered by its own x/y. A later write keeps it and may + // self-heal it when a unique carrier appears; it never blocks the write. + if (!opening.host && !initialMigration) { + const healed = resolveRoomOpeningHost(opening, segments); + if (healed) opening.host = healed; + continue; + } + const host = resolveRoomOpeningHost(opening, segments) + ?? (initialMigration ? migrateRoomOpeningHost(opening, segments) : null); + if (host) { opening.host = host; continue; } + // #316 §3.4: the initial migration never throws over an opening; a + // post-v9 write that LOST a carrier keeps the fail-closed refusal. + if (initialMigration) { delete opening.host; continue; } + throw new WallSegmentModelError('opening-host', opening.id); } }; @@ -703,7 +809,7 @@ const migrateSpace = ( delete space.open_spans; for (const room of space.rooms) delete room.open_to; migrateDraftSegments(space, initialMigration); - hostRoomOpenings(space, segments); + hostRoomOpenings(space, segments, initialMigration); return segments.reduce((count, segment) => count + (old.has(segment.id) ? 0 : 1), 0); }; diff --git a/test/fixtures/316-span-over-door-migrated.json b/test/fixtures/316-span-over-door-migrated.json new file mode 100644 index 00000000..21316deb --- /dev/null +++ b/test/fixtures/316-span-over-door-migrated.json @@ -0,0 +1,258 @@ +{ + "comment": "stored: a pre-migration v8 document — a room whose top wall carries a door and is fully covered by a legacy open_span; migrated: the same document after the current initial migration (#316 §3.1) — the door keeps its carrying atom, the border is zero on both sides. The golden scene renders `migrated`; the unit test pins it to the real writer byte for byte.", + "stored": { + "model_version": 8, + "spaces": [ + { + "id": "golden-span-over-door", + "title": "Span over door", + "cell_cm": 5, + "view_box": [ + 0, + 0, + 1, + 0.7 + ], + "settings": { + "fill_mode": "none", + "show_borders": true, + "show_names": true + }, + "rooms": [ + { + "id": "sod-room", + "name": "Room", + "area": null, + "poly": [ + [ + 0.2, + 0.3 + ], + [ + 0.6, + 0.3 + ], + [ + 0.6, + 0.6 + ], + [ + 0.2, + 0.6 + ] + ] + } + ], + "walls": [ + { + "key": "0.400000,0.300000@0.0000", + "a": [ + 0.2, + 0.3 + ], + "b": [ + 0.6, + 0.3 + ], + "cm": 15 + } + ], + "open_spans": [ + { + "a": [ + 0.2, + 0.3 + ], + "b": [ + 0.6, + 0.3 + ] + } + ], + "openings": [ + { + "id": "sod-door", + "type": "door", + "x": 0.4, + "y": 0.3, + "angle": 0, + "length": 0.09, + "cm": 90, + "flip_v": true + } + ] + } + ], + "markers": [], + "settings": {} + }, + "migrated": { + "model_version": 9, + "spaces": [ + { + "id": "golden-span-over-door", + "title": "Span over door", + "cell_cm": 5, + "view_box": [ + 0, + 0, + 1, + 0.7 + ], + "settings": { + "fill_mode": "none", + "show_borders": true, + "show_names": true + }, + "rooms": [ + { + "id": "sod-room", + "name": "Room", + "area": null, + "poly": [ + [ + 0.2, + 0.3 + ], + [ + 0.355, + 0.3 + ], + [ + 0.445, + 0.3 + ], + [ + 0.6, + 0.3 + ], + [ + 0.6, + 0.6 + ], + [ + 0.2, + 0.6 + ] + ], + "wall_ids": [ + "wall-s2g2iw3nbbxkym6sodv4", + "wall-qmhko777ctlb3hey6c3v", + "wall-odwfy5lyxkwsum2jewma", + "wall-l3r6mytgo2l4so24dljp", + "wall-mzbb6mwcqxj67rhw7mc5", + "wall-uyhvjlqcorfj3orzvhhj" + ] + } + ], + "walls": [ + { + "key": "0.400000,0.300000@0.0000", + "cm": 15, + "a": [ + 0.355, + 0.3 + ], + "b": [ + 0.445, + 0.3 + ] + } + ], + "openings": [ + { + "id": "sod-door", + "type": "door", + "x": 0.4, + "y": 0.3, + "angle": 0, + "length": 0.09, + "cm": 90, + "flip_v": true, + "host": { + "kind": "wall", + "id": "wall-qmhko777ctlb3hey6c3v", + "t": 0.5 + } + } + ], + "wall_segments": [ + { + "id": "wall-uyhvjlqcorfj3orzvhhj", + "a": [ + 0.2, + 0.3 + ], + "b": [ + 0.2, + 0.6 + ], + "cm": 0 + }, + { + "id": "wall-s2g2iw3nbbxkym6sodv4", + "a": [ + 0.2, + 0.3 + ], + "b": [ + 0.355, + 0.3 + ], + "cm": 0 + }, + { + "id": "wall-mzbb6mwcqxj67rhw7mc5", + "a": [ + 0.2, + 0.6 + ], + "b": [ + 0.6, + 0.6 + ], + "cm": 0 + }, + { + "id": "wall-qmhko777ctlb3hey6c3v", + "a": [ + 0.355, + 0.3 + ], + "b": [ + 0.445, + 0.3 + ], + "cm": 15 + }, + { + "id": "wall-odwfy5lyxkwsum2jewma", + "a": [ + 0.445, + 0.3 + ], + "b": [ + 0.6, + 0.3 + ], + "cm": 0 + }, + { + "id": "wall-l3r6mytgo2l4so24dljp", + "a": [ + 0.6, + 0.3 + ], + "b": [ + 0.6, + 0.6 + ], + "cm": 0 + } + ] + } + ], + "markers": [], + "settings": {} + } +} diff --git a/test/golden-matrix.test.mjs b/test/golden-matrix.test.mjs index 56b7a70e..48aef7de 100644 --- a/test/golden-matrix.test.mjs +++ b/test/golden-matrix.test.mjs @@ -367,7 +367,7 @@ test('sun-ray golden requires browser-painted light from a state-only sun entity assert.ok(scenario); const fixture = prepareGoldenFixture(scenario); const space = fixture.config.spaces.find((item) => item.id === scenario.space); - assert.equal(GOLDEN_MATRIX_VERSION, 46); + assert.equal(GOLDEN_MATRIX_VERSION, 47); assert.equal(space.settings.sun_rays, true); assert.equal(scenario.northDeg, 90, 'the sign-sensitive golden must keep a non-zero north direction'); diff --git a/test/wall-segment-model.test.mjs b/test/wall-segment-model.test.mjs index 04cc2fe1..65f15241 100644 --- a/test/wall-segment-model.test.mjs +++ b/test/wall-segment-model.test.mjs @@ -262,18 +262,23 @@ test('room opening host resolver updates t and rejects ambiguous or zero walls', ]), null); }); -test('an ambiguous room opening blocks the complete candidate without mutating input', () => { +test('a corner opening on bodyless walls migrates unhosted instead of blocking (#316 §3.3/§3.4)', () => { + // Until #316 the initial migration refused this candidate outright; the + // reviewed contract degrades it instead and never blocks the write. const input = configOf({ id: 'floor', title: 'Floor', rooms: [rectangle('room')], openings: [{ id: 'door', type: 'door', x: 0, y: 0, angle: 0, length: 0.2 }], }); const before = structuredClone(input); - assert.throws( - () => commitWallSegmentModel(input), - (error) => error instanceof WallSegmentModelError && error.reason === 'opening-host', - ); - assert.deepEqual(input, before); + const out = commitWallSegmentModel(input).config; + assert.deepEqual(input, before, 'the input candidate is never mutated'); + // Since #306 an unconfigured contour is explicitly bodyless (cm: 0), and a + // zero wall is never an opening carrier — the corner door therefore + // migrates UNHOSTED (§3.3) instead of blocking the whole candidate. + assert.equal('host' in out.spaces[0].openings[0], false); + const again = commitWallSegmentModel(structuredClone(out)).config; + assert.equal(JSON.stringify(again), JSON.stringify(out), 'the outcome is stable'); }); test('draft segment ids materialise once and remain stable', () => { @@ -391,3 +396,100 @@ test('every frontend structural transaction crosses the wall identity barrier', assert.doesNotMatch(commitMethod, /this\._writeConfig\(/, 'the common barrier must finish before the existing persistence path runs'); }); + +// --- #316: the initial migration auto-resolves opening-host conflicts --- + +const spanDoorConfig = () => ({ + model_version: 8, + spaces: [{ + id: 'B', title: 'B', cell_cm: 5, view_box: [0, 0, 1, 0.7], + rooms: [{ id: 'rB', poly: [[0.2, 0.2], [0.6, 0.2], [0.6, 0.5], [0.2, 0.5]] }], + walls: [{ key: wallKey([0.2, 0.2], [0.6, 0.2], GRID_STEP_N), + a: [0.2, 0.2], b: [0.6, 0.2], cm: 15 }], + open_spans: [{ a: [0.2, 0.2], b: [0.6, 0.2] }], + openings: [{ id: 'op1', type: 'door', x: 0.4, y: 0.2, angle: 0, length: 0.09, cm: 90 }], + }], + markers: [], settings: {}, +}); + +test('an opening keeps its wall through a legacy span cut (#316 §3.1) and the run stays idempotent', () => { + const out = commitWallSegmentModel(spanDoorConfig()).config; + const space = out.spaces[0]; + const top = space.wall_segments + .filter((s) => Math.abs(s.a[1] - 0.2) < 1e-9 && Math.abs(s.b[1] - 0.2) < 1e-9) + .sort((x, y) => x.a[0] - y.a[0]); + assert.equal(top.length, 3, 'the opening edges split the span run into three atoms'); + assert.equal(top[0].cm, 0, 'left of the door the border stays zero'); + assert.ok(top[1].cm > 0, 'the atom under the door keeps its real thickness'); + assert.equal(top[2].cm, 0, 'right of the door the border stays zero'); + assert.deepEqual(space.openings[0].host, { kind: 'wall', id: top[1].id, t: 0.5 }); + assert.equal('open_spans' in space, false); + const again = commitWallSegmentModel(structuredClone(out)).config; + assert.equal(JSON.stringify(again), JSON.stringify(out), 'commit(commit(x)) == commit(x)'); +}); + +test('an ambiguous carrier is resolved deterministically at a thickness boundary (#316 §3.2)', () => { + // Two contour atoms of one wall meet at x=0.4 (thickness change); a short + // opening centred exactly on the junction fits inside either atom. + const config = { + model_version: 8, + spaces: [{ + id: 'S', title: 'S', cell_cm: 5, view_box: [0, 0, 1, 0.7], + rooms: [{ id: 'r', poly: [[0.2, 0.2], [0.6, 0.2], [0.6, 0.5], [0.2, 0.5]] }], + walls: [ + { key: wallKey([0.2, 0.2], [0.4, 0.2], GRID_STEP_N), + a: [0.2, 0.2], b: [0.4, 0.2], cm: 10 }, + { key: wallKey([0.4, 0.2], [0.6, 0.2], GRID_STEP_N), + a: [0.4, 0.2], b: [0.6, 0.2], cm: 20 }, + ], + openings: [{ id: 'op', type: 'door', x: 0.4, y: 0.2, angle: 0, length: 0, cm: 0 }], + }], + markers: [], settings: {}, + }; + const out = commitWallSegmentModel(structuredClone(config)).config; + const space = out.spaces[0]; + const host = space.openings[0].host; + assert.equal(host?.kind, 'wall'); + const carrier = space.wall_segments.find((s) => s.id === host.id); + assert.ok(carrier, 'the picked carrier exists in the catalogue'); + // §3.2: equal distance → the thicker atom wins. + assert.equal(carrier.cm, 20); + const again = commitWallSegmentModel(structuredClone(out)).config; + assert.equal(JSON.stringify(again), JSON.stringify(out), 'the pick is stable'); +}); + +test('an opening with no usable carrier migrates unhosted and survives later writes (#316 §3.3/§3.4)', () => { + const config = spanDoorConfig(); + // The opening is far from every wall and across the grain — no carrier. + config.spaces[0].openings[0] = { + id: 'orphan', type: 'door', x: 0.9, y: 0.65, angle: 90, length: 0.05, cm: 90, + }; + const out = commitWallSegmentModel(structuredClone(config)).config; + const opening = out.spaces[0].openings[0]; + assert.equal('host' in opening, false, 'the orphan persists unhosted'); + // A later structural write keeps it and does not throw (§3.3). + const again = commitWallSegmentModel(structuredClone(out)).config; + assert.equal('host' in again.spaces[0].openings[0], false); + assert.equal(JSON.stringify(again), JSON.stringify(out)); +}); + +test('a post-v9 write that LOST its carrier keeps the fail-closed refusal (#316 AC5)', () => { + const migrated = commitWallSegmentModel(spanDoorConfig()).config; + const broken = structuredClone(migrated); + // Point the hosted opening at a segment id that no longer exists. + broken.spaces[0].openings[0].host = { kind: 'wall', id: 'wall-gone', t: 0.5 }; + broken.spaces[0].openings[0].x = 0.9; broken.spaces[0].openings[0].y = 0.65; + broken.spaces[0].openings[0].angle = 90; + assert.throws( + () => commitWallSegmentModel(broken), + (error) => error instanceof WallSegmentModelError && error.reason === 'opening-host', + ); +}); + +test('the #316 golden fixture matches the current initial migration byte for byte', () => { + const fixture = JSON.parse(readFileSync( + new URL('./fixtures/316-span-over-door-migrated.json', import.meta.url), 'utf8', + )); + const migrated = commitWallSegmentModel(structuredClone(fixture.stored)).config; + assert.deepEqual(migrated, fixture.migrated); +}); diff --git a/tests_backend/test_wall_segment_model.py b/tests_backend/test_wall_segment_model.py index 109be07c..f6eeb6f0 100644 --- a/tests_backend/test_wall_segment_model.py +++ b/tests_backend/test_wall_segment_model.py @@ -103,7 +103,13 @@ def test_partial_shared_boundary_has_exactly_one_two_owner_atom() -> None: assert list(owners.values()).count(2) == 1 -def test_ambiguous_opening_blocks_without_mutating_source() -> None: +def test_corner_opening_on_bodyless_walls_migrates_unhosted() -> None: + """#316 §3.3/§3.4: the initial migration degrades instead of blocking. + + Since #306 an unconfigured contour is explicitly bodyless (cm 0) and a + zero wall is never an opening carrier, so the corner door persists + unhosted; the migration never throws over an opening. + """ source = _config({ "id": "floor", "rooms": [_room("room")], "openings": [{ @@ -112,9 +118,10 @@ def test_ambiguous_opening_blocks_without_mutating_source() -> None: }], }) original = copy.deepcopy(source) - with pytest.raises(WallSegmentMigrationError, match="opening-host"): - commit_wall_segment_model(source) + migrated, _ = commit_wall_segment_model(source) assert source == original + assert "host" not in migrated["spaces"][0]["openings"][0] + assert commit_wall_segment_model(migrated)[0] == migrated def test_post_v8_new_atoms_are_random_and_promoted_draft_id_survives() -> None: @@ -369,7 +376,7 @@ def test_v8_open_span_migrates_to_zero_atoms_and_removes_legacy_fields() -> None assert commit_wall_segment_model(migrated)[0] == migrated -def test_v8_open_span_over_an_opening_blocks_atomically() -> None: +def test_v8_open_span_over_an_opening_spares_the_carrying_atom() -> None: base, _ = commit_wall_segment_model(_config({ "id": "floor", "rooms": [_room("room")], })) @@ -390,6 +397,50 @@ def test_v8_open_span_over_an_opening_blocks_atomically() -> None: base["model_version"] = 8 before = copy.deepcopy(base) + # #316 §3.1: the atom carrying the hosted door keeps its thickness while + # the rest of the span run turns to zero on both sides of the opening. + migrated, _ = commit_wall_segment_model(base) + assert base == before + space = migrated["spaces"][0] + bottom = sorted( + (segment for segment in space["wall_segments"] + if abs(segment["a"][1]) < 1e-9 and abs(segment["b"][1]) < 1e-9), + key=lambda segment: segment["a"][0], + ) + assert [segment["cm"] for segment in bottom] == [0.0, 15.0, 0.0] + host = space["openings"][0]["host"] + assert host["kind"] == "wall" and host["id"] == bottom[1]["id"] + assert "open_spans" not in space + assert commit_wall_segment_model(migrated)[0] == migrated + + +def test_unhosted_contour_opening_is_a_valid_degraded_v9_state() -> None: + """#316 AC4: schema and repeat writes keep the unhosted opening.""" + source = _config({ + "id": "floor", "rooms": [_room("room")], + "openings": [{ + "id": "orphan", "type": "door", "x": 0.9, "y": 0.65, + "angle": 90, "length": 0.05, + }], + }) + migrated, _ = commit_wall_segment_model(source) + opening = migrated["spaces"][0]["openings"][0] + assert "host" not in opening + validated = CONFIG_SCHEMA(copy.deepcopy(migrated)) + assert "host" not in validated["spaces"][0]["openings"][0] + assert commit_wall_segment_model(migrated)[0] == migrated + + +def test_post_v9_write_that_lost_its_carrier_keeps_the_refusal() -> None: + """#316 AC5: only the INITIAL migration degrades; a v9 write fails closed.""" + base, _ = commit_wall_segment_model(_config({ + "id": "floor", "rooms": [_room("room")], + })) + space = base["spaces"][0] + space["openings"] = [{ + "id": "door", "type": "door", "x": 0.9, "y": 0.65, + "angle": 90, "length": 0.05, + "host": {"kind": "wall", "id": "wall-gone", "t": 0.5}, + }] with pytest.raises(WallSegmentMigrationError, match="opening-host"): commit_wall_segment_model(base) - assert base == before