diff --git a/custom_components/houseplan/frontend/houseplan-assets/editor-DMlizeQy.js b/custom_components/houseplan/frontend/houseplan-assets/editor-DMlizeQy.js new file mode 100644 index 00000000..303a4630 --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/editor-DMlizeQy.js @@ -0,0 +1,14 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";import{c as e,l as o,t,d2 as s,A as a,b as l}from"./houseplan-card-OQuczTJf.js";class i extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],l=this._floorToken;l&&a.push({value:l,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const i="string"==typeof this._config?.floor?this._config.floor:"";i&&!e.some(e=>e.value===i)&&a.push({value:i,label:i}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;this._loadSpaces();const e=this._lang,o={title:t(e,"editor.title"),floor:t(e,"editor.floor"),default_floor:t(e,"editor.default_floor"),language:t(e,"editor.language"),icon_size:t(e,"editor.icon_size"),show_temperature:t(e,"editor.show_temperature"),live_states:t(e,"editor.live_states"),show_signal:t(e,"editor.show_signal"),kiosk:t(e,"editor.kiosk"),cycle:t(e,"editor.cycle")},s=this._schema,i=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),n=e=>l`o[e.name]||e.name} + @value-changed=${this._valueChanged} + >`;return l` + ${n(s.slice(0,3))} + ${i?l``:a} + ${n(s.slice(3))} + `}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}i.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",i); diff --git a/custom_components/houseplan/frontend/houseplan-assets/houseplan-card-OQuczTJf.js b/custom_components/houseplan/frontend/houseplan-assets/houseplan-card-OQuczTJf.js new file mode 100644 index 00000000..4e59d7d6 --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/houseplan-card-OQuczTJf.js @@ -0,0 +1,5238 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";const e=globalThis,t=e.ShadowRoot&&(void 0===e.ShadyCSS||e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),n=new WeakMap;let r=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const i=this.t;if(t&&void 0===e){const t=void 0!==i&&1===i.length;t&&(e=n.get(i)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),t&&n.set(i,e))}return e}toString(){return this.cssText}};const o=(e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,i,n)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+e[n+1],e[0]);return new r(n,e,i)},s=t?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return(e=>new r("string"==typeof e?e:e+"",void 0,i))(t)})(e):e,{is:a,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:u}=Object,p=globalThis,_=p.trustedTypes,m=_?_.emptyScript:"",g=p.reactiveElementPolyfillSupport,f=(e,t)=>e,v={toAttribute(e,t){switch(t){case Boolean:e=e?m:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},y=(e,t)=>!a(e,t),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=b){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&l(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:r}=c(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);r?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??b}static _$Ei(){if(this.hasOwnProperty(f("elementProperties")))return;const e=u(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(f("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(f("properties"))){const e=this.properties,t=[...h(e),...d(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(s(e))}else void 0!==e&&t.push(s(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.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(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,n)=>{if(t)i.adoptedStyleSheets=n.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const t of n){const n=document.createElement("style"),r=e.litNonce;void 0!==r&&n.setAttribute("nonce",r),n.textContent=t.cssText,i.appendChild(n)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const r=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(t,i.type);this._$Em=e,null==r?this.removeAttribute(n):this.setAttribute(n,r),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),r="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:v;this._$Em=n;const o=r.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,r){if(void 0!==e){const o=this.constructor;if(!1===n&&(r=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??y)(r,t)||i.useDefault&&i.reflect&&r===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:r},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==r||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[f("elementProperties")]=new Map,w[f("finalized")]=new Map,g?.({ReactiveElement:w}),(p.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,x=e=>e,$=k.trustedTypes,S=$?$.createPolicy("lit-html",{createHTML:e=>e}):void 0,M="$lit$",R=`lit$${Math.random().toFixed(9).slice(2)}$`,T="?"+R,C=`<${T}>`,D=document,A=()=>D.createComment(""),O=e=>null===e||"object"!=typeof e&&"function"!=typeof e,z=Array.isArray,P="[ \t\n\f\r]",F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,I=/-->/g,E=/>/g,N=RegExp(`>|${P}(?:([^\\s"'>=/]+)(${P}*=${P}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),H=/'/g,L=/"/g,q=/^(?:script|style|textarea|title)$/i,j=e=>(t,...i)=>({_$litType$:e,strings:t,values:i}),B=j(1),W=j(2),U=Symbol.for("lit-noChange"),G=Symbol.for("lit-nothing"),V=new WeakMap,K=D.createTreeWalker(D,129);function Y(e,t){if(!z(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(t):t}const Z=(e,t)=>{const i=e.length-1,n=[];let r,o=2===t?"":3===t?"":"",s=F;for(let t=0;t"===l[0]?(s=r??F,c=-1):void 0===l[1]?c=-2:(c=s.lastIndex-l[2].length,a=l[1],s=void 0===l[3]?N:'"'===l[3]?L:H):s===L||s===H?s=N:s===I||s===E?s=F:(s=N,r=void 0);const d=s===N&&e[t+1].startsWith("/>")?" ":"";o+=s===F?i+C:c>=0?(n.push(a),i.slice(0,c)+M+i.slice(c)+R+d):i+R+(-2===c?t:d)}return[Y(e,o+(e[i]||"")+(2===t?"":3===t?"":"")),n]};class X{constructor({strings:e,_$litType$:t},i){let n;this.parts=[];let r=0,o=0;const s=e.length-1,a=this.parts,[l,c]=Z(e,t);if(this.el=X.createElement(l,i),K.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(n=K.nextNode())&&a.length0){n.textContent=$?$.emptyScript:"";for(let i=0;iz(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==G&&O(this._$AH)?this._$AA.nextSibling.data=e:this.T(D.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:i}=e,n="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=X.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(t);else{const e=new Q(n,this),i=e.u(this.options);e.p(t),this.T(i),this._$AH=e}}_$AC(e){let t=V.get(e.strings);return void 0===t&&V.set(e.strings,t=new X(e)),t}k(e){z(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,n=0;for(const r of e)n===t.length?t.push(i=new ee(this.O(A()),this.O(A()),this,this.options)):i=t[n],i._$AI(r),n++;n2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=G}_$AI(e,t=this,i,n){const r=this.strings;let o=!1;if(void 0===r)e=J(this,e,t,0),o=!O(e)||e!==this._$AH&&e!==U,o&&(this._$AH=e);else{const n=e;let s,a;for(e=r[0],s=0;s{const n=i?.renderBefore??t;let r=n._$litPart$;if(void 0===r){const e=i?.renderBefore??null;n._$litPart$=r=new ee(t.insertBefore(A(),e),e,void 0,i??{})}return r._$AI(e),r},ce=globalThis;let he=class extends w{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=le(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return U}};he._$litElement$=!0,he.finalized=!0,ce.litElementHydrateSupport?.({LitElement:he});const de=ce.litElementPolyfillSupport;de?.({LitElement:he}),(ce.litElementVersions??=[]).push("4.2.2");const ue=2,pe=e=>(...t)=>({_$litDirective$:e,values:t});let _e=class{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}};const{I:me}=se,ge=e=>e,fe=()=>document.createComment(""),ve=(e,t,i)=>{const n=e._$AA.parentNode,r=void 0===t?e._$AB:t._$AA;if(void 0===i){const t=n.insertBefore(fe(),r),o=n.insertBefore(fe(),r);i=new me(t,o,e,e.options)}else{const t=i._$AB.nextSibling,o=i._$AM,s=o!==e;if(s){let t;i._$AQ?.(e),i._$AM=e,void 0!==i._$AP&&(t=e._$AU)!==o._$AU&&i._$AP(t)}if(t!==r||s){let e=i._$AA;for(;e!==t;){const t=ge(e).nextSibling;ge(n).insertBefore(e,r),e=t}}}return i},ye=(e,t,i=e)=>(e._$AI(t,i),e),be={},we=(e,t=be)=>e._$AH=t,ke=e=>{e._$AR(),e._$AA.remove()},xe=(e,t,i)=>{const n=new Map;for(let r=t;r<=i;r++)n.set(e[r],r);return n},$e=pe(class extends _e{constructor(e){if(super(e),e.type!==ue)throw Error("repeat() can only be used in text expressions")}dt(e,t,i){let n;void 0===i?i=t:void 0!==t&&(n=t);const r=[],o=[];let s=0;for(const t of e)r[s]=n?n(t,s):s,o[s]=i(t,s),s++;return{values:o,keys:r}}render(e,t,i){return this.dt(e,t,i).values}update(e,[t,i,n]){const r=(e=>e._$AH)(e),{values:o,keys:s}=this.dt(t,i,n);if(!Array.isArray(r))return this.ut=s,o;const a=this.ut??=[],l=[];let c,h,d=0,u=r.length-1,p=0,_=o.length-1;for(;d<=u&&p<=_;)if(null===r[d])d++;else if(null===r[u])u--;else if(a[d]===s[p])l[p]=ye(r[d],o[p]),d++,p++;else if(a[u]===s[_])l[_]=ye(r[u],o[_]),u--,_--;else if(a[d]===s[_])l[_]=ye(r[d],o[_]),ve(e,l[_+1],r[d]),d++,_--;else if(a[u]===s[p])l[p]=ye(r[u],o[p]),ve(e,r[d],r[u]),u--,p++;else if(void 0===c&&(c=xe(s,p,_),h=xe(a,d,u)),c.has(a[d]))if(c.has(a[u])){const t=h.get(s[p]),i=void 0!==t?r[t]:null;if(null===i){const t=ve(e,r[d]);ye(t,o[p]),l[p]=t}else l[p]=ye(i,o[p]),ve(e,r[d],i),r[t]=null;p++}else ke(r[u]),u--;else ke(r[d]),d++;for(;p<=_;){const t=ve(e,l[_+1]);ye(t,o[p]),l[p++]=t}for(;d<=u;){const e=r[d++];null!==e&&ke(e)}return this.ut=s,we(e,l),U}}),Se=new WeakMap;let Me=0;class Re extends he{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-"+ ++Me,this._focusInitial=()=>{const e=this._focusableElements(),t=e.find(e=>e.hasAttribute("autofocus"))||e[0]||(this._useHaDialog?null:this.renderRoot.querySelector(".close"))||this.renderRoot.querySelector(".surface")||this.renderRoot.querySelector("ha-dialog");t?.focus({preventScroll:!0})},this._requestClose=()=>{this._closing||(this._closing=!0,this.dispatchEvent(new CustomEvent("hp-close",{bubbles:!0,composed:!0})))},this._onKeyDown=e=>{if("Escape"===e.key){e.preventDefault(),e.stopImmediatePropagation(),this._pruneOverlays();const t=this._overlays[this._overlays.length-1];return t?void this._closeOverlay(t,"escape"):void this._requestClose()}if("Tab"!==e.key||this._useHaDialog)return;const t=this.renderRoot.querySelector(".close"),i=t?[t,...this._focusableElements()]:this._focusableElements();if(!i.length)return e.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const n=this._deepActiveElement(),r=i[0],o=i[i.length-1];!e.shiftKey||n!==r&&i.includes(n)?e.shiftKey||n!==o||(e.preventDefault(),r.focus()):(e.preventDefault(),o.focus())},this._onFallbackCancel=e=>{e.preventDefault(),this._requestClose()},this._onFallbackClick=e=>{this.dismissOnScrim&&e.target===e.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const e=this.getRootNode();this._focusRoot=e;const t=Se.get(e)||{dialogs:new Set,opener:this._opener};t.dialogs.add(this),Se.set(e,t),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const e=[...this._overlays];this._overlays=[];for(const t of e.reverse())t.close("disconnect");const t=this._focusRoot,i=this._opener;this._opener=null,this._focusRoot=null;const n=t?Se.get(t):void 0;n?.dialogs.delete(this),super.disconnectedCallback(),t&&n&&requestAnimationFrame(()=>{const e=Se.get(t);if(!e)return;if(!e.dialogs.size)return e.opener?.isConnected&&e.opener.focus({preventScroll:!0}),void Se.delete(t);const n=i?.closest("hp-dialog");i?.isConnected&&n&&e.dialogs.has(n)&&i.focus({preventScroll:!0})})}firstUpdated(e){if(super.firstUpdated(e),!this._useHaDialog){const e=this.renderRoot.querySelector("dialog");e&&!e.open&&e.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let e=document.activeElement;for(;e?.shadowRoot?.activeElement;)e=e.shadowRoot.activeElement;return e&&e!==document.body?e:null}_focusableElements(){const e=["[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(","),t=[],i=new Set,n=r=>{if(!i.has(r)){if(i.add(r),r instanceof HTMLElement){if(r.matches(e)&&t.push(r),r instanceof HTMLSlotElement){for(const e of r.assignedNodes({flatten:!0}))n(e);return}if(r.shadowRoot){for(const e of r.shadowRoot.childNodes)n(e);return}}for(const e of r.childNodes)n(e)}};for(const e of this.childNodes)n(e);const r=this.overlayPortal();return r&&n(r),t.filter(e=>{let t=e;for(;t;){const e=getComputedStyle(t);if(t.hidden||t.inert||"true"===t.getAttribute("aria-hidden")||"none"===e.display||"hidden"===e.visibility)return!1;if(t=t.assignedSlot||t.parentElement||(t.getRootNode()instanceof ShadowRoot?t.getRootNode().host:null),t===this)break}return!0})}_pruneOverlays(){this._overlays=this._overlays.filter(e=>e.owner.isConnected)}_closeOverlay(e,t){const i=this._overlays.findIndex(t=>t.token===e.token);i>=0&&this._overlays.splice(i,1),e.close(t)}registerOverlay(e){this._pruneOverlays();const t=this._overlays.find(t=>t.owner===e.owner);t&&this._overlays.splice(this._overlays.indexOf(t),1);const i=e.group||"transient";for(const e of[...this._overlays].reverse())e.group===i&&this._closeOverlay(e,"exclusive");const n={...e,group:i,token:Symbol("hp-overlay")};this._overlays.push(n);let r=!1;return()=>{if(r)return;r=!0;const e=this._overlays.findIndex(e=>e.token===n.token);e>=0&&this._overlays.splice(e,1)}}closeTransientOverlays(e="outside"){this._pruneOverlays();const t=[...this._overlays].filter(e=>"transient"===(e.group||"transient"));for(const i of t.reverse())this._closeOverlay(i,e);return t.length>0}overlayPortal(){return this.renderRoot.querySelector(".overlay-portal")}render(){const e=B` + ${this.icon?B``:G} + ${this.title} + `;return this._useHaDialog?B` + ${e} + + +
`:B` +
+
+ ${e} + +
+
+ +
+
+
`}}Re.properties={title:{type:String},icon:{type:String},wide:{type:Boolean,reflect:!0},dismissOnScrim:{type:Boolean,attribute:"dismiss-on-scrim"},hass:{attribute:!1}},Re.styles=o` + :host { + display: contents; + color: var(--primary-text-color, #e6e7eb); + font: inherit; + } + + ha-dialog { + --dialog-content-padding: 0; + --dialog-surface-background: var(--card-background-color, var(--hp-bg, #202126)); + --ha-dialog-border-radius: var(--rad-l, 18px); + /* HA's ha-dialog-header defaults this custom property to a one-line + fixed height. Our localized slot is intentionally allowed to wrap, + so leaving that default in place clips every line after the first at + the bottom of the header. auto is HA's public sizing hook and also + stays harmless on older ha-dialog implementations that do not consume + it. */ + --ha-dialog-header-title-height: auto; + color: inherit; + } + + ha-dialog::part(dialog) { + border: 1px solid var(--hp-accent, #d89300); + box-shadow: var(--shadow-3, 0 18px 48px rgb(0 0 0 / 0.34)); + overflow: hidden; + } + + /* The HA header slot is a flex item with a constrained inline size. The + old inline-flex title kept its min-content width, so HA clipped the last + word instead of giving it a second line. Keep every wrapper shrinkable + and let the text wrap; this applies to every hp-dialog, including long + device names and translated titles. */ + .header-title-slot { + display: block; + flex: 1 1 auto; + width: 100%; + max-width: 100%; + min-width: 0; + box-sizing: border-box; + white-space: normal; + } + + .title { + display: flex; + flex: 1 1 auto; + align-items: center; + gap: var(--sp-4, 12px); + width: 100%; + max-width: 100%; + min-width: 0; + font-weight: 600; + line-height: 1.25; + white-space: normal; + } + + .title ha-icon { + flex: none; + color: var(--hp-accent, #d89300); + } + + .title-text { + flex: 1 1 auto; + min-width: 0; + max-width: 100%; + white-space: normal; + overflow-wrap: anywhere; + word-break: normal; + } + + .footer { + /* ha-dialog lays out its footer slot as a flex row. display: contents + exposed the consumer's action row as a shrink-to-fit flex item, so a + wide device dialog got a half-width divider and its Hide action slid + toward the centre. Keep one full-width slot item in both HA and the + native fallback. */ + display: block; + width: 100%; + min-width: 0; + box-sizing: border-box; + } + + ::slotted([slot='footer']) { + width: 100%; + box-sizing: border-box; + } + + dialog { + width: auto; + max-width: none; + max-height: none; + margin: auto; + padding: 0; + border: 0; + overflow: visible; + color: inherit; + background: transparent; + } + + dialog::backdrop { + background: rgb(0 0 0 / 0.45); + } + + .surface { + width: min(360px, 92vw); + max-height: 92vh; + display: flex; + flex-direction: column; + overflow: hidden; + box-sizing: border-box; + color: inherit; + background: var(--card-background-color, var(--hp-bg, #202126)); + border: 1px solid var(--hp-accent, #d89300); + border-radius: var(--rad-l, 18px); + box-shadow: var(--shadow-3, 0 18px 48px rgb(0 0 0 / 0.34)); + } + + :host([wide]) .surface { + width: min(var(--hp-dialog-wide-width, 500px), 94vw); + } + + .header { + min-height: 56px; + display: flex; + align-items: center; + gap: var(--sp-4, 12px); + padding: var(--sp-4, 12px) var(--sp-5, 16px); + box-sizing: border-box; + border-bottom: 1px solid var(--hp-line, rgb(255 255 255 / 0.12)); + } + + .header .title { + flex: 1; + } + + .close { + width: 40px; + height: 40px; + flex: none; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 50%; + cursor: pointer; + } + + :host([data-pointer-hover]) .close:hover, + .close:focus-visible { + background: rgb(127 127 127 / 0.16); + } + + .content { + min-height: 0; + display: flex; + flex-direction: column; + } + + .overlay-portal { + position: fixed; + z-index: 2147483647; + inset: 0; + overflow: visible; + pointer-events: none; + } + + .overlay-portal:empty { + display: none; + } + + .overlay-portal > * { + pointer-events: auto; + } + `,customElements.get("hp-dialog")||customElements.define("hp-dialog",Re);const Te=new Set(["hacs","sun","backup","hassio","met","telegram_bot","mobile_app","systemmonitor","better_thermostat","adaptive_lighting","yandex_pogoda","upnp_serial_number"]),Ce=[{pattern:"протечк|leak|water sensor",icon:"mdi:water-alert"},{pattern:"клапан|valve",icon:"mdi:pipe-valve"},{pattern:"дым|smoke",icon:"mdi:smoke-detector"},{pattern:"термоголов|trv|radiator",icon:"mdi:radiator"},{pattern:"чайник|kettle|термопот",icon:"mdi:kettle"},{pattern:"сауна|sauna|harvia|парная|парилк",icon:"mdi:hot-tub"},{pattern:"температ|temperature|thermometer|climate sensor",icon:"mdi:thermometer"},{pattern:"qingping|air monitor|молекул|air quality",icon:"mdi:air-filter"},{pattern:"штор|curtain|blind|shade",icon:"mdi:roller-shade"},{pattern:"розетк|plug|socket|outlet",icon:"mdi:power-socket-de"},{pattern:"выключат|switch",icon:"mdi:light-switch"},{pattern:"лампа|лампочк|bulb|gx53|светильник|rgb|lamp|light strip",icon:"mdi:lightbulb"},{pattern:"камер|camera",icon:"mdi:cctv"},{pattern:"замок|ttlock|lock|sn609|sn9161",icon:"mdi:lock"},{pattern:"ворота|garage|gate",icon:"mdi:garage-variant"},{pattern:"калитк|door|открыт|contact",icon:"mdi:door"},{pattern:"счётчик|счетчик|kws|meter",icon:"mdi:meter-electric"},{pattern:"вводный автомат|breaker|wifimcbn",icon:"mdi:electric-switch"},{pattern:"myheat|котёл|котел|boiler|отоплен|heating",icon:"mdi:water-boiler"},{pattern:"холодильник|fridge",icon:"mdi:fridge"},{pattern:"стиральн|washer|washing",icon:"mdi:washing-machine"},{pattern:"сушилк|dryer",icon:"mdi:tumble-dryer"},{pattern:"пылесос|vacuum|dreame|roborock",icon:"mdi:robot-vacuum"},{pattern:"soundbar",icon:"mdi:soundbar"},{pattern:"колонк|станц|speaker|яндекс|yandex|алиса|alice",icon:"mdi:speaker"},{pattern:"tv|телевизор|hyundaitv|mitv|television",icon:"mdi:television"},{pattern:"keenetic|роутер|router|mesh|access point",icon:"mdi:router-wireless"},{pattern:"ибп|ups|kirpich",icon:"mdi:battery-charging-high"},{pattern:"slzb|координат|zigbee|coordinator",icon:"mdi:zigbee"},{pattern:"motion|движен|presence|присутств",icon:"mdi:motion-sensor"},{pattern:"humidity|влажн",icon:"mdi:water-percent"}];function De(e){const t=[];for(const i of e)if(i&&"string"==typeof i.pattern&&i.icon)try{t.push({re:new RegExp(i.pattern,"i"),icon:i.icon})}catch{}return t}function Ae(e){try{return new RegExp(e,"i"),!0}catch{return!1}}const Oe=De(Ce),ze={temperature:"mdi:thermometer",humidity:"mdi:water-percent",motion:"mdi:motion-sensor",occupancy:"mdi:motion-sensor",presence:"mdi:motion-sensor",door:"mdi:door",window:"mdi:window-closed",garage_door:"mdi:garage-variant",smoke:"mdi:smoke-detector",moisture:"mdi:water-alert",gas:"mdi:gas-cylinder",power:"mdi:meter-electric",energy:"mdi:meter-electric",illuminance:"mdi:brightness-5",co2:"mdi:molecule-co2",pm25:"mdi:air-filter",battery:"mdi:battery"},Pe="mdi:chip";function Fe(e,t,i){const n=((e||"")+" "+(t||"")).toLowerCase();for(const{re:e,icon:t}of i??Oe)if(e.test(n))return t;return Pe}const Ie=["light","switch","cover","valve","lock","climate","fan","media_player","camera","vacuum","humidifier","water_heater","alarm_control_panel","sensor","binary_sensor","event","button","number","select","update"];var Ee=/^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i,Ne=Math.ceil,He=Math.floor,Le="[BigNumber Error] ",qe=Le+"Number primitive has more than 15 significant digits: ",je=1e14,Be=14,We=9007199254740991,Ue=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],Ge=1e7,Ve=1e9;function Ke(e){var t=0|e;return e>0||e===t?t:t-1}function Ye(e){for(var t,i,n=1,r=e.length,o=e[0]+"";nc^i?1:-1;for(a=(l=r.length)<(c=o.length)?l:c,s=0;so[s]^i?1:-1;return l==c?0:l>c^i?1:-1}function Xe(e,t,i,n){if(ei||e!==He(e))throw Error(Le+(n||"Argument")+("number"==typeof e?ei?" out of range: ":" not an integer: ":" not a primitive number: ")+String(e))}function Je(e){var t=e.c.length-1;return Ke(e.e/Be)==t&&e.c[t]%2!=0}function Qe(e,t){return(e.length>1?e.charAt(0)+"."+e.slice(1):e)+(t<0?"e":"e+")+t}function et(e,t,i){var n,r;if(t<0){for(r=i+".";++t;r+=i);e=r+e}else if(++t>(n=e.length)){for(r=i,t-=n;--t;r+=i);e+=r}else ty?u.c=u.e=null:e.e=10;l/=10,a++);return void(a>y?u.c=u.e=null:(u.e=a,u.c=[e]))}d=String(e)}else{if(!Ee.test(d=String(e)))return r(u,d,c);u.s=45==d.charCodeAt(0)?(d=d.slice(1),-1):1}(a=d.indexOf("."))>-1&&(d=d.replace(".","")),(l=d.search(/e/i))>0?(a<0&&(a=l),a+=+d.slice(l+1),d=d.substring(0,l)):a<0&&(a=d.length)}else{if(Xe(t,2,$.length,"Base"),10==t&&S)return D(u=new M(e),_+u.e+1,m);if(d=String(e),c="number"==typeof e){if(0*e!=0)return r(u,d,c,t);if(u.s=1/e<0?(d=d.slice(1),-1):1,M.DEBUG&&d.replace(/^0\.0*|\./,"").length>15)throw Error(qe+e)}else u.s=45===d.charCodeAt(0)?(d=d.slice(1),-1):1;for(i=$.slice(0,t),a=l=0,h=d.length;la){a=h;continue}}else if(!s&&(d==d.toUpperCase()&&(d=d.toLowerCase())||d==d.toLowerCase()&&(d=d.toUpperCase()))){s=!0,l=-1,a=0;continue}return r(u,String(e),c,t)}c=!1,(a=(d=n(d,t,10,u.s)).indexOf("."))>-1?d=d.replace(".",""):a=d.length}for(l=0;48===d.charCodeAt(l);l++);for(h=d.length;48===d.charCodeAt(--h););if(d=d.slice(l,++h)){if(h-=l,c&&M.DEBUG&&h>15&&(e>We||e!==He(e)))throw Error(qe+u.s*e);if((a=a-l-1)>y)u.c=u.e=null;else if(a=f)?Qe(l,s):et(l,s,"0");else if(o=(e=D(new M(e),t,i)).e,a=(l=Ye(e.c)).length,1==n||2==n&&(t<=o||o<=g)){for(;as),l=et(l,o,"0"),o+1>a){if(--t>0)for(l+=".";t--;l+="0");}else if((t+=o-a)>0)for(o+1==a&&(l+=".");t--;l+="0");return e.s<0&&r?"-"+l:l}function T(e,t){for(var i,n,r=1,o=new M(e[0]);r=10;r/=10,n++);return(i=n+i*Be-1)>y?e.c=e.e=null:i=10;a/=10,r++);if((o=t-r)<0)o+=Be,s=t,l=d[c=0],h=He(l/u[r-s-1]%10);else if((c=Ne((o+1)/Be))>=d.length){if(!n)break e;for(;d.length<=c;d.push(0));l=h=0,r=1,s=(o%=Be)-Be+1}else{for(l=a=d[c],r=1;a>=10;a/=10,r++);h=(s=(o%=Be)-Be+r)<0?0:He(l/u[r-s-1]%10)}if(n=n||t<0||null!=d[c+1]||(s<0?l:l%u[r-s-1]),n=i<4?(h||n)&&(0==i||i==(e.s<0?3:2)):h>5||5==h&&(4==i||n||6==i&&(o>0?s>0?l/u[r-s]:0:d[c-1])%10&1||i==(e.s<0?8:7)),t<1||!d[0])return d.length=0,n?(t-=e.e+1,d[0]=u[(Be-t%Be)%Be],e.e=-t||0):d[0]=e.e=0,e;if(0==o?(d.length=c,a=1,c--):(d.length=c+1,a=u[Be-o],d[c]=s>0?He(l/u[r-s]%u[s])*a:0),n)for(;;){if(0==c){for(o=1,s=d[0];s>=10;s/=10,o++);for(s=d[0]+=a,a=1;s>=10;s/=10,a++);o!=a&&(e.e++,d[0]==je&&(d[0]=1));break}if(d[c]+=a,d[c]!=je)break;d[c--]=0,a=1}for(o=d.length;0===d[--o];d.pop());}e.e>y?e.c=e.e=null:e.e=f?Qe(t,i):et(t,i,"0"),e.s<0?"-"+t:t)}return M.clone=e,M.ROUND_UP=0,M.ROUND_DOWN=1,M.ROUND_CEIL=2,M.ROUND_FLOOR=3,M.ROUND_HALF_UP=4,M.ROUND_HALF_DOWN=5,M.ROUND_HALF_EVEN=6,M.ROUND_HALF_CEIL=7,M.ROUND_HALF_FLOOR=8,M.EUCLID=9,M.config=M.set=function(e){var t,i;if(null!=e){if("object"!=typeof e)throw Error(Le+"Object expected: "+e);if(e.hasOwnProperty(t="DECIMAL_PLACES")&&(Xe(i=e[t],0,Ve,t),_=i),e.hasOwnProperty(t="ROUNDING_MODE")&&(Xe(i=e[t],0,8,t),m=i),e.hasOwnProperty(t="EXPONENTIAL_AT")&&((i=e[t])&&i.pop?(Xe(i[0],-Ve,0,t),Xe(i[1],0,Ve,t),g=i[0],f=i[1]):(Xe(i,-Ve,Ve,t),g=-(f=i<0?-i:i))),e.hasOwnProperty(t="RANGE"))if((i=e[t])&&i.pop)Xe(i[0],-Ve,-1,t),Xe(i[1],1,Ve,t),v=i[0],y=i[1];else{if(Xe(i,-Ve,Ve,t),!i)throw Error(Le+t+" cannot be zero: "+i);v=-(y=i<0?-i:i)}if(e.hasOwnProperty(t="CRYPTO")){if((i=e[t])!==!!i)throw Error(Le+t+" not true or false: "+i);if(i){if("undefined"==typeof crypto||!crypto||!crypto.getRandomValues&&!crypto.randomBytes)throw b=!i,Error(Le+"crypto unavailable");b=i}else b=i}if(e.hasOwnProperty(t="MODULO_MODE")&&(Xe(i=e[t],0,9,t),w=i),e.hasOwnProperty(t="POW_PRECISION")&&(Xe(i=e[t],0,Ve,t),k=i),e.hasOwnProperty(t="FORMAT")){if("object"!=typeof(i=e[t]))throw Error(Le+t+" not an object: "+i);x=i}if(e.hasOwnProperty(t="ALPHABET")){if("string"!=typeof(i=e[t])||/^.?$|[+\-.\s]|(.).*\1/.test(i))throw Error(Le+t+" invalid: "+i);S="0123456789"==i.slice(0,10),$=i}}return{DECIMAL_PLACES:_,ROUNDING_MODE:m,EXPONENTIAL_AT:[g,f],RANGE:[v,y],CRYPTO:b,MODULO_MODE:w,POW_PRECISION:k,FORMAT:x,ALPHABET:$}},M.isBigNumber=function(e){if(!e||!0!==e._isBigNumber)return!1;if(!M.DEBUG)return!0;var t,i,n=e.c,r=e.e,o=e.s;e:if("[object Array]"=={}.toString.call(n)){if((1===o||-1===o)&&r>=-Ve&&r<=Ve&&r===He(r)){if(0===n[0]){if(0===r&&1===n.length)return!0;break e}if((t=(r+1)%Be)<1&&(t+=Be),String(n[0]).length==t){for(t=0;t=je||i!==He(i))break e;if(0!==i)return!0}}}else if(null===n&&null===r&&(null===o||1===o||-1===o))return!0;throw Error(Le+"Invalid BigNumber: "+e)},M.maximum=M.max=function(){return T(arguments,-1)},M.minimum=M.min=function(){return T(arguments,1)},M.random=(o=9007199254740992,s=Math.random()*o&2097151?function(){return He(Math.random()*o)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)},function(e){var t,i,n,r,o,a=0,l=[],c=new M(p);if(null==e?e=_:Xe(e,0,Ve),r=Ne(e/Be),b)if(crypto.getRandomValues){for(t=crypto.getRandomValues(new Uint32Array(r*=2));a>>11))>=9e15?(i=crypto.getRandomValues(new Uint32Array(2)),t[a]=i[0],t[a+1]=i[1]):(l.push(o%1e14),a+=2);a=r/2}else{if(!crypto.randomBytes)throw b=!1,Error(Le+"crypto unavailable");for(t=crypto.randomBytes(r*=7);a=9e15?crypto.randomBytes(7).copy(t,a):(l.push(o%1e14),a+=7);a=r/7}if(!b)for(;a=10;o/=10,a++);ai-1&&(null==s[r+1]&&(s[r+1]=0),s[r+1]+=s[r]/i|0,s[r]%=i)}return s.reverse()}return function(n,r,o,s,a){var l,c,h,d,u,p,g,f,v=n.indexOf("."),y=_,b=m;for(v>=0&&(d=k,k=0,n=n.replace(".",""),p=(f=new M(r)).pow(n.length-v),k=d,f.c=t(et(Ye(p.c),p.e,"0"),10,o,e),f.e=f.c.length),h=d=(g=t(n,r,o,a?(l=$,e):(l=e,$))).length;0==g[--d];g.pop());if(!g[0])return l.charAt(0);if(v<0?--h:(p.c=g,p.e=h,p.s=s,g=(p=i(p,f,y,b,o)).c,u=p.r,h=p.e),v=g[c=h+y+1],d=o/2,u=u||c<0||null!=g[c+1],u=b<4?(null!=v||u)&&(0==b||b==(p.s<0?3:2)):v>d||v==d&&(4==b||u||6==b&&1&g[c-1]||b==(p.s<0?8:7)),c<1||!g[0])n=u?et(l.charAt(1),-y,l.charAt(0)):l.charAt(0);else{if(g.length=c,u)for(--o;++g[--c]>o;)g[c]=0,c||(++h,g=[1].concat(g));for(d=g.length;!g[--d];);for(v=0,n="";v<=d;n+=l.charAt(g[v++]));n=et(n,h,l.charAt(0))}return n}}(),i=function(){function e(e,t,i){var n,r,o,s,a=0,l=e.length,c=t%Ge,h=t/Ge|0;for(e=e.slice();l--;)a=((r=c*(o=e[l]%Ge)+(n=h*o+(s=e[l]/Ge|0)*c)%Ge*Ge+a)/i|0)+(n/Ge|0)+h*s,e[l]=r%i;return a&&(e=[a].concat(e)),e}function t(e,t,i,n){var r,o;if(i!=n)o=i>n?1:-1;else for(r=o=0;rt[r]?1:-1;break}return o}function i(e,t,i,n){for(var r=0;i--;)e[i]-=r,r=e[i]1;e.splice(0,1));}return function(n,r,o,s,a){var l,c,h,d,u,p,_,m,g,f,v,y,b,w,k,x,$,S=n.s==r.s?1:-1,R=n.c,T=r.c;if(!(R&&R[0]&&T&&T[0]))return new M(n.s&&r.s&&(R?!T||R[0]!=T[0]:T)?R&&0==R[0]||!T?0*S:S/0:NaN);for(g=(m=new M(S)).c=[],S=o+(c=n.e-r.e)+1,a||(a=je,c=Ke(n.e/Be)-Ke(r.e/Be),S=S/Be|0),h=0;T[h]==(R[h]||0);h++);if(T[h]>(R[h]||0)&&c--,S<0)g.push(1),d=!0;else{for(w=R.length,x=T.length,h=0,S+=2,(u=He(a/(T[0]+1)))>1&&(T=e(T,u,a),R=e(R,u,a),x=T.length,w=R.length),b=x,v=(f=R.slice(0,x)).length;v=a/2&&k++;do{if(u=0,(l=t(T,f,x,v))<0){if(y=f[0],x!=v&&(y=y*a+(f[1]||0)),(u=He(y/k))>1)for(u>=a&&(u=a-1),_=(p=e(T,u,a)).length,v=f.length;1==t(p,f,_,v);)u--,i(p,x<_?$:T,_,a),_=p.length,l=1;else 0==u&&(l=u=1),_=(p=T.slice()).length;if(_=10;S/=10,h++);D(m,o+(m.e=h+c*Be-1)+1,s,d)}else m.e=c,m.r=+d;return m}}(),a=/^(-?)0([xbo])(?=\w[\w.]*$)/i,l=/^([^.]+)\.$/,c=/^\.([^.]+)$/,h=/^-?(Infinity|NaN)$/,d=/^\s*\+(?=[\w.])|^\s+|\s+$/g,r=function(e,t,i,n){var r,o=i?t:t.replace(d,"");if(h.test(o))e.s=isNaN(o)?null:o<0?-1:1;else{if(!i&&(o=o.replace(a,function(e,t,i){return r="x"==(i=i.toLowerCase())?16:"b"==i?2:8,n&&n!=r?e:t}),n&&(r=n,o=o.replace(l,"$1").replace(c,"0.$1")),t!=o))return new M(o,r);if(M.DEBUG)throw Error(Le+"Not a"+(n?" base "+n:"")+" number: "+t);e.s=null}e.c=e.e=null},u.absoluteValue=u.abs=function(){var e=new M(this);return e.s<0&&(e.s=1),e},u.comparedTo=function(e,t){return Ze(this,new M(e,t))},u.decimalPlaces=u.dp=function(e,t){var i,n,r,o=this;if(null!=e)return Xe(e,0,Ve),null==t?t=m:Xe(t,0,8),D(new M(o),e+o.e+1,t);if(!(i=o.c))return null;if(n=((r=i.length-1)-Ke(this.e/Be))*Be,r=i[r])for(;r%10==0;r/=10,n--);return n<0&&(n=0),n},u.dividedBy=u.div=function(e,t){return i(this,new M(e,t),_,m)},u.dividedToIntegerBy=u.idiv=function(e,t){return i(this,new M(e,t),0,1)},u.exponentiatedBy=u.pow=function(e,t){var i,n,r,o,s,a,l,c,h=this;if((e=new M(e)).c&&!e.isInteger())throw Error(Le+"Exponent not an integer: "+A(e));if(null!=t&&(t=new M(t)),s=e.e>14,!h.c||!h.c[0]||1==h.c[0]&&!h.e&&1==h.c.length||!e.c||!e.c[0])return c=new M(Math.pow(+A(h),s?e.s*(2-Je(e)):+A(e))),t?c.mod(t):c;if(a=e.s<0,t){if(t.c?!t.c[0]:!t.s)return new M(NaN);(n=!a&&h.isInteger()&&t.isInteger())&&(h=h.mod(t))}else{if(e.e>9&&(h.e>0||h.e<-1||(0==h.e?h.c[0]>1||s&&h.c[1]>=24e7:h.c[0]<8e13||s&&h.c[0]<=9999975e7)))return o=h.s<0&&Je(e)?-0:0,h.e>-1&&(o=1/o),new M(a?1/o:o);k&&(o=Ne(k/Be+2))}for(s?(i=new M(.5),a&&(e.s=1),l=Je(e)):l=(r=Math.abs(+A(e)))%2,c=new M(p);;){if(l){if(!(c=c.times(h)).c)break;o?c.c.length>o&&(c.c.length=o):n&&(c=c.mod(t))}if(r){if(0===(r=He(r/2)))break;l=r%2}else if(D(e=e.times(i),e.e+1,1),e.e>14)l=Je(e);else{if(0===(r=+A(e)))break;l=r%2}h=h.times(h),o?h.c&&h.c.length>o&&(h.c.length=o):n&&(h=h.mod(t))}return n?c:(a&&(c=p.div(c)),t?c.mod(t):o?D(c,k,m,void 0):c)},u.integerValue=function(e){var t=new M(this);return null==e?e=m:Xe(e,0,8),D(t,t.e+1,e)},u.isEqualTo=u.eq=function(e,t){return 0===Ze(this,new M(e,t))},u.isFinite=function(){return!!this.c},u.isGreaterThan=u.gt=function(e,t){return Ze(this,new M(e,t))>0},u.isGreaterThanOrEqualTo=u.gte=function(e,t){return 1===(t=Ze(this,new M(e,t)))||0===t},u.isInteger=function(){return!!this.c&&Ke(this.e/Be)>this.c.length-2},u.isLessThan=u.lt=function(e,t){return Ze(this,new M(e,t))<0},u.isLessThanOrEqualTo=u.lte=function(e,t){return-1===(t=Ze(this,new M(e,t)))||0===t},u.isNaN=function(){return!this.s},u.isNegative=function(){return this.s<0},u.isPositive=function(){return this.s>0},u.isZero=function(){return!!this.c&&0==this.c[0]},u.minus=function(e,t){var i,n,r,o,s=this,a=s.s;if(t=(e=new M(e,t)).s,!a||!t)return new M(NaN);if(a!=t)return e.s=-t,s.plus(e);var l=s.e/Be,c=e.e/Be,h=s.c,d=e.c;if(!l||!c){if(!h||!d)return h?(e.s=-t,e):new M(d?s:NaN);if(!h[0]||!d[0])return d[0]?(e.s=-t,e):new M(h[0]?s:3==m?-0:0)}if(l=Ke(l),c=Ke(c),h=h.slice(),a=l-c){for((o=a<0)?(a=-a,r=h):(c=l,r=d),r.reverse(),t=a;t--;r.push(0));r.reverse()}else for(n=(o=(a=h.length)<(t=d.length))?a:t,a=t=0;t0)for(;t--;h[i++]=0);for(t=je-1;n>a;){if(h[--n]=0;){for(i=0,u=y[r]%g,p=y[r]/g|0,o=r+(s=l);o>r;)i=((c=u*(c=v[--s]%g)+(a=p*c+(h=v[s]/g|0)*u)%g*g+_[o]+i)/m|0)+(a/g|0)+p*h,_[o--]=c%m;_[o]=i}return i?++n:_.splice(0,1),C(e,_,n)},u.negated=function(){var e=new M(this);return e.s=-e.s||null,e},u.plus=function(e,t){var i,n=this,r=n.s;if(t=(e=new M(e,t)).s,!r||!t)return new M(NaN);if(r!=t)return e.s=-t,n.minus(e);var o=n.e/Be,s=e.e/Be,a=n.c,l=e.c;if(!o||!s){if(!a||!l)return new M(r/0);if(!a[0]||!l[0])return l[0]?e:new M(a[0]?n:0*r)}if(o=Ke(o),s=Ke(s),a=a.slice(),r=o-s){for(r>0?(s=o,i=l):(r=-r,i=a),i.reverse();r--;i.push(0));i.reverse()}for((r=a.length)-(t=l.length)<0&&(i=l,l=a,a=i,t=r),r=0;t;)r=(a[--t]=a[t]+l[t]+r)/je|0,a[t]=je===a[t]?0:a[t]%je;return r&&(a=[r].concat(a),++s),C(e,a,s)},u.precision=u.sd=function(e,t){var i,n,r,o=this;if(null!=e&&e!==!!e)return Xe(e,1,Ve),null==t?t=m:Xe(t,0,8),D(new M(o),e,t);if(!(i=o.c))return null;if(n=(r=i.length-1)*Be+1,r=i[r]){for(;r%10==0;r/=10,n--);for(r=i[0];r>=10;r/=10,n++);}return e&&o.e+1>n&&(n=o.e+1),n},u.shiftedBy=function(e){return Xe(e,-9007199254740991,We),this.times("1e"+e)},u.squareRoot=u.sqrt=function(){var e,t,n,r,o,s=this,a=s.c,l=s.s,c=s.e,h=_+4,d=new M("0.5");if(1!==l||!a||!a[0])return new M(!l||l<0&&(!a||a[0])?NaN:a?s:1/0);if(0==(l=Math.sqrt(+A(s)))||l==1/0?(((t=Ye(a)).length+c)%2==0&&(t+="0"),l=Math.sqrt(+t),c=Ke((c+1)/2)-(c<0||c%2),n=new M(t=l==1/0?"5e"+c:(t=l.toExponential()).slice(0,t.indexOf("e")+1)+c)):n=new M(l+""),n.c[0])for((l=(c=n.e)+h)<3&&(l=0);;)if(o=n,n=d.times(o.plus(i(s,o,h,1))),Ye(o.c).slice(0,l)===(t=Ye(n.c)).slice(0,l)){if(n.e0&&_>0){for(o=_%a||a,h=p.substr(0,o);o<_;o+=a)h+=c+p.substr(o,a);l>0&&(h+=c+p.slice(o)),u&&(h="-"+h)}n=d?h+(i.decimalSeparator||"")+((l=+i.fractionGroupSize)?d.replace(new RegExp("\\d{"+l+"}\\B","g"),"$&"+(i.fractionGroupSeparator||"")):d):h}return(i.prefix||"")+n+(i.suffix||"")},u.toFraction=function(e){var t,n,r,o,s,a,l,c,h,d,u,_,g=this,f=g.c;if(null!=e&&(!(l=new M(e)).isInteger()&&(l.c||1!==l.s)||l.lt(p)))throw Error(Le+"Argument "+(l.isInteger()?"out of range: ":"not an integer: ")+A(l));if(!f)return new M(g);for(t=new M(p),h=n=new M(p),r=c=new M(p),_=Ye(f),s=t.e=_.length-g.e-1,t.c[0]=Ue[(a=s%Be)<0?Be+a:a],e=!e||l.comparedTo(t)>0?s>0?t:h:l,a=y,y=1/0,l=new M(_),c.c[0]=0;d=i(l,t,0,1),1!=(o=n.plus(d.times(r))).comparedTo(e);)n=r,r=o,h=c.plus(d.times(o=h)),c=o,t=l.minus(d.times(o=t)),l=o;return o=i(e.minus(n),r,0,1),c=c.plus(o.times(h)),n=n.plus(o.times(r)),c.s=h.s=g.s,u=i(h,r,s*=2,m).minus(g).abs().comparedTo(i(c,n,s,m).minus(g).abs())<1?[h,r]:[c,n],y=a,u},u.toNumber=function(){return+A(this)},u.toPrecision=function(e,t){return null!=e&&Xe(e,1,Ve),R(this,e,t,2)},u.toString=function(e){var t,i=this,r=i.s,o=i.e;return null===o?r?(t="Infinity",r<0&&(t="-"+t)):t="NaN":(null==e?t=o<=g||o>=f?Qe(Ye(i.c),o):et(Ye(i.c),o,"0"):10===e&&S?t=et(Ye((i=D(new M(i),_+o+1,m)).c),i.e,"0"):(Xe(e,2,$.length,"Base"),t=n(et(Ye(i.c),o,"0"),10,e,r,!0)),r<0&&i.c[0]&&(t="-"+t)),t},u.valueOf=u.toJSON=function(){return A(this)},u._isBigNumber=!0,u[Symbol.toStringTag]="BigNumber",u[Symbol.for("nodejs.util.inspect.custom")]=u.valueOf,null!=t&&M.set(t),M}(),it=class{key;left=null;right=null;constructor(e){this.key=e}},nt=class extends it{constructor(e){super(e)}},rt=class{size=0;modificationCount=0;splayCount=0;splay(e){const t=this.root;if(null==t)return this.compare(e,e),-1;let i=null,n=null,r=null,o=null,s=t;const a=this.compare;let l;for(;;)if(l=a(s.key,e),l>0){let t=s.left;if(null==t)break;if(l=a(t.key,e),l>0&&(s.left=t.right,t.right=s,s=t,t=s.left,null==t))break;null==i?n=s:i.left=s,i=s,s=t}else{if(!(l<0))break;{let t=s.right;if(null==t)break;if(l=a(t.key,e),l<0&&(s.right=t.left,t.left=s,s=t,t=s.right,null==t))break;null==r?o=s:r.right=s,r=s,s=t}}return null!=r&&(r.right=s.left,s.left=o),null!=i&&(i.left=s.right,s.right=n),this.root!==s&&(this.root=s,this.splayCount++),l}splayMin(e){let t=e,i=t.left;for(;null!=i;){const e=i;t.left=e.right,e.right=t,t=e,i=t.left}return t}splayMax(e){let t=e,i=t.right;for(;null!=i;){const e=i;t.right=e.left,e.left=t,t=e,i=t.right}return t}_delete(e){if(null==this.root)return null;if(0!=this.splay(e))return null;let t=this.root;const i=t,n=t.left;if(this.size--,null==n)this.root=t.right;else{const e=t.right;t=this.splayMax(n),t.right=e,this.root=t}return this.modificationCount++,i}addNewRoot(e,t){this.size++,this.modificationCount++;const i=this.root;null!=i?(t<0?(e.left=i,e.right=i.right,i.right=null):(e.right=i,e.left=i.left,i.left=null),this.root=e):this.root=e}_first(){const e=this.root;return null==e?null:(this.root=this.splayMin(e),this.root)}_last(){const e=this.root;return null==e?null:(this.root=this.splayMax(e),this.root)}clear(){this.root=null,this.size=0,this.modificationCount++}has(e){return this.validKey(e)&&0==this.splay(e)}defaultCompare(){return(e,t)=>et?1:0}wrap(){return{getRoot:()=>this.root,setRoot:e=>{this.root=e},getSize:()=>this.size,getModificationCount:()=>this.modificationCount,getSplayCount:()=>this.splayCount,setSplayCount:e=>{this.splayCount=e},splay:e=>this.splay(e),has:e=>this.has(e)}}},ot=class e extends rt{root=null;compare;validKey;constructor(e,t){super(),this.compare=e??this.defaultCompare(),this.validKey=t??(e=>null!=e&&null!=e)}delete(e){return!!this.validKey(e)&&null!=this._delete(e)}deleteAll(e){for(const t of e)this.delete(t)}forEach(e){const t=this[Symbol.iterator]();let i;for(;i=t.next(),!i.done;)e(i.value,i.value,this)}add(e){const t=this.splay(e);return 0!=t&&this.addNewRoot(new nt(e),t),this}addAndReturn(e){const t=this.splay(e);return 0!=t&&this.addNewRoot(new nt(e),t),this.root.key}addAll(e){for(const t of e)this.add(t)}isEmpty(){return null==this.root}isNotEmpty(){return null!=this.root}single(){if(0==this.size)throw"Bad state: No element";if(this.size>1)throw"Bad state: Too many element";return this.root.key}first(){if(0==this.size)throw"Bad state: No element";return this._first().key}last(){if(0==this.size)throw"Bad state: No element";return this._last().key}lastBefore(e){if(null==e)throw"Invalid arguments(s)";if(null==this.root)return null;if(this.splay(e)<0)return this.root.key;let t=this.root.left;if(null==t)return null;let i=t.right;for(;null!=i;)t=i,i=t.right;return t.key}firstAfter(e){if(null==e)throw"Invalid arguments(s)";if(null==this.root)return null;if(this.splay(e)>0)return this.root.key;let t=this.root.right;if(null==t)return null;let i=t.left;for(;null!=i;)t=i,i=t.left;return t.key}retainAll(t){const i=new e(this.compare,this.validKey),n=this.modificationCount;for(const e of t){if(n!=this.modificationCount)throw"Concurrent modification during iteration.";this.validKey(e)&&0==this.splay(e)&&i.add(this.root.key)}i.size!=this.size&&(this.root=i.root,this.size=i.size,this.modificationCount++)}lookup(e){if(!this.validKey(e))return null;return 0!=this.splay(e)?null:this.root.key}intersection(t){const i=new e(this.compare,this.validKey);for(const e of this)t.has(e)&&i.add(e);return i}difference(t){const i=new e(this.compare,this.validKey);for(const e of this)t.has(e)||i.add(e);return i}union(e){const t=this.clone();return t.addAll(e),t}clone(){const t=new e(this.compare,this.validKey);return t.size=this.size,t.root=this.copyNode(this.root),t}copyNode(e){if(null==e)return null;const t=new nt(e.key);return function e(t,i){let n,r;do{if(n=t.left,r=t.right,null!=n){const t=new nt(n.key);i.left=t,e(n,t)}if(null!=r){const e=new nt(r.key);i.right=e,t=r,i=e}}while(null!=r)}(e,t),t}toSet(){return this.clone()}entries(){return new lt(this.wrap())}keys(){return this[Symbol.iterator]()}values(){return this[Symbol.iterator]()}[Symbol.iterator](){return new at(this.wrap())}[Symbol.toStringTag]="[object Set]"},st=class{tree;path=new Array;modificationCount=null;splayCount;constructor(e){this.tree=e,this.splayCount=e.getSplayCount()}[Symbol.iterator](){return this}next(){return this.moveNext()?{done:!1,value:this.current()}:{done:!0,value:null}}current(){if(!this.path.length)return null;const e=this.path[this.path.length-1];return this.getValue(e)}rebuildPath(e){this.path.splice(0,this.path.length),this.tree.splay(e),this.path.push(this.tree.getRoot()),this.splayCount=this.tree.getSplayCount()}findLeftMostDescendent(e){for(;null!=e;)this.path.push(e),e=e.left}moveNext(){if(this.modificationCount!=this.tree.getModificationCount()){if(null==this.modificationCount){this.modificationCount=this.tree.getModificationCount();let e=this.tree.getRoot();for(;null!=e;)this.path.push(e),e=e.left;return this.path.length>0}throw"Concurrent modification during iteration."}if(!this.path.length)return!1;this.splayCount!=this.tree.getSplayCount()&&this.rebuildPath(this.path[this.path.length-1].key);let e=this.path[this.path.length-1],t=e.right;if(null!=t){for(;null!=t;)this.path.push(t),t=t.left;return!0}for(this.path.pop();this.path.length&&this.path[this.path.length-1].right===e;)e=this.path.pop();return this.path.length>0}},at=class extends st{getValue(e){return e.key}},lt=class extends st{getValue(e){return[e.key,e.key]}},ct=e=>()=>e,ht=e=>{const t=e?(t,i)=>i.minus(t).abs().isLessThanOrEqualTo(e):ct(!1);return(e,i)=>t(e,i)?0:e.comparedTo(i)};function dt(e){const t=e?(t,i,n,r,o)=>t.exponentiatedBy(2).isLessThanOrEqualTo(r.minus(i).exponentiatedBy(2).plus(o.minus(n).exponentiatedBy(2)).times(e)):ct(!1);return(e,i,n)=>{const r=e.x,o=e.y,s=n.x,a=n.y,l=o.minus(a).times(i.x.minus(s)).minus(r.minus(s).times(i.y.minus(a)));return t(l,r,o,s,a)?0:l.comparedTo(0)}}var ut=e=>e,pt=e=>{if(e){const t=new ot(ht(e)),i=new ot(ht(e)),n=(e,t)=>t.addAndReturn(e),r=e=>({x:n(e.x,t),y:n(e.y,i)});return r({x:new tt(0),y:new tt(0)}),r}return ut},_t=e=>({set:e=>{mt=_t(e)},reset:()=>_t(e),compare:ht(e),snap:pt(e),orient:dt(e)}),mt=_t(),gt=(e,t)=>e.ll.x.isLessThanOrEqualTo(t.x)&&t.x.isLessThanOrEqualTo(e.ur.x)&&e.ll.y.isLessThanOrEqualTo(t.y)&&t.y.isLessThanOrEqualTo(e.ur.y),ft=(e,t)=>{if(t.ur.x.isLessThan(e.ll.x)||e.ur.x.isLessThan(t.ll.x)||t.ur.y.isLessThan(e.ll.y)||e.ur.y.isLessThan(t.ll.y))return null;const i=e.ll.x.isLessThan(t.ll.x)?t.ll.x:e.ll.x,n=e.ur.x.isLessThan(t.ur.x)?e.ur.x:t.ur.x;return{ll:{x:i,y:e.ll.y.isLessThan(t.ll.y)?t.ll.y:e.ll.y},ur:{x:n,y:e.ur.y.isLessThan(t.ur.y)?e.ur.y:t.ur.y}}},vt=(e,t)=>e.x.times(t.y).minus(e.y.times(t.x)),yt=(e,t)=>e.x.times(t.x).plus(e.y.times(t.y)),bt=e=>yt(e,e).sqrt(),wt=(e,t,i)=>{const n={x:t.x.minus(e.x),y:t.y.minus(e.y)},r={x:i.x.minus(e.x),y:i.y.minus(e.y)};return vt(r,n).div(bt(r)).div(bt(n))},kt=(e,t,i)=>{const n={x:t.x.minus(e.x),y:t.y.minus(e.y)},r={x:i.x.minus(e.x),y:i.y.minus(e.y)};return yt(r,n).div(bt(r)).div(bt(n))},xt=(e,t,i)=>t.y.isZero()?null:{x:e.x.plus(t.x.div(t.y).times(i.minus(e.y))),y:i},$t=(e,t,i)=>t.x.isZero()?null:{x:i,y:e.y.plus(t.y.div(t.x).times(i.minus(e.x)))},St=class e{point;isLeft;segment;otherSE;consumedBy;static compare(t,i){const n=e.comparePoints(t.point,i.point);return 0!==n?n:(t.point!==i.point&&t.link(i),t.isLeft!==i.isLeft?t.isLeft?1:-1:zt.compare(t.segment,i.segment))}static comparePoints(e,t){return e.x.isLessThan(t.x)?-1:e.x.isGreaterThan(t.x)?1:e.y.isLessThan(t.y)?-1:e.y.isGreaterThan(t.y)?1:0}constructor(e,t){void 0===e.events?e.events=[this]:e.events.push(this),this.point=e,this.isLeft=t}link(e){if(e.point===this.point)throw new Error("Tried to link already linked events");const t=e.point.events;for(let e=0,i=t.length;e{const n=i.otherSE;t.set(i,{sine:wt(this.point,e.point,n.point),cosine:kt(this.point,e.point,n.point)})};return(e,n)=>{t.has(e)||i(e),t.has(n)||i(n);const{sine:r,cosine:o}=t.get(e),{sine:s,cosine:a}=t.get(n);return r.isGreaterThanOrEqualTo(0)&&s.isGreaterThanOrEqualTo(0)?o.isLessThan(a)?1:o.isGreaterThan(a)?-1:0:r.isLessThan(0)&&s.isLessThan(0)?o.isLessThan(a)?-1:o.isGreaterThan(a)?1:0:s.isLessThan(r)?-1:s.isGreaterThan(r)?1:0}}},Mt=class e{events;poly;_isExteriorRing;_enclosingRing;static factory(t){const i=[];for(let n=0,r=t.length;n0&&(e=i)}let t=e.segment.prevInResult(),i=t?t.prevInResult():null;for(;;){if(!t)return null;if(!i)return t.ringOut;if(i.ringOut!==t.ringOut)return i.ringOut?.enclosingRing()!==t.ringOut?t.ringOut:t.ringOut?.enclosingRing();t=i.prevInResult(),i=t?t.prevInResult():null}}},Rt=class{exteriorRing;interiorRings;constructor(e){this.exteriorRing=e,e.poly=this,this.interiorRings=[]}addInterior(e){this.interiorRings.push(e),e.poly=this}getGeom(){const e=this.exteriorRing.getGeom();if(null===e)return null;const t=[e];for(let e=0,i=this.interiorRings.length;e0?(this.tree.delete(t),i.push(e)):(this.segments.push(t),t.prev=n)}else{if(n&&r){const e=n.getIntersection(r);if(null!==e){if(!n.isAnEndpoint(e)){const t=this._splitSafely(n,e);for(let e=0,n=t.length;e0)return-1;const n=t.comparePoint(e.rightSE.point);return 0!==n?n:-1}if(i.isGreaterThan(n)){if(s.isLessThan(a)&&s.isLessThan(c))return-1;if(s.isGreaterThan(a)&&s.isGreaterThan(c))return 1;const i=t.comparePoint(e.leftSE.point);if(0!==i)return i;const n=e.comparePoint(t.rightSE.point);return n<0?1:n>0?-1:1}if(s.isLessThan(a))return-1;if(s.isGreaterThan(a))return 1;if(r.isLessThan(o)){const i=t.comparePoint(e.rightSE.point);if(0!==i)return i}if(r.isGreaterThan(o)){const i=e.comparePoint(t.rightSE.point);if(i<0)return 1;if(i>0)return-1}if(!r.eq(o)){const e=l.minus(s),t=r.minus(i),h=c.minus(a),d=o.minus(n);if(e.isGreaterThan(t)&&h.isLessThan(d))return 1;if(e.isLessThan(t)&&h.isGreaterThan(d))return-1}return r.isGreaterThan(o)?1:r.isLessThan(o)||l.isLessThan(c)?-1:l.isGreaterThan(c)?1:e.idt.id?1:0}constructor(e,t,i,n){this.id=++Ot,this.leftSE=e,e.segment=this,e.otherSE=t,this.rightSE=t,t.segment=this,t.otherSE=e,this.rings=i,this.windings=n}static fromRing(t,i,n){let r,o,s;const a=St.comparePoints(t,i);if(a<0)r=t,o=i,s=1;else{if(!(a>0))throw new Error(`Tried to create degenerate segment at [${t.x}, ${t.y}]`);r=i,o=t,s=-1}const l=new St(r,!0),c=new St(o,!1);return new e(l,c,[n],[s])}replaceRightSE(e){this.rightSE=e,this.rightSE.segment=this,this.rightSE.otherSE=this.leftSE,this.leftSE.otherSE=this.rightSE}bbox(){const e=this.leftSE.point.y,t=this.rightSE.point.y;return{ll:{x:this.leftSE.point.x,y:e.isLessThan(t)?e:t},ur:{x:this.rightSE.point.x,y:e.isGreaterThan(t)?e:t}}}vector(){return{x:this.rightSE.point.x.minus(this.leftSE.point.x),y:this.rightSE.point.y.minus(this.leftSE.point.y)}}isAnEndpoint(e){return e.x.eq(this.leftSE.point.x)&&e.y.eq(this.leftSE.point.y)||e.x.eq(this.rightSE.point.x)&&e.y.eq(this.rightSE.point.y)}comparePoint(e){return mt.orient(this.leftSE.point,e,this.rightSE.point)}getIntersection(e){const t=this.bbox(),i=e.bbox(),n=ft(t,i);if(null===n)return null;const r=this.leftSE.point,o=this.rightSE.point,s=e.leftSE.point,a=e.rightSE.point,l=gt(t,s)&&0===this.comparePoint(s),c=gt(i,r)&&0===e.comparePoint(r),h=gt(t,a)&&0===this.comparePoint(a),d=gt(i,o)&&0===e.comparePoint(o);if(c&&l)return d&&!h?o:!d&&h?a:null;if(c)return h&&r.x.eq(a.x)&&r.y.eq(a.y)?null:r;if(l)return d&&o.x.eq(s.x)&&o.y.eq(s.y)?null:s;if(d&&h)return null;if(d)return o;if(h)return a;const u=((e,t,i,n)=>{if(t.x.isZero())return $t(i,n,e.x);if(n.x.isZero())return $t(e,t,i.x);if(t.y.isZero())return xt(i,n,e.y);if(n.y.isZero())return xt(e,t,i.y);const r=vt(t,n);if(r.isZero())return null;const o={x:i.x.minus(e.x),y:i.y.minus(e.y)},s=vt(o,t).div(r),a=vt(o,n).div(r),l=e.x.plus(a.times(t.x)),c=i.x.plus(s.times(n.x)),h=e.y.plus(a.times(t.y)),d=i.y.plus(s.times(n.y));return{x:l.plus(c).div(2),y:h.plus(d).div(2)}})(r,this.vector(),s,e.vector());return null===u?null:gt(n,u)?mt.snap(u):null}split(t){const i=[],n=void 0!==t.events,r=new St(t,!0),o=new St(t,!1),s=this.rightSE;this.replaceRightSE(o),i.push(o),i.push(r);const a=new e(r,s,this.rings.slice(),this.windings.slice());return St.comparePoints(a.leftSE.point,a.rightSE.point)>0&&a.swapEvents(),St.comparePoints(this.leftSE.point,this.rightSE.point)>0&&this.swapEvents(),n&&(r.checkForConsuming(),o.checkForConsuming()),i}swapEvents(){const e=this.rightSE;this.rightSE=this.leftSE,this.leftSE=e,this.leftSE.isLeft=!0,this.rightSE.isLeft=!1;for(let e=0,t=this.windings.length;e0){const e=i;i=n,n=e}if(i.prev===n){const e=i;i=n,n=e}for(let e=0,t=n.rings.length;e1===e.length&&e[0].isSubject;this._isInResult=i(e)!==i(t);break}}return this._isInResult}},Pt=class{poly;isExterior;segments;bbox;constructor(e,t,i){if(!Array.isArray(e)||0===e.length)throw new Error("Input geometry is not a valid Polygon or MultiPolygon");if(this.poly=t,this.isExterior=i,this.segments=[],"number"!=typeof e[0][0]||"number"!=typeof e[0][1])throw new Error("Input geometry is not a valid Polygon or MultiPolygon");const n=mt.snap({x:new tt(e[0][0]),y:new tt(e[0][1])});this.bbox={ll:{x:n.x,y:n.y},ur:{x:n.x,y:n.y}};let r=n;for(let t=1,i=e.length;tAt.run("union",e,t),Nt=(e,...t)=>At.run("intersection",e,t),Ht=(e,...t)=>At.run("difference",e,t);mt.set;const Lt=/^#[0-9a-fA-F]{6}$/;function qt(e,t){return"string"==typeof e&&Lt.test(e)?e:t}const jt="(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])",Bt=new RegExp(`^rgb\\(${jt}, ${jt}, ${jt}\\)$`);function Wt(e){if(!Array.isArray(e)||e.length<3)return null;const t=e.slice(0,3);if(!t.every(e=>"number"==typeof e&&Number.isFinite(e)))return null;const[i,n,r]=t.map(e=>Math.round(Math.min(255,Math.max(0,e))));return`rgb(${i}, ${n}, ${r})`}function Ut(e){const t=Math.max(0,Math.min(120,(e-40)/140*120));return`hsl(${Math.round(t)}, 85%, 55%)`}function Gt(e,t){if(!(Number.isFinite(e)&&t>0))return e;const i=Math.round(e/t)*t;return Math.abs(i-e)<=1e-9*t?e:i}function Vt(e,t,i,n=1/0){if(!(i>0&&e?.every(Number.isFinite)&&t?.every(Number.isFinite)))return[t[0],t[1]];const r=t[0]-e[0],o=t[1]-e[1];if(Math.abs(r)+Math.abs(o)<=1e-12)return[e[0],e[1]];const s=Math.PI/4;let a=Math.atan2(o,r);a<0&&(a+=2*Math.PI);const l=Math.floor(a/s+.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 u=Math.max(0,Math.round((r*c+o*h)/(i*d)));if(Number.isFinite(n)&&n>=0){const t=(e,t)=>{if(!t)return 1/0;const r=t>0?n-e:e+n;return Math.max(0,Math.floor((r+1e-9*i)/i))};u=Math.min(u,t(e[0],c),t(e[1],h))}return[e[0]+c*u*i,e[1]+h*u*i]}function Kt(e,t){if(t){const t=e/2.54;let i=Math.floor(t/12),n=Math.round(t-12*i);return 12===n&&(i+=1,n=0),`${i}′ ${n}″`}return`${(e/100).toFixed(2)} m`}function Yt(e,t,i=1){const n=e[0].toFixed(i),r=e[1].toFixed(i),o=t[0].toFixed(i),s=t[1].toFixed(i),a=n=3?e.poly:e&&null!=e.x&&null!=e.y&&null!=e.w&&null!=e.h?[[e.x,e.y],[e.x+e.w,e.y],[e.x+e.w,e.y+e.h],[e.x,e.y+e.h]]:null}function Xt(e){const t=[];for(const i of e||[])i?.poly?.length>=3?t.push({poly:i.poly.map(e=>e.join(",")).join(" ")}):i&&null!=i.x&&null!=i.y&&null!=i.w&&null!=i.h&&t.push({rect:{x:i.x,y:i.y,w:i.w,h:i.h,rx:.03*Math.min(i.w,i.h)}});return t}function Jt(e){const t=[],i=new Set;for(const n of e||[]){const e=Zt(n);if(e)for(let n=0;n=90?e-=180:e<-90&&(e+=180),n.step&&n.step>0){const i=Math.sqrt(d),o=Math.min(Math.max(n.length||0,0)/2,i/2);let a=Math.round(u*i/n.step)*n.step;Math.abs(u*i-i/2)<=n.step/2&&(a=i/2),a=Math.max(o,Math.min(i-o,a));const l=a/i;r={x:t+l*c,y:s+l*h,angle:e}}else r={x:p[0],y:p[1],angle:e}}}return r}function ei(e,t,i){let n=null,r=1/0;for(let o=0;o=r)continue;r=_;const m=Math.sqrt(u),g=(i>0?Math.max(0,Math.min(m,Math.round(p*m/i)*i)):p*m)/m;n=[s+g*h,a+g*d]}return n}function ti(e,t,i,n,r,o=1){const s=t*Math.PI/180,a=[Math.cos(s),Math.sin(s)];let l=null,c=o;for(const t of Jt(n)){const i=[[t[0],t[1]],[t[2],t[3]]],n=t=>Math.abs(a[0]*(t[1]-e[1])-a[1]*(t[0]-e[0]));if(n(i[0])>o||n(i[1])>o)continue;const r=(i[0][0]-e[0])*a[0]+(i[0][1]-e[1])*a[1],s=(i[1][0]-e[0])*a[0]+(i[1][1]-e[1])*a[1],h=Math.min(r,s),d=Math.max(r,s),u=h>0?h:d<0?-d:0;u[e[0]+a[0]*t,e[1]+a[1]*t],g=(h+d)/2;return{wallA:m(h),wallB:m(d),sideA:p,sideB:_,midA:m((h-u)/2),midB:m((u+d)/2),wallCenter:m(g),centered:Math.abs(g)<=r}}function ii(e,t,i=!1){if("passage"===e)return 1;if(null==t||"unavailable"===t||"unknown"===t)return"window"===e?0:1;const n=function(e){return["on","open","home","detected","playing","cleaning"].includes(String(e))}(t)!==!!i;return n?1:0}function ni(e){return"passage"===e.type?[]:[e.contact,e.lock].filter(e=>"string"==typeof e&&e.length>0)}function ri(e,t,i=200){const n=t.trim().toLowerCase();return(n?e.filter(e=>e.label.toLowerCase().includes(n)||e.value.toLowerCase().includes(n)):e).slice(0,Math.max(0,i))}function oi(e,t,i=.001){return Math.abs(e[0]-t[0])e[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s)+o&&(i=!i)}return i}function ai(e,t,i){const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;let s=o?((e[0]-t[0])*n+(e[1]-t[1])*r)/o:0;return s=Math.max(0,Math.min(1,s)),Math.hypot(e[0]-(t[0]+s*n),e[1]-(t[1]+s*r))}function li(e,t){if(!t||t.length<2)return null;let i=null,n=1/0;for(let r=0;rr&&s<-r||o<-r&&s>r)&&(a>r&&l<-r||a<-r&&l>r)}function pi(e,t=24){const i=e.map(e=>e[0]),n=e.map(e=>e[1]),r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1;let c=0,h=0,d=0;for(let t=0;t1e-9?[h/(3*c),d/(3*c)]:[(r+o)/2,(s+a)/2],p=(t,i)=>{const n=((t,i)=>{if(!si([t,i],e))return-1/0;let n=1/0;for(let r=0;rm&&(m=c,_=[n,l])}if(_){const[e,i]=_,n=(o-r)/t,l=(a-s)/t;for(let t=-4;t<=4;t++)for(let r=-4;r<=4;r++){const o=e+n*t/4,s=i+l*r/4,a=p(o,s);a>m&&(m=a,_=[o,s])}}return _||_i(e)||e[0]}function _i(e,t=1e-6){if(!e||e.length<3)return null;const i=e.length,n=[e.reduce((e,t)=>e+t[0],0)/i,e.reduce((e,t)=>e+t[1],0)/i];if(hi(n,e,t))return n;for(let n=0;ngi(e,t,i));return n.filter(e=>!n.some(t=>t!==e&&gi(t,e,i)))}function yi(e){if(!e||e.length<3)return 0;let t=0;for(let i=0;i[e[0],e[1]]),[e[0][0],e[0][1]]]]}function wi(e,t){if(!e||!t||e.length<3||t.length<3)return null;const i=Et(bi(e),bi(t));if(1!==i.length)return null;if(1!==i[0].length)return null;const n=i[0][0].slice(0,-1).map(e=>[e[0],e[1]]);return n.length>=3?n:null}function ki(e,t,i){for(let n=0;n1&&oi(i[0],i[i.length-1],t)&&i.pop(),i}function $i(e,t,i=1e-6){if(!e||e.length<3||!t||t.length<2)return null;const n=t[0],r=t[t.length-1];if(oi(n,r,i))return null;const o=ki(e,n,i),s=ki(e,r,i);if(o<0||s<0)return null;const a=t.slice(1,-1);for(const t of a)if(!hi(t,e,i))return null;for(let i=0;i{const s=[t];let a=(n+1)%e.length;for(let t=0;t<=e.length&&(s.push(e[a]),a!==o);t++)a=(a+1)%e.length;return s.push(r),xi(s,i)};let c,h;if(o===s){const s=xi([...t],i);if(s.length<3||yi(s)<=i)return null;const a=[];for(let i=0;i=0?t:[...t].reverse();for(const e of i)a.push(e)}c=xi(a,i),h=s}else c=xi([...l(n,o,r,s),...[...a].reverse()],i),h=xi([...l(r,s,n,o),...a],i);return c.length<3||h.length<3||yi(c)<=i||yi(h)<=i||Math.abs(yi(c)+yi(h)-yi(e))>Math.max(i,1e-6*yi(e))?null:[c,h]}function Si(e,t,i){const[n,r]=e.split(":");return"device"===n?r:"entity"===n?"lg_"+r:t&&t.startsWith("v_")?t:i()}function Mi(e){return e.length?Math.round(e.reduce((e,t)=>e+t,0)/e.length):null}function Ri(e,t){if(t>e[2]/e[3]){const i=e[3],n=e[3]*t;return{x:e[0]-(n-e[2])/2,y:e[1],w:n,h:i}}const i=e[2],n=e[2]/t;return{x:e[0],y:e[1]-(n-e[3])/2,w:i,h:n}}function Ti(e,t,i,n){if(e.length<2)return;const r=t.x+n,o=t.x+t.w-n,s=t.y+n,a=t.y+t.h-n;for(let t=0;t<60;t++){let t=!1;for(let n=0;n=0)i=t.slice(0,r).trim(),n=t.slice(r+1).trim();else{const e=t.split(".");e.length>2&&(i=e.slice(0,2).join("."),n=e.slice(2).join("."))}return/^[a-z0-9_]+\.[a-z0-9_]+$/.test(i)?r>=0&&!n||n&&!/^[a-zA-Z0-9_.-]+$/.test(n)?null:n?{entity:i,attr:n}:{entity:i}:null}function Li(e,t){const i=String(e??"").trim(),n=String(t??"").trim(),r=Hi(n?`${i}:${n}`:i);return r?`{${r.entity}${r.attr?`:${r.attr}`:""}}`:""}function qi(e,t,i){const n=String(t??"").trim();if(!n)return null;const r=e?.states?.[n];if(!r)return null;const o=String(i??"").trim(),s=e=>e.slice(0,60);if(o){const t=function(e){if(null==e)return null;if(Array.isArray(e)){const t=e.map(e=>null==e?"":String(e)).join(", ");return t?t.slice(0,60):null}if("object"==typeof e)return null;const t=String(e);return""===t?null:t.slice(0,60)}(r.attributes?.[o]);if(null===t)return null;const i=e?.formatEntityAttributeValue;if("function"==typeof i)try{const t=i.call(e,r,o);if("string"==typeof t&&""!==t)return{text:s(t),formatted:!0}}catch{}return{text:t,formatted:!1}}const a=r.state;if(null==a||""===a)return null;const l=e?.formatEntityState;if("function"==typeof l)try{const t=l.call(e,r);if("string"==typeof t&&""!==t)return{text:s(t),formatted:!0}}catch{}return{text:s(String(a)),formatted:!1}}function ji(e,t,i){const n=String(t??"").trim(),r=String(i??"").trim()||n;if(!r)return e.text;const o=e.formatted&&n?function(e,t){if(!t)return e;const i=e.replace(/\s+$/,"");return i.endsWith(t)?i.slice(0,i.length-t.length).replace(/\s+$/,""):e}(e.text,n):e.text;return`${o} ${r}`}function Bi(e,t){const i=(t?.entity||"").trim();if(!i)return"";const n=e?.states?.[i],r=n?.state;if(!n||null==r||""===r||"unavailable"===r||"unknown"===r)return Ei;const o=(t?.attr||"").trim(),s=qi(e,i,o||null);if(null===s)return Ei;return ji(s,o?"":String(n.attributes?.unit_of_measurement??"").trim(),t?.unit)}function Wi(e,t,i,n=()=>!0){const r=e??"";let o=!1;const s=r.replace(/\{([^{}\r\n]+)\}/g,(e,t)=>{const r=Hi(t);return r?(o=!0,n(r.entity||"")?Bi(i,r):Ei):e});if(o)return s;const a=(t?.entity||"").trim();if(!a)return r;if(!n(a)){const e=r.indexOf(Ni);return e>=0?r.slice(0,e)+Ei+r.slice(e+2):r?`${r} ${Ei}`:Ei}const l=Bi(i,t),c=r.indexOf(Ni);return c>=0?r.slice(0,c)+l+r.slice(c+2):r?`${r} ${l}`:l}const Ui=20;function Gi(e){const t=Number(e?.scale);if(Number.isFinite(t)&&t>0)return Math.min(20,Math.max(.15,t));return{s:.7,m:1,l:1.5}[String(e?.size??"")]??1}function Vi(e,t){if(!t)return e;let i=e;for(const[e,n]of Object.entries(t))i=i.split("{"+e+"}").join(String(n));return i}const Ki="#55606c",Yi=.55,Zi=20,Xi=25,Ji={c:"#607d8b",a:.18};function Qi(e,t=Ji){const i=e&&"object"==typeof e?e:null,n=i?.a;return{c:qt(i?.c,t.c),a:"number"==typeof n&&Number.isFinite(n)?Math.min(1,Math.max(0,n)):t.a}}function en(e,t){const i=Qi(e),n=t?.settings?.custom_fill;return n&&"object"==typeof n?Qi(n,i):i}function tn(e){const t=e?.settings||{},i=!e?.plan_url,n="glow"===t.fill_mode;return{showBorders:t.show_borders??i,showNames:t.show_names??i,color:qt(t.room_color,Ki),opacity:"number"==typeof t.room_opacity?Math.min(1,Math.max(0,t.room_opacity)):.55,fill:["lqi","light","temp","custom"].includes(t.fill_mode)?t.fill_mode:"none",customFill:Qi(t.custom_fill),glow:"boolean"==typeof t.glow_enabled?t.glow_enabled:n,tempMin:"number"==typeof t.temp_min?t.temp_min:20,tempMax:"number"==typeof t.temp_max?t.temp_max:25,showLqi:"boolean"==typeof t.show_lqi?t.show_lqi:null,cardFontScale:"number"==typeof t.card_font_scale&&t.card_font_scale>0?Math.min(3,Math.max(.5,t.card_font_scale)):1,labelTemp:!0===t.label_temp,labelHum:!0===t.label_hum,labelLqi:!0===t.label_lqi,labelLight:!0===t.label_light,bgColor:qt(t.bg_color,null),hideDecor:!0===t.hide_decor,hideOpenings:!0===t.hide_openings}}function nn(e,t){if(t.bgColor)return t.bgColor;const i=e?.bg_color;return qt(i,"")}const rn={light_on:{c:"#ffd45c",a:.18},light_off:{c:"#9aa0a6",a:.14},light_none:{c:"#6b7480",a:0},temp_cold:{c:"#4fc3f7",a:.18},temp_ok:{c:"#66d17a",a:.18},temp_hot:{c:"#ffd45c",a:.18},lqi_low:{c:"#f25a4a",a:.18},lqi_high:{c:"#4bd28f",a:.18},glow_base:{c:"#0d1b2a",a:.5},glow_light:{c:"#ffd9a0",a:.85},wall_fill:{c:"#ffffff",a:1}};function on(e){const t={},i=e?.fill_colors||{};for(const e of Object.keys(rn)){const n=rn[e],r=i[e];t[e]={c:qt(r?.c,n.c),a:r&&"number"==typeof r.a?Math.min(1,Math.max(0,r.a)):n.a}}return t}function sn(e,t,i){const n=Math.min(1,Math.max(0,i)),r=[1,3,5].map(t=>parseInt(e.slice(t,t+2),16)),o=[1,3,5].map(e=>parseInt(t.slice(e,e+2),16)),s=r.map((e,t)=>Math.round(e+(o[t]-e)*n));return"#"+s.map(e=>e.toString(16).padStart(2,"0")).join("")}function an(e,t,i,n,r,o,s,a=Ji){const l=function(e,t,i,n,r,o,s,a=Ji){if("custom"===e)return Qi(a);if("lqi"===e){if(null==t)return null;const e=(t-40)/140;return{c:sn(s.lqi_low.c,s.lqi_high.c,e),a:s.lqi_low.a+(s.lqi_high.a-s.lqi_low.a)*Math.min(1,Math.max(0,e))}}if("light"===e)return"none"===i?s.light_none.a>0?s.light_none:null:"on"===i?s.light_on:s.light_off;if("temp"===e){if(null==n)return null;const e=Math.min(r,o),t=Math.max(r,o);return nt?s.temp_hot:s.temp_ok}return null}(e,t,i,n,r,o,s,a);return l?{color:l.c,opacity:l.a,mode:e}:null}const ln={blind:["mdi:blinds","mdi:blinds-open"],shade:["mdi:blinds","mdi:blinds-open"],shutter:["mdi:window-shutter","mdi:window-shutter-open"],curtain:["mdi:curtains-closed","mdi:curtains"],window:["mdi:window-closed","mdi:window-open"],awning:["mdi:awning-outline","mdi:awning"],door:["mdi:door-closed","mdi:door-open"],garage:["mdi:garage","mdi:garage-open"],gate:["mdi:gate","mdi:gate-open"],damper:["mdi:circle-slice-8","mdi:circle-outline"]},cn=[["mdi:roller-shade-closed","mdi:roller-shade"],["mdi:blinds-horizontal-closed","mdi:blinds-horizontal"],["mdi:garage-variant","mdi:garage-open-variant"],["mdi:door","mdi:door-open"]];function hn(e){for(const t of[...Object.values(ln),...cn])if(e===t[0]||e===t[1])return t;return null}function dn(e,t,i,n,r){if(!n||"unavailable"===n||"unknown"===n)return e;if(r){const i="cover"===t?hn(e):null;return i?"closed"===n?i[0]:i[1]:e}if("binary_sensor"===t){if("door"===i)return"on"===n?"mdi:door-open":"mdi:door-closed";if("window"===i)return"on"===n?"mdi:window-open":"mdi:window-closed";if("garage_door"===i)return"on"===n?"mdi:garage-open-variant":"mdi:garage-variant"}if("cover"===t){const t=ln[String(i||"")];if(t)return"closed"===n?t[0]:t[1];const r=hn(e);return r?"closed"===n?r[0]:r[1]:e}return"lock"===t?"locked"===n?"mdi:lock":"mdi:lock-open-variant":"light"===t&&"mdi:lightbulb"===e&&"on"===n?"mdi:lightbulb-on":e}function un(e){const t=Math.min(4e4,Math.max(1e3,e))/100,i=t<=66?255:329.698727446*Math.pow(t-60,-.1332047592),n=t<=66?99.4708025861*Math.log(t)-161.1195681661:288.1221695283*Math.pow(t-60,-.0755148492),r=t>=66?255:t<=19?0:138.5177312231*Math.log(t-10)-305.0447927307,o=e=>Math.round(Math.min(255,Math.max(0,e)));return[o(i),o(n),o(r)]}const pn=1/2.2;function _n(e){const t=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/.exec(e);return t?"#"+t.slice(1).map(e=>Math.min(255,Number(e)).toString(16).padStart(2,"0")).join(""):null}function mn(e){if(!e||"object"!=typeof e||Array.isArray(e))return null;const t=e;if(Object.keys(t).some(e=>"c"!==e&&"bri"!==e))return null;const i=qt(t.c,null);return i?void 0===t.bri||null===t.bri?{c:i}:"number"!=typeof t.bri||!Number.isFinite(t.bri)||t.bri<.01||t.bri>1?null:{c:i,bri:t.bri}:null}function gn(e,t,i){const n=mn(t),r=e?.attributes||{},o=n?.bri??function(e){const t=e?.attributes?.brightness,i="number"==typeof t?t:"string"==typeof t&&""!==t.trim()?Number(t):Number.NaN;return Number.isFinite(i)?Math.max(0,Math.min(1,i/255)):1}(e);if(n)return{c:n.c,bri:o};const s=Wt(r.rgb_color);if(s)return{c:_n(s)||qt(i,"#ffd9a0"),bri:o};const a=Number(r.color_temp_kelvin)||(Number(r.color_temp)>0?1e6/Number(r.color_temp):NaN);return Number.isFinite(a)&&a>0?{c:(l=un(a),"#"+l.slice(0,3).map(e=>Math.min(255,Math.max(0,Math.round(Number(e)||0))).toString(16).padStart(2,"0")).join("")),bri:o}:{c:qt(i,"#ffd9a0"),bri:o};var l}function fn(e,t,i){return"on"===e?.state?gn(e,t,i):null}function vn(e,t=1){const i=Math.max(0,Math.min(1,Number.isFinite(e)?e:1)),n=.7*Math.max(0,Math.min(1,Number.isFinite(t)?t:1))*(.4+.6*Math.pow(i,pn));return Math.max(0,Math.min(1,n))}function yn(e){return e.startsWith("light.")||e.startsWith("switch.")}function bn(e,t,i=1e-6){const n=[];if(!e||!t||e.length<3||t.length<3)return n;for(let r=0;ru||l>u)continue;const p=(r[0]-o[0])*h+(r[1]-o[1])*d,_=(s[0]-o[0])*h+(s[1]-o[1])*d,m=Math.max(0,Math.min(p,_)),g=Math.min(c,Math.max(p,_));g-m>i&&n.push([o[0]+h*m,o[1]+d*m,o[0]+h*g,o[1]+d*g])}}return n}function wn(e,t,i=1e-6){const n=[];for(const r of e){const e=[r[0],r[1]],o=[r[2],r[3]],s=o[0]-e[0],a=o[1]-e[1],l=Math.hypot(s,a);if(lo||r>o)continue;const s=(n[0]-e[0])*c+(n[1]-e[1])*h,a=(n[2]-e[0])*c+(n[3]-e[1])*h,u=Math.max(0,Math.min(s,a)),p=Math.min(l,Math.max(s,a));p-u>i&&d.push([u,p])}if(!d.length){n.push([e[0],e[1],o[0],o[1]]);continue}d.sort((e,t)=>e[0]-t[0]);let u=0;for(const[t,r]of d)t-u>i&&n.push([e[0]+c*u,e[1]+h*u,e[0]+c*t,e[1]+h*t]),u=Math.max(u,r);l-u>i&&n.push([e[0]+c*u,e[1]+h*u,o[0],o[1]])}return n}function kn(e,t,i=1e-6){const n=[];for(let t=0;t{if("string"!=typeof e||!e)return;const i=Mn(e);i.startsWith("/api/houseplan/content/")&&t.add(i)};for(const t of e?.spaces||[]){i(t?.plan_url);for(const e of t?.markers||[])for(const t of e?.pdfs||[])i(t?.url)}for(const t of e?.markers||[])for(const e of t?.pdfs||[])i(e?.url);return t}function Mn(e){return e?e.startsWith("/houseplan_files/plans/")?"/api/houseplan/content/plans/_/"+e.slice(23):e.startsWith("/houseplan_files/files/")?"/api/houseplan/content/files/"+e.slice(23):e:""}function Rn(e,t){const i=t?.settings?.fill_mode;return"none"===i||"lqi"===i||"light"===i||"temp"===i||"custom"===i?i:e}function Tn(e,t){const i=t?.settings;return"boolean"==typeof i?.glow?i.glow:"glow"===i?.fill_mode||e}function Cn(e,t,i,n){if(!t||!i||t===i)return e;const r="/files/"+t+"/",o="/files/"+i+"/";return e.map(e=>{if(!e.url.includes(r))return e;const t=e.url.split(r)[1]||"",[i,s]=[t.split("?")[0],t.includes("?")?"?"+t.split("?")[1]:""];if(n){const t=n[decodeURIComponent(i)]??n[i];return t?{...e,url:e.url.split(r+i)[0]+o+encodeURIComponent(t)+s}:e}return{...e,url:e.url.split(r).join(o)}})}function Dn(e,t=1){const i=Number(e);return Number.isFinite(i)&&i>0?Math.min(3,Math.max(.5,i)):t}function An(e,t,i){let n=null,r=null;for(const o of t){if(!(Math.abs(o[0]-e[0])<1e-6&&Math.abs(o[1]-e[1])<1e-6)){if(Math.abs(o[0]-e[0])<=i){const t=Math.abs(o[1]-e[1]);t>1e-6&&(!n||t1e-6&&(!r||t"number"==typeof e&&Number.isFinite(e),Wn=(e,t,i)=>Math.min(i,Math.max(t,e));function Un(e){return e.elevation<=-6?"night":e.elevation>=6?"day":e.rising?"dawn":"dusk"}function Gn(e){const t=(Math.floor(Number(e)||0)%1440+1440)%1440;return t>=300&&t<480?"dawn":t>=480&&t<1080?"day":t>=1080&&t<1260?"dusk":"night"}function Vn(e){const t=Un(e),i=e.azimuth*Math.PI/180;return{sunX:50-42*Math.sin(i),sunY:78-Wn(e.elevation,0,90)/90*64,sunOpacity:"night"===t?0:Wn((e.elevation+6)/12,0,1)}}function Kn(e){const t=(Math.floor(Number(e)||0)%1440+1440)%1440;if(t<300||t>=1260)return{sunX:50,sunY:78,sunOpacity:0};const i=(t-300)/960,n=(t-300)/120,r=(1260-t)/120;return{sunX:8+84*i,sunY:78-64*Math.sin(i*Math.PI),sunOpacity:Math.max(.18,Math.min(n,r,1))}}function Yn(e,t=new Date){const i=function(e){const t=e?.states?.["sun.sun"]?.attributes;return t&&Bn(t.azimuth)&&Bn(t.elevation)&&"boolean"==typeof t.rising?{azimuth:Ln(t.azimuth),elevation:t.elevation,rising:t.rising}:null}(e);if(i)return{phase:Un(i),source:"sun",...Vn(i)};const n="number"==typeof t?t:function(e=new Date){return 60*e.getHours()+e.getMinutes()}(t);return{phase:Gn(n),source:"clock",...Kn(n)}}function Zn(e){return`${e.source}|${e.phase}|${e.sunX.toFixed(2)}|${e.sunY.toFixed(2)}|`+e.sunOpacity.toFixed(3)}const Xn=[[-90,"#070c14"],[-12,"#070c14"],[-4,"#131a28"],[0,"#4a3527"],[10,"#e8ddcf"],[30,"#ffffff"],[90,"#ffffff"]],Jn=e=>Math.min(1,Math.max(0,e));function Qn(e,t,i=6){const n=e.angle*Math.PI/180,r=[Math.sin(n),-Math.cos(n)],o=n=>{const o=[e.x+r[0]*i*n,e.y+r[1]*i*n];return t.find(e=>e.poly.length>=3&&si(o,e.poly))||null},s=o(1),a=o(-1);return s&&a?null:s||a?s?{normal:[-r[0],-r[1]],roomId:s.id}:{normal:r,roomId:a.id}:null}function er(e,t,i){return i>0&&e[0]*t[0]+e[1]*t[1]>.05}function tr(e,t,i,n){return[[e[0],e[1]],[t[0],t[1]],[t[0]+i[0]*n,t[1]+i[1]*n],[e[0]+i[0]*n,e[1]+i[1]*n]]}function ir(e,t){try{const i=Nt([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]),n=[];for(const e of i){const t=e?.[0];!Array.isArray(t)||t.length<4||n.push(t.slice(0,t.length-1).map(e=>[e[0],e[1]]))}return n}catch{return[]}}function nr(e,t,i,n,r,o,s){if(!(n>0))return[];const a=qn(i,r),l=[-a[0],-a[1]],c=function(e){const t=Math.min(90,Math.max(0,e));return.7*(.8+1.7*Math.pow(1-t/90,1.6))}(n),h=[];for(const i of t){if(!(i.length>0))continue;const t=Qn(i,e);if(!t||!er(t.normal,a,n))continue;const r=e.find(e=>e.id===t.roomId);if(!r)continue;const d=o&&o[t.roomId]||r.poly,u=i.angle*Math.PI/180,p=i.length/2,_=[-t.normal[0],-t.normal[1]],m=Math.max(0,s?.[i.id]||0),g=i.x+_[0]*m/2,f=i.y+_[1]*m/2,v=Math.cos(u)*p,y=Math.sin(u)*p,b=[g-v,f-y],w=[g+v,f+y],k=c*i.length,x=ir(tr(b,w,l,k),d);if(!x.length)continue;const $=l[0]*_[0]+l[1]*_[1];h.push({openingId:i.id,roomId:t.roomId,polys:x,a:b,b:w,dir:l,len:k,normal:_,depth:k*$})}return h}const rr=e=>"number"==typeof e&&Number.isInteger(e)&&e>=0&&e<=359?e:null;function or(e,t){const i=rr(t?.north_deg);return null!==i?i:rr(e?.north_deg)}function sr(e,t){const i=e=>"static"===e||"daynight"===e?e:null;return i(t?.bg_mode)??i(e?.bg_mode)??"static"}function ar(e,t){const i=t?.sun_rays;return"boolean"==typeof i?i:!0===e?.sun_rays}function lr(e){const t=e?.states?.["sun.sun"]?.attributes,i=Number(t?.azimuth),n=Number(t?.elevation);return Number.isFinite(i)&&Number.isFinite(n)?{azimuth:i,elevation:n}:null}const cr=["dawn","day","dusk","night"];function hr(e){if(!e)return"";const t=jn[e.phase];return[`--hp-day-cycle-outline-near:${t.outlineNear}`,`--hp-day-cycle-outline-mid:${t.outlineMid}`,`--hp-day-cycle-outline-far:${t.outlineFar}`].join(";")}function dr(e,t=1){if(!e)return G;const i=[`--hp-day-cycle-sun-x:${e.sunX.toFixed(2)}%`,`--hp-day-cycle-sun-y:${e.sunY.toFixed(2)}%`,`--hp-day-cycle-sun-opacity:${e.sunOpacity.toFixed(3)}`,`opacity:${Math.min(1,Math.max(0,t)).toFixed(4)}`].join(";");return B``}const ur={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},pr=(e,t=1)=>{const i=Number(e);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):t},_r=e=>{let t=Number(e);return Number.isFinite(t)?(t=(t%360+360)%360,t>180?t-360:t):0};function mr(e,t,i){return _r(t)?[e.x,e.y]:i([e.x,e.y])}function gr(e,t,i,n){const r=Math.abs(i[0]-t[0]),o=Math.abs(i[1]-t[1]);return"line"===e?Math.hypot(r,o)>=n:r>=n&&o>=n}const fr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&n>0?n/r*i:0},vr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&i>0?n/i*r:0},yr=(e,t,i,n=ur.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return r;const o=Number(e?.width);return Number.isFinite(o)&&o>0?vr(o,t,i):n};function br(e,t){return{color:e.color,opacity:pr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),...t?{fill:e.fill,fill_color:e.fillColor,fill_opacity:pr(e.fillOpacity,.25)}:{}}}function wr(e){const t=e.x+e.w/2,i=e.y+e.h/2,n=_r(e.angle)*Math.PI/180,r=Math.cos(n),o=Math.sin(n),s=(e,n)=>{const s=e-t,a=n-i;return[t+s*r-a*o,i+s*o+a*r]};return[s(e.x,e.y),s(e.x+e.w,e.y),s(e.x+e.w,e.y+e.h),s(e.x,e.y+e.h)]}function kr(e){const t=wr(e),i=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],n=[(t[0][0]+t[2][0])/2,(t[0][1]+t[2][1])/2];return{points:[...t,i(t[0],t[1]),i(t[1],t[2]),i(t[2],t[3]),i(t[3],t[0]),n],segments:t.map((e,i)=>({a:e,b:t[(i+1)%4]}))}}function xr(e,t,i,n,r,o,s,a){const l=_r(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:e.w/2,g=i>0?-e.h/2:e.h/2,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v;let w=(y*c+b*h)*(t>0?1:-1),k=(y*d+b*u)*(i>0?1:-1),x=null;if(o){const t=w/Math.max(e.w,a),i=k/Math.max(e.h,a);x=Math.max(a/Math.max(e.w,a),a/Math.max(e.h,a),t,i),w=e.w*x,k=e.h*x}if(s>0)if(o){const t=Math.max(1,Math.round(e.w/s)),i=Math.max(1,Math.round(e.h/s));if(Math.abs(e.w-t*s)<1e-6&&Math.abs(e.h-i*s)<1e-6){const n=(e,t)=>{let i=Math.abs(e),n=Math.abs(t);for(;n;)[i,n]=[n,i%n];return Math.max(1,i)},r=1/n(t,i),o=Math.max(a/e.w,a/e.h),s=Math.max(o,Math.round((x??1)/r)*r);w=e.w*s,k=e.h*s}else{e.w>=e.h?(w=Math.round(w/s)*s,k=w*(e.h/Math.max(e.w,a))):(k=Math.round(k/s)*s,w=k*(e.w/Math.max(e.h,a)))}}else w=Math.round(w/s)*s,k=Math.round(k/s)*s;w=Math.max(a,w),k=Math.max(a,k);return{x:f+(t>0?w/2:-w/2)*c+(i>0?k/2:-k/2)*d-w/2,y:v+(t>0?w/2:-w/2)*h+(i>0?k/2:-k/2)*u-k/2,w:w,h:k,angle:_r(e.angle)||void 0}}const $r=(e,t,i)=>{const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;if(o<1e-12)return[...t];const s=Math.max(0,Math.min(1,((e[0]-t[0])*n+(e[1]-t[1])*r)/o));return[t[0]+n*s,t[1]+r*s]};function Sr(e,t,i,n){const r=n(e);let o=null;for(const r of t.points){const t=n(r),s=Math.hypot(t[0]-e[0],t[1]-e[1]);s<=i&&(!o||se.points),segments:e.flatMap(e=>e.segments)}}const Rr=Math.tan(.25*Math.PI/180);function Tr(e,t){const i=Math.abs(Number(t[0])-Number(e[0])),n=Math.abs(Number(t[1])-Number(e[1]));if(!([i,n].every(Number.isFinite)&&i>0&&n>0))return null;const r=i>=n?"horizontal":"vertical",o=Math.max(i,n),s=Math.min(i,n);return s/o>Rr?null:{axis:r,major:o,minor:s,angleDegrees:180*Math.atan2(s,o)/Math.PI}}function Cr(e,t){const i=Tr(e,t);return i?"horizontal"===i.axis?[Number(t[0]),Number(e[1])]:[Number(e[0]),Number(t[1])]:[Number(t[0]),Number(t[1])]}const Dr=e=>`${e[0]},${e[1]}`,Ar=(e,t)=>e[0]===t[0]&&e[1]===t[1],Or=(e,t)=>{const i=Dr(e),n=Dr(t);return i{let t=0;for(let i=0;i{if(e.length<3)return!1;for(let t=0;t1e-12},Fr=e=>{for(let t=0;t+1Ar(e,t.from)?[...t.to]:[...e],Er=(e,t)=>e.map(e=>Array.isArray(e?.poly)?{...e,poly:e.poly.map(e=>Ir(e,t))}:e),Nr=(e,t,i)=>{const n=e.flatMap((e,t)=>Zt(e)?.some(e=>Ar(e,i.from))?[t]:[]);if(!n.length)return!1;for(const i of n){const n=Zt(e[i]),r=Zt(t[i]);if(!n||!r)continue;if(!Pr(r))return!1;const o=Math.sign(zr(n)),s=Math.sign(zr(r));if(o&&s&&o!==s)return!1}const r=new Set;for(const e of n){const i=Zt(t[e]);if(i)for(let n=0;n{let i=0;for(const n of e){const e=Zt(n);if(e)for(let n=0;n{const{a:i,b:n,axis:r}=e,o="horizontal"===r?{from:n,to:[n[0],i[1]]}:{from:n,to:[i[0],n[1]]},s="horizontal"===r?{from:i,to:[i[0],n[1]]}:{from:i,to:[n[0],i[1]]};return[{move:o,preservedDegree:Hr(t,i)},{move:s,preservedDegree:Hr(t,n)}].sort((e,t)=>t.preservedDegree-e.preservedDegree||Dr(e.move.to).localeCompare(Dr(t.move.to))||Dr(e.move.from).localeCompare(Dr(t.move.from))).map(e=>e.move)};function qr(e){const t=JSON.parse(JSON.stringify(e||{}));let i=Array.isArray(t.rooms)?t.rooms:[];const n=new Map;for(const e of i){const t=Zt(e);if(t)for(let e=0;ee.key.localeCompare(t.key))){let t=null;for(const n of Lr(e,i)){const e=a.get(Dr(n.from));if(e&&e!==Dr(n.to))continue;const r=Er(i,n);if(Nr(i,r,n)){t=n,i=r;break}}t?(a.set(Dr(t.from),Dr(t.to)),r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}t.rooms=i;for(const e of t.room_drafts||[]){if(!Array.isArray(e?.points)||e.points.length<2)continue;const t=e.points.map(e=>[...e]),i=t.slice(0,-1).flatMap((i,n)=>{const r=t[n+1],o=Tr(i,r);return o?[{key:`${String(e.id||"")}:${n}`,a:[...i],b:[...r],axis:o.axis}]:[]});let n=t;for(const e of i){let t=null;for(const i of Lr(e,[{poly:n}])){const e=n.map(e=>Ir(e,i)),r=e.length>=4&&Ar(e[0],e[e.length-1]),o=r?e.slice(0,-1):e;if(r?Pr(o):Fr(o)){t=i,n=e;break}}t?(r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}e.points=n}for(const e of t.partitions||[]){if(!Array.isArray(e?.a)||!Array.isArray(e?.b))continue;const i=Tr(e.a,e.b);if(!i)continue;const n={key:String(e.id||Or(e.a,e.b)),a:[...e.a],b:[...e.b],axis:i.axis};let a=null;for(const i of Lr(n,[{poly:[e.a,e.b]}])){const n=Ir(e.a,i),r=Ir(e.b,i),o=Math.hypot(r[0]-n[0],r[1]-n[1]);if(!(o>0))continue;const s=(t.openings||[]).filter(t=>"partition"===t?.host?.kind&&t.host.id===e.id).every(e=>{const t=Number(e.host.t),i=Number(e.length);return Number.isFinite(t)&&t>=0&&t<=1&&Number.isFinite(i)&&i>0&&t*o-i/2>=-1e-12&&t*o+i/2<=o+1e-12});if(s){a=i,e.a=n,e.b=r;break}}a?(r++,s=Math.max(s,Math.hypot(a.to[0]-a.from[0],a.to[1]-a.from[1]))):o++}return{space:t,report:{wallsStraightened:r,wallsStraightenSkipped:o,maxStraightenShift:s},changed:r>0}}const jr=10**9,Br=240,Wr=1e-4;function Ur(e){if(Array.isArray(e))return e.map(e=>Ur(e));if(null!==e&&"object"==typeof e){const t={};for(const[i,n]of Object.entries(e))t[i]=Ur(n);return t}return e}function Gr(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=(e<0||Object.is(e,-0)?-1:1)*(Math.floor(Math.abs(e)*jr+.5)/jr);return 0===t?0:t}function Vr(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=e*Br,i=Math.round(t);if(Math.abs(t-i)null!==Yr(e)):[]}function Xr(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=Gr(e[i]))}function Jr(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=Vr(e[i]))}function Qr(e){if(Array.isArray(e))for(let t=0;t{for(const r of n){const n=t[r];"number"==typeof n&&Number.isFinite(n)&&i(n,e)}},n=t=>{if(Array.isArray(t))for(let n=0;n{if(Array.isArray(e))for(const t of e)n(t)};for(const i of Zr(e.rooms))t(i,["x","y","w","h"]),r(i.poly);for(const t of Zr(e.walls))n(t.a),n(t.b);for(const t of Zr(e.wall_segments))n(t.a),n(t.b);for(const i of Zr(e.openings))t(i,["x","y"]);for(const i of Zr(e.decor))"line"===i.kind?t(i,["x1","y1","x2","y2"]):"rect"===i.kind||"ellipse"===i.kind||"furniture"===i.kind?t(i,["x","y","w","h"]):"text"===i.kind&&t(i,["x","y"]);for(const t of Zr(e.room_drafts))r(t.points);for(const t of Zr(e.partitions))n(t.a),n(t.b);for(const t of Zr(e.wall_columns))n(t.center);for(const t of Zr(e.open_spans))n(t.a),n(t.b)}const r=Yr(t);if(!r)return;const o=new Map;if(n)for(const e of Zr(n.spaces))null!=e.id&&o.set(String(e.id),e);for(const e of Object.values(r)){const t=Yr(e);if(!t)continue;const n=null!=t.s&&o.get(String(t.s))||null;for(const e of["x","y"]){const r=t[e];"number"==typeof r&&Number.isFinite(r)&&i(r,n)}}}function io(e){const t=Number(e?.cell_cm);return t>0?t:5}function no(e,t={}){const i={canonicalized:0,far:0,maxShift:0,maxShiftCm:0,spaces:[],bySpace:new Map},n=Zr(Yr(e)?.spaces);let r=5;for(const e of n)r=Math.max(r,io(e));to(e,t,(e,t)=>{const n=e*Br,o=Math.abs(n-Math.round(n)),s=Vr(e),a=o>0&&o=Wr))return;const l=a&&"number"==typeof s?Math.abs(s-e):0;if(a?i.canonicalized++:i.far++,i.maxShift=Math.max(i.maxShift,l),i.maxShiftCm=Math.max(i.maxShiftCm,l*Br*(t?io(t):r)),!t?.id||!a)return;const c=String(t.id);let h=i.bySpace.get(c);h||(h={spaceId:c,space:String(t.title||c),canonicalized:0,far:0,maxShift:0,maxShiftCm:0},i.bySpace.set(c,h)),h.canonicalized++,h.maxShift=Math.max(h.maxShift,l),h.maxShiftCm=Math.max(h.maxShiftCm,l*Br*io(t))}),i.bySpace.size&&to(e,t,(e,t)=>{if(!t?.id)return;const n=i.bySpace.get(String(t.id));if(!n)return;const r=e*Br;Math.abs(r-Math.round(r))>=Wr&&n.far++}),i.spaces=[...i.bySpace.values()];const{bySpace:o,...s}=i;return s}function ro(e){return function(e){const t=e,i=Yr(t);i&&Jr(i,["x","y"]);return t}(Ur(e))}function oo(e){const t=e,i=Yr(t);if(!i)return t;for(const e of Object.values(i)){const t=Yr(e);t&&Jr(t,["x","y"])}return t}function so(e){return ao(Ur(e))}function ao(e){const t=e,i=Yr(t);if(!i)return t;for(const e of Zr(i.spaces)){Xr(e,["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"]);for(const t of Zr(e.rooms))Jr(t,["x","y","w","h"]),eo(t.poly);for(const t of Zr(e.walls))Qr(t.a),Qr(t.b);for(const t of Zr(e.wall_segments))Qr(t.a),Qr(t.b);for(const t of Zr(e.openings)){Jr(t,["x","y"]),Xr(t,["angle","length"]);const e=Yr(t.host);e&&Xr(e,["t"])}for(const t of Zr(e.decor))"line"===t.kind?Jr(t,["x1","y1","x2","y2"]):"rect"===t.kind||"ellipse"===t.kind||"furniture"===t.kind?(Jr(t,["x","y","w","h"]),Xr(t,["angle"])):"text"===t.kind&&(Jr(t,["x","y"]),Xr(t,["scale","angle"]));for(const t of Zr(e.room_drafts))eo(t.points);for(const t of Zr(e.partitions))Qr(t.a),Qr(t.b);for(const t of Zr(e.wall_columns))Qr(t.center),"square"===t.shape&&Xr(t,["angle"]);for(const t of Zr(e.open_spans))Qr(t.a),Qr(t.b)}for(const e of Zr(i.markers))Xr(e,["angle"]);return t}const lo=15,co=8;function ho(e,t,i,n,r){const o=i[0]-e[0],s=i[1]-e[1],a=Math.hypot(o,s);if(!(a>0)||a<=r+1e-9)return null;const l=o/a,c=s/a,h=t=>{const n=(t[0]-e[0])*l+(t[1]-e[1])*c,o=(r-n)/(a-n);return!Number.isFinite(o)||o<-1e-9||o>1+1e-9?null:[t[0]+(i[0]-t[0])*o,t[1]+(i[1]-t[1])*o]},d=h(t),u=h(n);return d&&u?[[e[0],e[1]],t,d,u,n]:null}const uo=Math.sin(.25*Math.PI/180);function po(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<3}function _o(e){const t=Number(e)>0?Number(e):5;if(5===t)return 8;const i=5/t*8;return Math.min(80,Math.max(.5,i))}function mo(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<2}function go(e){return Number.isFinite(e)?Math.max(1,Math.min(100,e)):1}function fo(e,t){return!Number.isFinite(e)||e<0?"":String(t?Math.round(e/2.54*100)/100:Math.round(100*e)/100)}function vo(e,t,i){if(!Number.isFinite(e)||e<=0)return 0;const n=Number(t)>0?Number(t):5;return go(e)/n*i}function yo(e,t){return t>0&&Number.isFinite(e)?Math.round(e/t)*t:e}function bo(e){return Math.max(1e-6*Math.abs(e),1e-9)}function wo(e,t){if(!(t>0&&Number.isFinite(e)))return e;const i=yo(e,t);return Math.abs(i-e)<=bo(t)?i:e}function ko(e,t){let i=t[0]-e[0],n=t[1]-e[1];const r=Math.hypot(i,n);return r<1e-12?[1,0]:(i/=r,n/=r,(i<-1e-12||Math.abs(i)<=1e-12&&n<0)&&(i=-i,n=-n),[i,n])}function xo(e,t,i){const n=[wo(e[0],i),wo(e[1],i)],r=[wo(t[0],i),wo(t[1],i)],o=yo((n[0]+r[0])/2,i),s=yo((n[1]+r[1])/2,i),[a,l]=ko(n,r);let c=Math.atan2(l,a);c<0&&(c+=Math.PI);const h=Math.round(1800*c)/1800,d=i>0&&i<.01?6:i<1?4:2;return`${o.toFixed(d)},${s.toFixed(d)}@${h.toFixed(4)}`}function $o(e,t,i,n){return 1===n?xo(e,t,i):xo([e[0]/n,e[1]/n],[t[0]/n,t[1]/n],i)}function So(e,t){if(!Array.isArray(e.a)||!Array.isArray(e.b)||e.a.length<2||e.b.length<2)return null;const i=[Number(e.a[0]),Number(e.a[1]),Number(e.b[0]),Number(e.b[1])];if(!i.every(Number.isFinite))return null;const n=t>0?t:1;return[[i[0]*n,i[1]*n],[i[2]*n,i[3]*n]]}function Mo(e,t,i,n,r){const o=r>0?r:1;return{key:$o(e,t,n,o),cm:go(i),a:[e[0]/o,e[1]/o],b:[t[0]/o,t[1]/o]}}function Ro(e,t){const i=t>0?t:1,n=[];for(const t of e){const e=t.key.lastIndexOf("@");if(e<0)continue;const[r,o]=t.key.slice(0,e).split(",").map(Number),s=Number(t.key.slice(e+1));[r,o,s].every(Number.isFinite)&&n.push({w:t,x:r*i,y:o*i,ang:s})}return n}function To(e,t){const[i,n]=ko(e,t);let r=Math.atan2(n,i);return r<0&&(r+=Math.PI),r}function Co(e,t){let i=Math.abs(e-t);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function Do(e,t,i,n,r=1){if(!e?.length)return null;const o=$o(t,i,n,r),s=e.find(e=>e.key===o);if(s)return s;const a=r>0?r:1,l=bo(n)*a,c=(e,t)=>Math.abs(e[0]-t[0])<=l&&Math.abs(e[1]-t[1])<=l;for(const n of e){const e=So(n,a);if(e&&(c(e[0],t)&&c(e[1],i)||c(e[0],i)&&c(e[1],t)))return n}const h=(t[0]+i[0])/2,d=(t[1]+i[1])/2,u=To(t,i),p=Math.max(.5*n,1e-9)*a;for(const t of Ro(e,a))if(Co(t.ang,u)&&Math.hypot(t.x-h,t.y-d)<=p)return t.w;return null}function Ao(e,t,i,n,r=1){const o=Do(e,t,i,n,r);if(o&&o.cm>0)return go(o.cm);const s=function(e,t,i,n,r){if(!e?.length)return null;const o=r>0?r:1,s=Math.hypot(i[0]-t[0],i[1]-t[1]);if(s<1e-12)return null;const a=To(t,i),l=Math.max(.5*n,1e-9)*o;let c=null;for(const n of e){if(!(n.cm>0))continue;const e=So(n,o);if(!e)continue;const r=Math.hypot(e[1][0]-e[0][0],e[1][1]-e[0][1]);if(r<1e-12||!Co(To(e[0],e[1]),a))continue;if(bs(t[0],t[1],e[0][0],e[0][1],e[1][0],e[1][1])>l||bs(i[0],i[1],e[0][0],e[0][1],e[1][0],e[1][1])>l)continue;if(r+l(o.has(e.key)||(e=>{const t=So(e,n);if(!t)return!1;const[i,o]=t,a=o[0]-i[0],c=o[1]-i[1],h=Math.hypot(a,c);if(h<=l)return!1;if(!s.some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];return Co(To(i,o),To(t,n))&&bs(i[0],i[1],t[0],t[1],n[0],n[1])<=l&&bs(o[0],o[1],t[0],t[1],n[0],n[1])<=l}))return!1;const d=(r||[]).some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];if(!Co(To(i,o),To(t,n)))return!1;const r=e=>Math.abs((e[0]-i[0])*c-(e[1]-i[1])*a)/h;if(r(t)>l||r(n)>l)return!1;const s=h*h,d=((t[0]-i[0])*a+(t[1]-i[1])*c)/s,u=((n[0]-i[0])*a+(n[1]-i[1])*c)/s;return Math.min(1,Math.max(d,u))-Math.max(0,Math.min(d,u))>l/h});return!d})(e))&&e.cm>=1&&e.cm<=100)}function zo(e,t,i,n=8){const[r,o]=ko(e,t);let s=Math.atan2(o,r);s<0&&(s+=Math.PI);let a=i*Math.PI/180%Math.PI;a<0&&(a+=Math.PI);let l=Math.abs(s-a);return l>Math.PI/2&&(l=Math.PI-l),l<=n*Math.PI/180}function Po(e,t,i,n,r=1,o="affine",s){if(!e?.length)return[];if(t.length!==i.length)return"fixed-topology"===o&&s?.(),e.slice();const a=r>0?r:1,l=Math.max(.5*n,1e-9)*a,c=Math.max(n*a*1e-6,1e-9),h=[],d=new Map,u=new Map,p=(e,t,i)=>{const n=e.get(t)||new Set;n.add(i),e.set(t,n)};for(let e=0;e[e[0]+(t[0]-e[0])*i,e[1]+(t[1]-e[1])*i],m=(e,t)=>Math.hypot(e[0]-t[0],e[1]-t[1])<=c,g=(e,t)=>{if("fixed-topology"===o){const i=t.na[0]-t.oa[0],n=t.na[1]-t.oa[1],r=t.nb[0]-t.ob[0],o=t.nb[1]-t.ob[1];return Math.hypot(i-r,n-o)<=c?[e[0]+i,e[1]+n]:m(e,t.oa)?[...t.na]:m(e,t.ob)?[...t.nb]:[...e]}const i=Math.max(0,Math.min(1,((e[0]-t.oa[0])*t.dx+(e[1]-t.oa[1])*t.dy)/t.len2));return _(t.na,t.nb,i)},f=(e,t)=>{const[i,n]=ko(e,t);return(t[0]-e[0])*i+(t[1]-e[1])*n>=0?[[...e],[...t]]:[[...t],[...e]]},v=[],y=[],b=(e,t,i)=>{if(Math.hypot(t[0]-e[0],t[1]-e[1])<=c)return;const[r,o]=f(e,t),s=go(i);if(y.some(e=>e.entry.cm===s&&m(e.span[0],r)&&m(e.span[1],o)))return;const l=Mo(r,o,s,n,a);v.push(l),y.push({entry:l,span:[r,o]})};for(const t of e){const e=So(t,a);if(e){const[i,n]=f(e[0],e[1]),r=n[0]-i[0],s=n[1]-i[1],a=r*r+s*s,d=Math.sqrt(a);if(d<=c){v.push({...t,cm:go(t.cm)});continue}const u=[];for(const e of h){if(!Co(To(i,n),To(e.oa,e.ob)))continue;const t=e=>Math.abs((e[0]-i[0])*s-(e[1]-i[1])*r)/d;if(t(e.oa)>l||t(e.ob)>l)continue;const o=((e.oa[0]-i[0])*r+(e.oa[1]-i[1])*s)/a,h=((e.ob[0]-i[0])*r+(e.ob[1]-i[1])*s)/a,p=Math.max(0,Math.min(o,h)),_=Math.min(1,Math.max(o,h));(_-p)*d>c&&u.push({lo:p,hi:_,move:e})}if(!u.length){"fixed-topology"===o?v.push({...t}):b(i,n,t.cm);continue}const p=[0,1,...u.flatMap(({lo:e,hi:t})=>[e,t])].sort((e,t)=>e-t).filter((e,t,i)=>0===t||Math.abs(e-i[t-1])*d>c),y=[];for(let e=0;e+1a>=e.lo-1e-12&&a<=e.hi+1e-12);if(!l.length){y.push([o,s]);continue}const h=[g(o,l[0].move),g(s,l[0].move)],f=l.slice(1).some(e=>{const t=g(o,e.move),i=g(s,e.move);return!m(h[0],t)||!m(h[1],i)});y.push(f?[o,s]:h)}const w=(e,t)=>{const i=e[1][0]-e[0][0],n=e[1][1]-e[0][1],r=t[1][0]-t[0][0],o=t[1][1]-t[0][1],s=Math.hypot(i,n);return!(s<=c||i*r+n*o<=0)&&Math.abs(i*o-n*r)/s<=c},k=[];for(const e of y){const t=k[k.length-1];t&&m(t[1],e[0])&&w(t,e)?t[1]=e[1]:k.push([[...e[0]],[...e[1]]])}if("fixed-topology"===o&&1===k.length){const[i,n]=k[0];if(m(i,e[0])&&m(n,e[1])||m(i,e[1])&&m(n,e[0])){v.push({...t});continue}}for(const[e,i]of k)b(e,i,t.cm);continue}if("fixed-topology"===o){const e=u.get(t.key);if(1===e?.size){const i=[...e][0];v.push(i===t.key?{...t}:{...t,key:i});continue}const i=[Ro([t],a)[0]];1!==a&&i.push(Ro([t],1)[0]);const n=i.filter(Boolean).some(e=>h.some(t=>{if(!Co(e.ang,To(t.oa,t.ob)))return!1;const i=((e.x-t.oa[0])*t.dx+(e.y-t.oa[1])*t.dy)/t.len2;return i>=-1e-6&&i<=1.000001&&bs(e.x,e.y,t.oa[0],t.oa[1],t.ob[0],t.ob[1])<=l}));((e?.size||0)>1||n)&&s?.(),v.push({...t});continue}let i="";const r=d.get(t.key);if(1===r?.size&&(i=[...r][0]),!i){const e=Ro([t],a)[0];if(e){const t=new Set;for(const i of h){if(!Co(e.ang,To(i.oa,i.ob)))continue;const r=((e.x-i.oa[0])*i.dx+(e.y-i.oa[1])*i.dy)/i.len2;if(r<-1e-6||r>1.000001)continue;if(bs(e.x,e.y,i.oa[0],i.oa[1],i.ob[0],i.ob[1])>l)continue;const o=g([e.x,e.y],i),[s,c]=ko(i.na,i.nb),h=Math.max(n*a,1e-6);t.add($o([o[0]-s*h,o[1]-c*h],[o[0]+s*h,o[1]+c*h],n,a))}1===t.size&&(i=[...t][0])}}v.push({...t,key:i||t.key,cm:go(t.cm)})}return v}function Fo(e,t,i,n,r=1,o="affine"){return Po(e,t,i,n,r,o)}function Io(e,t,i,n,r=1,o="fixed-topology"){let s=!1;const a=Po(e,t,i,n,r,o,()=>{s=!0});return{walls:s?(e||[]).map(e=>({...e})):a,rejected:s}}function Eo(e,t,i,n=1,r=[]){const o=n>0?n:1,s=Math.abs(i),a=Math.max(s*o*Wr,1e-9),l=(r||[]).flatMap(e=>{const t=So(e,o);return t?t.map(e=>[...e]):[]}),c=e=>e.every((e,t)=>(e=>{if(!(s>0))return!0;const t=e/o/s;return Math.abs(t-Math.round(t))Math.abs(e-i[t])<=a)),h=[],d=e=>JSON.stringify([e.key,e.cm,e.a,e.b]);for(const i of e||[]){const e=So(i,o);if(!e)continue;const[n,r]=e;if(![n[0],n[1],r[0],r[1]].every(Number.isFinite)||!c(n)||!c(r)){h.push(d(i));continue}const s=r[0]-n[0],l=r[1]-n[1],u=Math.hypot(s,l);if(u<=a){h.push(d(i));continue}const p=s/u,_=l/u,m=[];for(const e of t){const[t,i]=e;if(![t?.[0],t?.[1],i?.[0],i?.[1]].every(Number.isFinite))continue;const r=e=>Math.abs((e[0]-n[0])*_-(e[1]-n[1])*p);if(r(t)>a||r(i)>a)continue;const o=(t[0]-n[0])*p+(t[1]-n[1])*_,s=(i[0]-n[0])*p+(i[1]-n[1])*_,l=Math.max(0,Math.min(o,s)),c=Math.min(u,Math.max(o,s));c-l>a&&m.push([l,c])}m.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let g=0;for(const[e,t]of m){if(e>g+a)break;if(g=Math.max(g,t),g>=u-a)break}ge.key!==s);return null==n||n<1?a:[...a,Mo(t,i,n,r,o)]}function Ho(e,t,i,n,r,o=[],s=1){let a=e?e.slice():[];for(const e of function(e,t,i,n,r=1,o=[]){const s=ss(e,t,i,n,r,o);if(!s)return[];const a=[];for(let e=0;e0||(c=No(c,t,i,n,r,s)))}return c}function qo(e){const{a:t,b:i,halfDepth:n}=e;if(!Array.isArray(t)||!Array.isArray(i)||t.length<2||i.length<2||![t[0],t[1],i[0],i[1]].every(Number.isFinite))return null;const r=i[0]-t[0],o=i[1]-t[1],s=Math.hypot(r,o);if(!(s>1e-9&&n>0&&Number.isFinite(n)))return null;const a=-o/s*n,l=r/s*n;return[[t[0]+a,t[1]+l],[i[0]+a,i[1]+l],[i[0]-a,i[1]-l],[t[0]-a,t[1]-l]]}function jo(e,t,i){return Math.hypot(e[0]-t[0],e[1]-t[1])<=i}function Bo(e,t,i){const n=t.b[0]-t.a[0],r=t.b[1]-t.a[1],o=n*n+r*r;if(!(o>i*i))return!1;const s=((e[0]-t.a[0])*n+(e[1]-t.a[1])*r)/o;if(!(s>0&&s<1))return!1;const a=[t.a[0]+n*s,t.a[1]+r*s];return Math.hypot(e[0]-a[0],e[1]-a[1])<=i}function Wo(e,t,i,n){const r=Math.hypot(t,i);if(!(r>1e-9&&n>0))return;const o=[t/r,i/r],s=e.find(e=>Math.abs(e.u[0]*o[1]-e.u[1]*o[0])<1e-9&&e.u[0]*o[0]+e.u[1]*o[1]>1-1e-9);s?s.halfDepth=Math.max(s.halfDepth,n):e.push({u:o,halfDepth:n})}function Uo(e,t){try{const i=Ht(xs(e),xs(t));let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(Xo(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function Go(e,t=1e-6){const i=(e||[]).map((e,t)=>({segment:e,index:t})).filter(({segment:e})=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(({segment:e})=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>jo(t,e,n))||o.push(e);const s=[];for(const e of o){const t=[];let r=!1;for(const{segment:o,index:s}of i){const i=Math.hypot(o.b[0]-o.a[0],o.b[1]-o.a[1]);jo(e,o.a,n)?t.push({u:[(o.b[0]-o.a[0])/i,(o.b[1]-o.a[1])/i],halfDepth:o.halfDepth,length:i,index:s}):jo(e,o.b,n)?t.push({u:[(o.a[0]-o.b[0])/i,(o.a[1]-o.b[1])/i],halfDepth:o.halfDepth,length:i,index:s}):Bo(e,o,n)&&(r=!0)}if(r||2!==t.length)continue;const[o,a]=t,l=o.u[0]*a.u[1]-o.u[1]*a.u[0];if(Math.abs(l)<1e-9)continue;const c=l<0?1:-1,h=[-o.u[1],o.u[0]],d=[-a.u[1],a.u[0]],u=[e[0]+h[0]*o.halfDepth*c,e[1]+h[1]*o.halfDepth*c],p=[e[0]-d[0]*a.halfDepth*c,e[1]-d[1]*a.halfDepth*c];if(!es(u,o.u,p,a.u))continue;const _=[[o,a,p,[d[0]*-c,d[1]*-c]],[a,o,u,[h[0]*c,h[1]*c]]];for(const[t,,i,r]of _){const o=Math.min(2*t.halfDepth,t.length),a=[-t.u[1]*t.halfDepth,t.u[0]*t.halfDepth],l=[[e[0]+a[0],e[1]+a[1]],[e[0]+t.u[0]*o+a[0],e[1]+t.u[1]*o+a[1]],[e[0]+t.u[0]*o-a[0],e[1]+t.u[1]*o-a[1]],[e[0]-a[0],e[1]-a[1]]],c=e=>(e[0]-i[0])*r[0]+(e[1]-i[1])*r[1],h=[];for(let e=0;e=-1e-12&&h.push(t),n>1e-12&&r<-1e-12||n<-1e-12&&r>1e-12){const e=n/(n-r);h.push([t[0]+(i[0]-t[0])*e,t[1]+(i[1]-t[1])*e])}}h.length>=3&&Math.abs(Xo(h))>n*n&&s.push({segmentIndex:t.index,wedge:h})}}return s}function Vo(e,t=1e-6){const i=(e||[]).filter(e=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(e=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>jo(t,e,n))||o.push(e);const s=[],a=i.map((e,t)=>({roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`join-${t}`,kind:"outer",cm:0,open:!1,half:e.halfDepth})),l=ds(a,n);for(const e of us(l).fans)s.push(e);const c=e=>!!ps(l,e);for(const e of o){if(c(e))continue;const t=[];for(const r of i)jo(e,r.a,n)?Wo(t,r.b[0]-r.a[0],r.b[1]-r.a[1],r.halfDepth):jo(e,r.b,n)?Wo(t,r.a[0]-r.b[0],r.a[1]-r.b[1],r.halfDepth):Bo(e,r,n)&&(Wo(t,r.a[0]-e[0],r.a[1]-e[1],r.halfDepth),Wo(t,r.b[0]-e[0],r.b[1]-e[1],r.halfDepth));if(!(t.length<2)){t.sort((e,t)=>Math.atan2(e.u[1],e.u[0])-Math.atan2(t.u[1],t.u[0])||e.halfDepth-t.halfDepth);for(let i=0;in*n&&s.push(m)}}}return s}function Ko(e,t,i,n){if(!(t>0)||!e||e.length<2)return"";if(i&&e.length>=3){let i=e;const r=e[e.length-1];if(e.length>=4&&Math.hypot(e[0][0]-r[0],e[0][1]-r[1])<1e-9&&(i=e.slice(0,-1)),i.length>=3){const e=i.map((e,i)=>n?.[i]||t),r=js(i,e),o=ns(i,e);if(r&&o)return`${rs(r)} ${rs(os(o))}`}}const r=[];for(let i=0;i=1e-9&&a>0&&r.push({a:o,b:s,halfDepth:a})}const o=r.map(qo);for(const{segmentIndex:e,wedge:t}of Go(r)){const i=o[e];if(!i)continue;const n=Uo(i,t);n&&(o[e]=n)}const s=[...o.filter(e=>!!e),...Vo(r)],a=function(e){let t=null;try{for(const i of e){if(i.length<3)continue;const e=xs(i);t=t?Et(t,e):[e]}return t}catch{return null}}(s);return a?Fs(a):s.map(e=>rs(e)).join(" ")}function Yo(e,t,i,n,r=1){if(!i.length)return!1;const o=Zo(n,r),s=(e[0]+t[0])/2,a=(e[1]+t[1])/2,[l,c]=ko(e,t);for(const e of i){const[t,i]=ko([e[0],e[1]],[e[2],e[3]]);if(!(Math.abs(l*i-c*t)>.05)&&bs(s,a,e[0],e[1],e[2],e[3])<=o)return!0}return!1}function Zo(e,t){return Math.max(e*(t>0?t:1)*.04,1e-9)}function Xo(e){let t=0;for(let i=0;ie[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s+0)+o&&(i=!i)}return i}([c[0]+.001*a,c[1]+.001*l],e)||(a=-a,l=-l),[a,l]}function Qo(e,t){const i=e[0]*t[1]-e[1]*t[0],n=e[0]*t[0]+e[1]*t[1];return Math.abs(i)<1e-9&&n>0}function es(e,t,i,n){const r=t[0]*n[1]-t[1]*n[0];if(Math.abs(r)<1e-12)return null;const o=[i[0]-e[0],i[1]-e[1]],s=(o[0]*n[1]-o[1]*n[0])/r;return[e[0]+s*t[0],e[1]+s*t[1]]}function ts(e,t,i){const n=e?.length||0;if(n<3||!Array.isArray(i)||i.length!==n)return 0;const r=(Math.trunc(t)%n+n)%n,o=e[r],s=e[(r+1)%n],a=s[0]-o[0],l=s[1]-o[1],c=Math.hypot(a,l);if(!(c>0))return 0;const h=Math.max(0,Number(i[r])||0);if(!(h>0))return c;const d=[a/c,l/c],u=Jo(e,r),p=[o[0]+u[0]*h,o[1]+u[1]*h],_=t=>{const r=Math.max(0,Number(i[t])||0);if(!(r>0))return null;const s=e[t],a=e[(t+1)%n],l=a[0]-s[0],c=a[1]-s[1],h=Math.hypot(l,c);if(!(h>0))return null;const u=Jo(e,t),_=es(p,d,[s[0]+u[0]*r,s[1]+u[1]*r],[l/h,c/h]);return _?(_[0]-o[0])*d[0]+(_[1]-o[1])*d[1]:null},m=_((r-1+n)%n)??0,g=(_((r+1)%n)??c)-m;return g>0?g:0}function is(e,t,i,n,r,o,s,a=1){const l=(e||[]).find(e=>e?.id===t),c=Zt(l);if(!c||c.length<3)return null;const h=ms(e,t,i,n,r,o,s,a);if(!h)return c.map(()=>0);const d=4*Zo(r,a);return c.map((e,t)=>{const i=c[(t+1)%c.length],n=[(e[0]+i[0])/2,(e[1]+i[1])/2];for(let e=0;e!(e>0)))return e.map(e=>[e[0],e[1]]);const r=[];for(let o=0;o0||u>0)){r.push([e[o][0],e[o][1]]);continue}if(d>0!=u>0){const t=e[o],i=d>0?[t[0]+p*d,t[1]+_*d]:[t[0],t[1]],n=u>0?[t[0]+m*u,t[1]+g*u]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(Qo(w,k)){const t=e[o],i=[t[0]+p*d,t[1]+_*d],n=[t[0]+m*u,t[1]+g*u];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const S=es(x,w,$,k),M=Math.max(d,u,1e-9),R=ps(i,e[o])?.limit??4*M;if(S){const i=Math.hypot(S[0]-e[o][0],S[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push(S);continue}if(Es(e,t,o)){r.push(S);continue}}d>0&&r.push([e[o][0]+p*d,e[o][1]+_*d]),u>0&&r.push([e[o][0]+m*u,e[o][1]+g*u]),d>0||u>0||r.push([e[o][0],e[o][1]])}return r.length>=3?r:null}function rs(e,t=!0){if(!e.length)return"";let i=`M ${e[0][0]} ${e[0][1]}`;for(let t=1;te?.id===t),a=Zt(s);if(!a||a.length<3)return null;const l=Zo(n,r),c=[];for(const i of e||[]){if(!i||i.id===t)continue;const e=Zt(i);if(e)for(const t of bn(a,e,l))c.push([t[0],t[1]],[t[2],t[3]])}for(const e of i||[])c.push([e[0],e[1]],[e[2],e[3]]);for(const e of o||[]){const t=So(e,r);t&&c.push(t[0],t[1])}const h=[],d=[];for(let e=0;el)continue;const s=((e[0]-t[0])*(i[0]-t[0])+(e[1]-t[1])*(i[1]-t[1]))/(n*n);s<=r||s>=1-r||(o.some(e=>Math.abs(e-s)*n<=2*l)||o.push(s))}o.sort((e,t)=>e-t);for(const n of o)h.push([t[0]+(i[0]-t[0])*n,t[1]+(i[1]-t[1])*n]),d.push(e)}return{poly:h,parent:d,orig:a}}function as(e,t,i,n){const r=t.poly.length,o=new Array(r).fill(0);if(!e?.length)return o;const s=new Set,a=[];for(let l=0;l0?(o[l]=go(c.cm),s.add(c.key)):a.push(l)}if(!a.length)return o;const l=n>0?n:1,c=Math.max(.5*i,1e-9)*l,h=Ro(e,l).filter(e=>e.w.cm>0);for(let e=a.length-1;e>=0;e--){const i=a[e],n=t.poly[i],s=t.poly[(i+1)%r],d=To(n,s);let u=null;for(const e of h){const t=So(e.w,l);if(!t||!Co(To(t[0],t[1]),d))continue;if(bs(n[0],n[1],t[0][0],t[0][1],t[1][0],t[1][1])>c||bs(s[0],s[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;const i=Math.hypot(s[0]-n[0],s[1]-n[1]),r=Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1]),o=Math.max(0,r-i);(!u||oc||bs(r[0],r[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;i=!0,o=Math.max(0,Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1])-_)}else{if(bs(e.x,e.y,n[0],n[1],r[0],r[1])>c)continue;o=Math.hypot(e.x-d,e.y-u)}(!p||i&&!p.exact||i===p.exact&&o0?i:1,o=(e||[]).filter(e=>e&&!e.open&&null!==e.kind&&Number.isFinite(e.half)&&e.half>0&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&[e.a[0],e.a[1],e.b[0],e.b[1]].every(Number.isFinite)&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>n).sort((e,t)=>e.key.localeCompare(t.key)||e.a[0]-t.a[0]||e.a[1]-t.a[1]||e.b[0]-t.b[0]||e.b[1]-t.b[1]||e.half-t.half),s=new Map;for(const e of o){const t=s.get(e.key);t?e.half>t.half&&s.set(e.key,{...t,half:e.half}):s.set(e.key,e)}const a=[...s.values()].flatMap(e=>[{point:[e.a[0],e.a[1]],other:e.b,halfDepth:e.half,kind:e.kind,key:e.key},{point:[e.b[0],e.b[1]],other:e.a,halfDepth:e.half,kind:e.kind,key:e.key}]).sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]||e.other[0]-t.other[0]||e.other[1]-t.other[1]||e.halfDepth-t.halfDepth),l=new Map;for(const e of a){const[t,i]=ls(e.point,n),r=cs(t,i),o=l.get(r)||[];o.push(e),l.set(r,o)}const c=[],h=new Map;for(const e of a){const t=hs(h,e.point,n).filter(t=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])<=n).sort((t,i)=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])-Math.hypot(i.point[0]-e.point[0],i.point[1]-e.point[1])||t.point[0]-i.point[0]||t.point[1]-i.point[1]);let i=t[0];if(!i){i={point:[...e.point],rays:[]},c.push(i);const[t,r]=ls(i.point,n),o=cs(t,r),s=h.get(o)||[];s.push(i),h.set(o,s)}const r=e.other[0]-e.point[0],o=e.other[1]-e.point[1],s=Math.hypot(r,o);if(!(s>n))continue;const a=[r/s,o/s];let l=Math.atan2(a[1],a[0]);l<0&&(l+=2*Math.PI),i.rays.push({u:a,halfDepth:e.halfDepth,length:s,angle:l})}const d=[],u=e=>{const t=1e-9*Math.max(1,r),i=e.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);return i.filter((e,n)=>!i.some((i,r)=>r!==n&&i.halfDepth>=e.halfDepth-t&&i.length>=e.length-t&&(i.halfDepth>e.halfDepth+t||i.length>e.length+t||re.length-t.length||e.halfDepth-t.halfDepth).map(e=>({...e}))};for(const e of c){const t=e.rays.sort((e,t)=>e.angle-t.angle||e.length-t.length||e.halfDepth-t.halfDepth),i=[];for(const e of t){const t=i[i.length-1];t&&Math.abs(e.angle-t.angle)<=1e-9?t.supports.push({halfDepth:e.halfDepth,length:e.length}):i.push({u:[...e.u],angle:e.angle,supports:[{halfDepth:e.halfDepth,length:e.length}]})}if(i.length>1&&2*Math.PI-i[i.length-1].angle+i[0].angle<=1e-9){const e=i.pop();i[0].supports.push(...e.supports)}if(i.length<3)continue;const r=i.map(t=>{const i=u(t.supports),r=new Set,o=[];for(const s of i){const i=[e.point[0]+t.u[0]*s.length,e.point[1]+t.u[1]*s.length];for(const t of hs(l,i,n)){if("shared"!==t.kind||Math.hypot(t.point[0]-i[0],t.point[1]-i[1])>n)continue;const s=t.other[0]-t.point[0],a=t.other[1]-t.point[1],l=Math.hypot(s,a);if(!(l>n))continue;const c=s/l,h=a/l;if(Math.hypot(t.other[0]-e.point[0],t.other[1]-e.point[1])<=n)continue;const d=`${t.key}|${t.point[0]}|${t.point[1]}|${t.other[0]}|${t.other[1]}|${t.halfDepth}`;r.has(d)||(r.add(d),o.push({start:[t.point[0],t.point[1]],u:[c,h],length:l,halfDepth:t.halfDepth}))}}return o.sort((e,t)=>e.start[0]-t.start[0]||e.start[1]-t.start[1]||e.u[0]-t.u[0]||e.u[1]-t.u[1]||e.length-t.length||e.halfDepth-t.halfDepth),{u:[...t.u],halfDepth:Math.max(...i.map(e=>e.halfDepth)),length:Math.max(...i.map(e=>e.length)),supports:i,continuations:o}}).filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);if(r.length<3)continue;const o=Math.max(...r.map(e=>e.halfDepth));o>0&&Number.isFinite(o)&&d.push({point:[...e.point],rays:r,halfDepth:o,limit:1.25*o})}d.sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]);const p=new Map;for(const e of d){const[t,i]=ls(e.point,n),r=cs(t,i),o=p.get(r)||[];o.push(e),p.set(r,o)}return{epsilon:n,coordinateScale:r,nodes:d,index:p}}function us(e){const t={fans:[],supports:[]};if(!e?.nodes?.length)return t;const i=Math.max(e.epsilon,1e-9)**2;for(const n of e.nodes){const e=n.rays.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0).map(e=>({...e,thickLength:Math.max(...e.supports.filter(t=>t.halfDepth>=e.halfDepth-1e-12).map(e=>e.length),0),angle:(()=>{const t=Math.atan2(e.u[1],e.u[0]);return t<0?t+2*Math.PI:t})()})).sort((e,t)=>e.angle-t.angle);if(e.length<2)continue;const r=n.point;for(const i of e)for(const e of i.supports){if(!(e.halfDepth>0&&e.length>0))continue;const n=-i.u[1]*e.halfDepth,o=i.u[0]*e.halfDepth,s=[r[0]+i.u[0]*e.length,r[1]+i.u[1]*e.length];t.supports.push([[r[0]+n,r[1]+o],[s[0]+n,s[1]+o],[s[0]-n,s[1]-o],[r[0]-n,r[1]-o]])}for(let n=0;n{const e=s.angle-o.angle;return e>0?e:e+2*Math.PI})();if(a<1e-9)continue;const l=a>Math.PI+1e-9,c=4*Math.max(o.halfDepth,s.halfDepth),h=[r[0]-o.u[1]*o.halfDepth,r[1]+o.u[0]*o.halfDepth],d=[r[0]+s.u[1]*s.halfDepth,r[1]-s.u[0]*s.halfDepth],u=o.u[0]*s.u[1]-o.u[1]*s.u[0],p=e=>{let t=Math.atan2(e[1]-r[1],e[0]-r[0])-o.angle;for(;t<0;)t+=2*Math.PI;return t<=a+1e-9};let _=null;if(Math.abs(u)>1e-9){const e=((d[0]-h[0])*s.u[1]-(d[1]-h[1])*s.u[0])/u,t=((d[0]-h[0])*o.u[1]-(d[1]-h[1])*o.u[0])/u,i=[h[0]+o.u[0]*e,h[1]+o.u[1]*e];(l?e<=1e-9&&t<=1e-9:e>1e-9&&e<=o.thickLength&&t<=s.thickLength)&&Math.hypot(i[0]-r[0],i[1]-r[1])<=c&&p(i)&&(_=i)}const m=e=>{Math.abs(Xo(e))>i&&t.fans.push(e)};if(_){const e=1.5*Math.max(o.halfDepth,s.halfDepth);m(ho([r[0],r[1]],h,_,d,e)??[[r[0],r[1]],h,_,d]);continue}if(l){m([[r[0],r[1]],h,d]);continue}const g=(e,t)=>Math.min(t,Math.sqrt(Math.max(c**2-e**2,0)),2*Math.max(o.halfDepth,s.halfDepth)),f=[h[0]+o.u[0]*g(o.halfDepth,o.thickLength),h[1]+o.u[1]*g(o.halfDepth,o.thickLength)],v=[d[0]+s.u[0]*g(s.halfDepth,s.thickLength),d[1]+s.u[1]*g(s.halfDepth,s.thickLength)];m([[r[0],r[1]],h,f,v,d])}}return t}function ps(e,t){return!e||!Array.isArray(t)||t.length<2||!t.slice(0,2).every(Number.isFinite)?null:hs(e.index,t,e.epsilon).filter(i=>Math.hypot(i.point[0]-t[0],i.point[1]-t[1])<=e.epsilon).sort((e,i)=>Math.hypot(e.point[0]-t[0],e.point[1]-t[1])-Math.hypot(i.point[0]-t[0],i.point[1]-t[1])||e.point[0]-i.point[0]||e.point[1]-i.point[1])[0]||null}function _s(e,t,i,n,r,o,s){return ds(gs(e,t,i,n,r,o,s),4*Zo(n,s),s)}function ms(e,t,i,n,r,o,s,a=1){const l=ss(e,t,n,r,a,i);if(!l)return null;const c=function(e,t,i){const n=(e||[]).find(e=>e?.id===t),r=Zt(n);if(!r)return[];const o=[];for(const n of e||[]){if(!n||n.id===t)continue;const e=Zt(n);if(e)for(const t of bn(r,e,i))o.push(t)}return o}(e,t,Zo(r,a)),h=function(e,t,i,n,r){const o=Zo(n,r),s=[];for(let a=0;abs(h,d,e[0],e[1],e[2],e[3])<=o);s.push(u?"shared":"outer")}return s}(l.poly,c,n,r,a),d=as(i,l,r,a),u=d.map((e,t)=>h[t]&&e>0?vo(e,o,s)/2:0);return{...l,kinds:h,cms:d,offsets:u}}function gs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=ms(e,l.id,t,i,n,r,o,s);if(c)for(let e=0;e0&&(a=No(a,e.a,e.b,e.cm,n,s));return a}function vs(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=gs(e,t,i,n,r,o,s),l=new Map;for(const e of a){if(e.open||!e.kind||!e.roomId)continue;const t=l.get(e.key)||new Set;t.add(e.roomId),l.set(e.key,t)}const c=e=>{const t=[...l.get(e)||[]].sort();return 1!==t.length&&2!==t.length?`ambiguous:${e}`:`${1===t.length?"outer":"shared"}:${t.join("|")}`},h=[],d=new Set;for(const e of a)!e.open&&e.cm>0&&!d.has(e.key)&&(d.add(e.key),h.push({...e,ownerSignature:c(e.key)}));const u=[];for(const a of e||[]){if(!a?.id)continue;const l=ms(e,a.id,t,i,n,r,o,s);if(l)for(let e=0;e0)||null===l.kinds[i]){e++;continue}const o=c($o(l.poly[i],l.poly[(i+1)%l.poly.length],n,s));let a=e;for(;a+10&&u.push({a:[d[0],d[1]],b:[p[0],p[1]],key:$o(d,p,n,s),cm:r,len:_,ownerSignature:o}),e=a+1}}}u.sort((e,t)=>t.len-e.len||e.key.localeCompare(t.key));const p=[],_=new Set,m=new Set,g=4*Zo(n,s);for(const e of u){const t=h.filter(t=>!m.has(t.key)&&t.cm===e.cm&&t.ownerSignature===e.ownerSignature&&Co(To(t.a,t.b),To(e.a,e.b))&&bs(t.a[0],t.a[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g&&bs(t.b[0],t.b[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g);if(t.length){for(const e of t)m.add(e.key);_.has(e.key)||(_.add(e.key),p.push(Mo(e.a,e.b,e.cm,n,s)))}}for(const e of h)m.has(e.key)||_.has(e.key)||(_.add(e.key),p.push(Mo(e.a,e.b,e.cm,n,s)));return p}function ys(e,t,i,n,r,o,s,a=1){const l=Zo(r,a),c=(n[0]+n[2])/2,h=(n[1]+n[3])/2,d=To([n[0],n[1]],[n[2],n[3]]);let u=null;for(const n of gs(e,t,i,r,o,s,a)){if(!Co(To(n.a,n.b),d))continue;const e=bs(c,h,n.a[0],n.a[1],n.b[0],n.b[1]);e>4*l||(!u||e[e[0],e[1]]),o=Math.abs(Xo(r));r.length>=3&&o>i&&(t=r,i=o)}return t}function ks(e,t,i,n,r,o,s,a=1,l,c){const h=(e||[]).find(e=>e?.id===t),d=Zt(h);if(!d||d.length<3)return null;if(!i?.length)return d.map(e=>[e[0],e[1]]);const u=ms(e,t,i,n,r,o,s,a);if(!u||!u.offsets.some(e=>e>0))return d.map(e=>[e[0],e[1]]);const p=c||_s(e,i,n,r,o,s,a),_=ns(u.poly,u.offsets,p);if(!_)return d.map(e=>[e[0],e[1]]);if(!p.nodes.length)return _;const m=void 0===l?Ns(e,i,n,[],r,o,s,a):null,g=l??("ok"===m?.status||"degraded-extra"===m?.status?m.roomGeom:void 0);if(g)try{const e=ws(Ht(xs(u.poly),g));if(e)return e}catch{}return function(e,t){try{return ws(Nt(xs(e),xs(t)))}catch{return null}}(_,u.poly)||d.map(e=>[e[0],e[1]])}function xs(e){const t=e.map(e=>[e[0],e[1]]);return t.push([e[0][0],e[0][1]]),[t]}function $s(e){return!(!Array.isArray(e)||!e.length)&&e.every(e=>Array.isArray(e)&&e.length&&e.every(e=>Array.isArray(e)&&e.length>=4&&e.every(e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1])))&&Math.abs(yi(e[0]))>1e-9)}function Ss(e,t,i,n){const r=n?new Set(n):null;let o=null;for(let n=0;nt.epsilon))continue;const l=Ds([[e.point[0]+a[0]*n.halfDepth,e.point[1]+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r+a[0]*n.halfDepth,e.point[1]+s.u[1]*r+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r-a[0]*n.halfDepth,e.point[1]+s.u[1]*r-a[1]*n.halfDepth],[e.point[0]-a[0]*n.halfDepth,e.point[1]-a[1]*n.halfDepth]],t.coordinateScale);if(!l)continue;const c=xs(l);o=o?Et(o,c):c}}return o}function Ms(e,t,i){let n=null;for(const r of e.rays)for(const e of r.continuations){const r=[-e.u[1],e.u[0]],o=[e.start[0]+e.u[0]*e.length,e.start[1]+e.u[1]*e.length],s=Ds([[e.start[0]+r[0]*e.halfDepth,e.start[1]+r[1]*e.halfDepth],[o[0]+r[0]*e.halfDepth,o[1]+r[1]*e.halfDepth],[o[0]-r[0]*e.halfDepth,o[1]-r[1]*e.halfDepth],[e.start[0]-r[0]*e.halfDepth,e.start[1]-r[1]*e.halfDepth]],t.coordinateScale);if(!s)continue;const a=Nt(xs(s),i);Array.isArray(a)&&0!==a.length&&(n=n?Et(n,a):a)}return n}function Rs(e,t,i=2*(4*e.halfDepth+2*t.epsilon)){const n=function(e,t=uo){const i=new Set,n=Number.isFinite(t)&&t>=0?t:uo;for(let t=0;te-t)}(e);return n.length?Ss(e,t,i,n):null}function Ts(e,t,i,n,r){const o=function(e){let t=null;for(const i of e){const e=xs(i);try{t=t?Et(t,e):e}catch{}}return t}(function(e,t,i=!1){if(!e)return[];const n=[];for(const r of e.nodes)for(let o=0;o1e-9)||h>=Math.PI-1e-9)continue;const d=[-s.u[1],s.u[0]],u=[-a.u[1],a.u[0]],p=[r.point[0]+d[0]*s.halfDepth,r.point[1]+d[1]*s.halfDepth],_=[r.point[0]-u[0]*a.halfDepth,r.point[1]-u[1]*a.halfDepth],m=es(p,s.u,_,a.u);if(!m)continue;const g=Math.hypot(m[0]-r.point[0],m[1]-r.point[1]);if(!Number.isFinite(g)||g<=r.limit)continue;const f=t?Math.sqrt(Math.max(0,r.limit*r.limit-s.halfDepth*s.halfDepth)):0,v=t?Math.sqrt(Math.max(0,r.limit*r.limit-a.halfDepth*a.halfDepth)):0,y=Ds([[p[0]+s.u[0]*f,p[1]+s.u[1]*f],[_[0]+a.u[0]*v,_[1]+a.u[1]*v],m],e.coordinateScale);if(y&&n.push(y),i){const t=m[0]-r.point[0],i=m[1]-r.point[1],o=Math.hypot(t,i),s=g-r.limit;if(o>e.epsilon&&s>e.epsilon){const a=Math.min(Math.max(8*e.epsilon,.05*r.halfDepth),.25*s),l=t/o,c=i/o,h=-c,d=l,u=Ds([[m[0]-l*a+h*a,m[1]-c*a+d*a],[m[0]-l*a-h*a,m[1]-c*a-d*a],[m[0]+l*a,m[1]+c*a]],e.coordinateScale);u&&n.push(u)}}}return n}({...t,nodes:[e]},i,n));return o&&r?Ht(o,r):o}function Cs(e,t,i,n){if(!e||!t.nodes.length)return e;let r=null;try{r=function(e){let t=null;for(const i of e.nodes){const n=Rs(i,e);n&&(t=t?Et(t,n):n)}return t}(t)}catch{return e}let o=e;for(const e of t.nodes){const s=4*e.halfDepth+2*t.epsilon,a=2*s,l=[[e.point[0]-s,e.point[1]-s],[e.point[0]+s,e.point[1]-s],[e.point[0]+s,e.point[1]+s],[e.point[0]-s,e.point[1]+s]];try{let s=o;const c=Ts(e,t,!1,!0,r);c&&(s=Ht(s,c));let h=Ss(e,t,a);const d=Ts(e,t,!0,!0,r);d&&(h=Ht(h,d)),r&&(h=Et(h,r));const u=.02*Math.min(...e.rays.map(e=>e.halfDepth));if(h=Et(h,xs([[e.point[0]-u,e.point[1]-u],[e.point[0]+u,e.point[1]-u],[e.point[0]+u,e.point[1]+u],[e.point[0]-u,e.point[1]+u]])),!h)continue;let p=Nt(h,xs(l));n?p=Nt(p,n):i&&(p=Nt(p,i));const _=xs(l),m=Ht(s,_),g=i?Ht(Nt(s,_),i):null,f=Ms(e,t,_);o=Et(m,...g?[g]:[],...f?[f]:[],p)}catch{}}if(r)try{let e=r;n?e=Nt(e,n):i&&(e=Nt(e,i)),o=Et(o,e)}catch{}return o}function Ds(e,t=1){if(!Array.isArray(e)||e.length<3)return null;const i=Number.isFinite(t)&&t>0?t:1,n=1e-12*Math.max(1,i),r=[];for(const t of e){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),i=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(i))return null;const o=Math.round(e/n)*n,s=Math.round(i/n)*n;if(!Number.isFinite(o)||!Number.isFinite(s))return null;r.push([Object.is(o,-0)?0:o,Object.is(s,-0)?0:s])}return Math.abs(Xo(r))>n*n?r:null}function As(e,t,i,n){if(bs(e[0],e[1],t[0],t[1],i[0],i[1])>n)return!1;const r=i[0]-t[0],o=i[1]-t[1],s=(e[0]-t[0])*r+(e[1]-t[1])*o,a=r*r+o*o,l=n*Math.sqrt(a);return s>=-l&&s<=a+l}function Os(e,t,i){const n=[],r=[];for(let o=0;oi*i))continue;const d=i/Math.sqrt(h),u=[0,1];for(const e of t)for(const t of[e.a,e.b]){if(!As(t,s,a,i))continue;const e=((t[0]-s[0])*l+(t[1]-s[1])*c)/h;e>d&&e<1-d&&u.push(e)}u.sort((e,t)=>e-t);const p=u.filter((e,t)=>0===t||Math.abs(e-u[t-1])>d);for(let e=0;e=3&&r.length===n.length?{poly:n,offsets:r}:null}function zs(e,t,i,n,r,o,s,a){const l=(e||[]).map(Zt).filter(e=>!!e&&e.length>=3);if(!l.length)return null;let c=Et(xs(l[0]));for(let e=1;e"outer"===e.kind&&e.half>0),u=4*Zo(n,s),p=a||ds(h,u,s);let _=null;for(const e of function(e){const t=[];for(const i of Array.isArray(e)?e:[])if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,-1).map(e=>[e[0],e[1]]);i.length>=3&&t.push(i)}return t}(c)){const t=Os(e,d,u);if(!t||!t.offsets.some(e=>e>0))continue;const i=js(t.poly,t.offsets,p),n=ns(t.poly,t.offsets,p);if(!i||!n)continue;const r=Ht(xs(i),xs(n));_=_?Et(_,r):r}return{centre:c,shell:_||[]}}function Ps(e,t,i,n,r,o,s=1){try{const a=zs(e,t,i,n,r,o,s,_s(e,t,i,n,r,o,s));if(!a)return[];return a.shell?.length?Et(a.centre,a.shell):a.centre}catch{return null}}function Fs(e){if(!e)return"";let t="";for(const i of e)if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,e.length-1);i.length<3||(t+=(t?" ":"")+rs(i.map(e=>[e[0],e[1]])))}return t}const Is=15;function Es(e,t,i){const n=e?.length||0;if(n<3||t?.length!==n)return!1;const r=e[(i-1+n)%n],o=e[i],s=e[(i+1)%n],a=[r[0]-o[0],r[1]-o[1]],l=[s[0]-o[0],s[1]-o[1]],c=Math.hypot(a[0],a[1]),h=Math.hypot(l[0],l[1]);if(!(c>1e-9&&h>1e-9))return!1;const d=Math.max(-1,Math.min(1,(a[0]*l[0]+a[1]*l[1])/(c*h))),u=Math.acos(d);if(!(u>1e-9))return!1;if(u>=Is*Math.PI/180)return!1;const p=Math.max(Math.max(0,t[(i-1+n)%n]),Math.max(0,t[i]));if(!(p>0))return!1;const _=p/Math.tan(u/2);return Number.isFinite(_)&&_>0&&_e>0))continue;for(const e of l.offsets)e>0&&(u=Math.max(u,2*e));const c=js(l.poly,l.offsets,d),p=ns(l.poly,l.offsets,d);c&&h.push({outset:c,inset:p})}for(const e of l){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);if(t.length){const n=Math.min(Math.max(...t)-Math.min(...t),Math.max(...i)-Math.min(...i)),r=Math.min(...e.map((t,i)=>{const n=e[(i+1)%e.length];return Math.hypot(n[0]-t[0],n[1]-t[1])}));u=Math.max(u,e.length>16?n:r)}}const p=function(e,t,i,n,r,o,s,a){if(!t?.length||!i?.length)return[];const l=4*Zo(n,s),c=new Map;for(const a of gs(e,t,i,n,r,o,s))!a.open&&a.half>0&&!c.has(a.key)&&c.set(a.key,a);const h=[...c.values()];if(h.length<2)return[];const d=a||ds(h,l),u=[];for(const e of i)for(const t of[[e[0],e[1]],[e[2],e[3]]])u.some(e=>Math.hypot(e[0]-t[0],e[1]-t[1])<=l)||u.push(t);const p=[],_=(e,t)=>{let i=0,n=0;if(Math.hypot(e.a[0]-t[0],e.a[1]-t[1])<=l)i=e.b[0]-e.a[0],n=e.b[1]-e.a[1];else{if(!(Math.hypot(e.b[0]-t[0],e.b[1]-t[1])<=l))return null;i=e.a[0]-e.b[0],n=e.a[1]-e.b[1]}const r=Math.hypot(i,n);return r>l?[i/r,n/r]:null};for(const e of u){const t=h.map(t=>({iv:t,u:_(t,e)})).filter(e=>!!e.u);for(let i=0;i0?[e.slice(),u,m,_]:[e.slice(),_,m,u];else{if(!f)continue;{const t=[-r.u[1],r.u[0]],i=[-o.u[1],o.u[0]],n=s<0?1:-1,a=[e[0]+t[0]*r.iv.half*n,e[1]+t[1]*r.iv.half*n],l=[e[0]-i[0]*o.iv.half*n,e[1]-i[1]*o.iv.half*n];y=s>0?[e.slice(),a,l]:[e.slice(),l,a]}}Math.abs(Xo(y))>l*l&&p.push(y)}}return p}(e,t,i,r,o,s,a,d),_=n.length?Bs(e,t,i,r,o,s,a):null;let m="exterior";try{const v=zs(e,t,i,r,o,s,a,d);m="paper";const y=v?v.shell?.length?Et(v.centre,v.shell):v.centre:[],b=e=>{const t=xs(e.outset);if(!e.inset)return t;const i=xs(e.inset);return Ht(t,i)};m="room-rings";let w=null;for(const e of h)try{const t=b(e);w=w?Et(w,t):t}catch{}if(m="edge-bodies",v)for(const n of qs(e,t,i,r,o,s,a))try{const e=Nt(xs(n.quad),v.centre);w=w?Et(w,e):e}catch{}m="junctions",w=function(e,t,i=1,n=Et){let r=e;for(const e of t||[]){const t=Ds(e,i);if(t)try{const e=xs(t);r=r?n(r,e):e}catch{}}return r}(w,p,a),m="facade-clip",w&&v&&(w=Nt(w,v.centre)),m="exterior-shell";const k=[];let x=0;if(v?.shell?.length)if(w)try{const e=Et(w,v.shell);if(!$s(e))throw new Error("invalid shell union");w=e}catch{if(!$s(w)||!$s(v.shell))throw new Error("invalid shell");k.push({id:"exterior-shell",geom:v.shell}),x++}else w=v.shell;if(m="multi-wall-trim",w&&d.nodes.length){const e=e=>e.rays.some(e=>e.supports.some(e=>e.length<2*e.halfDepth)),t=d.nodes.filter(e);if(t.length){w=Cs(w,{...d,nodes:t},v?.centre,y)}}if(m="junction-corners",d.nodes.length){const n=us(d),l=function(e,t,i,n,r,o,s,a){try{const l=zs(e,t,i,n,r,o,s,{epsilon:a.epsilon,coordinateScale:a.coordinateScale,nodes:[],index:new Map});return l?l.shell?.length?Et(l.centre,l.shell):l.centre:null}catch{return null}}(e,t,i,r,o,s,a,d);for(const e of n.fans)try{let t=[xs(e)];if(l&&(t=Nt(t,l)),!t?.length)continue;w=w?Et(w,t):t}catch{}g=w,f=Math.max(d.epsilon,1e-9)**2,w=Array.isArray(g)?g.map(e=>{if(!Array.isArray(e)||!e.length)return e;const[t,...i]=e;return Math.abs(Xo(t||[]))<=f?null:[t,...i.filter(e=>Math.abs(Xo(e||[]))>f)]}).filter(e=>!!e):g}const $=w||[],S=[...$s($)?[{id:"room-primary",geom:$}]:[],...k.map((e,t)=>({id:`room-isolated-${t}`,geom:e.geom}))];m="openings";for(const e of n){if(!(e.length>0))continue;const t=Gs(_,e,!0);if(!t.negative&&!t.positive)continue;const i=e.angle*Math.PI/180,n=Math.cos(i),o=Math.sin(i),s=-o,l=n,c=e.length/2,h=1.25*Math.max(u,r*a),d=[[e.x-n*c-s*h,e.y-o*c-l*h],[e.x+n*c-s*h,e.y+o*c-l*h],[e.x+n*c+s*h,e.y+o*c+l*h],[e.x-n*c+s*h,e.y-o*c+l*h]];w&&(w=Ht(w,xs(d)));for(const e of k)e.geom=Ht(e.geom,xs(d))}m="extras";const M=[];let R=0;const T=c.mergeExtra||((e,t)=>e?Et(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(yi(t))<=1e-9){R++;continue}const i=[xs(t)];try{const t=T(w,i,e);if(!$s(t))throw new Error("invalid extra union");w=t}catch{R++,$s(i)&&M.push({id:`extra-${e}`,geom:i})}}M.push(...k),M.sort((e,t)=>Fs(e.geom).localeCompare(Fs(t.geom)));const C=w||[];return{status:R||x?"degraded-extra":"ok",geom:C,components:[...$s(C)?[{id:"primary",geom:C}]:[],...M.map((e,t)=>({...e,id:`isolated-${t}`}))],roomGeom:$,roomComponents:S,paperGeom:y,depthUnits:u,openingPadUnits:1.25*Math.max(u,r*a),openingIndex:_,multiWallNodes:d,degradedExtraCount:R+x}}catch{return c.onCoreFailure?.(m),{status:"failed-core",geom:[],components:[],roomGeom:[],paperGeom:[],roomComponents:[],depthUnits:u,openingIndex:null,multiWallNodes:d,degradedExtraCount:0}}var g,f}function Hs(e,t,i,n=[],r,o,s,a=1,l=[],c={}){if(!t?.length&&!l.length)return null;return Ls(Ns(e,t,i,n,r,o,s,a,l,c))}function Ls(e){if("failed-core"===e.status||"not-applicable"===e.status)return null;const t=e.components.map(e=>({id:e.id,d:Fs(e.geom),fillRule:"evenodd"})).filter(e=>!!e.d),i=t[0]?.d||"",n=Fs(e.paperGeom);if(t.length){const r={status:e.status,d:i,paths:t,components:e.components,roomGeom:e.roomGeom,multiWallNodes:e.multiWallNodes,paperD:n,depthUnits:e.depthUnits,fillRule:"evenodd"};return Object.defineProperties(r,{roomComponents:{value:e.roomComponents||[],enumerable:!1},openingIndex:{value:e.openingIndex,enumerable:!1},openingPadUnits:{value:e.openingPadUnits,enumerable:!1}}),r}return null}function qs(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=new Set,l=[];for(const c of e||[]){if(!c?.id)continue;const h=ms(e,c.id,t,i,n,r,o,s);if(!h)continue;const d=h.poly;for(let e=0;e0))continue;const p=$o(t,i,n,s);if(a.has(p))continue;a.add(p);const _=vo(u,r,o),[m,g]=Jo(d,e),f=-m,v=-g,y=_/2,b=[[t[0]+f*y,t[1]+v*y],[i[0]+f*y,i[1]+v*y],[i[0]+m*y,i[1]+g*y],[t[0]+m*y,t[1]+g*y]];l.push({key:p,kind:c,cm:u,quad:b,a:[t[0],t[1]],b:[i[0],i[1]],depthUnits:_})}}return l}function js(e,t,i){const n=e?.length||0;if(n<3||t.length!==n)return null;if(t.every(e=>!(e>0)))return e.map(e=>[e[0],e[1]]);os(e),t.slice().reverse();const r=[];for(let o=0;o0||l>0)){r.push([e[o][0],e[o][1]]);continue}if(a>0!=l>0){const t=e[o],i=a>0?[t[0]-c*a,t[1]-h*a]:[t[0],t[1]],n=l>0?[t[0]-d*l,t[1]-u*l]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(Qo(w,k)){const t=e[o],i=[t[0]-c*a,t[1]-h*a],n=[t[0]-d*l,t[1]-u*l];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const S=es(x,w,$,k),M=Math.max(a,l,1e-9),R=ps(i,e[o])?.limit??4*M;if(S){const i=Math.hypot(S[0]-e[o][0],S[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push(S);continue}if(Es(e,t,o)){r.push([e[o][0],e[o][1]]);continue}}a>0&&r.push([e[o][0]-c*a,e[o][1]-h*a]),l>0&&r.push([e[o][0]-d*l,e[o][1]-u*l])}return r.length>=3?r:null}function Bs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=ms(e,l.id,t,i,n,r,o,s);if(!c)continue;const h=Math.abs(yi(c.poly));for(let e=0;e[Math.max(t,e.x0),Math.min(i,e.x1)]).filter(e=>e[1]-e[0]>n).sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(!r.length)return{coverage:0,full:!1};let o=r[0][0],s=r[0][1],a=0,l=o<=t+n;for(let e=1;e=i-n,{coverage:a,full:l}}function Us(e,t){return Number(t.full)-Number(e.full)||e.faceDistance-t.faceDistance||e.area-t.area||e.roomId.localeCompare(t.roomId)}function Gs(e,t,i=!1){const n=Number(t?.x),r=Number(t?.y),o=Number(t?.angle),s=Number(t?.length);if(!([n,r,o,s].every(Number.isFinite)&&s>0))return{negative:null,positive:null};const a=o*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,u=s/2,p=Math.max(1e-9,e.adjacencyEps),_=new Map;let m=0;for(const t of e.edges){if(i&&!(t.half>0))continue;if(!zo(t.a,t.b,o))continue;const[e,s]=ko(t.a,t.b);if(Math.abs((n-t.a[0])*s-(r-t.a[1])*e)>p)continue;const a=(t.a[0]-n)*l+(t.a[1]-r)*c,g=(t.b[0]-n)*l+(t.b[1]-r)*c,f=Math.max(-u,Math.min(a,g)),v=Math.min(u,Math.max(a,g));if(v-f<=p)continue;const y=t.inward[0]*h+t.inward[1]*d>=0?1:-1,b=((t.a[0]+t.b[0])/2-n)*h+((t.a[1]+t.b[1])/2-r)*d,w=Math.abs(b+y*t.half),k=`${y}|${t.roomId}`,x={x0:f,x1:v,half:t.half,cm:t.cm,key:t.key,axis:[e,s]},$=_.get(k);$?($.pieces.push(x),$.faceDistance=Math.min($.faceDistance,w)):_.set(k,{roomId:t.roomId,side:y,order:m++,pieces:[x],faceDistance:w,area:t.area,coverage:0,full:!1})}for(const e of _.values()){const t=Ws(e.pieces,-u,u,p);e.coverage=t.coverage,e.full=t.full}const g=e=>{const t=[..._.values()].filter(t=>t.side===e&&t.coverage>p);return t.sort(Us),t[0]||null};return{negative:g(-1),positive:g(1)}}function Vs(e,t){const i=Gs(e,t),n=[i.negative,i.positive].filter(e=>!!e);if(!n.length)return{ox:0,oy:0,cm:0,side:-1};const r=i.negative&&i.positive?-1:n[0].side,o=t.flip_v?-r:r,s=(-1===o?i.negative:i.positive)||n[0],a=[...s.pieces].sort((e,t)=>(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))-(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))||t.x1-t.x0-(e.x1-e.x0)||e.key.localeCompare(t.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:o};const l=t.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*o*a.half,oy:h*o*a.half,cm:a.cm,side:o}}function Ks(e,t){const i=1e-9,n=t.filter(e=>Number.isFinite(e.x0)&&Number.isFinite(e.x1)&&Number.isFinite(e.half)&&e.x1>e.x0&&e.half>0);if(!n.length)return"";const r=n.flatMap(e=>[e.x0,e.x1]).sort((e,t)=>e-t),o=[];for(const e of r){const t=o[o.length-1];(void 0===t||e>t+i)&&o.push(e)}const s=[];for(let e=0;e+1t+i))continue;const a=(t+r)/2,l=n.reduce((e,t)=>a>=t.x0-i&&a<=t.x1+i?Math.max(e,t.half):e,0);if(!(l>0))continue;const c=s[s.length-1];c&&t<=c.x1+i&&Math.abs(l-c.half)<=i?c.x1=r:s.push({x0:t,x1:r,half:l})}const a=[];for(const e of s){const t=a[a.length-1],n=t?.[t.length-1];n&&e.x0<=n.x1+i?(e.x0=n.x1,t.push(e)):a.push([e])}return a.map(t=>{const i=t[0],n=t[t.length-1],r=Math.min(.25*Math.min(...t.map(e=>e.half)),.75),o=-e*r,s=[];if(1===e){s.push(`M ${i.x0} ${o} L ${n.x1} ${o}`);for(let e=t.length-1;e>=0;e--){const i=t[e];s.push(`L ${i.x1} ${i.half} L ${i.x0} ${i.half}`)}}else{s.push(`M ${n.x1} ${o} L ${i.x0} ${o}`);for(const e of t)s.push(`L ${e.x0} ${-e.half} L ${e.x1} ${-e.half}`)}return s.push("Z"),s.join(" ")}).join(" ")}function Ys(e,t,i,n){if(!n)return i;const r=e.angle*Math.PI/180,o=Math.cos(r),s=Math.sin(r),a=[],l=1e-9;for(const r of i){const[i,c]=r.axis,h=o*i+s*c;if(Math.abs(h)<=l)continue;const d=e.x*i+e.y*c,u=d+h*r.x0,p=d+h*r.x1,_=Math.min(u,p),m=Math.max(u,p),g=`${r.key}|${t}`,f=n.get(g)||[];let v=[[_,m]];for(const[e,t]of f){const i=[];for(const[n,r]of v)t<=n+l||e>=r-l?i.push([n,r]):(e>n+l&&i.push([n,Math.min(r,e)]),te[0]-t[0]||e[1]-t[1]),b=[];for(const e of y){const t=b[b.length-1];t&&e[0]<=t[1]+l?t[1]=Math.max(t[1],e[1]):b.push([e[0],e[1]])}n.set(g,b)}return a}function Zs(e,t){const i=new Map;return t.map(t=>function(e,t,i){const n=Gs(e,t,!0),r=n.negative,o=n.positive;if(!r&&!o)return null;let s;if(r&&o)s=[{candidate:r,side:-1},{candidate:o,side:1}];else{const e=r||o;s=[{candidate:e,side:-1},{candidate:e,side:1}]}const a=s.map(({candidate:e,side:n})=>({candidate:e,side:n,pieces:Ys(t,n,e.pieces,i)})),l=a.map(({candidate:e,side:t,pieces:i})=>({side:t,roomId:e.roomId,d:Ks(t,i)})),c=a.flatMap(({pieces:e})=>e);if(!c.length)return null;const h=Math.max(...c.map(e=>e.half));return{faces:l,minY:-h,maxY:h,wallKey:[...new Set(c.map(e=>e.key))].sort().join("|")}}(e,t,i))}const Xs=150,Js=1e-6;function Qs(e){return Number.isFinite(e)?Math.max(1,Math.min(Xs,e)):1}function ea(e){return((Number.isFinite(Number(e))?Number(e):0)%90+90)%90}const ta=e=>{const t=e.map(e=>[e[0],e[1]]);return!t.length||t[0][0]===t[t.length-1][0]&&t[0][1]===t[t.length-1][1]||t.push([...t[0]]),[t]},ia=(e,t)=>e[0]===t[0]&&e[1]===t[1];function na(e,t=1e-6){const i=Number.isFinite(t)&&t>0?t:Js,n=[];for(const t of e||[]){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),r=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(r))return null;const o=Math.round(e/i)*i,s=Math.round(r/i)*i;if(!Number.isFinite(o)||!Number.isFinite(s))return null;const a=[Object.is(o,-0)?0:o,Object.is(s,-0)?0:s];n.length&&ia(n[n.length-1],a)||n.push(a)}return n.length>1&&ia(n[0],n[n.length-1])&&n.pop(),n.length<3||new Set(n.map(e=>`${e[0]},${e[1]}`)).size<3?null:yi(n)>i*i?n:null}function ra(e){const t=[];for(const i of e||[])for(const e of i||[]){const i=(e||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||t.push(`M ${i.slice(0,-1).map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`)}return t.join(" ")}function oa(e,t,i,n,r){return qo({a:e,b:t,halfDepth:vo(i,n,r)/2})}function sa(e,t,i){const n=Number(t)>0?Number(t):5,r=Qs(e.cm)/n*i,o=e.center[0],s=e.center[1];if("circle"===e.shape){const e=r/2;return Array.from({length:96},(t,i)=>{const n=i/96*Math.PI*2;return[o+Math.cos(n)*e,s+Math.sin(n)*e]})}const a=r/2,l=ea(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l);return[[-a,-a],[a,-a],[a,a],[-a,a]].map(([e,t])=>[o+e*c-t*h,s+e*h+t*c])}function aa(e,t,i=1e-9){if(!t.length)return[e];let n=[ta(e)];try{for(const e of t){const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],o=Math.hypot(t,r);if(!(o>i))continue;const s=t/o,a=r/o,l=-a,c=s,h=1.25*Math.max(Number(e.depth)||0,4*i),d=Math.max(2*i,1e-9*o),u=[[e.a[0]-s*d-l*h,e.a[1]-a*d-c*h],[e.b[0]+s*d-l*h,e.b[1]+a*d-c*h],[e.b[0]+s*d+l*h,e.b[1]+a*d+c*h],[e.a[0]-s*d+l*h,e.a[1]-a*d+c*h]];n=Ht(n,ta(u))}return fa(n)}catch{return[e]}}function la(e,t){try{const i=Ht([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]);let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(yi(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function ca(e,t,i,n=Math.max(2e-4*i,1e-9),r=[]){const o=[],s=[],a=new Map;for(const e of r){const t=a.get(e.hostId)||[];t.push(e),a.set(e.hostId,t)}const l=[],c=[],h=[];for(const n of e.room_drafts||[])for(let e=0;e+10))continue;const a={a:n.points[e],b:n.points[e+1],halfDepth:s},c=qo(a);c&&(o.push(a),l.push(c))}const d=[];for(const n of e.partitions||[]){const e={a:n.a,b:n.b,halfDepth:vo(n.cm,t,i)/2};if(!(e.halfDepth>0))continue;const r=qo(e);r&&(s.push(e),c.push(r),d.push({id:n.id,body:r}))}const u=[...o,...s];for(const{segmentIndex:e,wedge:t}of Go(u,n)){const i=e=o.length&&(d[i.at].body=n))}for(const e of d)h.push(...aa(e.body,a.get(e.id)||[],n));const p=(e.wall_columns||[]).map(e=>sa(e,t,i)),_=Vo([...o,...s],n).flatMap(e=>aa(e,r,n));return{drafts:l,partitions:c,columns:p,patches:_,all:[...l,...h,..._,...p]}}function ha(e){try{const t=e.map(e=>na(e)).filter(e=>!!e).map(e=>ta(e));return t.length?Et(t[0],...t.slice(1)):null}catch{return null}}const da=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;function ua(e){const t=[];for(const i of e||[]){if(ma([i])<=1e-6)continue;const e=[];for(const t of i||[]){const i=(t||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||e.push(da(i.slice(0,-1)))}e.length&&t.push(e.join(" "))}return t}function pa(e,t,i={}){const n=ha(e.filter(e=>e.length>=3)),r=t.some(e=>!na(e))?null:ha(t);if(!n)return[];if(r)try{return ua(Nt(n,r))}catch{}return function(e,t,i){let n=null;for(let r=0;r=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]));return t}function fa(e){const t=[];for(const i of e||[]){const e=i?.[0];e?.length>=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]))}return t}function va(e,t){let i=!1;for(let n=0,r=t.length-1;ne[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s||1e-12)+o&&(i=!i)}return i}function ya(e,t,i){return function(e,t){for(const i of t||[]){const t=i?.[0];if(!t?.length||!va(e,t))continue;let n=!1;for(let t=1;tva(e,t))}function ba(e,t,i){if(Math.hypot(e.center[0]-t.center[0],e.center[1]-t.center[1])>i)return!1;if(Math.abs(Qs(e.cm)-Qs(t.cm))>1e-6)return!1;if(e.shape!==t.shape)return!0;if("circle"===e.shape||"circle"===t.shape)return!0;const n=Math.abs(ea(e.angle)-ea(t.angle));return Math.min(n,90-n)<=1e-6}const wa=2.54;function ka(e){const t="number"==typeof e?e:NaN;return!Number.isFinite(t)||t<=0||5===t?1:5/t}function xa(e,t){return e*ka(t)}function $a(e){return e?wa:1}function Sa(e,t){if(!t)return String(e);const i=e/wa;return String(Math.round(1e6*i)/1e6)}function Ma(e,t){return t?e*wa:e}const Ra=1e3;function Ta(e,t){const i=Number(e),n=Number.isFinite(i)&&i>0?i:1,r=n>=1?t:t*n,o=n>=1?t/n:t;return{x:(t-r)/2,y:(t-o)/2,w:r,h:o}}const Ca=.01,Da=100;function Aa(e,t=1e3){const i=Ta(e?.plan_aspect,t),n=Number(e?.plan_scale),r=Number.isFinite(n)&&n>0?Math.min(Da,Math.max(Ca,n)):1,o=Number(e?.plan_scale_x),s=Number(e?.plan_scale_y),a=Number.isFinite(o)&&o>0?Math.min(Da,Math.max(Ca,o)):r,l=Number.isFinite(s)&&s>0?Math.min(Da,Math.max(Ca,s)):r,c=Number(e?.plan_x),h=Number(e?.plan_y),d=_r(e?.plan_angle);return{x:i.x+(Number.isFinite(c)?ja(c):0)*t,y:i.y+(Number.isFinite(h)?ja(h):0)*t,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Oa(e){if(null==e.x||null==e.y)return{x:e.x,y:e.y,w:e.w,h:e.h};const t=Number(e.w)||0,i=Number(e.h)||0;return{x:t<0?e.x+t:e.x,y:i<0?e.y+i:e.y,w:Math.abs(t),h:Math.abs(i)}}function za(e){return e&&Array.isArray(e.spaces)?e.spaces.map(e=>{const t=Ra,i=function(e){return Array.isArray(e)&&4===e.length&&e.every(e=>Number.isFinite(e))&&e[2]>1e-6&&e[3]>1e-6?e:[0,0,1,1]}(e.view_box);return{id:e.id,title:e.title,cellCm:Number.isFinite(Number(e.cell_cm))&&Number(e.cell_cm)>0?Number(e.cell_cm):5,vb:[i[0]*Ra,i[1]*t,i[2]*Ra,i[3]*t],bg:e.plan_url?{href:Mn(e.plan_url),...Aa(e,Ra)}:null,rooms:(e.rooms||[]).map(e=>{const i={...e,...Oa(e)};return{id:i.id,name:i.name,area:i.area??null,open_to:i.open_to||void 0,settings:i.settings||void 0,x:null!=i.x?i.x*Ra:void 0,y:null!=i.y?i.y*t:void 0,w:null!=i.w?i.w*Ra:void 0,h:null!=i.h?i.h*t:void 0,poly:i.poly?i.poly.map(e=>[e[0]*Ra,e[1]*t]):void 0,wall_ids:Array.isArray(i.wall_ids)?[...i.wall_ids]:void 0}}),wall_segments:(e.wall_segments||[]).map(e=>({...e,id:String(e.id),a:[Number(e.a?.[0])*Ra,Number(e.a?.[1])*t],b:[Number(e.b?.[0])*Ra,Number(e.b?.[1])*t],cm:Number(e.cm)})),room_drafts:(e.room_drafts||[]).map(e=>({id:e.id,points:(e.points||[]).map(e=>[e[0]*Ra,e[1]*t]),segments:(e.segments||[]).map(e=>({..."string"==typeof e.id&&e.id?{id:e.id}:{},cm:Number(e.cm)}))})),partitions:(e.partitions||[]).map(e=>({id:e.id,a:[e.a[0]*Ra,e.a[1]*t],b:[e.b[0]*Ra,e.b[1]*t],cm:Number(e.cm)})),wall_columns:(e.wall_columns||[]).map(e=>({id:e.id,shape:"circle"===e.shape?"circle":"square",center:[e.center[0]*Ra,e.center[1]*t],cm:Number(e.cm),..."circle"===e.shape?{}:{angle:ea(e.angle)}}))}}):[]}const Pa=5e3,Fa=Pa*Ra,Ia=240,Ea=Ra/Ia,Na=1/Ia;function Ha(e){if(!Number.isFinite(e))return e;const t=Math.round(e*Ia/Ra)*Ra/Ia;return Math.abs(t-e)<=1e-9*Ea?e:t}function La(e){return{x:Ha(e.x),y:Ha(e.y)}}function qa(e){return Number.isFinite(e)?Math.min(Fa,Math.max(-Fa,e)):0}function ja(e){return Number.isFinite(e)?Math.min(Pa,Math.max(-Pa,e)):0}const Ba=1/3,Wa=200;function Ua(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e){const e=Number(o[0]),s=Number(o[1]);Number.isFinite(e)&&Number.isFinite(s)&&(en&&(n=e),s>r&&(r=s))}return t>n?null:{minX:t,minY:i,maxX:n,maxY:r}}function Ga(e){return e.poly&&e.poly.length?Ua(e.poly):null==e.x||null==e.y?null:Ua([[e.x,e.y],[e.x+(e.w||0),e.y+(e.h||0)]])}function Va(e,t){const i=[];for(const t of e.rooms||[]){const e=Ga(t);e&&i.push(e)}if(e.bg){const t=Ua(wr(e.bg));t&&i.push(t)}for(const e of t||[])if(Array.isArray(e)){const t=Ua([e]);t&&i.push(t)}else i.push(e);return i}const Ka=e=>{if(!e.length)return 0;const t=[...e].sort((e,t)=>e-t),i=t.length>>1;return t.length%2?t[i]:(t[i-1]+t[i])/2},Ya=e=>{let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)o.minXn&&(n=o.maxX),o.maxY>r&&(r=o.maxY);return t>n||i>r?null:{x:t,y:i,w:n-t,h:r-i}};function Za(e,t){let{x:i,y:n,w:r,h:o}=e;r<30&&(i=i+r/2-100,r=Wa),o<30&&(n=n+o/2-100,o=Wa);const s=Math.max(r,o)*t;return{x:i-s,y:n-s,w:r+2*s,h:o+2*s}}function Xa(e,t={}){const i=t.pad??.05,n=t.k??10,r=t.minSpread??50,o=e.filter(e=>Number.isFinite(e.minX)&&Number.isFinite(e.minY)&&Number.isFinite(e.maxX)&&Number.isFinite(e.maxY)&&Math.abs(e.minX)<=Fa&&Math.abs(e.maxX)<=Fa&&Math.abs(e.minY)<=Fa&&Math.abs(e.maxY)<=Fa);if(!o.length)return{core:null,all:null,outliers:0};const s=Ya(o);if(o.length<4){const e=Za(s,i);return{core:e,all:e,outliers:0}}const a=o.map(e=>(e.minX+e.maxX)/2),l=o.map(e=>(e.minY+e.maxY)/2),c=Ka(a),h=Ka(l),d=o.map((e,t)=>Math.max(Math.abs(a[t]-c),Math.abs(l[t]-h))),u=Math.max(((e,t)=>e.length?e[Math.min(e.length-1,Math.max(0,Math.round(t*(e.length-1))))]:0)([...d].sort((e,t)=>e-t),.75),r),p=d.map(e=>e>n*u),_=p.filter(Boolean).length,m=_&&_<=o.length*Ba?o.filter((e,t)=>!p[t]):o;return{core:Za(Ya(m)||s,i),all:Za(s,i),outliers:m===o?0:_}}function Ja(e,t,i=.05){const n=Xa(Va(e,t),{pad:i});if(n.core)return n.core;const r=e.vb&&4===e.vb.length&&e.vb[2]>0&&e.vb[3]>0?e.vb:[0,0,Ra,Ra];return{x:r[0],y:r[1],w:r[2],h:r[3]}}function Qa(e){const t=Ja(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function el(e){const t=[];for(const i of e.rooms||[]){const e=Ga(i);e&&t.push(e)}const i=Xa(t,{pad:0}).core,n=Ra*ka(e.cellCm??5);return i?Math.max(n,Math.min(Fa,Math.max(i.w,i.h))):n}function tl(e,t,i,n=1){const r=Number(i),o=Number.isFinite(n)&&n>0?n:1;return!Number.isFinite(r)||r<=0?e*o:e*el(t)*o/r}const il=[1,2,5,10,20,50,100,200,500,1e3];function nl(e,t,i=7){if(!(e>0&&t>0&&Number.isFinite(t)))return null;const n=il.find(n=>e*n*t>=i);if(void 0===n)return null;const r=il.find(e=>e>=5*n)??5*n;return{fine:n,coarse:r}}function rl(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}function ol(e,t,i,n){const r=i["rl_"+(e.id||"")];if(r&&r.s===t)return{x:r.x*Ra,y:r.y*Ra};const o=function(e){if(e.poly){const t=e.poly.length;return[e.poly.reduce((e,t)=>e+t[0],0)/t,e.poly.reduce((e,t)=>e+t[1],0)/t]}return[e.x+e.w/2,e.y+.1*Math.min(e.w,e.h)]}(e);return La({x:o[0],y:o[1]})}const sl=["furniture","appliance","sanitary","other"],al=[{id:"sofa",group:"furniture",w:220,h:90,g:[["r",0,0,1,1],["l",.09,.26,.91,.26],["l",.09,.26,.09,1],["l",.91,.26,.91,1],["l",.5,.26,.5,1]]},{id:"armchair",group:"furniture",w:90,h:85,g:[["r",0,0,1,1],["l",.14,.28,.86,.28],["l",.14,.28,.14,1],["l",.86,.28,.86,1]]},{id:"coffee_table",group:"furniture",w:110,h:60,g:[["r",0,0,1,1],["r",.08,.14,.84,.72]]},{id:"table_dining",group:"furniture",w:140,h:80,g:[["r",0,0,1,1],["r",.06,.11,.88,.78]]},{id:"table_round",group:"furniture",w:120,h:120,g:[["e",.5,.5,.5,.5],["e",.5,.5,.41,.41]]},{id:"chair",group:"furniture",w:45,h:45,g:[["r",0,0,1,.18],["r",.06,.18,.88,.8]]},{id:"desk",group:"furniture",w:120,h:60,g:[["r",0,0,1,1],["r",.63,.07,.31,.86],["l",.63,.5,.94,.5]]},{id:"bed_double",group:"furniture",w:160,h:200,g:[["r",0,0,1,1],["r",0,0,1,.07],["r",.06,.1,.4,.15],["r",.54,.1,.4,.15],["l",0,.33,1,.33]]},{id:"bed_single",group:"furniture",w:90,h:200,g:[["r",0,0,1,1],["r",0,0,1,.07],["r",.15,.1,.7,.15],["l",0,.33,1,.33]]},{id:"nightstand",group:"furniture",w:45,h:40,g:[["r",0,0,1,1],["r",.12,.14,.76,.33],["r",.12,.53,.76,.33]]},{id:"wardrobe",group:"furniture",w:100,h:60,g:[["r",0,0,1,1],["l",0,.72,1,.72],["l",.5,.72,.5,1]]},{id:"bookshelf",group:"furniture",w:80,h:30,g:[["r",0,0,1,1],["l",.34,0,.34,1],["l",.67,0,.67,1]]},{id:"fridge",group:"appliance",w:60,h:65,g:[["r",0,0,1,1],["l",0,.36,1,.36],["l",.83,.44,.83,.64]]},{id:"stove",group:"appliance",w:60,h:60,g:[["r",0,0,1,1],["e",.29,.31,.15,.15],["e",.71,.31,.15,.15],["e",.29,.71,.15,.15],["e",.71,.71,.15,.15]]},{id:"dishwasher",group:"appliance",w:60,h:60,g:[["r",0,0,1,1],["r",.1,.12,.8,.76],["e",.5,.5,.27,.27],["e",.5,.5,.13,.13]]},{id:"washer",group:"appliance",w:60,h:60,g:[["r",0,0,1,1],["l",.08,.17,.92,.17],["e",.5,.57,.3,.3],["e",.5,.57,.14,.14]]},{id:"dryer",group:"appliance",w:60,h:60,g:[["r",0,0,1,1],["l",.08,.17,.92,.17],["e",.5,.57,.3,.3],["p",.36,.5,.5,.64,.64,.5]]},{id:"tv",group:"appliance",w:120,h:30,g:[["r",0,0,1,.42],["l",.5,.42,.5,.72],["l",.3,.72,.7,.72]]},{id:"ac",group:"appliance",w:90,h:25,g:[["r",0,0,1,1],["l",.05,.55,.95,.55],["l",.05,.79,.95,.79]]},{id:"water_heater",group:"appliance",w:45,h:45,g:[["e",.5,.5,.5,.5],["e",.5,.5,.31,.31]]},{id:"toilet",group:"sanitary",w:40,h:70,g:[["r",.06,0,.88,.2],["e",.5,.58,.37,.35],["e",.5,.58,.22,.2]]},{id:"bathtub",group:"sanitary",w:170,h:75,g:[["r",0,0,1,1],["r",.05,.11,.77,.78],["e",.89,.5,.045,.1]]},{id:"shower",group:"sanitary",w:90,h:90,g:[["r",0,0,1,1],["l",0,0,1,1],["l",1,0,0,1],["e",.5,.5,.08,.08]]},{id:"sink",group:"sanitary",w:60,h:45,g:[["r",0,0,1,1],["e",.5,.6,.34,.3],["e",.5,.15,.07,.07]]},{id:"kitchen_sink",group:"sanitary",w:80,h:60,g:[["r",0,0,1,1],["r",.06,.24,.44,.64],["r",.54,.24,.4,.64],["e",.5,.12,.06,.06]]},{id:"bidet",group:"sanitary",w:40,h:55,g:[["e",.5,.5,.44,.5],["e",.5,.5,.26,.3]]},{id:"stairs",group:"other",w:100,h:280,g:[["r",0,0,1,1],["l",0,.111,1,.111],["l",0,.222,1,.222],["l",0,.333,1,.333],["l",0,.444,1,.444],["l",0,.556,1,.556],["l",0,.667,1,.667],["l",0,.778,1,.778],["l",0,.889,1,.889],["l",.5,.93,.5,.06],["p",.38,.16,.5,.06,.62,.16]]},{id:"fireplace",group:"other",w:120,h:40,g:[["r",0,0,1,1],["p",.22,1,.22,.42,.78,.42,.78,1]]},{id:"plant",group:"other",w:40,h:40,g:[["e",.5,.5,.22,.22],["l",.5,.28,.5,.02],["l",.5,.72,.5,.98],["l",.28,.5,.02,.5],["l",.72,.5,.98,.5],["l",.34,.34,.13,.13],["l",.66,.66,.87,.87],["l",.66,.34,.87,.13],["l",.34,.66,.13,.87]]},{id:"rug",group:"other",w:200,h:140,g:[["r",0,0,1,1],["r",.06,.09,.88,.82]]}],ll=new Map(al.map(e=>[e.id,e]));function cl(e){return e&&ll.get(e)||null}function hl(e){return al.filter(t=>t.group===e)}function dl(e){const t=cl(e);return t?{w:t.w,h:t.h}:{w:60,h:60}}function ul(e,t,i=Ea,n=1e3){const r=Number(t)>0?Number(t):5;return(Number(e)||0)/r*i/n}const pl=5e-4,_l=Pa;function ml(e){return Number.isFinite(e)?Math.max(pl,Math.min(_l,e)):pl}function gl(e){return Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1}const fl=e=>{const t=Math.round(1e3*e)/1e3;return Object.is(t,-0)?"0":String(t)};function vl(e,t,i){const n=cl(e);if(!(n&&t>0&&i>0))return"";const r=e=>fl(e*t),o=e=>fl(e*i),s=[];for(const e of n.g)if("r"===e[0]){const[,t,i,n,a]=e;s.push(`M${r(t)} ${o(i)}H${r(t+n)}V${o(i+a)}H${r(t)}Z`)}else if("l"===e[0]){const[,t,i,n,a]=e;s.push(`M${r(t)} ${o(i)}L${r(n)} ${o(a)}`)}else if("e"===e[0]){const[,n,a,l,c]=e;s.push(`M${r(n-l)} ${o(a)}A${fl(l*t)} ${fl(c*i)} 0 0 1 ${r(n+l)} ${o(a)}A${fl(l*t)} ${fl(c*i)} 0 0 1 ${r(n-l)} ${o(a)}Z`)}else{const t=e.slice(1);if(t.length<4)continue;let i=`M${r(t[0])} ${o(t[1])}`;for(let e=2;e+1{let t=(e%360+360)%360;return t>180&&(t-=360),t};function bl(e,t,i,n,r,o=0){let s=null,a=r;for(const r of n){const[n,l,c,h]=r,d=c-n,u=h-l,p=d*d+u*u;if(!p)continue;const _=Math.sqrt(p);let m=((e-n)*d+(t-l)*u)/p;m=Math.max(0,Math.min(1,m));let g=n+m*d,f=l+m*u;const v=Math.hypot(e-g,t-f);if(!(v0){const e=Math.round(m*_/o)*o;g=n+e/_*d,f=l+e/_*u}s={cx:g+y*(i/2),cy:f+b*(i/2),angle:yl(180*Math.atan2(-y,b)/Math.PI),dist:v}}return s}const wl=15e3,kl=2e3,xl=new WeakMap;function $l(e,t){let i=xl.get(e);if(!i){const t=new Set;i={hiddenAt:"hidden"===e.visibilityState?Date.now():0,token:0,subscribers:t,onVisibility:()=>{const t=xl.get(e);if(!t)return;const i=Date.now();if("hidden"===e.visibilityState){t.hiddenAt||(t.hiddenAt=i);const e={kind:"hidden",token:t.token,at:i,hiddenFor:0,long:!1};for(const i of[...t.subscribers])i(e);return}const n=t.hiddenAt?Math.max(0,i-t.hiddenAt):0;t.hiddenAt=0,t.token++;const r={kind:"visible",token:t.token,at:i,hiddenFor:n,long:n>=wl};for(const e of[...t.subscribers])e(r)},onPageShow:t=>{const i=xl.get(e);if(!i)return;const n=Date.now();i.token++;const r={kind:"pageshow",token:i.token,at:n,hiddenFor:0,long:!!t.persisted,persisted:!!t.persisted};for(const e of[...i.subscribers])e(r)}},xl.set(e,i),e.addEventListener("visibilitychange",i.onVisibility),e.defaultView?.addEventListener("pageshow",i.onPageShow)}return i.subscribers.add(t),()=>{const i=xl.get(e);i&&(i.subscribers.delete(t),i.subscribers.size||(e.removeEventListener("visibilitychange",i.onVisibility),e.defaultView?.removeEventListener("pageshow",i.onPageShow),xl.delete(e)))}}const Sl={now:()=>Date.now(),setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e),requestAnimationFrame:e=>window.requestAnimationFrame(e),cancelAnimationFrame:e=>window.cancelAnimationFrame(e)};class Ml{constructor(e,t=Sl){this.onChange=e,this.clock=t,this._state="steady",this._token=0,this._frameFingerprint="",this._hasCompleteFrame=!1,this._overlayPhase="none",this._recoveryReason=null,this._overlayTimer=0,this._overlayRaf=0,this._overlayOpaqueAt=0,this._barrierRafs=new Set,this._trace=[],this._disposed=!1}get state(){return this._state}get token(){return this._token}get frameFingerprint(){return this._frameFingerprint}get hasCompleteFrame(){return this._hasCompleteFrame}get overlayPhase(){return this._overlayPhase}get overlayVisible(){return"none"!==this._overlayPhase}get overlayBlocksInteraction(){return this.overlayVisible}get recoveryReason(){return this._recoveryReason}get trace(){return this._trace.map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}note(e,t={}){this.record(e,void 0,t)}record(e,t,i={}){this._trace.push({at:this.clock.now(),token:this._token,event:e,state:this._state,...t?{reason:t}:{},...i}),this._trace.length>80&&this._trace.splice(0,this._trace.length-80)}changed(){this._disposed||this.onChange()}adoptCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-adopted"),this.changed())}markCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-complete"),this.changed())}refreshCompleteFrame(e){!this._disposed&&this._hasCompleteFrame&&"steady"===this._state&&e&&e!==this._frameFingerprint&&(this._frameFingerprint=e,this.record("frame-refreshed"))}visibility(e){return"hidden"===e.kind?(this.record("visibility-hidden"),this._token):e.long||"visible"!==e.kind&&"pageshow"!==e.kind?this.beginCandidate("pageshow"===e.kind?"pageshow":"long-resume"):(this.record("pageshow"===e.kind?"pageshow-noop":"visibility-visible-quick"),this._token)}beginCandidate(e,t="plan"){return this._token++,this._recoveryReason=t,this._hasCompleteFrame?(this._state="connection"===t?"offline-stale":"holding",this.clearOverlay()):this.overlayVisible?this._state="overlay-visible":(this._state="overlay-pending",this.scheduleOverlay(t)),this.record("candidate-start",e),this.changed(),this._token}connectionLost(){return this.beginCandidate("connection-lost","connection")}candidateReady(e){return!this._disposed&&e===this._token&&(this._state="candidate-ready",this.record("candidate-ready"),this.changed(),!0)}async commitAfterPaint(e,t){if(this._disposed||e!==this._token)return!1;let i=!0;const n=(async()=>{for(await t.updateComplete();i&&!this._disposed&&e===this._token;)if(t.stageValid()&&t.assetsReady()){if(await this.nextFrame(),e!==this._token||!t.stageValid()||!t.assetsReady())continue;if(await this.nextFrame(),e===this._token&&t.stageValid()&&t.assetsReady())return!0}else await this.nextFrame();return!1})();let r=0;const o=new Promise(e=>{r=this.clock.setTimeout(()=>e({ready:!1,timedOut:!0}),kl)}),s=await Promise.race([n.then(e=>({ready:e,timedOut:!1})),o]);return i=!1,this.clock.clearTimeout(r),!this._disposed&&e===this._token&&(!(!s.ready&&!s.timedOut)&&(s.ready?(this._hasCompleteFrame=!0,this._frameFingerprint=t.frameFingerprint(),this.record("paint-barrier"),this.finishOverlayAfterCommit(),!0):(this.record("paint-barrier-timeout"),this._hasCompleteFrame?(this._state="connection"===this._recoveryReason?"offline-stale":"steady",this.clearOverlay()):(this._state="recovery-error","opaque"!==this._overlayPhase&&this.showOverlayNow()),this.changed(),!1)))}retry(e=this._recoveryReason||"plan"){return this.beginCandidate("retry",e)}nextFrame(){return new Promise(e=>{const t=this.clock.requestAnimationFrame(()=>{this._barrierRafs.delete(t),e()});this._barrierRafs.add(t)})}scheduleOverlay(e){this.clearOverlayTimer(),this._recoveryReason=e,this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._hasCompleteFrame||"overlay-pending"!==this._state&&"candidate-ready"!==this._state||(this._state="overlay-visible",this._overlayPhase="entering",this.record("overlay-enter"),this.changed(),this._overlayRaf=this.clock.requestAnimationFrame(()=>{this._overlayRaf=0,"entering"===this._overlayPhase&&(this._overlayPhase="fading-in",this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,"fading-in"===this._overlayPhase&&(this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-opaque"),this.changed())},150))}))},150)}showOverlayNow(){this.clearOverlayTimer(),this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-error")}finishOverlayAfterCommit(){if(this.clearOverlayTimer(),"none"===this._overlayPhase||"entering"===this._overlayPhase||"fading-in"===this._overlayPhase)return this.clearOverlay(),this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),void this.changed();const e=Math.max(0,this._overlayOpaqueAt+250-this.clock.now());this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="leaving",this.record("overlay-leave"),this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="none",this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),this.changed()},180)},e)}clearOverlayTimer(){this._overlayTimer&&this.clock.clearTimeout(this._overlayTimer),this._overlayTimer=0}clearOverlay(){this.clearOverlayTimer(),this._overlayRaf&&this.clock.cancelAnimationFrame(this._overlayRaf),this._overlayRaf=0,this._overlayPhase="none",this._overlayOpaqueAt=0}dispose(){this._disposed=!0,this._token++,this.clearOverlay();for(const e of this._barrierRafs)this.clock.cancelAnimationFrame(e);this._barrierRafs.clear()}}function Rl(e){let t=2166136261,i=2654435769;const n=new WeakSet,r=e=>{for(let n=0;n>>0)+(i>>>2)}},o=e=>{if(null===e)return void r("n");const t=typeof e;if("string"===t)return void r(`s${e.length}:${e}`);if("number"===t)return void r(`d${Number.isNaN(e)?"NaN":String(e)}`);if("boolean"===t)return void r(e?"t":"f");if("undefined"===t)return void r("u");if("object"!==t)return void r(`${t}:${String(e)}`);const i=e;if(n.has(i))r("[cycle]");else{if(n.add(i),Array.isArray(e)){r("[");for(const t of e)o(t);return r("]"),void n.delete(i)}r("{");for(const t of Object.keys(e).sort())r(t),o(e[t]);r("}"),n.delete(i)}};return o(e),`${(t>>>0).toString(16).padStart(8,"0")}${(i>>>0).toString(16).padStart(8,"0")}`}function Tl(e){return Rl(e)}const Cl=new WeakMap;class Dl{constructor(e,t=()=>Date.now()){this.onUpdate=e,this.now=t,this.fallbackAuthority={},this.referenceOwner={},this.referenced=new Set,this.queued=new Set,this.disposed=!1,this.sharedUpdate=()=>{this.disposed||this.onUpdate()}}bind(e){const t=((e,t)=>{const i=e?.connection||e?.callWS||t;return!i||"object"!=typeof i&&"function"!=typeof i?t:i})(e,this.fallbackAuthority);return this.shared&&this.authority===t||(this.shared&&(this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner)),this.authority=t,this.shared=(e=>{let t=Cl.get(e);return t||(t={signed:{},queued:new Set,inFlight:new Map,retry:new Map,listeners:new Set,settlers:new Set,references:new Map},Cl.set(e,t)),t})(t),this.disposed||(this.shared.listeners.add(this.sharedUpdate),this.shared.references.set(this.referenceOwner,new Set(this.referenced)))),this.shared}start(e,t){this.disposed=!1,this.referenced=new Set(t());const i=this.bind(e());i.listeners.add(this.sharedUpdate),i.references.set(this.referenceOwner,new Set(this.referenced)),this.stopTimer(),this.resignTimer=setInterval(()=>this.resign(e(),t()),288e5)}dispose(){if(this.disposed=!0,this.stopTimer(),clearTimeout(this.batchTimer),this.shared){this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner);for(const e of this.queued)this.shared.queued.delete(e)}this.queued.clear()}invalidate(e){const t=this.bind(e);clearTimeout(this.batchTimer),this.queued.clear(),t.queued.clear(),t.inFlight.clear(),t.retry.clear(),t.signed={}}stopTimer(){void 0!==this.resignTimer&&clearInterval(this.resignTimer),this.resignTimer=void 0}display(e,t){const i=Mn(t);if(!i.startsWith("/api/houseplan/content/"))return i;const n=this.bind(e);this.referenced.add(i),n.references.set(this.referenceOwner,new Set(this.referenced));const r=n.signed[i],o=r?this.now()-r.at:1/0;return o<$n?r.url:o{const t=[...this.queued];this.queued.clear();for(const e of t)i.queued.delete(e);this.sign(e,t)},30))}sign(e,t){if(!t.length||!e?.callWS)return;const i=this.bind(e);for(const n of function(e,t){const i=Math.max(1,Math.floor(t)),n=[];for(let t=0;t{const n=i.inFlight.get(e);return!(void 0!==n&&t-n<15e3)&&(i.inFlight.set(e,t),!0)});r.length&&e.callWS({type:"houseplan/content/sign",paths:r}).then(e=>{const t=this.now();let n=0,o=!1;for(const s of r){const r=e?.urls?.[s];if("string"==typeof r&&r){const e=i.signed[s];e?.loaded&&e.url!==r?(e.pending={url:r,at:t},this.preloadReplacement(i,s,r,t)):(i.signed[s]={url:r,at:t,loaded:e?.url===r&&!!e.loaded},o=!0),i.retry.delete(s),n++}else this.backOff(i,s)}if(n&&(this.trimShared(i),o))for(const e of[...i.listeners])e()}).catch(()=>{for(const e of r)this.backOff(i,e)}).finally(()=>{for(const e of r)i.inFlight.get(e)===t&&i.inFlight.delete(e);for(const e of[...i.settlers])e()})}}preloadReplacement(e,t,i,n){const r=()=>{const r=e.signed[t];if(r?.pending?.url===i){e.signed[t]={url:i,at:n,loaded:!0},e.retry.delete(t),this.trimShared(e);for(const t of[...e.listeners])t()}},o=()=>{const n=e.signed[t];n?.pending?.url===i&&(delete n.pending,this.backOff(e,t))};if("undefined"==typeof Image)return void r();const s=new Image;s.onload=()=>{("function"==typeof s.decode?s.decode():Promise.resolve()).then(r).catch(o)},s.onerror=o,s.src=i}preloadCurrentImage(e,t,i){if(i.loaded)return Promise.resolve(!0);if(i.preload)return i.preload;if("undefined"==typeof Image)return i.loaded=!0,Promise.resolve(!0);const n=i.url;return i.preload=new Promise(r=>{const o=new Image;let s=!1;const a=o=>{if(s)return;s=!0,clearTimeout(l);const a=e.signed[t];if(a===i&&delete a.preload,o&&a===i&&a.url===n){a.loaded=!0;for(const t of[...e.listeners])t();r(!0)}else o||a!==i||this.backOff(e,t),r(!1)};o.onload=()=>{("function"==typeof o.decode?o.decode():Promise.resolve()).then(()=>a(!0)).catch(()=>a(!1))},o.onerror=()=>a(!1);const l=setTimeout(()=>a(!1),kl);o.src=n}),i.preload}prepareImage(e,t){const i=Mn(t);if(!i.startsWith("/api/houseplan/content/"))return Promise.resolve(!0);const n=this.bind(e),r=()=>{const t=n.signed[i];if(t&&this.now()-t.atthis.now()&&!n.inFlight.has(i)&&!n.queued.has(i)?Promise.resolve(!1):null},o=r();return o?(s=o,new Promise(e=>{let t=!1;const i=i=>{t||(t=!0,clearTimeout(n),e(i))},n=setTimeout(()=>i(!1),kl);s.then(i).catch(()=>i(!1))})):new Promise(e=>{let t=!1,i=null;const o=i=>{t||(t=!0,clearTimeout(a),n.settlers.delete(s),e(i))},s=()=>{t||i||(i=r(),i&&i.then(o).catch(()=>o(!1)))},a=setTimeout(()=>o(!1),kl);n.settlers.add(s),s()});var s}backOff(e,t){const i=e.retry.get(t)?.delay||0,n=Math.min(6e4,i?2*i:2e3);e.retry.set(t,{notBefore:this.now()+n,delay:n})}trimShared(e){const t=Object.entries(e.signed);if(t.length<=512)return;const i=new Set(e.inFlight.keys());for(const t of e.references.values())for(const e of t)i.add(e);for(const[e,n]of t)(n.pending||n.preload)&&i.add(e);t.sort((e,t)=>t[1].at-e[1].at);const n=t.filter(([e])=>i.has(e));for(const e of t){if(n.length>=512)break;i.has(e[0])||n.push(e)}e.signed=Object.fromEntries(n)}resign(e,t){const i=this.bind(e);this.referenced=new Set(t),i.references.set(this.referenceOwner,new Set(this.referenced));const n=this.now(),r=new Set;for(const e of i.references.values())for(const t of e)r.add(t);const o={};for(const[e,t]of Object.entries(i.signed))r.has(e)&&n-t.at!!o[e]&&!o[e].pending))}markLoaded(e,t,i){const n=Mn(t);if(!n.startsWith("/api/houseplan/content/"))return;const r=this.bind(e).signed[n];if(r&&(!i||r.url===i)&&!r.loaded){r.loaded=!0;for(const t of[...this.bind(e).listeners])t()}}isReady(e,t){const i=Mn(t);if(!i.startsWith("/api/houseplan/content/"))return!0;const n=this.bind(e).signed[i];return!!n&&this.now()-n.ate.id===t)}var Ol="M11,18H13V16H11V18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6Z";function zl(e,t,i){return[e[0]*t+e[1]*i+e[2],e[3]*t+e[4]*i+e[5]]}function Pl(e,t){let i=0;for(const[n,r]of t){const t=zl(e,n[0],n[1]);i=Math.max(i,Math.hypot(t[0]-r[0],t[1]-r[1]))}return i}const Fl=e=>{if(null==e||""===e)return null;const t=Number(e);return Number.isFinite(t)?t:null},Il=e=>{const t=e,i=Fl(Array.isArray(t)?t[0]:t?.x),n=Fl(Array.isArray(t)?t[1]:t?.y);return null==i||null==n?null:[i,n]};function El(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Il(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}if(t.length<3)return null;let i=0,n=0,r=0;for(let e=0;ee+t[0],0)/t.length,t.reduce((e,t)=>e+t[1],0)/t.length]:[n/(3*i),r/(3*i)]}function Nl(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Il(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}const i=El(t);if(!i)return null;const n=t.map(e=>e[0]),r=t.map(e=>e[1]);return{centroid:i,bbox:[Math.min(...n),Math.min(...r),Math.max(...n),Math.max(...r)]}}function Hl(e){let t=e;if(t&&"object"==typeof t&&!Array.isArray(t)){const e=t;t=e.path??e.points??t}if(!Array.isArray(t)||!t.length)return[];let i=(t.some(e=>(e=>Array.isArray(e)?e.length>=2&&!Array.isArray(e[0])&&("object"!=typeof e[0]||null==e[0]):!!e&&"object"==typeof e&&("x"in e||"y"in e))(e))?[t]:t.filter(Array.isArray)).map(e=>e.map(Il).filter(e=>null!=e)).filter(e=>e.length>=2);i.length>64&&(i=i.slice(-64));const n=i.reduce((e,t)=>e+t.length,0);if(n<=4e3)return i.map(e=>e.slice());const r=4e3-2*i.length,o=i.map(e=>e.length-2),s=o.reduce((e,t)=>e+t,0),a=o.map(e=>r*e/s),l=a.map(Math.floor);let c=r-l.reduce((e,t)=>e+t,0);const h=a.map((e,t)=>({index:t,fraction:e-Math.floor(e)})).sort((e,t)=>t.fraction-e.fraction||e.index-t.index);for(let e=0;efunction(e,t){if(t>=e.length)return e.slice();if(t<=2)return[e[0],e[e.length-1]];const i=[];for(let n=0;ne.slice()),i=t[t.length-1];return i?(i.length>2?i.pop():t.pop(),t):[]}function jl(e,t){return"default"!==e?e:null!=t?String(t):"default"}function Bl(e){if(!e)return null;const t=e.vacuum_position||e.robot_position||null,i=t&&null!=Fl(t.x)&&null!=Fl(t.y)?{x:Fl(t.x),y:Fl(t.y),a:Fl(t.a??t.angle??t.theta)}:null,n=Hl(e.path?.path??e.path?.points??e.path),r=[],o=e.rooms,s=Array.isArray(o)?o.map((e,t)=>[String(e?.id??t),e]):o&&"object"==typeof o?Object.entries(o):[];for(const[e,t]of s){if(!t||"object"!=typeof t)continue;const i=String(t.name??t.label??"").trim(),n=[[Fl(t.cx),Fl(t.cy)],[Fl(t.center?.x),Fl(t.center?.y)],[Fl(t.x),Fl(t.y)]].find(([e,t])=>null!=e&&null!=t);let o=n?.[0]??null,s=n?.[1]??null;const a=Nl(t.outline),l=Fl(t.x0),c=Fl(t.y0),h=Fl(t.x1),d=Fl(t.y1),u=(null!=l&&null!=c&&null!=h&&null!=d?[Math.min(l,h),Math.min(c,d),Math.max(l,h),Math.max(c,d)]:null)||a?.bbox||null;if(null!=o&&null!=s||!a||([o,s]=a.centroid),null!=o&&null!=s||!u||(o=(u[0]+u[2])/2,s=(u[1]+u[3])/2),i&&null!=o&&null!=s){const t={id:e,name:i,cx:o,cy:s};u&&([t.x0,t.y0,t.x1,t.y1]=u),r.push(t)}}const a=function(e){return String(e.map_name??e.current_map??e.map_index??e.selected_map??"default")}(e);return i||r.length||n.length?{pos:i,path:n,rooms:r,mapId:a}:null}function Wl(e,t,i){return![e,t,i].every(Number.isFinite)||e<0||t<=0||i<=0?Number.POSITIVE_INFINITY:e/t*i}const Ul=40;function Gl(e,t,i){if(!e||!t)return null;const n=t.attributes||{},r=e.split(".")[0]||"",o=null!=i?.platform?String(i.platform):null,s=!!Il(n.vacuum_position??n.robot_position),a=!(!n.rooms||"object"!=typeof n.rooms),l=Hl(n.path?.path??n.path?.points??n.path).length>0,c=[n.map_name,n.current_map,n.map_index,n.selected_map].some(e=>null!=e),h="xiaomi_cloud_map_extractor"===o,d=a||l||c;let u=null;if(s?u="compatible":h?u="known_xcme_incomplete":d?u="partial":"camera"===r&&(u="camera"),!u)return null;const p=s?"camera"===r?300:200:h?100:d?50:0;return{entityId:e,name:String(n.friendly_name||e),platform:o,category:u,hasPosition:s,hasRooms:a,hasPath:l,hasMapId:c,score:p}}const Vl=e=>e.toLowerCase().replace(/[\s_\-.,]+/g,"");function Kl(e,t){const i=new Set(t.map(Vl).filter(Boolean)),n=new Set;for(const t of e){const e=Vl(t.name||"");e&&i.has(e)&&n.add(e)}return n.size}function Yl(e,t){const i=new Map(t.map(e=>[Vl(e.name),e])),n=[],r=[];for(const t of e){const e=i.get(Vl(t.name));e&&(n.push([[t.cx,t.cy],[e.cx,e.cy]]),r.push(t.name))}if(n.length<3)return null;const o=function(e){if(e.length<3)return null;let t=0,i=0,n=0,r=0,o=0,s=0,a=0,l=0,c=0,h=0,d=0,u=0;for(const[[p,_],[m,g]]of e){if(![p,_,m,g].every(Number.isFinite))return null;t+=p*p,i+=p*_,n+=p,r+=_*_,o+=_,s+=1,a+=p*m,l+=_*m,c+=m,h+=p*g,d+=_*g,u+=g}const p=[t,i,n,i,r,o,n,o,s],_=e=>{const[t,i,n,r,o,s,a,l,c]=p,h=t*(o*c-s*l)-i*(r*c-s*a)+n*(r*l-o*a);if(!Number.isFinite(h)||Math.abs(h)<1e-9)return null;const d=[(o*c-s*l)/h,(n*l-i*c)/h,(i*s-n*o)/h,(s*a-r*c)/h,(t*c-n*a)/h,(n*r-t*s)/h,(r*l-o*a)/h,(i*a-t*l)/h,(t*o-i*r)/h];return[d[0]*e[0]+d[1]*e[1]+d[2]*e[2],d[3]*e[0]+d[4]*e[1]+d[5]*e[2],d[6]*e[0]+d[7]*e[1]+d[8]*e[2]]},m=_([a,l,c]),g=_([h,d,u]);if(!m||!g)return null;const f=[m[0],m[1],m[2],g[0],g[1],g[2]];return f.every(Number.isFinite)?f:null}(n);return o?{matrix:o,matched:r,residual:Pl(o,n)}:null}function Zl(e,t,i){const n=e[e.length-1];if(n&&n[0]===t[0]&&n[1]===t[1])return e;if(e.push(t),e.length<=600)return e;let r=function(e,t){if(e.length<3)return e.slice();const i=new Uint8Array(e.length);i[0]=i[e.length-1]=1;const n=[[0,e.length-1]];for(;n.length;){const[r,o]=n.pop(),[s,a]=e[r],[l,c]=e[o],h=l-s,d=c-a,u=Math.hypot(h,d)||1e-9;let p=0,_=-1;for(let t=r+1;tp&&(p=i,_=t)}_>0&&p>t&&(i[_]=1,n.push([r,_],[_,o]))}const r=[];for(let t=0;t600&&(r=r.filter((e,t)=>t%2==0||t===r.length-1)),r}function Xl(e){return"cleaning"===e||"returning"===e||"on"===e}const Jl={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function Ql(e){const[t,i]=Jl[e.rot]||[1,0],n=e.mir?-1:1;return[e.s*t*n,-e.s*i,e.ox,e.s*i*n,e.s*t,e.oy]}function ec(e){const t=e[0]*e[4]-e[1]*e[3];if(!Number.isFinite(t)||Math.abs(t)<1e-12)return null;const i=t<0,n=Math.sqrt(Math.abs(t));let r=180*Math.atan2(-e[1],e[4])/Math.PI;return r=(90*Math.round(r/90)%360+360)%360,{ox:e[2],oy:e[5],s:n,rot:r,mir:i}}function tc(e,t){const i=[],n=[];for(const t of e)null!=t.x0?(i.push(t.x0,t.x1),n.push(t.y0,t.y1)):(i.push(t.cx),n.push(t.cy));if(!i.length)return{ox:t[0]+t[2]/2,oy:t[1]+t[3]/2,s:t[2]/1e4,rot:0,mir:!0};const r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1,c={ox:0,oy:0,s:.6*Math.min(t[2],t[3])/l,rot:0,mir:!0},h=Ql(c),[d,u]=zl(h,(r+o)/2,(s+a)/2);return c.ox=t[0]+t[2]/2-d,c.oy=t[1]+t[3]/2-u,c}function ic(e,t,i,n){const[r,o]=zl(Ql(t),i,n),s=Ql({...e,ox:0,oy:0}),[a,l]=zl(s,i,n);return{...e,ox:r-a,oy:o-l}}function nc(e){const t=e?.trail_mode;return"never"===t||"cleaning"===t||"always"===t?t:!1===e?.trail?"never":"cleaning"}const rc={availability:"available",status:"alarm",activity:"none"},oc=new Set(["motion","vibration","sound"]),sc=new Set(["occupancy","presence"]),ac=new Set(["door","window","garage_door","opening"]),lc=new Set(["running","power"]),cc=new Set(["smoke","gas","carbon_monoxide","moisture","safety","tamper","problem"]);const hc=new Set(["running","working","washing","rinsing","spinning","drying","heating","cooling","cleaning","cooking","playing","recording","pumping","irrigating","humidifying","dehumidifying","fan","preheating","defrosting"]),dc=new Set([...hc,"start","started","run","active","in_progress","wash","rinse","spin","dry"]),uc=new Set(["off","idle","paused","standby","docked","finished","complete","completed","stopped","ready","sleeping","stop","end","done","inactive"]),pc=new Set(["heat","cool","heat_cool","auto","dry","fan_only"]),_c=e=>""===e||"unknown"===e||"unavailable"===e||"__missing__"===e,mc=e=>String(e??"").trim().toLowerCase(),gc=e=>mc(e).replace(/[\s-]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),fc=new Map([["run_state",0],["job_state",0],["operation_state",0],["activity_state",0],["machine_state",1],["running_state",1],["status",2],["device_status",2],["machine_status",2]]),vc=new Set(["wifi","connection","signal","battery"]);function yc(e,t){const i=e?.entities?.[t]||{};if("config"===i.entity_category)return null;const n=String(t||"").split(".").slice(1).join("."),r=[i.translation_key,i.original_name,i.name],o=[...r,n];r.some(e=>mc(e))||o.push(e?.states?.[t]?.attributes?.friendly_name);const s=o.map(gc).filter(Boolean);if(s.some(e=>e.split("_").some(e=>vc.has(e))))return null;let a=null;for(const e of s)for(const[t,i]of fc)(e===t||e.endsWith(`_${t}`))&&(a=null==a?i:Math.min(a,i));return a}const bc=(e,t)=>null!=yc(e,t);function wc(e,t){if(!t.startsWith("switch."))return!1;const i=e?.entities?.[t]||{},n=e?.states?.[t],r=t.slice(7).toLowerCase();if(/(?:^|_)(?:main_)?power$/.test(r))return!0;if([i.translation_key,i.original_name,i.name].map(mc).some(e=>["power","main power","power switch","питание"].includes(e)))return!0;const o=mc(n?.attributes?.friendly_name);return/(?:^|[\s._-])(?:main[\s._-]+)?power$/.test(o)||/(?:^|[\s._-])питание$/.test(o)}function kc(e){for(const t of["hvac_action","action","current_operation","run_state","job_state","operation","activity"]){const i=mc(e?.[t]);if(hc.has(i)||uc.has(i))return i}return""}function xc(e,t){const i=e?.states?.[t],n=i?mc(i.state):"__missing__",r=String(t||"").split(".")[0],o=mc(i?.attributes?.device_class),s={eid:t,state:n,availability:_c(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===s.availability)return s;if(function(e,t,i){return"alarm_control_panel"===e?"triggered"===i:"on"===i&&In(e,t)}(r,o,n))return{...s,status:"alarm"};if("binary_sensor"===r)return oc.has(o)?{...s,edge:"rising"}:sc.has(o)?{...s,activity:"on"===n?"presence":"none"}:ac.has(o)?{...s,status:"on"===n?"open":"neutral",edge:"rising"}:"moving"===o?{...s,activity:"on"===n?"transition":"none"}:lc.has(o)&&"on"===n?{...s,status:"working",activity:"running"}:s;if("cover"===r)return{...s,activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("lock"===r)return{...s,status:"unlocked"===n||"open"===n?"open":"neutral",activity:"locking"===n||"unlocking"===n?"transition":"none",edge:"terminal_transition"};if("valve"===r)return{...s,status:["open","opening","closing"].includes(n)?"open":"neutral",activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("climate"===r){const e=kc(i.attributes),t=Array.isArray(i.attributes?.hvac_modes)?i.attributes.hvac_modes.map(mc):[],r=!uc.has(n)&&(pc.has(n)||hc.has(n)||t.includes(n));return(e?hc.has(e):r)?{...s,status:"working",activity:"running"}:s}if(["light","switch","fan","humidifier"].includes(r))return"on"===n?{...s,status:"working",activity:"running"}:s;if("media_player"===r)return"off"===n?{...s,availability:"unavailable"}:s;if("vacuum"===r)return"cleaning"===n?{...s,status:"working",activity:"running"}:"returning"===n?{...s,status:"working",activity:"transition"}:s;if("script"===r)return"on"===n?{...s,status:"working",activity:"running"}:s;if("automation"===r)return s;if("button"===r||"event"===r)return{...s,edge:"change"};const a=kc(i.attributes);return hc.has(a)||hc.has(n)&&!uc.has(n)?{...s,status:"working",activity:"running"}:s}function $c(e,t,i){const n=i.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category),r=t.find(t=>wc(e,t));if(!(n.length>1&&!!r))return t.map(t=>xc(e,t));const o=t.find(t=>t!==r&&bc(e,t)),s=xc(e,r);return"unavailable"===s.availability||"off"===s.state?t.map(t=>({eid:t,state:e?.states?.[t]?mc(e.states[t].state):"__missing__",availability:"unavailable",status:"neutral",activity:"none",edge:"none"})):t.map(t=>{if(t===o)return function(e,t){const i=e?.states?.[t],n=i?mc(i.state):"__missing__",r={eid:t,state:n,availability:_c(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===r.availability)return r;const o=kc(i?.attributes);return hc.has(o)||dc.has(n)&&!uc.has(n)?{...r,status:"working",activity:"running"}:r}(e,t);return{...t===r?s:xc(e,t),status:"neutral",activity:"none",edge:"none"}})}function Sc(e){if(!e.length)return{availability:"available",status:"neutral",activity:"none"};const t=e.filter(e=>"available"===e.availability);if(!t.length)return{availability:"unavailable",status:"neutral",activity:"none"};if(t.some(e=>"alarm"===e.status))return rc;const i=t.some(e=>"working"===e.status)?"working":t.some(e=>"open"===e.status)?"open":"neutral",n=t.some(e=>"transition"===e.activity)?"transition":t.some(e=>"presence"===e.activity)?"presence":t.some(e=>"running"===e.activity)?"running":"none";return{availability:"available",status:i,activity:n}}function Mc(e,t){if(!(e=>!!e&&!_c(e))(e)||"unavailable"===t.availability||e===t.state)return null;if("rising"===t.edge)return"off"===e&&"on"===t.state?"event":null;if("change"===t.edge)return"event";if("terminal_transition"===t.edge){const i=new Set([e,t.state]);if(i.has("closed")&&i.has("open")||i.has("locked")&&i.has("unlocked"))return"transition"}return null}const Rc=(e,t=0)=>{const i=Number(e);return Number.isInteger(i)&&i>=0?i:t},Tc=(e,t)=>{const i={rev:0,configRev:Rc(t),off:new Set};if(null==e)return{snapshot:i,valid:!1};const n=e.off;return!Number.isInteger(e.rev)||Number(e.rev)<0||!Number.isInteger(e.config_rev)||Number(e.config_rev)<0||!Array.isArray(n)||n.some(e=>"string"!=typeof e||!e)?{snapshot:i,valid:!1}:{snapshot:{rev:Number(e.rev),configRev:Number(e.config_rev),off:new Set(n)},valid:!0}};function Cc(e,t=0){return Tc(e,t).snapshot}function Dc(e,t,i,n){const r=Tc(t,i);return n&&r.valid&&r.snapshot.configRev===i?e.configRev===i&&r.snapshot.rev{try{const[i,n]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),r=jc(i,"id"),o=jc(n,"entity_id");if(!r||!o)throw new Error("invalid_registry_response");t.devices=r,t.entities=o,t.authoritative=!0,t.access="full",t.lastSuccess=Date.now(),t.error=void 0}catch(e){t.authoritative=!1,t.access="limited",t.error=function(e){if(e&&"object"==typeof e){const t=e;return String(t.message||t.code||t.error||"registry_unavailable")}return String(e||"registry_unavailable")}(e)}finally{t.revision++,t.loading=void 0,function(e){for(const t of[...e.listeners])try{t()}catch{}}(t)}})()),t.loading}function Wc(e,t){void 0===t.reloadTimer&&(t.reloadTimer=globalThis.setTimeout(()=>{t.reloadTimer=void 0,Bc(e,t)},80))}async function Uc(e,t){if(t.subscribing||t.unsubDevice&&t.unsubEntity)return t.subscribing;const i=e?.connection?.subscribeEvents;return"function"==typeof i?(t.subscribing=(async()=>{try{t.unsubDevice||(t.unsubDevice=await i.call(e.connection,()=>Wc(e,t),"device_registry_updated")),t.unsubEntity||(t.unsubEntity=await i.call(e.connection,()=>Wc(e,t),"entity_registry_updated"))}catch{}finally{0===t.refs&&(t.unsubDevice?.(),t.unsubEntity?.(),t.unsubDevice=void 0,t.unsubEntity=void 0),t.subscribing=void 0}})(),t.subscribing):void 0}function Gc(e,t){const i=qc(e);if(!i)return()=>{};const n=0===i.refs;i.refs++,i.listeners.add(t),("pending"===i.access||n)&&Bc(e,i),Uc(e,i);let r=!1;return()=>{r||(r=!0,i.listeners.delete(t),i.refs=Math.max(0,i.refs-1),i.refs>0||(i.unsubDevice?.(),i.unsubEntity?.(),i.unsubDevice=void 0,i.unsubEntity=void 0,void 0!==i.reloadTimer&&globalThis.clearTimeout(i.reloadTimer),i.reloadTimer=void 0))}}function Vc(e){const t=qc(e);if(!t)return{revision:0,authoritative:!1,access:"limited",devices:e?.devices||{},entities:e?.entities||{},lastSuccess:0,error:"registry_unavailable"};let i=e?.devices||{},n=e?.entities||{};if(t.authoritative){const r=t.liveDevices!==i||t.liveEntities!==n,o=void 0!==t.liveDevices||void 0!==t.liveEntities;if(r&&(t.liveDevices=i,t.liveEntities=n,t.projectedRevision=void 0,o&&Wc(e,t)),t.projectedRevision!==t.revision||!t.projectedDevices||!t.projectedEntities){const e={...t.devices},r={...t.entities};for(const[t,n]of Object.entries(i))Object.prototype.hasOwnProperty.call(e,t)||(e[t]=n);for(const[e,t]of Object.entries(n))Object.prototype.hasOwnProperty.call(r,e)||(r[e]=t);t.projectedDevices=e,t.projectedEntities=r,t.projectedRevision=t.revision}i=t.projectedDevices,n=t.projectedEntities}return{revision:t.revision,authoritative:t.authoritative,access:t.access,devices:i,entities:n,lastSuccess:t.lastSuccess,error:t.error}}function Kc(e){if(!e||"object"!=typeof e&&"function"!=typeof e)return 0;let t=Ec.get(e);return t||(t=Nc++,Ec.set(e,t)),t}function Yc(e,t=Vc(e)){return[t.revision,t.access,Kc(t.devices),Kc(t.entities)].join(":")}function Zc(e){return!!e&&null==e.disabled_by}function Xc(e,t=Vc(e)){const i={},n={},r={};for(const[e,n]of Object.entries(t.devices||{}))Zc(n)&&(i[e]=n);for(const[e,i]of Object.entries(t.entities||{})){if(!Zc(i))continue;const r=i.device_id?t.devices?.[i.device_id]:null;t.authoritative&&i.device_id&&!r||(r&&!Zc(r)||(n[e]=i))}for(const[i,n]of Object.entries(e?.states||{})){const e=t.entities?.[i];if(e&&!Zc(e))continue;const o=e?.device_id?t.devices?.[e.device_id]:null;t.authoritative&&e?.device_id&&!o||(o&&!Zc(o)||(r[i]=n))}return{...e,devices:i,entities:n,states:r}}function Jc(e,t=Vc(e)){return{...e,devices:t.devices||{},entities:t.entities||{}}}function Qc(e,t){const i=[];for(const[n,r]of Object.entries(e||{}))r?.device_id===t&&i.push(n);return i}function eh(){if(Lc)return Lc;if("undefined"==typeof localStorage)return{};try{const e=JSON.parse(localStorage.getItem(Hc)||"{}");if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Date.now(),i={};for(const[n,r]of Object.entries(e))!r||"active"!==r.kind&&"ha_disabled"!==r.kind||!Number.isFinite(r.ts)||t-r.ts>7776e6||(i[n]=r);return Lc=i,Lc}catch{return{}}}function th(e,t,i=Vc(e)){if(!t||"virtual"===t)return{kind:"active",enabledEntityIds:[],allEntityIds:[]};const n=t.indexOf(":");if(n<1)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const r=t.slice(0,n),o=t.slice(n+1);if("device"!==r&&"entity"!==r||!o)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const s=i.devices||{},a=i.entities||{};if(i.authoritative){if("device"===r){const e=s[o];if(!e)return{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[]};const t=Qc(a,o);if(!Zc(e))return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:t};const i=t.filter(e=>Zc(a[e]));return t.length&&!i.length?{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:t}:{kind:"active",enabledEntityIds:i,allEntityIds:t}}const t=a[o];return t&&!Zc(t)?{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!s[t.device_id]?{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!Zc(s[t.device_id])?{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]}:t||e?.states?.[o]?{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}:{kind:"orphaned",reason:"entity_missing",enabledEntityIds:[],allEntityIds:[]}}const l=function(e){return eh()[e]||null}(t);if("device"===r){const t=s[o],i=Qc(a,o);if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:i};const n=i.filter(e=>{const t=a[e];return null==t?.disabled_by&&(!t.device_id||null==s[t.device_id]?.disabled_by)});if(i.length&&!n.length&&i.every(e=>null!=a[e]?.disabled_by))return{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:i};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"device",enabledEntityIds:[],allEntityIds:i};if(t||n.some(t=>!!e?.states?.[t]))return{kind:"active",enabledEntityIds:n,allEntityIds:i}}else{const t=a[o];if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]};if(t?.device_id&&null!=s[t.device_id]?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"entity",enabledEntityIds:[],allEntityIds:[o]};if(t||e?.states?.[o])return{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}}return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]}}function ih(e){const t={};for(const[i,n]of Object.entries(e.entities)){if(!n?.device_id||!Zc(n))continue;const r=e.devices?.[n.device_id];r&&!Zc(r)||(t[n.device_id]=t[n.device_id]||[]).push(i)}return t}function nh(e,t){const i=new Map;for(const n of e){if(!0===n?.removed)continue;const e=n?.binding||"";if(!e.startsWith("entity:"))continue;const r=e.slice(7);if(!r)continue;const o=t?.entities?.[r]?.device_id;if(!o)continue;const s=i.get(o)||new Set;s.add(r),i.set(o,s)}return{byDevice:i}}function rh(e,t,i,n){const r=n.byDevice.get(t);return r?.size?{partial:!0,entityIds:i.filter(t=>!r.has(t)&&!e?.entities?.[t]?.hidden)}:{partial:!1,entityIds:[...i]}}function oh(e,t,i){if(t.identifiers?.[0]?.[0])return t.identifiers[0][0];for(const t of i){const i=e.entities[t]?.platform;if(i)return i}return""}function sh(e,t){if(/_device_temperature$/.test(t))return!1;if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_temperature$/.test(t);const n=i.attributes||{};return"temperature"===n.device_class||/°C|°F/.test(n.unit_of_measurement||"")||/_temperature$/.test(t)}const ah=["vacuum","lawn_mower","climate","media_player","light","cover","lock","valve","alarm_control_panel","water_heater","fan","humidifier","siren","camera","remote"],lh=e=>[...e.filter(e=>!e.reg?.hidden),...e.filter(e=>!!e.reg?.hidden)];function ch(e,t){const i=t.map(t=>({eid:t,reg:e?.entities?.[t]})).filter(e=>!!e.reg);if(!i.length)return[];const n=i.filter(e=>!e.reg.entity_category),r=n.length?n:i;for(const e of ah){const t=r.filter(t=>t.eid.startsWith(e+"."));if(t.length)return lh(t).map(e=>e.eid)}const o=r.filter(t=>function(e,t){if(!t.startsWith("binary_sensor."))return!1;const i=mc(e?.states?.[t]?.attributes?.device_class||e?.entities?.[t]?.device_class||e?.entities?.[t]?.original_device_class);return oc.has(i)||sc.has(i)||ac.has(i)||lc.has(i)||"moving"===i||cc.has(i)}(e,t.eid));if(o.length)return lh(o).map(e=>e.eid);const s=r.filter(e=>e.eid.startsWith("switch."));if(s.length){const t=lh(s),n=t.find(t=>wc(e,t.eid));if(s.length>1&&n){const t=i.filter(t=>t.eid!==n.eid&&"config"!==t.reg?.entity_category&&null!=yc(e,t.eid)),r=t.filter(e=>!e.reg?.entity_category),o=r.length?r:t;for(const t of[0,1,2]){const i=lh(o.filter(i=>yc(e,i.eid)===t));if(i.length)return[i[0].eid,n.eid]}}return[(n||t[0]).eid]}const a=[];for(const e of Ie)a.push(...lh(r.filter(t=>t.eid.startsWith(e+"."))));return a.push(...lh(r.filter(e=>!Ie.includes(e.eid.split(".")[0])))),a.map(e=>e.eid)}function hh(e,t,i){const n=t.map(t=>({eid:t,reg:e.entities[t],st:e.states[t]})).filter(e=>e.reg),r=[n.filter(e=>!e.reg.hidden&&!e.reg.entity_category),n.filter(e=>!e.reg.entity_category),n.filter(e=>!e.reg.hidden),n];if("mdi:thermometer"===i||"mdi:air-filter"===i)for(const t of r){const i=t.find(t=>sh(e,t.eid));if(i)return i.eid}const o=ch(e,t);return o.find(yn)||o[0]}function dh(e,t,i=[]){return[...new Set(uh(e,t,i))].filter(e=>yn(e))}function uh(e,t,i=[]){const n=e?.startsWith("entity:")?new Set([e.slice(7)]):new Set(i);return(t||[]).filter(e=>"string"==typeof e&&!n.has(e))}function ph(e,t){if("string"==typeof t)return e.area===t;const i=e.marker?.room_id;return i?!!t.id&&i===t.id:!!t.area&&e.area===t.area}function _h(e){const t=e.marker?.binding?.startsWith("entity:")?e.marker.binding.slice(7):null,i=e.entities.filter(yn),n=e.primary&&yn(e.primary)?e.primary:null;return[...new Set([t,n,...i].filter(e=>!!e&&yn(e)))]}function mh(e){const t=_h(e),i=e.marker?.light_entity;return i&&t.includes(i)?i:t[0]||null}function gh(e,t){if(!1===t.marker?.is_light)return[];if(!0===t.marker?.is_light){return[{eid:mh(t),via:"forced"}]}const i=t.primary||ch(e,t.entities)[0];return i&&!i.startsWith("light.")?[]:t.entities.filter(t=>t.startsWith("light.")&&!!e.states?.[t]).map(e=>({eid:e,via:"light"}))}const fh=new WeakMap,vh=new WeakMap;function yh(e){return e.map(e=>[e.id||"",!0===e.hidden?1:0,e.primary||"",[...e.entities].join(","),void 0===e.controls?"":[...e.controls].join(","),e.marker?.id||"",e.marker?.binding||"",e.marker?.is_light,e.marker?.tap_action||"",!0===e.marker?.removed?1:0,e.marker?.light_entity||"",null==e.marker?.controls?"":[...e.marker.controls].join(",")].join("")).join("")}function bh(e){const t=yh(e),i=fh.get(e);if(i?.fingerprint===t)return i;const n=e.filter(e=>!e.hidden),r=new Map,o=new Map;for(const t of e){o.set(t,uh(t.marker?.binding,t.marker?.controls??t.controls,t.entities));const e=t.hidden||!0!==t.marker?.is_light?null:t.marker?.id||t.id;e&&r.set(String(e),t)}const s=new Map;for(const t of e){const e=o.get(t)||[],i=new Set(void 0===t.controls?e.filter(yn):t.controls.filter(yn)),n=mh(t),a=i.size?[...i]:n?[n]:[];for(const i of e){if(!i.startsWith("marker:"))continue;const e=i.slice(7);if(!e||e===String(t.marker?.id||t.id||""))continue;if(!r.has(e))continue;const n=s.get(e)||{markerId:e,controllers:[],driverEids:[]};n.controllers.push({device:t,driverEids:[...a]}),n.driverEids=[...new Set([...n.driverEids,...a])],s.set(e,n)}}const a={fingerprint:t,visible:n,markerById:r,persistedByDevice:o,incomingByMarker:s};return fh.set(e,a),a}function wh(e){return bh(e).incomingByMarker}function kh(e,t){const i=dh(t.marker?.binding,t.controls??t.marker?.controls,t.entities),n=uh(t.marker?.binding,t.marker?.controls??t.controls,t.entities);return(null!=t.marker?.is_light||!i.length&&!n.some(e=>e.startsWith("marker:")))&&gh(e,t).length>0}function xh(e,t){return gh(e,t).some(e=>!!e.eid)}function $h(e,t,i,n){const r="always"===e||"auto"===e&&t,o=r&&!i;return{sourceExists:r,fromSourceEnabled:r&&i,manualEnabled:r,radiusEnabled:r,passive:o,effectiveMode:o&&"auto"===n?"fixed":n}}function Sh(e,t){const i=dh(t.marker?.binding,t.controls??t.marker?.controls,t.entities).map(e=>({eid:e,via:"controls"})),n=kh(e,t)?gh(e,t):[];for(const e of n)e.eid&&i.some(t=>t.eid===e.eid)||i.push(e);return i}function Mh(e,t,i,n){if(null!=i)return Mh(e,t,null,n).filter(e=>ph(e.device,i));const r=yh(t),o=function(e,t){const i=new Set;for(const e of t){for(const t of e.entities)i.add(t);for(const t of e.controls||e.marker?.controls||[])"string"!=typeof t||t.startsWith("marker:")||i.add(t)}return[...i].sort().map(t=>`${t}:${e?.states?.[t]?.state??""}`).join("|")}(e,t),s=Oc(n),a=vh.get(t);if(a?.graphFingerprint===r&&a.stateFingerprint===o&&a.virtualLightFingerprint===s&&a.registry===e?.entities)return a.sources;const{visible:l,markerById:c,persistedByDevice:h,incomingByMarker:d}=bh(t),u=null==i?l:l.filter(e=>ph(e,i)),p=new Map,_=new Map;for(const t of u){const i=Sh(e,t).filter(e=>"controls"!==e.via);for(const n of i){const i=!0===t.marker?.is_light?String(t.marker?.id||t.id||""):"",r=i?`marker:${i}`:`entity:${n.eid}`,o=n.eid?[n.eid]:[],s={key:r,eid:n.eid||"",stateEids:o,serviceEids:o,device:t,via:n.via,castsGlow:!0,passive:!n.eid,on:!n.eid||"on"===e.states?.[n.eid]?.state};p.set(t,[...p.get(t)||[],s]),n.eid&&_.set(n.eid,s)}}const m=new Map;for(const e of t){const t=h.get(e)||[],i=new Set(void 0===e.controls?t.filter(yn):e.controls);m.set(e,i)}for(const t of p.values())for(const i of t){if(!i.passive)continue;const t=i.key.slice(7),r=d.get(t);i.on=!r||r.driverEids.some(t=>"on"===e.states?.[t]?.state),!r&&zc(i.device.marker)&&(i.on=Pc(i.device.marker,n))}const g=new Map,f=e=>{const t=g.get(e.key);(!t||e.castsGlow&&!t.castsGlow)&&g.set(e.key,e)};for(const t of l){const n=h.get(t)||[],r=null==i||ph(t,i);for(const i of n){if(i.startsWith("marker:")){const e=c.get(i.slice(7)),t=e?p.get(e):null;if(t)for(const e of t)f(e);continue}if(!yn(i)||!m.get(t)?.has(i))continue;const n=_.get(i);n?f(n):r&&f({key:`entity:${i}`,eid:i,stateEids:[i],serviceEids:[i],device:t,via:"controls",castsGlow:!1,passive:!1,on:"on"===e.states?.[i]?.state})}for(const e of p.get(t)||[])f(e)}const v=[...g.values()];return vh.set(t,{graphFingerprint:r,stateFingerprint:o,virtualLightFingerprint:s,registry:e?.entities,sources:v}),v}function Rh(e){const t=e.filter(e=>e.castsGlow);return t.find(e=>e.on)||t[0]||null}function Th(e){return e.length?e.some(e=>e.on)?"on":"off":"none"}function Ch(e,t){const i=[];for(const n of t){const t=e.states[n];if(!t)continue;const r=(t.attributes?.unit_of_measurement||"").toLowerCase();if(/_(linkquality|lqi)$/.test(n)||"lqi"===r){const e=parseFloat(t.state);isNaN(e)||i.push(e);continue}const o=t.attributes?.linkquality??t.attributes?.lqi;if(null!=o){const e=parseFloat(o);isNaN(e)||i.push(e)}}return Mi(i)}function Dh(e,t){for(const i of t){if(!sh(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(10*n)/10}return null}function Ah(e,t){for(const i of t){if(!i.startsWith("climate."))continue;const t=e.states[i];if(!t||"unavailable"===t.state||"unknown"===t.state)continue;const n=parseFloat(t.attributes?.current_temperature);if(Number.isFinite(n))return Math.round(10*n)/10}return null}function Oh(e,t){if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_humidity$/.test(t);const n=i.attributes||{};return"humidity"===n.device_class||"%"===n.unit_of_measurement&&/_humidity$/.test(t)||/_humidity$/.test(t)}function zh(e,t){for(const i of t){if(!Oh(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(n)}return null}function Ph(e,t){if(!t)return[];const i=[];for(const[t,n]of Object.entries(e.entities)){if(!t.startsWith("light.")||n.hidden||!Zc(n))continue;let r=null;if("group"===n.platform)r=n.area_id||null;else{if(!n.device_id)continue;{const t=e.devices[n.device_id];if(!Zc(t))continue;if("Group"!==t?.model)continue;r=t.area_id||n.area_id||null}}if(!r)continue;const o=e.states[t];i.push({eid:t,name:n.name||o?.attributes?.friendly_name||t,area:r})}return i}function Fh(e,t,i,n,r){const o=Fe(t,i,r);if(o!==Pe)return o;const s=[];for(const t of n){const i=e.states[t]?.attributes?.device_class;i&&s.push(i)}return function(e){for(const t of e){const e=ze[t];if(e)return e}return null}(s)??Pe}function Ih(e,t){return e.map(e=>{if(!Array.isArray(e.controls))return e;const i=e.controls.filter(e=>!("string"==typeof e&&e.startsWith("marker:")&&t.has(e.slice(7))));return i.length===e.controls.length?e:{...e,controls:i.length?i:null}})}function Eh(e,t,i){if(!t||!i||t===i)return[...e];const n=`marker:${t}`,r=`marker:${i}`;return e.map(e=>{const t=Array.isArray(e.controls)?e.controls.map(e=>e===n?r:e):e.controls,i="derived_marker_state"===e.value_badge?.source?.kind&&e.value_badge.source.ref===n?{...e.value_badge,source:{...e.value_badge.source,ref:r}}:e.value_badge;return t===e.controls&&i===e.value_badge?e:{...e,controls:t,value_badge:i}})}function Nh(e,t,i){if(!t||t===i)return!0;const n=new Map;for(const t of e)n.set(t.id,(t.controls||[]).filter(e=>"string"==typeof e&&e.startsWith("marker:")).map(e=>e.slice(7)));const r=new Set,o=[i];for(;o.length;){const e=o.pop();if(e===t)return!0;r.has(e)||(r.add(e),o.push(...n.get(e)||[]))}return!1}function Hh(e,t,i,n){const r=new Set([t]),o=e.filter(e=>{const o=e.id===t||!n&&e.binding===i;return o&&r.add(e.id),!o});return{markers:n?o:[...o,{id:t,binding:i,removed:!0,hidden:!0}],cleanupIds:r}}function Lh(e){const t=new Set,i=new Set,n=new Set;for(const r of e||[]){const e=String(r.binding||"").indexOf(":");if(e<1)continue;const o=r.binding.slice(0,e),s=r.binding.slice(e+1);s&&(!0===r?.removed?"device"===o?t.add(s):"entity"===o&&i.add(s):"entity"===o&&n.add(s))}return{devices:t,entities:i,liveEntities:n}}function qh(e,t,i){if(i.liveEntities.has(t))return!1;if(i.entities.has(t))return!0;const n=e?.entities?.[t]?.device_id;return!!n&&i.devices.has(n)}function jh(e,t,i,n,r){const o=dh(t.binding,t.controls,e.entities).filter(e=>!qh(i,e,n)).filter(e=>"active"===th(i,"entity:"+e,r).kind);e.marker=t,e.controls=o,e.userHidden=!0===t.hidden,e.hidden=e.userHidden||"ha_disabled"===e.bindingStatus?.kind,t.name&&(e.name=t.name),t.icon&&(e.icon=t.icon),null!=t.model&&(e.model=t.model),e.link=t.link??null,e.description=t.description??null,e.pdfs=t.pdfs||[],e.tapAction=t.tap_action??null}function Bh(e,t,i,n){if("string"==typeof e.room_id&&e.room_id.length>0&&null===e.area)return{area:"",space:e.space||n};const r=e.area||t||"";return{area:r,space:r&&i[r]||e.space||n}}function Wh(e){const t=e.hass,i=e.registry||Vc(t),n=Xc(t,i),r=Jc(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,showAll:c,firstSpaceId:h,loc:d,iconRules:u}=e,p=!1!==a.group_lights,_=Lh(s),m=Ph(n,p).filter(e=>!qh(n,e.eid,_)),g=new Set(m.map(e=>e.area)),f=ih(n),v=function(e){const t={};for(const[i,n]of Object.entries(e.entities||{}))n?.device_id&&(t[n.device_id]=t[n.device_id]||[]).push(i);return t}(r),y=nh(s,r),b=new Set;for(const e of s){const[t,i]=e.binding.split(":");"device"!==t&&"entity"!==t||!i||b.add(e.binding)}const w=(e,t)=>s.find(i=>i.binding===e+":"+t),k={},x=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(b.has("device:"+e.id))continue;const s=th(t,"device:"+e.id,i);if("active"!==s.kind)continue;const h=w("device",e.id);if(h&&h.hidden&&!a.filter_seeded)continue;const _=rh(n,e.id,f[e.id]||[],y);if(_.partial&&!_.entityIds.length)continue;const m=_.entityIds,v=_.partial?{kind:"active",enabledEntityIds:m,allEntityIds:m}:s,$=oh(n,e,m),S=!a.filter_seeded;if(S&&!c){if(l.has($))continue;if("Group"===e.model)continue;if(/scene/i.test(e.model||""))continue;if(/bridge/i.test((e.model||"")+(e.name||"")))continue;if("myheat"===$&&e.via_device_id)continue}const M=(e.name_by_user||e.name||d("device.unnamed")).trim(),R=M+"|"+r;let T=Fh(n,M,e.model,m,u);if(m.some(e=>e.startsWith("lock."))&&(T="mdi:lock"),S&&!c&&p&&"mdi:lightbulb"===T&&g.has(r))continue;k[R]=(k[R]||0)+1;const C=k[R]>1?M+" "+k[R]:M,D={id:e.id,name:C,model:e.model||"",area:r,space:o[r],icon:T,entities:m,allEntities:v.allEntityIds,bindingStatus:v,bindingKind:"device",bindingRef:e.id,pdfs:[]};D.primary=hh(n,m,T),"mdi:thermometer"!==T&&"mdi:air-filter"!==T||(D.temp=Dh(n,m)),D.primary&&Oh(n,D.primary)&&(D.hum=zh(n,m)),x.push(D)}for(const e of m)o[e.area]&&(b.has("entity:"+e.eid)||x.push({id:"lg_"+e.eid,name:e.name,model:d("device.light_group"),area:e.area,space:o[e.area],icon:"mdi:lightbulb-group",entities:[e.eid],allEntities:[e.eid],bindingStatus:{kind:"active",enabledEntityIds:[e.eid],allEntityIds:[e.eid]},primary:e.eid,bindingKind:"entity",bindingRef:e.eid,pdfs:[]}));for(const e of s){if(e.removed)continue;const[s,l]=e.binding.split(":"),c="device"===s||"entity"===s?th(t,e.binding,i):null;if(!e.hidden||a.filter_seeded||"ha_disabled"===c?.kind)if("device"===s){const t=c;if("unverified"===t.kind)continue;const s=r.devices[l],{area:a,space:p}=Bh(e,s?.area_id,o,h),m="active"===t.kind?t.enabledEntityIds:[];let g=s?Fh(n,s.name_by_user||s.name||"",s.model,m,u):"mdi:help-circle";m.some(e=>e.startsWith("lock."))&&(g="mdi:lock");const f={id:e.id,name:s?.name_by_user||s?.name||d("device.fallback"),model:s?.model||"",area:a,space:p,icon:g,entities:m,allEntities:t.allEntityIds.length?t.allEntityIds:s&&v[s.id]||[],bindingStatus:t,bindingKind:"device",bindingRef:l};f.primary=hh(n,m,g),"mdi:thermometer"!==g&&"mdi:air-filter"!==g||(f.temp=Dh(n,m)),f.primary&&Oh(n,f.primary)&&(f.hum=zh(n,m)),jh(f,e,r,_,i),x.push(f)}else if("entity"===s){if(qh(r,l,_))continue;const t=c;if("unverified"===t.kind)continue;const s=r.entities[l],a=s?.area_id||s?.device_id&&r.devices[s.device_id]?.area_id||"",{area:d,space:p}=Bh(e,a,o,h),m=n.states[l],g=s?.name||m?.attributes?.friendly_name||l;let f=Fh(n,g,"",[l],u);l.startsWith("lock.")&&(f="mdi:lock");const v={id:e.id,name:g,model:"",area:d,space:p,icon:f,entities:"active"===t.kind?[l]:[],allEntities:[l],bindingStatus:t,primary:"active"===t.kind?l:void 0,bindingKind:"entity",bindingRef:l};"mdi:thermometer"!==f&&"mdi:air-filter"!==f||!v.entities.length||(v.temp=Dh(n,v.entities)),v.entities.length&&Oh(n,l)&&(v.hum=zh(n,v.entities)),jh(v,e,r,_,i),x.push(v)}else{const t=e.area||"",n=e.space||t&&o[t]||h,s={id:e.id,name:e.name||d("device.virtual"),model:e.model||"",area:t,space:n,icon:e.icon||"mdi:map-marker",entities:[],allEntities:[],bindingStatus:{kind:"active",enabledEntityIds:[],allEntityIds:[]},bindingKind:"virtual",virtual:!0};jh(s,e,r,_,i),x.push(s)}}return x}function Uh(e){const{marker:t,siblingMarkers:i=[],...n}=e;return Wh({...n,markers:[...i.filter(e=>e.id!==t.id),t]}).find(e=>e.id===t.id)||null}function Gh(e,t,i,n){if(!t)return null;if(function(e,t,i){if(!t)return!1;const n=t.indexOf(":");if(n<1)return!1;const r=t.slice(0,n),o=t.slice(n+1),s=Lh(i);return"device"===r?s.devices.has(o):"entity"===r&&qh(e,o,s)}(e,t,n))return null;const r=t.indexOf(":");if(r<0)return null;const o=t.slice(0,r),s=t.slice(r+1);if(!s)return null;if("entity"===o){const t=parseFloat(e.states[s]?.state);return Number.isFinite(t)?"temp"===i?Math.round(10*t)/10:Math.round(t):null}if("device"===o){const t=Object.entries(e.entities).filter(([,e])=>e.device_id===s).map(([e])=>e);return"temp"===i?Dh(e,t):zh(e,t)}return null}const Vh=new RegExp(["water","voda","coolant","flow_?temp","return_?temp","target","setpoint","chip","cpu","processor","board","core_temp","device_temp","batter","akkum","freezer","fridge","oven","kettle","boiler"].join("|"),"i");function Kh(e,t,i){const n=[];for(const r of t){if(r.area!==i||r.virtual)continue;const t=Ch(e,r.entities);null!=t&&n.push(t)}return Mi(n)}function Yh(e,t,i){const n=[];for(const r of t){if(r.area!==i)continue;if("mdi:thermometer"!==r.icon&&"mdi:air-filter"!==r.icon)continue;const t=Dh(e,r.entities);null!=t&&n.push(t)}return n.length?Math.round(n.reduce((e,t)=>e+t,0)/n.length*10)/10:null}const Zh={offStates:["off"],unknownUsesToggle:!0},Xh={light:Zh,switch:Zh,fan:Zh,humidifier:Zh,input_boolean:Zh,automation:Zh,remote:Zh,group:Zh,climate:{...Zh,featureMasks:{turn_on:256,turn_off:128,toggle:384}},media_player:{...Zh,featureMasks:{turn_on:128,turn_off:256,toggle:384}},siren:{...Zh,featureMasks:{turn_on:1,turn_off:2,toggle:3}},vacuum:{...Zh,featureMasks:{turn_on:1,turn_off:2,toggle:3}},water_heater:{...Zh,featureMasks:{turn_on:8,turn_off:8,toggle:8}},camera:{...Zh,featureMasks:{turn_on:1,turn_off:1,toggle:1}}};function Jh(e){return e.slice(0,e.indexOf("."))}function Qh(e,t,i){if(!e?.services||"object"!=typeof e.services)return!1;const n=e.services?.[t];return!!n&&Object.prototype.hasOwnProperty.call(n,i)}function ed(e,t,i){return Qh(e,t,i)?{domain:t,service:i}:Qh(e,"homeassistant",i)?{domain:"homeassistant",service:i}:null}function td(e,t){return e?.entities?.[t]||null}function id(e,t,i){const n=e?.states?.[i],r=td(t,i);return n?.attributes?.friendly_name||r?.name||r?.original_name||i}function nd(e,t){const i=td(e,t);if(null!=i?.disabled_by)return!0;const n=i?.device_id?e?.devices?.[i.device_id]:null;return null!=n?.disabled_by}function rd(e,t){const i=e?.attributes?.supported_features;if(null==i||""===i)return!1;const n=Number(i);return Number.isFinite(n)&&(n&t)===t}function od(e,t,i){const n=Jh(i);if("lock"===n||"alarm_control_panel"===n)return!0;if("cover"!==n)return!1;const r=e?.states?.[i],o=td(t,i),s=String(r?.attributes?.device_class||o?.device_class||o?.original_device_class||"");return Fi.has(s)}function sd(e,t,i,n,r){return{ref:i,entityId:n,name:n?id(e,t,n):null,reason:r}}function ad(e,t,i,n,r,o=null){return{target:null,skipped:sd(e,t,i,n,r),semantics:o,nextEffect:null,command:null}}function ld(e,t,i,n,r=i){const o=Jh(i);if("cover"!==o&&"valve"!==o)return function(e,t,i,n,r=i){const o=Jh(i),s=e?.states?.[i];if(nd(t,i))return ad(e,t,r,i,"ha-disabled","power");if(od(e,t,i))return ad(e,t,r,i,"secure");if(!s)return ad(e,t,r,i,"missing","power");if("unavailable"===s.state)return ad(e,t,r,i,"unavailable","power");const a=Xh[o];if(!a)return ad(e,t,r,i,"unsupported");let l,c;if("unknown"===s.state||""===s.state){if(!a.unknownUsesToggle)return ad(e,t,r,i,"unsupported","power");l="toggle",c="toggle"}else a.offStates.includes(String(s.state))?(l="turn-on",c="turn_on"):(l="turn-off",c="turn_off");const h=a.featureMasks?.[c];if(h&&!rd(s,h))return ad(e,t,r,i,"unsupported","power");const d=ed(e,o,c);return d?{target:{entityId:i,name:id(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:"power",nextEffect:l,command:{...d,data:{entity_id:i}}}:ad(e,t,r,i,"unsupported","power")}(e,t,i,n,r);if(nd(t,i))return ad(e,t,r,i,"ha-disabled",o);if(od(e,t,i))return ad(e,t,r,i,"secure",o);const s=e?.states?.[i];if(!s)return ad(e,t,r,i,"missing",o);if("unavailable"===s.state)return ad(e,t,r,i,"unavailable",o);const a=function(e,t,i){const n=String(i?.state||""),r="closed"===n?{service:`open_${t}`,effect:"open",feature:1}:"open"===n?{service:`close_${t}`,effect:"close",feature:2}:"opening"===n||"closing"===n?{service:`stop_${t}`,effect:"stop",feature:8}:null;return r&&rd(i,r.feature)&&Qh(e,t,r.service)?r:rd(i,3)&&Qh(e,t,"toggle")?{service:"toggle",effect:"toggle"}:null}(e,o,s);if(!a)return ad(e,t,r,i,"unsupported",o);return{target:{entityId:i,name:id(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:o,nextEffect:a.effect,command:{domain:o,service:a.service,data:{entity_id:i}}}}function cd(e){return"entity"===e.bindingKind?e.bindingRef&&yn(e.bindingRef)?[e.bindingRef]:[]:"virtual"===e.bindingKind?[]:_h(e)}function hd(e){const t=e.marker?.toggle_entity;return t&&cd(e).includes(t)?t:null}function dd(e,t,i){const n=function(e,t){if("entity"===e.bindingKind&&e.bindingRef){const t=e.marker?.light_entity?mh(e):null;return[...new Set([t,e.bindingRef].filter(e=>!!e))]}const i=e.entities.length?e.entities:e.allEntities||[],n=e.marker?.light_entity||e.primary&&yn(e.primary)?mh(e):null;return[...new Set([n,...ch(t,i)].filter(e=>!!e))]}(i,t);if(!n.length)return null;const r="entity"===i.bindingKind?"binding":"device-role";if("binding"===r)return ld(e,t,n[0],r);let o=null,s=null;for(const i of n){const n=ld(e,t,i,r);if(n.command)return n;const a=n.skipped?.reason;if("missing"===a||"unavailable"===a||"secure"===a)return n;"ha-disabled"!==a?o||=n:s||=n}return o||s}function ud(e){const t=e.skipped?.reason;return"missing"===t?"unavailable":t||"unsupported"}function pd(e,t){return{origin:e,kind:"none",semantics:null,targets:[],skippedTargets:[],noneReason:t,nextEffect:null,command:null}}function _d(e,t){return"cover"===e||"toggle"===e?"toggle":"more-info"===e||"run"===e||"info"===e?e:(null==e||""===e)&&"light"===t?"toggle":"info"}function md(e,t){return{origin:e,kind:"single",semantics:t.semantics,targets:t.target?[t.target]:[],skippedTargets:t.skipped?[t.skipped]:[],noneReason:t.command?null:ud(t),nextEffect:t.nextEffect,command:t.command}}function gd(e,t,i,n=[]){const r=new Map,o=[],s=new Set,a=e=>{const t=`${e.ref}\n${e.entityId||""}\n${e.reason}`;s.has(t)||(s.add(t),o.push(e))};for(const e of n)a(e);for(const n of i){const i=ld(e,t,n.entityId,n.via,n.ref);i.target?r.set(n.entityId,r.get(n.entityId)||i.target):i.skipped&&a(i.skipped)}const l=[...r.values()];if(!l.length)return{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:o.length&&o.every(e=>"secure"===e.reason)?"secure":"configured-targets-missing",nextEffect:null,command:null};const c=l.some(e=>"on"===e.state)?"turn_off":"turn_on",h=ed(e,"homeassistant",c);return h?{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:null,nextEffect:"turn_on"===c?"turn-on":"turn-off",command:{...h,data:{entity_id:l.map(e=>e.entityId)}}}:{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:[],skippedTargets:[...o,...l.map(i=>sd(e,t,i.entityId,i.entityId,"unsupported"))],noneReason:"unsupported",nextEffect:null,command:null}}function fd(e){return String(e.marker?.id||e.id||"")}function vd(e){const{hass:t,device:i}=e,n=e.registryHass||t,r=function(e){return"toggle"===e.tapAction?"explicit-toggle":"cover"===e.tapAction?"legacy-cover":!e.tapAction&&e.primary?.startsWith("light.")?"default-light":null}(i);if(!r)return null;const o=i.marker;if("explicit-toggle"===r&&zc(o)){const t=String(o?.id||i.id||""),n=wh(e.devices).get(t);if(n)return function(e,t){const i=e.registryHass||e.hass;return gd(e.hass,i,t.driverEids.map(e=>({entityId:e,via:"control-marker-driver",ref:`marker:${t.markerId}`})))}(e,n);const s=Pc(o,e.virtualLights);return{origin:r,kind:"single",semantics:"power",targets:[{entityId:"",name:i.name,state:s?"on":"off",via:"virtual-light"}],skippedTargets:[],noneReason:null,nextEffect:s?"turn-off":"turn-on",command:null,operation:{kind:"virtual-light",markerId:o.id}}}if("explicit-toggle"===r){if(uh(i.marker?.binding,i.marker?.controls??i.controls,i.entities).length)return function(e,t=null){const{hass:i,device:n,devices:r}=e,o=e.registryHass||i,s=uh(n.marker?.binding,n.marker?.controls??n.controls,n.entities),a=e.lightSources||Mh(i,r,null,e.virtualLights),l=new Map;for(const e of a){if(!e.key.startsWith("marker:"))continue;const t=l.get(e.key)||[];t.push(e),l.set(e.key,t)}const c=wh(r),h=new Map;for(const e of r){const t=String(e.marker?.id||e.id||"");t&&h.set(t,e)}const d=[],u=[];t&&d.push({entityId:t,via:"entity"===n.bindingKind?"binding":"device-role",ref:t});for(const e of s){if(!e.startsWith("marker:")){yn(e)?d.push({entityId:e,via:"control-entity",ref:e}):u.push(sd(i,o,e,e.includes(".")?e:null,"unsupported"));continue}const t=l.get(e)||[];if(!t.length){const t=h.get(e.slice(7));if("ha_disabled"===t?.bindingStatus?.kind){const n=t.bindingStatus.allEntityIds[0]||null;u.push({ref:e,entityId:n,name:t.name||(n?id(i,o,n):null),reason:"ha-disabled"})}else u.push(sd(i,o,e,null,"missing"));continue}const r=[...new Set(t.flatMap(e=>e.serviceEids))];if(r.length){for(const t of r)d.push({entityId:t,via:"control-entity",ref:e});continue}const s=t.some(e=>e.passive),a=e.slice(7),p=fd(n),_=c.get(a)?.controllers.find(e=>fd(e.device)===p);if(s&&_?.driverEids.length)for(const t of _.driverEids)d.push({entityId:t,via:"control-marker-driver",ref:e});else u.push(sd(i,o,e,null,s?"missing":"unsupported"))}return gd(i,o,d,u)}(e,hd(i))}if("legacy-cover"===r){const e=i.entities.find(e=>e.startsWith("cover."))||i.allEntities?.find(e=>e.startsWith("cover."));return e?md(r,ld(t,n,e,"device-role")):pd(r,"no-actionable-entity")}const s=hd(i),a=s?ld(t,n,s,"entity"===i.bindingKind?"binding":"device-role"):dd(t,n,i);return a?md(r,a):pd(r,i.virtual||"virtual"===i.bindingKind?"no-actionable-entity":"no-binding")}function yd(e){if(!e)return[];const t=Array.isArray(e.data.entity_id)?e.data.entity_id:[e.data.entity_id];return[...new Set(t)].sort()}function bd(e){return e?e.operation?e.operation:e.command?{kind:"ha-service",command:e.command}:null:null}const wd=new Set(["missing","ha-disabled","unavailable"]);function kd(e,t){if(!bd(e)||!e.nextEffect||!e.targets.length)return[];const i="group"===e.kind,n=i?e.targets.filter(e=>"on"===e.state).length:0,r=i?0===n?t.groupAllOff():t.groupCurrent(n,e.targets.length):t.state(e.targets[0]);let o;return o="toggle"===e.nextEffect?t.expectedByHa():i&&"turn-on"===e.nextEffect?t.groupAllOn():i&&"turn-off"===e.nextEffect?t.groupAllOff():t.effect(e.nextEffect),[t.current(r),t.expected(o),...e.skippedTargets.length?[t.unavailable(e.skippedTargets.length)]:[]]}function xd(e,t){const i=bd(e),n=bd(t);return!(!i||!n||i.kind!==n.kind)&&("virtual-light"===i.kind&&"virtual-light"===n.kind?i.markerId===n.markerId:"ha-service"===i.kind&&"ha-service"===n.kind&&function(e,t){const i=yd(e),n=yd(t);return i.length===n.length&&i.every((e,t)=>e===n[t])}(i.command,n.command))}function $d(e,t){const i=e.targets[0]||e.skippedTargets[0],n=[];return"group"===e.kind?e.targets.length&&n.push(t.group(e.targets)):i&&n.push(t.single(i)),e.nextEffect&&e.targets.length&&n.push("group"===e.kind?t.groupCurrentNext(e.targets,e.nextEffect):t.currentNext(e.targets[0],e.nextEffect)),e.skippedTargets.length&&n.push(t.skipped(e.skippedTargets)),!e.command&&e.noneReason&&n.push(t.none(e.noneReason)),n}const Sd=e=>!!e&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function Md(e,t=5,i=5){return vo(e.cm,t,i)/2}function Rd(e,t,i=1,n=5,r=5,o=0){const s=e.host;if(!s||"partition"!==s.kind||"string"!=typeof s.id||!s.id)return{resolved:null,reason:"invalid-host"};const a=t.find(e=>e.id===s.id);if(!a)return{resolved:null,reason:"missing-partition"};if(!Sd(a.a)||!Sd(a.b)||!Number.isFinite(s.t)||s.t<0||s.t>1)return{resolved:null,reason:"invalid-position"};const l=a.b[0]-a.a[0],c=a.b[1]-a.a[1],h=Math.hypot(l,c),d=Number(e.length)*i;if(!(h>1e-9&&d>0&&Number.isFinite(d)))return{resolved:null,reason:"invalid-length"};const u=s.t*h;if(u-d/2h-o+1e-9)return{resolved:null,reason:"does-not-fit"};const p=l/h,_=c/h;let m=180*Math.atan2(c,l)/Math.PI;return m>=90?m-=180:m<-90&&(m+=180),{reason:null,resolved:{opening:e,host:s,partition:a,center:[a.a[0]+l*s.t,a.a[1]+c*s.t],angle:m,length:d,depth:vo(a.cm,n,r),t:s.t,axis:{a:[a.a[0],a.a[1]],b:[a.b[0],a.b[1]],ux:p,uy:_,length:h}}}}function Td(e,t,i=1,n=5,r=5){return Rd(e,t,i,n,r,0)}function Cd(e,t,i=1,n=5,r=5){const o=e.host,s="partition"===o?.kind?t.find(e=>e.id===o.id):void 0;if(!s)return Td(e,t,i,n,r);const a=Rd(e,t,i,n,r,Md(s,n,r));return"does-not-fit"===a.reason?{resolved:null,reason:"does-not-fit-jamb"}:a}function Dd(e,t){return!e||(e.length!==t.length||e.host?.kind!==t.host?.kind||e.host?.id!==t.host?.id||e.host?.t!==t.host?.t)}function Ad(e){const{center:t,length:i,axis:n,host:r}=e,o=i/2;return{hostId:r.id,a:[t[0]-n.ux*o,t[1]-n.uy*o],b:[t[0]+n.ux*o,t[1]+n.uy*o],depth:e.depth}}function Od(e,t=!1){const i=t?1:-1,n=e.depth/2;return{ox:-e.axis.uy*i*n,oy:e.axis.ux*i*n,cm:e.partition.cm,side:i}}function zd(e,t,i){return e.flatMap(e=>!Sd(e.a)||!Sd(e.b)||Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])<=1e-9?[]:[{roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`partition:${e.id}`,kind:"outer",cm:e.cm,open:!1,half:vo(e.cm,t,i)/2,partitionHost:{kind:"partition",id:e.id}}])}function Pd(e,t,i){const{center:n,length:r,axis:o}=e,s=r/2,a=t.flatMap(e=>{if(!e.kind||e.open)return[];const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],a=Math.hypot(t,r);if(!(a>i))return[];const l=t/a,c=r/a;if(Math.abs(o.ux*c-o.uy*l)>1e-6)return[];if(Math.abs((n[0]-e.a[0])*c-(n[1]-e.a[1])*l)>i)return[];const h=e=>(e[0]-n[0])*o.ux+(e[1]-n[1])*o.uy,d=h(e.a),u=h(e.b),p=Math.max(-s,Math.min(d,u)),_=Math.min(s,Math.max(d,u));return _>=p-i?[[p,_]]:[]});if(!a.length)return!1;a.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let l=-s;for(const[e,t]of a){if(e>l+i)return!1;if(l=Math.max(l,t),l>=s-i)return!0}return!1}function Fd(e,t,i=1e-9){const n=e.length/(2*e.axis.length),r=e.t-n,o=e.t+n;return t.some(t=>{if(t.host.id!==e.host.id||t.opening.id===e.opening.id)return!1;const n=t.length/(2*t.axis.length);return Math.max(r,t.t-n)[]);for(let i=0;i=1-1e-9||u<=1e-9||u>=1-1e-9||(t[i].push(d),t[s].push(u))}}const i=[];for(let n=0;ne-t),1];for(let e=1;e{const i=t[2]-t[0],n=t[3]-t[1],r=i*i+n*n;if(!(r>0))return Math.hypot(e[0]-t[0],e[1]-t[1]);const o=Math.max(0,Math.min(1,((e[0]-t[0])*i+(e[1]-t[1])*n)/r));return Math.hypot(e[0]-(t[0]+o*i),e[1]-(t[1]+o*n))},qd=(e,t,i,n)=>{const r=n[2]-n[0],o=n[3]-n[1],s=t*o-i*r;if(Math.abs(s)<1e-12)return 1/0;const a=n[0]-e[0],l=n[1]-e[1],c=(a*o-l*r)/s;if(!(c>1e-9))return 1/0;const h=(a*i-l*t)/s;return h<-1e-9||h>1+1e-9?1/0:c};function jd(e,t,i,n=96){if(!(t>0&&Number.isFinite(e[0])&&Number.isFinite(e[1])))return[];const r=[];for(const n of i){if(!n||n.length<4)continue;if(![n[0],n[1],n[2],n[3]].every(Number.isFinite))continue;const i=Ld(e,n);if(i<1e-7)return[];i>t||r.push(n)}const o=[],s=Math.max(12,Math.round(n));for(let e=0;ee-t);const l=[];let c=Number.NEGATIVE_INFINITY;for(const i of o){if(i-c<1e-9)continue;c=i;const n=Math.cos(i),o=Math.sin(i);let s=t;for(const t of r){const i=qd(e,n,o,t);i=3?l:[]}const Bd=[o` + :host { + --hp-bg: var(--card-background-color, #16212e); + --hp-line: var(--divider-color, #2b3d4f); + --hp-txt: var(--primary-text-color, #e6edf3); + --hp-muted: var(--secondary-text-color, #8aa0b3); + --hp-accent: var(--primary-color, #3ea6ff); + --hp-on: #ffd45c; + --hp-open: #ff9f43; + /* design tokens (UI chrome only). The icon/plan scale math stays on + --icon-size/--dev-size cqw units and never uses these. */ + /* spacing scale, fact-based; stray 3/5/7/9/13/14px values are unified + onto the nearest step (max +-2px, the whole point of the pass) */ + --sp-1: 2px; + --sp-2: 4px; + --sp-3: 6px; + --sp-4: 8px; + --sp-5: 12px; + --sp-6: 16px; + /* px radii of dialogs/buttons/plates (the 22% badge radius is scale math) */ + --rad-s: 6px; + --rad-m: 8px; + --rad-l: 12px; + /* font tiers: fine print+labels / body+buttons / title */ + --fs-s: 12px; + --fs-m: 13px; + --fs-l: 15px; + /* elevation: badge / floating panel (menu, tip, toast) / dialog */ + --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.45); + --shadow-2: 0 6px 22px rgba(0, 0, 0, 0.45); + --shadow-3: 0 8px 30px rgba(0, 0, 0, 0.5); + } + ha-card { + overflow: visible; /* overflow:hidden breaks position:sticky on the header */ + } + .empty { + padding: 40px 24px; + color: var(--hp-txt); + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-4); + } + .empty .big { + --mdc-icon-size: 56px; + color: var(--hp-accent); + opacity: 0.7; + } + .empty .muted { + color: var(--hp-muted); + font-size: var(--fs-m); + margin: 0; + } + .empty .btn { + margin-top: var(--sp-4); + } + @keyframes fixedfloor-spin { + to { transform: rotate(360deg); } + } + .spacer { + flex: 1; + } + .bootveil { + position: absolute; + inset: 0; + z-index: 40; + display: flex; + align-items: center; + justify-content: center; + background: var(--hp-bg, #16212e); + opacity: 1; + transition: opacity 0.15s ease; + pointer-events: none; + } + .bootveil.off { + opacity: 0; + } + .bootveil .boothouse { + position: static; /* the main .zoomwrap SVG is pinned to inset:0 — not this icon */ + width: 56px; + height: 56px; + fill: var(--hp-accent); + opacity: 0.85; + animation: hp-boot-pulse 1.3s ease-in-out infinite; + } + @keyframes hp-boot-pulse { + 0%, 100% { opacity: 0.3; transform: scale(0.94); } + 50% { opacity: 0.9; transform: scale(1); } + } + @media (prefers-reduced-motion: reduce) { + .bootveil .boothouse { + animation: none; + opacity: 0.7; + } + } + @keyframes hp-pulse-short { + 0% { transform: scale(1); opacity: 0.55; } + 70% { opacity: 0.22; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + /* Alternate identity: a rapid retrigger restarts the browser timeline. */ + @keyframes hp-pulse-short-b { + 0% { transform: scale(1); opacity: 0.55; } + 70% { opacity: 0.22; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + @keyframes hp-pulse-continuous { + 0% { transform: scale(1); opacity: 0.55; } + 65% { opacity: 0.18; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + @keyframes hp-pulse-alarm { + 0% { transform: scale(1); opacity: 0.72; } + 100% { transform: scale(1.5); opacity: 0; } + } + /* Space changes keep their direction, but travel only a few percent: the + motion explains what changed without making the whole plan fly around. */ + @keyframes hp-slide-left { + 0% { transform: translateX(4%); opacity: 0.72; } + 100% { transform: translateX(0); opacity: 1; } + } + @keyframes hp-slide-right { + 0% { transform: translateX(-4%); opacity: 0.72; } + 100% { transform: translateX(0); opacity: 1; } + } + @keyframes hp-sunfade-in { + from { opacity: 0; } + to { opacity: 1; } + } + @keyframes hp-sunfade-out { + from { opacity: 1; } + to { opacity: 0; } + } + .sr-only { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; + } + .toast { + position: fixed; + pointer-events: none; + left: 50%; + bottom: 22px; + transform: translateX(-50%); + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + color: var(--hp-txt); + padding: var(--sp-4) var(--sp-6); + border-radius: var(--rad-l); + font-size: var(--fs-m); + box-shadow: var(--shadow-2); + z-index: 120; + max-width: 90vw; + } +`,o` + .fixedfloor-loading { + animation: fixedfloor-spin 1.1s linear infinite; + } + .fixedfloor-error p { + max-width: 42rem; + margin: 0; + overflow-wrap: anywhere; + } + @media (prefers-reduced-motion: reduce) { + .fixedfloor-loading { animation: none; } + } + .stage.noplan { + background: #ffffff; + } + /* Editors always keep the white drawing sheet — even when a backdrop + image is loaded. Without this, a picture plan painted the theme card + colour under the grid (owner 2026-08-05). View keeps the historical + theme / .noplan split. */ + .stage.mode-plan, + .stage.mode-devices, + .stage.mode-decor { + background: #ffffff; + } + .stage { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + touch-action: none; /* custom pinch/pan gestures */ + background: var(--ha-card-background, var(--card-background-color, #111)); + } + .zoomwrap { + position: absolute; + inset: 0; + z-index: 1; + } + .stage.mode-transition, + .stage.mode-transition .zoomwrap { + transition: none !important; + } + .stage.mode-transition .hp-view-only-layer, + .stage.mode-transition .hp-editor-only-layer { + pointer-events: none; + will-change: opacity; + } + .stage.mode-transition .hp-paper { + fill: var(--hp-mode-paper) !important; + } + /* Four-phase environment (#146): constant layers cross-fade because CSS + gradients themselves are not reliably interpolated. Everything stays + behind the plan; the plan tree is never dimmed, tinted or faded. */ + .hp-day-cycle-env { + position: absolute; + inset: 0; + z-index: 0; + overflow: hidden; + pointer-events: none; + isolation: isolate; + } + .hp-day-cycle-bg { + position: absolute; + inset: 0; + opacity: 0; + overflow: hidden; + transition: opacity 1100ms cubic-bezier(.22, .61, .36, 1); + } + .hp-day-cycle-bg.active { opacity: 1; } + .hp-day-cycle-sun { + position: absolute; + left: var(--hp-day-cycle-sun-x); + top: var(--hp-day-cycle-sun-y); + width: clamp(140px, 25cqw, 250px); + height: clamp(140px, 25cqw, 250px); + transform: translate(-50%, -50%); + border-radius: 50%; + filter: blur(10px); + opacity: var(--hp-day-cycle-sun-opacity); + transition: + left 1100ms cubic-bezier(.22, .61, .36, 1), + top 1100ms cubic-bezier(.22, .61, .36, 1), + opacity 1100ms cubic-bezier(.22, .61, .36, 1); + } + .stage.mode-transition .hp-day-cycle-env { transition: none; } + .stage.daycycle .hp-paperg, + .hp-static-stage.daycycle .hp-paperg { + filter: + drop-shadow(0 0 1px var(--hp-day-cycle-outline-near)) + drop-shadow(0 0 5px var(--hp-day-cycle-outline-mid)) + drop-shadow(0 0 10px var(--hp-day-cycle-outline-far)); + transition: filter 1100ms cubic-bezier(.22, .61, .36, 1); + } + @media (prefers-reduced-motion: reduce) { + .hp-day-cycle-bg, + .hp-day-cycle-sun, + .stage.daycycle .hp-paperg, + .hp-static-stage.daycycle .hp-paperg { + transition: none; + } + } + .sunlayer { + pointer-events: none; + } + .compass { + width: 120px; + height: 120px; + flex: none; + touch-action: none; + cursor: grab; + user-select: none; + } + .compass:active { + cursor: grabbing; + } + .compass .cring { + fill: rgba(255, 255, 255, 0.04); + stroke: var(--divider-color, #444); + stroke-width: 2; + } + .compass .ctick { + stroke: var(--secondary-text-color, #9aa4ad); + stroke-width: 2; + } + .compass .ctick.minor { + stroke-width: 1; + opacity: 0.6; + } + .compass .cneedle line { + stroke: var(--primary-color, #3ea6ff); + stroke-width: 2.5; + stroke-linecap: round; + } + .compass .cneedle path { + fill: var(--primary-color, #3ea6ff); + } + .compass .cneedle text { + fill: var(--text-primary-color, #fff); + font-size: 11px; + font-weight: 700; + } + .compass .cdeg { + fill: var(--secondary-text-color, #9aa4ad); + font-size: 13px; + } + .compass.unset .cneedle { + opacity: 0.35; + } + /* HP-1552: first-open boot veil — the plan hides until the stage height settles */ + .stage.hpboot .zoomwrap, + .stage.hpboot .zoombadge { + visibility: hidden; + } + /* AUD-1552-02: post-veil grace — HA chrome landing after the cap moves + the stage height smoothly; the viewport ResizeObserver refits the plan + along the transition, so a late panel glides instead of jumping. */ + .stage.hpsettle { + transition: height 0.25s ease; + } + @media (prefers-reduced-motion: reduce) { + .stage.hpsettle { + transition: none; + } + } + .zoomctl { + display: inline-flex; + gap: var(--sp-1); + background: rgba(127, 127, 127, 0.12); + border-radius: var(--rad-m); + padding: var(--sp-1); + } + .zoomctl .zb { + border: none; + padding: var(--sp-3) var(--sp-4); + } + .zoomctl .zb[disabled] { + opacity: 0.4; + pointer-events: none; + } + .projection-toggle { + min-width: 44px; + min-height: 44px; + justify-content: center; + padding: var(--sp-3); + } + /* docs/CANVAS.md §5: the plane has no edges, so you can pan until nothing + is on screen. One pointer home, one click back. */ + .homearrow { + position: absolute; + z-index: 12; + transform: translate(-50%, -50%); + width: 40px; + height: 40px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + background: var(--card-background-color, var(--hp-bg)); + color: var(--hp-accent); + border: 1px solid var(--hp-accent); + opacity: 0.9; + padding: 0; + } + .homearrow ha-icon { + --mdc-icon-size: 22px; + line-height: 1; + } + .zoombadge { + position: absolute; + z-index: 12; + left: var(--sp-4); + bottom: var(--sp-4); + background: var(--card-background-color, var(--hp-bg)); + opacity: 0.92; + color: var(--hp-txt); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-m); + padding: var(--sp-1) var(--sp-4); + font-size: var(--fs-s); + font-weight: 600; + pointer-events: none; + } + /* Only the plan canvas owns the whole zoom wrapper. Context trays now live + inside .stage as well, and may contain small SVG previews (furniture in + particular); the old descendant-wide stage-SVG selector stretched every + preview over the tray and stacked them into one blocking artefact. The + vacuum trail/fit overlays have their own explicit geometry below. */ + .zoomwrap > svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + } + .plan-svg { z-index: 1; } + .iso-underlay-svg { z-index: 0; overflow: visible; } + .iso-shadows-svg { z-index: 3; overflow: visible; } + .iso-walls-svg { + z-index: 4; + overflow: visible; + } + .iso-underlay-svg, + .iso-shadows-svg, + .iso-walls-svg, + .iso-underlay, + .iso-shadows, + .iso-walls, + .iso-openings { + pointer-events: none; + } + .iso-side-hi { stop-color: #b9bdbe; } + .iso-side-lo { stop-color: #969c9f; } + .iso-top-hi { stop-color: #fafaf7; } + .iso-top-lo { stop-color: #e2e4e2; } + .iso-wall-side { + fill: url(#hp-iso-wall-side) #a8acae; + stroke: #92989b; + stroke-width: 0.7; + vector-effect: non-scaling-stroke; + } + .iso-wall-top { + fill: url(#hp-iso-wall-top) #f3f3f1; + stroke: #d7d9d8; + stroke-width: 0.8; + vector-effect: non-scaling-stroke; + } + .iso-floor-side { + fill: #858b8d; + stroke: #71787b; + stroke-width: 0.7; + vector-effect: non-scaling-stroke; + } + .iso-opening-panel { + fill: #d7d9d7; + fill-opacity: 0.96; + stroke: #7f878b; + stroke-width: 0.9; + vector-effect: non-scaling-stroke; + } + .iso-opening-panel.iso-window { + fill: #dfeff4; + fill-opacity: 0.72; + stroke: #8aa7b1; + } + .iso-ambient-shadow { + fill: rgba(15, 21, 25, 0.22); + filter: url(#hp-iso-ambient-shadow); + } + .iso-contact-shadow { + fill: none; + stroke: rgba(22, 28, 31, 0.25); + stroke-width: 3; + filter: url(#hp-iso-contact-shadow); + vector-effect: non-scaling-stroke; + } + .iso-leaf-shadow { + fill: none; + stroke: rgba(18, 23, 27, 0.24); + stroke-width: 4; + filter: url(#hp-iso-leaf-shadow); + vector-effect: non-scaling-stroke; + } + @media (prefers-color-scheme: dark) { + .iso-side-hi { stop-color: #4c555a; } + .iso-side-lo { stop-color: #343c40; } + .iso-top-hi { stop-color: #687176; } + .iso-top-lo { stop-color: #50585d; } + .iso-wall-side { stroke: #30373b; } + .iso-wall-top { stroke: #7b858a; } + .iso-floor-side { fill: #2d3438; stroke: #20272a; } + .iso-opening-panel { fill: #626b70; stroke: #899399; } + .iso-opening-panel.iso-window { fill: #75919b; stroke: #abc6ce; } + .iso-ambient-shadow { fill: rgba(0, 0, 0, 0.34); } + .iso-contact-shadow, .iso-leaf-shadow { stroke: rgba(0, 0, 0, 0.38); } + } + @media (forced-colors: active) { + .iso-wall-side, .iso-wall-top, .iso-floor-side, .iso-opening-panel { + fill: Canvas; + stroke: CanvasText; + forced-color-adjust: auto; + } + .iso-ambient-shadow, .iso-contact-shadow, .iso-leaf-shadow { display: none; } + } + @supports not (filter: blur(1px)) { + .iso-ambient-shadow, .iso-contact-shadow, .iso-leaf-shadow { display: none; } + } + /* Opaque plan paper (owner 2026-08-03): the scene bg_color / daynight sky + shows ONLY around the plan, never through it. The colour is the + pre-bg_color canvas — the theme card background under an image plan, + plain white for a hand-drawn one (.stage.noplan). On drawn plans the + paper is per-room shapes following the room contours — fill only, + never a stroke, so the paper cannot poke past a wall. Night dimming + comes from the .zoomwrap brightness filter, never from alpha + (docs/SUN.md). */ + .hp-paper { + fill: var(--ha-card-background, var(--card-background-color, #111)); + stroke: none; + } + .stage.noplan .hp-paper, + .stage.mode-plan .hp-paper, + .stage.mode-devices .hp-paper, + .stage.mode-decor .hp-paper { + fill: #ffffff; + } + /* Owner 2026-08-04: «углы границ комнат всё ещё с зубцами». A miter join + on a 30-45° corner shoots a spike far past the wall (and flips to an + ugly bevel once past the miter limit) — the same defect the decor lines + had before they got round caps. Every room border, in EVERY renderer + that reuses these styles (plan view, plan editor, static space-card), + joins its walls with a ROUND join instead: the corner reads as the + stroke's own radius, never as a tooth. The linecap matters only for the + open outlines below, but it costs nothing to state it here. */ + .room { + transition: 0.12s; + cursor: default; /* v1.40.1: rooms are not clickable — the label's link icon is */ + stroke-linejoin: round; + stroke-linecap: round; + } + .room.overlay { + fill: transparent; + stroke: transparent; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + :host([data-pointer-hover]) .stage.mode-view .room.overlay:not(.styled):hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + .room.yard { + fill: rgba(75, 140, 90, 0.14); + stroke: #4b8c5a; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + :host([data-pointer-hover]) .stage.mode-view .room.yard:not(.styled):hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + .room.styled { + stroke: var(--room-stroke, transparent); + stroke-opacity: var(--room-stroke-op, 0); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + fill: var(--room-fill, transparent); + fill-opacity: var(--room-fill-op, 0); + } + .glow-base-layer, + .glow-base-tunnels, + .glow-pools-frame, + .glow-pools, + .glow-spot { + pointer-events: none; + } + /* The parent isolates all source spots from the room data fill, Glow base, + paper and backdrop. A spot is one circle clipped to the floor its lamp + can see, so the whole spot screen-blends as a single primitive — there is + no mask left to be dropped on a promoted layer. Per-stop alpha already + contains the shared 0.7 ceiling; the spot opacity below only animates + between 0 and 1 and is never another persistent alpha ceiling. */ + .glow-pools-frame, + .glow-pools, + .glow-spot { + isolation: isolate; + } + .glow-pools.blend-screen .glow-spot { + mix-blend-mode: screen; + } + .glow-spot { + opacity: 1; + transition: opacity 500ms ease; + } + .glow-spot.is-entering, + .glow-spot.is-leaving { + opacity: 0; + } + @media (prefers-reduced-motion: reduce) { + .glow-spot { + transition: none; + } + } + /* The explicit late room-hover layer owns the wash and halo. Keeping CSS + filters off room paths prevents Chromium from recompositing the sibling + screen-blended Glow layer for one bright frame on every hover. */ + :host([data-pointer-hover]) .stage.mode-view .room.styled:hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + /* doors, windows & gates */ + .op-leaf { + transition: transform 0.6s ease; + } + .op-arc { + stroke-width: calc(1.5px * var(--hp-cell-visual-scale, 1)); + transition: stroke-dashoffset 0.6s ease; + } + /* hover affordance: a rounded outline hugging the wall strip + a grab cursor */ + .op-outline { + fill: none; + stroke: var(--hp-accent); + stroke-width: calc(1.5px * var(--hp-cell-visual-scale, 1)); + opacity: 0; + transition: opacity 0.15s; + pointer-events: none; + } + :host([data-pointer-hover]) .stage.markup g.opening:hover .op-outline { + opacity: 0.9; + } + /* openings are pure status graphics outside Plan mode: no cursor, no hover, + no hit target — View must not interact with them at all */ + .op-hit { + fill: transparent; + pointer-events: none; + cursor: default; + } + .stage.markup .op-hit { + pointer-events: auto; + cursor: grab; + touch-action: none; /* drags, not scrolls, on touch */ + } + .stage.markup .op-hit:active { + cursor: grabbing; + } + .stage.markup .opening.orphan { + pointer-events: auto; + cursor: pointer; + color: var(--error-color, #db4437); + } + .stage.markup .opening.orphan circle { + fill: var(--hp-bg); + stroke: currentColor; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + .stage.markup .opening.orphan text { + fill: currentColor; + font-weight: 800; + font-size: calc(12px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + /* HP-1550-04: in the resize tool the wall handles own the hit test — the + transparent .op-hit of a door at the midpoint of a wall used to sit ON + TOP of the handle and made that wall ungrabbable for both rooms. + Openings are not editable in this tool (they ride along with the wall), + so their hit area goes fully inert; every other Plan tool is untouched. */ + .stage.markup.tool-resize .op-hit { + pointer-events: none; + cursor: default; + } + .stage.mode-view .oplock { + pointer-events: auto; + cursor: pointer; + } + @media (prefers-reduced-motion: reduce) { + .op-leaf, .op-arc { transition: none; } + } + .roomlabel { + pointer-events: none; /* draggable only in plan mode (rule below) */ + position: absolute; + transform: translate(-50%, -50%); + font-size: calc(var(--rl-icon-size, var(--icon-size, 2.5cqw)) * 0.5 * var(--rl-scale, 1) * var(--rl-font, 1) * var(--rl-space, 1)); + font-weight: 700; + letter-spacing: 0.04em; + white-space: nowrap; + cursor: grab; + user-select: none; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.15em; + text-align: center; + } + .rlname { + display: inline-flex; + align-items: center; + gap: 0.25em; + font-size: calc(1em * var(--rl-name, 1)); + } + .zoomwrap.slide-left { animation: hp-slide-left 0.18s cubic-bezier(0.2, 0.7, 0.2, 1); } + .zoomwrap.slide-right { animation: hp-slide-right 0.18s cubic-bezier(0.2, 0.7, 0.2, 1); } + @media (prefers-reduced-motion: reduce) { + .zoomwrap.slide-left, + .zoomwrap.slide-right { animation: none; } + } + /* The name is the anchor: the label box is centred on the room point, so + anything that takes part in its layout SHIFTS THE NAME. The gear button + and the metrics hang below as absolutes — the name renders in exactly + the same place in view mode and in the plan editor (owner's request), + and the button sits at the very bottom of the card. */ + /* Standalone, centred on the room, sized from the device icon: icon-size + already rescales with the view, so the button zooms WITH the plan + instead of keeping a constant screen size (owner's spec). */ + .rlgearbtn { + --gear-h: calc(var(--icon-size, 2.5cqw) * 0.77); /* owner: half the previous size */ + position: absolute; + /* dead-centred on the room, both axes (owner's spec) */ + transform: translate(-50%, -50%); + display: inline-flex; + align-items: center; + gap: 0.35em; + height: var(--gear-h); + padding: 0 calc(var(--gear-h) * 0.38); + border: 0; + border-radius: 999px; + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + font: inherit; + font-size: calc(var(--gear-h) * 0.42); + font-weight: 600; + line-height: 1; + white-space: nowrap; + cursor: pointer; + pointer-events: auto; + opacity: 0.92; + box-shadow: var(--shadow-1); + z-index: 2; + } + .rlgearbtn { transition: opacity 0.15s, filter 0.15s; } + :host([data-pointer-hover]) .rlgearbtn:hover { opacity: 1; filter: brightness(1.18); } + .rlgearbtn ha-icon { --mdc-icon-size: calc(var(--gear-h) * 0.55); display: inline-flex; } + .rlgear { + --mdc-icon-size: 0.9em; + display: inline-flex; + margin-right: 0.2em; + opacity: 0.6; + cursor: pointer; + pointer-events: auto; + } + :host([data-pointer-hover]) .rlgear:hover { opacity: 1; } + .rlgo { + --mdc-icon-size: 0.85em; + display: inline-flex; + opacity: 0.55; + } + .stage.mode-view .rlgo { + pointer-events: auto; + cursor: pointer; + } + :host([data-pointer-hover]) .stage.mode-view .rlgo:hover { opacity: 1; } + .roomlabel .rlmetrics { + position: absolute; /* below the name, outside the centring math */ + top: calc(100% + 0.15em); + left: 50%; + transform: translateX(-50%); + white-space: nowrap; + display: flex; + align-items: center; + gap: 0.55em; + font-size: calc(0.75em * var(--rl-meta, 1)); /* feedback: 0.62 was unreadable on a tablet */ + font-weight: 600; + letter-spacing: 0.02em; + opacity: 0.9; + } + .roomlabel .rlm { + display: inline-flex; + align-items: center; + gap: 0.12em; + } + .roomlabel .rlm ha-icon { + --mdc-icon-size: 1.05em; + display: inline-flex; + } + .roomlabel .rlm.lit { opacity: 1; } + .rlhandle { + display: none; + position: absolute; + width: 9px; + height: 9px; + border-radius: 2px; + background: var(--hp-accent); + border: 1px solid var(--card-background-color, #fff); + z-index: 2; + } + .rlhandle.tl { left: -6px; top: -6px; cursor: nwse-resize; } + .rlhandle.br { right: -6px; bottom: -6px; cursor: nwse-resize; } + .rlhandle.tr { right: -6px; top: -6px; cursor: nesw-resize; } + .rlhandle.bl { left: -6px; bottom: -6px; cursor: nesw-resize; } + :host([data-pointer-hover]) .stage.markup .roomlabel:hover .rlhandle { display: block; } + .stage.markup .roomlabel { pointer-events: auto; } + .roomlabel:active { cursor: grabbing; } + .measurelayer { + position: absolute; + inset: 0; + pointer-events: none; + } + .alignline { + stroke: var(--hp-accent); + stroke-width: calc(1.2px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(4px * var(--hp-cell-visual-scale, 1)) + calc(4px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + opacity: 0.9; + } + .aligndot { + fill: var(--hp-accent); + pointer-events: none; + } + .measurelabel.on45 { + color: #4bd28f; + border-color: #4bd28f; + } + .measurelabel { + position: absolute; + transform: translate(12px, -150%); + font-size: var(--fs-s); + font-weight: 600; + padding: 1px var(--sp-3); + border-radius: var(--rad-s); + background: rgba(0, 0, 0, 0.72); + color: #fff; + white-space: nowrap; + pointer-events: none; + user-select: none; + z-index: 3; + } + .measurelabel.opdimension { + transform: translate( + calc(-50% + var(--op-label-shift-x, 0px)), + calc(-50% + var(--op-label-shift-y, -12px)) + ); + border: 1px solid var(--hp-open, #ff9800); + } + /* decor (background) layer */ + .decorlayer .dshape { pointer-events: none; } + .stage.mode-decor .decorlayer .dshape { + pointer-events: visiblePainted; + cursor: pointer; + } + .stage.mode-decor.dtool-select .decorlayer .dshape { cursor: move; } + /* …but a DRAWING tool owns the canvas: existing shapes stop being targets + entirely, so a new line can start exactly on the end of an old one + instead of grabbing it (owner, 2026-08-04). Same for the picture tool — + a shape lying over the plan must not block the picture's own drag. + Only select (move) and erase (delete) keep the shapes clickable. */ + .stage.mode-decor.dtool-line .decorlayer .dshape, + .stage.mode-decor.dtool-rect .decorlayer .dshape, + .stage.mode-decor.dtool-ellipse .decorlayer .dshape, + .stage.mode-decor.dtool-text .decorlayer .dshape, + .stage.mode-decor.dtool-furniture .decorlayer .dshape, + .stage.mode-decor.dtool-backdrop .decorlayer .dshape { pointer-events: none; } + /* the furniture tool is a stamp: the press must reach the stage even when + it lands on a sofa that is already there (docs/FURNITURE.md §4) */ + .stage.mode-decor.dtool-furniture { cursor: copy; } + /* ONE exception (owner, 2026-08-04): under the TEXT tool an existing LABEL + is a target again — pressing it opens its editor instead of starting a + new label on top of the old one. Only labels: a line or a rectangle + under the text tool stays inert, so the press reaches the stage and a + new label is created there. */ + .stage.mode-decor.dtool-text .decorlayer .dshape.dtext, + .stage.mode-decor.dtool-select .decorlayer .dshape.dtext, + .stage.mode-decor.dtool-erase .decorlayer .dshape.dtext { + /* A label is one logical decor object. SVG's visiblePainted would hit + only the ink of individual glyphs, so spaces, counters and the area + inside its selection glow behaved like empty canvas. */ + pointer-events: visiblePainted; + pointer-events: bounding-box; + } + .stage.mode-decor.dtool-text .decorlayer .dshape.dtext { + cursor: text; + } + /* Erasing a hairline must not require pixel-perfect aim. The duplicate + geometry is invisible and exists only while Erase is active. A + non-scaling stroke keeps the target comfortably wide at every zoom. */ + .decorlayer .derasehit { + fill: none; + stroke: transparent; + stroke-width: 16px; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .stage.mode-decor.dtool-erase .decorlayer .derasehit { + pointer-events: stroke; + } + /* A dashed line must remain selectable across its gaps. This proxy also + makes the only entry to line-style properties — double click in Select — + practical for hairlines at every zoom. */ + .decorlayer .dselecthit { + fill: none; + stroke: transparent; + stroke-width: 16px; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .stage.mode-decor.dtool-select .decorlayer .dselecthit { + pointer-events: stroke; + cursor: move; + } + .decorlayer .dsel { + filter: drop-shadow(0 0 3px var(--hp-accent)); + } + .decorlayer .ddraft { + stroke-dasharray: + calc(6px * var(--hp-cell-visual-scale, 1)) + calc(5px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .decorlayer text { + font-weight: 600; + user-select: none; + dominant-baseline: middle; + text-anchor: middle; + } + .stage.mode-decor { + outline: 2px solid #26a69a; + outline-offset: -2px; + } + /* backdrop transform frame (docs/BACKDROP.md §2). Editor chrome: the + outline never takes a pointer, the four corner handles do — and they are + finger-sized (r = 2 % of the visible view), because this is dragged on a + tablet as often as with a mouse. */ + .bdframe .bdbox { + fill: none; + stroke: var(--hp-accent); + stroke-width: 2; + stroke-dasharray: 10 7; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.9; + } + /* the HIT circle: invisible, finger-sized, the only thing that takes a + pointer. The visible bead is .bdknob, a quarter of its radius — the same + visual/hit split .dthandle + .dtknob and .rszhandle + .rszicon use. */ + .bdframe .bdhandle { + fill: transparent; + stroke: none; + pointer-events: all; + touch-action: none; + } + .bdframe .bdknob { + fill: var(--hp-accent); + stroke: #fff; + stroke-width: 1; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + :host([data-pointer-hover]) .bdframe .bdhandle:hover + .bdknob { + fill: #fff; + stroke: var(--hp-accent); + } + .bdframe .bd-nwse { cursor: nwse-resize; } + .bdframe .bd-nesw { cursor: nesw-resize; } + /* the picture itself is the drag target for a move (grab, then grabbing) */ + .stage.mode-decor.bdgrab { cursor: grab; } + .stage.mode-decor.bdgrabbing, + .stage.mode-decor.bdgrabbing .bdframe .bdhandle { cursor: grabbing; } + .measurelabel.bdmeasure { + transform: translate(-50%, -50%); + border: 1px solid var(--hp-accent); + } + /* the selected decor object's frame — same chrome rules as the backdrop's: + the outline never takes a pointer, the handles always do, and they are + finger-sized because this is dragged on a tablet too */ + .dtframe .dtbox { + fill: none; + stroke: var(--hp-accent); + stroke-width: 1.5; + stroke-dasharray: 7 5; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.85; + } + .dtframe .dtstem, + .bdframe .dtstem { + stroke: var(--hp-accent); + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.85; + } + /* the HIT circle: invisible, finger-sized, the only thing that takes a + pointer. The visible bead is .dtknob, a quarter of its radius — the + same visual/hit split .rszhandle + .rszicon use. */ + .dtframe .dthandle { + fill: transparent; + stroke: none; + pointer-events: all; + touch-action: none; + } + .dtframe .dtknob { + fill: var(--hp-accent); + stroke: #fff; + stroke-width: 1; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + :host([data-pointer-hover]) .dtframe .dthandle:hover + .dtknob { + fill: #fff; + stroke: var(--hp-accent); + } + .dtframe .dt-nwse { cursor: nwse-resize; } + .dtframe .dt-nesw { cursor: nesw-resize; } + .dtframe .dtrot { cursor: grab; } + .dtframe .dtendpoint { cursor: crosshair; } + .bdframe .dtrot { cursor: grab; } + .dtarea { + resize: vertical; + min-height: 3.4em; + font: inherit; + line-height: 1.35; + } + .stage.mode-decor.dtool-line, .stage.mode-decor.dtool-rect, + .stage.mode-decor.dtool-ellipse, .stage.mode-decor.dtool-text { + cursor: crosshair; + } + .stage.mode-decor.dtool-erase, + .stage.mode-decor.dtool-erase .decorlayer .dshape { + cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Crect x='7' y='2' width='10' height='18' rx='2' fill='%23fff' stroke='%23111' stroke-width='1.5'/%3E%3Cpath d='M7 13h10v5a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2z' fill='%23ff9f43' stroke='%23111' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E") 5 22, pointer; + } + .stage.mode-decor .room, .stage.mode-decor .devlayer { pointer-events: none; } + .stage.mode-decor .oplock { pointer-events: none; } + /* Backdrop-editor de-emphasis is a shared mode-transition coordinate. + It multiplies whole presentation groups and never changes Glow source + alpha, additive blending, or the underlying resolved state. */ + .stage .room, + .stage .devlayer, + .stage .opening, + .stage .room-outline, + .stage .wallbodies, + .stage .opening-tunnels, + .stage .glow-base-layer, + .stage .glow-pools-frame, + .stage .zero-walls { + opacity: var(--hp-mode-architecture-opacity, 1); + } + .opening-preview { + opacity: 0.5; + pointer-events: none; + } + .opening-preview[data-kind="passage"] { + opacity: 1; + } + .passage-preview-cut { + fill: var(--wall-fill, #ffffff); + fill-opacity: 0.35; + stroke: none; + pointer-events: none; + } + .passage-preview-boundary { + stroke: var(--hp-open, #ff9800); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .opening-preview .op-leaf, + .opening-preview .op-arc { + transition: none; + } + .opening-preview-dot { + fill: var(--hp-open, #ff9800); + pointer-events: none; + } + .opening-dimensions, + .opening-dimension { + pointer-events: none; + } + .opening-dimension-line, + .opening-dimension-tick { + fill: none; + stroke: var(--hp-open, #ff9800); + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .opening-dimension-tick { + stroke-width: 2; + } + .stage.edit .room { + pointer-events: none; + } + .stage.markup { + cursor: crosshair; + } + /* room-picking stages: merge (both clicks) and split before a room is chosen */ + .stage.markup.tool-merge, + .stage.markup.tool-split.pickstage, + .stage.markup.tool-delroom { + cursor: pointer; + } + .stage.markup.tool-wallthick { cursor: default; } + .stage.markup.tool-wallthick.wallhot { cursor: pointer; } + /* Solid wall colour sits under the hatch (owner: both, not either/or). */ + .wallbody-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: var(--wall-fill-op, 1); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .wallbody { + fill: url(#hp-wall-hatch); + fill-rule: evenodd; + stroke: var(--room-stroke, var(--hp-muted)); + stroke-width: calc(0.6px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + /* Thin-on-screen: hatch collapses into noise — fill alone, stroke from fill path's sibling. */ + .wallbody.solid { + fill: none; + } + .wallthick-hover { + fill: var(--accent-color, #03a9f4); + fill-opacity: 0.38; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .wallthick-hover.isopen { + fill: var(--error-color, #f44336); + stroke: var(--error-color, #f44336); + } + .zero-wall { + stroke: var(--zero-wall-stroke, var(--hp-muted)); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(7px * var(--hp-cell-visual-scale, 1)) + calc(7px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: butt; + pointer-events: none; + opacity: 0.9; + } + .zero-walls.solid .zero-wall { + stroke-dasharray: none; + } + /* Rooms with zero/thick stretches: the polygon's own stroke is fully off. + The trimmed .room-outline draws normal walls; View hover gets its own + top overlay after the wall bodies. */ + .room.noedge { + stroke-opacity: 0 !important; + } + /* rooms with open boundaries draw their walls as separate M..L subpaths, + so a corner between two of them is two stroke ENDS meeting: round caps + fill it in the same way a round join fills a closed contour's corner + (owner 2026-08-04 — no teeth anywhere on a room border). */ + .room-outline { + fill: none; + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + /* Plan editor: trimmed outlines use the markup blue */ + .room-outline.outlined { + stroke: rgba(62, 166, 255, 0.55); + stroke-opacity: 1; + } + /* The wash is rendered directly above the resolved room fill but below + tunnels, Glow, sun and walls. Black at 22% reproduces the old + brightness(.78) contract without filtering/promoting an SVG ancestor or + changing the room's hue. The halo/outline are rendered again late, above + the wall bodies. */ + .room-hover-fill { + fill: #000; + fill-opacity: 0.22; + pointer-events: none; + } + .room-hover-halo { + fill: none; + stroke: var(--hp-accent); + stroke-opacity: 0.28; + stroke-width: calc(8px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .room-hover-outline { + fill: none; + stroke: var(--hp-accent); + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .stage.markup .room { + pointer-events: none; + } + .stage.markup .devlayer .dev { + display: none; /* in plan mode the icons do not get in the way; labels stay */ + } + /* mode frames: the edit modes are visible at a glance */ + .stage.mode-plan { + outline: 2px solid #ffc14d; + outline-offset: -2px; + } + .stage.mode-devices { + outline: 2px solid var(--hp-accent); + outline-offset: -2px; + } + .room.outlined { + stroke: rgba(62, 166, 255, 0.55); + fill: rgba(62, 166, 255, 0.06); + } + /* AFTER .outlined: same specificity — source order decides (gotcha x4) */ + .room.picked { + stroke: #ffc14d; + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + fill: rgba(255, 193, 77, 0.25); + } + /* Owner 2026-08-04: the grid is a HINT, not content — at full strength the + dots argued with the plan on white paper. Both levels are muted, the + hierarchy is kept (major still denser than fine). */ + .griddot { + fill: var(--hp-accent); + opacity: 0.35; + stroke: rgba(0, 0, 0, 0.35); + stroke-width: 0.4; + } + /* docs/CANVAS.md §7: every coarse node (5x/10x the live step) keeps a + bigger, more opaque dot, so zoomed far out the grid still reads as a + grid instead of a grey wash. */ + .griddot.major { + opacity: 0.5; + stroke-width: 0; + } + /* the contour being drawn in the Plan editor: each wall is its own , + so the round cap IS the corner (matches the finished .room border) */ + .seg { + stroke: var(--hp-accent); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: round; + stroke-linejoin: round; + } + .pathline { + stroke: #ffc14d; + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + } + .preview { + stroke: #ffc14d; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(6px * var(--hp-cell-visual-scale, 1)) + calc(5px * var(--hp-cell-visual-scale, 1)); + opacity: 0.7; + } + .active-axis { + stroke: #ffc14d; + stroke-width: 2; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .active-vertex { + fill: #ffc14d; + stroke: #171006; + stroke-width: 2; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .wall-repair-preview { + stroke: #d93025; + stroke-width: 4; + stroke-linecap: round; + stroke-dasharray: 5 4; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .drawwall-preview-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: calc(var(--wall-fill-op, 1) * 0.55); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .drawwall-preview { + fill: url(#hp-wall-hatch); + fill-opacity: 0.55; + fill-rule: evenodd; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(0.5px * var(--hp-cell-visual-scale, 1)); + stroke-opacity: 0.7; + pointer-events: none; + } + .drawwall-zero-preview { + fill: none; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: butt; + stroke-linejoin: round; + opacity: 0.72; + pointer-events: none; + } + .drawwall-zero-preview.dashed { + stroke-dasharray: + calc(7px * var(--hp-cell-visual-scale, 1)) + calc(7px * var(--hp-cell-visual-scale, 1)); + } + .vertex { + fill: #ffc14d; + stroke: #4a2800; + stroke-width: calc(1px * var(--hp-cell-visual-scale, 1)); + } + .vertex.first { + fill: #4bd28f; + stroke: #04121f; + } + .plan-snap-overlay, + .plan-snap-overlay *, + .hidden-wall-diagnostic, + .hidden-wall-diagnostic * { + pointer-events: none; + } + .plan-snap-line, + .hidden-wall-line { + fill: none; + stroke: color-mix(in srgb, var(--hp-accent) 82%, white 18%); + /* Explicit non-scaling-stroke in the SVG keeps this one screen pixel. */ + stroke-width: 1; + stroke-linecap: round; + opacity: 0.92; + } + .plan-snap-node, + .hidden-wall-node { + fill: var(--ha-card-background, var(--card-background-color, #fff)); + stroke: color-mix(in srgb, var(--hp-accent) 88%, #07131c 12%); + stroke-width: 1; + vector-effect: non-scaling-stroke; + } + .plan-snap-node.active { + fill: #ffc14d; + stroke: #171006; + stroke-width: 2; + } + .plan-snap-node.active.dynamic { + fill: #4bd28f; + stroke: #04121f; + } + .plan-snap-node.conflict { + fill: #fff; + stroke: #d93025; + stroke-width: 3; + } + @media (prefers-color-scheme: dark) { + .plan-snap-line { + stroke: color-mix(in srgb, var(--hp-accent) 72%, white 28%); + } + .hidden-wall-line { + stroke: color-mix(in srgb, var(--hp-accent) 72%, white 28%); + } + .plan-snap-node, + .hidden-wall-node { + fill: #17242c; + stroke: #9bdcf5; + } + .plan-snap-node.active { + fill: #ffc14d; + stroke: #fff4d6; + } + .plan-snap-node.active.dynamic { + fill: #4bd28f; + stroke: #eafff4; + } + } + @media (forced-colors: active) { + .plan-snap-line, + .hidden-wall-line { + stroke: CanvasText; + opacity: 1; + forced-color-adjust: auto; + } + .plan-snap-node, + .hidden-wall-node { + fill: Canvas; + stroke: CanvasText; + forced-color-adjust: auto; + } + .plan-snap-node.active, + .plan-snap-node.active.dynamic { + fill: Highlight; + stroke: HighlightText; + forced-color-adjust: auto; + } + } + /* RGB lights: the bulb takes the light's actual color */ + /* v1.52.0: the RGB tint of the icon/border is gone — a lamp's colour + lives ONLY in its glow spot (owner's rule). The ripple-color fallback + keeps using the light colour; that is set inline via --ripple-color. */ + /* Sun wedges (docs/SUN.md). The layer is present ONLY above the 3° + threshold; crossing it fades the whole layer in or out over EXACTLY + 2 s (owner 2026-08-03 — RAY_FADE_MS in src/sun.ts must match). The + geometry is untouched: this is a plain opacity animation on the group, + so overlapping wedges keep their own blending while it plays. */ + .sunlayer { + animation: hp-sunfade-in 2s linear both; + } + .sunlayer.out { + animation: hp-sunfade-out 2s linear both; + } + @media (prefers-reduced-motion: reduce) { + /* no fade at all: the rays are simply there or simply gone */ + .sunlayer, .sunlayer.out { animation: none; } + .sunlayer.out { opacity: 0; } + } + .devlayer { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 6; + } + .stage.mode-devices .dev { cursor: grab; } + .stage.mode-devices .dev:active { cursor: grabbing; } + .physical-hit { + fill: transparent; + stroke: transparent; + pointer-events: none; + cursor: grab; + } + .stage.tool-select .physical-hit { pointer-events: all; } + .physical-hit:active { cursor: grabbing; } + line.physical-hit { cursor: pointer; } + .physical-hit.selected { + fill: rgba(255, 193, 77, 0.24); + stroke: transparent; + } + line.physical-hit.selected { + stroke: transparent; + } + .physical-drag { + fill: rgba(255, 193, 77, 0.38); + stroke: #ffc14d; + stroke-width: 2.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .physical-chrome { pointer-events: none; } + .physical-chrome .frame, + .physical-chrome .stem { + fill: none; + stroke: #ffc14d; + stroke-width: 2; + vector-effect: non-scaling-stroke; + } + .physical-chrome .frame { fill: rgba(255, 193, 77, 0.22); } + .physical-chrome polyline.frame { fill: none; } + .physical-chrome .move-dot { + fill: #ffc14d; + stroke: #24262d; + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + } + .physical-chrome .rotate-handle { + fill: #24262d; + stroke: #ffc14d; + stroke-width: 2.5; + vector-effect: non-scaling-stroke; + pointer-events: all; + cursor: crosshair; + } + .drawwall.invalid input { border-color: var(--error-color, #db4437); } + .drawwall .rangehint { margin-inline-start: 4px; font-size: 0.78em; opacity: 0.72; } + .drawwall.invalid .rangehint { color: var(--error-color, #db4437); opacity: 1; } + .stage.markup.tool-partition, + .stage.markup.tool-column { cursor: crosshair; } + /* room resize tool (docs/RESIZE.md) */ + /* wall handle: invisible finger-sized hit circle (HP-1550-04 hit priority + kept), the visible glyph lives in the sibling .rszicon */ + .rszhandle { + fill: transparent; + stroke: none; + pointer-events: all; + cursor: grab; + touch-action: none; + } + .rszhandle:active { cursor: grabbing; } + .rszhandle.disabled, + .rszhandle.disabled:active { + cursor: not-allowed; + } + /* wall-with-arrows glyph: accent ink over a bg halo, readable on any plan */ + .rszicon { pointer-events: none; } + .rszicon path { + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; + } + .rszhalo { stroke: var(--hp-bg); stroke-width: 6; } + .rszink { stroke: var(--hp-accent); stroke-width: 2; } + :host([data-pointer-hover]) .rszhandle:hover + .rszicon .rszink { stroke-width: 3; } + .rszicon.disabled { opacity: 0.38; } + :host([data-pointer-hover]) .rszhandle.disabled:hover + .rszicon .rszink { stroke-width: 2; } + .rszmeasurelayer, + .rszmeasurelayer * { pointer-events: none; } + .rszmeasurehalo, + .rszmeasureink, + .rszleader { + fill: none; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + } + .rszmeasurehalo { + stroke: var(--hp-bg); + stroke-width: 7px; + opacity: 0.9; + } + .rszmeasureink { + stroke: var(--hp-accent); + stroke-width: 3px; + } + .rszleader { + stroke: var(--hp-accent); + stroke-width: 2px; + opacity: 0.95; + } + /* the decor draft badge rides the MIDDLE of the shape, so it is centred + horizontally and lifted clear of the line instead of trailing the + cursor the way a wall badge does (owner 2026-08-04) */ + .measurelabel.dmeasure { + transform: translate(-50%, -160%); + } + .measurelabel.rszarea { + transform: translate( + calc(-50% + var(--rsz-label-x, 0px)), + calc(-50% + var(--rsz-label-y, 0px)) + ); + background: rgba(0, 0, 0, 0.6); + border: 1px solid var(--hp-accent); + } + /* width and depth of a piece of furniture while its corner is dragged — + centred on the edge they measure (docs/FURNITURE.md §6) */ + .measurelabel.furnmeasure { + transform: translate(-50%, -50%); + border: 1px solid var(--hp-accent); + } + .alignmsg { margin: 0 0 8px; font-size: 13px; line-height: 1.45; } +`,o` + /* Unified device activity: alarm, short event and continuous state all + share this one renderer. No static rings are allowed. */ + .dev ha-icon { + position: relative; + z-index: 1; + } + .device-pulse { + position: absolute; + left: 50%; + top: 50%; + width: var(--dev-size); + height: var(--dev-size); + transform: translate(-50%, -50%); + pointer-events: none; + z-index: 0; + } + .device-pulse i { + position: absolute; + inset: 0; + border-radius: 50%; + border: 2px solid var(--ripple-color, var(--hp-accent)); + opacity: 0; + } + /* A witnessed edge: exactly three waves over the 3.3 s runtime window. */ + .device-pulse.short i { + animation: hp-pulse-short 1.1s cubic-bezier(.22,.61,.36,1) 1 forwards; + } + .device-pulse.short i:nth-child(2) { animation-delay: 1.1s; } + .device-pulse.short i:nth-child(3) { animation-delay: 2.2s; } + .device-pulse.short.gen2 i { animation-name: hp-pulse-short-b; } + .device-pulse.continuous i:nth-child(n + 2), + .device-pulse.alarm i:nth-child(n + 3) { display: none; } + .device-pulse.continuous i:first-child { + animation: hp-pulse-continuous 3.6s cubic-bezier(.45,.05,.55,.95) infinite; + } + .device-pulse.alarm i { + border-width: 3px; + border-color: #F0410C; + animation: hp-pulse-alarm 2.4s cubic-bezier(.22,.61,.36,1) infinite; + } + .device-pulse.alarm i:nth-child(2) { animation-delay: 1.2s; } + .activity-dot { + position: absolute; + right: 8%; + bottom: 8%; + width: 18%; + height: 18%; + min-width: 4px; + min-height: 4px; + border-radius: 50%; + background: var(--ripple-color, var(--hp-accent)); + border: 1px solid color-mix(in srgb, var(--hp-bg) 82%, transparent); + pointer-events: none; + z-index: 3; + } + .kioskdots { + position: absolute; + left: 50%; + bottom: var(--sp-5); + transform: translateX(-50%); + display: flex; + gap: var(--sp-4); + z-index: 5; + pointer-events: none; + } + .kdot { + width: 9px; + height: 9px; + border-radius: 50%; + background: var(--hp-muted); + opacity: 0.55; + } + .kdot.on { background: var(--hp-accent); opacity: 1; } + .dev.valonly { + /* Saved coordinates remain the centre of a Text shell. The shell may + expand, while the invisible anchor stays one core diameter wide. */ + width: var(--dev-size, var(--icon-size, 2.5cqw)); + } + .dev.valonly .device-core { + width: max-content; + min-width: var(--dev-size, var(--icon-size, 2.5cqw)); + padding-inline: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.16); + border-radius: calc(var(--dev-size, var(--icon-size, 2.5cqw)) / 2); + } + .dev .valtext { + overflow: visible; + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * var(--value-font-scale, .45)); + font-weight: 600; + white-space: nowrap; + } + @media (prefers-reduced-motion: reduce) { + .device-pulse { display: none; } + } + .dev .newdot { + position: absolute; + top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * -0.12); + right: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * -0.12); + width: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.34); + height: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.34); + border-radius: 50%; + background: #f0301f; + border: 2px solid var(--card-background-color, var(--hp-bg)); + pointer-events: none; + z-index: 2; + } + .dev { + position: absolute; + /* The surface resolves compatibility icon_size units once. The shared + face receives an effective base and only applies the per-device size. */ + --dev-size: calc(var(--device-base-size, 2.25cqw) * var(--dev-scale, 1)); + /* 101.5/80 is the package shell/core ratio, including its stroke. */ + --device-shell-size: calc(var(--dev-size) * 1.26875); + --device-shell-inset: calc(var(--dev-size) * 0.134375); + --device-shell-stroke-ratio: 0.01875; + --device-shell-border-width: max(1px, calc(var(--dev-size) * var(--device-shell-stroke-ratio))); + --device-core-bg: var(--card-background-color, #fff); + --device-core-fg: var(--primary-text-color, #252525); + --device-core-bg: light-dark(#fff, #252525); + --device-core-fg: light-dark(#252525, #fff); + --device-face-bg: var(--device-core-bg); + --device-face-fg: var(--device-core-fg); + --device-shell-base-stroke: light-dark(#BCBCBC, rgb(37 37 37 / 75%)); + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: 0 0 0 0 transparent; + --device-ring-color: transparent; + --device-ring-width: 0px; + /* The saved point is the exact centre of the icon core. */ + width: var(--dev-size); + height: var(--dev-size); + margin: calc(var(--dev-size) / -2) 0 0 calc(var(--dev-size) / -2); + border: 0; + background: transparent; + display: block; + color: var(--device-core-fg); + cursor: pointer; + pointer-events: auto; + transition: opacity 0.2s; + box-shadow: none; + outline: none; + z-index: 2; + } + .dev.theme-light { + --device-core-bg: #fff; + --device-core-fg: #000; + --device-shell-base-stroke: #BCBCBC; + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: 0 0 0 0 transparent; + } + .dev.theme-dark { + --device-core-bg: #252525; + --device-core-fg: #fff; + --device-shell-base-stroke: rgb(37 37 37 / 75%); + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .0375) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: + inset 0 calc(var(--dev-size) * 0.0125) calc(var(--dev-size) * 0.0125) rgb(255 255 255 / 70%); + } + .dev::before { + content: ''; + position: absolute; + left: 50%; + top: 50%; + width: max(44px, var(--device-shell-size)); + height: max(44px, var(--device-shell-size)); + transform: translate(-50%, -50%); + border-radius: 50%; + pointer-events: auto; + z-index: 3; + } + .device-shell { + position: absolute; + box-sizing: border-box; + display: flex; + align-items: center; + gap: calc(var(--dev-size) * 0.1); + padding: 0; + min-width: var(--dev-size); + min-height: var(--dev-size); + border: 0; + background: transparent; + box-shadow: none; + transition: opacity .2s; + pointer-events: none; + } + .device-shell-frame { + position: absolute; + z-index: 0; + box-sizing: border-box; + inset: calc(var(--device-shell-inset) / -1); + border: var(--device-shell-border-width) solid var(--device-shell-stroke); + /* A saturating radius is resolved from the final border box. Using a + second fractional length here lets border-box and radius quantise on + different sides of a device pixel at some zoom/DPR combinations. */ + border-radius: 9999px; + background: transparent; + box-shadow: var(--device-shell-shadow); + transition: border-color .15s, box-shadow .15s, opacity .2s; + pointer-events: auto; + /* Normative production fallback: never add a per-marker backdrop blur. */ + backdrop-filter: none; + } + .device-shell:not(.with-values) { + left: 0; + top: 0; + } + .device-shell:not(.with-values):not(.text-shell) .device-shell-frame { + border-radius: 50%; + } + .device-shell.with-values.pos-right { + left: 0; + top: 50%; + transform: translateY(-50%); + } + .device-shell.with-values.pos-left { + right: 0; + top: 50%; + transform: translateY(-50%); + flex-direction: row-reverse; + } + .device-shell.with-values.pos-bottom { + left: 50%; + top: 0; + transform: translateX(-50%); + flex-direction: column; + } + .device-shell.with-values.pos-top { + left: 50%; + bottom: 0; + transform: translateX(-50%); + flex-direction: column-reverse; + } + .device-core { + position: relative; + z-index: 1; + box-sizing: border-box; + flex: 0 0 auto; + width: var(--dev-size); + height: var(--dev-size); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background: var(--device-face-bg); + color: var(--device-face-fg); + box-shadow: + var(--device-core-inset-shadow), + 0 0 0 var(--device-ring-width) var(--device-ring-color); + line-height: 0; + transition: background .15s, color .15s, box-shadow .15s, opacity .2s; + pointer-events: none; + } + .device-sections { + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: center; + gap: calc(var(--dev-size) * .08); + min-width: 0; + pointer-events: none; + } + .device-shell.pos-top .device-sections, + .device-shell.pos-bottom .device-sections { + flex-direction: row; + } + .dev ha-icon { + /* from --dev-size, NOT --icon-size: the per-device size multiplier must + scale the GLYPH with its badge. Pinned to the base size, "make this + icon bigger" grew an empty box around a default-size glyph (user + report via the owner, 2026-07-29). */ + --mdc-icon-size: calc(var(--dev-size, var(--device-base-size, 2.25cqw)) * 0.55); + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + } + .dev.on { + --device-face-bg: #F0A00C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0A00C; + } + .dev.theme-light.on { --device-face-fg: #fff; } + .dev.theme-dark.on { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .0375; + } + .dev.open { + --device-face-bg: var(--hp-open); + --device-face-fg: light-dark(#fff, #252525); + } + .dev.theme-light.open { --device-face-fg: #fff; } + .dev.theme-dark.open { --device-face-fg: #252525; } + .dev.lock-locked { + --device-face-bg: #66D17A; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #66D17A; + } + .dev.theme-light.lock-locked { --device-face-fg: #fff; } + .dev.theme-dark.lock-locked { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + .dev.lock-unlocked { + --device-face-bg: #F0410C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0410C; + } + .dev.theme-light.lock-unlocked { --device-face-fg: #fff; } + .dev.theme-dark.lock-unlocked { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + /* Interaction wins ordinary state colours. Alarm keeps priority through + the more-specific rule below. Unavailable has no visual hover. */ + :host([data-pointer-hover]) .dev:not(.unavail):hover { + --device-face-bg: #0C82F0; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: var(--device-shell-base-stroke); + } + :host([data-pointer-hover]) .dev.theme-light:not(.unavail):hover { --device-face-fg: #fff; } + :host([data-pointer-hover]) .dev.theme-dark:not(.unavail):hover { --device-face-fg: #252525; } + :host([data-pointer-hover]) .dev:hover, + .dev:focus-visible { z-index: 5; } + .dev.unavail { + opacity: 0.35; + --device-face-bg: #B5BAC1; + --device-shell-stroke: var(--device-shell-base-stroke); + } + .dev.virtual .device-shell-frame { + border-style: dashed; + } + /* "hide from plan" flag, shown only in the device editor with the + "show hidden devices" toggle on (docs/FILTERING.md). BLUE, so a hidden + device cannot be mistaken for an unavailable one (translucent dark) — + and no live-state paint at all: a ghost is configuration, not status + (owner's request). */ + .dev.ghost { + opacity: 0.6; + color: var(--hp-accent); + } + .dev.ghost .device-shell-frame { + border-style: dashed; + border-color: var(--hp-accent); + box-shadow: none; + } + .dev.ghost .device-core { + background: rgba(62, 166, 255, 0.22); /* fallback for old WebViews */ + background: color-mix(in srgb, var(--hp-accent) 30%, var(--card-background-color, #1c2530)); + color: var(--hp-accent); + } + /* HA-disabled is not a user hide: neutral grey + a power-off badge keeps + the two ghosts distinguishable without relying on colour alone. */ + .dev.ghost.ha-disabled { + opacity: 0.62; + color: var(--secondary-text-color, #9aa0aa); + } + .dev.ghost.ha-disabled .device-shell-frame { + border-color: var(--secondary-text-color, #9aa0aa); + } + .dev.ghost.ha-disabled .device-core { + background: rgba(120, 124, 134, 0.2); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 24%, var(--card-background-color, #1c2530)); + color: var(--secondary-text-color, #9aa0aa); + } + .dev .habadge { + position: absolute; + right: -18%; + bottom: -18%; + display: grid; + place-items: center; + width: 46%; + height: 46%; + min-width: 12px; + min-height: 12px; + border-radius: 50%; + background: var(--card-background-color, #242832); + border: 1px solid currentColor; + } + .dev .habadge ha-icon { width: 72%; height: 72%; } + .dev.sel { + --device-ring-color: #F0A00C; + --device-ring-width: calc(var(--dev-size) * 0.0375); + } + .dev:focus-visible { + --device-ring-color: #0C82F0; + --device-ring-width: calc(var(--dev-size) * 0.0375); + } + .dev:not(.on):not(.open):not(.alarm):not(.lock-locked):not(.lock-unlocked):not(.unavail):focus-visible { + --device-face-fg: #0C82F0; + } + /* Alert stays above focus, selection, hover and ordinary semantic paint. */ + .dev.alarm, + :host([data-pointer-hover]) .dev.alarm:hover, + .dev.alarm:focus-visible { + --device-face-bg: #F0410C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0410C; + } + .dev.theme-light.alarm { --device-face-fg: #fff; } + .dev.theme-dark.alarm { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + .dev .value-badge { + position: relative; + z-index: 2; + box-sizing: border-box; + width: max-content; + min-width: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * .7875); + height: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * .7875); + display: flex; + align-items: center; + justify-content: center; + overflow: visible; + background: var(--device-core-bg); + border: 0; + border-radius: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.39375); + padding: 0 calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.14); + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * var(--value-font-scale, .45)); + font-weight: 600; + line-height: 1; + color: var(--device-core-fg); + white-space: nowrap; + pointer-events: none; + } + .dev .value-badge.unavailable, + .dev .value-badge.missing { opacity: 0.66; } + .dev .lqi { + position: absolute; + top: calc(50% + var(--device-shell-size) / 2 + var(--dev-size) * .05); + left: 50%; + transform: translateX(-50%); + margin-top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.05); + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.38); + font-weight: 600; + line-height: 1; + text-shadow: 0 0 3px rgba(0, 0, 0, 0.9), 0 0 2px rgba(0, 0, 0, 0.9); + white-space: nowrap; + pointer-events: none; + } + .dev .lqi.below-value-badge { + margin-top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.8875); + } + .temprange { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + margin-left: auto; + color: var(--hp-muted); + font-size: var(--fs-s); + } + /* live vacuum: a round puck, no badge plate, soft pulse (docs/VACUUM.md) */ + .vacpuck { + position: absolute; + /* the base badge, but round and 20% smaller — the owner's wording: + «иконка похожа на иконку базы, только круглая и чуть меньше» */ + --puck-size: calc(var(--device-base-size, 2.25cqw) * 0.8); + width: var(--puck-size); + height: var(--puck-size); + border-radius: 50%; + transform: translate(-50%, -50%); + --vac-core-bg: light-dark(#fff, #252525); + --vac-core-fg: light-dark(#252525, #fff); + background: var(--vac-core-bg); + border: 1px solid #BCBCBC; + box-shadow: + 0 1px 2px rgb(37 40 45 / 12%), + 0 4px 8px -1.07px rgb(37 40 45 / 18%); + color: var(--vac-core-fg); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 6; + /* glide between sparse position updates; .jump disables it so the robot + never appears to drive through walls after a data gap */ + transition: left 1.2s linear, top 1.2s linear; + animation: vacpulse 2.2s ease-out infinite; + } + .vacpuck.theme-light { --vac-core-bg: #fff; --vac-core-fg: #252525; } + .vacpuck.theme-dark { --vac-core-bg: #252525; --vac-core-fg: #fff; } + .vacpuck.jump { transition: none; } + .vacpuck.stale { opacity: 0.45; animation: none; } + .vacpuck ha-icon { + --mdc-icon-size: calc(var(--puck-size) * 0.68); + color: var(--vac-core-fg); + /* same centering recipe as .dev ha-icon: without flex + line-height 0 + the glyph sits on its text baseline and appears to float around the + circle (owner report 2026-07-31) */ + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + width: var(--mdc-icon-size); + height: var(--mdc-icon-size); + } + @keyframes vacpulse { + 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--hp-accent) 45%, transparent); } + 70% { box-shadow: 0 0 0 12px transparent; } + 100% { box-shadow: 0 0 0 0 transparent; } + } + @media (prefers-reduced-motion: reduce) { + .vacpuck { animation: none; } + } + .vactrail { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 5; + overflow: visible; + } + .vactrail polyline, + .vactrail path { + fill: none; + stroke-linejoin: round; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + } + /* dark halo + light core: neutral, and one of the two always contrasts + with whatever fill is underneath */ + .vactrail g.prev { opacity: 0.4; } + .vactrail .case { + stroke: rgba(0, 0, 0, 0.4); + stroke-width: 2.25; + } + .vactrail .core { + stroke: rgba(255, 255, 255, 0.82); + stroke-width: 0.9; + } + .devicepreview-empty { + min-height: 82px; + margin: 4px 0 14px; + padding: var(--sp-4); + display: flex; + align-items: center; + justify-content: center; + gap: var(--sp-3); + border: 1px dashed var(--hp-line); + border-radius: var(--rad-m); + color: var(--hp-muted); + text-align: center; + } +`,o` + .hdr { + position: sticky; + top: var(--header-height, 56px); + z-index: 20; + background: var(--card-background-color, var(--hp-bg)); + border-radius: var(--ha-card-border-radius, 12px) var(--ha-card-border-radius, 12px) 0 0; + } + .tabs { + display: flex; + gap: var(--sp-2); + background: rgba(127, 127, 127, 0.12); + padding: var(--sp-2); + border-radius: var(--rad-l); + flex-wrap: wrap; + } + .tab { + border: 0; + background: transparent; + color: var(--hp-muted); + display: inline-flex; + align-items: center; + padding: var(--sp-3) var(--sp-5); + border-radius: var(--rad-m); + font-size: var(--fs-m); + font-weight: 600; + cursor: pointer; + transition: 0.15s; + font-family: inherit; + } + :host([data-pointer-hover]) .tab:hover { + color: var(--hp-txt); + } + .tab.active { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + /* docs/CANVAS.md §4.1: objects an order of magnitude away from the plan + do not decide the opening view — one quiet chip says so and offers to + take them in. Never a modal (owner). */ + .farhint { + position: absolute; + left: 50%; + transform: translateX(-50%); + bottom: var(--sp-4); + z-index: 12; + display: flex; + align-items: center; + gap: var(--sp-2); + max-width: calc(100% - var(--sp-8)); + background: var(--card-background-color, var(--hp-bg)); + opacity: 0.94; + color: var(--hp-txt); + border: 1px solid var(--divider-color, #33404d); + border-radius: var(--rad-m); + padding: var(--sp-1) var(--sp-3); + font-size: var(--fs-s); + } + .farhint ha-icon { + --mdc-icon-size: 18px; + color: var(--hp-warn, #e2a03f); + flex: none; + } + .farhint span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .dropbtn { + display: flex; + align-items: center; + gap: var(--sp-4); + width: 100%; + text-align: left; + border: 1px solid var(--hp-muted); + border-radius: var(--rad-m); + background: transparent; + color: var(--hp-txt); + padding: var(--sp-4) 10px; + cursor: pointer; + font-family: inherit; + font-size: var(--fs-m); + margin-top: var(--sp-3); + } + .dropbtn .ref { color: var(--hp-muted); font-size: var(--fs-s); margin-left: auto; } + .dropbtn ha-icon { --mdc-icon-size: 18px; margin-left: var(--sp-2); } + .dropbtn.open { border-color: var(--hp-accent); } + .droppanel { + border: 1px solid var(--hp-accent); + border-top: none; + border-radius: 0 0 var(--rad-m) var(--rad-m); + padding: var(--sp-3); + margin-top: -4px; + } + .hdr.kioskhide { display: none; } + .decorbar .dcolor { + width: 30px; height: 26px; padding: 0; border: none; background: none; cursor: pointer; + } + .decorbar .dwidth { + font-family: inherit; font-size: var(--fs-s); border-radius: var(--rad-s); + background: var(--hp-bg2, transparent); color: var(--hp-txt); border: 1px solid var(--hp-muted); + padding: var(--sp-2) var(--sp-3); + } + .decorbar .bdhint { + font-size: var(--fs-s); + color: var(--hp-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .decorbar .dfill { + display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-s); cursor: pointer; + } + .decorbar .dfill input[type="checkbox"] { + width: 16px; + height: 16px; + flex: none; + margin: 0; + padding: 0; + } + .decorbar hp-color-opacity { flex: 0 0 auto; } + .modes { + display: inline-flex; + gap: var(--sp-1); + background: rgba(127, 127, 127, 0.12); + border-radius: var(--rad-l); + padding: var(--sp-2); + } + .modetab { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + border: 0; + background: transparent; + color: var(--hp-muted); + padding: var(--sp-3) 10px; /* 10px h-padding kept: +2px would wrap the header modes row */ + border-radius: var(--rad-m); + font-size: var(--fs-m); + font-weight: 600; + cursor: pointer; + font-family: inherit; + transition: background-color 0.14s ease, color 0.14s ease, transform 0.14s ease; + } + .modetab:active { transform: scale(0.97); } + .modetab ha-icon { --mdc-icon-size: 15px; } + /* issue #220: a tab can be dragged to a new position in the editors */ + .tab[data-reorderable] { cursor: grab; } + .tab.dragging { cursor: grabbing; opacity: 0.55; } + .tab.drop-before { box-shadow: inset 2px 0 0 0 var(--primary-color, #03a9f4); } + .tab.drop-after { box-shadow: inset -2px 0 0 0 var(--primary-color, #03a9f4); } + .modetab .closex { + --mdc-icon-size: 13px; + box-sizing: border-box; + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + min-width: 24px; + min-height: 24px; + /* Keep the old 13 × 13 flex footprint (+2 px left margin) while the + pointer target grows around it. Header width, height and wrapping do + not move; only near-misses that used to hit the active tab reach X. */ + margin: -5.5px -5.5px -5.5px -3.5px; + opacity: 0.75; + cursor: pointer; + border-radius: var(--rad-s); + } + :host([data-pointer-hover]) .modetab .closex:hover { opacity: 1; } + .editbar .barclose { + box-sizing: border-box; + width: 40px; + height: 40px; + padding: 0; + margin: 0; + min-width: 40px; + min-height: 40px; + justify-content: center; + gap: 0; + line-height: 0; + } + .editbar .barclose ha-icon { flex: none; margin: 0; } + .modetab.active { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + @media (max-width: 720px) { + .modetab .ml { display: none; } + } + .editbar { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: stretch; + border-bottom: 1px solid var(--hp-line); + font-size: var(--fs-m); + } + .editbar-tools { + display: flex; + align-items: center; + gap: 10px; + padding: var(--sp-4) var(--sp-5); + flex-wrap: wrap; + min-width: 0; + outline: none; + } + .editbar-end { + display: flex; + align-items: center; + padding: var(--sp-4) var(--sp-5); + border-inline-start: 1px solid var(--hp-line); + background: var(--card-background-color, var(--hp-bg)); + position: relative; + z-index: 2; + } + .tab .tabedit { + --mdc-icon-size: 13px; + display: inline-flex; + align-items: center; + margin-left: var(--sp-3); + opacity: 0.4; + } + :host([data-pointer-hover]) .tab:hover .tabedit { + opacity: 0.9; + } + .tab.tabadd { + padding: var(--sp-3) var(--sp-4); + } + .tab.tabadd ha-icon { + --mdc-icon-size: 15px; + } + .rhint { + font-size: var(--fs-s); + color: var(--hp-muted); + margin-bottom: var(--sp-3); + } + .togglehint { + overflow-wrap: anywhere; + } + .togglehint > div + div { + margin-top: var(--sp-1); + } + /* Keep the last editor bar mounted while the row collapses. This makes + both entering and leaving an editor change the card geometry gradually; + the header ResizeObserver keeps the stage fitted throughout. */ + .editorchrome { + display: block; + height: 0; + opacity: 0; + visibility: hidden; + overflow: hidden; + } + .editorchrome:not(.open) { + pointer-events: none; + } + .editorchrome.open { + height: auto; + opacity: 1; + visibility: visible; + overflow: visible; + } + .editorchrome.transitioning { + overflow: hidden; + will-change: height; + pointer-events: none; + } + /* The toolbar is already visible while its height is interpolating. Its + explicit navigation control must remain usable even though all editing + tools stay frozen until the transition settles. */ + .editorchrome.transitioning .barclose { + pointer-events: auto; + } + .editorchrome-inner { + min-height: 0; + transform-origin: top center; + } + .editorchrome.transitioning .editorchrome-inner { + will-change: opacity; + } + @media (prefers-reduced-motion: reduce) { + .modetab { transition: none; } + } + .editbar .warn { + color: #ffc14d; + } + .editbar .sname { + font-weight: 600; + } + .editbar input { + width: 74px; + background: transparent; + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + } + .editbar label, + .editbar .hint { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editbar .drawwall { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .editbar .wallsgroup { + display: inline-flex; + align-items: center; + gap: 10px; + white-space: nowrap; + } + .editbar .drawwall input { + width: 4.2em; + } + .editbar .drawwall .opl { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .menuwrap { + position: fixed; + inset: 0; + z-index: 80; + } + .menu { + position: fixed; + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-l); + box-shadow: var(--shadow-2); + min-width: 210px; + max-width: 300px; + overflow: hidden; + transform: translate(0, 8px); + } + .menu .hd { + padding: var(--sp-4) var(--sp-5); + font-weight: 600; + font-size: var(--fs-m); + border-bottom: 1px solid var(--hp-line); + display: flex; + align-items: center; + gap: var(--sp-3); + } + .menu .hd ha-icon, + .menu .it.all ha-icon { + color: var(--hp-accent); + --mdc-icon-size: 16px; + } + .menu .it { + padding: var(--sp-4) var(--sp-5); + font-size: var(--fs-m); + cursor: pointer; + display: flex; + align-items: center; + gap: var(--sp-4); + } + .menu .it ha-icon { + --mdc-icon-size: 16px; + color: var(--hp-muted); + } + :host([data-pointer-hover]) .menu .it:hover { + background: rgba(127, 127, 127, 0.15); + } + .menu .it.all { + color: var(--hp-accent); + font-weight: 600; + } + .tip { + position: fixed; + pointer-events: none; + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + color: var(--hp-txt); + padding: var(--sp-3) 10px; + border-radius: var(--rad-m); + font-size: var(--fs-m); + box-shadow: var(--shadow-2); + z-index: 60; + max-width: 260px; + } + .tip .m { + color: var(--hp-muted); + font-size: var(--fs-s); + display: block; + } +`,o` + .head { + display: flex; + align-items: center; + gap: 10px; + padding: 10px var(--sp-5); + border-bottom: 1px solid var(--hp-line); + flex-wrap: wrap; + } + .title { + font-size: var(--fs-l); + font-weight: 600; + display: flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .title ha-icon { + color: var(--hp-accent); + --mdc-icon-size: 18px; + } + @media (max-width: 620px) { + .head { gap: var(--sp-3); padding: var(--sp-4) 10px; } + .head .count { display: none; } + .head .title { font-size: var(--fs-m); } + } + .count { + font-size: var(--fs-s); + color: var(--hp-muted); + } + .btn { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + background: transparent; + color: var(--hp-txt); + padding: var(--sp-3) 10px; + border-radius: var(--rad-m); + cursor: pointer; + transition: 0.15s; + font-family: inherit; + font-size: var(--fs-m); + } + .btn ha-icon { + --mdc-icon-size: 17px; + } + :host([data-pointer-hover]) .btn:hover { + border-color: var(--hp-accent); + } + .btn.on { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + border-color: var(--hp-accent); + } + .btn.ghost { + border: none; + } + .btn[disabled] { + opacity: 0.5; + pointer-events: none; + } + /* the compass dial in the general settings (docs/SUN.md) */ + .sunrow { + display: flex; + align-items: center; + gap: var(--sp-5); + margin: var(--sp-3) 0; + } + .suncol { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--sp-3); + min-width: 0; + } + .recoveryoverlay { + position: absolute; + inset: 0; + /* Above the contextual editor tray (70): recovery is the one state in + which every stage-editing surface must be inert. Dialogs live outside + the stage and retain their own higher card-level stacking context. */ + z-index: 75; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--sp-4); + padding: var(--sp-6); + box-sizing: border-box; + /* The final solid layer guarantees an opaque recovery surface even when + a custom HA theme exposes its card colour as rgba(). */ + background: + linear-gradient(var(--ha-card-background, var(--card-background-color, #111)), + var(--ha-card-background, var(--card-background-color, #111))), + #111; + color: var(--primary-text-color, #fff); + text-align: center; + pointer-events: auto; + transition: opacity 0.15s ease; + } + .recoveryoverlay.phase-entering, + .recoveryoverlay.phase-leaving { + opacity: 0; + } + .recoveryoverlay.phase-fading-in, + .recoveryoverlay.phase-opaque { + opacity: 1; + } + .recoveryoverlay ha-icon { + --mdc-icon-size: 44px; + color: var(--hp-accent); + } + .editorloading { + position: absolute; + z-index: 74; + left: 50%; + top: 50%; + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-5); + border: 1px solid color-mix(in srgb, var(--hp-accent) 45%, transparent); + border-radius: 999px; + background: color-mix(in srgb, + var(--ha-card-background, var(--card-background-color, #111)) 92%, transparent); + color: var(--primary-text-color); + box-shadow: 0 6px 22px rgb(0 0 0 / 18%); + transform: translate(-50%, -50%); + pointer-events: none; + animation: editor-loading-in 0.15s ease both; + } + .editorloading ha-icon { + --mdc-icon-size: 22px; + color: var(--hp-accent); + animation: editor-loading-spin 0.9s linear infinite; + } + @keyframes editor-loading-in { + from { opacity: 0; transform: translate(-50%, calc(-50% + 4px)); } + to { opacity: 1; transform: translate(-50%, -50%); } + } + @keyframes editor-loading-spin { to { transform: rotate(360deg); } } + @media (prefers-reduced-motion: reduce) { + .recoveryoverlay, + .editorloading, + .editorloading ha-icon { + transition: none; + animation: none; + } + } + .oplock { + --oplock-size: calc(var(--icon-size, 2.5cqw) * 0.62); + --oplock-core-size: calc(var(--oplock-size) / 1.26875); + --oplock-stroke-ratio: 0.01875; + --oplock-stroke-width: max(1px, calc(var(--oplock-core-size) * var(--oplock-stroke-ratio))); + --oplock-core-bg: light-dark(#fff, #252525); + --oplock-core-fg: light-dark(#252525, #fff); + --oplock-shell-stroke: light-dark(#BCBCBC, rgb(37 37 37 / 75%)); + --oplock-shell-shadow: + 0 calc(var(--oplock-core-size) * .025) calc(var(--oplock-core-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--oplock-core-size) * .1) calc(var(--oplock-core-size) * .175) + calc(var(--oplock-core-size) * -.025) rgb(37 40 45 / 18%); + --oplock-core-shadow: 0 0 0 0 transparent; + pointer-events: none; /* inert while editing; clickable in View (rule below) */ + position: absolute; + transform: translate(-50%, -50%); + width: var(--oplock-size); + height: var(--oplock-size); + display: grid; + place-items: center; + border: 0; + background: transparent; + z-index: 1; + } + .oplock.theme-light { + --oplock-core-bg: #fff; + --oplock-core-fg: #252525; + --oplock-shell-stroke: #BCBCBC; + } + .oplock.theme-dark { + --oplock-core-bg: #252525; + --oplock-core-fg: #fff; + --oplock-shell-stroke: rgb(37 37 37 / 75%); + --oplock-core-shadow: + inset 0 calc(var(--oplock-core-size) * .0125) + calc(var(--oplock-core-size) * .0125) rgb(255 255 255 / 70%); + } + .oplock-shell { + box-sizing: border-box; + width: 100%; + height: 100%; + border: var(--oplock-stroke-width) solid var(--oplock-shell-stroke); + border-radius: 50%; + background: transparent; + box-shadow: var(--oplock-shell-shadow); + display: grid; + place-items: center; + pointer-events: none; + backdrop-filter: none; + } + .oplock-core { + width: var(--oplock-core-size); + height: var(--oplock-core-size); + border-radius: 50%; + background: var(--oplock-core-bg); + color: var(--oplock-core-fg); + box-shadow: var(--oplock-core-shadow); + display: grid; + place-items: center; + pointer-events: none; + } + .oplock ha-icon { + --mdc-icon-size: calc(var(--oplock-core-size) * 0.55); + display: flex; + line-height: 0; + } + .oplock.locked { + --oplock-core-bg: #66D17A; + --oplock-core-fg: light-dark(#fff, #252525); + --oplock-shell-stroke: #66D17A; + } + .oplock.theme-light.locked { --oplock-core-fg: #fff; } + .oplock.theme-dark.locked { + --oplock-core-fg: #252525; + --oplock-stroke-ratio: .025; + } + .oplock.unlocked { + --oplock-core-bg: #F0410C; + --oplock-core-fg: light-dark(#fff, #252525); + --oplock-shell-stroke: #F0410C; + } + .oplock.theme-light.unlocked { --oplock-core-fg: #fff; } + .oplock.theme-dark.unlocked { + --oplock-core-fg: #252525; + --oplock-stroke-ratio: .025; + } + .oplock.unknown { --oplock-core-fg: var(--hp-muted); } + .btn.lockact { + width: 100%; + justify-content: center; + display: flex; + align-items: center; + gap: var(--sp-3); + margin-top: var(--sp-4); + } + .btn.lockact.warn { + color: var(--error-color, #d33); + border-color: var(--error-color, #d33); + } + .oprow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) 0; + } + .oprow b { margin-left: auto; } + .oprow.ok b { color: #66d17a; } + .oprow.warn b { color: var(--hp-open); } + .bindharow { + display: flex; + align-items: center; + gap: var(--sp-5); + flex-wrap: wrap; + } + .bindharow .entcheck { opacity: 0.9; } + .ctrlchips { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-2) 0; } + .ctrlchip { + display: inline-flex; align-items: center; gap: var(--sp-2); + background: var(--hp-accent); color: var(--text-primary-color, #fff); + border-radius: var(--rad-l); padding: var(--sp-2) var(--sp-4); font-size: var(--fs-s); + } + .ctrlchip ha-icon { --mdc-icon-size: 14px; cursor: pointer; } + .ctrllist { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-2); } + .ctrlopt { + display: flex; align-items: center; gap: var(--sp-4); text-align: left; + border: 0; background: transparent; color: var(--hp-txt); + padding: var(--sp-3) var(--sp-4); border-radius: var(--rad-s); cursor: pointer; font-family: inherit; font-size: var(--fs-m); + } + :host([data-pointer-hover]) .ctrlopt:hover { + background: var(--secondary-background-color, rgba(128,128,128,0.15)); + } + .ctrlopt .sub { color: var(--hp-muted); font-size: var(--fs-s); margin-left: auto; } + .ctrlopt ha-icon { --mdc-icon-size: 16px; } + .ctrlstates { display: flex; flex-direction: column; gap: var(--sp-2); } + .ctrlstate { display: inline-flex; align-items: center; gap: var(--sp-3); color: var(--hp-muted); } + .ctrlstate.on { color: var(--hp-txt); } + .ctrlstate ha-icon { --mdc-icon-size: 15px; } + .cardpreview { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-2); + margin: var(--sp-4) 0 var(--sp-1); + padding: 10px; + border: 1px dashed var(--hp-muted); + border-radius: var(--rad-m); + } + .cardpreview .cpname { font-weight: 700; letter-spacing: 0.04em; } + .cardpreview .cpmeta { + display: inline-flex; + align-items: center; + gap: 0.3em; + font-weight: 600; + opacity: 0.85; + } + .cardpreview .cpmeta ha-icon { --mdc-icon-size: 1.05em; } + .iconauto { + display: flex; + align-items: center; + gap: var(--sp-3); + font-size: var(--fs-s); + margin: var(--sp-2) 0 0; + } + .iconauto ha-icon { --mdc-icon-size: 18px; } + .iconauto span { flex: 1; } + .iconauto .btn { min-height: 32px; padding: 0 var(--sp-3); } + hp-dialog .dfill { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + cursor: pointer; + } + .wallthick-dlg { + position: absolute; + z-index: 40; + min-width: 200px; + transform: translate(-50%, 8px); + padding: 10px 12px; + border-radius: 10px; + background: var(--card-background-color, #fff); + box-shadow: 0 8px 28px rgba(0,0,0,.22); + display: flex; + flex-direction: column; + gap: 8px; + pointer-events: auto; + } + .wallthick-dlg .row { + display: flex; + align-items: center; + gap: 8px; + } + .wallthick-dlg input[type="number"] { + width: 5.5em; + padding: 4px 6px; + border: 1px solid var(--divider-color, #ccc); + border-radius: 6px; + background: var(--input-fill, transparent); + color: var(--primary-text-color); + } + .areasel, + .namein { + background: var(--hp-bg); + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + font-family: inherit; + } + .namein { + width: 130px; + } + .habindingbanner { + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-4); + margin-bottom: var(--sp-4); + border: 1px solid var(--warning-color, #ff9800); + border-radius: var(--rad-m); + background: color-mix(in srgb, var(--warning-color, #ff9800) 12%, transparent); + color: var(--primary-text-color, #f1f3f6); + } + .habindingbanner > span { flex: 1; min-width: 0; } + .habindingbanner > ha-icon { color: var(--warning-color, #ff9800); flex: 0 0 auto; } + .habindingbanner.limited { + border-color: var(--secondary-text-color, #9aa0aa); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 10%, transparent); + } + .habindingbanner.limited > ha-icon { color: var(--secondary-text-color, #9aa0aa); } + .srcrow { + display: flex; + align-items: center; + gap: var(--sp-4); + font-size: var(--fs-m); + cursor: pointer; + padding: var(--sp-1) 0; + } + .dispsection { + margin-top: var(--sp-5) !important; + padding-top: var(--sp-4); + border-top: 1px solid var(--hp-line); + font-weight: 600; + color: var(--hp-txt) !important; + } + .colorrow { + display: flex; + align-items: center; + gap: var(--sp-4); + } + .gsrow > hp-color-opacity { + min-width: min(100%, 210px); + justify-content: space-between; + } + .ripple-colorrow > hp-color-opacity { + width: 100%; + justify-content: space-between; + } + .ripple-sizerow > .opl { + min-width: 0; + } + .colorrow input[type='range'] { flex: 1; } + .colorrow .tempin { width: 70px; flex: none; } + /* beat the generic hp-dialog .body .namein { width:100% } rule */ + hp-dialog .body .temprange .tempin { width: 56px; flex: none; padding: var(--sp-2) var(--sp-3); } + hp-dialog .body .colorrow .tempin { width: 72px; flex: none; } + .srcrow { flex-wrap: nowrap; } + /* native HA controls (rendered only when the HA frontend defines them; + old HA and the smoke env keep the plain inputs). ha-switch is taller + than a checkbox - cap its footprint so .srcrow keeps its rhythm. */ + .srcrow ha-switch { flex: none; } + .colorrow ha-slider { flex: 1; min-width: 0; } + .srcrow > span:first-of-type { white-space: nowrap; } + .colorrow .opl { color: var(--hp-muted); font-size: var(--fs-s); } + .colorrow .opv { font-size: var(--fs-s); min-width: 34px; text-align: right; } + .markerlightgroup { + min-width: 0; + margin: var(--sp-5) 0 0; + padding: var(--sp-4); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + } + .markerlightgroup legend { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-1); + padding: 0 var(--sp-2); + color: var(--hp-txt); + font-weight: 600; + } + .markerlightgroup legend > span { min-width: 0; overflow-wrap: anywhere; } + .markerlightgroup[disabled] > :not(legend) { opacity: .62; } + .markerhelpfield { margin-top: var(--sp-4); } + .markerhelplabel { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-1); + margin-bottom: var(--sp-1); + } + .markerhelplabel > label { min-width: 0; overflow-wrap: anywhere; } + .markerradios { display: grid; gap: var(--sp-1); min-width: 0; } + .markerlightgroup .srcrow > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + } + .markerglowvalue { margin: var(--sp-3) 0; flex-wrap: wrap; } + .markerglowvalue hp-color-opacity { flex: none; } + .markerlightdisabled { + display: flex; + align-items: center; + gap: var(--sp-2); + margin-top: var(--sp-2) !important; + } + .markerlightdisabled ha-icon { --mdc-icon-size: 18px; flex: none; } + .markerbadgetechnical { + min-width: 0; + margin: var(--sp-1) 0 var(--sp-2) !important; + overflow-wrap: anywhere; + } + .markerbadgetechnical code { white-space: normal; } + .planrow { + display: flex; + align-items: center; + gap: 10px; + } + /* the "already uploaded" picker: a plan is never deleted for being + unreferenced, so it has to be findable again */ + .savedplans { + display: flex; + flex-direction: column; + gap: var(--sp-3); + max-height: 240px; + overflow: auto; + margin: var(--sp-3) 0 var(--sp-1); + padding: var(--sp-3); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: var(--hp-bg2, rgba(255, 255, 255, 0.03)); + /* The same collapse that ate .candlist (v1.53.1): a scroll box is a + flex item whose automatic minimum size is ZERO (overflow != visible), + so inside hp-dialog .body — a flex column taller than its 66vh cap — + it shrank to a 14px sliver: the rows were in the DOM, the owner saw + a thin rounded stripe under the "Already uploaded" button. Don't + shrink, and keep a floor even when the box is empty or loading. */ + flex: 0 0 auto; + min-height: 2.6em; + } + .savedplan { + display: flex; + align-items: center; + gap: 10px; + } + .savedplan.cur { outline: 1px solid var(--hp-accent); border-radius: var(--rad-s); } + .savedplan img { + width: 56px; + height: 40px; + object-fit: contain; + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + background: #fff; + flex: none; + } + .savedmeta { display: flex; flex-direction: column; min-width: 0; flex: 1; } + .savedmeta b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .savedmeta .muted { font-size: var(--fs-s); } + .savedplan .btn.danger ha-icon { color: #f25a4a; } + .savedplan .btn[disabled] { opacity: 0.4; pointer-events: none; } + .planprev { + max-width: 120px; + max-height: 70px; + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + background: #fff; + } + .planname { + font-size: var(--fs-m); + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .planname.muted { + color: var(--hp-muted); + } + .filebtn { + cursor: pointer; + } + .fileupload { display: inline-flex; min-width: 0; } + .fileupload > input { display: none; } + .btn.danger { + border-color: #b3402a; + color: #ff7a5c; + } + hp-dialog .row .spacer { + flex: 1; + } + hp-dialog .body { + max-height: 66vh; + overflow-y: auto; + } + .descin { + width: 100%; + box-sizing: border-box; + background: var(--hp-bg); + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + font-family: inherit; + resize: vertical; + /* flex column of the dialog body squeezes textareas — keep a usable height */ + min-height: 92px; + flex-shrink: 0; + line-height: 1.35; + } + .bindsel { + display: flex; + flex-direction: column; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + padding: var(--sp-4); + } + .bindsel .opt { + display: flex; + align-items: center; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + background: transparent; + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + cursor: pointer; + font-size: var(--fs-m); + font-family: inherit; + } + .bindsel .opt.on { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + border-color: var(--hp-accent); + } + .curbind { + display: flex; + align-items: center; + gap: var(--sp-3); + font-size: var(--fs-m); + color: var(--hp-txt); + flex-wrap: wrap; + } + .curbind .ref { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .vacbox .vacbtns { display: flex; gap: var(--sp-4); margin: var(--sp-3) 0; flex-wrap: wrap; } + .vacdiag { display: grid; gap: 4px; margin-bottom: var(--sp-3); } + .vacdiag > div { display: flex; justify-content: space-between; gap: var(--sp-5); } + .vacdiag > div > span { color: var(--secondary-text-color); } + .vacdiag > div > b { text-align: right; overflow-wrap: anywhere; } + .vacpicker { margin: var(--sp-3) 0; } + .vacsource-warning { display: grid; gap: 8px; } + .vacsource-warning .btn { justify-self: start; } + .vacpicker > summary { display: inline-flex; width: auto; list-style: none; cursor: pointer; } + .vacpicker > summary::-webkit-details-marker { display: none; } + .vacsource-list { display: grid; gap: 6px; margin-top: 8px; } + .vacsource-list details { padding: 6px 0 0; } + .vacsource-list details > summary { cursor: pointer; font-weight: 600; } + .vacsource { display: flex; align-items: center; justify-content: space-between; gap: 12px; + width: 100%; min-width: 0; padding: 9px 10px; border: 1px solid var(--divider-color); + border-radius: 10px; color: var(--primary-text-color); background: var(--secondary-background-color); + text-align: left; cursor: pointer; } + .vacsource.on { border-color: var(--accent-color); box-shadow: inset 3px 0 var(--accent-color); } + .vacsource > span:first-child { min-width: 0; display: grid; gap: 2px; } + .vacsource small { color: var(--secondary-text-color); overflow-wrap: anywhere; } + .vacsource-meta { color: var(--secondary-text-color); text-align: right; font-size: 0.82em; } + .vacxcme pre { margin: 8px 0 0; white-space: pre-wrap; user-select: text; } + .vacfit { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + z-index: 12; + overflow: visible; + touch-action: none; + cursor: grab; + /* the devlayer is pointer-events: none and every child opts back in — + without this line real clicks flew straight through the overlay + (owner: «уголки не кликабельны»; synthetic smoke events bypass + hit-testing, which is why they lied) */ + pointer-events: auto; + } + .vacfit:active { cursor: grabbing; } + .vacfit polygon { + fill: color-mix(in srgb, var(--hp-accent) 16%, transparent); + stroke: var(--hp-accent); + stroke-width: 2; + vector-effect: non-scaling-stroke; + stroke-dasharray: 6 4; + } + .vacfit text { + fill: var(--hp-accent); + font-size: 26px; + text-anchor: middle; + dominant-baseline: middle; + pointer-events: none; + user-select: none; + } + /* ---- the furniture palette (docs/FURNITURE.md §3) ------------------- */ + .furnpalette { + display: flex; + flex-direction: column; + max-height: 38vh; + border-top: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12)); + background: var(--card-background-color, var(--hp-bg)); + font-size: 0.85em; + } + .furnhd { + display: flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + font-weight: 600; + opacity: 0.9; + } + .furnhd .spacer { flex: 1; } + .furnbody { + overflow: auto; + padding: 0 8px 6px; + } + .furngroup { + margin: 6px 0 3px; + font-size: 0.85em; + text-transform: uppercase; + letter-spacing: 0.04em; + opacity: 0.6; + } + .furnrow { + display: flex; + flex-wrap: wrap; + gap: 4px; + } + .furnitem { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; + width: 74px; + padding: 4px 2px; + border: 1px solid transparent; + border-radius: 8px; + background: rgba(127, 127, 127, 0.08); + color: inherit; + font: inherit; + font-size: 0.8em; + line-height: 1.15; + text-align: center; + cursor: pointer; + } + :host([data-pointer-hover]) .furnitem:hover { background: rgba(127, 127, 127, 0.18); } + .furnitem.on { + border-color: var(--hp-accent); + background: rgba(38, 166, 154, 0.18); + } + .furnprev { + width: 40px; + height: 40px; + color: var(--primary-text-color, currentColor); + } + .furnsize { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 6px; + padding: 6px 8px; + border-top: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12)); + } + .furnsize label { + display: flex; + align-items: baseline; + gap: 3px; + opacity: 0.8; + } + .furnsize .furnunit { opacity: 0.6; font-size: 0.85em; } + .furnsize input { + width: 5.5em; + padding: 3px 5px; + } + .furnhint { opacity: 0.6; } + .vacfitdot { fill: var(--hp-accent); pointer-events: none; } + /* hit target: invisible and finger-sized; .vacfitknob is the visible bead */ + .vacfithandle { + fill: transparent; + stroke: none; + cursor: nwse-resize; + } + .vacfitknob { + fill: var(--hp-bg); + stroke: var(--hp-accent); + stroke-width: 2; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .vaccalbar { + position: fixed; + left: 50%; + bottom: 24px; + transform: translateX(-50%); + display: flex; + gap: var(--sp-5); + align-items: center; + background: var(--hp-bg); + color: var(--hp-txt); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-l); + padding: 10px var(--sp-5); + z-index: 60; + box-shadow: var(--shadow-2); + } + .candlist { + max-height: 160px; + overflow-y: auto; + border-top: 1px solid var(--hp-line); + /* A scrollable box is a flex item that HAPPILY collapses: inside the + dialog body (a flex column) this list rendered its rows into a 1px + sliver — the DOM had 26 candidates and the user saw nothing. In the + binding dropdown it sits inside .droppanel (block context) and never + showed the bug. Field report, 2026-07-30. */ + flex: 0 0 auto; + min-height: 2.6em; + } + .cand { + display: flex; + justify-content: space-between; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + cursor: pointer; + border-radius: var(--rad-s); + font-size: var(--fs-m); + } + :host([data-pointer-hover]) .cand:hover { + background: rgba(127, 127, 127, 0.15); + } + .cand.sel { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + .cand .cs { + color: var(--hp-muted); + font-size: var(--fs-s); + white-space: nowrap; + } + .opening-entity-candidate { + width: 100%; + border: 0; + background: transparent; + color: inherit; + font: inherit; + text-align: left; + } + .opening-entity-candidate.sel { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + .opening-entity-empty { cursor: default; } + .cand.sel .cs { + color: var(--text-primary-color, #fff); + opacity: 0.85; + } + .cand.muted { + color: var(--hp-muted); + cursor: default; + } + .pdfedit { + display: flex; + flex-wrap: wrap; + gap: var(--sp-3); + align-items: center; + } + .pdftag { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: var(--sp-2) var(--sp-3); + font-size: var(--fs-s); + } + .pdftag a { + color: var(--hp-txt); + text-decoration: none; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .pdftag .x { + --mdc-icon-size: 15px; + cursor: pointer; + color: var(--hp-muted); + } + :host([data-pointer-hover]) .pdftag .x:hover { + color: #ff7a5c; + } + .entlist { + display: flex; + flex-direction: column; + gap: var(--sp-2); + margin-bottom: 10px; + } + .entrow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + border-radius: var(--rad-m); + background: var(--secondary-background-color, rgba(128, 128, 128, 0.12)); + } + .entrow ha-icon { --mdc-icon-size: 20px; color: var(--hp-muted); } + .entrow.on ha-icon { color: var(--hp-accent); } + .entrow .en { flex: 1; font-size: var(--fs-m); } + .entrow .ev { font-size: var(--fs-m); color: var(--hp-muted); } + .entbtn { + min-width: 74px; + min-height: 32px; + padding: var(--sp-2) var(--sp-5); + border: 1px solid var(--hp-muted); + border-radius: 999px; + background: transparent; + color: var(--hp-txt); + font: inherit; + font-size: var(--fs-m); + cursor: pointer; + } + .entbtn.on { + background: var(--hp-accent); + border-color: var(--hp-accent); + color: var(--text-primary-color, #fff); + font-weight: 600; + } + .inforow { + display: flex; + gap: 10px; + font-size: var(--fs-m); + margin: var(--sp-2) 0; + } + .inforow .k { + color: var(--hp-muted); + min-width: 84px; + } + .inforow a { + color: var(--hp-accent); + word-break: break-all; + } + .infodesc { + font-size: var(--fs-m); + white-space: pre-wrap; + margin-top: var(--sp-3); + } + .infodesc.muted { + color: var(--hp-muted); + } + .pdflist { + display: flex; + flex-direction: column; + gap: var(--sp-2); + } + .pdf { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + color: var(--hp-accent); + text-decoration: none; + } + ha-icon-picker { + display: block; + } + .floorrow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-2); + font-size: var(--fs-m); + cursor: pointer; + } + .floorrow .floorlvl { + color: var(--hp-muted); + font-size: var(--fs-s); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: 0 var(--sp-3); + } + .rtest { + display: flex; + align-items: center; + gap: var(--sp-4); + margin-bottom: var(--sp-4); + } + .rtest .namein { flex: 1; } + .rtest ha-icon { color: var(--hp-accent); } + .rtesticon { font-size: var(--fs-s); color: var(--hp-muted); } + .rrow { + display: flex; + align-items: center; + gap: var(--sp-3); + margin: var(--sp-1) 0; + } + .rrow .rpat { flex: 2; } + .rrow .ricon { flex: 1.4; } + .rrow .rpat.bad { border-color: #ff7a5c; } + .rrow .rprev { --mdc-icon-size: 18px; color: var(--hp-txt); min-width: 18px; } + .rrow .ract { + --mdc-icon-size: 16px; + color: var(--hp-muted); + cursor: pointer; + } + :host([data-pointer-hover]) .rrow .ract:hover { color: var(--hp-txt); } + :host([data-pointer-hover]) .rrow .ract.del:hover { color: #ff7a5c; } + .gsrow .gsl { + min-width: 150px; + font-size: var(--fs-m); + color: var(--hp-muted); + } + .optimize-live { + display: grid; + justify-items: start; + gap: var(--sp-2); + margin-bottom: var(--sp-3); + } + .optimize-live .alignmsg, .optimize-live .rhint { margin-bottom: 0; } + .optimize-cleanup { min-height: 44px; } + .optimize-selected { color: var(--hp-txt); } + .optimize-details { + margin-top: var(--sp-3); + color: var(--hp-muted); + font-size: var(--fs-s); + overflow-wrap: anywhere; + } + .optimize-details > summary { + width: fit-content; + color: var(--hp-txt); + cursor: pointer; + font-weight: 600; + } + .optimize-details > summary:focus-visible { + outline: 2px solid var(--hp-accent); + outline-offset: 3px; + border-radius: var(--rad-s); + } + .optimize-details ul { margin: var(--sp-3) 0; padding-inline-start: 22px; } + .optimize-details li + li { margin-top: var(--sp-1); } + .btn.alignall { width: 100%; justify-content: center; } + .backupactions { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--sp-3); + } + .backupactions .btn { justify-content: center; min-width: 0; } + .backupupload { display: inline-flex; min-width: 0; } + .backupupload > .btn { width: 100%; justify-content: center; } + .backupupload input { display: none; } + .backupbody { min-width: 0; } + .backupplanonly { margin-inline-start: var(--sp-4) !important; align-items: flex-start !important; } + .backupplanonly > span:first-of-type { display: grid; gap: 2px; white-space: normal; } + .backupplanonly small { color: var(--secondary-text-color); line-height: 1.35; } + .backupplanonlystatus { color: var(--hp-accent) !important; font-weight: 700; } + .backupfile, .backupsummary, .backupcontent { + display: flex; + flex-direction: column; + min-width: 0; + gap: var(--sp-1); + } + .backupfile b, .backupcontent span { + overflow-wrap: anywhere; + } + .backupfile span, .backupsummary span, .backupcontent span { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .backupcounts { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--sp-2) var(--sp-4); + font-size: var(--fs-s); + } + .backupwarn, .backuperror { + border-radius: var(--rad-s); + padding: var(--sp-3); + font-size: var(--fs-s); + line-height: 1.45; + overflow-wrap: anywhere; + } + .backupwarn { background: color-mix(in srgb, var(--hp-accent) 12%, transparent); } + .backuperror { background: rgba(179, 64, 42, .16); color: #ff7a5c; } + .backupdetails { + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: var(--sp-2) var(--sp-3); + font-size: var(--fs-s); + } + .backupdetails summary { cursor: pointer; font-weight: 700; } + .backupdetails > div { display: grid; gap: var(--sp-1); padding-block-start: var(--sp-2); } + .backupdetails code { overflow-wrap: anywhere; color: var(--hp-muted); } + .backupchoices { + display: flex; + flex-direction: column; + gap: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + min-width: 0; + } + .backupchoices label { margin: 0 !important; display: flex; gap: var(--sp-2); } + .backupconfirm { align-items: flex-start !important; } + .backupconfirm > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + } + @media (max-width: 520px) { + .backupactions, .backupcounts { grid-template-columns: 1fr; } + } + .aboutver { + font-size: var(--fs-s); + color: var(--hp-muted); + margin: var(--sp-2) 0 var(--sp-3); + } + .aboutlink { + display: flex; + align-items: center; + gap: var(--sp-3); + width: fit-content; + color: var(--hp-accent); + text-decoration: none; + font-size: var(--fs-m); + padding: var(--sp-1) 0; + } + :host([data-pointer-hover]) .aboutlink:hover { text-decoration: underline; } + .aboutlink ha-icon { --mdc-icon-size: 18px; line-height: 1; } + hp-dialog .body { + padding: var(--sp-5) var(--sp-6); + display: flex; + flex-direction: column; + gap: var(--sp-3); + } + hp-dialog .tapconfirm-body { + min-width: 0; + overflow-x: hidden; + } + hp-dialog .tapconfirm-body p { + max-width: 100%; + min-width: 0; + margin: 0; + overflow-wrap: anywhere; + white-space: normal; + } + hp-dialog .tapconfirm-line { + color: var(--hp-muted); + } + hp-dialog .body label { + font-size: var(--fs-s); + color: var(--hp-muted); + margin-top: var(--sp-3); + } + hp-dialog .body .namein, + hp-dialog .body .areasel { + width: 100%; + box-sizing: border-box; + } + /* Room settings contains long radio labels, two source pickers and live + previews, so it deliberately uses hp-dialog's medium width. Keep its + content shrinkable as well: the generic srcrow rule is nowrap because + compact switch rows need it, but here that created a horizontal scroll + box even on a wide desktop viewport. */ + hp-dialog.roomdialog .body { + min-width: 0; + overflow-x: hidden; + } + hp-dialog.roomdialog .body > * { + min-width: 0; + max-width: 100%; + box-sizing: border-box; + } + hp-dialog.roomdialog .srcrow { + min-width: 0; + align-items: flex-start; + } + hp-dialog.roomdialog .srcrow > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + line-height: 1.35; + } + hp-dialog.roomdialog .dropbtn > b, + hp-dialog.roomdialog .dropbtn > .ref { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + hp-dialog .row { + display: flex; + justify-content: flex-end; + gap: var(--sp-4); + width: 100%; + min-width: 0; + box-sizing: border-box; + padding: var(--sp-5) var(--sp-6); + border-top: 1px solid var(--hp-line); + } + /* Stable destructive/commit footer contract. A flex spacer cannot react + when translated labels no longer fit: justify-content then overflows + the destructive button through the left inset. Two real groups wrap + as units instead — destructive actions stay left, while Cancel/Save + move together to a right-aligned second row when necessary. */ + hp-dialog .row.dialog-action-footer { + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + row-gap: var(--sp-4); + } + hp-dialog .dialog-action-group { + display: flex; + flex: 0 1 auto; + flex-wrap: wrap; + align-items: center; + gap: var(--sp-4); + max-width: 100%; + min-width: 0; + } + hp-dialog .dialog-action-group .btn { + flex: 0 0 auto; + min-height: 44px; + } + hp-dialog .dialog-action-danger { + margin-right: auto; + } + hp-dialog .dialog-action-commit { + margin-left: auto; + justify-content: flex-end; + } + hp-dialog .row.markerfooter { + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + } + hp-dialog .row.roomfooter { + align-items: center; + flex-wrap: wrap; + } + /* Device info can have Edit + Open in HA + Close. It uses a wide dialog; + wrapping remains as a phone fallback, but without a flex spacer (which + used to strand Edit alone on the first line). */ + hp-dialog .row.infofooter { + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + gap: var(--sp-3); + } + hp-dialog .row.infofooter .btn { + flex-shrink: 0; + } + hp-dialog .row.infofooter .infofooter-close { + margin-left: auto; + } + @media (max-width: 480px) { + hp-dialog .row.infofooter { + padding: var(--sp-4) var(--sp-5); + } + } + .markeractions, + .markersaveactions { + display: flex; + align-items: center; + gap: var(--sp-4); + } + .markeractions:empty { display: none; } + .markersaveactions { margin-left: auto; } + .device-inbox { + display: flex; + flex-direction: column; + gap: var(--sp-4); + padding: var(--sp-5) var(--sp-6); + min-width: 0; + } + .device-inbox-dialog { --hp-dialog-wide-width: 920px; } + .device-inbox-head { + display: grid; + grid-template-columns: minmax(180px, 1fr) auto; + align-items: center; + gap: var(--sp-4); + } + .device-inbox-search { + width: 100%; + min-width: 0; + box-sizing: border-box; + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: transparent; + color: var(--hp-txt); + font: inherit; + padding: 11px 14px; + } + .device-inbox-tabs { + display: flex; + gap: var(--sp-2); + overflow-x: auto; + scrollbar-width: thin; + padding-bottom: var(--sp-1); + } + .device-inbox-tabs button { + flex: 0 0 auto; + border: 1px solid var(--hp-line); + border-radius: 999px; + background: transparent; + color: var(--hp-txt); + font: inherit; + padding: 8px 12px; + cursor: pointer; + } + .device-inbox-tabs button.on { + border-color: var(--hp-accent); + background: color-mix(in srgb, var(--hp-accent) 18%, transparent); + } + .device-inbox-tabs button span { color: var(--hp-muted); margin-inline-start: 4px; } + .device-inbox-filters { + display: flex; + flex-wrap: wrap; + gap: var(--sp-4) var(--sp-6); + color: var(--hp-muted); + } + .device-inbox-filters label { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + cursor: pointer; + } + .device-inbox-results { display: grid; gap: var(--sp-3); min-width: 0; } + .device-inbox-row { + display: grid; + grid-template-columns: 42px minmax(180px, 1fr) minmax(180px, auto); + align-items: center; + gap: var(--sp-4); + min-width: 0; + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + padding: var(--sp-4); + background: color-mix(in srgb, var(--hp-txt) 3%, transparent); + } + .device-inbox-icon { --mdc-icon-size: 28px; color: var(--hp-txt); justify-self: center; } + .device-inbox-copy { min-width: 0; } + .device-inbox-name { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); } + .device-inbox-new { + border-radius: 999px; + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + font-size: var(--fs-s); + padding: 2px 7px; + } + .device-inbox-meta, + .device-inbox-reason, + .device-inbox-copy code { + display: block; + color: var(--hp-muted); + font-size: var(--fs-s); + overflow-wrap: anywhere; + white-space: normal; + } + .device-inbox-status { color: var(--error-color, #db4437); margin-inline-start: var(--sp-2); } + .device-inbox-actions { + display: flex; + justify-content: flex-end; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-2); + } + .device-inbox-actions .btn { min-height: 36px; padding: 7px 10px; } + .device-inbox-menu { position: relative; } + .device-inbox-menu summary { list-style: none; cursor: pointer; } + .device-inbox-menu summary::-webkit-details-marker { display: none; } + .device-inbox-menu-items { + position: absolute; + z-index: 2; + inset-inline-end: 0; + top: calc(100% + var(--sp-1)); + display: grid; + gap: var(--sp-1); + min-width: 180px; + padding: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: var(--hp-panel, var(--card-background-color, #fff)); + box-shadow: 0 8px 24px rgba(0, 0, 0, .22); + } + .device-inbox-menu-items .btn { justify-content: flex-start; width: 100%; } + .device-inbox-empty { color: var(--hp-muted); text-align: center; padding: var(--sp-8); } + .device-inbox-more { align-self: center; } + @media (max-width: 680px) { + .device-inbox { padding: var(--sp-4); } + .device-inbox-head { grid-template-columns: minmax(0, 1fr); } + .device-inbox-head .btn { justify-self: stretch; } + .device-inbox-tabs { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + overflow-x: visible; + } + .device-inbox-tabs button { + min-width: 0; + overflow-wrap: anywhere; + } + .device-inbox-row { grid-template-columns: 36px minmax(0, 1fr); } + .device-inbox-actions { grid-column: 1 / -1; justify-content: flex-start; } + } +`];var Wd={"editor.context_actions":"Actions: {object}","editor.tool_options":"Tool options: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Tool group: {group}","editor.group_active":"{group} — active: {item}","editor.disabled_action":"{action} is unavailable: {reason}","editor.loading":"Loading editor…","editor.loading_aria":"The plan editor is loading","editor.load_failed":"Could not load the editor.","editor.refresh_advice":"Refresh the page and try again.","color_picker.title":"Color picker","color_picker.hue":"Hue","color_picker.saturation":"Saturation","color_picker.value":"Brightness","color_picker.hex":"Hex color","color_picker.invalid_hex":"Enter a 3- or 6-digit hex color","btn.properties":"Properties","btn.keep_as_walls":"Keep as walls","btn.delete_room_keep_walls":"Delete room, keep walls","btn.delete_room_with_walls":"Delete room and walls","title.markup_select":"Select and edit walls, columns and saved outlines","title.markup_column":"Column: click a grid point to place a square column","markup.partition":"Partition","markup.column":"Column","markup.hint_column":"click a grid point to place a square column","history.draft_segment":"Add room-draft segment","history.draft_merge":"Join unfinished room outlines","history.draft_segment_delete":"Remove room-draft segment","history.partition_add":"Add partition","history.column_add":"Add column","history.physical_edit":"Change physical object","history.physical_delete":"Delete physical object","history.physical_move":"Move physical object","history.contour_to_partitions":"Convert contour to closed walls","history.wall_chain_finish":"Finish wall chain","history.wall_face_batch":"Create rooms from walls","toast.column_duplicate":"A column with the same centre and outer size already exists","confirm.delete_draft":"Delete the whole unfinished room contour?","confirm.delete_draft_segment":"Delete this draft segment? The remaining contour may split in two.","physical.partition_properties":"Partition properties","physical.column_properties":"Column properties","physical.draft_properties":"Draft segment properties","physical.shape":"Shape","physical.square":"Square","physical.circle":"Circle","physical.diameter":"Diameter","physical.side":"Side","physical.rotation":"Rotation angle","physical.length":"Length","physical.allowed_range":"Allowed: {min}–{max} {unit}","physical.delete_segment":"Delete segment","physical.delete_draft":"Delete entire outline","physical.column_size_title":"Outer side of the square column placed by the click (1–150 cm).","card.title":"House plan","count.devices":"{n} dev.","empty.no_spaces":"No spaces yet.","empty.add_first":"Add the first space and upload a floor plan.","empty.install":'Install the House Plan integration and add it in "Devices & services".',"btn.add_space":"Add space","btn.cancel":"Cancel","btn.save":"Save","btn.close":"Close","btn.delete":"Delete","btn.edit":"Edit","btn.open_in_ha":"Open in HA","btn.reset":"Reset","btn.attach":"Attach…","btn.upload":"Upload…","btn.replace":"Replace…","title.zoom_in":"Zoom in","title.zoom_out":"Zoom out","title.zoom_fit":"Fit all","title.add_device":"Add a device to the plan","title.show_all":"Show hidden and disabled devices as service markers (this tab only)","title.markup":"Room markup: grid, lines, outlines","title.configure_space":"Configure space","title.add_space":"Add space","title.markup_add":"Walls: draw a continuous chain; Shift locks to 45°. Changing tool or leaving the editor finishes it as independent walls","title.markup_merge":"Merge: click one room, then the neighbour it shares a wall with","title.markup_split":"Split a room: click the room, then two points on its walls","title.markup_delroom":"Delete room: click inside a room and confirm","title.need_plan":"Upload a floor-plan image","markup.add":"Walls","markup.merge":"Merge","markup.split":"Split","markup.resize":"Resize","title.markup_resize":"Resize rooms: drag an available horizontal or vertical wall handle","markup.hint_resize":"drag an available wall handle · the wall stops at the first unsafe position · Esc cancels · Ctrl+Z — undo","resize.disabled.diagonal":"This wall is angled; Resize supports only horizontal and vertical walls","resize.disabled.side-angle":"An adjoining wall is angled; Resize requires both adjoining walls to meet this wall at right angles","resize.disabled.duplicate-physical-wall":"A separate partition, unfinished outline, or column overlaps this wall; remove or move it before resizing","resize.disabled.partial-shared":"A neighbouring room uses only part of this wall, so it cannot be moved safely as one shared wall","resize.disabled.unequal-shared":"The neighbouring room uses different endpoints or wall length, so the walls cannot move together safely","resize.disabled.multiple-rooms":"Moving this wall would affect more than two rooms","resize.disabled.thickness-conflict":"The wall thickness cannot be preserved safely","resize.disabled.opening-conflict":"An opening on this wall cannot be moved safely","resize.disabled.invalid-geometry":"This wall cannot be resized without changing the plan structure","resize.limit_stopped":"Wall stopped: the next step would break a junction limit","resize.commit_failed":"Resize was cancelled because the final plan did not pass the geometry check","resize.preview_failed":"Resize stopped at the last safe position because the plan geometry could not be preserved","markup.opening":"Opening","markup.delete_room":"Delete room","history.undo":"Undo","history.redo":"Redo","history.undo_named":"Undo: {name} (Ctrl+Z)","history.redo_named":"Redo: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Nothing to undo","history.redo_empty":"Nothing to redo","history.undone":"Undone: {name}","history.redone":"Redone: {name}","history.add_room":"Create room","history.split_room":"Split room","history.merge_rooms":"Merge rooms","history.resize_room":"Resize room","history.wall_thickness":"Change wall thickness","history.add_opening":"Add door or window opening","history.edit_opening":"Edit opening","history.move_opening":"Move opening","history.delete_opening":"Delete opening","history.delete_room":"Delete room","history.delete_room_keep_walls":"Delete room, keep walls","history.delete_room_with_walls":"Delete room and walls","history.decor_add":"Add decor object","history.decor_edit":"Edit decor object","history.decor_move":"Move decor object","history.decor_transform":"Transform decor object","history.decor_delete":"Delete decor object","history.backdrop_transform":"Transform plan backdrop","title.markup_opening":"Openings: click a wall to place, click an opening to edit","opening.new":"New opening","opening.edit":"Opening","opening.door":"Door","opening.window":"Window","opening.gate":"Gate","opening.passage":"Open passage","opening.passage_binding_warning":"Saving will remove the open/close sensor and lock.","opening.invalid_passage_fields":"The open passage on plan “{room}” has unsupported settings: {fields}.","opening.type_label":"Type","opening.length_label":"Length, cm","opening.contact_label":"Open/close sensor","opening.lock_label":"Lock","opening.none":"— none —","opening.search_ph":"Search: name or entity id…","opening.invert":"Invert open/closed","opening.flip_h":"Hinge on the other jamb","opening.flip_v":"Opens to the other side","opening.open":"Open","opening.closed":"Closed","opening.locked":"Locked","opening.unlocked":"Unlocked","opening.state_unknown":"unavailable","opening.no_entities":"No sensors bound — a static symbol on the plan.","toast.opening_no_wall":"Click next to a room wall or independent wall","opening.host_partition":"Independent wall","opening.partition_orphan":"The independent wall for this opening no longer exists","opening.partition_jamb_margin":"Leave at least {distance} between the opening and the end of the wall","opening.rebind_partition":"Attach to another independent wall","confirm.delete_partition_openings_title":"Delete wall and openings?","confirm.delete_partition_openings_body":"This wall contains {count} opening(s). They will be deleted together.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Delete","markup.hint_points":"points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room","markup.hint_start":"click a grid dot to start a wall chain","tip.lqi":"average zigbee signal:","tip.area":"area: {value}","info.device_header":"Device on the plan","info.model":"Model","info.state":"State","info.link":"Link","info.manuals":"Manuals","info.none":"No additional information","marker.new_device":"New device","marker.name_label":"Name (shown on the plan)","marker.name_ph":"Name","marker.binding_label":"Bind to an HA device","marker.binding_disabled":"disabled in Home Assistant","marker.virtual_option":"Virtual device (no binding)","marker.search_ph":"Search device / group…","marker.nothing_found":"nothing found","marker.room_label":"Room","marker.room_override":" (override placement)","marker.room_choose":"— select a room —","marker.room_auto":"— by device area (auto) —","marker.icon_label":"Icon","marker.icon_ph":"mdi:… (empty = auto)","marker.display_label":"Display","display.badge":"Icon + state","display.icon_ripple":"Icon + state and activity","display.static_icon":"Always static icon","marker.display_hint":"Icon + state changes the plate for work, open, alarm and unavailable states. Icon + state and activity additionally shows a short pulse for events and a continuous pulse for ongoing work, movement or presence. Value + state replaces the icon with one unambiguous HA value. A static icon never reacts to device states.","marker.display_hint_badge":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon_ripple":"The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.","marker.display_hint_value":"One unambiguous Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.","marker.display_hint_static_icon":"The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.","marker.static_alarm_warning":"This device can report alarms. Static display hides the marker's visual alarm indication.","marker.preview.title":"Display preview","marker.preview.actual":"Now","marker.preview.example":"Example","marker.preview.integration":"Provided by","marker.preview.source":"Display source","marker.preview.current_state":"Current state","marker.preview.result":"On the plan","marker.preview.details":"Source details","marker.preview.select_source":"Choose a Home Assistant device or entity to see its actual display.","marker.preview.unknown_provider":"Unknown integration","marker.preview.virtual_provider":"House Plan · virtual device","marker.preview.no_source":"No active source","marker.preview.no_state":"No current state","marker.preview.mixed_states":"Several different states","marker.preview.multiple_sources":"{n} sources","marker.preview.more_sources":"+{n} more","marker.preview.scaled":"The preview is scaled to {n}% to fit. The saved size is unchanged.","marker.preview.demo_activity":"Show activity example","marker.preview.demo_notice":"Temporary activity example; the actual device state is unchanged.","marker.preview.demo_short":"Show short activity","marker.preview.demo_continuous":"Show continuous activity","marker.preview.stop_continuous":"Stop continuous activity","marker.preview.demo_short_notice":"Short activity example; the actual device state is unchanged.","marker.preview.demo_continuous_notice":"Continuous activity example; the actual device state is unchanged.","marker.preview.demo_already_visible":"The current state already shows a real activity or alarm effect.","marker.preview.reduced_motion":"System reduced-motion is enabled, so ordinary activity is shown as a dot.","marker.preview.reason.neutral":"Neutral dark plate","marker.preview.reason.working":"Yellow plate: the device is working now","marker.preview.reason.working_activity":"Yellow plate and activity effect: the device is working now","marker.preview.reason.open":"Orange plate: physically open or unlocked","marker.preview.reason.cover_icon_state":"Neutral plate; the cover entity controls the displayed state and icon","marker.preview.reason.presence":"Activity effect while presence is detected","marker.preview.reason.event":"Short activity effect after a detected event","marker.preview.reason.transition":"Activity effect while the device is moving or changing state","marker.preview.reason.media_neutral":"Media devices stay on a neutral dark plate while available","marker.preview.reason.unavailable":"Subdued neutral plate: unavailable or off","marker.preview.reason.alarm":"Red alarm plate; alarm indication is always shown","marker.preview.reason.live_states_disabled":"Live-state styling is disabled for this card","marker.preview.reason.value_no_state":"No usable state value; the icon is shown instead","marker.preview.reason.value_ambiguous_sources":"Several possible value sources; the icon is shown instead","marker.preview.reason.value_non_scalar":"The source did not return a simple value; the icon is shown instead","marker.preview.reason.value_virtual":"A virtual device has no Home Assistant value; the icon is shown instead","marker.preview.reason.vacuum_live_plan_only":"Live vacuum position and trail are available only on the full plan","marker.preview.reason.hidden_design_preview":"The device is hidden on the plan; this design preview remains visible","marker.preview.reason.composite_power_source":"State comes from the device Power entity; auxiliary switches are ignored","marker.preview.reason.activity_display_disabled":"The selected display mode does not show ordinary activity effects","marker.preview.reason.ha_disabled":"The Home Assistant binding is disabled and will be hidden on the plan","marker.preview.reason.orphaned":"The saved Home Assistant binding can no longer be found","marker.preview.reason.static_icon":"Static mode: device state does not change the icon","marker.activity_color":"Activity pulse color","marker.ripple_size":"Activity pulse size","marker.activity_alarm_note":"Color and size affect ordinary activity only and do not change red alarms.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Recent event","marker.pulse_a11y_presence":"Presence detected","marker.pulse_a11y_transition":"Changing state","marker.pulse_a11y_running":"Working","marker.state_a11y_neutral":"Default state","marker.state_a11y_working":"Working","marker.state_a11y_open":"Open","marker.state_a11y_locked":"Locked","marker.state_a11y_unlocked":"Unlocked","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Unavailable","marker.lqi_a11y_low":"LQI {value}, low signal","marker.lqi_a11y_mid":"LQI {value}, medium signal","marker.lqi_a11y_high":"LQI {value}, high signal","marker.size_label":"Icon size / rotation","marker.angle_label":"Rotate","marker.model_label":"Model","marker.model_ph":"e.g. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Description","marker.desc_ph":"Notes, specs…","marker.manuals_label":"Manuals (PDF etc.)","marker.sub_device":"device","marker.sub_z2m_group":" · Z2M group","marker.sub_group":"group","marker.sub_helper":"helper","space.new":"New space","space.header":"Space","space.title_label":"Title","space.title_ph":"e.g. Garage","space.plan_label":"Floor plan (background)","space.no_plan":"no plan image","space.plan_alt":"plan","room.new":"New room","room.name_label":"Display name","room.name_ph":"e.g. Terrace","room.area_label":"Home Assistant area (unassigned)","room.no_area_option":"— no area —","room.default_name":"Room","device.unnamed":"unnamed","device.light_group":"light group","device.fallback":"device","device.virtual":"virtual device","confirm.delete_room":'Delete room "{name}"?',"confirm.delete_room_title":'Delete room "{name}"?',"confirm.delete_room_body":"Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.","confirm.merge_rooms":'Merge rooms "{a}" and "{b}"?',"confirm.remove_marker":'Delete "{name}" from the plan? The device will disappear completely and stop contributing to plan data. You can add it again later.',"confirm.erase_decor":"Erase the {kind} object? You can undo this action from the editor history.","confirm.delete_space":'Delete space "{title}" with all its rooms and markup?',"space.delete_blocked":"This space is still used by {n} device(s). Move them to another space or delete them first.","toast.pos_save_failed":"Failed to save position: {err}","toast.no_entity":"The device has no suitable entity","toast.ha_disabled_action":"A Home Assistant object that is disabled cannot be used on the plan.","toast.ha_disabled_show_device":"A device disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_show_entity":"An entity disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_add":"A disabled Home Assistant object cannot be added to the plan. Enable it in Home Assistant first.","toast.ha_binding_unverified":"The object status could not be verified through the Home Assistant registry. Display and actions are temporarily unavailable.","toast.markup_needs_server":"Markup is available after the config is moved to the server","toast.space_order_changed":"Order changed. If any card pins its floor by number, check those panels.","toast.conflict":"Config was changed in another window — data refreshed, repeat your last action","toast.cfg_save_failed":"Failed to save config: {err}","toast.room_overlap":"The outline overlaps room “{name}” — rooms must not overlap","toast.contour_min_edges":"Draw at least two edges before closing the outline","toast.contour_cannot_close":"The outline cannot close because it is degenerate or intersects itself","toast.merge_not_adjacent":"Only rooms that share a wall can be merged","toast.rooms_merged":"Rooms merged into “{name}”","toast.split_pick_wall":"Start the cut on the room’s wall","toast.split_bad_cut":"The cut must run wall to wall inside the room, without crossing walls or itself","merge.header":"Merge rooms","merge.hint":"The merged room keeps one name and one area. The other area is released — its devices leave the plan until another room claims it.","merge.keep":"Keep","merge.no_area":"no area","room.split_header":"New room from the split","toast.room_saved":"Room saved ({n}). Devices added: {added}. Outline the next one or exit markup.","toast.room_saved_no_area":"Room saved ({n}, no area). Outline the next one or exit markup.","toast.marker_needs_server":"Device editing is available after the config is moved to the server","toast.virtual_name_required":"Enter a name for the virtual device","toast.marker_saved":"Device saved","toast.marker_removed":"Device deleted from the plan","toast.integration_missing":"The House Plan integration is not installed — management unavailable","toast.plan_formats":"Supported formats: SVG, PNG, JPG, WebP","toast.plan_required":"Upload a floor plan — it is required","toast.space_added_onboard":"Space added. Outline the rooms: click grid dots and close the contour.","toast.space_added":"Space added","toast.space_saved":"Space saved","toast.space_deleted":"Space deleted","toast.delete_failed":"Delete failed: {err}","toast.error":"Error: {err}","toast.toggle_target_unavailable":"Target “{name}” is unavailable — no action was performed","toast.toggle_targets_unavailable":"Targets are unavailable: {names}. No action was performed","toast.file_failed":'File "{name}" was not uploaded: {err}',"toast.files_attached":"Files attached: {n}","err.unknown":"unknown error","err.code":"code {code}","err.too_large":"file larger than {mb} MB","err.bad_ext":"unsupported type (PDF/image expected)","err.unauthorized":"administrator rights required","editor.title":"Title","editor.default_floor":"Initial space","editor.default_floor_missing":"Initial space “{id}” no longer exists. Choose another space.","editor.floor":"Fixed space","editor.floor_none":"— not fixed —","editor.floor_index":"YAML index {index} (preserved)","fixed_floor.loading":"Loading the fixed space…","fixed_floor.invalid_title":"The fixed space is unavailable","fixed_floor.invalid_body":"Check floor in the card configuration. The configured value is: {value}","editor.icon_size":"Icon size, % of plan width","editor.show_temperature":"Show temperature","editor.live_states":"Live states (on/off, open…)","editor.show_signal":"Show zigbee signal (LQI)","editor.language":"Interface language","editor.lang_auto":"Auto (HA profile)","editor.lang_en":"English","editor.lang_ru":"Русский","title.icon_rules":"Icon rules: which MDI icon devices get by name","rules.title":"Icon rules","rules.hint":"Rules are checked top-down against “device name + model” (case-insensitive regex); the first match wins. When nothing matches, the entity device class decides, then the generic chip icon.","rules.pattern_ph":"regex, e.g. plug|socket","rules.icon_ph":"mdi:power-socket-de","rules.add":"Add rule","rules.reset":"Reset to defaults","rules.test_ph":"Try a device name…","rules.invalid":"invalid regex","rules.saved":"Icon rules saved","btn.up":"Up","btn.down":"Down","tap.info":"Device card","tap.more_info":"HA more-info dialog","tap.toggle":"Toggle state","marker.tap_label":"Tap action for this device","tap.toggle_note":"The resolved state is shown below. Secure devices are never toggled from the plan.","import.title":"Create spaces from HA floors","import.hint":"Your Home Assistant already knows these floors. Pick the ones to turn into plan spaces — you will upload a floor-plan image for each one next. Rooms are then outlined by hand on the plan.","import.start":"Create {n} space(s)","import.manual":"Start from scratch","import.progress":"Floor {i} of {n}","import.done":"Spaces created. Outline the rooms: click grid dots and close the contour.","btn.skip":"Skip","space.scale_label":"Scale (grid cell size)","space.scale_unit":"cm per cell","space.scale_unit_imperial":"in per cell","space.display_section":"Display","space.show_borders":"Always show room borders","space.zero_wall_style":"Zero-thickness walls","space.zero_wall_dashed":"Dashed","space.zero_wall_solid":"Solid","space.zero_wall_help":"Dashed walls let light through. Solid walls block light even at zero thickness.","space.show_names":"Show room names (drag to move)","space.room_color":"Border & name color","space.opacity":"Opacity","space.fill_label":"Room fill","fill.none":"None","fill.lqi":"Zigbee signal","fill.light":"Lights","fill.custom":"Custom color","space.custom_fill":"Fill color","space.source_file":"I have a floor-plan image","space.source_draw":"No image — I'll outline rooms by hand","space.orientation":"Canvas","orient.landscape":"Landscape","orient.portrait":"Portrait","orient.square":"Square","fill.temp":"Temperature","space.temp_min":"Comfort from","space.temp_max":"to","tip.temp_avg":"average temperature:","tip.hum_avg":"average humidity:","space_card.button":"Open the space plan","space_card.not_found":"Space “{id}” not found","space_card.loading":"Loading…","continuity.restore_plan":"Restoring floor plan…","continuity.restore_connection":"Restoring device connection…","continuity.retry":"Try again","editor.space":"Space","editor.show_button":"Show button","editor.button_label":"Button label","editor.button_target":"Target dashboard path","marker.sub_entity":"entity","title.general_settings":"General settings","gs.title":"General settings","gs.hint":"Fill colors apply to every space; each color has its own opacity. Which fill mode a space uses is set in that space's dialog.","gs.light_group":"Fill: lights","gs.light_on":"Lights on","gs.light_off":"All lights off","gs.temp_group":"Fill: temperature","gs.temp_cold":"Cold","gs.temp_ok":"Comfortable","gs.temp_hot":"Hot","gs.lqi_group":"Fill: zigbee signal","gs.lqi_low":"Weak signal","gs.lqi_high":"Strong signal","gs.reset":"Reset to defaults","gs.saved":"General settings saved","space.show_lqi":"Show zigbee signal (LQI) next to devices","space.hide_decor":"Hide the decorative layer","space.hide_decor_tip":"Lines, shapes, labels and furniture stay where they are — visible in the backdrop editor, not on the plan.","space.hide_openings":"Hide openings","space.hide_openings_tip":"Door, window and gate symbols are not drawn, but the openings keep working: light passes through, the sun comes in at a window, contact sensors still open them. The plan editor always shows them.","gs.light_none":"No light sources","mode.plan":"Plan editor","mode.devices":"Device editor","display.value":"Value + state","marker.subarea":"no area, manual","device.new":"New device — open its editor to dismiss","opening.unlock_action":"Unlock","opening.lock_action":"Lock","opening.lock_pending":"Working…","title.close_editor":"Close editor (back to view)","devbar.add":"Add","devbar.show_all":"Hidden and disabled","devbar.rules":"Icon rules","device_inbox.button":"Devices","device_inbox.title":"Devices on the plan","device_inbox.search":"Search devices, entities and integrations…","device_inbox.add_virtual":"Add virtual device","device_inbox.tab_on_plan":"On plan","device_inbox.tab_available":"Available","device_inbox.tab_hidden":"Hidden","device_inbox.tab_readd":"Available again","device_inbox.only_new":"New only","device_inbox.show_entities":"Show entities","device_inbox.show_hidden":"Show hidden on plan","device_inbox.new":"New","device_inbox.find":"Find on plan","device_inbox.edit":"Edit","device_inbox.hide":"Hide","device_inbox.show":"Show","device_inbox.add":"Add","device_inbox.readd":"Add again","device_inbox.hide_available":"Hide from list","device_inbox.show_more":"Show more","device_inbox.more_actions":"More actions","device_inbox.find_hidden_hint":"Enable “Show hidden on plan” first","device_inbox.show_disabled":"Activate this binding in Home Assistant before showing it","device_inbox.empty_on_plan":"No matching devices are on the plan yet.","device_inbox.empty_available":"No devices are available to add.","device_inbox.empty_hidden":"There are no hidden devices.","device_inbox.empty_readd":"No removed devices are available to add again.","device_inbox.reason_visible_auto":"Discovered automatically","device_inbox.reason_visible_explicit":"Added explicitly","device_inbox.reason_manual_hidden":"Hidden by user","device_inbox.reason_automatic_hidden":"Hidden automatically","device_inbox.reason_service_entry":"Service-only registry entry","device_inbox.reason_excluded_integration":"Integration excluded by device filters","device_inbox.reason_excluded_domain":"Non-spatial entity type","device_inbox.reason_grouped_light":"Represented by a room light group","device_inbox.reason_represented_by_parent":"Represented by its parent device","device_inbox.reason_removed":"Previously removed from the plan","device_inbox.reason_available":"Available to add to the plan","device_inbox.reason_no_bound_room":"HA area is not linked to a plan room","device_inbox.status_ha_disabled":"Disabled in Home Assistant","device_inbox.status_orphaned":"Binding is no longer present in Home Assistant","device_inbox.status_unverified":"Home Assistant registry is temporarily unavailable","device_inbox.saved":"Device list updated","space.roomcard_section":"Room card shows:","space.label_temp":"Temperature","space.label_hum":"Humidity","space.label_lqi":"Average Zigbee signal","space.label_light":"Lights on/off","roomcard.light_on":"On","roomcard.light_off":"Off","roomcard.light_partial":"{on} of {total}","toast.split_pick_inside":"Intermediate cut points must be inside the room","mode.decor":"Background editor","decor.select":"Select","decor.line":"Line","decor.rect":"Rectangle","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Erase","decor.erase_confirm_title":"Erase object?","decor.color":"Color","decor.width":"Line width","decor.line_style":"Line style","decor.line_style_solid":"Solid","decor.line_style_dashed":"Dashed","decor.fill":"Fill","decor.fill_color":"Fill color","decor.length":"Length","decor.size":"Size","decor.angle":"Rotation angle, °","decor.text_size":"Text size","decor.backdrop_properties":"Plan backdrop properties","decor.text_title":"Text label","decor.object_title":"Edit {kind}","decor.text_label":"Text","decor.live_group":"Insert HA variable","decor.live_entity":"Entity","decor.live_entity_ph":"choose an entity","decor.live_attr":"Value","decor.live_attr_ph":"choose state or attribute","decor.live_state":"State","decor.backdrop":"Backdrop image","decor.backdrop_hint":"Drag to move; pull a corner to resize; use the top handle to rotate. Shift changes proportions or frees the angle.","decor.backdrop_reset":"Reset the picture","decor.backdrop_reset_done":"The picture is back at its original place and size","marker.icon_auto":"Auto: {icon} (by icon rules; pick one to override)","marker.icon_pin_auto":"Pin","mode.plan_tip":"Plan editor — the geometry of the home: draw and split/merge rooms, bind them to HA areas, place doors, windows and gates, move room cards, set the scale","mode.devices_tip":"Device editor — everything about icons: drag to position, click to edit binding/icon/display, add virtual devices, icon rules","mode.decor_tip":"Background editor — purely visual decor under the plan: lines, rectangles, ovals and text labels that never react to clicks","space.glow_enabled":"Light-source glow","gs.glow_group":"Light-source glow","gs.glow_base":"House darkness","gs.glow_light":"Default light color / intensity","gs.wall_group":"Walls","gs.wall_fill":"Wall fill","gs.glow_radius":"Glow radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Controls other light sources","marker.controls_hint":"With tap action “Toggle”, a click flips every source added here. The marker’s own bound entity is controlled directly and cannot be added; use the switch below to classify it as a light.","marker.controls_filter":"Search lights and switches…","info.controls":"Controls","marker.glow_radius_label":"Glow radius","marker.glow_radius.help":"Sets the glow radius in metres or feet; an empty value uses the radius from general settings.","marker.glow_radius.help.aria":"Help: glow radius","markup.wallthick":"Thickness","markup.select":"Select","title.markup_wallthick":"Thickness — click a wall to set its thickness from 0 to 100 cm.","markup.hint_wallthick":"click a wall · Esc closes without applying","wallthick.field":"Thickness","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Apply to all walls of this room","markup.draw_wall_title":"Thickness of each new wall segment (0–100 cm). Shared walls keep the existing value.","room.queue_progress":"Room {current} of {total}","toast.wall_rooms_saved":"Created rooms: {n}","toast.wall_chain_saved":"Wall chain saved","toast.wallthick_pick":"Click a wall","toast.wallthick_set":"Wall thickness set","toast.wallthick_cleared":"Wall thickness removed","toast.physical_range":"Enter a value from {min} to {max} {unit}","toast.zero_wall_opening_conflict":"Remove the opening on this wall segment first.","toast.zero_wall_ambiguous":"The wall segment is ambiguous. Simplify or adjust the junction.","toast.zero_wall_migration_blocked":"The space was not converted: {reason}. No data was changed.","toast.physical_angle":"Enter a rotation angle from 0° up to, but not including, 90°","toast.physical_limit":"The space has reached the limit for this type of geometry","toast.geometry_unsafe":"Change canceled: wall geometry could not be built safely.","junction.limit_angle":"The angle between walls is too sharp: {actual}°, minimum {limit}°.","junction.limit_valence":"Too many walls meet in one node: {actual}, maximum {limit}.","junction.limit_length":"The wall segment is too short: {actual} cm, minimum {limit} cm.","junction.limit_distance":"Walls and nodes are too close: {actual} cm, minimum {limit} cm.","junction.limit_clearance":"No room interior is left: {actual} cm², minimum {limit} cm².","junction.limit_check_failed":"The junction check could not run — the change was not saved","toast.wall_model_migration_blocked":"The wall model could not be updated: {reason}. The plan was not changed. Run “Optimize plans”; if the error repeats, fix the conflicting wall geometry.","toast.wall_model_client_outdated":"Update the card and reload the page before editing the plan.","wall_model.reason.invalid-room":"invalid room contour","wall_model.reason.zero-length":"zero-length wall segment","wall_model.reason.third-owner":"wall shared by more than two rooms","wall_model.reason.duplicate-id":"conflicting wall identifiers","wall_model.reason.thickness-conflict":"conflicting wall thickness values","wall_model.reason.opening-host":"opening cannot be assigned to one wall","toast.delete_room_pick":"Click inside the room you want to delete","toast.plan_snap_ambiguous":"Zoom in to choose the wall node","toast.wall_repair_ambiguous":"The room outline has more than one possible connection. Zoom in and connect it explicitly.","toast.wall_repair_too_large":"The gap is larger than 2 cm. Connect the walls before creating the room.","toast.wall_repair_changed":"The wall geometry changed. Try creating the room again.","toast.opening_on_zero_wall":"Openings cannot sit on a zero-thickness wall","marker.from_ha_option":"Pick from the HA list","marker.show_entities":"Show entities","marker.show_entities_tip":"Adds not only devices to the list, but all their entities too","marker.pick_ph":"Choose a device…","room.open_area":"Open the HA area","view.volumetric":"Volumetric view","view.flat":"Flat view","kiosk.title":"This screen's sizes","kiosk.hint":"Stored on this device only — every wall tablet or TV can have its own comfortable sizes.","kiosk.icon_scale":"Device icon size","kiosk.font_scale":"Room card text size","editor.kiosk":"Wall device (kiosk) mode","editor.cycle":"Auto-switch spaces every N seconds (kiosk, 0 = off)","room.settings_title":"Room settings","room.settings_section":"Room settings (override the space)","room.fill_label":"Fill in THIS room","fill.inherit":"As the space","room.custom_fill_space":"Space color","room.custom_fill_own":"Room color","room.temp_src_label":"Temperature source","room.hum_src_label":"Humidity source","room.src_average":"Average over the room's sensors (default)","room.src_pick":"A specific HA device or entity","room.src_ph":"Choose a source…","toast.room_updated":"Room updated","space.card_font":"Room-card font size (whole space)","room.sizes_section":"Font sizes","room.name_scale":"Room name size","room.label_scale":"Metrics size","preview.room_name":"Living room","toast.cfg_reload_failed":"Could not reload the plan from the server: {err}","room.settings_short":"Room settings","room.unnamed":"Unnamed room","marker.use_climate_temp":"Include the device temperature in the room","marker.use_climate_temp_tip":"Adds an air conditioner or thermostat current_temperature to the room average. Configure the external value badge separately below.","marker.value_badge_title":"Value badge","marker.value_badge.help":"Shows one selected value next to the icon. It does not affect room metrics, light, Glow or the tap action.","marker.value_badge.help.aria":"Help: device value badge","marker.value_badge_enabled":"Show a value badge","marker.value_badge_source":"Value","marker.value_badge_source.help":"Choose a specific state, supported attribute, or derived value of this device.","marker.value_badge_source.help.aria":"Help: value badge source","marker.value_badge_position":"Position","marker.value_badge_position.help":"The chosen side stays fixed and does not flip automatically at a plan edge.","marker.value_badge_position.help.aria":"Help: value badge position","marker.value_badge_right":"Right","marker.value_badge_bottom":"Below","marker.value_badge_left":"Left","marker.value_badge_top":"Above","marker.value_badge_empty":"This device has no available values","marker.value_badge_static":"A static icon does not show live values. The setting is preserved.","marker.value_badge_missing":"Source unavailable","marker.value_badge_missing_hint":"The saved source is currently unavailable. Keep it, disable the badge, or choose another value.","marker.value_badge_duplicate":"The same value is already shown inside the icon.","marker.value_badge_state":"State · {name}","marker.value_badge_marker_state":"Light-source state · {name}","marker.value_badge_lqi":"Average Zigbee signal quality","marker.value_badge_attr_current_temperature":"Current temperature · {name}","marker.value_badge_attr_temperature":"Target temperature · {name}","marker.value_badge_attr_current_humidity":"Current humidity · {name}","marker.value_badge_attr_humidity":"Humidity · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Speed · {name}","marker.value_badge_attr_brightness":"Brightness · {name}","marker.value_badge_attr_volume_level":"Volume · {name}","marker.value_badge_attr_battery_level":"Battery · {name}","marker.value_badge_attr_fan_speed":"Fan speed · {name}","marker.light_role_label":"Is this device a light source?","marker.light_role.help":"Controls whether this marker itself is a spatial light source. Linked lights above remain independent room-light controls.","marker.light_role.help.aria":"Help: whether this device is a light source","marker.light_role_auto_yes":"Auto (light source)","marker.light_role_auto_no":"Auto (not a light source)","marker.light_role_always":"Always a light source","marker.light_role_never":"Never a light source","marker.light_entity_label":"Leading light entity","marker.light_entity.help":"For a composite device, choose the entity whose state, colour and brightness represent this plan source. The automatic fallback remains compatible with older plans.","marker.light_entity.help.aria":"Help: leading light entity","marker.light_entity_auto":"Automatic ({entity})","marker.light_entity_none":"no controllable entity","marker.light_entity_missing":"The saved entity {entity} is unavailable. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.toggle_entity_label":"Entity to toggle","marker.toggle_entity.help":"For a composite device, choose the exact own light or switch operated by a tap. Automatic keeps the previous target rules and is independent from the leading light entity.","marker.toggle_entity.help.aria":"Help: entity to toggle","marker.toggle_entity_auto":"Automatic ({entity})","marker.toggle_entity_none":"no own controllable entity","marker.toggle_entity_missing":"The saved entity {entity} is no longer among this marker’s selectable channels. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.glow_color_label":"Glow colour and brightness","marker.glow_mode.help":"Use live source values, override only its colour, or fix both colour and brightness. The minimum is 1%; to disable the source, choose “Never”.","marker.glow_mode.help.aria":"Help: glow colour and brightness","marker.glow_mode_auto":"From source","marker.glow_mode_color":"Set colour","marker.glow_mode_fixed":"Set colour and brightness","marker.glow_color":"Glow colour","marker.glow_brightness":"Brightness","marker.glow_disabled_never":"Glow settings are unavailable because this marker is explicitly not a light source.","marker.glow_disabled_auto":"Auto mode found no spatial light source for this marker.","marker.glow_disabled_no_entity":"No active controllable Home Assistant entity is available for this spatial source.","marker.glow_passive_hint":"This source has no own Home Assistant data. Set its colour and brightness manually; its radius remains available.","marker.control_broken":"Saved source is missing or no longer marked as a light","marker.control_missing_label":"Missing plan light","marker.control_passive":"passive source","toast.marker_control_cycle":"This link would create a circular chain of light controls.","toast.marker_binding_required":"Choose a Home Assistant device before linking another light source.","confirm.unlock":"Unlock “{name}”?","toast.files_migrate_failed":"Attachments could not be moved to the new binding, links keep pointing at the old files: {err}","space.pick_saved":"Already uploaded","space.pick_saved_hint":"Plans stored on the server, including ones you detached earlier","space.no_saved":"No plans stored on the server yet.","space.loading":"Loading…","space.used_by":"in use: {list}","space.in_use":"A space still uses this plan — detach it first","btn.use":"Use","confirm.delete_plan":'Delete the plan file "{name}" from the server? This cannot be undone.',"toast.plans_list_failed":"Could not list the stored plans: {err}","toast.plan_delete_failed":"Could not delete the plan: {err}","marker.hide":"Hide","marker.hide_tip":'The device will disappear from the plan after saving but will still count toward the room signal. Restore it through the "Devices" catalog in the device editor.',"marker.show":"Show","marker.show_tip":"The device will appear on the plan again after saving.","marker.hidden_ghost":"Device hidden by the user","marker.ha_disabled_device":"The device is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_entity":"The entity is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_all_entities":"The device has no active Home Assistant entities, so it is hidden from the plan.","marker.ha_registry_limited":"The full Home Assistant registry is unavailable to this user. The unverified object cannot be shown or used for now.","marker.delete_tip":"Completely delete the device from the plan and every aggregate. You can add it again later.","tap.run":"Run automation/script/scene","tap.cover":"Open/close (curtains/blinds)","marker.run_target_label":"What to run","marker.run_search_ph":"Search: automation, script or scene…","marker.run_target_gone":"Target {id} not found — pick again","marker.tap_confirm":"Ask for confirmation","marker.tap_confirm_tip":"Show a confirmation dialog before acting — a guard against accidental taps.","marker.toggle_hint_single":"Target: {name} ({id}).","marker.virtual_light_target":"Virtual light: {name}.","marker.virtual_light_current":"Manual state: {state} → {effect}.","marker.virtual_light_state_on":"on","marker.virtual_light_state_off":"off","marker.toggle_hint_group":"Will toggle {count} source(s): {names}.","marker.toggle_hint_current":"Now: {state} → {effect}.","marker.toggle_hint_group_current":"Currently on: {on} of {count} → {effect}.","marker.toggle_hint_skipped":"Will be skipped ({count}): {targets}.","marker.toggle_effect_turn_on":"will turn on","marker.toggle_effect_turn_off":"will turn off","marker.toggle_effect_open":"will open","marker.toggle_effect_close":"will close","marker.toggle_effect_stop":"will stop","marker.toggle_effect_toggle":"state will toggle","marker.toggle_skip_missing":"not found","marker.toggle_skip_ha_disabled":"disabled in HA","marker.toggle_skip_unavailable":"unavailable","marker.toggle_skip_unsupported":"toggle is unsupported","marker.toggle_skip_secure":"blocked for security","marker.toggle_none_no_binding":"This device has no binding, so there is no state to toggle. Tapping will do nothing.","marker.toggle_none_no_actionable_entity":"This device has no state that can be toggled. Tapping will do nothing.","marker.toggle_none_configured_targets_missing":"The configured targets are unavailable. The device's own entity will not be substituted for them.","marker.toggle_none_ha_disabled":"The target is disabled in Home Assistant and cannot be used on the plan.","marker.toggle_none_unavailable":"The target is currently unavailable. Tapping will do nothing.","marker.toggle_none_unsupported":"Home Assistant exposes no safe toggle operation for this entity. Tapping will do nothing.","marker.toggle_none_secure":"Toggling locks, alarms and secure gates from the plan is blocked for security.","run.automation":"automation","run.script":"script","run.scene":"scene","confirm.tap_run":'Run "{name}"?',"confirm.tap_toggle":'Toggle "{name}"?',"confirm.tap_cover":'Open/close "{name}"?',"confirm.current_state":"Current state: {state}","confirm.expected_state":"After switching: {state}","confirm.group_current":"on {on} of {total}","confirm.group_all_on":"all are on","confirm.group_all_off":"all are off","confirm.unavailable_targets":"Unavailable: {count}","confirm.expected_by_ha":"Home Assistant will determine the state","confirm.state_on":"On","confirm.state_off":"Off","confirm.state_open":"Open","confirm.state_closed":"Closed","confirm.state_opening":"Opening","confirm.state_closing":"Closing","confirm.state_stopped":"Stopped","confirm.state_unknown":"Unknown","toast.run_started":"Started: {name}","toast.run_target_missing":"Run target not found — check the device settings","toast.run_target_required":"Pick an automation, script or scene","toast.tap_target_changed":"The action target changed. Try again.","toast.virtual_light_toggle_failed":"Could not toggle the virtual light: {err}","toast.value_badge_source_required":"Choose a value for the badge","btn.run":"Run","vac.section":"Robot vacuum: live position","vac.autocal":"Set up automatically","vac.live":"Live position on the plan","vac.trail":"Show the robot's path","vac.cal_maps":"Calibrated maps: {maps}","vac.autocal_no_rooms":"The integration reports no room list — open “Fit manually”","vac.autocal_no_match":"Room names did not match (need ≥3 in common) — open “Fit manually”","vac.autocal_done":"Done: bound via {rooms} rooms. Start a cleanup and check","vac.cal_need_pos":"The robot is not reporting coordinates — start a cleanup and pause it","vac.cal_done":"Calibration saved. Start a cleanup and check","vac.cal_cancelled":"Calibration cancelled","vac.fit":"Fit manually","vac.fit_hint":"Drag the robot map into place, stretch by the corners","vac.fit_rotate":"Rotate 90°","vac.fit_mirror":"Mirror","vac.trail_never":"Never","vac.trail_cleaning":"While cleaning","vac.trail_always":"Always","gs.bg_group":"Stage background","gs.bg_color":"Background around the plan","gs.bg_default":"Theme default","gs.bg_theme":"theme default","gs.bg_mode":"Plan background","gs.bg_static":"Static color","gs.bg_daynight":"Follows the Sun","gs.bg_daynight_hint":"The background moves through dawn, day, dusk and night using sun.sun, or your local clock when sun data is unavailable. No compass is needed for the background.","gs.sun_group":"Sun","gs.sun_missing":"The sun.sun entity was not found — the background follows your local clock; window rays are unavailable.","gs.north":"North on the plan","gs.north_ph":"not set","gs.north_hint":"Set north only for window rays (1° steps, 15° with Shift); the Sun background works without it.","gs.north_clear":"Clear","gs.north_letter":"N","gs.sun_rays":"Sunlight through windows","gs.about_group":"About","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · docs & issues","gs.about_telegram":"Telegram chat","space.bg_color":"Background around the plan","space.bg_inherit":"Inherit general","space.bg_inherited":"inherits general settings","space.bg_mode":"Plan background","space.north":"North on the plan (override)","space.north_inherited":"inherited: {v}","space.sun_rays":"Sunlight through windows","space.sun_inherit":"Inherit general","space.sun_on":"On","space.sun_off":"Off","canvas.far_objects":"{n} object(s) far from the plan","canvas.show_far":"Show","canvas.home_tip":"The plan is over there — click to fit it","gs.grid_group":"Plan maintenance","gs.grid_hint":"Updates data models, aligns plan elements to the grid and merges redundant wall fragments. An exact report is shown before anything is stored.","gs.align_all":"Optimize plans","gs.align_title":"Optimize plans","gs.align_none":"All plans already use the current optimized data model.","gs.optimize_no_automatic_changes":"There are no automatic changes to apply. Review the items below.","gs.align_count":"{n} of {total} elements will move, by at most {cm} cm.","gs.align_where":"The largest shift is in “{s}”.","gs.align_turned":"Openings whose angle is corrected: {n}.","gs.align_removed_drafts":"Invalid outlines collapsed by the grid and removed: {n}.","gs.optimize_redundant_drafts":"Saved wall chains hidden by solid room walls and removed: {n}.","gs.align_preflight_failed":"Could not safely verify the geometry of the following spaces: {spaces}{more}.","gs.align_preflight_hint":"Plans were not changed. Copy the diagnostics with the button below and attach them to the bug report together with a space export.","gs.preflight_reason_prepare-exception":"Could not prepare the space geometry (exception while building the model)","gs.preflight_reason_wall-null":"The wall body did not build (the union came back empty)","gs.preflight_reason_wall-degraded-extra":"The wall body degraded with extra geometry","gs.preflight_reason_wall-failed-core":"The wall body core failed to assemble","gs.preflight_reason_wall-exception":"Wall construction threw an exception","gs.preflight_reason_floor-null":"The floor outline did not build","gs.preflight_reason_floor-exception":"Floor construction threw an exception","gs.preflight_copy":"Copy diagnostics","gs.preflight_copied":"Diagnostics copied","gs.preflight_update_hint":"The card and integration versions differ — update House Plan and retry.","gs.align_preflight_space":"Space {n}","gs.align_preflight_more":", and {n} more","gs.optimize_changes":"Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.","gs.zero_walls_migrated":"Virtual wall spans converted: {n}.","gs.wall_segments_migrated":"Wall segments stabilised: {n}.","gs.optimize_lattice_summary":"Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.","gs.optimize_lattice_space":"{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.","gs.optimize_coincident_partitions":"Hidden independent wall sections absorbed into room walls: {n}.","gs.optimize_openings_rehosted":"Openings reattached to room walls: {n}.","gs.optimize_walls_straightened":"Walls straightened: {n}; maximum movement: {cm} cm.","gs.optimize_walls_straightened_where":"Largest wall correction: {s}.","gs.optimize_walls_straighten_skipped":"Near-axis walls left unchanged because they could not be repaired safely: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} spaces → no data fill + independent Glow; {rooms} rooms → inherited data fill + independent Glow.","gs.optimize_references":"References repaired: spaces — {spaces}; rooms — {rooms}; positions — {positions}; devices detached from missing spaces — {detached}.","gs.optimize_reference_more":", and {n} more","gs.optimize_orphans_removed":"Forgotten records removed: {total} — room labels: {rooms}; devices: {devices}; group markers: {groups}. They belonged to spaces deleted earlier.","gs.optimize_live_positions":"Old positions in deleted spaces belong to existing objects: {n}{names}. They will be kept.","gs.optimize_live_positions_remove":"Old positions in deleted spaces belong to existing objects: {n}{names}. They are selected for removal.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Remove old positions","gs.optimize_live_keep":"Keep old positions","gs.optimize_live_selected":"Old positions will be removed after Optimize is applied.","gs.optimize_unverified":"Could not safely verify positions: {n}. They were left unchanged.","gs.optimize_registry_limited":"Full administrator access to the Home Assistant registries is required for a safe check.","gs.optimize_vacuum_warning":"Vacuum room mappings that still need review: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"And {n} more records.","gs.optimize_detail_removed":"will be removed","gs.optimize_detail_live":"will be kept","gs.optimize_detail_unverified":"not verified","gs.optimize_detail_room_label":"room label","gs.optimize_detail_device":"device","gs.optimize_detail_group":"group marker","gs.optimize_detail_unknown":"unknown owner","gs.optimize_detail_item":"{status}: {kind} {id}; old space {space}","gs.align_warn":"Elements deliberately placed between grid nodes will move. One undo is available after the operation, only until the next plan edit.","gs.align_run":"Optimize","gs.align_done":"Plans optimized: {n} elements moved, {m} records maintained, {r} references repaired","gs.optimize_undo":"Undo last optimization","gs.optimize_undone":"The last optimization was undone","decor.furniture":"Furniture","furn.title":"Furniture library","furn.symbol":"Symbol","furn.group_furniture":"Furniture","furn.group_appliance":"Appliances","furn.group_sanitary":"Plumbing","furn.group_other":"Other","furn.width":"Width","furn.depth":"Depth","furn.pick_hint":"Pick a symbol, then click on the plan.","furn.place_hint":"Click on the plan — the piece lands against the nearest wall. Shift places it free.","furn.sym_sofa":"Sofa","furn.sym_armchair":"Armchair","furn.sym_coffee_table":"Coffee table","furn.sym_table_dining":"Dining table","furn.sym_table_round":"Round table","furn.sym_chair":"Chair","furn.sym_desk":"Desk","furn.sym_bed_double":"Double bed","furn.sym_bed_single":"Single bed","furn.sym_nightstand":"Nightstand","furn.sym_wardrobe":"Wardrobe","furn.sym_bookshelf":"Bookshelf","furn.sym_fridge":"Fridge","furn.sym_stove":"Cooker","furn.sym_dishwasher":"Dishwasher","furn.sym_washer":"Washing machine","furn.sym_dryer":"Tumble dryer","furn.sym_tv":"TV","furn.sym_ac":"Air conditioner","furn.sym_water_heater":"Water heater","furn.sym_toilet":"Toilet","furn.sym_bathtub":"Bathtub","furn.sym_shower":"Shower","furn.sym_sink":"Washbasin","furn.sym_kitchen_sink":"Kitchen sink","furn.sym_bidet":"Bidet","furn.sym_stairs":"Stairs","furn.sym_fireplace":"Fireplace","furn.sym_plant":"Plant","furn.sym_rug":"Rug","common.yes":"Yes","common.no":"No","vac.diag_source":"Source","vac.diag_platform":"Integration","vac.diag_status":"Status","vac.diag_position":"Position","vac.diag_rooms":"Rooms","vac.diag_rooms_value":"{total} · {matched} names match · {readiness}","vac.autocal_ready":"auto-calibration available","vac.autocal_not_ready":"need 3 matching names","vac.diag_path":"Integration path","vac.diag_map":"Map ID","vac.source_none":"not selected","vac.source_status_ok":"Ready","vac.source_status_missing":"Missing","vac.source_status_disabled":"Disabled in Home Assistant","vac.source_status_unavailable":"Unavailable","vac.source_status_unverified":"Cannot verify with current permissions","vac.source_status_unsupported":"No position data","vac.source_status_none":"No source","vac.source_banner_missing":"The saved source no longer exists. It was not replaced automatically; choose another source or restore it in Home Assistant.","vac.source_banner_disabled":"The saved source is disabled in Home Assistant. Enable it there or choose another source.","vac.source_banner_unverified":"Current Home Assistant permissions cannot verify this saved source. It remains pinned and will not be replaced automatically.","vac.choose_source":"Choose source","vac.source_auto":"Automatic","vac.source_auto_hint":"Use a compatible entity from this device","vac.all_cameras":"All cameras","vac.all_cameras_warn":"A camera may not provide robot data. Choose one only if it is your vacuum map.","vac.all_cameras_empty":"No other camera entities found.","vac.platform_unknown":"unknown integration","vac.cap_position":"position","vac.cap_rooms_short":"rooms","vac.cap_path":"path","vac.cap_map":"map ID","vac.cap_none":"no robot data detected","vac.xcme_hint":"Enable these Xiaomi Cloud Map Extractor attributes:","vac.documentation":"Documentation","vac.residual_title":"Check automatic calibration","vac.residual_message":"The matched rooms disagree by up to {error}. Apply this approximate calibration, refine it manually, or cancel without changing the saved setup.","vac.apply_proposal":"Apply","gs.backup_group":"Backup and transfer","gs.backup_hint":"Download a portable JSON backup or preview and import a backup made by House Plan.","backup.export_open":"Export","backup.import_open":"Import","backup.export_title":"Export House Plan","backup.import_title":"Import House Plan","backup.export_hint":"Choose whether the backup should contain the whole House Plan configuration or only the current space.","backup.full":"Full backup","backup.current_space":"Current space","backup.current_space_title":"Current space: {title}","backup.no_current_space":"No current space","backup.plan_only":"Plan only","backup.plan_only_hint":"Keep rooms, walls, openings, decor and room-label positions without devices or Home Assistant bindings.","backup.plan_only_preview":"This file contains the plan only","backup.privacy_warning":"The archive keeps names, Home Assistant identifiers and exact coordinates. Internal plans and attachments are referenced, not embedded; runtime states and vacuum trails are not included.","backup.download":"Download JSON","backup.export_done":"Backup downloaded","backup.reading":"Checking the backup…","backup.revalidated":"The plan changed after this preview. The summary was refreshed; review it and confirm again.","backup.error.unauthorized":"You do not have permission to export or import this plan.","backup.error.not_ready":"House Plan is not ready yet. Try again in a moment.","backup.error.too_large":"The backup exceeds the 8 MiB limit.","backup.error.invalid_json":"The selected file is not valid JSON.","backup.error.invalid_format":"The selected file is not a House Plan backup.","backup.error.unsupported_export_version":"This backup format is not supported by the installed version.","backup.error.future_model":"The backup was created by a newer House Plan data model.","backup.error.invalid_config":"The backup contains an invalid House Plan configuration.","backup.error.wall_model_migration_blocked":"The backup wall model could not be upgraded safely. Optimize the source plan first, then export it again.","backup.error.invalid_layout":"The backup contains invalid object positions.","backup.error.invalid_content":"The backup contains invalid or inconsistent content references.","backup.error.space_not_found":"The selected space no longer exists.","backup.error.capacity_exceeded":"Adding this backup would exceed the plan limits.","backup.error.preview_expired":"The preview expired. Select the backup file again.","backup.error.preview_owner_mismatch":"This preview belongs to another Home Assistant user.","backup.error.conflict":"The plan changed after the preview. Review the refreshed summary.","backup.error.content_confirmation_required":"Confirm that unavailable local content may be detached.","backup.error.commit_failed":"The backup could not be applied safely. The previous plan was restored or is pending recovery.","backup.error.missing_plan":"A referenced plan file disappeared after the preview. Review the backup again.","backup.error.missing_content":"A referenced local attachment disappeared after the preview. Review the backup again.","backup.error.marker_control_missing":"A linked plan light is missing from the backup.","backup.error.marker_control_not_light":"A linked plan target is no longer marked as a light source.","backup.error.marker_control_self":"A light source cannot control itself.","backup.error.marker_control_cycle":"The backup contains a circular chain of light controls.","backup.error.duplicate_marker_control":"The backup contains a duplicate plan-light link.","backup.error.no_backup":"There is no import or optimization snapshot to restore.","backup.same_source":"Created on this Home Assistant instance","backup.foreign_source":"Created on another Home Assistant instance","backup.created":"Created: {value}","backup.versions":"Card {card}; integration {integration}; data model {model}","backup.count_spaces":"Spaces: {n}","backup.count_rooms":"Rooms: {n}","backup.count_walls":"Walls: {n}","backup.count_openings":"Openings: {n}","backup.count_decor":"Decor objects: {n}","backup.count_markers":"Devices: {n}","backup.count_layout":"Positions: {n}","backup.bindings":"Bindings — devices: {device}, entities: {entity}, virtual: {virtual}; positions without a space: {legacy}","backup.binding_status":"Target status — active: {active}, disabled: {disabled}, missing: {missing}","backup.missing_areas":"Areas missing on the target: {areas}","backup.dropped_marker_links":"Plan-light links outside this transferred space were omitted: {n}.","backup.repaired_target_refs":"Existing references restored by this space import: {n}.","backup.preserved_unresolved_refs":"References that could not be restored unambiguously were preserved: {n}.","backup.preserved_unresolved_hint":"No data was guessed or deleted. After the import, run Optimize plans to inspect the remaining references.","backup.import_details":"Import reference details","backup.import_detail.incoming_remapped":"References updated inside the imported copy: {n}","backup.import_detail.target_repaired":"Existing references restored: {n}","backup.import_detail.preserved_unresolved":"Unresolved references preserved: {n}","backup.import_detail.collisions":"Destination conflicts preserved safely: {n}","backup.import_detail.dropped_links":"Incoming links omitted by transfer rules: {n}","backup.import_detail.bounded_lineages":"Overly nested identifiers left bounded: {n}","backup.replace_warning":"This replaces the current configuration and layout. Uploaded files are never deleted. One undo remains available until the next plan edit.","backup.foreign_bookkeeping":"Instance-specific known/new-device bookkeeping will not be imported.","backup.final_name":"New space name","backup.target_settings":"The target instance's global settings remain unchanged.","backup.duplicates":"Bindings already present: {n}","backup.skip":"Skip duplicate devices","backup.virtual_copy":"Add safe static virtual copies","backup.content":"Referenced content","backup.content_available":"available locally","backup.content_external":"external link","backup.content_detach_required":"will be detached","backup.confirm_detach":"I understand that unavailable internal plans and attachments will be detached from the imported configuration.","backup.replace":"Replace","backup.add":"Add space","backup.space_done":"Space imported: {rooms} rooms, {markers} devices, {refs} existing references restored","backup.full_done":"Backup restored: {spaces} spaces, {rooms} rooms, {markers} devices","backup.undo_import":"Undo last full import","backup.import_undone":"Full import undone"};const Ud=[{code:"en",nativeLabel:"English",dictionary:Wd},{code:"ru",nativeLabel:"Русский",dictionary:{"editor.context_actions":"Действия: {object}","editor.tool_options":"Параметры инструмента: {tool}","editor.palette":"Палитра: {tool}","editor.open_group":"Группа инструментов: {group}","editor.group_active":"{group} — активно: {item}","editor.disabled_action":"{action} недоступно: {reason}","editor.loading":"Загружаем редактор…","editor.loading_aria":"Редактор плана загружается","editor.load_failed":"Не удалось загрузить редактор.","editor.refresh_advice":"Обновите страницу и повторите попытку.","color_picker.title":"Выбор цвета","color_picker.hue":"Оттенок","color_picker.saturation":"Насыщенность","color_picker.value":"Яркость","color_picker.hex":"Цвет HEX","color_picker.invalid_hex":"Введите цвет HEX из 3 или 6 цифр","btn.properties":"Свойства","btn.keep_as_walls":"Оставить стенами","btn.delete_room_keep_walls":"Удалить комнату, оставить стены","btn.delete_room_with_walls":"Удалить комнату и стены","title.markup_select":"Выбор и редактирование стен, колонн и сохранённых контуров","title.markup_column":"Колонна: кликните точку сетки для квадратной колонны","markup.partition":"Перегородка","markup.column":"Колонна","markup.hint_column":"кликните точку сетки, чтобы поставить квадратную колонну","history.draft_segment":"Добавление сегмента черновика комнаты","history.draft_merge":"Соединение незавершённых контуров комнаты","history.draft_segment_delete":"Удаление сегмента черновика комнаты","history.partition_add":"Добавление перегородки","history.column_add":"Добавление колонны","history.physical_edit":"Изменение физического объекта","history.physical_delete":"Удаление физического объекта","history.physical_move":"Перемещение физического объекта","history.contour_to_partitions":"Преобразование контура в замкнутые стены","history.wall_chain_finish":"Завершение цепочки стен","history.wall_face_batch":"Создание комнат из стен","toast.column_duplicate":"Колонна с тем же центром и внешним размером уже существует","confirm.delete_draft":"Удалить весь незавершённый контур комнаты?","confirm.delete_draft_segment":"Удалить этот сегмент черновика? Оставшийся контур может разделиться на два.","physical.partition_properties":"Свойства перегородки","physical.column_properties":"Свойства колонны","physical.draft_properties":"Свойства сегмента черновика","physical.shape":"Форма","physical.square":"Квадрат","physical.circle":"Круг","physical.diameter":"Диаметр","physical.side":"Сторона","physical.rotation":"Угол поворота","physical.length":"Длина","physical.allowed_range":"Допустимо: {min}–{max} {unit}","physical.delete_segment":"Удалить сегмент","physical.delete_draft":"Удалить весь контур","physical.column_size_title":"Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).","card.title":"План дома","count.devices":"{n} устр.","empty.no_spaces":"Пространств пока нет.","empty.add_first":"Добавьте первое пространство и загрузите план этажа.","empty.install":"Установите интеграцию House Plan и добавьте запись в «Устройства и службы».","btn.add_space":"Добавить пространство","btn.cancel":"Отмена","btn.save":"Сохранить","btn.close":"Закрыть","btn.delete":"Удалить","btn.edit":"Редактировать","btn.open_in_ha":"Открыть в HA","btn.reset":"Сброс","btn.attach":"Прикрепить…","btn.upload":"Загрузить…","btn.replace":"Заменить…","title.zoom_in":"Приблизить","title.zoom_out":"Отдалить","title.zoom_fit":"Вписать всё","title.add_device":"Добавить устройство на план","title.show_all":"Показать скрытые и деактивированные устройства служебными маркерами (только в этой вкладке)","title.markup":"Разметка комнат: сетка, линии, контуры","title.configure_space":"Настроить пространство","title.add_space":"Добавить пространство","title.markup_add":"Стены: рисуйте непрерывную цепочку; Shift фиксирует 45°. Смена инструмента или выход завершает её как независимые стены","title.markup_merge":"Объединить: клик по одной комнате, затем по соседней с общей стеной","title.markup_split":"Разделить комнату: клик по комнате, затем две точки на её стенах","title.markup_delroom":"Удалить комнату: кликните внутри комнаты и подтвердите удаление","title.need_plan":"Загрузите подложку (план этажа)","markup.add":"Стены","markup.merge":"Объединить","markup.split":"Разделить","markup.resize":"Размер","title.markup_resize":"Изменение размера комнат: тяните доступную ручку горизонтальной или вертикальной стены","markup.hint_resize":"тяните доступную ручку стены · стена упирается в первую небезопасную позицию · Esc — отмена · Ctrl+Z — отмена шага","resize.disabled.diagonal":"Стена расположена под углом: Resize поддерживает только горизонтальные и вертикальные стены","resize.disabled.side-angle":"Примыкающая стена расположена под углом: для Resize обе примыкающие стены должны образовывать прямой угол","resize.disabled.duplicate-physical-wall":"Стену перекрывает отдельная перегородка, незавершённый контур или колонна; удалите или переместите её перед изменением размера","resize.disabled.partial-shared":"Соседняя комната использует только часть этой стены, поэтому её нельзя безопасно двигать как одну общую стену","resize.disabled.unequal-shared":"У соседней комнаты другие конечные точки или длина стены, поэтому стены нельзя безопасно двигать вместе","resize.disabled.multiple-rooms":"Перемещение затронуло бы больше двух комнат","resize.disabled.thickness-conflict":"Толщину стены нельзя безопасно сохранить","resize.disabled.opening-conflict":"Проём на этой стене нельзя безопасно переместить","resize.disabled.invalid-geometry":"Эту стену нельзя переместить без изменения структуры плана","resize.limit_stopped":"Стена остановлена: дальше нарушается ограничение стыков","resize.commit_failed":"Изменение размера отменено: итоговый план не прошёл проверку геометрии","resize.preview_failed":"Стена остановлена в последней безопасной позиции: геометрию плана нельзя сохранить без потерь","markup.opening":"Проём","markup.delete_room":"Удалить комнату","history.undo":"Отменить","history.redo":"Повторить","history.undo_named":"Отменить: {name} (Ctrl+Z)","history.redo_named":"Повторить: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Нет операций для отмены","history.redo_empty":"Нет операций для повтора","history.undone":"Отменено: {name}","history.redone":"Повторено: {name}","history.add_room":"Создание комнаты","history.split_room":"Разделение комнаты","history.merge_rooms":"Объединение комнат","history.resize_room":"Изменение размера комнаты","history.wall_thickness":"Изменение толщины стены","history.add_opening":"Добавление дверного или оконного проёма","history.edit_opening":"Изменение проёма","history.move_opening":"Перемещение проёма","history.delete_opening":"Удаление проёма","history.delete_room":"Удаление комнаты","history.delete_room_keep_walls":"Удаление комнаты с сохранением стен","history.delete_room_with_walls":"Удаление комнаты и её стен","history.decor_add":"Добавление объекта декора","history.decor_edit":"Изменение объекта декора","history.decor_move":"Перемещение объекта декора","history.decor_transform":"Трансформация объекта декора","history.decor_delete":"Удаление объекта декора","history.backdrop_transform":"Трансформация подложки плана","title.markup_opening":"Проёмы: клик по стене — добавить, клик по проёму — редактировать","opening.new":"Новый проём","opening.edit":"Проём","opening.door":"Дверь","opening.window":"Окно","opening.gate":"Ворота","opening.passage":"Открытый проём","opening.passage_binding_warning":"При сохранении датчик открытия и замок будут удалены.","opening.invalid_passage_fields":"У открытого проёма на плане «{room}» есть недопустимые параметры: {fields}.","opening.type_label":"Тип","opening.length_label":"Длина, см","opening.contact_label":"Датчик открытия","opening.lock_label":"Замок","opening.none":"— нет —","opening.search_ph":"Поиск: имя или entity_id…","opening.invert":"Инвертировать открыто/закрыто","opening.flip_h":"Петли с другой стороны","opening.flip_v":"Открывается в другую сторону","opening.open":"Открыто","opening.closed":"Закрыто","opening.locked":"Заперто","opening.unlocked":"Не заперто","opening.state_unknown":"недоступно","opening.no_entities":"Датчики не привязаны — статичный символ на плане.","toast.opening_no_wall":"Кликните рядом со стеной комнаты или независимой стеной","opening.host_partition":"Независимая стена","opening.partition_orphan":"Независимая стена этого проёма больше не существует","opening.partition_jamb_margin":"Оставьте от края проёма до торца стены минимум {distance}","opening.rebind_partition":"Привязать к другой независимой стене","confirm.delete_partition_openings_title":"Удалить стену и проёмы?","confirm.delete_partition_openings_body":"В стене есть проёмы: {count}. Они будут удалены вместе со стеной.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Удалить","markup.hint_points":"точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната","markup.hint_start":"кликните точку сетки, чтобы начать цепочку стен","tip.lqi":"средний сигнал zigbee:","tip.area":"площадь: {value}","info.device_header":"Устройство на плане","info.model":"Модель","info.state":"Состояние","info.link":"Ссылка","info.manuals":"Инструкции","info.none":"Нет дополнительной информации","marker.new_device":"Новое устройство","marker.name_label":"Имя (отображается на плане)","marker.name_ph":"Название","marker.binding_label":"Привязка к устройству HA","marker.binding_disabled":"деактивировано в Home Assistant","marker.virtual_option":"Виртуальное устройство (без привязки)","marker.search_ph":"Поиск устройства / группы…","marker.nothing_found":"ничего не найдено","marker.room_label":"Комната","marker.room_override":" (переопределить размещение)","marker.room_choose":"— выберите комнату —","marker.room_auto":"— по зоне устройства (авто) —","marker.icon_label":"Иконка","marker.icon_ph":"mdi:… (пусто = авто)","marker.display_label":"Отображение","display.badge":"Значок + состояние","display.icon_ripple":"Значок + состояние и активность","display.static_icon":"Всегда статичный значок","marker.display_hint":"Значок + состояние меняет подложку при работе, открытии, тревоге и недоступности. Значок + состояние и активность дополнительно показывает короткую пульсацию для событий и постоянную — для работы, движения или присутствия. Значение + состояние заменяет значок одним однозначным значением HA. Статичный значок не реагирует на состояния устройства.","marker.display_hint_badge":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon_ripple":"Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.","marker.display_hint_value":"Значок заменяется одним однозначным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.","marker.display_hint_static_icon":"Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.","marker.static_alarm_warning":"Это устройство может сообщать о тревогах. Статичный режим скрывает визуальную тревогу маркера.","marker.preview.title":"Предпросмотр отображения","marker.preview.actual":"Сейчас","marker.preview.example":"Пример","marker.preview.integration":"Интеграция","marker.preview.source":"Источник отображения","marker.preview.current_state":"Текущее состояние","marker.preview.result":"На плане","marker.preview.details":"Подробнее об источниках","marker.preview.select_source":"Выберите устройство или сущность Home Assistant, чтобы увидеть фактическое отображение.","marker.preview.unknown_provider":"Интеграция неизвестна","marker.preview.virtual_provider":"House Plan · виртуальное устройство","marker.preview.no_source":"Нет активного источника","marker.preview.no_state":"Нет текущего состояния","marker.preview.mixed_states":"Несколько разных состояний","marker.preview.multiple_sources":"Источников: {n}","marker.preview.more_sources":"ещё {n}","marker.preview.scaled":"Предпросмотр уменьшен до {n}%, чтобы поместиться. Сохранённый размер не изменится.","marker.preview.demo_activity":"Показать пример активности","marker.preview.demo_notice":"Временный пример активности; фактическое состояние устройства не меняется.","marker.preview.demo_short":"Показать краткую активность","marker.preview.demo_continuous":"Показать постоянную активность","marker.preview.stop_continuous":"Остановить постоянную активность","marker.preview.demo_short_notice":"Пример краткой активности; фактическое состояние устройства не меняется.","marker.preview.demo_continuous_notice":"Пример постоянной активности; фактическое состояние устройства не меняется.","marker.preview.demo_already_visible":"Текущее состояние уже показывает реальную активность или тревогу.","marker.preview.reduced_motion":"В системе включено уменьшение движения, поэтому обычная активность показана точкой.","marker.preview.reason.neutral":"Нейтральная тёмная подложка","marker.preview.reason.working":"Жёлтая подложка: устройство сейчас работает","marker.preview.reason.working_activity":"Жёлтая подложка и эффект активности: устройство сейчас работает","marker.preview.reason.open":"Оранжевая подложка: физически открыто или разблокировано","marker.preview.reason.cover_icon_state":"Нейтральная подложка; состояние и значок определяет сущность шторы или заслонки","marker.preview.reason.presence":"Эффект активности, пока обнаружено присутствие","marker.preview.reason.event":"Короткий эффект активности после события","marker.preview.reason.transition":"Эффект активности во время движения или смены состояния","marker.preview.reason.media_neutral":"Медиаустройство остаётся на нейтральной тёмной подложке, пока доступно","marker.preview.reason.unavailable":"Приглушённая нейтральная подложка: отключено или недоступно","marker.preview.reason.alarm":"Красная тревожная подложка; тревога отображается всегда","marker.preview.reason.live_states_disabled":"Оформление по живым состояниям отключено в настройках карточки","marker.preview.reason.value_no_state":"Нет подходящего значения состояния — вместо него показан значок","marker.preview.reason.value_ambiguous_sources":"Подходит несколько источников значения — вместо него показан значок","marker.preview.reason.value_non_scalar":"Источник вернул не простое значение — вместо него показан значок","marker.preview.reason.value_virtual":"У виртуального устройства нет значения HA — вместо него показан значок","marker.preview.reason.vacuum_live_plan_only":"Живая позиция и след пылесоса доступны только на полном плане","marker.preview.reason.hidden_design_preview":"Устройство скрыто на плане, но его оформление видно в предпросмотре","marker.preview.reason.composite_power_source":"Состояние берётся из сущности питания устройства; вспомогательные переключатели не учитываются","marker.preview.reason.activity_display_disabled":"Выбранный режим отображения не показывает обычные эффекты активности","marker.preview.reason.ha_disabled":"Привязка отключена в Home Assistant, поэтому устройство будет скрыто на плане","marker.preview.reason.orphaned":"Сохранённая привязка Home Assistant больше не найдена","marker.preview.reason.static_icon":"Статичный режим: состояние устройства не меняет значок","marker.activity_color":"Цвет пульсации активности","marker.ripple_size":"Размер пульсации активности","marker.activity_alarm_note":"Цвет и размер относятся только к обычной активности и не влияют на красную тревогу.","marker.pulse_a11y_alarm":"Тревога","marker.pulse_a11y_event":"Недавнее событие","marker.pulse_a11y_presence":"Обнаружено присутствие","marker.pulse_a11y_transition":"Изменение состояния","marker.pulse_a11y_running":"Работает","marker.state_a11y_neutral":"Обычное состояние","marker.state_a11y_working":"Работает","marker.state_a11y_open":"Открыто","marker.state_a11y_locked":"Заблокировано","marker.state_a11y_unlocked":"Разблокировано","marker.state_a11y_alarm":"Тревога","marker.state_a11y_unavailable":"Недоступно","marker.lqi_a11y_low":"LQI {value}, слабый сигнал","marker.lqi_a11y_mid":"LQI {value}, средний сигнал","marker.lqi_a11y_high":"LQI {value}, сильный сигнал","marker.size_label":"Размер / поворот значка","marker.angle_label":"Поворот","marker.model_label":"Модель","marker.model_ph":"напр. Aqara T&H","marker.link_label":"Ссылка","marker.desc_label":"Описание","marker.desc_ph":"Заметки, характеристики…","marker.manuals_label":"Инструкции (PDF и т.п.)","marker.sub_device":"устройство","marker.sub_z2m_group":" · Z2M-группа","marker.sub_group":"группа","marker.sub_helper":"хелпер","space.new":"Новое пространство","space.header":"Пространство","space.title_label":"Название","space.title_ph":"Например: Гараж","space.plan_label":"Подложка (план)","space.no_plan":"нет подложки","space.plan_alt":"план","room.new":"Новая комната","room.name_label":"Отображаемое имя","room.name_ph":"Например: Терраса","room.area_label":"Зона Home Assistant (свободные)","room.no_area_option":"— без зоны —","room.default_name":"Комната","device.unnamed":"без имени","device.light_group":"группа света","device.fallback":"устройство","device.virtual":"виртуальное устройство","confirm.delete_room":"Удалить комнату «{name}»?","confirm.delete_room_title":"Удалить комнату «{name}»?","confirm.delete_room_body":"Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.","confirm.merge_rooms":"Слить комнаты «{a}» и «{b}»?","confirm.remove_marker":"Удалить «{name}» с плана? Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.","confirm.erase_decor":"Стереть объект «{kind}»? Действие можно отменить из истории редактора.","confirm.delete_space":"Удалить пространство «{title}» со всеми комнатами и разметкой?","space.delete_blocked":"Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.","toast.pos_save_failed":"Не удалось сохранить позицию: {err}","toast.no_entity":"У устройства нет подходящей сущности","toast.ha_disabled_action":"Деактивированный объект Home Assistant нельзя использовать на плане.","toast.ha_disabled_show_device":"Деактивированное в Home Assistant устройство нельзя показать на плане. Сначала активируйте его в Home Assistant.","toast.ha_disabled_show_entity":"Деактивированную в Home Assistant сущность нельзя показать на плане. Сначала активируйте её в Home Assistant.","toast.ha_disabled_add":"Деактивированный объект Home Assistant нельзя добавить на план. Сначала активируйте его в Home Assistant.","toast.ha_binding_unverified":"Статус объекта не удалось подтвердить по реестру Home Assistant. Отображение и действия временно недоступны.","toast.markup_needs_server":"Разметка доступна после переноса конфига на сервер","toast.space_order_changed":"Порядок изменён. Если где-то этаж карточки задан номером, проверьте такие панели.","toast.conflict":"Конфиг изменён в другом окне — данные обновлены, повторите последнее действие","toast.cfg_save_failed":"Не удалось сохранить конфиг: {err}","toast.room_overlap":"Контур накладывается на комнату «{name}» — комнаты не должны накладываться","toast.contour_min_edges":"Чтобы замкнуть контур, сначала нарисуйте минимум две грани","toast.contour_cannot_close":"Контур нельзя замкнуть: он вырожден или пересекает сам себя","toast.merge_not_adjacent":"Объединять можно только комнаты с общей стеной","toast.rooms_merged":"Комнаты объединены в «{name}»","toast.split_pick_wall":"Начните разрез на стене комнаты","toast.split_bad_cut":"Разрез — от стены до стены внутри комнаты, без пересечения стен и самого себя","merge.header":"Объединение комнат","merge.hint":"У объединённой комнаты одно имя и одна зона. Вторая зона освобождается — её устройства уйдут с плана, пока их не заберёт другая комната.","merge.keep":"Оставить","merge.no_area":"без зоны","room.split_header":"Новая комната после разделения","toast.room_saved":"Комната сохранена ({n}). Устройств добавлено: {added}. Обведите следующую или выйдите из разметки.","toast.room_saved_no_area":"Комната сохранена ({n}, без зоны). Обведите следующую или выйдите из разметки.","toast.marker_needs_server":"Редактирование устройств доступно после переноса конфига на сервер","toast.virtual_name_required":"Укажите имя виртуального устройства","toast.marker_saved":"Устройство сохранено","toast.marker_removed":"Устройство удалено с плана","toast.integration_missing":"Интеграция House Plan не установлена — управление недоступно","toast.plan_formats":"Поддерживаются SVG, PNG, JPG, WebP","toast.plan_required":"Загрузите подложку — план этажа обязателен","toast.space_added_onboard":"Пространство добавлено. Обведите комнаты: кликайте по точкам сетки и замкните контур.","toast.space_added":"Пространство добавлено","toast.space_saved":"Пространство сохранено","toast.space_deleted":"Пространство удалено","toast.delete_failed":"Ошибка удаления: {err}","toast.error":"Ошибка: {err}","toast.toggle_target_unavailable":"Цель «{name}» недоступна — действие не выполнено","toast.toggle_targets_unavailable":"Цели недоступны: {names}. Действие не выполнено","toast.file_failed":"Файл «{name}» не загружен: {err}","toast.files_attached":"Прикреплено файлов: {n}","err.unknown":"неизвестная ошибка","err.code":"код {code}","err.too_large":"файл больше {mb} МБ","err.bad_ext":"недопустимый тип (нужен PDF/изображение)","err.unauthorized":"нужны права администратора","editor.title":"Заголовок","editor.default_floor":"Стартовое пространство","editor.default_floor_missing":"Стартовое пространство «{id}» больше не существует. Выберите другое.","editor.floor":"Закреплённое пространство","editor.floor_none":"— не закреплять —","editor.floor_index":"YAML-индекс {index} (сохранён)","fixed_floor.loading":"Загружаем закреплённое пространство…","fixed_floor.invalid_title":"Закреплённое пространство недоступно","fixed_floor.invalid_body":"Проверьте floor в конфигурации карточки. Настроенное значение: {value}","editor.icon_size":"Размер иконок, % ширины плана","editor.show_temperature":"Показывать температуру","editor.live_states":"Живые состояния (вкл/выкл, открыто…)","editor.show_signal":"Показывать сигнал zigbee (LQI)","editor.language":"Язык интерфейса","editor.lang_auto":"Авто (профиль HA)","editor.lang_en":"English","editor.lang_ru":"Русский","title.icon_rules":"Правила иконок: какая MDI-иконка достаётся устройству по имени","rules.title":"Правила иконок","rules.hint":"Правила проверяются сверху вниз по строке «имя устройства + модель» (regex без учёта регистра); срабатывает первое совпадение. Если ничего не подошло — решает device class сущности, затем — иконка-заглушка.","rules.pattern_ph":"regex, напр. розетк|plug","rules.icon_ph":"mdi:power-socket-de","rules.add":"Добавить правило","rules.reset":"Сбросить к умолчаниям","rules.test_ph":"Проверьте имя устройства…","rules.invalid":"некорректный regex","rules.saved":"Правила иконок сохранены","btn.up":"Вверх","btn.down":"Вниз","tap.info":"Карточка устройства","tap.more_info":"Диалог HA (more-info)","tap.toggle":"Переключить состояние","marker.tap_label":"Действие по нажатию для этого устройства","tap.toggle_note":"Под селектором показано, какое состояние изменится. Защищённые устройства не переключаются с плана.","import.title":"Создать пространства из этажей HA","import.hint":"Home Assistant уже знает эти этажи. Отметьте, какие превратить в пространства плана — далее для каждого попросим картинку плана. Комнаты затем обводятся вручную по плану.","import.start":"Создать: {n}","import.manual":"Начать с нуля","import.progress":"Этаж {i} из {n}","import.done":"Пространства созданы. Обведите комнаты: кликайте по точкам сетки и замкните контур.","btn.skip":"Пропустить","space.scale_label":"Масштаб (размер клетки сетки)","space.scale_unit":"см на клетку","space.scale_unit_imperial":"дюйм на клетку","space.display_section":"Отображение","space.show_borders":"Всегда отображать границы комнат","space.zero_wall_style":"Стены нулевой толщины","space.zero_wall_dashed":"Пунктирные","space.zero_wall_solid":"Сплошные","space.zero_wall_help":"Пунктирные стены пропускают свет. Сплошные стены блокируют свет, даже при нулевой толщине.","space.show_names":"Отображать названия комнат (перетаскиваются)","space.room_color":"Цвет границ и названий","space.opacity":"Прозрачность","space.fill_label":"Заливка комнат","fill.none":"Нет","fill.lqi":"По силе зигби-сигнала","fill.light":"По освещению","fill.custom":"Свой цвет","space.custom_fill":"Цвет заливки","space.source_file":"У меня есть картинка плана","space.source_draw":"Нет подложки — нарисую комнаты вручную","space.orientation":"Холст","orient.landscape":"Альбомный","orient.portrait":"Портретный","orient.square":"Квадрат","fill.temp":"По температуре","space.temp_min":"Комфорт от","space.temp_max":"до","tip.temp_avg":"средняя температура:","tip.hum_avg":"средняя влажность:","space_card.button":"Перейти к пространству","space_card.not_found":"Пространство «{id}» не найдено","space_card.loading":"Загрузка…","continuity.restore_plan":"Восстанавливаем план…","continuity.restore_connection":"Восстанавливаем подключение к устройствам…","continuity.retry":"Повторить","editor.space":"Пространство","editor.show_button":"Показывать кнопку","editor.button_label":"Текст кнопки","editor.button_target":"Путь дашборда (куда вести)","marker.sub_entity":"сущность","title.general_settings":"Общие настройки","gs.title":"Общие настройки","gs.hint":"Цвета заливок действуют на все пространства; у каждого цвета своя прозрачность. Какой режим заливки использует пространство — задаётся в его диалоге.","gs.light_group":"Заливка: освещение","gs.light_on":"Свет включён","gs.light_off":"Весь свет выключен","gs.temp_group":"Заливка: температура","gs.temp_cold":"Холодно","gs.temp_ok":"Комфорт","gs.temp_hot":"Жарко","gs.lqi_group":"Заливка: зигби-сигнал","gs.lqi_low":"Слабый сигнал","gs.lqi_high":"Сильный сигнал","gs.reset":"Сбросить к умолчаниям","gs.saved":"Общие настройки сохранены","space.show_lqi":"Показывать зигби-сигнал (LQI) у устройств","space.hide_decor":"Скрыть декоративный слой","space.hide_decor_tip":"Линии, фигуры, надписи и мебель остаются на месте — их видно в редакторе подложки, но не на плане.","space.hide_openings":"Скрыть проёмы","space.hide_openings_tip":"Двери, окна и ворота не рисуются, но продолжают работать: свет проходит, солнце светит в окна, датчики открытия срабатывают. В редакторе плана проёмы видно всегда.","gs.light_none":"Нет источников света","mode.plan":"Редактор плана","mode.devices":"Редактор устройств","display.value":"Значение + состояние","marker.subarea":"без зоны, вручную","device.new":"Новое устройство — откройте его редактор, чтобы снять отметку","opening.unlock_action":"Открыть замок","opening.lock_action":"Закрыть замок","opening.lock_pending":"Выполняется…","title.close_editor":"Закрыть редактор (вернуться к просмотру)","devbar.add":"Добавить","devbar.show_all":"Скрытые и деактивированные","devbar.rules":"Правила иконок","device_inbox.button":"Устройства","device_inbox.title":"Устройства на плане","device_inbox.search":"Поиск по устройствам, сущностям и интеграциям…","device_inbox.add_virtual":"Добавить виртуальное устройство","device_inbox.tab_on_plan":"На плане","device_inbox.tab_available":"Доступны","device_inbox.tab_hidden":"Скрытые","device_inbox.tab_readd":"Доступны снова","device_inbox.only_new":"Только новые","device_inbox.show_entities":"Показывать сущности","device_inbox.show_hidden":"Показывать скрытые на плане","device_inbox.new":"Новое","device_inbox.find":"Найти на плане","device_inbox.edit":"Настроить","device_inbox.hide":"Скрыть","device_inbox.show":"Показать","device_inbox.add":"Добавить","device_inbox.readd":"Добавить заново","device_inbox.hide_available":"Скрыть из списка","device_inbox.show_more":"Показать ещё","device_inbox.more_actions":"Другие действия","device_inbox.find_hidden_hint":"Сначала включите «Показывать скрытые на плане»","device_inbox.show_disabled":"Перед показом активируйте эту привязку в Home Assistant","device_inbox.empty_on_plan":"На плане пока нет подходящих устройств.","device_inbox.empty_available":"Нет доступных устройств для добавления.","device_inbox.empty_hidden":"Скрытых устройств нет.","device_inbox.empty_readd":"Нет удалённых устройств, доступных для повторного добавления.","device_inbox.reason_visible_auto":"Найдено автоматически","device_inbox.reason_visible_explicit":"Добавлено явно","device_inbox.reason_manual_hidden":"Скрыто пользователем","device_inbox.reason_automatic_hidden":"Скрыто автоматически","device_inbox.reason_service_entry":"Служебная запись реестра","device_inbox.reason_excluded_integration":"Интеграция исключена фильтрами устройств","device_inbox.reason_excluded_domain":"Непространственный тип сущности","device_inbox.reason_grouped_light":"Представлено группой света комнаты","device_inbox.reason_represented_by_parent":"Представлено родительским устройством","device_inbox.reason_removed":"Ранее удалено с плана","device_inbox.reason_available":"Можно добавить на план","device_inbox.reason_no_bound_room":"Зона HA не связана с комнатой плана","device_inbox.status_ha_disabled":"Отключено в Home Assistant","device_inbox.status_orphaned":"Привязка больше не найдена в Home Assistant","device_inbox.status_unverified":"Реестр Home Assistant временно недоступен","device_inbox.saved":"Список устройств обновлён","space.roomcard_section":"В карточке комнаты:","space.label_temp":"Температура","space.label_hum":"Влажность","space.label_lqi":"Средний Zigbee-сигнал","space.label_light":"Свет вкл/выкл","roomcard.light_on":"Вкл","roomcard.light_off":"Выкл","roomcard.light_partial":"{on} из {total}","toast.split_pick_inside":"Промежуточные точки разреза — внутри комнаты","mode.decor":"Редактор подложки","decor.select":"Выбрать","decor.line":"Линия","decor.rect":"Прямоугольник","decor.ellipse":"Овал","decor.text":"Надпись","decor.erase":"Стереть","decor.erase_confirm_title":"Стереть объект?","decor.color":"Цвет","decor.width":"Толщина линии","decor.line_style":"Стиль линии","decor.line_style_solid":"Сплошная","decor.line_style_dashed":"Пунктирная","decor.fill":"Заливка","decor.fill_color":"Цвет заливки","decor.length":"Длина","decor.size":"Размер","decor.angle":"Угол поворота, °","decor.text_size":"Размер текста","decor.backdrop_properties":"Свойства картинки-подложки","decor.text_title":"Надпись","decor.object_title":"Редактирование: {kind}","decor.text_label":"Текст","decor.live_group":"Вставить переменную HA","decor.live_entity":"Сущность","decor.live_entity_ph":"выберите сущность","decor.live_attr":"Значение","decor.live_attr_ph":"выберите состояние или атрибут","decor.live_state":"Состояние","decor.backdrop":"Картинка-подложка","decor.backdrop_hint":"Тяните картинку — перемещение; угол — размер; верхнюю ручку — поворот. Shift меняет пропорции или снимает шаг угла.","decor.backdrop_reset":"Вернуть картинку","decor.backdrop_reset_done":"Картинка вернулась на своё место и в свой размер","marker.icon_auto":"Авто: {icon} (по правилам иконок; выберите свою, чтобы заменить)","marker.icon_pin_auto":"Закрепить","mode.plan_tip":"Редактор плана — геометрия дома: рисование и объединение/разделение комнат, привязка к зонам HA, двери, окна и ворота, карточки комнат, масштаб","mode.devices_tip":"Редактор устройств — всё про значки: перетаскивание, клик — настройка привязки/иконки/отображения, виртуальные устройства, правила иконок","mode.decor_tip":"Редактор подложки — чисто визуальный декор под планом: линии, прямоугольники, овалы и надписи, не реагирующие на клики","space.glow_enabled":"Свечение источников света","gs.glow_group":"Свечение источников света","gs.glow_base":"Темнота дома","gs.glow_light":"Цвет света по умолчанию / интенсивность","gs.wall_group":"Стены","gs.wall_fill":"Цвет заливки стен","gs.glow_radius":"Радиус свечения","gs.unit_m":"м","gs.unit_ft":"фут","marker.controls_label":"Управляет другими источниками света","marker.controls_hint":"При действии «Переключить» клик разом переключает все добавленные здесь источники. Собственная сущность маркера управляется напрямую и сюда не добавляется; чтобы считать её светом, включите флаг ниже.","marker.controls_filter":"Поиск ламп и выключателей…","info.controls":"Управляет","marker.glow_radius_label":"Радиус свечения","marker.glow_radius.help":"Задаёт радиус свечения в метрах или футах; пустое значение использует радиус из общих настроек.","marker.glow_radius.help.aria":"Подсказка: радиус свечения","markup.wallthick":"Толщина","markup.select":"Выбрать","title.markup_wallthick":"Толщина — клик по стене задаёт толщину от 0 до 100 см.","markup.hint_wallthick":"клик по стене · Esc закрывает без применения","wallthick.field":"Толщина","wallthick.unit_cm":"см","wallthick.unit_in":"дюйм","wallthick.apply_room":"Применить ко всем стенам комнаты","markup.draw_wall_title":"Толщина каждого нового сегмента стены (0–100 см). Общие стены сохраняют существующее значение.","room.queue_progress":"Комната {current} из {total}","toast.wall_rooms_saved":"Создано комнат: {n}","toast.wall_chain_saved":"Цепочка стен сохранена","toast.wallthick_pick":"Кликните по стене","toast.wallthick_set":"Толщина стены задана","toast.wallthick_cleared":"Толщина стены убрана","toast.physical_range":"Введите значение от {min} до {max} {unit}","toast.zero_wall_opening_conflict":"Сначала удалите проём на этом участке стены.","toast.zero_wall_ambiguous":"Не удалось однозначно выбрать участок стены. Уточните геометрию узла.","toast.zero_wall_migration_blocked":"Пространство не преобразовано: {reason}. Данные не изменены.","toast.physical_angle":"Введите угол поворота от 0° до 90°, не включая 90°","toast.physical_limit":"В пространстве достигнут лимит объектов этого типа","toast.geometry_unsafe":"Изменение отменено: геометрию стен нельзя безопасно построить.","junction.limit_angle":"Слишком острый угол между стенами: {actual}°, минимум {limit}°.","junction.limit_valence":"Слишком много стен в одном узле: {actual}, максимум {limit}.","junction.limit_length":"Слишком короткий участок стены: {actual} см, минимум {limit} см.","junction.limit_distance":"Стены и узлы слишком близко: {actual} см, минимум {limit} см.","junction.limit_clearance":"Внутри комнаты не остаётся места: {actual} см², минимум {limit} см².","junction.limit_check_failed":"Проверку стыков выполнить не удалось — изменение не сохранено","toast.wall_model_migration_blocked":"Не удалось обновить модель стен: {reason}. План не изменён. Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.","toast.wall_model_client_outdated":"Обновите карточку и перезагрузите страницу перед редактированием плана.","wall_model.reason.invalid-room":"некорректный контур комнаты","wall_model.reason.zero-length":"отрезок стены нулевой длины","wall_model.reason.third-owner":"стена принадлежит более чем двум комнатам","wall_model.reason.duplicate-id":"конфликт идентификаторов стен","wall_model.reason.thickness-conflict":"конфликт значений толщины стены","wall_model.reason.opening-host":"проём нельзя однозначно привязать к стене","toast.delete_room_pick":"Кликните внутри комнаты, которую нужно удалить","toast.plan_snap_ambiguous":"Увеличьте масштаб, чтобы выбрать узел стены","toast.wall_repair_ambiguous":"У контура несколько возможных соединений. Увеличьте масштаб и соедините стены явно.","toast.wall_repair_too_large":"Разрыв больше 2 см. Соедините стены перед созданием комнаты.","toast.wall_repair_changed":"Геометрия стен изменилась. Попробуйте создать комнату ещё раз.","toast.opening_on_zero_wall":"Проёмы на стене нулевой толщины запрещены","marker.from_ha_option":"Выбрать из списка HA","marker.show_entities":"Показывать сущности","marker.show_entities_tip":"Добавляет в список не только устройства, но и все их сущности","marker.pick_ph":"Выберите устройство…","room.open_area":"Открыть зону в HA","view.volumetric":"Объёмный вид","view.flat":"Плоский вид","kiosk.title":"Размеры на этом экране","kiosk.hint":"Хранится только на этом устройстве — у каждого настенного планшета или ТВ свои удобные размеры.","kiosk.icon_scale":"Размер значков устройств","kiosk.font_scale":"Размер текста карточек комнат","editor.kiosk":"Режим настенного устройства (киоск)","editor.cycle":"Автосмена пространств каждые N секунд (киоск, 0 = выкл)","room.settings_title":"Настройки комнаты","room.settings_section":"Настройки комнаты (переопределяют пространство)","room.fill_label":"Заливка в ЭТОЙ комнате","fill.inherit":"Как у пространства","room.custom_fill_space":"Цвет пространства","room.custom_fill_own":"Цвет комнаты","room.temp_src_label":"Источник температуры","room.hum_src_label":"Источник влажности","room.src_average":"Средняя по датчикам комнаты (по умолчанию)","room.src_pick":"Конкретное устройство или сущность HA","room.src_ph":"Выберите источник…","toast.room_updated":"Комната обновлена","space.card_font":"Размер шрифта карточек комнат (всё пространство)","room.sizes_section":"Размеры шрифтов","room.name_scale":"Размер названия","room.label_scale":"Размер подписей","preview.room_name":"Гостиная","toast.cfg_reload_failed":"Не удалось перечитать план с сервера: {err}","room.settings_short":"Настройки комнаты","room.unnamed":"Комната без имени","marker.use_climate_temp":"Учитывать температуру устройства в комнате","marker.use_climate_temp_tip":"Добавляет current_temperature кондиционера или термостата в среднюю температуру комнаты. Внешний бейдж со значением настраивается отдельно ниже.","marker.value_badge_title":"Бейдж со значением","marker.value_badge.help":"Показывает одно выбранное значение рядом со значком. Не влияет на комнатные показатели, свет, Glow и действие по нажатию.","marker.value_badge.help.aria":"Подсказка: бейдж со значением устройства","marker.value_badge_enabled":"Отображать бейдж со значением","marker.value_badge_source":"Значение","marker.value_badge_source.help":"Выберите конкретное состояние, поддерживаемый атрибут или производное значение этого устройства.","marker.value_badge_source.help.aria":"Подсказка: источник значения бейджа","marker.value_badge_position":"Расположение","marker.value_badge_position.help":"Выбранная сторона сохраняется постоянно и не переворачивается автоматически у края плана.","marker.value_badge_position.help.aria":"Подсказка: расположение бейджа","marker.value_badge_right":"Справа","marker.value_badge_bottom":"Снизу","marker.value_badge_left":"Слева","marker.value_badge_top":"Сверху","marker.value_badge_empty":"У этого устройства нет доступных значений","marker.value_badge_static":"Статичный значок не показывает живые значения. Настройка сохранится.","marker.value_badge_missing":"Источник недоступен","marker.value_badge_missing_hint":"Сохранённый источник сейчас недоступен. Можно сохранить его, отключить бейдж или выбрать другой.","marker.value_badge_duplicate":"То же значение уже показано внутри значка.","marker.value_badge_state":"Состояние · {name}","marker.value_badge_marker_state":"Состояние источника света · {name}","marker.value_badge_lqi":"Качество Zigbee-сигнала (среднее)","marker.value_badge_attr_current_temperature":"Текущая температура · {name}","marker.value_badge_attr_temperature":"Целевая температура · {name}","marker.value_badge_attr_current_humidity":"Текущая влажность · {name}","marker.value_badge_attr_humidity":"Влажность · {name}","marker.value_badge_attr_current_position":"Положение · {name}","marker.value_badge_attr_percentage":"Скорость · {name}","marker.value_badge_attr_brightness":"Яркость · {name}","marker.value_badge_attr_volume_level":"Громкость · {name}","marker.value_badge_attr_battery_level":"Заряд батареи · {name}","marker.value_badge_attr_fan_speed":"Скорость вентилятора · {name}","marker.light_role_label":"Является источником света","marker.light_role.help":"Определяет, является ли сам маркер пространственным источником света. Привязанные выше лампы остаются независимыми источниками для комнаты.","marker.light_role.help.aria":"Подсказка: является ли устройство источником света","marker.light_role_auto_yes":"Автоматически (источник света)","marker.light_role_auto_no":"Автоматически (не источник света)","marker.light_role_always":"Всегда источник света","marker.light_role_never":"Никогда не источник света","marker.light_entity_label":"Ведущая сущность света","marker.light_entity.help":"Для составного устройства выберите сущность, состояние, цвет и яркость которой представляют этот источник на плане. Автоматический вариант сохраняет совместимость со старыми планами.","marker.light_entity.help.aria":"Подсказка: ведущая сущность света","marker.light_entity_auto":"Автоматически ({entity})","marker.light_entity_none":"нет управляемой сущности","marker.light_entity_missing":"Сохранённая сущность {entity} недоступна. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.toggle_entity_label":"Переключаемая сущность","marker.toggle_entity.help":"Для составного устройства выберите собственную лампу или переключатель, которой управляет нажатие. Автоматический вариант сохраняет прежние правила цели и не зависит от ведущей сущности света.","marker.toggle_entity.help.aria":"Подсказка: переключаемая сущность","marker.toggle_entity_auto":"Автоматически ({entity})","marker.toggle_entity_none":"нет собственной управляемой сущности","marker.toggle_entity_missing":"Сохранённой сущности {entity} больше нет среди выбираемых каналов этого маркера. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.glow_color_label":"Цвет и яркость свечения","marker.glow_mode.help":"Используйте данные источника, задайте только цвет или зафиксируйте цвет и яркость. Минимум — 1%; чтобы отключить источник, выберите «Никогда».","marker.glow_mode.help.aria":"Подсказка: цвет и яркость свечения","marker.glow_mode_auto":"Из источника","marker.glow_mode_color":"Задать цвет","marker.glow_mode_fixed":"Задать цвет и яркость","marker.glow_color":"Цвет свечения","marker.glow_brightness":"Яркость","marker.glow_disabled_never":"Настройки свечения недоступны: маркер явно исключён из источников света.","marker.glow_disabled_auto":"В автоматическом режиме у этого маркера не найден пространственный источник света.","marker.glow_disabled_no_entity":"Для пространственного источника нет активной управляемой сущности Home Assistant.","marker.glow_passive_hint":"У источника нет собственных данных Home Assistant. Задайте цвет и яркость вручную; радиус остаётся доступным.","marker.control_broken":"Сохранённый источник отсутствует или больше не отмечен как источник света","marker.control_missing_label":"Отсутствующий источник на плане","marker.control_passive":"пассивный источник","toast.marker_control_cycle":"Такая связь создаст циклическую цепочку управления светом.","toast.marker_binding_required":"Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.","confirm.unlock":"Открыть замок «{name}»?","toast.files_migrate_failed":"Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}","space.pick_saved":"Уже загруженные","space.pick_saved_hint":"Планы, сохранённые на сервере, включая отцеплённые ранее","space.no_saved":"На сервере пока нет сохранённых планов.","space.loading":"Загрузка…","space.used_by":"используется: {list}","space.in_use":"План используется пространством — сначала отцепите его","btn.use":"Выбрать","confirm.delete_plan":"Удалить файл плана «{name}» с сервера? Действие необратимо.","toast.plans_list_failed":"Не удалось получить список планов: {err}","toast.plan_delete_failed":"Не удалось удалить план: {err}","marker.hide":"Скрыть","marker.hide_tip":"Устройство исчезнет с плана после сохранения, но продолжит участвовать в расчёте сигнала комнаты. Вернуть его можно через каталог «Устройства» в редакторе устройств.","marker.show":"Показать","marker.show_tip":"Устройство снова появится на плане после сохранения.","marker.hidden_ghost":"Устройство скрыто пользователем","marker.ha_disabled_device":"Устройство деактивировано в Home Assistant и скрыто с плана.","marker.ha_disabled_entity":"Сущность деактивирована в Home Assistant и скрыта с плана.","marker.ha_disabled_all_entities":"У устройства нет активных сущностей Home Assistant, поэтому оно скрыто с плана.","marker.ha_registry_limited":"Полный реестр Home Assistant недоступен этому пользователю. Неподтверждённый объект временно нельзя показывать или использовать.","marker.delete_tip":"Полностью удалить устройство с плана и из всех расчётов. Позже его можно добавить заново.","tap.run":"Запустить автоматизацию/скрипт/сцену","tap.cover":"Открыть/закрыть (шторы/жалюзи)","marker.run_target_label":"Что запускать","marker.run_search_ph":"Поиск: автоматизация, скрипт или сцена…","marker.run_target_gone":"Цель {id} не найдена — выберите заново","marker.tap_confirm":"Спрашивать подтверждение","marker.tap_confirm_tip":"Перед выполнением показать диалог подтверждения — защита от случайных нажатий.","marker.toggle_hint_single":"Цель: {name} ({id}).","marker.virtual_light_target":"Виртуальный свет: {name}.","marker.virtual_light_current":"Ручное состояние: {state} → {effect}.","marker.virtual_light_state_on":"включён","marker.virtual_light_state_off":"выключен","marker.toggle_hint_group":"Переключатся источники ({count}): {names}.","marker.toggle_hint_current":"Сейчас: {state} → {effect}.","marker.toggle_hint_group_current":"Сейчас включено {on} из {count} → {effect}.","marker.toggle_hint_skipped":"Не будут затронуты ({count}): {targets}.","marker.toggle_effect_turn_on":"включится","marker.toggle_effect_turn_off":"выключится","marker.toggle_effect_open":"откроется","marker.toggle_effect_close":"закроется","marker.toggle_effect_stop":"остановится","marker.toggle_effect_toggle":"состояние переключится","marker.toggle_skip_missing":"не найдено","marker.toggle_skip_ha_disabled":"деактивировано в HA","marker.toggle_skip_unavailable":"недоступно","marker.toggle_skip_unsupported":"переключение не поддерживается","marker.toggle_skip_secure":"заблокировано из соображений безопасности","marker.toggle_none_no_binding":"У устройства нет привязки, состояние переключать нечем. По нажатию ничего не произойдёт.","marker.toggle_none_no_actionable_entity":"У устройства нет состояния, которое можно переключить. По нажатию ничего не произойдёт.","marker.toggle_none_configured_targets_missing":"Настроенные цели сейчас недоступны. Собственная сущность устройства не будет подставлена вместо них.","marker.toggle_none_ha_disabled":"Цель деактивирована в Home Assistant и не может использоваться на плане.","marker.toggle_none_unavailable":"Цель сейчас недоступна. По нажатию ничего не произойдёт.","marker.toggle_none_unsupported":"Для этой сущности Home Assistant не предоставляет безопасного переключения. По нажатию ничего не произойдёт.","marker.toggle_none_secure":"Переключение замков, сигнализации и защитных ворот с плана заблокировано из соображений безопасности.","run.automation":"автоматизация","run.script":"скрипт","run.scene":"сцена","confirm.tap_run":"Запустить «{name}»?","confirm.tap_toggle":"Переключить «{name}»?","confirm.tap_cover":"Открыть/закрыть «{name}»?","confirm.current_state":"Текущее состояние: {state}","confirm.expected_state":"После переключения: {state}","confirm.group_current":"включено {on} из {total}","confirm.group_all_on":"все включены","confirm.group_all_off":"все выключены","confirm.unavailable_targets":"Недоступно: {count}","confirm.expected_by_ha":"Состояние определит Home Assistant","confirm.state_on":"Включено","confirm.state_off":"Выключено","confirm.state_open":"Открыто","confirm.state_closed":"Закрыто","confirm.state_opening":"Открывается","confirm.state_closing":"Закрывается","confirm.state_stopped":"Остановлено","confirm.state_unknown":"Неизвестно","toast.run_started":"Запущено: {name}","toast.run_target_missing":"Цель запуска не найдена — проверьте настройки устройства","toast.run_target_required":"Выберите автоматизацию, скрипт или сцену","toast.tap_target_changed":"Цель действия изменилась. Повторите попытку.","toast.virtual_light_toggle_failed":"Не удалось переключить виртуальный свет: {err}","toast.value_badge_source_required":"Выберите значение для бейджа","btn.run":"Выполнить","vac.section":"Робот-пылесос: живая позиция","vac.autocal":"Настроить автоматически","vac.live":"Живая позиция на плане","vac.trail":"Показывать путь робота","vac.cal_maps":"Откалиброваны карты: {maps}","vac.autocal_no_rooms":"Интеграция не отдаёт список комнат — откройте «Подогнать вручную»","vac.autocal_no_match":"Не совпали имена комнат (нужно ≥3 общих) — откройте «Подогнать вручную»","vac.autocal_done":"Готово: привязка по {rooms} комнатам. Запустите уборку и проверьте","vac.cal_need_pos":"Робот сейчас не отдаёт координаты — запустите уборку и поставьте на паузу","vac.cal_done":"Калибровка сохранена. Запустите уборку и проверьте","vac.cal_cancelled":"Калибровка отменена","vac.fit":"Подогнать вручную","vac.fit_hint":"Перетащите карту робота на место, растяните за уголки","vac.fit_rotate":"Повернуть 90°","vac.fit_mirror":"Отразить","vac.trail_never":"Не показывать никогда","vac.trail_cleaning":"Во время уборки","vac.trail_always":"Показывать всегда","gs.bg_group":"Фон сцены","gs.bg_color":"Цвет фона вокруг плана","gs.bg_default":"Как в теме","gs.bg_theme":"по умолчанию — из темы","gs.bg_mode":"Фон плана","gs.bg_static":"Статичный цвет","gs.bg_daynight":"Следует за Солнцем","gs.bg_daynight_hint":"Фон проходит рассвет, день, закат и ночь по данным sun.sun, а при их недоступности — по локальным часам. Компас для фона не нужен.","gs.sun_group":"Солнце","gs.sun_missing":"Сущность sun.sun не найдена — фон следует локальным часам, а оконные лучи недоступны.","gs.north":"Север на плане","gs.north_ph":"не задан","gs.north_hint":"Север нужен только для оконных лучей (шаг 1°, с Shift 15°); солнечный фон работает без него.","gs.north_clear":"Сбросить","gs.north_letter":"С","gs.sun_rays":"Солнце в окнах","gs.about_group":"О карточке","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · документация и issues","gs.about_telegram":"Чат в Telegram","space.bg_color":"Цвет фона вокруг плана","space.bg_inherit":"Наследовать общий","space.bg_inherited":"наследуется из общих настроек","space.bg_mode":"Фон плана","space.north":"Север на плане (переопределение)","space.north_inherited":"наследуется: {v}","space.sun_rays":"Солнце в окнах","space.sun_inherit":"Наследовать общий","space.sun_on":"Вкл","space.sun_off":"Выкл","canvas.far_objects":"Объектов далеко от плана: {n}","canvas.show_far":"Показать","canvas.home_tip":"План там — нажмите, чтобы вписать","gs.grid_group":"Обслуживание планов","gs.grid_hint":"Обновляет модели данных, выравнивает элементы по сетке и объединяет лишние фрагменты стен. Перед записью будет показан точный отчёт.","gs.align_all":"Оптимизировать планы","gs.align_title":"Оптимизировать планы","gs.align_none":"Все планы уже используют актуальную и оптимальную модель данных.","gs.optimize_no_automatic_changes":"Автоматических изменений нет. Проверьте пункты ниже.","gs.align_count":"Сдвинется элементов: {n} из {total}, максимум на {cm} см.","gs.align_where":"Наибольший сдвиг — в пространстве «{s}».","gs.align_turned":"Проёмов с исправлением угла: {n}.","gs.align_removed_drafts":"Схлопнувшиеся на сетке некорректные контуры удалены: {n}.","gs.optimize_redundant_drafts":"Сохранённые цепочки стен, полностью скрытые стенами комнат, удалены: {n}.","gs.align_preflight_failed":"Не удалось безопасно проверить геометрию следующих пространств: {spaces}{more}.","gs.align_preflight_hint":"Планы не изменены. Скопируйте диагностику кнопкой ниже и приложите её к отчёту об ошибке вместе с экспортом пространства.","gs.preflight_reason_prepare-exception":"Не удалось подготовить геометрию пространства (исключение при сборке модели)","gs.preflight_reason_wall-null":"Тело стен не построилось (объединение вернуло пустоту)","gs.preflight_reason_wall-degraded-extra":"Тело стен деградировало с лишней геометрией","gs.preflight_reason_wall-failed-core":"Ядро тела стен не собралось","gs.preflight_reason_wall-exception":"Построение стен упало с исключением","gs.preflight_reason_floor-null":"Контур пола не построился","gs.preflight_reason_floor-exception":"Построение пола упало с исключением","gs.preflight_copy":"Скопировать диагностику","gs.preflight_copied":"Диагностика скопирована","gs.preflight_update_hint":"Версии карточки и интеграции различаются — обновите House Plan и повторите.","gs.align_preflight_space":"Пространство {n}","gs.align_preflight_more":" и ещё {n}","gs.optimize_changes":"Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.","gs.zero_walls_migrated":"Преобразовано виртуальных участков: {n}.","gs.wall_segments_migrated":"Стабилизировано сегментов стен: {n}.","gs.optimize_lattice_summary":"Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.","gs.optimize_lattice_space":"{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.","gs.optimize_coincident_partitions":"Скрытые участки независимых стен поглощены стенами комнат: {n}.","gs.optimize_openings_rehosted":"Проёмы перепривязаны к стенам комнат: {n}.","gs.optimize_walls_straightened":"Выпрямлено стен: {n}; максимальное перемещение: {cm} см.","gs.optimize_walls_straightened_where":"Максимальная правка стены: {s}.","gs.optimize_walls_straighten_skipped":"Оставлено почти осевых стен, которые нельзя безопасно выпрямить: {n}.","gs.optimize_glow_migration":"Старый Glow: пространств — {spaces} → без заливки данных + независимый Glow; комнат — {rooms} → наследуемая заливка + независимый Glow.","gs.optimize_references":"Исправлено ссылок: пространства — {spaces}; комнаты — {rooms}; позиции — {positions}; устройств отвязано от отсутствующих пространств — {detached}.","gs.optimize_reference_more":", и ещё {n}","gs.optimize_orphans_removed":"Убрано забытых записей: {total} — подписи комнат: {rooms}; устройства: {devices}; групповые метки: {groups}. Все они принадлежали пространствам, удалённым ранее.","gs.optimize_live_positions":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они будут сохранены.","gs.optimize_live_positions_remove":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они выбраны для удаления.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Убрать старые позиции","gs.optimize_live_keep":"Сохранить старые позиции","gs.optimize_live_selected":"Старые позиции будут убраны после применения оптимизации.","gs.optimize_unverified":"Не удалось безопасно проверить позиций: {n}. Они оставлены без изменений.","gs.optimize_registry_limited":"Для безопасной проверки нужен полный доступ администратора к реестрам Home Assistant.","gs.optimize_vacuum_warning":"Сопоставления комнат пылесоса требуют проверки: {n}.","gs.optimize_details":"Подробности","gs.optimize_details_more":"И ещё записей: {n}.","gs.optimize_detail_removed":"будет удалено","gs.optimize_detail_live":"будет сохранено","gs.optimize_detail_unverified":"не проверено","gs.optimize_detail_room_label":"подпись комнаты","gs.optimize_detail_device":"устройство","gs.optimize_detail_group":"групповая метка","gs.optimize_detail_unknown":"неизвестный владелец","gs.optimize_detail_item":"{status}: {kind} {id}; прежнее пространство {space}","gs.align_warn":"Элементы, намеренно поставленные между узлами, будут сдвинуты. После операции доступна одна отмена — только до следующего изменения плана.","gs.align_run":"Оптимизировать","gs.align_done":"Планы оптимизированы: сдвинуто элементов — {n}, обслужено записей — {m}, исправлено ссылок — {r}","gs.optimize_undo":"Отменить последнюю оптимизацию","gs.optimize_undone":"Последняя оптимизация отменена","decor.furniture":"Мебель","furn.title":"Библиотека мебели","furn.symbol":"Символ","furn.group_furniture":"Мебель","furn.group_appliance":"Техника","furn.group_sanitary":"Сантехника","furn.group_other":"Прочее","furn.width":"Ширина","furn.depth":"Глубина","furn.pick_hint":"Выберите символ и кликните по плану.","furn.place_hint":"Кликните по плану — предмет встанет к ближайшей стене. Shift — свободно.","furn.sym_sofa":"Диван","furn.sym_armchair":"Кресло","furn.sym_coffee_table":"Журнальный столик","furn.sym_table_dining":"Обеденный стол","furn.sym_table_round":"Круглый стол","furn.sym_chair":"Стул","furn.sym_desk":"Письменный стол","furn.sym_bed_double":"Двуспальная кровать","furn.sym_bed_single":"Односпальная кровать","furn.sym_nightstand":"Тумбочка","furn.sym_wardrobe":"Шкаф","furn.sym_bookshelf":"Стеллаж","furn.sym_fridge":"Холодильник","furn.sym_stove":"Плита","furn.sym_dishwasher":"Посудомоечная машина","furn.sym_washer":"Стиральная машина","furn.sym_dryer":"Сушильная машина","furn.sym_tv":"Телевизор","furn.sym_ac":"Кондиционер","furn.sym_water_heater":"Бойлер","furn.sym_toilet":"Унитаз","furn.sym_bathtub":"Ванна","furn.sym_shower":"Душ","furn.sym_sink":"Раковина","furn.sym_kitchen_sink":"Кухонная мойка","furn.sym_bidet":"Биде","furn.sym_stairs":"Лестница","furn.sym_fireplace":"Камин","furn.sym_plant":"Растение","furn.sym_rug":"Ковёр","common.yes":"Да","common.no":"Нет","vac.diag_source":"Источник","vac.diag_platform":"Интеграция","vac.diag_status":"Статус","vac.diag_position":"Позиция","vac.diag_rooms":"Комнаты","vac.diag_rooms_value":"{total} · совпало имён: {matched} · {readiness}","vac.autocal_ready":"автокалибровка доступна","vac.autocal_not_ready":"нужно 3 совпавших имени","vac.diag_path":"Путь интеграции","vac.diag_map":"ID карты","vac.source_none":"не выбран","vac.source_status_ok":"Готов","vac.source_status_missing":"Не найден","vac.source_status_disabled":"Деактивирован в Home Assistant","vac.source_status_unavailable":"Недоступен","vac.source_status_unverified":"Нельзя проверить с текущими правами","vac.source_status_unsupported":"Нет данных позиции","vac.source_status_none":"Нет источника","vac.source_banner_missing":"Сохранённый источник больше не существует. Он не заменён автоматически: выберите другой или восстановите его в Home Assistant.","vac.source_banner_disabled":"Сохранённый источник деактивирован в Home Assistant. Активируйте его там или выберите другой.","vac.source_banner_unverified":"Текущих прав Home Assistant недостаточно для проверки источника. Привязка сохранена и не будет заменена автоматически.","vac.choose_source":"Выбрать источник","vac.source_auto":"Автоматически","vac.source_auto_hint":"Использовать совместимую сущность этого устройства","vac.all_cameras":"Все камеры","vac.all_cameras_warn":"Камера может не отдавать данные робота. Выбирайте её только если это карта вашего пылесоса.","vac.all_cameras_empty":"Других сущностей камеры не найдено.","vac.platform_unknown":"интеграция неизвестна","vac.cap_position":"позиция","vac.cap_rooms_short":"комнаты","vac.cap_path":"путь","vac.cap_map":"ID карты","vac.cap_none":"данные робота не обнаружены","vac.xcme_hint":"Включите атрибуты Xiaomi Cloud Map Extractor:","vac.documentation":"Документация","vac.residual_title":"Проверьте автокалибровку","vac.residual_message":"Совпавшие комнаты расходятся максимум на {error}. Примените приблизительную калибровку, подгоните её вручную либо отмените без изменения сохранённых настроек.","vac.apply_proposal":"Применить","gs.backup_group":"Резервная копия и перенос","gs.backup_hint":"Скачайте переносимую JSON-копию или проверьте и импортируйте копию, созданную House Plan.","backup.export_open":"Экспорт","backup.import_open":"Импорт","backup.export_title":"Экспорт House Plan","backup.import_title":"Импорт House Plan","backup.export_hint":"Выберите, должна ли копия содержать всю конфигурацию House Plan или только текущее пространство.","backup.full":"Полная копия","backup.current_space":"Текущее пространство","backup.current_space_title":"Текущее пространство: {title}","backup.no_current_space":"Нет текущего пространства","backup.plan_only":"Только планировка","backup.plan_only_hint":"Сохранить комнаты, стены, проёмы, декор и позиции подписей комнат без устройств и привязок Home Assistant.","backup.plan_only_preview":"Файл содержит только планировку","backup.privacy_warning":"Архив сохраняет названия, идентификаторы Home Assistant и точные координаты. Внутренние планы и вложения указываются ссылками, но не вкладываются; текущие состояния и маршруты пылесосов не включаются.","backup.download":"Скачать JSON","backup.export_done":"Резервная копия скачана","backup.reading":"Проверяем резервную копию…","backup.revalidated":"После предпросмотра план изменился. Сводка обновлена — проверьте её и подтвердите ещё раз.","backup.error.unauthorized":"У вас нет прав на экспорт или импорт этого плана.","backup.error.not_ready":"House Plan ещё не готов. Повторите попытку через несколько секунд.","backup.error.too_large":"Размер резервной копии превышает 8 МиБ.","backup.error.invalid_json":"Выбранный файл не является корректным JSON.","backup.error.invalid_format":"Выбранный файл не является резервной копией House Plan.","backup.error.unsupported_export_version":"Эта версия формата резервной копии не поддерживается установленной версией.","backup.error.future_model":"Резервная копия создана в более новой версии модели данных House Plan.","backup.error.invalid_config":"Резервная копия содержит некорректную конфигурацию House Plan.","backup.error.wall_model_migration_blocked":"Не удалось безопасно обновить модель стен из резервной копии. Сначала оптимизируйте исходный план и повторите экспорт.","backup.error.invalid_layout":"Резервная копия содержит некорректные позиции объектов.","backup.error.invalid_content":"Резервная копия содержит некорректные или несогласованные ссылки на файлы.","backup.error.space_not_found":"Выбранное пространство больше не существует.","backup.error.capacity_exceeded":"Добавление этой копии превысит ограничения размера плана.","backup.error.preview_expired":"Время предпросмотра истекло. Выберите файл резервной копии заново.","backup.error.preview_owner_mismatch":"Этот предпросмотр принадлежит другому пользователю Home Assistant.","backup.error.conflict":"После предпросмотра план изменился. Проверьте обновлённую сводку.","backup.error.content_confirmation_required":"Подтвердите отсоединение недоступных локальных файлов.","backup.error.commit_failed":"Не удалось безопасно применить копию. Предыдущий план восстановлен или ожидает восстановления.","backup.error.missing_plan":"После предпросмотра исчез связанный файл плана. Проверьте копию ещё раз.","backup.error.missing_content":"После предпросмотра исчез связанный локальный файл. Проверьте копию ещё раз.","backup.error.marker_control_missing":"В резервной копии отсутствует связанный источник света на плане.","backup.error.marker_control_not_light":"Связанная цель больше не отмечена как источник света.","backup.error.marker_control_self":"Источник света не может управлять самим собой.","backup.error.marker_control_cycle":"Резервная копия содержит циклическую цепочку управления светом.","backup.error.duplicate_marker_control":"Резервная копия содержит повторяющуюся связь с источником света.","backup.error.no_backup":"Нет снимка импорта или оптимизации, который можно восстановить.","backup.same_source":"Создано на этом экземпляре Home Assistant","backup.foreign_source":"Создано на другом экземпляре Home Assistant","backup.created":"Создано: {value}","backup.versions":"Карточка {card}; интеграция {integration}; модель данных {model}","backup.count_spaces":"Пространств: {n}","backup.count_rooms":"Комнат: {n}","backup.count_walls":"Стен: {n}","backup.count_openings":"Проёмов: {n}","backup.count_decor":"Объектов декора: {n}","backup.count_markers":"Устройств: {n}","backup.count_layout":"Позиций: {n}","backup.bindings":"Привязки — устройства: {device}, сущности: {entity}, виртуальные: {virtual}; позиций без пространства: {legacy}","backup.binding_status":"Статус на целевом экземпляре — активных: {active}, деактивированных: {disabled}, отсутствующих: {missing}","backup.missing_areas":"На целевом экземпляре отсутствуют зоны: {areas}","backup.dropped_marker_links":"Связи с источниками света вне переносимого пространства пропущены: {n}.","backup.repaired_target_refs":"Существующих ссылок восстановлено этим импортом: {n}.","backup.preserved_unresolved_refs":"Неоднозначные ссылки сохранены без изменений: {n}.","backup.preserved_unresolved_hint":"House Plan ничего не угадывал и не удалял. После импорта запустите «Оптимизировать планы», чтобы проверить оставшиеся ссылки.","backup.import_details":"Подробности восстановления ссылок","backup.import_detail.incoming_remapped":"Ссылок обновлено внутри импортируемой копии: {n}","backup.import_detail.target_repaired":"Существующих ссылок восстановлено: {n}","backup.import_detail.preserved_unresolved":"Неразрешимых ссылок сохранено: {n}","backup.import_detail.collisions":"Конфликтов назначения безопасно сохранено: {n}","backup.import_detail.dropped_links":"Входящих связей пропущено по правилам переноса: {n}","backup.import_detail.bounded_lineages":"Чрезмерно вложенных идентификаторов ограничено: {n}","backup.replace_warning":"Текущая конфигурация и расположение будут заменены. Загруженные файлы не удаляются. Одну отмену можно выполнить до следующего изменения плана.","backup.foreign_bookkeeping":"Служебные списки известных и новых устройств другого экземпляра импортированы не будут.","backup.final_name":"Название нового пространства","backup.target_settings":"Глобальные настройки целевого экземпляра не изменятся.","backup.duplicates":"Уже существующих привязок: {n}","backup.skip":"Пропустить повторяющиеся устройства","backup.virtual_copy":"Добавить безопасные статичные виртуальные копии","backup.content":"Связанное содержимое","backup.content_available":"доступно локально","backup.content_external":"внешняя ссылка","backup.content_detach_required":"будет отвязано","backup.confirm_detach":"Я понимаю, что недоступные внутренние планы и вложения будут отвязаны от импортируемой конфигурации.","backup.replace":"Заменить","backup.add":"Добавить пространство","backup.space_done":"Пространство импортировано: комнат — {rooms}, устройств — {markers}, существующих ссылок восстановлено — {refs}","backup.full_done":"Копия восстановлена: пространств — {spaces}, комнат — {rooms}, устройств — {markers}","backup.undo_import":"Отменить последний полный импорт","backup.import_undone":"Полный импорт отменён"}}],Gd=Wd;function Vd(e){return"string"==typeof e?e.trim().replaceAll("_","-").toLowerCase():""}const Kd=new Map(Ud.map(e=>[Vd(e.code),e]));function Yd(e){return Kd.get(Vd(e))}function Zd(e,t){const i=[{value:"",label:e},...Ud.map(({code:e,nativeLabel:t})=>({value:e,label:t}))],n="string"==typeof t?t:"";return n&&!i.some(e=>e.value===n)&&i.push({value:n,label:Yd(n)?.nativeLabel??n}),i}function Xd(e,t){return function(e,t,i,n){const r=new Map(i.map(e=>[Vd(e),e])),o=r.get(Vd(e));if(o)return o;const s=Vd(t),a=r.get(s);return a||(r.get(s.split("-")[0]||"")??n)}(t,e?.locale?.language||e?.language,Ud.map(({code:e})=>e),"en")}function Jd(e,t,i){const n=Yd(e)?.dictionary;return Vi(n?.[t]??Gd[t]??t,i)}function Qd(e,t){const i=Yd(e)?.dictionary[t]??Gd[t];return"string"==typeof i&&i.trim().length>0}function eu(e){const t=e.length/2,i=e.face.cm>0?e.face.cm/e.cellCm*e.gridPitch/2:xa(4,e.cellCm),n="gate"===e.type?Math.sin(10*Math.PI/180)*t:0;return{half:t,jambHalf:i,gateDepth:n,outlineHalf:Math.max(xa(16,e.cellCm),i+xa(8,e.cellCm),n+xa(8,e.cellCm)),hitHalf:Math.max(xa(20,e.cellCm),i+xa(10,e.cellCm),n+xa(12,e.cellCm))}}function tu(e){if("passage"===e.type)return W``;const t=Math.max(0,Math.min(1,e.amount)),{half:i,jambHalf:n}=eu(e),r=ka(e.cellCm),o=1.75*r,s=e.flipH?-1:1,a=e.flipV?-1:1,l="gate"===e.type?1:a;e.type,e.flipV,e.angle,e.face;let c;if("window"===e.type){const o=Math.PI/2*i,s=e.face.cm>0?W``:W``;c=W` + + + + + + + + + + + + + + ${s} + `}else if("gate"===e.type){const n=10*e.face.side*t;c=W` + + + + + + + + + + + + `}else{const n=Math.PI/2*e.length;c=W` + + + + + + + + `}return W` + + + ${c} + `}const iu={climate:["current_temperature","temperature","current_humidity","humidity"],water_heater:["current_temperature","temperature"],cover:["current_position"],valve:["current_position"],fan:["percentage"],humidifier:["current_humidity","humidity"],light:["brightness"],media_player:["volume_level"],vacuum:["battery_level","fan_speed"],lawn_mower:["battery_level","fan_speed"]};function nu(e){return e?e.sourceLabel?`${e.sourceLabel}: ${e.fullText}`:e.fullText:""}const ru=new WeakMap;function ou(e){return e?"entity_state"===e.kind?`state:${e.entity_id}`:"entity_attribute"===e.kind?`attr:${e.entity_id}:${e.attribute}`:"derived_marker_state"===e.kind?`marker:${e.ref}`:"derived:lqi":""}function su(e){if("derived:lqi"===e)return{kind:"derived_lqi"};if(e.startsWith("state:"))return{kind:"entity_state",entity_id:e.slice(6)};if(e.startsWith("attr:")){const t=e.slice(5),i=t.lastIndexOf(":");if(i>0)return{kind:"entity_attribute",entity_id:t.slice(0,i),attribute:t.slice(i+1)}}return e.startsWith("marker:marker:")?{kind:"derived_marker_state",ref:e.slice(7)}:null}function au(e,t){const i=e?.entities?.[t],n=e?.states?.[t];return String(i?.name||i?.original_name||n?.attributes?.friendly_name||t)}function lu(e){return e.replaceAll("_"," ")}function cu(e,t=1){const i=Number(e);return Number.isFinite(i)?`${Math.round(i*t)} %`:null}function hu(e){if("derived_lqi"===e.kind)return"lqi";if("entity_attribute"===e.kind){if(e.attribute.includes("temperature"))return"temperature";if(e.attribute.includes("humidity"))return"humidity"}return"default"}function du(e,t,i,n=[]){let r=null,o="",s="available";if("entity_state"===i.kind){o=au(e,i.entity_id);const t=e?.states?.[i.entity_id];if(t)if(pu(e,i.entity_id))if(["unknown","unavailable"].includes(String(t.state).toLowerCase()))s="unavailable";else{const n=qi(e,i.entity_id);r=n?ji(n,String(t.attributes?.unit_of_measurement||"")):null,r||(s="unavailable")}else s="unavailable";else s="missing"}else if("entity_attribute"===i.kind){o=`${lu(i.attribute)} · ${au(e,i.entity_id)}`;const t=e?.states?.[i.entity_id];t?pu(e,i.entity_id)?(r=function(e,t,i){const n=e?.states?.[t];if(!n||!(i in(n.attributes||{})))return null;const r=qi(e,t,i);if(r?.formatted)return r.text;const o=n.attributes?.[i];if("brightness"===i)return cu(o,100/255);if("volume_level"===i)return cu(o,100);if(["current_position","percentage","current_humidity","humidity","battery_level"].includes(i))return cu(o);if("current_temperature"===i||"temperature"===i){const t=Number(o);if(!Number.isFinite(t))return null;const i=String(e?.config?.unit_system?.temperature||"°C");return`${Math.round(10*t)/10} ${i}`}return r?.text||(["string","number","boolean"].includes(typeof o)?String(o):null)}(e,i.entity_id,i.attribute),null==r&&(s="unavailable")):s="unavailable":s="missing"}else if("derived_lqi"===i.kind){o="LQI";const i=Ch(e,t.entities);null==i?s="unavailable":r=String(i)}else{o="Light state";const t=n.find(e=>e.ref===i.ref);if(t){const i=t.on?"on":"off",n=e?.localize?.(`state.default.${i}`);r="string"==typeof n&&n?n:i,o=t.name||o}else s="missing"}const a=e?.localize?.("state.default.unavailable")||"Unavailable";return{source:i,sourceLabel:o,text:r??"—",fullText:r??a,availability:s,isLqi:"derived_lqi"===i.kind,tone:hu(i)}}function uu(e,t){if(!0===t.marker?.use_climate_temp){const i=t.entities.find(t=>t.startsWith("climate.")&&Number.isFinite(Number(e?.states?.[t]?.attributes?.current_temperature)));return i?{kind:"entity_attribute",entity_id:i,attribute:"current_temperature"}:null}if("mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon){const i=t.entities.find(t=>sh(e,t)&&Number.isFinite(Number(e?.states?.[t]?.state)));if(i)return{kind:"entity_state",entity_id:i}}return t.primary&&Oh(e,t.primary)&&Number.isFinite(Number(e?.states?.[t.primary]?.state))?{kind:"entity_state",entity_id:t.primary}:null}function pu(e,t){const i=e?.entities?.[t];if(i&&!Zc(i))return!1;const n=i?.device_id?e?.devices?.[i.device_id]:null;return!n||Zc(n)}function _u(e,t){return pu(e,t)&&!!e?.states?.[t]}function mu(e,t,i=[t]){const n=function(e,t){const i=e=>[e.id,e.primary,e.hidden?1:0,e.userHidden?1:0,e.entities.join(","),(e.controls||[]).join(","),e.marker?.binding||"",!0===e.marker?.is_light?1:0,e.marker?.light_entity||"",(e.marker?.controls||[]).join(",")].join("|");return`${i(e)}\n${t.map(i).join("\n")}`}(t,i),r=ru.get(t);if(r&&r.states===(e?.states||null)&&r.entities===(e?.entities||null)&&r.devices===(e?.devices||null)&&r.signature===n)return r.result;const o=new Set(t.entities);for(const e of t.controls||[])e.startsWith("marker:")||o.add(e);const s=[],a=Mh(e,i),l=a.filter(e=>e.key.startsWith("marker:")).map(e=>({ref:e.key,on:e.on,name:e.device?.name||e.key})),c=i=>{const n=ou(i);if(s.some(e=>e.key===n))return;const r=du(e,t,i,l),o="entity_attribute"===i.kind?`${i.entity_id} · ${i.attribute}`:"entity_state"===i.kind?i.entity_id:"derived_marker_state"===i.kind?i.ref:"LQI";s.push({key:n,source:i,label:r.sourceLabel,technical:o,value:r.text,available:"available"===r.availability})};for(const t of[...o].sort()){if(!_u(e,t))continue;const i=t.split(".")[0],n=e?.entities?.[t];if("button"===i||"event"===i||"config"===n?.entity_category)continue;c({kind:"entity_state",entity_id:t});const r=e?.states?.[t];for(const e of iu[i]||[])e in(r?.attributes||{})&&c({kind:"entity_attribute",entity_id:t,attribute:e})}const h=new Set((t.marker?.controls||t.controls||[]).filter(e=>e.startsWith("marker:")));!0===t.marker?.is_light&&t.marker.id&&h.add(`marker:${t.marker.id}`);const d=new Set(a.map(e=>e.key));for(const e of[...h].sort())d.has(e)&&c({kind:"derived_marker_state",ref:e});return t.virtual||null==Ch(e,t.entities)||c({kind:"derived_lqi"}),ru.set(t,{states:e?.states||null,entities:e?.entities||null,devices:e?.devices||null,signature:n,result:s}),s}function gu(e,t,i){const n=uu(e,t);if(n&&i.some(e=>e.key===ou(n)))return n;const r=t.primary&&i.find(e=>e.key===`state:${t.primary}`);if(r)return r.source;const o=[e=>e.technical.includes("temperature"),e=>e.technical.includes("humidity"),e=>e.technical.includes("battery")];for(const e of o){const t=i.find(e);if(t)return t.source}return i.find(e=>"derived_lqi"!==e.source.kind)?.source||i[0]?.source||null}function fu(e){return e.touched?{value_badge:{enabled:e.enabled,source:e.source,position:e.position}}:e.originalHas?{value_badge:e.original}:{}}function vu(e,t,i){return{kind:"none",reason:"none",generation:e,expiresAt:null,color:t,diameterScale:i,animated:!1,reducedMotionIndicator:"none"}}function yu(e,t,i,n,r=null){return{kind:t,reason:"short"===t?"event":"running",generation:Math.max(1,Math.trunc(i)),expiresAt:"short"===t?r:null,color:e.color,diameterScale:n?1:e.diameterScale,animated:!n,reducedMotionIndicator:n?"dot":"none"}}const bu={availability:"available",status:"neutral",activity:"none"};function wu(e){return e<=40?"low":e<180?"mid":"high"}function ku(e){return Ut(e)}function xu(e){return"static_icon"===e.display?"neutral":"alarm"===e.visual.status?"alarm":"unavailable"===e.visual.availability?"unavailable":e.lockState?e.lockState:"working"===e.visual.status?"working":"open"===e.visual.status?"open":"neutral"}const $u={sourceKind:"none",decisionIds:["source.skipped_static_fast_path"],visualSources:[],criticalSources:[],samples:[]};function Su(e,t){const i=e?.entities?.[t],n=e?.states?.[t];return String(i?.name||i?.original_name||n?.attributes?.friendly_name||t)}function Mu(e,t){const i=e?.states?.[t];if(!i)return"";if("function"==typeof e?.formatEntityState)try{const t=e.formatEntityState(i);if("string"==typeof t&&t)return t}catch{}return String(i.state??"")}function Ru(e,t){if(t.virtual||"virtual"===t.bindingKind||"virtual"===t.marker?.binding)return"available";return(t.entities||[]).some(t=>{const i=String(e?.states?.[t]?.state??"").trim().toLowerCase();return""!==i&&"unknown"!==i&&"unavailable"!==i})?"available":"unavailable"}function Tu(e,t,i,n){return{eid:t,role:i,name:Su(e,t),state:String(e?.states?.[t]?.state??""),stateText:Mu(e,t),integrationDomain:e?.entities?.[t]?.platform||null,sample:n||xc(e,t)}}function Cu(e,t,i=[t],n,r=e){const o=t.hidden&&t.userHidden?{...t,hidden:!1}:t;let s="none",a=[];const l=[],c=[...o.entities,...o.allEntities||[]].some(e=>e.startsWith("cover."))?{...o,tapAction:"cover"}:o,h=(d=vd({hass:e,devices:i,device:c,lightSources:n,registryHass:r}),"cover"!==d?.semantics?null:d.targets[0]?.entityId||d.skippedTargets[0]?.entityId||null);var d;const u=Mh(e,[o]),p=uh(o.marker?.binding,o.marker?.controls??o.controls,o.entities),_=new Set(p.filter(e=>e.startsWith("marker:"))),m=!0===o.marker?.is_light||_.size>0?n||Mh(e,i):u,g=m.filter(e=>e.device.id===o.id&&"controls"!==e.via),f=u.filter(e=>"controls"!==e.via),v=g.length?g:f,y=zc(o.marker),b=y?[...v]:[...u.filter(e=>"controls"===e.via),...v];if(_.size)for(const e of m){if(!_.has(e.key))continue;e.stateEids.length>0&&b.some(t=>t.stateEids.some(t=>e.stateEids.includes(t)))||b.some(t=>t.key===e.key)||b.push({...e,via:"controls",castsGlow:!1})}const w=ch(r,o.entities),k=!!h&&("cover"===o.tapAction||o.primary?.startsWith("cover.")||w.some(e=>e.startsWith("cover.")));if(h&&!k&&l.push("source.cover_capability_bypassed"),k)s="cover",l.push("source.cover"),a=[Tu(e,h,"cover")];else if(b.length)s=!y&&b.some(e=>"controls"===e.via)?"controls":"light",y?l.push("source.manual_virtual_light"):l.push("controls"===s?"source.controls":"source.owned_light"),"controls"!==s||!o.virtual&&"virtual"!==o.bindingKind||l.push("source.virtual_controller"),a=b.map(i=>{const n="controls"===i.via?"control":"forced"===i.via?"forced_light":"light";if(!i.passive)return Tu(e,i.eid,n);const r=i.on?"on":"off";return{eid:i.key,role:n,name:t.name,state:r,stateText:r,integrationDomain:null,sample:{eid:i.key,state:r,availability:"available",status:i.on?"working":"neutral",activity:"none",edge:"none"}}});else{const t=ch(r,o.entities),i=t.length?t:o.entities.filter(t=>!!e?.states?.[t]);if(i.length){s="device_role",l.push("source.device_role");const t=$c(r===e?e:{...r,states:e?.states||{}},i,o.entities),n=i.some(e=>bc(r,e));a=t.map(t=>{const i=n?wc(r,t.eid)?"power_gate":bc(r,t.eid)?"lifecycle":"device_role":"device_role";return Tu(e,t.eid,i,t)})}else o.primary?(s="primary",l.push("source.primary_fallback"),a=[Tu(e,o.primary,"primary")]):l.push("source.none")}p.length>0&&"controls"!==s&&"light"!==s&&"cover"!==s&&l.push("source.filtered_saved_controls");const x=[];for(const t of o.entities||[]){const i=xc(e,t);"alarm"!==i.status||a.some(e=>e.eid===t)||x.push(Tu(e,t,"critical",i))}return x.length&&l.push("source.critical_sibling"),{sourceKind:s,decisionIds:l,visualSources:a,criticalSources:x,samples:[...a,...x].map(e=>e.sample)}}function Du(e,t,i,n){if(t.virtual)return{source:null,text:null,fallback:"value_virtual"};if(n){const i=function(e,t){if(!0!==t.marker?.use_climate_temp)return null;for(const i of t.entities){if(!i.startsWith("climate."))continue;const t=Number(e?.states?.[i]?.attributes?.current_temperature);if(Number.isFinite(t))return{eid:i,text:Math.round(10*t)/10+"°"}}return null}(e,t);if(i)return{source:{kind:"temperature",eid:i.eid,attribute:"current_temperature",text:i.text},text:i.text,fallback:null};const n=function(e,t){if("mdi:thermometer"!==t.icon&&"mdi:air-filter"!==t.icon)return null;for(const i of t.entities){if(!sh(e,i))continue;const t=Number(e?.states?.[i]?.state);if(Number.isFinite(t))return{eid:i,text:Math.round(10*t)/10+"°"}}return null}(e,t);if(n)return{source:{kind:"temperature",eid:n.eid,text:n.text},text:n.text,fallback:null};const r=function(e,t){if(!t.primary||!Oh(e,t.primary))return null;const i=Number(e?.states?.[t.primary]?.state);return Number.isFinite(i)?{eid:t.primary,text:`${Math.round(i)}%`}:null}(e,t);if(r)return{source:{kind:"humidity",eid:r.eid,text:r.text},text:r.text,fallback:null}}const r=i.visualSources.filter(e=>!e.eid.startsWith("marker:"));let o=r.map(e=>e.eid);const s=r.find(e=>"power_gate"===e.role);if(s&&(o=[s.eid]),!o.length&&i.visualSources.some(e=>e.eid.startsWith("marker:"))&&(o=ch(e,t.entities),!o.length&&t.primary&&e?.states?.[t.primary]&&(o=[t.primary])),o=[...new Set(o)],1!==o.length)return{source:null,text:null,fallback:o.length?"value_ambiguous_sources":"value_no_state"};const a=o[0],l=function(e,t){const i=e?.states?.[t];if(!i||null==i.state||""===String(i.state).trim())return{text:"",fallback:"value_no_state"};const n=i.state;if(!["string","number","boolean"].includes(typeof n))return{text:"",fallback:"value_non_scalar"};const r=String(n).trim().toLowerCase();if("unknown"===r||"unavailable"===r)return{text:"",fallback:"value_no_state"};const o=qi(e,t);return o?{text:ji(o,String(i.attributes?.unit_of_measurement||"")),fallback:null}:{text:"",fallback:"value_no_state"}}(e,a);return l.fallback?{source:null,text:null,fallback:l.fallback}:{source:{kind:"entity",eid:a,text:l.text},text:l.text,fallback:null}}function Au(e,t,i){const n=e.marker?.binding||(e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:e.virtual?"virtual":""),r=[...t.visualSources.map(e=>`${e.role}:${e.eid}`),...t.criticalSources.map(e=>`critical:${e.eid}`)].sort(),o=i?`${i.kind}:${i.eid}:${i.attribute||""}`:"none";return[n,t.sourceKind,...r,`value:${o}`].join("\n")}function Ou(e,t,i){return Au(t,i||Cu(e,t),null).replace(/\nvalue:none$/,"")}function zu(e){if(e.effectiveHidden)return[];if("static_icon"===e.display)return["static-icon"];const t=[],{visual:i}=e;return"alarm"===e.pulse.kind?t.push("alarm"):"unavailable"===i.availability?t.push("unavail"):"working"===i.status?t.push("on"):"open"===i.status&&t.push("open"),e.lockState&&t.push(`lock-${e.lockState}`),"none"!==e.pulse.reason&&"alarm"!==e.pulse.reason&&t.push("activity-"+e.pulse.reason),e.pulse.generation%2==0&&(t.push("pulse-gen2"),"short"===e.pulse.kind&&t.push("activity-gen2")),t}function Pu(e,t,i){const n=Ai(t.marker?.display),r="static_icon"===n,o=r&&!1===i.sourceDetails?$u:Cu(e,t,i.lightDevices||[t],i.lightSources,i.registryHass||e),s=t.bindingStatus,a="ha_disabled"===s?.kind,l="orphaned"===s?.kind,c=a?"ha_disabled":l?"orphaned":"active",h=!0===t.userHidden||!0===t.marker?.hidden,d=Sc(o.samples),u=o.visualSources.find(e=>e.eid.startsWith("lock.")),p=u?["unlocked","open"].includes(u.state.toLowerCase())?"unlocked":"locked"===u.state.toLowerCase()?"locked":null:null,_=!zc(t.marker)&&uh(t.marker?.binding,t.marker?.controls??t.controls,t.entities).length>0,m="controls"===o.sourceKind||_&&"light"!==o.sourceKind&&"cover"!==o.sourceKind,g=r&&!1===i.sourceDetails?{source:null,text:null,fallback:null}:Du(e,t,o,i.showTemperature),f=Au(t,o,g.source),v=Ou(e,t,o),y=i.activityRuntime,b=i.now??Date.now(),w=y?.expiresAt||(y?.flashTs?y.flashTs+3300:0),k=y?.sources===v&&y.flashTs&&y.flashKind&&w>b?y.flashKind:null,x=function(e){const t=[],i="ha_disabled"===e.bindingLifecycle||"orphaned"===e.bindingLifecycle;let n=!1;"ha_disabled"===e.bindingLifecycle?(n=!0,t.push("lifecycle.ha_disabled_hidden")):e.userHidden&&!e.designPreview?(n=!0,t.push("lifecycle.user_hidden")):e.userHidden?t.push("lifecycle.user_hidden_preview"):"orphaned"===e.bindingLifecycle?t.push("lifecycle.orphaned_diagnostic"):t.push("lifecycle.active");const r="static_icon"===e.display;let o=e.controllerFace?{...e.sourceVisual,availability:e.controllerAvailability}:e.sourceVisual;t.push(e.controllerFace?"available"===e.controllerAvailability?"availability.controller_available":"availability.controller_unavailable":"availability.source"),n?(o=bu,t.push("face.hidden")):r?(o=bu,t.push("face.static")):"alarm"===e.sourceVisual.status||e.liveStates?t.push("face.dynamic"):(o=bu,t.push("face.live_states_disabled")),!r&&!n&&e.liveStates&&"alarm"!==e.sourceVisual.status&&e.shortActivity&&(o={...o,activity:e.shortActivity},t.push(`activity.short_${e.shortActivity}`)),"alarm"===o.status?t.push("status.alarm"):"unavailable"===o.availability?t.push("status.unavailable"):"working"===o.status?t.push("status.working"):"open"===o.status?t.push("status.open"):t.push("status.neutral");const s="value"===e.display&&!n&&e.valueAvailable?"value":"icon";t.push("value"===s?"content.value":"value"===e.display?"content.value_fallback_icon":"content.icon"),"value"===e.display&&!e.valueAvailable&&e.valueFallback&&t.push(`content.${e.valueFallback}`);const a=e.liveStates&&!r&&!n,l=!r&&!n,c=!n&&!i&&!r&&"available"===o.availability&&("alarm"===o.status||e.liveStates&&"icon_ripple"===e.display),h=l&&e.vacuumLiveRequested;return t.push(a?"diagnostics.dynamic_icon":"diagnostics.base_icon"),t.push(l?"diagnostics.metrics_enabled":"diagnostics.metrics_suppressed"),t.push(c?"activity.pulse_eligible":"activity.pulse_suppressed"),t.push(h?"diagnostics.vacuum_live":"diagnostics.vacuum_static"),{effectiveHidden:n,bindingUnavailable:i,visual:o,face:s,dynamicIcon:a,metrics:l,liveColor:a,pulseEligible:c,vacuumLive:h,decisionIds:t}}({bindingLifecycle:c,userHidden:h,designPreview:!0===i.designPreview,display:n,liveStates:i.liveStates,sourceVisual:d,controllerFace:m,controllerAvailability:m?Ru(e,t):"available",shortActivity:k,valueAvailable:null!=g.text,valueFallback:g.fallback,vacuumLiveRequested:!0===t.marker?.vacuum?.live}),{effectiveHidden:$,visual:S}=x,M="icon_ripple"===n&&!$&&i.liveStates&&"alarm"!==S.status?S.activity:"none",R=x.metrics&&i.showTemperature?!0===t.marker?.use_climate_temp?Ah(e,t.entities):"mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon?Dh(e,t.entities):null:null,T=x.metrics&&i.showTemperature&&t.primary&&Oh(e,t.primary)?zh(e,t.entities):null,C=x.metrics&&i.showSignal&&!t.virtual?Ch(e,t.entities):null,D=i.lightSources||("derived_marker_state"===t.marker?.value_badge?.source?.kind?Mh(e,i.lightDevices||[t]):[]),A=function(e,t,i){const n=null!=t.marker?.value_badge;if(i.effectiveHidden||"static_icon"===i.display)return null;const r=t.marker?.value_badge;if(n)return r?.enabled?r.source?{configured:!0,enabled:!0,position:r.position||"right",...du(e,t,r.source,i.markerStates)}:{configured:!0,enabled:!0,source:null,sourceLabel:"",text:"—",fullText:e?.localize?.("state.default.unavailable")||"Unavailable",position:r.position||"right",availability:"missing",isLqi:!1,tone:"default"}:null;if(!i.showTemperature||"value"===i.display)return null;const o=uu(e,t);if(!o)return null;let s=null,a="default";if("entity_attribute"===o.kind&&"current_temperature"===o.attribute){const i=Ah(e,t.entities);null!=i&&(s=`${i}°`),a="temperature"}else if("mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon){const i=Dh(e,t.entities);null!=i&&(s=`${i}°`),a="temperature"}else{const i=zh(e,t.entities);null!=i&&(s=`${i}%`),a="humidity"}return null==s?null:{configured:!1,enabled:!0,source:o,position:"right",sourceLabel:"entity_attribute"===o.kind?`${lu(o.attribute)} · ${au(e,o.entity_id)}`:"entity_state"===o.kind?au(e,o.entity_id):"",text:s,fullText:s,availability:"available",isLqi:!1,tone:a}}(e,t,{showTemperature:i.showTemperature,showSignal:i.showSignal,display:n,effectiveHidden:$,markerStates:D.filter(e=>e.key.startsWith("marker:")).map(e=>({ref:e.key,on:e.on,name:e.device.name}))}),O=o.visualSources.find(e=>!e.eid.startsWith("marker:")),z="cover"===o.sourceKind?O?.eid:t.primary||O?.eid,P=z?e?.states?.[z]:null,F=x.dynamicIcon?dn(t.icon,z?.split(".")[0],P?.attributes?.device_class,P?.state,!!t.marker?.icon):t.icon,I=x.liveColor&&o.visualSources.filter(e=>!e.eid.startsWith("marker:")).map(t=>function(e){return e&&"on"===e.state?Wt(e.attributes?.rgb_color):null}(e?.states?.[t.eid])).find(e=>!!e)||null,E=Number(t.marker?.size)>0?Number(t.marker.size):1,N=Number(t.marker?.angle)||0,H=Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,L=qt(t.marker?.ripple_color,null),q=r?null:L||I||null,j=function(e){const{display:t,visual:i,semanticActivity:n,liveStates:r,effectiveHidden:o,bindingUnavailable:s=!1,reducedMotion:a=!1}=e,l=Math.max(1,Math.trunc(e.shortGeneration||1)),c=Number.isFinite(e.diameterScale)?Math.max(1,Number(e.diameterScale)):1.5,h=e.color||function(e,t){return"presence"===t?"#1DC21D":"running"===t||"working"===e.status||"open"===e.status?"#F0A00C":"#0C82F0"}(i,n);if(o||s||"unavailable"===i.availability||"static_icon"===t)return vu(l,h,c);if("alarm"===i.status)return{kind:"alarm",reason:"alarm",generation:l,expiresAt:null,color:"#F0410C",diameterScale:1.5,animated:!a,reducedMotionIndicator:"none"};if(!r||"icon_ripple"!==t)return vu(l,h,c);const d=e.now??Date.now(),u=e.shortExpiresAt||null;return e.shortReason&&null!=u&&u>d?{kind:"short",reason:e.shortReason,generation:l,expiresAt:u,color:h,diameterScale:a?1:c,animated:!a,reducedMotionIndicator:a?"dot":"none"}:"presence"===n||"transition"===n||"running"===n?{kind:"continuous",reason:n,generation:l,expiresAt:null,color:h,diameterScale:a?1:c,animated:!a,reducedMotionIndicator:a?"dot":"none"}:vu(l,h,c)}({display:n,visual:S,semanticActivity:d.activity,shortReason:y?.sources===v?y?.flashKind:null,shortGeneration:y?.gen,shortExpiresAt:y?.sources===v?w:null,now:b,liveStates:i.liveStates,effectiveHidden:$,bindingUnavailable:x.bindingUnavailable,reducedMotion:i.reducedMotion,color:q,diameterScale:H}),B="value"===x.face?g.text:null,W="ha_disabled"===s?.kind?s.reason:null,U="ha_disabled"===(G={lifecycle:c,display:n,liveStates:i.liveStates,sourceKind:o.sourceKind,primaryDomain:(t.primary||"").split(".")[0],visual:S,activity:M}).lifecycle?"ha_disabled":"orphaned"===G.lifecycle?"orphaned":"static_icon"===G.display?"static_icon":"alarm"===G.visual.status?"alarm":G.liveStates?"unavailable"===G.visual.availability?"unavailable":"cover"===G.sourceKind?"cover_icon_state":"presence"===G.activity?"presence":"event"===G.activity?"event":"transition"===G.activity?"transition":"working"===G.visual.status?"icon_ripple"===G.display&&"none"!==G.activity?"working_activity":"working":"open"===G.visual.status?"open":"media_player"===G.primaryDomain?"media_neutral":"neutral":"live_states_disabled";var G;const V=[];i.designPreview&&h&&V.push("hidden_design_preview"),r||!0!==t.marker?.vacuum?.live||V.push("vacuum_live_plan_only");const K=o.visualSources.some(t=>"power_gate"===t.role||wc(e,t.eid)),Y=t.entities.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category).length;K&&Y>1&&V.push("composite_power_source"),"icon_ripple"!==n&&"static_icon"!==n&&"alarm"!==d.status&&"none"!==d.activity&&V.push("activity_display_disabled");const Z={binding:t.marker?.binding||(t.bindingKind&&t.bindingRef?`${t.bindingKind}:${t.bindingRef}`:t.virtual?"virtual":""),sourceKind:o.sourceKind,visualSources:o.visualSources,criticalSources:o.criticalSources,valueSource:g.source,sourceSignature:f,decisionIds:[...o.decisionIds,...x.decisionIds,...A?["diagnostics.value_badge"]:[],...null==C?[]:[`diagnostics.lqi_${wu(C)}`],`pulse.${j.kind}_${j.reason}`],visual:S,lockState:p,display:n,icon:F,valueText:B,valueFullText:B,fallbackReason:"value"!==n||B?null:g.fallback,activity:M,activityGeneration:y?.gen||1,pulse:j,classes:[],tempText:null==R?null:String(R),humText:null==T?null:String(T),valueBadge:A,lqiText:null==C||A?.isLqi?null:String(C),lqiColor:null==C?null:ku(C),lqiBand:null==C?null:wu(C),lightColor:I,scale:E,angle:N,rippleScale:H,rippleColor:q,userHidden:h,effectiveHidden:$,haDisabled:a,disabledReason:W,orphaned:l,vacuumLive:x.vacuumLive,explanation:{reason:U,notices:V}};return{...Z,classes:zu(Z)}}function Fu(e,t=new WeakMap){if(null===e||"object"!=typeof e)return e;const i=e,n=t.get(i);if(n)return n;if(Array.isArray(e)){const n=[];t.set(i,n);for(const i of e)n.push(Fu(i,t));return Object.freeze(n)}const r={};t.set(i,r);for(const[i,n]of Object.entries(e))"function"!=typeof n&&(r[i]=Fu(n,t));return Object.freeze(r)}function Iu(e){const t=new Map(e);let i;return i=Object.freeze({get size(){return t.size},get:e=>t.get(e),has:e=>t.has(e),entries:()=>t.entries(),keys:()=>t.keys(),values:()=>t.values(),forEach:(e,n)=>t.forEach((t,r)=>e.call(n,t,r,i)),[Symbol.iterator]:()=>t[Symbol.iterator]()}),i}function Eu(e){const t=new Set(e.entityIds||[]),i=new Set(e.deviceIds||[]),n=new Set(e.areaIds||[]);for(const n of e.devices){for(const e of n.entities||[])t.add(e);n.primary&&t.add(n.primary);for(const e of n.controls||[])t.add(e);n.marker?.vacuum?.source&&t.add(n.marker.vacuum.source),"device"===n.bindingKind&&n.bindingRef&&i.add(n.bindingRef),"entity"===n.bindingKind&&n.bindingRef&&t.add(n.bindingRef)}const r={},o={};for(const[o,s]of Object.entries(e.hass?.entities||{})){const a=s?.device_id?e.hass?.devices?.[s.device_id]:null;(t.has(o)||s?.device_id&&i.has(s.device_id)||n.has(s?.area_id)||n.has(a?.area_id))&&(t.add(o),r[o]=s,s?.device_id&&i.add(s.device_id))}for(const t of i){const i=e.hass?.devices?.[t];i&&(o[t]=i)}const s={};for(const i of t){const t=e.hass?.states?.[i];t&&(s[i]=t)}const a=Object.freeze({states:Fu(s),entities:Fu(r),devices:Fu(o),config:Fu(e.hass?.config),locale:Fu(e.hass?.locale),themes:Fu(e.hass?.themes)});return Object.freeze({sourceSequence:e.sourceSequence,capturedAt:e.capturedAt??Date.now(),hass:a,devices:Fu([...e.devices]),positions:Iu([...e.positions||[]].map(([e,t])=>[e,Object.freeze({x:t.x,y:t.y})])),presentations:Iu([...e.presentations].map(([e,t])=>[e,Fu(t)])),facts:Iu([...e.facts||[]].map(([e,t])=>[e,Fu(t)]))})}const Nu=(e,t)=>`${e}:${t?1:0}`;function Hu(e){return"boolean"==typeof e?.themes?.darkMode?e.themes.darkMode?"theme-dark":"theme-light":""}function Lu(e){const t=[];if(1!==e.scale&&t.push(`--dev-scale:${e.scale}`),"none"!==e.pulse.kind){t.push(`--ripple-scale:${e.pulse.diameterScale}`);const r=(i=e.pulse.color,n=null,"string"==typeof i&&(Lt.test(i)||Bt.test(i))?i:n);r&&t.push(`--ripple-color:${r}`)}var i,n;return t}function qu(e){const t=[...String(e)].reduce((e,t)=>/\s/.test(t)?e+.35:e+(t.codePointAt(0)>255?1:.62),0);return t<=8?.45:Math.max(.25,Math.round(3.6/t*1e3)/1e3)}function ju(e,t){const i=e.pulse,n=i.generation%2==0,r=function(e){const t=e.valueBadge;if(!t||!1!==t.configured)return[];const i=[];return null!=e.tempText&&"temperature"!==t.tone&&i.push({kind:"temperature",text:e.tempText,suffix:"°"}),null!=e.humText&&"humidity"!==t.tone&&i.push({kind:"humidity",text:e.humText,suffix:"%"}),i}(e),o=e.valueBadge,s=o?.position||"right",a=!!o||r.length>0,l=["device-shell",null!=e.valueText?"text-shell":"",a?`with-values pos-${s}`:"",r.length?"with-legacy":""].filter(Boolean).join(" ");return B` + ${"none"!==i.kind&&"dot"!==i.reducedMotionIndicator?B``:G} + ${"dot"===i.reducedMotionIndicator?B``:G} + ${t.newDevice?B``:G} + ${e.haDisabled?B``:G} + + ${null!=e.lqiText?B`${e.lqiText}`:G} + `}function Bu(e){return!Number.isFinite(e)||e<=0?2.25:e/2.5*2.25}function Wu({openings:e,geometries:t,fillsByRoomId:i,idPrefix:n="data",groupClass:r="opening-tunnels",dataLayer:o="data"}){const s=e.map((e,r)=>{const o=t[r];if(!o)return G;const s=o.faces.find(e=>-1===e.side),a=o.faces.find(e=>1===e.side);if(!s||!a)return G;const l=i.get(s.roomId)||null,c=i.get(a.roomId)||null;if(!l&&!c)return G;const h=`${s.d} ${a.d}`,d=!!l&&!!c&&l.color===c.color&&l.opacity===c.opacity,u=`translate(${e.rx} ${e.ry}) rotate(${e.angle})`;if(d)return W``;const p=o.maxY-o.minY;if(!(p>0))return G;const _=`${(100*Math.max(0,Math.min(1,-o.minY/p))).toFixed(6)}%`,m=l||{color:"#000000",opacity:0},g=c||{color:"#000000",opacity:0},f=`hp-opening-tunnel-${n.replace(/[^a-zA-Z0-9_-]/g,"-")}-${r}`;return W``});return W``}function Uu(e,t,i){const n=i>0?i:1;return{a:[e[0]/n,e[1]/n],b:[t[0]/n,t[1]/n]}}function Gu(e,t){const i=t>0?t:1;return[e.a[0]*i,e.a[1]*i,e.b[0]*i,e.b[1]*i]}function Vu(e){return Array.isArray(e)&&e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1]))}function Ku(e){if(!Array.isArray(e))return[];const t=[];for(const i of e){if(!i||"object"!=typeof i)continue;const e=i;if(!Vu(e.a)||!Vu(e.b))continue;const n=[Number(e.a[0]),Number(e.a[1])],r=[Number(e.b[0]),Number(e.b[1])];Math.hypot(r[0]-n[0],r[1]-n[1])<.001||t.push({a:n,b:r})}return t}function Yu(e,t,i,n,r=!0){const o=(e||[]).filter(e=>e?.id),s=Ku(t);if(s.length)return function(e,t,i,n){const r=Ku(e);if(!r.length)return[];const o=function(e,t){const i=[],n=(e||[]).filter(e=>e?.id);for(let e=0;e4*n||o>4*n)continue;const s=(e[0]-r)*u+(e[1]-l)*p,c=(e[2]-r)*u+(e[3]-l)*p,h=Math.max(0,Math.min(s,c)),m=Math.min(d,Math.max(s,c));if(m-he.lo-t.lo||e.hi-t.hi);const i=[];for(const e of t){const t=i[i.length-1];t&&e.lo<=t.hi+a?t.hi=Math.max(t.hi,e.hi):i.push({...e})}for(const t of i){const i=[r+u*t.lo,l+p*t.lo],n=[r+u*t.hi,l+p*t.hi];Math.hypot(n[0]-i[0],n[1]-i[1])i.pair===e&&Math.abs(i.ux*s-i.uy*o)<=1e-6&&Math.abs((t[0]-i.origin[0])*i.uy-(t[1]-i.origin[1])*i.ux)<=c&&Math.abs((t[2]-i.origin[0])*i.uy-(t[3]-i.origin[1])*i.ux)<=c);h||(h={pair:e,origin:[t[0],t[1]],ux:o,uy:s,ranges:[]},l.push(h));const d=(t[0]-h.origin[0])*h.ux+(t[1]-h.origin[1])*h.uy,u=(t[2]-h.origin[0])*h.ux+(t[3]-h.origin[1])*h.uy;h.ranges.push({lo:Math.min(d,u),hi:Math.max(d,u)})}const h=[];for(const e of l){e.ranges.sort((e,t)=>e.lo-t.lo||e.hi-t.hi);const t=[];for(const i of e.ranges){const e=t[t.length-1];e&&i.lo<=e.hi+a?e.hi=Math.max(e.hi,i.hi):t.push({...i})}for(const n of t){const t=[e.origin[0]+e.ux*n.lo,e.origin[1]+e.uy*n.lo],r=[e.origin[0]+e.ux*n.hi,e.origin[1]+e.uy*n.hi];Math.hypot(r[0]-t[0],r[1]-t[1])>=a&&h.push(Uu(t,r,i))}}return h}(s,e,i,n).map(e=>Gu(e,i));if(!r)return[];const a=[],l=(e,t)=>(e.open_to||[]).includes(t.id)||(t.open_to||[]).includes(e.id);for(let e=0;er)&&zo([o[0],o[1]],[o[2],o[3]],i))return!0;return!1}const Xu=e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1])),Ju=(e,t,i)=>[Number(e[0])*i,Number(e[1])*i,Number(t[0])*i,Number(t[1])*i],Qu=e=>{const t=`${Number(e[0]).toFixed(9)},${Number(e[1]).toFixed(9)}`,i=`${Number(e[2]).toFixed(9)},${Number(e[3]).toFixed(9)}`;return t<=i?`${t}|${i}`:`${i}|${t}`},ep=e=>{const t=new Map;for(const i of e.flat())!Array.isArray(i)||i.length<4||!i.every(Number.isFinite)||Math.hypot(i[2]-i[0],i[3]-i[1])<=1e-9||t.set(Qu(i),[...i]);return[...t.values()]};function tp(e){return"solid"===e?.zero_wall_style?"solid":"dashed"}function ip(e,t=1,i){const n=[];for(const r of Array.isArray(e?.wall_segments)?e.wall_segments:[])0===Number(r?.cm)&&Xu(r?.a)&&Xu(r?.b)&&(i&&!i.has(String(r.id||""))||n.push(Ju(r.a,r.b,t)));return ep([n])}function np(e,t=1){const i=[];for(const n of Array.isArray(e?.partitions)?e.partitions:[])0===Number(n?.cm)&&Xu(n?.a)&&Xu(n?.b)&&i.push(Ju(n.a,n.b,t));for(const n of Array.isArray(e?.room_drafts)?e.room_drafts:[]){const e=Array.isArray(n?.points)?n.points:[];for(let r=0;r+1e?.host?.kind===t.kind&&e.host.id===t.id)}const ap=new WeakMap,lp=new WeakMap;function cp(e){const t=za(e.cfg),i={};for(const t of e.cfg.spaces||[])for(const e of t.rooms||[])e.area&&(i[e.area]=t.id);const n=e.cfg.settings?.exclude_integrations?new Set(e.cfg.settings.exclude_integrations):Te,r=De(e.cfg.settings?.icon_rules?.length?e.cfg.settings.icon_rules:Ce);return Wh({hass:e.hass,registry:e.registry,areaToSpace:i,markers:e.cfg.markers||[],settings:e.cfg.settings||{},excluded:n,showAll:!!e.cfg.settings?.show_all,firstSpaceId:t[0]?.id||"",loc:t=>Jd(e.lang,t),iconRules:r})}function hp(e){const t=za(e.cfg).find(t=>t.id===e.spaceId);if(!t)return null;const i=tn(e.cfg.spaces.find(t=>t.id===e.spaceId)),n=on(e.cfg.settings),r=e.iconSize??2.5,o=r>8?2.5:r,s=Bu(o),a=e.registry?Xc(e.hass,e.registry):e.hass,l=e.registry?Jc(e.hass,e.registry):e.hass,c=(e.devices||cp(e)).filter(t=>t.space===e.spaceId),h=c.filter(e=>!e.hidden),d=function(e,t,i){const n={},r=i/100*el(t)*1.3;for(const i of t.rooms){if(!i.area)continue;const t=e.filter(e=>e.area===i.area);if(!t.length)continue;const o=rl(i),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(t.length*a/Math.max(l,1)))),h=a/c,d=l/Math.max(Math.ceil(t.length/c),1),u=t.map((e,t)=>({x:o.x+s+h*(t%c+.5),y:o.y+s+d*(Math.floor(t/c)+.5)}));Ti(u,o,r,.5*s),t.forEach((e,t)=>n[e.id]=La(u[t]))}return n}(c,t,o),u=[];for(const t of h){const i=e.layout[t.id];if(i&&i.s===e.spaceId){const e=i.x*Ra,t=i.y*Ra;u.push({minX:e,minY:t,maxX:e,maxY:t})}}const p=e.cfg.spaces.find(t=>t.id===e.spaceId)||{},_=Array.isArray(p.walls)?p.walls:[],m=Number(p.cell_cm)>0?Number(p.cell_cm):5,g=op(p,t,Ra,.02*Ea),f=(p.openings||[]).flatMap(e=>{if("partition"!==e.host?.kind)return[];const i=Td(e,t.partitions,Ra,m,Ea).resolved;return i?[i]:[]}),v=Rl({partitions:t.partitions,roomDrafts:t.room_drafts,columns:t.wall_columns,cellCm:m,hostedOpenings:f.map(e=>({id:e.opening.id,host:e.host,length:e.length,type:e.opening.type}))}),y=function(e,t,i,n){let r=lp.get(e);r||(r=new Map,lp.set(e,r));const o=r.get(t);if(o?.fingerprint===i)return o.value;const s=n();return r.set(t,{fingerprint:i,value:s}),s}(e.cfg,t.id,v,()=>ca(t,m,Ea,2e-4*Ea,f.map(Ad)).all);for(const e of y){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);t.length&&u.push({minX:Math.min(...t),minY:Math.min(...i),maxX:Math.max(...t),maxY:Math.max(...i)})}for(const e of g.lines)u.push({minX:Math.min(e[0],e[2]),minY:Math.min(e[1],e[3]),maxX:Math.max(e[0],e[2]),maxY:Math.max(e[1],e[3])});const b=Ja(t,u),w=[b.x,b.y,b.w,b.h],k=new Map(t.rooms.map(t=>{const r=Rn(i.fill,t);return[t,an(r,"lqi"===r&&t.area?Kh(a,c,t.area):null,"light"===r?Th(Mh(a,c,t,e.virtualLights)):"none","temp"===r&&t.area?Yh(a,c,t.area):null,i.tempMin,i.tempMax,n,en(i.customFill,t))]})),x=new Map;for(const e of t.rooms)e.id&&x.set(e.id,k.get(e)||null);const $=function(e,t=1e3){const i=[];for(const[n,r]of(e||[]).entries()){if("passage"!==r?.type)continue;const e={...r,id:String(r.id||`passage-${n}`),type:"passage",rx:Number(r.x)*t,ry:Number(r.y)*t,rlen:Number(r.length)*t};[e.rx,e.ry,e.rlen,e.angle].every(Number.isFinite)&&e.rlen>0&&i.push(e)}return i}((p.openings||[]).flatMap(e=>{if(!e.host||"wall"===e.host.kind)return[e];const t=f.find(t=>t.opening.id===e.id);return t?[Id(e,t,Ra)]:[]}),Ra),S=gs(t.rooms,_,g.contour,Na,m,Ea,Ra),M=f.filter(e=>Pd(e,S,2e-4*Ea)).map(e=>({x:e.center[0],y:e.center[1],angle:e.angle,length:e.length})),R=t.rooms.filter(e=>e.area||i.showBorders||"none"!==Rn(i.fill,e)).map(e=>{let n="room "+(t.bg?"overlay":"yard"),r="";const o=Rn(i.fill,e);if(i.showBorders||"none"!==o){n+=" styled";const t=[`--room-stroke:${i.color}`,`--room-stroke-op:${i.showBorders&&!g.contour.length?i.opacity:0}`],o=k.get(e)||null;o?(n+=" filled",t.push(`--room-fill:${o.color}`,`--room-fill-op:${o.opacity.toFixed(3)}`)):t.push("--room-fill:transparent","--room-fill-op:0"),r=t.join(";")}const s=e.id||G,a=e.area||G,l=e.poly?W``:W``;return l}),T=t.rooms.filter(e=>{const t=k.get(e);return Tn(i.glow,e)&&(!t||t.opacity<=0)}).map(e=>e.poly?W``:W``),C=new Map;for(const e of t.rooms)if(e.id){const t=k.get(e)||null;C.set(e.id,Tn(i.glow,e)&&(!t||t.opacity<=0)?{color:n.glow_base.c,opacity:n.glow_base.a,mode:"glow"}:null)}const D=Mh(a,h,null,e.virtualLights),A=h.map(n=>{const r=function(e,t,i,n,r){const o=t[e.id];return o&&o.s===e.space?{x:o.x*Ra,y:o.y*Ra}:n[e.id]?n[e.id]:La(Qa(r))}(n,e.layout,e.cfg,d,t),o=(r.x-w[0])/w[2]*100,s=(r.y-w[1])/w[3]*100,c=i.showLqi??!1!==e.showSignal,u=e.presentations?.get(Nu(n.id,c))||Pu(a,n,{liveStates:!1!==e.liveStates,showTemperature:!1!==e.showTemperature,showSignal:c,activityRuntime:e.activityRuntime?.get(n.id),sourceDetails:!1,lightDevices:h,lightSources:D,registryHass:l,reducedMotion:e.reducedMotion}),p=[`left:${o}%`,`top:${s}%`,...Lu(u)],_=xu(u),m=[n.name,Jd(e.lang,`marker.state_a11y_${_}`),"none"!==u.pulse.kind?Jd(e.lang,`marker.pulse_a11y_${u.pulse.reason}`):"",u.valueFullText||u.valueText||"",nu(u.valueBadge),null!=u.lqiText&&u.lqiBand?Jd(e.lang,`marker.lqi_a11y_${u.lqiBand}`,{value:u.lqiText}):""].filter(Boolean).join(", ");return B``}),O=i.showNames?t.rooms.filter(e=>e.name).map(n=>{const r=ol(n,t.id,e.layout,e.cfg),o=(r.x-w[0])/w[2]*100,s=(r.y-w[1])/w[3]*100,a=Math.min(1,i.opacity+.25);return B`
${n.name}
`}):[],z=t.bg?e.displayUrl?e.displayUrl(t.bg.href):t.bg.href:"",P=e.cfg.spaces.find(t=>t.id===e.spaceId)?.settings||{},F="daynight"===sr(e.cfg?.settings,P)?Yn(a,e.dayCycleNow??new Date):null,I=nn(e.cfg?.settings,i),E=!!(_.length||y.length&&i.showBorders),N=E?Rl($.length?{rooms:t.rooms,walls:_,extras:y,cellCm:m,zero:g.contour,passages:$.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),hostedCompositeOpenings:M}:{rooms:t.rooms,walls:_,extras:y,cellCm:m,zero:g.contour}):"",H=E?function(e,t,i,n){let r=ap.get(e);r||(r=new Map,ap.set(e,r));const o=r.get(t);if(o?.fingerprint===i)return o.value;const s=n();return r.set(t,{fingerprint:i,value:s}),s}(e.cfg,t.id,N,()=>Hs(t.rooms,_,g.contour,[...$.filter(e=>"partition"!==e.host?.kind).map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),...M],Na,m,Ea,Ra,y)):null,L=$.length&&_.length?function(e,t,i,n,r,o,s,a=1){return[r,o,s,a].every(Number.isFinite)&&o>0&&a>0&&i?.length?Zs(Bs(e,i,n,r,o,s,a),t):t.map(()=>null)}(t.rooms,$.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),_,g.contour,Na,m,Ea,Ra):$.map(()=>null),q=$.length?Wu({openings:$,geometries:L,fillsByRoomId:x,idPrefix:`${t.id}-static-data`,groupClass:"opening-tunnels static-opening-tunnels",dataLayer:"data"}):G,j=$.length?Wu({openings:$,geometries:L,fillsByRoomId:C,idPrefix:`${t.id}-static-glow`,groupClass:"opening-tunnels glow-base-tunnels static-opening-tunnels",dataLayer:"glow-base"}):G,U=_.length&&H?.paperD?[{path:H.paperD}]:Xt(t.rooms),V=i.showBorders?H:null,K=e.stageWidth&&w[2]?e.stageWidth/w[2]:1,Y=_o(m),Z=!!V&&(po(V.depthUnits,K)||mo(Y,K)),X=i.color||"#607d8b",J=i.hideOpenings?[]:f.map(e=>{const t=e.opening,i="passage"!==t.type&&t.contact?a.states?.[t.contact]?.state:null,n=ii(t.type,i,!!t.invert),r=n>0&&!!t.contact,o="gate"===t.type?!t.flip_v:!!t.flip_v,s={type:t.type,length:e.length,angle:e.angle,amount:n,flipH:!!t.flip_h,flipV:!!t.flip_v,base:X,tone:r?"var(--hp-open)":X,cellCm:m,gridPitch:Ea,face:Od(e,o)};return W` + ${tu(s)} + `});return B` +
+ ${dr(F)} + + ${V?W` + + + + `:G} + ${U.map(e=>"path"in e?W``:"poly"in e?W``:W``)} + ${z?W`e.assetLoaded?.(t.bg.href,z)} + transform=${t.bg.angle?`rotate(${t.bg.angle} ${t.bg.x+t.bg.w/2} ${t.bg.y+t.bg.h/2})`:G} + preserveAspectRatio="none" />`:G} + ${R} + ${i.showBorders&&g.contour.length?W``:G} + ${q} + ${T.length?W``:G} + ${j} + ${V?W` + ${V.paths.map(e=>W` + + `)} + `:G} + ${i.showBorders&&g.lines.length?W``:G} + ${J} + + ${""} +
${A}${O}
+
+ `}let dp=null,up=null,pp=0,_p=-1,mp=null,gp=[];const fp=new Set,vp=(e,t)=>{"function"==typeof e&&t.push(e)};function yp(){if(dp)return dp;try{const e=JSON.parse(localStorage.getItem("houseplan_card_cfg_v1")||"null");if(e&&e.config&&Array.isArray(e.config.spaces)){const t=e.layout||{};return{config:e.config,rev:e.rev||0,configFingerprint:e.config_fingerprint||Rl(e.config),layout:t,layoutRev:e.layout_rev||0,layoutFingerprint:e.layout_fingerprint||Rl(t),virtualLights:Cc(e.virtual_lights,e.rev||0)}}}catch{}return null}function bp(e,t=!1){if(t&&(dp=null,pp++,up))return up.catch(()=>null).then(()=>bp(e,!1));if(dp)return Promise.resolve(dp);if(up)return _p!==pp?up.catch(()=>null).then(()=>bp(e,!1)):up;return _p=pp,up=async function(e,t){const[i,n]=await Promise.all([e.callWS({type:"houseplan/config/get"}),e.callWS({type:"houseplan/layout/get"})]),r=i?.rev??0,o=dp?Dc(dp.virtualLights,i?.virtual_lights,r,!!i&&"virtual_lights"in i):Cc(i?.virtual_lights,r),s={config:i?.config??null,rev:r,configFingerprint:Rl(i?.config??null),layout:n?.layout??{},layoutRev:n?.rev??0,layoutFingerprint:Rl(n?.layout??{}),virtualLights:o};t===pp&&(dp=s);const a=e.connection;if(a?.subscribeEvents&&mp!==a){for(const e of gp)e();gp=[],mp=a;const e=()=>{dp=null,pp++,fp.forEach(e=>e())},t=[];try{if(vp(await a.subscribeEvents(e,"houseplan_config_updated"),t),vp(await a.subscribeEvents(e,"houseplan_layout_updated"),t),vp(await a.subscribeEvents(e=>{if(dp){const t=Fc(dp.virtualLights,e?.data);if(t===dp.virtualLights)return;dp={...dp,virtualLights:t}}else pp++;fp.forEach(e=>e())},"houseplan_virtual_light_updated"),t),mp===a)gp=t;else for(const e of t)e()}catch{for(const e of t)e();mp===a&&(mp=null)}}return s}(e,pp).finally(()=>{up=null,_p=-1}),up}const wp=3300;function kp(e,t){return{sources:e,last:Object.fromEntries(t.map(e=>[e.eid,e.state])),flashTs:0,flashKind:null,timer:0,gen:0,expiresAt:0,alarmActive:"alarm"===Sc(t).status}}function xp(e,t,i,n){n(e.timer);const r=kp(t,i);Object.assign(e,r)}function $p(e,t,i,n,r){e.flashTs&&i-e.flashTs"transition"===e.activity)&&(i(e.timer),e.flashTs=0,e.flashKind=null,e.expiresAt=0);if("alarm"===Sc(t).status){e.alarmActive||(i(e.timer),e.flashTs=0,e.flashKind=null,e.expiresAt=0);for(const i of t)e.last[i.eid]=i.state;return e.alarmActive=!0,null}if(e.alarmActive){for(const i of t)e.last[i.eid]=i.state;return e.alarmActive=!1,null}let n=null;for(const i of t){const t=Mc(e.last[i.eid],i);("event"===t||!n&&t)&&(n=t),e.last[i.eid]=i.state}return n}class Mp{constructor(e,t=()=>{}){this._host=e,this._onGateChange=t,this._modality="unknown",this._gate=!1,this._media=null,this._connected=!1,this._onMediaChange=()=>this._syncGate()}get modality(){return this._modality}get hoverEnabled(){return this._gate}connect(e=globalThis.window){this._connected||(this._connected=!0,this._modality="unknown",this._media="function"==typeof e?.matchMedia?e.matchMedia("(any-hover: hover) and (any-pointer: fine)"):null,this._media?.addEventListener?.("change",this._onMediaChange),this._setGate(!1))}disconnect(){this._media?.removeEventListener?.("change",this._onMediaChange),this._media=null,this._connected=!1,this._modality="unknown",this._setGate(!1)}note(e){return this._modality=function(e,t){const i="mouse"===(n=t.pointerType)||"touch"===n||"pen"===n?n:null;var n;return i?"mouse"===i&&t.sourceCapabilities?.firesTouchEvents?e:i:e}(this._modality,e),this._syncGate(),this._modality}suspend(){this._setGate(!1)}_syncGate(){var e,t;this._setGate((e=this._modality,t=!!this._media?.matches,"mouse"===e&&t))}_setGate(e){this._gate!==e&&(this._gate=e,this._host.toggleAttribute("data-pointer-hover",e),this._onGateChange(e))}}class Rp extends he{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id}))}catch{this._spaces=[]}finally{this._spacesLoading=!1}}}get _lang(){return Xd(this.hass,this._config?.language)}get _schema(){const e=this._spaces||[];return[e.length?{name:"space",selector:{select:{mode:"dropdown",options:e}}}:{name:"space",selector:{text:{}}},{name:"title",selector:{text:{}}},{name:"show_button",selector:{boolean:{}}},{name:"button_label",selector:{text:{}}},{name:"button_target",selector:{text:{}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}}]}render(){if(!this.hass||!this._config)return G;this._loadSpaces();const e=this._lang,t={space:Jd(e,"editor.space"),title:Jd(e,"editor.title"),show_button:Jd(e,"editor.show_button"),button_label:Jd(e,"editor.button_label"),button_target:Jd(e,"editor.button_target"),icon_size:Jd(e,"editor.icon_size"),show_temperature:Jd(e,"editor.show_temperature"),live_states:Jd(e,"editor.live_states"),show_signal:Jd(e,"editor.show_signal")};return B`t[e.name]||e.name} + @value-changed=${this._valueChanged} + >`}_valueChanged(e){const t={...this._config||{},...e.detail.value};delete t.aspect_ratio;const i=new Event("config-changed",{bubbles:!0,composed:!0});i.detail={config:t},this.dispatchEvent(i)}}Rp.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-space-card-editor")||customElements.define("houseplan-space-card-editor",Rp);const Tp=e=>{history.pushState(null,"",e),((e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)})(window,"location-changed",{replace:!1})};class Cp extends he{constructor(){super(...arguments),this._snap=null,this._loading=!1,this._reloadQueued=!1,this._forceReloadQueued=!1,this._reloadRetryTimer=0,this._dayCycleTimer=0,this._dayCycleClockKey="",this._stageWidth=0,this._pendingStageWidth=0,this._stageWidthRaf=0,this._haRegistryConnection=null,this._haRegistryRevision=-1,this._devices=[],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._connHooked=null,this._connectionWasLost=!1,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotActivity="",this._capturedSnapshotVirtual="",this._activityRuntime=new Map,this._reducedMotion=!1,this._pointerModality=new Mp(this),this._onMotionChange=e=>{this._reducedMotion=e.matches,this._capturedSnapshotSequence=-1,this.requestUpdate()},this._onHaRegistryUpdate=()=>{const e=Vc(this.hass).revision;e!==this._haRegistryRevision&&(this._haRegistryRevision=e,this._refreshDevices(),this._capturedSnapshotSequence=-1,this.requestUpdate())},this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=Zn(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),"hidden"!==e.kind){if(!e.long){const e=Date.now();let t=!1;for(const i of this._activityRuntime.values())!i.flashKind||(i.expiresAt||i.flashTs+3300)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&(this._capturedSnapshotSequence=-1,this.requestUpdate()))}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._load(!0)}else this._pointerModality.suspend()},this._onConnLost=()=>{this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost()},this._onConnReady=()=>{!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._load(!0)},this._onAssetLoaded=(e,t)=>{this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()},this._loadedOnce=!1,this._signer=new Dl(()=>this.requestUpdate()),this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._load(!0)},this._goToSpace=()=>{const e=(this._config?.button_target||"/plan-doma").replace(/#.*$/,"");Tp(`${e}#space=${encodeURIComponent(this._config.space)}`)}}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRevision=-1,this._haRegistryRelease=Gc(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}_newContinuityController(){return new Ml(()=>{this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}_dayCycleState(e=new Date){const t=this._snap?.config;if(!t||!this._config)return null;const i=t.spaces?.find(e=>e.id===this._config?.space)?.settings||{};return"daynight"!==sr(t.settings,i)?null:Yn(this._renderDeviceSnapshot?.hass||this.hass,e)}_syncDayCycleClock(){const e=this._dayCycleState();this._dayCycleClockKey=e?Zn(e):"";const t="clock"===e?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;t&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!t&&this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(e){"hidden"!==e.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}static getConfigElement(){return document.createElement("houseplan-space-card-editor")}static getStubConfig(e){const t=yp();return{type:"custom:houseplan-space-card",space:za(t?.config||null)[0]?.id||"",show_button:!0,live_states:!0,show_temperature:!0,show_signal:!0}}setConfig(e){if(!e||!e.space)throw new Error('houseplan-space-card: "space" is required');this._config={show_button:!0,button_target:"/plan-doma",live_states:!0,show_temperature:!0,show_signal:!0,...e},this._snap=this._snap||yp()}connectedCallback(){var e;this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this.hass&&this._ensureHaRegistryAuthority(),this._continuityUnsub?.(),this._continuityUnsub=$l(this.ownerDocument,this._pageVisibility),this._unsub=(e=()=>{this._beginContinuityCandidate("config-event",!1),this._reloadQueued=!0,this._load()},fp.add(e),()=>fp.delete(e)),this._signer.start(()=>this.hass,()=>this._referenced())}disconnectedCallback(){this._pointerModality.disconnect(),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._unsub?.(),this._unsub=void 0,window.clearTimeout(this._reloadRetryTimer),this._reloadRetryTimer=0,this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._stageObserver?.disconnect(),this._stageObserver=void 0,this._observedStage=void 0,this._stageWidthRaf&&cancelAnimationFrame(this._stageWidthRaf),this._stageWidthRaf=0,this._pendingStageWidth=0,this._signer.dispose(),this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null;for(const e of this._activityRuntime.values())window.clearTimeout(e.timer);this._activityRuntime.clear(),this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}willUpdate(e){e.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._hookConnection()),!this.hass||this._loading||this._snap&&!e.has("hass")||this._snap&&this._loadedOnce||this._load(),(e.has("hass")||e.has("_snap")||e.has("_config")||!this._devices.length)&&this._refreshDevices(),this._captureRenderDeviceSnapshot(),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._frameFingerprint())}_stampActivity(e,t){$p(e,t,Date.now(),window.clearTimeout.bind(window),e=>window.setTimeout(()=>this.requestUpdate(),e))}_syncActivity(e,t,i=this.hass){if(!1===this._config?.live_states){for(const e of this._activityRuntime.values())window.clearTimeout(e.timer);return void this._activityRuntime.clear()}const n=new Set,r=Mh(t,e,null,this._snap?.virtualLights);for(const o of e){if(o.hidden)continue;if("icon_ripple"!==Ai(o.marker?.display))continue;n.add(o.id);const s=Cu(t,o,e,r,i),a=s.samples,l=Ou(t,o,s);let c=this._activityRuntime.get(o.id);if(!c||c.sources!==l){c&&window.clearTimeout(c.timer),c=kp(l,a),this._activityRuntime.set(o.id,c);continue}const h=Sp(c,a,window.clearTimeout.bind(window));h&&this._stampActivity(c,h)}for(const[e,t]of this._activityRuntime)n.has(e)||(window.clearTimeout(t.timer),this._activityRuntime.delete(e))}_refreshDevices(){if(!this.hass||!this._snap?.config||!this._config)return;const e=Vc(this.hass),t=cp({hass:this.hass,registry:e,cfg:this._snap.config,lang:this._lang});this._syncActivity(t,Xc(this.hass,e),this.hass),this._devices=t}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRuntime.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+3300)>e?1:0)).join("|"),i=this._snap?.virtualLights?`${this._snap.virtualLights.configRev}:${this._snap.virtualLights.rev}`:"";if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotActivity===t&&this._capturedSnapshotVirtual===i)return;const n=Xc(this.hass,Vc(this.hass)),r=new Map,o=new Set(["sun.sun"]),s=new Set,a=new Set,l=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void o.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?s.add(n):"entity"===i&&o.add(n)},c=za(this._snap?.config||null).find(e=>e.id===this._config?.space);for(const e of c?.rooms||[])e.area&&a.add(e.area),l(e.settings?.temp_source),l(e.settings?.hum_source);const h=this._snap?.config?.spaces?.find(e=>e.id===this._config?.space);for(const e of h?.openings||[])for(const t of ni(e))o.add(t);const d=Mh(n,this._devices,null,this._snap?.virtualLights);for(const e of this._devices)for(const t of[!1,!0])r.set(Nu(e.id,t),Pu(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRuntime.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:d,registryHass:this.hass,reducedMotion:this._reducedMotion}));const u=Eu({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,entityIds:o,deviceIds:s,areaIds:a});this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotActivity=t,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=u:(this._visibleDeviceSnapshot=u,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}_beginContinuityCandidate(e,t,i="plan"){return this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._continuity.beginCandidate(e,i)}_backdropRaw(){return this._snap?.config&&this._config&&za(this._snap.config).find(e=>e.id===this._config.space)?.bg?.href||""}_candidateBackdrop(e){return e&&this._config&&za(e).find(e=>e.id===this._config.space)?.bg?.href||""}_assetsReady(){const e=this._backdropRaw();return!e||this._signer.isReady(this.hass,e)}_frameFingerprint(){const e=this._snap;return Tl([e?.rev||0,e?.configFingerprint||Rl(e?.config),e?.layoutRev||0,e?.layoutFingerprint||Rl(e?.layout),e?.virtualLights?`${e.virtualLights.configRev}:${e.virtualLights.rev}`:"",this._config?.space||"",this._stageWidth,this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_stageValid(){const e=this._observedStage;return!!e&&e.clientWidth>0&&e.clientHeight>0}_settleContinuityFrame(){if(!this._stageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state){if(this._assetsReady())return this._renderSnapshotAt=Date.now(),void this._continuity.markCompleteFrame(this._frameFingerprint());this._beginContinuityCandidate("asset-wait",!0,"asset")}if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._stageValid(),assetsReady:()=>this._assetsReady(),frameFingerprint:()=>this._frameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}updated(){const e=this.renderRoot.querySelector(".hp-static-stage")||void 0;if(e!==this._observedStage)if(this._stageObserver?.disconnect(),this._observedStage=e,e){const t=()=>{const i=e.clientWidth;if(!(i<=0||Math.abs(i-this._stageWidth)<=.5)){if(this._stageWidth<=0)return this._stageWidth=i,void this.requestUpdate();this._pendingStageWidth=i,this._stageWidthRaf||(this._stageWidthRaf=requestAnimationFrame(()=>{this._stageWidthRaf=0;const e=this._pendingStageWidth;this._pendingStageWidth=0,!e||!this._observedStage||this._observedStage.clientWidth<=0||(Math.abs(this._observedStage.clientWidth-e)>.5?t():Math.abs(e-this._stageWidth)<=.5||(this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._stageWidth=e,this.requestUpdate()))}))}};this._stageObserver=new ResizeObserver(t),this._stageObserver.observe(e),t()}else this._stageObserver=void 0;this._syncDayCycleClock(),this._settleContinuityFrame()}async _load(e=!1){if(this.hass){if(this._loading)return this._reloadQueued=!0,void(this._forceReloadQueued||=e);this._loading=!0,this._reloadQueued=!1;try{const t=await bp(this.hass,e),i=!this._snap||this._snap.configFingerprint!==t.configFingerprint,n=!this._snap||this._snap.layoutFingerprint!==t.layoutFingerprint,r=!this._snap||this._snap.virtualLights!==t.virtualLights;if(i&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(t.config)))return this._continuity.note("asset-failed"),window.clearTimeout(this._reloadRetryTimer),void(this._reloadRetryTimer=window.setTimeout(()=>{this._load(!0)},1e3));window.clearTimeout(this._reloadRetryTimer),this._reloadRetryTimer=0,(i||n)&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),i||n||r?this._snap=t:this._snap&&(this._snap.rev=t.rev,this._snap.layoutRev=t.layoutRev),i&&this._continuity.note("config-candidate",{configRev:t.rev}),n&&this._continuity.note("layout-candidate",{layoutRev:t.layoutRev}),r&&(this._capturedSnapshotSequence=-1),this._loadedOnce=!0,this._connectionWasLost=!1,this._continuityDataReady=!0,this._refreshDevices()}catch{}finally{if(this._loading=!1,this._continuityDataReady=!0,this.requestUpdate(),this._reloadQueued){const e=this._forceReloadQueued;this._reloadQueued=!1,this._forceReloadQueued=!1,this._load(e)}}}}get _lang(){return Xd(this.hass,this._config?.language)}getCardSize(){const e=za(this._snap?.config||null).find(e=>e.id===this._config?.space);if(e){const t=e.vb[3]/e.vb[2];return Math.max(3,Math.round(8*t))+(!1===this._config?.show_button?0:1)}return 6}_errorCard(e){return B` +
${e}
+
`}_referenced(){return Sn(this._snap?.config)}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return G;const e="connection"===this._continuity.recoveryReason;return B`
+ + ${Jd(this._lang,e?"continuity.restore_connection":"continuity.restore_plan")} + ${"recovery-error"===this._continuity.state?B``:G} +
`}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}render(){if(!this._config)return G;const e=this._snap?.config;if(!e)return this._errorCard(Jd(this._lang,"space_card.loading"));const t=this._config.space,i=this._renderDeviceSnapshot,n=hp({hass:i?.hass||this.hass,cfg:e,layout:this._snap?.layout||{},spaceId:t,iconSize:this._config.icon_size,stageWidth:this._stageWidth,lang:this._lang,displayUrl:e=>this._signer.display(this.hass,e),assetLoaded:this._onAssetLoaded,registry:i?{revision:i.sourceSequence,authoritative:!1,access:"limited",entities:{...i.hass.entities},devices:{...i.hass.devices},lastSuccess:i.capturedAt}:Vc(this.hass),devices:[...i?.devices||this._devices],presentations:i?.presentations,activityRuntime:this._activityRuntime,reducedMotion:this._reducedMotion,virtualLights:this._snap?.virtualLights,liveStates:!1!==this._config.live_states,showTemperature:!1!==this._config.show_temperature,showSignal:!1!==this._config.show_signal,inert:this._continuity.overlayBlocksInteraction});if(!n)return this._errorCard(Jd(this._lang,"space_card.not_found",{id:t}));const r=za(e).find(e=>e.id===t),o=void 0!==this._config.title?this._config.title:r?.title||"",s=!1!==this._config.show_button,a=this._config.button_label||Jd(this._lang,"space_card.button"),l=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null;return B` + this._pointerModality.note(e)} + @pointerdown=${e=>this._pointerModality.note(e)} + @pointermove=${e=>this._pointerModality.note(e)}> + ${o?B`
${o}
`:G} +
+ ${n} + ${this._renderRecoveryOverlay()} +
+ ${s?B`
+ +
`:G} +
+ `}}Cp.properties={hass:{attribute:!1},_config:{state:!0},_snap:{state:!0},_continuityEpoch:{state:!0}},Cp.styles=[Bd,o` + .hp-static-title { + font-weight: 700; + padding: 10px 14px 6px; + font-size: 16px; + color: var(--primary-text-color); + } + .hp-static-body { + position: relative; + } + .hp-static-stage { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + pointer-events: none; /* kill ALL interaction on the schematic (§4) */ + background: var(--ha-card-background, var(--card-background-color, #111)); + } + .hp-static-stage svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + z-index: 1; + } + /* Opaque plan paper — the scene bg_color/day-cycle environment shows only AROUND + the plan (owner 2026-08-03). The static card keeps its historical + canvas colour: the theme card background. Drawn plans paper the room + contours (per-room shapes, fill only, no stroke) — same contract as + the full card. */ + .hp-paper { + fill: var(--ha-card-background, var(--card-background-color, #111)); + stroke: none; + } + .wallbody-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: var(--wall-fill-op, 1); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .wallbody { + fill: url(#hp-wall-hatch); + fill-rule: evenodd; + stroke: var(--room-stroke, var(--hp-muted, #607d8b)); + stroke-width: calc(0.6px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .wallbody.solid { + fill: none; + } + .hp-static-stage .devlayer { + position: absolute; + inset: 0; + z-index: 2; + } + .hp-static-foot { + padding: 8px 12px 12px; + pointer-events: auto; /* the button stays clickable */ + } + .hp-static-btn { + width: 100%; + padding: 9px 14px; + border: none; + border-radius: 10px; + background: var(--primary-color, #3ea6ff); + color: var(--text-primary-color, #fff); + font-size: 14px; + font-weight: 600; + cursor: pointer; + } + :host([data-pointer-hover]) .hp-static-btn:hover { + filter: brightness(1.08); + } + .hp-static-error { + padding: 24px; + text-align: center; + color: var(--secondary-text-color, #9aa4ad); + } + `],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",Cp),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-space-card"===e.type)||window.customCards.push({type:"houseplan-space-card",name:"House Plan — Space (static)",description:"Read-only live schematic of a single houseplan space, with a deep-link button.",preview:!1,documentation:"https://github.com/Matysh/houseplan-card"});const Dp=o` + :host { + --hp-editor-tray-bg-fallback: color-mix(in srgb, var(--card-background-color, var(--hp-bg)) 94%, var(--hp-line)); + --hp-editor-tray-bg: color-mix(in srgb, var(--card-background-color, var(--hp-bg)) 86%, transparent); + --hp-editor-tray-border: color-mix(in srgb, var(--hp-line) 82%, var(--hp-accent)); + --hp-editor-tray-blur: 8px; + --hp-editor-tray-shadow: var(--shadow-2); + } + + /* Contextual editor controls float over the stage. Their appearance must + never alter stage height, viewport fitting or the pinned close action. */ + .editor-secondary-host { + position: absolute; + inset: var(--sp-2) var(--sp-4) auto; + z-index: 70; + display: flex; + justify-content: flex-end; + pointer-events: none; + } + .editor-secondary-host.kind-palette, + .editor-secondary-host.kind-group { + justify-content: flex-start; + } + .editor-secondary { + pointer-events: none; + max-width: 100%; + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-4); + color: var(--hp-txt); + background: var(--card-background-color, var(--hp-bg)); + background: var(--hp-editor-tray-bg-fallback); + border: 1px solid var(--hp-line); + border-color: var(--hp-editor-tray-border); + border-radius: var(--rad-l); + box-shadow: var(--hp-editor-tray-shadow); + opacity: 0; + visibility: hidden; + transform: translateY(-4px); + transition: + opacity 0.1s ease, + transform 0.1s cubic-bezier(0.2, 0.7, 0.2, 1), + visibility 0s linear 0.1s; + touch-action: auto; + } + .editor-secondary-host.open .editor-secondary { + pointer-events: auto; + opacity: 1; + visibility: visible; + transform: translateY(0); + transition-duration: 0.14s, 0.14s, 0s; + transition-delay: 0s; + } + .editor-secondary-host.blocked .editor-secondary { pointer-events: none; } + @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { + .editor-secondary { + background: var(--hp-editor-tray-bg); + -webkit-backdrop-filter: blur(var(--hp-editor-tray-blur)); + backdrop-filter: blur(var(--hp-editor-tray-blur)); + } + } + .editor-secondary-content, + .editor-group-items { + display: flex; + align-items: center; + gap: var(--sp-3); + min-width: 0; + } + .editor-context-label { + max-width: 14rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-inline-end: var(--sp-4); + border-inline-end: 1px solid var(--hp-line); + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editor-secondary.kind-palette { + width: min(760px, 100%); + align-items: stretch; + padding: 0; + overflow: hidden; + } + .editor-secondary.kind-palette .editor-secondary-content, + .editor-secondary.kind-palette .furnpalette { + width: 100%; + } + .editor-secondary.kind-palette .furnpalette { + max-height: 38vh; + border: 0; + background: transparent; + } + .editor-group-launcher .group-chevron { + --mdc-icon-size: 16px; + transition: transform 0.14s ease; + } + .editor-group-launcher[aria-expanded="true"] .group-chevron { transform: rotate(180deg); } + + .editor-secondary .bdhint { + font-size: var(--fs-s); + color: var(--hp-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .editor-secondary .dfill { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + font-size: var(--fs-s); + cursor: pointer; + } + .editor-secondary .dfill input[type="checkbox"] { + width: 16px; + height: 16px; + flex: none; + margin: 0; + padding: 0; + } + .editor-secondary hp-color-opacity { flex: 0 0 auto; } + .editor-secondary input { + width: 74px; + background: transparent; + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + } + .editor-secondary label, + .editor-secondary .hint { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editor-secondary .drawwall { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .editor-secondary .drawwall input { width: 4.2em; } + .editor-secondary .drawwall .opl { + color: var(--hp-muted); + font-size: var(--fs-s); + } + + @container (min-width: 560px) and (max-width: 899px) { + .editor-secondary-content, + .editor-group-items { + flex-wrap: wrap; + justify-content: flex-end; + } + } + @container (max-width: 559px) { + .editor-secondary-host { inset-inline: var(--sp-4); } + .editor-secondary { max-width: 100%; } + .editor-secondary-content, + .editor-group-items { + overflow-x: auto; + scrollbar-width: thin; + } + .editor-secondary-content > *, + .editor-group-items > * { flex: none; } + .editor-context-label { display: none; } + } + @media (prefers-reduced-motion: reduce) { + .editor-secondary { transition: none; } + .editor-group-launcher .group-chevron { transition: none; } + } +`;function Ap(e){return e instanceof Error?e.name||"Error":typeof e}function Op(e){return Rl({id:e?.id??"",cell_cm:e?.cell_cm,rooms:e?.rooms||[],walls:e?.walls||[],wall_segments:e?.wall_segments||[],open_spans:e?.open_spans||[],openings:e?.openings||[],partitions:e?.partitions||[],room_drafts:e?.room_drafts||[],wall_columns:e?.wall_columns||[]})}function zp(e,t,i={}){const n=(Array.isArray(e?.spaces)?e.spaces:[]).find(e=>String(e?.id||"")===String(t||"")),r=Op(n);if(!n)return{spaceId:String(t||""),displayName:"",status:"failed",reason:"prepare-exception",fingerprint:r,ok:!1};const o=Hp({...e,spaces:[n]},{...i,fingerprint:()=>r}).spaces[0]||{spaceId:String(t||""),displayName:"",status:"failed",reason:"prepare-exception"};return{...o,fingerprint:r,ok:"failed"!==o.status}}function Pp(e,t,i,n=Ea,r=1e3){return(Array.isArray(e?.openings)?e.openings:[]).flatMap(e=>{const o={...e,rx:Number(e.x)*r,ry:Number(e.y)*r,rlen:Number(e.length)*r};if(!e.host||"wall"===e.host.kind)return[o];const s=Td(e,t.partitions,r,i,n);return s.resolved?[{...e,rx:s.resolved.center[0],ry:s.resolved.center[1],rlen:s.resolved.length,angle:s.resolved.angle,partitionHost:s.resolved}]:[]})}function Fp(e,t=()=>!0){return e.flatMap(e=>e.host&&e.partitionHost&&t(e)?[Ad(e.partitionHost)]:[])}function Ip(e,t,i,n,r,o,s=Ea,a=1e3){const l=gs(t.rooms,[...i],n,r,o,s,a);return e.flatMap(e=>{const t={x:e.rx,y:e.ry,angle:Number(e.angle)||0,length:e.rlen};return e.host&&"wall"!==e.host.kind?e.partitionHost&&Pd(e.partitionHost,l,2e-4*s)?[t]:[]:[t]})}function Ep(e,t){const i=Na,n=Ea,r=Ra,o=Number.isFinite(Number(t.cellCm))&&Number(t.cellCm)>0?Number(t.cellCm):5,s=Array.isArray(e?.walls)?e.walls:[],a=function(e,t,i=Ea,n=1e3){return Yu(t.rooms,e?.open_spans,n,.02*i)}(e,t,n,r),l=function(e,t,i=Ea){if(!t.length)return[];const n=e.filter(e=>e?.id),r=.02*i,o=[];for(let e=0;e{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return h.some(e=>Pn(t,e)<4*r)}).map(e=>[...e]);d.length&&o.push({a:s,b:a,segs:d})}return o}(t.rooms,a,n).flatMap(e=>e.segs),c=Pp(e,t,o,n,r),h=Fp(c),d=ca(t,o,n,2e-4*n,h).all;return{space:t,walls:s,openCuts:l,openings:c,roomOpenings:Ip(c,t,s,l,i,o,n,r),partitionCuts:h,physicalBodies:d,wallKeyPitch:i,cellCm:o,gridPitch:n,coordScale:r}}function Np(e,t,i){const n="string"==typeof e?.title?e.title.trim():"",r=null==e?.id?"":String(e.id).trim();return{spaceId:r,displayName:n||r||i(t+1)}}function Hp(e,t={}){const i=(t.fingerprint||Rl)(e),n=Array.isArray(e?.spaces)?e.spaces:[],r=t.fallbackSpaceName||(e=>`Space ${e}`),o=t.prepareSpace||Ep,s=t.wallPass||Ns,a=t.floorPass||Ps,l=[];for(let i=0;i0||d.physicalBodies.length>0;if(!d.space.rooms.length&&!u){l.push({...h,status:"not-applicable"});continue}let p=null;if(u){try{p=s(d.space.rooms,d.walls,d.openCuts,d.roomOpenings,d.wallKeyPitch,d.cellCm,d.gridPitch,d.coordScale,d.physicalBodies)}catch(e){l.push({...h,status:"failed",reason:"wall-exception",detail:Ap(e)});continue}if(null==p){l.push({...h,status:"failed",reason:"wall-null"});continue}if("degraded-extra"===p.status){l.push({...h,status:"failed",reason:"wall-degraded-extra"});continue}if("failed-core"===p.status){l.push({...h,status:"failed",reason:"wall-failed-core"});continue}t.captureWallGeometry?.(d,p)}if(d.space.rooms.length&&null==p?.paperGeom){let e;try{e=a(d.space.rooms,d.walls,d.openCuts,d.wallKeyPitch,d.cellCm,d.gridPitch,d.coordScale)}catch(e){l.push({...h,status:"failed",reason:"floor-exception",detail:Ap(e)});continue}if(null==e){l.push({...h,status:"failed",reason:"floor-null"});continue}}l.push({...h,status:"ok"})}const c=l.filter(e=>"failed"===e.status);return{fingerprint:i,spaces:l,failures:c,ok:0===c.length}}function Lp(e,t){return e.catch(()=>{}).then(t)}class qp{constructor(e=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(e))}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(e){this._undo.push(e),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const e=this._undo.pop()??null;return e&&this._redo.push(e),e}redo(){const e=this._redo.pop()??null;return e&&this._undo.push(e),e}clear(){this._undo=[],this._redo=[]}}const jp=new WeakMap;const Bp=(e,t,i)=>255===e[i+3]&&t.every((t,n)=>Math.abs(e[i+n]-t)<=2);async function Wp(e){const t=e.defaultView;if(!t||!t.CSS?.supports?.("mix-blend-mode","screen"))return!1;const i=[128,32,16],n=[16,64,128],r=[9,19,29],o=`\n \n \n \n \n \n `,s=t.URL.createObjectURL(new Blob([o],{type:"image/svg+xml"}));try{const o=await new Promise((e,i)=>{const n=new t.Image,r=t.setTimeout(()=>i(new Error("SVG blend probe timeout")),1e3);n.onload=()=>{t.clearTimeout(r),e(n)},n.onerror=()=>{t.clearTimeout(r),i(new Error("SVG blend probe failed"))},n.src=s}),a=e.createElement("canvas");a.width=4,a.height=1;const l=a.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 Bp(c,i,0)&&Bp(c,function(e,t){return[0,1,2].map(i=>Math.round(255-(255-e[i])*(255-t[i])/255))}(i,n),4)&&Bp(c,n,8)&&Bp(c,r,12)}catch{return!1}finally{t.URL.revokeObjectURL(s)}}const Up={now:()=>performance.now(),requestFrame:e=>requestAnimationFrame(e),cancelFrame:e=>cancelAnimationFrame(e)},Gp=e=>Math.max(0,Math.min(1,e)),Vp=(e,t,i)=>e+(t-e)*i,Kp=(e,t,i)=>{const n=1-e;return 3*n*n*e*t+3*n*e*e*i+e*e*e};function Yp(e,t){return{centerX:e.x+e.w/2,centerY:e.y+e.h/2,pixelsPerUnit:t>0&&e.w>0?t/e.w:1,viewBox:{...e}}}function Zp(e,t,i){const n=Math.max(1e-9,e.pixelsPerUnit),r=Math.max(1e-9,t/n),o=Math.max(1e-9,i/n);return{x:e.centerX-r/2,y:e.centerY-o/2,w:r,h:o}}function Xp(e){const t=e.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(t);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const n=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(t)?.[1];return n?[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16),8===n.length?parseInt(n.slice(6,8),16)/255:1]:null}function Jp(e,t,i){const n=Xp(e),r=Xp(t);if(!n||!r)return i<.5?e:t;const o=Gp(i);return`rgba(${Math.round(Vp(n[0],r[0],o))}, ${Math.round(Vp(n[1],r[1],o))}, ${Math.round(Vp(n[2],r[2],o))}, ${Vp(n[3],r[3],o).toFixed(3)})`}function Qp(e,t,i){const n=(e=>{const t=Gp(e);if(0===t||1===t)return t;let i=0,n=1,r=t;for(let e=0;e<12;e++)r=(i+n)/2,Kp(r,.2,.2){const t=this._state;if(!t||t.token!==r)return;const i=Gp((e-t.startedAt)/t.duration);t.presented=i>=1?t.to:Qp(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i<1?this._raf=this._clock.requestFrame(s):(this._raf=0,this._hooks.settled(t),this._state?.token===r&&(this._state=null))};return this._raf=this._clock.requestFrame(s),r}cancel(e=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=t.to,this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}}class t_{constructor(e){this.options=e,this._state="idle",this._inFlight=null}get state(){return this._state}ensure(){return"ready"===this._state?Promise.resolve(!0):"failed"===this._state?Promise.resolve(!1):(this._inFlight||(this._setState("loading"),this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}async _loadWithRetry(){let e=new Error("Editor runtime did not load");for(const t of[0,1])try{const e=await this.options.load(t);if(e.fingerprint!==this.options.expectedFingerprint)throw new Error(`Editor runtime fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${e.fingerprint}`);const i=e.create();return this.options.install(i),this._setState("ready"),!0}catch(t){e=t}return this._setState("failed"),this.options.failed?.(e),!1}_setState(e){e!==this._state&&(this._state=e,this.options.stateChanged?.(e))}}const i_="houseplan_card_labs_v1",n_=Object.freeze([Object.freeze({id:"iso",issue:89,since:"1.62.0",expires:"1.65.0",summary:"Volumetric plan renderer"})]);function r_(e){const t=/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/.exec(String(e||"").trim());if(!t)return null;const i=t.slice(1).map(Number);return i.every(e=>Number.isSafeInteger(e))?i:null}function o_(e,t){for(let i=0;i<3;i++)if(e[i]!==t[i])return e[i]e.split(",")).map(e=>e.trim()).filter(Boolean)}function d_(e,t,i,n=n_){const r=function(e,t=n_){const i=r_(e),n=new Map;if(!i||!a_(t))return n;for(const e of t){const t=r_(e.since),r=r_(e.expires);o_(i,t)>=0&&o_(i,r)<0&&n.set(e.id,e)}return n}(i,n),o=new Set(a_(n)?n.map(e=>e.id):[]),s=new Set(function(e){if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>"string"==typeof e):[]}catch{return[]}}(t).filter(e=>r.has(e)));let a=!1;const l=e=>{if("off"===e)return s.clear(),void(a=!0);const t=e.startsWith("-"),i=t?e.slice(1):e;o.has(i)&&(a=!0,t||!r.has(i)?s.delete(i):s.add(i))};for(const t of h_(new URLSearchParams(String(e.search||"").replace(/^\?/,""))))l(t);for(const t of h_(l_(e.hash)))l(t);const c=Object.freeze([...s].sort());return{active:c,space:c_(e.hash),persist:a?JSON.stringify(c):void 0,knownUrlOperation:a}}let u_={active:Object.freeze([]),space:""},p_="",__=!1,m_="";const g_=new Set;function f_(){if("undefined"==typeof window)return u_;const e=d_(window.location,function(){try{return window.localStorage.getItem(i_)}catch{return null}}(),p_);void 0!==e.persist&&function(e){try{window.localStorage.setItem(i_,e)}catch{}}(e.persist),u_={active:e.active,space:e.space},window.__hpLabs=e.active;for(const e of g_)e(u_);return u_}function v_(){f_()}function y_(e){return p_=e,"undefined"==typeof window?u_:(__||(__=!0,window.addEventListener("hashchange",v_),window.addEventListener("popstate",v_)),f_())}const b_=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])});function w_(e){return[e.rotDeg,e.tiltDeg,e.xyScale,e.zScale,e.origin[0],e.origin[1]].every(Number.isFinite)&&Math.abs(e.xyScale)>1e-12&&Math.abs(Math.cos(e.tiltDeg*Math.PI/180))>1e-12}function k_(e,t,i=b_){if(!(w_(i)&&Number.isFinite(e[0])&&Number.isFinite(e[1])&&Number.isFinite(t)))throw new Error("invalid isometric projection input");const n=i.rotDeg*Math.PI/180,r=i.tiltDeg*Math.PI/180,o=e[0]-i.origin[0],s=e[1]-i.origin[1],a=(o*Math.cos(n)-s*Math.sin(n))*i.xyScale,l=(o*Math.sin(n)+s*Math.cos(n))*i.xyScale;return[i.origin[0]+a,i.origin[1]+l*Math.cos(r)-t*i.zScale*Math.sin(r)]}function x_(e,t=b_){if(!w_(t)||!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=(e[0]-t.origin[0])/t.xyScale,o=(e[1]-t.origin[1])/(t.xyScale*Math.cos(n));return[t.origin[0]+r*Math.cos(i)+o*Math.sin(i),t.origin[1]-r*Math.sin(i)+o*Math.cos(i)]}function $_(e=b_){return`matrix(${function(e=b_){if(!w_(e))throw new Error("invalid isometric camera");const t=e.rotDeg*Math.PI/180,i=e.tiltDeg*Math.PI/180,n=e.xyScale*Math.cos(t),r=-e.xyScale*Math.sin(t),o=e.xyScale*Math.sin(t)*Math.cos(i),s=e.xyScale*Math.cos(t)*Math.cos(i);return[n,o,r,s,e.origin[0]-n*e.origin[0]-r*e.origin[1],e.origin[1]-o*e.origin[0]-s*e.origin[1]]}(e).map(e=>Number(e.toFixed(12))).join(" ")})`}function S_(e,t=b_){const{rect:i,wallHeight:n}=e,r=e.openingHeight??n,o=e.floorDepth??0;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||n<0||r<0||o<0)throw new Error("invalid isometric frame");const s=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],a=Math.max(n,r),l=s.flatMap(e=>[k_(e,-o,t),k_(e,a,t)]),c=l.map(e=>e[0]),h=l.map(e=>e[1]),d=Math.min(...c),u=Math.min(...h);return{x:d,y:u,w:Math.max(...c)-d,h:Math.max(...h)-u}}const M_=e=>`${Number(e[0].toFixed(4))} ${Number(e[1].toFixed(4))}`;function R_(e){let t=0;for(let i=0;iArray.isArray(e)&&Number.isFinite(e[0])&&Number.isFinite(e[1])).map(e=>[Number(e[0]),Number(e[1])]),i=t[t.length-1];return t.length>1&&t[0][0]===i[0]&&t[0][1]===i[1]&&t.pop(),t}(e);if(i.length<3)return[];const n=!t;return R_(i)>0===n?i:[...i].reverse()}function C_(e,t,i){return e.length?`M ${e.map(e=>M_(k_(e,i,t))).join(" L ")} Z`:""}function D_(e,t,i){const n=t[1]-e[1],r=-(t[0]-e[0]),o=i.rotDeg*Math.PI/180;return n*Math.sin(o)+r*Math.cos(o)}function A_(e,t,i=b_){if(!Number.isFinite(t)||t<0)throw new Error("invalid floor edge height");const n=(e||[]).map(e=>(e||[]).map((e,t)=>function(e,t){const i=T_(e,t);if(!i.length)return i;let n=0;for(let e=1;e0)).filter(e=>e.length>=3&&Math.abs(R_(e))>=1e-9)).filter(e=>e.length&&R_(e[0])>0);n.sort((e,t)=>{const i=e[0][0],n=t[0][0];return i[0]-n[0]||i[1]-n[1]||Math.abs(R_(t[0]))-Math.abs(R_(e[0]))});const r=[],o=[];let s=0;for(let e=0;ee.depth-t.depth||e.component-t.component||e.edge-t.edge),{footprintPath:r.join(" "),sides:o,componentCount:n.length,edgeCount:s}}function O_(e,t){return e^=Math.round(64*(Number.isFinite(t)?t:0)),Math.imul(e,16777619)>>>0}const z_=e=>e.every(Number.isFinite);function P_(e,t,i,n){const r=e[0]*i,o=e[1]*n,s=t*Math.PI/180;return[r*Math.cos(s)-o*Math.sin(s),r*Math.sin(s)+o*Math.cos(s)]}function F_(e,t,i,n,r,o,s){const a=e.flipH?-1:1,l="gate"===e.type?1:e.flipV?-1:1,c=(e.type,e.flipV,e.angle,e.face,{ox:0,oy:0}),h=function(e,t){return[e[0]+t[0],e[1]+t[1]]}([e.x+c.ox,e.y+c.oy],P_(i,e.angle,a,l));return{leaf:t,hinge:h,closedVector:P_(n,e.angle,a,l),quarterVector:P_([-n[1],n[0]],e.angle,a,l),turnDeg:r,bottom:o,top:s}}const I_=e=>`${Number(e[0].toFixed(4))} ${Number(e[1].toFixed(4))}`;function E_(e,t,i=b_){const n=Math.max(0,Math.min(1,Number.isFinite(t)?t:0));return e.leaves.map(t=>{const r=function(e,t){const i=e.turnDeg*t*Math.PI/180;return[e.hinge[0]+e.closedVector[0]*Math.cos(i)+e.quarterVector[0]*Math.sin(i),e.hinge[1]+e.closedVector[1]*Math.cos(i)+e.quarterVector[1]*Math.sin(i)]}(t,n),o=k_(t.hinge,t.bottom,i),s=k_(r,t.bottom,i),a=k_(r,t.top,i),l=k_(t.hinge,t.top,i);return{id:e.id,sourceIndex:e.sourceIndex,type:e.type,leaf:t.leaf,d:`M ${I_(o)} L ${I_(s)} L ${I_(a)} L ${I_(l)} Z`,shadowD:`M ${I_(k_(t.hinge,0,i))} L ${I_(k_(r,0,i))}`,depth:Math.max(o[1],s[1])}})}const N_={window:120,door:90,passage:90,gate:300};function H_(e){return N_[e]}function L_(e,t){return{type:e,lengthCm:H_(e),flipH:!1,flipV:!1,revision:t}}function q_(e,t){const i=Math.max(0,e.renderedLength)/2,n=Math.max(0,e.target.physicalHalfWidth),r=n+.18*Math.max(0,t),o=e=>({x1:e,y1:-r,x2:e,y2:r});return{rect:{x:-i,y:n?-n:0,width:2*i,height:2*n},boundaries:[o(-i),o(i)]}}function j_(e,t){const i=[e[0],e[1]],n=[t[0],t[1]];return function(e,t){return e[0]-t[0]||e[1]-t[1]}(i,n)<=0?{a:i,b:n}:{a:n,b:i}}function B_(e){const t=new Map;return e.forEach((e,i)=>{if(!e.kind||e.open)return;const n=j_(e.a,e.b);if(Math.hypot(n.b[0]-n.a[0],n.b[1]-n.a[1])<=1e-9)return;const r=function(e,t){const i=e=>(Math.abs(e)<=5e-10?0:Math.round(1e6*e)/1e6).toFixed(6);return`${i(e[0])},${i(e[1])}>${i(t[0])},${i(t[1])}`}(n.a,n.b),o=t.get(r);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,e.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(e.partitionHost&&(o.partitionHost&&o.partitionHost.id!==e.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=e.partitionHost));t.set(r,{segmentKey:r,a:n.a,b:n.b,physicalHalfWidth:Math.max(0,e.half||0),sourceOrder:i,...e.partitionHost?{partitionHost:e.partitionHost}:{}})}),[...t.values()]}function W_(e,t){if(Math.abs(e.distance-t.distance)>1e-9)return e.distance-t.distance;if(Math.abs(e.perpendicular-t.perpendicular)>1e-9)return e.perpendicular-t.perpendicular;return(e.target.segmentKeyt.target.segmentKey?1:0)||e.target.sourceOrder-t.target.sourceOrder}function U_(e){const t=B_(e.intervals).map(t=>{const i=function(e,t){const i=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,a=(e[0]-t.a[0])*o+(e[1]-t.a[1])*s,l=Math.max(0,Math.min(r,a)),c=t.a[0]+l*o,h=t.a[1]+l*s;return{along:l,length:r,x:c,y:h,distance:Math.hypot(e[0]-c,e[1]-h),perpendicular:Math.abs((e[0]-t.a[0])*s-(e[1]-t.a[1])*o)}}(e.pointer,t);return{target:t,...i,envelope:Math.max(e.baseTolerance,t.physicalHalfWidth+e.bodyPointerPadding)}}).filter(e=>e.distance<=e.envelope+1e-9).filter(t=>!function(e,t,i,n,r){const o=t.b[0]-t.a[0],s=t.b[1]-t.a[1],a=Math.hypot(o,s);if(!(a>1e-9))return!1;const l=o/a,c=s/a;for(const o of i){if(!o.open&&o.kind)continue;const i=j_(o.a,o.b),s=i.b[0]-i.a[0],a=i.b[1]-i.a[1],h=Math.hypot(s,a);if(!(h>1e-9))continue;const d=s/h,u=a/h;if(Math.abs(l*u-c*d)>1e-6)continue;if(Math.abs((i.a[0]-t.a[0])*c-(i.a[1]-t.a[1])*l)>r)continue;const p=(e[0]-i.a[0])*d+(e[1]-i.a[1])*u,_=1e-9;if(!(p<=_||p>=h-_)&&Math.abs((e[0]-i.a[0])*u-(e[1]-i.a[1])*d)<=n+1e-9)return!0}return!1}(e.pointer,t.target,e.intervals,t.envelope,Math.max(1e-9,Math.min(e.baseTolerance,.04*e.gridStep)))),i=t.filter(t=>!!t.target.partitionHost&&e.renderedLength+2*t.target.physicalHalfWidth>t.length+1e-9).sort(W_),n=t.filter(t=>!t.target.partitionHost||e.renderedLength+2*t.target.physicalHalfWidth<=t.length+1e-9).sort(W_);let r=n[0];if(!r)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=n.filter(e=>Math.abs(e.distance-r.distance)<=1e-9&&Math.abs(e.perpendicular-r.perpendicular)<=1e-9),s=o.filter(e=>e.target.partitionHost);if(s.length){if(1!==new Set(s.map(e=>e.target.partitionHost.id)).size||s.some(e=>e.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const e=s[0],t=e.target.b[0]-e.target.a[0],i=e.target.b[1]-e.target.a[1],n=Math.hypot(t,i),a=t/n,l=i/n;if(!o.every(t=>{const i=t.target.b[0]-t.target.a[0],n=t.target.b[1]-t.target.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,c=Math.abs(a*s-l*o)<=1e-6,h=Math.abs((t.target.a[0]-e.target.a[0])*l-(t.target.a[1]-e.target.a[1])*a);return c&&h<=1e-9}))return{candidate:null,jambBlockedTarget:null};r=e}if(r.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:a,length:l}=r,c=a.b[0]-a.a[0],h=a.b[1]-a.a[1],d=c/l,u=h/l,p=a.partitionHost?a.physicalHalfWidth:0,_=Math.min(Math.max(0,e.renderedLength)/2+p,l/2);let m=r.along;const g=Math.max(e.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=a.a[0]+d*m,y=a.a[1]+u*m,b=Math.max(0,e.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),$=Math.max(0,l-k),S=[a.a[0]+d*(w-x/2),a.a[1]+u*(w-x/2)],M=[a.a[0]+d*(k+$/2),a.a[1]+u*(k+$/2)];let R=180*Math.atan2(h,c)/Math.PI;R>=90?R-=180:R<-90&&(R+=180);const T=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:e.preset.revision,geometryRevision:e.geometryRevision,pointer:[e.pointer[0],e.pointer[1]],type:e.preset.type,lengthCm:e.preset.lengthCm,flipH:e.preset.flipH,flipV:e.preset.flipV,x:v,y:y,angle:R,renderedLength:e.renderedLength,target:a,...a.partitionHost?{host:{...a.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:S},{distance:$,midpoint:M}],guide:T?{x:v,y:y,angle:R}:null}},jambBlockedTarget:null}}function G_(e,t,i,n,r=1e-6){return e.presetRevision===i&&e.geometryRevision===n&&Math.hypot(e.pointer[0]-t[0],e.pointer[1]-t[1])<=r}function V_(e){return!(!e.canEdit||e.kiosk||e.fixedFloor)&&("view"!==e.mode&&("mouse"===e.pointerType&&e.spaceCount>1))}const K_="1.68.1",Y_="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479",Z_=1500,X_=(e,t)=>{if(!e.has(t))return{hit:!1};const i=e.get(t);return e.delete(t),e.set(t,i),{hit:!0,value:i}},J_=(e,t,i,n)=>{for(e.delete(t),e.set(t,i);e.size>n;){const t=e.keys().next().value;if(void 0===t)break;e.delete(t)}},Q_=new Map;let em=0;const tm=e=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(e??{})}`;let im=1e4;const nm="houseplan_card_layout_v1",rm="houseplan_card_cfg_v1",om="houseplan_card_zoom_v1",sm="houseplan_card_nav_v1",am="houseplan_card_kiosk_v1",lm="houseplan_card_view_v1",cm="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",hm=1e3,dm=[[0,1],[45,.88],[70,.62],[86,.32],[100,0]],um=(e,t)=>{const i=Math.min(e.x,t.x),n=Math.min(e.y,t.y);return{x:i,y:n,w:Math.max(e.x+e.w,t.x+t.w)-i,h:Math.max(e.y+e.h,t.y+t.h)-n}},pm=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),_m=(e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)},mm=e=>{history.pushState(null,"",e),_m(window,"location-changed",{replace:!1})},gm=(e,t)=>{let i,n=null;const r=(...r)=>{clearTimeout(i),n=r,i=window.setTimeout(()=>{i=void 0;const t=n;n=null,t&&e(...t)},t)};return r.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const t=n;n=null,t&&e(...t)},r.cancel=()=>{clearTimeout(i),i=void 0,n=null},r.pending=()=>void 0!==i,r},fm=e=>{try{e.target?.setPointerCapture?.(e.pointerId)}catch{}};class vm extends he{constructor(){super(...arguments),this._editorRuntime=null,this._onboardingRuntime=null,this._editorRuntimeLoadingVisible=!1,this._editorModeRequest=0,this._warmModeRequest=0,this._editorRuntimeLoader=new t_({expectedFingerprint:Y_,load:async e=>{const t=0===e?await import("./houseplan-editor-runtime-Bk__jFmU.js"):await import((()=>{const e=new URL("./houseplan-editor-runtime-Bk__jFmU.js",import.meta.url);return e.searchParams.set("hp_retry",K_),e.href})());return{fingerprint:t.EDITOR_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanEditorRuntime(this)}},install:e=>{this._editorRuntime=e},stateChanged:e=>this._editorRuntimeStateChanged(e),failed:e=>{console.error("[houseplan] unable to load editor runtime",e),this._showToast(`${this._t("editor.load_failed")} ${this._t("editor.refresh_advice")}`)}}),this._onboardingRuntimeLoader=new t_({expectedFingerprint:Y_,load:async e=>{const t=0===e?await import("./houseplan-onboarding-runtime-Dor16U6K.js"):await import((()=>{const e=new URL("./houseplan-onboarding-runtime-Dor16U6K.js",import.meta.url);return e.searchParams.set("hp_retry",K_),e.href})());return{fingerprint:t.ONBOARDING_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanOnboardingRuntime(this)}},install:e=>{this._onboardingRuntime=e},failed:e=>{console.error("[houseplan] unable to load onboarding runtime",e),this._showToast(`${this._t("editor.load_failed")} ${this._t("editor.refresh_advice")}`)}}),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=Cc(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._tip=null,this._hoverRoom=null,this._pointerModality=new Mp(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...ur},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=e=>{this._reducedMotion=e.matches,this._cancelDevicePressFeedback(),e.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:e.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 e_({frame:e=>this._applyModeTransitionFrame(e),settled:e=>this._settleModeTransition(e)}),this._editorSecondaryCopy={groupActive:(e,t)=>this._t("editor.group_active",{group:e,item:t}),openGroup:e=>this._t("editor.open_group",{group:e}),disabledAction:(e,t)=>this._t("editor.disabled_action",{action:e,reason:t})},this._tool="draw",this._geometryHistory=new qp(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._wallUnionCacheValue=null,this._wallUnionPool=new Map,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._innerContourCache=new Map,this._glowClipCache=new Map,this._glowGeometryWarnings=new Set,this._lightBarrierCache=null,this._lightBarrierPool=new Map,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._rszLimitViolation=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:e=>this._guardTouchGesture(e)},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._deviceInbox=null,this._deviceInboxReturn=null,this._deviceInboxMemo=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=e=>this._onKey(e),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++em,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=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),"hidden"===e.kind)return this._clearTransientHover(!0),this._cancelDevicePressFeedback(),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,!e.long){const e=Date.now();let t=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+wp)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&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=e=>{const t=this._effectiveProjection();this._labs=e;const i=this._effectiveProjection();this._convertProjectionView(t,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const e=this._hashSpace();if(e&&this._model.find(t=>t.id===e)&&e!==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(e),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 e=Vc(this.hass);e.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=e.revision,this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,function(e){const t=qc(e);t&&(Wc(e,t),Uc(e,t))}(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 Dl(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=gm(()=>{if(this._serverStorage){const e=[...this._dirtyPos];this._dirtyPos.clear();for(const t of e){const e=ro(this._layout[t]);e&&(this._layout={...this._layout,[t]:e},this._sentPos.set(t,e),this.hass.callWS({type:"houseplan/layout/update",device_id:t,pos:e}).then(e=>this._noteLayoutRev(e)).catch(e=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(e)}))).finally(()=>{this._sentPos.get(t)===e&&this._sentPos.delete(t)}))}this._cacheSnapshot()}else this._layout=oo(Ur(this._layout)),localStorage.setItem(nm,JSON.stringify(this._layout))},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>this._editorRuntimeOrThrow()._undoGeometry(),this._redoGeometry=()=>this._editorRuntimeOrThrow()._redoGeometry(),this._saveConfigDebounced=gm(()=>{this._serverCfg&&this._writeConfig().catch(e=>{const t=!0===e?.physicalGeometryRolledBack;"geometry-unsafe"!==e?.code&&("wall_model_client_outdated"===e?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===e?.code?(this._showToast(this._t("toast.conflict")),t||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)})),t&&this._reloadRejectedPhysicalWrite())})},500),this._draftSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>this._editorRuntimeOrThrow()._savePhysicalDialog(),this._deletePhysicalSelection=()=>this._editorRuntimeOrThrow()._deletePhysicalSelection(),this._confirmPartitionDelete=()=>this._editorRuntimeOrThrow()._confirmPartitionDelete(),this._deleteDraftWhole=()=>this._editorRuntimeOrThrow()._deleteDraftWhole(),this._deleteDraftSegment=()=>this._editorRuntimeOrThrow()._deleteDraftSegment(),this._confirmRoomDelete=e=>this._editorRuntimeOrThrow()._confirmRoomDelete(e),this._rebindPartitionOpening=()=>this._editorRuntimeOrThrow()._rebindPartitionOpening(),this._keepClosedAsPartitions=()=>this._editorRuntimeOrThrow()._keepClosedAsPartitions(),this._toggleServerPlans=async()=>this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._toggleServerPlans():this._editorRuntimeOrThrow()._toggleServerPlans(),this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=Zn(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(this._editorRuntime)return this._editorRuntime._openSettingsDialog();this._ensureEditorRuntime().then(e=>{e&&this._openSettingsDialog()})},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._editorRuntimeOrThrow()._openAlignDialog(),this._toggleOptimizeLivePositions=()=>this._editorRuntimeOrThrow()._toggleOptimizeLivePositions(),this._optimizeUndoBusy=!1,this._openBackupExport=()=>this._editorRuntimeOrThrow()._openBackupExport(),this._openRulesDialog=()=>this._editorRuntimeOrThrow()._openRulesDialog(),this._climateCache=null,this._gearPtCache=new WeakMap}_editorRuntimeOrThrow(){if(!this._editorRuntime)throw new Error("Houseplan editor runtime is not loaded");return this._editorRuntime}async _ensureEditorRuntime(){return this._editorRuntimeLoader.ensure()}async _ensureOnboardingRuntime(){return this._onboardingRuntimeLoader.ensure()}_editorRuntimeStateChanged(e){clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,"loading"!==e?(this._editorRuntimeLoadingVisible=!1,this.requestUpdate()):this._editorRuntimeLoadingTimer=window.setTimeout(()=>{this._editorRuntimeLoadingVisible=!0,this.requestUpdate()},150)}async _requestMode(e,t=!0,i=!1){const n=++this._editorModeRequest;if(i&&(this._warmModeRequest=n,this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._pendingRefitSize=null),"view"===e||await this._ensureEditorRuntime()){if(n===this._editorModeRequest&&this.isConnected)return i?(this._adoptMode(e),this._warmRevivePending&&(clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmReviveDialog()),this.requestUpdate(),void this.updateComplete.then(()=>requestAnimationFrame(()=>requestAnimationFrame(()=>{if(this._warmModeRequest!==n||n!==this._editorModeRequest)return;const e=this._stageEl;this._lastValidStageSize=e&&e.clientWidth>0&&e.clientHeight>0?[e.clientWidth,e.clientHeight]:null,this._pendingRefitSize=null,this._warmModeRequest=0})))):void this._setMode(e,t);this._warmModeRequest===n&&(this._warmModeRequest=0)}else this._warmModeRequest===n&&(this._warmModeRequest=0)}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(e,t){const i=String(e||"").trim();if(!i)return t;const n=document.createElement("span");n.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(n);const r=getComputedStyle(n).color||t;return n.remove(),r}_currentModeVisual(e=this._mode){const t=this._modeTransition.presented||this._modeTransitionVisual;if(t)return{...t,viewport:{...t.viewport,viewBox:{...t.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const n=this.renderRoot.querySelector(".editorchrome"),r=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),s=this.renderRoot.querySelector(".hp-backdrop"),a=this.renderRoot.querySelector(".zoomwrap"),l=a?getComputedStyle(a).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:e,editorChromeHeight:"view"===e?0:n?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:Yp(r,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"===e?.35:1,backdropOpacity:s&&Number(getComputedStyle(s).opacity)||1,viewWeight:"view"===e?1:0,editorWeight:"view"===e?0:1,toolbarContentOpacity:"view"===e?0:1}}_viewForModeTarget(e,t,i,n,r){const o=Ri(this._baseVb(),n/Math.max(1,r)),s=Math.min(vm.ZOOM_MAX,Math.max(vm.ZOOM_MIN,e)),a=o.w/s,l=o.h/s,c=t??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-a/2,y:h-l/2,w:a,h:l},o)}_targetStageColor(e){return"view"!==e?"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(e){return"view"===e&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(e){return 1}_applyModeTransitionFrame(e){e.targetMode===this._mode&&(this._modeTransitionVisual=e.presented,this._view={...e.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(e){if(e.targetMode!==this._mode)return;const t=this._modeTransitionRequest;this._view={...e.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[e.to.stageWidth,e.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._modeTransitionBusy||e.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-e.to.stageWidth)>.5||Math.abs(i.clientHeight-e.to.stageHeight)>.5)){const e=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}const n=this.renderRoot.activeElement;(!n||!n.isConnected||!!n.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(e=!0){const t=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(e),e&&t||(this._modeTransitionVisual=null)}_adoptMode(e){this._cancelModeTransition(!1),this._mode=e,"view"!==e&&(this._editorChromeMode=e)}_commitViewModeAtomic(e,t,i,n){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=t,e){const r=this._stageEl?.clientWidth||e.stageWidth,o=Math.max(1,e.stageHeight+e.editorChromeHeight);this._view=this._viewForModeTarget(t,i,n,r,o),this._lastValidStageSize=[r,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(e,t,i,n,r,o){this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._mode!==i)return void(e===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const s=this.renderRoot.querySelector(".editorchrome"),a=s?.querySelector(".editorchrome-inner"),l="view"===i?0:a?.scrollHeight||a?.getBoundingClientRect().height||0,c=Math.max(1,t.stageHeight+t.editorChromeHeight),h=Math.max(1,c-l),d=this._stageEl?.clientWidth||t.stageWidth;if(d<=0||h<=0)return this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._applyView(n,r,o),void this.requestUpdate();const u=this._viewForModeTarget(n,r,o,d,h),p={presentedMode:i,editorChromeHeight:l,stageWidth:d,stageHeight:h,viewport:Yp(u,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(t,p,i,this._reducedMotion||_?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(e=this._model,t=this._loadOk){const i=this._config?.floor,n=function(e){if(!e.hasFloor)return{kind:"absent"};const t=e.floor;if("string"==typeof t)return t.length?e.spaceIds.includes(t)?{kind:"valid",id:t,source:"id"}:{kind:"invalid",reason:"unknown-id",value:t}:{kind:"invalid",reason:"empty-id",value:t};if("number"==typeof t){if(!Number.isFinite(t))return{kind:"invalid",reason:"non-finite-index",value:t};if(!Number.isInteger(t))return{kind:"invalid",reason:"fractional-index",value:t};if(t<0)return{kind:"invalid",reason:"negative-index",value:t};const i=e.spaceIds[t];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:t}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:t}}({spaceIds:e.map(e=>e.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||t?n:"number"==typeof i?"valid"===n.kind||"invalid"===n.kind&&"out-of-range-index"===n.reason?{kind:"pending",value:i}:n:"valid"===n.kind||"invalid"===n.kind&&"unknown-id"!==n.reason?n:{kind:"pending",value:i}}_canCommitSpace(e,t=!1){if(t||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===e}_commitSpace(e,t=!1){return!!this._canCommitSpace(e,t)&&(e!==this._space&&(this._clearTransientHover(!0),this._cancelDevicePressFeedback()),this._space=e,!0)}_slideTo(e,t){if(e===this._space)return!0;if(!this._canCommitSpace(e))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(e),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=t,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return V_({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(e,t){V_({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:e.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(fm(e),this._tabDragRelease=e=>this._tabPointerUp(e),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:t,pointerId:e.pointerId,x:e.clientX,y:e.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(e,t,i){const n=this._model.map(e=>e.id),r=n.indexOf(i);if(r<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const s of o){const o=s.dataset.id||"";if(!o||o===i)continue;const a=s.getBoundingClientRect();if(ea.right||ta.bottom)continue;const l=n.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,n;const r=this._tabDropTargetAt(e.clientX,e.clientY,t.id);t.moved&&t.targetId===r?.targetId&&t.placement===r?.placement||(this._tabDrag={...t,moved:!0,targetId:r?.targetId||null,placement:r?.placement||null})}_tabPointerUp(e){const t=this._tabDrag;if(t&&t.pointerId!==e.pointerId)return;const i="pointerup"===e.type&&t?.moved?this._tabDropTargetAt(e.clientX,e.clientY,t.id):null;"pointerup"===e.type&&t?.moved&&this._suppressNextTabClick(),this._endTabDrag(),t?.moved&&i&&this._commitTabOrder(t.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(e){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(e)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(e,t){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const n=this._model.map(e=>e.id),r=function(e,t,i){const n=e.indexOf(t),r=e.indexOf(i);if(n<0||r<0||n===r)return e;const o=e.slice();return o.splice(n,1),o.splice(r,0,t),o}(n,e,t);if(r===n)return;const o=new Map(this._devices.map(e=>[String(e.id),String(e.area||"")])),s=function(e,t,i,n=()=>""){if(!i)return[];const r=[];for(const o of e){if(!o||!0===o.removed)continue;const e="string"==typeof o.id?o.id:"";if(!e)continue;if("string"==typeof o.space&&o.space)continue;const s=("string"==typeof o.area?o.area:"")||n(e)||"";s&&t[s]||r.push({id:e,space:i})}return r}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),n[0]||"",e=>o.get(e)||"");if(s.length){const e=new Map(s.map(e=>[e.id,e.space]));for(const t of i.markers||[]){const i=e.get(String(t.id));i&&(t.space=i)}}i.spaces=function(e,t){const i=new Map(t.map((e,t)=>[e,t]));return e.map((e,t)=>({space:e,index:t})).sort((e,t)=>(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)||e.index-t.index).map(e=>e.space)}(i.spaces||[],r),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(e){if(this._endTabDrag(),e===this._space)return;const t=this._model.map(e=>e.id),i=t.indexOf(this._space),n=t.indexOf(e);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(e,i>=0&&n0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const e=this._model.map(e=>e.id),t=e.indexOf(this._space);this._slideTo(e[(t+1)%e.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}get _wallUnionCache(){return this._wallUnionCacheValue}set _wallUnionCache(e){this._wallUnionCacheValue=e,null===e&&this._wallUnionPool.clear()}_newContinuityController(){return new Ml(()=>{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(lm,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(e){const t=this._view;if(!t)return null;const i=[t.x+t.w/2,t.y+t.h/2],n="iso"===e?x_(i):i;return{x:n[0],y:n[1]}}_convertProjectionView(e,t){if(e===t)return;const i=this._logicalViewCenter(e);this._view=null;const n=i?"iso"===t?k_([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,n?.[0],n?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(e){if(!this._labsIso||"view"!==this._mode)return;const t=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:e},"iso"===e){const e=this._isoSceneKey();e&&this._isoFallback.delete(e)}this._saveViewPreference();const i=this._effectiveProjection();this._convertProjectionView(t,i)}_hashSpace(){return c_(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 e=(t=this.ownerDocument,jp.get(t)?.resolved);var t;void 0!==e&&(this._glowScreenBlend=e),this._continuityUnsub?.(),this._continuityUnsub=$l(this.ownerDocument,this._pageVisibility),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(e=>{for(const t of e)for(const e of t.addedNodes)this._syncPointerHoverSubtree(e)}),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(e){const t=jp.get(e);if(t)return t.promise;const i={promise:Promise.resolve(!1)};return i.promise=Wp(e).catch(()=>!1).then(e=>(i.resolved=e,e)),jp.set(e,i),i.promise}(this.ownerDocument).then(e=>{e!==this._glowScreenBlend&&(this._glowScreenBlend=e,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>Sn(this._serverCfg)),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(e,t){g_.add(t);const i=y_(e);return"undefined"==typeof window&&t(i),()=>{g_.delete(t)}}(K_,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},Z_)),!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._warmModeRequest=0,this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const e of this._activityRt.values())clearTimeout(e.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),clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,this._editorRuntimeLoadingVisible=!1,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 e of this._glowFadeTimers.values())clearTimeout(e);for(const e of this._glowEnterRafs.values())cancelAnimationFrame(e);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(e){if("Escape"===e.key&&this._vacFit)return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void e.stopPropagation();if("Escape"===e.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._closeMarkerDialog();if(this._deviceInbox)return void(this._deviceInbox=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 e.preventDefault(),void this._editorSecondary?.closeGroup(!0)}const t=e.composedPath?.()||[e.target],i=t.some(e=>e?.matches?.('input, textarea, select, [contenteditable="true"]')),n=t.some(e=>e?.classList?.contains?.("editor-secondary")),r=e.ctrlKey||e.metaKey,o=e.key.toLowerCase(),s=/^[a-z]$/.test(o),a="z"===o||!s&&"KeyZ"===e.code,l="y"===o||!s&&"KeyY"===e.code,c=r&&(a&&e.shiftKey||l),h=r&&a&&!e.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;return c?(e.preventDefault(),void this._redoGeometry()):h?(e.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry()):"Delete"!==e.key&&"Backspace"!==e.key||!this._decorSel||i||n?void("Escape"===e.key&&(e.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"))):(e.preventDefault(),void this._decorDeleteSel())}if(this._markup&&(!h&&!c||!i)){if(("Delete"===e.key||"Backspace"===e.key)&&this._physicalSel&&!i&&!n)return e.preventDefault(),void this._deletePhysicalSelection();if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._resize?.dragging?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"===e.key)return this._physicalDrag||this._physicalRotate?(e.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(e.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(e.preventDefault(),void this._finishWallChain()):this._physicalSel?(e.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():("exit-tool"===this._resize?.escapeIdle()&&(this._tool="draw"),void this.requestUpdate())):"split"===this._tool?(e.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?(e.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(e.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(e.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 e=this._geometrySnapshot();this._path=this._path.slice(0,-1),this._draftSegmentCms=this._draftSegmentCms.slice(0,-1);const t=this._curSpaceCfg,i=(t.room_drafts||[]).findIndex(e=>e.id===this._activeDraftId);if(i>=0){const n=Array.isArray(t.room_drafts[i]?.segments)?t.room_drafts[i].segments:[];this._path.length<2?(t.room_drafts.splice(i,1),t.room_drafts.length||delete t.room_drafts,this._activeDraftId=null):t.room_drafts[i]={id:this._activeDraftId,points:this._path.map(e=>[e[0]/hm,e[1]/hm]),segments:this._draftSegmentCms.map((e,t)=>({...n[t]||{},cm:e}))},this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),e)}return}this._path=this._path.slice(0,-1)}}_undoActiveDraftPoint(){const e=this._activeDraftId,t=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 n=e?this._spaceModel()?.room_drafts.find(t=>t.id===e):null;n?(this._activeDraftId=n.id,this._path=n.points.map(e=>[...e]),this._draftSegmentCms=this._adoptDraftCms(this._path,n.segments.map(e=>e.cm),n.id),this._resumeDraftBySpace[this._space]=n.id):(this._activeDraftId=null,this._path=t?[t]:[],this._draftSegmentCms=[],e&&this._resumeDraftBySpace[this._space]===e&&delete this._resumeDraftBySpace[this._space]),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:i.name}))}static async getConfigElement(){return await import("./editor-DMlizeQy.js"),document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(e){for(const e of Q_.values())for(const t of e)clearTimeout(t.evict);Q_.clear(),im=e&&e>0?e:1e4}static _warmBootStats(){let e=0,t=0;const i=[];for(const n of Q_.values())for(const r of n)e++,r.dlg&&(t++,i.push(r.dlg.kind));return{keys:Q_.size,slots:e,dlgs:t,drafts:i}}setConfig(e){const t=this._config,i=!!t&&Object.prototype.hasOwnProperty.call(t,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...e};(i!==this._hasFixedFloor||t?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&e.default_floor&&this._commitSpace(e.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(om)||"{}")||{}}catch{this._zoomBySpace={}}try{const e=JSON.parse(localStorage.getItem(lm)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(e).filter(e=>"flat"===e[1]||"iso"===e[1]))}catch{this._viewPreference={}}this._labs=y_(K_);try{const e=JSON.parse(localStorage.getItem(am)||"null");this._kioskScale={icon:Dn(e?.icon),font:Dn(e?.font)}}catch{}try{const e=JSON.parse(localStorage.getItem(rm)||"null");e&&e.config&&Array.isArray(e.config.spaces)&&(this._serverCfg=e.config,this._cfgEpoch++,this._cfgRev=e.rev||0,this._cfgContentFingerprint=e.config_fingerprint||Rl(e.config),this._layout=e.layout||{},this._layoutRev=e.layout_rev||0,this._layoutContentFingerprint=e.layout_fingerprint||Rl(this._layout),this._virtualLights=Cc(e.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 e=tm(this._config);if(this._warmKey===e&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const t=this.parentNode,i=this._warmIdx(t),n=Q_.get(e);if(!n||!n.length)return;const r=n.find(e=>e.owner===this._warmGen);if(r)return this._warmLongReturn=!!r.freed&&Date.now()-r.freed>=wl,clearTimeout(r.evict),r.evict=0,r.freed=0,r.live=!0,this._warmSlot=r,this._warmKey=e,r.frameFingerprint&&this._continuity.adoptCompleteFrame(r.frameFingerprint),void(!this._devices.length&&r.devices?.length&&(this._devices=[...r.devices]));const{slot:o,sure:s}=((e,t,i,n)=>{const r=e=>{const t=!!i&&e.place?.deref()===i;return t&&e.idx===n?4:e.live?0:t?3:2};let o=null,s=0,a=0,l=null;for(const i of e){if(i.owner===t)continue;l=i;const e=r(i);e<=0||(e>s?(o=i,s=e,a=1):e===s&&a++)}return!o||a>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(n,this._warmGen,t,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=wl,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},Z_)),this._warmKey=e,s?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=t?new WeakRef(t):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:t?new WeakRef(t):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},n.push(this._warmSlot),this._warmTrim(n)))}_warmIdx(e){const t=e?.children;if(!t)return-1;for(let e=0;e4;){const t=e.findIndex(e=>!e.live);if(t<0)break;clearTimeout(e[t].evict),e.splice(t,1)}}_warmScheduleEvict(e,t){if(clearTimeout(e.evict),!(e.dlg||e.vp&&"view"!==e.vp.mode))return;const i=e.freed,n=e.owner;e.evict=window.setTimeout(()=>{if(e.evict=0,e.freed!==i||e.owner!==n)return;var r;e.dlg=null,e.vp=(r=e.vp)&&"view"!==r.mode?{...r,mode:"view",zoom:r.snap?.space===r.space?r.snap.zoom:r.zoom,view:null,snap:null,tool:"draw",decorTool:"select",showHidden:!1,selId:null,rszSel:null,decorSel:null}:r,e.frameFingerprint="";const o=Q_.get(t);if(!e.live&&o&&o.length>1){const t=o.indexOf(e);t>=0&&o.splice(t,1)}},im+250)}_warmAdoptViewport(e){const t=this._warmVp;if(!t||this._warmSlot?.path!==location.pathname)return void(this._warmVp=null);const i=this._fixedFloorState();if(this._hashApplied||!this._model.find(e=>e.id===t.space)||"valid"===i.kind&&i.id!==t.space||this._hasFixedFloor&&"valid"!==i.kind)return void(this._warmVp=null);this._commitSpace(t.space,!0),this._navApplied=!0;const n="view"!==t.mode&&this._canEdit&&!e.kiosk?t.mode:"view";this._adoptMode("view"),this._pendingNavMode="view"===t.mode||this._canEdit||e.kiosk?null:t.mode,this._zoom=t.zoom;const r=this._effectiveProjection(),o=r===t.projection&&this._labsIso===t.activeLabsIso;if(this._view=o&&t.view?{...t.view}:null,this._viewModeSnap=o&&t.snap?{...t.snap}:null,!o&&t.logicalCenter){const e="iso"===r?k_([t.logicalCenter.x,t.logicalCenter.y],0):[t.logicalCenter.x,t.logicalCenter.y];this._applyView(t.zoom,e[0],e[1])}var s;this._tool="opening"===(s=function(e){return"partition"===e?"draw":e}(s=t.tool))?"draw":"string"==typeof s&&pm.has(s)?s:"draw",this._decorTool=t.decorTool,this._showHidden=t.showHidden,this._showFar!==t.showFar&&(this._showFar=t.showFar,this._frame=null),this._selId=t.selId,this._resize?.restoreSelection(t.rszSel),this._decorSel=t.decorSel,this._warmVpArmed=!0,"view"!==n&&this._requestMode(n,!1,!0)}_warmPatch(e,t=!1){if(this._config?.kiosk)return;const i=tm(this._config);if(!this._warmSlot||this._warmKey===i){if(!this._warmSlot){if(!t)return;const e=this.parentNode;this._warmKey=i,this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:this._warmIdx(e),live:!0,hdrH:this._hdrH,stageH:0,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0};const n=Q_.get(i)||[];for(n.push(this._warmSlot),Q_.set(i,n),this._warmTrim(n);Q_.size>8;){const e=Q_.keys().next().value;if(void 0===e||e===i)break;for(const t of Q_.get(e)||[])clearTimeout(t.evict);Q_.delete(e)}}Object.assign(this._warmSlot,e)}}_warmViewportState(){const e=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:e,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(e),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._resize?.selectedRoomId,decorSel:this._decorSel}}_warmDialogState(){const e=(e,t)=>({kind:e,space:this._space,mode:this._mode,data:t});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?e("openingInfo",this._openingInfo.id):this._infoCard?e("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:e("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:e("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:e("marker",this._markerDialog):this._openingDialog?e("opening",this._openingDialog):this._backdropDialog?e("backdrop",this._backdropDialog):this._decorShapeDialog?e("decorShape",this._decorShapeDialog):this._decorTextDialog?e("decorText",this._decorTextDialog):this._roomDialog?e("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:e("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const e={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices};if(this._warmRevivePending||(e.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const t=this.parentNode;e.place=t?new WeakRef(t):null,e.idx=this._warmIdx(t)}this._warmPatch(e)}_warmReviveDialog(){const e=this._warmSlot;if(this._warmReviveTimer=void 0,!e||!e.dlg)return void(this._warmRevivePending=!1);const t=e.dlg,i=e.freed;if(t.mode===this._mode||"view"===t.mode||this._warmVp?.mode!==t.mode||this._editorRuntime){if(this._warmRevivePending=!1,e.dlg=null,e.freed=0,clearTimeout(e.evict),e.evict=0,i&&!(Date.now()-i>im)&&t.space===this._space&&t.mode===this._mode){switch(t.kind){case"space":this._spaceDialog={...t.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...t.data,busy:!1};break;case"settings":this._settingsDialog={...t.data,busy:!1};break;case"rules":this._rulesDialog={...t.data,busy:!1};break;case"opening":this._openingDialog={...t.data};break;case"backdrop":this._backdropDialog={...t.data};break;case"decorShape":this._decorShapeDialog={...t.data};break;case"decorText":{this._decorTextDialog={...t.data};const e=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:e,end:e};break}case"room":{const e=t.data;this._roomEditId=e.editId,this._roomFill=e.fill,this._roomCustomFill=e.customFill||null,this._roomTempSrc=e.tempSrc,this._roomHumSrc=e.humSrc,this._roomSrcOpen=e.srcOpen,this._roomSrcFilter=e.srcFilter,this._roomNameScale=e.nameScale,this._roomLabelScale=e.labelScale,this._areaSel=e.areaSel,this._nameSel=e.nameSel,this._pendingSplit=e.pendingSplit,this._wallFaceBatch=e.wallFaceBatch||null,this._path=e.path,this._wallFaceBatch&&(this._activeDraftId=this._wallFaceBatch.activeDraftId,this._draftSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const e=this._devices.find(e=>e.id===t.data);e&&(this._infoCard=e);break}case"openingInfo":{const e=(this._curSpaceCfg?.openings||[]).find(e=>e.id===t.data);e&&(this._openingInfo=e);break}}this.requestUpdate()}}else this._warmRevivePending=!0}_cacheSnapshot(){if(this._serverCfg)try{this._cfgContentFingerprint=Rl(this._serverCfg),this._layoutContentFingerprint=Rl(this._layout),this._virtualLights=function(e,t,i){if(e.configRev===i)return e;const n=new Set((Array.isArray(t?.markers)?t.markers:[]).filter(zc).map(e=>e.id));return{...e,configRev:i,off:new Set([...e.off].filter(e=>n.has(e)))}}(this._virtualLights,this._serverCfg,this._cfgRev),localStorage.setItem(rm,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:Ac(this._virtualLights)}))}catch{}}_beginContinuityCandidate(e,t,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(e,i))}_continuityStageValid(){const e=this._stageEl;return!!e&&e.clientWidth>0&&e.clientHeight>0}_continuityAssetsReady(){if(!this._model.length)return!1;const e=this._model.length?this._spaceModel():null;return!e?.bg?.href||this._signer.isReady(this.hass,e.bg.href)}_initialSpaceSelection(e,t=this._loadOk){const i=this._fixedFloorState(e,t);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(e){const t=new Set(e.spaceIds.filter(e=>!!e));if(!t.size)return{id:null,source:"none"};const i=[["hash",!1===e.acceptHash?null:e.hashSpace],["current",e.preserveCurrent?e.currentSpace:null],["saved",e.savedSpace],["default",e.defaultSpace],["first",e.spaceIds[0]]];for(const[e,n]of i)if(n&&t.has(n))return{id:n,source:e};return{id:null,source:"none"}}({spaceIds:e.map(e=>e.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(e,t=this._loadOk){const i=this._initialSpaceSelection(e,t);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(e,t=this._space){const i=za(e),n=this._fixedFloorState(i,!0);if(this._hasFixedFloor&&"valid"!==n.kind)return"";const r=this._initialSpaceSelection(i,!0).id||(i.some(e=>e.id===t)?t:i[0]?.id);return i.find(e=>e.id===r)?.bg?.href||""}_visualFrameFingerprint(){const e=this._stageEl,t=e?[e.clientWidth,e.clientHeight]:[0,0];return Tl([this._cfgRev,this._cfgContentFingerprint||Rl(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||Rl(this._layout),this._space,this._mode,this._view,t,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 e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(e,t){this._signer.markLoaded(this.hass,e,t),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 e="connection"===this._continuity.recoveryReason;return B`
e.stopPropagation()} + @click=${e=>e.stopPropagation()} + @wheel=${e=>e.stopPropagation()}> + + ${this._t(e?"continuity.restore_connection":"continuity.restore_plan")} + ${"recovery-error"===this._continuity.state?B``:G} +
`}_renderEditorRuntimeLoading(){return this._editorRuntimeLoadingVisible?B`
+ + ${this._t("editor.loading")} +
`:G}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}getCardSize(){return 12}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const e=this._serverCfg?.spaces||[];let t=e.length+":";for(const i of e){t+=(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 e of i.rooms||[]){const i=e.poly?.[0],n=e.poly?.[e.poly.length-1];t+=(e.poly?.length||0)+"."+(e.id||"")+"."+(e.open_to||[]).join("+")+"."+(e.area||"")+"."+JSON.stringify(e.settings||0)+"."+(e.x??"")+","+(e.y??"")+","+(e.w??"")+","+(e.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(n?n[0]+"/"+n[1]:"")+";"}}return t}get _model(){if(!this._serverCfg)return[];const e=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===e)return this._modelCache.model;const t=this._buildModel();return this._modelCache={key:e,model:t},t}_buildModel(){if(!this._serverCfg)return[];const e=this._renderCfg;return za(e).map((t,i)=>{const n=e.spaces[i]?.plan_url;return t.bg&&n?{...t,bg:{...t.bg,href:n}}:t})}_spaceModel(){return this._hasFixedFloor?Al(this._model,this._space):(e=this._model,t=this._space,e.find(e=>e.id===t)??e[0]);var e,t}_spaceModelById(e){return Al(this._model,e)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0;for(const e of this._pointers.keys())for(const t of this.renderRoot.querySelectorAll("*"))try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}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._deviceInbox=null,this._deviceInboxReturn=null,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 e={};for(const t of this._model)for(const i of t.rooms)i.area&&(e[i.area]={space:t.id,room:i});return e}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._showHidden||!this._settings.filter_seeded&&!!this._settings.show_all}_seedHiddenDevices(){if(!this._serverCfg||!this._norm||!this._canEdit)return;const e=this._serverCfg,t=function(e){const t=e.hass,i=e.registry||Vc(t),n=Xc(t,i),r=Jc(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,iconRules:c}=e,h=!1!==a.group_lights,d=Lh(s),u=Ph(n,h).filter(e=>!qh(n,e.eid,d)),p=new Set(u.map(e=>e.area)),_=ih(n),m=nh(s,r),g=new Set(s.map(e=>e.binding)),f=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(g.has("device:"+e.id))continue;if("active"!==th(t,"device:"+e.id,i).kind)continue;const s=rh(n,e.id,_[e.id]||[],m);if(s.partial&&!s.entityIds.length)continue;const a=s.entityIds,d=oh(n,e,a);let u=l.has(d)||"Group"===e.model||/scene/i.test(e.model||"")||/bridge/i.test((e.model||"")+(e.name||""))||"myheat"===d&&!!e.via_device_id;if(!u&&h&&p.has(r)){const t=(e.name_by_user||e.name||"").trim();"mdi:lightbulb"===Fh(n,t,e.model,a,c)&&(u=!0)}u&&f.push("device:"+e.id)}return f}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!t.length&&e.settings?.filter_seeded)return;e.markers=e.markers||[];const i=[];for(const n of t){const t="h"+n.slice(n.indexOf(":")+1);e.markers.push({id:t,binding:n,hidden:!0}),i.push(n.slice(n.indexOf(":")+1))}const n={...e.settings||{},filter_seeded:!0};delete n.show_all,i.length&&Array.isArray(n.new_device_ids)&&(n.new_device_ids=n.new_device_ids.filter(e=>!i.includes(e))),e.settings=n,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const e=this._settings.icon_rules;if(!e||!Array.isArray(e)||!e.length)return;const t=JSON.stringify(e);return t!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=t,this._rulesCompiled=De(e)),this._rulesCompiled}get _fillColors(){return on(this._settings)}get _excluded(){const e=this._settings.exclude_integrations;return e?new Set(e):Te}willUpdate(e){e.has("_serverCfg")&&this._cfgEpoch++,this._syncEmptySpaceState(),e.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._editorRuntime&&this._dtMeasure();const e=this._stageEl;e&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>this._refitView()),this._roViewport.observe(e)),e&&this._booting&&!this._bootTimer&&this._bootWatch();const t=this.renderRoot.querySelector(".hdr");if(t&&e&&!this._roHdr){const i=()=>{const t=this.renderRoot.querySelector("ha-card");if(!t)return;const i=e.getBoundingClientRect().top-t.getBoundingClientRect().top,n=Math.min(Math.max(t.getBoundingClientRect().top,0),120),r=Math.round(i+n);r>=0&&r!==this._hdrH&&(this._hdrH=r),r>=0&&!this._booting&&!this._config?.kiosk&&e.clientHeight>0&&this._warmPatch({hdrH:r,stageH:e.clientHeight})};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(t),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(e&&!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 e=function(e){const t=e?.floors;if(!t||"object"!=typeof t)return[];const i=[];for(const e of Object.values(t))e&&e.floor_id&&i.push({id:e.floor_id,name:e.name||e.floor_id,level:e.level??null});return i.sort((e,t)=>{const i=e.level??1e9,n=t.level??1e9;return i!==n?i-n:e.name.localeCompare(t.name)}),i}(this.hass);e.length?this._importDialog={floors:e.map(e=>({...e,checked:!0}))}:this._openSpaceDialog("create")}}_adoptStructuralResponses(e,t,i){const n=e?.config,r=n&&Array.isArray(n.spaces)?n:null,o=Rl(r),s=o!==(this._cfgContentFingerprint||Rl(this._serverCfg));if(s&&(this._geometryHistory.clear(),this._pendingPhysicalWrites.clear(),this._serverCfg&&this._clearGeometryGesture(),this._serverCfg=r,this._cfgContentFingerprint=o),this._cfgRev=e?.rev??this._cfgRev,e&&("virtual_lights"in e||"config"in e)){const t=Dc(this._virtualLights,e.virtual_lights,this._cfgRev,"virtual_lights"in e);Oc(t)!==Oc(this._virtualLights)&&(this._virtualLights=t,this._capturedSnapshotVirtual="")}let a=!1;if(void 0!==t||void 0!==i){const e=i??t?.layout??{},n=Rl(e);a=n!==(this._layoutContentFingerprint||Rl(this._layout)),a&&(this._layout=e,this._layoutContentFingerprint=n),this._layoutRev=t?.rev??this._layoutRev}return this._canOptimizeUndo=!(!e?.can_optimize_undo&&!t?.can_optimize_undo),this._haIntegrationVersion="string"==typeof e?.integration_version?e.integration_version:this._haIntegrationVersion,this._undoKind=e?.undo_kind||t?.undo_kind||null,"boolean"==typeof e?.can_write&&(this._serverCanWrite=e.can_write),s&&this._continuity.note("config-candidate",{configRev:this._cfgRev}),a&&this._continuity.note("layout-candidate",{layoutRev:this._layoutRev}),{configChanged:s,layoutChanged:a}}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const e=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(e,!1),!0}async _loadFromServer(){this._loading=!0,this._loadTries++;const e=this._space,t=!!this._view;try{const[i,n]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]),r=i?.config&&Array.isArray(i.config.spaces)?i.config:null,o=Rl(r)!==(this._cfgContentFingerprint||Rl(this._serverCfg))||Rl(n?.layout??{})!==(this._layoutContentFingerprint||Rl(this._layout));if(o){if(!await this._signer.prepareImage(this.hass,this._candidateBackdrop(r)))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&&!n?.can_optimize_undo),this._haIntegrationVersion="string"==typeof i?.integration_version?i.integration_version:this._haIntegrationVersion,this._adoptStructuralResponses(i,n),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:t&&this._space===e||this._restoreZoom(),this._loadOk=!0,this.hass.callWS({type:"houseplan/trail/get"}).then(e=>{this._vacSrvTrails=e?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(e){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(nm)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const e=this.hass?.connection;if(!e)return;if(e!==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=e),this._liveSyncAttempt)return;const t=this._liveSyncGeneration,i=[],n=(n,r,o,s)=>{n()||i.push(async()=>{const i=await e.subscribeEvents(s,o);t===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===e&&!n()?r(i):i?.()})};if(n(()=>this._unsubCfg,e=>{this._unsubCfg=e},"houseplan_config_updated",e=>{const t=Number(e?.data?.rev??-1);t!==this._cfgRev&&this._reloadConfigOnly(!1,t)}),n(()=>this._unsubTrail,e=>{this._unsubTrail=e},"houseplan_trail_updated",async()=>{try{const e=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=e?.trails||{},this.requestUpdate()}catch{}}),n(()=>this._unsubLayout,e=>{this._unsubLayout=e},"houseplan_layout_updated",e=>this._onLayoutEvent(Number(e?.data?.rev??-1))),n(()=>this._unsubVirtual,e=>{this._unsubVirtual=e},"houseplan_virtual_light_updated",e=>{const t=Fc(this._virtualLights,e?.data);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const r=function(e){return Promise.allSettled(e.map(e=>Promise.resolve().then(e)))}(i).then(()=>{});this._liveSyncAttempt=r,r.finally(()=>{this._liveSyncAttempt===r&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(e=!1,t){if(!e){if(void 0!==t&&t<=this._cfgRev)return;if(this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(()=>this._reloadConfigOnly(!1,t),400))}this._beginContinuityCandidate("config-reload",!1);try{const e=await this.hass.callWS({type:"houseplan/config/get"}),t=e?.config&&Array.isArray(e.config.spaces)?e.config:null;if(Rl(t)!==(this._cfgContentFingerprint||Rl(this._serverCfg))&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(t)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0);const i=this._space;this._adoptStructuralResponses(e),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._space!==i&&this._restoreZoom(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}catch(e){this._showToast(this._t("toast.cfg_reload_failed",{err:this._errText(e)}))}finally{this._continuityDataReady=!0,this.requestUpdate()}}_scheduleLoadRetry(e=!1){if(void 0!==this._loadRetryTimer)return;const t=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!e&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},t)}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._haRegistryRelease=Gc(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return Vc(this.hass)}get _planHass(){const e=this._haRegistry,t=Yc(this.hass,e),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===t)return i.active;const n=Xc(this.hass,e),r=Jc(this.hass,e);return this._planHassMemo={hass:this.hass,sig:t,active:n,full:r},n}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRt.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+wp)>e?1:0)).join("|"),i=Oc(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===t)return;const n=this._planHass,r=new Map,o=new Map,s=new Set(["sun.sun"]);this._vacFit?.source&&s.add(this._vacFit.source);const a=new Set,l=new Set,c=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void s.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?a.add(n):"entity"===i&&s.add(n)};for(const e of this._model)for(const t of e.rooms)t.area&&l.add(t.area),c(t.settings?.temp_source),c(t.settings?.hum_source);for(const e of this._serverCfg?.spaces||[])for(const t of e.openings||[])for(const e of ni(t))s.add(e);for(const e of this._serverCfg?.spaces||[])for(const t of e.decor||[])if("text"===t.kind){for(const e of String(t.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const t=Hi(e[1]);t?.entity&&s.add(t.entity)}t.entity&&s.add(t.entity),o.set(`decor:${e.id}:${t.id}`,Wi(t.text,t,n,e=>!!n.entities?.[e]&&!!n.states?.[e]&&!qh(n,e,Lh(this._markers))))}const h=Mh(n,this._devices,null,this._virtualLights);for(const e of this._devices){for(const t of[!1,!0])r.set(Nu(e.id,t),Pu(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(e)){const t=this._vacSource(e,n),i=t?Bl(n?.states?.[t]?.attributes):null,r=this._vacRt.get(e.id);o.set(`vacuum:${e.id}`,{source:t,telemetry:i,mapId:i?this._vacMapId(e,i,n):null,runtime:r?{trail:r.trail,lastTs:r.lastTs,moving:r.moving,jump:r.jump}:null,server:this._vacSrvTrails[e.id]||null})}}const d=Eu({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,positions:(u=this._model.length>0,p=this._devices,_=e=>this._livePos(e),u?new Map(p.map(e=>[e.id,_(e)])):new Map),facts:o,entityIds:s,deviceIds:a,areaIds:l});var u,p,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=t,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(e){return th(this.hass,e,this._haRegistry)}houseplanDiagnostics(){const e=function(e){const t=Vc(e);return{access:t.access,authoritative:t.authoritative,revision:t.revision,lastSuccess:t.lastSuccess,error:t.error}}(this.hass),t={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const e of this._markers)e.removed||"virtual"===e.binding||t[this._bindingStatus(e.binding).kind]++;return{registry:{...e,lastSuccessAgeMs:e.lastSuccess?Math.max(0,Date.now()-e.lastSuccess):null},bindings:t}}_openBindingInHa(e){const[t,i]=e.split(":");if(i)if("device"!==t){if("entity"===t){const e=this._fullRegistryHass.entities?.[i];e?.device_id&&mm("/config/devices/device/"+encodeURIComponent(e.device_id))}}else mm("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(e){const[t,i]=e.split(":");return!!i&&("device"===t||"entity"===t&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const e=this._markerDialog;if(!e)return;const t="ha"===e.bindingMode?this._bindingStatus(e.binding):null,i=e.hideFromPlan||"ha_disabled"===t?.kind;i&&"ha_disabled"===t?.kind?this._showToast(this._t("entity"===t.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===t?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...e,hideFromPlan:!i}}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}_display(e){return this._signer.display(this.hass,e)}_resign(){this._signer.resign(this.hass,Sn(this._serverCfg))}_onLayoutEvent(e){e<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{e<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(e){const t=e?.rev;"number"==typeof t&&t>this._layoutRev&&(this._layoutRev=t)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const e=new Map;for(const t of this._dirtyPos)this._layout[t]&&e.set(t,this._layout[t]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[t,i]of this._sentPos)e.set(t,i);try{const t=await this.hass.callWS({type:"houseplan/layout/get"}),i={...t?.layout||{}};for(const[t,n]of e)i[t]=n;const n=Rl(i);n!==(this._layoutContentFingerprint||Rl(this._layout))&&(this._layout=i,this._layoutContentFingerprint=n),this._layoutRev=t?.rev??this._layoutRev,this._canOptimizeUndo=!!t?.can_optimize_undo,this._haIntegrationVersion="string"==typeof t?.integration_version?t.integration_version:this._haIntegrationVersion,this._undoKind=t?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_maybeRebuildDevices(){const e=this.hass;if(!e?.devices||!e?.entities||!e?.areas)return;const t=this._haRegistry,i=Yc(e,t)+":"+Object.keys(e.areas).length+":"+(this._norm?"n":"l")+":"+Xd(e,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const n=new Map(this._devices.map(e=>[e.id,e.bindingStatus?.kind||"active"]));this._devices=Wh({hass:e,registry:t,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:e=>this._t(e),iconRules:this._iconRules});const r=this._markers.filter(e=>!e.removed&&"virtual"!==e.binding).map(e=>e.binding).sort(),o=t.revision+":"+r.join("|");if(t.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const n of r)i.set(n,th(e,n,t));!function(e){if("undefined"==typeof localStorage||!e.size)return;const t=eh(),i=Date.now();for(const[n,r]of e)"active"===r.kind?t[n]={kind:"active",ts:i}:"ha_disabled"===r.kind&&(t[n]={kind:"ha_disabled",reason:r.reason,ts:i});const n=Object.fromEntries(Object.entries(t).sort((e,t)=>t[1].ts-e[1].ts).slice(0,1500));Lc=n;try{localStorage.setItem(Hc,JSON.stringify(n))}catch{}}(i),this._haBindingCacheKey=o}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),this._syncActivityRuntime();const s=new Set(this._devices.filter(e=>!e.hidden).map(e=>e.id));for(const e of this._vacRt.keys())s.has(e)||this._vacRt.delete(e);if(this._infoCard){const e=this._devices.find(e=>e.id===this._infoCard.id);this._infoCard=e&&"ha_disabled"!==e.bindingStatus?.kind?e:null}const a=this._devices.some(e=>"ha_disabled"===e.bindingStatus?.kind&&"ha_disabled"!==n.get(e.id));a&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(e=>e.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._drag&&"ha_disabled"===this._devices.find(e=>e.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)&&(_m(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const e=this._devices.filter(e=>!e.marker&&!e.virtual).map(e=>e.id).sort(),t=e.join(",");if(t===this._newSyncKey)return;this._newSyncKey=t;const i=this._settings,{fresh:n,known:r}=function(e,t){if(!Array.isArray(t))return{fresh:[],known:[...e]};const i=new Set(t),n=e.filter(e=>!i.has(e));return{fresh:n,known:n.length?[...t,...n]:t}}(e,i.known_devices);if(!Array.isArray(i.known_devices)||n.length){const e=[...new Set([...i.new_device_ids||[],...n])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:r,new_device_ids:e}},this._saveConfig()}}get _newIds(){const e=this._settings.new_device_ids;return new Set(Array.isArray(e)?e:[])}_ackNewDevice(e){if(!this._newIds.has(e)||!this._serverCfg)return;const t=this._settings;this._serverCfg={...this._serverCfg,settings:{...t,new_device_ids:(t.new_device_ids||[]).filter(t=>t!==e)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(e){if(!e)return null;const t=[];for(const i of this._renderDevices){if(i.area!==e||i.virtual)continue;const n=Ch(this._renderPlanHass,i.entities);null!=n&&t.push(n)}return Mi(t)}_roomBounds(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}_defaultPositions(){const e={},t=this._config?.icon_size??2.5;for(const i of this._model){const n=t/100*el(i)*1.3;for(const t of i.rooms){if(!t.area)continue;const r=this._devices.filter(e=>e.area===t.area&&e.space===i.id);if(!r.length)continue;const o=this._roomBounds(t),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(r.length*a/Math.max(l,1)))),h=Math.ceil(r.length/c),d=a/c,u=l/Math.max(h,1),p=r.map((e,t)=>({x:o.x+s+d*(t%c+.5),y:o.y+s+u*(Math.floor(t/c)+.5)}));Ti(p,o,n,.5*s),r.forEach((t,i)=>e[t.id]=La(p[i]))}}return e}_pos(e){const t=this._renderDeviceSnapshot?.positions.get(e.id);return t?{x:t.x,y:t.y}:this._livePos(e)}_livePos(e){const t=this._spaceModelById(e.space),i=this._layout[e.id];if(i)if(this._norm){if(i.s===e.space)return{x:i.x*hm,y:i.y*hm}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[e.id]?this._defPos[e.id]:t?La(Qa(t)):{x:500,y:500}}_savePos(e,t,i){if(this._spaceModelById(e.space)){if(this._norm){const n=this._gridPitch,r=Math.round(t/n)*n,o=Math.round(i/n)*n,s=this._layout[e.id]?.k;this._layout={...this._layout,[e.id]:{s:e.space,x:ja(r/hm),y:ja(o/hm),...s?{k:s}:{}}}}else this._layout={...this._layout,[e.id]:{x:Math.round(t),y:Math.round(i)}};this._dirtyPos.add(e.id),this._persistLayout()}}_visualSamples(e){return Cu(this._renderPlanHass,e,this._renderDevices,void 0,this._fullRegistryHass).samples}_devicePresentation(e,t=!1!==this._config?.show_signal,i=!1){const n=i?null:this._renderDeviceSnapshot?.presentations.get(Nu(e.id,t));return n||Pu(this._renderPlanHass,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,designPreview:i,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(e){return this._devicePresentation(e).visual}_stateClass(e,t=this._deviceVisual(e)){const i=this._devicePresentation(e);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===t.status||t.activity,zu({...i,visual:t}).join(" "))}_liveTemp(e){if(!this._config?.show_temperature)return null;if(!0===e.marker?.use_climate_temp){const t=Ah(this._renderPlanHass,e.entities);if(null!=t)return t}return"mdi:thermometer"!==e.icon&&"mdi:air-filter"!==e.icon?null:Dh(this._renderPlanHass,e.entities)}_bindingEntities(e){if("virtual"===e||!e)return[];const t=this._bindingStatus(e);return"active"===t.kind?t.enabledEntityIds:t.allEntityIds}_bindingHasClimate(e){return this._bindingEntities(e).some(e=>e.startsWith("climate."))}_bindingHasAlarm(e){return this._bindingEntities(e).some(e=>{const t=this._planHass?.states?.[e]||this.hass?.states?.[e],i=this._fullRegistryHass.entities[e]||this.hass?.entities?.[e];return In(e.split(".")[0],t?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_liveHum(e){return this._config?.show_temperature&&e.primary&&Oh(this.hass,e.primary)?zh(this.hass,e.entities):null}_deviceBindingActive(e,t=!0){if(e.virtual||"virtual"===e.bindingKind)return!0;if(!e.bindingKind||!e.bindingRef)return!1;const i=this._bindingStatus(`${e.bindingKind}:${e.bindingRef}`);return"active"===i.kind||(t&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(e){e?this._planEntityAvailable(e)?(this._nativeMoreInfoEntity=e,_m(this,"hass-more-info",{entityId:e})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(e,t){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==e)for(const i of[t,this._stageEl])try{i?.hasPointerCapture?.(e)&&i.releasePointerCapture(e)}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(e,t){"view"===this._mode&&(e.preventDefault(),e.stopPropagation(),this._deviceBindingActive(t)&&(t.primary?this._openMoreInfo(t.primary):this._infoCard=t))}_clickDevice(e,t){if(e.stopPropagation(),this._drag?.moved||this._suppressClick||this._holdFired)return;if("plan"===this._mode)return;if("devices"===this._mode)return void this._openMarkerDialog(t);const i=this._devices.find(e=>e.id===t.id);if(!i)return;const n=_d(i.tapAction,i.primary?.split(".")[0]),r=(e,t)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:e,exec:t}:t()};if("toggle"===n){const e=this._toggleIntent(i);if(!e)return;if(!bd(e))return void this._showUnavailableToggleTargets(e);const t=e=>{const t=bd(e);if(!t)return;if("virtual-light"===t.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:t.markerId}).then(e=>{const t=Fc(this._virtualLights,e);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(e=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(e)})));const{command:n}=t;this._startDevicePressFeedback(i.id),this.hass.callService(n.domain,n.service,n.data).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)})))},n=((o=e).targets.length?o.targets:o.skippedTargets).map(e=>e.name||e.entityId||e.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const r=this._toggleConfirmationLines(e);if(!r.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:n}),lines:r,initialIntent:e,deviceId:i.id,exec:()=>{const n=this._devices.find(e=>e.id===i.id),r=n?this._toggleIntent(n):null;r&&!bd(r)&&this._showUnavailableToggleTargets(r)||(r&&xd(e,r)?t(r):this._showToast(this._t("toast.tap_target_changed")))}}}else t(e);return}var o;if("info"===n)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===n){const e=i.marker?.tap_target||"",t=function(e){const t=String(e||"").split(".")[0];return"automation"===t?{domain:"automation",service:"trigger"}:"script"===t?{domain:"script",service:"turn_on"}:"scene"===t?{domain:"scene",service:"turn_on"}:null}(e),n=this.hass.states[e];if(!t||!n)return void this._showToast(this._t("toast.run_target_missing"));const o=n.attributes?.friendly_name||e;return void r(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(e)&&(this._startDevicePressFeedback(i.id),this.hass.callService(t.domain,t.service,{entity_id:e}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)}))))})}"more-info"===n&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(e){const t=function(e){if(!e||"group"!==e.kind||bd(e)||"configured-targets-missing"!==e.noneReason)return[];if(!e.skippedTargets.length||e.skippedTargets.some(e=>!wd.has(e.reason)&&"secure"!==e.reason))return[];const t=[],i=new Set;for(const n of e.skippedTargets){if(!wd.has(n.reason))continue;const e=String(n.name||n.entityId||n.ref||"").trim();e&&!i.has(e)&&(i.add(e),t.push(e))}return t}(e);return!!t.length&&(this._showToast(1===t.length?this._t("toast.toggle_target_unavailable",{name:t[0]}):this._t("toast.toggle_targets_unavailable",{names:t.join(", ")})),!0)}_keyDevice(e,t){"Enter"!==e.key&&" "!==e.key||"view"!==this._mode&&"devices"!==this._mode||(e.preventDefault(),this._clickDevice(e,t))}_startDevicePressFeedback(e){const t=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(t=>t.dataset.id===e),i=t?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const n=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),r=Number.isFinite(n)?Math.max(.95,Math.min(1,n)):1;this._devicePressAnimations.get(e)?.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(r)},{scale:"0.95",offset:.5},{scale:"1"}],s=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(e,s);const a=()=>{this._devicePressAnimations.get(e)===s&&this._devicePressAnimations.delete(e)};s.addEventListener("finish",a,{once:!0}),s.addEventListener("cancel",a,{once:!0})}_cancelDevicePressFeedback(){for(const e of this._devicePressAnimations.values())e.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const e=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(e=>e.dataset.id||""));for(const[t,i]of this._devicePressAnimations)e.has(t)||(i.cancel(),this._devicePressAnimations.delete(t))}_t(e,t){return Jd(Xd(this.hass,this._config?.language),e,t)}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(e){return this._editorRuntimeOrThrow()._help(e)}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(e){const t=[];for(const i of this._devices){if(i.space!==e.id||i.hidden)continue;const n=this._pos(i);t.push({minX:n.x,minY:n.y,maxX:n.x,maxY:n.y})}if(e.id===this._space){for(const e of this._openingsR){const i=Number(e.angle)*Math.PI/180,n=Math.cos(i)*e.rlen/2,r=Math.sin(i)*e.rlen/2,o=Ua([[e.rx-n,e.ry-r],[e.rx+n,e.ry+r]]);o&&t.push(o)}const i=this._decorH;for(const e of this._decorList){const n=Ua("line"===e.kind?[[e.x1*hm,e.y1*i],[e.x2*hm,e.y2*i]]:"text"===e.kind?[[e.x*hm,e.y*i]]:wr({x:e.x*hm,y:e.y*i,w:e.w*hm,h:e.h*i,angle:e.angle}));n&&t.push(n)}for(const i of this._physicalBodiesR(e)){const e=Ua(i);e&&t.push(e)}}return Va(e,t)}_frameOf(){const e=this._spaceModel();if(!e){this._frame=null;const e={x:0,y:0,w:hm,h:hm};return{rect:e,all:e,outliers:0}}const t=this._frame,i="view"!==this._mode;if(t&&t.id===e.id&&this._bdDrag)return t;if(t&&t.id===e.id&&t.model===e&&t.layout===this._layout&&t.devs===this._devices&&t.far===this._showFar&&t.grow===i)return t;const n=Xa(this._contentItems(e));let r=n.all||Ja(e),o=this._showFar?r:n.core||Ja(e);return t&&t.id===e.id&&i&&t.grow&&(o=um(t.rect,o),r=um(t.all,r)),this._frame={id:e.id,model:e,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:r,outliers:n.outliers},this._frame}_isoSource(){const e=this._spaceModel();if(!e)return null;const t=this._spaceWalls,i=this._openCuts(),n=this._openingsR.map((e,t)=>({id:String(e.id||t),sourceIndex:t,type:e.type,x:e.rx,y:e.ry,angle:Number(e.angle)||0,length:e.rlen>0?e.rlen:900,flipH:!!e.flip_h,flipV:!!e.flip_v})),r=xa(64,this._cellCm),o=xa(10,this._cellCm),s=`${e.id}|${function(e){let t=2166136261;const i=e=>{if("number"!=typeof e)if("string"!=typeof e)if("boolean"!=typeof e)if(Array.isArray(e)){t=O_(t,e.length);for(const t of e)i(t)}else{if(e&&"object"==typeof e){const t=e;for(const e of Object.keys(t).sort())i(e),i(t[e]);return}t=O_(t,-1)}else t=O_(t,e?1:0);else for(const i of e)t=O_(t,i.codePointAt(0)||0);else t=O_(t,e)};return i(e),t.toString(36)}({rooms:e.rooms,walls:t,openCuts:i,openings:n,partitions:e.partitions,roomDrafts:e.room_drafts,columns:e.wall_columns,cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,camera:b_,wallHeight:r,floorEdgeHeight:o,algorithm:3})}`;return{key:s,build:()=>{const o=ca(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e)).all,s=this._roomWallOpeningInputs(this._openingsR,e),a=t.length||o.length?Ns(e.rooms,t,i,s,this._wallKeyPitch,this._cellCm,this._gridPitch,hm,o):null;if(a&&("failed-core"===a.status||"not-applicable"===a.status))throw new Error("wall boolean geometry failed");const l=a?.paperGeom??Ps(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm);if(!l)throw new Error("floor boolean geometry failed");const c=a?.openingIndex||Bs(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm),h=n.map(e=>{const i=this._openingsR[e.sourceIndex],n="gate"===e.type?!e.flipV:e.flipV,o=i?.partitionHost?Od(i.partitionHost,n):t.length||"gate"===e.type?Vs(c,{x:e.x,y:e.y,angle:e.angle,length:e.length,flip_v:n}):{ox:0,oy:0,cm:0,side:-1};return function(e,t=64){if(!(z_([e.x,e.y,e.angle,e.length,e.face.ox,e.face.oy,t])&&e.length>0&&t>0))throw new Error("invalid isometric opening input");const i=e.length/2;let n;if("passage"===e.type)n=[];else if("gate"===e.type){const r=10*e.face.side;n=[F_(e,0,[-i,0],[i,0],r,0,.88*t),F_(e,1,[i,0],[-i,0],-r,0,.88*t)]}else n="window"===e.type?[F_(e,0,[-i,0],[i,0],-90,.27*t,.78*t),F_(e,1,[i,0],[-i,0],90,.27*t,.78*t)]:[F_(e,0,[-i,0],[e.length,0],-90,0,.92*t)];return{id:e.id,sourceIndex:e.sourceIndex,type:e.type,leaves:Object.freeze(n.map(e=>Object.freeze(e)))}}({...e,face:o},r)});return{walls:a?.components.flatMap(e=>e.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 e=this._isoSource();if(!e)return null;const t=this._isoGeometryCache.get(e.key);if(t)return{key:e.key,...t};const i=this._frameOf().rect,n=e.build(),r=xa(64,this._cellCm),o=xa(10,this._cellCm),s=function(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)for(const e of o.leaves){const o=Math.hypot(e.closedVector[0],e.closedVector[1]);t=Math.min(t,e.hinge[0]-o),i=Math.min(i,e.hinge[1]-o),n=Math.max(n,e.hinge[0]+o),r=Math.max(r,e.hinge[1]+o)}return z_([t,i,n,r])?{x:t,y:i,w:n-t,h:r-i}:null}(n.openings),a=S_({rect:s?um(i,s):i,wallHeight:r,openingHeight:r,floorDepth:o}),l=function(e,t=b_,i=64){if(!Number.isFinite(i)||i<0)throw new Error("invalid wall height");const n=[],r=[],o=[];let s=0;for(let a=0;a<(e||[]).length;a++){const l=e[a];for(let e=0;e<(l||[]).length;e++){const c=T_(l[e],e>0);if(!(c.length<3||Math.abs(R_(c))<1e-9)){n.push(C_(c,t,i)),s+=c.length;for(let n=0;ne.depth-t.depth||e.polygon-t.polygon||e.ring-t.ring||e.edge-t.edge),{topPath:n.join(" "),sides:r,contactPath:o.join(" "),edgeCount:s}}(n.walls,b_,r),c={geometry:l,floor:A_(n.floor,o),openings:n.openings,frame:a};return J_(this._isoGeometryCache,e.key,c,8),{key:e.key,...c}}_effectiveProjection(){if("iso"!==this._desiredProjection||!this._model.length)return"flat";const e=this._isoSceneKey()||`${this._space}|invalid`;if(this._isoFallback.has(e))return"flat";try{const e=this._isoScene();return e?(t="iso",i=e.key,n=this._isoFallback,"iso"===t&&i&&!n.has(i)?"iso":"flat"):"flat"}catch(t){if(!this._isoFallback.has(e)){this._isoFallback.add(e);const i=e.split("|");console.warn(`HOUSEPLAN ISO FALLBACK: #89, space ${this._space}, fingerprint ${i[i.length-1]}, ${t instanceof Error?t.message:"renderer error"}`)}return"flat"}var t,i,n}_scenePoint(e){return"iso"===this._renderProjection?k_(e,0):e}_floorView(e){if("iso"!==this._renderProjection)return e;const t=x_([e.x,e.y]),i=x_([e.x+e.w,e.y+e.h]);return{x:t[0],y:t[1],w:i[0]-t[0],h:i[1]-t[1]}}_baseVb(){if("iso"===this._effectiveProjection()){if(!this._spaceDisplayForRender().showBorders){const e=S_({rect:this._frameOf().rect,wallHeight:xa(64,this._cellCm)});return[e.x,e.y,e.w,e.h]}const e=this._isoScene()?.frame??this._frameOf().rect;return[e.x,e.y,e.w,e.h]}const e=this._frameOf().rect;return[e.x,e.y,e.w,e.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:B`
+ + ${this._t("canvas.far_objects",{n:this._outliers})} + +
`}_renderHomeArrow(){if(this._booting)return G;const e=this._view;if(!e||!e.w||!e.h)return G;const t=this._baseVb(),i=t[0],n=t[1],r=t[2],o=t[3];if(!(i+r<=e.x||i>=e.x+e.w||n+o<=e.y||n>=e.y+e.h))return G;const s=Math.atan2(n+o/2-(e.y+e.h/2),i+r/2-(e.x+e.w/2)),a=50+38*Math.cos(s),l=50+38*Math.sin(s);return B``}_stageAspect(){const e=this._stageEl,t=this._baseVb();return e&&e.clientHeight?e.clientWidth/e.clientHeight:t[2]/t[3]}_viewOr(e){return this._view&&this._view.w?this._view:Ri(e,this._stageAspect())}_roomLabelReferenceViewWidth(e){if(!this._markup)return e.w;const t=this._stageEl,i=this.renderRoot.querySelector(".editorchrome");if(!t||t.clientWidth<=0||t.clientHeight<=0)return e.w;const n=t.clientHeight+(i?.getBoundingClientRect().height||0);return n<=0?e.w:this._viewForModeTarget(this._zoom,void 0,void 0,t.clientWidth,n).w}_screenToVb(e,t){const i=this._stageEl,n=this._viewOr(this._baseVb()),r=i?.clientWidth||1,o=i?.clientHeight||1;return[n.x+e/r*n.w,n.y+t/o*n.h]}_clampView(e,t){const i=(e,t,i,n)=>{const r=1*Math.max(t,n),o=i-r,s=i+n-t+r;return Math.max(Math.min(o,s),Math.min(Math.max(o,s),e))};return{w:e.w,h:e.h,x:i(e.x,e.w,t.x,t.w),y:i(e.y,e.h,t.y,t.h)}}_applyView(e,t,i){const n=this._baseVb(),r=Ri(n,this._stageAspect()),o=Math.min(vm.ZOOM_MAX,Math.max(vm.ZOOM_MIN,e)),s=r.w/o,a=r.h/o,l=this._viewOr(n),c=t??l.x+l.w/2,h=i??l.y+l.h/2,d=this._clampView({x:c-s/2,y:h-a/2,w:s,h:a},r);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 e=()=>{if(!this._booting)return;const t=Date.now(),i=this._stageEl?this._stageEl.clientHeight:0;i!==this._bootLastH&&(this._bootLastH=i,this._bootLastChange=t);const n=t-this._bootStart;n>=1200||n>=700&&i>0&&t-this._bootLastChange>=250?this._bootSettled():this._bootTimer=window.setTimeout(e,100)};this._bootTimer=window.setTimeout(e,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 e=this._stageEl?.clientHeight??0;!this._config?.kiosk&&e>0&&this._warmPatch({hdrH:this._hdrH,stageH:e,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},Z_)}_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||this._warmModeRequest)return;const e=this._stageEl;if(!e||"visible"!==document.visibilityState||e.clientWidth<=0||e.clientHeight<=0)return void(this._viewportInvalidAt||(this._viewportInvalidAt=Date.now()));const t=[e.clientWidth,e.clientHeight],i=this._lastValidStageSize,n=!!i&&Math.abs(i[0]-t[0])<=.5&&Math.abs(i[1]-t[1])<=.5,r=this._viewportInvalidAt?Date.now()-this._viewportInvalidAt:0;if(this._viewportInvalidAt=0,!i)return this._lastValidStageSize=t,void(this._view||this._applyView(this._zoom));n?this._pendingRefitSize=null:(this._pendingRefitSize=t,this._refitRaf||(this._refitRaf=requestAnimationFrame(()=>{this._refitRaf=0;const e=this._pendingRefitSize;this._pendingRefitSize=null;const t=this._stageEl;if(!e||!t||t.clientWidth<=0||t.clientHeight<=0)return;if(Math.abs(t.clientWidth-e[0])>.5||Math.abs(t.clientHeight-e[1])>.5)return void this._refitView();const i=this._lastValidStageSize;if(i&&Math.abs(i[0]-e[0])<=.5&&Math.abs(i[1]-e[1])<=.5)return;this._lastValidStageSize=e;const n=this._view;r>=wl?this._beginContinuityCandidate("stage-size-restored",!0,"stage-size"):this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._applyView(this._zoom,n?n.x+n.w/2:void 0,n?n.y+n.h/2:void 0)})))}_zoomAt(e,t,i){const n=this._stageEl;if(!n)return;const r=Ri(this._baseVb(),this._stageAspect()),o=Math.min(vm.ZOOM_MAX,Math.max(vm.ZOOM_MIN,i));"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1));const s=n.clientWidth,a=n.clientHeight,l=this._screenToVb(e,t),c=r.w/o,h=r.h/o;this._zoom=o,this._view=this._clampView({x:l[0]-e/s*c,y:l[1]-t/a*h,w:c,h:h},r)}_onWheel(e){const t=this._stageEl;if(!t)return;e.preventDefault();const i=t.getBoundingClientRect(),n=e.deltaY<0?1.15:1/1.15;this._zoomAt(e.clientX-i.left,e.clientY-i.top,this._zoom*n),this._saveZoom()}_stepZoom(e){const t=this._stageEl;t&&(this._zoomAt(t.clientWidth/2,t.clientHeight/2,this._zoom*(e>0?1.4:1/1.4)),this._saveZoom())}_resetZoom(){const e=this._baseVb();"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=1,this._view=Ri(e,this._stageAspect()),this._saveZoom()}_saveZoom(){if("view"===this._mode){this._zoomBySpace={...this._zoomBySpace,[this._space]:this._zoom};try{localStorage.setItem(om,JSON.stringify(this._zoomBySpace))}catch{}}}_restoreZoom(){const e=this._zoomBySpace[this._space]||1;this._zoom=e;const t=this._stageEl;if(t&&t.clientHeight){const t=this._baseVb();return this._applyView(e,t[0]+t[2]/2,t[1]+t[3]/2),void this.requestUpdate()}this._view=null,requestAnimationFrame(()=>{if(!this._stageEl)return;const t=this._baseVb();this._applyView(e,t[0]+t[2]/2,t[1]+t[3]/2),this.requestUpdate()})}_stagePointerDown(e){if(this._vacFit)return;if(this._kiosk&&(this._cyclePausedUntil=Date.now()+6e4,0===this._pointers.size?(this._swipeStart={x:e.clientX,y:e.clientY,id:e.pointerId},e.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&&e.target.closest?.(".roomlabel, .rlhandle, .rszhandle, .dev, .oplock, .op-hit, button"))return;if("devices"===this._mode&&e.target.closest(".dev"))return;if("decor"===this._mode&&this._decorPointerDown(e))return;this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY});const t=this._viewOr(this._baseVb());if(1===this._pointers.size)this._panStart={sx:e.clientX,sy:e.clientY,vx:t.x,vy:t.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 e=[...this._pointers.values()],t=Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y);this._pinchStart={dist:t,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(e){if(this._physicalRotate?.pid!==e.pointerId)if(this._physicalDrag?.pid!==e.pointerId)if(this._dtDrag?.pid!==e.pointerId)if(this._bdDrag?.pid!==e.pointerId){if(this._decorDraft?.pid===e.pointerId){const t=this._decorDraft;let i=this._decorSnap(this._svgPoint(e),e.pointerType);if(e.shiftKey&&("rect"===t.kind||"ellipse"===t.kind)){const e=i[0]-t.a[0],n=i[1]-t.a[1],r=Math.max(Math.abs(e),Math.abs(n));i=this._snap([t.a[0]+(e<0?-r:r),t.a[1]+(n<0?-r:r)])}return void(this._decorDraft={...t,b:i})}if(this._decorMove?.pid!==e.pointerId)if(this._pointers.has(e.pointerId)){if(this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY}),this._markup&&1===this._pointers.size&&this._markupMove(e),this._pinchStart&&this._pointers.size>=2){"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const e=[...this._pointers.values()],t=Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y)/(this._pinchStart.dist||1),i=this._stageEl.getBoundingClientRect(),n=(e[0].x+e[1].x)/2-i.left,r=(e[0].y+e[1].y)/2-i.top;this._zoomAt(n,r,this._pinchStart.zoom*t),this._suppressClick=!0,this._saveZoom()}else if(this._panStart){const t=e.clientX-this._panStart.sx,i=e.clientY-this._panStart.sy;Math.abs(t)+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(t)+Math.abs(i)>8&&(this._panLock=this._swipeZone&&Math.abs(t)>1.5*Math.abs(i)?"swipe":"pan");const n=this._stageEl;if("pan"===this._panLock&&n){const e=this._baseVb(),r=this._viewOr(e),o=Ri(e,this._stageAspect());this._view=this._clampView({x:this._panStart.vx-t/(n.clientWidth||1)*r.w,y:this._panStart.vy-i/(n.clientHeight||1)*r.h,w:r.w,h:r.h},o)}}}else this._markupMove(e);else this._decorMoveUpdate(e)}else this._bdMove(e);else this._dtMove(e);else this._physicalMove(e);else this._physicalRotateMove(e)}_stagePointerLeave(e){this._markup&&("opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover())}_stagePointerUp(e){if(this._kiosk){clearTimeout(this._kioskHoldTimer);const t=this._swipeStart;if(this._swipeStart=null,t&&t.id===e.pointerId){const i=e.clientX-t.x,n=e.clientY-t.y;if(Math.abs(i)+Math.abs(n)<8){const e=Date.now();e-this._lastTap<350&&this._resetZoom(),this._lastTap=e}const r="pan"===this._panLock?null:function(e,t,i,n,r,o=60){if(i>1.001||n.length<2)return null;if(Math.abs(e)e.id),this._space);r&&this._slideTo(r,i<0?"left":"right")&&(this._saveNav(),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._showKioskDots())}}if(this._physicalDrag?.pid===e.pointerId)return void this._physicalUp(e);if(this._physicalRotate?.pid===e.pointerId)return void this._physicalRotateUp(e);if(this._dtDrag?.pid===e.pointerId)return void this._dtUp();if(this._bdDrag?.pid===e.pointerId)return void this._bdUp();if(this._decorDraft?.pid===e.pointerId)return void this._decorCommitDraft();if(this._decorMove?.pid===e.pointerId)return this._decorMove.moved&&(this._recordGeometry(this._t("history.decor_move"),this._decorMove.before),this._saveConfig()),void(this._decorMove=null);const t=!!this._pinchStart||!!this._panStart;this._pointers.delete(e.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null,setTimeout(()=>this._suppressClick=!1,0)),t&&0===this._pointers.size&&this.requestUpdate()}_clickRoom(e){!this._suppressClick&&e.area&&mm("/config/areas/area/"+e.area)}_pointerDown(e,t){if("plan"===this._mode)return;if("view"===this._mode){this._holdFired=!1,clearTimeout(this._holdTimer);const i=e.pointerId,n=e.currentTarget;return void(this._holdTimer=window.setTimeout(()=>{this._holdFired=!0,this._interruptViewGesture(i,n),this._infoCard=t},600))}if("ha_disabled"===t.bindingStatus?.kind)return;e.preventDefault();const i=this._pos(t);this._drag={id:t.id,sx:e.clientX,sy:e.clientY,ox:i.x,oy:i.y,moved:!1},fm(e),this._tip=null}_pointerMove(e,t){if(!this._drag||this._drag.id!==t.id)return;const i=this.renderRoot.querySelector(".stage");if(!i)return;const n=this._baseVb(),r=i.getBoundingClientRect(),o=this._viewOr(n),s=(e.clientX-this._drag.sx)/r.width*o.w,a=(e.clientY-this._drag.sy)/r.height*o.h;Math.abs(e.clientX-this._drag.sx)+Math.abs(e.clientY-this._drag.sy)>3&&(this._drag.moved=!0,clearTimeout(this._holdTimer));const l=qa(this._drag.ox+s),c=qa(this._drag.oy+a);this._savePos(t,l,c)}_pointerUp(e,t){if(clearTimeout(this._holdTimer),!this._drag||this._drag.id!==t.id)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&(this._selId=t.id,window.setTimeout(()=>this._drag=null,0))}_showToast(e){for(const e of this.renderRoot.querySelectorAll("hp-dialog"))e.closeTransientOverlays("toast");this._toast=e,clearTimeout(this._toastTimer),this._toastTimer=window.setTimeout(()=>{this._toast=""},3500)}_syncPointerHoverTargets(){const e=this._pointerModality.hoverEnabled;for(const t of this.renderRoot.querySelectorAll(cm))t.toggleAttribute("data-pointer-hover",e)}_syncPointerHoverSubtree(e){if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e,i=this._pointerModality.hoverEnabled;t.matches(cm)&&t.toggleAttribute("data-pointer-hover",i);for(const e of t.querySelectorAll(cm))e.toggleAttribute("data-pointer-hover",i)}_clearTransientHover(e=!1){e&&this._pointerModality.suspend(),this._tip&&(this._tip=null),this._hoverRoom&&(this._hoverRoom=null)}_notePointer(e){const t=this._pointerModality.modality,i=this._pointerModality.note(e);"touch"!==i&&"pen"!==i||t===i&&!this._tip&&!this._hoverRoom||this._clearTransientHover()}_guardTouchGesture(e){if(this._editorSecondary?.handleOutsideDismiss(e))return;if("click"===e.type){if(!this._suppressClick&&!this._touchSequenceMultitouch&&Date.now()>this._touchClickBlockUntil)return;return e.preventDefault(),void e.stopImmediatePropagation()}const t=e;if(this._notePointer(t),"touch"===t.pointerType)if("pointerdown"!==e.type){if("pointermove"===e.type){const e=this._touchContacts.get(t.pointerId);if(!e)return;const i={...e,x:t.clientX,y:t.clientY};if(this._touchContacts.set(t.pointerId,i),this._touchSequenceMultitouch&&"view"===this._mode&&!this._vacFit&&this._pinchStart&&[...this._touchContacts.values()].every(e=>e.inStage)){this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY});const e=[...this._touchContacts.values()];if(e.length>=2&&this._stageEl){const[t,i]=e,n=Math.hypot(t.x-i.x,t.y-i.y)/(this._pinchStart.dist||1),r=this._stageEl.getBoundingClientRect();this._zoomAt((t.x+i.x)/2-r.left,(t.y+i.y)/2-r.top,this._pinchStart.zoom*n),this._saveZoom()}}return}if("pointerup"===e.type||"pointercancel"===e.type||"lostpointercapture"===e.type){if(this._clearTransientHover(),this._touchContacts.delete(t.pointerId),this._touchSequenceMultitouch){if(this._touchClickBlockUntil=Date.now()+500,this._pointers.delete(t.pointerId),!this._vacFit&&this._pointers.size>=2){const[e,t]=[...this._pointers.values()];this._pinchStart={dist:Math.hypot(e.x-t.x,e.y-t.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(t.pointerId,{x:t.clientX,y:t.clientY,inStage:!!t.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 e=[...this._touchContacts.values()];if("view"===this._mode&&!this._vacFit&&e.every(e=>e.inStage)){this._pointers=new Map([...this._touchContacts].map(([e,t])=>[e,{x:t.x,y:t.y}]));const[t,i]=e;this._pinchStart={dist:Math.hypot(t.x-i.x,t.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(e,t,i,n,r,o){this._notePointer(e),this._pointerModality.hoverEnabled&&(this._drag||(this._tip={x:e.clientX,y:e.clientY,title:t,meta:i,lqi:n,temp:r,hum:o}))}get _gridPitch(){return Ea}get _cellCm(){const e=Number(this._curSpaceCfg?.cell_cm);return Number.isFinite(e)&&e>0?e:5}_fmtLen(e,t){const i=function(e,t,i,n){return Math.hypot(t[0]-e[0],t[1]-e[1])/i*n}(e,t,this._gridPitch,this._cellCm);return Kt(i,"mi"===this.hass?.config?.unit_system?.length)}get _curSpaceCfg(){const e=this._resize?.preview;return e&&e.space===this._space?e.sp:this._serverCfg?.spaces.find(e=>e.id===this._space)}get _renderCfg(){const e=this._resize?.preview;return e&&this._serverCfg?{...this._serverCfg,spaces:this._serverCfg.spaces.map(t=>t.id===e.space?e.sp:t)}:this._serverCfg}get _spaceH(){return this._curSpaceCfg,hm}get _segments(){const e=this._curSpaceCfg,t=this._spaceH;return Jt(e?.rooms||[]).map(e=>[e[0]*hm,e[1]*t,e[2]*hm,e[3]*t])}_savedNav(){if(this._hasFixedFloor)return null;try{return JSON.parse(localStorage.getItem(sm)||"null")}catch{return null}}_saveNav(){if(!this._hasFixedFloor)try{localStorage.setItem(sm,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._deviceInbox=null,this._deviceInboxReturn=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 e=this._warmSlot;e?.owner===this._warmGen&&(e.vp=this._warmViewportState(),e.dlg=null,e.frameFingerprint="",clearTimeout(e.evict),e.evict=0),this._saveNav()}_setMode(e,t=!0){return this._warmModeRequest=0,this._editorRuntime?this._editorRuntime._setMode(e,t):"view"===e?void this._editorModeRequest++:void this._requestMode(e,t)}_primeDrawWallField(){return this._editorRuntimeOrThrow()._primeDrawWallField()}get _drawWallFieldValue(){return null===this._drawWallField?fo(15,this._imperial):this._drawWallField}get _drawWallCm(){const e=(e=>{const t=String(e??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(t))return null;const i=Number(t);return Number.isFinite(i)?i:null})(this._drawWallFieldValue);if(null==e||e<0)return null;const t=this._imperial?2.54*e:e,i="column"===this._tool?Xs:100;return t>=("column"===this._tool?1:0)&&t<=i?t:null}get _drawWallMaxCm(){return"column"===this._tool?Xs:100}_showPhysicalRange(e=this._drawWallMaxCm,t=0){return this._editorRuntimeOrThrow()._showPhysicalRange(e,t)}_draftSegmentCount(e=this._curSpaceCfg){return this._editorRuntimeOrThrow()._draftSegmentCount(e)}_mergeSpacePartitions(e,t){return this._editorRuntimeOrThrow()._mergeSpacePartitions(e,t)}_finishWallChain(){return this._editorRuntimeOrThrow()._finishWallChain()}_activateMarkupTool(e){return this._editorRuntimeOrThrow()._activateMarkupTool(e)}_limitReached(e){return this._editorRuntimeOrThrow()._limitReached(e)}_svgPoint(e){return this._editorRuntimeOrThrow()._svgPoint(e)}_snap(e){return this._editorRuntimeOrThrow()._snap(e)}_snapDrawPoint(e,t=!1){return this._editorRuntimeOrThrow()._snapDrawPoint(e,t)}_planSnapOpeningCuts(e,t){return this._editorRuntimeOrThrow()._planSnapOpeningCuts(e,t)}_planSnapGeometrySnapshot(){return this._editorRuntimeOrThrow()._planSnapGeometrySnapshot()}_hiddenWallDiagnosticSnapshot(){return this._editorRuntimeOrThrow()._hiddenWallDiagnosticSnapshot()}_planStructuralGeometrySnapshot(){return this._editorRuntimeOrThrow()._planStructuralGeometrySnapshot()}_planSnapContextKey(e){return this._editorRuntimeOrThrow()._planSnapContextKey(e)}_resolvePlanDrawPoint(e,t){return this._editorRuntimeOrThrow()._resolvePlanDrawPoint(e,t)}get _activePlanSnapCandidate(){if(!this._markup||"draw"!==this._tool)return null;const e=this._planSnapHover;if(!e)return null;const t=this._planSnapGeometrySnapshot();return e.contextKey===this._planSnapContextKey(t.key)?e.candidate:null}get _activePlanSnapConflicts(){if(!this._markup||"draw"!==this._tool)return[];const e=this._planSnapHover;if(!e)return[];const t=this._planSnapGeometrySnapshot();return e.contextKey===this._planSnapContextKey(t.key)?e.conflicts:[]}_clearPlanSnapHover(e=!0){return this._editorRuntime?this._editorRuntimeOrThrow()._clearPlanSnapHover(e):(this._planSnapHover=null,void(e&&(this._cursorPt=null)))}_samePt(e,t){return oi(e,t)}_dropLegacySegments(){return this._editorRuntimeOrThrow()._dropLegacySegments()}_rollbackRejectedPhysicalWrites(e){return this._editorRuntimeOrThrow()._rollbackRejectedPhysicalWrites(e)}async _reloadRejectedPhysicalWrite(){return this._editorRuntimeOrThrow()._reloadRejectedPhysicalWrite()}get _cfgWriting(){return this._writesPending>0}async _sendConfigCandidate(e){const t=so(e),i=await this.hass.callWS({type:"houseplan/config/set",config:t,expected_rev:this._cfgRev});this._cfgRev=i?.rev??this._cfgRev+1}_writeConfig(){if(this._editorRuntime)return this._editorRuntime._writeConfig();this._writesPending++,this._writeChain=Lp(this._writeChain,async()=>{if(!this._serverCfg)return;const e=so(this._serverCfg),t=Rl(e);t!==Rl(this._serverCfg)&&(this._serverCfg=e),this._cfgContentFingerprint=t,await this._sendConfigCandidate(e)});return this._writeChain.finally(()=>{this._writesPending--})}_saveConfig(){this._cfgEpoch++,this._saveConfigDebounced()}_geometrySnapshotFromConfig(e,t){return this._editorRuntimeOrThrow()._geometrySnapshotFromConfig(e,t)}_geometrySnapshot(e=this._space){return this._editorRuntimeOrThrow()._geometrySnapshot(e)}_recordGeometry(e,t){return this._editorRuntimeOrThrow()._recordGeometry(e,t)}_restoreGeometryStateInConfig(e,t,i=!1){return this._editorRuntimeOrThrow()._restoreGeometryStateInConfig(e,t,i)}_restoreGeometryStateLocal(e){return this._editorRuntimeOrThrow()._restoreGeometryStateLocal(e)}_wallModelBlockerLabel(e){return this._editorRuntimeOrThrow()._wallModelBlockerLabel(e)}_hasLegacyZeroWallFields(e=this._serverCfg){return this._editorRuntimeOrThrow()._hasLegacyZeroWallFields(e)}_showWallModelMigrationBlocked(e){return this._editorRuntimeOrThrow()._showWallModelMigrationBlocked(e)}_limitSegmentsOf(e){return this._editorRuntimeOrThrow()._limitSegmentsOf(e)}_junctionLimitViolations(e,t,i){return this._editorRuntimeOrThrow()._junctionLimitViolations(e,t,i)}_junctionLimitLabel(e){return this._editorRuntimeOrThrow()._junctionLimitLabel(e)}_junctionLimitsIntroduced(e,t,i){return this._editorRuntimeOrThrow()._junctionLimitsIntroduced(e,t,i)}_commitPhysicalGeometry(e,t,i=[]){return this._editorRuntimeOrThrow()._commitPhysicalGeometry(e,t,i)}_clearGeometryGesture(){return this._editorRuntime?this._editorRuntimeOrThrow()._clearGeometryGesture():(this._path=[],this._planSnapHover=null,this._cursorPt=null,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingPreset=null,this._openingRebindId=null,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._resize?.reset(),this._decorDraft=null,this._decorMove=null,this._dtDrag=null,void(this._bdDrag=null))}_stagePointerCancel(e){if(this._editorRuntime)return this._editorRuntime._stagePointerCancel(e)}_applyGeometryState(e,t=!1){return this._editorRuntimeOrThrow()._applyGeometryState(e,t)}_roomAt(e){return this._editorRuntimeOrThrow()._roomAt(e)}_overlapRoom(e){return this._editorRuntimeOrThrow()._overlapRoom(e)}_pointInRoom(e,t){return t.poly?si(e,t.poly):null!=t.x&&e[0]>=t.x&&e[0]<=t.x+t.w&&e[1]>=t.y&&e[1]<=t.y+t.h}_contourSelfIntersects(e){return this._editorRuntimeOrThrow()._contourSelfIntersects(e)}_canAppendRoomDraftPoint(){return this._editorRuntimeOrThrow()._canAppendRoomDraftPoint()}_markupClick(e){if(this._editorRuntime)return this._editorRuntime._markupClick(e)}_draftEndAt(e,t){return this._editorRuntimeOrThrow()._draftEndAt(e,t)}_mergeDraftEndpoint(e){return this._editorRuntimeOrThrow()._mergeDraftEndpoint(e)}_adoptDraftCms(e,t,i){return this._editorRuntimeOrThrow()._adoptDraftCms(e,t,i)}_draftSegmentsForPath(e,t,i){return this._editorRuntimeOrThrow()._draftSegmentsForPath(e,t,i)}_persistActiveDraftSegment(){return this._editorRuntimeOrThrow()._persistActiveDraftSegment()}_activeWallSourceKey(e){return this._editorRuntimeOrThrow()._activeWallSourceKey(e)}_wallGraphSources(e){return this._editorRuntimeOrThrow()._wallGraphSources(e)}_wallFaceGraph(e,t){return this._editorRuntimeOrThrow()._wallFaceGraph(e,t)}_offerWallFaces(e,t=this._path.length-2,i){return this._editorRuntimeOrThrow()._offerWallFaces(e,t,i)}_beginWallFaceBatch(e){return this._editorRuntimeOrThrow()._beginWallFaceBatch(e)}_offerExistingWallFace(e){return this._editorRuntimeOrThrow()._offerExistingWallFace(e)}_columnClick(e){return this._editorRuntimeOrThrow()._columnClick(e)}_openPhysicalDialog(e,t,i){return this._editorRuntimeOrThrow()._openPhysicalDialog(e,t,i)}_physicalDown(e,t,i){return this._editorRuntimeOrThrow()._physicalDown(e,t,i)}_clampPhysicalDelta(e,t,i){return this._editorRuntimeOrThrow()._clampPhysicalDelta(e,t,i)}_physicalMove(e){return this._editorRuntimeOrThrow()._physicalMove(e)}_physicalUp(e){return this._editorRuntimeOrThrow()._physicalUp(e)}_registerPhysicalTap(e,t,i){return this._editorRuntimeOrThrow()._registerPhysicalTap(e,t,i)}_cancelPhysicalGesture(){return this._editorRuntimeOrThrow()._cancelPhysicalGesture()}_physicalRotateDown(e,t){return this._editorRuntimeOrThrow()._physicalRotateDown(e,t)}_physicalRotateMove(e){return this._editorRuntimeOrThrow()._physicalRotateMove(e)}_physicalRotateUp(e){return this._editorRuntimeOrThrow()._physicalRotateUp(e)}_rszRooms(){return this._editorRuntimeOrThrow()._rszRooms()}_rszOpenings(){return this._editorRuntimeOrThrow()._rszOpenings()}_rszObstacles(){return this._editorRuntimeOrThrow()._rszObstacles()}_rszOptsFor(e,t){return this._editorRuntimeOrThrow()._rszOptsFor(e,t)}_rszResolution(e,t,i){return this._editorRuntimeOrThrow()._rszResolution(e,t,i)}_rszSnapshot(){return this._editorRuntimeOrThrow()._rszSnapshot()}_rszResetController(){return this._editorRuntimeOrThrow()._rszResetController()}_rszProjectPreview(e,t,i,n,r){return this._editorRuntimeOrThrow()._rszProjectPreview(e,t,i,n,r)}_rszAcceptPreview(e,t){return this._editorRuntimeOrThrow()._rszAcceptPreview(e,t)}_rszSpaceCandidateGeometry(e,t){return this._editorRuntimeOrThrow()._rszSpaceCandidateGeometry(e,t)}_rszSpaceCandidateRenderable(e,t){return this._editorRuntimeOrThrow()._rszSpaceCandidateRenderable(e,t)}_rszCandidateRenderable(e){return this._editorRuntimeOrThrow()._rszCandidateRenderable(e)}_rszEdgeDown(e,t,i){return this._editorRuntimeOrThrow()._rszEdgeDown(e,t,i)}_rszReasonText(e){return this._editorRuntimeOrThrow()._rszReasonText(e)}_rszDisabledActivate(e,t){return this._editorRuntimeOrThrow()._rszDisabledActivate(e,t)}_rszDisabledKey(e,t){return this._editorRuntimeOrThrow()._rszDisabledKey(e,t)}_rszMove(e){return this._editorRuntimeOrThrow()._rszMove(e)}_rszUp(e){return this._editorRuntimeOrThrow()._rszUp(e)}_rszCancelDrag(e){return this._editorRuntimeOrThrow()._rszCancelDrag(e)}_rszPointerCancel(e){return this._editorRuntimeOrThrow()._rszPointerCancel(e)}_rszEdgeLabels(e,t,i=this._resize?.rooms){return this._editorRuntimeOrThrow()._rszEdgeLabels(e,t,i)}_rszInnerSpanCms(e,t,i){return this._editorRuntimeOrThrow()._rszInnerSpanCms(e,t,i)}_renderResizeMeasurements(){return this._editorRuntimeOrThrow()._renderResizeMeasurements()}_renderResizeLayer(e){return this._editorRuntimeOrThrow()._renderResizeLayer(e)}get _openingsR(){const e=this._curSpaceCfg,t=this._spaceH,i=this._spaceModel();return i?(e?.openings||[]).flatMap(e=>{const n={...e,rx:e.x*hm,ry:e.y*t,rlen:e.length*hm};if(!e.host||"wall"===e.host.kind)return[n];const r=Td(e,i.partitions,hm,this._cellCm,this._gridPitch);if(!r.resolved)return"plan"===this._mode?[{...n,orphanReason:r.reason||"invalid-host"}]:[];let[o,s]=r.resolved.center;const a=this._physicalDrag;return a?.moved&&"partition"===a.kind&&a.id===e.host.id&&(o+=a.delta[0],s+=a.delta[1]),[{...e,rx:o,ry:s,rlen:r.resolved.length,angle:r.resolved.angle,partitionHost:r.resolved}]}):[]}_partitionOpeningCuts(e=this._spaceModel(),t=()=>!0){if(!e)return[];return Fp(Pp(this._curSpaceCfg?.id===e.id?this._curSpaceCfg:null,e,this._cellCm,this._gridPitch,hm),t)}_roomWallOpeningInputs(e=this._openingsR,t=this._spaceModel()){if(!t)return[];const i=this._openCuts();return Ip(e,t,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm)}_openingFace(e,t,i){return e.partitionHost?Od(e.partitionHost,i):Vs(t,{x:e.rx,y:e.ry,angle:e.angle,length:e.rlen,flip_v:i})}_cmToUnits(e){return e/this._cellCm*this._gridPitch}get _decorList(){const e=this._curSpaceCfg;return Array.isArray(e?.decor)?e.decor:[]}get _decorH(){return hm}_decorResolvedStyle(e){return function(e,t,i,n=ur){const r="rect"===e?.kind||"ellipse"===e?.kind,o=e,s=qt(o?.color,n.color);return{color:s,opacity:pr(o?.opacity,n.opacity),widthCm:yr(e,t,i,n.widthCm),fill:!!r&&!0===o?.fill,fillColor:qt(o?.fill_color,o?.fill?s:n.fillColor),fillOpacity:r&&o?.fill?pr(o?.fill_opacity,.25):n.fillOpacity}}(e,this._cellCm,this._gridPitch,ur)}_decorWidthUnits(e){return((e,t,i,n=ur.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return fr(r,t,i);const o=Number(e?.width);return Number.isFinite(o)&&o>0?o:fr(n,t,i)})(e,this._cellCm,this._gridPitch,ur.widthCm)}_decorTextSizeCm(e){if("text"===e?.kind){const t=Number(e.size_cm);return Number.isFinite(t)&&t>0?t:vr(20*Gi(e),this._cellCm,this._gridPitch)}return vr(20,this._cellCm,this._gridPitch)}_decorTextUnits(e){if("text"!==e.kind)return 20;const t=Number(e.size_cm);return Number.isFinite(t)&&t>0?fr(t,this._cellCm,this._gridPitch):20*Gi(e)}_decorSmallField(e){return Math.round(100*(this._imperial?e/2.54:e))/100}_decorSmallCm(e){const t=this._imperial?2.54*e:e;return Number.isFinite(t)?Math.max(.1,Math.min(100,t)):.1}_decorTextCm(e){const t=this._imperial?2.54*e:e;return Number.isFinite(t)?Math.max(.1,Math.min(2e3,t)):.1}_decorLargeField(e){return Math.round(100*(this._imperial?e/30.48:e/100))/100}_decorLargeCm(e){const t=this._imperial?30.48*e:100*e;return Number.isFinite(t)?Math.max(.1,Math.min(Pa*this._cellCm,t)):.1}_angleField(e){const t=Number(e);return Number.isFinite(t)?String(Number(t.toFixed(3))):"0"}_decorBoxOf(e){return"rect"!==e.kind&&"ellipse"!==e.kind&&"furniture"!==e.kind?null:{x:e.x*hm,y:e.y*this._decorH,w:e.w*hm,h:e.h*this._decorH,angle:_r(e.angle)||void 0}}_decorSnapGeometry(e){return this._editorRuntimeOrThrow()._decorSnapGeometry(e)}_decorSnap(e,t="mouse",i){return this._editorRuntimeOrThrow()._decorSnap(e,t,i)}_replaceDecor(e,t){return this._editorRuntimeOrThrow()._replaceDecor(e,t)}_cancelDecorGesture(){return this._editorRuntimeOrThrow()._cancelDecorGesture()}_decorPointerDown(e){return this._editorRuntimeOrThrow()._decorPointerDown(e)}_decorCommitDraft(){return this._editorRuntimeOrThrow()._decorCommitDraft()}_decorShapeDown(e,t){return this._editorRuntimeOrThrow()._decorShapeDown(e,t)}_decorMoveUpdate(e){return this._editorRuntimeOrThrow()._decorMoveUpdate(e)}_decorShapeDbl(e,t){if(this._editorRuntime)return this._editorRuntime._decorShapeDbl(e,t)}_openDecorProperties(e){return this._editorRuntimeOrThrow()._openDecorProperties(e)}_decorOpenText(e){return this._editorRuntimeOrThrow()._decorOpenText(e)}_decorRememberTextSelection(e){return this._editorRuntimeOrThrow()._decorRememberTextSelection(e)}_decorInsertLiveVariable(e){return this._editorRuntimeOrThrow()._decorInsertLiveVariable(e)}_decorSaveText(){return this._editorRuntimeOrThrow()._decorSaveText()}_decorSaveShape(){return this._editorRuntimeOrThrow()._decorSaveShape()}get _dtSel(){return"decor"===this._mode&&"select"===this._decorTool&&this._decorSel&&this._decorList.find(e=>e.id===this._decorSel)||null}_dtPivot(e){return this._editorRuntimeOrThrow()._dtPivot(e)}_dtApply(e,t){return this._editorRuntimeOrThrow()._dtApply(e,t)}_dtStart(e,t,i,n){return this._editorRuntimeOrThrow()._dtStart(e,t,i,n)}_dtMove(e){return this._editorRuntimeOrThrow()._dtMove(e)}_dtUp(){return this._editorRuntimeOrThrow()._dtUp()}_dtMeasure(){return this._editorRuntimeOrThrow()._dtMeasure()}_deleteDecor(e){return this._editorRuntimeOrThrow()._deleteDecor(e)}_decorDeleteSel(){return this._editorRuntimeOrThrow()._decorDeleteSel()}_confirmDecorErase(){return this._editorRuntimeOrThrow()._confirmDecorErase()}get _furnWalls(){const e=this._rawPhysicalBodiesR().flatMap(e=>e.map((t,i)=>{const n=e[(i+1)%e.length];return[t[0],t[1],n[0],n[1]]}));return[...this._segments,...e]}get _furnWallReach(){return 6*this._gridPitch}_furnFieldValue(e){return this._editorRuntimeOrThrow()._furnFieldValue(e)}_furnFieldToCm(e){return this._editorRuntimeOrThrow()._furnFieldToCm(e)}_furnPick(e){return this._editorRuntimeOrThrow()._furnPick(e)}_furnPlace(e,t=!1){return this._editorRuntimeOrThrow()._furnPlace(e,t)}_furnMoveUpdate(e){return this._editorRuntimeOrThrow()._furnMoveUpdate(e)}_decorApplyBox(e,t){return this._editorRuntimeOrThrow()._decorApplyBox(e,t)}get _furnLive(){const e=this._dtDrag;if(!e||"scale"!==e.kind||!e.orig)return null;const t=this._decorList.find(t=>t.id===e.id);if(!t||"furniture"!==t.kind)return null;const i=hm,n=this._decorH,r=t.w*i,o=t.h*n,s=function(e,t,i,n,r){const o=e+i/2,s=t+n/2,a=(Number(r)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(e,t)=>{const i=e-o,n=t-s;return[o+i*l-n*c,s+i*c+n*l]};return[h(e,t),h(e+i,t),h(e+i,t+n),h(e,t+n)]}(t.x*i,t.y*n,r,o,Number(t.angle)||0),a=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],l=a(s[0],s[1]),c=a(s[0],s[3]);return[{x:l[0],y:l[1],text:this._fmtLen([0,0],[r,0])},{x:c[0],y:c[1],text:this._fmtLen([0,0],[0,o])}]}_renderFurnPalette(){return this._editorRuntimeOrThrow()._renderFurnPalette()}get _bdBase(){const e=this._curSpaceCfg;return e?.plan_url?{...Ta(e.plan_aspect,hm)}:null}get _bdRect(){const e=this._curSpaceCfg;return e?.plan_url?Aa(e,hm):null}get _bdParams(){const e=this._curSpaceCfg,t=Number(e?.plan_x),i=Number(e?.plan_y),n=Number(e?.plan_scale),r=Number(e?.plan_scale_x),o=Number(e?.plan_scale_y),s=Number.isFinite(n)&&n>0?n:1;return{dx:Number.isFinite(t)?t:0,dy:Number.isFinite(i)?i:0,sx:Number.isFinite(r)&&r>0?r:s,sy:Number.isFinite(o)&&o>0?o:s,angle:_r(e?.plan_angle)}}_openBackdropDialog(e){if(this._editorRuntime)return this._editorRuntime._openBackdropDialog(e)}_saveBackdropDialog(){return this._editorRuntimeOrThrow()._saveBackdropDialog()}get _bdActive(){return"decor"===this._mode&&!!this._bdRect&&"backdrop"===this._decorTool}get _bdMovable(){return"decor"===this._mode&&"backdrop"===this._decorTool&&!!this._bdRect}_bdApply(e,t,i,n,r){return this._editorRuntimeOrThrow()._bdApply(e,t,i,n,r)}_bdStart(e,t,i=!1){return this._editorRuntimeOrThrow()._bdStart(e,t,i)}_bdMove(e){return this._editorRuntimeOrThrow()._bdMove(e)}get _bdMoved(){if("decor"!==this._mode||!this._bdRect)return!1;const e=this._bdParams;return 0!==e.dx||0!==e.dy||1!==e.sx||1!==e.sy||0!==e.angle}_bdReset(){return this._editorRuntimeOrThrow()._bdReset()}_bdUp(){return this._editorRuntimeOrThrow()._bdUp()}get _bdLive(){if(!this._bdDrag)return null;const e=this._bdRect;return e?{x:e.x+e.w/2,y:e.y+e.h/2,text:`${this._fmtLen([0,0],[e.w,0])} × ${this._fmtLen([0,0],[0,e.h])}`}:null}_renderBackdropFrame(e){return this._editorRuntime?this._editorRuntimeOrThrow()._renderBackdropFrame(e):G}_renderTextFrame(e){const t=this._dtSel,i=this._dtBox;if(!t||!i||i.id!==t.id)return G;const n=.018*Math.max(e.w,e.h),r=n/4;if("line"===t.kind){const e=[t.x1*hm,t.y1*this._decorH],i=[t.x2*hm,t.y2*this._decorH];return W` + + ${[e,i].map((e,t)=>W`this._dtStart(e,"scale",void 0,t)}> + `)} + `}const[o,s]=this._dtPivot(t),a=Number(t.angle)||0,l=2.2*n;return W` + + + this._dtStart(e,"rotate")}> + + ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([e,t,o])=>W`this._dtStart(i,"scale",[e,t])}>`)} + `}_renderDecorLayer(){const e=hm,t=this._decorH,i="decor"===this._mode,n=i&&"erase"===this._decorTool,r=this._decorList.map(r=>{const o="dshape"+(i&&this._decorSel===r.id?" dsel":""),s=this._decorResolvedStyle(r),a=this._decorWidthUnits(r),l=e=>this._decorShapeDown(e,r),c=e=>this._decorShapeDbl(e,r);if("line"===r.kind)return W` + ${i&&"select"===this._decorTool?W``:G} + ${n?W``:G}`;if("rect"===r.kind){const i=(r.x+r.w/2)*e,h=(r.y+r.h/2)*t,d=_r(r.angle);return W` + ${n?W``:G}`}if("ellipse"===r.kind){const i=(r.x+r.w/2)*e,h=(r.y+r.h/2)*t,d=_r(r.angle);return W` + ${n?W``:G}`}if("furniture"===r.kind){const i=r.w*e,h=r.h*t,d=vl(r.symbol,i,h);if(!d)return G;const u=Number(r.angle)||0,p=r.x*e+i/2,_=r.y*t+h/2,m=`${u?`rotate(${u} ${p} ${_}) `:""}translate(${r.x*e} ${r.y*t})`;return W` + ${n?W``:G}`}if("text"===r.kind){const i=this._decorTextUnits(r),n=this._renderDeviceSnapshot?.facts.get(`decor:${this._space}:${r.id}`),a=function(e){return String(e??"").replace(/\r\n?/g,"\n").split("\n")}("string"==typeof n?n:Wi(r.text,r,this._renderPlanHass,e=>this._renderEntityAvailable(e))),h=r.x*e,d=r.y*t,u=Number(r.angle)||0,p=d-(a.length-1)*i*1.2/2;return W`${a.map((e,t)=>W`${e}`)}`}return G});let o=G;const s=this._decorDraft;if(s){const e=this._decorStyle,t=fr(e.widthCm,this._cellCm,this._gridPitch);if("line"===s.kind)o=W``;else{const i=Math.min(s.a[0],s.b[0]),n=Math.min(s.a[1],s.b[1]),r=Math.abs(s.b[0]-s.a[0]),a=Math.abs(s.b[1]-s.a[1]);o="rect"===s.kind?W``:W``}}return W`${r}${o}`}get _editorToolbarGroups(){return"plan"!==this._mode?[]:[{id:"opening",label:this._t("markup.opening"),icon:"mdi:door",activeItemId:"opening"===this._tool?this._openingPreset?.type:void 0,items:[{id:"window",label:this._t("opening.window"),icon:"mdi:window-closed-variant",role:"tool",invoke:()=>this._activateOpeningPlacement("window")},{id:"door",label:this._t("opening.door"),icon:"mdi:door-open",role:"tool",invoke:()=>this._activateOpeningPlacement("door")},{id:"passage",label:this._t("opening.passage"),icon:"mdi:arch",role:"tool",invoke:()=>this._activateOpeningPlacement("passage")},{id:"gate",label:this._t("opening.gate"),icon:"mdi:gate",role:"tool",invoke:()=>this._activateOpeningPlacement("gate")}]}]}_renderEditorGroupLauncher(e){return this._editorRuntimeOrThrow()._renderEditorGroupLauncher(e)}get _editorSecondaryContextId(){const e=`editor:${this._mode}:${this._space}:${this._cfgEpoch}`,t=this._editorSecondary?.activeGroup(this._editorToolbarGroups);if(t)return`${e}:group:${t.id}:${this._editorSecondary?.groupGeneration}`;if("plan"===this._mode){const t=this._physicalSel;return t?`${e}:selection:${t.kind}:${t.id}:${t.segment??""}`:`${e}:tool:${this._tool}:${this._path.length}`}return"decor"===this._mode?"furniture"===this._decorTool?`${e}:palette:furniture:${this._furnPalette?.symbol||"none"}`:"select"===this._decorTool&&this._decorSel?`${e}:selection:decor:${this._decorSel}`:`${e}:tool:${this._decorTool}:${this._bdMoved?1:0}:${this._bdDrag?1:0}`:`${e}:none`}_runEditorContext(e,t){return this._editorRuntimeOrThrow()._runEditorContext(e,t)}_renderEditorGroupModel(e){return this._editorRuntimeOrThrow()._renderEditorGroupModel(e)}_renderDrawWallControl(){return this._editorRuntimeOrThrow()._renderDrawWallControl()}_renderPlanSecondary(){return this._editorRuntimeOrThrow()._renderPlanSecondary()}_renderDecorSecondary(){return this._editorRuntimeOrThrow()._renderDecorSecondary()}_withBackdropReset(e){return this._editorRuntimeOrThrow()._withBackdropReset(e)}get _editorSecondaryDialogBlocked(){return!!(this._tapConfirm||this._vacCalConfirm||this._roomDialog||this._mergeDialog||this._openingDialog||this._physicalDialog||this._openingInfo||this._decorTextDialog||this._decorShapeDialog||this._backdropDialog||this._decorEraseConfirm||this._spaceDialog||this._markerDialog||this._deviceInbox||this._infoCard||this._rulesDialog||this._settingsDialog||this._alignDialog||this._importDialog||this._kioskDialog||this._backupExportDialog||this._backupImportDialog||this._wallDialog)}_renderEditorSecondary(){return this._editorRuntimeOrThrow()._renderEditorSecondary()}_renderDecorBar(){return this._editorRuntimeOrThrow()._renderDecorBar()}_renderDecorEraseConfirm(){return this._editorRuntimeOrThrow()._renderDecorEraseConfirm()}_renderDecorTextDialog(){return this._editorRuntimeOrThrow()._renderDecorTextDialog()}_renderDecorShapeDialog(){return this._editorRuntimeOrThrow()._renderDecorShapeDialog()}_renderBackdropDialog(){return this._editorRuntimeOrThrow()._renderBackdropDialog()}_cssPxToRender(e){return this._editorRuntimeOrThrow()._cssPxToRender(e)}_renderZeroWalls(e){if(e&&!e.showBorders&&!this._editing)return W``;const t=this._zeroWalls();if(!t.lines.length)return W``;const i=e?.color||"var(--hp-muted)";return W` + ${t.lines.map(e=>W``)} + `}_zeroWalls(){const e=this._spaceModel();return e?op(this._curSpaceCfg,e,hm,.02*this._gridPitch):{style:tp(this._curSpaceCfg),lines:[],contour:[],barriers:[],transmissive:[]}}_openCuts(){return this._zeroWalls().contour}_deleteRoomClick(e){return this._editorRuntimeOrThrow()._deleteRoomClick(e)}get _wallKeyPitch(){return Na}get _spaceWalls(){const e=this._curSpaceCfg?.walls;return Array.isArray(e)?e:[]}_cfgOpenCuts(){const e=this._curSpaceCfg,t=this._spaceModel();if(!e||!t)return[];const i=ip(e,1),n=rp(e,t.rooms,hm,.02*this._gridPitch).map(e=>e.map(e=>e/hm)),r=new Set;return[...i,...n].filter(e=>{const t=e.map(e=>Number(e).toFixed(9)).join(","),i=[e[2],e[3],e[0],e[1]].map(e=>Number(e).toFixed(9)).join(","),n=t[e[0]/hm,e[1]/hm,e[2]/hm,e[3]/hm]))}_paperShapes(e){if(!this._spaceWalls.length)return Xt(e);const t=this._wallUnionGeometry();return t?.paperD?[{path:t.paperD}]:Xt(e)}_wallUnionGeometry(){const e=this._spaceModel();if(!e)return null;const t=this._spaceWalls,i=this._physicalBodiesR();if(!t.length&&!i.length)return null;const n=`${this._space}|${this._cfgEpoch}|${e.rooms.length}`;if(!this._wallUnionCache||this._wallUnionCache.key!==n){const r=X_(this._wallUnionPool,n);if(r.hit)this._wallUnionCache=r.value;else{const r=this._openCuts(),o=this._roomWallOpeningInputs(),s=Hs(e.rooms,t,r,o,this._wallKeyPitch,this._cellCm,this._gridPitch,hm,i);s&&Object.defineProperty(s,"sourceFingerprint",{value:Rl([this._curSpaceCfg,this._cellCm,this._gridPitch]),enumerable:!1});const a={key:n,value:s};J_(this._wallUnionPool,n,a,8),this._wallUnionCache=a}}return this._wallUnionCache.value}_thickWallCuts(){const e=this._spaceModel();if(!e)return[];const t=this._spaceWalls;if(!t.length)return[];const i=this._openCuts();return qs(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm).map(e=>[e.a[0],e.a[1],e.b[0],e.b[1]])}_innerRoomContour(e,t,i=this._openCuts(),n=this._wallUnionGeometry()?.roomGeom,r=this._wallUnionGeometry()?.multiWallNodes){const o=i.map(e=>e.join(",")).join(";"),s=`${e.id}|${this._cfgEpoch}|${t}|${o}`,a=X_(this._innerContourCache,s);if(a.hit)return a.value;const l=ks(e.rooms,t,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm,n,r);return J_(this._innerContourCache,s,l,600),l}_wallThickHit(e){return this._editorRuntimeOrThrow()._wallThickHit(e)}get _wallThickHover(){if(!this._markup||"wallthick"!==this._tool||!this._cursorPt||this._wallDialog)return null;const e=this._wallThickHit(this._cursorPt);if(!e)return null;const t=function(e,t,i){const n=Number.isFinite(e)&&e>0?e:0,r=Number.isFinite(t)&&t>0?t:5,o=Number.isFinite(i)&&i>0?i:0;return n>0?vo(n,r,o)/2:xa(1.5*o,r)}(e.cm,this._cellCm,this._gridPitch);let i="";for(const n of e.segs)i+=(i?" ":"")+Ko([[n[0],n[1]],[n[2],n[3]]],t,!1);return{segs:e.segs,open:e.open,d:i}}_wallThickClick(e){return this._editorRuntimeOrThrow()._wallThickClick(e)}_wallThickApply(e){return this._editorRuntimeOrThrow()._wallThickApply(e)}_wallHatchDefs(e){const t=_o(this._cellCm);return W` + + + + `}_resolvedRoomFills(e,t){const i=new Map,n=new Map;for(const r of e.rooms){const e=this._roomDialog&&r.id===this._roomEditId?this._roomFill||t.fill:Rn(t.fill,r),o=this._roomDialog&&r.id===this._roomEditId?this._roomCustomFill||t.customFill:en(t.customFill,r),s=an(e,"lqi"===e&&r.area?this._roomLqi(r.area):null,"light"===e?Th(Mh(this._renderPlanHass,this._renderDevices,r,this._virtualLights)):"none","temp"===e?this._roomTemp(r):null,t.tempMin,t.tempMax,this._fillColors,o);i.set(r,s),r.id&&n.set(r.id,s)}return{byRoom:i,byId:n}}_spaceDisplayForRender(){const e=tn(this._curSpaceCfg),t=this._spaceDialog;return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,showBorders:t.showBorders,showNames:t.showNames,hideDecor:t.hideDecor,hideOpenings:t.hideOpenings,color:t.roomColor,opacity:t.roomOpacity,fill:t.fillMode,customFill:t.customFill?Qi(t.customFill):Ji,glow:t.glowEnabled,tempMin:t.tempMin,tempMax:t.tempMax,showLqi:t.showLqi,cardFontScale:t.cardFontScale,labelTemp:t.labelTemp,labelHum:t.labelHum,labelLqi:t.labelLqi,labelLight:t.labelLight}:e}_openingWallIndexFor(e,t){const i=e.rooms.map(e=>`${e.id}:${e.poly?.map(e=>e.join(",")).join("/")||`${e.x},${e.y},${e.w},${e.h}`}`).join(";"),n=this._spaceWalls.map(e=>`${e.key}:${e.a?.join(",")||""}:${e.b?.join(",")||""}:${e.cm}`).join(";"),r=t.map(e=>e.join(",")).join(";"),o=[e.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,n,r].join("|");let s=this._openingWallIndexCache.get(o);return s||(s=Bs(e.rooms,this._spaceWalls,t,this._wallKeyPitch,this._cellCm,this._gridPitch,hm)),J_(this._openingWallIndexCache,o,s,4),{key:o,value:s}}_renderOpeningTunnelFills(e,t,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return W``;if("glow-base"===i&&![...t.byRoom.values()].some(Boolean))return W``;const n=this._openCuts(),r=this._openingsR.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),o=r.map(e=>`${e.x},${e.y},${e.angle},${e.length}`).join(";"),s=this._openingWallIndexFor(e,n),a=`${s.key}|${o}`;return this._openingTunnelCache&&this._openingTunnelCache.key===a||(this._openingTunnelCache={key:a,value:Zs(s.value,r)}),Wu({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:t.byId,idPrefix:`${e.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(e,t,i){const n=new Map,r=new Map,o=this._fillColors.glow_base;for(const s of e.rooms){const e=i.byRoom.get(s),a=Tn(t.glow,s)&&(!e||e.opacity<=0)?{color:o.c,opacity:o.a,mode:"glow"}:null;n.set(s,a),s.id&&r.set(s.id,a)}return{byRoom:n,byId:r}}_renderGlowBaseRooms(e,t){if(this._markup||![...t.byRoom.values()].some(Boolean))return W``;const i=new Map(e.rooms.map(e=>[e,Zt(e)])),n=this._openCuts(),r=this._wallUnionGeometry()?.roomGeom,o=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z",s=e.rooms.map(s=>{const a=t.byRoom.get(s)||null,l=i.get(s)||null;if(!a||!l)return G;const c=this._spaceWalls.length&&s.id&&this._innerRoomContour(e,s.id,n,r)||l,h=vi(c,e.rooms.filter(e=>e!==s).map(e=>i.get(e)).filter(e=>!!e)),d=this._cleanFloor(s,c,e).path;return d||h.length?W``:s.poly||c!==l?W``:W``});return W``}_renderWallBodies(e){if("iso"===this._renderProjection)return W``;if(e&&!e.showBorders&&("view"===this._mode||"devices"===this._mode))return W``;const t=this._wallUnionGeometry();if(!t)return W``;const i=this._stageEl,n=this._viewOr(this._baseVb()),r=i&&i.clientWidth&&n.w?i.clientWidth/n.w:1,o=e?.color||"#607d8b",s=po(t.depthUnits,r)||mo(_o(this._cellCm),r),a=this._fillColors.wall_fill;return W` + ${t.paths.map(e=>W` + + `)} + `}_isoDecorationLayers(e){const t="undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("filter","blur(1px)"),i="function"==typeof matchMedia&&matchMedia("(forced-colors: active)").matches;return function(e){const t=!!e.showBorders;return{structural:t,panels:t&&!e.hideOpenings,shadows:t&&e.filtersSupported&&!e.forcedColors,materialNuance:t&&!e.forcedColors,floorSymbols:!e.hideOpenings&&!t}}({showBorders:e.showBorders,hideOpenings:e.hideOpenings,filtersSupported:t,forcedColors:i})}_isoOpeningPanels(e){if(!e.panels)return[];const t=this._isoScene();if(!t)return[];return t.openings.flatMap(e=>{const t=this._openingsR[e.sourceIndex];return t?E_(e,this._openingAmt(t)):[]}).sort((e,t)=>e.depth-t.depth||e.sourceIndex-t.sourceIndex||e.leaf-t.leaf)}_renderIsoDefs(e,t){const i=ka(this._cellCm);return W` + ${"walls"===t&&e.materialNuance?W` + + + + + + `:G} + ${"underlay"===t&&e.shadows?W` + + + `:G} + ${"shadows"===t&&e.shadows?W` + + + + + + `:G} + `}_renderIsoUnderlay(e){if(!e.structural)return W``;const t=this._isoScene()?.floor;return t?W``:W``}_renderIsoShadows(e,t){if(!e.shadows)return W``;const i=this._isoScene()?.geometry;return i?W``:W``}_renderIsoWalls(e,t){if("iso"!==this._renderProjection)return W``;if(!e.structural)return W``;const i=this._isoScene();return i?W` + ${this._renderIsoDefs(e,"walls")} + ${i.geometry.sides.map(e=>W``)} + + ${e.panels?W``:G} + `:W``}_roomHoverPaths(e){const t=this._hoverRoom;if("view"!==this._mode||!t||t.space!==e.id)return null;const i=e.rooms.find(e=>e===t.room||!!e.id&&e.id===t.room.id);if(!i)return null;const n=Zt(i);if(!n)return null;const r=e.rooms.filter(e=>e!==i).map(e=>({room:e,poly:Zt(e)})).filter(e=>!!e.poly),o=vi(n,r.map(e=>e.poly)),s=this._openCuts(),a=.02*this._gridPitch,l=s.filter(e=>{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return n.some((e,i)=>Pn(t,[e[0],e[1],...n[(i+1)%n.length]])<=4*a)}),c=this._spaceWalls,h=this._wallUnionGeometry()?.roomGeom,d=c.length&&i.id&&this._innerRoomContour(e,i.id,s,h)||n,u=[{axis:n,face:d}];for(const t of o){const i=r.find(e=>e.poly===t)?.room;let n=t;if(c.length&&i?.id){const r=ms(e.rooms,i.id,c,s,this._wallKeyPitch,this._cellCm,this._gridPitch,hm);r&&(n=js(r.poly,r.offsets)||t)}u.push({axis:t,face:n})}const p=this._roomWallOpeningInputs(this._openingsR,e).map(e=>{const t=e.angle*Math.PI/180,i=Math.cos(t)*e.length/2,n=Math.sin(t)*e.length/2;return[e.x-i,e.y-n,e.x+i,e.y+n]}),_=l.concat(p),m=u.map(({axis:e,face:t})=>{const i=_.map(i=>((e,t,i)=>{const n=e[2]-e[0],r=e[3]-e[1],o=Math.hypot(n,r);if(o.05)&&Pn([c,h],[i[0],i[1],n[0],n[1]])<=4*a){d=!0;break}}if(!d)return null;let u=null;for(let e=0;e.05)continue;const p=Pn([c,h],[t[0],t[1],n[0],n[1]]);(!u||p!!e);return i.length?kn(t,i,a).map(e=>`M ${e[0]} ${e[1]} L ${e[2]} ${e[3]}`).join(" "):`M ${t.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return null;const g=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;return{fillD:[this._cleanFloor(i,d,e).path||g(d),...o.map(g)].join(" "),outlineD:m}}_renderRoomHoverFill(e){return e?W` + + `:W``}_renderRoomHoverOutline(e){return e?W` + + + `:W``}_renderWallThickUi(){return this._editorRuntime?this._editorRuntimeOrThrow()._renderWallThickUi():W``}_renderWallThickDialog(){return this._editorRuntimeOrThrow()._renderWallThickDialog()}_openingAt(e){return this._editorRuntimeOrThrow()._openingAt(e)}_resolveOpeningPlacement(e){return this._editorRuntimeOrThrow()._resolveOpeningPlacement(e)}_activateOpeningPlacement(e){return this._editorRuntimeOrThrow()._activateOpeningPlacement(e)}_clearOpeningPlacement(e){return this._editorRuntime?this._editorRuntimeOrThrow()._clearOpeningPlacement(e):(this._openingHoverCandidate=null,this._openingJambBlockCm=null,void(e&&(this._openingPreset=null,this._openingRebindId=null)))}_openingClick(e){return this._editorRuntimeOrThrow()._openingClick(e)}_editOpening(e){if(this._editorRuntime)return this._editorRuntimeOrThrow()._editOpening(e)}_opPointerDown(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerDown(e,t)}_opPointerMove(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerMove(e,t)}_opRuler(e,t){return this._editorRuntimeOrThrow()._opRuler(e,t)}_opPointerUp(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerUp(e,t)}_opClick(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opClick(e,t)}_saveOpening(){return this._editorRuntimeOrThrow()._saveOpening()}_deleteOpening(){return this._editorRuntimeOrThrow()._deleteOpening()}_contactCandidates(){return this._editorRuntimeOrThrow()._contactCandidates()}_lockCandidates(){return this._editorRuntimeOrThrow()._lockCandidates()}_toggleOpeningEntityPicker(e){return this._editorRuntimeOrThrow()._toggleOpeningEntityPicker(e)}_filterOpeningEntities(e,t){return this._editorRuntimeOrThrow()._filterOpeningEntities(e,t)}_selectOpeningEntity(e,t){return this._editorRuntimeOrThrow()._selectOpeningEntity(e,t)}_mergeClick(e){return this._editorRuntimeOrThrow()._mergeClick(e)}_commitMerge(){return this._editorRuntimeOrThrow()._commitMerge()}_splitClick(e){return this._editorRuntimeOrThrow()._splitClick(e)}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])&&(null!=this._closingWallCm||!this._activeDraftId)}_markupMove(e){if(this._markup&&this._editorRuntime)return this._editorRuntime._markupMove(e)}get _openingPreview(){const e=this._openingPreset;if("opening"!==this._tool||!e||!this._cursorPt)return null;const t=this._cursorPt,i=this._openingHoverCandidate;if(i&&G_(i,[t[0],t[1]],e.revision,this._cfgEpoch))return i;if(this._openingAt(t))return this._openingHoverCandidate=null,null;const n=this._resolveOpeningPlacement(t);return this._openingHoverCandidate=n,n}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){return this._editorRuntimeOrThrow()._saveRoom()}_decideWallFace(e){return this._editorRuntimeOrThrow()._decideWallFace(e)}_wallSourceCmAt(e,t,i){return this._editorRuntimeOrThrow()._wallSourceCmAt(e,t,i)}_activePathWithRepair(e,t){return this._editorRuntimeOrThrow()._activePathWithRepair(e,t)}_validateWallRepair(e,t){return this._editorRuntimeOrThrow()._validateWallRepair(e,t)}_applyWallRepair(e,t){return this._editorRuntimeOrThrow()._applyWallRepair(e,t)}_applyWallFaceBatch(){return this._editorRuntimeOrThrow()._applyWallFaceBatch()}_commitRoom(){return this._editorRuntimeOrThrow()._commitRoom()}_cancelPath(){return this._editorRuntimeOrThrow()._cancelPath()}_resumeLastDraft(){return this._editorRuntimeOrThrow()._resumeLastDraft()}_roomDialogCancel(){return this._editorRuntimeOrThrow()._roomDialogCancel()}get _freeAreas(){const e=new Set;for(const t of this._serverCfg?.spaces||[])for(const i of t.rooms||[])i.area&&e.add(i.area);for(const t of this._wallFaceBatch?.decisions||[])t.create&&t.area&&e.add(t.area);return Object.values(this.hass?.areas||{}).filter(t=>!e.has(t.area_id)).sort((e,t)=>(e.name||"").localeCompare(t.name||""))}_openDeviceInbox(){return this._editorRuntimeOrThrow()._openDeviceInbox()}_closeMarkerDialog(){return this._editorRuntimeOrThrow()._closeMarkerDialog()}_deviceInboxCandidates(e){return this._editorRuntimeOrThrow()._deviceInboxCandidates(e)}_deviceInboxRows(){return this._editorRuntimeOrThrow()._deviceInboxRows()}_deviceForInboxRow(e){return this._editorRuntimeOrThrow()._deviceForInboxRow(e)}_openInboxMarker(e,t=!1){return this._editorRuntimeOrThrow()._openInboxMarker(e,t)}async _setInboxHidden(e,t){return this._editorRuntimeOrThrow()._setInboxHidden(e,t)}_findInboxDevice(e){return this._editorRuntimeOrThrow()._findInboxDevice(e)}_deviceInboxTabKey(e){return this._editorRuntimeOrThrow()._deviceInboxTabKey(e)}_openMarkerDialog(e){if(this._editorRuntime)return this._editorRuntime._openMarkerDialog(e);this._ensureEditorRuntime().then(t=>{t&&this._openMarkerDialog(e)})}_runCandidates(){return this._editorRuntimeOrThrow()._runCandidates()}_bindingCandidates(){return this._editorRuntimeOrThrow()._bindingCandidates()}_physicalBodiesR(e=this._spaceModel()){if(!e)return[];const t=`${e.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===t)return this._physicalBodiesCache.all;const i=ca(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e));return this._physicalBodiesCache={key:t,...i},i.all}_rawPhysicalBodiesR(e=this._spaceModel()){if(!e)return[];this._physicalBodiesR(e);const t=this._physicalBodiesCache;return t?[...t.drafts,...t.partitions,...t.columns]:[]}_cleanFloor(e,t,i=this._spaceModel()){if(!i)return{floor:t,geom:null,path:"",area:ma([[[...t,t[0]]]])};const n=e.id||`#${i.rooms.indexOf(e)}`,r=`${i.id}|${this._cfgEpoch}|${n}`;if(!this._resize?.preview){const e=X_(this._cleanFloorCache,r);if(e.hit)return e.value}const o=t.map(e=>e[0]),s=t.map(e=>e[1]),a=[Math.min(...o),Math.min(...s),Math.max(...o),Math.max(...s)],l=this._physicalBodiesR(i).filter(e=>{const t=e.map(e=>e[0]),i=e.map(e=>e[1]);return Math.max(...t)>=a[0]&&Math.min(...t)<=a[2]&&Math.max(...i)>=a[1]&&Math.min(...i)<=a[3]}),c=l.length?_a(t,l):null,h={floor:t,geom:c,path:c?ra(c):"",area:ma(c||[[[...t,t[0]]]])};return this._resize?.preview||J_(this._cleanFloorCache,r,h,600),h}_autoIconForBinding(e){if("virtual"===e)return"mdi:map-marker";const[t,i]=e.split(":");if(!i)return"";const n=this._fullRegistryHass,r=this._bindingStatus(e),o="active"===r.kind?r.enabledEntityIds:r.allEntityIds;if("device"===t){const e=n.devices?.[i];if(!e)return"mdi:help-circle";const t=o;return t.some(e=>e.startsWith("lock."))?"mdi:lock":Fh(n,e.name_by_user||e.name||"",e.model,t,this._iconRules)}if("entity"===t){const e=n.entities?.[i],t=this.hass.states?.[i],r=e?.name||t?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":Fh(n,r,"",[i],this._iconRules)}return""}_allRoomsFlat(){const e=[];for(const t of this._serverCfg?.spaces||[])for(const i of t.rooms||[])i.area?e.push({value:t.id+"#"+i.area,label:(t.title||t.id)+" · "+i.name}):i.id&&e.push({value:t.id+"#@"+i.id,label:(t.title||t.id)+" · "+i.name+" · "+this._t("marker.subarea")});return e}_errText(e){if(!e)return this._t("err.unknown");if("string"==typeof e)return e;if("invalid_passage_fields"===e.code){const t=String(e.message||e.error||"").match(/space=([^;]*);\s*opening=([^;]*);\s*fields=([^;]*)/);if(t){const e=this._serverCfg?.spaces?.find(e=>String(e.id)===t[1]),i={contact:"opening.contact_label",lock:"opening.lock_label",invert:"opening.invert",flip_h:"opening.flip_h",flip_v:"opening.flip_v"},n=t[3].split(",").filter(Boolean).map(e=>i[e]?this._t(i[e]):e).join(", ");return this._t("opening.invalid_passage_fields",{room:e?.title||t[1],fields:n})}}if("invalid_partition_opening_jamb_margin"===e.code){const t=String(e.message||e.error||"").match(/margin_cm=([^;]*)/),i=t?Number(t[1]):NaN;if(Number.isFinite(i))return this._t("opening.partition_jamb_margin",{distance:Kt(i,this._imperial)})}if(e.message)return e.message;if(e.error)return e.error;if(null!=e.code)return this._t("err.code",{code:e.code});try{return JSON.stringify(e)}catch{return String(e)}}_backupErrorText(e){return this._editorRuntimeOrThrow()._backupErrorText(e)}async _pickMarkerFiles(e){return this._editorRuntimeOrThrow()._pickMarkerFiles(e)}_removeMarkerPdf(e){return this._editorRuntimeOrThrow()._removeMarkerPdf(e)}_markerLightFields(e){return this._editorRuntimeOrThrow()._markerLightFields(e)}_markerTapActionFields(e){return this._editorRuntimeOrThrow()._markerTapActionFields(e)}_markerToggleEntityFields(e){return this._editorRuntimeOrThrow()._markerToggleEntityFields(e)}async _saveMarker(){return this._editorRuntimeOrThrow()._saveMarker()}async _deleteMarker(){return this._editorRuntimeOrThrow()._deleteMarker()}_normPos(e,t,i){return{s:e,x:t/hm,y:i/hm}}_spaceDialogUsesOnboardingRuntime(e){return"create"===e&&!this._editorRuntime&&(!!this._onboardingRuntime||0===(this._serverCfg?.spaces.length||0)||this._importTotal>0||this._importQueue.length>0)}_spaceRuntimeOrThrow(){if(!this._onboardingRuntime)throw new Error("Houseplan onboarding runtime is not loaded");return this._onboardingRuntime}_openSpaceDialog(e,t){return this._spaceDialogUsesOnboardingRuntime(e)?this._onboardingRuntime?void this._onboardingRuntime._openSpaceDialog(e,t):void this._ensureOnboardingRuntime().then(i=>{i&&this._spaceRuntimeOrThrow()._openSpaceDialog(e,t)}):this._editorRuntime?this._editorRuntime._openSpaceDialog(e,t):void this._ensureEditorRuntime().then(i=>{i&&this._openSpaceDialog(e,t)})}async _pickPlanFile(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._pickPlanFile(e):this._editorRuntimeOrThrow()._pickPlanFile(e)}_useServerPlan(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._useServerPlan(e):this._editorRuntimeOrThrow()._useServerPlan(e)}async _readPlanAspect(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._readPlanAspect(e):this._editorRuntimeOrThrow()._readPlanAspect(e)}async _deleteServerPlan(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._deleteServerPlan(e):this._editorRuntimeOrThrow()._deleteServerPlan(e)}_renderServerPlans(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime(e.mode)?this._onboardingRuntime._renderServerPlans(e):this._editorRuntimeOrThrow()._renderServerPlans(e)}async _saveSpaceDialog(){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._saveSpaceDialog():this._editorRuntimeOrThrow()._saveSpaceDialog()}async _deleteSpace(){return this._editorRuntimeOrThrow()._deleteSpace()}async _saveConfigNow(){return this._editorRuntimeOrThrow()._saveConfigNow()}_startImport(){return this._onboardingRuntime?this._onboardingRuntime._startImport():this._editorRuntimeOrThrow()._startImport()}_openNextImport(){return this._onboardingRuntime?this._onboardingRuntime._openNextImport():this._editorRuntimeOrThrow()._openNextImport()}_skipImport(){return this._onboardingRuntime?this._onboardingRuntime._skipImport():this._editorRuntimeOrThrow()._skipImport()}_renderImportDialog(){return this._onboardingRuntime?this._onboardingRuntime._renderImportDialog():this._editorRuntimeOrThrow()._renderImportDialog()}_sunGlobal(){const e=this._settingsDialog;return e?{...this._settings,north_deg:e.northDeg??void 0,bg_mode:e.bgMode,sun_rays:e.sunRays}:this._settings}_sunSpace(){const e=this._spaceDialog,t=this._curSpaceCfg?.settings||{};return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,north_deg:e.northDeg??void 0,bg_mode:e.bgMode??void 0,sun_rays:e.sunRays??void 0}:t}_effNorth(){return or(this._sunGlobal(),this._sunSpace())}_effBgMode(){return sr(this._sunGlobal(),this._sunSpace())}_dayCycleState(e=new Date){return(this._modeTransitionVisual?.viewWeight??("view"===this._mode?1:0))<=0||"daynight"!==this._effBgMode()?null:Yn(this._renderPlanHass,e)}_syncDayCycleClock(){const e=this._dayCycleState();this._dayCycleClockKey=e?Zn(e):"";const t="clock"===e?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;t&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!t&&this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(e){"hidden"!==e.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_effSunRays(){return ar(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?lr(this._renderPlanHass):null}_renderSunRays(e){const t=W``,i=this._modeTransitionVisual?.viewWeight??0;if(this._editing&&i<=0||!this._effSunRays())return this._sunFadeReset(),t;const n=this._effNorth(),r=null!==n?lr(this._renderPlanHass):null;if(!r||r.elevation<=0)return this._sunFadeReset(),t;if(o=r.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return t;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const s=this._zeroWalls(),a=s.barriers.map(e=>e.join(",")).join(";"),l=`${e.id}|${r.azimuth}|${r.elevation}|${n}|${this._cfgEpoch}|${s.style}|${a}`;if(!this._sunRaysCache||this._sunRaysCache.key!==l){const t=e.rooms.map(e=>({id:e.id||"",poly:Zt(e)})).filter(e=>!!e.id&&!!e.poly),i=this._openingsR.filter(e=>"window"===e.type&&"partition"!==e.host?.kind).map(e=>({id:e.id,x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),o=this._spaceWalls,a=this._openCuts(),c=this._openingWallIndexFor(e,a).value,h={},d={},u=this._wallUnionGeometry()?.roomGeom;if(o.length){for(const i of t){const t=this._innerRoomContour(e,i.id,a,u);t&&(h[i.id]=t)}for(const e of i){const t=Vs(c,{x:e.x,y:e.y,angle:e.angle,length:e.length});t.cm>0&&(d[e.id]=vo(t.cm,this._cellCm,this._gridPitch))}}let p=nr(t,i,r.azimuth,r.elevation,n,o.length?h:void 0,o.length?d:void 0);const _=[...this._physicalBodiesR(e),...s.barriers.map(e=>[[e[0],e[1]],[e[2],e[3]]])];_.length&&(p=p.map(e=>{const t=function(e,t,i){return i>0?e.map(e=>function(e){const t=[...e].sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(t.length<=2)return t;const i=(e,t,i)=>(t[0]-e[0])*(i[1]-e[1])-(t[1]-e[1])*(i[0]-e[0]),n=[];for(const e of t){for(;n.length>=2&&i(n[n.length-2],n[n.length-1],e)<=0;)n.pop();n.push(e)}const r=[];for(let e=t.length-1;e>=0;e--){const n=t[e];for(;r.length>=2&&i(r[r.length-2],r[r.length-1],n)<=0;)r.pop();r.push(n)}return n.slice(0,-1).concat(r.slice(0,-1))}([...e,...e.map(e=>[e[0]+t[0]*i,e[1]+t[1]*i])])).filter(e=>e.length>=3):e}(_,e.dir,e.len),i=e.polys.map(e=>_a(e,t));return{...e,paths:i.map(ra).filter(Boolean),polys:i.flatMap(fa)}}).filter(e=>e.paths?.length||e.polys.length)),this._sunRaysCache={key:l,rays:p,rims:p.map(e=>function(e,t=1e-4){const[i,n]=e.dir,r=-n,o=i,s=[];for(const a of[e.a,e.b]){const l=[];for(const s of e.polys)for(let e=0;et)continue;if(Math.abs((h[0]-a[0])*r+(h[1]-a[1])*o)>t)continue;const d=(c[0]-a[0])*i+(c[1]-a[1])*n,u=(h[0]-a[0])*i+(h[1]-a[1])*n;Math.abs(u-d)<=t||l.push(de[0]-t[0]);const c=[];for(const e of l){const i=c[c.length-1];i&&e[0]<=i[1]+t?i[1]=Math.max(i[1],e[1]):c.push([e[0],e[1]])}for(const[e,t]of c)s.push([[a[0]+i*e,a[1]+n*e],[a[0]+i*t,a[1]+n*t]])}return s}(e))}}const c=this._sunRaysCache.rays,h=this._sunRaysCache.rims;if(!c.length)return t;const d=(u=function(e){const t=Math.min(90,Math.max(-90,Number(e)||0));let i=Xn[Xn.length-1][1];for(let e=1;e + ${c.map((e,t)=>{const i=(e.a[0]+e.b[0])/2,n=(e.a[1]+e.b[1])/2,r=i+e.normal[0]*e.depth,o=n+e.normal[1]*e.depth;return W` + ${p.map(([e,t])=>W``)} + + + ${_.map(([e,t])=>W``)} + `})} + + + ${c.map((e,t)=>e.paths?.length?e.paths.map(e=>W``):e.polys.map(e=>W``))} + ${c.map((e,t)=>(h[t]||[]).map(e=>W``))} + `}_sunFadeReset(){this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunShown=!1,this._sunOut=!1}_compassPoint(e){const t=e.currentTarget.getBoundingClientRect(),i=e.clientX-(t.left+t.width/2),n=e.clientY-(t.top+t.height/2);if(Math.hypot(i,n)<5)return;let r=Math.round(180*Math.atan2(i,-n)/Math.PI);e.shiftKey&&(r=15*Math.round(r/15)),r=(r%360+360)%360,this._settingsDialog={...this._settingsDialog,northDeg:r}}_renderCompass(){const e=this._settingsDialog.northDeg;return B`{e.currentTarget.setPointerCapture(e.pointerId),this._compassDrag=!0,this._compassPoint(e)}} + @pointermove=${e=>{this._compassDrag&&this._compassPoint(e)}} + @pointerup=${()=>this._compassDrag=!1} + @pointercancel=${()=>this._compassDrag=!1}> + + ${[0,45,90,135,180,225,270,315].map(e=>W``)} + + + + ${this._t("gs.north_letter")} + + ${null===e?"—":e+"°"} + `}_stageBg(e){const t=this._settingsDialog,i=this._spaceDialog,n=t?t.bgColor||"":nn(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":e.bgColor||"")||n}_stageBgHex(){const e=this._stageEl;if(e){const t=getComputedStyle(e).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(t)return"#"+t.slice(1,4).map(e=>(+e).toString(16).padStart(2,"0")).join("")}return"#111111"}_preflightDiagnostics(e,t){return this._editorRuntimeOrThrow()._preflightDiagnostics(e,t)}_reportPreflightFailure(e,t){return this._editorRuntimeOrThrow()._reportPreflightFailure(e,t)}_preflightVersionsDiffer(){return this._editorRuntimeOrThrow()._preflightVersionsDiffer()}async _copyPreflightDiagnostics(){return this._editorRuntimeOrThrow()._copyPreflightDiagnostics()}_checkOptimizeGeometry(e){return this._editorRuntimeOrThrow()._checkOptimizeGeometryImpl(e)}_checkSpacePhysicalGeometry(e,t,i){return this._editorRuntimeOrThrow()._checkSpacePhysicalGeometryImpl(e,t,i)}_optimizeReferenceContext(e){return this._editorRuntimeOrThrow()._optimizeReferenceContext(e)}_previewAlignDialog(e){return this._editorRuntimeOrThrow()._previewAlignDialog(e)}async _runAlignToGrid(){return this._editorRuntimeOrThrow()._runAlignToGrid()}async _undoPlanOptimization(){return this._editorRuntimeOrThrow()._undoPlanOptimization()}async _runBackupExport(){return this._editorRuntimeOrThrow()._runBackupExport()}async _pickBackupImport(e){return this._editorRuntimeOrThrow()._pickBackupImport(e)}async _setBackupDuplicatePolicy(e){return this._editorRuntimeOrThrow()._setBackupDuplicatePolicy(e)}async _applyBackupImport(){return this._editorRuntimeOrThrow()._applyBackupImport()}_renderBackupExportDialog(){return this._editorRuntimeOrThrow()._renderBackupExportDialog()}_renderBackupImportDialog(){return this._editorRuntimeOrThrow()._renderBackupImportDialog()}_setFillColor(e,t){return this._editorRuntimeOrThrow()._setFillColor(e,t)}async _saveSettingsDialog(){return this._editorRuntimeOrThrow()._saveSettingsDialog()}_boolInput(e,t,i=!1){return this._editorRuntimeOrThrow()._boolInput(e,t,i)}_rangeInput(e,t,i,n,r,o=!1,s){return this._editorRuntimeOrThrow()._rangeInput(e,t,i,n,r,o,s)}_renderColorRow(e,t){return this._editorRuntimeOrThrow()._renderColorRow(e,t)}get _glowRadiusCm(){const e=Number(this._settings.glow_radius_cm);return Number.isFinite(e)&&e>0?e:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const e=this._glowRadiusCm;return this._imperial?String(Math.round(e/30.48*10)/10):String(e/100)}_glowTransition(e,t){let i=this._glowRenderedSources.get(e);if(t){const t=this._glowFadeTimers.get(e);if(null!=t&&(clearTimeout(t),this._glowFadeTimers.delete(e)),null==i){this._suspendGlowFeatherForTransition(),i=++this._glowSourceSeq,this._glowRenderedSources.set(e,i),this._glowEnteringSources.add(e);const t=requestAnimationFrame(()=>{this._glowEnterRafs.get(e)===t&&(this._glowEnterRafs.delete(e),this._glowEnteringSources.delete(e),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(e,t)}return{domId:i,entering:this._glowEnteringSources.has(e),leaving:!1}}if(null==i)return null;const n=this._glowEnterRafs.get(e);if(null!=n&&cancelAnimationFrame(n),this._glowEnterRafs.delete(e),this._glowEnteringSources.delete(e),!this._glowFadeTimers.has(e)){this._suspendGlowFeatherForTransition();const t=window.setTimeout(()=>{this._glowFadeTimers.get(e)===t&&(this._glowFadeTimers.delete(e),this._glowRenderedSources.delete(e),this._glowLastAppearance.delete(e),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(e,t)}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 e=Math.max(0,this._glowFeatherSuspendUntil-Date.now())+17,t=()=>{this._glowFeatherResumeTimer=0,Date.now()=128){const e=this._glowGeometryWarnings.values().next().value;e&&this._glowGeometryWarnings.delete(e)}this._glowGeometryWarnings.add(r),console.warn(`HOUSEPLAN GLOW GEOMETRY FALLBACK: #218, space ${e}, room ${i}, phase ${n}`)}}_lightBarriers(e,t){const i=Rl([this._curSpaceCfg,this._cellCm,this._gridPitch]),n=`${e.id}|${i}`,r=X_(this._lightBarrierPool,n);if(r.hit)return this._lightBarrierCache=r.value,r.value.value;const o=this._zeroWalls(),s=this._openCuts(),a=[...o.transmissive],l=Math.max(this._cmToUnits(10),.5*this._gridPitch),c=e=>t.some(t=>this._pointInRoom(e,t.r)),h=this._openingsR.filter(e=>{if("door"!==(t=String(e.type))&&"gate"!==t&&"passage"!==t)return!1;var t;const i=e.angle*Math.PI/180,n=-Math.sin(i),r=Math.cos(i);return c([e.rx+n*l,e.ry+r*l])&&c([e.rx-n*l,e.ry-r*l])}),d=this._roomWallOpeningInputs(h,e);for(const e of d){const t=e.angle*Math.PI/180,i=Math.cos(t)*e.length/2,n=Math.sin(t)*e.length/2;a.push([e.x-i,e.y-n,e.x+i,e.y+n])}const u=new Set(h.filter(e=>e.partitionHost).map(e=>e.id)),p=[e.id,this._cfgEpoch,this._cellCm,this._gridPitch,[...u].sort().join(",")].join("|");this._lightPhysicalBodiesCache?.key!==p&&(this._lightPhysicalBodiesCache={key:p,all:ca(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e,e=>u.has(e.id))).all});const _=this._lightPhysicalBodiesCache.all,m=this._spaceWalls,g=.02*this._gridPitch,f=[],v=this._wallUnionGeometry(),y=v?.sourceFingerprint,b=v&&y===i?function(e,t=[],i=[],n={}){if("failed-core"===e.status||"not-applicable"===e.status)return null;const r=e.roomComponents?.length?e.roomComponents:$s(e.roomGeom)?[{id:"room-primary",geom:e.roomGeom}]:[];let o=r[0]?.geom||null;const s=r.slice(1).map(e=>({...e}));try{for(const i of t){if(!(i.length>0&&e.openingIndex))continue;const t=Gs(e.openingIndex,i,!0);if(!t.negative&&!t.positive)continue;const n=i.angle*Math.PI/180,r=Math.cos(n),a=Math.sin(n),l=-a,c=r,h=i.length/2,d=e.openingPadUnits??1.25*Math.max(e.depthUnits,1),u=xs([[i.x-r*h-l*d,i.y-a*h-c*d],[i.x+r*h-l*d,i.y+a*h-c*d],[i.x+r*h+l*d,i.y+a*h+c*d],[i.x-r*h+l*d,i.y-a*h+c*d]]);o&&(o=Ht(o,u));for(const e of s)e.geom=Ht(e.geom,u)}const r=[...s];let a=s.length;const l=n.mergeExtra||((e,t)=>e?Et(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(yi(t))<=1e-9){a++;continue}const n=[xs(t)];try{const t=l(o,n,e);if(!$s(t))throw new Error("invalid extra union");o=t}catch{a++,$s(n)&&r.push({id:`policy-extra-${e}`,geom:n})}}r.sort((e,t)=>Fs(e.geom).localeCompare(Fs(t.geom)));const c=o||[];return{status:a?"degraded-extra":"ok",geom:c,components:[...$s(c)?[{id:"primary",geom:c}]:[],...r.map((e,t)=>({...e,id:`isolated-${t}`}))]}}catch{return null}}(v,d,_):null,w=b||(m.length||_.length?Ns(e.rooms,m,s,d,this._wallKeyPitch,this._cellCm,this._gridPitch,hm,_):null);if(!w||"ok"!==w.status&&"degraded-extra"!==w.status)for(const e of _)f.push(...Hd(e));else for(const e of w.components)for(const t of ga(e.geom))f.push(...Hd(t));for(const{poly:e}of t)for(const t of a.length?kn(e,a,g):Hd(e))f.push(t);for(const e of o.barriers)f.push(e);const k={occluders:Nd(f),floor:t.map(e=>e.poly),fingerprint:i,masonryGeometry:!w||"ok"!==w.status&&"degraded-extra"!==w.status?[]:w.components.flatMap(e=>e.geom),opaqueBodies:_},x={key:n,value:k};return J_(this._lightBarrierPool,n,x,8),this._lightBarrierCache=x,k}_renderGlowLayer(e,t){const i=this._fillColors,n=this._glowRadiusCm/this._cellCm*this._gridPitch,r=e.rooms.map(e=>({r:e,poly:Zt(e)})).filter(e=>!!e.poly),o=r.filter(({r:e})=>Tn(t.glow,e));if(!o.length)return this._forgetGlowSpace(e.id),W``;const{occluders:s,floor:a,fingerprint:l,masonryGeometry:c,opaqueBodies:h}=this._lightBarriers(e,r),d=Mh(this._renderPlanHass,this._renderDevices,null,this._virtualLights).filter(t=>t.device.space===e.id),u=new Map;for(const e of d){if(!e.device.id)continue;const t=u.get(e.device.id)||[];t.push(e),u.set(e.device.id,t)}const p=[],_=new Set;for(const t of this._renderDevices){if(t.space!==e.id)continue;const o=Rh(u.get(t.id)||[]);if(!o)continue;const d=`${e.id}|${t.id}`;_.add(d);const m=fn(o.passive?{state:o.on?"on":"off",attributes:{}}:this._renderPlanHass.states[o.eid],t.marker?.glow_color,i.glow_light.c),g=Number(t.marker?.glow_radius_cm),f=Number.isFinite(g)&&g>0?g/this._cellCm*this._gridPitch:n,v=this._pos(t);if(ya([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:vn(m.bri,i.glow_light.a)});const b=this._glowLastAppearance.get(d);if(!b)continue;let w=null;const k=`${e.id}|${l}|${v.x.toFixed(4)},${v.y.toFixed(4)}|${f.toFixed(4)}`,x=X_(this._glowClipCache,k);if(x.hit)w=x.value;else{const t=jd([v.x,v.y],f,s,96);w={lit:t.length>=3?pa([t],a,{onBoundsFailure:({boundIndex:t,phase:i})=>{const n=r[t]?.r;this._warnGlowGeometryFallback(e.id,l,n?.id||`#${t}`,i)}}):[]},J_(this._glowClipCache,k,w,256)}p.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=`${e.id}|`;for(const e of this._glowRenderedSources.keys())e.startsWith(m)&&!_.has(e)&&this._forgetGlowSource(e);if(!p.length)return W``;const g=this._spaceWalls,f=o.length===r.length?[]:this._openCuts(),v=this._wallUnionGeometry()?.roomGeom,y=o.length===r.length?null:o.map(({r:t,poly:i})=>{const n=g.length&&t.id&&this._innerRoomContour(e,t.id,f,v)||i,o=this._cleanFloor(t,n,e).path,s=vi(n,r.filter(e=>e.r!==t).map(e=>e.poly)),a=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z";return[o||a(n),...s.map(a)].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=p.reduce((e,t)=>({x:Math.min(e.x,t.pos.x-t.r-S),y:Math.min(e.y,t.pos.y-t.r-S),maxX:Math.max(e.maxX,t.pos.x+t.r+S),maxY:Math.max(e.maxY,t.pos.y+t.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,W` + ${$e(p,e=>e.key,e=>{const t=e.domId,i=e.geometry;return W` + ${""} + + ${dm.map(([t,i])=>W` + `)} + + ${""} + ${i?W` + + + `:G}`})} + ${y?W`${y.map(e=>W``)}`:G} + ${""} + + + + + ${""} + + + ${$e(p,e=>e.key,e=>{const t=e.domId;return W` + + + `})} + + `}_renderAlignDialog(){return this._editorRuntimeOrThrow()._renderAlignDialog()}_renderSettingsDialog(){return this._editorRuntimeOrThrow()._renderSettingsDialog()}_rulesSet(e){return this._editorRuntimeOrThrow()._rulesSet(e)}async _saveRules(){return this._editorRuntimeOrThrow()._saveRules()}_renderRulesDialog(){return this._editorRuntimeOrThrow()._renderRulesDialog()}_saveKioskScale(e){this._kioskScale={...this._kioskScale,...e};try{localStorage.setItem(am,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const e=this._kioskScale,t=(t,i)=>{const n=Math.round(100*e[t]);return B` +
+ {const i=Number(e.target.value);Number.isFinite(i)&&this._saveKioskScale({[t]:i/100})}} aria-label=${i} /> + ${n}% +
`};return B`this._kioskDialog=!1}> +
+
${this._t("kiosk.hint")}
+ ${t("icon",this._t("kiosk.icon_scale"))} + ${t("font",this._t("kiosk.font_scale"))} +
+
+ + + +
+
`}_fixedFloorValue(e){if("string"==typeof e)return e||"''";try{const t=JSON.stringify(e);return(void 0===t?String(e):t).slice(0,160)}catch{return String(e).slice(0,160)}}render(){const e=!!this._importDialog||!(!this._spaceDialog||!this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)),t="view"!==this._mode||!!(this._roomDialog||this._mergeDialog||this._openingDialog||this._physicalDialog||this._partitionDeleteDialog||this._roomDeleteDialog||this._decorTextDialog||this._decorShapeDialog||this._backdropDialog||this._decorEraseConfirm||this._spaceDialog&&!this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)||this._deviceInbox||this._markerDialog||this._rulesDialog||this._settingsDialog||this._alignDialog||this._backupExportDialog||this._backupImportDialog||this._kioskDialog||this._vacFit||this._vacCalConfirm);if(e&&!this._onboardingRuntime&&this._ensureOnboardingRuntime(),t&&!this._editorRuntime&&this._ensureEditorRuntime(),!this._config||!this.hass)return G;const i=this._model,n=this.houseplanDiagnostics(),r=this._fixedFloorState(i);if("pending"===r.kind)return B` +
+
${this._config.title||this._t("card.title")}
+
+
+ +

${this._t("fixed_floor.loading")}

+
+
`;if("invalid"===r.kind)return B` +
+
${this._config.title||this._t("card.title")}
+
+ +
`;if(!i.length)return B` +
+
${this._config.title||this._t("card.title")}
+
+
+ +

${this._t("empty.no_spaces")}

+ ${this._serverStorage?B`

${this._t("empty.add_first")}

+ `:B`

${this._t("empty.install")}

`} +
+ ${this._spaceDialog&&(this._onboardingRuntime||this._editorRuntime)?this._renderSpaceDialog():G} + ${this._importDialog&&this._onboardingRuntime?this._renderImportDialog():G} + ${this._toast?B``:G} +
`;const o=this._spaceModel();if(!o)return G;const s="valid"===r.kind?[o]:i,a=o.vb,l=this._effectiveProjection();this._renderProjection=l,this._labs.active.length&&function(e){p_||y_(e);const t=u_,i=t.active.join(",");if(!i||i===m_)return;m_=i;const n=new Map(n_.map(e=>[e.id,e])),r=t.active.map(e=>{const t=n.get(e);return`${e} (#${t.issue}, expires ${t.expires})`}).join(", ");console.info(`HOUSEPLAN LABS: ${r}`)}(K_);const c="iso"===l,h="devices"===this._mode&&this._showAll,d=this._renderDevices.filter(e=>e.space===o.id&&(!e.hidden||h)),u=this._renderDeviceSnapshot,p=this._spaceDisplayForRender(),_=c?this._isoDecorationLayers(p):null,m=_?this._isoOpeningPanels(_):[],g=this._resolvedRoomFills(o,p),f=this._resolvedGlowBase(o,p,g),v=p.showLqi??this._config.show_signal??!0,y=this._config.icon_size??2.5,b=y>8?2.5:y,w=Bu(b),k=this._viewOr(this._baseVb()),x=this._floorView(k),$=this._editing?"":this._stageBg(p),S=this._opMeasureView,M=this._decorMeasure,R=this._bdLive,T=this._furnLive,C="view"===this._mode?this._editorChromeMode:this._mode,D=this._roomHoverPaths(o),A=o.bg?this._display(o.bg.href):"",O=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null,z=this._modeTransitionVisual,P=this._dayCycleState(),F=z?.viewWeight??("view"===this._mode?1:0),I=this._modeTransition.state?.from.presentedMode,E=!this._markup||!!z&&("view"===z.presentedMode||"devices"===z.presentedMode||"view"===I||"devices"===I),N=z?.stageColor||$,H=z?.sceneBrightness??1;return B` + this._notePointer(e)} + @pointerdown=${this._touchGestureGuard} + @pointermove=${this._touchGestureGuard} + @pointerup=${this._touchGestureGuard} + @pointercancel=${this._touchGestureGuard} + @lostpointercapture=${this._touchGestureGuard} + @click=${this._touchGestureGuard}> +
+
+
+ + ${this._config.title||this._t("card.title")} +
+
this._tabPointerMove(e)}> + ${s.map(e=>B``)} + ${""} + ${!this._canEdit||this._kiosk||this._hasFixedFloor?G:B``} +
+ ${this._canEdit?B`
+ ${[["plan","mdi:floor-plan"],["devices","mdi:tune-variant"],["decor","mdi:draw"]].map(([e,t])=>B``)} +
`:G} + ${this._t("count.devices",{n:d.filter(e=>!e.hidden).length})} + + ${this._labsIso&&"view"===this._mode&&!this._kiosk?B``:G} +
+ + ${""} + + +
+ ${this._norm&&this._canEdit?B``:G} +
+ ${this._canEdit&&!this._kiosk?B`
+
+ ${this._editorRuntime?"plan"===C?this._renderMarkupBar():"devices"===C?this._renderDevicesBar():this._renderDecorBar():G} +
+
`:G} +
+ +
this._markupClick(e)} + @wheel=${e=>this._onWheel(e)} + @pointerdown=${e=>{this._notePointer(e),this._stagePointerDown(e)}} + @pointermove=${e=>this._stagePointerMove(e)} + @pointerleave=${e=>this._stagePointerLeave(e)} + @pointerup=${e=>this._stagePointerUp(e)} + @pointercancel=${e=>this._stagePointerCancel(e)}> + ${dr(P,F)} + ${this._editorRuntime?this._renderEditorSecondary():G} +
+ ${c&&_?.structural?W``:G} + + + ${""} + ${this._wallHatchDefs(p.color)}${W`${this._paperShapes(o.rooms).map(e=>"path"in e?W``:"poly"in e?W``:W``)}`} + ${this._editing?this._renderMarkupDefs(a):G} + ${""} + ${this._editing&&!this._markup&&this._gridLevels()?W``:G} + ${o.bg&&A?W`this._onBackdropLoaded(o.bg.href,A)} + transform=${o.bg.angle?`rotate(${o.bg.angle} ${o.bg.x+o.bg.w/2} ${o.bg.y+o.bg.h/2})`:G} + @dblclick=${e=>this._openBackdropDialog(e)} + preserveAspectRatio="none" />`:G} + ${(()=>{const e=this._openCuts(),t=this._thickWallCuts(),i=this._wallUnionGeometry()?.roomGeom,n=new Map,r=e=>(n.has(e)||n.set(e,Zt(e)),n.get(e));return o.rooms.filter(e=>e.area||"view"===this._mode||this._markup||p.showBorders).map(n=>{let s="room "+(o.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||n.id!==this._mergeSel&&n.id!==this._splitSel?.roomId||(s+=" picked");let a="";const l=Rn(p.fill,n);if(!this._markup&&(p.showBorders||"none"!==l)){s+=" styled";const e=[];e.push(`--room-stroke:${p.color}`,`--room-stroke-op:${p.showBorders?p.opacity:0}`);const t=g.byRoom.get(n)||null;t?(s+=" filled",e.push(`--room-fill:${t.color}`,`--room-fill-op:${t.opacity}`)):e.push("--room-fill:transparent","--room-fill-op:0"),a=e.join(";")}let c;const h=e=>{"view"===this._mode&&(void 0===c&&(c=this._roomArea(n)),this._showTip(e,n.name||this._t("room.unnamed"),c?this._t("tip.area",{value:c}):"",v?this._roomLqi(n.area):null,this._roomTemp(n),this._roomHum(n)))},d=r(n),u=this._markup&&(n.id===this._mergeSel||n.id===this._splitSel?.roomId),_=d&&!u?e.filter(e=>{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return d.some((e,i)=>Pn(t,[e[0],e[1],...d[(i+1)%d.length]])<=.08*this._gridPitch)}):[],m=u?[]:t,f=_.concat(m);f.length&&(s+=" noedge");const y=this._spaceWalls.length&&n.id&&d&&this._innerRoomContour(o,n.id,e,i)||d,b=y?vi(y,(w=n,o.rooms.filter(e=>e!==w).map(r).filter(Boolean))):[];var w;const k=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z",x=y?this._cleanFloor(n,y,o).path:"",$=n.id||G,S=n.area||G,M=x&&y?W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`:b.length&&y?W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`:y&&y!==d?W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`:n.poly?W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`:W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`,R=f.length&&d?kn(d,f,.02*this._gridPitch):null,T=R?W``:G;return W`${M}${T}`})})()} + ${this._renderRoomHoverFill(D)} + ${this._renderOpeningTunnelFills(o,g)} + ${this._renderGlowBaseRooms(o,f)} + ${this._renderOpeningTunnelFills(o,f,"glow-base")} + ${""} + ${p.hideDecor&&"decor"!==this._mode?G:this._renderDecorLayer()} + ${E?this._renderGlowLayer(o,p):G} + ${this._renderSunRays(o)} + ${this._editing?W`${this._renderAlignGuides()}`:G} + ${this._markup?W`${this._renderMarkupLayer(a)}`:G} + ${""} + ${""} + ${this._editing?G:this._renderZeroWalls(p)} + ${this._renderWallBodies(p)} + ${this._markup&&"resize"===this._tool?this._renderResizeMeasurements():G} + ${this._renderRoomHoverOutline(D)} + ${""} + ${this._editing?this._renderZeroWalls(p):G} + ${this._markup?W`${this._renderHiddenWallDiagnosticOverlay()}`:G} + ${this._markup?W`${this._renderOpeningPlacementPreview()}`:G} + ${S?this._renderOpeningDimensionGuides(S):G} + ${S?.guide?this._renderOpeningCenterTick(S.guide):G} + ${""} + ${""} + ${this._markup?W`${this._renderActiveChainInk()}`:G} + ${this._markup?W`${this._renderPlanSnapOverlay()}`:G} + ${p.hideOpenings&&!this._markup||_&&!_.floorSymbols?G:this._renderOpenings(p)} + ${this._renderWallThickUi()} + ${this._markup&&"resize"===this._tool?this._renderResizeLayer(k):G} + ${""} + ${this._renderBackdropFrame(k)} + ${this._renderTextFrame(k)} + + + ${c&&_?.structural?W` + `:G} + ${""} +
+ ${d.map(e=>this._renderDevice(e,k,v))} + ${this._renderVacuums(d,k)} + ${this._renderVacFit(k)} + ${this._renderOpeningLocks(k)} + ${p.showNames||this._markup?o.rooms.map(e=>this._renderRoomLabel(e,o,k,p)):G} + ${this._markup?o.rooms.map(e=>this._renderRoomGear(e,o,k)):G} +
+ ${this._measureAnchor?B`
${this._renderMeasureLabel(k)}
`:G} + ${this._resize?.liveLabels?B`
${this._resize?.liveLabels?.map(e=>B`
${e.text}
`)}
`:G} + ${S?B`
${S.labels.map(e=>B`
${e.text}
`)}
`:G} + ${this._wallDialog?B`
${this._renderWallThickDialog()}
`:G} + ${M?B`
${M.text}
`:G} + ${T?B`
${T.map(e=>B`
${e.text}
`)}
`:G} + ${R?B`
${R.text}
`:G} +
+ ${this._zoom>1?B`
${Math.round(100*this._zoom)}%
`:G} + ${this._renderFarHint()} + ${this._renderHomeArrow()} + ${this._renderEditorRuntimeLoading()} + ${this._renderRecoveryOverlay()} + ${this._booting||this._bootFading?B``:G} +
+ + ${this._roomDialog&&this._editorRuntime?this._renderRoomDialog():G} + ${this._mergeDialog&&this._editorRuntime?this._renderMergeDialog():G} + ${this._openingDialog&&this._editorRuntime?this._renderOpeningDialog():G} + ${this._physicalDialog&&this._editorRuntime?this._renderPhysicalDialog():G} + ${this._partitionDeleteDialog&&this._editorRuntime?this._renderPartitionDeleteDialog():G} + ${this._roomDeleteDialog&&this._editorRuntime?this._renderRoomDeleteDialog():G} + ${this._openingInfo?this._renderOpeningInfoCard():G} + ${this._decorTextDialog&&this._editorRuntime?this._renderDecorTextDialog():G} + ${this._decorShapeDialog&&this._editorRuntime?this._renderDecorShapeDialog():G} + ${this._backdropDialog&&this._editorRuntime?this._renderBackdropDialog():G} + ${this._decorEraseConfirm&&this._editorRuntime?this._renderDecorEraseConfirm():G} + ${this._spaceDialog&&(this._onboardingRuntime||this._editorRuntime)?this._renderSpaceDialog():G} + ${this._deviceInbox&&this._editorRuntime?this._renderDeviceInbox():G} + ${this._markerDialog&&this._editorRuntime?this._renderMarkerDialog():G} + ${this._vacCalConfirm?B`this._vacCalConfirm=null}> +
+

${this._t("vac.residual_message",{error:this._vacCalConfirm.error})}

+
+
+ + + + +
+
`:G} + ${this._infoCard?this._renderInfoCard():G} + ${this._rulesDialog&&this._editorRuntime?this._renderRulesDialog():G} + ${this._settingsDialog&&this._editorRuntime?this._renderSettingsDialog():G} + ${this._alignDialog&&this._editorRuntime?this._renderAlignDialog():G} + ${this._backupExportDialog&&this._editorRuntime?this._renderBackupExportDialog():G} + ${this._backupImportDialog&&this._editorRuntime?this._renderBackupImportDialog():G} + ${this._importDialog&&this._onboardingRuntime?this._renderImportDialog():G} + ${this._tip?B`
+ ${this._tip.title}${this._tip.meta?B`${this._tip.meta}`:G} + ${null!=this._tip.temp?B`${this._t("tip.temp_avg")} ${this._tip.temp}°`:G} + ${null!=this._tip.hum?B`${this._t("tip.hum_avg")} ${this._tip.hum}%`:G} + ${null!=this._tip.lqi?B`${this._t("tip.lqi")} + ${this._tip.lqi}`:G} +
`:G} + ${this._kiosk&&!this._hasFixedFloor&&this._kioskDots&&this._model.length>1?B`
+ ${this._model.map(e=>B``)} +
`:G} + ${this._kioskDialog?this._renderKioskDialog():G} + ${this._vacFit?B`
+ ${this._t("vac.fit_hint")} + + + + +
`:G} + ${this._tapConfirm?B`this._tapConfirm=null}> +
+ ${"run"===this._tapConfirm.kind?B`

${this._tapConfirm.text}

`:this._tapConfirm.lines.map((e,t)=>B` +

${e}

`)} +
+
+ + + +
+
`:G} + ${this._toast?B``:G} +
+ `}_vacCandidateStatus(e,t,i=this._planHass){const n=this._bindingStatus("entity:"+e);if("ha_disabled"===n.kind)return"disabled";if("orphaned"===n.kind)return"missing";if("unverified"===n.kind)return"unverified";const r=i?.states?.[e];return"unavailable"===r?.state?"unavailable":t?.hasPosition?"ok":"unsupported"}_vacOpenAllCameras(e){const t=this._haRegistry.entities||{},i=[];for(const[e,n]of Object.entries(this.hass?.states||{})){if(!e.startsWith("camera."))continue;const r=Gl(e,n,t[e]);r&&i.push(r)}this._vacAllCameraCache={devId:e.id,candidates:i},this._vacAllCamerasFor=e.id}_vacSourceResolution(e,t=!1,i=this._planHass){const n=e.marker?.vacuum,r="string"==typeof n?.source&&!!n.source,o=new Set(e.entities||[]),s=new Set(o);r&&s.add(n.source);const a=i?.entities||{},l=[];for(const e of s){const t=i?.states?.[e],o=Gl(e,t,a[e]);o?l.push(o):r&&e===n.source&&l.push({entityId:e,name:String(t?.attributes?.friendly_name||e),platform:a[e]?.platform?String(a[e].platform):null,category:e.startsWith("camera.")?"camera":"partial",hasPosition:!1,hasRooms:!1,hasPath:!1,hasMapId:!1,score:0})}if(t&&this._vacAllCameraCache?.devId===e.id){const e=new Set(l.map(e=>e.entityId));for(const t of this._vacAllCameraCache.candidates)e.has(t.entityId)||l.push(t)}const c={};for(const e of l)c[e.entityId]=this._vacCandidateStatus(e.entityId,e,i);return function(e,t,i,n){const r="string"==typeof e&&e.length>0,o=new Set(t),s=Array.from(i).sort((t,i)=>r&&t.entityId===e?-1:r&&i.entityId===e?1:i.score-t.score||t.entityId.localeCompare(i.entityId));if(r){const t=s.find(t=>t.entityId===e);return{entityId:e,status:n[e]||(t?.hasPosition?"ok":"unverified"),pinned:!0,candidates:s}}const a=s.find(e=>o.has(e.entityId)&&e.hasPosition&&"ok"===n[e.entityId]);return a?{entityId:a.entityId,status:"ok",pinned:!1,candidates:s}:{entityId:null,status:"none",pinned:!1,candidates:s}}(n?.source,o,l,c)}_vacSource(e,t=this._planHass){if(!1===e.marker?.vacuum?.live)return null;const i=this._vacSourceResolution(e,!1,t);return"ok"===i.status||"unsupported"===i.status?i.entityId:null}_vacEntity(e){return e.primary?.startsWith("vacuum.")?e.primary:(e.entities||[]).find(e=>e.startsWith("vacuum."))||null}_isVacDev(e){return!!this._vacEntity(e)}_activitySourceKey(e){return this._activitySnapshot(e).sourceKey}_activitySnapshot(e,t=Mh(this._planHass,this._devices,null,this._virtualLights)){const i=Cu(this._planHass,e,this._devices,t,this._fullRegistryHass);return{samples:i.samples,sourceKey:Ou(this._planHass,e,i)}}_stampActivity(e,t,i){let n=this._activityRt.get(e);n||(n=kp(i||"",[]),this._activityRt.set(e,n)),null!=i&&(n.sources=i),$p(n,t,Date.now(),window.clearTimeout.bind(window),e=>window.setTimeout(()=>this.requestUpdate(),e))}_syncActivityRuntime(){const e=new Map;if(!this.hass)return e;if(!1===this._config?.live_states){for(const e of this._activityRt.values())clearTimeout(e.timer);return this._activityRt.clear(),e}const t=new Set,i=Mh(this._planHass,this._devices,null,this._virtualLights);for(const n of this._devices){if(n.hidden)continue;if("icon_ripple"!==Ai(n.marker?.display))continue;t.add(n.id);const r=this._activitySnapshot(n,i);e.set(n.id,r);const{samples:o,sourceKey:s}=r;let a=this._activityRt.get(n.id);a?a.sources!==s&&xp(a,s,o,window.clearTimeout.bind(window)):(a=kp(s,o),this._activityRt.set(n.id,a))}for(const[e,i]of this._activityRt)t.has(e)||(clearTimeout(i.timer),this._activityRt.delete(e));return e}_activityTick(){if(!this.hass)return;const e=this._syncActivityRuntime();for(const t of this._devices){if(t.hidden)continue;if("icon_ripple"!==Ai(t.marker?.display))continue;const i=e.get(t.id)||this._activitySnapshot(t),{samples:n,sourceKey:r}=i,o=this._activityRt.get(t.id);if(!o||o.sources!==r)continue;const s=Sp(o,n,window.clearTimeout.bind(window));s&&this._stampActivity(t.id,s,r)}}_vacTick(){if(this.hass)for(const e of this._devices){if(e.hidden||!this._isVacDev(e))continue;if("static_icon"===Ai(e.marker?.display)){this._vacRt.delete(e.id);continue}const t=this._vacSource(e);if(!t)continue;const i=this._vacEntity(e),n=Xl(this.hass.states[i||""]?.state),r=Bl(this.hass.states[t]?.attributes);let o=this._vacRt.get(e.id);o||(o={trail:[],lastKey:"",lastTs:0,moving:!1,jump:!1,endedTs:0,lastPos:null},this._vacRt.set(e.id,o)),n&&!o.moving&&(o.trail=[],o.lastPos=null);const s="never"!==nc(e.marker?.vacuum)&&!r?.path.length;!n&&o.moving&&(o.endedTs=Date.now(),s&&o.lastPos&&(o.trail=Zl(o.trail,o.lastPos,40)),o.lastPos=null),o.moving=n;const a=r?.pos;if(n&&a){const e=a.x+":"+a.y;if(e!==o.lastKey){const t=Date.now();o.jump=o.lastTs>0&&t-o.lastTs>1e4,o.lastKey=e,o.lastTs=t,s&&o.lastPos&&(o.trail=Zl(o.trail,o.lastPos,40)),o.lastPos=[a.x,a.y]}}}}_vacEnsureMarker(e){const t=this._serverCfg;if(!t)return null;t.markers=t.markers||[];const i=t.markers.find(t=>t.id===e.id);if(i)return i;if("device"!==e.bindingKind&&"entity"!==e.bindingKind||!e.bindingRef)return null;const n={id:e.id,binding:e.bindingKind+":"+e.bindingRef,space:e.space||null,area:e.area||null,hidden:!!e.hidden};return t.markers.push(n),n}_renderVacSection(e){return this._editorRuntimeOrThrow()._renderVacSection(e)}_vacMapId(e,t,i=this._planHass){return this._editorRuntimeOrThrow()._vacMapId(e,t,i)}_vacSaveMatrix(e,t,i,n){return this._editorRuntimeOrThrow()._vacSaveMatrix(e,t,i,n)}_vacPlanRoomAnchors(e){return this._editorRuntimeOrThrow()._vacPlanRoomAnchors(e)}_vacAutoCalibrate(e){return this._editorRuntimeOrThrow()._vacAutoCalibrate(e)}_vacApplyCalibrationProposal(e){return this._editorRuntimeOrThrow()._vacApplyCalibrationProposal(e)}_vacStartFit(e){return this._editorRuntimeOrThrow()._vacStartFit(e)}_vacFitSave(){return this._editorRuntimeOrThrow()._vacFitSave()}_vacFitTurn(e){return this._editorRuntimeOrThrow()._vacFitTurn(e)}_vacGhostCentre(e){return this._editorRuntimeOrThrow()._vacGhostCentre(e)}_vacDelta(e,t,i){return this._editorRuntimeOrThrow()._vacDelta(e,t,i)}_vacFitPointer(e,t){return this._editorRuntimeOrThrow()._vacFitPointer(e,t)}_renderVacFit(e){return this._editorRuntime?this._editorRuntimeOrThrow()._renderVacFit(e):G}_vacRafLoop(){this._vacRaf=requestAnimationFrame(()=>{const e=this.renderRoot,t=this._stageEl,i=this._vacLastView,n=e?.querySelectorAll?.(".vacpuck")||[];if(!t||!i||!n.length)return void(this._vacRaf=0);const r=t.getBoundingClientRect();for(const t of n){const n=t.getAttribute("data-mid"),o=t.getBoundingClientRect(),s=i.x+(o.left+o.width/2-r.left)/r.width*i.w,a=i.y+(o.top+o.height/2-r.top)/r.height*i.h;for(const t of e.querySelectorAll(`line.tip[data-mid="${n}"]`))t.setAttribute("x2",s.toFixed(1)),t.setAttribute("y2",a.toFixed(1))}this._vacRafLoop()})}_renderVacuums(e,t){if(this._markup||"decor"===this._mode)return G;const i=this._space+"|"+t.x+"|"+t.y+"|"+t.w+"|"+t.h,n=this._vacJumpOnce||i!==this._vacViewKey;this._vacViewKey=i,this._vacJumpOnce=!1;const r=[],o=[];for(const i of e){if(i.hidden||!this._isVacDev(i))continue;if("static_icon"===Ai(i.marker?.display))continue;const e=this._renderDeviceSnapshot?.facts.get(`vacuum:${i.id}`),s=e?.source??this._vacSource(i,this._renderPlanHass);if(!s)continue;const a=e?.telemetry??Bl(this._renderPlanHass?.states[s]?.attributes);if(!a)continue;const l=String(e?.mapId??this._vacMapId(i,a,this._renderPlanHass)),c=i.marker?.vacuum?.calibration?.[l];if(!c||6!==c.length)continue;const h=e?.runtime??this._vacRt.get(i.id),d=h?.moving??!1,u=nc(i.marker?.vacuum),p="always"===u||"cleaning"===u&&d,_=e?.server??this._vacSrvTrails[i.id],m=_?.current?.map_id===l&&Array.isArray(_.current.points)?_.current:null,g=_?.previous?.map_id===l&&Array.isArray(_.previous.points)?_.previous:null;if("always"===u&&g&&g.points.length>1){const e=g.points.map(([e,t])=>{const[i,n]=zl(c,e,t),r=this._scenePoint([i,n]);return r[0].toFixed(1)+","+r[1].toFixed(1)}).join(" ");o.push(W``)}if(p){const e=Ll(a,m,h?.trail||[]),t=!d||"integration"!==e.source&&"server"!==e.source?e.path:ql(e.path);if(t.length){const e=t.map(e=>e.map(([e,t],i)=>{const[n,r]=zl(c,e,t),o=this._scenePoint([n,r]);return`${i?"L":"M"} ${o[0].toFixed(1)} ${o[1].toFixed(1)}`}).join(" ")).join(" ");o.push(W``);const n=t[t.length-1];if(d&&n?.length>=2){const e=n[n.length-1],[t,r]=zl(c,e[0],e[1]),s=this._scenePoint([t,r]),a=s[0].toFixed(1),l=s[1].toFixed(1);o.push(W``)}}}if(!d||!a.pos)continue;const[f,v]=zl(c,a.pos.x,a.pos.y),y=this._scenePoint([f,v]),b=(y[0]-t.x)/t.w*100,w=(y[1]-t.y)/t.h*100,k=h&&h.lastTs>0&&Date.now()-h.lastTs>6e4,x=i.marker?.icon||i.icon||"mdi:robot-vacuum";r.push(B`
{e.stopPropagation();const t=this._vacEntity(i);t&&this._openMoreInfo(t)}}> + +
`)}return this._vacLastView=t,r.length&&!this._vacRaf&&this._vacRafLoop(),r.length||o.length?B` + ${o.length?W`${o}`:G} + ${r}`:G}_renderDevice(e,t,i=!0){const n=this._pos(e),r=this._scenePoint([n.x,n.y]),o=(r[0]-t.x)/t.w*100,s=(r[1]-t.y)/t.h*100,a=this._devicePresentation(e,i),l=[`left:${o}%`,`top:${s}%`,...Lu(a)],c=a.disabledReason,h=a.haDisabled?this._t(`marker.ha_disabled_${c}`):e.userHidden?this._t("marker.hidden_ghost"):e.name,d=xu(a),u="view"===this._mode||"devices"===this._mode,p=[h,a.haDisabled?"":this._t(`marker.state_a11y_${d}`),"none"!==a.pulse.kind?this._t(`marker.pulse_a11y_${a.pulse.reason}`):"",a.valueFullText||a.valueText||"",nu(a.valueBadge),null!=a.lqiText&&a.lqiBand?this._t(`marker.lqi_a11y_${a.lqiBand}`,{value:a.lqiText}):""].filter(Boolean).join(", "),_=[e.model,a.valueBadge?.fullText||"",null!=a.lqiText?"LQI "+a.lqiText:""].filter(Boolean).join(" · ");return B`
this._clickDevice(t,e)} + @keydown=${t=>this._keyDevice(t,e)} + @contextmenu=${t=>this._ctxDevice(t,e)} + @pointerover=${t=>this._showTip(t,e.name,a.haDisabled?h:_)} + @pointerleave=${()=>this._clearTransientHover()} + @pointerdown=${t=>this._pointerDown(t,e)} + @pointermove=${t=>{this._pointerMove(t,e),this._showTip(t,e.name,a.haDisabled?h:_)}} + @pointerup=${t=>this._pointerUp(t,e)} + @pointercancel=${t=>this._pointerUp(t,e)} + > + ${ju(a,{newDevice:this._newIds.has(e.id),newDeviceTitle:this._t("device.new"),disabledTitle:a.haDisabled?h:""})} +
`}_roomArea(e){const t=Zt(e);if(!t)return null;const i=this._spaceModel();if(!i)return null;const n=this._spaceWalls.length&&e.id&&this._innerRoomContour(i,e.id)||t,r=this._cleanFloor(e,n),o=this._cellCm/this._gridPitch;return Hn(r.area*o*o/1e4,"mi"===this._renderPlanHass?.config?.unit_system?.length)}_roomTemp(e){const t=e.settings?.temp_source;return t?Gh(this._renderPlanHass,t,"temp",this._markers):e.area?this._climate().get(e.area)?.temp??null:null}_roomHum(e){const t=e.settings?.hum_source;return t?Gh(this._renderPlanHass,t,"hum",this._markers):e.area?this._climate().get(e.area)?.hum??null:null}_climate(){const e=this._serverCfg?.markers,t=this._renderPlanHass,i=this._climateCache;if(i&&i.h===t&&i.r===this._iconRules&&i.mk===e)return i.m;const n=function(e,t,i){const n=new Map;if(!e?.entities)return n;const r=Lh(i),o=new Set;for(const e of i||[]){if(e?.removed||!0!==e?.use_climate_temp)continue;const t=(e.binding||"").indexOf(":");t>0&&o.add(e.binding.slice(t+1))}const s=new Map;for(const[t,i]of Object.entries(e.entities)){if(i.device_id&&r.devices.has(i.device_id)&&!r.liveEntities.has(t)||!i.device_id&&r.entities.has(t)&&!r.liveEntities.has(t))continue;const n=i.device_id?e.devices?.[i.device_id]:null,a=i.area_id||n?.area_id||null;if(!a)continue;if(i.entity_category)continue;if(!(o.size>0&&t.startsWith("climate.")&&(o.has(t)||i.device_id&&o.has(i.device_id)))){if(Te.has(i.platform))continue;if(Vh.test(t))continue}let l=s.get(a);l||(l=new Map,s.set(a,l));const c=i.device_id||t;let h=l.get(c);if(!h){const r=e.states?.[t];h={name:(n?n.name_by_user||n.name:i.name||r?.attributes?.friendly_name||t)||t,model:n?.model,ents:[]},l.set(c,h)}h.ents.push(t)}for(const[i,r]of s){const s=[],a=[];for(const[i,n]of r){const r=Fh(e,n.name,n.model,n.ents,t),l="mdi:thermometer"===r||"mdi:air-filter"===r;if(l){const t=Dh(e,n.ents);null!=t&&s.push(t)}if(o.size>0&&(o.has(i)||n.ents.some(e=>o.has(e)))){const t=Ah(e,n.ents);null!=t&&s.push(t)}if(l||"mdi:water-percent"===r){const t=zh(e,n.ents);null!=t&&a.push(t)}}(s.length||a.length)&&n.set(i,{temp:s.length?Math.round(s.reduce((e,t)=>e+t,0)/s.length*10)/10:null,hum:a.length?Math.round(a.reduce((e,t)=>e+t,0)/a.length):null})}return n}(t,this._iconRules,e);return this._climateCache={h:t,r:this._iconRules,mk:e,m:n},n}_resetRoomDialogFields(){return this._editorRuntimeOrThrow()._resetRoomDialogFields()}_openRoomEdit(e){return this._editorRuntimeOrThrow()._openRoomEdit(e)}_roomSettingsFromDialog(){return this._editorRuntimeOrThrow()._roomSettingsFromDialog()}_saveRoomEdit(){return this._editorRuntimeOrThrow()._saveRoomEdit()}_roomSrcCandidates(){return this._editorRuntimeOrThrow()._roomSrcCandidates()}_roomSrcLabel(e){return this._editorRuntimeOrThrow()._roomSrcLabel(e)}_labelPos(e,t){const i=this._layout["rl_"+(e.id||"")];if(i&&i.s===t)return{x:i.x*hm,y:i.y*hm};const n=this._roomCenter(e),r=this._gridPitch;return{x:qa(Gt(n[0],r)),y:qa(Gt(n[1],r))}}_labelDown(e,t,i){if(this._editorRuntime)return this._editorRuntimeOrThrow()._labelDown(e,t,i)}_labelMove(e,t,i){if(this._editorRuntime)return this._editorRuntimeOrThrow()._labelMove(e,t,i)}_labelUp(e){if(this._editorRuntime)return this._editorRuntimeOrThrow()._labelUp(e)}_labelScale(e){const t=this._layout["rl_"+(e.id||"")]?.k;return"number"==typeof t&&Number.isFinite(t)?Math.min(3,Math.max(.5,t)):1}_rlResizeDown(e,t,i){return this._editorRuntimeOrThrow()._rlResizeDown(e,t,i)}_rlResizeMove(e){return this._editorRuntimeOrThrow()._rlResizeMove(e)}_rlResizeUp(){return this._editorRuntimeOrThrow()._rlResizeUp()}_renderRoomGear(e,t,i){return this._editorRuntimeOrThrow()._renderRoomGear(e,t,i)}_renderRoomLabel(e,t,i,n){if(!e.name&&!this._markup)return G;const r=this._labelPos(e,t.id),o=this._scenePoint([r.x,r.y]),s=(o[0]-i.x)/i.w*100,a=(o[1]-i.y)/i.h*100,l=Math.min(1,n.opacity+.25),c=this._labelScale(e),h=[];if(e.area||e.settings?.temp_source||e.settings?.hum_source||n.labelLight){if(n.labelTemp){const t=this._roomTemp(e);null!=t&&h.push(B`${t}°`)}if(n.labelHum){const t=this._roomHum(e);null!=t&&h.push(B`${t}%`)}if(n.labelLqi&&e.area){const t=this._roomLqi(e.area);null!=t&&h.push(B`${t}`)}if(n.labelLight){const t=(d=Mh(this._renderPlanHass,this._renderDevices,e,this._virtualLights)).length?{on:d.filter(e=>e.on).length,total:d.length}:null;if(t){const e=0===t.on?this._t("roomcard.light_off"):t.on===t.total?this._t("roomcard.light_on"):this._t("roomcard.light_partial",{on:t.on,total:t.total});h.push(B`${e}`)}}}var d;const u=!!e.area,p=!this._markup;return B`
this._labelDown(i,e,t.id)} + @pointermove=${i=>this._labelMove(i,e,t.id)} + @pointerup=${()=>this._labelUp(e)} + @pointercancel=${()=>this._labelUp(e)} + >${e.name||(this._markup?this._t("room.unnamed"):"")}${u?B`{t.stopPropagation(),this._clickRoom(e)}:G} + @pointerdown=${p?e=>e.stopPropagation():G}>`:G} + ${h.length?B`${h}`:G} + ${"plan"===this._mode?["tl","tr","bl","br"].map(i=>B`this._rlResizeDown(i,e,t.id)} + @pointermove=${e=>this._rlResizeMove(e)} + @pointerup=${()=>this._rlResizeUp()} + @pointercancel=${()=>this._rlResizeUp()}>`):G} +
`}get _measureAnchor(){return this._markup&&this._cursorPt?"draw"===this._tool&&this._path.length&&!this._contourClosed?this._path[this._path.length-1]:"split"===this._tool&&this._splitSel?.pts?.length?this._splitSel.pts[this._splitSel.pts.length-1]:null:null}_renderMeasureLabel(e){const t=this._measureAnchor,i=this._cursorPt,n=(i[0]-e.x)/e.w*100,r=(i[1]-e.y)/e.h*100,o=On(t,i),s=Math.round(10*o)/10,a=function(e,t,i=.001){if(e.length<2||t.length<2)return!1;const n=Math.abs(t[0]-e[0]),r=Math.abs(t[1]-e[1]);if(!Number.isFinite(n)||!Number.isFinite(r)||Math.hypot(n,r)<=i)return!1;const o=Math.max(n,r,1);return n<=i*o||r<=i*o||Math.abs(n-r)<=i*o}(t,i,2e-4*this._gridPitch);return B`
+ ${this._fmtLen(t,i)} · ${s}°
`}get _decorMeasure(){const e=this._decorDraft;if(!e||"decor"!==this._mode)return null;const[t,i]=e.a,[n,r]=e.b;if(Math.abs(t-n)<1e-6&&Math.abs(i-r)<1e-6)return null;const o=(t+n)/2,s=(i+r)/2;if("line"===e.kind){const t=On(e.a,e.b);return{x:o,y:s,on45:zn(t),text:`${this._fmtLen(e.a,e.b)} · ${Math.round(10*t)/10}°`}}const a=this._fmtLen([t,i],[n,i]),l=this._fmtLen([n,i],[n,r]);if("ellipse"===e.kind){const e=this._fmtLen([0,0],[Math.abs(n-t)/2,0]),a=this._fmtLen([0,0],[0,Math.abs(r-i)/2]);return{x:o,y:s,on45:!1,text:Math.abs(Math.abs(n-t)-Math.abs(r-i))<1e-6?`R ${e}`:`Rx ${e} × Ry ${a}`}}return{x:o,y:s,on45:!1,text:`${a} × ${l} · ${Hn(vr(Math.abs(n-t),this._cellCm,this._gridPitch)*vr(Math.abs(r-i),this._cellCm,this._gridPitch)/1e4,this._imperial)}`}}get _alignPoint(){if(this._markup){if("draw"===this._tool&&this._path.length&&!this._contourClosed&&this._cursorPt)return this._cursorPt;if("split"===this._tool&&this._splitSel?.pts?.length&&this._cursorPt)return this._cursorPt;if(this._drag?.id.startsWith("rl_")&&this._drag.moved){const e=this._drag.id.slice(3),t=this._spaceModel()?.rooms.find(t=>t.id===e);return t?(()=>{const e=this._labelPos(t,this._space);return[e.x,e.y]})():null}return null}if("devices"===this._mode&&this._drag?.moved){const e=this._devices.find(e=>e.id===this._drag.id);return e?(()=>{const t=this._pos(e);return[t.x,t.y]})():null}if("decor"===this._mode){if(this._decorDraft)return this._decorDraft.b;if(this._decorMove){const e=this._decorList.find(e=>e.id===this._decorMove.id);if(!e)return null;const t=hm,i=this._decorH;return"line"===e.kind?[e.x1*t,e.y1*i]:[e.x*t,e.y*i]}return null}return null}_alignCandidates(){return this._editorRuntimeOrThrow()._alignCandidates()}_renderAlignGuides(){return this._editorRuntimeOrThrow()._renderAlignGuides()}_renderOpeningCenterTick(e){return this._editorRuntimeOrThrow()._renderOpeningCenterTick(e)}_renderOpeningDimensionGuides(e){return this._editorRuntimeOrThrow()._renderOpeningDimensionGuides(e)}_roomCenter(e){if(e.poly){const t=e.poly.length;return[e.poly.reduce((e,t)=>e+t[0],0)/t,e.poly.reduce((e,t)=>e+t[1],0)/t]}return[e.x+e.w/2,e.y+.1*Math.min(e.w,e.h)]}_openingAmt(e){const t=e.contact&&this._renderOpeningEntityAvailable(e.contact)?this._renderPlanHass.states[e.contact]?.state:null;return ii(e.type,t,!!e.invert)}_planEntityAvailable(e){return!!e&&(!qh(this._fullRegistryHass,e,Lh(this._markers))&&"active"===this._bindingStatus("entity:"+e).kind)}_renderEntityAvailable(e){return!!e&&(!qh(this._renderPlanHass,e,Lh(this._markers))&&(!!this._renderPlanHass.entities?.[e]&&!!this._renderPlanHass.states?.[e]))}_openingEntityAvailable(e){return function(e,t,i=Vc(e)){return!!t&&"active"===th(e,`entity:${t}`,i).kind}(this.hass,e,this._haRegistry)}_renderOpeningEntityAvailable(e){return t=this._renderPlanHass,!!(i=e)&&!!t?.states?.[i];var t,i}_renderOpeningPlacementPreview(){return this._editorRuntimeOrThrow()._renderOpeningPlacementPreview()}_renderOpenings(e){const t=this._openingsR;if(!t.length)return W``;const i=this._spaceModel();if(!i)return W``;const n=e.color,r=this._spaceWalls,o=this._openCuts(),s=this._openingWallIndexFor(i,o).value;return W`${t.map(e=>{if(e.orphanReason)return W`{t.stopPropagation(),this._editOpening(e)}}> + + ! + `;const t=this._openingAmt(e),i=t>0&&!!e.contact&&this._renderOpeningEntityAvailable(e.contact)?"var(--hp-open)":n,o="gate"===e.type?!e.flip_v:e.flip_v,a=e.partitionHost||r.length||"gate"===e.type?this._openingFace(e,s,!!o):{ox:0,oy:0,cm:0,side:-1},l={type:e.type,length:e.rlen,angle:e.angle,amount:t,flipH:!!e.flip_h,flipV:!!e.flip_v,base:n,tone:i,cellCm:this._cellCm,gridPitch:this._gridPitch,face:a},{half:c,outlineHalf:h,hitHalf:d}=eu(l),u=xa(10,this._cellCm),p=xa(12,this._cellCm);return W` + ${tu(l)} + + this._opClick(t,e)} + @pointerdown=${t=>this._opPointerDown(t,e)} + @pointermove=${t=>this._opPointerMove(t,e)} + @pointerup=${t=>this._opPointerUp(t,e)} + @pointercancel=${t=>this._opPointerUp(t,e)}> + `})}`}_renderOpeningLocks(e){const t=this._openingsR.filter(e=>!e.orphanReason&&("door"===e.type||"gate"===e.type)&&e.lock&&this._renderOpeningEntityAvailable(e.lock));if(!t.length)return B``;const i=this._spaceModel();if(!i)return B``;const n=this._openCuts(),r=this._openingWallIndexFor(i,n).value;return B`${t.map(t=>{const i=this._renderPlanHass.states[t.lock]?.state,n="locked"===i,o=n||["unlocked","open","opening","unlocking","locking"].includes(String(i)),s=(t.angle+90)*Math.PI/180,a="gate"===t.type?this._openingFace(t,r,!t.flip_v):null,l=xa(16,this._cellCm),c=a?-l*a.side:l*(t.flip_v?-1:1),h=t.rx+Math.cos(s)*c,d=t.ry+Math.sin(s)*c,u=this._scenePoint([h,d]),p=(u[0]-e.x)/e.w*100,_=(u[1]-e.y)/e.h*100;return B`
{e.stopPropagation(),"view"===this._mode&&(this._openingInfo=t)}}> + +
`})}`}_lockAction(e,t){if(this._openingEntityAvailable(e)){if("unlock"===t){const t=this.hass?.states?.[e]?.attributes?.friendly_name||e;if(!confirm(this._t("confirm.unlock",{name:t})))return}this.hass?.callService?.("lock",t,{entity_id:e})}}_renderOpeningInfoCard(){const e=this._openingInfo,t="passage"!==e.type&&e.contact&&this._openingEntityAvailable(e.contact)?e.contact:null,i=("door"===e.type||"gate"===e.type)&&e.lock&&this._openingEntityAvailable(e.lock)?e.lock:null,n=t?this.hass.states[t]?.state:null,r=this._openingAmt(e),o=i?this.hass.states[i]?.state:null,s="door"===e.type?"opening.door":"gate"===e.type?"opening.gate":"passage"===e.type?"opening.passage":"opening.window",a="door"===e.type?"mdi:door":"gate"===e.type?"mdi:gate":"passage"===e.type?"mdi:arch":"mdi:window-closed-variant",l="gate"===e.type?r>0?"mdi:gate-open":"mdi:gate":r>0?"mdi:door-open":"mdi:door-closed",c=(e,t,i,n="")=>B`
${t}${i}
`;return B`this._openingInfo=null}> +
+ ${t?c(l,this._t("opening.contact_label"),"unavailable"===n||null==n?this._t("opening.state_unknown"):this._t(r>0?"opening.open":"opening.closed"),r>0?"warn":"ok"):G} + ${i?c("locked"===o?"mdi:lock":"mdi:lock-open-variant",this._t("opening.lock_label"),"locked"===o?this._t("opening.locked"):["unlocked","open"].includes(String(o))?this._t("opening.unlocked"):this._t("opening.state_unknown"),"locked"===o?"ok":"warn"):G} + ${i&&("locked"===o||["unlocked","open"].includes(String(o)))?B``:i&&["locking","unlocking"].includes(String(o))?B``:G} + ${t||i?G:B`

${this._t("opening.no_entities")}

`} +
+
+ + +
+
`}_renderOpeningDialog(){return this._editorRuntimeOrThrow()._renderOpeningDialog()}_gridLevels(){return this._editorRuntimeOrThrow()._gridLevels()}_renderMarkupDefs(e){return this._editorRuntimeOrThrow()._renderMarkupDefs(e)}_renderPhysicalEditorLayer(){return this._editorRuntimeOrThrow()._renderPhysicalEditorLayer()}_renderHiddenWallDiagnosticOverlay(){return this._editorRuntimeOrThrow()._renderHiddenWallDiagnosticOverlay()}_renderPlanSnapOverlay(){return this._editorRuntimeOrThrow()._renderPlanSnapOverlay()}_syncPlanSnapActiveMarker(e){return this._editorRuntimeOrThrow()._syncPlanSnapActiveMarker(e)}_syncPlanSnapConflictMarkers(e){return this._editorRuntimeOrThrow()._syncPlanSnapConflictMarkers(e)}_planSnapPhysicalSegment(e){return this._editorRuntimeOrThrow()._planSnapPhysicalSegment(e)}_drawPreviewJoinPatchD(e,t){return this._editorRuntimeOrThrow()._drawPreviewJoinPatchD(e,t)}_renderMarkupLayer(e){return this._editorRuntimeOrThrow()._renderMarkupLayer(e)}_renderActiveChainInk(){return this._editorRuntimeOrThrow()._renderActiveChainInk()}_renderPartitionDeleteDialog(){return this._editorRuntimeOrThrow()._renderPartitionDeleteDialog()}_renderRoomDeleteDialog(){return this._editorRuntimeOrThrow()._renderRoomDeleteDialog()}_renderPhysicalDialog(){return this._editorRuntimeOrThrow()._renderPhysicalDialog()}_renderMarkupBar(){return this._editorRuntimeOrThrow()._renderMarkupBar()}_renderDevicesBar(){return this._editorRuntimeOrThrow()._renderDevicesBar()}_renderDeviceInbox(){return this._editorRuntimeOrThrow()._renderDeviceInbox()}_cardEntities(e){const t=this._planHass,i=[],n=new Set,r=e=>{if(!e||n.has(e)||!t.states[e])return;const r=t.entities[e];if("config"===r?.entity_category||"diagnostic"===r?.entity_category)return;n.add(e);const o=e.split(".")[0];["light","switch","fan","humidifier","siren","input_boolean"].includes(o)?i.push({eid:e,kind:"toggle"}):["cover","valve","lock","climate","media_player","vacuum","water_heater"].includes(o)?i.push({eid:e,kind:"open"}):["sensor","binary_sensor","number","select"].includes(o)&&i.push({eid:e,kind:"value"})};for(const i of Mh(t,this._devices,null,this._virtualLights))if(i.device.id===e.id)for(const e of[...i.serviceEids,...i.stateEids])r(e);e.primary&&r(e.primary);for(const t of e.entities)r(t);return i.slice(0,12)}_cardToggle(e){const t=e.split(".")[0];"lock"!==t&&"alarm_control_panel"!==t&&this._planEntityAvailable(e)&&this.hass.callService("homeassistant","toggle",{entity_id:e}).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)})))}_renderInfoCard(){const e=this._infoCard,t=e.primary?this.hass.states[e.primary]:void 0,i=t?qi(this.hass,e.primary)?.text??t.state:null,n=(e.controls??e.marker?.controls??[]).filter(yn).filter(e=>this._planEntityAvailable(e));return B` +
+ ${(()=>{const t=this._cardEntities(e);return t.length?B`
+ ${t.map(({eid:e,kind:t})=>{const i=this.hass.states[e],n=this.hass.entities[e]?.name||i?.attributes?.friendly_name||e,r=i?qi(this.hass,e)?.text??i.state:"",o="on"===i?.state||["open","unlocked","playing","cleaning"].includes(i?.state);return B`
+ + ${n} + ${"toggle"===t?B``:"open"===t?B``:B`${r}`} +
`})} +
`:G})()} + ${e.model?B`
${this._t("info.model")}${e.model}
`:G} + ${i&&!this._cardEntities(e).length?B`
${this._t("info.state")}${i}
`:G} + ${Ci(e.link)?B`
${this._t("info.link")} + ${e.link}
`:G} + ${e.description?B`
${e.description}
`:G} + ${e.pdfs&&e.pdfs.length?B`
${this._t("info.manuals")} + ${e.pdfs.map(e=>B` + ${e.name}`)}
`:G} + ${n.length?B`
${this._t("info.controls")} + + ${n.map(e=>{const t=this.hass.states[e],i="on"===t?.state;return B` + + ${t?.attributes?.friendly_name||e}`})} +
`:G} + ${e.model||i||e.link||e.description||e.pdfs&&e.pdfs.length||n.length?G:B`
${this._t("info.none")}
`} +
+
+ + ${e.primary?B``:G} + +
+
`}_markerValueBadgeFields(e){return this._editorRuntimeOrThrow()._markerValueBadgeFields(e)}_markerDraft(e){return this._editorRuntimeOrThrow()._markerDraft(e)}_markerPreviewDevice(e){return this._editorRuntimeOrThrow()._markerPreviewDevice(e)}_markerPreviewDevices(e){return this._editorRuntimeOrThrow()._markerPreviewDevices(e)}_toggleIntent(e,t=this._devices){return this._editorRuntimeOrThrow()._toggleIntent(e,t)}_toggleIntentForDialog(e){return this._editorRuntimeOrThrow()._toggleIntentForDialog(e)}_toggleStateText(e,t){return this._editorRuntimeOrThrow()._toggleStateText(e,t)}_toggleConfirmationStateText(e){return this._editorRuntimeOrThrow()._toggleConfirmationStateText(e)}_toggleConfirmationLines(e){return this._editorRuntimeOrThrow()._toggleConfirmationLines(e)}_toggleHintLines(e){return this._editorRuntimeOrThrow()._toggleHintLines(e)}_effectiveStoredTapAction(e,t){return this._editorRuntimeOrThrow()._effectiveStoredTapAction(e,t)}_effectiveMarkerTapAction(e,t=this._markerPreviewDevice(e)){return this._editorRuntimeOrThrow()._effectiveMarkerTapAction(e,t)}_announceToggleDraft(e){return this._editorRuntimeOrThrow()._announceToggleDraft(e)}_valueBadgeForBinding(e,t){return this._editorRuntimeOrThrow()._valueBadgeForBinding(e,t)}_markerSpatialSource(e){return this._editorRuntimeOrThrow()._markerSpatialSource(e)}_markerAutoHasSpatialSource(e){return this._editorRuntimeOrThrow()._markerAutoHasSpatialSource(e)}_setMarkerLightRole(e){return this._editorRuntimeOrThrow()._setMarkerLightRole(e)}_controlRefInfo(e){return this._editorRuntimeOrThrow()._controlRefInfo(e)}_valueBadgeCandidateLabel(e){return this._editorRuntimeOrThrow()._valueBadgeCandidateLabel(e)}_controlCandidates(e){return this._editorRuntimeOrThrow()._controlCandidates(e)}_addControlRef(e,t){return this._editorRuntimeOrThrow()._addControlRef(e,t)}_setMarkerGlowMode(e){return this._editorRuntimeOrThrow()._setMarkerGlowMode(e)}_renderMarkerDialog(){return this._editorRuntimeOrThrow()._renderMarkerDialog()}_renderSpaceDialog(){return this._onboardingRuntime&&this._spaceDialog&&this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)?this._onboardingRuntime._renderSpaceDialog():this._editorRuntimeOrThrow()._renderSpaceDialog()}_renderMergeDialog(){return this._editorRuntimeOrThrow()._renderMergeDialog()}_renderCardPreview(e,t,i){const n=18*e;return B`
+ + ${this._t("preview.room_name")} + + 22.4° · + 45% · + ${this._t("roomcard.light_partial",{on:1,total:3})} + +
`}_renderRoomSource(e){return this._editorRuntimeOrThrow()._renderRoomSource(e)}_renderRoomDialog(){return this._editorRuntimeOrThrow()._renderRoomDialog()}}vm.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_editorRuntimeLoadingVisible:{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},_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},_deviceInbox:{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}},vm.ZOOM_MAX=8,vm.ZOOM_MIN=1/3,vm.styles=[Bd,Dp],customElements.get("houseplan-card")||customElements.define("houseplan-card",vm),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-card"===e.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${K_} `,"background:#3ea6ff;color:#04121f;font-weight:700","");export{Ao as $,G as A,Qt as B,Ia as C,le as D,U as E,Zt as F,Na as G,Td as H,Id as I,gs as J,lo as K,Pd as L,Md as M,No as N,vs as O,Cd as P,Bs as Q,Gs as R,vo as S,oi as T,ao as U,xo as V,Ku as W,Yu as X,ss as Y,Wr as Z,zo as _,o as a,ts as a$,no as a0,oo as a1,qr as a2,rp as a3,Ra as a4,Fo as a5,Ea as a6,Oo as a7,Ca as a8,Da as a9,ea as aA,Al as aB,op as aC,Rl as aD,Lp as aE,_s as aF,Ns as aG,ks as aH,Op as aI,hi as aJ,si as aK,$i as aL,va as aM,sa as aN,oa as aO,Pa as aP,Io as aQ,Eo as aR,Ls as aS,Kt as aT,tl as aU,ma as aV,_a as aW,Nn as aX,Hn as aY,pi as aZ,is as a_,Ui as aa,Gi as ab,Hi as ac,Li as ad,za as ae,ms as af,ns as ag,qs as ah,qo as ai,Xs as aj,ba as ak,sp as al,Qs as am,fs as an,ar as ao,sr as ap,or as aq,nn as ar,Ce as as,Qd as at,k_ as au,fo as av,qa as aw,Gt as ax,Vt as ay,Cr as az,B as b,Yi as b$,W as b0,Pp as b1,Fp as b2,kr as b3,Mr as b4,Sr as b5,vr as b6,ja as b7,_r as b8,gr as b9,Fd as bA,wi as bB,li as bC,ei as bD,ci as bE,Lo as bF,Si as bG,mn as bH,mu as bI,gu as bJ,uh as bK,_d as bL,Ai as bM,Ii as bN,En as bO,Cn as bP,Eh as bQ,ro as bR,Hh as bS,Ih as bT,tn as bU,Qi as bV,Ji as bW,Sa as bX,tp as bY,Xi as bZ,Zi as b_,br as ba,On as bb,pr as bc,fr as bd,mr as be,xr as bf,gl as bg,dl as bh,ml as bi,ul as bj,bl as bk,sl as bl,hl as bm,Ho as bn,_o as bo,xa as bp,eu as bq,zd as br,U_ as bs,Od as bt,Vs as bu,L_ as bv,G_ as bw,Zu as bx,ti as by,Dd as bz,he as c,co as c$,Ki as c0,$a as c1,Hp as c2,zp as c3,rn as c4,Kr as c5,lr as c6,De as c7,Fe as c8,Ae as c9,vd as cA,kd as cB,$d as cC,Rh as cD,Mh as cE,kh as cF,_h as cG,yn as cH,dh as cI,Nh as cJ,gn as cK,Pu as cL,ou as cM,xh as cN,$h as cO,mh as cP,cd as cQ,Oi as cR,Di as cS,su as cT,Ci as cU,Ma as cV,zi as cW,Pi as cX,so as cY,cl as cZ,vl as c_,Bl as ca,Kl as cb,Vi as cc,nc as cd,jl as ce,El as cf,Yl as cg,Wl as ch,Ul as ci,ec as cj,tc as ck,Ql as cl,ic as cm,zl as cn,Dn as co,An as cp,ii as cq,q_ as cr,tu as cs,H_ as ct,nl as cu,ys as cv,Vo as cw,Ko as cx,fu as cy,Uh as cz,Bd as d,ri as d0,Fa as d1,Zd as d2,vm as d3,pe as e,Hu as f,Lu as g,ui as h,_e as i,Tr as j,fi as k,Xd as l,Ol as m,Nt as n,yi as o,gi as p,Lh as q,ju as r,qt as s,Jd as t,qh as u,nu as v,yu as w,Jt as x,wn as y,Pn as z}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js b/custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js new file mode 100644 index 00000000..cb04dde5 --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js @@ -0,0 +1,2572 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";import{e as t,i as e,E as s,D as i,b as o,A as a,a as n,c as r,s as l,m as h,d as c,l as d,t as p,w as _,f as u,g as m,v as g,r as f,h as b,j as y,p as v,k as $,n as w,o as k,q as x,u as S,x as M,y as D,z as C,B as P,G as I,C as T,F as R,H as F,I as N,J as z,K as A,L as O,M as L,N as E,O as B,P as H,Q as G,R as W,S as j,T as q,U,V as K,W as V,X as J,Y,Z as X,_ as Z,$ as Q,a0 as tt,a1 as et,a2 as st,a3 as it,a4 as ot,a5 as at,a6 as nt,a7 as rt,a8 as lt,a9 as ht,aa as ct,ab as dt,ac as pt,ad as _t,ae as ut,af as mt,ag as gt,ah as ft,ai as bt,aj as yt,ak as vt,al as $t,am as wt,an as kt,ao as xt,ap as St,aq as Mt,ar as Dt,as as Ct,at as Pt,au as It,av as Tt,aw as Rt,ax as Ft,ay as Nt,az as zt,aA as At,aB as Ot,aC as Lt,aD as Et,aE as Bt,aF as Ht,aG as Gt,aH as Wt,aI as jt,aJ as qt,aK as Ut,aL as Kt,aM as Vt,aN as Jt,aO as Yt,aP as Xt,aQ as Zt,aR as Qt,aS as te,aT as ee,aU as se,aV as ie,aW as oe,aX as ae,aY as ne,aZ as re,a_ as le,a$ as he,b0 as ce,b1 as de,b2 as pe,b3 as _e,b4 as ue,b5 as me,b6 as ge,b7 as fe,b8 as be,b9 as ye,ba as ve,bb as $e,bc as we,bd as ke,be as xe,bf as Se,bg as Me,bh as De,bi as Ce,bj as Pe,bk as Ie,bl as Te,bm as Re,bn as Fe,bo as Ne,bp as ze,bq as Ae,br as Oe,bs as Le,bt as Ee,bu as Be,bv as He,bw as Ge,bx as We,by as je,bz as qe,bA as Ue,bB as Ke,bC as Ve,bD as Je,bE as Ye,bF as Xe,bG as Ze,bH as Qe,bI as ts,bJ as es,bK as ss,bL as is,bM as os,bN as as,bO as ns,bP as rs,bQ as ls,bR as hs,bS as cs,bT as ds,bU as ps,bV as _s,bW as us,bX as ms,bY as gs,bZ as fs,b_ as bs,b$ as ys,c0 as vs,c1 as $s,c2 as ws,c3 as ks,c4 as xs,c5 as Ss,c6 as Ms,c7 as Ds,c8 as Cs,c9 as Ps,ca as Is,cb as Ts,cc as Rs,cd as Fs,ce as Ns,cf as zs,cg as As,ch as Os,ci as Ls,cj as Es,ck as Bs,cl as Hs,cm as Gs,cn as Ws,co as js,cp as qs,cq as Us,cr as Ks,cs as Vs,ct as Js,cu as Ys,cv as Xs,cw as Zs,cx as Qs,cy as ti,cz as ei,cA as si,cB as ii,cC as oi,cD as ai,cE as ni,cF as ri,cG as li,cH as hi,cI as ci,cJ as di,cK as pi,cL as _i,cM as ui,cN as mi,cO as gi,cP as fi,cQ as bi,cR as yi,cS as vi,cT as $i,cU as wi,cV as ki,cW as xi,cX as Si,cY as Mi,cZ as Di,c_ as Ci,c$ as Pi,d0 as Ii,d1 as Ti}from"./houseplan-card-OQuczTJf.js";import{i as Ri,c as Fi,a as Ni,s as zi,t as Ai}from"./space-deletion-7mvB_XVT.js";const Oi={},Li=t(class extends e{constructor(){super(...arguments),this.ot=Oi}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 s}else if(this.ot===e)return s;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}}),Ei=(t,e,s)=>Math.min(s,Math.max(e,Number.isFinite(t)?t:e));function Bi(t){return Number.isFinite(t)?(t%360+360)%360:0}function Hi(t){if("string"!=typeof t)return null;const e=t.trim().replace(/^#/,""),s=/^[0-9a-fA-F]{3}$/.test(e)?e.split("").map(t=>`${t}${t}`).join(""):e;return/^[0-9a-fA-F]{6}$/.test(s)?`#${s.toLowerCase()}`:null}function Gi(t){const e=Hi(t);return e?{r:Number.parseInt(e.slice(1,3),16),g:Number.parseInt(e.slice(3,5),16),b:Number.parseInt(e.slice(5,7),16)}:null}function Wi(t){const e=Ei(t.r,0,255)/255,s=Ei(t.g,0,255)/255,i=Ei(t.b,0,255)/255,o=Math.max(e,s,i),a=o-Math.min(e,s,i);let n=0;return a>0&&(n=o===e?(s-i)/a%6*60:o===s?60*((i-e)/a+2):60*((e-s)/a+4)),{h:Bi(n),s:0===o?0:a/o*100,v:100*o}}function ji(t){return function(t){const e=t=>Math.round(Ei(t,0,255)).toString(16).padStart(2,"0");return`#${e(t.r)}${e(t.g)}${e(t.b)}`}(function(t){const e=Bi(t.h),s=Ei(t.s,0,100)/100,i=Ei(t.v,0,100)/100,o=i*s,a=o*(1-Math.abs(e/60%2-1)),n=i-o;let r;return r=e<60?[o,a,0]:e<120?[a,o,0]:e<180?[0,o,a]:e<240?[0,a,o]:e<300?[a,0,o]:[o,0,a],{r:Math.round(255*(r[0]+n)),g:Math.round(255*(r[1]+n)),b:Math.round(255*(r[2]+n))}}(t))}function qi(t){const e=t.visualViewport;return e&&Number.isFinite(e.width)&&Number.isFinite(e.height)?{left:Number(e.offsetLeft)||0,top:Number(e.offsetTop)||0,width:Math.max(0,Number(e.width)||0),height:Math.max(0,Number(e.height)||0)}:{left:0,top:0,width:t.innerWidth,height:t.innerHeight}}function Ui(t,e,s,i=7,o=8){const a=s.left+o,n=s.top+o,r=Math.max(a,s.left+s.width-o),l=Math.max(n,s.top+s.height-o),h=Math.max(0,r-a),c=Math.max(0,l-n),d=Math.min(Math.max(0,e.width),h),p=Math.min(Math.max(0,e.height),c);let _=t.left;_+d>r&&(_=t.right-d),_=Math.min(Math.max(a,_),Math.max(a,r-d));const u=t.bottom+i,m=t.top-i-p;let g="bottom",f=u;return u+p>l&&m>=n?(g="top",f=Math.min(Math.max(n,m),Math.max(n,l-p))):f=Math.min(Math.max(n,u),Math.max(n,l-p)),{left:Math.round(_),top:Math.round(f),side:g,maxWidth:Math.round(h),maxHeight:Math.round(c)}}class Ki{constructor(t,e,s){this.owner=t,this.name=e,this.keydown=s,this.host=null,this.root=null}window(){return this.owner.ownerDocument.defaultView}dialog(){return this.owner.closest("hp-dialog")}usesPopover(t=!1){const e=this.window();return!t&&!!e&&function(t){const e=t.HTMLElement?.prototype;return"function"==typeof e?.showPopover&&"function"==typeof e?.hidePopover}(e)}get hasFallback(){return!!this.host}containsPath(t){return t.includes(this.owner)||!!this.host&&t.includes(this.host)}ownsActiveElement(){let t=this.owner.ownerDocument.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return!(!t||t!==this.owner&&!this.owner.shadowRoot?.contains(t)&&!this.root?.contains(t))}renderFallback(t,e){const s=this.ensureFallback();return s?(i(o`${t}`,s),s):null}surface(t,e){return e?this.owner.shadowRoot?.querySelector(t)||null:this.root?.querySelector(t)||null}destroy(){this.root&&i(a,this.root),this.host?.remove(),this.host=null,this.root=null}ensureFallback(){if(this.root?.isConnected)return this.root;const t=this.dialog()?.overlayPortal()||this.owner.ownerDocument.body;if(!t)return null;const e=this.owner.ownerDocument.createElement("div");return e.dataset.hpOverlay=this.name,e.style.display="contents",this.keydown&&e.addEventListener("keydown",this.keydown,!0),t.append(e),this.host=e,this.root=e.attachShadow({mode:"open"}),this.root}}const Vi={title:"Color picker",hue:"Hue",saturation:"Saturation",value:"Brightness",hex:"Hex color",invalidHex:"Enter a 3- or 6-digit hex color"};class Ji extends r{constructor(){super(...arguments),this.label="",this.opacityLabel="Opacity",this.color="#607d8b",this.opacity=1,this.disabled=!1,this.showOpacity=!0,this.pickerLabels=Vi,this._open=!1,this._pickerRaf=0,this._emitRaf=0,this._forceFallback=!1,this._overlayDispose=null,this._hue=0,this._saturation=0,this._value=0,this._hexDraft="#607d8b",this._hexInvalid=!1,this._lastValidColor="#607d8b",this._activePointerId=null,this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closePicker(!1,"outside")},this._keyDown=t=>{this._open&&"Escape"===t.key&&(t.preventDefault(),t.stopImmediatePropagation(),this._closePicker(this._floating.ownsActiveElement(),"escape"))},this._floating=new Ki(this,"color-opacity",this._keyDown),this._queuePickerPosition=()=>{if(!this._open)return;this._pickerRaf&&cancelAnimationFrame(this._pickerRaf);const t=this._window();t&&(this._pickerRaf=t.requestAnimationFrame(()=>{this._pickerRaf=0,this._positionPicker()||this._closePicker()}))}}connectedCallback(){super.connectedCallback(),this._syncFromColor(this.color,!1),this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.addEventListener("resize",this._queuePickerPosition),t?.addEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.addEventListener("resize",this._queuePickerPosition),t?.visualViewport?.addEventListener("scroll",this._queuePickerPosition),this.addEventListener("keydown",this._keyDown,!0)}disconnectedCallback(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.removeEventListener("resize",this._queuePickerPosition),t?.removeEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.removeEventListener("resize",this._queuePickerPosition),t?.visualViewport?.removeEventListener("scroll",this._queuePickerPosition),this.removeEventListener("keydown",this._keyDown,!0),this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._pickerRaf=0,this._emitRaf=0,this._closePicker(!1,"disconnect"),super.disconnectedCallback()}updated(t){if(t.has("color")){const t=Hi(this.color);t&&t!==this._lastValidColor&&this._syncFromColor(t,this._open)}this.disabled&&this._open?this._closePicker():this._open&&(this._supportsPopover()||this._renderFallback(),(t.has("color")||t.has("opacity")||t.has("showOpacity")||t.has("label")||t.has("opacityLabel")||t.has("pickerLabels"))&&this._queuePickerPosition())}_window(){return this._floating.window()}_supportsPopover(){return this._floating.usesPopover(this._forceFallback)}_dialog(){return this._floating.dialog()}async _toggle(){this.disabled||(this._open?this._closePicker():(this._forceFallback=!1,this._syncFromColor(this.color,!1),this._hexInvalid=!1,this._activePointerId=null,this._open=!0,await this.updateComplete,this._open&&(this._supportsPopover()||this._renderFallback(),this._positionPicker()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closePicker("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closePicker())))}_closePicker(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;const s=this._overlayDispose;this._overlayDispose=null,s?.();const i=this.renderRoot.querySelector(".picker");if(i?.hidePopover)try{i.matches(":popover-open")&&i.hidePopover()}catch{}this._open=!1,this._cancelQueuedEmit(),this._activePointerId=null,this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_surface(){return this._floating.surface(".picker",this._supportsPopover())}_renderFallback(){const t=Ji.styles.cssText;this._floating.renderFallback(this._pickerTemplate(!1),t)}_positionPicker(){if(!this._open)return!1;const t=this._window(),e=this.renderRoot.querySelector(".trigger");let s=this._surface();if(!t||!e?.isConnected||!s?.isConnected)return!1;const i=qi(t);if(s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden",this._supportsPopover()&&s.showPopover)try{s.matches(":popover-open")||s.showPopover()}catch{if(this._forceFallback=!0,this._renderFallback(),s=this._surface(),!s?.isConnected)return!1;s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden"}const o=e.getBoundingClientRect(),a=s.getBoundingClientRect();if(!(o.width&&o.height&&a.width&&a.height))return!1;const n=Ui(o,a,i);return s.style.left=`${n.left}px`,s.style.top=`${n.top}px`,s.dataset.side=n.side,s.style.visibility="",!0}_labels(){const t=this.pickerLabels||Vi;return{title:t.title||Vi.title,hue:t.hue||Vi.hue,saturation:t.saturation||Vi.saturation,value:t.value||Vi.value,hex:t.hex||Vi.hex,invalidHex:t.invalidHex||Vi.invalidHex}}_syncFromColor(t,e){const s=Hi(l(t,"#607d8b"))||"#607d8b",i=Gi(s);if(!i)return;const o=Wi(i);(!e||o.s>1e-4)&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._hexDraft=s,this._hexInvalid=!1,this._lastValidColor=s}_cancelQueuedEmit(t=!1){this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._emitRaf=0,t&&this._syncFromColor(this._lastValidColor,!0)}_queueHsvEmit(){if(this._emitRaf)return;const t=this._window();t?this._emitRaf=t.requestAnimationFrame(()=>{this._emitRaf=0,this._emitHsv()}):this._emitHsv()}_emitHsv(){this._emit(ji({h:this._hue,s:this._saturation,v:this._value}),this.opacity)}_setHue(t){this._hue=Math.min(359,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setSaturation(t){this._saturation=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setValue(t){this._value=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setOpacity(t){this._emit(this._lastValidColor,t)}_shiftRangeKey(t,e,s,i,o){if(!t.shiftKey)return;const a="ArrowRight"===t.key||"ArrowUp"===t.key?10:"ArrowLeft"===t.key||"ArrowDown"===t.key?-10:0;a&&(t.preventDefault(),t.stopPropagation(),o(Math.min(i,Math.max(s,e+a))))}_setSvFromPointer(t,e){const s=t.currentTarget.getBoundingClientRect();s.width&&s.height&&(this._saturation=Math.min(100,Math.max(0,(t.clientX-s.left)/s.width*100)),this._value=Math.min(100,Math.max(0,100*(1-(t.clientY-s.top)/s.height))),e?(this._cancelQueuedEmit(),this._emitHsv()):this._queueHsvEmit())}_svPointerDown(t){if(t.preventDefault(),t.stopPropagation(),null===this._activePointerId){this._activePointerId=t.pointerId;try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}this._setSvFromPointer(t,!0)}}_svPointerMove(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!1))}_svPointerUp(t){if(t.pointerId===this._activePointerId){t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!0),this._activePointerId=null;try{t.currentTarget.releasePointerCapture(t.pointerId)}catch{}}}_svPointerCancel(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._activePointerId=null,this._cancelQueuedEmit(!0))}_svLostPointerCapture(t){t.pointerId===this._activePointerId&&(this._activePointerId=null,this._cancelQueuedEmit(!0))}_hexInput(t){const e=t.target.value;this._hexDraft=e,this._hexInvalid=!1;const s=Hi(e),i=s?Gi(s):null;if(!s||!i)return;const o=Wi(i);o.s>1e-4&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._emit(s,this.opacity,!0)}_commitHex(){const t=Hi(this._hexDraft);if(!t)return this._hexDraft=this._lastValidColor,void(this._hexInvalid=!0);this._hexDraft=t,this._hexInvalid=!1,t!==this._lastValidColor&&this._emit(t,this.opacity)}_hexKeyDown(t){"Enter"===t.key&&(t.preventDefault(),t.stopPropagation(),this._commitHex())}_emit(t,e,s=!1){const i=Hi(t)||this._lastValidColor,o=Number.isFinite(e)?e:Number(this.opacity)||0,a=Math.min(1,Math.max(0,o));this.color=i,this.opacity=a,this._lastValidColor=i,s||(this._hexDraft=i),this._hexInvalid=!1,this.dispatchEvent(new CustomEvent("hp-color-opacity-change",{detail:{color:i,opacity:a},bubbles:!0,composed:!0}))}_pickerTemplate(t){const e=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),s=ji({h:this._hue,s:this._saturation,v:this._value}),i=ji({h:this._hue,s:100,v:100}),n=this._labels(),r=Math.round(this._hue),l=Math.round(this._saturation),h=Math.round(this._value);return o` + `}render(){const t=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),e=l(this.color,"#607d8b"),s=this.showOpacity?`${this.label||"Color"}: ${e}, ${t}%`:`${this.label||"Color"}: ${e}`;return o` + ${this.label?o`${this.label}`:a} + + ${this._open&&!this.disabled&&this._supportsPopover()?this._pickerTemplate(!0):a} + `}}Ji.properties={label:{type:String},opacityLabel:{type:String,attribute:"opacity-label"},color:{type:String},opacity:{type:Number},disabled:{type:Boolean,reflect:!0},showOpacity:{type:Boolean,attribute:"show-opacity"},pickerLabels:{attribute:!1},_open:{state:!0},_hue:{state:!0},_saturation:{state:!0},_value:{state:!0},_hexDraft:{state:!0},_hexInvalid:{state:!0}},Ji.styles=n` + :host { + position: relative; + display: inline-flex; + align-items: center; + gap: 6px; + min-width: 0; + } + .label { + font-size: 12px; + color: var(--secondary-text-color, #9aa4ad); + white-space: nowrap; + } + .trigger { + width: 40px; + height: 40px; + flex: none; + box-sizing: border-box; + padding: 3px; + border: 1px solid var(--divider-color, #666); + border-radius: 7px; + background: + linear-gradient(45deg, #b8b8b8 25%, transparent 25%) 0 0 / 10px 10px, + linear-gradient(45deg, transparent 75%, #b8b8b8 75%) 0 0 / 10px 10px, + linear-gradient(45deg, transparent 75%, #b8b8b8 75%) 5px -5px / 10px 10px, + linear-gradient(45deg, #b8b8b8 25%, #eee 25%) 5px 5px / 10px 10px; + cursor: pointer; + } + :host([data-pointer-hover]) .trigger:hover { + border-color: var(--primary-color, #03a9f4); + } + .trigger[aria-expanded='true'] { + border-color: var(--primary-color, #03a9f4); + outline: none; + box-shadow: 0 0 0 1px var(--primary-color, #03a9f4); + } + .trigger:focus-visible { + border-color: var(--primary-color, #03a9f4); + outline: 2px solid var(--primary-color, #03a9f4); + outline-offset: 2px; + } + .swatch { + display: block; + width: 100%; + height: 100%; + border-radius: 3px; + box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.18); + pointer-events: none; + } + .picker { + /* The popover attribute promotes this surface into the browser top layer, outside + hp-dialog's scrolling/clipping body. JS supplies viewport coordinates. */ + position: fixed; + z-index: 2147483647; + inset: auto; + top: 0; + left: 0; + width: min(292px, calc(100vw - 16px)); + max-height: calc(100vh - 16px); + margin: 0; + box-sizing: border-box; + display: grid; + gap: 10px; + padding: 12px; + overflow: auto; + color: var(--primary-text-color, #fff); + background: var(--card-background-color, #202126); + border: 1px solid var(--primary-color, #03a9f4); + border-radius: 10px; + box-shadow: 0 10px 28px rgb(0 0 0 / 0.34); + } + .picker[popover]:not(:popover-open) { + /* Keep the author-level display:grid from exposing the surface for one + frame before showPopover() promotes it into the top layer. */ + display: none; + } + .picker-head, + .row, + .control-head { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; + } + .picker-head { + justify-content: space-between; + } + .caption { + flex: 1; + min-width: 0; + overflow: hidden; + color: var(--secondary-text-color, #9aa4ad); + font-size: 12px; + text-overflow: ellipsis; + white-space: nowrap; + } + .preview { + width: 52px; + height: 30px; + flex: none; + box-sizing: border-box; + padding: 3px; + border: 1px solid var(--divider-color, #666); + border-radius: 7px; + background: + linear-gradient(45deg, #b8b8b8 25%, transparent 25%) 0 0 / 10px 10px, + linear-gradient(45deg, transparent 75%, #b8b8b8 75%) 0 0 / 10px 10px, + linear-gradient(45deg, transparent 75%, #b8b8b8 75%) 5px -5px / 10px 10px, + linear-gradient(45deg, #b8b8b8 25%, #eee 25%) 5px 5px / 10px 10px; + } + .preview > span { + display: block; + width: 100%; + height: 100%; + border-radius: 3px; + } + .sv-field { + position: relative; + width: 100%; + height: 132px; + overflow: hidden; + box-sizing: border-box; + border: 1px solid var(--divider-color, #666); + border-radius: 8px; + background: + linear-gradient(to top, #000, transparent), + linear-gradient(to right, #fff, var(--hp-picker-hue, #f00)); + cursor: crosshair; + touch-action: none; + user-select: none; + } + .sv-thumb { + position: absolute; + left: var(--hp-picker-saturation, 0%); + top: var(--hp-picker-value, 100%); + width: 14px; + height: 14px; + box-sizing: border-box; + border: 2px solid #fff; + border-radius: 50%; + box-shadow: 0 0 0 1px rgb(0 0 0 / .65), 0 1px 3px rgb(0 0 0 / .5); + transform: translate(-50%, -50%); + pointer-events: none; + } + .control { + display: grid; + gap: 2px; + min-width: 0; + } + .control-value { + flex: none; + color: var(--secondary-text-color, #9aa4ad); + font-size: 12px; + } + input[type='range'] { + width: auto; + height: 40px; + min-width: 0; + flex: 1; + margin: -5px 0; + accent-color: var(--primary-color, #03a9f4); + touch-action: none; + } + .hue-range { + accent-color: var(--hp-picker-hue, #f00); + --hp-picker-hue-track: linear-gradient(to right, + #f00 0%, #ff0 16.667%, #0f0 33.333%, #0ff 50%, + #00f 66.667%, #f0f 83.333%, #f00 100%); + --hp-picker-hue-thumb-shadow: + 0 0 0 2px var(--card-background-color, #202126), + 0 0 0 3px var(--primary-text-color, #fff); + } + .hue-range::-webkit-slider-runnable-track { + height: 10px; + box-sizing: border-box; + border: 1px solid var(--divider-color, #666); + border-radius: 999px; + background: var(--hp-picker-hue-track); + } + .hue-range::-moz-range-track { + height: 10px; + box-sizing: border-box; + border: 1px solid var(--divider-color, #666); + border-radius: 999px; + background: var(--hp-picker-hue-track); + } + .hue-range::-moz-range-progress { + height: 10px; + border: 0; + border-radius: 999px; + background: transparent; + } + .hue-range::-webkit-slider-thumb { + border-radius: 50%; + box-shadow: var(--hp-picker-hue-thumb-shadow); + } + .hue-range::-moz-range-thumb { + border-radius: 50%; + box-shadow: var(--hp-picker-hue-thumb-shadow); + } + input[type='text'], + input[type='number'] { + min-height: 40px; + box-sizing: border-box; + border: 1px solid var(--divider-color, #666); + border-radius: 6px; + padding: 6px 8px; + color: var(--primary-text-color, #fff); + background: var(--input-fill-color, transparent); + font: inherit; + } + input[type='text'] { + width: 100%; + } + input[type='number'] { + width: 50px; + flex: none; + } + input:focus-visible, + .sv-field:focus-visible { + outline: 2px solid var(--primary-color, #03a9f4); + outline-offset: 1px; + } + input[aria-invalid='true'] { + border-color: var(--error-color, #db4437); + } + .error { + color: var(--error-color, #db4437); + font-size: 11px; + line-height: 1.25; + } + .pct { + color: var(--secondary-text-color, #9aa4ad); + font-size: 12px; + } + :host([disabled]) { + opacity: .5; + pointer-events: none; + } + @media (prefers-reduced-motion: reduce) { + .picker { transition: none !important; } + } + @media (forced-colors: active) { + .hue-range::-webkit-slider-runnable-track { + border-color: ButtonText; + background: Canvas; + } + .hue-range::-moz-range-track { + border-color: ButtonText; + background: Canvas; + } + .hue-range::-webkit-slider-thumb { + box-shadow: none; + } + .hue-range::-moz-range-thumb { + box-shadow: none; + } + } + `,customElements.get("hp-color-opacity")||customElements.define("hp-color-opacity",Ji);let Yi=0;class Xi extends r{constructor(){super(...arguments),this.text="",this.ariaLabel="",this.pointerHover=!1,this._open=!1,this._openTimer=0,this._closeTimer=0,this._positionRaf=0,this._forceFallback=!1,this._hoverOwned=!1,this._overlayDispose=null,this._scrollDialog=null,this._descriptionId="hp-help-description-"+ ++Yi,this._surfacePointerEnter=()=>{const t=this._window();this._closeTimer&&t?.clearTimeout(this._closeTimer),this._closeTimer=0},this._surfacePointerLeave=()=>{this._scheduleClose()},this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closeHelp(!1,"outside")},this._dialogScroll=t=>{const e=this._floating.containsPath(t.composedPath()),s=t.target,i=this._dialog(),o=s instanceof Node&&(s===i||s instanceof Element&&s.contains(this));var a;this._open&&(a=o,!e&&a)&&this._closeHelp(!1,"scroll")},this._keyDown=t=>{if(!this._open||t.defaultPrevented)return;if("Escape"===t.key)return t.preventDefault(),t.stopImmediatePropagation(),void this._closeHelp(this._floating.ownsActiveElement(),"escape");const e=this.renderRoot.querySelector(".trigger");if(!e||!t.composedPath().includes(e))return;const s=this._surface();if(!s||s.scrollHeight<=s.clientHeight)return;const i=Math.max(40,.8*s.clientHeight),o={ArrowDown:40,ArrowUp:-40,PageDown:i,PageUp:-i};if("Home"===t.key)s.scrollTop=0;else if("End"===t.key)s.scrollTop=s.scrollHeight;else{if(!(t.key in o))return;s.scrollBy({top:o[t.key],behavior:"auto"})}t.preventDefault(),t.stopImmediatePropagation()},this._floating=new Ki(this,"help",this._keyDown),this._queuePosition=()=>{if(!this._open||this._positionRaf)return;const t=this._window();t&&(this._positionRaf=t.requestAnimationFrame(()=>{this._positionRaf=0,this._position()||this._closeHelp()}))}}connectedCallback(){super.connectedCallback(),this.addEventListener("keydown",this._keyDown,!0)}willUpdate(){this.toggleAttribute("data-has-content",this._hasContent())}disconnectedCallback(){const t=this.ownerDocument.defaultView;this._unsubscribeOpenListeners(),this.removeEventListener("keydown",this._keyDown,!0),this._clearTimers(),this._positionRaf&&t?.cancelAnimationFrame(this._positionRaf),this._positionRaf=0,this._closeHelp(!1,"disconnect"),super.disconnectedCallback()}updated(t){if(t.has("pointerHover")&&!this.pointerHover){const t=this._window();this._openTimer&&t?.clearTimeout(this._openTimer),this._openTimer=0,this._hoverOwned&&this._closeHelp(!1,"outside")}this._hasContent()||!this._open?this._open&&t.has("text")&&(this._usesPopover()||this._renderFallback(),this._queuePosition()):this._closeHelp()}_window(){return this._floating.window()}_dialog(){return this._floating.dialog()}_usesPopover(){return this._floating.usesPopover(this._forceFallback)}_hasContent(){return t=this.text,e=this.ariaLabel,"string"==typeof t&&t.trim().length>0&&"string"==typeof e&&e.trim().length>0;var t,e}_clearTimers(){const t=this._window();this._openTimer&&t?.clearTimeout(this._openTimer),this._closeTimer&&t?.clearTimeout(this._closeTimer),this._openTimer=0,this._closeTimer=0}_scheduleOpen(){const t=this._window();this.pointerHover&&t&&!this._open&&!this._openTimer&&(this._closeTimer&&t.clearTimeout(this._closeTimer),this._closeTimer=0,this._openTimer=t.setTimeout(()=>{this._openTimer=0,this.isConnected&&(this._hoverOwned=!0,this._openHelp())},300))}_scheduleClose(){const t=this._window(),e=this.renderRoot.querySelector(".trigger");t&&!e?.matches(":focus-visible")&&(this._openTimer&&t.clearTimeout(this._openTimer),this._closeTimer&&t.clearTimeout(this._closeTimer),this._openTimer=0,this._closeTimer=t.setTimeout(()=>{this._closeTimer=0,this.isConnected&&this._closeHelp()},150))}_triggerPointerEnter(t){this.pointerHover&&"mouse"===t.pointerType&&this._scheduleOpen()}_triggerPointerLeave(t){"mouse"===t.pointerType&&this._scheduleClose()}_triggerFocus(){queueMicrotask(()=>{const t=this.renderRoot.querySelector(".trigger");t?.matches(":focus-visible")&&(this._hoverOwned=!1,this._openHelp())})}_triggerBlur(){this._scheduleClose()}_triggerClick(){this._open?this._closeHelp():(this._hoverOwned=!1,this._openHelp())}_subscribeOpenListeners(){this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("keydown",this._keyDown,!0);const t=this._window();t?.addEventListener("resize",this._queuePosition),t?.addEventListener("orientationchange",this._queuePosition),t?.visualViewport?.addEventListener("resize",this._queuePosition),t?.visualViewport?.addEventListener("scroll",this._queuePosition),this._scrollDialog=this._dialog(),this._scrollDialog?.addEventListener("scroll",this._dialogScroll,!0)}_unsubscribeOpenListeners(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("keydown",this._keyDown,!0);const t=this._window();t?.removeEventListener("resize",this._queuePosition),t?.removeEventListener("orientationchange",this._queuePosition),t?.visualViewport?.removeEventListener("resize",this._queuePosition),t?.visualViewport?.removeEventListener("scroll",this._queuePosition),this._scrollDialog?.removeEventListener("scroll",this._dialogScroll,!0),this._scrollDialog=null}async _openHelp(){!this._open&&this._hasContent()&&(this._clearTimers(),this._forceFallback=!1,this._open=!0,this._subscribeOpenListeners(),await this.updateComplete,this._open&&(this._usesPopover()||this._renderFallback(),this._position()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closeHelp("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closeHelp()))}_closeHelp(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;this._clearTimers();const s=this._overlayDispose;this._overlayDispose=null,s?.();const i=this.renderRoot.querySelector(".tooltip");if(i?.hidePopover)try{i.matches(":popover-open")&&i.hidePopover()}catch{}this._open=!1,this._hoverOwned=!1,this._unsubscribeOpenListeners(),this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_tooltipTemplate(t){return o``}_renderFallback(){const t=Xi.styles.cssText;this._floating.renderFallback(this._tooltipTemplate(!1),t)}_surface(){return this._floating.surface(".tooltip",this._usesPopover())}_position(){if(!this._open)return!1;const t=this._window(),e=this.renderRoot.querySelector(".trigger");let s=this._surface();if(!t||!e?.isConnected||!s?.isConnected)return!1;const i=qi(t);if(s.style.maxWidth=`${Math.max(0,Math.min(320,i.width-16))}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden",this._usesPopover()&&s.showPopover)try{s.matches(":popover-open")||s.showPopover()}catch{if(this._forceFallback=!0,this._renderFallback(),s=this._surface(),!s?.isConnected)return!1;s.style.visibility="hidden"}const o=e.getBoundingClientRect(),a=s.getBoundingClientRect();if(!(o.width&&o.height&&a.width&&a.height))return!1;const n=Ui(o,a,i);return s.style.left=`${n.left}px`,s.style.top=`${n.top}px`,s.dataset.side=n.side,s.style.visibility="",!0}render(){if(!this._hasContent())return a;const t=this.ariaLabel.trim();return o` + ${this.text} + + ${this._usesPopover()?this._tooltipTemplate(!0):a} + `}}Xi.properties={text:{type:String},ariaLabel:{type:String,attribute:"aria-label"},pointerHover:{type:Boolean,attribute:"data-pointer-hover",reflect:!0},_open:{state:!0},_forceFallback:{state:!0}},Xi.styles=n` + :host { + display: none; + flex: none; + vertical-align: middle; + } + + :host([data-has-content]) { + display: inline-flex; + } + + .trigger { + width: 32px; + height: 32px; + display: inline-flex; + align-items: center; + justify-content: center; + flex: none; + box-sizing: border-box; + padding: 0; + color: var(--secondary-text-color, #9aa4ad); + background: transparent; + border: 0; + border-radius: 50%; + cursor: help; + -webkit-tap-highlight-color: transparent; + } + + .trigger svg { + display: block; + width: 18px; + height: 18px; + fill: currentColor; + } + + :host([data-pointer-hover]) .trigger:hover, + .trigger:focus-visible, + .trigger[aria-expanded='true'] { + color: var(--primary-text-color, #fff); + background: rgb(127 127 127 / 0.18); + outline: none; + } + + .trigger:focus-visible { + box-shadow: 0 0 0 2px var(--primary-color, #03a9f4); + } + + .tooltip { + position: fixed; + z-index: 2147483647; + inset: auto; + top: 0; + left: 0; + width: max-content; + max-width: min(320px, calc(100vw - 16px)); + max-height: calc(100vh - 16px); + margin: 0; + box-sizing: border-box; + padding: 9px 11px; + overflow: auto; + color: var(--primary-text-color, #fff); + background: var(--card-background-color, #202126); + border: 1px solid var(--divider-color, rgb(255 255 255 / 0.2)); + border-radius: 9px; + box-shadow: 0 8px 24px rgb(0 0 0 / 0.32); + font: 400 13px/1.4 system-ui, sans-serif; + text-align: start; + white-space: normal; + overflow-wrap: anywhere; + opacity: 1; + transform: translateY(0); + transition: opacity 120ms ease, transform 120ms ease; + } + + .tooltip[data-side='top'] { + transform-origin: bottom center; + } + + .tooltip[data-side='bottom'] { + transform-origin: top center; + } + + .tooltip[popover]:not(:popover-open) { + display: none; + } + + @starting-style { + .tooltip { + opacity: 0; + transform: translateY(3px); + } + } + + .sr-only { + /* Keep the accessibility-only description outside every dialog scroll + container's overflow geometry. Toggling the hidden attribute on the former + absolutely-positioned node made some browsers add a vertical + scrollbar while help was open, even though the visible tooltip was + already in the Popover top layer / fixed fallback portal. */ + position: fixed; + inset: 0 auto auto 0; + width: 1px; + height: 1px; + padding: 0; + margin: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + clip-path: inset(50%); + white-space: nowrap; + border: 0; + } + + @media (pointer: coarse) { + .trigger { + width: 40px; + height: 40px; + } + } + + @media (prefers-reduced-motion: reduce) { + .tooltip { + transition: none; + } + } + `,customElements.get("hp-help")||customElements.define("hp-help",Xi);const Zi=new WeakMap;function Qi(t){const e=function(t){const e=t?.connection||t;return!e||"object"!=typeof e&&"function"!=typeof e?null:e}(t);if(!e)return null;let s=Zi.get(e);return s||(s={revision:0,loaded:!1,configEntries:{},manifests:{},listeners:new Set,refs:0},Zi.set(e,s)),s}function to(t){t.revision++;for(const e of[...t.listeners])try{e()}catch{}}function eo(t,e){const s=Qi(t);if(!s)return()=>{};s.refs++,s.listeners.add(e),async function(t,e){e.loading||"function"!=typeof t?.callWS?e.loading:e.loaded&&e.loadedAt&&Date.now()-e.loadedAt<3e5||(e.loading=(async()=>{const[s,i]=await Promise.allSettled([t.callWS({type:"config_entries/get"}),t.callWS({type:"manifest/list"})]);"fulfilled"===s.status&&Array.isArray(s.value)&&(e.configEntries=Object.fromEntries(s.value.filter(t=>"string"==typeof t?.entry_id).map(t=>[t.entry_id,t]))),"fulfilled"===i.status&&Array.isArray(i.value)&&(e.manifests=Object.fromEntries(i.value.filter(t=>"string"==typeof t?.domain).map(t=>[t.domain,t]))),e.loaded=!0,e.loadedAt=Date.now(),e.loading=void 0,to(e)})().catch(()=>{e.loaded=!0,e.loadedAt=Date.now(),e.loading=void 0,to(e)}),e.loading)}(t,s),async function(t,e){if(e.unsubscribe||e.subscribing)return e.subscribing;const s=t?.connection?.subscribeMessage;"function"==typeof s&&(e.subscribing=(async()=>{try{e.unsubscribe=await s.call(t.connection,t=>{const s=Array.isArray(t)?t:Array.isArray(t?.entries)?t.entries:t?[t]:[];let i=!1;const o={...e.configEntries};for(const t of s){const e=t?.entry||t?.data?.entry||("string"==typeof t?.entry_id?t:null),s=e?.entry_id;if("string"!=typeof s)continue;const a=t?.type||t?.action||t?.data?.action;"removed"===a||"remove"===a?delete o[s]:o[s]=e,i=!0}i&&(e.configEntries=o,to(e))},{type:"config_entries/subscribe"})}catch{}finally{0===e.refs&&(e.unsubscribe?.(),e.unsubscribe=void 0),e.subscribing=void 0}})(),e.subscribing)}(t,s);let i=!1;return()=>{i||(i=!0,s.listeners.delete(e),s.refs=Math.max(0,s.refs-1),s.refs||(s.unsubscribe?.(),s.unsubscribe=void 0))}}function so(t){const e=Qi(t);return e?{revision:e.revision,loaded:e.loaded,configEntries:e.configEntries,manifests:e.manifests}:{revision:0,loaded:!1,configEntries:{},manifests:{}}}function io(t,e,s=so(t),i){const o=s.manifests[e];return function(t,e){if("function"!=typeof t?.localize)return"";try{const s=`component.${e}.title`,i=t.localize(s);return"string"==typeof i&&i!==s?i:""}catch{return""}}(t,e)||String(o?.name||"")||String(i||"")||e.replace(/_/g," ")}function oo(t,e,s,i,o){const a=String(e||"").trim();if(!a)return null;const n=o?i.configEntries[o]:null;return{domain:a,label:io(t,a,i,n?.title),configEntryId:o,configEntryTitle:n?.title,confidence:s}}function ao(t){const e={"registry-owner":0,"entity-platform":1,"identifier-fallback":2},s=new Set;return t.filter(t=>!!t).sort((t,s)=>e[t.confidence]-e[s.confidence]||t.label.localeCompare(s.label)||t.domain.localeCompare(s.domain)).filter(t=>{const e=`${t.domain}\n${t.configEntryId||""}`;return!s.has(e)&&(s.add(e),!0)})}function no(t,e,s,i=so(t)){const o=s.entities?.[e]||t?.entities?.[e];if(!o)return null;const a=o.config_entry_id||void 0,n=a?i.configEntries[a]?.domain:"";return oo(t,o.platform||n,"entity-platform",i,a)}class ro extends r{constructor(){super(...arguments),this.deviceName="",this._metadataConnection=null,this._demoUntil=0,this._demoTimer=0,this._demoGeneration=1,this._demoKind=null,this._reducedMotion=!1,this._onMotionChange=t=>{this._reducedMotion=t.matches,this.requestUpdate()},this._startShortDemo=()=>{const t=this.presentation;t&&"icon_ripple"===t.display&&"none"===t.pulse.kind&&(this._demoGeneration++,this._demoKind="short",this._demoUntil=Date.now()+3300,window.clearTimeout(this._demoTimer),this._demoTimer=window.setTimeout(()=>{this._demoUntil=0,this._demoTimer=0,this._demoKind=null,this.requestUpdate()},3330),this.requestUpdate())},this._toggleContinuousDemo=()=>{const t=this.presentation;t&&"icon_ripple"===t.display&&"none"===t.pulse.kind&&("continuous"===this._demoKind?this._clearDemo():(this._clearDemo(),this._demoGeneration++,this._demoKind="continuous",this._demoUntil=Number.POSITIVE_INFINITY),this.requestUpdate())}}connectedCallback(){super.connectedCallback(),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this._ensureMetadata()}disconnectedCallback(){this._metadataRelease?.(),this._metadataRelease=void 0,this._metadataConnection=null,this._clearDemo(),this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,super.disconnectedCallback()}willUpdate(t){t.has("hass")&&this._ensureMetadata();const e=this.presentation,s=t.get("presentation");t.has("presentation")&&s?.binding!==e?.binding&&this._clearDemo(),e&&this._demoKind&&("icon_ripple"!==e.display||"none"!==e.pulse.kind)&&this._clearDemo()}_ensureMetadata(){const t=this.hass?.connection||null;t&&t!==this._metadataConnection&&(this._metadataRelease?.(),this._metadataConnection=t,this._metadataRelease=eo(this.hass,()=>this.requestUpdate()))}_clearDemo(){window.clearTimeout(this._demoTimer),this._demoTimer=0,this._demoUntil=0,this._demoKind=null}get _lang(){return d(this.hass)}_t(t,e){return p(this._lang,t,e)}_providerText(t){return"houseplan"===t.domain?this._t("marker.preview.virtual_provider"):t.label.toLowerCase()===t.domain.toLowerCase()?t.domain:`${t.label} (${t.domain})`}_providers(){return this.presentation&&this.registry?function(t,e,s,i=so(t)){if("virtual"===e)return[{domain:"houseplan",label:"House Plan",confidence:"registry-owner"}];const o=e.indexOf(":");if(o<1)return[];const a=e.slice(0,o),n=e.slice(o+1);if("entity"===a){const e=no(t,n,s,i);return e?[e]:[]}if("device"!==a)return[];const r=s.devices?.[n]||t?.devices?.[n];if(!r)return[];const l=[r.config_entry_id,...Array.isArray(r.config_entries)?r.config_entries:[]].filter(t=>"string"==typeof t&&!!t).map(e=>{const s=i.configEntries[e];return oo(t,s?.domain,"registry-owner",i,e)});if(l.some(Boolean))return ao(l);const h=[];for(const[e,o]of Object.entries(s.entities||{}))o?.device_id===n&&null==o?.disabled_by&&h.push(no(t,e,s,i));return h.some(Boolean)?ao(h):ao((Array.isArray(r.identifiers)?r.identifiers:[]).map(e=>{const s=Array.isArray(e)?e[0]:null;return oo(t,s,"identifier-fallback",i)}))}(this.hass,this.presentation.binding,this.registry,so(this.hass)):[]}_providerSummary(t){if(!t.length)return this._t("marker.preview.unknown_provider");const e=t.slice(0,2).map(t=>this._providerText(t)),s=t.length-e.length;return e.join(", ")+(s>0?` · ${this._t("marker.preview.more_sources",{n:s})}`:"")}_sourceSummary(t){const e=t.visualSources;return e.length?1===e.length?`${e[0].name} · ${e[0].eid} · ${this._sourceProvider(e[0].eid)}`:2===e.length?e.map(t=>t.name).join(" · "):this._t("marker.preview.multiple_sources",{n:e.length}):this._t("marker.preview.no_source")}_stateSummary(t){if(!t.visualSources.length)return this._t("marker.preview.no_state");if(1===t.visualSources.length)return t.visualSources[0].stateText||this._t("marker.preview.no_state");const e=[...new Set(t.visualSources.map(t=>t.stateText).filter(Boolean))];return 1===e.length?e[0]:this._t("marker.preview.mixed_states")}_reason(t){return this._t(`marker.preview.reason.${t}`)}_sourceProvider(t){if(!this.registry)return this._t("marker.preview.unknown_provider");const e=no(this.hass,t,this.registry,so(this.hass));return e?this._providerText(e):this._t("marker.preview.unknown_provider")}render(){const t=this.presentation;if(!t)return a;const e=!!this._demoKind&&this._demoUntil>Date.now()&&"icon_ripple"===t.display&&"none"===t.pulse.kind,s=e?(()=>{const e=_(t.pulse,this._demoKind,this._demoGeneration,this._reducedMotion,"short"===this._demoKind?this._demoUntil:null);return{...t,pulse:e,classes:[...t.classes.filter(t=>!t.startsWith("pulse-")),`pulse-${e.kind}`,...e.generation%2==0?["pulse-gen2"]:[]]}})():t,i=this._providers(),n="none"!==t.pulse.kind,r=s.scale*(s.pulse.animated?s.pulse.diameterScale:1);let l=-r/2,h=r/2,c=-r/2,d=r/2;if(s.valueBadge){const t=s.scale*Math.min(4,Math.max(.9,.29*s.valueBadge.text.length+.28)),e=.7*s.scale,i=.6*s.scale;"right"===s.valueBadge.position&&(h=Math.max(h,i+t)),"left"===s.valueBadge.position&&(l=Math.min(l,-i-t)),"top"===s.valueBadge.position&&(c=Math.min(c,-i-e)),"bottom"===s.valueBadge.position&&(d=Math.max(d,i+e))}if(null!=s.lqiText){const t=s.scale*("bottom"===s.valueBadge?.position?1.55:.95);d=Math.max(d,t)}const p=Math.min(1,2.35/Math.max(1,h-l),2.35/Math.max(1,d-c)),b=Math.round(100*p),y=[`left:calc(50% - ${54*((l+h)/2)*p}px)`,`top:calc(50% - ${54*((c+d)/2)*p}px)`,p<1?`transform:scale(${p})`:""].filter(Boolean).join(";"),v=["dev",u(this.hass),...s.classes,"virtual"===s.binding?"virtual":"",s.haDisabled?"ghost ha-disabled":"",null!=s.valueText?"valonly":""].filter(Boolean).join(" "),$=m(s).join(";"),w=e?this._t("continuous"===this._demoKind?"marker.preview.demo_continuous_notice":"marker.preview.demo_short_notice"):this._reason(t.explanation.reason),k=[this.deviceName,this._providerSummary(i),this._stateSummary(t),w,t.valueFullText||"",g(t.valueBadge),null!=t.lqiText&&t.lqiBand?this._t(`marker.lqi_a11y_${t.lqiBand}`,{value:t.lqiText}):""].filter(Boolean).join(". ");return o`
+
+ ${this._t("marker.preview.title")} + + ${this._t(e?"marker.preview.example":"marker.preview.actual")} + +
+
+ +
+
${this._t("marker.preview.integration")}${this._providerSummary(i)}
+
${this._t("marker.preview.source")}${this._sourceSummary(t)}
+
${this._t("marker.preview.current_state")}${this._stateSummary(t)}
+
${this._t("marker.preview.result")}${w}
+ ${t.fallbackReason?o`

${this._reason(t.fallbackReason)}

`:a} + ${t.explanation.notices.map(t=>o`

${this._reason(t)}

`)} + ${p<1?o`

${this._t("marker.preview.scaled",{n:b})}

`:a} + ${e&&this._reducedMotion?o`

${this._t("marker.preview.reduced_motion")}

`:a} +
+
+ ${t.visualSources.length||t.criticalSources.length?o`
+ ${this._t("marker.preview.details")} +
+ ${[...t.visualSources,...t.criticalSources].map(t=>o` +
+ ${t.name}${t.eid} + ${t.stateText||t.state} + ${this._sourceProvider(t.eid)} +
`)} +
+
`:a} + ${"icon_ripple"===t.display?o`
+ + +
`:a} +
`}}ro.properties={hass:{attribute:!1},presentation:{attribute:!1},registry:{attribute:!1},deviceName:{attribute:!1}},ro.styles=[c,n` + :host { display: block; min-width: 0; } + .devicepreview { + margin: 4px 0 14px; + padding: 14px; + border: 1px solid var(--divider-color, rgba(127, 127, 127, 0.28)); + border-radius: 14px; + background: color-mix(in srgb, var(--card-background-color, #20232b) 92%, var(--primary-color, #03a9f4)); + color: var(--primary-text-color, #fff); + overflow: hidden; + } + .previewhead { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; } + .previewbadge { + padding: 3px 9px; + border-radius: 999px; + color: var(--secondary-text-color, #9aa0aa); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 12%, transparent); + font-size: 12px; + font-weight: 700; + } + .previewbadge.example { color: var(--warning-color, #ffb300); } + .previewgrid { display: grid; grid-template-columns: minmax(170px, 0.8fr) minmax(240px, 1.2fr); gap: 16px; align-items: stretch; } + .previewstage { + position: relative; + min-height: 168px; + border-radius: 12px; + background: var(--secondary-background-color, rgba(0, 0, 0, 0.16)); + overflow: hidden; + pointer-events: none; + container-type: inline-size; + --icon-size: 54px; + --device-base-size: 48.6px; + } + .previewfit { position: absolute; left: 50%; top: 50%; transform-origin: center; } + .previewstage .dev { left: 0; top: 0; cursor: default; } + :host([data-pointer-hover]) .previewstage .dev:hover { z-index: 2; } + .previewfacts { min-width: 0; display: grid; align-content: start; gap: 8px; } + .previewfacts > div { display: grid; grid-template-columns: minmax(115px, 0.8fr) minmax(0, 1.3fr); gap: 8px; } + .previewfacts span { color: var(--secondary-text-color, #9aa0aa); } + .previewfacts b { min-width: 0; overflow-wrap: anywhere; } + .previewnotice { margin: 2px 0 0; color: var(--secondary-text-color, #9aa0aa); font-size: 13px; } + .previewdetails { margin-top: 12px; } + .previewdetails summary { cursor: pointer; color: var(--secondary-text-color, #9aa0aa); } + .previewtable { display: grid; gap: 8px; margin-top: 9px; } + .previewsource { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 3px 10px; font-size: 13px; } + .previewsource > * { min-width: 0; overflow-wrap: anywhere; } + .previewsource code { color: var(--secondary-text-color, #9aa0aa); } + .previewdemo { + min-height: 40px; + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + border: 1px solid var(--divider-color, rgba(127, 127, 127, 0.35)); + border-radius: 10px; + background: transparent; + color: inherit; + cursor: pointer; + } + .previewdemos { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; } + .previewdemo:focus-visible { outline: 2px solid var(--primary-color, #03a9f4); outline-offset: 2px; } + .previewdemo:disabled { opacity: 0.5; cursor: not-allowed; } + @media (max-width: 640px) { + .previewgrid { grid-template-columns: minmax(0, 1fr); } + .previewstage { min-height: 142px; } + .previewfacts > div { grid-template-columns: minmax(0, 1fr); gap: 2px; } + } + `],customElements.get("hp-device-preview")||customElements.define("hp-device-preview",ro);const lo=(t,e)=>[t[0]-e[0],t[1]-e[1]],ho=(t,e)=>[t[0]+e[0],t[1]+e[1]],co=(t,e)=>t[0]*e[0]+t[1]*e[1],po=t=>Math.hypot(t[0],t[1]);function _o(t){let e=0;for(let s=0;st[1]!=l>t[1]&&t[0]<(r-a)*(t[1]-n)/(l-n)+a&&(s=!s)}return s}([r[0]+n[0]*l,r[1]+n[1]*l],t)&&(n=[-n[0],-n[1]]),n}function go(t){const e=t.length;if(e<3)return!1;for(let s=0;s(t[0]-o[0])*r[1]-(t[1]-o[1])*r[0],h=t=>(t[0]-o[0])*r[0]+(t[1]-o[1])*r[1],c=s,d=n-s;for(const e of t){const t=Math.abs(l(e));if(t<=s)continue;const o=h(e);o<=c||o>=d||tMath.abs(n+(t-p)/g*(r-n));i=Math.min(i,f(u),f(m))}}return i}function bo(t,e,s){if($(t,e,s))return!0;if(v(t,e,s)||v(e,t,s))return!1;let i=0;try{const s=w([[...t.map(t=>[t[0],t[1]]),[t[0][0],t[0][1]]]],[[...e.map(t=>[t[0],t[1]]),[e[0][0],e[0][1]]]]);for(const t of s)t?.[0]&&(i+=k(t[0]))}catch{return!1}return i>Math.max(1e-7,s*s)}function yo(t,e,s){for(const i of e)for(let e=0;es)continue;const h=(t.x-o[0])*l[0]+(t.y-o[1])*l[1];if(h-t.length/2>=-s&&h+t.length/2<=r+s)return!0}return!1}function vo(t,e,s){const i=Math.abs(e[0]-t[0]),o=Math.abs(e[1]-t[1]);return i<=s&&o>s?"v":o<=s&&i>s?"h":null}function $o(t,e,s){return Math.abs(t[0]-e[0])<=s&&Math.abs(t[1]-e[1])<=s}function wo(t,e,s,i,o){return $o(t,s,o)&&$o(e,i,o)||$o(t,i,o)&&$o(e,s,o)}function ko(t,e,s,i,o){const a=vo(t,e,o);return a&&vo(s,i,o)===a?"h"===a?Math.abs(t[1]-s[1])>o||Math.abs(t[1]-i[1])>o?0:Math.max(0,Math.min(Math.max(t[0],e[0]),Math.max(s[0],i[0]))-Math.max(Math.min(t[0],e[0]),Math.min(s[0],i[0]))):Math.abs(t[0]-s[0])>o||Math.abs(t[0]-i[0])>o?0:Math.max(0,Math.min(Math.max(t[1],e[1]),Math.max(s[1],i[1]))-Math.max(Math.min(t[1],e[1]),Math.min(s[1],i[1]))):0}function xo(t,e,s,i){const o=t.length,a=vo(t[(e-1+o)%o],t[e],i),n=vo(t[(e+1)%o],t[(e+2)%o],i),r="h"===s?"v":"h";return a===r&&n===r}function So(t){let e=1/0,s=1/0,i=-1/0,o=-1/0;for(const a of t)e=Math.min(e,a[0]),s=Math.min(s,a[1]),i=Math.max(i,a[0]),o=Math.max(o,a[1]);return[e,s,i,o]}function Mo(t,e,s){const i=So(t),o=So(e);return i[2]o}const Co=(t,e)=>"h"===e?t[0]:t[1],Po=(t,e)=>"h"===e?t[1]:t[0];function Io(t,e,s,i,o){const a=t.find(t=>t.id===e);if(!a)return null;const n=a.poly[s],r=a.poly[(s+1)%a.poly.length],l=vo(n,r,o);if(!l)return null;const h=0===i?r:n,c=0===i?n:r,d=Co(h,l),p=Co(c,l),_=Po(h,l),u=function(t,e,s,i){const o=[];for(const a of t)for(let t=0;ti||Math.abs(Po(r,e)-s)>i)continue;const l=Co(n,e),h=Co(r,e),c=Math.min(l,h),d=Math.max(l,h);d-c>i&&o.push({roomId:a.id,edge:t,lo:c,hi:d})}return o.sort((t,e)=>t.lo-e.lo||t.hi-e.hi||t.roomId.localeCompare(e.roomId)||t.edge-e.edge)}(t,l,_,o),m=function(t,e,s,i){const o=[e,s];for(const a of t){const t=Math.max(e,a.lo),n=Math.min(s,a.hi);n-t>i&&o.push(t,n)}const a=[...new Set(o)].sort((t,e)=>t-e),n=[];for(let e=0;e+1r>t.lo-i&&rt.roomId))].sort();n.push({lo:s,hi:o,owners:l})}return n}(u,Math.min(d,p),Math.max(d,p),o);return!m.length||m.some(t=>t.owners.length<1||t.owners.length>2)?null:{roomId:e,edge:s,movedEndpoint:i,axis:l,line:_,fixed:d,moving:p,intervals:u,baseline:m}}function To(t,e,s){const i=[];for(const o of t.intervals){const a=e.polys[o.roomId];if(!a){i.push(o);continue}if(o.edge<0||o.edge>=a.length)continue;const n=a[o.edge],r=a[(o.edge+1)%a.length];if(vo(n,r,s)!==t.axis||Math.abs(Po(n,t.axis)-t.line)>s||Math.abs(Po(r,t.axis)-t.line)>s)continue;const l=Co(n,t.axis),h=Co(r,t.axis),c=Math.min(l,h),d=Math.max(l,h);d-c>s&&i.push({...o,lo:c,hi:d})}return i}function Ro(t,e,s){return new Set(t.filter(t=>e>t.lo-s&&et.roomId)).size}function Fo(t,e,s){for(const i of e.sideOwnership){const e=t.polys[i.roomId];if(!e)return!1;const o=e[i.edge],a=e[(i.edge+1)%e.length];if(vo(o,a,s)!==i.axis)return!1;const n=Co(0===i.movedEndpoint?o:a,i.axis),r=To(i,t,s),l=(i.moving>=i.fixed?i.baseline[i.baseline.length-1]:i.baseline[0]).owners.length;if(l<1||l>2)return!1;const h=Math.min(i.fixed,i.moving,n),c=Math.max(i.fixed,i.moving,n),d=[h,c,i.fixed,i.moving,n];for(const t of i.intervals)d.push(t.lo,t.hi);for(const t of r)d.push(t.lo,t.hi);const p=[...new Set(d.filter(t=>t>=h&&t<=c))].sort((t,e)=>t-e),_=Math.min(i.fixed,i.moving),u=Math.max(i.fixed,i.moving),m=Math.min(i.fixed,n),g=Math.max(i.fixed,n);for(let t=0;t+1_-s&&am-s&&a2||d>2)return!1;if(n&&h){if(c!==d)return!1}else if(!n&&h){if(d!==l||c>0&&c!==d)return!1}else if(2===c?2!==d:d>1)return!1}}return!0}function No(t,e,s,i){const o=[s.n[0]*i,s.n[1]*i],a={polys:{},openings:{},movedSpans:{}};for(const e of s.roomIds){const i=t.find(t=>t.id===e),n=s.edgeByRoom[e];if(!i||null==n)continue;const r=(n+1)%i.poly.length;a.polys[e]=i.poly.map((t,e)=>e===n||e===r?ho(t,o):[...t]),a.movedSpans[e]=[[ho(i.poly[n],o),ho(i.poly[r],o)]]}for(const t of e)s.movingOpeningIds.includes(t.id)&&(a.openings[t.id]=[t.x+o[0],t.y+o[1]]);return a}function zo(t,e,s,i,o,a,n,r){if(!function(t,e,s,i){if(uo([t.x,t.y],e,s)>2*i)return!1;const o=po(lo(s,e));if(o<=i)return!1;const a=[(s[0]-e[0])/o,(s[1]-e[1])/o],n=(t.x-e[0])*a[0]+(t.y-e[1])*a[1];return n>=-i&&n<=o+i}(t,e,s,r))return!0;if(uo([t.x,t.y],i,o)>2*r)return!1;const l=0===a?i:o;return po(lo([t.x,t.y],l))>=t.length/2+n-r}function Ao(t,e,s,i){const o=i.movingHalf||0;return"circle"===t.kind?uo(t.center,e,s)2)return!1;const r=No(t,e,s,i);if(Object.keys(r.polys).length!==s.roomIds.length)return!1;if(!Fo(r,s,a))return!1;const l=new Set(s.roomIds),h=t=>r.polys[t.id]||t.poly;for(const i of s.roomIds){const l=t.find(t=>t.id===i),h=r.polys[i],c=s.edgeByRoom[i];if(!l||!h||h.length!==s.topology[i]||h.length!==l.poly.length||!go(h))return!1;const d=l.poly.length,p=(c-1+d)%d,_=[p,c,(c+1)%d];for(const t of _)if(y(h[t],h[(t+1)%d]))return!1;const u=_o(l.poly),m=_o(h);if(Math.abs(m)t.id===e),i=r.polys[e];for(const o of t){if(o.id===e||l.has(o.id))continue;const t=h(o);if(!Mo(s.poly,o.poly,a)||!Mo(i,t,a))if(v(s.poly,o.poly,a)){if(!v(i,t,a))return!1}else if(v(o.poly,s.poly,a)){if(!v(t,i,a))return!1}else if(v(i,t,a)||v(t,i,a)||bo(i,t,a))return!1}}t.find(t=>t.id===s.roomId);const c=r.polys[s.roomId],d=s.edgeByRoom[s.roomId],p=c[d],_=c[(d+1)%c.length];if(Math.abs(i)>a)for(const t of o.obstacles||[])if(Ao(t,p,_,o))return!1;for(const t of e){if(!s.movingOpeningIds.includes(t.id))continue;const e=r.openings[t.id];if(!e||t.hosted)return!1;if(!yo({...t,x:e[0],y:e[1]},[c],2*a))return!1}return!0}const Lo=new WeakMap,Eo=t=>"number"==typeof t&&Number.isFinite(t),Bo=(t,e)=>{const s=new Map;for(const i of t||[])!Eo(i?.cm)||!e&&i.cm<=0||s.set(i.cm,(s.get(i.cm)||0)+1);return s},Ho=t=>[String(t),"см"].join(" ");function Go(t,e,s={}){if(s.allowClear)return[];const i=!0===s.exactMultiplicity,o=Bo(t,i),a=Bo(e,i),n=[];for(const[t,e]of o){const s=a.get(t)||0;0===s?n.push({invariant:"wall_records",kind:"lost",owner:Ho(t),reference:`было ${e}`,detail:"записи этой толщины исчезли целиком"}):i&&s!==e&&n.push({invariant:"wall_records",kind:"count",owner:Ho(t),reference:`было ${e}, стало ${s}`,detail:"изменилось число записей этой толщины"})}if(i)for(const[t,e]of a)o.has(t)||n.push({invariant:"wall_records",kind:"count",owner:Ho(t),reference:`было 0, стало ${e}`,detail:"появились записи новой толщины"});return n}class Wo{constructor(){this._selectedRoomId=null,this._session=null,this._eligibility=null}get dragging(){return null!==this._session}ownsPointer(t){return this._session?.pointerId===t}get selectedRoomId(){return this._selectedRoomId}get snapshotIdentity(){return this._session?.snapshotIdentity||null}get activePointerId(){return this._session?.pointerId??null}get moved(){return!0===this._session?.moved}get delta(){return this._session?.delta||0}get rooms(){return this._session?.rooms||null}get openings(){return this._session?.openings||null}get plan(){return this._session?.plan||null}get preview(){return this._session?.accepted?.preview||null}get liveLabels(){return this._session?.accepted?.labels||null}selectRoom(t){this._selectedRoomId=t}restoreSelection(t){this._selectedRoomId=t}escapeIdle(){return this._selectedRoomId?(this._selectedRoomId=null,"selection-cleared"):"exit-tool"}resolve(t,e,s){this._eligibility&&this._eligibility.context===t||(this._eligibility={context:t,values:new Map});const i=this._eligibility.values.get(e);if(i)return i;const o=s();return this._eligibility.values.set(e,o),o}begin(t){return!this._session&&(this._session={pointerId:t.pointerId,start:[...t.start],roomId:t.roomId,plan:t.plan,options:t.options,rooms:t.rooms,openings:t.openings,snapshotIdentity:t.snapshotIdentity,before:t.before,moved:!1,delta:0,changedRoomIds:[...t.plan.roomIds],rejectionNotified:!1,wallUnionBefore:t.wallUnionBefore,accepted:null},!0)}move(t){const e=this._session;if(!e||e.pointerId!==t.pointerId)return{kind:"no-op"};const s=(i=e.start,o=t.point,a=e.plan.n,[i?.[0],i?.[1],o?.[0],o?.[1],a?.[0],a?.[1]].every(Number.isFinite)?(o[0]-i[0])*a[0]+(o[1]-i[1])*a[1]:0);var i,o,a;const n=t.snap([e.plan.a[0]+e.plan.n[0]*s,e.plan.a[1]+e.plan.n[1]*s]),r=(n[0]-e.plan.a[0])*e.plan.n[0]+(n[1]-e.plan.a[1])*e.plan.n[1],l=function(t,e,s,i,o,a){if(!Number.isFinite(i)||Math.abs(i)<1e-9)return 0;const n=Math.sign(i),r=Math.abs(i),l=Math.max(Math.abs(o),1e-6);let h=Lo.get(s);h&&h.opts===a||(h={opts:a,values:new Map},Lo.set(s,h));const c=h.values;let d=0;for(let i=Math.min(l,r),o=0;o<4096&&i<=r+1e-9;o++,i=Math.min(r,i+l)){const o=n*i,h=`${o.toFixed(9)}|${l.toFixed(9)}`;let p=c.get(h);if(void 0===p&&(p=Oo(t,e,s,o,a),c.size<4096&&c.set(h,p)),!p)break;if(d=o,Math.abs(i-r)<=1e-9)break}return d}(e.rooms,e.openings,e.plan,r,t.step,e.options);if(e.moved&&l===e.delta)return{kind:"no-op"};const h=No(e.rooms,e.openings,e.plan,l);let c;try{if(c=t.project(e.snapshotIdentity,h.polys,h.openings,e.changedRoomIds,e.rooms),!c.ok)return this._projectionRejected(e);if(Go(c.value.beforeWalls,c.value.afterWalls,{exactMultiplicity:!0}).length)return this._projectionRejected(e)}catch{return this._projectionRejected(e)}const d=e.accepted,p={preview:c.value.preview,labels:null,artifact:c.value.artifact,beforeWalls:c.value.beforeWalls,afterWalls:c.value.afterWalls};e.accepted=p;try{t.publish(p.preview,p.artifact),p.labels=t.measure(h,e.plan)}catch{e.accepted=d;try{t.publish(d?.preview||null,d?.artifact||null)}catch{}return this._projectionRejected(e)}return e.moved=!0,e.delta=l,{kind:"accepted",preview:c.value.preview,labels:p.labels,artifact:c.value.artifact}}finish(t){const e=this._session;if(!e||e.pointerId!==t.pointerId)return{kind:"no-op"};const s=e.accepted;let i;if(e.moved&&Math.abs(e.delta)>1e-9&&s)if(t.currentSnapshotIdentity!==e.snapshotIdentity)i={kind:"rejected",reason:"stale-snapshot"};else if(Oo(e.rooms,e.openings,e.plan,e.delta,e.options))if(Go(s.beforeWalls,s.afterWalls,{exactMultiplicity:!0}).length)i={kind:"rejected",reason:"wall-records"};else{let o=!1;try{o=t.validatePreview(s.preview)}catch{o=!1}i=o?{kind:"commit",preview:s.preview,before:e.before}:{kind:"rejected",reason:"invalid-candidate"}}else i={kind:"rejected",reason:"invalid-topology"};else i={kind:"no-op"};return this._session=null,"commit"===i.kind&&(this._eligibility=null),i}cancel(t,e){const s=this._session;return!s||void 0!==e&&s.pointerId!==e?{kind:"no-op"}:(this._session=null,this._eligibility=null,{kind:"cancelled",restoreWallUnion:t===s.snapshotIdentity?s.wallUnionBefore:null})}reset(){this._selectedRoomId=null,this._session=null,this._eligibility=null}_projectionRejected(t){const e=!t.rejectionNotified;return t.rejectionNotified=!0,{kind:"rejected",notify:e}}}const jo=(t,e)=>[(t[0]-e.x)/Math.max(1e-9,e.w)*e.stageWidth,(t[1]-e.y)/Math.max(1e-9,e.h)*e.stageHeight];function qo(t){const{poly:e,edge:s,text:i,view:o}=t,a=e[s],n=e[(s+1)%e.length],r=[(a[0]+n[0])/2,(a[1]+n[1])/2],l=function(t,e){const s=t[e],i=t[(e+1)%t.length],o=i[0]-s[0],a=i[1]-s[1],n=Math.hypot(o,a)||1;return(t=>{let e=0;for(let s=0;s=0?[-a/n,o/n]:[a/n,-o/n]}(e,s),h=Math.hypot(n[0]-a[0],n[1]-a[1])||1,c=[(n[0]-a[0])/h,(n[1]-a[1])/h],d=jo(r,o),p=jo(t.gearCenter,o),_=Math.max(34,7.2*i.length+12),u=Math.abs(l[0])>=Math.abs(l[1])?Math.max(28,_/2+4):Math.max(28,13),m=d[0]+l[0]*u,g=d[1]+l[1]*u,f=e=>{return s=m+c[0]*e,i=g+c[1]*e,o=_,a=18,n=p[0],r=p[1],l=t.gearWidthPx,h=t.gearHeightPx,2*Math.abs(s-n)=Math.abs(c[1])?c[0]:c[1])>0?-1:1,e=Math.max(o.stageWidth,o.stageHeight,64);for(let s=4;s<=e;s+=4){const e=s*t;if(!f(e)){b=e;break}const i=-e;if(!f(i)){b=i;break}}}const y=l[0]*u+c[0]*b,v=l[1]*u+c[1]*b,$=Math.hypot(y,v)||1,w=v/$*12,k=[r[0]+y/$*12*o.w/Math.max(1,o.stageWidth),r[1]+w*o.h/Math.max(1,o.stageHeight)];return{anchor:r,offsetXPx:y,offsetYPx:v,tangentOffsetPx:b,side:Math.abs(l[0])>=Math.abs(l[1])?l[0]<0?"left":"right":l[1]<0?"above":"below",leader:{a:r,b:k}}}const Uo=1e-9,Ko=1e7,Vo=t=>{const e=Math.sign(t)*Math.floor(Math.abs(t)*Ko+.5)/Ko;return Object.is(e,-0)?0:e},Jo=t=>`${Vo(t[0])},${Vo(t[1])}`,Yo=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),Xo=(t,e)=>Math.atan2(e[1]-t[1],e[0]-t[0]),Zo=t=>Array.isArray(t)&&t.length>=2&&t.every(t=>Number.isFinite(t)),Qo=t=>(t||[]).filter(t=>Zo(t?.a)&&Zo(t?.b)&&Yo(t.a,t.b)>Uo);function ta(t,{minAngleDeg:e=15,maxValence:s=6}={}){const i=new Map;for(const e of Qo(t))for(const[t,s]of[[e.a,e.b],[e.b,e.a]]){const e=i.get(Jo(t))||[];e.push(Xo(t,s)),i.set(Jo(t),e)}const o=[];for(const[t,a]of i){if(a.length>s&&o.push({rule:"valence",subject:t,actual:a.length,limit:s}),a.length<2)continue;const i=[...a].sort((t,e)=>t-e);let n=1/0;for(let t=0;tUo&&s(180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI%180+180)%180,sa=(t,e,s=1)=>{const i=Math.abs(ea(t)-ea(e));return Math.min(i,180-i)<=s},ia=t=>{const e=new Map;for(const s of t)for(const t of[s.a,s.b]){const i=e.get(Jo(t));i?i.push(s):e.set(Jo(t),[s])}return e};function oa(t,e,s){const i=Qo(e),o=s??ia(i),a=new Set([t]);let n=Yo(t.a,t.b);const r=[t.a,t.b];for(;r.length;){const e=r.pop();for(const s of o.get(Jo(e))||[])a.has(s)||sa(s,t)&&Number(s.cm||0)===Number(t.cm||0)&&(a.add(s),n+=Yo(s.a,s.b),r.push(s.a,s.b))}return n}function aa(t,e,s,{minLengthCm:i=20}={}){const o=[],a=Qo(t),n=ia(a);for(const t of a){const r=oa(t,a,n)/s*(e||1),l=Math.max(i,Number(t.cm)>0?Number(t.cm):0);r{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o,n=a<=Uo?0:Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))};function ra(t,e,s,{minDistanceCm:i=5}={}){const o=Qo(t),a=new Map;for(const t of o)a.set(Jo(t.a),t.a),a.set(Jo(t.b),t.b);const n=((t,e,s)=>t/(e||1)*s)(i,e,s),r=n>Uo?n:1,l=(t,e)=>`${Math.floor(t/r)},${Math.floor(e/r)}`,h=new Map;for(const[t,e]of a){const s=l(e[0],e[1]),i=h.get(s);i?i.push([t,e]):h.set(s,[[t,e]])}const c=new Map;for(const t of o){const e=Math.min(t.a[0],t.b[0])-n,s=Math.max(t.a[0],t.b[0])+n,i=Math.min(t.a[1],t.b[1])-n,o=Math.max(t.a[1],t.b[1])+n;for(let a=Math.floor(e/r);a<=Math.floor(s/r);a++)for(let e=Math.floor(i/r);e<=Math.floor(o/r);e++){const s=`${a},${e}`,i=c.get(s);i?i.push(t):c.set(s,[t])}}const d=[];for(const[t,o]of a){const a=Math.floor(o[0]/r),l=Math.floor(o[1]/r);for(let r=-1;r<=1;r++)for(let c=-1;c<=1;c++)for(const[p,_]of h.get(`${a+r},${l+c}`)||[]){if(t>=p)continue;const a=Yo(o,_);a<=2e-7||a{const i=a[(s+1)%a.length];return t+(e[0]*i[1]-i[0]*e[1])},0))/2,r=(s||1)/i,l=n*r*r;return lt.removed).map(t=>t.binding)),c=new Set;for(const t of s)t.id!==n&&("device"===t.bindingKind&&t.bindingRef&&c.add(`device:${t.bindingRef}`),"entity"===t.bindingKind&&t.bindingRef&&c.add(`entity:${t.bindingRef}`));const d=new Set;for(const t of s)"device"===t.bindingKind&&t.name&&d.add(`${t.name.trim()}|${t.area||""}`);const p=[];for(const t of Object.values(e?.devices||{})){if(!t||"service"===t.entry_type)continue;const e=`device:${t.id}`;if(c.has(e))continue;const s=String(t.name_by_user||t.name||t.id).trim();e!==a&&!h.has(e)&&d.has(`${s}|${t.area_id||""}`)||p.push({value:e,label:s,sub:(t.model||r.device)+("Group"===t.model?r.z2mGroup:""),kind:"device",ref:t.id,areaId:t.area_id||"",model:t.model||""})}for(const[t,s]of Object.entries(e?.entities||{})){const i=`entity:${t}`;if(c.has(i))continue;if(S(e,t,l)&&!h.has(i))continue;const o=ha.has(s?.platform),a="group"===s?.platform;if(!o&&!a)continue;if(s?.hidden&&!h.has(i))continue;const n=e?.states?.[t];p.push({value:i,label:s?.name||n?.attributes?.friendly_name||t,sub:`${t.split(".")[0]} · ${a?r.group:r.helper}`,kind:"entity",ref:t,areaId:s?.area_id||s?.device_id&&e?.devices?.[s.device_id]?.area_id||"",model:"",parentDeviceId:s?.device_id||void 0})}if(o){const t=new Set(p.map(t=>t.value));for(const[s,i]of Object.entries(e?.entities||{})){const o=`entity:${s}`;if(c.has(o)||t.has(o)||i?.hidden&&!h.has(o))continue;const a=!!i?.device_id&&l.devices.has(i.device_id);if(S(e,s,l)&&!h.has(o)&&!a)continue;const n=e?.states?.[s],d=i?.device_id?e?.devices?.[i.device_id]:null,_=d?String(d.name_by_user||d.name||""):"";p.push({value:o,label:i?.name||n?.attributes?.friendly_name||s,sub:`${s.split(".")[0]} · ${r.entity}${_?` · ${_}`:""}`,kind:"entity",ref:s,areaId:i?.area_id||d?.area_id||"",model:"",parentDeviceId:i?.device_id||void 0})}}return p.sort((t,e)=>t.label.localeCompare(e.label)||t.value.localeCompare(e.value))}const da={kind:"active",enabledEntityIds:[],allEntityIds:[]};function pa(t){return t.startsWith("entity:")?"entity":"device"}function _a(t){const e=t.binding.indexOf(":"),s=e>=0?t.binding.slice(e+1):"",i=Object.keys(t).filter(t=>!["id","binding","hidden"].includes(t));return t.id===`h${s}`&&0===i.length}const ua=.001;function ma(t){return!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1])}function ga(t){return`${t[0].toFixed(6)},${t[1].toFixed(6)}`}function fa(t,e,s){return Math.abs(t[0]-e[0])"room"!==t.kind&&s.some(s=>s!==t&&function(t,e,s){const i=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(i,o);if(!(a>s))return!1;const n=i/a,r=o/a,l=e=>Math.abs((e[0]-t.a[0])*r-(e[1]-t.a[1])*n);if(l(e.a)>s||l(e.b)>s)return!1;const h=(e.a[0]-t.a[0])*n+(e.a[1]-t.a[1])*r,c=(e.b[0]-t.a[0])*n+(e.b[1]-t.a[1])*r;return Math.min(a,Math.max(h,c))-Math.max(0,Math.min(h,c))>s}(t,s,e))),o=i.map(t=>{const[e,s]=ba(t.a,t.b);return{a:e,b:s,key:`hidden|${va(t,e,s)}`,sourceKind:t.kind,sourceId:t.id}}).sort((t,e)=>t.key.localeCompare(e.key)),a=i.flatMap(t=>[t.a,t.b].map((e,s)=>({point:[e[0],e[1]],key:`hidden|${ya(t)}|endpoint-${s}`,sourceKind:t.kind,sourceId:t.id}))).sort((t,e)=>t.key.localeCompare(e.key));return{segments:o,endpoints:a}}function xa(t){const e=t.epsilon??ua,s=t.roomCuts||[],i=new Map;for(const e of t.partitionCuts||[]){if("string"!=typeof e.hostId||!e.hostId||!ma(e.a)||!ma(e.b))continue;const t=i.get(e.hostId)||[];t.push([e.a[0],e.a[1],e.b[0],e.b[1]]),i.set(e.hostId,t)}const o=[];for(const[e,i]of M(t.space.rooms).entries())i.length<4||o.push({a:[i[0],i[1]],b:[i[2],i[3]],kind:"room",id:`room-edge-${e}`,cuts:s});for(const e of t.space.room_drafts||[])if(e.id!==t.activeDraftId)for(let t=0;t+1wa(s,t,e)))continue;const t=ga(s);n.has(t)||n.set(t,{point:[s[0],s[1]],key:t})}}}return{segments:[...a.values()].sort((t,e)=>t.key.localeCompare(e.key)),endpoints:[...n.values()].sort((t,e)=>t.key.localeCompare(e.key))}}function Sa(t,e,s){return e.some(e=>ma(e)&&fa(t,e,s))}function Ma(t,e,s){if(!s)return!0;const i=t-s.distance;return i<-1e-9||Math.abs(i)<=1e-9&&e.localeCompare(s.key)<0}function Da(t,e,s){const i=s.epsilon??ua,o=s.excludePoints||[],a=[...t.endpoints,...(s.extraEndpoints||[]).filter(t=>ma(t.point)).map(t=>({point:[t.point[0],t.point[1]],key:t.key}))],n=new Map;for(const t of a){if(Sa(t.point,o,i))continue;const e=ga(t.point),s=n.get(e);(!s||t.key.localeCompare(s.key)<0)&&n.set(e,t)}return[...n.values()].map(t=>({kind:"endpoint",point:[...t.point],key:t.key,distance:Math.hypot(e[0]-t.point[0],e[1]-t.point[1])})).filter(t=>t.distance<=s.tolerance).sort((t,e)=>t.distance-e.distance||t.key.localeCompare(e.key))}function Ca(t,e){if(!t.length)return null;if(e>0){const s=new Set;for(let i=0;i1)return{kind:"ambiguous",candidate:null,conflicts:t.filter(t=>s.has(t.key)).map(t=>({point:[...t.point],key:t.key}))}}return{kind:"resolved",candidate:t[0],conflicts:[]}}function Pa(t,e,s){const i=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(i,o);if(!(a>0))return[...t.a];const n=i/a,r=o/a,l=Math.max(0,Math.min(a,(e[0]-t.a[0])*n+(e[1]-t.a[1])*r)),h=s>0?Math.max(0,Math.min(a,Math.round(l/s)*s)):l;return[t.a[0]+n*h,t.a[1]+r*h]}function Ia(t,e,s){if(!(ma(e)&&ma(s.anchor)&&s.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const i=s.epsilon??ua,o=function(t,e){const s=e[0]-t[0],i=e[1]-t[1];if(!(Math.hypot(s,i)>Number.EPSILON))return null;const o=Math.round(Math.atan2(i,s)/(Math.PI/4))*(Math.PI/4);return[Math.cos(o),Math.sin(o)]}(s.anchor,e);if(!o)return{kind:"none",candidate:null,conflicts:[]};const a=Da(t,e,s).filter(t=>function(t,e,s,i){const o=t[0]-e[0],a=t[1]-e[1];return o*s[0]+a*s[1]>i&&Math.abs(o*s[1]-a*s[0])<=i*Math.max(Math.hypot(o,a),1)}(t.point,s.anchor,o,i)),n=Ca(a,s.distinguishTolerance||0);if(n)return n;let r=null;for(const a of t.segments){const t=a.b[0]-a.a[0],n=a.b[1]-a.a[1],l=a.a[0]-s.anchor[0],h=a.a[1]-s.anchor[1],c=o[0]*n-o[1]*t;let d=null;if(Math.abs(c)<=i*Math.max(Math.hypot(t,n),1)){if(Math.abs(l*o[1]-h*o[0])>i*Math.max(Math.hypot(l,h),1))continue;const t=[a.a,a.b].map(t=>({point:t,along:(t[0]-s.anchor[0])*o[0]+(t[1]-s.anchor[1])*o[1]})).filter(t=>t.along>i).sort((t,e)=>t.along-e.along);t.length&&(d=[...t[0].point])}else{const e=(l*n-h*t)/c,a=(l*o[1]-h*o[0])/c;e>i&&a>=-i&&a<=1+i&&(d=[s.anchor[0]+o[0]*e,s.anchor[1]+o[1]*e])}if(!d)continue;const p=Math.hypot(e[0]-d[0],e[1]-d[1]);p>s.tolerance||Sa(d,s.excludePoints||[],i)||!Ma(p,a.key,r)||(r={kind:"line",point:d,key:a.key,distance:p,segment:a})}return r?{kind:"resolved",candidate:r,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}const Ta=.001;function Ra(t,e,s,i){const o=Number.isFinite(t)&&t>0?Math.floor(t):0,a=t=>"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,n=a(s),r=a(i)??0,l=[];let h=null;for(let t=0;t=2&&Number.isFinite(t[0])&&Number.isFinite(t[1])}function za(t,e,s,i){return t*i-e*s}function Aa(t){let e=0;for(let s=0;st.localeCompare(e)),e[0]}function Ha(t,e,s){const i=[...t];for(let t=!0;t&&i.length>=3;){t=!1;for(let o=0;o=0){i.splice(o,1),t=!0;break}}}return i}function Ga(t,e){const s=t.map(t=>Math.max(0,Math.min(1,t))).sort((t,e)=>t-e),i=[];for(const t of s)(!i.length||Math.abs(t-i[i.length-1])>e)&&i.push(t);return i}function Wa(t,e){return[t.a[0]+(t.b[0]-t.a[0])*e,t.a[1]+(t.b[1]-t.a[1])*e]}function ja(t,e,s){const i=function(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;return o>0?((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o:0}(t,e);if(i<-s||i>1+s)return null;const o=Wa(e,i);return Math.hypot(o[0]-t[0],o[1]-t[1])<=s?Math.max(0,Math.min(1,i)):null}function qa(t,e,s,i,o){const a=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=e.b[0]-e.a[0],l=e.b[1]-e.a[1],h=e.a[0]-t.a[0],c=e.a[1]-t.a[1],d=za(a,n,r,l),p=Math.max(Math.hypot(a,n),Math.hypot(r,l),1);if(Math.abs(d)>o*p){const t=za(h,c,r,l)/d,e=za(h,c,a,n)/d;return void(t>=-o&&t<=1+o&&e>=-o&&e<=1+o&&(s.push(Math.max(0,Math.min(1,t))),i.push(Math.max(0,Math.min(1,e)))))}if(!(Math.abs(za(h,c,a,n))>o*p)){for(const i of[e.a,e.b]){const e=ja(i,t,o);null!=e&&s.push(e)}for(const s of[t.a,t.b]){const t=ja(s,e,o);null!=t&&i.push(t)}}}function Ua(t){let e=t+1|0;return e^=e<<13,e^=e>>>17,e^=e<<5,e>>>0}function Ka(t,e){return t.minY-e.minY||t.index-e.index}function Va(t){return t.subtreeMaxY=Math.max(t.item.maxY,t.left?.subtreeMaxY??-1/0,t.right?.subtreeMaxY??-1/0),t}function Ja(t){const e=t.right;return t.right=e.left,e.left=Va(t),Va(e)}function Ya(t){const e=t.left;return t.left=e.right,e.right=Va(t),Va(e)}function Xa(t,e){return t?(Ka(e,t.item)<0?(t.left=Xa(t.left,e),t.left.priority0)t.right=Za(t.right,e);else{if(!t.left)return t.right;if(!t.right)return t.left;t.left.priority=e&&Qa(t.left,e,s,i),t.item.minY<=s&&t.item.maxY>=e&&i.push(t.item),t.item.minY<=s&&Qa(t.right,e,s,i))}function tn(t,e=.001){const s=Number.isFinite(e)&&e>0?e:Ta,i=t.filter(t=>Na(t.a)&&Na(t.b)&&"string"==typeof t.key&&t.key.length>0&&Math.hypot(t.b[0]-t.a[0],t.b[1]-t.a[1])>s),o=i.map(()=>[0,1]);!function(t,e,s){const i=t.map((t,e)=>({index:e,minX:Math.min(t.a[0],t.b[0])-s,maxX:Math.max(t.a[0],t.b[0])+s,minY:Math.min(t.a[1],t.b[1])-s,maxY:Math.max(t.a[1],t.b[1])+s})),o=[...i].sort((t,e)=>t.minX-e.minX||t.minY-e.minY||t.index-e.index),a=[...i].sort((t,e)=>t.maxX-e.maxX||t.index-e.index),n=new Set;let r=null,l=0;for(const i of o){for(;lt.index-e.index);for(const a of o)qa(t[a.index],t[i.index],e[a.index],e[i.index],s);n.add(i.index),r=Xa(r,i)}}(i,o,s);const a=new Map;for(let t=0;t({key:t,a:e.a,b:e.b,sourceKeys:[...e.sourceKeys].sort((t,e)=>t.localeCompare(e))})).sort((t,e)=>t.key.localeCompare(e.key))}function en(t,e=.001){const s=Number.isFinite(e)&&e>0?e:Ta,i=tn(t,s),o=new Map,a=new Map,n=new Map(i.map(t=>[t.key,t]));for(const t of i){const e=La(t.a,s),i=La(t.b,s);o.set(e,t.a),o.set(i,t.b),a.has(e)||a.set(e,new Set),a.has(i)||a.set(i,new Set),a.get(e).add(i),a.get(i).add(e)}const r=new Map;for(const[t,e]of a){const s=o.get(t);r.set(t,[...e].sort((t,e)=>{const i=o.get(t),a=o.get(e);return Math.atan2(i[1]-s[1],i[0]-s[0])-Math.atan2(a[1]-s[1],a[0]-s[0])||t.localeCompare(e)}))}const l=new Set,h=new Map,c=(t,e)=>`${t}>${e}`;for(const t of i){const e=[La(t.a,s),La(t.b,s)];for(const[t,a]of[e,[e[1],e[0]]]){if(l.has(c(t,a)))continue;const e=[],d=[];let p=t,_=a,u=!1;for(let s=0;s<=2*i.length+2;s++){const s=c(p,_);if(l.has(s)){u=p===t&&_===a;break}l.add(s),e.push(p),d.push(Ea(p,_));const i=r.get(_)||[],o=i.indexOf(p);if(o<0||!i.length)break;if(p=_,_=i[(o-1+i.length)%i.length],p===t&&_===a){u=!0;break}}if(!u||new Set(e).size<3||new Set(e).size!==e.length)continue;const m=e.map(t=>o.get(t)),g=Aa(m);if(!(g>s*s))continue;const f=Ba(Ha(e,o,s)),b=new Set;for(const t of d)for(const e of n.get(t)?.sourceKeys||[])b.add(e);const y={ring:m,key:f,area:g,atomKeys:[...d],sourceKeys:[...b].sort((t,e)=>t.localeCompare(e))};h.has(f)||h.set(f,y)}}return{atoms:i,faces:[...h.values()].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key))}}function sn(t,e,s=.001){if(!Na(e))return null;const i=t.faces.filter(t=>{if(t.ring.some((i,o)=>function(t,e,s,i){const o=s[0]-e[0],a=s[1]-e[1],n=o*o+a*a;if(!(n>0))return Math.hypot(t[0]-e[0],t[1]-e[1])<=i;const r=((t[0]-e[0])*o+(t[1]-e[1])*a)/n;return!(r<0||r>1)&&Math.hypot(e[0]+o*r-t[0],e[1]+a*r-t[1])<=i}(e,i,t.ring[(o+1)%t.ring.length],s)))return!1;let i=!1;for(let s=0,o=t.ring.length-1;se[1]!=n[1]>e[1]&&e[0]<(n[0]-a[0])*(e[1]-a[1])/(n[1]-a[1])+a[0]&&(i=!i)}return i});return[...i].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key))[0]||null}function on(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o,n=a>0?Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a)):0;return Math.hypot(e[0]+i*n-t[0],e[1]+o*n-t[1])}function an(t,e,s=.5){let i=Math.abs(t-e)%180;return i>90&&(i=180-i),i<=s}function nn(t,e,s,i){const o=t.filter(t=>"outer"===t.kind&&!t.open&&t.cm>0).map(t=>({interval:t,reusePartitionId:e.find(e=>function(t,e,s){return!(Math.abs(t.cm-e.cm)>1e-6)&&(an(180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI,180*Math.atan2(e.b[1]-e.a[1],e.b[0]-e.a[0])/Math.PI,.001)&&on(e.a,t.a,t.b)<=s&&on(e.b,t.a,t.b)<=s)}(e,t,i))?.id||null})),a=new Map;for(const e of s){if("partition"===e.host?.kind)continue;const s=t.map(t=>{const s=180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI;return{interval:t,distance:an(e.angle,s)?on([e.x,e.y],t.a,t.b):1/0}}).filter(t=>t.distance<=i).sort((t,e)=>t.distance-e.distance||t.interval.key.localeCompare(e.interval.key)),o=s[0]?.interval;"outer"===o?.kind&&!o.open&&o.cm>0&&a.set(e.id,o.key)}return{materialize:o,openingIntervals:a,removeOpeningIds:[...a.keys()].sort((t,e)=>t.localeCompare(e))}}function rn(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;return o>0?Math.max(0,Math.min(1,((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o)):0}const ln=t=>!t.key.startsWith("static:room|");function hn(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;if(!(o>0))return null;const a=((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o,n=[e.a[0]+s*a,e.a[1]+i*a];return{point:n,t:a,distance:Math.hypot(n[0]-t[0],n[1]-t[1])}}function cn(t,e){return e>0?Math.hypot(t[0]-Math.round(t[0]/e)*e,t[1]-Math.round(t[1]/e)*e):0}function dn(t,e,s){if(ln(t.source)!==ln(e.source))return ln(t.source)?t:e;const i=cn(t.point,s),o=cn(e.point,s);return Math.abs(i-o)>1e-9?i>o?t:e:function(t,e){return t[0]-e[0]||t[1]-e[1]}(t.point,e.point)>0?t:e}function pn(t){return[t.from[0],t.from[1],t.to[0],t.to[1],t.targetKind].map(t=>"number"==typeof t?t.toFixed(6):t).join("|")}function _n(t,e){return t.map(t=>t.key!==e.sourceKey?t:{...t,[e.endpoint]:[...e.to]})}function un(t,e){const s=e.epsilon??.001;if(!(e.maxDistance>=0)||!e.point&&!e.requiredSourceKey)return{kind:"none"};const i=new Map,o=t.flatMap(t=>[{source:t,endpoint:"a",point:t.a},{source:t,endpoint:"b",point:t.b}]);for(let t=0;ts)||l>e.maxDistance)continue;const h=dn(n,r,e.gridStep||0),c=h===n?r:n;if(!ln(h.source))continue;const d={sourceKey:h.source.key,endpoint:h.endpoint,from:[h.point[0],h.point[1]],to:[c.point[0],c.point[1]],targetSourceKey:c.source.key,targetKind:"endpoint",distance:l};i.set(pn(d),d)}for(const a of o)if(ln(a.source))for(const o of t){if(o===a.source)continue;const t=hn(a.point,o);if(!t||t.t<=s||t.t>=1-s||!(t.distance>s)||t.distance>e.maxDistance)continue;const n={sourceKey:a.source.key,endpoint:a.endpoint,from:[a.point[0],a.point[1]],to:t.point,targetSourceKey:o.key,targetKind:"line",distance:t.distance};i.set(pn(n),n)}const a=[];for(const o of i.values()){const i=en(_n(t,o),s),n=e.point?sn(i,e.point,s):i.faces.find(t=>!e.requiredSourceKey||t.sourceKeys.includes(e.requiredSourceKey))||null;n&&a.push({proposal:o,face:n})}if(a.sort((t,e)=>t.proposal.distance-e.proposal.distance||pn(t.proposal).localeCompare(pn(e.proposal))),!a.length)return{kind:"none"};return new Set(a.map(t=>`${pn(t.proposal)}|${t.face.key}`)).size>1?{kind:"ambiguous",proposals:a.map(t=>t.proposal)}:{kind:"repair",...a[0]}}const mn=(t,e)=>(t.composedPath?.()||[t.target]).some(t=>(t=>!!t&&"function"==typeof t.matches)(t)&&e(t));class gn{constructor(t){this.host=t,this._openGroupId=null,this._groupGeneration=0,this._renderedContext="",this._focusOwned=!1,this._currentModel=null,this._blocked=!1,this._dismissPointerTarget=null,this._globalDismissListening=!1,this._globalDismissGuard=t=>{this.handleOutsideDismiss(t)}}get hasOpenGroup(){return null!==this._openGroupId}get groupGeneration(){return this._groupGeneration}activeGroup(t){return this._openGroupId&&t.find(t=>t.id===this._openGroupId)||null}reset(){this._openGroupId=null,this._contentAnimation?.cancel(),this._contentAnimation=void 0,this._renderedContext="",this._focusOwned=!1,this._currentModel=null,this._blocked=!1,this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}closeForNavigation(){const t="palette"===this._currentModel?.kind?this._currentModel.dismiss:void 0,e=!!this._openGroupId||!!t;this._openGroupId=null,t?.(),t&&(this._currentModel=null),this._clearDismissClick(),e&&this.host.requestUpdate(),this._syncGlobalDismissListener()}openPalette(){this._openGroupId&&this.closeGroup(!1)}toggleGroup(t,e){this._openGroupId!==e?t.some(t=>t.id===e)&&("palette"===this._currentModel?.kind&&this._currentModel.dismiss?.(),this._groupGeneration+=1,this._openGroupId=e,this.host.clearTip(),this.host.requestUpdate(),this._syncGlobalDismissListener()):this.closeGroup(!1)}closeGroup(t){const e=this._openGroupId;this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener(),t&&e&&this.host.updateComplete().then(()=>{const t=this.host.root(),s=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===e&&null!==t.offsetParent);(s||t.querySelector(".editbar-tools"))?.focus?.()})}renderGroupLauncher(t,e,s){const i=this._openGroupId===t.id,a=t.items.find(e=>e.id===t.activeItemId&&!e.disabled);return o``}renderGroupModel(t,e,s){const i=t.items.find(t=>!t.disabled)?.id,n=t.items.some(e=>e.id===t.activeItemId&&!e.disabled)?t.activeItemId:void 0;return{contextId:e,kind:"group",ariaLabel:s.openGroup(t.label),visibleLabel:t.label,content:o`
this._groupKeydown(t)}> + ${t.items.map(e=>o``)} +
`}}runContext(t,e,s){t===e&&s()}render(t,e){this._currentModel=t,this._blocked=e;const s=t?.kind||"hidden";return o`
+ +
`}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"),s=this._renderedContext,i=e?.dataset.contextId||"";if(i&&s&&i!==s&&!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=i,s&&i!==s&&this._focusOwned){const s=i?e?.querySelector('[tabindex="0"], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'):t.querySelector(".editbar-tools");s?.focus?.(),this._focusOwned=!!i}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 o=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===this._openGroupId);o&&null!==o.offsetParent||this.closeGroup(!0)}handleOutsideDismiss(t){if(mn(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 s=mn(t,t=>t.classList.contains("editor-secondary")),i=mn(t,t=>!!t.dataset.editorGroup),o=mn(t,t=>!!t.dataset.editorPalette),a=mn(t,t=>t.classList.contains("stage"));if(!(s||i||o||"stay-open-on-canvas"===e?.dismissPolicy&&a))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,s){if(t.id!==this._openGroupId)return;const i=t.items.find(t=>t.id===e);if(!i||i.disabled)return;const o="toggle"===i.role&&"stay-open"===i.closePolicy,a=0===s.detail;o||(this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener()),i.invoke(),!o&&a&&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 s=e.indexOf(this.host.root().activeElement),i="Home"===t.key?0:"End"===t.key?e.length-1:"ArrowLeft"===t.key?s<=0?e.length-1:s-1:(s+1)%e.length;e[i]?.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 fn=t=>t.stopPropagation(),bn=1e-6*I,yn=6*I;function vn(t){return Number.isFinite(t)?Math.round(t/I)*I:t}const $n=(t,e,s,i)=>Math.hypot(s-t,i-e),wn=(t,e,s,i,o,a,n,r)=>Math.hypot(Math.max(Math.abs(o-t),Math.abs(o+n-(t+s))),Math.max(Math.abs(a-e),Math.abs(a+r-(e+i)))),kn=(t,e,s,i,o,a,n)=>{const r=Math.max(Number(i)||0,0)/2,l=Math.PI/180,h=Math.cos(s*l)*r,c=Math.sin(s*l)*r,d=Math.cos(n*l)*r,p=Math.sin(n*l)*r,_=Math.max($n(t+h,e+c,o+d,a+p),$n(t-h,e-c,o-d,a-p)),u=Math.max($n(t+h,e+c,o-d,a-p),$n(t-h,e-c,o+d,a+p));return Math.min(_,u)},xn=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function Sn(t,e){const s=JSON.parse(JSON.stringify(t||[])),i=JSON.parse(JSON.stringify(e||{}));let o=0,a=0,n=0,r=0,l="",h=0,c=0,d=0;const p=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=bn&&c++},_=(t,e)=>{p(t[0],e[0]),p(t[1],e[1])},u={};let m=5;for(const t of s){const e=xn(t);null!=t?.id&&(u[String(t.id)]=e),e>m&&(m=e)}const g=(t,e,s,i=!1)=>{if(!(t>bn||i))return;o++,t>n&&(n=t);const a=t*T*e;a>r&&(r=a,l=s)};for(const t of s){const e=xn(t),s=null!=t?.id?String(t.id):"";for(const i of t.rooms||[]){a++;let t=0;if(i.poly?.length)i.poly=i.poly.map(e=>{const s=[vn(e[0]),vn(e[1])];return t=Math.max(t,$n(e[0],e[1],s[0],s[1])),_(e,s),s});else if(null!=i.x&&null!=i.y){const e=i.x,s=i.y,o=i.w||0,a=i.h||0,n=vn(e+o),r=vn(s+a),l=vn(e),h=vn(s),c=Math.max(I,n-l),d=Math.max(I,r-h);t=wn(e,s,o,a,l,h,c,d),i.x=l,i.y=h,i.w=c,i.h=d,p(e,l),p(s,h),p(e+o,l+c),p(s+a,h+d)}g(t,e,s)}for(const i of t.room_drafts||[]){a++;let t=0;const o=i.points||[],n=o.map(e=>{const s=[vn(e[0]),vn(e[1])];return t=Math.max(t,$n(e[0],e[1],s[0],s[1])),s}),r=n.length?[n[0]]:[],l=n.length?[[o[0],n[0]]]:[],h=[];for(let t=0;t+1=2)for(const[t,e]of l)_(t,e);g(t,e,s)}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 i of t.partitions||[]){a++;const o=[i.a[0],i.a[1]],n=[i.b[0],i.b[1]],r=[vn(o[0]),vn(o[1])],l=[vn(n[0]),vn(n[1])];let h=Math.max($n(o[0],o[1],r[0],r[1]),$n(n[0],n[1],l[0],l[1]));const c=$n(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).every(t=>{const e=Number(t.length),s=Number(t.host.t),i=s*c;return Number.isFinite(e)&&e>0&&Number.isFinite(s)&&s>=0&&s<=1&&i-e/2>=-bn&&i+e/2<=c+bn});c>bn&&d?(i.a=r,i.b=l,_(o,r),_(n,l)):h=0,g(h,e,s)}for(const i of t.wall_columns||[]){a++;const t=[i.center[0],i.center[1]],o=[vn(t[0]),vn(t[1])],n=$n(t[0],t[1],o[0],o[1]);i.center=o,_(t,o),g(n,e,s)}for(const i of t.decor||[]){a++;let t=0;if("line"===i.kind){const e=[i.x1,i.y1],s=[i.x2,i.y2],o=[vn(e[0]),vn(e[1])],a=[vn(s[0]),vn(s[1])];t=Math.max($n(e[0],e[1],o[0],o[1]),$n(s[0],s[1],a[0],a[1])),i.x1=o[0],i.y1=o[1],i.x2=a[0],i.y2=a[1],_(e,o),_(s,a)}else{const e=i.x,s=i.y,o=i.w,a=i.h,n=vn(e),r=vn(s);if(null!=i.w&&null!=i.h){const l=vn(e+o),h=vn(s+a),c=Math.max(I,l-n),d=Math.max(I,h-r);t=wn(e,s,o,a,n,r,c,d),i.w=c,i.h=d,p(e+o,n+c),p(s+a,r+d)}else t=$n(e,s,n,r);i.x=n,i.y=r,p(e,n),p(s,r)}g(t,e,s)}for(const i of t.openings||[]){if(a++,"partition"===i.host?.kind){const o=(t.partitions||[]).find(t=>t.id===i.host.id),a=Number(i.host.t);if(!o||!Number.isFinite(a)||a<0||a>1)continue;const n=o.b[0]-o.a[0],r=o.b[1]-o.a[1];if(Math.hypot(n,r)<=bn)continue;const l=o.a[0]+n*a,c=o.a[1]+r*a;let d=180*Math.atan2(r,n)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(i.angle),_=!(Number.isFinite(p)&&p===d),u=kn(i.x,i.y,Number.isFinite(p)?p:d,Number(i.length)||0,l,c,d);i.x=l,i.y=c,i.angle=d,_&&h++,g(u,e,s,_);continue}const o=P([i.x,i.y],t.rooms||[],yn,{step:I,length:Number(i.length)||0});if(!o)continue;const n=Number(i.angle),r=!(Number.isFinite(n)&&n===o.angle),l=kn(i.x,i.y,Number.isFinite(n)?n:o.angle,Number(i.length)||0,o.x,o.y,o.angle);i.x=o.x,i.y=o.y,i.angle=o.angle,r&&h++,g(l,e,s,r)}}for(const[t,e]of Object.entries(i)){if(!e||"object"!=typeof e)continue;const s=e;if("number"!=typeof s.x||"number"!=typeof s.y)continue;a++;const o=vn(s.x),n=vn(s.y),r=$n(s.x,s.y,o,n);i[t]={...s,x:o,y:n},p(s.x,o),p(s.y,n);const l="string"==typeof s.s?s.s:"";g(r,u[l]??m,l)}return{spaces:s,layout:i,report:{moved:o,coordsCanonicalized:c,total:a,maxShift:n,maxShiftCm:r,maxSpace:l,rotated:h,removedDrafts:d},changed:o>0||c>0}}function Mn(t,e){const s=e.base+t*e.span;return Math.min(1,Math.max(0,s))}const Dn=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Cn=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function Pn(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(a<=0)return Cn(t,e);let n=((t[0]-e[0])*i+(t[1]-e[1])*o)/a;return n=Math.max(0,Math.min(1,n)),Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))}function In(t,e,s,i,o){for(const i of e)if(i&&!s.has(i.id)&&Dn(i.a)&&Dn(i.b)&&(Cn(t,i.a)<=o||Cn(t,i.b)<=o))return!0;for(const e of i?.roomPolygons||[])for(let s=0;s0&&r>0))return null;if(Math.abs(o[0]/n*(a[1]/r)-o[1]/n*(a[0]/r))>s)return null;for(const[s,o]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(Cn(s,o)<=i)return[(s[0]+o[0])/2,(s[1]+o[1])/2];return null}function Rn(t,e){const s=.05*(Number(e.pitch)>0?Number(e.pitch):1),i=new Map;let o=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&Dn(t.a)&&Dn(t.b));if(o.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const a=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let n=0;for(let t=0;tCn(e,t.at)>s);let c=h[0]??r.a,d=h[h.length-1]??l.b;if(h.length<2&&(c=r.a,d=l.b),d[0]0?(d[0]-c[0])/_:0,m=_>0?(d[1]-c[1])/_:0,g=t=>_>0?((t[0]-c[0])*u+(t[1]-c[1])*m)/_:0;for(const t of[r,l]){const e=g(t.a),s=g(t.b)-e;for(const[o,a]of i)a.toId===t.id&&i.set(o,{fromId:a.fromId,toId:p.id,base:e+a.base*s,span:a.span*s});i.set(t.id,{fromId:t.id,toId:p.id,base:e,span:s})}a&&a.add(p.id),o=o.filter((e,s)=>s!==t.i&&s!==t.j),o.splice(t.i,0,p),n++}return{partitions:o,merged:n,openingMoves:[...i.values()]}}function Fn(t,e,s,i){if(!t?.length||!s.length)return 0;const o=new Map(s.map(t=>[t.fromId,t]));let a=0;for(const s of t){const t=s?.host;if(!t||"partition"!==t.kind)continue;const n=o.get(t.id);if(!n)continue;s.host={...t,id:n.toId,t:Mn(t.t,n)},a++;const r=F(s,e,i.coordScale,i.cellCm,i.gridPitch).resolved;r&&Object.assign(s,N(s,r,i.coordScale))}return a}function Nn(t,e){const s=e?.excludeDraftId||null;return{roomPolygons:(t?.rooms||[]).map(t=>R(t)).filter(t=>!!t),columns:t?.wall_columns||[],draftEnds:(t?.room_drafts||[]).flatMap(t=>{if(s&&t?.id===s)return[];const e=t?.points||[];return e.length?[e[0],e[e.length-1]]:[]})}}const zn=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),An=(t,e)=>t[0]-e[0]||t[1]-e[1],On=(t,e,s,i)=>[t[0]+e*i,t[1]+s*i],Ln=(t,e,s,i)=>(t[0]-e[0])*s+(t[1]-e[1])*i,En=(t,e,s,i,o)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o))return null;const l=a/r,h=n/r,c=e=>Math.abs((e[0]-t[0])*h-(e[1]-t[1])*l);if(c(s)>o||c(i)>o)return null;const d=Ln(s,t,l,h),p=Ln(i,t,l,h),_=Math.max(0,Math.min(d,p)),u=Math.min(r,Math.max(d,p));return u-_>o?{lo:_,hi:u}:null},Bn=(t,e,s)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>s,Hn=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},Gn=(t,e,s,i)=>{const o=t.b[0]-t.a[0],a=t.b[1]-t.a[1],n=Math.hypot(o,a);if(!(n>i))return!0;const r=o/n,l=a/n,h=j(t.cm,s.cellCm,s.gridPitch)/2;return e.some(e=>{const o=e?.center;if(!zn(o))return!0;const a=Ln(o,t.a,r,l),c=Math.abs((o[0]-t.a[0])*l-(o[1]-t.a[1])*r),d=j(Number(e.cm),s.cellCm,s.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||a>=-d-i&&a<=n+d+i&&c<=h+d+i})},Wn=(t,e,s)=>{if(t.host){const i=F(t,e,s.coordScale,s.cellCm,s.gridPitch).resolved;return i?{center:i.center,angle:i.angle,length:i.length}:null}const i=Number(t.x)*s.coordScale,o=Number(t.y)*s.coordScale,a=Number(t.angle),n=Number(t.length)*s.coordScale;return[i,o,a,n].every(Number.isFinite)&&n>0?{center:[i,o],angle:a,length:n}:null},jn=(t,e,s)=>{const i=t.angle*Math.PI/180,o=Math.cos(i),a=Math.sin(i),n=e.angle*Math.PI/180,r=Math.cos(n),l=Math.sin(n);if(Math.abs(o*l-a*r)>1e-6)return!1;const h=e.center[0]-t.center[0],c=e.center[1]-t.center[1];if(Math.abs(h*a-c*o)>s)return!1;const d=h*o+c*a;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]}),Un=(t,e,s,i)=>{const o=`~r-${(t=>{let e=2166136261;for(let s=0;s>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${s[0].toFixed(9)},${s[1].toFixed(9)}`)}`,a=`${t.slice(0,Math.max(1,64-o.length))}${o}`;let n=a;for(let t=2;i.has(n);t++){const e=`-${t}`;n=`${a.slice(0,64-e.length)}${e}`}return i.add(n),n},Kn=(t,e)=>{const s=[];for(const i of t){const t=s[s.length-1];!(t&&Math.abs(t.hi-i.lo)<=e&&t.safe===i.safe)||i.safe&&t.signature!==i.signature?s.push({lo:i.lo,hi:i.hi,a:i.a,b:i.b,safe:i.safe,signature:i.signature,roomIds:i.roomIds,finalCm:i.finalCm}):(t.hi=i.hi,t.b=i.b)}return s};function Vn(t,e,s,i,o){const a=s||[],n=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l=Array.isArray(t?.room_drafts)?t.room_drafts:[],h={walls:a,partitions:n,openings:r,roomDrafts:l,partitionsReconciled:0,openingsRehosted:0,removedDrafts:0};if(!n.length&&!l.length)return h;const c=Math.max(2e-4*o.gridPitch,1e-9);let d=a,p=n,_=r;const u=z(e.rooms,d,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),m=((t,e,s,i)=>{const o=new Map(t.map(t=>[t.id,t])),a=new Set;for(const t of e){if(!o.get(t.id)||!Array.isArray(t.points)||t.points.length<2||t.segments.length!==t.points.length-1)continue;let e=!0;for(let o=0;o+10)){e=!1;break}const l=Math.hypot(n[0]-a[0],n[1]-a[1]);if(!(l>i)){e=!1;break}const h=s.flatMap(t=>{const e=t.cm>0?t.cm:A;if(t.open||"outer"!==t.kind&&"shared"!==t.kind||e+it.lo-e.lo||t.hi-e.hi);let c=0;for(const t of h){if(t.lo>c+i)break;if(c=Math.max(c,t.hi),c>=l-i)break}c!m.has(t.id));let f=0,b=0;const y=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...n].sort((t,e)=>t.id.localeCompare(e.id))){if(!p.some(e=>e.id===t.id))continue;if(!Hn(t))continue;const s=y.get(t.id);if(!(s&&zn(s.a)&&zn(s.b)&&Number.isFinite(s.cm)&&s.cm>0))continue;const[a,n]=An(s.a,s.b)<=0?[[s.a[0],s.a[1]],[s.b[0],s.b[1]]]:[[s.b[0],s.b[1]],[s.a[0],s.a[1]]],r=n[0]-a[0],l=n[1]-a[1],h=Math.hypot(r,l);if(!(h>c))continue;const u=r/h,g=l/h,v=z(e.rooms,d,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),$=v.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=En(a,n,t.a,t.b,c);return e?[{interval:t,range:e}]:[]});if(!$.length)continue;const w=_.filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).map(t=>({opening:t,resolved:F(t,e.partitions,o.coordScale,o.cellCm,o.gridPitch).resolved}));if(w.some(t=>!t.resolved))continue;const k=[0,h];for(const{range:t}of $)k.push(t.lo,t.hi);const x=k.slice(),S=new Map;for(const{opening:t,resolved:e}of w){const s=Ln(e.center,a,u,g),i={lo:s-e.length/2,hi:s+e.length/2};S.set(t.id,i),x.push(Math.max(0,i.lo),Math.min(h,i.hi))}const M=[...new Set(x.filter(t=>Number.isFinite(t)&&t>=-c&&t<=h+c).map(t=>Math.max(0,Math.min(h,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),D=p.map(t=>qn(t,o.coordScale)).filter(t=>t.id!==s.id),C=e.room_drafts.filter(t=>!m.has(t.id)),P=[];for(let t=0;t+1c))continue;const r=On(a,u,g,i),l=On(a,u,g,n),h=$.filter(({range:t})=>t.lo<=i+c&&t.hi>=n-c).map(({interval:t})=>t),d=new Map;for(const t of h)d.set(t.roomId,t);const p=[...d.values()],_=new Set(p.map(t=>t.kind)),m=new Set(p.map(t=>t.cm>0?t.cm:A)),f=p[0]?.kind,b=[...d.keys()].sort(),y=1===_.size&&1===m.size&&("outer"===f&&1===b.length||"shared"===f&&2===b.length),v={id:s.id,a:r,b:l,cm:s.cm},w=D.some(t=>!!En(r,l,t.a,t.b,c)),k=C.some(t=>t.points.some((e,s)=>s+10?p[0].cm:A:0,I=y?Math.max(S,s.cm):s.cm;P.push({lo:i,hi:n,a:r,b:l,safe:x,signature:x?`${f}|${b.join(",")}|${I}`:"",roomIds:b,roomCm:S,finalCm:I})}if(!P.some(t=>t.safe))continue;const I=new Map;for(const{opening:t,resolved:e}of w){const i=S.get(t.id),a=k.some(t=>t>i.lo+c&&tBn(t,i,c)),r=new Set(n.filter(t=>t.safe).map(t=>t.signature));if(!a&&n.length>0&&n.every(t=>t.safe)&&1===r.size&&O(e,v,c)){I.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=L(s,o.cellCm,o.gridPitch),h={lo:i.lo-l,hi:i.hi+l};for(const t of P)Bn(t,h,c)&&(t.safe=!1,t.signature="")}let T=!0;for(;T;){T=!1;for(const[t,e]of[...I.entries()]){const i=S.get(t),a=P.filter(t=>Bn(t,i,c));if(a.length>0&&a.every(t=>t.safe)&&a.every(t=>t.signature===e.signature))continue;I.delete(t);const n=L(s,o.cellCm,o.gridPitch),r={lo:i.lo-n,hi:i.hi+n};for(const t of P)Bn(t,r,c)&&(t.safe=!1,t.signature="");T=!0}}const R=Kn(P,c),j=R.filter(t=>t.safe),q=R.filter(t=>!t.safe);if(!j.length)continue;if(p.length-1+q.length>2e3)continue;let U=d;for(const t of j){const[e,i]=An(s.a,s.b)<=0?[t.a,t.b]:[t.b,t.a];U=E(U,e,i,t.finalCm,o.pitch,o.coordScale)}if(U=B(e.rooms,U,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),U.length>500)continue;const K=new Set(p.map(t=>t.id));K.delete(s.id);const V=q.map((t,e)=>{const i=[t.a[0]/o.coordScale,t.a[1]/o.coordScale],a=[t.b[0]/o.coordScale,t.b[1]/o.coordScale],n=0===e?s.id:Un(s.id,i,a,K);return K.add(n),{id:n,a:i,b:a,cm:s.cm}}),J=p.findIndex(t=>t.id===s.id),Y=p.slice();Y.splice(J,1,...V);const X=Y.map(t=>qn(t,o.coordScale)),Z=new Map;let Q=!0;for(const{opening:t,resolved:e}of w){const s=I.get(t.id);if(s){const e=N(t,s.resolved,o.coordScale),{host:i,...a}=e;Z.set(t.id,a);continue}const i=S.get(t.id),a=V[q.findIndex(t=>t.lo<=i.lo+c&&t.hi>=i.hi-c)],n=a&&X.find(t=>t.id===a.id);if(!a||!n){Q=!1;break}const r=n.b[0]-n.a[0],l=n.b[1]-n.a[1],h=Math.hypot(r,l),d=Ln(e.center,n.a,r/h,l/h),p={...N(t,e,o.coordScale),host:{kind:"partition",id:a.id,t:d/h}};if(!H(p,X,o.coordScale,o.cellCm,o.gridPitch).resolved){Q=!1;break}Z.set(t.id,p)}if(!Q)continue;const tt=_.map(t=>Z.get(t.id)||t),et=[...I.keys()].map(t=>Z.get(t)),st=et.map(t=>Wn(t,X,o));if(st.some(t=>!t))continue;let it=!1;for(let t=0;tt.id));for(const t of tt){if(ot.has(t.id))continue;const e=Wn(t,X,o);e&&st.some(t=>jn(t,e,c))&&(it=!0)}if(it)continue;const at=G(e.rooms,U,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale);[...I.entries()].every(([t,e])=>{const s=Z.get(t),i=W(at,{x:s.x*o.coordScale,y:s.y*o.coordScale,angle:s.angle,length:s.length*o.coordScale},!0),a=[i.negative,i.positive].filter(t=>!!t?.full),n=e.signature.split("|")[1].split(","),r=new Set(a.map(t=>t.roomId));return a.length===n.length&&r.size===n.length&&n.every(t=>r.has(t))})&&(d=U,p=Y,_=tt,f+=j.length,b+=I.size)}return{walls:d,partitions:p,openings:_,roomDrafts:g,partitionsReconciled:f,openingsRehosted:b,removedDrafts:m.size}}const Jn=t=>JSON.parse(JSON.stringify(t)),Yn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Xn=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function Zn(t,e){let s=String(e??"");const i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=new RegExp(`^${i}_(.+)_([0-9a-f]{8})$`);let a=0;for(;a<16;a++){const t=o.exec(s);if(!t)return{root:s,layers:a,bounded:!1};s=t[1]}return{root:s,layers:a,bounded:o.test(s)}}const Qn=(t,e,s)=>{const i=t.get(e)||[];i.push(s),t.set(e,i)};const tr=1e-9;class er extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const sr=t=>JSON.parse(JSON.stringify(t)),ir=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),or=t=>[Number(t[0]),Number(t[1])],ar=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,nr=(t,e)=>{const s=ar(t),i=ar(e);return sar(t)<=ar(e)?[or(t),or(e)]:[or(e),or(t)],lr=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),hr=t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],s=[];for(let i=1;i{const s=new Set,i=t=>{const e=Number(t);if(!Number.isFinite(e))return;const i=e/I;Math.abs(i-Math.round(i))>=X&&s.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of R(e)||[])i(t[0]),i(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])i(t?.a?.[0]),i(t?.a?.[1]),i(t?.b?.[0]),i(t?.b?.[1]);for(const t of e)i(t?.[0]),i(t?.[1]);return s.size},dr=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;return a>1e-18?((t[0]-e[0])*i+(t[1]-e[1])*o)/a:0},pr=(t,e,s)=>{const i=Math.max(0,Math.min(1,dr(t,e,s)));return Math.hypot(t[0]-(e[0]+(s[0]-e[0])*i),t[1]-(e[1]+(s[1]-e[1])*i))},_r=(t,e,s,i,o=tr)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(r<=o)return 0;const l=e=>Math.abs((e[0]-t[0])*n-(e[1]-t[1])*a)/r;if(l(s)>o||l(i)>o)return 0;const h=dr(s,t,e),c=dr(i,t,e);return Math.max(0,Math.min(1,Math.max(h,c))-Math.max(0,Math.min(h,c)))*r},ur=t=>{const e=(new TextEncoder).encode(t),s=8*e.length,i=64*Math.ceil((e.length+9)/64),o=new Uint8Array(i);o.set(e),o[e.length]=128;const a=new DataView(o.buffer);a.setUint32(i-8,Math.floor(s/4294967296),!1),a.setUint32(i-4,s>>>0,!1);const n=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),h=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,o=h(s,17)^h(s,19)^s>>>10;l[t]=l[t-16]+i+l[t-7]+o>>>0}let[e,s,i,o,c,d,p,_]=r;for(let t=0;t<64;t++){const a=_+(h(c,6)^h(c,11)^h(c,25))+(c&d^~c&p)+n[t]+l[t]>>>0,r=e&s^e&i^s&i;_=p,p=d,d=c,c=o+a>>>0,o=i,i=s,s=e,e=a+((h(e,2)^h(e,13)^h(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+s>>>0,r[2]=r[2]+i>>>0,r[3]=r[3]+o>>>0,r[4]=r[4]+c>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+_>>>0}const c=new Uint8Array(32),d=new DataView(c.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let s=0,i=0,o="";for(const a of t)for(i=i<<8|a,s+=8;s>=5;)o+=e[i>>>s-5&31],s-=5;return s&&(o+=e[i<<5-s&31]),o},gr=(t,e,s,i,o="")=>{const[a,n]=rr(e,s),r=`${t}|${ar(a)}|${ar(n)}|${[...i].sort().join(",")}${o}`;return`wall-${mr(ur(r)).slice(0,20)}`};let fr=0;const br=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),s=`wall-${e||mr(ur(`${Date.now()}|${fr++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(s))return s}throw new er("duplicate-id","id factory exhausted")},yr=t=>{const e=new Map;for(const s of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(s&&"string"==typeof s.id&&ir(s.a)&&ir(s.b)){if(e.has(s.id))throw new er("duplicate-id",s.id);e.set(s.id,s)}return e},vr=(t,e,s)=>{const i=(s,i)=>{const o=t[0]-s[0],a=t[1]-s[1];return Math.abs(e[0]-i[0]-o)<=tr&&Math.abs(e[1]-i[1]-a)<=tr?[o,a]:null};return i(s.a,s.b)||i(s.b,s.a)},$r=(t,e)=>{const s=Array.isArray(t.rooms)?t.rooms:[],i=V(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),o=i.length?i:J(s,null,1,.04*I,!0),a=[];for(const t of s){const s=R(t),i=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(s&&i.length===s.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&&o.some(e=>pr([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*I)):[],l=r.map(t=>{const e=Number(t.angle)*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Number(t.length)/2,o=[Number(t.x),Number(t.y)];return{a:[o[0]-s[0]*i,o[1]-s[1]*i],b:[o[0]+s[0]*i,o[1]+s[1]*i]}}),h=(t,e)=>r.some(s=>{const i=[Number(s.x),Number(s.y)];if(!Z(t,e,Number(s.angle)))return!1;if(pr(i,t,e)>.02*I)return!1;const o=lr(t,e),a=dr(i,t,e)*o,n=Number(s.length)/2;return a+n>=-tr&&a-n<=o+tr}),c=new Map,d=[];for(const i of s){const r=String(i?.id||""),p=R(i);if(!r||!p||p.length<3)throw new er("invalid-room",r);const _=Y(s,r,n,I,1,[...t.walls||[],...l]);if(!_||_.poly.length<3)throw new er("invalid-room",r);const u=Array.isArray(i.wall_ids)?i.wall_ids:[],m=u.length===p.length;let g=null,f=m;if(f)for(let t=0;ttr||Math.abs(i[1]-g[1])>tr)){f=!1;break}g=i}const b=[];for(let t=0;t<_.poly.length;t++){const s=_.poly[t],i=_.poly[(t+1)%_.poly.length];if(lr(s,i)<=tr)throw new er("zero-length",r);const n=nr(s,i);let l=c.get(n);if(!l){const[t,e]=rr(s,i);l={key:n,a:t,b:e,owners:new Set,preferredIds:new Set,positionalIds:new Set,preferredCarriers:new Map,parentKeys:new Set,zeroWall:!1},c.set(n,l)}if(l.owners.add(r),l.owners.size>2)throw new er("third-owner",n);const d=m?u[_.parent[t]]:void 0;if("string"==typeof d&&d){const o=e.get(d);f||!o||_r(s,i,o.a,o.b)>tr?l.preferredIds.add(d):l.positionalIds.add(d),l.preferredCarriers.set(d,{a:or(p[_.parent[t]]),b:or(p[(_.parent[t]+1)%p.length])})}const g=_.parent[t];l.parentKeys.add(K(p[g],p[(g+1)%p.length],I));const y=[(s[0]+i[0])/2,(s[1]+i[1])/2],v=t=>t.some(t=>pr(y,[t[0],t[1]],[t[2],t[3]])<=.04*I);l.zeroWall||=v(a)||v(o)&&!h(s,i),b.push(n)}const y={...i};delete y.wall_ids,d.push({...y,poly:_.poly.map(t=>[t[0],t[1]]),wall_ids:b})}return{atoms:[...c.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},wr=(t,e,s,i,o)=>{const a=new Map([...s.values()].map(t=>[nr(t.a,t.b),t])),n=(t=>{const e=new Map;for(const s of t)"wall"===s.host?.kind&&e.set(s.host.id,(e.get(s.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=o?.get(t.key);if(e){const i=s.get(e);if(!i)throw new er("duplicate-id",e);r.set(t,i);continue}if(t.preferredIds.size>1)throw new er("duplicate-id",[...t.preferredIds].sort().join(","));const i=[...t.preferredIds][0],l=i?s.get(i):void 0;if(l){r.set(t,l);continue}const h=i?t.preferredCarriers.get(i):void 0;if(i&&h){r.set(t,{id:i,a:h.a,b:h.b,cm:0});continue}const c=a.get(t.key);if(c){r.set(t,c);continue}const d=[...s.values()].filter(e=>_r(t.a,t.b,e.a,e.b)>tr),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(n.get(e.id)||0)-(n.get(t.id)||0)||lr(e.a,e.b)-lr(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=s.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const s=l.get(e.id)||[];s.push(t),l.set(e.id,s)}for(const[t,e]of l){const i=s.get(t)||r.get(e[0]);if(!i)throw new er("duplicate-id",t);const o=[(i.a[0]+i.b[0])/2,(i.a[1]+i.b[1])/2];e.sort((t,e)=>{const s=pr(o,t.a,t.b)<=tr?0:1,a=pr(o,e.a,e.b)<=tr?0:1;if(s!==a)return s-a;return(pr(i.a,t.a,t.b)<=tr?0:1)-(pr(i.a,e.a,e.b)<=tr?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const h=(t=>{const e=new Set;for(const s of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(s)?s:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(s?.segments)?s.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(h.has(t.id))throw new er("duplicate-id",t.id);h.add(t.id)}const c=e.filter(t=>!t.id);if(i){const e=c.map(e=>{const[s,i]=rr(e.a,e.b),o=`${String(t.id||"")}|${ar(s)}|${ar(i)}|${[...e.owners].sort().join(",")}`,a=mr(ur(o));return{atom:e,seed:o,digest:a,base:`wall-${a.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),s=new Map;for(const t of e){const e=s.get(t.digest);if(e&&e!==t.seed)throw new er("duplicate-id",t.digest);s.set(t.digest,t.seed);let i=1,o=t.base;for(;h.has(o);)o=`${t.base}-${++i}`;t.atom.id=o,h.add(o)}}else for(const t of c)t.id=br(h),h.add(t.id)},kr=(t,e)=>{if("partition"===t.host?.kind)return null;const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=e=>{if(!(Number(e.cm)>0))return!1;const i=dr(s,e.a,e.b),o=lr(e.a,e.b),a=Number(t.length)/2;return i>=-tr&&i<=1+tr&&pr(s,e.a,e.b)<=.02*I&&Z(e.a,e.b,Number(t.angle))&&Number.isFinite(a)&&a>=0&&i*o-a>=-tr&&i*o+a<=o+tr},o="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,a=o&&i(o)?[o]:e.filter(i);if(1!==a.length)return null;const n=a[0];return{kind:"wall",id:n.id,t:Math.max(0,Math.min(1,dr(s,n.a,n.b)))}},xr=(t,e)=>{const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=Number(t.length)/2,o=e.filter(e=>{if(!(Number(e.cm)>0))return!1;const o=dr(s,e.a,e.b),a=lr(e.a,e.b);return o>=-tr&&o<=1+tr&&pr(s,e.a,e.b)<=.02*I&&Z(e.a,e.b,Number(t.angle))&&Number.isFinite(i)&&i>=0&&o*a-i>=-tr&&o*a+i<=a+tr}),a=(e=>{if(!e.length)return null;const i="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null;return i||[...e].sort((t,e)=>pr(s,t.a,t.b)-pr(s,e.a,e.b)||Number(e.cm)-Number(t.cm)||(t.ide.id?1:0))[0]})(o);return a?{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,dr(s,a.a,a.b)))}:null},Sr=(t,e,s)=>{const i=yr(t),{atoms:o,rooms:a}=$r(t,i);wr(t,o,i,e,s);const n=o.map(e=>{const s=e.id?i.get(e.id):void 0,o=((t,e,s)=>{if(e.zeroWall)return 0;const i=Array.isArray(t.walls)?t.walls:[],o=K(e.a,e.b,I),a=i.filter(t=>Number(t.cm)>0&&(!(t.key!==o&&!e.parentKeys.has(t.key))||!(!ir(t.a)||!ir(t.b))&&_r(e.a,e.b,t.a,t.b)>=lr(e.a,e.b)-tr)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(a.map(t=>t.toFixed(9))).size>1)throw new er("thickness-conflict",e.key);if(a.length)return a[0];const n=Q(i,e.a,e.b,I,1);return n>0?n:Number(s?.cm)>0?Number(s.cm):0})(t,e,s);return{...s||{},id:e.id,a:[...e.a],b:[...e.b],cm:o}}),r=new Map(o.map(t=>[t.key,t.id]));for(const t of a)t.wall_ids=t.wall_ids.map(t=>r.get(t));t.rooms=a,t.wall_segments=n,t.walls=n.filter(t=>t.cm>0).map(t=>({key:K(t.a,t.b,I),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 s=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&&s.add(t.id);for(const i of Array.isArray(t.room_drafts)?t.room_drafts:[]){const o=Array.isArray(i.segments)?i.segments:[];for(let a=0;a{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;if(!t.host&&!s){const s=kr(t,e);s&&(t.host=s);continue}const i=kr(t,e)??(s?xr(t,e):null);if(i)t.host=i;else{if(!s)throw new er("opening-host",t.id);delete t.host}}})(t,n,e),n.reduce((t,e)=>t+(i.has(e.id)?0:1),0)};function Mr(t,e={}){const s=JSON.stringify(t),i=sr(t);U(i);let o=0;const a=Number(i?.model_version||0)<9;for(const t of Array.isArray(i?.spaces)?i.spaces:[]){const s=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0;o+=Sr(t,a,s)}return i.model_version=9,U(i),{config:i,changed:s!==JSON.stringify(i),migratedSegments:o}}const Dr=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Cr(t,e){const s=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const i=new Map;for(const e of t)Dr(e)&&"string"==typeof e.id&&e.id&&i.set(e.id,e);const o=e.map((e,o)=>{if(Dr(e)&&"string"==typeof e.id&&e.id){const t=i.get(e.id);return t?s(t,e):sr(e)}return o[e,e in t?s(t[e],i):sr(i)]);for(const e of Object.keys(t))delete t[e];for(const[e,s]of i)t[e]=s;return t}return sr(e)};return s(t,e)}const Pr=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Ir=(t,e,s)=>Math.min(s,Math.max(e,t)),Tr=t=>ut({spaces:[t]})[0],Rr=(t,e,s)=>{const i=s>0?s:1,o=t=>`${(t[0]/i).toFixed(12)},${(t[1]/i).toFixed(12)}`,a=o(t),n=o(e);return a0?n:1,l=Math.max(i*r*.02,1e-9),h=[];for(const e of t||[])for(const t of R(e)||[])h.push([t[0],t[1]]);const c=[];for(const t of s||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&c.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 n of t||[]){if(!n?.id)continue;const _=mt(t,n.id,e,s,i,o,a,r);if(_)for(let t=0;t<_.orig.length;t++){const e=[];for(let s=0;s<_.parent.length;s++)_.parent[s]===t&&e.push(s);for(let t=1;t+10&&u>0&&n===m&&u!==n))continue;const g=_.poly[i],f=_.poly[(i+1)%_.poly.length],b=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(b>l&&b<.5*a-1e-9*a))continue;if(d(g,c)||d(f,c))continue;if(d(g,h)&&d(f,h))continue;const y=Rr(g,f,r),v=p.get(y);v?v.targets.add(n):p.set(y,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([n])})}}}let _=e.slice();const u=(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 s=[Number(t.a[0])*r,Number(t.a[1])*r],i=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...s,...i].every(Number.isFinite)&&(u(s,e.a)&&u(i,e.b)||u(s,e.b)&&u(i,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>Rr(t.a,t.b,r).localeCompare(Rr(e.a,e.b,r)))){const e=[...t.targets][0],s=_.filter(e=>m(e,t));if(new Set(s.map(t=>t.cm)).size>1)continue;let o=!1;_=_.map(s=>m(s,t)?(o=!0,s.cm===e?s:{...s,cm:e}):s),o||(_=E(_,t.a,t.b,e,i,r))}return _}const Nr=t=>{const e=[];for(const s of t||[]){const t=R(s);if(t?.length)for(let s=0;s"string"==typeof t?.id?t.id:"").filter(Boolean),c=new Set(h),d=new Map;for(const t of h){const e=Zn("space",t);e.layers>0&&Xn("space",e.root)&&Qn(d,e.root,t)}const p=new Map,_=new Map,u=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s=new Map;for(const i of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof i?.id?i.id:"";if(!t)continue;const o=Zn("room",t);o.layers>0&&Xn("room",o.root)&&Qn(s,o.root,t),_.has(t)||_.set(t,e),u.has(t)||u.set(t,String(i.name||""));const a="string"==typeof i.area?i.area:"";if(a){const s=m.get(a)||[];s.push({spaceId:e,roomId:t}),m.set(a,s)}}p.set(e,s)}const g=new Set(_.keys()),f=new Map,b=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?b.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:[]},v=new Set,$=t=>c.has(t)?null:(()=>{const e=Zn("space",t).root;if(!Xn("space",e))return null;const s=d.get(e)||[];return 1===s.length?s[0]:null})(),w=(t,e)=>{const s=Zn("room",t).root;if(!Xn("room",s))return null;const i=p.get(e)?.get(s)||[];return 1===i.length?i[0]:null},k=t=>{const e=s.effectiveAreaByMarker?.[t]||"",i=e&&m.get(e)||[];return 1===i.length?i[0]:null},x=(t,e,s)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const i=e?w(t.room_id,e):null;i?(t.room_id=i,y.roomRefsRemapped++):s?(t.room_id=s.roomId,y.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const i=t.vacuum?.segment_map;if(i&&"object"==typeof i&&!Array.isArray(i))for(const t of Object.keys(i)){const s=i[t];if("string"!=typeof s||!s||g.has(s))continue;const o=e?w(s,e):null;o?(i[t]=o,y.roomRefsRemapped++):y.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s="string"==typeof t.space?t.space:"",i=s&&!c.has(s),a=o[e],n="string"==typeof a?.s?a.s:"",r=n&&!c.has(n),l=!0===t.removed;let h=s&&c.has(s)?s:null,d=null,p=!1;if(i){const i=$(s);i?(t.space=i,h=i,p=!0,y.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,h=null,y.markersDetached++):(d=k(e),d?(t.space=d.spaceId,h=d.spaceId,y.spaceRefsRemapped++):(delete t.space,h=null,y.markersDetached++))}l&&!p||x(t,h,d),r&&p&&n===s&&h&&(o[e]={...a,s:h},y.positionsRemapped++,v.add(e))}for(const t of Object.keys(o)){if(v.has(t))continue;const e=o[t],s="string"==typeof e?.s?e.s:"";if(!s||c.has(s))continue;const i=$(s);if(i){if(t.startsWith("rl_")){const s=t.slice(3),a=w(s,i);if(a){const s=`rl_${a}`;Yn(o,s)||(o[s]={...e,s:i}),delete o[t],y.roomRefsRemapped++,y.positionsRemapped++;continue}}o[t]={...e,s:i},y.positionsRemapped++}}const S=s.ownerRoster,M=!0===S?.authoritative,D=new Set(S?.deviceIds||[]),C=new Set(S?.entityIds||[]),P=new Set(Array.isArray(i.settings?.known_devices)?i.settings.known_devices.filter(t=>"string"==typeof t):[]),I=(t,e="")=>{const s=String(S?.names?.[t]||e||"").trim();return s&&s!==t?s:""},T=(t,e,s,i="",o)=>({id:t,spaceId:e,kind:s,name:I(t,i),...o?{reason:o}:{}}),R=t=>{"room_label"===t?y.orphanRoomLabelsRemoved++:"group"===t?y.orphanGroupPositionsRemoved++:y.orphanDevicePositionsRemoved++},F=new Set;for(const[t,e]of Object.entries(o)){const i="string"==typeof e?.s?e.s:"";if(!i||c.has(i))continue;let a,n;const r=f.get(t),l=b.get(t);if(r)a=T(t,i,"device",String(r.name||"")),n="live";else if(l)a=T(t,i,"device",String(l.name||"")),n="absent";else if(t.startsWith("rl_")){const e=t.slice(3);a=T(t,i,"room_label",u.get(e)||""),n=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);a=T(t,i,"group"),n=C.has(e)?"live":M?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")}else D.has(t)?(a=T(t,i,"device"),n="live"):P.has(t)?(a=T(t,i,"device"),n=M?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")):(a=T(t,i,"unknown","","unknown_owner"),n="unverified");if("absent"!==n){if("live"===n){if(y.liveMissingPositions.push(a),!0===s.removeLiveMissingPositions){delete o[t],y.liveMissingPositionsRemoved++,R(a.kind),y.removedPositions.push(a);continue}}else y.unverifiedPositions.push(a);y.positionsUnresolved++,F.add(i)}else delete o[t],R(a.kind),y.removedPositions.push(a)}return y.deadSpaceIds=[...F].sort((t,e)=>t.localeCompare(e)),{config:i,layout:o,report:y,changed:JSON.stringify(i)!==a||JSON.stringify(o)!==n}}(t,e,s),n=a.config,r=tt(n,a.layout);U(n),et(a.layout);const l=JSON.stringify(t||{}),h=JSON.stringify(e||{}),c=Number.isInteger(Number(n.model_version))?Number(n.model_version):0,d=(t=>{let e=0,s=0,i=0;for(const s of t.markers||[]){if("ripple"===s.display&&(s.display="icon_ripple",e++),Array.isArray(s.controls)){const t="string"==typeof s.binding&&s.binding.startsWith("entity:")?s.binding.slice(7):"",i=t?s.controls.filter(e=>e!==t):s.controls;JSON.stringify(i)!==JSON.stringify(s.controls)&&(s.controls=i.length?i:null,e++)}const t=s.vacuum;t&&Pr(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const o of t.spaces||[]){const t=o.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,s++);for(const t of o.rooms||[]){const s=t.settings;"glow"===s?.fill_mode&&("boolean"!=typeof s.glow&&(s.glow=!0),delete s.fill_mode,e++,i++)}if(Pr(o,"segments")&&(delete o.segments,e++),Pr(o,"plan_scale")){const t=Number(o.plan_scale);Number.isFinite(t)&&t>=lt&&t<=ht&&(Pr(o,"plan_scale_x")||(o.plan_scale_x=t),Pr(o,"plan_scale_y")||(o.plan_scale_y=t),delete o.plan_scale,e++)}const a=Number(o.cell_cm);Pr(o,"cell_cm")&&(!Number.isFinite(a)||a<.1||a>1e3)&&(o.cell_cm=Number.isFinite(a)&&a>0?Ir(a,.1,1e3):5,e++);const n=Number(o.cell_cm),r=Number.isFinite(n)&&n>0?n:5;for(const t of o.wall_columns||[])if("circle"===t.shape)Pr(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Pr(t,"angle")){const s=((Number(t.angle)||0)%90+90)%90;t.angle!==s&&(t.angle=s,e++)}for(const t of o.decor||[]){if(Pr(t,"width")){const s=Number(t.width);(Pr(t,"width_cm")||Number.isFinite(s))&&(Pr(t,"width_cm")||(t.width_cm=Number(Ir(s/nt*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Pr(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Pr(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(Ir(ct*dt(t)/nt*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Pr(t,"scale")||Pr(t,"size"))&&(delete t.scale,delete t.size,e++);let s=String(t.text??"");const i=[...s.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!pt(t[1]));if(!(Pr(t,"entity")||Pr(t,"attr")||Pr(t,"unit")))continue;const o=String(t.unit??"").trim(),a="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||o?"":_t(t.entity,a);if(i||n){if(n){const e=s.indexOf("{}");s=e>=0?s.slice(0,e)+n+s.slice(e+2):`${s}${s?" ":""}${n}`,t.text=s}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:s,glowRooms:i}})(n);let p=d.total;const _=(u=n.spaces||[],JSON.parse(JSON.stringify(u)));var u;const m=Sn(n.spaces||[],a.layout);let g=0,f=0,b=0,y="";const v=m.spaces.map(t=>{const e=st(t);g+=e.report.wallsStraightened,f+=e.report.wallsStraightenSkipped;const s=Number(t?.cell_cm)>0?Number(t.cell_cm):5,i=e.report.maxStraightenShift/I*s;return i>b&&(b=i,y=String(t?.id||"")),e.space}),$=g?Sn(v,m.layout):{...m,spaces:v};n.spaces=$.spaces;const w=g?{...m.report,moved:m.report.moved+$.report.moved,coordsCanonicalized:m.report.coordsCanonicalized+$.report.coordsCanonicalized,maxShift:Math.max(m.report.maxShift,$.report.maxShift),maxShiftCm:Math.max(m.report.maxShiftCm,$.report.maxShiftCm),maxSpace:$.report.maxShiftCm>m.report.maxShiftCm?$.report.maxSpace:m.report.maxSpace,rotated:m.report.rotated+$.report.rotated,removedDrafts:m.report.removedDrafts+$.report.removedDrafts}:{...m.report};let k=0,x=0,S=0,M=0,D=0,C=0,P=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),a=Tr(e),r=Tr(s);if(!a||!r)continue;const l=Nr(a.rooms),h=Nr(r.rooms),c=.02*nt,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:K(t.a,t.b,I),cm:0})),p=new Set(d.map(t=>t.key)),u=it(e,a.rooms,ot,c);x+=u.length;for(const t of u){const e=[t[0]/ot,t[1]/ot],s=[t[2]/ot,t[3]/ot],i=K(e,s,I);p.has(i)||(p.add(i),d.push({key:i,a:e,b:s,cm:0}))}const m=d.length,g=at(d,l,h,I,ot),f=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(!(a>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const n=Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))},b=g.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*ot),s=t.b.map(t=>t*ot);return h.some(([t,i])=>f(e,t,i)<=4*c&&f(s,t,i)<=4*c)});S+=Math.max(0,m-b.length);const y=(s.wall_segments||[]).filter(t=>Number(t.cm)>0);s.wall_segments=[...y,...b.map(({key:t,...e})=>e)];const v=b.map(t=>[t.a[0]*ot,t.a[1]*ot,t.b[0]*ot,t.b[1]*ot]),$=Array.isArray(e.walls)?e.walls.length:0;let w=at(e.walls,l,h,I,ot);w=Fr(r.rooms,w,v,I,Number(s.cell_cm)>0?Number(s.cell_cm):5,nt,ot),w=B(r.rooms,w,v,I,Number(s.cell_cm)>0?Number(s.cell_cm):5,nt,ot),w=rt(w,s.rooms||[],I,1,v.map(t=>[t[0]/ot,t[1]/ot,t[2]/ot,t[3]/ot])),k+=Math.max(0,$-w.length),w.length?s.walls=w:delete s.walls;const R=Rn(s.partitions||[],{pitch:I,geometry:Nn(s)});R.merged&&(M+=R.merged,s.partitions=R.partitions,Fn(s.openings,s.partitions,R.openingMoves,{coordScale:ot,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:nt}));const F=Tr(s);if(F){const t=o(s,F,s.walls||[],v,{pitch:I,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:nt,coordScale:ot});t.partitionsReconciled&&(D+=t.partitionsReconciled,C+=t.openingsRehosted,t.partitions.length?s.partitions=t.partitions:delete s.partitions,t.openings.length?s.openings=t.openings:delete s.openings,t.walls.length?s.walls=t.walls:delete s.walls),t.removedDrafts&&(P+=t.removedDrafts,t.roomDrafts.length?s.room_drafts=t.roomDrafts:delete s.room_drafts)}JSON.stringify({zero:(s.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:s.walls||[]})!==i&&T++}let R=0;c<=9&&(R=function(t){const e=Mr(t);return Cr(t,e.config),{...e,config:t}}(n).migratedSegments);const F=U(n),N=et($.layout),z=JSON.stringify(F)!==l||JSON.stringify(N)!==h;c<9&&z&&(F.model_version=9);const A=JSON.stringify(F)!==l||JSON.stringify(N)!==h,O=Number.isInteger(Number(F.model_version))?Number(F.model_version):c,L=A?w:{...w,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0,removedDrafts:0},E=A?a.report:{...a.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:F,layout:N,report:{...L,modelFrom:c,modelTo:O,migrated:A?p:0,glowSpacesMigrated:A?d.glowSpaces:0,glowRoomsMigrated:A?d.glowRooms:0,canonicalized:A?T:0,wallSegmentsMigrated:A?R:0,legacyZeroWallsMigrated:A?x:0,wallsMerged:A?k:0,spansMerged:A?S:0,partitionsMerged:A?M:0,partitionsReconciled:A?D:0,openingsRehosted:A?C:0,redundantDraftsRemoved:A?P:0,wallsStraightened:A?g:0,wallsStraightenSkipped:f,maxStraightenShiftCm:A?b:0,maxStraightenSpace:A?y:"",latticeCoordinatesCanonicalized:A?r.canonicalized:0,latticeCoordinatesFar:A?r.far:0,latticeMaxShift:A?r.maxShift:0,latticeMaxShiftCm:A?r.maxShiftCm:0,latticeSpaces:A?r.spaces:[],...E},changed:A}}const Ar=(t,e)=>t[0]*e[1]-t[1]*e[0],Or=(t,e)=>t[0]*e[0]+t[1]*e[1],Lr=(t,e)=>[t[0]-e[0],t[1]-e[1]],Er=(t,e,s)=>[t[0]+e[0]*s,t[1]+e[1]*s];function Br(t,e,s){return Math.abs(Ar(t,e))<=s}function Hr(t,e,s){return Math.abs(Ar(Lr(t,e),s))}function Gr(t,e,s,i,o){const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o&&s>0))return[];const l=[a/r,n/r];return function(t,e,s){const i=e.map(([e,s])=>[Math.max(0,Math.min(e,s)),Math.min(t,Math.max(e,s))]).filter(([t,e])=>e>t+s).sort((t,e)=>t[0]-e[0]||t[1]-e[1]),o=[];for(const t of i){const e=o[o.length-1];!e||t[0]>e[1]+s?o.push([...t]):e[1]=Math.max(e[1],t[1])}const a=[];let n=0;for(const[t,e]of o)t>n+s&&a.push([n,t]),n=Math.max(n,e);return t>n+s&&a.push([n,t]),a}(r,i.flatMap(e=>{const i=e.b[0]-e.a[0],a=e.b[1]-e.a[1],n=Math.hypot(i,a);if(!(n>o&&Br(l,[i/n,a/n],1e-6)))return[];if(Hr(e.a,t,l)>1.1*Math.max(s,o)||Hr(e.b,t,l)>1.1*Math.max(s,o))return[];return[[Or(Lr(e.a,t),l),Or(Lr(e.b,t),l)]]}),o).flatMap(([e,i])=>{const o=bt({a:Er(t,l,e),b:Er(t,l,i),halfDepth:s});return o?[o]:[]})}function Wr(t){const e=t.coordScale??1,s=Math.max(t.epsilon??2e-4*t.gridPitch,1e-9),i=[];for(const s of t.rooms||[]){if(!s?.id)continue;const o=mt(t.rooms,s.id,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e);if(!o||o.poly.length<3)continue;const a=gt(o.poly,o.offsets);!a||a.length<3||i.push({roomId:s.id,profile:o,inner:a})}i.sort((t,e)=>t.roomId.localeCompare(e.roomId));const o=(t.roomOpenings||[]).map(t=>{const e=t.angle*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Math.max(0,t.length)/2;return{a:Er([t.x,t.y],s,-i),b:Er([t.x,t.y],s,i)}}),a=[];for(const i of ft(t.rooms,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e))for(const t of Gr(i.a,i.b,i.depthUnits/2,o,s))a.push({body:t});const n=new Map;for(const e of t.partitionCuts||[]){const t=n.get(e.hostId)||[];t.push(e),n.set(e.hostId,t)}for(const e of t.partitions||[]){const i=j(e.cm,t.cellCm,t.gridPitch)/2;for(const t of Gr(e.a,e.b,i,n.get(e.id)||[],s))a.push({body:t,partitionId:e.id})}return{rooms:i,boundaries:a,epsilon:s}}function jr(t,e,s,i){const o=t.profile.offsets[e];if(!(o>0))return null;const a=function(t,e){const s=t[e],i=t[(e+1)%t.length],o=i[0]-s[0],a=i[1]-s[1],n=Math.hypot(o,a)||1;return function(t){let e=0;for(let s=0;s=0?[-a/n,o/n]:[a/n,-o/n]}(t.profile.poly,e),n=Er(s.center,a,o),r=[];for(let e=0;ei&&Br(s.axis,[l[0]/h,l[1]/h],1e-6)))continue;if(Hr(o,n,s.axis)>i||Hr(a,n,s.axis)>i)continue;const c=Or(Lr(o,n),s.axis),d=Or(Lr(a,n),s.axis);r.push([Math.min(c,d),Math.max(c,d)])}const l=function(t,e){t.sort((t,e)=>t[0]-e[0]||t[1]-e[1]);const s=[];for(const i of t){const t=s[s.length-1];!t||i[0]>t[1]+e?s.push([...i]):t[1]=Math.max(t[1],i[1])}return s}(r,i).find(([t,e])=>t<=i&&e>=-i);if(!l)return null;const[h,c]=l,d=Er(n,s.axis,-s.half),p=Er(n,s.axis,s.half),_=Math.max(0,-s.half-h),u=Math.max(0,c-s.half),m=_>0?Er(n,s.axis,h):d,g=u>0?Er(n,s.axis,c):p,f=Or(a,s.normal)>=0?1:-1,b=(e,i,o)=>({from:e,to:i,label:[(e[0]+i[0])/2,(e[1]+i[1])/2],axis:s.axis,labelNormal:a,distance:o,roomId:t.roomId,roomSide:f,source:"room-face"});return{left:b(d,m,_),right:b(p,g,u)}}function qr(t){const e=Er(t.center,t.axis,-t.half),s=Er(t.center,t.axis,t.half),i=Er(t.center,t.axis,Math.min(-t.half,t.targetLo)),o=Er(t.center,t.axis,Math.max(t.half,t.targetHi)),a=(e,s)=>({from:e,to:s,label:[(e[0]+s[0])/2,(e[1]+s[1])/2],axis:t.axis,labelNormal:t.normal,distance:Math.hypot(s[0]-e[0],s[1]-e[1]),source:"host-end"});return[a(e,i),a(s,o)]}function Ur(t,e,s,i){const o=Lr(s,e),a=Or(o,o);if(!(a>i*i))return Math.hypot(...Lr(t,e))<=i;const n=Or(Lr(t,e),o)/a;if(n<-i||n>1+i)return!1;const r=Er(e,o,Math.max(0,Math.min(1,n)));return Math.hypot(...Lr(t,r))<=i}function Kr(t,e,s){let i=!1;for(let o=0,a=e.length-1;ot[1]!=h>t[1]&&t[0]<(l-n)*(t[1]-r)/(h-r)+n&&(i=!i)}return i}function Vr(t,e,s,i,o,a){const n=Lr(i,s),r=Ar(e,n);if(Math.abs(r)<=a)return null;const l=Lr(s,t),h=Ar(l,n)/r,c=Ar(l,e)/r;return h<-a||h>o+a||c<-a||c>1+a?null:Math.max(0,Math.min(o,h))}function Jr(t,e,s){const i=qr(s),o="partition"===t.host?.kind?t.host.id:void 0;return[{base:i[0],direction:[-s.axis[0],-s.axis[1]]},{base:i[1],direction:s.axis}].map(({base:t,direction:s})=>{const i=t.distance,a=function(t,e,s,i,o,a){let n=null;for(const r of i)if(!o||r.partitionId!==o){if(Kr(t,r.body,a))return 0;for(let i=0;iOr(Lr(t,o),s));return{center:o,axis:s,normal:i,half:Math.max(0,t.renderedLength)/2,targetLo:Math.min(...a),targetHi:Math.max(...a)}}(t),i=e.rooms.flatMap(t=>{const i=function(t,e,s){const{profile:i}=t;let o=null;for(let t=0;t0))continue;const a=i.poly[t],n=i.poly[(t+1)%i.poly.length],r=Lr(n,a),l=Math.hypot(r[0],r[1]);if(!(l>s&&Br(e.axis,[r[0]/l,r[1]/l],1e-6)))continue;if(Hr(a,e.center,e.axis)>s||Hr(n,e.center,e.axis)>s)continue;const h=Or(Lr(a,e.center),e.axis),c=Or(Lr(n,e.center),e.axis),d=Math.min(h,c),p=Math.max(h,c);if(d>-e.half+s||p0?d:p<0?-p:0);(!o||_2)return qr(s);if(i.length){const t=i.map(({room:t,edge:i})=>jr(t,i,s,e.epsilon));if(t.some(t=>!t))return qr(s);const o=t;return[...o.map(t=>t.left),...o.map(t=>t.right)]}return Jr(t,e,s)}const Xr="1.68.1",Zr={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon"},Qr={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon"},tl=2e3,el=1e3,sl=t=>{const e=String(t??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e))return null;const s=Number(e);return Number.isFinite(s)?s:null},il=(t,e,s,i)=>{for(t.delete(e),t.set(e,s);t.size>i;){const e=t.keys().next().value;if(void 0===e)break;t.delete(e)}},ol=1e3,al=2e3,nl=t=>{try{t.target?.setPointerCapture?.(t.pointerId)}catch{}},rl="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";class ll{constructor(t){this.host=t,this._junctionBaselineCache=new WeakMap,this._undoGeometry=()=>{if(this.host._physicalDrag||this.host._physicalRotate)return void this._cancelPhysicalGesture();if(this.host._decorDraft)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)return void this._cancelDecorGesture();if(this.host._resize.dragging)return void this._rszCancelDrag();const t=this.host._geometryHistory.undo();t&&(this._applyGeometryState(t.before,!0)?this.host._showToast(this.host._t("history.undone",{name:t.name})):this.host._geometryHistory.clear())},this._redoGeometry=()=>{if(this.host._physicalDrag||this.host._physicalRotate)return void this._cancelPhysicalGesture();if(this.host._decorDraft)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)return void this._cancelDecorGesture();if(this.host._resize.dragging)return void this._rszCancelDrag();const t=this.host._geometryHistory.redo();t&&(this._applyGeometryState(t.after,!0)?this.host._showToast(this.host._t("history.redone",{name:t.name})):this.host._geometryHistory.clear())},this._savePhysicalDialog=()=>{const t=this.host._physicalDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=sl(t.cm);if(null==i)return void this._showPhysicalRange("column"===t.kind?yt:100,"column"===t.kind?1:0);const o=this.host._imperial?2.54*i:i,a="column"===t.kind?yt:100,n="column"===t.kind?1:0;if(!Number.isFinite(o)||oa)return void this._showPhysicalRange(a,n);if("column"===t.kind){const e=s.wall_columns.find(e=>e.id===t.id);if(!e)return;const i=sl(t.angle||"0");if("circle"!==t.shape&&(null==i||i<0||i>=90))return void this.host._showToast(this.host._t("toast.physical_angle"));const a="circle"===t.shape?{id:t.id,shape:"circle",center:e.center,cm:o}:{id:t.id,shape:"square",center:e.center,cm:o,angle:i};if(s.wall_columns.some(e=>e.id!==t.id&&vt(e,a,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"))}const r=this._geometrySnapshot();if("partition"===t.kind){const s=(e.partitions||[]).find(e=>e.id===t.id);if(s&&0===o&&$t(e.openings,{kind:"partition",id:t.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));s&&(s.cm=o)}else if("column"===t.kind){const s=(e.wall_columns||[]).find(e=>e.id===t.id);s&&(s.cm=wt(o),s.shape="circle"===t.shape?"circle":"square","square"===s.shape?s.angle=sl(t.angle||"0"):delete s.angle)}else{const s=(e.room_drafts||[]).find(e=>e.id===t.id);s?.segments?.[t.segment||0]&&(s.segments[t.segment||0].cm=o)}const l=this._commitPhysicalGeometry(this.host._t("history.physical_edit"),r);this.host._physicalDialog=null,l||this.host.requestUpdate()},this._deletePhysicalSelection=()=>{const t=this.host._physicalSel,e=this.host._curSpaceCfg;if(!t||!e)return;if("draft"===t.kind)return void this._deleteDraftWhole();const s=this._geometrySnapshot();if("partition"===t.kind){const s=(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(s.length)return void(this.host._partitionDeleteDialog={id:t.id,openings:s.map(t=>JSON.parse(JSON.stringify(t)))})}const i="partition"===t.kind?"partitions":"column"===t.kind?"wall_columns":"room_drafts";e[i]=(e[i]||[]).filter(e=>e.id!==t.id),e[i].length||delete e[i],this.host._activeDraftId===t.id&&this._cancelPath(),this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._confirmPartitionDelete=()=>{const t=this.host._partitionDeleteDialog,e=this.host._curSpaceCfg;if(!t||!e)return;const s=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.host._partitionDeleteDialog=null,this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._deleteDraftWhole=()=>{const t="draft"===this.host._physicalDialog?.kind?this.host._physicalDialog.id:"draft"===this.host._physicalSel?.kind?this.host._physicalSel.id:null,e=this.host._curSpaceCfg;if(!t||!e||!confirm(this.host._t("confirm.delete_draft")))return;const s=this._geometrySnapshot();e.room_drafts=(e.room_drafts||[]).filter(e=>e.id!==t),e.room_drafts.length||delete e.room_drafts,this.host._activeDraftId===t&&this._cancelPath(),this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._deleteDraftSegment=()=>{const t=this.host._physicalDialog,e=this.host._curSpaceCfg;if(!t||"draft"!==t.kind||!e)return;if(!confirm(this.host._t("confirm.delete_draft_segment")))return;const s=(e.room_drafts||[]).findIndex(e=>e.id===t.id);if(s<0)return;const i=e.room_drafts[s],o=Math.max(0,Math.min(i.segments.length-1,t.segment||0)),a=[],n=i.points.slice(0,o+1),r=i.points.slice(o+1);if(n.length>=2&&a.push({id:i.id,points:n,segments:i.segments.slice(0,o)}),r.length>=2&&a.push({id:a.length?`${i.id}-${Date.now().toString(36)}`:i.id,points:r,segments:i.segments.slice(o+1)}),2===a.length&&e.room_drafts.length>=200)return void this.host._showToast(this.host._t("toast.physical_limit"));const l=this._geometrySnapshot();e.room_drafts.splice(s,1,...a),e.room_drafts.length||delete e.room_drafts,this.host._activeDraftId===i.id&&this._cancelPath(),this.host._physicalDialog=null,this.host._physicalSel=a.length?{kind:"draft",id:a[0].id}:null,this._commitPhysicalGeometry(this.host._t("history.draft_segment_delete"),l)},this._confirmRoomDelete=t=>{const e=this.host._roomDeleteDialog,s=this.host._curSpaceCfg,i=this.host._spaceModel();if(!e||!s||!i)return;const o=i.rooms.find(t=>t.id===e.roomId);if(!o)return void(this.host._roomDeleteDialog=null);const a=this.host._openCuts(),n=nn(z(i.rooms,this.host._spaceWalls,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol).filter(t=>t.roomId===o.id),i.partitions,this.host._openingsR.map(t=>({...t,x:t.rx,y:t.ry})),.02*this.host._gridPitch),r=new Set(n.materialize.filter(t=>!t.reusePartitionId).map(t=>t.interval.key)).size;if(t&&(s.partitions||[]).length+r>al)return void this.host._showToast(this.host._t("toast.physical_limit"));const l=this._geometrySnapshot(),h=kt(i.rooms,this.host._spaceWalls,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol);if(t){s.partitions||=[];const t=new Map,e=new Map,i=t=>{const e=(s.wall_segments||[]).find(e=>{const s=[Number(e.a?.[0])*ol,Number(e.a?.[1])*ol],i=[Number(e.b?.[0])*ol,Number(e.b?.[1])*ol];return this._samePt(t.a,s)&&this._samePt(t.b,i)||this._samePt(t.a,i)&&this._samePt(t.b,s)});return"string"==typeof e?.id&&e.id?e.id:null},o=Date.now().toString(36);for(const a of n.materialize){let n=a.reusePartitionId?s.partitions.find(t=>t.id===a.reusePartitionId):e.get(a.interval.key);n||(n={id:i(a.interval)||`partition-room-${o}-${e.size}`,a:[a.interval.a[0]/ol,a.interval.a[1]/ol],b:[a.interval.b[0]/ol,a.interval.b[1]/ol],cm:a.interval.cm},s.partitions.push(n),e.set(a.interval.key,n)),t.set(a.interval.key,n)}for(const e of s.openings||[]){const s=n.openingIntervals.get(e.id),i=s?t.get(s):null,o=this.host._openingsR.find(t=>t.id===e.id);if(!i||!o)continue;const a={a:[i.a[0]*ol,i.a[1]*ol],b:[i.b[0]*ol,i.b[1]*ol]};e.host={kind:"partition",id:i.id,t:rn([o.rx,o.ry],a)}}}else if(n.removeOpeningIds.length){const t=new Set(n.removeOpeningIds);s.openings=(s.openings||[]).filter(e=>!t.has(e.id)),s.openings.length||delete s.openings}s.rooms=s.rooms.filter(t=>t.id!==o.id),this.host._cfgEpoch++;const c=this.host._normalizeWalls(h,this.host._openCuts());c.length?s.walls=c:delete s.walls,this.host._roomDeleteDialog=null,this._commitPhysicalGeometry(this.host._t(t?"history.delete_room_keep_walls":"history.delete_room_with_walls"),l),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate()},this._rebindPartitionOpening=()=>{const t=this.host._openingDialog;if(!t?.id)return;const e=t.id;this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingRebindId=e,this.host._openingPreset={type:t.type,lengthCm:t.lengthCm,flipH:t.flipH,flipV:t.flipV,revision:++this.host._openingPresetRevision},this.host._openingDialog=null,this.host._openingHoverCandidate=null)},this._deviceInboxTabKey=t=>{if("ArrowLeft"!==t.key&&"ArrowRight"!==t.key)return;const e=this.host._deviceInbox;if(!e)return;const s=["on_plan","available","hidden","readd"],i="ArrowRight"===t.key?1:-1,o=(s.indexOf(e.tab)+i+s.length)%s.length;this.host._deviceInbox={...e,tab:s[o],limit:100,onlyNew:!1},t.preventDefault()},this._keepClosedAsPartitions=()=>{if(this.host._wallFaceBatch)return void this._decideWallFace(!1);if(!this.host._contourClosed||this.host._pendingSplit||!this.host._curSpaceCfg)return;const t=this.host._curSpaceCfg,e=this.host._path.slice(0,-1);if((t.partitions||[]).length+e.length>al)return void this.host._showToast(this.host._t("toast.physical_limit"));const s=this._geometrySnapshot(),i=Ra(e.length,[...this.host._draftSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,A);t.partitions||=[];const o=Date.now().toString(36),a=this.host._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this.host._activeDraftId):null,n=this._draftSegmentsForPath(this.host._path,a,i);for(let s=0;st.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this.host._t("history.contour_to_partitions"),s),this.host._roomDialog=!1,this.host._path=[],delete this.host._resumeDraftBySpace[this.host._space],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null},this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,saved:t?.plans||[],savedBusy:!1})}catch(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}},this._openSettingsDialog=()=>{if(!this.host._norm)return;const t=this.host._glowRadiusCm,e=this.host._imperial?Math.round(t/30.48*10)/10:Math.round(t)/100;this.host._settingsDialog={colors:JSON.parse(JSON.stringify(this.host._fillColors)),glowRadius:e,bgColor:Dt(this.host._settings,{bgColor:null})||null,northDeg:Mt(this.host._settings,{}),bgMode:St(this.host._settings,{}),sunRays:xt(this.host._settings,{}),busy:!1}},this._openAlignDialog=()=>this._previewAlignDialog(!1),this._toggleOptimizeLivePositions=()=>{const t=this.host._alignDialog;t&&!t.busy&&t.report.liveMissingPositions.length&&this._previewAlignDialog(!t.removeLiveMissingPositions)},this._openBackupExport=()=>{this.host._settingsDialog=null,this.host._backupExportDialog={kind:"full",planOnly:!1,busy:!1,error:""}},this._openRulesDialog=()=>{if(!this.host._norm)return;const t=this.host._settings.icon_rules,e=(t&&t.length?t:Ct).map(t=>({...t}));this.host._rulesDialog={rules:e,test:"",busy:!1}},t._editorSecondary=new gn({root:()=>t.renderRoot,requestUpdate:()=>t.requestUpdate(),updateComplete:()=>t.updateComplete,clearTip:()=>{t._tip=null}}),t._resize=new Wo}_help(t){const e=`${t}.aria`,s=d(this.host.hass,this.host._config?.language);return Pt(s,t)&&Pt(s,e)?o``:a}_setMode(t,e=!0){this.host._endTabDrag(),this.host._pendingNavMode=null;const s=this.host._spaceModel();if(!s)return this.host._cancelModeTransition(!1),void(this.host._mode="view");if(this.host._kiosk&&"view"!==t)return;if(this.host._mode===t){if(!e&&"view"===t&&this.host._modeTransitionBusy){const e=this.host._currentModeVisual(t),s=this.host._modeTransitionTargetZoom,i=this.host._modeTransitionTargetCenterX,o=this.host._modeTransitionTargetCenterY;this.host._cancelModeTransition(!1),this.host._commitViewModeAtomic(e,s,i,o)}return}if(this.host._bootSoftCancel(),("plan"===t||"decor"===t)&&!this.host._norm)return void this.host._showToast(this.host._t("toast.markup_needs_server"));if(this.host._wallFaceBatch&&this._roomDialogCancel(),"plan"===this.host._mode&&"draw"===this.host._tool&&!this._finishWallChain())return;this.host._clearTransientHover(!0),this.host._cancelDevicePressFeedback();const i=this.host._mode,o=this.host._effectiveProjection(),a=this.host._currentModeVisual(i),n=this.host._modeTransitionBusy,r=a&&"view"!==i&&"view"!==t?{...a,toolbarContentOpacity:this.host._reducedMotion?1:.35}:a;this.host._cancelModeTransition(!1),this.host._editorSecondary.closeForNavigation(),(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)&&this._cancelDecorGesture();const l=!s.bg&&"view"===t!=("view"===i),h=n&&"view"===i&&"view"!==t?this.host._modeTransitionEditorCamera:null;let c=h?.zoom??(n?this.host._modeTransitionTargetZoom:this.host._zoom),d=h?h.centerX:n?this.host._modeTransitionTargetCenterX:r?.viewport.centerX,p=h?h.centerY:n?this.host._modeTransitionTargetCenterY:r?.viewport.centerY;if("view"===i&&"view"!==t&&!n){const e=this.host._view;if(this.host._viewModeSnap={space:this.host._space,zoom:this.host._zoom,cx:e?this.host._logicalViewCenter(o)?.x:void 0,cy:e?this.host._logicalViewCenter(o)?.y:void 0},"iso"===o){const e=this.host._logicalViewCenter("iso");d=e?.x,p=e?.y,this.host._view=null,this.host._mode=t,this.host._applyView(this.host._zoom,e?.x,e?.y)}l&&(c=1,d=void 0,p=void 0)}if("plan"===i&&this.host._activeDraftId&&(this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId),this.host._mode=t,"devices"===i&&"devices"!==t&&(this.host._showHidden=!1,this.host._deviceInbox=null,this.host._deviceInboxReturn=null,this.host._deviceInboxMemo=null),this.host._editorChromeMode="view"===t?i:t,"view"===t){"view"===i||n||(this.host._modeTransitionEditorCamera={zoom:this.host._zoom,centerX:r?.viewport.centerX,centerY:r?.viewport.centerY});const t=this.host._viewModeSnap;if(t&&t.space===this.host._space){c=t.zoom;const e=this.host._labsIso&&"iso"===this.host._viewPreference[this.host._space]?"iso":"flat",s=null!=t.cx&&null!=t.cy&&"iso"===e?It([t.cx,t.cy],0):null;d=s?.[0]??t.cx,p=s?.[1]??t.cy}else t&&(c=this.host._zoomBySpace[this.host._space]||1,d=void 0,p=void 0)}else this.host._modeTransitionEditorCamera={zoom:c,centerX:d,centerY:p};this.host._modeTransitionTargetZoom=c,this.host._modeTransitionTargetCenterX=d,this.host._modeTransitionTargetCenterY=p,("iso"===o||"view"===t&&this.host._labsIso&&"iso"===this.host._viewPreference[this.host._space])&&(this.host._modeTransitionForceAtomic=!0);const _=++this.host._modeTransitionRequest;e?r?(this.host._modeTransitionPreparing=!0,this.host._modeTransitionVisual=r,this.host._prepareModeTransition(_,r,t,c,d,p)):(this.host._modeTransitionPreparing=!1,this.host._modeTransitionVisual=null,this.host._zoom=c,this.host._view=null,requestAnimationFrame(()=>{this.host.isConnected&&_===this.host._modeTransitionRequest&&this.host._mode===t&&(this.host._applyView(c,d,p),"view"===t&&(this.host._viewModeSnap=null,this.host._modeTransitionEditorCamera=null),this.host.requestUpdate())})):"view"===t&&this.host._commitViewModeAtomic(r,c,d,p),this.host._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this.host._tool="draw",this.host._mergeSel=null,this.host._mergeDialog=null,this.host._splitSel=null,this.host._pendingSplit=null,this.host._selId=null,this.host._physicalSel=null,this.host._physicalDialog=null,this.host._physicalDrag=null,this._rszResetController(),this.host._tip=null,this.host._hoverRoom=null,this.host._decorDraft=null,this.host._decorSel=null,this.host._decorMove=null,this.host._backdropDialog=null,this.host._decorTool="select",this.host._bdDrag=null,this.host._dtDrag=null,this.host._dtBox=null,"plan"===t&&(this._primeDrawWallField(),this._resumeLastDraft()),this.host._saveNav()}_primeDrawWallField(){null===this.host._drawWallField&&(this.host._drawWallField=Tt(A,this.host._imperial))}_showPhysicalRange(t=this.host._drawWallMaxCm,e=0){this.host._showToast(this.host._t("toast.physical_range",{min:Tt(e,this.host._imperial),max:Tt(t,this.host._imperial),unit:this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}))}_draftSegmentCount(t=this.host._curSpaceCfg){return(t?.room_drafts||[]).reduce((t,e)=>t+(Array.isArray(e.segments)?e.segments.length:0),0)}_mergeSpacePartitions(t,e){const s=t?.partitions||[];if(s.length<2)return 0;const i=Rn(s,{pitch:I,seedIds:e,geometry:Nn(t,{excludeDraftId:this.host._activeDraftId})});return i.merged?(t.partitions=i.partitions,Fn(t.openings,t.partitions,i.openingMoves,{coordScale:ol,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch}),i.merged):0}_finishWallChain(){if("draw"!==this.host._tool||this.host._wallFaceBatch||this.host._roomDialog)return!0;const t=this.host._curSpaceCfg;if(!t||this.host._path.length<2)return this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),!0;const e=Fa(this.host._path,Ra(this.host._path.length-1,this.host._draftSegmentCms,this.host._drawWallCm,A)),s=e.length;if((t.partitions||[]).length+s>al)return this.host._showToast(this.host._t("toast.physical_limit")),!1;const i=this._geometrySnapshot();t.partitions||=[];const o=Date.now().toString(36),a=[],n=this.host._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this.host._activeDraftId):null,r=this._draftSegmentsForPath(this.host._path,n,e.map(t=>t.cm));for(let i=0;it.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this.host._t("history.wall_chain_finish"),i),delete this.host._resumeDraftBySpace[this.host._space],this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),!0}_activateMarkupTool(t){t!==this.host._tool&&(this.host._wallFaceBatch&&this._roomDialogCancel(),("draw"!==this.host._tool||this._finishWallChain())&&(this._cancelPath(),"resize"===this.host._tool&&(this.host._resize.dragging?this._rszCancelDrag():this.host._resize.reset()),this.host._tool=t,"draw"===t&&this._resumeLastDraft(),"resize"===t&&this.host._resize.selectRoom(null),"wallthick"===t&&(this.host._wallDialog=null)))}_limitReached(t){const e=this.host._curSpaceCfg;if(!e)return!0;const s="draft"===t?(e.room_drafts||[]).length>=200:"partition"===t?(e.partitions||[]).length>=al:(e.wall_columns||[]).length>=500;return s&&this.host._showToast(this.host._t("toast.physical_limit")),s}_svgPoint(t){const e=this.host.renderRoot.querySelector(".stage").getBoundingClientRect();return this.host._screenToVb(t.clientX-e.left,t.clientY-e.top)}_snap(t){const e=this.host._gridPitch;return[Rt(Ft(t[0],e)),Rt(Ft(t[1],e))]}_snapDrawPoint(t,e=!1){const s=this.host._path[this.host._path.length-1],i=e&&s?Nt(s,t,this.host._gridPitch,Ti):t;return this._snap(i)}_planSnapOpeningCuts(t,e){if(!this.host._openingsR.length)return[];const s=this.host._openingWallIndexFor(t,e).value,i=[];for(const e of this.host._roomWallOpeningInputs(this.host._openingsR,t)){const t=W(s,e);if(!t.negative&&!t.positive)continue;const o=e.angle*Math.PI/180,a=Math.cos(o)*e.length/2,n=Math.sin(o)*e.length/2;i.push([e.x-a,e.y-n,e.x+a,e.y+n])}return i}_planSnapGeometrySnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|empty`,value:{segments:[],endpoints:[]}};const e=[this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._planSnapGeometryCache?.key===e)return this.host._planSnapGeometryCache;const s=this.host._openCuts(),i=xa({space:t,activeDraftId:this.host._activeDraftId,roomCuts:this._planSnapOpeningCuts(t,s),partitionCuts:this._partitionOpeningCuts(t),epsilon:2e-4*this.host._gridPitch});return this.host._planSnapGeometryCache={key:e,value:i},this.host._planSnapGeometryCache}_hiddenWallDiagnosticSnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|hidden-empty`,value:{segments:[],endpoints:[]}};const e=["hidden",this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._hiddenWallDiagnosticCache?.key===e)return this.host._hiddenWallDiagnosticCache;const s=ka({space:t,activeDraftId:this.host._activeDraftId,epsilon:2e-4*this.host._gridPitch});return this.host._hiddenWallDiagnosticCache={key:e,value:s},this.host._hiddenWallDiagnosticCache}_planStructuralGeometrySnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|structural-empty`,value:{segments:[],endpoints:[]}};const e=["structural",this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._planStructuralGeometryCache?.key===e)return this.host._planStructuralGeometryCache;const s=xa({space:t,activeDraftId:this.host._activeDraftId,epsilon:2e-4*this.host._gridPitch});return this.host._planStructuralGeometryCache={key:e,value:s},this.host._planStructuralGeometryCache}_planSnapContextKey(t){const e=this.host._path[0],s=this.host._path[this.host._path.length-1];return[t,this.host._tool,this.host._path.length,e?`${e[0]},${e[1]}`:"",s?`${s[0]},${s[1]}`:""].join("|")}_resolvePlanDrawPoint(t,e){const s=this._planSnapGeometrySnapshot(),i=this.host._path[this.host._path.length-1],o="draw"===this.host._tool&&this.host._path.length>=3?[{point:this.host._path[0],key:"closure:first-point"}]:[],a={tolerance:this._cssPxToRender(12),distinguishTolerance:this._cssPxToRender(8),gridStep:this.host._gridPitch,excludePoints:i?[i]:[],extraEndpoints:o,epsilon:2e-4*this.host._gridPitch},n=e&&i?Ia(s.value,t,{...a,anchor:i}):function(t,e,s){if(!(ma(e)&&s.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const i=s.epsilon??ua,o=s.excludePoints||[],a=Ca(Da(t,e,s),s.distinguishTolerance||0);if(a)return a;let n=null;for(const a of t.segments){const t=[a.a[0],a.a[1],a.b[0],a.b[1]],r=C([e[0],e[1]],t);if(r>s.tolerance)continue;const l=Pa(a,e,s.gridStep);!Sa(l,o,i)&&Ma(r,a.key,n)&&(n={kind:"line",point:l,key:a.key,distance:r,segment:a})}return n?{kind:"resolved",candidate:n,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}(s.value,t,a),r="resolved"===n.kind?n.candidate:null,l=r?[...r.point]:this._snapDrawPoint(t,e),h=i?zt(i,l):l;return{point:h,candidate:r&&q(h,r.point)?r:null,conflicts:"ambiguous"===n.kind?n.conflicts:[],ambiguous:"ambiguous"===n.kind,contextKey:this._planSnapContextKey(s.key)}}_clearPlanSnapHover(t=!0){this.host._planSnapHover=null,this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers([]),t&&(this.host._cursorPt=null)}_samePt(t,e){return q(t,e)}_dropLegacySegments(){for(const t of this.host._serverCfg?.markers||[])"ripple"===t.display&&(t.display="icon_ripple");for(const t of this.host._serverCfg?.spaces||[]){delete t.segments;const e=new Set,s=t=>"string"==typeof t&&t.length>=1&&t.length<=64&&!e.has(t),i=t=>(e.add(t),!0),o=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(Number(t))&&Math.abs(Number(t))<=Xt);if(Array.isArray(t.partitions)&&(t.partitions=t.partitions.filter(t=>t&&s(t.id)&&o(t.a)&&o(t.b)&&Math.hypot(t.a[0]-t.b[0],t.a[1]-t.b[1])>1e-9&&i(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&&s(t.id)&&o(t.center)&&i(t.id)).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[Number(t.center[0]),Number(t.center[1])],cm:wt(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:At(t.angle)}})),t.wall_columns.length||delete t.wall_columns),Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t&&s(t.id)&&Array.isArray(t.points)&&t.points.length>=2&&t.points.every(o)&&i(t.id)).map(t=>{const e=hr(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=Ot(ut({spaces:[t]}),t.id),s=e?Lt(t,e,ol,.02*nt).contour.map(t=>t.map(t=>t/ol)):V(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]);t.walls=rt(t.walls,t.rooms||[],I,1,s),t.walls.length||delete t.walls}}}_rollbackRejectedPhysicalWrites(t){if(!this.host._serverCfg||!t.length)return!1;let e=!1;for(const[s]of t){const t=this.host._pendingPhysicalWrites.get(s);t&&(e=this._restoreGeometryStateInConfig(this.host._serverCfg,t.before)||e,this.host._pendingPhysicalWrites.delete(s))}return!!e&&(this._clearGeometryGesture(),this.host._geometryHistory.clear(),this.host._cfgEpoch++,this.host._modelCache=null,this.host._wallUnionCache=null,this.host._physicalBodiesCache=null,this.host._frame=null,this.host._regSignature="",this.host._cfgContentFingerprint=Et(this.host._serverCfg),this.host._maybeRebuildDevices(),this.host.requestUpdate(),!0)}async _reloadRejectedPhysicalWrite(){const t=this.host._writeChain;await t.catch(()=>{}),await this.host._reloadConfigOnly(!0)}_writeConfig(){this.host._writesPending++,this.host._writeChain=Bt(this.host._writeChain,async()=>{if(!this.host._serverCfg)return;this._dropLegacySegments();const t=Mi(this.host._serverCfg),e=Et(t),s=[...this.host._pendingPhysicalWrites.entries()];for(const[e,i]of s){const s=t.spaces.find(t=>t.id===e),o=jt(s);if(o===i.fingerprint)continue;let a=!1;try{a=this.host._checkSpacePhysicalGeometry(t,e).ok}catch{a=!1}if(!a)throw this._restoreGeometryStateLocal(i.before),this.host._pendingPhysicalWrites.delete(e),this.host._geometryHistory.clear(),this.host._showToast(this.host._t("toast.geometry_unsafe")),Object.assign(new Error("unsafe wall geometry"),{code:"geometry-unsafe"});i.fingerprint=o}e!==Et(this.host._serverCfg)&&(this.host._serverCfg=t),this.host._cfgContentFingerprint=e;try{await this.host._sendConfigCandidate(t)}catch(t){if(!this._rollbackRejectedPhysicalWrites(s))throw t;const e=t&&"object"==typeof t?t:Object.assign(new Error(String(t)),{cause:t});throw e.physicalGeometryRolledBack=!0,e}for(const[t,e]of s)this.host._pendingPhysicalWrites.get(t)?.fingerprint===e.fingerprint&&this.host._pendingPhysicalWrites.delete(t)});return this.host._writeChain.finally(()=>{this.host._writesPending--})}_saveConfig(){this.host._cfgEpoch++,this.host._saveConfigDebounced()}_geometrySnapshotFromConfig(t,e){const s=t?.spaces?.find(t=>t.id===e);if(!s)return null;const i=t=>JSON.parse(JSON.stringify(t)),o={};for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==s[t]&&(o[t]=s[t]);return{spaceId:e,rooms:i(s.rooms||[]),...Array.isArray(s.openings)?{openings:i(s.openings)}:{},...Array.isArray(s.walls)?{walls:i(s.walls)}:{},...Array.isArray(s.wall_segments)?{wall_segments:i(s.wall_segments)}:{},...Array.isArray(s.open_spans)?{open_spans:i(s.open_spans)}:{},...Array.isArray(s.room_drafts)?{room_drafts:i(s.room_drafts)}:{},...Array.isArray(s.partitions)?{partitions:i(s.partitions)}:{},...Array.isArray(s.wall_columns)?{wall_columns:i(s.wall_columns)}:{},...Array.isArray(s.decor)?{decor:i(s.decor)}:{},plan_transform:o}}_geometrySnapshot(t=this.host._space){return this._geometrySnapshotFromConfig(this.host._serverCfg,t)}_recordGeometry(t,e){if(!e)return;const s=this._geometrySnapshot(e.spaceId);s&&JSON.stringify(e)!==JSON.stringify(s)&&(this.host._geometryHistory.push({name:t,before:e,after:s}),this.host.requestUpdate())}_restoreGeometryStateInConfig(t,e,s=!1){const i=t?.spaces?.find(t=>t.id===e.spaceId);if(!i)return!1;const o=t=>JSON.parse(JSON.stringify(t)),a=new Map((i.rooms||[]).map(t=>[t.id,t]));if(i.rooms=o(e.rooms),s)for(const t of i.rooms){const e=a.get(t.id);!Array.isArray(t.wall_ids)&&Array.isArray(e?.wall_ids)&&e.wall_ids.length===t.poly?.length&&(t.wall_ids=o(e.wall_ids))}const n=(t,e)=>{void 0!==e?i[t]=o(e):s&&"wall_segments"===t||delete i[t]},r=new Map((i.openings||[]).map(t=>[t.id,t])),l=new Map((i.room_drafts||[]).map(t=>[t.id,t]));if(n("openings",e.openings),n("walls",e.walls),n("wall_segments",e.wall_segments),n("open_spans",e.open_spans),n("room_drafts",e.room_drafts),n("partitions",e.partitions),n("wall_columns",e.wall_columns),n("decor",e.decor),s){for(const t of i.openings||[]){const e=r.get(t.id);t.host||"wall"!==e?.host?.kind||(t.host=o(e.host))}for(const t of i.room_drafts||[]){const e=l.get(t.id);for(let s=0;s<(t.segments||[]).length;s++)!t.segments[s]?.id&&e?.segments?.[s]?.id&&(t.segments[s].id=e.segments[s].id)}}for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete i[t];return Object.assign(i,o(e.plan_transform||{})),!0}_restoreGeometryStateLocal(t){return!!this._restoreGeometryStateInConfig(this.host._serverCfg,t)&&(this.host._cfgEpoch++,this.host._modelCache=null,this.host._wallUnionCache=null,this.host._physicalBodiesCache=null,this.host._frame=null,this.host.requestUpdate(),!0)}_wallModelBlockerLabel(t){const e=t instanceof er?t.reason:"invalid-room";return this.host._t(`wall_model.reason.${e}`)}_hasLegacyZeroWallFields(t=this.host._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.host._showToast(this.host._t(e,{reason:this._wallModelBlockerLabel(t)}))}_limitSegmentsOf(t){const e=[];for(const s of t?.wall_segments||[])s?.a&&s?.b&&e.push({id:String(s.id||""),a:s.a,b:s.b,cm:Number(s.cm)});for(const s of t?.partitions||[])s?.a&&s?.b&&e.push({id:String(s.id||""),a:s.a,b:s.b,cm:Number(s.cm)});for(const s of t?.room_drafts||[]){const t=Array.isArray(s?.points)?s.points:[],i=Array.isArray(s?.segments)?s.segments:[];for(let o=0;o+1t?.id===e);if(!i)return[];const o=Number(i.cell_cm)>0?Number(i.cell_cm):5,a=this._limitSegmentsOf(i),n=[...ta(a),...aa(a,o,I),...ra(a,o,I)];let r=null;try{r=Ht(i.rooms||[],i.walls||[],[],I,o,I,1)}catch{r=null}let l="ok"===s?.status||"degraded-extra"===s?.status?s.roomGeom:null;if(!l&&r&&r.nodes.length)try{const t=Gt(i.rooms||[],i.walls||[],[],[],I,o,I,1);l="ok"===t?.status||"degraded-extra"===t?.status?t.roomGeom:null}catch{l=null}for(const t of i.rooms||[]){const e=String(t?.id||"");if(!e)continue;let s=null;try{s=Wt(i.rooms||[],e,i.walls||[],[],I,o,I,1,l??void 0,r)}catch{s=null}n.push(...la(e,s,o,I))}return n}_junctionLimitLabel(t){const e=t=>String(Math.round(10*t)/10);return this.host._t(`junction.limit_${t.rule}`,{actual:e(t.actual),limit:e(t.limit)})}_junctionLimitsIntroduced(t,e,s,i){let o;const a=(e?.spaces||[]).find(t=>t?.id===s);let n="";try{n=jt(a)}catch{n=""}const r=e&&"object"==typeof e?this._junctionBaselineCache.get(e):void 0;if(r&&n&&r.fingerprint===n&&r.spaceId===s&&(o=r.violations),!o){try{const t=Number(e?.model_version||0)>=9?e:Mr(e).config;o=this.host._junctionLimitViolations(t,s)}catch{return[]}e&&"object"==typeof e&&n&&this._junctionBaselineCache.set(e,{spaceId:s,fingerprint:n,violations:o})}let l=[];try{l=this.host._junctionLimitViolations(t,s,i)}catch{return[{rule:"check_failed",subject:s,actual:0,limit:0}]}return function(t,e){const s=new Map;for(const t of e||[])s.set(t.rule,(s.get(t.rule)||0)+1);const i=new Map;for(const e of t||[])i.set(e.rule,[...i.get(e.rule)||[],e]);const o=[];for(const[t,e]of i){const i=e.length-(s.get(t)||0);i>0&&o.push(...e.slice(0,i))}return o}(l,o)}_commitPhysicalGeometry(t,e,s=[]){if(!e||!this.host._serverCfg)return!1;const i=this.host._serverCfg,o=this._geometrySnapshotFromConfig(i,e.spaceId),a=i.spaces.find(t=>t.id===e.spaceId);if(!a||jt(e)===jt(a))return!1;let n,r=!1;try{r=this.host._checkSpacePhysicalGeometry(i,e.spaceId).ok}catch{r=!1}if(!r)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;let l=e;try{if(Number(i.model_version||0)<9){const t=JSON.parse(JSON.stringify(i));if(!this._restoreGeometryStateInConfig(t,e))throw new er("invalid-room",e.spaceId);const s=Mr(t).config;l=this._geometrySnapshotFromConfig(s,e.spaceId)||e;const a=JSON.parse(JSON.stringify(s));if(!o||!this._restoreGeometryStateInConfig(a,o,!0))throw new er("invalid-room",e.spaceId);const r=s.spaces.find(t=>t.id===e.spaceId),h=a.spaces.find(t=>t.id===e.spaceId);if(!Array.isArray(o.wall_segments)&&JSON.stringify(e.rooms)===JSON.stringify(o.rooms))for(const t of h?.wall_segments||[])t.cm=Q(o.walls,t.a,t.b,I,1);const c=((t,e,s)=>{const i=new Map,o=new Map((t?.rooms||[]).map(t=>[t.id,t])),a=new Map((e||[]).map(t=>[t.id,t])),{rooms:n}=$r(s,yr(t));for(const t of n){const e=a.get(t.id),n=o.get(t.id),r=R(e),l=(s.rooms||[]).find(e=>e.id===t.id),h=R(l),c=R(n);if(r&&h&&c&&r.length===h.length&&c.length===n?.wall_ids?.length&&t.poly.length===t.wall_ids.length)for(let e=0;e{const o=[];for(let a=0;atr||pr(r,s,i)>tr)continue;const l=dr(n,s,i),h=dr(r,s,i);l<-tr||h>1+tr||h<=l+tr||o.push({start:l,id:e[a]})}return o.sort((t,e)=>t.start-e.start)},o=s(c,n.wall_ids,r[e],r[(e+1)%r.length]),a=s(t.poly,t.wall_ids,h[e],h[(e+1)%h.length]);if(o.length&&o.length===a.length)for(let t=0;tt.id===e.spaceId),i=this.host._path.length>=2?this.host._path.map(t=>[t[0]/ol,t[1]/ol]):[];i.push(...s.map(t=>[t[0],t[1]])),h=cr(t)<=cr(l,i)&&this.host._checkSpacePhysicalGeometry(n,e.spaceId).ok}catch{h=!1}if(!h)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;const c=JSON.parse(JSON.stringify(i));this._restoreGeometryStateInConfig(c,e);const d=this._junctionLimitsIntroduced(n,c,e.spaceId);if(d.length)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this._junctionLimitLabel(d[0])),!1;Cr(i,n),this._recordGeometry(t,l);const p=i.spaces.find(t=>t.id===e.spaceId),_=this.host._pendingPhysicalWrites.get(e.spaceId);return this.host._pendingPhysicalWrites.set(e.spaceId,{before:_?.before||l,fingerprint:jt(p)}),this._saveConfig(),!0}_clearGeometryGesture(){this.host._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!1),this.host._mergeSel=null,this.host._mergeDialog=null,this.host._splitSel=null,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._wallRepairDiagnostic=null,this.host._roomDeleteDialog=null,this.host._wallDialog=null,this.host._physicalDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this.host._openingDialog=null,this._rszResetController(),this.host._decorDraft=null,this.host._decorMove=null,this.host._dtDrag=null,this.host._bdDrag=null}_stagePointerCancel(t){if(clearTimeout(this.host._kioskHoldTimer),this.host._swipeStart?.id===t.pointerId&&(this.host._swipeStart=null),this.host._physicalDrag?.pid===t.pointerId||this.host._physicalRotate?.pid===t.pointerId)return void this._cancelPhysicalGesture();if(this.host._decorDraft?.pid===t.pointerId)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove?.pid===t.pointerId||this.host._dtDrag?.pid===t.pointerId||this.host._bdDrag?.pid===t.pointerId)return void this._cancelDecorGesture();"opening"===this.host._tool?(this.host._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this.host._tool&&this._clearPlanSnapHover();const e=!!this.host._pinchStart||!!this.host._panStart;this.host._pointers.delete(t.pointerId),this.host._pointers.size<2&&(this.host._pinchStart=null),0===this.host._pointers.size&&(this.host._panStart=null,this.host._panLock=null),e&&0===this.host._pointers.size&&this.host.requestUpdate()}_applyGeometryState(t,e=!1){if(!this.host._canCommitSpace(t.spaceId))return!1;const s=this._geometrySnapshot(t.spaceId);if(!s||!this._restoreGeometryStateLocal(t))return!1;const i=this.host._serverCfg,o=jt(s)!==jt(t);if(o){let o=!1;try{const s=i?this.host._checkSpacePhysicalGeometry(i,t.spaceId):null;o=!!s?.ok||!(!e||"wall-degraded-extra"!==s?.reason)}catch{o=!1}if(!o)return this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1}let a;try{a=Mr(i).config}catch(t){return this._restoreGeometryStateLocal(s),this._showWallModelMigrationBlocked(t),!1}if(o){let o=!1;try{const s=a?this.host._checkSpacePhysicalGeometry(a,t.spaceId):null;o=!!s?.ok||!(!e||"wall-degraded-extra"!==s?.reason)}catch{o=!1}if(!o)return this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;Cr(i,a);const n=i?.spaces.find(e=>e.id===t.spaceId),r=this.host._pendingPhysicalWrites.get(t.spaceId);this.host._pendingPhysicalWrites.set(t.spaceId,{before:r?.before||s,fingerprint:jt(n)})}else Cr(i,a);return this._clearGeometryGesture(),this.host._space!==t.spaceId&&(this.host._commitSpace(t.spaceId),this.host._saveNav(),this.host._restoreZoom()),this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this._saveConfig(),this.host.requestUpdate(),!0}_roomAt(t){return this.host._spaceModel()?.rooms.find(e=>{const s=R(e);return!!s&&qt(t,s)})}_overlapRoom(t){return this.host._spaceModel()?.rooms.find(e=>{const s=R(e);return!!s&&$(t,s)})}_pointInRoom(t,e){return e.poly?Ut(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(!go(t))return!0;const e=t.length,s=.001;for(let i=0;i=500)return this.host._showToast(this.host._t("toast.physical_limit")),!1;const t=this.host._curSpaceCfg;return!(!this.host._activeDraftId&&(t?.room_drafts||[]).length>=200||this._draftSegmentCount(t)>=2e3||(t?.partitions||[]).length+this.host._path.length>al)||(this.host._showToast(this.host._t("toast.physical_limit")),!1)}_markupClick(t){if(this.host._vacFit)return;if(!this.host._markup)return;const e=this.host._spaceModel();if(!e)return void this._clearGeometryGesture();if(this.host._suppressClick)return;if(this.host._drag||this.host._rlResize)return;const s=t.composedPath?.()||[];if(s.some(t=>t?.classList?.contains?.("roomlabel")||t?.classList?.contains?.("rlhandle")))return;if(s.some(t=>t?.classList?.contains?.("physical-hit")))return;const i=this._svgPoint(t);if("select"===this.host._tool)return void(this.host._physicalSel=null);if("resize"===this.host._tool){if(this.host._resize.dragging||s.some(t=>t?.classList?.contains?.("rszhandle")))return;const t=[...e.rooms].reverse().find(t=>this._pointInRoom(i,t));return this.host._resize.selectRoom(t?.id||null),void this.host.requestUpdate()}if("delroom"===this.host._tool)return void this._deleteRoomClick(i);if("opening"===this.host._tool)return void this._openingClick(i);if("merge"===this.host._tool)return void this._mergeClick(i);if("wallthick"===this.host._tool)return void this._wallThickClick(i);if("split"===this.host._tool)return void this._splitClick(i);if("column"===this.host._tool)return void this._columnClick(i);this.host._wallRepairDiagnostic=null;const o=this._resolvePlanDrawPoint(i,t.shiftKey);if(o.ambiguous)return this.host._planSnapHover={contextKey:o.contextKey,candidate:null,conflicts:o.conflicts},this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers(o.conflicts),void this.host._showToast(this.host._t("toast.plan_snap_ambiguous"));let a=o.point;if(t.ctrlKey||t.metaKey){if(t.preventDefault(),this.host._path.length<3)return;a=zt(this.host._path[this.host._path.length-1],this.host._path[0])}if(!this.host._path.length){if(!t.shiftKey&&!o.candidate&&this._offerExistingWallFace(i))return;const e=this._draftEndAt(a);return e?(this.host._activeDraftId=e.draft.id,this.host._resumeDraftBySpace[this.host._space]=e.draft.id,this.host._path=e.reverse?[...e.draft.points].reverse().map(t=>[...t]):e.draft.points.map(t=>[...t]),void(this.host._draftSegmentCms=this._adoptDraftCms(this.host._path,e.reverse?[...e.draft.segments].reverse().map(t=>t.cm):e.draft.segments.map(t=>t.cm),e.draft.id))):(this.host._activeDraftId=null,this.host._draftSegmentCms=[],void(this.host._path=[a]))}const n=this.host._path[this.host._path.length-1];if(this._samePt(a,n))return;const r=this._draftEndAt(a,this.host._activeDraftId||void 0);if(r)return void this._mergeDraftEndpoint(r);if(!this._canAppendRoomDraftPoint())return;const l=this.host._drawWallCm;if(null==l)return void this._showPhysicalRange(100);const h=this.host._path.map(t=>[...t]);this.host._path=[...this.host._path,a],this.host._draftSegmentCms=[...this.host._draftSegmentCms,l],this._persistActiveDraftSegment(),this._offerWallFaces(h)}_draftEndAt(t,e){const s=this.host._spaceModel();if(!s)return null;const i=this.host._viewOr(this.host._baseVb()),o=Math.max(.15*this.host._gridPitch,this.host._stageEl?.clientWidth?i.w/this.host._stageEl.clientWidth*12:0);for(const i of s.room_drafts||[]){if(i.id===e)continue;if(i.points.length<2)continue;const s=i.points[0],a=i.points[i.points.length-1];if(Math.hypot(t[0]-a[0],t[1]-a[1])<=o)return{draft:i,reverse:!1};if(Math.hypot(t[0]-s[0],t[1]-s[1])<=o)return{draft:i,reverse:!0}}return null}_mergeDraftEndpoint(t){const e=this.host._curSpaceCfg;if(!e||!this.host._path.length)return;const s=this.host._path.map(t=>[...t]),i=this._wallGraphSources(s),o=Array.isArray(e.room_drafts)?e.room_drafts:[],a=this.host._activeDraftId?o.find(t=>t.id===this.host._activeDraftId):null,n=o.find(e=>e.id===t.draft.id);if(!n)return;const r=t.reverse?t.draft.points.map(t=>[...t]):[...t.draft.points].reverse().map(t=>[...t]),l=t.reverse?(n.segments||[]).map(t=>({...t})):[...n.segments||[]].reverse().map(t=>({...t})),h=this.host._path[this.host._path.length-1],c=this._samePt(h,r[0]),d=c?null:this.host._drawWallCm;if(!c&&null==d)return void this._showPhysicalRange(100);const p=this._draftSegmentsForPath(this.host._path,a,this.host._draftSegmentCms),_=[...this.host._path.map(t=>[...t]),...c?r.slice(1):r],u=[...p,...null==d?[]:[{cm:d}],...l],m=_.length>=4&&this._samePt(_[0],_[_.length-1]),g=_,f=u;if(g.length>500)return void this.host._showToast(this.host._t("toast.physical_limit"));const b=(a?.segments?.length||0)+(n.segments?.length||0);if(this._draftSegmentCount(e)-b+f.length>2e3)return void this.host._showToast(this.host._t("toast.physical_limit"));if(m){const t=g.slice(0,-1);if(this._contourSelfIntersects(t)||k(t)<=1e-6)return void this.host._showToast(this.host._t("toast.contour_cannot_close"));const e=this._overlapRoom(t);if(e)return void this.host._showToast(this.host._t("toast.room_overlap",{name:e.name||""}))}const y=this._geometrySnapshot(),v=this.host._activeDraftId||t.draft.id,$={...a||n,id:v,points:g.map(t=>[t[0]/ol,t[1]/ol]),segments:f};e.room_drafts=o.filter(e=>e.id!==t.draft.id&&(!this.host._activeDraftId||e.id!==this.host._activeDraftId)),e.room_drafts.push($),this.host._activeDraftId=v,this.host._resumeDraftBySpace[this.host._space]=v,this.host._path=g,this.host._draftSegmentCms=this._adoptDraftCms(g,f.map(t=>Number(t.cm)),v),this.host._physicalSel=null,this._commitPhysicalGeometry(this.host._t("history.draft_merge"),y),null!=d&&this._offerWallFaces(s,s.length-1,i)}_adoptDraftCms(t,e,s){const i=Math.max(0,t.length-1),o=Ra(i,e,this.host._drawWallCm,A);return e.length!==i&&console.debug(`[houseplan] draft ${s??"?"}: восстановлено толщин ${i-e.length} (#234)`),o}_draftSegmentsForPath(t,e,s){const i=Array.isArray(e?.points)?e.points.map(t=>[Number(t?.[0])*ol,Number(t?.[1])*ol]):[],o=Array.isArray(e?.segments)?e.segments:[];return Ra(Math.max(0,t.length-1),s,this.host._drawWallCm,A).map((e,s)=>{const a=t[s],n=t[s+1],r=i.findIndex((t,e)=>{if(e+1>=i.length)return!1;const s=i[e+1];return this._samePt(a,t)&&this._samePt(n,s)||this._samePt(a,s)&&this._samePt(n,t)});return{...r>=0?o[r]:{},cm:e}})}_persistActiveDraftSegment(){if(this.host._path.length<2||!this.host._curSpaceCfg)return;const t=this._geometrySnapshot(),e=this.host._curSpaceCfg;e.room_drafts||=[],this.host._activeDraftId||(this.host._activeDraftId="draft-"+Date.now().toString(36)),this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId;const s=e.room_drafts.findIndex(t=>t.id===this.host._activeDraftId),i={...s>=0?e.room_drafts[s]:{},id:this.host._activeDraftId,points:this.host._path.map(t=>[t[0]/ol,t[1]/ol]),segments:this._draftSegmentsForPath(this.host._path,s>=0?e.room_drafts[s]:null,this.host._draftSegmentCms)};s>=0?e.room_drafts[s]=i:e.room_drafts.push(i),this._commitPhysicalGeometry(this.host._t("history.draft_segment"),t)}_activeWallSourceKey(t){return`active:${this.host._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 s=0;s+1t.key===s);if(i>=0){const[t]=this.host._wallFaceGraphCache.splice(i,1);return this.host._wallFaceGraphCache.push(t),t.value}const o=en(t,e);return this.host._wallFaceGraphCache.push({key:s,value:o}),this.host._wallFaceGraphCache.length>4&&this.host._wallFaceGraphCache.shift(),o}_offerWallFaces(t,e=this.host._path.length-2,s){if(this.host._path.length<2||this.host._wallFaceBatch||this.host._roomDialog)return;const i=this.host._spaceModel();if(!i)return;const o=this._activeWallSourceKey(e),a=2e-4*this.host._gridPitch;let n,r;try{const e=s||this._wallGraphSources(t);r=this._wallGraphSources(this.host._path),n=function(t,e,s){const i=new Set(t.faces.map(t=>t.key));return e.faces.filter(t=>!i.has(t.key)&&t.sourceKeys.includes(s))}(this._wallFaceGraph(e,a),this._wallFaceGraph(r,a),o)}catch{return}if(!n.length){const t=un(r,{requiredSourceKey:o,maxDistance:j(2,this.host._cellCm,this.host._gridPitch),gridStep:this.host._gridPitch,epsilon:a});return"ambiguous"===t.kind?(this.host._wallRepairDiagnostic=t.proposals[0]||null,void this.host._showToast(this.host._t(0===this.host._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 i.rooms){const e=R(t);if(!t.id||!e)continue;const s=Kt(e,this.host._path,.02*this.host._gridPitch);if(!s)continue;const[i,o]=s,a=k(i)>=k(o)?i:o,r=a===i?o:i,l=[...n].sort((t,e)=>Math.abs(t.area-k(r))-Math.abs(e.area-k(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:a,newPoly:r},consumeAllActive:!0}])}const l=n.filter(t=>!(t.ring.length<3||this._contourSelfIntersects(t.ring))&&!this._overlapRoom(t.ring));l.length&&this._beginWallFaceBatch(l)}_beginWallFaceBatch(t){this.host._wallRepairDiagnostic=null,this.host._wallFaceBatch={candidates:[...t].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key)),index:0,decisions:[],activePath:this.host._path.map(t=>[...t]),activeCms:[...this.host._draftSegmentCms],activeDraftId:this.host._activeDraftId},this._clearPlanSnapHover(),this.host._nameSel="",this.host._areaSel="",this._resetRoomDialogFields(),this.host._roomDialog=!0}_offerExistingWallFace(t){if(this.host._path.length||this.host._wallFaceBatch||this.host._roomDialog)return!1;const e=2e-4*this.host._gridPitch;try{let s,i=sn(this._wallFaceGraph(this._wallGraphSources([]),e),t,e);if(!i){const o=un(this._wallGraphSources([]),{point:t,maxDistance:j(2,this.host._cellCm,this.host._gridPitch),gridStep:this.host._gridPitch,epsilon:e});if("ambiguous"===o.kind)return this.host._wallRepairDiagnostic=o.proposals[0]||null,this.host._showToast(this.host._t(0===this.host._drawWallCm?"toast.zero_wall_ambiguous":"toast.wall_repair_ambiguous")),!0;if("repair"===o.kind)i=o.face,s=o.proposal;else if("none"===o.kind){const s=un(this._wallGraphSources([]),{point:t,maxDistance:this._cssPxToRender(12),gridStep:this.host._gridPitch,epsilon:e});if("repair"===s.kind)return this.host._wallRepairDiagnostic=s.proposal,this.host._showToast(this.host._t("toast.wall_repair_too_large")),!0}}return!(!i||i.ring.length<3||this._contourSelfIntersects(i.ring)||this._overlapRoom(i.ring))&&(this._beginWallFaceBatch([{...i,existing:!s,repair:s}]),!0)}catch{return!1}}_columnClick(t){const e=this._snap(t),s=this.host._drawWallCm;if(null==s)return void this._showPhysicalRange(yt,1);if(!this.host._curSpaceCfg||this._limitReached("column"))return;const i=this.host._spaceModel();if(!i)return;const o={id:"column-"+Date.now().toString(36),shape:"square",center:e,cm:wt(s),angle:0},a=(i.wall_columns||[]).find(t=>vt(t,o,.02*this.host._gridPitch));if(a)return clearTimeout(this.host._duplicateColumnTimer),this.host._duplicateColumnId=a.id,this.host._duplicateColumnTimer=window.setTimeout(()=>{this.host._duplicateColumnId=null},900),void this.host._showToast(this.host._t("toast.column_duplicate"));const n=this._geometrySnapshot(),r=this.host._curSpaceCfg;r.wall_columns||=[],r.wall_columns.push({...o,center:[e[0]/ol,e[1]/ol]}),this._commitPhysicalGeometry(this.host._t("history.column_add"),n)}_openPhysicalDialog(t,e,s){const i=this.host._spaceModel();if(i)if("partition"===t){const s=i.partitions.find(t=>t.id===e);s&&(this.host._physicalDialog={kind:t,id:e,cm:Tt(s.cm,this.host._imperial),length:this.host._fmtLen(s.a,s.b)})}else if("column"===t){const s=i.wall_columns.find(t=>t.id===e);s&&(this.host._physicalDialog={kind:t,id:e,cm:Tt(s.cm,this.host._imperial),shape:s.shape,angle:this.host._angleField("square"===s.shape?At(s.angle):0)})}else{const o=i.room_drafts.find(t=>t.id===e),a=Math.max(0,Math.min(o?.segments.length?o.segments.length-1:0,s||0));o?.segments[a]&&(this.host._physicalDialog={kind:t,id:e,segment:a,cm:Tt(o.segments[a].cm,this.host._imperial),length:this.host._fmtLen(o.points[a],o.points[a+1])})}}_physicalDown(t,e,s){const i=this.host._spaceModel();if(!i)return;t.stopPropagation(),nl(t);const o=this._svgPoint(t),a=[];for(const t of[...i.wall_columns].reverse())Vt(o,Jt(t,this.host._cellCm,this.host._gridPitch))&&a.push({kind:"column",id:t.id});for(const t of[...i.partitions].reverse()){const e=Yt(t.a,t.b,t.cm,this.host._cellCm,this.host._gridPitch);e&&Vt(o,e)&&a.push({kind:"partition",id:t.id})}a.some(t=>t.kind===e&&t.id===s)||a.unshift({kind:e,id:s});const n=a.map(t=>`${t.kind}:${t.id}`).sort().join("|"),r=performance.now(),l=this.host._physicalPickCycle,h=a.length>1&&l?.signature===n&&r-l.at>380&&r-l.at<=1200&&Math.hypot(t.clientX-l.x,t.clientY-l.y)<=10?(l.index+1)%a.length:Math.max(0,a.findIndex(t=>t.kind===e&&t.id===s));this.host._physicalPickCycle={signature:n,index:h,x:t.clientX,y:t.clientY,at:r},e=a[h].kind,s=a[h].id;const c="partition"===e?i.partitions.find(t=>t.id===s):i.wall_columns.find(t=>t.id===s);c&&(this.host._physicalSel={kind:e,id:s},this.host._physicalDrag={pid:t.pointerId,kind:e,id:s,start:this._svgPoint(t),startClient:[t.clientX,t.clientY],before:this._geometrySnapshot(),moved:!1,base:JSON.parse(JSON.stringify(c)),delta:[0,0]})}_clampPhysicalDelta(t,e,s){const i="partition"===t?[e.a,e.b]:[e.center],o=i.map(t=>t[0]),a=i.map(t=>t[1]);return[Math.max(-Xt*ol-Math.min(...o),Math.min(Xt*ol-Math.max(...o),s[0])),Math.max(-Xt*ol-Math.min(...a),Math.min(Xt*ol-Math.max(...a),s[1]))]}_physicalMove(t){const e=this.host._physicalDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const s=this._svgPoint(t),i="partition"===e.kind?e.base.a:e.base.center,o=this._snap([i[0]+s[0]-e.start[0],i[1]+s[1]-e.start[1]]),a=this._clampPhysicalDelta(e.kind,e.base,[o[0]-i[0],o[1]-i[1]]);this.host._physicalDrag={...e,delta:a,moved:e.moved||Math.hypot(t.clientX-e.startClient[0],t.clientY-e.startClient[1])>=5}}_physicalUp(t){const e=this.host._physicalDrag;if(!e||e.pid!==t.pointerId)return;if(t.stopPropagation(),this.host._physicalDrag=null,!e.moved)return void this._registerPhysicalTap(e.kind,e.id);const s=this.host._spaceModel();if(!this.host._curSpaceCfg||!s)return;const i=this.host._curSpaceCfg;if("partition"===e.kind){const t=(i.partitions||[]).find(t=>t.id===e.id),s=e.base;if(t){const o={...s,a:[s.a[0]+e.delta[0],s.a[1]+e.delta[1]],b:[s.b[0]+e.delta[0],s.b[1]+e.delta[1]]};t.a=[o.a[0]/ol,o.a[1]/ol],t.b=[o.b[0]/ol,o.b[1]/ol];for(const t of i.openings||[]){if("partition"!==t.host?.kind||t.host.id!==e.id)continue;const s=F(t,[o],ol,this.host._cellCm,this.host._gridPitch).resolved;s&&Object.assign(t,N(t,s,ol))}}}else{const t=(i.wall_columns||[]).find(t=>t.id===e.id),o=e.base,a={...o,center:[o.center[0]+e.delta[0],o.center[1]+e.delta[1]]};if(s.wall_columns.some(t=>t.id!==e.id&&vt(t,a,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"));t&&(t.center=[(o.center[0]+e.delta[0])/ol,(o.center[1]+e.delta[1])/ol])}this._commitPhysicalGeometry(this.host._t("history.physical_move"),e.before)}_registerPhysicalTap(t,e,s){const i=performance.now(),o=this.host._physicalLastTap?.kind===t&&this.host._physicalLastTap.id===e&&this.host._physicalLastTap.segment===s&&i-this.host._physicalLastTap.at<=360;this.host._physicalLastTap={kind:t,id:e,segment:s,at:i},o&&(this.host._physicalLastTap=null,this._openPhysicalDialog(t,e,s))}_cancelPhysicalGesture(){this.host._physicalDrag=null,this.host._physicalRotate=null,this.host.requestUpdate()}_physicalRotateDown(t,e){if("square"!==e.shape||!this.host._spaceModel())return;t.preventDefault(),t.stopPropagation(),nl(t);const s=this._svgPoint(t);this.host._physicalSel={kind:"column",id:e.id},this.host._physicalRotate={pid:t.pointerId,id:e.id,center:[...e.center],startAngle:180*Math.atan2(s[1]-e.center[1],s[0]-e.center[0])/Math.PI,baseAngle:At(e.angle),angle:At(e.angle),before:this._geometrySnapshot(),moved:!1}}_physicalRotateMove(t){const e=this.host._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation();const s=this._svgPoint(t),i=180*Math.atan2(s[1]-e.center[1],s[0]-e.center[0])/Math.PI,o=e.baseAngle+i-e.startAngle,a=At(t.shiftKey?o:5*Math.round(o/5));this.host._physicalRotate={...e,angle:a,moved:e.moved||Math.abs(o-e.baseAngle)>=.5}}_physicalRotateUp(t){const e=this.host._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation(),this.host._physicalRotate=null;const s=this.host._spaceModel();if(!e.moved||!this.host._curSpaceCfg||!s)return;const i=s.wall_columns.find(t=>t.id===e.id);if(!i||"square"!==i.shape)return;const o={...i,angle:e.angle};if(s.wall_columns.some(t=>t.id!==e.id&&vt(t,o,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"));const a=this.host._curSpaceCfg.wall_columns?.find(t=>t.id===e.id);a&&(a.angle=e.angle,this._commitPhysicalGeometry(this.host._t("history.physical_edit"),e.before))}_rszRooms(){const t=[],e=this.host._spaceModel();if(!e)return t;for(const s of e.rooms){const e=s.id?R(s):null;e&&t.push({id:s.id,poly:e,wall_ids:Array.isArray(s.wall_ids)?[...s.wall_ids]:void 0})}return s=t,i=Math.max(1e-12,1e-12*this.host._gridPitch),s.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 s=!0;for(;s&&e.length>3;){s=!1;for(let t=0;t0){e.splice(t,1),s=!0;break}}}return{...t,poly:e}});var s,i}_rszOpenings(){return this.host._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.host._spaceModel();if(!t)return[];const e=[];for(const s of t.partitions||[])e.push({kind:"segment",a:[...s.a],b:[...s.b],half:j(s.cm,this.host._cellCm,this.host._gridPitch)/2});for(const s 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]*ol,t.a[1]*this.host._spaceH],b:[t.b[0]*ol,t.b[1]*this.host._spaceH]})),o=Math.abs(t[0]-e[0])<=.05*this.host._gridPitch?"v":Math.abs(t[1]-e[1])<=.05*this.host._gridPitch?"h":null,a=i.filter(s=>!!o&&("h"===o?!(Math.abs(s.a[1]-t[1])>.05*this.host._gridPitch||Math.abs(s.b[1]-t[1])>.05*this.host._gridPitch)&&Math.min(Math.max(t[0],e[0]),Math.max(s.a[0],s.b[0]))-Math.max(Math.min(t[0],e[0]),Math.min(s.a[0],s.b[0]))>.05*this.host._gridPitch:!(Math.abs(s.a[0]-t[0])>.05*this.host._gridPitch||Math.abs(s.b[0]-t[0])>.05*this.host._gridPitch)&&Math.min(Math.max(t[1],e[1]),Math.max(s.a[1],s.b[1]))-Math.max(Math.min(t[1],e[1]),Math.min(s.a[1],s.b[1]))>.05*this.host._gridPitch)),n=new Set(a.map(t=>Number(t.wall.cm)).filter(t=>t>0));return{minDim:this.host._cmToUnits(30),eps:.05*this.host._gridPitch,step:this.host._gridPitch,movingHalf:s>0?j(s,this.host._cellCm,this.host._gridPitch)/2:0,obstacles:this._rszObstacles(),thicknessConflict:n.size>1}}_rszResolution(t,e,s){const i=this.host._resize.snapshotIdentity||s||this._rszSnapshot(),o=`${this.host._space}|${this.host._cellCm}|${this.host._gridPitch}|${i}`,a=`${t}:${e}`;return this.host._resize.resolve(o,a,()=>{const s=[...this.host._resize.rooms||this._rszRooms()],i=s.find(e=>e.id===t),o=i?.poly?.[e]||[0,0],a=i?.poly?.[(e+1)%(i?.poly?.length||1)]||[0,0];return function(t,e,s,i,o){const{eps:a}=o,n=t.find(t=>t.id===s);if(!n||i<0||i>=(n.poly?.length||0)||n.poly.length<4||!go(n.poly))return{enabled:!1,reason:"invalid-geometry"};const r=n.poly[i],l=n.poly[(i+1)%n.poly.length],h=vo(r,l,a);if(!h)return{enabled:!1,reason:"diagonal"};if(!xo(n.poly,i,h,a))return{enabled:!1,reason:"side-angle"};if(o.thicknessConflict)return{enabled:!1,reason:"thickness-conflict"};for(const t of o.obstacles||[])if(Do(t,r,l,o))return{enabled:!1,reason:"duplicate-physical-wall"};const c=po(lo(l,r)),d=[],p=new Set;let _=!1,u=!1;for(const e of t)if(e.id!==s)for(let t=0;t1||d.length>1)return{enabled:!1,reason:"multiple-rooms"};const m={[s]:i},g=[s];if(1===d.length){const t=d[0];if(!go(t.room.poly))return{enabled:!1,reason:"invalid-geometry"};if(!xo(t.room.poly,t.edge,h,a))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(!(uo([t.x,t.y],r,l)>2*a)){if(t.hosted||t.length>c+2*a)return{enabled:!1,reason:"opening-conflict"};f.push(t.id)}const b=Object.fromEntries(g.map(e=>[e,t.find(t=>t.id===e).poly.length])),y=[];for(const e of g){const s=t.find(t=>t.id===e),i=m[e],o=(i-1+s.poly.length)%s.poly.length,n=(i+1)%s.poly.length,r=Io(t,e,o,1,a),l=Io(t,e,n,0,a);if(!r||!l)return{enabled:!1,reason:"partial-shared"};y.push(r,l)}const v={roomId:s,edge:i,a:[...r],b:[...l],n:mo(n.poly,i),roomIds:g,edgeByRoom:m,topology:b,movingOpeningIds:f,sideOwnership:y};if(!Oo(t,e,v,0,o))return{enabled:!1,reason:"invalid-geometry"};const $=Math.abs(Number(o.step));if(Number.isFinite($)&&$>a){const s=[-$,$];if(!s.some(s=>Oo(t,e,v,s,o))){if(!s.some(s=>Fo(No(t,e,v,s),v,a)))return{enabled:!1,reason:"partial-shared"};const i={...o,obstacles:[]};return s.some(s=>Oo(t,e,v,s,i))?{enabled:!1,reason:"duplicate-physical-wall"}:e.length&&s.some(e=>Oo(t,[],v,e,o))?{enabled:!1,reason:"opening-conflict"}:{enabled:!1,reason:"invalid-geometry"}}}return{enabled:!0,plan:v}}(s,[...this.host._resize.openings||this._rszOpenings()],t,e,this._rszOptsFor(o,a))})}_rszSnapshot(){return JSON.stringify(this._geometrySnapshot()||{spaceId:this.host._space,rooms:[],openings:[],walls:[],open_spans:[]})}_rszResetController(){const t=null!==this.host._resize.preview;this.host._resize.reset(),t&&this.host._cfgEpoch++}_rszProjectPreview(t,e,s,i,o){this.host._rszLimitViolation=null;const a=this.host._serverCfg?.spaces.find(t=>t.id===this.host._space);if(!a||!this.host._serverCfg)return{ok:!1,reason:"missing-context"};const n=JSON.parse(t),r={...a,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]?r[t]=n[t]:delete r[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]?r[t]=n.plan_transform[t]:delete r[t];const l=this.host._spaceH;for(const[t,s]of Object.entries(e)){const e=r.rooms.find(e=>e.id===t);e&&(e.poly=s.map(t=>[t[0]/ol,t[1]/l]),delete e.x,delete e.y,delete e.w,delete e.h)}for(const[t,e]of Object.entries(s)){const s=(r.openings||[]).find(e=>e.id===t);s&&(s.x=e[0]/ol,s.y=e[1]/l)}const h=[],c=[];for(const t of i){const e=o.find(e=>e.id===t),s=r.rooms.find(e=>e.id===t);if(!e||!s?.poly)continue;const i=s.poly.map(t=>[t[0]*ol,t[1]*l]);if(e.poly.length!==i.length)continue;const a=Array.isArray(e.wall_ids)?e.wall_ids:[];for(let t=0;tt.id===s):null;o&&(o.a=[i[t][0]/ol,i[t][1]/ol],o.b=[i[(t+1)%i.length][0]/ol,i[(t+1)%i.length][1]/ol])}}if(h.length&&Array.isArray(r.walls)&&r.walls.length){const t=Zt(r.walls,h,c,this.host._wallKeyPitch,ol,"fixed-topology");if(t.rejected)return{ok:!1,reason:"wall-metadata"};r.walls=t.walls}const d=[];for(const t of r.rooms||[]){const e=R(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=p(t);_.set(e,(_.get(e)||0)+1)}const u=[];for(const t of r.walls||[]){const e=p(t),s=_.get(e)||0;s?_.set(e,s-1):u.push(t)}if(Qt(u,d,this.host._wallKeyPitch,ol,n.walls||[]).length)return{ok:!1,reason:"wall-metadata"};const m=this._rszSpaceCandidateGeometry(this.host._space,r);if(!m.ok)return{ok:!1,reason:"physical-geometry"};const g={...this.host._serverCfg,spaces:(this.host._serverCfg?.spaces||[]).map(t=>t?.id===this.host._space?r:t)},f=this._junctionLimitsIntroduced(g,this.host._serverCfg,this.host._space,m.wallGeometry);return f.length?(this.host._rszLimitViolation=f[0],{ok:!1,reason:"junction-limit"}):{ok:!0,value:{preview:{space:this.host._space,sp:r},beforeWalls:n.walls||[],afterWalls:r.walls||[],artifact:m.wallGeometry}}}_rszAcceptPreview(t,e){if(this.host._cfgEpoch++,!t||!e)return;const s=te(e);if(!s)return;const i=`${this.host._space}|${this.host._cfgEpoch}|${t.sp.rooms.length}`;Object.defineProperty(s,"sourceFingerprint",{value:Et([t.sp,this.host._cellCm,this.host._gridPitch]),enumerable:!1});const o={key:i,value:s};il(this.host._wallUnionPool,i,o,8),this.host._wallUnionCache=o}_rszSpaceCandidateGeometry(t,e){if(!this.host._serverCfg)return{ok:!1,wallGeometry:null};const s={...this.host._serverCfg,spaces:this.host._serverCfg.spaces.map(s=>s.id===t?e:s)};let i=null;try{return{ok:this.host._checkSpacePhysicalGeometry(s,t,t=>{i=t}).ok,wallGeometry:i}}catch{return{ok:!1,wallGeometry:null}}}_rszSpaceCandidateRenderable(t,e){if(!this.host._serverCfg)return!1;try{const s={...this.host._serverCfg,spaces:this.host._serverCfg.spaces.map(s=>s.id===t?e:s)};return this.host._checkSpacePhysicalGeometry(s,t).ok}catch{return!1}}_rszCandidateRenderable(t){return!!t&&t.space===this.host._space&&this._rszSpaceCandidateRenderable(t.space,t.sp)}_rszEdgeDown(t,e,s){if("resize"!==this.host._tool||this.host._resize.dragging)return;t.stopPropagation(),t.preventDefault();const i=this._rszRooms(),o=this._rszResolution(e,s);if(!o.enabled)return void this.host._showToast(this._rszReasonText(o.reason));nl(t);const a=o.plan,n=this._svgPoint(t),r=`${this.host._space}|${this.host._cfgEpoch}|${i.length}`,l=this.host._wallUnionCache?.key===r?this.host._wallUnionCache.value:null,h=this._rszSnapshot();this.host._resize.begin({pointerId:t.pointerId,start:[n[0],n[1]],roomId:e,plan:a,options:this._rszOptsFor(a.a,a.b),rooms:i,openings:this._rszOpenings(),snapshotIdentity:h,before:JSON.parse(h),wallUnionBefore:l})}_rszReasonText(t){return this.host._t(`resize.disabled.${t}`)}_rszDisabledActivate(t,e){t.stopPropagation(),t.preventDefault(),this.host._showToast(this._rszReasonText(e))}_rszDisabledKey(t,e){"Enter"!==t.key&&" "!==t.key||this._rszDisabledActivate(t,e)}_rszMove(t){if(!this.host._resize.ownsPointer(t.pointerId))return;t.stopPropagation();const e=this._svgPoint(t),s=this.host._resize.move({pointerId:t.pointerId,point:[e[0],e[1]],step:this.host._gridPitch,snap:t=>{const e=this._snap(t);return[e[0],e[1]]},project:(t,e,s,i,o)=>this._rszProjectPreview(t,e,s,i,o),publish:(t,e)=>this._rszAcceptPreview(t,e),measure:(t,e)=>this._rszEdgeLabels(t,e)});if("rejected"===s.kind)return s.notify&&this.host._showToast(this.host._rszLimitViolation?`${this.host._t("resize.limit_stopped")} — `+this._junctionLimitLabel(this.host._rszLimitViolation):this.host._t("resize.preview_failed")),void this.host.requestUpdate();"accepted"===s.kind&&this.host.requestUpdate()}_rszUp(t){if(!this.host._resize.ownsPointer(t.pointerId))return;t.stopPropagation();const e=this.host._resize.finish({pointerId:t.pointerId,currentSnapshotIdentity:this._rszSnapshot(),validatePreview:t=>this._rszCandidateRenderable(t)});if("no-op"===e.kind)return this.host._cfgEpoch++,void this.host.requestUpdate();if("rejected"===e.kind)return this.host._cfgEpoch++,this.host._showToast(this.host._t("resize.commit_failed")),void this.host.requestUpdate();const s=e.preview,i=this.host._serverCfg?.spaces.find(t=>t.id===s.space);i&&(i.rooms=s.sp.rooms,i.openings=s.sp.openings,Array.isArray(s.sp.walls)&&(s.sp.walls.length?i.walls=s.sp.walls:delete i.walls),Array.isArray(s.sp.wall_segments)&&(i.wall_segments=s.sp.wall_segments)),this.host._suppressClick=!0,setTimeout(()=>this.host._suppressClick=!1,0),this._commitPhysicalGeometry(this.host._t("history.resize_room"),e.before),this.host.requestUpdate()}_rszCancelDrag(t){const e=this.host._resize.cancel(this._rszSnapshot(),t);if("no-op"!==e.kind){if(this.host._cfgEpoch++,e.restoreWallUnion){const t=this.host._spaceModel();if(t){const s=`${this.host._space}|${this.host._cfgEpoch}|${t.rooms.length}`,i={key:s,value:e.restoreWallUnion};il(this.host._wallUnionPool,s,i,8),this.host._wallUnionCache=i}}this.host.requestUpdate()}}_rszPointerCancel(t){this.host._resize.ownsPointer(t.pointerId)&&(t.stopPropagation(),this._rszCancelDrag(t.pointerId))}_rszEdgeLabels(t,e,s=this.host._resize.rooms){const i=s,o=[],a=t.polys[e.roomId]||i?.find(t=>t.id===e.roomId).poly;if(!a||!i)return o;const n=a.length,r=this._rszInnerSpanCms(e.roomId,a,t.polys);for(const t of function(t,e){const s=t.length;return[(e-1+s)%s,(e+1)%s]}(a,e.edge)){const e=a[t],s=a[(t+1)%n],i=r?.[t];o.push({kind:"length",x:(e[0]+s[0])/2,y:(e[1]+s[1])/2,text:null==i?this.host._fmtLen(e,s):ee(i,"mi"===this.host.hass?.config?.unit_system?.length),edge:{a:[e[0],e[1]],b:[s[0],s[1]]}})}const l="mi"===this.host.hass?.config?.unit_system?.length,h=e.roomIds,c=this.host._spaceWalls,d=this.host._physicalBodiesR(),p=this.host._baseVb(),_=this.host._view&&this.host._view.w>0&&this.host._view.h>0?this.host._view:{x:p[0],y:p[1],w:p[2],h:p[3]},[u,m]=this.host._lastValidStageSize||[_.w,_.h],g={..._,stageWidth:Math.max(1,u),stageHeight:Math.max(1,m)},f=this.host._spaceModel(),b=this.host._config?.icon_size??2.5,y=f?se(b>8?2.5:b,f,_.w,this.host._kiosk?this.host._kioskScale.icon:1)*g.stageWidth/100:24,v=Math.max(10,.77*y),$=this.host._t("room.settings_short"),w=v*(1.457+.66*Math.max(1,$.length)*.42);for(const s of h){const a=t.polys[s]||i.find(t=>t.id===s).poly,n=c.length&&f&&this.host._innerRoomContour(f,s)||a,r=d.length?ie(oe(n,d))*Math.pow(this.host._cellCm/this.host._gridPitch,2)/1e4:ae(n,this.host._gridPitch,this.host._cellCm),h=ne(r,l),p=qo({poly:a,edge:e.edgeByRoom[s],text:h,view:g,gearCenter:re(a),gearWidthPx:w,gearHeightPx:v});o.push({kind:"area",roomId:s,x:p.anchor[0],y:p.anchor[1],text:h,placement:p})}return o}_rszInnerSpanCms(t,e,s){const i=Object.keys(s).length?Object.entries(s).map(([t,e])=>({id:t,poly:e})):this.host._spaceModel()?.rooms;if(!i?.length)return null;const o=this.host._spaceWalls;if(!o.length)return null;const a=this.host._openCuts(),n=le(i,t,o,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol);if(!n||n.length!==e.length)return null;const r=this.host._cellCm/this.host._gridPitch;return e.map((t,s)=>he(e,s,n)*r)}_renderResizeMeasurements(){const t=this.host._resize.liveLabels;if(!t?.length)return a;const e=t.filter(t=>"length"===t.kind),s=t.filter(t=>"area"===t.kind);return ce``}_renderResizeLayer(t){const e=Math.max(.013*t.w,5),s=e/2,i=t=>t.toFixed(1),o=`M ${i(-.7*s)} 0 H ${i(.7*s)} M 0 ${i(-.22*s)} V ${i(-s)} M ${i(-.32*s)} ${i(-.6*s)} L 0 ${i(-s)} L ${i(.32*s)} ${i(-.6*s)} M 0 ${i(.22*s)} V ${i(s)} M ${i(-.32*s)} ${i(.6*s)} L 0 ${i(s)} L ${i(.32*s)} ${i(.6*s)}`,a=[],n=this._rszRooms(),r=this.host._resize.snapshotIdentity||this._rszSnapshot();for(const t of n)for(let s=0;sthis._rszEdgeDown(e,t.id,s)} + @pointermove=${t=>this._rszMove(t)} + @pointerup=${t=>this._rszUp(t)} + @pointercancel=${t=>this._rszPointerCancel(t)} + @lostpointercapture=${t=>this._rszPointerCancel(t)} + @click=${_?t=>this._rszDisabledActivate(t,p.reason):null} + @keydown=${_?t=>this._rszDisabledKey(t,p.reason):null}> + ${u} + `),a.push(ce``)}return ce`${a}`}_partitionOpeningCuts(t=this.host._spaceModel(),e=()=>!0){if(!t)return[];const s=this.host._curSpaceCfg?.id===t.id?this.host._curSpaceCfg:null,i=de(s,t,this.host._cellCm,this.host._gridPitch,ol);return pe(i,e)}_decorSnapGeometry(t){const e=this.host._spaceModel();if(!e)return{points:[],segments:[]};const s=t||"",i=this.host._decorSnapCache;if(i&&i.epoch===this.host._cfgEpoch&&i.space===this.host._space&&i.height===this.host._decorH&&i.exclude===s)return i.geometry;const o=[];for(const e of this.host._decorList)if(e.id!==t)if("line"===e.kind){const t=[e.x1*ol,e.y1*this.host._decorH],s=[e.x2*ol,e.y2*this.host._decorH];o.push({points:[t,s,[(t[0]+s[0])/2,(t[1]+s[1])/2]],segments:[{a:t,b:s}]})}else if("text"===e.kind)o.push({points:[[e.x*ol,e.y*this.host._decorH]],segments:[]});else{const t=this.host._decorBoxOf(e);t&&o.push(_e(t))}for(const t of e.rooms){const e=R(t);e?.length&&o.push({points:e.flatMap((t,s)=>{const i=e[(s+1)%e.length];return[t,[(t[0]+i[0])/2,(t[1]+i[1])/2]]}),segments:e.map((t,s)=>({a:t,b:e[(s+1)%e.length]}))})}const a=ue(o);return this.host._decorSnapCache={epoch:this.host._cfgEpoch,space:this.host._space,height:this.host._decorH,exclude:s,geometry:a},a}_decorSnap(t,e="mouse",s){const i=this.host._stageEl,o=this.host._viewOr(this.host._baseVb()),a="touch"===e||"pen"===e?14:8,n=i?o.w/Math.max(1,i.clientWidth)*a:this.host._gridPitch;return me(t,this._decorSnapGeometry(s),n,t=>this._snap(t)).point}_replaceDecor(t,e){const s=this.host._curSpaceCfg;s&&(s.decor=this.host._decorList.map(s=>s.id===t?{...s,...e}:s),this.host.requestUpdate())}_cancelDecorGesture(){const t=this.host._decorMove?.before||this.host._dtDrag?.before||this.host._bdDrag?.before,e=t&&this.host._serverCfg?.spaces.find(e=>e.id===t.spaceId);if(t&&e){const s=t=>JSON.parse(JSON.stringify(t));void 0!==t.decor?e.decor=s(t.decor):delete e.decor;for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete e[t];Object.assign(e,s(t.plan_transform||{})),this.host._cfgEpoch++}this.host._decorMove=null,this.host._dtDrag=null,this.host._bdDrag=null,this.host.requestUpdate()}_decorPointerDown(t){const e=this.host._decorTool;if("select"===e||"erase"===e?t.target.closest?.(".dshape"):null)return!0;if("line"===e||"rect"===e||"ellipse"===e){t.preventDefault();const s=this._decorSnap(this._svgPoint(t),t.pointerType);return this.host._decorDraft={kind:e,a:s,b:s,pid:t.pointerId},nl(t),!0}if("text"===e){const e=this._decorSnap(this._svgPoint(t),t.pointerType);return this.host._decorTextDialog={x:fe(e[0]/ol),y:fe(e[1]/this.host._decorH),text:"",color:this.host._decorStyle.color,opacity:this.host._decorStyle.opacity,angle:"0",sizeCm:ge(ct,this.host._cellCm,this.host._gridPitch)},this.host._decorTextSelection={start:0,end:0},!0}if("furniture"===e)return!!this.host._furnPalette&&(t.preventDefault(),this._furnPlace(this._svgPoint(t),t.shiftKey),!0);if("select"===e&&(this.host._decorSel=null),this.host._bdMovable){const e=this.host._bdRect,s=this._svgPoint(t),i=e.x+e.w/2,o=e.y+e.h/2,a=-be(e.angle)*Math.PI/180,n=s[0]-i,r=s[1]-o,l=[i+n*Math.cos(a)-r*Math.sin(a),o+n*Math.sin(a)+r*Math.cos(a)];if(l[0]>=e.x&&l[0]<=e.x+e.w&&l[1]>=e.y&&l[1]<=e.y+e.h)return t.preventDefault(),this._bdStart(t)}return!1}_decorCommitDraft(){const t=this.host._decorDraft;if(this.host._decorDraft=null,!t)return;const e=.5*this.host._gridPitch;if(!ye(t.kind,t.a,t.b,e))return;const s=ol,i=this.host._decorH,o=this.host._decorStyle,a=this._geometrySnapshot(),n="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),r=fe;let l;if("line"===t.kind)l={id:n,kind:"line",x1:r(t.a[0]/s),y1:r(t.a[1]/i),x2:r(t.b[0]/s),y2:r(t.b[1]/i),...ve(o,!1)};else{const e=r(Math.min(t.a[0],t.b[0])/s),a=r(Math.min(t.a[1],t.b[1])/i),h=Math.abs(t.b[0]-t.a[0])/s,c=Math.abs(t.b[1]-t.a[1])/i;l={id:n,kind:t.kind,x:e,y:a,w:h,h:c,...ve(o,!0)}}this.host._curSpaceCfg.decor=[...this.host._decorList,l],this.host._decorSel=n,this._recordGeometry(this.host._t("history.decor_add"),a),this._saveConfig(),this.host.requestUpdate()}_decorShapeDown(t,e){if("decor"!==this.host._mode)return;const s=this.host._decorTool;if("text"===s){if("text"!==e.kind)return;return t.stopPropagation(),t.preventDefault(),void this._decorOpenText(e)}"select"!==s&&"erase"!==s||(t.stopPropagation(),t.preventDefault(),"erase"!==s?(this.host._decorSel=e.id,this.host._decorMove={id:e.id,start:this._svgPoint(t),orig:JSON.parse(JSON.stringify(e)),pid:t.pointerId,moved:!1,before:this._geometrySnapshot()},nl(t)):this.host._decorEraseConfirm={id:e.id,kind:e.kind})}_decorMoveUpdate(t){const e=this.host._decorMove;if("furniture"===e.orig?.kind)return void this._furnMoveUpdate(t);const s=this._svgPoint(t),i=e.orig,o=("line"===i.kind?i.x1:i.x)*ol,a=("line"===i.kind?i.y1:i.y)*this.host._decorH,n=this._decorSnap([o+(s[0]-e.start[0]),a+(s[1]-e.start[1])],t.pointerType,e.id);let r=(n[0]-o)/ol,l=(n[1]-a)/this.host._decorH;const h=e.orig,c="line"===h.kind?Math.min(h.x1,h.x2):h.x,d="line"===h.kind?Math.min(h.y1,h.y2):h.y,p="line"===h.kind?Math.abs(h.x2-h.x1):h.w||0,_="line"===h.kind?Math.abs(h.y2-h.y1):h.h||0,u=Xt;r=Math.max(-u-c,Math.min(u-c-p,r)),l=Math.max(-u-d,Math.min(u-d-_,l)),(r||l)&&(e.moved=!0);this.host._curSpaceCfg.decor=this.host._decorList.map(t=>{if(t.id!==e.id)return t;const s=e.orig;return"line"===t.kind?{...t,x1:s.x1+r,y1:s.y1+l,x2:s.x2+r,y2:s.y2+l}:{...t,x:s.x+r,y:s.y+l}}),this.host.requestUpdate()}_decorShapeDbl(t,e){"decor"===this.host._mode&&"select"===this.host._decorTool&&(t.preventDefault(),t.stopPropagation(),this.host._decorMove=null,this.host._decorSel=e.id,this._openDecorProperties(e))}_openDecorProperties(t){if("decor"!==this.host._mode||"select"!==this.host._decorTool)return;if("text"===t.kind)return void this._decorOpenText(t);if(!["line","rect","ellipse","furniture"].includes(t.kind))return;const e=this.host._decorResolvedStyle(t),s="line"===t.kind?t:null,i=this.host._decorBoxOf(t);this.host._decorShapeDialog={id:t.id,kind:t.kind,color:e.color,opacity:e.opacity,widthCm:e.widthCm,angle:this.host._angleField(be(s?$e([s.x1*ol,s.y1*this.host._decorH],[s.x2*ol,s.y2*this.host._decorH]):t.angle)),...s?{lengthCm:ge(Math.hypot((s.x2-s.x1)*ol,(s.y2-s.y1)*this.host._decorH),this.host._cellCm,this.host._gridPitch),lineStyle:"dashed"===s.line_style?"dashed":"solid"}:{},...i?{sizeWCm:ge(i.w,this.host._cellCm,this.host._gridPitch),sizeHCm:ge(i.h,this.host._cellCm,this.host._gridPitch)}:{},..."furniture"===t.kind?{symbol:t.symbol}:{},..."rect"===t.kind||"ellipse"===t.kind?{fill:e.fill,fillColor:e.fillColor,fillOpacity:e.fillOpacity}:{}}}_decorOpenText(t){if("text"!==t.kind)return;let e=String(t.text??"");const s=[...e.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!pt(t[1])),i=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,a=s||i?"":_t(t.entity,o),n=!(!String(t.entity??"").trim()||s||a&&!i);if(a&&!n){const t=e.indexOf("{}");e=t>=0?e.slice(0,t)+a+e.slice(t+2):`${e}${e?" ":""}${a}`}this.host._decorTextDialog={id:t.id,x:t.x,y:t.y,text:e,color:l(t.color,this.host._decorStyle.color),opacity:we(t.opacity,this.host._decorStyle.opacity),angle:this.host._angleField(t.angle),sizeCm:this.host._decorTextSizeCm(t),pickerEntity:t.entity||"",preserveLegacy:n||void 0},this.host._decorTextSelection={start:e.length,end:e.length}}_decorRememberTextSelection(t){this.host._decorTextSelection={start:t.selectionStart??t.value.length,end:t.selectionEnd??t.value.length}}_decorInsertLiveVariable(t){const e=this.host._decorTextDialog;if(!e)return;const s=_t(e.pickerEntity,t);if(!s)return;const i=e.text,o=Math.max(0,Math.min(i.length,this.host._decorTextSelection.start)),a=Math.max(o,Math.min(i.length,this.host._decorTextSelection.end));if(i.length-(a-o)+s.length>200)return;const n=i.slice(0,o)+s+i.slice(a),r=o+s.length;this.host._decorTextSelection={start:r,end:r},this.host._decorTextDialog={...e,text:n,preserveLegacy:void 0},this.host.updateComplete.then(()=>{const t=this.host.renderRoot.querySelector("textarea.dtarea");t&&(t.focus(),t.setSelectionRange(r,r))})}_decorSaveText(){const t=this.host._decorTextDialog,e=String(t?.text??"").replace(/\r\n?/g,"\n").trim();if(!t||!e)return void(this.host._decorTextDialog=null);const s=this._geometrySnapshot(),i=this.host._curSpaceCfg,o={color:t.color,opacity:we(t.opacity),size_cm:Number(Math.max(.1,Math.min(tl,t.sizeCm)).toFixed(4)),...be(t.angle)?{angle:be(t.angle)}:{}};if(t.id)i.decor=this.host._decorList.map(s=>{if(s.id!==t.id)return s;if("text"!==s.kind)return s;if(t.preserveLegacy){const{angle:t,size:i,scale:a,...n}=s;return{...n,text:e,...o}}const{entity:i,attr:a,unit:n,...r}=s,{angle:l,size:h,scale:c,...d}=r;return{...d,text:e,...o}});else{const s="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5);i.decor=[...this.host._decorList,{id:s,kind:"text",x:t.x,y:t.y,text:e,...o}],this.host._decorSel=s}this.host._decorTextDialog=null,this._recordGeometry(this.host._t(t.id?"history.decor_edit":"history.decor_add"),s),this._saveConfig(),this.host.requestUpdate()}_decorSaveShape(){const t=this.host._decorShapeDialog;if(!t)return;const e=this._geometrySnapshot(),s={color:t.color,opacity:we(t.opacity),widthCm:Math.max(.1,Math.min(100,Number(t.widthCm)||.1)),fill:!!t.fill,fillColor:t.fillColor||t.color,fillOpacity:we(t.fillOpacity,.25)};this.host._curSpaceCfg.decor=this.host._decorList.map(e=>{if(e.id!==t.id)return e;const i="rect"===t.kind||"ellipse"===t.kind,o=ve(s,i);if("line"===e.kind){const s=(e.x1+e.x2)/2*ol,i=(e.y1+e.y2)/2*this.host._decorH,a=ke(Math.max(.1,Number(t.lengthCm)||.1),this.host._cellCm,this.host._gridPitch),n=be(t.angle)*Math.PI/180,r=Math.cos(n)*a/2,l=Math.sin(n)*a/2,h=this._snap([s-r,i-l]),c=this._snap([s+r,i+l]),{width:d,line_style:p,..._}=e;return{..._,...o,x1:fe(h[0]/ol),y1:fe(h[1]/this.host._decorH),x2:fe(c[0]/ol),y2:fe(c[1]/this.host._decorH),..."dashed"===t.lineStyle?{line_style:"dashed"}:{}}}if("rect"===e.kind||"ellipse"===e.kind||"furniture"===e.kind){const s=e.w*ol,i=e.h*this.host._decorH,a=Math.max(this.host._gridPitch,Ft(ke(Number(t.sizeWCm),this.host._cellCm,this.host._gridPitch),this.host._gridPitch)),n=Math.max(this.host._gridPitch,Ft(ke(Number(t.sizeHCm),this.host._cellCm,this.host._gridPitch),this.host._gridPitch)),r=e.x*ol+s/2,l=e.y*this.host._decorH+i/2,h=be(t.angle),c=xe({x:r-a/2,y:l-n/2},h,t=>this._snap(t)),{width:d,angle:p,..._}=e;return{..._,...o,x:fe(c[0]/ol),y:fe(c[1]/this.host._decorH),w:a/ol,h:n/this.host._decorH,..."furniture"===e.kind&&t.symbol?{symbol:t.symbol}:{},...h?{angle:h}:{}}}return e}),this.host._decorStyle={...s,fill:"rect"===t.kind||"ellipse"===t.kind?s.fill:this.host._decorStyle.fill,fillColor:"rect"===t.kind||"ellipse"===t.kind?s.fillColor:this.host._decorStyle.fillColor,fillOpacity:"rect"===t.kind||"ellipse"===t.kind?s.fillOpacity:this.host._decorStyle.fillOpacity},this.host._decorShapeDialog=null,this._recordGeometry(this.host._t("history.decor_edit"),e),this._saveConfig(),this.host.requestUpdate()}_dtPivot(t){return"line"===t.kind?[(t.x1+t.x2)/2*ol,(t.y1+t.y2)/2*this.host._decorH]:"furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind?[(t.x+t.w/2)*ol,(t.y+t.h/2)*this.host._decorH]:[t.x*ol,t.y*this.host._decorH]}_dtApply(t,e){const s=this.host._curSpaceCfg;s&&(s.decor=this.host._decorList.map(s=>{if(s.id!==t)return s;const i={...s};"text"===s.kind&&void 0!==e.textSizeCm&&(delete i.size,delete i.scale);const o={...i};return void 0!==e.textSizeCm&&(o.size_cm=Number(Math.max(.1,Math.min(tl,e.textSizeCm)).toFixed(4))),void 0!==e.angle&&(e.angle?o.angle=Number(e.angle.toFixed(2)):delete o.angle),o}),this.host._cfgEpoch++,this.host.requestUpdate())}_dtStart(t,e,s,i){const o=this.host._dtSel;if(!o)return;t.stopPropagation(),t.preventDefault();const[a,n]=this._dtPivot(o),r=this._svgPoint(t),l=this.host._decorBoxOf(o);this.host._dtDrag={id:o.id,kind:e,pid:t.pointerId,ax:a,ay:n,r0:Math.hypot(r[0]-a,r[1]-n),a0:180*Math.atan2(r[1]-n,r[0]-a)/Math.PI,textSizeCm0:"text"===o.kind?this.host._decorTextSizeCm(o):1,angle0:"line"===o.kind?0:Number(o.angle)||0,sgx:s?.[0],sgy:s?.[1],orig:l||void 0,origShape:JSON.parse(JSON.stringify(o)),before:this._geometrySnapshot(),lineEnd:i,moved:!1},nl(t)}_dtMove(t){const e=this.host._dtDrag;if(!e)return;const s=this._svgPoint(t);if(void 0!==e.lineEnd&&"line"===e.origShape.kind){const i=this._decorSnap(s,t.pointerType,e.id),o=fe(i[0]/ol),a=fe(i[1]/this.host._decorH),n=e.origShape,r=0===e.lineEnd?n.x1:n.x2,l=0===e.lineEnd?n.y1:n.y2;return(Math.abs(o-r)>1e-9||Math.abs(a-l)>1e-9)&&(e.moved=!0),void this._replaceDecor(e.id,0===e.lineEnd?{x1:o,y1:a}:{x2:o,y2:a})}if("scale"===e.kind&&e.orig){const i=Se(e.orig,e.sgx??1,e.sgy??1,s[0],s[1],!t.shiftKey,this.host._gridPitch,this.host._gridPitch),o=Math.abs(i.x-e.orig.x)>1e-6||Math.abs(i.y-e.orig.y)>1e-6||Math.abs(i.w-e.orig.w)>1e-6||Math.abs(i.h-e.orig.h)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._decorApplyBox(e.id,i)}if("scale"===e.kind){const t=Math.hypot(s[0]-e.ax,s[1]-e.ay);if(e.r0<1e-6)return;const i=Math.max(.1,Math.min(tl,e.textSizeCm0*(t/e.r0))),o=Math.abs(i-e.textSizeCm0)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._dtApply(e.id,{textSizeCm:i})}const i=180*Math.atan2(s[1]-e.ay,s[0]-e.ax)/Math.PI;let o=e.angle0+(i-e.a0);t.shiftKey||(o=5*Math.round(o/5)),o=(o%360+360)%360,o>180&&(o-=360);const a=Math.abs(o-e.angle0)>1e-6;(a||e.moved)&&(e.moved||=a,this._dtApply(e.id,{angle:o}))}_dtUp(){const t=this.host._dtDrag;this.host._dtDrag=null,t?.moved&&(this._recordGeometry(this.host._t("history.decor_transform"),t.before),this._saveConfig()),this.host.requestUpdate()}_dtMeasure(){const t=this.host._dtSel;if(!t)return void(this.host._dtBox&&(this.host._dtBox=null,this.host.requestUpdate()));let e;if("line"===t.kind){const s=t.x1*ol,i=t.y1*this.host._decorH,o=t.x2*ol,a=t.y2*this.host._decorH;e={id:t.id,x:Math.min(s,o),y:Math.min(i,a),w:Math.abs(o-s),h:Math.abs(a-i)}}else if("furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind)e={id:t.id,x:t.x*ol,y:t.y*this.host._decorH,w:t.w*ol,h:t.h*this.host._decorH};else{const s=this.host.renderRoot.querySelector(`text.dtext[data-id="${t.id}"]`);if(!s||"function"!=typeof s.getBBox)return;let i;try{i=s.getBBox()}catch{return}if(!i||!i.width&&!i.height)return;e={id:t.id,x:i.x,y:i.y,w:i.width,h:i.height}}const s=this.host._dtBox;s&&s.id===e.id&&Math.abs(s.x-e.x)<.01&&Math.abs(s.y-e.y)<.01&&Math.abs(s.w-e.w)<.01&&Math.abs(s.h-e.h)<.01||(this.host._dtBox=e,this.host.requestUpdate())}_deleteDecor(t){if(!this.host._decorList.some(e=>e.id===t))return;const e=this._geometrySnapshot();this.host._curSpaceCfg.decor=this.host._decorList.filter(e=>e.id!==t),this.host._decorSel===t&&(this.host._decorSel=null),this._recordGeometry(this.host._t("history.decor_delete"),e),this._saveConfig(),this.host.requestUpdate()}_decorDeleteSel(){this.host._decorSel&&this._deleteDecor(this.host._decorSel)}_confirmDecorErase(){const t=this.host._decorEraseConfirm;this.host._decorEraseConfirm=null,t&&this._deleteDecor(t.id)}_furnFieldValue(t){return Math.round(100*(this.host._imperial?t/30.48:t/100))/100}_furnFieldToCm(t){return Me(this.host._imperial?30.48*t:100*t)}_furnPick(t){const e=De(t);this.host._furnPalette={symbol:t,w:e.w,h:e.h}}_furnPlace(t,e=!1){const s=this.host._furnPalette,i=this.host._curSpaceCfg;if(!s||!i)return;const o=ol,a=this.host._decorH,n=Ce(Pe(s.w,this.host._cellCm,this.host._gridPitch,o)),r=Ce(Pe(s.h,this.host._cellCm,this.host._gridPitch,o)),l=this._geometrySnapshot(),h=this._decorSnap(t);let c=h[0],d=h[1],p=0;const _=e?null:Ie(c,d,r*a,this.host._furnWalls,this.host._furnWallReach,this.host._gridPitch);_&&(c=_.cx,d=_.cy,p=_.angle);const u="df"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),m={id:u,kind:"furniture",symbol:s.symbol,x:fe(c/o-n/2),y:fe(d/a-r/2),w:n,h:r,...ve(this.host._decorStyle,!1)};p&&(m.angle=Number(p.toFixed(2))),i.decor=[...this.host._decorList,m],this.host._decorSel=u,this.host._decorTool="select",this.host._furnPalette=null,this._recordGeometry(this.host._t("history.decor_add"),l),this._saveConfig(),this.host.requestUpdate()}_furnMoveUpdate(t){const e=this.host._decorMove;if("furniture"!==e.orig.kind)return;const s=e.orig,i=this.host._curSpaceCfg;if(!i)return;const o=ol,a=this.host._decorH,n=this._svgPoint(t),r=(s.x+s.w/2)*o+(n[0]-e.start[0]),l=(s.y+s.h/2)*a+(n[1]-e.start[1]);let h,c,d=Number(s.angle)||0;const p=t.shiftKey?null:Ie(r,l,s.h*a,this.host._furnWalls,this.host._furnWallReach,this.host._gridPitch);if(p)h=p.cx/o-s.w/2,c=p.cy/a-s.h/2,d=p.angle;else{const i=this._decorSnap([r-s.w/2*o,l-s.h/2*a],t.pointerType,e.id);h=i[0]/o,c=i[1]/a}h=fe(h),c=fe(c),(Math.abs(h-s.x)>1e-9||Math.abs(c-s.y)>1e-9||Math.abs(d-(Number(s.angle)||0))>1e-9)&&(e.moved=!0),i.decor=this.host._decorList.map(t=>{if(t.id!==e.id)return t;const s={...t,x:h,y:c};return d?s.angle=Number(d.toFixed(2)):delete s.angle,s}),this.host.requestUpdate()}_decorApplyBox(t,e){const s=this.host._curSpaceCfg;if(!s)return;const i=ol,o=this.host._decorH;s.decor=this.host._decorList.map(s=>{if(s.id!==t)return s;const a=xe(e,s.angle,t=>this._snap(t));return{...s,x:fe(a[0]/i),y:fe(a[1]/o),w:Math.max(this.host._gridPitch/i,Math.min(2*Xt,e.w/i)),h:Math.max(this.host._gridPitch/o,Math.min(2*Xt,e.h/o))}}),this.host._cfgEpoch++,this.host.requestUpdate()}_renderFurnPalette(){const t=this.host._furnPalette,e=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return o`
t.stopPropagation()}> +
+ ${this.host._t("furn.title")} + + +
+
+ ${Te.map(e=>o` +
${this.host._t(`furn.group_${e}`)}
+
+ ${Re(e).map(e=>o``)} +
`)} +
+ ${t?o`
+ + this.host._furnPalette={...t,w:this._furnFieldToCm(Number(e.target.value))}} /> + + this.host._furnPalette={...t,h:this._furnFieldToCm(Number(e.target.value))}} /> + ${this.host._t("furn.place_hint")} +
`:o`
${this.host._t("furn.pick_hint")}
`} +
`}_openBackdropDialog(t){if(!this.host._bdMovable||!this.host._bdRect)return;t?.preventDefault(),t?.stopPropagation(),this.host._bdDrag=null;const e=this.host._bdRect;this.host._backdropDialog={widthCm:ge(e.w,this.host._cellCm,this.host._gridPitch),heightCm:ge(e.h,this.host._cellCm,this.host._gridPitch),angle:this.host._angleField(e.angle)}}_saveBackdropDialog(){const t=this.host._backdropDialog,e=this.host._bdBase,s=this.host._bdRect;if(!t||!e||!s)return;const i=be(t.angle),o=this._geometrySnapshot(),a=Math.min(e.w*ht,Math.max(e.w*lt,Ft(ke(t.widthCm,this.host._cellCm,this.host._gridPitch),this.host._gridPitch))),n=Math.min(e.h*ht,Math.max(e.h*lt,Ft(ke(t.heightCm,this.host._cellCm,this.host._gridPitch),this.host._gridPitch))),r=s.x+s.w/2,l=s.y+s.h/2,h=xe({x:r-a/2,y:l-n/2},i,t=>this._snap(t));this._bdApply((h[0]-e.x)/ol,(h[1]-e.y)/ol,a/e.w,n/e.h,i),this.host._backdropDialog=null,this._recordGeometry(this.host._t("history.backdrop_transform"),o),this._saveConfig()}_bdApply(t,e,s,i,o){const a=this.host._curSpaceCfg;if(!a)return;a.plan_x=Number(fe(t).toFixed(6)),a.plan_y=Number(fe(e).toFixed(6)),delete a.plan_scale,a.plan_scale_x=Number(Math.min(ht,Math.max(lt,s)).toFixed(6)),a.plan_scale_y=Number(Math.min(ht,Math.max(lt,i)).toFixed(6));const n=be(o);n?a.plan_angle=Number(n.toFixed(2)):delete a.plan_angle,this.host._cfgEpoch++,this.host.requestUpdate()}_bdStart(t,e,s=!1){const i=this.host._bdBase,o=this.host._bdRect;if(!i||!o)return!1;const a=this._svgPoint(t),n=e?e[0]:0,r=e?e[1]:0,l=n>0?o.x:o.x+o.w,h=r>0?o.y:o.y+o.h;return this.host._bdDrag={kind:s?"rotate":e?"scale":"move",pid:t.pointerId,sx:a[0],sy:a[1],base:i,p0:this.host._bdParams,fx:l,fy:h,sgx:n,sgy:r,rect0:{x:o.x,y:o.y,w:o.w,h:o.h,angle:o.angle},before:this._geometrySnapshot(),moved:!1},nl(t),!0}_bdMove(t){const e=this.host._bdDrag;if(!e)return;const s=this._svgPoint(t),i=e.base;if("move"===e.kind){const t=e.rect0.x,o=e.rect0.y,a=this._snap([t+(s[0]-e.sx),o+(s[1]-e.sy)]),n=Math.abs(a[0]-t)>1e-9||Math.abs(a[1]-o)>1e-9;if(!n&&!e.moved)return;return e.moved||=n,void this._bdApply((a[0]-i.x)/ol,(a[1]-i.y)/ol,e.p0.sx,e.p0.sy,e.p0.angle)}if("rotate"===e.kind){const i=e.rect0.x+e.rect0.w/2,o=e.rect0.y+e.rect0.h/2,a=180*Math.atan2(e.sy-o,e.sx-i)/Math.PI;let n=e.p0.angle+(180*Math.atan2(s[1]-o,s[0]-i)/Math.PI-a);t.shiftKey||(n=5*Math.round(n/5)),n=be(n);const r=Math.abs(n-e.p0.angle)>1e-9;if(!r&&!e.moved)return;return e.moved||=r,void this._bdApply(e.p0.dx,e.p0.dy,e.p0.sx,e.p0.sy,n)}const o=Se(e.rect0,e.sgx,e.sgy,s[0],s[1],!t.shiftKey,this.host._gridPitch,Math.min(i.w,i.h)*lt),a=o.w/Math.max(1e-9,i.w),n=o.h/Math.max(1e-9,i.h),r=Math.abs(a-e.p0.sx)>1e-9||Math.abs(n-e.p0.sy)>1e-9||Math.abs(o.x-e.rect0.x)>1e-9||Math.abs(o.y-e.rect0.y)>1e-9;if(!r&&!e.moved)return;e.moved||=r;const l=xe(o,e.p0.angle,t=>this._snap(t));this._bdApply((l[0]-i.x)/ol,(l[1]-i.y)/ol,a,n,e.p0.angle)}_bdReset(){const t=this.host._curSpaceCfg;if(!t)return;const e=this._geometrySnapshot();delete t.plan_x,delete t.plan_y,delete t.plan_scale,delete t.plan_scale_x,delete t.plan_scale_y,delete t.plan_angle,this.host._bdDrag=null,this._recordGeometry(this.host._t("history.backdrop_transform"),e),this._saveConfig(),this.host._showToast(this.host._t("decor.backdrop_reset_done")),this.host.requestUpdate()}_bdUp(){const t=this.host._bdDrag;this.host._bdDrag=null,t?.moved&&(this._recordGeometry(this.host._t("history.backdrop_transform"),t.before),this._saveConfig()),this.host.requestUpdate()}_renderBackdropFrame(t){const e=this.host._bdRect;if(!this.host._bdActive||!e)return a;const s=.02*Math.max(t.w,t.h),i=s/4,o=e.x+e.w/2,n=e.y+e.h/2,r=be(e.angle),l=2.2*s;return ce` + + + {t.stopPropagation(),t.preventDefault(),this._bdStart(t,void 0,!0)}}> + + ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([t,o,a])=>{const n=t<0?e.x:e.x+e.w,r=o<0?e.y:e.y+e.h;return ce`{e.stopPropagation(),e.preventDefault(),this._bdStart(e,[t,o])}}>`})} + `}_renderEditorGroupLauncher(t){return this.host._editorSecondary.renderGroupLauncher(t,this.host._editorToolbarGroups,this.host._editorSecondaryCopy)}_runEditorContext(t,e){this.host._editorSecondary.runContext(t,this.host._editorSecondaryContextId,e)}_renderEditorGroupModel(t){return this.host._editorSecondary.renderGroupModel(t,this.host._editorSecondaryContextId,this.host._editorSecondaryCopy)}_renderDrawWallControl(){const t="column"===this.host._tool?1:0;return o``}_renderPlanSecondary(){const t=this.host._editorSecondaryContextId,e=this.host._physicalSel;if(e){if(!("partition"===e.kind?!!this.host._curSpaceCfg.partitions?.some(t=>t.id===e.id):"column"===e.kind?!!this.host._curSpaceCfg.wall_columns?.some(t=>t.id===e.id):!!this.host._curSpaceCfg.room_drafts?.some(t=>t.id===e.id)))return null;const s="partition"===e.kind?this.host._t("markup.partition"):"column"===e.kind?this.host._t("markup.column"):this.host._t("markup.add");return{contextId:t,kind:"selection",ariaLabel:this.host._t("editor.context_actions",{object:s}),visibleLabel:s,content:o` + + `}}const s="draw"===this.host._tool||"column"===this.host._tool,i="column"===this.host._tool?"markup.hint_column":"resize"===this.host._tool?"markup.hint_resize":"wallthick"===this.host._tool?"markup.hint_wallthick":null,n="draw"===this.host._tool?this.host._t(this.host._path.length?"markup.hint_points":"markup.hint_start",this.host._path.length?{n:this.host._path.length}:void 0):"";if(!s&&!i&&!n)return null;const r="draw"===this.host._tool&&this.host._path.length>0;return{contextId:t,kind:r?"operation":"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t("draw"===this.host._tool?"markup.add":"column"===this.host._tool?"markup.column":"resize"===this.host._tool?"markup.resize":"markup.wallthick")}),content:o` + ${s?this._renderDrawWallControl():a} + ${n?o`${n}`:a} + ${i?o`${this.host._t(i)}`:a} + ${"draw"===this.host._tool&&this.host._path.length?o``:a}`}}_renderDecorSecondary(){const t=this.host._editorSecondaryContextId;if("furniture"===this.host._decorTool)return{contextId:t,kind:"palette",ariaLabel:this.host._t("editor.palette",{tool:this.host._t("decor.furniture")}),launcherId:"furniture",dismissPolicy:this.host._furnPalette?"stay-open-on-canvas":"outside",dismiss:()=>{"furniture"===this.host._decorTool&&(this.host._furnPalette=null,this.host._decorTool="select",this.host.requestUpdate())},content:this._renderFurnPalette()};const e=this.host._dtSel;if(e){const s=this.host._t(`decor.${e.kind}`);return{contextId:t,kind:"selection",ariaLabel:this.host._t("editor.context_actions",{object:s}),visibleLabel:s,content:o` + + `}}const s="line"===this.host._decorTool||"rect"===this.host._decorTool||"ellipse"===this.host._decorTool,i="rect"===this.host._decorTool||"ellipse"===this.host._decorTool,n="backdrop"===this.host._decorTool&&!!this.host._bdRect;return s||n?{contextId:t,kind:"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t(s?`decor.${this.host._decorTool}`:"decor.backdrop")}),content:o` + ${s?o` + this.host._decorStyle={...this.host._decorStyle,...t.detail}}> + + ${i?o` + this.host._decorStyle={...this.host._decorStyle,fillColor:t.detail.color,fillOpacity:t.detail.opacity}}>`:a} + `:a} + ${n?o`${this.host._t("decor.backdrop_hint")}`:a}`}:null}_withBackdropReset(t){if(!this.host._bdMoved||this.host._bdDrag||"palette"===t?.kind)return t;const e=this.host._editorSecondaryContextId,s=o``;return t?{...t,kind:"selection"===t.kind?"mixed":t.kind,content:o`${t.content}${s}`}:{contextId:e,kind:"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t("decor.backdrop")}),content:s}}_renderEditorSecondary(){if(!this.host._editing)return a;const t=this.host._editorSecondary.activeGroup(this.host._editorToolbarGroups),e=t?this._renderEditorGroupModel(t):"plan"===this.host._mode?this._renderPlanSecondary():"decor"===this.host._mode?this._withBackdropReset(this._renderDecorSecondary()):null;return this.host._editorSecondary.render(e,this.host._editorSecondaryDialogBlocked)}_renderDecorBar(){const t=[["select","mdi:cursor-default-outline","decor.select"],...this.host._bdRect?[["backdrop","mdi:image-move","decor.backdrop"]]:[],["line","mdi:vector-line","decor.line"],["rect","mdi:rectangle-outline","decor.rect"],["ellipse","mdi:ellipse-outline","decor.ellipse"],["text","mdi:format-text","decor.text"],["furniture","mdi:sofa-outline","decor.furniture"],["erase","mdi:eraser","decor.erase"]],e=this.host._geometryHistory.undoName,s=this.host._geometryHistory.redoName;return o`
+
+ ${t.map(([t,e,s])=>o``)} + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} + + +
+
+ +
+
`}_renderDecorEraseConfirm(){const t=this.host._decorEraseConfirm,e=this.host._t(`decor.${t.kind}`);return o`this.host._decorEraseConfirm=null}> +

${this.host._t("confirm.erase_decor",{kind:e})}

+
+ + + +
+
`}_renderDecorTextDialog(){const t=this.host._decorTextDialog,e=(t.pickerEntity||"").trim(),s=e?this.host.hass?.states?.[e]:null;return o`this.host._decorTextDialog=null}> +
+ + ${""} + + this.host._decorTextDialog={...t,...e.detail}}> + +
this.host._decorTextDialog={...t,sizeCm:this.host._decorTextCm(Number(e.target.value))}} /> + ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
+ + this.host._decorTextDialog={...t,angle:e.target.value}} /> + + + this.host._decorTextDialog={...t,pickerEntity:e.target.value}} /> + + ${Object.keys(this.host.hass?.states||{}).map(t=>o``)} + + ${e?o` + + + `:a} +
+
+ + + +
+
`}_renderDecorShapeDialog(){const t=this.host._decorShapeDialog,e="rect"===t.kind||"ellipse"===t.kind,s=this.host._t("decor."+t.kind),i=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return o`this.host._decorShapeDialog=null}> +
+ ${"furniture"===t.kind?o` + + `:a} + this.host._decorShapeDialog={...t,...e.detail}}> + +
this.host._decorShapeDialog={...t,widthCm:this.host._decorSmallCm(Number(e.target.value))}} />${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
+ ${"line"===t.kind?o` + +
+ + +
+ +
this.host._decorShapeDialog={...t,lengthCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ${i}
`:o` + +
this.host._decorShapeDialog={...t,sizeWCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ×this.host._decorShapeDialog={...t,sizeHCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ${i}
`} + + this.host._decorShapeDialog={...t,angle:e.target.value}} /> + ${e?o` + this.host._decorShapeDialog={...t,fillColor:e.detail.color,fillOpacity:e.detail.opacity}}>`:a} +
+
+ + + +
+
`}_renderBackdropDialog(){const t=this.host._backdropDialog,e=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return o`this.host._backdropDialog=null}> +
+ +
this.host._backdropDialog={...t,widthCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ×this.host._backdropDialog={...t,heightCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ${e}
+ + this.host._backdropDialog={...t,angle:e.target.value}} /> +
+
+ + +
+
`}_cssPxToRender(t){const e=this.host._stageEl,s=this.host._viewOr(this.host._baseVb());return e?.clientWidth&&e.clientHeight?Math.max(s.w/e.clientWidth,s.h/e.clientHeight)*t:this.host._gridPitch/8*t}_deleteRoomClick(t){const e=this.host._spaceModel();if(!e)return;const s=[...e.rooms].reverse().find(e=>this._pointInRoom(t,e));s?s.id&&(this.host._roomDeleteDialog={roomId:s.id,name:s.name}):this.host._showToast(this.host._t("toast.delete_room_pick"))}_wallThickHit(t){const e=this.host._spaceModel();if(!e)return null;const s=6*this.host._gridPitch,i=this.host._openCuts();let o=null;const a=(t,e,i)=>{e>s||(!o||e100)return void this._showPhysicalRange(100);if("room"!==e.source.kind){const t=this._geometrySnapshot();if("partition"===e.source.kind){const t=(s.partitions||[]).find(t=>t.id===e.source.id);if(!t)return;if(0===n&&$t(s.openings,{kind:"partition",id:t.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));t.cm=n}else{const t=(s.room_drafts||[]).find(t=>t.id===e.source.id),i=t?.segments?.[e.source.segment];if(!i)return;i.cm=n}this.host._wallDialog=null;return this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),t)&&this.host._showToast(this.host._t("toast.wallthick_set")),void this.host.requestUpdate()}const r=this._geometrySnapshot(),l=n>0?n:null;if(0===n){const i=.02*this.host._gridPitch,o=[e.a[0],e.a[1],e.b[0],e.b[1]],a=(s.rooms||[]).find(t=>t.id===e.roomId),n=new Set(t&&a&&Array.isArray(a.wall_ids)?a.wall_ids:(s.wall_segments||[]).filter(t=>{const e=[Number(t.a?.[0])*ol,Number(t.a?.[1])*ol],s=[Number(t.b?.[0])*ol,Number(t.b?.[1])*ol];return C(e,o)<=i&&C(s,o)<=i}).map(t=>String(t.id))),r=(s.openings||[]).some(t=>{if("partition"===t.host?.kind)return!1;if("wall"===t.host?.kind&&n.has(t.host.id))return!0;if(t.host)return!1;const e=[Number(t.x)*ol,Number(t.y)*ol];return e.every(Number.isFinite)&&C(e,o)<=i});if(r)return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"))}let h,c=this.host._openCuts();if(n>0&&c.length){const o=[];if(t&&e.roomId){const t=(s.rooms||[]).find(t=>t.id===e.roomId),a=new Set(Array.isArray(t?.wall_ids)?t.wall_ids:[]);for(const t of s.wall_segments||[])a.has(t.id)&&o.push([Number(t.a?.[0])*ol,Number(t.a?.[1])*ol,Number(t.b?.[0])*ol,Number(t.b?.[1])*ol]);if(!o.length){const t=i.rooms.find(t=>t.id===e.roomId),s=t?R(t):null;for(let t=0;s&&t!o.some(e=>C([t[0],t[1]],e)<=a&&C([t[2],t[3]],e)<=a&&C([e[0],e[1]],t)<=a&&C([e[2],e[3]],t)<=a))}h=t&&e.roomId?Fe(s.walls,i.rooms,e.roomId,l,this.host._wallKeyPitch,c,ol):E(s.walls,e.a,e.b,l,this.host._wallKeyPitch,ol),h=this.host._normalizeWalls(h,c);for(const t of s.wall_segments||[])t.cm=Q(h,t.a,t.b,I,1);h.length?s.walls=h:delete s.walls,this.host._wallDialog=null,this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),r)&&this.host._showToast(this.host._t(0===n?"toast.wallthick_cleared":"toast.wallthick_set")),this.host.requestUpdate()}_wallHatchDefs(t){if(!this.host._spaceWalls.length&&!this.host._physicalBodiesR().length&&!this.host._markup)return ce``;const e=Ne(this.host._cellCm);return ce` + + + + `}_renderWallThickUi(){const t=this.host._wallThickHover;return t&&t.d?ce``:ce``}_renderWallThickDialog(){const t=this.host._wallDialog;return t?o`
t.stopPropagation()}> +
+ + {this.host._wallDialog={...t,value:e.target.value}}} + @keydown=${t=>{"Enter"===t.key&&(t.preventDefault(),this._wallThickApply(!1))}} /> + ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")} +
+
+ ${"room"===t.source.kind?o``:a} + + +
+
`:o``}_openingAt(t){if(!this.host._openingsR.length)return null;const e=this.host._openingsR.flatMap(e=>{const s=e.angle*Math.PI/180,i=t[0]-e.rx,o=t[1]-e.ry,a=i*Math.cos(s)+o*Math.sin(s);return Math.abs(a)>e.rlen/2+ze(12,this.host._cellCm)?[]:[{o:e,localY:-i*Math.sin(s)+o*Math.cos(s)}]});if(!e.length)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i).value;return e.find(({o:t,localY:e})=>{const s="gate"===t.type?!t.flip_v:t.flip_v,i=t.partitionHost||this.host._spaceWalls.length||"gate"===t.type?this.host._openingFace(t,o,!!s):{ox:0,oy:0,cm:0,side:-1},a=Ae({type:t.type,length:t.rlen,angle:t.angle,amount:this.host._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,face:i});return Math.abs(e)<=a.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this.host._openingPreset;if("opening"!==this.host._tool||!e)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i),a=`${o.key}|partitions:${this.host._cfgEpoch}`;this.host._openingPlacementIntervalsCache&&this.host._openingPlacementIntervalsCache.key===a||(this.host._openingPlacementIntervalsCache={key:a,value:[...z(s.rooms,this.host._spaceWalls,i,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol),...Oe(s.partitions,this.host._cellCm,this.host._gridPitch)]}),this.host._openingDimensionContextCache&&this.host._openingDimensionContextCache.key===a||(this.host._openingDimensionContextCache={key:a,value:Wr({rooms:s.rooms,walls:this.host._spaceWalls,openCuts:i,partitions:s.partitions,roomOpenings:this.host._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(s),pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:ol,epsilon:2e-4*this.host._gridPitch})});const n=Le({pointer:[t[0],t[1]],preset:e,geometryRevision:this.host._cfgEpoch,renderedLength:this.host._cmToUnits(e.lengthCm),intervals:this.host._openingPlacementIntervalsCache.value,baseTolerance:1.5*this.host._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this.host._pointerModality.modality||"pen"===this.host._pointerModality.modality?10:6),gridStep:this.host._gridPitch});this.host._openingJambBlockCm=n.jambBlockedTarget?n.jambBlockedTarget.physicalHalfWidth/this.host._gridPitch*this.host._cellCm:null;const r=n.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let h;if(r.host){const t=F({id:"preview",type:r.type,x:r.x/ol,y:r.y/ol,angle:r.angle,length:r.renderedLength/ol,host:r.host},s.partitions,ol,this.host._cellCm,this.host._gridPitch).resolved;h=t?Ee(t,l):{ox:0,oy:0,cm:0,side:-1}}else h=Be(o.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const c="mi"===this.host.hass?.config?.unit_system?.length,d=Yr(r,this.host._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:ee(t.distance/this.host._gridPitch*this.host._cellCm,c),dimension:t}));return{...r,face:h,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingPreset=He(t,++this.host._openingPresetRevision),this.host._openingHoverCandidate=null,this.host._cursorPt=null)}_clearOpeningPlacement(t){this.host._openingHoverCandidate=null,this.host._openingJambBlockCm=null,t&&(this.host._openingPreset=null,this.host._openingRebindId=null)}_openingClick(t){const e=this.host._spaceModel();if(!e)return;const s=this.host._openingRebindId?null:this._openingAt(t);if(s)return void this._editOpening(s);const i=this.host._openingPreset;if(!i)return;const o=this.host._openingHoverCandidate,a=o&&Ge(o,[t[0],t[1]],i.revision,this.host._cfgEpoch)?o:this._resolveOpeningPlacement(t);if(!a){if(null!=this.host._openingJambBlockCm)return void this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:ee(this.host._openingJambBlockCm,this.host._imperial)}));const s=1.5*this.host._gridPitch,i=P(t,e.rooms,s);return i&&We(i.x,i.y,i.angle,this.host._openCuts(),s)?void this.host._showToast(this.host._t("toast.opening_on_zero_wall")):void this.host._showToast(this.host._t("toast.opening_no_wall"))}const n=this.host._openingRebindId?this.host._curSpaceCfg?.openings?.find(t=>t.id===this.host._openingRebindId):null;this.host._openingDialog={...n?{id:n.id,type:n.type,lengthCm:Math.round(n.length*ol/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:n.contact||"",lock:n.lock||"",invert:!!n.invert,flipH:!!n.flip_h,flipV:!!n.flip_v}:{type:a.type,lengthCm:a.lengthCm,contact:"",lock:"",invert:!1,flipH:a.flipH,flipV:a.flipV},...a.host?{host:a.host}:{},x:a.x,y:a.y,angle:a.angle},this.host._openingRebindId=null,this.host._openingHoverCandidate=null,this.host._cursorPt=null}_editOpening(t){this.host._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this.host._gridPitch*this.host._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.host._mode&&this.host._spaceModel()&&"resize"!==this.host._tool){t.preventDefault(),t.stopPropagation();try{nl(t)}catch{}this.host._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this.host._opDrag.sx)+Math.abs(t.clientY-this.host._opDrag.sy)<=3)return;const s=this.host._spaceModel();if(!s)return;const i=this._svgPoint(t),o=this.host._curSpaceCfg,a=o?.openings?.find(t=>t.id===e.id);if(!a)return;if("partition"===a.host?.kind){const t=s.partitions.find(t=>t.id===a.host.id);if(!t)return;const e=t.b[0]-t.a[0],o=t.b[1]-t.a[1],n=Math.hypot(e,o);if(!(n>1e-9))return;const r=e/n,l=o/n;if(Math.abs((i[0]-t.a[0])*l-(i[1]-t.a[1])*r)>4*this.host._gridPitch)return;const h=a.length*ol/2+L(t,this.host._cellCm,this.host._gridPitch);let c=(i[0]-t.a[0])*r+(i[1]-t.a[1])*l;if(c=Math.round(c/this.host._gridPitch)*this.host._gridPitch,c=Math.max(h,Math.min(n-h,c)),n<2*h-1e-9)return;const d=c/n,p=(t.a[0]+r*c)/ol,_=(t.a[1]+l*c)/this.host._spaceH;let u=180*Math.atan2(o,e)/Math.PI;u>=90?u-=180:u<-90&&(u+=180);const m=a.host.t!==d||a.x!==p||a.y!==_||a.angle!==u;return this.host._opDrag.moved=!0,m&&(this.host._opDrag.dirty=!0),a.host={...a.host,t:d},a.x=p,a.y=_,a.angle=u,this.host._opMeasure=null,m&&this.host._cfgEpoch++,void this.host.requestUpdate()}const n=P(i,s.rooms,4*this.host._gridPitch);if(!n)return;this.host._opDrag.moved=!0;const r=this._opRuler(n,a.length*ol);this.host._opMeasure=r.measure;const l=r.x/ol,h=r.y/this.host._spaceH,c=a.x!==l||a.y!==h||a.angle!==n.angle;if(c&&(this.host._opDrag.dirty=!0),a.x=l,a.y=h,a.angle=n.angle,Number(this.host._serverCfg?.model_version||0)>=9){const t=kr(a,o?.wall_segments||[]);t?a.host=t:delete a.host}c&&this.host._cfgEpoch++,this.host.requestUpdate()}_opRuler(t,e){const s=this.host._spaceModel()?.rooms||[],i=this.host._gridPitch/2;let o=t.x,a=t.y,n=je([o,a],t.angle,e,s,i);if(n&&n.centered&&(o!==n.wallCenter[0]||a!==n.wallCenter[1]))[o,a]=n.wallCenter,n=je([o,a],t.angle,e,s,i);else if(n){const[r,l]=n.wallA,[h,c]=n.wallB,d=h-r,p=c-l,_=Math.hypot(d,p);if(_>0){const h=this.host._gridPitch,c=Math.min(e/2,_/2);let u=Math.round(((o-r)*d+(a-l)*p)/_/h)*h;u=Math.max(c,Math.min(_-c,u)),o=r+u/_*d,a=l+u/_*p,n=je([o,a],t.angle,e,s,i)||n}}if(!n)return{x:o,y:a,angle:t.angle,measure:null};const r="mi"===this.host.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:ee(t/this.host._gridPitch*this.host._cellCm,r)});return{x:o,y:a,angle:t.angle,measure:{labels:[l(n.sideA,n.midA),l(n.sideB,n.midB)],guide:n.centered?{x:n.wallCenter[0],y:n.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;const s=this.host._opDrag,i=s.moved;this.host._opMeasure=null,i&&s.dirty&&this._commitPhysicalGeometry(this.host._t("history.move_opening"),s.before),i?window.setTimeout(()=>this.host._opDrag=null,0):this.host._opDrag=null}_opClick(t,e){"plan"===this.host._mode&&"resize"===this.host._tool||(t.stopPropagation(),this.host._opDrag?.moved||"plan"===this.host._mode&&this._editOpening(e))}_saveOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=this._geometrySnapshot(),o=this.host._spaceH,a=(e.openings||[]).find(e=>e.id===t.id),n={...a||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/ol,y:t.y/o,angle:t.angle,length:a&&!t.lengthTouched?a.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/ol,...t.host?{host:{...t.host}}:{}};if("partition"===n.host?.kind){const t=qe(a,n)?H(n,s.partitions,ol,this.host._cellCm,this.host._gridPitch):F(n,s.partitions,ol,this.host._cellCm,this.host._gridPitch);if(!t.resolved){const e=s.partitions.find(t=>t.id===n.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=L(e,this.host._cellCm,this.host._gridPitch);this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:ee(t/this.host._gridPitch*this.host._cellCm,this.host._imperial)}))}else this.host._showToast(this.host._t("opening.partition_orphan"));return}const i=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===n.id)return[];const e=F(t,s.partitions,ol,this.host._cellCm,this.host._gridPitch).resolved;return e?[e]:[]});if(Ue(t.resolved,i))return void this.host._showToast(this.host._t("toast.opening_no_wall"));Object.assign(n,N(n,t.resolved,ol))}else if(Number(this.host._serverCfg?.model_version||0)>=9){const t=kr(n,e.wall_segments||[]);if(!t)return void this.host._showToast(this.host._t("toast.opening_no_wall"));n.host=t}else delete n.host;"passage"===t.type?(delete n.contact,delete n.lock,delete n.invert,delete n.flip_h,delete n.flip_v):(n.contact=t.contact||null,n.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,n.invert=t.invert||void 0,n.flip_h="gate"!==t.type&&t.flipH||void 0,n.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===n.id);r>=0?e.openings[r]=n:e.openings.push(n),this._commitPhysicalGeometry(this.host._t(t.id?"history.edit_opening":"history.add_opening"),i),this.host._openingDialog=null,this.host.requestUpdate()}_deleteOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg;if(!t?.id||!e?.openings)return;const s=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this.host._t("history.delete_opening"),s),this.host._openingDialog=null,this.host.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.host.hass.states)){if(!this.host._openingEntityAvailable(e))continue;const s=e.split(".")[0];if("binary_sensor"!==s&&"cover"!==s)continue;const i=this.host.hass.states[e],o=["door","window","opening","garage_door","garage"].includes(i?.attributes?.device_class||"");("cover"!==s||o)&&t.push([e,i?.attributes?.friendly_name||e,o?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.host.hass.states).filter(t=>t.startsWith("lock.")&&this.host._openingEntityAvailable(t)).map(t=>({value:t,label:this.host.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this.host._openingDialog;if(!e)return;const s="contact"===t?!e.contactOpen:!e.lockOpen;this.host._openingDialog={...e,contactOpen:"contact"===t&&s,lockOpen:"lock"===t&&s}}_filterOpeningEntities(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contactFilter:e}:{...s,lockFilter:e})}_selectOpeningEntity(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contact:e,contactOpen:!1,contactFilter:""}:{...s,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms,i=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;const o=i.id;if(!this.host._mergeSel||this.host._mergeSel===o)return void(this.host._mergeSel=this.host._mergeSel===o?null:o);const a=s.find(t=>t.id===this.host._mergeSel),n=a?R(a):null,r=R(i),l=n&&r?Ke(n,r):null;if(!l)return this.host._showToast(this.host._t("toast.merge_not_adjacent")),void(this.host._mergeSel=null);this.host._mergeDialog={aId:this.host._mergeSel,bId:o,poly:l,pick:"a"},this.host._mergeSel=null}_commitMerge(){const t=this.host._mergeDialog,e=this.host._curSpaceCfg;if(!t||!e||!this.host._spaceModel())return;const s=this._geometrySnapshot(),i=this.host._spaceH,o="a"===t.pick?t.aId:t.bId,a="a"===t.pick?t.bId:t.aId,n=e.rooms.find(t=>t.id===o);if(!n)return void(this.host._mergeDialog=null);n.poly=t.poly.map(t=>[t[0]/ol,t[1]/i]),delete n.x,delete n.y,delete n.w,delete n.h,e.rooms=e.rooms.filter(t=>t.id!==a);const r=this._commitPhysicalGeometry(this.host._t("history.merge_rooms"),s);this.host._mergeDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),r&&this.host._showToast(this.host._t("toast.rooms_merged",{name:n.name||""}))}_splitClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms;if(!this.host._splitSel){const e=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this.host._splitSel={roomId:e.id,pts:[]})}const i=s.find(t=>t.id===this.host._splitSel.roomId),o=i?R(i):null;if(!i||!o)return void(this.host._splitSel=null);const a=.02*this.host._gridPitch,n=6*this.host._gridPitch,r=Ve(t,o),l=r&&Je(r,o,this.host._gridPitch)||r,h=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=n?l:null,c=!!h&&Ye(h,o,a),d=this.host._splitSel.pts;if(!d.length)return c?void(this.host._splitSel={...this.host._splitSel,pts:[h]}):void this.host._showToast(this.host._t("toast.split_pick_wall"));if(!c){const e=this._snap(t);return qt(e,o,a)?void(this.host._splitSel={...this.host._splitSel,pts:[...d,e]}):void this.host._showToast(this.host._t("toast.split_pick_inside"))}const p=Kt(o,[...d,h],a);if(!p)return void this.host._showToast(this.host._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[_,u]=p,m=k(_)>=k(u)?_:u,g=m===_?u:_;this.host._pendingSplit={roomId:i.id,mainPoly:m,newPoly:g},this.host._cursorPt=null,this.host._nameSel="",this.host._areaSel="",this.host._roomDialog=!0}_markupMove(t){if(!this.host._markup)return;if("column"===this.host._tool)return void(this.host._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this.host._tool||"wallthick"===this.host._tool)return void(this.host._cursorPt=this._svgPoint(t));const e="draw"===this.host._tool&&!this.host._contourClosed,s="split"===this.host._tool&&!!this.host._splitSel?.pts?.length;if(!e&&!s)return;const i=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(i,t.shiftKey);return this.host._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this.host._path.length?void(this.host._cursorPt=e.point):void this._syncPlanSnapActiveMarker(e.candidate)}this.host._cursorPt=this._snap(i)}_saveRoom(){(this.host._areaSel||this.host._nameSel.trim())&&(this.host._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this.host._wallFaceBatch;if(!e)return;const s=e.candidates[e.index];if(!s)return;if(!t&&(s.existing||s.repair)&&1===e.candidates.length)return this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate();const i=t?{candidate:s,create:!0,name:this.host._nameSel.trim(),area:this.host._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:s,create:!1},o=[...e.decisions,i],a=e.index+1;if(a"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,o=.02*this.host._gridPitch,a=this.host._spaceModel();if(!a)return A;for(const e of this._planSnapGeometrySnapshot().value.segments){if("room"===e.sourceKind||C(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>o)continue;if("partition"===e.sourceKind)return i(a.partitions.find(t=>t.id===e.sourceId)?.cm)??A;const s=e.sourceId.lastIndexOf(":"),n=s>=0?e.sourceId.slice(0,s):e.sourceId,r=s>=0?Number(e.sourceId.slice(s+1)):-1;return i(a.room_drafts.find(t=>t.id===n)?.segments[r]?.cm)??A}const n=Ra(Math.max(0,e.length-1),s,this.host._drawWallCm,A);for(let s=0;s+1[...t]);if(!e?.sourceKey.startsWith("active:"))return s;const i=/:(\d+)$/.exec(e.sourceKey),o=i?Number(i[1])+("b"===e.endpoint?1:0):-1;return o>=0&&oe.key===t.sourceKey),a=i.find(e=>e.key===t.targetSourceKey);if(!o||!a)return!1;const n="a"===t.endpoint?o.a:o.b;return!(Math.hypot(n[0]-t.from[0],n[1]-t.from[1])>s)&&(!(C(t.to,[a.a[0],a.a[1],a.b[0],a.b[1]])>s)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const s=t.sourceKey.slice(17).split("|")[0];return!!s&&e.some(t=>"partition"===t.host?.kind&&t.host.id===s)}(t,this.host._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const s=this.host._curSpaceCfg;if(!s||!this._validateWallRepair(t,e.activePath))return!1;const i=e=>{e[0]=t.to[0]/ol,e[1]=t.to[1]/ol};if(t.sourceKey.startsWith("active:")){const o=/:(\d+)$/.exec(t.sourceKey),a=o?Number(o[1])+("b"===t.endpoint?1:0):-1;if(a<0||a>=e.activePath.length)return!1;e.activePath[a]=[...t.to];const n=(s.room_drafts||[]).find(t=>t.id===e.activeDraftId);return n?.points?.[a]&&i(n.points[a]),!0}if(!t.sourceKey.startsWith("static:"))return!1;const[o,a]=t.sourceKey.slice(7).split("|");if("partition"===o){const e=(s.partitions||[]).find(t=>t.id===a);if(!e)return!1;const o=[e.a[0]*ol,e.a[1]*ol],n=[e.b[0]*ol,e.b[1]*ol],r=Math.hypot(o[0]-t.from[0],o[1]-t.from[1])<=2e-4*this.host._gridPitch?e.a:Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this.host._gridPitch?e.b:null;return!!r&&(i(r),!0)}if("draft"===o){const e=a.lastIndexOf(":"),o=e>=0?a.slice(0,e):"",n=e>=0?Number(a.slice(e+1)):-1,r=(s.room_drafts||[]).find(t=>t.id===o);if(!r?.points?.[n]||!r?.points?.[n+1])return!1;const l=[n,n+1].find(e=>Math.hypot(r.points[e][0]*ol-t.from[0],r.points[e][1]*ol-t.from[1])<=2e-4*this.host._gridPitch);return null!=l&&(i(r.points[l]),!0)}return!1}_applyWallFaceBatch(){const t=this.host._wallFaceBatch,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=(t,e)=>{this.host._showToast(this.host._t(t,e)),this._roomDialogCancel()},o=t.decisions.filter(t=>t.create),a=o.map(t=>t.candidate.ring),n=s.rooms;for(let t=0;ts.id!==e&&!!R(s)&&$(a[t],R(s)));if(s)return void i("toast.room_overlap",{name:s.name||""})}if((e.rooms||[]).length+o.length>400)return void i("toast.physical_limit");if(o.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void i("toast.contour_cannot_close");const r=o.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void i("toast.wall_repair_changed");const l=this._activePathWithRepair(t.activePath,r[0]),h=2e-4*this.host._gridPitch,c=new Map;for(let e=0;et.candidate.atomKeys)),e=o.some(t=>t.candidate.consumeAllActive);for(const s of tn(this._wallGraphSources(l),h)){const i=s.sourceKeys.find(t=>c.has(t));!i||e||t.has(s.key)||d.push({a:s.a,b:s.b,cm:c.get(i)})}}else d.push(...Fa(l,Ra(l.length-1,t.activeCms,this.host._drawWallCm,A)));if((e.partitions||[]).length+d.length>al)return void i("toast.physical_limit");const p=o.map(t=>t.candidate.ring.map(()=>"")),_=t.activeDraftId?(e.room_drafts||[]).find(e=>e.id===t.activeDraftId):null,u=this._draftSegmentsForPath(t.activePath,_,t.activeCms),m=(t,e)=>{const s=`${t[0].toFixed(9)},${t[1].toFixed(9)}`,i=`${e[0].toFixed(9)},${e[1].toFixed(9)}`;return s<=i?`${s}|${i}`:`${i}|${s}`};for(let e=0;et.candidate.ring.forEach((s,i)=>{const o=t.candidate.ring[(i+1)%t.candidate.ring.length];C(s,n)<=h&&C(o,n)<=h&&r.push({kind:"room",owner:e,edge:i,a:s,b:o})})),d.forEach((t,e)=>{C(t.a,n)<=h&&C(t.b,n)<=h&&r.push({kind:"partition",owner:e,edge:0,a:t.a,b:t.b})});const l=[(i[0]+a[0])/2,(i[1]+a[1])/2];r.sort((t,e)=>{const s=[t.a[0],t.a[1],t.b[0],t.b[1]],o=[e.a[0],e.a[1],e.b[0],e.b[1]];return(C(l,s)<=h?0:1)-(C(l,o)<=h?0:1)||(C(i,s)<=h?0:1)-(C(i,o)<=h?0:1)||m(t.a,t.b).localeCompare(m(e.a,e.b))});const c=r[0];if(!c)continue;const _=m(c.a,c.b);for(const t of r)m(t.a,t.b)===_&&("room"===t.kind?p[t.owner][t.edge]=s:d[t.owner].id=s)}const g=this._geometrySnapshot();if(r[0]&&!this._applyWallRepair(r[0],t))return void i("toast.wall_repair_changed");const f=o.some(t=>!!t.candidate.split),b=f?kt(s.rooms,e.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol):null,y=f&&Array.isArray(e.walls)?e.walls:null;for(const t of o){const s=t.candidate.split;if(!s)continue;const o=e.rooms.find(t=>t.id===s.roomId);if(!o)return void i("toast.contour_cannot_close");o.poly=s.mainPoly.map(t=>[t[0]/ol,t[1]/this.host._spaceH]),delete o.x,delete o.y,delete o.w,delete o.h}const v=Date.now().toString(36),w=[];if(o.forEach((t,s)=>{const i=t.area?this.host.hass.areas[t.area]?.name:"",o={id:`r${v}-${s}`,name:t.name||i||this.host._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/ol,t[1]/this.host._spaceH]),...p[s].some(Boolean)?{wall_ids:p[s]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(o),w.push({room:o,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,s)=>e.partitions.push({id:t.id||`partition-${v}-${s}`,a:[t.a[0]/ol,t.a[1]/ol],b:[t.b[0]/ol,t.b[1]/ol],cm:t.cm}))),f){const t=this.host._normalizeWalls(b,this.host._openCuts());t.length?e.walls=t:y?.length?e.walls=y:delete e.walls}if(w.length){this.host._cfgEpoch++;const s=this.host._openCuts(),i=this.host._spaceModel();if(!i)return;let o=e.walls;for(const{room:e,decision:a}of w){const n=a.candidate.ring,r=this._wallSourceCmAt(n[0],t.activePath,t.activeCms);o=Xe(o,i.rooms,e.id,r,this.host._wallKeyPitch,s,ol);for(const a of z(i.rooms,o,s,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol)){if(a.roomId!==e.id||"outer"!==a.kind)continue;const s=[(a.a[0]+a.b[0])/2,(a.a[1]+a.b[1])/2];o=E(o,a.a,a.b,this._wallSourceCmAt(s,t.activePath,t.activeCms),this.host._wallKeyPitch,ol)}}const a=this.host._normalizeWalls(o,s);a.length?e.walls=a:delete e.walls}if(!this._commitPhysicalGeometry(this.host._t("history.wall_face_batch"),g))return;delete this.host._resumeDraftBySpace[this.host._space],this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices();const x=new Set(o.map(t=>t.area).filter(t=>!!t));if(x.size){const t={...this.host._layout};for(const e of this.host._devices){if(!x.has(e.area||"")||e.space!==this.host._space)continue;if(this.host._layout[e.id])continue;const s=this.host._defPos[e.id];s&&(t[e.id]={s:this.host._space,x:s.x/ol,y:s.y/ol},this.host._dirtyPos.add(e.id))}this.host._layout=t,this.host._persistLayout()}this.host._showToast(this.host._t(o.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:o.length}))}_commitRoom(){const t=this.host._curSpaceCfg,e=this.host._spaceModel();if(!t||!e)return;const s=this._geometrySnapshot(),i=this.host._spaceH,o=!!this.host._pendingSplit,a=o?kt(e.rooms,t.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol):null,n=o&&Array.isArray(t.walls)?t.walls:null;let r;if(this.host._pendingSplit){const e=t.rooms.find(t=>t.id===this.host._pendingSplit.roomId);if(!e)return this.host._pendingSplit=null,this.host._splitSel=null,void(this.host._roomDialog=!1);e.poly=this.host._pendingSplit.mainPoly.map(t=>[t[0]/ol,t[1]/i]),delete e.x,delete e.y,delete e.w,delete e.h,r=this.host._pendingSplit.newPoly}else{if(!this.host._contourClosed)return;r=this.host._path.slice(0,-1)}const l=this.host._areaSel?this.host.hass.areas[this.host._areaSel]?.name:"",h={id:"r"+Date.now().toString(36),name:this.host._nameSel||l||this.host._t("room.default_name"),area:this.host._areaSel||null,poly:r.map(t=>[t[0]/ol,t[1]/i]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(!o&&this.host._activeDraftId){const e=Array.isArray(t.room_drafts)?t.room_drafts.find(t=>t.id===this.host._activeDraftId):null,s=Ra(r.length,[...this.host._draftSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,A),i=this._draftSegmentsForPath(this.host._path,e,s);i.length===r.length&&i.every(t=>!!t.id)&&(h.wall_ids=i.map(t=>t.id))}if(t.rooms.push(h),!o&&this.host._activeDraftId&&Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),o){const e=this.host._normalizeWalls(a,this.host._openCuts());e.length?t.walls=e:n?.length?t.walls=n:delete t.walls}if(!o){const e=Ra(r.length,[...this.host._draftSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,A),s=e[0];if(null!=s){this.host._cfgEpoch++;const i=this.host._openCuts(),o=this.host._spaceModel();if(!o)return;let a=Xe(t.walls,o.rooms,h.id,s,this.host._wallKeyPitch,i,ol);for(const t of z(o.rooms,a,i,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol)){if(t.roomId!==h.id||"outer"!==t.kind)continue;const s=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],i=r.findIndex((t,e)=>{const i=r[(e+1)%r.length];return C(s,[t[0],t[1],i[0],i[1]])<=.02*this.host._gridPitch});i>=0&&(a=E(a,t.a,t.b,e[i],this.host._wallKeyPitch,ol))}a=this.host._normalizeWalls(a,i),a.length?t.walls=a:delete t.walls}}const c=this._commitPhysicalGeometry(this.host._t(o?"history.split_room":"history.add_room"),s);this.host._path=[],delete this.host._resumeDraftBySpace[this.host._space],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this.host._pendingSplit=null,this.host._splitSel=null;const d=this.host._areaSel;if(this.host._areaSel="",this.host._nameSel="",this.host._roomDialog=!1,this.host._regSignature="",this.host._maybeRebuildDevices(),!c)return;let p=0;if(d){const t=ol,e={...this.host._layout};for(const s of this.host._devices){if(s.area!==d||s.space!==this.host._space)continue;if(p++,this.host._layout[s.id])continue;const i=this.host._defPos[s.id];i&&(e[s.id]={s:this.host._space,x:i.x/ol,y:i.y/t},this.host._dirtyPos.add(s.id))}this.host._layout=e,this.host._persistLayout()}const _=this.host._model.find(t=>t.id===this.host._space)?.rooms.length||0;this.host._showToast(d?this.host._t("toast.room_saved",{n:_,added:p}):this.host._t("toast.room_saved_no_area",{n:_}))}_cancelPath(){this.host._wallRepairDiagnostic=null,this.host._activeDraftId&&(this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId),this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),this.host._roomDialog=!1,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._splitSel=null,this.host._mergeSel=null,this.host._mergeDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this._clearOpeningPlacement(!0)}_resumeLastDraft(){const t=this.host._resumeDraftBySpace[this.host._space];if(!t)return;const e=this.host._spaceModel()?.room_drafts.find(e=>e.id===t);e?(this.host._activeDraftId=t,this.host._path=e.points.map(t=>[...t]),this.host._draftSegmentCms=this._adoptDraftCms(this.host._path,e.segments.map(t=>t.cm),e.id),this._clearPlanSnapHover()):delete this.host._resumeDraftBySpace[this.host._space]}_roomDialogCancel(){if(this.host._roomDialog=!1,this.host._roomEditId)return this.host._roomEditId=null,this.host._nameSel="",void(this.host._areaSel="");if(this.host._wallFaceBatch){const t=this.host._wallFaceBatch;return this.host._wallFaceBatch=null,this.host._path=t.activePath.map(t=>[...t]),this.host._draftSegmentCms=[...t.activeCms],this.host._activeDraftId=t.activeDraftId,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate()}if(this.host._pendingSplit)return this.host._pendingSplit=null,void(this.host._splitSel=null);this.host._undoPoint()}_openDeviceInbox(){this.host._deviceInboxReturn=null,this.host._deviceInbox=this.host._deviceInbox||{tab:"on_plan",search:"",showEntities:!1,onlyNew:!1,limit:100}}_closeMarkerDialog(){if(this.host._markerDialog=null,this.host._deviceInboxReturn){const t={...this.host._deviceInboxReturn};this.host._deviceInbox=t,this.host._deviceInboxReturn=null,t.anchor&&this.host.updateComplete.then(()=>requestAnimationFrame(()=>{const e=`.device-inbox-row[data-binding="${CSS.escape(t.anchor)}"]`;this.host.renderRoot.querySelector(e)?.scrollIntoView({block:"nearest"})}))}}_deviceInboxCandidates(t){return ca({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:t,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}})}_deviceInboxRows(){const t=this.host._deviceInbox||this.host._deviceInboxReturn,e=!!t?.showEntities,s=[this.host._haRegistry.revision,this.host._cfgRev,this.host._cfgEpoch,this.host._regSignature,this.host._newSyncKey,e?1:0,this.host._showAll?1:0,d(this.host.hass,this.host._config?.language)].join("|");if(this.host._deviceInboxMemo?.key===s)return this.host._deviceInboxMemo.rows;const i=this._deviceInboxCandidates(e),o=new Set(i.map(t=>t.value));for(const t of this.host._markers)t.binding&&"virtual"!==t.binding&&o.add(t.binding);for(const t of this.host._devices)t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&o.add(`${t.bindingKind}:${t.bindingRef}`);const a=new Map;for(const t of o)a.set(t,this.host._bindingStatus(t));const n=this.host._areaToSpace,r={};for(const[t,e]of Object.entries(this.host.hass?.areas||{}))r[t]=n[t]?.room?.name||e?.name||t;for(const[t,e]of Object.entries(n))r[t]=e.room.name||r[t]||t;const l=Object.fromEntries(this.host._model.map(t=>[t.id,t.title])),h=Object.fromEntries(Object.entries(n).map(([t,e])=>[t,e.space])),c={},p=new Map;for(const[t,e]of Object.entries(this.host._fullRegistryHass.entities||{})){const s=String(e?.platform||"").trim();if(s&&(c[`entity:${t}`]=s),s&&e?.device_id){const t=p.get(e.device_id)||new Set;t.add(s),p.set(e.device_id,t)}}for(const[t,e]of p)c[`device:${t}`]=[...e].sort().join(", ");const _={};for(const[t,e]of Object.entries(this.host._fullRegistryHass.devices||{})){const s=`device:${t}`,i=p.get(t)||new Set,o=Array.isArray(e?.identifiers?.[0])?String(e.identifiers[0][0]||""):"",a=[o,...i].some(t=>this.host._excluded.has(t));"service"===e?.entry_type?_[s]="service_entry":a?_[s]="excluded_integration":"Group"===e?.model?_[s]="grouped_light":/scene/i.test(e?.model||"")?_[s]="excluded_domain":(/bridge/i.test(`${e?.model||""}${e?.name||""}`)||"myheat"===o&&e?.via_device_id)&&(_[s]="represented_by_parent")}const u=function(t){const{devices:e,markers:s,candidates:i,statuses:o,newDeviceIds:a,showHiddenOnPlan:n,areaNames:r={},spaceNames:l={},spaceByArea:h={},integrationByBinding:c={},reasonByBinding:d={}}=t,p=new Map;for(const t of e)!t.virtual&&t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&p.set(`${t.bindingKind}:${t.bindingRef}`,t);const _=new Map,u=new Map;for(const t of s)t?.binding&&"virtual"!==t.binding&&(t.removed?u.set(t.binding,t):_.set(t.binding,t));const m=new Map(i.map(t=>[t.value,t])),g=new Set([...p.keys(),..._.keys(),...m.keys(),...[...u.keys()].filter(t=>m.has(t))]),f=[];for(const t of g){const e=p.get(t),s=_.get(t),i=s?void 0:u.get(t),g=m.get(t);let b;if(i&&g)b="readd";else if(!0===s?.hidden)b="hidden";else if(e||s)b="on_plan";else{if(!g)continue;b="available"}const y=e?.bindingStatus||o.get(t)||da,v=s||i,$=pa(t),w=e?.area||g?.areaId||v?.area||"",k=e?.space||v?.space||h[w]||"",x=e?.name||v?.name||g?.label||t,S=e?.model||v?.model||g?.model||"",M=!!g?.parentDeviceId&&p.has(`device:${g.parentDeviceId}`),D="readd"===b?"removed":"hidden"===b?s&&_a(s)?d[t]||"automatic_hidden":"manual_hidden":"on_plan"===b?s?"visible_explicit":"visible_auto":d[t]||(M?"represented_by_parent":w&&k?"available":"no_bound_room"),C=!!e&&(!e.hidden||n),P="active"===y.kind,I=C&&(P||"ha_disabled"===y.kind&&n),T=[x,S,c[t],r[w],l[k],t,g?.sub].filter(Boolean).join(" ").toLocaleLowerCase();f.push({key:t,binding:t,category:b,status:y,reason:D,deviceId:e?.id,markerId:v?.id,name:x,icon:e?.icon||v?.icon||("entity"===$?"mdi:code-braces":"mdi:devices"),model:S,integration:c[t]||"",areaId:w,areaName:r[w]||"",spaceId:k,spaceName:l[k]||"",kind:$,isNew:!!e&&a.has(e.id),searchText:T,canFind:I,canEdit:!!e||!!s,canHide:"on_plan"===b&&P,canShow:"hidden"===b&&P,canAdd:("available"===b||"readd"===b)&&P})}const b=t=>"active"===t.status.kind?1:0;return f.sort((t,e)=>t.category.localeCompare(e.category)||Number(e.isNew)-Number(t.isNew)||b(t)-b(e)||t.name.localeCompare(e.name)||t.binding.localeCompare(e.binding))}({devices:this.host._devices,markers:this.host._markers,candidates:i,statuses:a,newDeviceIds:this.host._newIds,showHiddenOnPlan:this.host._showAll,areaNames:r,spaceNames:l,spaceByArea:h,integrationByBinding:c,reasonByBinding:_});return this.host._deviceInboxMemo={key:s,rows:u},u}_deviceForInboxRow(t){const e=t.deviceId?this.host._devices.find(e=>e.id===t.deviceId):null;if(e)return e;const s=t.markerId?this.host._markers.find(e=>e.id===t.markerId):null;return!s||s.removed?null:{id:s.id,name:t.name,model:t.model,area:t.areaId,space:t.spaceId||this.host._space,hidden:!0===s.hidden||"ha_disabled"===t.status.kind,userHidden:!0===s.hidden,bindingStatus:t.status,icon:t.icon,entities:"active"===t.status.kind?t.status.enabledEntityIds:[],allEntities:t.status.allEntityIds,primary:"active"===t.status.kind?t.status.enabledEntityIds[0]:void 0,marker:s,bindingKind:t.kind,bindingRef:t.binding.slice(t.binding.indexOf(":")+1),pdfs:s.pdfs||[]}}_openInboxMarker(t,e=!1){const s=this.host._deviceInbox;if(s){if(this.host._deviceInboxReturn={...s,anchor:t.key},this.host._deviceInbox=null,!e){const e=this._deviceForInboxRow(t);return void(e?this._openMarkerDialog(e):this._closeMarkerDialog())}this._openMarkerDialog(),this.host._markerDialog?this.host._markerDialog={...this.host._markerDialog,bindingMode:"ha",binding:t.binding,bindingOpen:!1,showEntities:"entity"===t.kind,name:""}:this._closeMarkerDialog()}}async _setInboxHidden(t,e){const s=this.host._deviceInbox,i=this.host._serverCfg;if(!s||!i||s.busy||"active"!==t.status.kind)return;const o=i.markers||[],a=o.find(e=>!e.removed&&e.binding===t.binding);if(!e&&!a)return;const n=a?.id||Ze(t.binding,t.markerId,()=>`m_${Date.now().toString(36)}`),r=a?{...a,hidden:e}:{id:n,binding:t.binding,hidden:!0};i.markers=[...o.filter(e=>e.id!==n&&(e.binding!==t.binding||!0===e.removed)),r],this.host._deviceInbox={...s,busy:t.key,anchor:t.key};try{await this._saveConfigNow(),this.host._regSignature="",this.host._deviceInboxMemo=null,this.host._maybeRebuildDevices(),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("device_inbox.saved"))}catch(t){this.host._serverCfg===i&&(i.markers=o),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_findInboxDevice(t){if(!t.canFind)return;const e=this._deviceForInboxRow(t);if(!e)return;if(this.host._deviceInbox=null,e.space&&e.space!==this.host._space){if(!this.host._commitSpace(e.space))return;this.host._restoreZoom()}const s=()=>{const t=this.host._devices.find(t=>t.id===e.id)||e,s=this.host._pos(t);this.host._applyView(this.host._zoom,s.x,s.y),this.host._selId=t.id,this.host.requestUpdate(),window.setTimeout(()=>{this.host._selId===t.id&&(this.host._selId=null,this.host.requestUpdate())},1500)};requestAnimationFrame(()=>requestAnimationFrame(s))}_openMarkerDialog(t){if(this.host._vacAllCamerasFor=null,this.host._vacAllCameraCache=null,t&&this.host._ackNewDevice(t.id),this.host._norm)if(t){const e=t.marker,s=Object.prototype.hasOwnProperty.call(e||{},"is_light"),i=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),o=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),a=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),n=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),r=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),h=Qe(e?.glow_color),c=this.host._devicePresentation(t,!0).valueBadge,d=ts(this.host._planHass,t,this.host._devices),p=es(this.host._planHass,t,d);this.host._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.host._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:os(t.marker?.display),rippleColor:l(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:is(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:n,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:ss(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:s,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:i,originalLightEntity:e?.light_entity,glowMode:null!=h?.bri?"fixed":h?"color":"auto",glowColor:h?.c||this.host._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(h?.bri??1))),glowColorDrafted:!!h,glowBrightnessDrafted:null!=h?.bri,glowTouched:!1,originalHasGlowColor:o&&(!!h||null===e?.glow_color),originalGlowColor:h||(null===e?.glow_color?null:void 0),valueBadgeEnabled:a?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||p,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:a,originalValueBadge:e?.value_badge,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this.host._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.host._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.host._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.host._showToast(this.host._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of as)for(const[s,i]of Object.entries(this.host.hass.states))s.startsWith(e+".")&&this.host._planEntityAvailable(s)&&t.push({value:s,label:i?.attributes?.friendly_name||s,sub:this.host._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=ca({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:!!this.host._markerDialog?.showEntities,currentBinding:this.host._markerDialog?.binding,currentDeviceId:this.host._markerDialog?.devId,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}}),e=(this.host._markerDialog?.bindingFilter||"").toLowerCase().trim(),s=e?t.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(e)):t;return s.sort((t,e)=>t.label.localeCompare(e.label)),s.slice(0,200)}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,s=this.host._t(t);if(s!==t)return s}return this.host._errText(t)}async _pickMarkerFiles(t){const e=t.target,s=e.files?[...e.files]:[];if(e.value="",!s.length||!this.host._markerDialog)return;const i=this.host._markerDialog.uploadId||this.host._markerDialog.devId||"new",o=[];for(const t of s)try{const e=new FormData;e.append("marker_id",i),e.append("file",t,t.name);const s=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}),a=await s.json().catch(()=>({}));if(!s.ok||a.error){const t={too_large:this.host._t("err.too_large",{mb:a.max_mb||50}),bad_ext:this.host._t("err.bad_ext"),unauthorized:this.host._t("err.unauthorized")};throw new Error(t[a.error]||a.error||"HTTP "+s.status)}o.push({name:a.name||t.name,url:a.url})}catch(e){this.host._showToast(this.host._t("toast.file_failed",{name:t.name,err:this.host._errText(e)}))}o.length&&this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:[...this.host._markerDialog.pdfs,...o]},this.host._showToast(this.host._t("toast.files_attached",{n:o.length})))}_removeMarkerPdf(t){this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:this.host._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 s={c:l(t.glowColor,this.host._fillColors.glow_light.c)};"fixed"===t.glowMode&&(s.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=s}}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.host._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.host._showToast(this.host._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this.host._showToast(this.host._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this.host._showToast(this.host._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this.host._bindingStatus(t.binding),s=t.devId?this.host._markers.find(e=>e.id===t.devId):null,i=!s||s.binding!==t.binding;if("active"!==e.kind&&i)return void this.host._showToast(this.host._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===s?.hidden&&!t.hideFromPlan)return this.host._markerDialog={...t,hideFromPlan:!0},void this.host._showToast(this.host._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const s=this.host._serverCfg;if(!s)return;const i=s.markers||[],o=ns(t.room);let a=o?.space||null;const n=o?.area||null,r=o?.roomId||null,l=Ze(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),h=t.devId,c=h?this.host._devices.find(t=>t.id===h):null,d=o?.space||c?.space||null,p=d?this.host._spaceModelById(d):this.host._spaceModel();if(!p)return;const _=p.id;"virtual"!==t.binding||a||(a=_),this.host._markerDialog={...t,busy:!0};try{const o="virtual"===t.binding?[]:i.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=o.length>0,u=ss(t.binding,t.controls,this.host._bindingEntities(t.binding)),m=i.find(t=>t.id===l||t.id===h)?.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:u.length?u:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=sl(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._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=a,g.area=n,g.room_id=r);const f=c?.marker?.room_id??null,b=!!t.room&&null!=c&&(c.space!==a||c.area!==n||f!==r);let y=!1;const v=t.uploadId||h;if(v&&v!==l&&g.pdfs?.length)try{const t=await this.host.hass.callWS({type:"houseplan/files/migrate",from_id:v,to_id:l}),e=t?.mapping||{};g.pdfs=rs(g.pdfs,v,l,e),y=Object.keys(e).length>0}catch(t){this.host._showToast(this.host._t("toast.files_migrate_failed",{err:this.host._errText(t)}))}s.markers=i,h&&h!==l&&(s.markers=ls(s.markers,h,l)),h&&h!==l&&"derived_marker_state"===g.value_badge?.source?.kind&&g.value_badge.source.ref===`marker:${h}`&&(g.value_badge.source={kind:"derived_marker_state",ref:`marker:${l}`}),s.markers=s.markers.filter(t=>t.id!==l&&t.id!==h&&("virtual"===g.binding||t.binding!==g.binding)),s.markers.push(g);let $=null;const w=h?this.host._layout[h]:null,k=w?{s:w.s||c?.space||this.host._space,x:w.x,y:w.y}:h&&c&&this.host._defPos[h]?this.host._normPos(c.space,this.host._defPos[h].x,this.host._defPos[h].y):null;if(!d&&k&&k.s===_)l===h&&this.host._layout[l]&&!b||($={s:k.s,x:k.x,y:k.y},this.host._layout={...this.host._layout,[l]:$});else if(d||!this.host._layout[l]||b){let t=p.vb[0]+p.vb[2]/2,e=p.vb[1]+p.vb[3]/2;const s=r?p.rooms.find(t=>t.id===r):n?p.rooms.find(t=>t.area===n):void 0;s&&([t,e]=this.host._roomCenter(s)),$=this.host._normPos(_,t,e),this.host._layout={...this.host._layout,[l]:$}}if(await this._saveConfigNow(),$){const t=hs($);this.host._layout={...this.host._layout,[l]:t},this.host._noteLayoutRev(await this.host.hass.callWS({type:"houseplan/layout/update",device_id:l,pos:t}))}const x=new Set(o);h&&h!==l&&x.add(h),x.delete(l);for(const t of x)delete this.host._layout[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{});y&&v&&await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:v}).catch(()=>{}),this._closeMarkerDialog(),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_saved"))}catch(t){this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteMarker(){const t=this.host._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this.host._devices.find(e=>e.id===t.devId):null,s=this.host._markers.find(e=>e.id===t.devId);if(!e&&!s)return;const i=t.name||this.host._t("device.fallback");if(!confirm(this.host._t("confirm.remove_marker",{name:i})))return;const o=this.host._serverCfg;o.markers=o.markers||[];const a=o.markers,n=e?.id||s.id,r=e?"virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"":s.binding;if(!r)return;const l=cs(o.markers,n,r,"virtual"===r);o.markers=ds(l.markers,l.cleanupIds);const h=l.cleanupIds;this.host._markerDialog={...t,busy:!0};try{await this._saveConfigNow();for(const t of h){delete this.host._layout[t],delete this.host._defPos[t],this.host._dirtyPos.delete(t),this.host._sentPos.delete(t);const e=this.host._activityRt.get(t);e&&clearTimeout(e.timer),this.host._activityRt.delete(t),this.host._vacRt.delete(t),delete this.host._vacSrvTrails[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this.host._deviceInboxReturn&&(this.host._deviceInboxReturn={...this.host._deviceInboxReturn,tab:"readd",anchor:r}),this._closeMarkerDialog(),this.host._infoCard?.id===n&&this.host._closeInfoCard(),this.host._selId===n&&(this.host._selId=null),this.host._drag?.id===n&&(this.host._drag=null),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_removed"))}catch(t){this.host._serverCfg===o&&(o.markers=a),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_openSpaceDialog(t,e){if(this.host._serverStorage&&this.host._serverCfg)if("edit"===t){const s=this.host._serverCfg.spaces.find(t=>t.id===e);if(!s)return;const i=ps(s),o=s.settings?.custom_fill&&"object"==typeof s.settings.custom_fill?_s(s.settings.custom_fill):null,a="none"===i.fill?{...o||us,a:0}:o;this.host._spaceDialog={mode:t,spaceId:e,title:s.title,planUrl:s.plan_url||null,planFile:null,source:s.plan_url?"file":"draw",showBorders:i.showBorders,showNames:i.showNames,zeroWallStyle:gs(s),displayTouched:!0,hideDecor:i.hideDecor,hideOpenings:i.hideOpenings,roomColor:i.color,roomOpacity:i.opacity,fillMode:"none"===i.fill?"custom":i.fill,customFill:a,glowEnabled:i.glow,bgColor:i.bgColor,bgMode:"static"===s.settings?.bg_mode||"daynight"===s.settings?.bg_mode?s.settings.bg_mode:null,northDeg:Mt({},s.settings),sunRays:"boolean"==typeof s.settings?.sun_rays?s.settings.sun_rays:null,tempMin:i.tempMin,tempMax:i.tempMax,showLqi:i.showLqi??this.host._config?.show_signal??!0,cardFontScale:i.cardFontScale,labelTemp:i.labelTemp,labelHum:i.labelHum,labelLqi:i.labelLqi,labelLight:i.labelLight,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,cellCmInput:ms(Number(s.cell_cm)>0?Number(s.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1}}else this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...Ri(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:vs,roomOpacity:ys,fillMode:"custom",customFill:{...us,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:bs,tempMax:fs,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:$s(this.host._imperial),cellCmInput:ms($s(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1};else this.host._showToast(this.host._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,s=e.files?.[0];if(!s||!this.host._spaceDialog)return;const i={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[s.type]||(s.name.toLowerCase().endsWith(".svg")?"svg":"");if(!i)return void this.host._showToast(this.host._t("toast.plan_formats"));const o=new Uint8Array(await s.arrayBuffer());let a="";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.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:i,b64:n,aspect:l,name:s.name}}}_useServerPlan(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this.host._display(t);if(e){const s=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:0),s.onerror=()=>t(0),s.src=e}),i=this.host._spaceDialog;return i&&i.planUrl===t&&Number.isFinite(s)&&s>0?(this.host._spaceDialog={...i,savedAspect:s},s):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this.host._spaceDialog;e?.saved&&(this.host._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`
${this.host._t("space.loading")}
`;const e=t.saved||[];if(!e.length)return o`
${this.host._t("space.no_saved")}
`;return o`
+ ${e.map(e=>{return o` +
+ +
+ ${e.name} + ${s=e.size,s>=1048576?(s/1048576).toFixed(1)+" MB":Math.round(s/1024)+" KB"}${e.used_by.length?" · "+this.host._t("space.used_by",{list:e.used_by.join(", ")}):""} +
+ + +
`;var s})} +
`}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const e="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const s="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let i=null;if("file"===t.source&&t.planFile){i={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:s,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let o=t.savedAspect||null;!i&&"file"===t.source&&t.planUrl&&!o&&this.host._aspectJob&&(o=await this.host._aspectJob||null);const a=this.host._serverCfg;let n;if("create"===t.mode)n=Fi(s,t.title.trim()),a.spaces.push(n);else{if(n=a.spaces.find(t=>t.id===s),!n)throw new Error("space "+s+" is gone from the config");n.title=t.title.trim()}i?(n.plan_url=i.url,n.plan_aspect=i.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==n.plan_url&&(n.plan_url=t.planUrl,n.plan_aspect=o),"draw"===t.source&&(n.plan_url=null,n.plan_aspect=null,delete n.plan_x,delete n.plan_y,delete n.plan_scale,delete n.plan_scale_x,delete n.plan_scale_y,delete n.plan_angle),n.settings={...n.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):bs,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):fs,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},n.zero_wall_style=t.zeroWallStyle,n.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(el,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(n.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length?this._openNextImport():e||this.host._importTotal>0?(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._showToast(this.host._t(e&&!this.host._importTotal?"toast.space_added_onboard":"import.done"))):(this.host._showToast("create"===t.mode?this.host._t("toast.space_added"):this.host._t("toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?this._setMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._saveNav())))}catch(t){"conflict"!==t?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this.host._serverCfg;if(!e)return;const s=e.spaces.find(e=>e.id===t.spaceId),i=Ni(e,this.host._layout||{},t.spaceId||""),o=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(!i.count||o){if(confirm(this.host._t("confirm.delete_space",{title:s.title}))){this.host._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain;const e=await this.host.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev}),[s,i]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._adoptStructuralResponses(s,i),this.host._cfgRev=e?.config_rev??this.host._cfgRev,this.host._layoutRev=e?.layout_rev??this.host._layoutRev,this.host._spaceDialog=null,this.host._space===t.spaceId&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(e){"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const s=this.host._serverCfg;if(this.host._spaceDialog&&s){const e=Ni(s,this.host._layout||{},t.spaceId||""),i=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:i?0:e.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(e)}))}}}else this.host._spaceDialog={...t,deleteBlockers:i.count}}async _saveConfigNow(){this.host._cfgEpoch++;try{await this._writeConfig()}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this.host._reloadConfigOnly(),t}}_startImport(){const t=this.host._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,e.length?(this.host._importQueue=e,this.host._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();void 0!==t&&(this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...Ri(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:vs,roomOpacity:ys,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:bs,tempMax:fs,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:$s(this.host._imperial),cellCmInput:ms($s(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._showToast(this.host._t("import.done")))}_renderImportDialog(){const t=this.host._importDialog,e=t.floors.filter(t=>t.checked).length;return o`this.host._importDialog=null}> +
+
${this.host._t("import.hint")}
+ ${t.floors.map((e,s)=>o``)} +
+
+ + + +
+
`}_preflightDiagnostics(t,e){const s=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:Xr,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:s.has(t.spaceId)?jt(s.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this.host._reportedPreflightFingerprint||(this.host._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this.host._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==Xr}async _copyPreflightDiagnostics(){const t=this.host._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this.host._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.preflight_copied"))}catch{this.host._preflightClipboardFallback=e}}_checkOptimizeGeometryImpl(t){return ws(t,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometryImpl(t,e,s){return ks(t,e,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)}),captureWallGeometry:s?(t,e)=>s(e):void 0})}_optimizeReferenceContext(t){const e=this.host._haRegistry,s=this.host._fullRegistryHass,i={},o=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,s]of Object.entries(e.devices||{}))i[t]=o(s?.name_by_user,s?.name,s?.model);for(const[t,s]of Object.entries(e.entities||{}))i[`lg_${t}`]=o(this.host.hass?.states?.[t]?.attributes?.friendly_name,s?.name,s?.original_name);for(const t of this.host._devices)i[t.id]=o(t.name,i[t.id]);for(const t of this.host._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),a=e>0?t.binding.slice(0,e):"",n=e>0?t.binding.slice(e+1):"",r="device"===a?s?.devices?.[n]:"entity"===a?s?.entities?.[n]:null;i[t.id]=o(t.name,"device"===a?r?.name_by_user:null,r?.name,"entity"===a?this.host.hass?.states?.[n]?.attributes?.friendly_name:null,i[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this.host._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.host.hass?.states||{})])],names:i},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this.host._norm||!this.host._serverCfg)return;const e=this.host._serverCfg.spaces||[];let s;try{s=zr(this.host._serverCfg,this.host._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const i=s.changed?this.host._checkOptimizeGeometry(s.config):null;i&&this._reportPreflightFailure(i,s.config);const o=Math.ceil(10*s.report.maxShiftCm)/10,a=e.find(t=>null!=t?.id&&String(t.id)===s.report.maxSpace),n=e.length>1&&a?String(a.title||a.id):"";this.host._preflightClipboardFallback=null,this.host._alignDialog={report:s.report,config:s.config,layout:s.layout,cm:o,where:n,preflight:i,changed:s.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this.host._alignDialog;if(!t||t.busy||!this.host._serverCfg||!t.changed||!t.preflight?.ok)return;const e=Et(t.config);if(t.preflight.fingerprint!==e){const e=this.host._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this.host._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this.host._alignDialog={...t,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),await this.host._writeChain;const e=await this.host.hass.callWS({type:"houseplan/plan/optimize",config:t.config,layout:t.layout,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});this.host._serverCfg=t.config,this.host._layout=t.layout,this.host._geometryHistory.clear(),this.host._cfgRev=e?.config_rev??this.host._cfgRev+1,this.host._layoutRev=e?.layout_rev??this.host._layoutRev+1,this.host._canOptimizeUndo=!!e?.can_undo,this.host._undoKind=e?.can_undo?"optimize":null,this.host._dirtyPos.clear(),this.host._sentPos.clear(),this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._cacheSnapshot(),this.host._alignDialog=null,this.host._preflightClipboardFallback=null,this.host.requestUpdate(),this.host._showToast(this.host._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.host._alignDialog&&(this.host._alignDialog={...this.host._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this.host._showToast(this.host._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _undoPlanOptimization(){if(!this.host._canOptimizeUndo||this.host._optimizeUndoBusy)return;const t=this.host._undoKind;this._clearGeometryGesture(),this.host._optimizeUndoBusy=!0,this.host.requestUpdate();try{await this.host.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[e,s]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._serverCfg=e?.config||this.host._serverCfg,this.host._cfgRev=e?.rev??this.host._cfgRev,this.host._layout=s?.layout||this.host._layout,this.host._geometryHistory.clear(),this.host._layoutRev=s?.rev??this.host._layoutRev,this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._cacheSnapshot(),this.host.requestUpdate(),this.host._showToast(this.host._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}finally{this.host._optimizeUndoBusy=!1,this.host.requestUpdate()}}async _runBackupExport(){const t=this.host._backupExportDialog;if(t&&!t.busy){this.host._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.host.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this.host._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:Xr}),s=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),i=URL.createObjectURL(s),o=document.createElement("a");o.href=i,o.download=e.filename||`houseplan-${t.kind}.json`,o.style.display="none",document.body.append(o),o.click(),o.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),0),this.host._backupExportDialog=null,this.host._showToast(this.host._t("backup.export_done"))}catch(t){this.host._backupExportDialog&&(this.host._backupExportDialog={...this.host._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,s=e.files?.[0];if(e.value="",s){this.host._settingsDialog=null,this.host._backupImportDialog={filename:s.name,size:s.size,token:"",preview:null,expectedConfigRev:this.host._cfgRev,expectedLayoutRev:this.host._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),await this.host._writeChain,this.host._persistLayout.pending()&&this.host._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:s,headers:{"content-type":"application/json"}},i=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error)throw Object.assign(new Error(o.message||o.error||`HTTP ${i.status}`),{code:o.error});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,token:o.token,preview:o.preview,expectedConfigRev:o.expected_config_rev,expectedLayoutRev:o.expected_layout_rev,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this.host._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this.host._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const s=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,preview:{...e.preview,...s.preview},expectedConfigRev:s.expected_config_rev,expectedLayoutRev:s.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this.host._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this.host._backupImportDialog={...t,busy:!0,error:""};const e=this.host._space;try{const s=await this.host.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}),[i,o]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._adoptStructuralResponses(i,o),this.host._geometryHistory.clear(),this.host._dirtyPos.clear(),this.host._sentPos.clear(),this.host._defPos={},this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._visibleDeviceSnapshot=null,this.host._candidateDeviceSnapshot=null,this.host._stagedDeviceSnapshotToken=-1,this.host._capturedSnapshotConfigEpoch=-1,this.host._regSignature="",this.host._signer.invalidate(this.host.hass),this.host._resign(),this.host._maybeRebuildDevices();const a=this.host._serverCfg?.spaces||[],n="space"===s.kind&&s.space_id?s.space_id:a.some(t=>t.id===e)?e:a[0]?.id||this.host._space;this.host._hasFixedFloor?this.host._adoptInitialSpace(this.host._model,!0):this.host._commitSpace(n),this.host._backupImportDialog=null,this.host._cacheSnapshot(),this.host.requestUpdate();const r="space"===s.kind?t.preview.counts:s.counts;this.host._showToast(this.host._t("space"===s.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(s.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this.host._backupImportDialog?.token)try{const t=this.host._backupImportDialog,e=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this.host._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this.host._t("backup.revalidated")})}catch(e){t=e}this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this.host._backupExportDialog,e=(this.host._serverCfg?.spaces||[]).find(t=>t.id===this.host._space);return o`this.host._backupExportDialog=null}> +
+
${this.host._t("backup.export_hint")}
+ + + ${"space"===t.kind&&e?o``:a} +
${this.host._t("backup.privacy_warning")}
+ ${t.error?o``:a} +
+
+ + + +
+
`}_renderBackupImportDialog(){const t=this.host._backupImportDialog,e=t.preview,s=e?.counts||{},i=e?.reference_report||{},n=t=>Object.values(t||{}).reduce((t,e)=>t+(Number(e)||0),0),r=[["incoming_remapped",n(i.remapped?.incoming)],["target_repaired",n(i.remapped?.target)],["preserved_unresolved",n(i.preservedUnresolved)],["collisions",n(i.collisions)],["dropped_links",n(i.droppedIncomingLinks)],["bounded_lineages",Number(i.boundedLineages)||0]].filter(([,t])=>t>0);return o`this.host._backupImportDialog=null}> +
+
${t.filename}${(t.size/1024).toFixed(1)} KB
+ ${t.busy&&!e?o`
${this.host._t("backup.reading")}
`:a} + ${t.error?o``:a} + ${e?o` +
+ ${this.host._t("full"===e.kind?"backup.full":"backup.current_space")} + ${e.plan_only?o`${this.host._t("backup.plan_only_preview")}`:a} + ${this.host._t("same"===e.source?"backup.same_source":"backup.foreign_source")} + ${this.host._t("backup.created",{value:e.created_at||"—"})} + ${this.host._t("backup.versions",{card:e.card_version||"—",integration:e.integration_version||"—",model:String(e.model_version??"—")})} +
+
+ ${this.host._t("backup.count_spaces",{n:"full"===e.kind?`${e.current_counts?.spaces||0} → ${s.spaces||0}`:String(s.spaces||0)})} + ${this.host._t("backup.count_rooms",{n:"full"===e.kind?`${e.current_counts?.rooms||0} → ${s.rooms||0}`:String(s.rooms||0)})} + ${this.host._t("backup.count_walls",{n:"full"===e.kind?`${e.current_counts?.walls||0} → ${s.walls||0}`:String(s.walls||0)})} + ${this.host._t("backup.count_openings",{n:"full"===e.kind?`${e.current_counts?.openings||0} → ${s.openings||0}`:String(s.openings||0)})} + ${this.host._t("backup.count_decor",{n:"full"===e.kind?`${e.current_counts?.decor||0} → ${s.decor||0}`:String(s.decor||0)})} + ${this.host._t("backup.count_markers",{n:"full"===e.kind?`${e.current_counts?.markers||0} → ${s.markers||0}`:String(s.markers||0)})} + ${this.host._t("backup.count_layout",{n:"full"===e.kind?`${e.current_counts?.layout||0} → ${s.layout||0}`:String(s.layout||0)})} +
+ ${e.bindings?o`
${this.host._t("backup.bindings",{device:String(e.bindings.device||0),entity:String(e.bindings.entity||0),virtual:String(e.bindings.virtual||0),legacy:String(e.legacy_positions||0)})}
${this.host._t("backup.binding_status",{active:String(e.bindings.active||0),disabled:String(e.bindings.disabled||0),missing:String(e.bindings.missing||0)})}
`:a} + ${e.missing_areas?.length?o`
${this.host._t("backup.missing_areas",{areas:e.missing_areas.join(", ")})}
`:a} + ${e.dropped_marker_links?o`
${this.host._t("backup.dropped_marker_links",{n:String(e.dropped_marker_links)})}
`:a} + ${e.repaired_target_refs?o`
${this.host._t("backup.repaired_target_refs",{n:String(e.repaired_target_refs)})}
`:a} + ${e.preserved_unresolved_refs?o` +
${this.host._t("backup.preserved_unresolved_refs",{n:String(e.preserved_unresolved_refs)})}
${this.host._t("backup.preserved_unresolved_hint")}
+ `:a} + ${r.length?o`
+ ${this.host._t("backup.import_details")} +
+ ${r.map(([t,e])=>o`${this.host._t(`backup.import_detail.${t}`,{n:String(e)})}`)} + ${(i.examples||[]).slice(0,8).map(t=>o` + ${t.owner} → ${t.reference} + `)} +
+
`:a} + ${"full"===e.kind?o` +
${this.host._t("backup.replace_warning")}
+ ${"foreign"===e.source?o`
${this.host._t("backup.foreign_bookkeeping")}
`:a}`:o` +
${this.host._t("backup.final_name")}${e.space_title}
+
${this.host._t("backup.target_settings")}
+ ${e.duplicates?o`
${this.host._t("backup.duplicates",{n:String(e.duplicates)})} + + +
`:a}`} + ${e.content?.length?o`
+ ${this.host._t("backup.content")} + ${e.content.map(t=>o`${t.url} · ${this.host._t("available"===t.state?"backup.content_available":"external"===t.state?"backup.content_external":"backup.content_detach_required")}`)} +
`:a} + ${e.confirmation_required?o``:a} + `:a} +
+
+ + + ${e?o``:a} +
+
`}_setFillColor(t,e){const s=this.host._settingsDialog;this.host._settingsDialog={...s,colors:{...s.colors,[t]:{...s.colors[t],...e}}}}async _saveSettingsDialog(){const t=this.host._settingsDialog;if(t&&!t.busy){this.host._settingsDialog={...t,busy:!0};try{const e=this.host._serverCfg,s=JSON.stringify(t.colors)===JSON.stringify(xs),i={...e.settings};s?delete i.fill_colors:i.fill_colors=t.colors;const o=this.host._imperial?30.48*t.glowRadius:100*t.glowRadius;Number.isFinite(o)&&o>0&&300!==Math.round(o)?i.glow_radius_cm=Math.round(o):delete i.glow_radius_cm,t.bgColor?i.bg_color=t.bgColor:delete i.bg_color,null!==t.northDeg&&Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359?i.north_deg=t.northDeg:delete i.north_deg,i.bg_mode=t.bgMode,t.sunRays?i.sun_rays=!0:delete i.sun_rays,delete i.weather_entity,this.host._serverCfg={...e,settings:i},await this._saveConfigNow(),this.host._settingsDialog=null,this.host.requestUpdate(),this.host._showToast(this.host._t("gs.saved"))}catch(t){this.host._settingsDialog&&(this.host._settingsDialog={...this.host._settingsDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}}_boolInput(t,e,s=!1){const i=t=>e(!!t.target.checked);return customElements.get("ha-switch")?o``:o``}_rangeInput(t,e,s,i,n,r=!1,l){const h=t=>{const e=Number(t.target.value);Number.isFinite(e)&&n(e)};return customElements.get("ha-slider")?o``:o``}_renderColorRow(t,e){const s=this.host._settingsDialog.colors[t];return o`
+ {this._setFillColor(t,{c:e.detail.color,a:e.detail.opacity})}}> +
`}_renderAlignDialog(){const t=this.host._alignDialog,e=t.report,s=t.changed&&!t.preflight?.ok,i=t.preflight?.failures||[],n=i.slice(0,3).map(t=>t.displayName),r=n.length?n.join(", "):this.host._t("gs.align_preflight_space",{n:"1"}),l=Math.max(0,i.length-n.length),h=l?this.host._t("gs.align_preflight_more",{n:String(l)}):"",c=e.spaceRefsRemapped+e.roomRefsRemapped+e.positionsRemapped+e.markersDetached,d=e.migrated+e.canonicalized+e.coordsCanonicalized+e.wallSegmentsMigrated+e.wallsMerged+e.spansMerged+e.partitionsMerged+e.partitionsReconciled+e.openingsRehosted+e.redundantDraftsRemoved,p=e.moved+e.rotated+e.removedDrafts+e.coordsCanonicalized+e.wallsStraightened,_=Math.ceil(10*e.maxStraightenShiftCm)/10,u=(this.host._serverCfg?.spaces||[]).find(t=>String(t?.id||"")===e.maxStraightenSpace),m=(this.host._serverCfg?.spaces||[]).length>1&&u?String(u.title||u.id):"",g=e.orphanRoomLabelsRemoved+e.orphanDevicePositionsRemoved+e.orphanGroupPositionsRemoved,f=e.liveMissingPositions.map(t=>t.name).filter(Boolean),b=f.slice(0,3).join(", "),y=Math.max(0,f.length-3),v=b?this.host._t("gs.optimize_live_names",{names:b,more:y?this.host._t("gs.optimize_reference_more",{n:String(y)}):""}):"",$=e.unverifiedPositions.some(t=>"registry_unavailable"===t.reason),w=t=>e.removedPositions.some(e=>e.id===t.id)?this.host._t("gs.optimize_detail_removed"):e.liveMissingPositions.some(e=>e.id===t.id)?this.host._t("gs.optimize_detail_live"):this.host._t("gs.optimize_detail_unverified"),k=t=>this.host._t("room_label"===t?"gs.optimize_detail_room_label":"group"===t?"gs.optimize_detail_group":"device"===t?"gs.optimize_detail_device":"gs.optimize_detail_unknown"),x=[...e.removedPositions,...e.liveMissingPositions.filter(t=>!e.removedPositions.some(e=>e.id===t.id)),...e.unverifiedPositions],S=x.slice(0,10),M=Math.max(0,x.length-S.length);return o`{this.host._alignDialog=null,this.host._preflightClipboardFallback=null}}> +
+ ${s?o` +

${this.host._t("gs.align_preflight_failed",{spaces:r,more:h})}

+ ${i.slice(0,10).map(t=>o`

+ ${t.displayName}: ${this.host._t(`gs.preflight_reason_${t.reason}`)} +

`)} + ${i.length>10?o`

+ ${this.host._t("gs.align_preflight_more",{n:String(i.length-10)})} +

`:a} +
${this.host._t("gs.align_preflight_hint")}
+ ${this._preflightVersionsDiffer()?o` +
${this.host._t("gs.preflight_update_hint")}
`:a} +
+ +
+ ${this.host._preflightClipboardFallback?o`
+ ${this.host._t("gs.preflight_copy")} +
${this.host._preflightClipboardFallback}
+
`:a}`:t.changed?o` + ${e.moved?o`

${this.host._t("gs.align_count",{n:String(e.moved),total:String(e.total),cm:String(t.cm)})}

`:a} + ${e.latticeCoordinatesCanonicalized?o` +

${this.host._t("gs.optimize_lattice_summary",{n:String(e.latticeCoordinatesCanonicalized),cm:Ss(e.latticeMaxShiftCm)})}

+ ${e.latticeSpaces.map(t=>o`

${this.host._t("gs.optimize_lattice_space",{space:t.space,n:String(t.canonicalized),far:String(t.far)})}

`)} + `:a} + ${t.where?o`

${this.host._t("gs.align_where",{s:t.where})}

`:a} + ${e.rotated?o`

${this.host._t("gs.align_turned",{n:String(e.rotated)})}

`:a} + ${e.removedDrafts?o`

${this.host._t("gs.align_removed_drafts",{n:String(e.removedDrafts)})}

`:a} + ${e.redundantDraftsRemoved?o`

${this.host._t("gs.optimize_redundant_drafts",{n:String(e.redundantDraftsRemoved)})}

`:a} + ${e.wallSegmentsMigrated?o`

${this.host._t("gs.wall_segments_migrated",{n:String(e.wallSegmentsMigrated)})}

`:a} + ${e.legacyZeroWallsMigrated?o`

${this.host._t("gs.zero_walls_migrated",{n:String(e.legacyZeroWallsMigrated)})}

`:a} + ${d?o`

${this.host._t("gs.optimize_changes",{m:String(e.migrated),c:String(e.canonicalized),p:String(e.coordsCanonicalized),w:String(e.wallsMerged),s:String(e.spansMerged),i:String(e.partitionsMerged)})}

`:a} + ${e.partitionsReconciled?o`

${this.host._t("gs.optimize_coincident_partitions",{n:String(e.partitionsReconciled)})}

`:a} + ${e.openingsRehosted?o`

${this.host._t("gs.optimize_openings_rehosted",{n:String(e.openingsRehosted)})}

`:a} + ${e.wallsStraightened?o`

${this.host._t("gs.optimize_walls_straightened",{n:String(e.wallsStraightened),cm:String(_)})}

`:a} + ${m?o`

${this.host._t("gs.optimize_walls_straightened_where",{s:m})}

`:a} + ${e.glowSpacesMigrated||e.glowRoomsMigrated?o`

${this.host._t("gs.optimize_glow_migration",{spaces:String(e.glowSpacesMigrated),rooms:String(e.glowRoomsMigrated)})}

`:a} + ${p?o`
${this.host._t("gs.align_warn")}
`:a}`:o`

${this.host._t(e.liveMissingPositions.length||e.unverifiedPositions.length||e.nestedRefsUnresolved?"gs.optimize_no_automatic_changes":"gs.align_none")}

`} + ${!s&&e.wallsStraightenSkipped?o`

${this.host._t("gs.optimize_walls_straighten_skipped",{n:String(e.wallsStraightenSkipped)})}

`:a} + ${c?o`

${this.host._t("gs.optimize_references",{spaces:String(e.spaceRefsRemapped),rooms:String(e.roomRefsRemapped),positions:String(e.positionsRemapped),detached:String(e.markersDetached)})}

`:a} + ${g?o`

${this.host._t("gs.optimize_orphans_removed",{total:String(g),rooms:String(e.orphanRoomLabelsRemoved),devices:String(e.orphanDevicePositionsRemoved),groups:String(e.orphanGroupPositionsRemoved)})}

`:a} + ${e.liveMissingPositions.length?o`
+

${this.host._t(t.removeLiveMissingPositions?"gs.optimize_live_positions_remove":"gs.optimize_live_positions",{n:String(e.liveMissingPositions.length),names:v})}

+ + ${t.removeLiveMissingPositions?o`
+ ${this.host._t("gs.optimize_live_selected")} +
`:a} +
`:a} + ${e.unverifiedPositions.length?o``:a} + ${e.nestedRefsUnresolved?o``:a} + ${x.length?o`
+ ${this.host._t("gs.optimize_details")} +
    + ${S.map(t=>o`
  • ${this.host._t("gs.optimize_detail_item",{status:w(t),kind:k(t.kind),id:t.id,space:t.spaceId})}
  • `)} +
+ ${M?o`
${this.host._t("gs.optimize_details_more",{n:String(M)})}
`:a} +
`:a} +
+
+ + + ${t.changed&&t.preflight?.ok?o` + `:a} +
+
`}_renderSettingsDialog(){return o`this.host._settingsDialog=null}> +
+
${this.host._t("gs.hint")}
+ + ${this._renderColorRow("light_on","gs.light_on")} + ${this._renderColorRow("light_off","gs.light_off")} + ${this._renderColorRow("light_none","gs.light_none")} + + ${this._renderColorRow("temp_cold","gs.temp_cold")} + ${this._renderColorRow("temp_ok","gs.temp_ok")} + ${this._renderColorRow("temp_hot","gs.temp_hot")} + + ${this._renderColorRow("lqi_low","gs.lqi_low")} + ${this._renderColorRow("lqi_high","gs.lqi_high")} + + ${this._renderColorRow("glow_base","gs.glow_base")} + ${this._renderColorRow("glow_light","gs.glow_light")} +
+ ${this.host._t("gs.glow_radius")} + {const e=sl(t.target.value);null!=e&&e>0&&(this.host._settingsDialog={...this.host._settingsDialog,glowRadius:e})}} /> + ${this.host._imperial?this.host._t("gs.unit_ft"):this.host._t("gs.unit_m")} +
+ + ${this._renderColorRow("wall_fill","gs.wall_fill")} + +
+ ${this.host._t("gs.bg_mode")} + +
+ ${"static"===this.host._settingsDialog.bgMode?o`
+ {this.host._settingsDialog={...this.host._settingsDialog,bgColor:t.detail.color}}}> + ${this.host._settingsDialog.bgColor?o``:o`${this.host._t("gs.bg_theme")}`} +
`:o`
${this.host._t("gs.bg_daynight_hint")}
`} + + ${Ms(this.host.hass)?a:o`
${this.host._t("gs.sun_missing")}
`} +
+ ${this.host._renderCompass()} +
+ ${this.host._t("gs.north")} +
+ {const e=t.target.value.trim(),s=""===e?null:Math.round(Number(e));this.host._settingsDialog={...this.host._settingsDialog,northDeg:null!==s&&Number.isFinite(s)?Math.min(359,Math.max(0,s)):null}}} /> + ${null!==this.host._settingsDialog.northDeg?o``:a} +
+ ${null===this.host._settingsDialog.northDeg?o`
${this.host._t("gs.north_hint")}
`:a} +
+
+ + ${this.host._canEdit?o` + +
${this.host._t("gs.backup_hint")}
+
+ + + + this._pickBackupImport(t)} /> + + ${this.host._canOptimizeUndo&&"import"===this.host._undoKind?o` + `:a} +
`:a} + +
${this.host._t("gs.grid_hint")}
+
+ +
+ ${this.host._canOptimizeUndo&&"import"!==this.host._undoKind?o`
+ +
`:a} + +
${this.host._t("gs.about_version",{v:Xr})}
+ + ${this.host._t("gs.about_github")} + + ${this.host._t("gs.about_telegram")} +
+
+ + + + +
+
`}_rulesSet(t){this.host._rulesDialog={...this.host._rulesDialog,rules:t}}async _saveRules(){const t=this.host._rulesDialog;if(!t||t.busy)return;const e=t.rules.filter(t=>t.pattern.trim()&&t.icon.trim());this.host._rulesDialog={...t,busy:!0};try{const t=this.host._serverCfg,s=JSON.stringify(e)===JSON.stringify(Ct),i={...t.settings};s?delete i.icon_rules:i.icon_rules=e,this.host._serverCfg={...t,settings:i},await this._saveConfigNow(),this.host._rulesDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("rules.saved"))}catch(t){this.host._rulesDialog&&(this.host._rulesDialog={...this.host._rulesDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_renderRulesDialog(){const t=this.host._rulesDialog,e=Ds(t.rules),s=t.test.trim()?Cs(t.test,"",e):null,i=(e,s)=>{const i=[...t.rules],o=e+s;o<0||o>=i.length||([i[e],i[o]]=[i[o],i[e]],this._rulesSet(i))};return o`this.host._rulesDialog=null}> +
+
${this.host._t("rules.hint")}
+
+ this.host._rulesDialog={...t,test:e.target.value}} /> + ${s?o`${s}`:a} +
+ ${t.rules.map((e,s)=>{const a=""!==e.pattern.trim()&&!Ps(e.pattern);return o`
+ {const o=[...t.rules];o[s]={...e,pattern:i.target.value},this._rulesSet(o)}} /> + {const o=[...t.rules];o[s]={...e,icon:i.target.value},this._rulesSet(o)}} /> + + i(s,-1)}> + i(s,1)}> + this._rulesSet(t.rules.filter((t,e)=>e!==s))}> +
`})} + +
+
+ + + + +
+
`}_saveKioskScale(t){this.host._kioskScale={...this.host._kioskScale,...t};try{localStorage.setItem("houseplan_card_kiosk_v1",JSON.stringify(this.host._kioskScale))}catch{}this.host.requestUpdate()}_renderKioskDialog(){const t=this.host._kioskScale,e=(e,s)=>o` +
+ ${this._rangeInput(50,300,5,Math.round(100*t[e]),t=>this._saveKioskScale({[e]:t/100}))} + ${Math.round(100*t[e])}% +
`;return o`this.host._kioskDialog=!1}> +
+
${this.host._t("kiosk.hint")}
+ ${e("icon",this.host._t("kiosk.icon_scale"))} + ${e("font",this.host._t("kiosk.font_scale"))} +
+
+ + + +
+
`}_renderVacSection(t){const e=this.host._devices.find(e=>e.id===t.devId);if(!e||!this.host._isVacDev(e))return a;const s=e.marker?.vacuum||{},i=this.host._vacAllCamerasFor===e.id,n=this.host._vacSourceResolution(e,i),r=n.entityId,l=n.candidates.find(t=>t.entityId===r)||null,h=r?Is(this.host.hass?.states[r]?.attributes):null,c=!1!==s.live&&("ok"===n.status||"unsupported"===n.status),d=this._vacPlanRoomAnchors(e.space),p=h?Ts(h.rooms,d.map(t=>t.name)):0,_=!!(c&&h&&p>=3),u=Object.keys(s.calibration||{}),m=t=>{const s=this.host._vacEnsureMarker(e);s&&(s.vacuum={...s.vacuum||{},...t},this.host._regSignature="",this.host._maybeRebuildDevices(),this._saveConfig(),this.host.requestUpdate())},g=new Set(e.entities||[]),f=n.candidates.filter(t=>g.has(t.entityId)||t.entityId===s.source),b=i?n.candidates.filter(t=>t.entityId.startsWith("camera.")&&!f.some(e=>e.entityId===t.entityId)):[],y=t=>[t.hasPosition?this.host._t("vac.cap_position"):"",t.hasRooms?this.host._t("vac.cap_rooms_short"):"",t.hasPath?this.host._t("vac.cap_path"):"",t.hasMapId?this.host._t("vac.cap_map"):""].filter(Boolean).join(" · ")||this.host._t("vac.cap_none"),v=t=>o` + `,$=n.candidates.some(t=>g.has(t.entityId)&&"known_xcme_incomplete"===t.category)||!!n.pinned&&!!r?.startsWith("camera.")&&!l?.hasPosition;return o` + +
+
+
${this.host._t("vac.diag_source")}${r||this.host._t("vac.source_none")}
+ ${l?.platform?o`
${this.host._t("vac.diag_platform")}${l.platform}
`:a} +
${this.host._t("vac.diag_status")}${this.host._t(`vac.source_status_${n.status}`)}
+
${this.host._t("vac.diag_position")}${h?.pos?this.host._t("common.yes"):this.host._t("common.no")}
+
${this.host._t("vac.diag_rooms")}${Rs(this.host._t("vac.diag_rooms_value"),{total:String(h?.rooms.length||0),matched:String(p),readiness:this.host._t(p>=3?"vac.autocal_ready":"vac.autocal_not_ready")})}
+
${this.host._t("vac.diag_path")}${h?.path.length?this.host._t("common.yes"):this.host._t("common.no")}
+
${this.host._t("vac.diag_map")}${h?.mapId??"default"}
+
+ ${"missing"===n.status||"disabled"===n.status||"unverified"===n.status?o`
+ ${this.host._t(`vac.source_banner_${n.status}`)} + +
`:a} + ${$?o`
+ ${this.host._t("vac.xcme_hint")} +
attributes:
+  - vacuum_position
+  - rooms
+  - path
+  - map_name
+
`:a} +
+ ${this.host._t("vac.choose_source")} +
+ + ${f.map(v)} +
{t.currentTarget.open?this.host._vacOpenAllCameras(e):(this.host._vacAllCamerasFor=null,this.host._vacAllCameraCache=null)}}> + ${this.host._t("vac.all_cameras")} +
${this.host._t("vac.all_cameras_warn")}
+ ${i?b.length?b.map(v):o`
${this.host._t("vac.all_cameras_empty")}
`:a} +
+
+
+
+ ${_?o``:a} + ${c?o``:a} + ${this.host._t("vac.documentation")} +
+ ${h?o` + + + + ${u.length?o`
${Rs(this.host._t("vac.cal_maps"),{maps:u.join(", ")})}
`:a} + `:a} +
`}_vacMapId(t,e,s=this.host._planHass){const i=this.host._vacEntity(t),o=i?s?.states?.[i]?.attributes?.selected_map:null;return Ns(e.mapId,o)}_vacSaveMatrix(t,e,s,i){const o=this.host._devices.find(e=>e.id===t),a=o?this.host._vacEnsureMarker(o):this.host._serverCfg?.markers?.find(e=>e.id===t);if(!a)return!1;const n={...a.vacuum||{}};return n.source=e,n.calibration={...n.calibration||{},[s]:i.map(t=>Number(t.toFixed(6)))},a.vacuum=n,this.host._regSignature="",this.host._maybeRebuildDevices(),this._saveConfig(),this.host.requestUpdate(),!0}_vacPlanRoomAnchors(t){return(this.host._spaceModelById(t)?.rooms||[]).map(t=>({room:t,poly:R(t)})).filter(({room:t,poly:e})=>t.name&&e).map(({room:t,poly:e})=>{const s=zs(e);return s?{name:String(t.name),cx:s[0],cy:s[1]}:null}).filter(Boolean)}_vacAutoCalibrate(t){const e=this.host._vacSource(t),s=e?Is(this.host.hass?.states[e]?.attributes):null;if(!e||!s||s.rooms.length<3)return void this.host._showToast(this.host._t("vac.autocal_no_rooms"));const i=this._vacPlanRoomAnchors(t.space),o=As(s.rooms,i);if(!o)return void this.host._showToast(this.host._t("vac.autocal_no_match"));const a=this.host._serverCfg?.spaces?.find(e=>e.id===t.space),n=Number(a?.cell_cm),r=Number.isFinite(n)&&n>0?n:5,l=Os(o.residual,this.host._gridPitch,r),h=this._vacMapId(t,s);l>Ls?this.host._vacCalConfirm={markerId:t.id,source:e,mapId:h,matrix:o.matrix,rooms:o.matched.length,error:ee(l,"mi"===this.host.hass?.config?.unit_system?.length)}:this._vacSaveMatrix(t.id,e,h,o.matrix)&&this.host._showToast(Rs(this.host._t("vac.autocal_done"),{rooms:String(o.matched.length)}))}_vacApplyCalibrationProposal(t){const e=this.host._vacCalConfirm;if(e){if(this.host._vacCalConfirm=null,t){const t=this.host._devices.find(t=>t.id===e.markerId),s=Es(e.matrix);if(!t||!s)return;if(this.host._markerDialog=null,t.space!==this.host._space&&!this.host._commitSpace(t.space))return;return void(this.host._vacFit={markerId:e.markerId,source:e.source,mapId:e.mapId,p:s,drag:null})}this._vacSaveMatrix(e.markerId,e.source,e.mapId,e.matrix)&&this.host._showToast(Rs(this.host._t("vac.autocal_done"),{rooms:String(e.rooms)}))}}_vacStartFit(t){const e=this.host._vacSource(t),s=e?Is(this.host.hass?.states[e]?.attributes):null;if(!e||!s)return void this.host._showToast(this.host._t("vac.cal_need_pos"));const i=this._vacMapId(t,s),o=t.marker?.vacuum?.calibration?.[i],a=this.host._spaceModelById(t.space);if(!a)return;const n=a.vb,r=o&&6===o.length&&Es(o)||Bs(s.rooms,n);this.host._markerDialog=null,(t.space===this.host._space||this.host._commitSpace(t.space))&&(this.host._vacFit={markerId:t.id,source:e,mapId:i,p:r,drag:null})}_vacFitSave(){const t=this.host._vacFit;if(!t)return;const e=this._vacSaveMatrix(t.markerId,t.source,t.mapId,Hs(t.p));this.host._vacFit=null,e&&this.host._showToast(this.host._t("vac.cal_done"))}_vacFitTurn(t){const e=this.host._vacFit;if(!e)return;const s=Is(this.host.hass?.states[e.source]?.attributes),i=this._vacGhostCentre(s?.rooms||[]),o={...e.p,...t};this.host._vacFit={...e,p:Gs(o,e.p,i[0],i[1])}}_vacGhostCentre(t){const e=[],s=[];for(const i of t)e.push(i.x0??i.cx,i.x1??i.cx),s.push(i.y0??i.cy,i.y1??i.cy);return e.length?[(Math.min(...e)+Math.max(...e))/2,(Math.min(...s)+Math.max(...s))/2]:[0,0]}_vacDelta(t,e,s){const i=this.host._stageEl,o=i?.clientWidth||1,a=i?.clientHeight||1;return[e/o*t.w,s/a*t.h]}_vacFitPointer(t,e){const s=this.host._vacFit;if(!s)return;if(t.stopPropagation(),"pointerdown"===t.type){const e=t.target,i=e.getAttribute?.("data-corner");try{t.currentTarget.setPointerCapture?.(t.pointerId)}catch{}return void(this.host._vacFit={...s,drag:i?{kind:"scale",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:Number(i.split(",")[0]),fy:Number(i.split(",")[1])}:{kind:"move",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:0,fy:0}})}const i=s.drag;if(i){if("pointermove"===t.type){const[o,a]=this._vacDelta(e,t.clientX-i.sx,t.clientY-i.sy);if("move"===i.kind)this.host._vacFit={...s,p:{...i.p0,ox:i.p0.ox+o,oy:i.p0.oy+a}};else{const t=Is(this.host.hass?.states[s.source]?.attributes),e=this._vacGhostCentre(t?.rooms||[]),n=Hs(i.p0),[r,l]=Ws(n,e[0],e[1]),[h,c]=Ws(n,i.fx,i.fy),d=Math.hypot(r-h,l-c)||1,[p,_]=[2*r-h,2*l-c],u=Math.hypot(p+2*o-h,_+2*a-c)/2,m=Math.max(.05,u/d),g={...i.p0,s:i.p0.s*m};this.host._vacFit={...s,p:Gs(g,i.p0,i.fx,i.fy)}}return}"pointerup"!==t.type&&"pointercancel"!==t.type||(this.host._vacFit={...s,drag:null})}}_renderVacFit(t){const e=this.host._vacFit;if(!e)return a;const s=Is(this.host._renderPlanHass?.states?.[e.source]?.attributes);if(!s)return a;const i=Hs(e.p),n=[],r=[],l=[];for(const t of s.rooms){if(null==t.x0)continue;const e=[[t.x0,t.y0],[t.x1,t.y0],[t.x1,t.y1],[t.x0,t.y1]].map(([t,e])=>Ws(i,t,e));e.forEach(([t,e])=>{r.push(t),l.push(e)});const[s,o]=Ws(i,t.cx,t.cy);n.push(ce` + ${t.name}`)}let h=a;if(s.pos){const[e,o]=Ws(i,s.pos.x,s.pos.y);h=ce``}const c=[];if(r.length){const e=(()=>{const t=i[0]*i[4]-i[1]*i[3];return(e,s)=>[(i[4]*(e-i[2])-i[1]*(s-i[5]))/t,(-i[3]*(e-i[2])+i[0]*(s-i[5]))/t]})(),s=Math.min(...r),o=Math.max(...r),a=Math.min(...l),n=Math.max(...l),h=.022*t.w,d=h/4;for(const[t,i,r,l]of[[s,a,o,n],[o,a,s,n],[o,n,s,a],[s,n,o,a]]){const s=e(r,l);c.push(ce` + `)}}return o`this._vacFitPointer(e,t)} + @pointermove=${e=>this._vacFitPointer(e,t)} + @pointerup=${e=>this._vacFitPointer(e,t)} + @pointercancel=${e=>this._vacFitPointer(e,t)}>${n}${h}${c}`}_resetRoomDialogFields(){this.host._roomEditId=null,this.host._roomFill="",this.host._roomCustomFill=null,this.host._roomTempSrc="",this.host._roomHumSrc="",this.host._roomSrcOpen=null,this.host._roomSrcFilter="",this.host._roomNameScale=1,this.host._roomLabelScale=1}_openRoomEdit(t){if(!t.id)return;this.host._roomEditId=t.id,this.host._nameSel=t.name||"",this.host._areaSel=t.area||"",this.host._roomFill="glow"===t.settings?.fill_mode?"":t.settings?.fill_mode||"";const e=t.settings?.custom_fill;this.host._roomCustomFill=e&&"object"==typeof e?_s(e,ps(this.host._curSpaceCfg).customFill):null,this.host._roomTempSrc=t.settings?.temp_source||"",this.host._roomHumSrc=t.settings?.hum_source||"",this.host._roomNameScale=js(t.settings?.name_scale),this.host._roomLabelScale=js(t.settings?.label_scale),this.host._roomSrcOpen=null,this.host._roomSrcFilter="",this.host._roomDialog=!0}_roomSettingsFromDialog(){const t={};return this.host._roomFill&&(t.fill_mode=this.host._roomFill),this.host._roomCustomFill&&(t.custom_fill=this.host._roomCustomFill),this.host._roomTempSrc&&(t.temp_source=this.host._roomTempSrc),this.host._roomHumSrc&&(t.hum_source=this.host._roomHumSrc),1!==this.host._roomNameScale&&(t.name_scale=this.host._roomNameScale),1!==this.host._roomLabelScale&&(t.label_scale=this.host._roomLabelScale),Object.keys(t).length?t:null}_saveRoomEdit(){const t=this.host._curSpaceCfg,e=t?.rooms.find(t=>t.id===this.host._roomEditId);if(!e)return this.host._roomDialog=!1,void(this.host._roomEditId=null);e.name=this.host._nameSel.trim()||e.name,e.area=this.host._areaSel||null;const s=e.settings||{},i={...s};this.host._roomFill?i.fill_mode=this.host._roomFill:delete i.fill_mode,this.host._roomCustomFill?i.custom_fill=this.host._roomCustomFill:delete i.custom_fill,"glow"===s.fill_mode&&"boolean"!=typeof s.glow&&(i.glow=!0),this.host._roomTempSrc?i.temp_source=this.host._roomTempSrc:delete i.temp_source,this.host._roomHumSrc?i.hum_source=this.host._roomHumSrc:delete i.hum_source,1!==this.host._roomNameScale?i.name_scale=this.host._roomNameScale:delete i.name_scale,1!==this.host._roomLabelScale?i.label_scale=this.host._roomLabelScale:delete i.label_scale,Object.keys(i).length?e.settings=i:delete e.settings,this._saveConfig(),this.host._roomDialog=!1,this.host._roomEditId=null,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._showToast(this.host._t("toast.room_updated"))}_roomSrcCandidates(){const t=this.host._planHass,e=x(this.host._markers),s=this.host._roomSrcFilter.trim().toLowerCase(),i=[];for(const o of Object.values(t.devices)){if("service"===o.entry_type)continue;if(e.devices.has(o.id))continue;const t=(o.name_by_user||o.name||o.id).trim();s&&!t.toLowerCase().includes(s)||i.push({value:"device:"+o.id,label:t,sub:o.model||this.host._t("marker.sub_device")})}for(const[o,a]of Object.entries(t.entities)){if(!o.startsWith("sensor.")||a.hidden)continue;if(S(t,o,e))continue;const n=a.name||t.states[o]?.attributes?.friendly_name||o;s&&!(n+" "+o).toLowerCase().includes(s)||i.push({value:"entity:"+o,label:n,sub:o})}return i.sort((t,e)=>t.label.localeCompare(e.label)),i.slice(0,200)}_roomSrcLabel(t){const e=t.indexOf(":"),s=t.slice(0,e),i=t.slice(e+1);return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i}_labelPos(t,e){const s=this.host._layout["rl_"+(t.id||"")];if(s&&s.s===e)return{x:s.x*ol,y:s.y*ol};const i=this._snap(this.host._roomCenter(t));return{x:i[0],y:i[1]}}_labelDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=this._labelPos(e,s);this.host._drag={id:"rl_"+(e.id||""),sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},nl(t),this.host._tip=null}_labelMove(t,e,s){const i="rl_"+(e.id||"");if(!this.host._drag||this.host._drag.id!==i)return;const o=this.host._stageEl;if(!o)return;const a=this.host._spaceModelById(s);if(!a)return;const n=a.vb,r=o.getBoundingClientRect(),l=this.host._viewOr(n),h=(t.clientX-this.host._drag.sx)/r.width*l.w,c=(t.clientY-this.host._drag.sy)/r.height*l.h;Math.abs(t.clientX-this.host._drag.sx)+Math.abs(t.clientY-this.host._drag.sy)>3&&(this.host._drag.moved=!0);const d=Rt(this.host._drag.ox+h),p=Rt(this.host._drag.oy+c);this.host._savePos({id:i,space:s},d,p)}_labelUp(t){const e="rl_"+(t.id||"");if(!this.host._drag||this.host._drag.id!==e)return;const s=this.host._drag.moved;this.host._drag=s?this.host._drag:null,s&&window.setTimeout(()=>this.host._drag=null,0)}_labelScale(t){const e=this.host._layout["rl_"+(t.id||"")]?.k;return"number"==typeof e&&Number.isFinite(e)?Math.min(3,Math.max(.5,e)):1}_rlResizeDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=t.target.closest(".roomlabel");if(!i)return;const o=i.getBoundingClientRect(),a=o.left+o.width/2,n=o.top+o.height/2,r=Math.max(8,Math.hypot(t.clientX-a,t.clientY-n));this.host._rlResize={id:"rl_"+(e.id||""),space:s,k0:this._labelScale(e),cx:a,cy:n,d0:r},nl(t)}_rlResizeMove(t){const e=this.host._rlResize;if(!e)return;t.stopPropagation();const s=Math.max(8,Math.hypot(t.clientX-e.cx,t.clientY-e.cy)),i=Math.min(3,Math.max(.5,e.k0*(s/e.d0))),o=this.host._layout[e.id];if(o)this.host._layout={...this.host._layout,[e.id]:{...o,k:i}};else{const t=e.id.slice(3),s=this.host._spaceModelById(e.space);if(!s)return;const o=s.rooms.find(e=>e.id===t);if(!o)return;const a=this._labelPos(o,e.space);this.host._layout={...this.host._layout,[e.id]:{s:e.space,x:a.x/ol,y:a.y/ol,k:i}}}this.host._dirtyPos.add(e.id)}_rlResizeUp(){this.host._rlResize&&(this.host._rlResize=null,this.host._persistLayout())}_renderRoomGear(t,e,s){if(!t.id)return a;let i=null;if(t.poly?(i=this.host._gearPtCache.get(t.poly)||null,i||(i=re(t.poly),this.host._gearPtCache.set(t.poly,i))):null!=t.x&&null!=t.y&&(i=[t.x+(t.w||0)/2,t.y+(t.h||0)/2]),!i)return a;const n=(i[0]-s.x)/s.w*100,r=(i[1]-s.y)/s.h*100;return o``}_alignCandidates(){const t=[],e=this.host._spaceModel();if(this.host._markup){if(!e)return t;if(this.host._drag?.id.startsWith("rl_")){const s=this.host._drag.id.slice(3);for(const i of e.rooms){if(!i.name||i.id===s)continue;const e=this._labelPos(i,this.host._space);t.push([e.x,e.y])}return t}for(const s of e.rooms){const e=R(s);if(e)for(const s of e)t.push(s)}if("draw"===this.host._tool)for(const e of this.host._path)t.push(e);if("split"===this.host._tool&&this.host._splitSel?.pts)for(const e of this.host._splitSel.pts)t.push(e);return t}if("devices"===this.host._mode){for(const e of this.host._devices){if(e.space!==this.host._space||e.id===this.host._drag?.id||"ha_disabled"===e.bindingStatus?.kind)continue;const s=this.host._pos(e);t.push([s.x,s.y])}return t}if("decor"===this.host._mode){const e=this.host._decorMove?.id;return t.push(...this._decorSnapGeometry(e).points),this.host._decorDraft&&t.push(this.host._decorDraft.a),t}return t}_renderAlignGuides(){const t=this.host._alignPoint;if(!t)return ce``;const e=this.host._drag?.id.startsWith("rl_")?.5*this.host._gridPitch:.05*this.host._gridPitch,s=qs(t,this._alignCandidates(),e);if(!s.length)return ce``;const i=this.host._gridPitch,o=1.5*i;return ce` + ${s.map(e=>{const[s,a,n,r]="x"===e.axis?[e.at,e.from[1],e.at,t[1]+Math.sign(t[1]-e.from[1])*o]:[e.from[0],e.at,t[0]+Math.sign(t[0]-e.from[0])*o,e.at];return ce` + `})} + `}_renderOpeningCenterTick(t){const e=(t.angle+90)*Math.PI/180,s=ze(15,this.host._cellCm);return ce``}_renderOpeningDimensionGuides(t){const e=t.labels.flatMap(t=>t.dimension?[t.dimension]:[]);if(!e.length)return ce``;const s=this._cssPxToRender(4);return ce``}_renderOpeningPlacementPreview(){const t=this.host._openingPreview;if(!t)return ce``;const e={type:t.type,length:t.renderedLength,angle:t.angle,amount:Us(t.type,null),flipH:t.flipH,flipV:t.flipV,base:"var(--hp-open)",tone:"var(--hp-open)",cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,face:t.face},s="passage"===t.type?Ks(t,ze(this.host._gridPitch,this.host._cellCm)):null;return ce` + `}_renderOpeningDialog(){const t=this.host._openingDialog,e=this.host._spaceModel()?.partitions||[],s=t.id?this.host._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,i={id:t.id||"preview",type:t.type,x:t.x/ol,y:t.y/this.host._spaceH,angle:t.angle,length:s&&!t.lengthTouched?s.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/ol,...t.host?{host:t.host}:{}},n=qe(s,i),r=t.host?n?H(i,e,ol,this.host._cellCm,this.host._gridPitch):F(i,e,ol,this.host._cellCm,this.host._gridPitch):null,l="does-not-fit-jamb"===r?.reason,h=t.host?e.find(e=>e.id===t.host.id):null,c=h?ee(h.cm/2,this.host._imperial):"",d=!!t.host&&!r?.resolved&&!l,p="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",_=(e,s)=>{const i="contact"===e?t.contact:t.lock,n="contact"===e?!!t.contactOpen:!!t.lockOpen,r="contact"===e?t.contactFilter||"":t.lockFilter||"",l=s.find(t=>t.value===i),h=l?.label||this.host.hass.states[i]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[i]?.name||i,c=Ii(s,r);return o` + + ${n?o`
+ this._filterOpeningEntities(e,t.target.value)} /> +
+ + ${c.map(t=>o` + `)} + ${c.length?a:o`
${this.host._t("marker.nothing_found")}
`} +
+
`:a}`};return o`this.host._openingDialog=null}> +
+ ${t.host?o` +
+ ${d||l?o``:a} + ${d?this.host._t("opening.partition_orphan"):l?this.host._t("opening.partition_jamb_margin",{distance:c}):this.host._t("opening.host_partition")} +
`:a} + + + + + + + + {const s=sl(e.target.value);null!=s&&(this.host._openingDialog={...t,lengthCm:s,lengthTouched:!0})}} /> + + ${"passage"===t.type&&(t.contact||t.lock)?o`
+ + ${this.host._t("opening.passage_binding_warning")} +
`:a} + + ${"passage"!==t.type?o` + ${_("contact",this._contactCandidates())} + ${t.contact?o``:a}`:a} + + ${"door"===t.type||"gate"===t.type?o` + ${_("lock",this._lockCandidates())}`:a} + + ${"gate"!==t.type&&"passage"!==t.type?o``:a} + ${"passage"!==t.type?o``:a} +
+ +
`}_gridLevels(){const t=this.host._stageEl,e=this.host._viewOr(this.host._baseVb()),s=t&&t.clientWidth&&e.w?t.clientWidth/e.w:1;return Ys(this.host._gridPitch,s)}_renderMarkupDefs(t){const e=this._gridLevels();if(!e)return ce``;const s=this.host._gridPitch*e.fine,i=this.host._gridPitch*e.coarse,o=this.host._gridPitch*e.fine*.14;return ce` + + + + + + + + + + + + + + `}_renderPhysicalEditorLayer(){const t=this.host._spaceModel();if(!t)return ce``;const e=this.host._gridPitch,s=this.host._viewOr(this.host._baseVb()),i=this.host._stageEl,o=i?.clientWidth?s.w/i.clientWidth:e/8,n=Math.max(.22*e,8*o),r=Math.max(n,12*o),l=t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`,h=(t,e)=>this.host._physicalSel?.kind===t&&this.host._physicalSel.id===e||"column"===t&&this.host._duplicateColumnId===e,c=(t.room_drafts||[]).flatMap(t=>t.points.slice(0,-1).map((e,s)=>{const i=t.points[s+1],a=Number(t.segments[s]?.cm),n=j(Number.isFinite(a)?a:15,this.host._cellCm,this.host._gridPitch);return ce`{this.host._physicalSel={kind:"draft",id:t.id,segment:s},this._registerPhysicalTap("draft",t.id,s)}}>`})),d=(t.partitions||[]).map(t=>{const e=Yt(t.a,t.b,t.cm,this.host._cellCm,this.host._gridPitch);return e?ce`this._physicalDown(e,"partition",t.id)} + @pointermove=${t=>this._physicalMove(t)} + @pointerup=${t=>this._physicalUp(t)}>`:ce`this._physicalDown(e,"partition",t.id)} + @pointermove=${t=>this._physicalMove(t)} + @pointerup=${t=>this._physicalUp(t)}>`}),p=(t.wall_columns||[]).map(t=>{const e=this.host._physicalRotate?.id===t.id?{...t,angle:this.host._physicalRotate.angle}:t,s=Jt(e,this.host._cellCm,this.host._gridPitch);return ce`this._physicalDown(e,"column",t.id)} + @pointermove=${t=>this._physicalMove(t)} + @pointerup=${t=>this._physicalUp(t)}>`}),_=this.host._physicalDrag,u=(()=>{if(!_?.moved)return a;if("partition"===_.kind&&0===Number(_.base.cm)){const t=_.base;return ce``}const t="partition"===_.kind?Yt(_.base.a,_.base.b,_.base.cm,this.host._cellCm,this.host._gridPitch):Jt(_.base,this.host._cellCm,this.host._gridPitch);return t?ce``:a})(),m=(()=>{const s=this.host._physicalSel;if(!s)return a;if("draft"===s.kind){const e=t.room_drafts.find(t=>t.id===s.id);return e?ce` + t.join(",")).join(" ")}> + ${e.points.map(t=>ce``)} + `:a}if("partition"===s.kind){const e=t.partitions.find(t=>t.id===s.id);if(!e)return a;const i=Yt(e.a,e.b,e.cm,this.host._cellCm,this.host._gridPitch),o=(e.a[0]+e.b[0])/2,r=(e.a[1]+e.b[1])/2;return ce` + ${i?ce``:ce``} + + + + `}const i=t.wall_columns.find(t=>t.id===s.id);if(!i)return a;const h=this.host._physicalRotate?.id===i.id?{...i,angle:this.host._physicalRotate.angle}:i,c=Jt(h,this.host._cellCm,this.host._gridPitch);if("square"!==h.shape)return ce` + + + `;const d=j(h.cm,this.host._cellCm,this.host._gridPitch),p=At(h.angle)*Math.PI/180,_=Math.sin(p),u=-Math.cos(p),m=[h.center[0]+_*d/2,h.center[1]+u*d/2],g=[m[0]+_*Math.max(e,24*o),m[1]+u*Math.max(e,24*o)];return ce` + + + + this._physicalRotateDown(t,i)} + @pointermove=${t=>this._physicalRotateMove(t)} + @pointerup=${t=>this._physicalRotateUp(t)}> + `})();return ce`${c}${d}${p}${u}${m}`}_renderHiddenWallDiagnosticOverlay(){if(!this.host._markup)return ce``;const t=this._hiddenWallDiagnosticSnapshot().value;if(!t.segments.length)return ce``;const e=j(5,this.host._cellCm,this.host._gridPitch);return ce``}_renderPlanSnapOverlay(){if(!this.host._markup)return ce``;const t=this._planSnapGeometrySnapshot().value,e=this.host._activePlanSnapCandidate,s=new Set(this.host._activePlanSnapConflicts.map(t=>t.key)),i=j(5,this.host._cellCm,this.host._gridPitch),o=j(10,this.host._cellCm,this.host._gridPitch);return ce``}_syncPlanSnapActiveMarker(t){const e=this.host.renderRoot?.querySelector('[data-hp="plan-snap-active-marker"]');if(e){if(e.setAttribute("class",`plan-snap-node${t?" active":""}${"line"===t?.kind?" dynamic":""}`),e.setAttribute("data-active",t?"true":"false"),e.setAttribute("visibility",t?"visible":"hidden"),!t)return e.removeAttribute("data-kind"),void e.removeAttribute("data-key");e.setAttribute("data-kind",t.kind),e.setAttribute("data-key",t.key),e.setAttribute("cx",String(t.point[0])),e.setAttribute("cy",String(t.point[1])),e.setAttribute("r",String(j(10,this.host._cellCm,this.host._gridPitch)))}}_syncPlanSnapConflictMarkers(t){const e=new Set(t.map(t=>t.key));for(const t of this.host.renderRoot?.querySelectorAll('.plan-snap-node[data-kind="endpoint"]')||[])t.setAttribute("class","plan-snap-node"+(e.has(t.dataset.key||"")?" conflict":""))}_planSnapPhysicalSegment(t){let e=0;const s=this.host._spaceModel();if(!s)return null;if("partition"===t.sourceKind)e=Number(s.partitions.find(e=>e.id===t.sourceId)?.cm)||0;else if("draft"===t.sourceKind){const i=/^(.*):(\d+)$/.exec(t.sourceId),o=i?s.room_drafts.find(t=>t.id===i[1]):null;e=o&&i&&Number(o.segments[Number(i[2])]?.cm)||0}else e=Xs(s.rooms,this.host._spaceWalls,this.host._openCuts(),[t.a[0],t.a[1],t.b[0],t.b[1]],this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol);return e>0?{a:[...t.a],b:[...t.b],halfDepth:j(e,this.host._cellCm,this.host._gridPitch)/2}:null}_drawPreviewJoinPatchD(t,e){if(t.length<2)return"";const s=[];for(let i=0;i+10&&s.push({a:t[i],b:t[i+1],halfDepth:e[i]});if(!s.length)return"";const i=2e-4*this.host._gridPitch,o=this._planSnapGeometrySnapshot().value.segments.filter(e=>t.some(t=>C(t,[e.a[0],e.a[1],e.b[0],e.b[1]])<=i)).map(t=>this._planSnapPhysicalSegment(t)).filter(t=>!!t);return Zs([...s,...o],i).map(t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`).join(" ")}_renderMarkupLayer(t){const e=this.host._openCuts(),s=this.host._thickWallCuts(),i=e.concat(s),o=i.length?D(this.host._segments,i,.02*this.host._gridPitch):this.host._segments,n=this.host._path,r=this.host._gridPitch,l=this.host._viewOr(this.host._baseVb()),h="draw"===this.host._tool?this.host._drawWallCm:null,c=(()=>"draw"===this.host._tool&&n.length&&null!=h?this.host._contourClosed?n:this.host._cursorPt?[...n,this.host._cursorPt]:n.length>=2?n:null:null)(),d=c?Ra(c.length-1,this.host._contourClosed?[...this.host._draftSegmentCms,this.host._closingWallCm??void 0]:this.host._draftSegmentCms,h,A).map(t=>j(t,this.host._cellCm,this.host._gridPitch)/2):[],p=c?Qs(c,j(h,this.host._cellCm,this.host._gridPitch)/2,this.host._contourClosed,d):"",_=c?this._drawPreviewJoinPatchD(c,d):"",u=this.host._wallFaceBatch?.candidates[this.host._wallFaceBatch.index]?.repair||this.host._wallRepairDiagnostic;return ce` + ${this._gridLevels()?ce``:a} + ${o.map(t=>ce``)} + ${this._renderPhysicalEditorLayer()} + ${"column"===this.host._tool&&this.host._cursorPt&&this.host._drawWallCm?ce`{const t={shape:"square",center:this.host._cursorPt,cm:this.host._drawWallCm};return`M ${Jt(t,this.host._cellCm,this.host._gridPitch).map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`})()}>`:a} + ${p?ce` + `:a} + ${c&&0===h?ce`t.join(",")).join(" ")}>`:a} + ${_?ce` + `:a} + ${u?ce``:a} + ${"split"===this.host._tool&&this.host._splitSel?.pts?.length?ce`${this.host._splitSel.pts.length>1?ce``:a} + ${this.host._splitSel.pts.map((t,e)=>ce``)} + ${this.host._cursorPt?ce``:a}`:a} + `}_renderActiveChainInk(){const t=this.host._path,e=this.host._gridPitch;return ce` + ${t.length>1?ce``:a} + ${t.length&&this.host._cursorPt&&"draw"===this.host._tool&&!this.host._contourClosed?ce` + ${this.host._activePlanSnapCandidate||this.host._activePlanSnapConflicts.length?a:ce``}`:a} + ${t.map((t,s)=>ce``)} + `}_renderPartitionDeleteDialog(){const t=this.host._partitionDeleteDialog,e="mi"===this.host.hass?.config?.unit_system?.length;return o`this.host._partitionDeleteDialog=null}> +
+

${this.host._t("confirm.delete_partition_openings_body",{count:t.openings.length})}

+
    + ${t.openings.map(t=>o`
  • ${this.host._t("confirm.delete_partition_openings_item",{type:this.host._t(`opening.${t.type}`),length:ee(t.length*ol/this.host._gridPitch*this.host._cellCm,e)})}
  • `)} +
+
+
+ + + +
+
`}_renderRoomDeleteDialog(){const t=this.host._roomDeleteDialog;return o`this.host._roomDeleteDialog=null}> +
+

${this.host._t("confirm.delete_room_body")}

+
+
+ + + + +
+
`}_renderPhysicalDialog(){const t=this.host._physicalDialog,e="column"===t.kind;return o`this.host._physicalDialog=null}> +
+ ${e?o` + `:a} + +
this.host._physicalDialog={...t,cm:e.target.value}} /> + ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
+ ${e&&"square"===t.shape?o` + + this.host._physicalDialog={...t,angle:e.target.value}} />`:a} + ${t.length?o`
${this.host._t("physical.length")}: ${t.length}
`:a} +
+ +
`}_renderMarkupBar(){const t=this.host._geometryHistory.undoName,e=this.host._geometryHistory.redoName,s=t?this.host._t("history.undo_named",{name:t}):this.host._t("history.undo_empty"),i=e?this.host._t("history.redo_named",{name:e}):this.host._t("history.redo_empty");return o`
+
+ + + + + + + + + + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} + + + + +
+
+ +
+
`}_renderDevicesBar(){return o`
+
+ + + + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} +
+
+ +
+
`}_renderDeviceInbox(){const t=this.host._deviceInbox,e=this._deviceInboxRows(),s=Object.fromEntries(["on_plan","available","hidden","readd"].map(t=>[t,e.filter(e=>e.category===t).length])),i=function(t,e,s,i=!1){const o=s.trim().toLocaleLowerCase();return t.filter(t=>t.category===e&&(!i||t.isNew)&&(!o||t.searchText.includes(o)))}(e,t.tab,t.search,"on_plan"===t.tab&&t.onlyNew),n=i.slice(0,t.limit),r=t=>this.host._t(`device_inbox.tab_${t}`),l=`device_inbox.empty_${t.tab}`;return o`this.host._deviceInbox=null}> +
+
+ this.host._deviceInbox={...t,search:e.target.value,limit:100}} /> + +
+
this._deviceInboxTabKey(t)}> + ${["on_plan","available","hidden","readd"].map(e=>o` + `)} +
+
+ ${"on_plan"===t.tab?o``:a} + ${"available"===t.tab?o``:a} + +
+
+ ${n.length?n.map(t=>{const e="on_plan"===t.category?t.canFind?o``:o``:"hidden"===t.category?o``:o``,s="active"===t.status.kind?"":this.host._t(`device_inbox.status_${t.status.kind}`);return o`
+ +
+
${t.name} + ${t.isNew?o`${this.host._t("device_inbox.new")}`:a} +
+
+ ${[t.model,t.integration,t.spaceName,t.areaName].filter(Boolean).join(" · ")} +
+
+ ${this.host._t(`device_inbox.reason_${t.reason}`)} + ${s?o`${s}`:a} +
+ ${t.binding} +
+
+ ${e} + ${t.canEdit||t.canHide||"available"===t.category||"hidden"===t.category||this.host._bindingHasHaPage(t.binding)?o` +
+ + + +
+ ${t.canEdit&&("on_plan"!==t.category||t.canFind)?o``:a} + ${t.canHide?o``:a} + ${"available"===t.category?o``:a} + ${"hidden"===t.category?o``:a} + ${this.host._bindingHasHaPage(t.binding)?o``:a} +
+
`:a} +
+
`}):o`
${this.host._t(l)}
`} +
+ ${i.length>n.length?o``:a} +
+
+ +
+
`}_markerValueBadgeFields(t){return ti({touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition})}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=ns(t.room),s=Ze(t.binding,t.devId,()=>"__hp_device_preview__"),i=this.host._markers.find(e=>e.id===s||e.id===t.devId),o=ss(t.binding,t.controls,this.host._bindingEntities(t.binding)),a=this._effectiveStoredTapAction(t),n={id:s,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"===a&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:o.length?o:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=sl(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._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:i?.vacuum||null};return("virtual"===t.binding||t.room)&&(n.space=e?.space||("virtual"===t.binding?this.host._space:null),n.area=e?.area||null,n.room_id=e?.roomId||null),n}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const s=`${this.host._haRegistry.revision}\n${Et(this.host._markers)}\n${JSON.stringify(e)}`;if(this.host._markerPreviewMemo?.key===s)return this.host._markerPreviewMemo.device;const i=ei({hass:this.host.hass,registry:this.host._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this.host._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this.host._markers,settings:this.host._settings,excluded:this.host._excluded,showAll:this.host._showAll,firstSpaceId:this.host._model[0]?.id||this.host._space,loc:t=>this.host._t(t),iconRules:this.host._iconRules});return this.host._markerPreviewMemo={key:s,device:i},i}_markerPreviewDevices(t){const e=this.host._markerPreviewDevicesMemo;if(e?.base===this.host._devices&&e.preview===t)return e.devices;const s=[...this.host._devices.filter(e=>e.id!==t.id),t];return this.host._markerPreviewDevicesMemo={base:this.host._devices,preview:t,devices:s},s}_toggleIntent(t,e=this.host._devices){return si({hass:this.host._planHass,registryHass:this.host._fullRegistryHass,devices:e,device:t,virtualLights:this.host._virtualLights})}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s=this._markerPreviewDevices(e);return this._toggleIntent(e,s)}_toggleStateText(t,e){const s=this.host._planHass?.states?.[t]||this.host.hass?.states?.[t];try{return s&&"function"==typeof this.host.hass?.formatEntityState?this.host.hass.formatEntityState(s):e}catch{return e}}_toggleConfirmationStateText(t){const e=String(t.state||"unknown"),s=t.entityId?this._toggleStateText(t.entityId,e):e;if(s.trim().toLocaleLowerCase()!==e.trim().toLocaleLowerCase())return s;const i={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 i?this.host._t(i):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 ii(t,{state:t=>this._toggleConfirmationStateText(t),current:t=>this.host._t("confirm.current_state",{state:t}),expected:t=>this.host._t("confirm.expected_state",{state:t}),groupCurrent:(t,e)=>this.host._t("confirm.group_current",{on:t,total:e}),groupAllOn:()=>this.host._t("confirm.group_all_on"),groupAllOff:()=>this.host._t("confirm.group_all_off"),unavailable:t=>this.host._t("confirm.unavailable_targets",{count:t}),effect:t=>this.host._t(e[t]),expectedByHa:()=>this.host._t("confirm.expected_by_ha")})}_toggleHintLines(t){if(!t)return[];const e=t=>this.host._t(`marker.toggle_effect_${t.replace("-","_")}`),s=t=>this.host._t(`marker.toggle_skip_${t.replace("-","_")}`);return oi(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this.host._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),s=t.name||e;return this.host._t("marker.toggle_hint_single",{name:s,id:e})},group:t=>this.host._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,s)=>"virtual-light"===t.via?this.host._t("marker.virtual_light_current",{state:this.host._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(s)}):this.host._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(s)}),groupCurrentNext:(t,s)=>this.host._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(s)}),skipped:t=>this.host._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${s(t.reason)})`}).join(", ")}),none:t=>this.host._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:is(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),s=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},i="toggle"===s.tapAction?this._toggleHintLines(this._toggleIntentForDialog(s)).join(" "):"";return{...s,tapHintAnnouncement:i}}_valueBadgeForBinding(t,e){const s={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},i=this._markerPreviewDevice(s);if(!i)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const o=[...this.host._devices.filter(t=>t.id!==i.id),i],a=ts(this.host._planHass,i,o),n=es(this.host._planHass,i,a);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!n,valueBadgeSource:n,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s={...e,hidden:!1};return ai(ni(this.host._planHass,[...this.host._devices.filter(t=>t.id!==s.id),s],null,this.host._virtualLights).filter(t=>t.device.id===s.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},s=this._markerPreviewDevice(e);return!!s&&ri(this.host._planHass,{...s})}_setMarkerLightRole(t){const e=this.host._markerDialog;e&&(this.host._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.host.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this.host._planEntityAvailable(t)};const e=t.slice(7),s=this.host._markers.find(t=>t.id===e),i=this.host._devices.find(t=>t.id===e);if(!s||s.removed||!0!==s.is_light)return{label:this.host._t("marker.control_missing_label"),sub:`${this.host._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const o=this.host._serverCfg?.spaces.find(t=>t.id===(i?.space||s.space)),a=!!i&&li(i).length>0;return{label:s.name||i?.name||e,sub:[o?.title||i?.space||s.space,s.room_id||i?.area,a?"":this.host._t("marker.control_passive")].filter(Boolean).join(" · "),icon:s.icon||i?.icon||"mdi:lightbulb-outline",warning:!0===s.hidden||!0===i?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this.host._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this.host._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this.host._t("marker.value_badge_state",{name:t.label});const s=this.host.hass.states[e.entity_id]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this.host._t(`marker.value_badge_attr_${e.attribute}`,{name:s})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",s=[],i=new Set;for(const t of this.host._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this.host._bindingStatus(t.binding).kind)continue;const o=this.host._devices.find(e=>e.id===t.id);if(!o||o.hidden)continue;const a=this._controlRefInfo(`marker:${t.id}`);for(const t of li(o))i.add(t);s.push({value:`marker:${t.id}`,label:a.label,sub:a.sub,icon:a.icon,search:`${a.label} ${a.sub} ${t.id} ${li(o).join(" ")}`.toLowerCase()})}const o=Object.keys(this.host.hass.states||{}).filter(e=>hi(e)&&!i.has(e)&&ci(t.binding,[e],this.host._bindingEntities(t.binding)).length>0&&this.host._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()}}),a=t.controlsFilter.trim().toLowerCase();return[...s,...o].filter(e=>!t.controls.includes(e.value)&&(!a||e.search.includes(a))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const s=this._markerDraft(t)?.id||t.devId||"";if(!s)return void this.host._showToast(this.host._t("toast.marker_binding_required"));const i=e.slice(7),o=this._markerDraft(t),a=o?[...this.host._markers.filter(t=>t.id!==s),o]:this.host._markers;if(di(a,s,i))return void this.host._showToast(this.host._t("toast.marker_control_cycle"))}this.host._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this.host._markerDialog;if(!e)return;if("auto"===t)return void(this.host._markerDialog={...e,glowMode:t,glowTouched:!0});const s=this._markerSpatialSource(e),i=pi(s?this.host._planHass.states[s.eid]:void 0,null,this.host._fillColors.glow_light.c),o=!e.glowColorDrafted,a="fixed"===t&&!e.glowBrightnessDrafted;this.host._markerDialog={...e,glowMode:t,glowColor:o?i.c:e.glowColor,glowBrightness:a?Math.max(1,Math.round(100*i.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderMarkerDialog(){const t=this.host._markerDialog,e="virtual"===t.bindingMode,s=this._bindingCandidates();this.host._bindingEntities(t.binding);const i=e?null:this.host._bindingStatus(t.binding),n=!e&&this.host._bindingHasHaPage(t.binding),r=this._markerPreviewDevice(t),l=this._effectiveMarkerTapAction(t,r),h=r?ps(this.host._serverCfg?.spaces.find(t=>t.id===r.space)):null,c=r?this._markerPreviewDevices(r):this.host._devices,d="toggle"===l&&r?this._toggleIntent(r,c):null,p=this._toggleHintLines(d),_=r?_i(this.host._planHass,r,{liveStates:!1!==this.host._config?.live_states,showTemperature:!1!==this.host._config?.show_temperature,showSignal:h?.showLqi??!1!==this.host._config?.show_signal,designPreview:!0,activityRuntime:this.host._activityRt.get(r.id),lightDevices:c,registryHass:this.host._fullRegistryHass,reducedMotion:this.host._reducedMotion}):null,u=r?ts(this.host._planHass,r,c):[],m=r?es(this.host._planHass,r,u):null,g=t.valueBadgeTouched?t.valueBadgeEnabled:!!_?.valueBadge,f=t.valueBadgeTouched?t.valueBadgeSource:_?.valueBadge?.source||t.valueBadgeSource,b=t.valueBadgeTouched?t.valueBadgePosition:_?.valueBadge?.position||t.valueBadgePosition,y=ui(f),v=!!f&&!u.some(t=>t.key===y),$=u.find(t=>t.key===y),w=_?.valueSource?_.valueSource.attribute?`attr:${_.valueSource.eid}:${_.valueSource.attribute}`:`state:${_.valueSource.eid}`:"",k=this._markerAutoHasSpatialSource(t),x=!!r&&mi(this.host._planHass,{...r}),S=gi(t.lightRole,k,x,t.glowMode),M=!S.sourceExists,D=!S.fromSourceEnabled,C=S.passive,P=S.effectiveMode,I="never"===t.lightRole?this.host._t("marker.glow_disabled_never"):"auto"!==t.lightRole||k?C?this.host._t("marker.glow_passive_hint"):this.host._t("marker.glow_disabled_no_entity"):this.host._t("marker.glow_disabled_auto"),T=r?li(r):[],R=r&&fi(r)||"",F=!!t.lightEntity&&!T.includes(t.lightEntity),N=r?bi(r):[],z=!!t.toggleEntity&&!N.includes(t.toggleEntity),A="toggle"===l?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,O=A?[...A.targets,...A.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",L=(()=>{if(e)return null;const i=s.find(e=>e.value===t.binding);if(i)return i.label;const[o,a]=t.binding.split(":");return"device"===o?this.host._fullRegistryHass.devices[a]?.name_by_user||this.host._fullRegistryHass.devices[a]?.name||a:this.host._fullRegistryHass.entities[a]?.name||this.host.hass.states[a]?.attributes?.friendly_name||a})();return o`this._closeMarkerDialog()}> +
+ ${"ha_disabled"===i?.kind?o`
+ + ${this.host._t(`marker.ha_disabled_${i.reason}`)} + ${n?o``:a} +
`:"unverified"===i?.kind&&t.binding?o`
+ + ${this.host._t("marker.ha_registry_limited")} +
`:a} + + this.host._markerDialog={...t,name:e.target.value}} /> + + +
+ +
+ + +
+ ${"ha"===t.bindingMode?o` + ${t.bindingOpen?o`
+ this.host._markerDialog={...t,bindingFilter:e.target.value}} /> +
+ ${s.map(e=>o`
{const s={...t,binding:e.value,bindingOpen:!1,controls:ss(e.value,t.controls,this.host._bindingEntities(e.value)),autoIcon:this.host._autoIconForBinding(e.value)};this.host._markerDialog=this._announceToggleDraft({...s,...this._valueBadgeForBinding(s,e.value)})}}> + ${e.label}${e.sub} +
`)} + ${s.length?a:o`
${this.host._t("marker.nothing_found")}
`} +
+
`:a}`:a} +
+ + + + + ${this._renderVacSection(t)} + + + + ${"toggle"===l&&(N.length>1||z)?o`
+
+ + ${this._help("marker.toggle_entity.help")} +
+ + ${z?o`

+ + ${this.host._t("marker.toggle_entity_missing",{entity:t.toggleEntity,fallback:O||this.host._t("marker.toggle_entity_none")})} +

`:a} +
`:a} + ${"toggle"===l?o`
+ ${p.map(t=>o`
${t}
`)} +
+
${t.tapHintAnnouncement}
`:a} + ${"run"===l?(()=>{const e=t.runFilter.trim().toLowerCase(),s=this._runCandidates().filter(t=>!e||t.label.toLowerCase().includes(e)||t.value.includes(e)),i=t.tapTarget?this._runCandidates().find(e=>e.value===t.tapTarget):null;return o` + + ${t.tapTarget&&!i?o`
${this.host._t("marker.run_target_gone",{id:t.tapTarget})}
`:a} + {t.target.select()}} + @input=${e=>this.host._markerDialog={...t,runFilter:e.target.value,tapTarget:""}} /> + ${i?a:o`
+ ${s.slice(0,40).map(e=>o`
this.host._markerDialog={...t,tapTarget:e.value,runFilter:""}}> + ${e.label}${e.sub} +
`)} + ${s.length?a:o`
${this.host._t("marker.nothing_found")}
`} +
`}`})():a} + ${"run"===l||"toggle"===l?o``:a} + + +
${this.host._t("marker.controls_hint")}
+ ${t.controls.length?o`
+ ${t.controls.map(e=>{const s=this._controlRefInfo(e);return o` + ${s.label} + this.host._markerDialog=this._announceToggleDraft({...t,controls:t.controls.filter(t=>t!==e)})}> + `})} +
`:a} + this.host._markerDialog={...t,controlsFilter:e.target.value}} /> + ${t.controlsFilter.trim()?o`
+ ${this._controlCandidates(t).map(e=>o``)} +
`:a} + + ${this.host._bindingHasClimate(t.binding)?o``:a} +
+ ${this.host._t("marker.light_role_label")}${this._help("marker.light_role.help")} +
+ + + +
+
+ + ${"always"===t.lightRole&&(T.length>1||F)?o`
+
+ + ${this._help("marker.light_entity.help")} +
+ + ${F?o`

+ + ${this.host._t("marker.light_entity_missing",{entity:t.lightEntity,fallback:R||"—"})} +

`:a} +
`:a} + +
+ ${this.host._t("marker.glow_color_label")}${this._help("marker.glow_mode.help")} +
+ + + +
+ ${"auto"!==P?o`
+ {this.host._markerDialog={...t,glowMode:P,glowColor:e.detail.color,glowColorDrafted:!0,glowTouched:!0}}}> + ${"fixed"===P?o` + ${this.host._t("marker.glow_brightness")} + ${this._rangeInput(1,100,1,t.glowBrightness,e=>{this.host._markerDialog={...t,glowMode:P,glowBrightness:e,glowBrightnessDrafted:!0,glowTouched:!0}},M,this.host._t("marker.glow_brightness"))} + ${Math.round(t.glowBrightness)}%`:a} +
`:a} +
+
+
+ + ${this._help("marker.glow_radius.help")} +
+
+ this.host._markerDialog={...t,glowRadius:e.target.value}} /> + ${this.host._imperial?this.host._t("gs.unit_ft"):this.host._t("gs.unit_m")} +
+
+ ${M||C?o`

+ ${I} +

`:a} + + + ${customElements.get("ha-icon-picker")?o`{const s=e.detail.value||"";(t.icon||s!==t.autoIcon)&&(this.host._markerDialog={...t,icon:s})}}>`:o`this.host._markerDialog={...t,icon:e.target.value}} />`} + ${!t.icon&&t.autoIcon?o`

+ ${this.host._t("marker.icon_auto",{icon:t.autoIcon})} +

`:a} + + + +

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

+ ${"static_icon"===t.display&&this.host._bindingHasAlarm(t.binding)?o`
+ + ${this.host._t("marker.static_alarm_warning")} +
`:a} +
+ ${this.host._t("marker.value_badge_title")}${this._help("marker.value_badge.help")} + + ${"static_icon"===t.display?o`

+ ${this.host._t("marker.value_badge_static")} +

`:u.length||t.valueBadgeSource?a:o`

+ ${this.host._t("marker.value_badge_empty")} +

`} + ${g?o` +
+ + ${this._help("marker.value_badge_source.help")} +
+ + ${$?o`

${$.technical}

`:a} + ${v?o`

+ ${this.host._t("marker.value_badge_missing_hint")} +

`:a} + ${"value"===t.display&&y===w?o`

+ ${this.host._t("marker.value_badge_duplicate")} +

`:a} +
+ + ${this._help("marker.value_badge_position.help")} +
+ + `:a} +
+ ${_?o` + `:o`
+ + ${this.host._t("marker.preview.select_source")} +
`} + ${"icon_ripple"===t.display?o`
+ {this.host._markerDialog={...t,rippleColor:e.detail.color}}}> +
+
+ ${this.host._t("marker.ripple_size")} + ${this._rangeInput(1,8,.5,t.rippleSize,e=>this.host._markerDialog={...t,rippleSize:e})} + ×${t.rippleSize} +
+

${this.host._t("marker.activity_alarm_note")}

`:a} + + +
+ ${this._rangeInput(.5,3,.1,t.size,e=>this.host._markerDialog={...t,size:e})} + ×${t.size.toFixed(1)} + ${this.host._t("marker.angle_label")} + ${""} + ${this._rangeInput(0,355,5,t.angle,e=>this.host._markerDialog={...t,angle:e})} + ${t.angle}° +
+ + + this.host._markerDialog={...t,model:e.target.value}} /> + + + this.host._markerDialog={...t,link:e.target.value}} /> + + + + + +
+ ${t.pdfs.map(t=>o` + ${t.name} + this._removeMarkerPdf(t.url)}>`)} + + + this._pickMarkerFiles(t)} /> + +
+
+
+
+ ${t.devId?o``:a} + ${t.devId?o``:a} +
+
+ + +
+
+
`}_renderSpaceDialog(){const t=this.host._spaceDialog,e=this.host._importTotal>0&&"create"===t.mode?this.host._t("import.progress",{i:this.host._importTotal-this.host._importQueue.length,n:this.host._importTotal}):"",s=()=>{this.host._spaceDialog=null,this.host._importQueue=[],this.host._importTotal=0};return o` +
+ + this.host._spaceDialog={...t,title:e.target.value}} /> + + + ${"file"===t.source?o`
+ ${t.planFile?o`${t.planFile.name}`:t.planUrl?o`${this.host._t("space.plan_alt")}`:o`${this.host._t("space.no_plan")}`} + + + this._pickPlanFile(t)} /> + + +
+ ${t.pickSaved?this._renderServerPlans(t):a}`:a} + + + +
+ {const s=e.target.value,i=sl(s),o=null==i?null:ki(i,this.host._imperial);this.host._spaceDialog={...t,cellCmInput:s,cellCmTouched:!0,cellCm:null!=o&&o>0?Math.max(.1,Math.min(el,o)):t.cellCm}}} /> + ${this.host._t(this.host._imperial?"space.scale_unit_imperial":"space.scale_unit")} +
+ + + + + +
${this.host._t("space.zero_wall_help")}
+ + + ${""} + +
${this.host._t("space.hide_decor_tip")}
+ +
${this.host._t("space.hide_openings_tip")}
+ + ${[["labelTemp","space.label_temp"],["labelHum","space.label_hum"],["labelLqi","space.label_lqi"],["labelLight","space.label_light"]].map(([e,s])=>o``)} + +
+ ${this._rangeInput(50,300,5,Math.round(100*t.cardFontScale),e=>this.host._spaceDialog={...t,cardFontScale:e/100})} + ${Math.round(100*t.cardFontScale)}% +
+ ${this.host._renderCardPreview(t.cardFontScale,1,1)} +
+ {this.host._spaceDialog={...t,roomColor:e.detail.color,roomOpacity:e.detail.opacity}}}> +
+ + + ${"static"===(t.bgMode??St(this.host._settings,{}))?o`
+ {this.host._spaceDialog={...t,bgColor:e.detail.color}}}> + ${t.bgColor?o``:o`${this.host._t("space.bg_inherited")}`} +
`:a} + +
+ {const s=e.target.value.trim(),i=""===s?null:Math.round(Number(s));this.host._spaceDialog={...t,northDeg:null!==i&&Number.isFinite(i)?Math.min(359,Math.max(0,i)):null}}} /> + ${null===t.northDeg?this.host._t("space.north_inherited",{v:null===Mt(this.host._settings,{})?"—":String(Mt(this.host._settings,{}))+"°"}):"°"} +
+ + + + ${xi.map(t=>[t,"fill."+t]).map(([e,s])=>o` + ${"custom"===e&&"custom"===t.fillMode?o`
+ ${this.host._t("space.custom_fill")} + {this.host._spaceDialog={...t,customFill:{c:e.detail.color,a:e.detail.opacity}}}}> + ${t.customFill?o``:a} +
`:a}`)} + + ${t.deleteBlockers?o``:a} +
+ +
`}_renderMergeDialog(){const t=this.host._mergeDialog,e=this.host._spaceModel()?.rooms||[],s=(s,i)=>{const a=e.find(t=>t.id===s),n=a?.area?this.host.hass.areas[a.area]?.name:null;return o``};return o`this.host._mergeDialog=null}> +
+

${this.host._t("merge.hint")}

+ + ${s(t.aId,"a")} + ${s(t.bId,"b")} +
+
+ + + +
+
`}_renderRoomSource(t){const e="temp"===t?this.host._roomTempSrc:this.host._roomHumSrc,s=e=>{"temp"===t?this.host._roomTempSrc=e:this.host._roomHumSrc=e,this.host.requestUpdate()},i=this.host._roomSrcOpen===t;return o` + + + + ${e||i?o` + ${i?o`
+ {this.host._roomSrcFilter=t.target.value,this.host.requestUpdate()}} /> +
+ ${this._roomSrcCandidates().map(t=>o`
{s(t.value),this.host._roomSrcOpen=null}}> + ${t.label}${t.sub} +
`)} +
+
`:a}`:a}`}_renderRoomDialog(){const t=!!this.host._roomEditId,e=t?null:this.host._wallFaceBatch,s=e&&e.candidates.length>1?this.host._t("room.queue_progress",{current:e.index+1,total:e.candidates.length}):"",i=!!this.host._areaSel||!!this.host._nameSel.trim(),n=ps(this.host._curSpaceCfg),r=this.host._roomFill||n.fill,l=this.host._roomCustomFill||n.customFill,h=[...this.host._freeAreas];if(t&&this.host._areaSel&&!h.some(t=>t.area_id===this.host._areaSel)){const t=this.host.hass.areas[this.host._areaSel];t&&h.unshift(t)}return o`this._roomDialogCancel()}> +
+ ${s?o`

+ ${s} +

`:a} + + this.host._nameSel=t.target.value} /> + + + + + + ${[["","fill.inherit"],...Si.map(t=>[t,"fill."+t])].map(([t,e])=>o``)} + ${"custom"===r?o`
+ ${this.host._roomCustomFill?this.host._t("room.custom_fill_own"):this.host._t("room.custom_fill_space")} + {this.host._roomCustomFill={c:t.detail.color,a:t.detail.opacity}}}> + ${this.host._roomCustomFill?o``:a} +
`:a} + ${this._renderRoomSource("temp")} + ${this._renderRoomSource("hum")} + + + +
+ ${this._rangeInput(50,300,5,Math.round(100*this.host._roomNameScale),t=>{this.host._roomNameScale=t/100,this.host.requestUpdate()})} + ${Math.round(100*this.host._roomNameScale)}% +
+ +
+ ${this._rangeInput(50,300,5,Math.round(100*this.host._roomLabelScale),t=>{this.host._roomLabelScale=t/100,this.host.requestUpdate()})} + ${Math.round(100*this.host._roomLabelScale)}% +
+ ${this.host._renderCardPreview(ps(this.host._curSpaceCfg).cardFontScale,this.host._roomNameScale,this.host._roomLabelScale)} +
+
+ + + ${t?o``:o`${this.host._pendingSplit?a:o``} + `} +
+
`}}export{rl as EDITOR_RUNTIME_FINGERPRINT,ll as HouseplanEditorRuntime}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js b/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js new file mode 100644 index 00000000..8c2b8480 --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js @@ -0,0 +1,217 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";import{bU as t,bV as s,bW as e,bX as o,aq as a,bY as l,c1 as i,bZ as h,b_ as n,b$ as c,c0 as r,b as p,A as _,cV as d,ap as u,ar as g,cW as m}from"./houseplan-card-OQuczTJf.js";import{i as b,c as $,a as v,s as f,t as y}from"./space-deletion-7mvB_XVT.js";const w=1e3,D=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},S="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";class C{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_openSpaceDialog(p,_){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===p){const i=this.host._serverCfg.spaces.find(t=>t.id===_);if(!i)return;const h=t(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?s(i.settings.custom_fill):null,c="none"===h.fill?{...n||e,a:0}:n;return void(this.host._spaceDialog={mode:p,spaceId:_,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:h.showBorders,showNames:h.showNames,zeroWallStyle:l(i),displayTouched:!0,hideDecor:h.hideDecor,hideOpenings:h.hideOpenings,roomColor:h.color,roomOpacity:h.opacity,fillMode:"none"===h.fill?"custom":h.fill,customFill:c,glowEnabled:h.glow,bgColor:h.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:a({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:h.tempMin,tempMax:h.tempMax,showLqi:h.showLqi??this.host._config?.show_signal??!0,cardFontScale:h.cardFontScale,labelTemp:h.labelTemp,labelHum:h.labelHum,labelLqi:h.labelLqi,labelLight:h.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:o(Number(i.cell_cm)>0?Number(i.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const d=i(this.host._imperial);this.host._spaceDialog={mode:p,title:"",planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:{...e,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:d,cellCmInput:o(d,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;const o={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[e.type]||(e.name.toLowerCase().endsWith(".svg")?"svg":"");if(!o)return void this.host._showToast(this.host._t("toast.plan_formats"));const a=new Uint8Array(await e.arrayBuffer());let l="";for(let t=0;t{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:1.414),s.onerror=()=>t(1.414),s.src=h});URL.revokeObjectURL(h),this.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:o,b64:i,aspect:n,name:e.name}}}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`
${this.host._t("space.loading")}
`;const s=t.saved||[];if(!s.length)return p`
${this.host._t("space.no_saved")}
`;return p`
+ ${s.map(s=>{return p` +
+ +
+ ${s.name} + ${e=s.size,e>=1048576?`${(e/1048576).toFixed(1)} MB`:`${Math.round(e/1024)} KB`}${s.used_by.length?` · ${this.host._t("space.used_by",{list:s.used_by.join(", ")})}`:""} +
+ + +
`;var e})} +
`}async _saveConfigNow(){this.host._cfgEpoch++;try{await this.host._writeConfig()}catch(t){const s=t;throw s?.physicalGeometryRolledBack?await this.host._reloadRejectedPhysicalWrite():"conflict"===s?.code&&await this.host._reloadConfigOnly(),t}}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const s="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const e="create"===t.mode?`s${Date.now().toString(36)}`:t.spaceId;let o=null;if("file"===t.source&&t.planFile){o={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:e,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let a=t.savedAspect||null;!o&&"file"===t.source&&t.planUrl&&!a&&this.host._aspectJob&&(a=await this.host._aspectJob||null);const l=this.host._serverCfg;let i=l.spaces.find(t=>t.id===e);if("create"===t.mode)i=$(e,t.title.trim()),l.spaces.push(i);else{if(!i)throw new Error(`space ${e} is gone from the config`);i.title=t.title.trim()}if(!i)throw new Error(`space ${e} is unavailable`);if(o?(i.plan_url=o.url,i.plan_aspect=o.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==i.plan_url&&(i.plan_url=t.planUrl,i.plan_aspect=a),"draw"===t.source&&(i.plan_url=null,i.plan_aspect=null,delete i.plan_x,delete i.plan_y,delete i.plan_scale,delete i.plan_scale_x,delete i.plan_scale_y,delete i.plan_angle),i.settings={...i.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):n,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):h,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},i.zero_wall_style=t.zeroWallStyle,i.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(w,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(i.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length)this._openNextImport();else if(s||this.host._importTotal>0){const t=this.host._importTotal>0;this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),await this.host._requestMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._showToast(this.host._t(s&&!t?"toast.space_added_onboard":"import.done"))}else this.host._showToast(this.host._t("create"===t.mode?"toast.space_added":"toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?await this.host._requestMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._saveNav()))}catch(t){const s=t;"conflict"!==s?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const s=this.host._serverCfg;if(!s)return;const e=s.spaces.find(s=>s.id===t.spaceId);if(!e)return;const o=v(s,this.host._layout||{},t.spaceId||""),a=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;if(!o.count||a){if(confirm(this.host._t("confirm.delete_space",{title:e.title}))){this.host._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain;const s=await this.host.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev}),[e,o]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._adoptStructuralResponses(e,o),this.host._cfgRev=s?.config_rev??this.host._cfgRev,this.host._layoutRev=s?.layout_rev??this.host._layoutRev,this.host._spaceDialog=null,this.host._space===t.spaceId&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(s){const e=s;"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const o=this.host._serverCfg;if(this.host._spaceDialog&&o){const s=v(o,this.host._layout||{},t.spaceId||""),e=1===o.spaces.length&&o.spaces[0]?.id===t.spaceId;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:e?0:s.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(s)}))}}}else this.host._spaceDialog={...t,deleteBlockers:o.count}}_startImport(){const t=this.host._importDialog;if(!t)return;const s=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,s.length?(this.host._importQueue=s,this.host._importTotal=s.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();if(void 0===t)return;const s=i(this.host._imperial);this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:s,cellCmInput:o(s,this.host._imperial),cellCmTouched:!1,busy:!1}}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this.host._requestMode("plan").then(()=>{this.host._showToast(this.host._t("import.done"))}))}_renderImportDialog(){const t=this.host._importDialog,s=t.floors.filter(t=>t.checked).length;return p`this.host._importDialog=null}> +
+
${this.host._t("import.hint")}
+ ${t.floors.map((s,e)=>p``)} +
+
+ + + +
+
`}_boolInput(t,s){return p`s(t.target.checked)} />`}_rangeInput(t,s,e,o,a){return p`a(Number(t.target.value))} />`}_renderSpaceDialog(){return this._renderSpaceDialogBody(this.host._spaceDialog)}_renderSpaceDialogBody(t){const s=this.host._importTotal>0&&"create"===t.mode?this.host._t("import.progress",{i:this.host._importTotal-this.host._importQueue.length,n:this.host._importTotal}):"",l=()=>{this.host._spaceDialog=null,this.host._importQueue=[],this.host._importTotal=0};return p` +
+ + this.host._spaceDialog={...t,title:s.target.value}} /> + + + ${"file"===t.source?p`
+ ${t.planFile?p`${t.planFile.name}`:t.planUrl?p`${this.host._t("space.plan_alt")}`:p`${this.host._t("space.no_plan")}`} + + + this._pickPlanFile(t)} /> + + +
+ ${t.pickSaved?this._renderServerPlans(t):_}`:_} + + + +
+ {const e=s.target.value,o=D(e),a=null==o?null:d(o,this.host._imperial);this.host._spaceDialog={...t,cellCmInput:e,cellCmTouched:!0,cellCm:null!=a&&a>0?Math.max(.1,Math.min(w,a)):t.cellCm}}} /> + ${this.host._t(this.host._imperial?"space.scale_unit_imperial":"space.scale_unit")} +
+ + + + + +
${this.host._t("space.zero_wall_help")}
+ + + +
${this.host._t("space.hide_decor_tip")}
+ +
${this.host._t("space.hide_openings_tip")}
+ + ${[["labelTemp","space.label_temp"],["labelHum","space.label_hum"],["labelLqi","space.label_lqi"],["labelLight","space.label_light"]].map(([s,e])=>p``)} + +
+ ${this._rangeInput(50,300,5,Math.round(100*t.cardFontScale),s=>{this.host._spaceDialog={...t,cardFontScale:s/100}})} + ${Math.round(100*t.cardFontScale)}% +
+ ${this.host._renderCardPreview(t.cardFontScale,1,1)} +
+ {this.host._spaceDialog={...t,roomColor:s.detail.color,roomOpacity:s.detail.opacity}}}> +
+ + + ${"static"===(t.bgMode??u(this.host._settings,{}))?p` +
+ {this.host._spaceDialog={...t,bgColor:s.detail.color}}}> + ${t.bgColor?p``:p`${this.host._t("space.bg_inherited")}`} +
`:_} + +
+ {const e=s.target.value.trim(),o=""===e?null:Math.round(Number(e));this.host._spaceDialog={...t,northDeg:null!==o&&Number.isFinite(o)?Math.min(359,Math.max(0,o)):null}}} /> + ${null===t.northDeg?this.host._t("space.north_inherited",{v:null===a(this.host._settings,{})?"—":`${a(this.host._settings,{})}°`}):"°"} +
+ + + + ${m.map(t=>[t,`fill.${t}`]).map(([s,o])=>p` + ${"custom"===s&&"custom"===t.fillMode?p` +
+ ${this.host._t("space.custom_fill")} + {this.host._spaceDialog={...t,customFill:{c:s.detail.color,a:s.detail.opacity}}}}> + ${t.customFill?p``:_} +
`:_}`)} + + ${t.deleteBlockers?p``:_} +
+ +
`}}export{C as HouseplanOnboardingRuntime,S as ONBOARDING_RUNTIME_FINGERPRINT}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/space-deletion-7mvB_XVT.js b/custom_components/houseplan/frontend/houseplan-assets/space-deletion-7mvB_XVT.js new file mode 100644 index 00000000..8496f87c --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/space-deletion-7mvB_XVT.js @@ -0,0 +1 @@ +function e(e,o){return{id:e,title:o,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function o(e="file"){const o="draw"===e;return{source:e,showBorders:o,showNames:o,displayTouched:!1}}function r(e,o){if(e.displayTouched)return{...e,source:o};const r="draw"===o;return{...e,source:o,showBorders:r,showNames:r}}function s(e,o,r){return{...e,[o]:r,displayTouched:!0}}function t(e,o,r){const s=(e?.spaces||[]).find(e=>e?.id===r),t=new Set((s?.rooms||[]).map(e=>String(e?.id||"")).filter(Boolean)),n=[...new Set((e?.markers||[]).filter(e=>!0!==e?.removed&&"string"==typeof e?.id).filter(e=>e.space===r||"string"==typeof e.room_id&&t.has(e.room_id)||o?.[e.id]?.s===r).map(e=>e.id))].sort((e,o)=>e.localeCompare(o));return{markerIds:n,count:n.length}}globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";export{t as a,e as c,o as i,r as s,s as t}; diff --git a/dist/houseplan-assets/editor-DMlizeQy.js b/dist/houseplan-assets/editor-DMlizeQy.js new file mode 100644 index 00000000..303a4630 --- /dev/null +++ b/dist/houseplan-assets/editor-DMlizeQy.js @@ -0,0 +1,14 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";import{c as e,l as o,t,d2 as s,A as a,b as l}from"./houseplan-card-OQuczTJf.js";class i extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],l=this._floorToken;l&&a.push({value:l,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const i="string"==typeof this._config?.floor?this._config.floor:"";i&&!e.some(e=>e.value===i)&&a.push({value:i,label:i}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;this._loadSpaces();const e=this._lang,o={title:t(e,"editor.title"),floor:t(e,"editor.floor"),default_floor:t(e,"editor.default_floor"),language:t(e,"editor.language"),icon_size:t(e,"editor.icon_size"),show_temperature:t(e,"editor.show_temperature"),live_states:t(e,"editor.live_states"),show_signal:t(e,"editor.show_signal"),kiosk:t(e,"editor.kiosk"),cycle:t(e,"editor.cycle")},s=this._schema,i=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),n=e=>l`o[e.name]||e.name} + @value-changed=${this._valueChanged} + >`;return l` + ${n(s.slice(0,3))} + ${i?l``:a} + ${n(s.slice(3))} + `}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}i.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",i); diff --git a/dist/houseplan-assets/houseplan-card-OQuczTJf.js b/dist/houseplan-assets/houseplan-card-OQuczTJf.js new file mode 100644 index 00000000..4e59d7d6 --- /dev/null +++ b/dist/houseplan-assets/houseplan-card-OQuczTJf.js @@ -0,0 +1,5238 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";const e=globalThis,t=e.ShadowRoot&&(void 0===e.ShadyCSS||e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),n=new WeakMap;let r=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const i=this.t;if(t&&void 0===e){const t=void 0!==i&&1===i.length;t&&(e=n.get(i)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),t&&n.set(i,e))}return e}toString(){return this.cssText}};const o=(e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,i,n)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+e[n+1],e[0]);return new r(n,e,i)},s=t?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return(e=>new r("string"==typeof e?e:e+"",void 0,i))(t)})(e):e,{is:a,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:u}=Object,p=globalThis,_=p.trustedTypes,m=_?_.emptyScript:"",g=p.reactiveElementPolyfillSupport,f=(e,t)=>e,v={toAttribute(e,t){switch(t){case Boolean:e=e?m:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},y=(e,t)=>!a(e,t),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=b){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&l(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:r}=c(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);r?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??b}static _$Ei(){if(this.hasOwnProperty(f("elementProperties")))return;const e=u(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(f("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(f("properties"))){const e=this.properties,t=[...h(e),...d(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(s(e))}else void 0!==e&&t.push(s(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.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(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,n)=>{if(t)i.adoptedStyleSheets=n.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const t of n){const n=document.createElement("style"),r=e.litNonce;void 0!==r&&n.setAttribute("nonce",r),n.textContent=t.cssText,i.appendChild(n)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const r=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(t,i.type);this._$Em=e,null==r?this.removeAttribute(n):this.setAttribute(n,r),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),r="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:v;this._$Em=n;const o=r.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,r){if(void 0!==e){const o=this.constructor;if(!1===n&&(r=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??y)(r,t)||i.useDefault&&i.reflect&&r===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:r},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==r||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[f("elementProperties")]=new Map,w[f("finalized")]=new Map,g?.({ReactiveElement:w}),(p.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,x=e=>e,$=k.trustedTypes,S=$?$.createPolicy("lit-html",{createHTML:e=>e}):void 0,M="$lit$",R=`lit$${Math.random().toFixed(9).slice(2)}$`,T="?"+R,C=`<${T}>`,D=document,A=()=>D.createComment(""),O=e=>null===e||"object"!=typeof e&&"function"!=typeof e,z=Array.isArray,P="[ \t\n\f\r]",F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,I=/-->/g,E=/>/g,N=RegExp(`>|${P}(?:([^\\s"'>=/]+)(${P}*=${P}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),H=/'/g,L=/"/g,q=/^(?:script|style|textarea|title)$/i,j=e=>(t,...i)=>({_$litType$:e,strings:t,values:i}),B=j(1),W=j(2),U=Symbol.for("lit-noChange"),G=Symbol.for("lit-nothing"),V=new WeakMap,K=D.createTreeWalker(D,129);function Y(e,t){if(!z(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(t):t}const Z=(e,t)=>{const i=e.length-1,n=[];let r,o=2===t?"":3===t?"":"",s=F;for(let t=0;t"===l[0]?(s=r??F,c=-1):void 0===l[1]?c=-2:(c=s.lastIndex-l[2].length,a=l[1],s=void 0===l[3]?N:'"'===l[3]?L:H):s===L||s===H?s=N:s===I||s===E?s=F:(s=N,r=void 0);const d=s===N&&e[t+1].startsWith("/>")?" ":"";o+=s===F?i+C:c>=0?(n.push(a),i.slice(0,c)+M+i.slice(c)+R+d):i+R+(-2===c?t:d)}return[Y(e,o+(e[i]||"")+(2===t?"":3===t?"":"")),n]};class X{constructor({strings:e,_$litType$:t},i){let n;this.parts=[];let r=0,o=0;const s=e.length-1,a=this.parts,[l,c]=Z(e,t);if(this.el=X.createElement(l,i),K.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(n=K.nextNode())&&a.length0){n.textContent=$?$.emptyScript:"";for(let i=0;iz(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==G&&O(this._$AH)?this._$AA.nextSibling.data=e:this.T(D.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:i}=e,n="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=X.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(t);else{const e=new Q(n,this),i=e.u(this.options);e.p(t),this.T(i),this._$AH=e}}_$AC(e){let t=V.get(e.strings);return void 0===t&&V.set(e.strings,t=new X(e)),t}k(e){z(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,n=0;for(const r of e)n===t.length?t.push(i=new ee(this.O(A()),this.O(A()),this,this.options)):i=t[n],i._$AI(r),n++;n2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=G}_$AI(e,t=this,i,n){const r=this.strings;let o=!1;if(void 0===r)e=J(this,e,t,0),o=!O(e)||e!==this._$AH&&e!==U,o&&(this._$AH=e);else{const n=e;let s,a;for(e=r[0],s=0;s{const n=i?.renderBefore??t;let r=n._$litPart$;if(void 0===r){const e=i?.renderBefore??null;n._$litPart$=r=new ee(t.insertBefore(A(),e),e,void 0,i??{})}return r._$AI(e),r},ce=globalThis;let he=class extends w{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=le(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return U}};he._$litElement$=!0,he.finalized=!0,ce.litElementHydrateSupport?.({LitElement:he});const de=ce.litElementPolyfillSupport;de?.({LitElement:he}),(ce.litElementVersions??=[]).push("4.2.2");const ue=2,pe=e=>(...t)=>({_$litDirective$:e,values:t});let _e=class{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}};const{I:me}=se,ge=e=>e,fe=()=>document.createComment(""),ve=(e,t,i)=>{const n=e._$AA.parentNode,r=void 0===t?e._$AB:t._$AA;if(void 0===i){const t=n.insertBefore(fe(),r),o=n.insertBefore(fe(),r);i=new me(t,o,e,e.options)}else{const t=i._$AB.nextSibling,o=i._$AM,s=o!==e;if(s){let t;i._$AQ?.(e),i._$AM=e,void 0!==i._$AP&&(t=e._$AU)!==o._$AU&&i._$AP(t)}if(t!==r||s){let e=i._$AA;for(;e!==t;){const t=ge(e).nextSibling;ge(n).insertBefore(e,r),e=t}}}return i},ye=(e,t,i=e)=>(e._$AI(t,i),e),be={},we=(e,t=be)=>e._$AH=t,ke=e=>{e._$AR(),e._$AA.remove()},xe=(e,t,i)=>{const n=new Map;for(let r=t;r<=i;r++)n.set(e[r],r);return n},$e=pe(class extends _e{constructor(e){if(super(e),e.type!==ue)throw Error("repeat() can only be used in text expressions")}dt(e,t,i){let n;void 0===i?i=t:void 0!==t&&(n=t);const r=[],o=[];let s=0;for(const t of e)r[s]=n?n(t,s):s,o[s]=i(t,s),s++;return{values:o,keys:r}}render(e,t,i){return this.dt(e,t,i).values}update(e,[t,i,n]){const r=(e=>e._$AH)(e),{values:o,keys:s}=this.dt(t,i,n);if(!Array.isArray(r))return this.ut=s,o;const a=this.ut??=[],l=[];let c,h,d=0,u=r.length-1,p=0,_=o.length-1;for(;d<=u&&p<=_;)if(null===r[d])d++;else if(null===r[u])u--;else if(a[d]===s[p])l[p]=ye(r[d],o[p]),d++,p++;else if(a[u]===s[_])l[_]=ye(r[u],o[_]),u--,_--;else if(a[d]===s[_])l[_]=ye(r[d],o[_]),ve(e,l[_+1],r[d]),d++,_--;else if(a[u]===s[p])l[p]=ye(r[u],o[p]),ve(e,r[d],r[u]),u--,p++;else if(void 0===c&&(c=xe(s,p,_),h=xe(a,d,u)),c.has(a[d]))if(c.has(a[u])){const t=h.get(s[p]),i=void 0!==t?r[t]:null;if(null===i){const t=ve(e,r[d]);ye(t,o[p]),l[p]=t}else l[p]=ye(i,o[p]),ve(e,r[d],i),r[t]=null;p++}else ke(r[u]),u--;else ke(r[d]),d++;for(;p<=_;){const t=ve(e,l[_+1]);ye(t,o[p]),l[p++]=t}for(;d<=u;){const e=r[d++];null!==e&&ke(e)}return this.ut=s,we(e,l),U}}),Se=new WeakMap;let Me=0;class Re extends he{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-"+ ++Me,this._focusInitial=()=>{const e=this._focusableElements(),t=e.find(e=>e.hasAttribute("autofocus"))||e[0]||(this._useHaDialog?null:this.renderRoot.querySelector(".close"))||this.renderRoot.querySelector(".surface")||this.renderRoot.querySelector("ha-dialog");t?.focus({preventScroll:!0})},this._requestClose=()=>{this._closing||(this._closing=!0,this.dispatchEvent(new CustomEvent("hp-close",{bubbles:!0,composed:!0})))},this._onKeyDown=e=>{if("Escape"===e.key){e.preventDefault(),e.stopImmediatePropagation(),this._pruneOverlays();const t=this._overlays[this._overlays.length-1];return t?void this._closeOverlay(t,"escape"):void this._requestClose()}if("Tab"!==e.key||this._useHaDialog)return;const t=this.renderRoot.querySelector(".close"),i=t?[t,...this._focusableElements()]:this._focusableElements();if(!i.length)return e.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const n=this._deepActiveElement(),r=i[0],o=i[i.length-1];!e.shiftKey||n!==r&&i.includes(n)?e.shiftKey||n!==o||(e.preventDefault(),r.focus()):(e.preventDefault(),o.focus())},this._onFallbackCancel=e=>{e.preventDefault(),this._requestClose()},this._onFallbackClick=e=>{this.dismissOnScrim&&e.target===e.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const e=this.getRootNode();this._focusRoot=e;const t=Se.get(e)||{dialogs:new Set,opener:this._opener};t.dialogs.add(this),Se.set(e,t),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const e=[...this._overlays];this._overlays=[];for(const t of e.reverse())t.close("disconnect");const t=this._focusRoot,i=this._opener;this._opener=null,this._focusRoot=null;const n=t?Se.get(t):void 0;n?.dialogs.delete(this),super.disconnectedCallback(),t&&n&&requestAnimationFrame(()=>{const e=Se.get(t);if(!e)return;if(!e.dialogs.size)return e.opener?.isConnected&&e.opener.focus({preventScroll:!0}),void Se.delete(t);const n=i?.closest("hp-dialog");i?.isConnected&&n&&e.dialogs.has(n)&&i.focus({preventScroll:!0})})}firstUpdated(e){if(super.firstUpdated(e),!this._useHaDialog){const e=this.renderRoot.querySelector("dialog");e&&!e.open&&e.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let e=document.activeElement;for(;e?.shadowRoot?.activeElement;)e=e.shadowRoot.activeElement;return e&&e!==document.body?e:null}_focusableElements(){const e=["[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(","),t=[],i=new Set,n=r=>{if(!i.has(r)){if(i.add(r),r instanceof HTMLElement){if(r.matches(e)&&t.push(r),r instanceof HTMLSlotElement){for(const e of r.assignedNodes({flatten:!0}))n(e);return}if(r.shadowRoot){for(const e of r.shadowRoot.childNodes)n(e);return}}for(const e of r.childNodes)n(e)}};for(const e of this.childNodes)n(e);const r=this.overlayPortal();return r&&n(r),t.filter(e=>{let t=e;for(;t;){const e=getComputedStyle(t);if(t.hidden||t.inert||"true"===t.getAttribute("aria-hidden")||"none"===e.display||"hidden"===e.visibility)return!1;if(t=t.assignedSlot||t.parentElement||(t.getRootNode()instanceof ShadowRoot?t.getRootNode().host:null),t===this)break}return!0})}_pruneOverlays(){this._overlays=this._overlays.filter(e=>e.owner.isConnected)}_closeOverlay(e,t){const i=this._overlays.findIndex(t=>t.token===e.token);i>=0&&this._overlays.splice(i,1),e.close(t)}registerOverlay(e){this._pruneOverlays();const t=this._overlays.find(t=>t.owner===e.owner);t&&this._overlays.splice(this._overlays.indexOf(t),1);const i=e.group||"transient";for(const e of[...this._overlays].reverse())e.group===i&&this._closeOverlay(e,"exclusive");const n={...e,group:i,token:Symbol("hp-overlay")};this._overlays.push(n);let r=!1;return()=>{if(r)return;r=!0;const e=this._overlays.findIndex(e=>e.token===n.token);e>=0&&this._overlays.splice(e,1)}}closeTransientOverlays(e="outside"){this._pruneOverlays();const t=[...this._overlays].filter(e=>"transient"===(e.group||"transient"));for(const i of t.reverse())this._closeOverlay(i,e);return t.length>0}overlayPortal(){return this.renderRoot.querySelector(".overlay-portal")}render(){const e=B` + ${this.icon?B``:G} + ${this.title} + `;return this._useHaDialog?B` + ${e} + + +
`:B` +
+
+ ${e} + +
+
+ +
+
+
`}}Re.properties={title:{type:String},icon:{type:String},wide:{type:Boolean,reflect:!0},dismissOnScrim:{type:Boolean,attribute:"dismiss-on-scrim"},hass:{attribute:!1}},Re.styles=o` + :host { + display: contents; + color: var(--primary-text-color, #e6e7eb); + font: inherit; + } + + ha-dialog { + --dialog-content-padding: 0; + --dialog-surface-background: var(--card-background-color, var(--hp-bg, #202126)); + --ha-dialog-border-radius: var(--rad-l, 18px); + /* HA's ha-dialog-header defaults this custom property to a one-line + fixed height. Our localized slot is intentionally allowed to wrap, + so leaving that default in place clips every line after the first at + the bottom of the header. auto is HA's public sizing hook and also + stays harmless on older ha-dialog implementations that do not consume + it. */ + --ha-dialog-header-title-height: auto; + color: inherit; + } + + ha-dialog::part(dialog) { + border: 1px solid var(--hp-accent, #d89300); + box-shadow: var(--shadow-3, 0 18px 48px rgb(0 0 0 / 0.34)); + overflow: hidden; + } + + /* The HA header slot is a flex item with a constrained inline size. The + old inline-flex title kept its min-content width, so HA clipped the last + word instead of giving it a second line. Keep every wrapper shrinkable + and let the text wrap; this applies to every hp-dialog, including long + device names and translated titles. */ + .header-title-slot { + display: block; + flex: 1 1 auto; + width: 100%; + max-width: 100%; + min-width: 0; + box-sizing: border-box; + white-space: normal; + } + + .title { + display: flex; + flex: 1 1 auto; + align-items: center; + gap: var(--sp-4, 12px); + width: 100%; + max-width: 100%; + min-width: 0; + font-weight: 600; + line-height: 1.25; + white-space: normal; + } + + .title ha-icon { + flex: none; + color: var(--hp-accent, #d89300); + } + + .title-text { + flex: 1 1 auto; + min-width: 0; + max-width: 100%; + white-space: normal; + overflow-wrap: anywhere; + word-break: normal; + } + + .footer { + /* ha-dialog lays out its footer slot as a flex row. display: contents + exposed the consumer's action row as a shrink-to-fit flex item, so a + wide device dialog got a half-width divider and its Hide action slid + toward the centre. Keep one full-width slot item in both HA and the + native fallback. */ + display: block; + width: 100%; + min-width: 0; + box-sizing: border-box; + } + + ::slotted([slot='footer']) { + width: 100%; + box-sizing: border-box; + } + + dialog { + width: auto; + max-width: none; + max-height: none; + margin: auto; + padding: 0; + border: 0; + overflow: visible; + color: inherit; + background: transparent; + } + + dialog::backdrop { + background: rgb(0 0 0 / 0.45); + } + + .surface { + width: min(360px, 92vw); + max-height: 92vh; + display: flex; + flex-direction: column; + overflow: hidden; + box-sizing: border-box; + color: inherit; + background: var(--card-background-color, var(--hp-bg, #202126)); + border: 1px solid var(--hp-accent, #d89300); + border-radius: var(--rad-l, 18px); + box-shadow: var(--shadow-3, 0 18px 48px rgb(0 0 0 / 0.34)); + } + + :host([wide]) .surface { + width: min(var(--hp-dialog-wide-width, 500px), 94vw); + } + + .header { + min-height: 56px; + display: flex; + align-items: center; + gap: var(--sp-4, 12px); + padding: var(--sp-4, 12px) var(--sp-5, 16px); + box-sizing: border-box; + border-bottom: 1px solid var(--hp-line, rgb(255 255 255 / 0.12)); + } + + .header .title { + flex: 1; + } + + .close { + width: 40px; + height: 40px; + flex: none; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 50%; + cursor: pointer; + } + + :host([data-pointer-hover]) .close:hover, + .close:focus-visible { + background: rgb(127 127 127 / 0.16); + } + + .content { + min-height: 0; + display: flex; + flex-direction: column; + } + + .overlay-portal { + position: fixed; + z-index: 2147483647; + inset: 0; + overflow: visible; + pointer-events: none; + } + + .overlay-portal:empty { + display: none; + } + + .overlay-portal > * { + pointer-events: auto; + } + `,customElements.get("hp-dialog")||customElements.define("hp-dialog",Re);const Te=new Set(["hacs","sun","backup","hassio","met","telegram_bot","mobile_app","systemmonitor","better_thermostat","adaptive_lighting","yandex_pogoda","upnp_serial_number"]),Ce=[{pattern:"протечк|leak|water sensor",icon:"mdi:water-alert"},{pattern:"клапан|valve",icon:"mdi:pipe-valve"},{pattern:"дым|smoke",icon:"mdi:smoke-detector"},{pattern:"термоголов|trv|radiator",icon:"mdi:radiator"},{pattern:"чайник|kettle|термопот",icon:"mdi:kettle"},{pattern:"сауна|sauna|harvia|парная|парилк",icon:"mdi:hot-tub"},{pattern:"температ|temperature|thermometer|climate sensor",icon:"mdi:thermometer"},{pattern:"qingping|air monitor|молекул|air quality",icon:"mdi:air-filter"},{pattern:"штор|curtain|blind|shade",icon:"mdi:roller-shade"},{pattern:"розетк|plug|socket|outlet",icon:"mdi:power-socket-de"},{pattern:"выключат|switch",icon:"mdi:light-switch"},{pattern:"лампа|лампочк|bulb|gx53|светильник|rgb|lamp|light strip",icon:"mdi:lightbulb"},{pattern:"камер|camera",icon:"mdi:cctv"},{pattern:"замок|ttlock|lock|sn609|sn9161",icon:"mdi:lock"},{pattern:"ворота|garage|gate",icon:"mdi:garage-variant"},{pattern:"калитк|door|открыт|contact",icon:"mdi:door"},{pattern:"счётчик|счетчик|kws|meter",icon:"mdi:meter-electric"},{pattern:"вводный автомат|breaker|wifimcbn",icon:"mdi:electric-switch"},{pattern:"myheat|котёл|котел|boiler|отоплен|heating",icon:"mdi:water-boiler"},{pattern:"холодильник|fridge",icon:"mdi:fridge"},{pattern:"стиральн|washer|washing",icon:"mdi:washing-machine"},{pattern:"сушилк|dryer",icon:"mdi:tumble-dryer"},{pattern:"пылесос|vacuum|dreame|roborock",icon:"mdi:robot-vacuum"},{pattern:"soundbar",icon:"mdi:soundbar"},{pattern:"колонк|станц|speaker|яндекс|yandex|алиса|alice",icon:"mdi:speaker"},{pattern:"tv|телевизор|hyundaitv|mitv|television",icon:"mdi:television"},{pattern:"keenetic|роутер|router|mesh|access point",icon:"mdi:router-wireless"},{pattern:"ибп|ups|kirpich",icon:"mdi:battery-charging-high"},{pattern:"slzb|координат|zigbee|coordinator",icon:"mdi:zigbee"},{pattern:"motion|движен|presence|присутств",icon:"mdi:motion-sensor"},{pattern:"humidity|влажн",icon:"mdi:water-percent"}];function De(e){const t=[];for(const i of e)if(i&&"string"==typeof i.pattern&&i.icon)try{t.push({re:new RegExp(i.pattern,"i"),icon:i.icon})}catch{}return t}function Ae(e){try{return new RegExp(e,"i"),!0}catch{return!1}}const Oe=De(Ce),ze={temperature:"mdi:thermometer",humidity:"mdi:water-percent",motion:"mdi:motion-sensor",occupancy:"mdi:motion-sensor",presence:"mdi:motion-sensor",door:"mdi:door",window:"mdi:window-closed",garage_door:"mdi:garage-variant",smoke:"mdi:smoke-detector",moisture:"mdi:water-alert",gas:"mdi:gas-cylinder",power:"mdi:meter-electric",energy:"mdi:meter-electric",illuminance:"mdi:brightness-5",co2:"mdi:molecule-co2",pm25:"mdi:air-filter",battery:"mdi:battery"},Pe="mdi:chip";function Fe(e,t,i){const n=((e||"")+" "+(t||"")).toLowerCase();for(const{re:e,icon:t}of i??Oe)if(e.test(n))return t;return Pe}const Ie=["light","switch","cover","valve","lock","climate","fan","media_player","camera","vacuum","humidifier","water_heater","alarm_control_panel","sensor","binary_sensor","event","button","number","select","update"];var Ee=/^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i,Ne=Math.ceil,He=Math.floor,Le="[BigNumber Error] ",qe=Le+"Number primitive has more than 15 significant digits: ",je=1e14,Be=14,We=9007199254740991,Ue=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],Ge=1e7,Ve=1e9;function Ke(e){var t=0|e;return e>0||e===t?t:t-1}function Ye(e){for(var t,i,n=1,r=e.length,o=e[0]+"";nc^i?1:-1;for(a=(l=r.length)<(c=o.length)?l:c,s=0;so[s]^i?1:-1;return l==c?0:l>c^i?1:-1}function Xe(e,t,i,n){if(ei||e!==He(e))throw Error(Le+(n||"Argument")+("number"==typeof e?ei?" out of range: ":" not an integer: ":" not a primitive number: ")+String(e))}function Je(e){var t=e.c.length-1;return Ke(e.e/Be)==t&&e.c[t]%2!=0}function Qe(e,t){return(e.length>1?e.charAt(0)+"."+e.slice(1):e)+(t<0?"e":"e+")+t}function et(e,t,i){var n,r;if(t<0){for(r=i+".";++t;r+=i);e=r+e}else if(++t>(n=e.length)){for(r=i,t-=n;--t;r+=i);e+=r}else ty?u.c=u.e=null:e.e=10;l/=10,a++);return void(a>y?u.c=u.e=null:(u.e=a,u.c=[e]))}d=String(e)}else{if(!Ee.test(d=String(e)))return r(u,d,c);u.s=45==d.charCodeAt(0)?(d=d.slice(1),-1):1}(a=d.indexOf("."))>-1&&(d=d.replace(".","")),(l=d.search(/e/i))>0?(a<0&&(a=l),a+=+d.slice(l+1),d=d.substring(0,l)):a<0&&(a=d.length)}else{if(Xe(t,2,$.length,"Base"),10==t&&S)return D(u=new M(e),_+u.e+1,m);if(d=String(e),c="number"==typeof e){if(0*e!=0)return r(u,d,c,t);if(u.s=1/e<0?(d=d.slice(1),-1):1,M.DEBUG&&d.replace(/^0\.0*|\./,"").length>15)throw Error(qe+e)}else u.s=45===d.charCodeAt(0)?(d=d.slice(1),-1):1;for(i=$.slice(0,t),a=l=0,h=d.length;la){a=h;continue}}else if(!s&&(d==d.toUpperCase()&&(d=d.toLowerCase())||d==d.toLowerCase()&&(d=d.toUpperCase()))){s=!0,l=-1,a=0;continue}return r(u,String(e),c,t)}c=!1,(a=(d=n(d,t,10,u.s)).indexOf("."))>-1?d=d.replace(".",""):a=d.length}for(l=0;48===d.charCodeAt(l);l++);for(h=d.length;48===d.charCodeAt(--h););if(d=d.slice(l,++h)){if(h-=l,c&&M.DEBUG&&h>15&&(e>We||e!==He(e)))throw Error(qe+u.s*e);if((a=a-l-1)>y)u.c=u.e=null;else if(a=f)?Qe(l,s):et(l,s,"0");else if(o=(e=D(new M(e),t,i)).e,a=(l=Ye(e.c)).length,1==n||2==n&&(t<=o||o<=g)){for(;as),l=et(l,o,"0"),o+1>a){if(--t>0)for(l+=".";t--;l+="0");}else if((t+=o-a)>0)for(o+1==a&&(l+=".");t--;l+="0");return e.s<0&&r?"-"+l:l}function T(e,t){for(var i,n,r=1,o=new M(e[0]);r=10;r/=10,n++);return(i=n+i*Be-1)>y?e.c=e.e=null:i=10;a/=10,r++);if((o=t-r)<0)o+=Be,s=t,l=d[c=0],h=He(l/u[r-s-1]%10);else if((c=Ne((o+1)/Be))>=d.length){if(!n)break e;for(;d.length<=c;d.push(0));l=h=0,r=1,s=(o%=Be)-Be+1}else{for(l=a=d[c],r=1;a>=10;a/=10,r++);h=(s=(o%=Be)-Be+r)<0?0:He(l/u[r-s-1]%10)}if(n=n||t<0||null!=d[c+1]||(s<0?l:l%u[r-s-1]),n=i<4?(h||n)&&(0==i||i==(e.s<0?3:2)):h>5||5==h&&(4==i||n||6==i&&(o>0?s>0?l/u[r-s]:0:d[c-1])%10&1||i==(e.s<0?8:7)),t<1||!d[0])return d.length=0,n?(t-=e.e+1,d[0]=u[(Be-t%Be)%Be],e.e=-t||0):d[0]=e.e=0,e;if(0==o?(d.length=c,a=1,c--):(d.length=c+1,a=u[Be-o],d[c]=s>0?He(l/u[r-s]%u[s])*a:0),n)for(;;){if(0==c){for(o=1,s=d[0];s>=10;s/=10,o++);for(s=d[0]+=a,a=1;s>=10;s/=10,a++);o!=a&&(e.e++,d[0]==je&&(d[0]=1));break}if(d[c]+=a,d[c]!=je)break;d[c--]=0,a=1}for(o=d.length;0===d[--o];d.pop());}e.e>y?e.c=e.e=null:e.e=f?Qe(t,i):et(t,i,"0"),e.s<0?"-"+t:t)}return M.clone=e,M.ROUND_UP=0,M.ROUND_DOWN=1,M.ROUND_CEIL=2,M.ROUND_FLOOR=3,M.ROUND_HALF_UP=4,M.ROUND_HALF_DOWN=5,M.ROUND_HALF_EVEN=6,M.ROUND_HALF_CEIL=7,M.ROUND_HALF_FLOOR=8,M.EUCLID=9,M.config=M.set=function(e){var t,i;if(null!=e){if("object"!=typeof e)throw Error(Le+"Object expected: "+e);if(e.hasOwnProperty(t="DECIMAL_PLACES")&&(Xe(i=e[t],0,Ve,t),_=i),e.hasOwnProperty(t="ROUNDING_MODE")&&(Xe(i=e[t],0,8,t),m=i),e.hasOwnProperty(t="EXPONENTIAL_AT")&&((i=e[t])&&i.pop?(Xe(i[0],-Ve,0,t),Xe(i[1],0,Ve,t),g=i[0],f=i[1]):(Xe(i,-Ve,Ve,t),g=-(f=i<0?-i:i))),e.hasOwnProperty(t="RANGE"))if((i=e[t])&&i.pop)Xe(i[0],-Ve,-1,t),Xe(i[1],1,Ve,t),v=i[0],y=i[1];else{if(Xe(i,-Ve,Ve,t),!i)throw Error(Le+t+" cannot be zero: "+i);v=-(y=i<0?-i:i)}if(e.hasOwnProperty(t="CRYPTO")){if((i=e[t])!==!!i)throw Error(Le+t+" not true or false: "+i);if(i){if("undefined"==typeof crypto||!crypto||!crypto.getRandomValues&&!crypto.randomBytes)throw b=!i,Error(Le+"crypto unavailable");b=i}else b=i}if(e.hasOwnProperty(t="MODULO_MODE")&&(Xe(i=e[t],0,9,t),w=i),e.hasOwnProperty(t="POW_PRECISION")&&(Xe(i=e[t],0,Ve,t),k=i),e.hasOwnProperty(t="FORMAT")){if("object"!=typeof(i=e[t]))throw Error(Le+t+" not an object: "+i);x=i}if(e.hasOwnProperty(t="ALPHABET")){if("string"!=typeof(i=e[t])||/^.?$|[+\-.\s]|(.).*\1/.test(i))throw Error(Le+t+" invalid: "+i);S="0123456789"==i.slice(0,10),$=i}}return{DECIMAL_PLACES:_,ROUNDING_MODE:m,EXPONENTIAL_AT:[g,f],RANGE:[v,y],CRYPTO:b,MODULO_MODE:w,POW_PRECISION:k,FORMAT:x,ALPHABET:$}},M.isBigNumber=function(e){if(!e||!0!==e._isBigNumber)return!1;if(!M.DEBUG)return!0;var t,i,n=e.c,r=e.e,o=e.s;e:if("[object Array]"=={}.toString.call(n)){if((1===o||-1===o)&&r>=-Ve&&r<=Ve&&r===He(r)){if(0===n[0]){if(0===r&&1===n.length)return!0;break e}if((t=(r+1)%Be)<1&&(t+=Be),String(n[0]).length==t){for(t=0;t=je||i!==He(i))break e;if(0!==i)return!0}}}else if(null===n&&null===r&&(null===o||1===o||-1===o))return!0;throw Error(Le+"Invalid BigNumber: "+e)},M.maximum=M.max=function(){return T(arguments,-1)},M.minimum=M.min=function(){return T(arguments,1)},M.random=(o=9007199254740992,s=Math.random()*o&2097151?function(){return He(Math.random()*o)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)},function(e){var t,i,n,r,o,a=0,l=[],c=new M(p);if(null==e?e=_:Xe(e,0,Ve),r=Ne(e/Be),b)if(crypto.getRandomValues){for(t=crypto.getRandomValues(new Uint32Array(r*=2));a>>11))>=9e15?(i=crypto.getRandomValues(new Uint32Array(2)),t[a]=i[0],t[a+1]=i[1]):(l.push(o%1e14),a+=2);a=r/2}else{if(!crypto.randomBytes)throw b=!1,Error(Le+"crypto unavailable");for(t=crypto.randomBytes(r*=7);a=9e15?crypto.randomBytes(7).copy(t,a):(l.push(o%1e14),a+=7);a=r/7}if(!b)for(;a=10;o/=10,a++);ai-1&&(null==s[r+1]&&(s[r+1]=0),s[r+1]+=s[r]/i|0,s[r]%=i)}return s.reverse()}return function(n,r,o,s,a){var l,c,h,d,u,p,g,f,v=n.indexOf("."),y=_,b=m;for(v>=0&&(d=k,k=0,n=n.replace(".",""),p=(f=new M(r)).pow(n.length-v),k=d,f.c=t(et(Ye(p.c),p.e,"0"),10,o,e),f.e=f.c.length),h=d=(g=t(n,r,o,a?(l=$,e):(l=e,$))).length;0==g[--d];g.pop());if(!g[0])return l.charAt(0);if(v<0?--h:(p.c=g,p.e=h,p.s=s,g=(p=i(p,f,y,b,o)).c,u=p.r,h=p.e),v=g[c=h+y+1],d=o/2,u=u||c<0||null!=g[c+1],u=b<4?(null!=v||u)&&(0==b||b==(p.s<0?3:2)):v>d||v==d&&(4==b||u||6==b&&1&g[c-1]||b==(p.s<0?8:7)),c<1||!g[0])n=u?et(l.charAt(1),-y,l.charAt(0)):l.charAt(0);else{if(g.length=c,u)for(--o;++g[--c]>o;)g[c]=0,c||(++h,g=[1].concat(g));for(d=g.length;!g[--d];);for(v=0,n="";v<=d;n+=l.charAt(g[v++]));n=et(n,h,l.charAt(0))}return n}}(),i=function(){function e(e,t,i){var n,r,o,s,a=0,l=e.length,c=t%Ge,h=t/Ge|0;for(e=e.slice();l--;)a=((r=c*(o=e[l]%Ge)+(n=h*o+(s=e[l]/Ge|0)*c)%Ge*Ge+a)/i|0)+(n/Ge|0)+h*s,e[l]=r%i;return a&&(e=[a].concat(e)),e}function t(e,t,i,n){var r,o;if(i!=n)o=i>n?1:-1;else for(r=o=0;rt[r]?1:-1;break}return o}function i(e,t,i,n){for(var r=0;i--;)e[i]-=r,r=e[i]1;e.splice(0,1));}return function(n,r,o,s,a){var l,c,h,d,u,p,_,m,g,f,v,y,b,w,k,x,$,S=n.s==r.s?1:-1,R=n.c,T=r.c;if(!(R&&R[0]&&T&&T[0]))return new M(n.s&&r.s&&(R?!T||R[0]!=T[0]:T)?R&&0==R[0]||!T?0*S:S/0:NaN);for(g=(m=new M(S)).c=[],S=o+(c=n.e-r.e)+1,a||(a=je,c=Ke(n.e/Be)-Ke(r.e/Be),S=S/Be|0),h=0;T[h]==(R[h]||0);h++);if(T[h]>(R[h]||0)&&c--,S<0)g.push(1),d=!0;else{for(w=R.length,x=T.length,h=0,S+=2,(u=He(a/(T[0]+1)))>1&&(T=e(T,u,a),R=e(R,u,a),x=T.length,w=R.length),b=x,v=(f=R.slice(0,x)).length;v=a/2&&k++;do{if(u=0,(l=t(T,f,x,v))<0){if(y=f[0],x!=v&&(y=y*a+(f[1]||0)),(u=He(y/k))>1)for(u>=a&&(u=a-1),_=(p=e(T,u,a)).length,v=f.length;1==t(p,f,_,v);)u--,i(p,x<_?$:T,_,a),_=p.length,l=1;else 0==u&&(l=u=1),_=(p=T.slice()).length;if(_=10;S/=10,h++);D(m,o+(m.e=h+c*Be-1)+1,s,d)}else m.e=c,m.r=+d;return m}}(),a=/^(-?)0([xbo])(?=\w[\w.]*$)/i,l=/^([^.]+)\.$/,c=/^\.([^.]+)$/,h=/^-?(Infinity|NaN)$/,d=/^\s*\+(?=[\w.])|^\s+|\s+$/g,r=function(e,t,i,n){var r,o=i?t:t.replace(d,"");if(h.test(o))e.s=isNaN(o)?null:o<0?-1:1;else{if(!i&&(o=o.replace(a,function(e,t,i){return r="x"==(i=i.toLowerCase())?16:"b"==i?2:8,n&&n!=r?e:t}),n&&(r=n,o=o.replace(l,"$1").replace(c,"0.$1")),t!=o))return new M(o,r);if(M.DEBUG)throw Error(Le+"Not a"+(n?" base "+n:"")+" number: "+t);e.s=null}e.c=e.e=null},u.absoluteValue=u.abs=function(){var e=new M(this);return e.s<0&&(e.s=1),e},u.comparedTo=function(e,t){return Ze(this,new M(e,t))},u.decimalPlaces=u.dp=function(e,t){var i,n,r,o=this;if(null!=e)return Xe(e,0,Ve),null==t?t=m:Xe(t,0,8),D(new M(o),e+o.e+1,t);if(!(i=o.c))return null;if(n=((r=i.length-1)-Ke(this.e/Be))*Be,r=i[r])for(;r%10==0;r/=10,n--);return n<0&&(n=0),n},u.dividedBy=u.div=function(e,t){return i(this,new M(e,t),_,m)},u.dividedToIntegerBy=u.idiv=function(e,t){return i(this,new M(e,t),0,1)},u.exponentiatedBy=u.pow=function(e,t){var i,n,r,o,s,a,l,c,h=this;if((e=new M(e)).c&&!e.isInteger())throw Error(Le+"Exponent not an integer: "+A(e));if(null!=t&&(t=new M(t)),s=e.e>14,!h.c||!h.c[0]||1==h.c[0]&&!h.e&&1==h.c.length||!e.c||!e.c[0])return c=new M(Math.pow(+A(h),s?e.s*(2-Je(e)):+A(e))),t?c.mod(t):c;if(a=e.s<0,t){if(t.c?!t.c[0]:!t.s)return new M(NaN);(n=!a&&h.isInteger()&&t.isInteger())&&(h=h.mod(t))}else{if(e.e>9&&(h.e>0||h.e<-1||(0==h.e?h.c[0]>1||s&&h.c[1]>=24e7:h.c[0]<8e13||s&&h.c[0]<=9999975e7)))return o=h.s<0&&Je(e)?-0:0,h.e>-1&&(o=1/o),new M(a?1/o:o);k&&(o=Ne(k/Be+2))}for(s?(i=new M(.5),a&&(e.s=1),l=Je(e)):l=(r=Math.abs(+A(e)))%2,c=new M(p);;){if(l){if(!(c=c.times(h)).c)break;o?c.c.length>o&&(c.c.length=o):n&&(c=c.mod(t))}if(r){if(0===(r=He(r/2)))break;l=r%2}else if(D(e=e.times(i),e.e+1,1),e.e>14)l=Je(e);else{if(0===(r=+A(e)))break;l=r%2}h=h.times(h),o?h.c&&h.c.length>o&&(h.c.length=o):n&&(h=h.mod(t))}return n?c:(a&&(c=p.div(c)),t?c.mod(t):o?D(c,k,m,void 0):c)},u.integerValue=function(e){var t=new M(this);return null==e?e=m:Xe(e,0,8),D(t,t.e+1,e)},u.isEqualTo=u.eq=function(e,t){return 0===Ze(this,new M(e,t))},u.isFinite=function(){return!!this.c},u.isGreaterThan=u.gt=function(e,t){return Ze(this,new M(e,t))>0},u.isGreaterThanOrEqualTo=u.gte=function(e,t){return 1===(t=Ze(this,new M(e,t)))||0===t},u.isInteger=function(){return!!this.c&&Ke(this.e/Be)>this.c.length-2},u.isLessThan=u.lt=function(e,t){return Ze(this,new M(e,t))<0},u.isLessThanOrEqualTo=u.lte=function(e,t){return-1===(t=Ze(this,new M(e,t)))||0===t},u.isNaN=function(){return!this.s},u.isNegative=function(){return this.s<0},u.isPositive=function(){return this.s>0},u.isZero=function(){return!!this.c&&0==this.c[0]},u.minus=function(e,t){var i,n,r,o,s=this,a=s.s;if(t=(e=new M(e,t)).s,!a||!t)return new M(NaN);if(a!=t)return e.s=-t,s.plus(e);var l=s.e/Be,c=e.e/Be,h=s.c,d=e.c;if(!l||!c){if(!h||!d)return h?(e.s=-t,e):new M(d?s:NaN);if(!h[0]||!d[0])return d[0]?(e.s=-t,e):new M(h[0]?s:3==m?-0:0)}if(l=Ke(l),c=Ke(c),h=h.slice(),a=l-c){for((o=a<0)?(a=-a,r=h):(c=l,r=d),r.reverse(),t=a;t--;r.push(0));r.reverse()}else for(n=(o=(a=h.length)<(t=d.length))?a:t,a=t=0;t0)for(;t--;h[i++]=0);for(t=je-1;n>a;){if(h[--n]=0;){for(i=0,u=y[r]%g,p=y[r]/g|0,o=r+(s=l);o>r;)i=((c=u*(c=v[--s]%g)+(a=p*c+(h=v[s]/g|0)*u)%g*g+_[o]+i)/m|0)+(a/g|0)+p*h,_[o--]=c%m;_[o]=i}return i?++n:_.splice(0,1),C(e,_,n)},u.negated=function(){var e=new M(this);return e.s=-e.s||null,e},u.plus=function(e,t){var i,n=this,r=n.s;if(t=(e=new M(e,t)).s,!r||!t)return new M(NaN);if(r!=t)return e.s=-t,n.minus(e);var o=n.e/Be,s=e.e/Be,a=n.c,l=e.c;if(!o||!s){if(!a||!l)return new M(r/0);if(!a[0]||!l[0])return l[0]?e:new M(a[0]?n:0*r)}if(o=Ke(o),s=Ke(s),a=a.slice(),r=o-s){for(r>0?(s=o,i=l):(r=-r,i=a),i.reverse();r--;i.push(0));i.reverse()}for((r=a.length)-(t=l.length)<0&&(i=l,l=a,a=i,t=r),r=0;t;)r=(a[--t]=a[t]+l[t]+r)/je|0,a[t]=je===a[t]?0:a[t]%je;return r&&(a=[r].concat(a),++s),C(e,a,s)},u.precision=u.sd=function(e,t){var i,n,r,o=this;if(null!=e&&e!==!!e)return Xe(e,1,Ve),null==t?t=m:Xe(t,0,8),D(new M(o),e,t);if(!(i=o.c))return null;if(n=(r=i.length-1)*Be+1,r=i[r]){for(;r%10==0;r/=10,n--);for(r=i[0];r>=10;r/=10,n++);}return e&&o.e+1>n&&(n=o.e+1),n},u.shiftedBy=function(e){return Xe(e,-9007199254740991,We),this.times("1e"+e)},u.squareRoot=u.sqrt=function(){var e,t,n,r,o,s=this,a=s.c,l=s.s,c=s.e,h=_+4,d=new M("0.5");if(1!==l||!a||!a[0])return new M(!l||l<0&&(!a||a[0])?NaN:a?s:1/0);if(0==(l=Math.sqrt(+A(s)))||l==1/0?(((t=Ye(a)).length+c)%2==0&&(t+="0"),l=Math.sqrt(+t),c=Ke((c+1)/2)-(c<0||c%2),n=new M(t=l==1/0?"5e"+c:(t=l.toExponential()).slice(0,t.indexOf("e")+1)+c)):n=new M(l+""),n.c[0])for((l=(c=n.e)+h)<3&&(l=0);;)if(o=n,n=d.times(o.plus(i(s,o,h,1))),Ye(o.c).slice(0,l)===(t=Ye(n.c)).slice(0,l)){if(n.e0&&_>0){for(o=_%a||a,h=p.substr(0,o);o<_;o+=a)h+=c+p.substr(o,a);l>0&&(h+=c+p.slice(o)),u&&(h="-"+h)}n=d?h+(i.decimalSeparator||"")+((l=+i.fractionGroupSize)?d.replace(new RegExp("\\d{"+l+"}\\B","g"),"$&"+(i.fractionGroupSeparator||"")):d):h}return(i.prefix||"")+n+(i.suffix||"")},u.toFraction=function(e){var t,n,r,o,s,a,l,c,h,d,u,_,g=this,f=g.c;if(null!=e&&(!(l=new M(e)).isInteger()&&(l.c||1!==l.s)||l.lt(p)))throw Error(Le+"Argument "+(l.isInteger()?"out of range: ":"not an integer: ")+A(l));if(!f)return new M(g);for(t=new M(p),h=n=new M(p),r=c=new M(p),_=Ye(f),s=t.e=_.length-g.e-1,t.c[0]=Ue[(a=s%Be)<0?Be+a:a],e=!e||l.comparedTo(t)>0?s>0?t:h:l,a=y,y=1/0,l=new M(_),c.c[0]=0;d=i(l,t,0,1),1!=(o=n.plus(d.times(r))).comparedTo(e);)n=r,r=o,h=c.plus(d.times(o=h)),c=o,t=l.minus(d.times(o=t)),l=o;return o=i(e.minus(n),r,0,1),c=c.plus(o.times(h)),n=n.plus(o.times(r)),c.s=h.s=g.s,u=i(h,r,s*=2,m).minus(g).abs().comparedTo(i(c,n,s,m).minus(g).abs())<1?[h,r]:[c,n],y=a,u},u.toNumber=function(){return+A(this)},u.toPrecision=function(e,t){return null!=e&&Xe(e,1,Ve),R(this,e,t,2)},u.toString=function(e){var t,i=this,r=i.s,o=i.e;return null===o?r?(t="Infinity",r<0&&(t="-"+t)):t="NaN":(null==e?t=o<=g||o>=f?Qe(Ye(i.c),o):et(Ye(i.c),o,"0"):10===e&&S?t=et(Ye((i=D(new M(i),_+o+1,m)).c),i.e,"0"):(Xe(e,2,$.length,"Base"),t=n(et(Ye(i.c),o,"0"),10,e,r,!0)),r<0&&i.c[0]&&(t="-"+t)),t},u.valueOf=u.toJSON=function(){return A(this)},u._isBigNumber=!0,u[Symbol.toStringTag]="BigNumber",u[Symbol.for("nodejs.util.inspect.custom")]=u.valueOf,null!=t&&M.set(t),M}(),it=class{key;left=null;right=null;constructor(e){this.key=e}},nt=class extends it{constructor(e){super(e)}},rt=class{size=0;modificationCount=0;splayCount=0;splay(e){const t=this.root;if(null==t)return this.compare(e,e),-1;let i=null,n=null,r=null,o=null,s=t;const a=this.compare;let l;for(;;)if(l=a(s.key,e),l>0){let t=s.left;if(null==t)break;if(l=a(t.key,e),l>0&&(s.left=t.right,t.right=s,s=t,t=s.left,null==t))break;null==i?n=s:i.left=s,i=s,s=t}else{if(!(l<0))break;{let t=s.right;if(null==t)break;if(l=a(t.key,e),l<0&&(s.right=t.left,t.left=s,s=t,t=s.right,null==t))break;null==r?o=s:r.right=s,r=s,s=t}}return null!=r&&(r.right=s.left,s.left=o),null!=i&&(i.left=s.right,s.right=n),this.root!==s&&(this.root=s,this.splayCount++),l}splayMin(e){let t=e,i=t.left;for(;null!=i;){const e=i;t.left=e.right,e.right=t,t=e,i=t.left}return t}splayMax(e){let t=e,i=t.right;for(;null!=i;){const e=i;t.right=e.left,e.left=t,t=e,i=t.right}return t}_delete(e){if(null==this.root)return null;if(0!=this.splay(e))return null;let t=this.root;const i=t,n=t.left;if(this.size--,null==n)this.root=t.right;else{const e=t.right;t=this.splayMax(n),t.right=e,this.root=t}return this.modificationCount++,i}addNewRoot(e,t){this.size++,this.modificationCount++;const i=this.root;null!=i?(t<0?(e.left=i,e.right=i.right,i.right=null):(e.right=i,e.left=i.left,i.left=null),this.root=e):this.root=e}_first(){const e=this.root;return null==e?null:(this.root=this.splayMin(e),this.root)}_last(){const e=this.root;return null==e?null:(this.root=this.splayMax(e),this.root)}clear(){this.root=null,this.size=0,this.modificationCount++}has(e){return this.validKey(e)&&0==this.splay(e)}defaultCompare(){return(e,t)=>et?1:0}wrap(){return{getRoot:()=>this.root,setRoot:e=>{this.root=e},getSize:()=>this.size,getModificationCount:()=>this.modificationCount,getSplayCount:()=>this.splayCount,setSplayCount:e=>{this.splayCount=e},splay:e=>this.splay(e),has:e=>this.has(e)}}},ot=class e extends rt{root=null;compare;validKey;constructor(e,t){super(),this.compare=e??this.defaultCompare(),this.validKey=t??(e=>null!=e&&null!=e)}delete(e){return!!this.validKey(e)&&null!=this._delete(e)}deleteAll(e){for(const t of e)this.delete(t)}forEach(e){const t=this[Symbol.iterator]();let i;for(;i=t.next(),!i.done;)e(i.value,i.value,this)}add(e){const t=this.splay(e);return 0!=t&&this.addNewRoot(new nt(e),t),this}addAndReturn(e){const t=this.splay(e);return 0!=t&&this.addNewRoot(new nt(e),t),this.root.key}addAll(e){for(const t of e)this.add(t)}isEmpty(){return null==this.root}isNotEmpty(){return null!=this.root}single(){if(0==this.size)throw"Bad state: No element";if(this.size>1)throw"Bad state: Too many element";return this.root.key}first(){if(0==this.size)throw"Bad state: No element";return this._first().key}last(){if(0==this.size)throw"Bad state: No element";return this._last().key}lastBefore(e){if(null==e)throw"Invalid arguments(s)";if(null==this.root)return null;if(this.splay(e)<0)return this.root.key;let t=this.root.left;if(null==t)return null;let i=t.right;for(;null!=i;)t=i,i=t.right;return t.key}firstAfter(e){if(null==e)throw"Invalid arguments(s)";if(null==this.root)return null;if(this.splay(e)>0)return this.root.key;let t=this.root.right;if(null==t)return null;let i=t.left;for(;null!=i;)t=i,i=t.left;return t.key}retainAll(t){const i=new e(this.compare,this.validKey),n=this.modificationCount;for(const e of t){if(n!=this.modificationCount)throw"Concurrent modification during iteration.";this.validKey(e)&&0==this.splay(e)&&i.add(this.root.key)}i.size!=this.size&&(this.root=i.root,this.size=i.size,this.modificationCount++)}lookup(e){if(!this.validKey(e))return null;return 0!=this.splay(e)?null:this.root.key}intersection(t){const i=new e(this.compare,this.validKey);for(const e of this)t.has(e)&&i.add(e);return i}difference(t){const i=new e(this.compare,this.validKey);for(const e of this)t.has(e)||i.add(e);return i}union(e){const t=this.clone();return t.addAll(e),t}clone(){const t=new e(this.compare,this.validKey);return t.size=this.size,t.root=this.copyNode(this.root),t}copyNode(e){if(null==e)return null;const t=new nt(e.key);return function e(t,i){let n,r;do{if(n=t.left,r=t.right,null!=n){const t=new nt(n.key);i.left=t,e(n,t)}if(null!=r){const e=new nt(r.key);i.right=e,t=r,i=e}}while(null!=r)}(e,t),t}toSet(){return this.clone()}entries(){return new lt(this.wrap())}keys(){return this[Symbol.iterator]()}values(){return this[Symbol.iterator]()}[Symbol.iterator](){return new at(this.wrap())}[Symbol.toStringTag]="[object Set]"},st=class{tree;path=new Array;modificationCount=null;splayCount;constructor(e){this.tree=e,this.splayCount=e.getSplayCount()}[Symbol.iterator](){return this}next(){return this.moveNext()?{done:!1,value:this.current()}:{done:!0,value:null}}current(){if(!this.path.length)return null;const e=this.path[this.path.length-1];return this.getValue(e)}rebuildPath(e){this.path.splice(0,this.path.length),this.tree.splay(e),this.path.push(this.tree.getRoot()),this.splayCount=this.tree.getSplayCount()}findLeftMostDescendent(e){for(;null!=e;)this.path.push(e),e=e.left}moveNext(){if(this.modificationCount!=this.tree.getModificationCount()){if(null==this.modificationCount){this.modificationCount=this.tree.getModificationCount();let e=this.tree.getRoot();for(;null!=e;)this.path.push(e),e=e.left;return this.path.length>0}throw"Concurrent modification during iteration."}if(!this.path.length)return!1;this.splayCount!=this.tree.getSplayCount()&&this.rebuildPath(this.path[this.path.length-1].key);let e=this.path[this.path.length-1],t=e.right;if(null!=t){for(;null!=t;)this.path.push(t),t=t.left;return!0}for(this.path.pop();this.path.length&&this.path[this.path.length-1].right===e;)e=this.path.pop();return this.path.length>0}},at=class extends st{getValue(e){return e.key}},lt=class extends st{getValue(e){return[e.key,e.key]}},ct=e=>()=>e,ht=e=>{const t=e?(t,i)=>i.minus(t).abs().isLessThanOrEqualTo(e):ct(!1);return(e,i)=>t(e,i)?0:e.comparedTo(i)};function dt(e){const t=e?(t,i,n,r,o)=>t.exponentiatedBy(2).isLessThanOrEqualTo(r.minus(i).exponentiatedBy(2).plus(o.minus(n).exponentiatedBy(2)).times(e)):ct(!1);return(e,i,n)=>{const r=e.x,o=e.y,s=n.x,a=n.y,l=o.minus(a).times(i.x.minus(s)).minus(r.minus(s).times(i.y.minus(a)));return t(l,r,o,s,a)?0:l.comparedTo(0)}}var ut=e=>e,pt=e=>{if(e){const t=new ot(ht(e)),i=new ot(ht(e)),n=(e,t)=>t.addAndReturn(e),r=e=>({x:n(e.x,t),y:n(e.y,i)});return r({x:new tt(0),y:new tt(0)}),r}return ut},_t=e=>({set:e=>{mt=_t(e)},reset:()=>_t(e),compare:ht(e),snap:pt(e),orient:dt(e)}),mt=_t(),gt=(e,t)=>e.ll.x.isLessThanOrEqualTo(t.x)&&t.x.isLessThanOrEqualTo(e.ur.x)&&e.ll.y.isLessThanOrEqualTo(t.y)&&t.y.isLessThanOrEqualTo(e.ur.y),ft=(e,t)=>{if(t.ur.x.isLessThan(e.ll.x)||e.ur.x.isLessThan(t.ll.x)||t.ur.y.isLessThan(e.ll.y)||e.ur.y.isLessThan(t.ll.y))return null;const i=e.ll.x.isLessThan(t.ll.x)?t.ll.x:e.ll.x,n=e.ur.x.isLessThan(t.ur.x)?e.ur.x:t.ur.x;return{ll:{x:i,y:e.ll.y.isLessThan(t.ll.y)?t.ll.y:e.ll.y},ur:{x:n,y:e.ur.y.isLessThan(t.ur.y)?e.ur.y:t.ur.y}}},vt=(e,t)=>e.x.times(t.y).minus(e.y.times(t.x)),yt=(e,t)=>e.x.times(t.x).plus(e.y.times(t.y)),bt=e=>yt(e,e).sqrt(),wt=(e,t,i)=>{const n={x:t.x.minus(e.x),y:t.y.minus(e.y)},r={x:i.x.minus(e.x),y:i.y.minus(e.y)};return vt(r,n).div(bt(r)).div(bt(n))},kt=(e,t,i)=>{const n={x:t.x.minus(e.x),y:t.y.minus(e.y)},r={x:i.x.minus(e.x),y:i.y.minus(e.y)};return yt(r,n).div(bt(r)).div(bt(n))},xt=(e,t,i)=>t.y.isZero()?null:{x:e.x.plus(t.x.div(t.y).times(i.minus(e.y))),y:i},$t=(e,t,i)=>t.x.isZero()?null:{x:i,y:e.y.plus(t.y.div(t.x).times(i.minus(e.x)))},St=class e{point;isLeft;segment;otherSE;consumedBy;static compare(t,i){const n=e.comparePoints(t.point,i.point);return 0!==n?n:(t.point!==i.point&&t.link(i),t.isLeft!==i.isLeft?t.isLeft?1:-1:zt.compare(t.segment,i.segment))}static comparePoints(e,t){return e.x.isLessThan(t.x)?-1:e.x.isGreaterThan(t.x)?1:e.y.isLessThan(t.y)?-1:e.y.isGreaterThan(t.y)?1:0}constructor(e,t){void 0===e.events?e.events=[this]:e.events.push(this),this.point=e,this.isLeft=t}link(e){if(e.point===this.point)throw new Error("Tried to link already linked events");const t=e.point.events;for(let e=0,i=t.length;e{const n=i.otherSE;t.set(i,{sine:wt(this.point,e.point,n.point),cosine:kt(this.point,e.point,n.point)})};return(e,n)=>{t.has(e)||i(e),t.has(n)||i(n);const{sine:r,cosine:o}=t.get(e),{sine:s,cosine:a}=t.get(n);return r.isGreaterThanOrEqualTo(0)&&s.isGreaterThanOrEqualTo(0)?o.isLessThan(a)?1:o.isGreaterThan(a)?-1:0:r.isLessThan(0)&&s.isLessThan(0)?o.isLessThan(a)?-1:o.isGreaterThan(a)?1:0:s.isLessThan(r)?-1:s.isGreaterThan(r)?1:0}}},Mt=class e{events;poly;_isExteriorRing;_enclosingRing;static factory(t){const i=[];for(let n=0,r=t.length;n0&&(e=i)}let t=e.segment.prevInResult(),i=t?t.prevInResult():null;for(;;){if(!t)return null;if(!i)return t.ringOut;if(i.ringOut!==t.ringOut)return i.ringOut?.enclosingRing()!==t.ringOut?t.ringOut:t.ringOut?.enclosingRing();t=i.prevInResult(),i=t?t.prevInResult():null}}},Rt=class{exteriorRing;interiorRings;constructor(e){this.exteriorRing=e,e.poly=this,this.interiorRings=[]}addInterior(e){this.interiorRings.push(e),e.poly=this}getGeom(){const e=this.exteriorRing.getGeom();if(null===e)return null;const t=[e];for(let e=0,i=this.interiorRings.length;e0?(this.tree.delete(t),i.push(e)):(this.segments.push(t),t.prev=n)}else{if(n&&r){const e=n.getIntersection(r);if(null!==e){if(!n.isAnEndpoint(e)){const t=this._splitSafely(n,e);for(let e=0,n=t.length;e0)return-1;const n=t.comparePoint(e.rightSE.point);return 0!==n?n:-1}if(i.isGreaterThan(n)){if(s.isLessThan(a)&&s.isLessThan(c))return-1;if(s.isGreaterThan(a)&&s.isGreaterThan(c))return 1;const i=t.comparePoint(e.leftSE.point);if(0!==i)return i;const n=e.comparePoint(t.rightSE.point);return n<0?1:n>0?-1:1}if(s.isLessThan(a))return-1;if(s.isGreaterThan(a))return 1;if(r.isLessThan(o)){const i=t.comparePoint(e.rightSE.point);if(0!==i)return i}if(r.isGreaterThan(o)){const i=e.comparePoint(t.rightSE.point);if(i<0)return 1;if(i>0)return-1}if(!r.eq(o)){const e=l.minus(s),t=r.minus(i),h=c.minus(a),d=o.minus(n);if(e.isGreaterThan(t)&&h.isLessThan(d))return 1;if(e.isLessThan(t)&&h.isGreaterThan(d))return-1}return r.isGreaterThan(o)?1:r.isLessThan(o)||l.isLessThan(c)?-1:l.isGreaterThan(c)?1:e.idt.id?1:0}constructor(e,t,i,n){this.id=++Ot,this.leftSE=e,e.segment=this,e.otherSE=t,this.rightSE=t,t.segment=this,t.otherSE=e,this.rings=i,this.windings=n}static fromRing(t,i,n){let r,o,s;const a=St.comparePoints(t,i);if(a<0)r=t,o=i,s=1;else{if(!(a>0))throw new Error(`Tried to create degenerate segment at [${t.x}, ${t.y}]`);r=i,o=t,s=-1}const l=new St(r,!0),c=new St(o,!1);return new e(l,c,[n],[s])}replaceRightSE(e){this.rightSE=e,this.rightSE.segment=this,this.rightSE.otherSE=this.leftSE,this.leftSE.otherSE=this.rightSE}bbox(){const e=this.leftSE.point.y,t=this.rightSE.point.y;return{ll:{x:this.leftSE.point.x,y:e.isLessThan(t)?e:t},ur:{x:this.rightSE.point.x,y:e.isGreaterThan(t)?e:t}}}vector(){return{x:this.rightSE.point.x.minus(this.leftSE.point.x),y:this.rightSE.point.y.minus(this.leftSE.point.y)}}isAnEndpoint(e){return e.x.eq(this.leftSE.point.x)&&e.y.eq(this.leftSE.point.y)||e.x.eq(this.rightSE.point.x)&&e.y.eq(this.rightSE.point.y)}comparePoint(e){return mt.orient(this.leftSE.point,e,this.rightSE.point)}getIntersection(e){const t=this.bbox(),i=e.bbox(),n=ft(t,i);if(null===n)return null;const r=this.leftSE.point,o=this.rightSE.point,s=e.leftSE.point,a=e.rightSE.point,l=gt(t,s)&&0===this.comparePoint(s),c=gt(i,r)&&0===e.comparePoint(r),h=gt(t,a)&&0===this.comparePoint(a),d=gt(i,o)&&0===e.comparePoint(o);if(c&&l)return d&&!h?o:!d&&h?a:null;if(c)return h&&r.x.eq(a.x)&&r.y.eq(a.y)?null:r;if(l)return d&&o.x.eq(s.x)&&o.y.eq(s.y)?null:s;if(d&&h)return null;if(d)return o;if(h)return a;const u=((e,t,i,n)=>{if(t.x.isZero())return $t(i,n,e.x);if(n.x.isZero())return $t(e,t,i.x);if(t.y.isZero())return xt(i,n,e.y);if(n.y.isZero())return xt(e,t,i.y);const r=vt(t,n);if(r.isZero())return null;const o={x:i.x.minus(e.x),y:i.y.minus(e.y)},s=vt(o,t).div(r),a=vt(o,n).div(r),l=e.x.plus(a.times(t.x)),c=i.x.plus(s.times(n.x)),h=e.y.plus(a.times(t.y)),d=i.y.plus(s.times(n.y));return{x:l.plus(c).div(2),y:h.plus(d).div(2)}})(r,this.vector(),s,e.vector());return null===u?null:gt(n,u)?mt.snap(u):null}split(t){const i=[],n=void 0!==t.events,r=new St(t,!0),o=new St(t,!1),s=this.rightSE;this.replaceRightSE(o),i.push(o),i.push(r);const a=new e(r,s,this.rings.slice(),this.windings.slice());return St.comparePoints(a.leftSE.point,a.rightSE.point)>0&&a.swapEvents(),St.comparePoints(this.leftSE.point,this.rightSE.point)>0&&this.swapEvents(),n&&(r.checkForConsuming(),o.checkForConsuming()),i}swapEvents(){const e=this.rightSE;this.rightSE=this.leftSE,this.leftSE=e,this.leftSE.isLeft=!0,this.rightSE.isLeft=!1;for(let e=0,t=this.windings.length;e0){const e=i;i=n,n=e}if(i.prev===n){const e=i;i=n,n=e}for(let e=0,t=n.rings.length;e1===e.length&&e[0].isSubject;this._isInResult=i(e)!==i(t);break}}return this._isInResult}},Pt=class{poly;isExterior;segments;bbox;constructor(e,t,i){if(!Array.isArray(e)||0===e.length)throw new Error("Input geometry is not a valid Polygon or MultiPolygon");if(this.poly=t,this.isExterior=i,this.segments=[],"number"!=typeof e[0][0]||"number"!=typeof e[0][1])throw new Error("Input geometry is not a valid Polygon or MultiPolygon");const n=mt.snap({x:new tt(e[0][0]),y:new tt(e[0][1])});this.bbox={ll:{x:n.x,y:n.y},ur:{x:n.x,y:n.y}};let r=n;for(let t=1,i=e.length;tAt.run("union",e,t),Nt=(e,...t)=>At.run("intersection",e,t),Ht=(e,...t)=>At.run("difference",e,t);mt.set;const Lt=/^#[0-9a-fA-F]{6}$/;function qt(e,t){return"string"==typeof e&&Lt.test(e)?e:t}const jt="(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])",Bt=new RegExp(`^rgb\\(${jt}, ${jt}, ${jt}\\)$`);function Wt(e){if(!Array.isArray(e)||e.length<3)return null;const t=e.slice(0,3);if(!t.every(e=>"number"==typeof e&&Number.isFinite(e)))return null;const[i,n,r]=t.map(e=>Math.round(Math.min(255,Math.max(0,e))));return`rgb(${i}, ${n}, ${r})`}function Ut(e){const t=Math.max(0,Math.min(120,(e-40)/140*120));return`hsl(${Math.round(t)}, 85%, 55%)`}function Gt(e,t){if(!(Number.isFinite(e)&&t>0))return e;const i=Math.round(e/t)*t;return Math.abs(i-e)<=1e-9*t?e:i}function Vt(e,t,i,n=1/0){if(!(i>0&&e?.every(Number.isFinite)&&t?.every(Number.isFinite)))return[t[0],t[1]];const r=t[0]-e[0],o=t[1]-e[1];if(Math.abs(r)+Math.abs(o)<=1e-12)return[e[0],e[1]];const s=Math.PI/4;let a=Math.atan2(o,r);a<0&&(a+=2*Math.PI);const l=Math.floor(a/s+.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 u=Math.max(0,Math.round((r*c+o*h)/(i*d)));if(Number.isFinite(n)&&n>=0){const t=(e,t)=>{if(!t)return 1/0;const r=t>0?n-e:e+n;return Math.max(0,Math.floor((r+1e-9*i)/i))};u=Math.min(u,t(e[0],c),t(e[1],h))}return[e[0]+c*u*i,e[1]+h*u*i]}function Kt(e,t){if(t){const t=e/2.54;let i=Math.floor(t/12),n=Math.round(t-12*i);return 12===n&&(i+=1,n=0),`${i}′ ${n}″`}return`${(e/100).toFixed(2)} m`}function Yt(e,t,i=1){const n=e[0].toFixed(i),r=e[1].toFixed(i),o=t[0].toFixed(i),s=t[1].toFixed(i),a=n=3?e.poly:e&&null!=e.x&&null!=e.y&&null!=e.w&&null!=e.h?[[e.x,e.y],[e.x+e.w,e.y],[e.x+e.w,e.y+e.h],[e.x,e.y+e.h]]:null}function Xt(e){const t=[];for(const i of e||[])i?.poly?.length>=3?t.push({poly:i.poly.map(e=>e.join(",")).join(" ")}):i&&null!=i.x&&null!=i.y&&null!=i.w&&null!=i.h&&t.push({rect:{x:i.x,y:i.y,w:i.w,h:i.h,rx:.03*Math.min(i.w,i.h)}});return t}function Jt(e){const t=[],i=new Set;for(const n of e||[]){const e=Zt(n);if(e)for(let n=0;n=90?e-=180:e<-90&&(e+=180),n.step&&n.step>0){const i=Math.sqrt(d),o=Math.min(Math.max(n.length||0,0)/2,i/2);let a=Math.round(u*i/n.step)*n.step;Math.abs(u*i-i/2)<=n.step/2&&(a=i/2),a=Math.max(o,Math.min(i-o,a));const l=a/i;r={x:t+l*c,y:s+l*h,angle:e}}else r={x:p[0],y:p[1],angle:e}}}return r}function ei(e,t,i){let n=null,r=1/0;for(let o=0;o=r)continue;r=_;const m=Math.sqrt(u),g=(i>0?Math.max(0,Math.min(m,Math.round(p*m/i)*i)):p*m)/m;n=[s+g*h,a+g*d]}return n}function ti(e,t,i,n,r,o=1){const s=t*Math.PI/180,a=[Math.cos(s),Math.sin(s)];let l=null,c=o;for(const t of Jt(n)){const i=[[t[0],t[1]],[t[2],t[3]]],n=t=>Math.abs(a[0]*(t[1]-e[1])-a[1]*(t[0]-e[0]));if(n(i[0])>o||n(i[1])>o)continue;const r=(i[0][0]-e[0])*a[0]+(i[0][1]-e[1])*a[1],s=(i[1][0]-e[0])*a[0]+(i[1][1]-e[1])*a[1],h=Math.min(r,s),d=Math.max(r,s),u=h>0?h:d<0?-d:0;u[e[0]+a[0]*t,e[1]+a[1]*t],g=(h+d)/2;return{wallA:m(h),wallB:m(d),sideA:p,sideB:_,midA:m((h-u)/2),midB:m((u+d)/2),wallCenter:m(g),centered:Math.abs(g)<=r}}function ii(e,t,i=!1){if("passage"===e)return 1;if(null==t||"unavailable"===t||"unknown"===t)return"window"===e?0:1;const n=function(e){return["on","open","home","detected","playing","cleaning"].includes(String(e))}(t)!==!!i;return n?1:0}function ni(e){return"passage"===e.type?[]:[e.contact,e.lock].filter(e=>"string"==typeof e&&e.length>0)}function ri(e,t,i=200){const n=t.trim().toLowerCase();return(n?e.filter(e=>e.label.toLowerCase().includes(n)||e.value.toLowerCase().includes(n)):e).slice(0,Math.max(0,i))}function oi(e,t,i=.001){return Math.abs(e[0]-t[0])e[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s)+o&&(i=!i)}return i}function ai(e,t,i){const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;let s=o?((e[0]-t[0])*n+(e[1]-t[1])*r)/o:0;return s=Math.max(0,Math.min(1,s)),Math.hypot(e[0]-(t[0]+s*n),e[1]-(t[1]+s*r))}function li(e,t){if(!t||t.length<2)return null;let i=null,n=1/0;for(let r=0;rr&&s<-r||o<-r&&s>r)&&(a>r&&l<-r||a<-r&&l>r)}function pi(e,t=24){const i=e.map(e=>e[0]),n=e.map(e=>e[1]),r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1;let c=0,h=0,d=0;for(let t=0;t1e-9?[h/(3*c),d/(3*c)]:[(r+o)/2,(s+a)/2],p=(t,i)=>{const n=((t,i)=>{if(!si([t,i],e))return-1/0;let n=1/0;for(let r=0;rm&&(m=c,_=[n,l])}if(_){const[e,i]=_,n=(o-r)/t,l=(a-s)/t;for(let t=-4;t<=4;t++)for(let r=-4;r<=4;r++){const o=e+n*t/4,s=i+l*r/4,a=p(o,s);a>m&&(m=a,_=[o,s])}}return _||_i(e)||e[0]}function _i(e,t=1e-6){if(!e||e.length<3)return null;const i=e.length,n=[e.reduce((e,t)=>e+t[0],0)/i,e.reduce((e,t)=>e+t[1],0)/i];if(hi(n,e,t))return n;for(let n=0;ngi(e,t,i));return n.filter(e=>!n.some(t=>t!==e&&gi(t,e,i)))}function yi(e){if(!e||e.length<3)return 0;let t=0;for(let i=0;i[e[0],e[1]]),[e[0][0],e[0][1]]]]}function wi(e,t){if(!e||!t||e.length<3||t.length<3)return null;const i=Et(bi(e),bi(t));if(1!==i.length)return null;if(1!==i[0].length)return null;const n=i[0][0].slice(0,-1).map(e=>[e[0],e[1]]);return n.length>=3?n:null}function ki(e,t,i){for(let n=0;n1&&oi(i[0],i[i.length-1],t)&&i.pop(),i}function $i(e,t,i=1e-6){if(!e||e.length<3||!t||t.length<2)return null;const n=t[0],r=t[t.length-1];if(oi(n,r,i))return null;const o=ki(e,n,i),s=ki(e,r,i);if(o<0||s<0)return null;const a=t.slice(1,-1);for(const t of a)if(!hi(t,e,i))return null;for(let i=0;i{const s=[t];let a=(n+1)%e.length;for(let t=0;t<=e.length&&(s.push(e[a]),a!==o);t++)a=(a+1)%e.length;return s.push(r),xi(s,i)};let c,h;if(o===s){const s=xi([...t],i);if(s.length<3||yi(s)<=i)return null;const a=[];for(let i=0;i=0?t:[...t].reverse();for(const e of i)a.push(e)}c=xi(a,i),h=s}else c=xi([...l(n,o,r,s),...[...a].reverse()],i),h=xi([...l(r,s,n,o),...a],i);return c.length<3||h.length<3||yi(c)<=i||yi(h)<=i||Math.abs(yi(c)+yi(h)-yi(e))>Math.max(i,1e-6*yi(e))?null:[c,h]}function Si(e,t,i){const[n,r]=e.split(":");return"device"===n?r:"entity"===n?"lg_"+r:t&&t.startsWith("v_")?t:i()}function Mi(e){return e.length?Math.round(e.reduce((e,t)=>e+t,0)/e.length):null}function Ri(e,t){if(t>e[2]/e[3]){const i=e[3],n=e[3]*t;return{x:e[0]-(n-e[2])/2,y:e[1],w:n,h:i}}const i=e[2],n=e[2]/t;return{x:e[0],y:e[1]-(n-e[3])/2,w:i,h:n}}function Ti(e,t,i,n){if(e.length<2)return;const r=t.x+n,o=t.x+t.w-n,s=t.y+n,a=t.y+t.h-n;for(let t=0;t<60;t++){let t=!1;for(let n=0;n=0)i=t.slice(0,r).trim(),n=t.slice(r+1).trim();else{const e=t.split(".");e.length>2&&(i=e.slice(0,2).join("."),n=e.slice(2).join("."))}return/^[a-z0-9_]+\.[a-z0-9_]+$/.test(i)?r>=0&&!n||n&&!/^[a-zA-Z0-9_.-]+$/.test(n)?null:n?{entity:i,attr:n}:{entity:i}:null}function Li(e,t){const i=String(e??"").trim(),n=String(t??"").trim(),r=Hi(n?`${i}:${n}`:i);return r?`{${r.entity}${r.attr?`:${r.attr}`:""}}`:""}function qi(e,t,i){const n=String(t??"").trim();if(!n)return null;const r=e?.states?.[n];if(!r)return null;const o=String(i??"").trim(),s=e=>e.slice(0,60);if(o){const t=function(e){if(null==e)return null;if(Array.isArray(e)){const t=e.map(e=>null==e?"":String(e)).join(", ");return t?t.slice(0,60):null}if("object"==typeof e)return null;const t=String(e);return""===t?null:t.slice(0,60)}(r.attributes?.[o]);if(null===t)return null;const i=e?.formatEntityAttributeValue;if("function"==typeof i)try{const t=i.call(e,r,o);if("string"==typeof t&&""!==t)return{text:s(t),formatted:!0}}catch{}return{text:t,formatted:!1}}const a=r.state;if(null==a||""===a)return null;const l=e?.formatEntityState;if("function"==typeof l)try{const t=l.call(e,r);if("string"==typeof t&&""!==t)return{text:s(t),formatted:!0}}catch{}return{text:s(String(a)),formatted:!1}}function ji(e,t,i){const n=String(t??"").trim(),r=String(i??"").trim()||n;if(!r)return e.text;const o=e.formatted&&n?function(e,t){if(!t)return e;const i=e.replace(/\s+$/,"");return i.endsWith(t)?i.slice(0,i.length-t.length).replace(/\s+$/,""):e}(e.text,n):e.text;return`${o} ${r}`}function Bi(e,t){const i=(t?.entity||"").trim();if(!i)return"";const n=e?.states?.[i],r=n?.state;if(!n||null==r||""===r||"unavailable"===r||"unknown"===r)return Ei;const o=(t?.attr||"").trim(),s=qi(e,i,o||null);if(null===s)return Ei;return ji(s,o?"":String(n.attributes?.unit_of_measurement??"").trim(),t?.unit)}function Wi(e,t,i,n=()=>!0){const r=e??"";let o=!1;const s=r.replace(/\{([^{}\r\n]+)\}/g,(e,t)=>{const r=Hi(t);return r?(o=!0,n(r.entity||"")?Bi(i,r):Ei):e});if(o)return s;const a=(t?.entity||"").trim();if(!a)return r;if(!n(a)){const e=r.indexOf(Ni);return e>=0?r.slice(0,e)+Ei+r.slice(e+2):r?`${r} ${Ei}`:Ei}const l=Bi(i,t),c=r.indexOf(Ni);return c>=0?r.slice(0,c)+l+r.slice(c+2):r?`${r} ${l}`:l}const Ui=20;function Gi(e){const t=Number(e?.scale);if(Number.isFinite(t)&&t>0)return Math.min(20,Math.max(.15,t));return{s:.7,m:1,l:1.5}[String(e?.size??"")]??1}function Vi(e,t){if(!t)return e;let i=e;for(const[e,n]of Object.entries(t))i=i.split("{"+e+"}").join(String(n));return i}const Ki="#55606c",Yi=.55,Zi=20,Xi=25,Ji={c:"#607d8b",a:.18};function Qi(e,t=Ji){const i=e&&"object"==typeof e?e:null,n=i?.a;return{c:qt(i?.c,t.c),a:"number"==typeof n&&Number.isFinite(n)?Math.min(1,Math.max(0,n)):t.a}}function en(e,t){const i=Qi(e),n=t?.settings?.custom_fill;return n&&"object"==typeof n?Qi(n,i):i}function tn(e){const t=e?.settings||{},i=!e?.plan_url,n="glow"===t.fill_mode;return{showBorders:t.show_borders??i,showNames:t.show_names??i,color:qt(t.room_color,Ki),opacity:"number"==typeof t.room_opacity?Math.min(1,Math.max(0,t.room_opacity)):.55,fill:["lqi","light","temp","custom"].includes(t.fill_mode)?t.fill_mode:"none",customFill:Qi(t.custom_fill),glow:"boolean"==typeof t.glow_enabled?t.glow_enabled:n,tempMin:"number"==typeof t.temp_min?t.temp_min:20,tempMax:"number"==typeof t.temp_max?t.temp_max:25,showLqi:"boolean"==typeof t.show_lqi?t.show_lqi:null,cardFontScale:"number"==typeof t.card_font_scale&&t.card_font_scale>0?Math.min(3,Math.max(.5,t.card_font_scale)):1,labelTemp:!0===t.label_temp,labelHum:!0===t.label_hum,labelLqi:!0===t.label_lqi,labelLight:!0===t.label_light,bgColor:qt(t.bg_color,null),hideDecor:!0===t.hide_decor,hideOpenings:!0===t.hide_openings}}function nn(e,t){if(t.bgColor)return t.bgColor;const i=e?.bg_color;return qt(i,"")}const rn={light_on:{c:"#ffd45c",a:.18},light_off:{c:"#9aa0a6",a:.14},light_none:{c:"#6b7480",a:0},temp_cold:{c:"#4fc3f7",a:.18},temp_ok:{c:"#66d17a",a:.18},temp_hot:{c:"#ffd45c",a:.18},lqi_low:{c:"#f25a4a",a:.18},lqi_high:{c:"#4bd28f",a:.18},glow_base:{c:"#0d1b2a",a:.5},glow_light:{c:"#ffd9a0",a:.85},wall_fill:{c:"#ffffff",a:1}};function on(e){const t={},i=e?.fill_colors||{};for(const e of Object.keys(rn)){const n=rn[e],r=i[e];t[e]={c:qt(r?.c,n.c),a:r&&"number"==typeof r.a?Math.min(1,Math.max(0,r.a)):n.a}}return t}function sn(e,t,i){const n=Math.min(1,Math.max(0,i)),r=[1,3,5].map(t=>parseInt(e.slice(t,t+2),16)),o=[1,3,5].map(e=>parseInt(t.slice(e,e+2),16)),s=r.map((e,t)=>Math.round(e+(o[t]-e)*n));return"#"+s.map(e=>e.toString(16).padStart(2,"0")).join("")}function an(e,t,i,n,r,o,s,a=Ji){const l=function(e,t,i,n,r,o,s,a=Ji){if("custom"===e)return Qi(a);if("lqi"===e){if(null==t)return null;const e=(t-40)/140;return{c:sn(s.lqi_low.c,s.lqi_high.c,e),a:s.lqi_low.a+(s.lqi_high.a-s.lqi_low.a)*Math.min(1,Math.max(0,e))}}if("light"===e)return"none"===i?s.light_none.a>0?s.light_none:null:"on"===i?s.light_on:s.light_off;if("temp"===e){if(null==n)return null;const e=Math.min(r,o),t=Math.max(r,o);return nt?s.temp_hot:s.temp_ok}return null}(e,t,i,n,r,o,s,a);return l?{color:l.c,opacity:l.a,mode:e}:null}const ln={blind:["mdi:blinds","mdi:blinds-open"],shade:["mdi:blinds","mdi:blinds-open"],shutter:["mdi:window-shutter","mdi:window-shutter-open"],curtain:["mdi:curtains-closed","mdi:curtains"],window:["mdi:window-closed","mdi:window-open"],awning:["mdi:awning-outline","mdi:awning"],door:["mdi:door-closed","mdi:door-open"],garage:["mdi:garage","mdi:garage-open"],gate:["mdi:gate","mdi:gate-open"],damper:["mdi:circle-slice-8","mdi:circle-outline"]},cn=[["mdi:roller-shade-closed","mdi:roller-shade"],["mdi:blinds-horizontal-closed","mdi:blinds-horizontal"],["mdi:garage-variant","mdi:garage-open-variant"],["mdi:door","mdi:door-open"]];function hn(e){for(const t of[...Object.values(ln),...cn])if(e===t[0]||e===t[1])return t;return null}function dn(e,t,i,n,r){if(!n||"unavailable"===n||"unknown"===n)return e;if(r){const i="cover"===t?hn(e):null;return i?"closed"===n?i[0]:i[1]:e}if("binary_sensor"===t){if("door"===i)return"on"===n?"mdi:door-open":"mdi:door-closed";if("window"===i)return"on"===n?"mdi:window-open":"mdi:window-closed";if("garage_door"===i)return"on"===n?"mdi:garage-open-variant":"mdi:garage-variant"}if("cover"===t){const t=ln[String(i||"")];if(t)return"closed"===n?t[0]:t[1];const r=hn(e);return r?"closed"===n?r[0]:r[1]:e}return"lock"===t?"locked"===n?"mdi:lock":"mdi:lock-open-variant":"light"===t&&"mdi:lightbulb"===e&&"on"===n?"mdi:lightbulb-on":e}function un(e){const t=Math.min(4e4,Math.max(1e3,e))/100,i=t<=66?255:329.698727446*Math.pow(t-60,-.1332047592),n=t<=66?99.4708025861*Math.log(t)-161.1195681661:288.1221695283*Math.pow(t-60,-.0755148492),r=t>=66?255:t<=19?0:138.5177312231*Math.log(t-10)-305.0447927307,o=e=>Math.round(Math.min(255,Math.max(0,e)));return[o(i),o(n),o(r)]}const pn=1/2.2;function _n(e){const t=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/.exec(e);return t?"#"+t.slice(1).map(e=>Math.min(255,Number(e)).toString(16).padStart(2,"0")).join(""):null}function mn(e){if(!e||"object"!=typeof e||Array.isArray(e))return null;const t=e;if(Object.keys(t).some(e=>"c"!==e&&"bri"!==e))return null;const i=qt(t.c,null);return i?void 0===t.bri||null===t.bri?{c:i}:"number"!=typeof t.bri||!Number.isFinite(t.bri)||t.bri<.01||t.bri>1?null:{c:i,bri:t.bri}:null}function gn(e,t,i){const n=mn(t),r=e?.attributes||{},o=n?.bri??function(e){const t=e?.attributes?.brightness,i="number"==typeof t?t:"string"==typeof t&&""!==t.trim()?Number(t):Number.NaN;return Number.isFinite(i)?Math.max(0,Math.min(1,i/255)):1}(e);if(n)return{c:n.c,bri:o};const s=Wt(r.rgb_color);if(s)return{c:_n(s)||qt(i,"#ffd9a0"),bri:o};const a=Number(r.color_temp_kelvin)||(Number(r.color_temp)>0?1e6/Number(r.color_temp):NaN);return Number.isFinite(a)&&a>0?{c:(l=un(a),"#"+l.slice(0,3).map(e=>Math.min(255,Math.max(0,Math.round(Number(e)||0))).toString(16).padStart(2,"0")).join("")),bri:o}:{c:qt(i,"#ffd9a0"),bri:o};var l}function fn(e,t,i){return"on"===e?.state?gn(e,t,i):null}function vn(e,t=1){const i=Math.max(0,Math.min(1,Number.isFinite(e)?e:1)),n=.7*Math.max(0,Math.min(1,Number.isFinite(t)?t:1))*(.4+.6*Math.pow(i,pn));return Math.max(0,Math.min(1,n))}function yn(e){return e.startsWith("light.")||e.startsWith("switch.")}function bn(e,t,i=1e-6){const n=[];if(!e||!t||e.length<3||t.length<3)return n;for(let r=0;ru||l>u)continue;const p=(r[0]-o[0])*h+(r[1]-o[1])*d,_=(s[0]-o[0])*h+(s[1]-o[1])*d,m=Math.max(0,Math.min(p,_)),g=Math.min(c,Math.max(p,_));g-m>i&&n.push([o[0]+h*m,o[1]+d*m,o[0]+h*g,o[1]+d*g])}}return n}function wn(e,t,i=1e-6){const n=[];for(const r of e){const e=[r[0],r[1]],o=[r[2],r[3]],s=o[0]-e[0],a=o[1]-e[1],l=Math.hypot(s,a);if(lo||r>o)continue;const s=(n[0]-e[0])*c+(n[1]-e[1])*h,a=(n[2]-e[0])*c+(n[3]-e[1])*h,u=Math.max(0,Math.min(s,a)),p=Math.min(l,Math.max(s,a));p-u>i&&d.push([u,p])}if(!d.length){n.push([e[0],e[1],o[0],o[1]]);continue}d.sort((e,t)=>e[0]-t[0]);let u=0;for(const[t,r]of d)t-u>i&&n.push([e[0]+c*u,e[1]+h*u,e[0]+c*t,e[1]+h*t]),u=Math.max(u,r);l-u>i&&n.push([e[0]+c*u,e[1]+h*u,o[0],o[1]])}return n}function kn(e,t,i=1e-6){const n=[];for(let t=0;t{if("string"!=typeof e||!e)return;const i=Mn(e);i.startsWith("/api/houseplan/content/")&&t.add(i)};for(const t of e?.spaces||[]){i(t?.plan_url);for(const e of t?.markers||[])for(const t of e?.pdfs||[])i(t?.url)}for(const t of e?.markers||[])for(const e of t?.pdfs||[])i(e?.url);return t}function Mn(e){return e?e.startsWith("/houseplan_files/plans/")?"/api/houseplan/content/plans/_/"+e.slice(23):e.startsWith("/houseplan_files/files/")?"/api/houseplan/content/files/"+e.slice(23):e:""}function Rn(e,t){const i=t?.settings?.fill_mode;return"none"===i||"lqi"===i||"light"===i||"temp"===i||"custom"===i?i:e}function Tn(e,t){const i=t?.settings;return"boolean"==typeof i?.glow?i.glow:"glow"===i?.fill_mode||e}function Cn(e,t,i,n){if(!t||!i||t===i)return e;const r="/files/"+t+"/",o="/files/"+i+"/";return e.map(e=>{if(!e.url.includes(r))return e;const t=e.url.split(r)[1]||"",[i,s]=[t.split("?")[0],t.includes("?")?"?"+t.split("?")[1]:""];if(n){const t=n[decodeURIComponent(i)]??n[i];return t?{...e,url:e.url.split(r+i)[0]+o+encodeURIComponent(t)+s}:e}return{...e,url:e.url.split(r).join(o)}})}function Dn(e,t=1){const i=Number(e);return Number.isFinite(i)&&i>0?Math.min(3,Math.max(.5,i)):t}function An(e,t,i){let n=null,r=null;for(const o of t){if(!(Math.abs(o[0]-e[0])<1e-6&&Math.abs(o[1]-e[1])<1e-6)){if(Math.abs(o[0]-e[0])<=i){const t=Math.abs(o[1]-e[1]);t>1e-6&&(!n||t1e-6&&(!r||t"number"==typeof e&&Number.isFinite(e),Wn=(e,t,i)=>Math.min(i,Math.max(t,e));function Un(e){return e.elevation<=-6?"night":e.elevation>=6?"day":e.rising?"dawn":"dusk"}function Gn(e){const t=(Math.floor(Number(e)||0)%1440+1440)%1440;return t>=300&&t<480?"dawn":t>=480&&t<1080?"day":t>=1080&&t<1260?"dusk":"night"}function Vn(e){const t=Un(e),i=e.azimuth*Math.PI/180;return{sunX:50-42*Math.sin(i),sunY:78-Wn(e.elevation,0,90)/90*64,sunOpacity:"night"===t?0:Wn((e.elevation+6)/12,0,1)}}function Kn(e){const t=(Math.floor(Number(e)||0)%1440+1440)%1440;if(t<300||t>=1260)return{sunX:50,sunY:78,sunOpacity:0};const i=(t-300)/960,n=(t-300)/120,r=(1260-t)/120;return{sunX:8+84*i,sunY:78-64*Math.sin(i*Math.PI),sunOpacity:Math.max(.18,Math.min(n,r,1))}}function Yn(e,t=new Date){const i=function(e){const t=e?.states?.["sun.sun"]?.attributes;return t&&Bn(t.azimuth)&&Bn(t.elevation)&&"boolean"==typeof t.rising?{azimuth:Ln(t.azimuth),elevation:t.elevation,rising:t.rising}:null}(e);if(i)return{phase:Un(i),source:"sun",...Vn(i)};const n="number"==typeof t?t:function(e=new Date){return 60*e.getHours()+e.getMinutes()}(t);return{phase:Gn(n),source:"clock",...Kn(n)}}function Zn(e){return`${e.source}|${e.phase}|${e.sunX.toFixed(2)}|${e.sunY.toFixed(2)}|`+e.sunOpacity.toFixed(3)}const Xn=[[-90,"#070c14"],[-12,"#070c14"],[-4,"#131a28"],[0,"#4a3527"],[10,"#e8ddcf"],[30,"#ffffff"],[90,"#ffffff"]],Jn=e=>Math.min(1,Math.max(0,e));function Qn(e,t,i=6){const n=e.angle*Math.PI/180,r=[Math.sin(n),-Math.cos(n)],o=n=>{const o=[e.x+r[0]*i*n,e.y+r[1]*i*n];return t.find(e=>e.poly.length>=3&&si(o,e.poly))||null},s=o(1),a=o(-1);return s&&a?null:s||a?s?{normal:[-r[0],-r[1]],roomId:s.id}:{normal:r,roomId:a.id}:null}function er(e,t,i){return i>0&&e[0]*t[0]+e[1]*t[1]>.05}function tr(e,t,i,n){return[[e[0],e[1]],[t[0],t[1]],[t[0]+i[0]*n,t[1]+i[1]*n],[e[0]+i[0]*n,e[1]+i[1]*n]]}function ir(e,t){try{const i=Nt([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]),n=[];for(const e of i){const t=e?.[0];!Array.isArray(t)||t.length<4||n.push(t.slice(0,t.length-1).map(e=>[e[0],e[1]]))}return n}catch{return[]}}function nr(e,t,i,n,r,o,s){if(!(n>0))return[];const a=qn(i,r),l=[-a[0],-a[1]],c=function(e){const t=Math.min(90,Math.max(0,e));return.7*(.8+1.7*Math.pow(1-t/90,1.6))}(n),h=[];for(const i of t){if(!(i.length>0))continue;const t=Qn(i,e);if(!t||!er(t.normal,a,n))continue;const r=e.find(e=>e.id===t.roomId);if(!r)continue;const d=o&&o[t.roomId]||r.poly,u=i.angle*Math.PI/180,p=i.length/2,_=[-t.normal[0],-t.normal[1]],m=Math.max(0,s?.[i.id]||0),g=i.x+_[0]*m/2,f=i.y+_[1]*m/2,v=Math.cos(u)*p,y=Math.sin(u)*p,b=[g-v,f-y],w=[g+v,f+y],k=c*i.length,x=ir(tr(b,w,l,k),d);if(!x.length)continue;const $=l[0]*_[0]+l[1]*_[1];h.push({openingId:i.id,roomId:t.roomId,polys:x,a:b,b:w,dir:l,len:k,normal:_,depth:k*$})}return h}const rr=e=>"number"==typeof e&&Number.isInteger(e)&&e>=0&&e<=359?e:null;function or(e,t){const i=rr(t?.north_deg);return null!==i?i:rr(e?.north_deg)}function sr(e,t){const i=e=>"static"===e||"daynight"===e?e:null;return i(t?.bg_mode)??i(e?.bg_mode)??"static"}function ar(e,t){const i=t?.sun_rays;return"boolean"==typeof i?i:!0===e?.sun_rays}function lr(e){const t=e?.states?.["sun.sun"]?.attributes,i=Number(t?.azimuth),n=Number(t?.elevation);return Number.isFinite(i)&&Number.isFinite(n)?{azimuth:i,elevation:n}:null}const cr=["dawn","day","dusk","night"];function hr(e){if(!e)return"";const t=jn[e.phase];return[`--hp-day-cycle-outline-near:${t.outlineNear}`,`--hp-day-cycle-outline-mid:${t.outlineMid}`,`--hp-day-cycle-outline-far:${t.outlineFar}`].join(";")}function dr(e,t=1){if(!e)return G;const i=[`--hp-day-cycle-sun-x:${e.sunX.toFixed(2)}%`,`--hp-day-cycle-sun-y:${e.sunY.toFixed(2)}%`,`--hp-day-cycle-sun-opacity:${e.sunOpacity.toFixed(3)}`,`opacity:${Math.min(1,Math.max(0,t)).toFixed(4)}`].join(";");return B``}const ur={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},pr=(e,t=1)=>{const i=Number(e);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):t},_r=e=>{let t=Number(e);return Number.isFinite(t)?(t=(t%360+360)%360,t>180?t-360:t):0};function mr(e,t,i){return _r(t)?[e.x,e.y]:i([e.x,e.y])}function gr(e,t,i,n){const r=Math.abs(i[0]-t[0]),o=Math.abs(i[1]-t[1]);return"line"===e?Math.hypot(r,o)>=n:r>=n&&o>=n}const fr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&n>0?n/r*i:0},vr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&i>0?n/i*r:0},yr=(e,t,i,n=ur.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return r;const o=Number(e?.width);return Number.isFinite(o)&&o>0?vr(o,t,i):n};function br(e,t){return{color:e.color,opacity:pr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),...t?{fill:e.fill,fill_color:e.fillColor,fill_opacity:pr(e.fillOpacity,.25)}:{}}}function wr(e){const t=e.x+e.w/2,i=e.y+e.h/2,n=_r(e.angle)*Math.PI/180,r=Math.cos(n),o=Math.sin(n),s=(e,n)=>{const s=e-t,a=n-i;return[t+s*r-a*o,i+s*o+a*r]};return[s(e.x,e.y),s(e.x+e.w,e.y),s(e.x+e.w,e.y+e.h),s(e.x,e.y+e.h)]}function kr(e){const t=wr(e),i=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],n=[(t[0][0]+t[2][0])/2,(t[0][1]+t[2][1])/2];return{points:[...t,i(t[0],t[1]),i(t[1],t[2]),i(t[2],t[3]),i(t[3],t[0]),n],segments:t.map((e,i)=>({a:e,b:t[(i+1)%4]}))}}function xr(e,t,i,n,r,o,s,a){const l=_r(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:e.w/2,g=i>0?-e.h/2:e.h/2,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v;let w=(y*c+b*h)*(t>0?1:-1),k=(y*d+b*u)*(i>0?1:-1),x=null;if(o){const t=w/Math.max(e.w,a),i=k/Math.max(e.h,a);x=Math.max(a/Math.max(e.w,a),a/Math.max(e.h,a),t,i),w=e.w*x,k=e.h*x}if(s>0)if(o){const t=Math.max(1,Math.round(e.w/s)),i=Math.max(1,Math.round(e.h/s));if(Math.abs(e.w-t*s)<1e-6&&Math.abs(e.h-i*s)<1e-6){const n=(e,t)=>{let i=Math.abs(e),n=Math.abs(t);for(;n;)[i,n]=[n,i%n];return Math.max(1,i)},r=1/n(t,i),o=Math.max(a/e.w,a/e.h),s=Math.max(o,Math.round((x??1)/r)*r);w=e.w*s,k=e.h*s}else{e.w>=e.h?(w=Math.round(w/s)*s,k=w*(e.h/Math.max(e.w,a))):(k=Math.round(k/s)*s,w=k*(e.w/Math.max(e.h,a)))}}else w=Math.round(w/s)*s,k=Math.round(k/s)*s;w=Math.max(a,w),k=Math.max(a,k);return{x:f+(t>0?w/2:-w/2)*c+(i>0?k/2:-k/2)*d-w/2,y:v+(t>0?w/2:-w/2)*h+(i>0?k/2:-k/2)*u-k/2,w:w,h:k,angle:_r(e.angle)||void 0}}const $r=(e,t,i)=>{const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;if(o<1e-12)return[...t];const s=Math.max(0,Math.min(1,((e[0]-t[0])*n+(e[1]-t[1])*r)/o));return[t[0]+n*s,t[1]+r*s]};function Sr(e,t,i,n){const r=n(e);let o=null;for(const r of t.points){const t=n(r),s=Math.hypot(t[0]-e[0],t[1]-e[1]);s<=i&&(!o||se.points),segments:e.flatMap(e=>e.segments)}}const Rr=Math.tan(.25*Math.PI/180);function Tr(e,t){const i=Math.abs(Number(t[0])-Number(e[0])),n=Math.abs(Number(t[1])-Number(e[1]));if(!([i,n].every(Number.isFinite)&&i>0&&n>0))return null;const r=i>=n?"horizontal":"vertical",o=Math.max(i,n),s=Math.min(i,n);return s/o>Rr?null:{axis:r,major:o,minor:s,angleDegrees:180*Math.atan2(s,o)/Math.PI}}function Cr(e,t){const i=Tr(e,t);return i?"horizontal"===i.axis?[Number(t[0]),Number(e[1])]:[Number(e[0]),Number(t[1])]:[Number(t[0]),Number(t[1])]}const Dr=e=>`${e[0]},${e[1]}`,Ar=(e,t)=>e[0]===t[0]&&e[1]===t[1],Or=(e,t)=>{const i=Dr(e),n=Dr(t);return i{let t=0;for(let i=0;i{if(e.length<3)return!1;for(let t=0;t1e-12},Fr=e=>{for(let t=0;t+1Ar(e,t.from)?[...t.to]:[...e],Er=(e,t)=>e.map(e=>Array.isArray(e?.poly)?{...e,poly:e.poly.map(e=>Ir(e,t))}:e),Nr=(e,t,i)=>{const n=e.flatMap((e,t)=>Zt(e)?.some(e=>Ar(e,i.from))?[t]:[]);if(!n.length)return!1;for(const i of n){const n=Zt(e[i]),r=Zt(t[i]);if(!n||!r)continue;if(!Pr(r))return!1;const o=Math.sign(zr(n)),s=Math.sign(zr(r));if(o&&s&&o!==s)return!1}const r=new Set;for(const e of n){const i=Zt(t[e]);if(i)for(let n=0;n{let i=0;for(const n of e){const e=Zt(n);if(e)for(let n=0;n{const{a:i,b:n,axis:r}=e,o="horizontal"===r?{from:n,to:[n[0],i[1]]}:{from:n,to:[i[0],n[1]]},s="horizontal"===r?{from:i,to:[i[0],n[1]]}:{from:i,to:[n[0],i[1]]};return[{move:o,preservedDegree:Hr(t,i)},{move:s,preservedDegree:Hr(t,n)}].sort((e,t)=>t.preservedDegree-e.preservedDegree||Dr(e.move.to).localeCompare(Dr(t.move.to))||Dr(e.move.from).localeCompare(Dr(t.move.from))).map(e=>e.move)};function qr(e){const t=JSON.parse(JSON.stringify(e||{}));let i=Array.isArray(t.rooms)?t.rooms:[];const n=new Map;for(const e of i){const t=Zt(e);if(t)for(let e=0;ee.key.localeCompare(t.key))){let t=null;for(const n of Lr(e,i)){const e=a.get(Dr(n.from));if(e&&e!==Dr(n.to))continue;const r=Er(i,n);if(Nr(i,r,n)){t=n,i=r;break}}t?(a.set(Dr(t.from),Dr(t.to)),r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}t.rooms=i;for(const e of t.room_drafts||[]){if(!Array.isArray(e?.points)||e.points.length<2)continue;const t=e.points.map(e=>[...e]),i=t.slice(0,-1).flatMap((i,n)=>{const r=t[n+1],o=Tr(i,r);return o?[{key:`${String(e.id||"")}:${n}`,a:[...i],b:[...r],axis:o.axis}]:[]});let n=t;for(const e of i){let t=null;for(const i of Lr(e,[{poly:n}])){const e=n.map(e=>Ir(e,i)),r=e.length>=4&&Ar(e[0],e[e.length-1]),o=r?e.slice(0,-1):e;if(r?Pr(o):Fr(o)){t=i,n=e;break}}t?(r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}e.points=n}for(const e of t.partitions||[]){if(!Array.isArray(e?.a)||!Array.isArray(e?.b))continue;const i=Tr(e.a,e.b);if(!i)continue;const n={key:String(e.id||Or(e.a,e.b)),a:[...e.a],b:[...e.b],axis:i.axis};let a=null;for(const i of Lr(n,[{poly:[e.a,e.b]}])){const n=Ir(e.a,i),r=Ir(e.b,i),o=Math.hypot(r[0]-n[0],r[1]-n[1]);if(!(o>0))continue;const s=(t.openings||[]).filter(t=>"partition"===t?.host?.kind&&t.host.id===e.id).every(e=>{const t=Number(e.host.t),i=Number(e.length);return Number.isFinite(t)&&t>=0&&t<=1&&Number.isFinite(i)&&i>0&&t*o-i/2>=-1e-12&&t*o+i/2<=o+1e-12});if(s){a=i,e.a=n,e.b=r;break}}a?(r++,s=Math.max(s,Math.hypot(a.to[0]-a.from[0],a.to[1]-a.from[1]))):o++}return{space:t,report:{wallsStraightened:r,wallsStraightenSkipped:o,maxStraightenShift:s},changed:r>0}}const jr=10**9,Br=240,Wr=1e-4;function Ur(e){if(Array.isArray(e))return e.map(e=>Ur(e));if(null!==e&&"object"==typeof e){const t={};for(const[i,n]of Object.entries(e))t[i]=Ur(n);return t}return e}function Gr(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=(e<0||Object.is(e,-0)?-1:1)*(Math.floor(Math.abs(e)*jr+.5)/jr);return 0===t?0:t}function Vr(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=e*Br,i=Math.round(t);if(Math.abs(t-i)null!==Yr(e)):[]}function Xr(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=Gr(e[i]))}function Jr(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=Vr(e[i]))}function Qr(e){if(Array.isArray(e))for(let t=0;t{for(const r of n){const n=t[r];"number"==typeof n&&Number.isFinite(n)&&i(n,e)}},n=t=>{if(Array.isArray(t))for(let n=0;n{if(Array.isArray(e))for(const t of e)n(t)};for(const i of Zr(e.rooms))t(i,["x","y","w","h"]),r(i.poly);for(const t of Zr(e.walls))n(t.a),n(t.b);for(const t of Zr(e.wall_segments))n(t.a),n(t.b);for(const i of Zr(e.openings))t(i,["x","y"]);for(const i of Zr(e.decor))"line"===i.kind?t(i,["x1","y1","x2","y2"]):"rect"===i.kind||"ellipse"===i.kind||"furniture"===i.kind?t(i,["x","y","w","h"]):"text"===i.kind&&t(i,["x","y"]);for(const t of Zr(e.room_drafts))r(t.points);for(const t of Zr(e.partitions))n(t.a),n(t.b);for(const t of Zr(e.wall_columns))n(t.center);for(const t of Zr(e.open_spans))n(t.a),n(t.b)}const r=Yr(t);if(!r)return;const o=new Map;if(n)for(const e of Zr(n.spaces))null!=e.id&&o.set(String(e.id),e);for(const e of Object.values(r)){const t=Yr(e);if(!t)continue;const n=null!=t.s&&o.get(String(t.s))||null;for(const e of["x","y"]){const r=t[e];"number"==typeof r&&Number.isFinite(r)&&i(r,n)}}}function io(e){const t=Number(e?.cell_cm);return t>0?t:5}function no(e,t={}){const i={canonicalized:0,far:0,maxShift:0,maxShiftCm:0,spaces:[],bySpace:new Map},n=Zr(Yr(e)?.spaces);let r=5;for(const e of n)r=Math.max(r,io(e));to(e,t,(e,t)=>{const n=e*Br,o=Math.abs(n-Math.round(n)),s=Vr(e),a=o>0&&o=Wr))return;const l=a&&"number"==typeof s?Math.abs(s-e):0;if(a?i.canonicalized++:i.far++,i.maxShift=Math.max(i.maxShift,l),i.maxShiftCm=Math.max(i.maxShiftCm,l*Br*(t?io(t):r)),!t?.id||!a)return;const c=String(t.id);let h=i.bySpace.get(c);h||(h={spaceId:c,space:String(t.title||c),canonicalized:0,far:0,maxShift:0,maxShiftCm:0},i.bySpace.set(c,h)),h.canonicalized++,h.maxShift=Math.max(h.maxShift,l),h.maxShiftCm=Math.max(h.maxShiftCm,l*Br*io(t))}),i.bySpace.size&&to(e,t,(e,t)=>{if(!t?.id)return;const n=i.bySpace.get(String(t.id));if(!n)return;const r=e*Br;Math.abs(r-Math.round(r))>=Wr&&n.far++}),i.spaces=[...i.bySpace.values()];const{bySpace:o,...s}=i;return s}function ro(e){return function(e){const t=e,i=Yr(t);i&&Jr(i,["x","y"]);return t}(Ur(e))}function oo(e){const t=e,i=Yr(t);if(!i)return t;for(const e of Object.values(i)){const t=Yr(e);t&&Jr(t,["x","y"])}return t}function so(e){return ao(Ur(e))}function ao(e){const t=e,i=Yr(t);if(!i)return t;for(const e of Zr(i.spaces)){Xr(e,["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"]);for(const t of Zr(e.rooms))Jr(t,["x","y","w","h"]),eo(t.poly);for(const t of Zr(e.walls))Qr(t.a),Qr(t.b);for(const t of Zr(e.wall_segments))Qr(t.a),Qr(t.b);for(const t of Zr(e.openings)){Jr(t,["x","y"]),Xr(t,["angle","length"]);const e=Yr(t.host);e&&Xr(e,["t"])}for(const t of Zr(e.decor))"line"===t.kind?Jr(t,["x1","y1","x2","y2"]):"rect"===t.kind||"ellipse"===t.kind||"furniture"===t.kind?(Jr(t,["x","y","w","h"]),Xr(t,["angle"])):"text"===t.kind&&(Jr(t,["x","y"]),Xr(t,["scale","angle"]));for(const t of Zr(e.room_drafts))eo(t.points);for(const t of Zr(e.partitions))Qr(t.a),Qr(t.b);for(const t of Zr(e.wall_columns))Qr(t.center),"square"===t.shape&&Xr(t,["angle"]);for(const t of Zr(e.open_spans))Qr(t.a),Qr(t.b)}for(const e of Zr(i.markers))Xr(e,["angle"]);return t}const lo=15,co=8;function ho(e,t,i,n,r){const o=i[0]-e[0],s=i[1]-e[1],a=Math.hypot(o,s);if(!(a>0)||a<=r+1e-9)return null;const l=o/a,c=s/a,h=t=>{const n=(t[0]-e[0])*l+(t[1]-e[1])*c,o=(r-n)/(a-n);return!Number.isFinite(o)||o<-1e-9||o>1+1e-9?null:[t[0]+(i[0]-t[0])*o,t[1]+(i[1]-t[1])*o]},d=h(t),u=h(n);return d&&u?[[e[0],e[1]],t,d,u,n]:null}const uo=Math.sin(.25*Math.PI/180);function po(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<3}function _o(e){const t=Number(e)>0?Number(e):5;if(5===t)return 8;const i=5/t*8;return Math.min(80,Math.max(.5,i))}function mo(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<2}function go(e){return Number.isFinite(e)?Math.max(1,Math.min(100,e)):1}function fo(e,t){return!Number.isFinite(e)||e<0?"":String(t?Math.round(e/2.54*100)/100:Math.round(100*e)/100)}function vo(e,t,i){if(!Number.isFinite(e)||e<=0)return 0;const n=Number(t)>0?Number(t):5;return go(e)/n*i}function yo(e,t){return t>0&&Number.isFinite(e)?Math.round(e/t)*t:e}function bo(e){return Math.max(1e-6*Math.abs(e),1e-9)}function wo(e,t){if(!(t>0&&Number.isFinite(e)))return e;const i=yo(e,t);return Math.abs(i-e)<=bo(t)?i:e}function ko(e,t){let i=t[0]-e[0],n=t[1]-e[1];const r=Math.hypot(i,n);return r<1e-12?[1,0]:(i/=r,n/=r,(i<-1e-12||Math.abs(i)<=1e-12&&n<0)&&(i=-i,n=-n),[i,n])}function xo(e,t,i){const n=[wo(e[0],i),wo(e[1],i)],r=[wo(t[0],i),wo(t[1],i)],o=yo((n[0]+r[0])/2,i),s=yo((n[1]+r[1])/2,i),[a,l]=ko(n,r);let c=Math.atan2(l,a);c<0&&(c+=Math.PI);const h=Math.round(1800*c)/1800,d=i>0&&i<.01?6:i<1?4:2;return`${o.toFixed(d)},${s.toFixed(d)}@${h.toFixed(4)}`}function $o(e,t,i,n){return 1===n?xo(e,t,i):xo([e[0]/n,e[1]/n],[t[0]/n,t[1]/n],i)}function So(e,t){if(!Array.isArray(e.a)||!Array.isArray(e.b)||e.a.length<2||e.b.length<2)return null;const i=[Number(e.a[0]),Number(e.a[1]),Number(e.b[0]),Number(e.b[1])];if(!i.every(Number.isFinite))return null;const n=t>0?t:1;return[[i[0]*n,i[1]*n],[i[2]*n,i[3]*n]]}function Mo(e,t,i,n,r){const o=r>0?r:1;return{key:$o(e,t,n,o),cm:go(i),a:[e[0]/o,e[1]/o],b:[t[0]/o,t[1]/o]}}function Ro(e,t){const i=t>0?t:1,n=[];for(const t of e){const e=t.key.lastIndexOf("@");if(e<0)continue;const[r,o]=t.key.slice(0,e).split(",").map(Number),s=Number(t.key.slice(e+1));[r,o,s].every(Number.isFinite)&&n.push({w:t,x:r*i,y:o*i,ang:s})}return n}function To(e,t){const[i,n]=ko(e,t);let r=Math.atan2(n,i);return r<0&&(r+=Math.PI),r}function Co(e,t){let i=Math.abs(e-t);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function Do(e,t,i,n,r=1){if(!e?.length)return null;const o=$o(t,i,n,r),s=e.find(e=>e.key===o);if(s)return s;const a=r>0?r:1,l=bo(n)*a,c=(e,t)=>Math.abs(e[0]-t[0])<=l&&Math.abs(e[1]-t[1])<=l;for(const n of e){const e=So(n,a);if(e&&(c(e[0],t)&&c(e[1],i)||c(e[0],i)&&c(e[1],t)))return n}const h=(t[0]+i[0])/2,d=(t[1]+i[1])/2,u=To(t,i),p=Math.max(.5*n,1e-9)*a;for(const t of Ro(e,a))if(Co(t.ang,u)&&Math.hypot(t.x-h,t.y-d)<=p)return t.w;return null}function Ao(e,t,i,n,r=1){const o=Do(e,t,i,n,r);if(o&&o.cm>0)return go(o.cm);const s=function(e,t,i,n,r){if(!e?.length)return null;const o=r>0?r:1,s=Math.hypot(i[0]-t[0],i[1]-t[1]);if(s<1e-12)return null;const a=To(t,i),l=Math.max(.5*n,1e-9)*o;let c=null;for(const n of e){if(!(n.cm>0))continue;const e=So(n,o);if(!e)continue;const r=Math.hypot(e[1][0]-e[0][0],e[1][1]-e[0][1]);if(r<1e-12||!Co(To(e[0],e[1]),a))continue;if(bs(t[0],t[1],e[0][0],e[0][1],e[1][0],e[1][1])>l||bs(i[0],i[1],e[0][0],e[0][1],e[1][0],e[1][1])>l)continue;if(r+l(o.has(e.key)||(e=>{const t=So(e,n);if(!t)return!1;const[i,o]=t,a=o[0]-i[0],c=o[1]-i[1],h=Math.hypot(a,c);if(h<=l)return!1;if(!s.some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];return Co(To(i,o),To(t,n))&&bs(i[0],i[1],t[0],t[1],n[0],n[1])<=l&&bs(o[0],o[1],t[0],t[1],n[0],n[1])<=l}))return!1;const d=(r||[]).some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];if(!Co(To(i,o),To(t,n)))return!1;const r=e=>Math.abs((e[0]-i[0])*c-(e[1]-i[1])*a)/h;if(r(t)>l||r(n)>l)return!1;const s=h*h,d=((t[0]-i[0])*a+(t[1]-i[1])*c)/s,u=((n[0]-i[0])*a+(n[1]-i[1])*c)/s;return Math.min(1,Math.max(d,u))-Math.max(0,Math.min(d,u))>l/h});return!d})(e))&&e.cm>=1&&e.cm<=100)}function zo(e,t,i,n=8){const[r,o]=ko(e,t);let s=Math.atan2(o,r);s<0&&(s+=Math.PI);let a=i*Math.PI/180%Math.PI;a<0&&(a+=Math.PI);let l=Math.abs(s-a);return l>Math.PI/2&&(l=Math.PI-l),l<=n*Math.PI/180}function Po(e,t,i,n,r=1,o="affine",s){if(!e?.length)return[];if(t.length!==i.length)return"fixed-topology"===o&&s?.(),e.slice();const a=r>0?r:1,l=Math.max(.5*n,1e-9)*a,c=Math.max(n*a*1e-6,1e-9),h=[],d=new Map,u=new Map,p=(e,t,i)=>{const n=e.get(t)||new Set;n.add(i),e.set(t,n)};for(let e=0;e[e[0]+(t[0]-e[0])*i,e[1]+(t[1]-e[1])*i],m=(e,t)=>Math.hypot(e[0]-t[0],e[1]-t[1])<=c,g=(e,t)=>{if("fixed-topology"===o){const i=t.na[0]-t.oa[0],n=t.na[1]-t.oa[1],r=t.nb[0]-t.ob[0],o=t.nb[1]-t.ob[1];return Math.hypot(i-r,n-o)<=c?[e[0]+i,e[1]+n]:m(e,t.oa)?[...t.na]:m(e,t.ob)?[...t.nb]:[...e]}const i=Math.max(0,Math.min(1,((e[0]-t.oa[0])*t.dx+(e[1]-t.oa[1])*t.dy)/t.len2));return _(t.na,t.nb,i)},f=(e,t)=>{const[i,n]=ko(e,t);return(t[0]-e[0])*i+(t[1]-e[1])*n>=0?[[...e],[...t]]:[[...t],[...e]]},v=[],y=[],b=(e,t,i)=>{if(Math.hypot(t[0]-e[0],t[1]-e[1])<=c)return;const[r,o]=f(e,t),s=go(i);if(y.some(e=>e.entry.cm===s&&m(e.span[0],r)&&m(e.span[1],o)))return;const l=Mo(r,o,s,n,a);v.push(l),y.push({entry:l,span:[r,o]})};for(const t of e){const e=So(t,a);if(e){const[i,n]=f(e[0],e[1]),r=n[0]-i[0],s=n[1]-i[1],a=r*r+s*s,d=Math.sqrt(a);if(d<=c){v.push({...t,cm:go(t.cm)});continue}const u=[];for(const e of h){if(!Co(To(i,n),To(e.oa,e.ob)))continue;const t=e=>Math.abs((e[0]-i[0])*s-(e[1]-i[1])*r)/d;if(t(e.oa)>l||t(e.ob)>l)continue;const o=((e.oa[0]-i[0])*r+(e.oa[1]-i[1])*s)/a,h=((e.ob[0]-i[0])*r+(e.ob[1]-i[1])*s)/a,p=Math.max(0,Math.min(o,h)),_=Math.min(1,Math.max(o,h));(_-p)*d>c&&u.push({lo:p,hi:_,move:e})}if(!u.length){"fixed-topology"===o?v.push({...t}):b(i,n,t.cm);continue}const p=[0,1,...u.flatMap(({lo:e,hi:t})=>[e,t])].sort((e,t)=>e-t).filter((e,t,i)=>0===t||Math.abs(e-i[t-1])*d>c),y=[];for(let e=0;e+1a>=e.lo-1e-12&&a<=e.hi+1e-12);if(!l.length){y.push([o,s]);continue}const h=[g(o,l[0].move),g(s,l[0].move)],f=l.slice(1).some(e=>{const t=g(o,e.move),i=g(s,e.move);return!m(h[0],t)||!m(h[1],i)});y.push(f?[o,s]:h)}const w=(e,t)=>{const i=e[1][0]-e[0][0],n=e[1][1]-e[0][1],r=t[1][0]-t[0][0],o=t[1][1]-t[0][1],s=Math.hypot(i,n);return!(s<=c||i*r+n*o<=0)&&Math.abs(i*o-n*r)/s<=c},k=[];for(const e of y){const t=k[k.length-1];t&&m(t[1],e[0])&&w(t,e)?t[1]=e[1]:k.push([[...e[0]],[...e[1]]])}if("fixed-topology"===o&&1===k.length){const[i,n]=k[0];if(m(i,e[0])&&m(n,e[1])||m(i,e[1])&&m(n,e[0])){v.push({...t});continue}}for(const[e,i]of k)b(e,i,t.cm);continue}if("fixed-topology"===o){const e=u.get(t.key);if(1===e?.size){const i=[...e][0];v.push(i===t.key?{...t}:{...t,key:i});continue}const i=[Ro([t],a)[0]];1!==a&&i.push(Ro([t],1)[0]);const n=i.filter(Boolean).some(e=>h.some(t=>{if(!Co(e.ang,To(t.oa,t.ob)))return!1;const i=((e.x-t.oa[0])*t.dx+(e.y-t.oa[1])*t.dy)/t.len2;return i>=-1e-6&&i<=1.000001&&bs(e.x,e.y,t.oa[0],t.oa[1],t.ob[0],t.ob[1])<=l}));((e?.size||0)>1||n)&&s?.(),v.push({...t});continue}let i="";const r=d.get(t.key);if(1===r?.size&&(i=[...r][0]),!i){const e=Ro([t],a)[0];if(e){const t=new Set;for(const i of h){if(!Co(e.ang,To(i.oa,i.ob)))continue;const r=((e.x-i.oa[0])*i.dx+(e.y-i.oa[1])*i.dy)/i.len2;if(r<-1e-6||r>1.000001)continue;if(bs(e.x,e.y,i.oa[0],i.oa[1],i.ob[0],i.ob[1])>l)continue;const o=g([e.x,e.y],i),[s,c]=ko(i.na,i.nb),h=Math.max(n*a,1e-6);t.add($o([o[0]-s*h,o[1]-c*h],[o[0]+s*h,o[1]+c*h],n,a))}1===t.size&&(i=[...t][0])}}v.push({...t,key:i||t.key,cm:go(t.cm)})}return v}function Fo(e,t,i,n,r=1,o="affine"){return Po(e,t,i,n,r,o)}function Io(e,t,i,n,r=1,o="fixed-topology"){let s=!1;const a=Po(e,t,i,n,r,o,()=>{s=!0});return{walls:s?(e||[]).map(e=>({...e})):a,rejected:s}}function Eo(e,t,i,n=1,r=[]){const o=n>0?n:1,s=Math.abs(i),a=Math.max(s*o*Wr,1e-9),l=(r||[]).flatMap(e=>{const t=So(e,o);return t?t.map(e=>[...e]):[]}),c=e=>e.every((e,t)=>(e=>{if(!(s>0))return!0;const t=e/o/s;return Math.abs(t-Math.round(t))Math.abs(e-i[t])<=a)),h=[],d=e=>JSON.stringify([e.key,e.cm,e.a,e.b]);for(const i of e||[]){const e=So(i,o);if(!e)continue;const[n,r]=e;if(![n[0],n[1],r[0],r[1]].every(Number.isFinite)||!c(n)||!c(r)){h.push(d(i));continue}const s=r[0]-n[0],l=r[1]-n[1],u=Math.hypot(s,l);if(u<=a){h.push(d(i));continue}const p=s/u,_=l/u,m=[];for(const e of t){const[t,i]=e;if(![t?.[0],t?.[1],i?.[0],i?.[1]].every(Number.isFinite))continue;const r=e=>Math.abs((e[0]-n[0])*_-(e[1]-n[1])*p);if(r(t)>a||r(i)>a)continue;const o=(t[0]-n[0])*p+(t[1]-n[1])*_,s=(i[0]-n[0])*p+(i[1]-n[1])*_,l=Math.max(0,Math.min(o,s)),c=Math.min(u,Math.max(o,s));c-l>a&&m.push([l,c])}m.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let g=0;for(const[e,t]of m){if(e>g+a)break;if(g=Math.max(g,t),g>=u-a)break}ge.key!==s);return null==n||n<1?a:[...a,Mo(t,i,n,r,o)]}function Ho(e,t,i,n,r,o=[],s=1){let a=e?e.slice():[];for(const e of function(e,t,i,n,r=1,o=[]){const s=ss(e,t,i,n,r,o);if(!s)return[];const a=[];for(let e=0;e0||(c=No(c,t,i,n,r,s)))}return c}function qo(e){const{a:t,b:i,halfDepth:n}=e;if(!Array.isArray(t)||!Array.isArray(i)||t.length<2||i.length<2||![t[0],t[1],i[0],i[1]].every(Number.isFinite))return null;const r=i[0]-t[0],o=i[1]-t[1],s=Math.hypot(r,o);if(!(s>1e-9&&n>0&&Number.isFinite(n)))return null;const a=-o/s*n,l=r/s*n;return[[t[0]+a,t[1]+l],[i[0]+a,i[1]+l],[i[0]-a,i[1]-l],[t[0]-a,t[1]-l]]}function jo(e,t,i){return Math.hypot(e[0]-t[0],e[1]-t[1])<=i}function Bo(e,t,i){const n=t.b[0]-t.a[0],r=t.b[1]-t.a[1],o=n*n+r*r;if(!(o>i*i))return!1;const s=((e[0]-t.a[0])*n+(e[1]-t.a[1])*r)/o;if(!(s>0&&s<1))return!1;const a=[t.a[0]+n*s,t.a[1]+r*s];return Math.hypot(e[0]-a[0],e[1]-a[1])<=i}function Wo(e,t,i,n){const r=Math.hypot(t,i);if(!(r>1e-9&&n>0))return;const o=[t/r,i/r],s=e.find(e=>Math.abs(e.u[0]*o[1]-e.u[1]*o[0])<1e-9&&e.u[0]*o[0]+e.u[1]*o[1]>1-1e-9);s?s.halfDepth=Math.max(s.halfDepth,n):e.push({u:o,halfDepth:n})}function Uo(e,t){try{const i=Ht(xs(e),xs(t));let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(Xo(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function Go(e,t=1e-6){const i=(e||[]).map((e,t)=>({segment:e,index:t})).filter(({segment:e})=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(({segment:e})=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>jo(t,e,n))||o.push(e);const s=[];for(const e of o){const t=[];let r=!1;for(const{segment:o,index:s}of i){const i=Math.hypot(o.b[0]-o.a[0],o.b[1]-o.a[1]);jo(e,o.a,n)?t.push({u:[(o.b[0]-o.a[0])/i,(o.b[1]-o.a[1])/i],halfDepth:o.halfDepth,length:i,index:s}):jo(e,o.b,n)?t.push({u:[(o.a[0]-o.b[0])/i,(o.a[1]-o.b[1])/i],halfDepth:o.halfDepth,length:i,index:s}):Bo(e,o,n)&&(r=!0)}if(r||2!==t.length)continue;const[o,a]=t,l=o.u[0]*a.u[1]-o.u[1]*a.u[0];if(Math.abs(l)<1e-9)continue;const c=l<0?1:-1,h=[-o.u[1],o.u[0]],d=[-a.u[1],a.u[0]],u=[e[0]+h[0]*o.halfDepth*c,e[1]+h[1]*o.halfDepth*c],p=[e[0]-d[0]*a.halfDepth*c,e[1]-d[1]*a.halfDepth*c];if(!es(u,o.u,p,a.u))continue;const _=[[o,a,p,[d[0]*-c,d[1]*-c]],[a,o,u,[h[0]*c,h[1]*c]]];for(const[t,,i,r]of _){const o=Math.min(2*t.halfDepth,t.length),a=[-t.u[1]*t.halfDepth,t.u[0]*t.halfDepth],l=[[e[0]+a[0],e[1]+a[1]],[e[0]+t.u[0]*o+a[0],e[1]+t.u[1]*o+a[1]],[e[0]+t.u[0]*o-a[0],e[1]+t.u[1]*o-a[1]],[e[0]-a[0],e[1]-a[1]]],c=e=>(e[0]-i[0])*r[0]+(e[1]-i[1])*r[1],h=[];for(let e=0;e=-1e-12&&h.push(t),n>1e-12&&r<-1e-12||n<-1e-12&&r>1e-12){const e=n/(n-r);h.push([t[0]+(i[0]-t[0])*e,t[1]+(i[1]-t[1])*e])}}h.length>=3&&Math.abs(Xo(h))>n*n&&s.push({segmentIndex:t.index,wedge:h})}}return s}function Vo(e,t=1e-6){const i=(e||[]).filter(e=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(e=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>jo(t,e,n))||o.push(e);const s=[],a=i.map((e,t)=>({roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`join-${t}`,kind:"outer",cm:0,open:!1,half:e.halfDepth})),l=ds(a,n);for(const e of us(l).fans)s.push(e);const c=e=>!!ps(l,e);for(const e of o){if(c(e))continue;const t=[];for(const r of i)jo(e,r.a,n)?Wo(t,r.b[0]-r.a[0],r.b[1]-r.a[1],r.halfDepth):jo(e,r.b,n)?Wo(t,r.a[0]-r.b[0],r.a[1]-r.b[1],r.halfDepth):Bo(e,r,n)&&(Wo(t,r.a[0]-e[0],r.a[1]-e[1],r.halfDepth),Wo(t,r.b[0]-e[0],r.b[1]-e[1],r.halfDepth));if(!(t.length<2)){t.sort((e,t)=>Math.atan2(e.u[1],e.u[0])-Math.atan2(t.u[1],t.u[0])||e.halfDepth-t.halfDepth);for(let i=0;in*n&&s.push(m)}}}return s}function Ko(e,t,i,n){if(!(t>0)||!e||e.length<2)return"";if(i&&e.length>=3){let i=e;const r=e[e.length-1];if(e.length>=4&&Math.hypot(e[0][0]-r[0],e[0][1]-r[1])<1e-9&&(i=e.slice(0,-1)),i.length>=3){const e=i.map((e,i)=>n?.[i]||t),r=js(i,e),o=ns(i,e);if(r&&o)return`${rs(r)} ${rs(os(o))}`}}const r=[];for(let i=0;i=1e-9&&a>0&&r.push({a:o,b:s,halfDepth:a})}const o=r.map(qo);for(const{segmentIndex:e,wedge:t}of Go(r)){const i=o[e];if(!i)continue;const n=Uo(i,t);n&&(o[e]=n)}const s=[...o.filter(e=>!!e),...Vo(r)],a=function(e){let t=null;try{for(const i of e){if(i.length<3)continue;const e=xs(i);t=t?Et(t,e):[e]}return t}catch{return null}}(s);return a?Fs(a):s.map(e=>rs(e)).join(" ")}function Yo(e,t,i,n,r=1){if(!i.length)return!1;const o=Zo(n,r),s=(e[0]+t[0])/2,a=(e[1]+t[1])/2,[l,c]=ko(e,t);for(const e of i){const[t,i]=ko([e[0],e[1]],[e[2],e[3]]);if(!(Math.abs(l*i-c*t)>.05)&&bs(s,a,e[0],e[1],e[2],e[3])<=o)return!0}return!1}function Zo(e,t){return Math.max(e*(t>0?t:1)*.04,1e-9)}function Xo(e){let t=0;for(let i=0;ie[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s+0)+o&&(i=!i)}return i}([c[0]+.001*a,c[1]+.001*l],e)||(a=-a,l=-l),[a,l]}function Qo(e,t){const i=e[0]*t[1]-e[1]*t[0],n=e[0]*t[0]+e[1]*t[1];return Math.abs(i)<1e-9&&n>0}function es(e,t,i,n){const r=t[0]*n[1]-t[1]*n[0];if(Math.abs(r)<1e-12)return null;const o=[i[0]-e[0],i[1]-e[1]],s=(o[0]*n[1]-o[1]*n[0])/r;return[e[0]+s*t[0],e[1]+s*t[1]]}function ts(e,t,i){const n=e?.length||0;if(n<3||!Array.isArray(i)||i.length!==n)return 0;const r=(Math.trunc(t)%n+n)%n,o=e[r],s=e[(r+1)%n],a=s[0]-o[0],l=s[1]-o[1],c=Math.hypot(a,l);if(!(c>0))return 0;const h=Math.max(0,Number(i[r])||0);if(!(h>0))return c;const d=[a/c,l/c],u=Jo(e,r),p=[o[0]+u[0]*h,o[1]+u[1]*h],_=t=>{const r=Math.max(0,Number(i[t])||0);if(!(r>0))return null;const s=e[t],a=e[(t+1)%n],l=a[0]-s[0],c=a[1]-s[1],h=Math.hypot(l,c);if(!(h>0))return null;const u=Jo(e,t),_=es(p,d,[s[0]+u[0]*r,s[1]+u[1]*r],[l/h,c/h]);return _?(_[0]-o[0])*d[0]+(_[1]-o[1])*d[1]:null},m=_((r-1+n)%n)??0,g=(_((r+1)%n)??c)-m;return g>0?g:0}function is(e,t,i,n,r,o,s,a=1){const l=(e||[]).find(e=>e?.id===t),c=Zt(l);if(!c||c.length<3)return null;const h=ms(e,t,i,n,r,o,s,a);if(!h)return c.map(()=>0);const d=4*Zo(r,a);return c.map((e,t)=>{const i=c[(t+1)%c.length],n=[(e[0]+i[0])/2,(e[1]+i[1])/2];for(let e=0;e!(e>0)))return e.map(e=>[e[0],e[1]]);const r=[];for(let o=0;o0||u>0)){r.push([e[o][0],e[o][1]]);continue}if(d>0!=u>0){const t=e[o],i=d>0?[t[0]+p*d,t[1]+_*d]:[t[0],t[1]],n=u>0?[t[0]+m*u,t[1]+g*u]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(Qo(w,k)){const t=e[o],i=[t[0]+p*d,t[1]+_*d],n=[t[0]+m*u,t[1]+g*u];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const S=es(x,w,$,k),M=Math.max(d,u,1e-9),R=ps(i,e[o])?.limit??4*M;if(S){const i=Math.hypot(S[0]-e[o][0],S[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push(S);continue}if(Es(e,t,o)){r.push(S);continue}}d>0&&r.push([e[o][0]+p*d,e[o][1]+_*d]),u>0&&r.push([e[o][0]+m*u,e[o][1]+g*u]),d>0||u>0||r.push([e[o][0],e[o][1]])}return r.length>=3?r:null}function rs(e,t=!0){if(!e.length)return"";let i=`M ${e[0][0]} ${e[0][1]}`;for(let t=1;te?.id===t),a=Zt(s);if(!a||a.length<3)return null;const l=Zo(n,r),c=[];for(const i of e||[]){if(!i||i.id===t)continue;const e=Zt(i);if(e)for(const t of bn(a,e,l))c.push([t[0],t[1]],[t[2],t[3]])}for(const e of i||[])c.push([e[0],e[1]],[e[2],e[3]]);for(const e of o||[]){const t=So(e,r);t&&c.push(t[0],t[1])}const h=[],d=[];for(let e=0;el)continue;const s=((e[0]-t[0])*(i[0]-t[0])+(e[1]-t[1])*(i[1]-t[1]))/(n*n);s<=r||s>=1-r||(o.some(e=>Math.abs(e-s)*n<=2*l)||o.push(s))}o.sort((e,t)=>e-t);for(const n of o)h.push([t[0]+(i[0]-t[0])*n,t[1]+(i[1]-t[1])*n]),d.push(e)}return{poly:h,parent:d,orig:a}}function as(e,t,i,n){const r=t.poly.length,o=new Array(r).fill(0);if(!e?.length)return o;const s=new Set,a=[];for(let l=0;l0?(o[l]=go(c.cm),s.add(c.key)):a.push(l)}if(!a.length)return o;const l=n>0?n:1,c=Math.max(.5*i,1e-9)*l,h=Ro(e,l).filter(e=>e.w.cm>0);for(let e=a.length-1;e>=0;e--){const i=a[e],n=t.poly[i],s=t.poly[(i+1)%r],d=To(n,s);let u=null;for(const e of h){const t=So(e.w,l);if(!t||!Co(To(t[0],t[1]),d))continue;if(bs(n[0],n[1],t[0][0],t[0][1],t[1][0],t[1][1])>c||bs(s[0],s[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;const i=Math.hypot(s[0]-n[0],s[1]-n[1]),r=Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1]),o=Math.max(0,r-i);(!u||oc||bs(r[0],r[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;i=!0,o=Math.max(0,Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1])-_)}else{if(bs(e.x,e.y,n[0],n[1],r[0],r[1])>c)continue;o=Math.hypot(e.x-d,e.y-u)}(!p||i&&!p.exact||i===p.exact&&o0?i:1,o=(e||[]).filter(e=>e&&!e.open&&null!==e.kind&&Number.isFinite(e.half)&&e.half>0&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&[e.a[0],e.a[1],e.b[0],e.b[1]].every(Number.isFinite)&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>n).sort((e,t)=>e.key.localeCompare(t.key)||e.a[0]-t.a[0]||e.a[1]-t.a[1]||e.b[0]-t.b[0]||e.b[1]-t.b[1]||e.half-t.half),s=new Map;for(const e of o){const t=s.get(e.key);t?e.half>t.half&&s.set(e.key,{...t,half:e.half}):s.set(e.key,e)}const a=[...s.values()].flatMap(e=>[{point:[e.a[0],e.a[1]],other:e.b,halfDepth:e.half,kind:e.kind,key:e.key},{point:[e.b[0],e.b[1]],other:e.a,halfDepth:e.half,kind:e.kind,key:e.key}]).sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]||e.other[0]-t.other[0]||e.other[1]-t.other[1]||e.halfDepth-t.halfDepth),l=new Map;for(const e of a){const[t,i]=ls(e.point,n),r=cs(t,i),o=l.get(r)||[];o.push(e),l.set(r,o)}const c=[],h=new Map;for(const e of a){const t=hs(h,e.point,n).filter(t=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])<=n).sort((t,i)=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])-Math.hypot(i.point[0]-e.point[0],i.point[1]-e.point[1])||t.point[0]-i.point[0]||t.point[1]-i.point[1]);let i=t[0];if(!i){i={point:[...e.point],rays:[]},c.push(i);const[t,r]=ls(i.point,n),o=cs(t,r),s=h.get(o)||[];s.push(i),h.set(o,s)}const r=e.other[0]-e.point[0],o=e.other[1]-e.point[1],s=Math.hypot(r,o);if(!(s>n))continue;const a=[r/s,o/s];let l=Math.atan2(a[1],a[0]);l<0&&(l+=2*Math.PI),i.rays.push({u:a,halfDepth:e.halfDepth,length:s,angle:l})}const d=[],u=e=>{const t=1e-9*Math.max(1,r),i=e.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);return i.filter((e,n)=>!i.some((i,r)=>r!==n&&i.halfDepth>=e.halfDepth-t&&i.length>=e.length-t&&(i.halfDepth>e.halfDepth+t||i.length>e.length+t||re.length-t.length||e.halfDepth-t.halfDepth).map(e=>({...e}))};for(const e of c){const t=e.rays.sort((e,t)=>e.angle-t.angle||e.length-t.length||e.halfDepth-t.halfDepth),i=[];for(const e of t){const t=i[i.length-1];t&&Math.abs(e.angle-t.angle)<=1e-9?t.supports.push({halfDepth:e.halfDepth,length:e.length}):i.push({u:[...e.u],angle:e.angle,supports:[{halfDepth:e.halfDepth,length:e.length}]})}if(i.length>1&&2*Math.PI-i[i.length-1].angle+i[0].angle<=1e-9){const e=i.pop();i[0].supports.push(...e.supports)}if(i.length<3)continue;const r=i.map(t=>{const i=u(t.supports),r=new Set,o=[];for(const s of i){const i=[e.point[0]+t.u[0]*s.length,e.point[1]+t.u[1]*s.length];for(const t of hs(l,i,n)){if("shared"!==t.kind||Math.hypot(t.point[0]-i[0],t.point[1]-i[1])>n)continue;const s=t.other[0]-t.point[0],a=t.other[1]-t.point[1],l=Math.hypot(s,a);if(!(l>n))continue;const c=s/l,h=a/l;if(Math.hypot(t.other[0]-e.point[0],t.other[1]-e.point[1])<=n)continue;const d=`${t.key}|${t.point[0]}|${t.point[1]}|${t.other[0]}|${t.other[1]}|${t.halfDepth}`;r.has(d)||(r.add(d),o.push({start:[t.point[0],t.point[1]],u:[c,h],length:l,halfDepth:t.halfDepth}))}}return o.sort((e,t)=>e.start[0]-t.start[0]||e.start[1]-t.start[1]||e.u[0]-t.u[0]||e.u[1]-t.u[1]||e.length-t.length||e.halfDepth-t.halfDepth),{u:[...t.u],halfDepth:Math.max(...i.map(e=>e.halfDepth)),length:Math.max(...i.map(e=>e.length)),supports:i,continuations:o}}).filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);if(r.length<3)continue;const o=Math.max(...r.map(e=>e.halfDepth));o>0&&Number.isFinite(o)&&d.push({point:[...e.point],rays:r,halfDepth:o,limit:1.25*o})}d.sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]);const p=new Map;for(const e of d){const[t,i]=ls(e.point,n),r=cs(t,i),o=p.get(r)||[];o.push(e),p.set(r,o)}return{epsilon:n,coordinateScale:r,nodes:d,index:p}}function us(e){const t={fans:[],supports:[]};if(!e?.nodes?.length)return t;const i=Math.max(e.epsilon,1e-9)**2;for(const n of e.nodes){const e=n.rays.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0).map(e=>({...e,thickLength:Math.max(...e.supports.filter(t=>t.halfDepth>=e.halfDepth-1e-12).map(e=>e.length),0),angle:(()=>{const t=Math.atan2(e.u[1],e.u[0]);return t<0?t+2*Math.PI:t})()})).sort((e,t)=>e.angle-t.angle);if(e.length<2)continue;const r=n.point;for(const i of e)for(const e of i.supports){if(!(e.halfDepth>0&&e.length>0))continue;const n=-i.u[1]*e.halfDepth,o=i.u[0]*e.halfDepth,s=[r[0]+i.u[0]*e.length,r[1]+i.u[1]*e.length];t.supports.push([[r[0]+n,r[1]+o],[s[0]+n,s[1]+o],[s[0]-n,s[1]-o],[r[0]-n,r[1]-o]])}for(let n=0;n{const e=s.angle-o.angle;return e>0?e:e+2*Math.PI})();if(a<1e-9)continue;const l=a>Math.PI+1e-9,c=4*Math.max(o.halfDepth,s.halfDepth),h=[r[0]-o.u[1]*o.halfDepth,r[1]+o.u[0]*o.halfDepth],d=[r[0]+s.u[1]*s.halfDepth,r[1]-s.u[0]*s.halfDepth],u=o.u[0]*s.u[1]-o.u[1]*s.u[0],p=e=>{let t=Math.atan2(e[1]-r[1],e[0]-r[0])-o.angle;for(;t<0;)t+=2*Math.PI;return t<=a+1e-9};let _=null;if(Math.abs(u)>1e-9){const e=((d[0]-h[0])*s.u[1]-(d[1]-h[1])*s.u[0])/u,t=((d[0]-h[0])*o.u[1]-(d[1]-h[1])*o.u[0])/u,i=[h[0]+o.u[0]*e,h[1]+o.u[1]*e];(l?e<=1e-9&&t<=1e-9:e>1e-9&&e<=o.thickLength&&t<=s.thickLength)&&Math.hypot(i[0]-r[0],i[1]-r[1])<=c&&p(i)&&(_=i)}const m=e=>{Math.abs(Xo(e))>i&&t.fans.push(e)};if(_){const e=1.5*Math.max(o.halfDepth,s.halfDepth);m(ho([r[0],r[1]],h,_,d,e)??[[r[0],r[1]],h,_,d]);continue}if(l){m([[r[0],r[1]],h,d]);continue}const g=(e,t)=>Math.min(t,Math.sqrt(Math.max(c**2-e**2,0)),2*Math.max(o.halfDepth,s.halfDepth)),f=[h[0]+o.u[0]*g(o.halfDepth,o.thickLength),h[1]+o.u[1]*g(o.halfDepth,o.thickLength)],v=[d[0]+s.u[0]*g(s.halfDepth,s.thickLength),d[1]+s.u[1]*g(s.halfDepth,s.thickLength)];m([[r[0],r[1]],h,f,v,d])}}return t}function ps(e,t){return!e||!Array.isArray(t)||t.length<2||!t.slice(0,2).every(Number.isFinite)?null:hs(e.index,t,e.epsilon).filter(i=>Math.hypot(i.point[0]-t[0],i.point[1]-t[1])<=e.epsilon).sort((e,i)=>Math.hypot(e.point[0]-t[0],e.point[1]-t[1])-Math.hypot(i.point[0]-t[0],i.point[1]-t[1])||e.point[0]-i.point[0]||e.point[1]-i.point[1])[0]||null}function _s(e,t,i,n,r,o,s){return ds(gs(e,t,i,n,r,o,s),4*Zo(n,s),s)}function ms(e,t,i,n,r,o,s,a=1){const l=ss(e,t,n,r,a,i);if(!l)return null;const c=function(e,t,i){const n=(e||[]).find(e=>e?.id===t),r=Zt(n);if(!r)return[];const o=[];for(const n of e||[]){if(!n||n.id===t)continue;const e=Zt(n);if(e)for(const t of bn(r,e,i))o.push(t)}return o}(e,t,Zo(r,a)),h=function(e,t,i,n,r){const o=Zo(n,r),s=[];for(let a=0;abs(h,d,e[0],e[1],e[2],e[3])<=o);s.push(u?"shared":"outer")}return s}(l.poly,c,n,r,a),d=as(i,l,r,a),u=d.map((e,t)=>h[t]&&e>0?vo(e,o,s)/2:0);return{...l,kinds:h,cms:d,offsets:u}}function gs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=ms(e,l.id,t,i,n,r,o,s);if(c)for(let e=0;e0&&(a=No(a,e.a,e.b,e.cm,n,s));return a}function vs(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=gs(e,t,i,n,r,o,s),l=new Map;for(const e of a){if(e.open||!e.kind||!e.roomId)continue;const t=l.get(e.key)||new Set;t.add(e.roomId),l.set(e.key,t)}const c=e=>{const t=[...l.get(e)||[]].sort();return 1!==t.length&&2!==t.length?`ambiguous:${e}`:`${1===t.length?"outer":"shared"}:${t.join("|")}`},h=[],d=new Set;for(const e of a)!e.open&&e.cm>0&&!d.has(e.key)&&(d.add(e.key),h.push({...e,ownerSignature:c(e.key)}));const u=[];for(const a of e||[]){if(!a?.id)continue;const l=ms(e,a.id,t,i,n,r,o,s);if(l)for(let e=0;e0)||null===l.kinds[i]){e++;continue}const o=c($o(l.poly[i],l.poly[(i+1)%l.poly.length],n,s));let a=e;for(;a+10&&u.push({a:[d[0],d[1]],b:[p[0],p[1]],key:$o(d,p,n,s),cm:r,len:_,ownerSignature:o}),e=a+1}}}u.sort((e,t)=>t.len-e.len||e.key.localeCompare(t.key));const p=[],_=new Set,m=new Set,g=4*Zo(n,s);for(const e of u){const t=h.filter(t=>!m.has(t.key)&&t.cm===e.cm&&t.ownerSignature===e.ownerSignature&&Co(To(t.a,t.b),To(e.a,e.b))&&bs(t.a[0],t.a[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g&&bs(t.b[0],t.b[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g);if(t.length){for(const e of t)m.add(e.key);_.has(e.key)||(_.add(e.key),p.push(Mo(e.a,e.b,e.cm,n,s)))}}for(const e of h)m.has(e.key)||_.has(e.key)||(_.add(e.key),p.push(Mo(e.a,e.b,e.cm,n,s)));return p}function ys(e,t,i,n,r,o,s,a=1){const l=Zo(r,a),c=(n[0]+n[2])/2,h=(n[1]+n[3])/2,d=To([n[0],n[1]],[n[2],n[3]]);let u=null;for(const n of gs(e,t,i,r,o,s,a)){if(!Co(To(n.a,n.b),d))continue;const e=bs(c,h,n.a[0],n.a[1],n.b[0],n.b[1]);e>4*l||(!u||e[e[0],e[1]]),o=Math.abs(Xo(r));r.length>=3&&o>i&&(t=r,i=o)}return t}function ks(e,t,i,n,r,o,s,a=1,l,c){const h=(e||[]).find(e=>e?.id===t),d=Zt(h);if(!d||d.length<3)return null;if(!i?.length)return d.map(e=>[e[0],e[1]]);const u=ms(e,t,i,n,r,o,s,a);if(!u||!u.offsets.some(e=>e>0))return d.map(e=>[e[0],e[1]]);const p=c||_s(e,i,n,r,o,s,a),_=ns(u.poly,u.offsets,p);if(!_)return d.map(e=>[e[0],e[1]]);if(!p.nodes.length)return _;const m=void 0===l?Ns(e,i,n,[],r,o,s,a):null,g=l??("ok"===m?.status||"degraded-extra"===m?.status?m.roomGeom:void 0);if(g)try{const e=ws(Ht(xs(u.poly),g));if(e)return e}catch{}return function(e,t){try{return ws(Nt(xs(e),xs(t)))}catch{return null}}(_,u.poly)||d.map(e=>[e[0],e[1]])}function xs(e){const t=e.map(e=>[e[0],e[1]]);return t.push([e[0][0],e[0][1]]),[t]}function $s(e){return!(!Array.isArray(e)||!e.length)&&e.every(e=>Array.isArray(e)&&e.length&&e.every(e=>Array.isArray(e)&&e.length>=4&&e.every(e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1])))&&Math.abs(yi(e[0]))>1e-9)}function Ss(e,t,i,n){const r=n?new Set(n):null;let o=null;for(let n=0;nt.epsilon))continue;const l=Ds([[e.point[0]+a[0]*n.halfDepth,e.point[1]+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r+a[0]*n.halfDepth,e.point[1]+s.u[1]*r+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r-a[0]*n.halfDepth,e.point[1]+s.u[1]*r-a[1]*n.halfDepth],[e.point[0]-a[0]*n.halfDepth,e.point[1]-a[1]*n.halfDepth]],t.coordinateScale);if(!l)continue;const c=xs(l);o=o?Et(o,c):c}}return o}function Ms(e,t,i){let n=null;for(const r of e.rays)for(const e of r.continuations){const r=[-e.u[1],e.u[0]],o=[e.start[0]+e.u[0]*e.length,e.start[1]+e.u[1]*e.length],s=Ds([[e.start[0]+r[0]*e.halfDepth,e.start[1]+r[1]*e.halfDepth],[o[0]+r[0]*e.halfDepth,o[1]+r[1]*e.halfDepth],[o[0]-r[0]*e.halfDepth,o[1]-r[1]*e.halfDepth],[e.start[0]-r[0]*e.halfDepth,e.start[1]-r[1]*e.halfDepth]],t.coordinateScale);if(!s)continue;const a=Nt(xs(s),i);Array.isArray(a)&&0!==a.length&&(n=n?Et(n,a):a)}return n}function Rs(e,t,i=2*(4*e.halfDepth+2*t.epsilon)){const n=function(e,t=uo){const i=new Set,n=Number.isFinite(t)&&t>=0?t:uo;for(let t=0;te-t)}(e);return n.length?Ss(e,t,i,n):null}function Ts(e,t,i,n,r){const o=function(e){let t=null;for(const i of e){const e=xs(i);try{t=t?Et(t,e):e}catch{}}return t}(function(e,t,i=!1){if(!e)return[];const n=[];for(const r of e.nodes)for(let o=0;o1e-9)||h>=Math.PI-1e-9)continue;const d=[-s.u[1],s.u[0]],u=[-a.u[1],a.u[0]],p=[r.point[0]+d[0]*s.halfDepth,r.point[1]+d[1]*s.halfDepth],_=[r.point[0]-u[0]*a.halfDepth,r.point[1]-u[1]*a.halfDepth],m=es(p,s.u,_,a.u);if(!m)continue;const g=Math.hypot(m[0]-r.point[0],m[1]-r.point[1]);if(!Number.isFinite(g)||g<=r.limit)continue;const f=t?Math.sqrt(Math.max(0,r.limit*r.limit-s.halfDepth*s.halfDepth)):0,v=t?Math.sqrt(Math.max(0,r.limit*r.limit-a.halfDepth*a.halfDepth)):0,y=Ds([[p[0]+s.u[0]*f,p[1]+s.u[1]*f],[_[0]+a.u[0]*v,_[1]+a.u[1]*v],m],e.coordinateScale);if(y&&n.push(y),i){const t=m[0]-r.point[0],i=m[1]-r.point[1],o=Math.hypot(t,i),s=g-r.limit;if(o>e.epsilon&&s>e.epsilon){const a=Math.min(Math.max(8*e.epsilon,.05*r.halfDepth),.25*s),l=t/o,c=i/o,h=-c,d=l,u=Ds([[m[0]-l*a+h*a,m[1]-c*a+d*a],[m[0]-l*a-h*a,m[1]-c*a-d*a],[m[0]+l*a,m[1]+c*a]],e.coordinateScale);u&&n.push(u)}}}return n}({...t,nodes:[e]},i,n));return o&&r?Ht(o,r):o}function Cs(e,t,i,n){if(!e||!t.nodes.length)return e;let r=null;try{r=function(e){let t=null;for(const i of e.nodes){const n=Rs(i,e);n&&(t=t?Et(t,n):n)}return t}(t)}catch{return e}let o=e;for(const e of t.nodes){const s=4*e.halfDepth+2*t.epsilon,a=2*s,l=[[e.point[0]-s,e.point[1]-s],[e.point[0]+s,e.point[1]-s],[e.point[0]+s,e.point[1]+s],[e.point[0]-s,e.point[1]+s]];try{let s=o;const c=Ts(e,t,!1,!0,r);c&&(s=Ht(s,c));let h=Ss(e,t,a);const d=Ts(e,t,!0,!0,r);d&&(h=Ht(h,d)),r&&(h=Et(h,r));const u=.02*Math.min(...e.rays.map(e=>e.halfDepth));if(h=Et(h,xs([[e.point[0]-u,e.point[1]-u],[e.point[0]+u,e.point[1]-u],[e.point[0]+u,e.point[1]+u],[e.point[0]-u,e.point[1]+u]])),!h)continue;let p=Nt(h,xs(l));n?p=Nt(p,n):i&&(p=Nt(p,i));const _=xs(l),m=Ht(s,_),g=i?Ht(Nt(s,_),i):null,f=Ms(e,t,_);o=Et(m,...g?[g]:[],...f?[f]:[],p)}catch{}}if(r)try{let e=r;n?e=Nt(e,n):i&&(e=Nt(e,i)),o=Et(o,e)}catch{}return o}function Ds(e,t=1){if(!Array.isArray(e)||e.length<3)return null;const i=Number.isFinite(t)&&t>0?t:1,n=1e-12*Math.max(1,i),r=[];for(const t of e){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),i=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(i))return null;const o=Math.round(e/n)*n,s=Math.round(i/n)*n;if(!Number.isFinite(o)||!Number.isFinite(s))return null;r.push([Object.is(o,-0)?0:o,Object.is(s,-0)?0:s])}return Math.abs(Xo(r))>n*n?r:null}function As(e,t,i,n){if(bs(e[0],e[1],t[0],t[1],i[0],i[1])>n)return!1;const r=i[0]-t[0],o=i[1]-t[1],s=(e[0]-t[0])*r+(e[1]-t[1])*o,a=r*r+o*o,l=n*Math.sqrt(a);return s>=-l&&s<=a+l}function Os(e,t,i){const n=[],r=[];for(let o=0;oi*i))continue;const d=i/Math.sqrt(h),u=[0,1];for(const e of t)for(const t of[e.a,e.b]){if(!As(t,s,a,i))continue;const e=((t[0]-s[0])*l+(t[1]-s[1])*c)/h;e>d&&e<1-d&&u.push(e)}u.sort((e,t)=>e-t);const p=u.filter((e,t)=>0===t||Math.abs(e-u[t-1])>d);for(let e=0;e=3&&r.length===n.length?{poly:n,offsets:r}:null}function zs(e,t,i,n,r,o,s,a){const l=(e||[]).map(Zt).filter(e=>!!e&&e.length>=3);if(!l.length)return null;let c=Et(xs(l[0]));for(let e=1;e"outer"===e.kind&&e.half>0),u=4*Zo(n,s),p=a||ds(h,u,s);let _=null;for(const e of function(e){const t=[];for(const i of Array.isArray(e)?e:[])if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,-1).map(e=>[e[0],e[1]]);i.length>=3&&t.push(i)}return t}(c)){const t=Os(e,d,u);if(!t||!t.offsets.some(e=>e>0))continue;const i=js(t.poly,t.offsets,p),n=ns(t.poly,t.offsets,p);if(!i||!n)continue;const r=Ht(xs(i),xs(n));_=_?Et(_,r):r}return{centre:c,shell:_||[]}}function Ps(e,t,i,n,r,o,s=1){try{const a=zs(e,t,i,n,r,o,s,_s(e,t,i,n,r,o,s));if(!a)return[];return a.shell?.length?Et(a.centre,a.shell):a.centre}catch{return null}}function Fs(e){if(!e)return"";let t="";for(const i of e)if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,e.length-1);i.length<3||(t+=(t?" ":"")+rs(i.map(e=>[e[0],e[1]])))}return t}const Is=15;function Es(e,t,i){const n=e?.length||0;if(n<3||t?.length!==n)return!1;const r=e[(i-1+n)%n],o=e[i],s=e[(i+1)%n],a=[r[0]-o[0],r[1]-o[1]],l=[s[0]-o[0],s[1]-o[1]],c=Math.hypot(a[0],a[1]),h=Math.hypot(l[0],l[1]);if(!(c>1e-9&&h>1e-9))return!1;const d=Math.max(-1,Math.min(1,(a[0]*l[0]+a[1]*l[1])/(c*h))),u=Math.acos(d);if(!(u>1e-9))return!1;if(u>=Is*Math.PI/180)return!1;const p=Math.max(Math.max(0,t[(i-1+n)%n]),Math.max(0,t[i]));if(!(p>0))return!1;const _=p/Math.tan(u/2);return Number.isFinite(_)&&_>0&&_e>0))continue;for(const e of l.offsets)e>0&&(u=Math.max(u,2*e));const c=js(l.poly,l.offsets,d),p=ns(l.poly,l.offsets,d);c&&h.push({outset:c,inset:p})}for(const e of l){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);if(t.length){const n=Math.min(Math.max(...t)-Math.min(...t),Math.max(...i)-Math.min(...i)),r=Math.min(...e.map((t,i)=>{const n=e[(i+1)%e.length];return Math.hypot(n[0]-t[0],n[1]-t[1])}));u=Math.max(u,e.length>16?n:r)}}const p=function(e,t,i,n,r,o,s,a){if(!t?.length||!i?.length)return[];const l=4*Zo(n,s),c=new Map;for(const a of gs(e,t,i,n,r,o,s))!a.open&&a.half>0&&!c.has(a.key)&&c.set(a.key,a);const h=[...c.values()];if(h.length<2)return[];const d=a||ds(h,l),u=[];for(const e of i)for(const t of[[e[0],e[1]],[e[2],e[3]]])u.some(e=>Math.hypot(e[0]-t[0],e[1]-t[1])<=l)||u.push(t);const p=[],_=(e,t)=>{let i=0,n=0;if(Math.hypot(e.a[0]-t[0],e.a[1]-t[1])<=l)i=e.b[0]-e.a[0],n=e.b[1]-e.a[1];else{if(!(Math.hypot(e.b[0]-t[0],e.b[1]-t[1])<=l))return null;i=e.a[0]-e.b[0],n=e.a[1]-e.b[1]}const r=Math.hypot(i,n);return r>l?[i/r,n/r]:null};for(const e of u){const t=h.map(t=>({iv:t,u:_(t,e)})).filter(e=>!!e.u);for(let i=0;i0?[e.slice(),u,m,_]:[e.slice(),_,m,u];else{if(!f)continue;{const t=[-r.u[1],r.u[0]],i=[-o.u[1],o.u[0]],n=s<0?1:-1,a=[e[0]+t[0]*r.iv.half*n,e[1]+t[1]*r.iv.half*n],l=[e[0]-i[0]*o.iv.half*n,e[1]-i[1]*o.iv.half*n];y=s>0?[e.slice(),a,l]:[e.slice(),l,a]}}Math.abs(Xo(y))>l*l&&p.push(y)}}return p}(e,t,i,r,o,s,a,d),_=n.length?Bs(e,t,i,r,o,s,a):null;let m="exterior";try{const v=zs(e,t,i,r,o,s,a,d);m="paper";const y=v?v.shell?.length?Et(v.centre,v.shell):v.centre:[],b=e=>{const t=xs(e.outset);if(!e.inset)return t;const i=xs(e.inset);return Ht(t,i)};m="room-rings";let w=null;for(const e of h)try{const t=b(e);w=w?Et(w,t):t}catch{}if(m="edge-bodies",v)for(const n of qs(e,t,i,r,o,s,a))try{const e=Nt(xs(n.quad),v.centre);w=w?Et(w,e):e}catch{}m="junctions",w=function(e,t,i=1,n=Et){let r=e;for(const e of t||[]){const t=Ds(e,i);if(t)try{const e=xs(t);r=r?n(r,e):e}catch{}}return r}(w,p,a),m="facade-clip",w&&v&&(w=Nt(w,v.centre)),m="exterior-shell";const k=[];let x=0;if(v?.shell?.length)if(w)try{const e=Et(w,v.shell);if(!$s(e))throw new Error("invalid shell union");w=e}catch{if(!$s(w)||!$s(v.shell))throw new Error("invalid shell");k.push({id:"exterior-shell",geom:v.shell}),x++}else w=v.shell;if(m="multi-wall-trim",w&&d.nodes.length){const e=e=>e.rays.some(e=>e.supports.some(e=>e.length<2*e.halfDepth)),t=d.nodes.filter(e);if(t.length){w=Cs(w,{...d,nodes:t},v?.centre,y)}}if(m="junction-corners",d.nodes.length){const n=us(d),l=function(e,t,i,n,r,o,s,a){try{const l=zs(e,t,i,n,r,o,s,{epsilon:a.epsilon,coordinateScale:a.coordinateScale,nodes:[],index:new Map});return l?l.shell?.length?Et(l.centre,l.shell):l.centre:null}catch{return null}}(e,t,i,r,o,s,a,d);for(const e of n.fans)try{let t=[xs(e)];if(l&&(t=Nt(t,l)),!t?.length)continue;w=w?Et(w,t):t}catch{}g=w,f=Math.max(d.epsilon,1e-9)**2,w=Array.isArray(g)?g.map(e=>{if(!Array.isArray(e)||!e.length)return e;const[t,...i]=e;return Math.abs(Xo(t||[]))<=f?null:[t,...i.filter(e=>Math.abs(Xo(e||[]))>f)]}).filter(e=>!!e):g}const $=w||[],S=[...$s($)?[{id:"room-primary",geom:$}]:[],...k.map((e,t)=>({id:`room-isolated-${t}`,geom:e.geom}))];m="openings";for(const e of n){if(!(e.length>0))continue;const t=Gs(_,e,!0);if(!t.negative&&!t.positive)continue;const i=e.angle*Math.PI/180,n=Math.cos(i),o=Math.sin(i),s=-o,l=n,c=e.length/2,h=1.25*Math.max(u,r*a),d=[[e.x-n*c-s*h,e.y-o*c-l*h],[e.x+n*c-s*h,e.y+o*c-l*h],[e.x+n*c+s*h,e.y+o*c+l*h],[e.x-n*c+s*h,e.y-o*c+l*h]];w&&(w=Ht(w,xs(d)));for(const e of k)e.geom=Ht(e.geom,xs(d))}m="extras";const M=[];let R=0;const T=c.mergeExtra||((e,t)=>e?Et(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(yi(t))<=1e-9){R++;continue}const i=[xs(t)];try{const t=T(w,i,e);if(!$s(t))throw new Error("invalid extra union");w=t}catch{R++,$s(i)&&M.push({id:`extra-${e}`,geom:i})}}M.push(...k),M.sort((e,t)=>Fs(e.geom).localeCompare(Fs(t.geom)));const C=w||[];return{status:R||x?"degraded-extra":"ok",geom:C,components:[...$s(C)?[{id:"primary",geom:C}]:[],...M.map((e,t)=>({...e,id:`isolated-${t}`}))],roomGeom:$,roomComponents:S,paperGeom:y,depthUnits:u,openingPadUnits:1.25*Math.max(u,r*a),openingIndex:_,multiWallNodes:d,degradedExtraCount:R+x}}catch{return c.onCoreFailure?.(m),{status:"failed-core",geom:[],components:[],roomGeom:[],paperGeom:[],roomComponents:[],depthUnits:u,openingIndex:null,multiWallNodes:d,degradedExtraCount:0}}var g,f}function Hs(e,t,i,n=[],r,o,s,a=1,l=[],c={}){if(!t?.length&&!l.length)return null;return Ls(Ns(e,t,i,n,r,o,s,a,l,c))}function Ls(e){if("failed-core"===e.status||"not-applicable"===e.status)return null;const t=e.components.map(e=>({id:e.id,d:Fs(e.geom),fillRule:"evenodd"})).filter(e=>!!e.d),i=t[0]?.d||"",n=Fs(e.paperGeom);if(t.length){const r={status:e.status,d:i,paths:t,components:e.components,roomGeom:e.roomGeom,multiWallNodes:e.multiWallNodes,paperD:n,depthUnits:e.depthUnits,fillRule:"evenodd"};return Object.defineProperties(r,{roomComponents:{value:e.roomComponents||[],enumerable:!1},openingIndex:{value:e.openingIndex,enumerable:!1},openingPadUnits:{value:e.openingPadUnits,enumerable:!1}}),r}return null}function qs(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=new Set,l=[];for(const c of e||[]){if(!c?.id)continue;const h=ms(e,c.id,t,i,n,r,o,s);if(!h)continue;const d=h.poly;for(let e=0;e0))continue;const p=$o(t,i,n,s);if(a.has(p))continue;a.add(p);const _=vo(u,r,o),[m,g]=Jo(d,e),f=-m,v=-g,y=_/2,b=[[t[0]+f*y,t[1]+v*y],[i[0]+f*y,i[1]+v*y],[i[0]+m*y,i[1]+g*y],[t[0]+m*y,t[1]+g*y]];l.push({key:p,kind:c,cm:u,quad:b,a:[t[0],t[1]],b:[i[0],i[1]],depthUnits:_})}}return l}function js(e,t,i){const n=e?.length||0;if(n<3||t.length!==n)return null;if(t.every(e=>!(e>0)))return e.map(e=>[e[0],e[1]]);os(e),t.slice().reverse();const r=[];for(let o=0;o0||l>0)){r.push([e[o][0],e[o][1]]);continue}if(a>0!=l>0){const t=e[o],i=a>0?[t[0]-c*a,t[1]-h*a]:[t[0],t[1]],n=l>0?[t[0]-d*l,t[1]-u*l]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(Qo(w,k)){const t=e[o],i=[t[0]-c*a,t[1]-h*a],n=[t[0]-d*l,t[1]-u*l];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const S=es(x,w,$,k),M=Math.max(a,l,1e-9),R=ps(i,e[o])?.limit??4*M;if(S){const i=Math.hypot(S[0]-e[o][0],S[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push(S);continue}if(Es(e,t,o)){r.push([e[o][0],e[o][1]]);continue}}a>0&&r.push([e[o][0]-c*a,e[o][1]-h*a]),l>0&&r.push([e[o][0]-d*l,e[o][1]-u*l])}return r.length>=3?r:null}function Bs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=ms(e,l.id,t,i,n,r,o,s);if(!c)continue;const h=Math.abs(yi(c.poly));for(let e=0;e[Math.max(t,e.x0),Math.min(i,e.x1)]).filter(e=>e[1]-e[0]>n).sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(!r.length)return{coverage:0,full:!1};let o=r[0][0],s=r[0][1],a=0,l=o<=t+n;for(let e=1;e=i-n,{coverage:a,full:l}}function Us(e,t){return Number(t.full)-Number(e.full)||e.faceDistance-t.faceDistance||e.area-t.area||e.roomId.localeCompare(t.roomId)}function Gs(e,t,i=!1){const n=Number(t?.x),r=Number(t?.y),o=Number(t?.angle),s=Number(t?.length);if(!([n,r,o,s].every(Number.isFinite)&&s>0))return{negative:null,positive:null};const a=o*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,u=s/2,p=Math.max(1e-9,e.adjacencyEps),_=new Map;let m=0;for(const t of e.edges){if(i&&!(t.half>0))continue;if(!zo(t.a,t.b,o))continue;const[e,s]=ko(t.a,t.b);if(Math.abs((n-t.a[0])*s-(r-t.a[1])*e)>p)continue;const a=(t.a[0]-n)*l+(t.a[1]-r)*c,g=(t.b[0]-n)*l+(t.b[1]-r)*c,f=Math.max(-u,Math.min(a,g)),v=Math.min(u,Math.max(a,g));if(v-f<=p)continue;const y=t.inward[0]*h+t.inward[1]*d>=0?1:-1,b=((t.a[0]+t.b[0])/2-n)*h+((t.a[1]+t.b[1])/2-r)*d,w=Math.abs(b+y*t.half),k=`${y}|${t.roomId}`,x={x0:f,x1:v,half:t.half,cm:t.cm,key:t.key,axis:[e,s]},$=_.get(k);$?($.pieces.push(x),$.faceDistance=Math.min($.faceDistance,w)):_.set(k,{roomId:t.roomId,side:y,order:m++,pieces:[x],faceDistance:w,area:t.area,coverage:0,full:!1})}for(const e of _.values()){const t=Ws(e.pieces,-u,u,p);e.coverage=t.coverage,e.full=t.full}const g=e=>{const t=[..._.values()].filter(t=>t.side===e&&t.coverage>p);return t.sort(Us),t[0]||null};return{negative:g(-1),positive:g(1)}}function Vs(e,t){const i=Gs(e,t),n=[i.negative,i.positive].filter(e=>!!e);if(!n.length)return{ox:0,oy:0,cm:0,side:-1};const r=i.negative&&i.positive?-1:n[0].side,o=t.flip_v?-r:r,s=(-1===o?i.negative:i.positive)||n[0],a=[...s.pieces].sort((e,t)=>(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))-(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))||t.x1-t.x0-(e.x1-e.x0)||e.key.localeCompare(t.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:o};const l=t.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*o*a.half,oy:h*o*a.half,cm:a.cm,side:o}}function Ks(e,t){const i=1e-9,n=t.filter(e=>Number.isFinite(e.x0)&&Number.isFinite(e.x1)&&Number.isFinite(e.half)&&e.x1>e.x0&&e.half>0);if(!n.length)return"";const r=n.flatMap(e=>[e.x0,e.x1]).sort((e,t)=>e-t),o=[];for(const e of r){const t=o[o.length-1];(void 0===t||e>t+i)&&o.push(e)}const s=[];for(let e=0;e+1t+i))continue;const a=(t+r)/2,l=n.reduce((e,t)=>a>=t.x0-i&&a<=t.x1+i?Math.max(e,t.half):e,0);if(!(l>0))continue;const c=s[s.length-1];c&&t<=c.x1+i&&Math.abs(l-c.half)<=i?c.x1=r:s.push({x0:t,x1:r,half:l})}const a=[];for(const e of s){const t=a[a.length-1],n=t?.[t.length-1];n&&e.x0<=n.x1+i?(e.x0=n.x1,t.push(e)):a.push([e])}return a.map(t=>{const i=t[0],n=t[t.length-1],r=Math.min(.25*Math.min(...t.map(e=>e.half)),.75),o=-e*r,s=[];if(1===e){s.push(`M ${i.x0} ${o} L ${n.x1} ${o}`);for(let e=t.length-1;e>=0;e--){const i=t[e];s.push(`L ${i.x1} ${i.half} L ${i.x0} ${i.half}`)}}else{s.push(`M ${n.x1} ${o} L ${i.x0} ${o}`);for(const e of t)s.push(`L ${e.x0} ${-e.half} L ${e.x1} ${-e.half}`)}return s.push("Z"),s.join(" ")}).join(" ")}function Ys(e,t,i,n){if(!n)return i;const r=e.angle*Math.PI/180,o=Math.cos(r),s=Math.sin(r),a=[],l=1e-9;for(const r of i){const[i,c]=r.axis,h=o*i+s*c;if(Math.abs(h)<=l)continue;const d=e.x*i+e.y*c,u=d+h*r.x0,p=d+h*r.x1,_=Math.min(u,p),m=Math.max(u,p),g=`${r.key}|${t}`,f=n.get(g)||[];let v=[[_,m]];for(const[e,t]of f){const i=[];for(const[n,r]of v)t<=n+l||e>=r-l?i.push([n,r]):(e>n+l&&i.push([n,Math.min(r,e)]),te[0]-t[0]||e[1]-t[1]),b=[];for(const e of y){const t=b[b.length-1];t&&e[0]<=t[1]+l?t[1]=Math.max(t[1],e[1]):b.push([e[0],e[1]])}n.set(g,b)}return a}function Zs(e,t){const i=new Map;return t.map(t=>function(e,t,i){const n=Gs(e,t,!0),r=n.negative,o=n.positive;if(!r&&!o)return null;let s;if(r&&o)s=[{candidate:r,side:-1},{candidate:o,side:1}];else{const e=r||o;s=[{candidate:e,side:-1},{candidate:e,side:1}]}const a=s.map(({candidate:e,side:n})=>({candidate:e,side:n,pieces:Ys(t,n,e.pieces,i)})),l=a.map(({candidate:e,side:t,pieces:i})=>({side:t,roomId:e.roomId,d:Ks(t,i)})),c=a.flatMap(({pieces:e})=>e);if(!c.length)return null;const h=Math.max(...c.map(e=>e.half));return{faces:l,minY:-h,maxY:h,wallKey:[...new Set(c.map(e=>e.key))].sort().join("|")}}(e,t,i))}const Xs=150,Js=1e-6;function Qs(e){return Number.isFinite(e)?Math.max(1,Math.min(Xs,e)):1}function ea(e){return((Number.isFinite(Number(e))?Number(e):0)%90+90)%90}const ta=e=>{const t=e.map(e=>[e[0],e[1]]);return!t.length||t[0][0]===t[t.length-1][0]&&t[0][1]===t[t.length-1][1]||t.push([...t[0]]),[t]},ia=(e,t)=>e[0]===t[0]&&e[1]===t[1];function na(e,t=1e-6){const i=Number.isFinite(t)&&t>0?t:Js,n=[];for(const t of e||[]){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),r=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(r))return null;const o=Math.round(e/i)*i,s=Math.round(r/i)*i;if(!Number.isFinite(o)||!Number.isFinite(s))return null;const a=[Object.is(o,-0)?0:o,Object.is(s,-0)?0:s];n.length&&ia(n[n.length-1],a)||n.push(a)}return n.length>1&&ia(n[0],n[n.length-1])&&n.pop(),n.length<3||new Set(n.map(e=>`${e[0]},${e[1]}`)).size<3?null:yi(n)>i*i?n:null}function ra(e){const t=[];for(const i of e||[])for(const e of i||[]){const i=(e||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||t.push(`M ${i.slice(0,-1).map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`)}return t.join(" ")}function oa(e,t,i,n,r){return qo({a:e,b:t,halfDepth:vo(i,n,r)/2})}function sa(e,t,i){const n=Number(t)>0?Number(t):5,r=Qs(e.cm)/n*i,o=e.center[0],s=e.center[1];if("circle"===e.shape){const e=r/2;return Array.from({length:96},(t,i)=>{const n=i/96*Math.PI*2;return[o+Math.cos(n)*e,s+Math.sin(n)*e]})}const a=r/2,l=ea(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l);return[[-a,-a],[a,-a],[a,a],[-a,a]].map(([e,t])=>[o+e*c-t*h,s+e*h+t*c])}function aa(e,t,i=1e-9){if(!t.length)return[e];let n=[ta(e)];try{for(const e of t){const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],o=Math.hypot(t,r);if(!(o>i))continue;const s=t/o,a=r/o,l=-a,c=s,h=1.25*Math.max(Number(e.depth)||0,4*i),d=Math.max(2*i,1e-9*o),u=[[e.a[0]-s*d-l*h,e.a[1]-a*d-c*h],[e.b[0]+s*d-l*h,e.b[1]+a*d-c*h],[e.b[0]+s*d+l*h,e.b[1]+a*d+c*h],[e.a[0]-s*d+l*h,e.a[1]-a*d+c*h]];n=Ht(n,ta(u))}return fa(n)}catch{return[e]}}function la(e,t){try{const i=Ht([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]);let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(yi(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function ca(e,t,i,n=Math.max(2e-4*i,1e-9),r=[]){const o=[],s=[],a=new Map;for(const e of r){const t=a.get(e.hostId)||[];t.push(e),a.set(e.hostId,t)}const l=[],c=[],h=[];for(const n of e.room_drafts||[])for(let e=0;e+10))continue;const a={a:n.points[e],b:n.points[e+1],halfDepth:s},c=qo(a);c&&(o.push(a),l.push(c))}const d=[];for(const n of e.partitions||[]){const e={a:n.a,b:n.b,halfDepth:vo(n.cm,t,i)/2};if(!(e.halfDepth>0))continue;const r=qo(e);r&&(s.push(e),c.push(r),d.push({id:n.id,body:r}))}const u=[...o,...s];for(const{segmentIndex:e,wedge:t}of Go(u,n)){const i=e=o.length&&(d[i.at].body=n))}for(const e of d)h.push(...aa(e.body,a.get(e.id)||[],n));const p=(e.wall_columns||[]).map(e=>sa(e,t,i)),_=Vo([...o,...s],n).flatMap(e=>aa(e,r,n));return{drafts:l,partitions:c,columns:p,patches:_,all:[...l,...h,..._,...p]}}function ha(e){try{const t=e.map(e=>na(e)).filter(e=>!!e).map(e=>ta(e));return t.length?Et(t[0],...t.slice(1)):null}catch{return null}}const da=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;function ua(e){const t=[];for(const i of e||[]){if(ma([i])<=1e-6)continue;const e=[];for(const t of i||[]){const i=(t||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||e.push(da(i.slice(0,-1)))}e.length&&t.push(e.join(" "))}return t}function pa(e,t,i={}){const n=ha(e.filter(e=>e.length>=3)),r=t.some(e=>!na(e))?null:ha(t);if(!n)return[];if(r)try{return ua(Nt(n,r))}catch{}return function(e,t,i){let n=null;for(let r=0;r=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]));return t}function fa(e){const t=[];for(const i of e||[]){const e=i?.[0];e?.length>=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]))}return t}function va(e,t){let i=!1;for(let n=0,r=t.length-1;ne[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s||1e-12)+o&&(i=!i)}return i}function ya(e,t,i){return function(e,t){for(const i of t||[]){const t=i?.[0];if(!t?.length||!va(e,t))continue;let n=!1;for(let t=1;tva(e,t))}function ba(e,t,i){if(Math.hypot(e.center[0]-t.center[0],e.center[1]-t.center[1])>i)return!1;if(Math.abs(Qs(e.cm)-Qs(t.cm))>1e-6)return!1;if(e.shape!==t.shape)return!0;if("circle"===e.shape||"circle"===t.shape)return!0;const n=Math.abs(ea(e.angle)-ea(t.angle));return Math.min(n,90-n)<=1e-6}const wa=2.54;function ka(e){const t="number"==typeof e?e:NaN;return!Number.isFinite(t)||t<=0||5===t?1:5/t}function xa(e,t){return e*ka(t)}function $a(e){return e?wa:1}function Sa(e,t){if(!t)return String(e);const i=e/wa;return String(Math.round(1e6*i)/1e6)}function Ma(e,t){return t?e*wa:e}const Ra=1e3;function Ta(e,t){const i=Number(e),n=Number.isFinite(i)&&i>0?i:1,r=n>=1?t:t*n,o=n>=1?t/n:t;return{x:(t-r)/2,y:(t-o)/2,w:r,h:o}}const Ca=.01,Da=100;function Aa(e,t=1e3){const i=Ta(e?.plan_aspect,t),n=Number(e?.plan_scale),r=Number.isFinite(n)&&n>0?Math.min(Da,Math.max(Ca,n)):1,o=Number(e?.plan_scale_x),s=Number(e?.plan_scale_y),a=Number.isFinite(o)&&o>0?Math.min(Da,Math.max(Ca,o)):r,l=Number.isFinite(s)&&s>0?Math.min(Da,Math.max(Ca,s)):r,c=Number(e?.plan_x),h=Number(e?.plan_y),d=_r(e?.plan_angle);return{x:i.x+(Number.isFinite(c)?ja(c):0)*t,y:i.y+(Number.isFinite(h)?ja(h):0)*t,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Oa(e){if(null==e.x||null==e.y)return{x:e.x,y:e.y,w:e.w,h:e.h};const t=Number(e.w)||0,i=Number(e.h)||0;return{x:t<0?e.x+t:e.x,y:i<0?e.y+i:e.y,w:Math.abs(t),h:Math.abs(i)}}function za(e){return e&&Array.isArray(e.spaces)?e.spaces.map(e=>{const t=Ra,i=function(e){return Array.isArray(e)&&4===e.length&&e.every(e=>Number.isFinite(e))&&e[2]>1e-6&&e[3]>1e-6?e:[0,0,1,1]}(e.view_box);return{id:e.id,title:e.title,cellCm:Number.isFinite(Number(e.cell_cm))&&Number(e.cell_cm)>0?Number(e.cell_cm):5,vb:[i[0]*Ra,i[1]*t,i[2]*Ra,i[3]*t],bg:e.plan_url?{href:Mn(e.plan_url),...Aa(e,Ra)}:null,rooms:(e.rooms||[]).map(e=>{const i={...e,...Oa(e)};return{id:i.id,name:i.name,area:i.area??null,open_to:i.open_to||void 0,settings:i.settings||void 0,x:null!=i.x?i.x*Ra:void 0,y:null!=i.y?i.y*t:void 0,w:null!=i.w?i.w*Ra:void 0,h:null!=i.h?i.h*t:void 0,poly:i.poly?i.poly.map(e=>[e[0]*Ra,e[1]*t]):void 0,wall_ids:Array.isArray(i.wall_ids)?[...i.wall_ids]:void 0}}),wall_segments:(e.wall_segments||[]).map(e=>({...e,id:String(e.id),a:[Number(e.a?.[0])*Ra,Number(e.a?.[1])*t],b:[Number(e.b?.[0])*Ra,Number(e.b?.[1])*t],cm:Number(e.cm)})),room_drafts:(e.room_drafts||[]).map(e=>({id:e.id,points:(e.points||[]).map(e=>[e[0]*Ra,e[1]*t]),segments:(e.segments||[]).map(e=>({..."string"==typeof e.id&&e.id?{id:e.id}:{},cm:Number(e.cm)}))})),partitions:(e.partitions||[]).map(e=>({id:e.id,a:[e.a[0]*Ra,e.a[1]*t],b:[e.b[0]*Ra,e.b[1]*t],cm:Number(e.cm)})),wall_columns:(e.wall_columns||[]).map(e=>({id:e.id,shape:"circle"===e.shape?"circle":"square",center:[e.center[0]*Ra,e.center[1]*t],cm:Number(e.cm),..."circle"===e.shape?{}:{angle:ea(e.angle)}}))}}):[]}const Pa=5e3,Fa=Pa*Ra,Ia=240,Ea=Ra/Ia,Na=1/Ia;function Ha(e){if(!Number.isFinite(e))return e;const t=Math.round(e*Ia/Ra)*Ra/Ia;return Math.abs(t-e)<=1e-9*Ea?e:t}function La(e){return{x:Ha(e.x),y:Ha(e.y)}}function qa(e){return Number.isFinite(e)?Math.min(Fa,Math.max(-Fa,e)):0}function ja(e){return Number.isFinite(e)?Math.min(Pa,Math.max(-Pa,e)):0}const Ba=1/3,Wa=200;function Ua(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e){const e=Number(o[0]),s=Number(o[1]);Number.isFinite(e)&&Number.isFinite(s)&&(en&&(n=e),s>r&&(r=s))}return t>n?null:{minX:t,minY:i,maxX:n,maxY:r}}function Ga(e){return e.poly&&e.poly.length?Ua(e.poly):null==e.x||null==e.y?null:Ua([[e.x,e.y],[e.x+(e.w||0),e.y+(e.h||0)]])}function Va(e,t){const i=[];for(const t of e.rooms||[]){const e=Ga(t);e&&i.push(e)}if(e.bg){const t=Ua(wr(e.bg));t&&i.push(t)}for(const e of t||[])if(Array.isArray(e)){const t=Ua([e]);t&&i.push(t)}else i.push(e);return i}const Ka=e=>{if(!e.length)return 0;const t=[...e].sort((e,t)=>e-t),i=t.length>>1;return t.length%2?t[i]:(t[i-1]+t[i])/2},Ya=e=>{let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)o.minXn&&(n=o.maxX),o.maxY>r&&(r=o.maxY);return t>n||i>r?null:{x:t,y:i,w:n-t,h:r-i}};function Za(e,t){let{x:i,y:n,w:r,h:o}=e;r<30&&(i=i+r/2-100,r=Wa),o<30&&(n=n+o/2-100,o=Wa);const s=Math.max(r,o)*t;return{x:i-s,y:n-s,w:r+2*s,h:o+2*s}}function Xa(e,t={}){const i=t.pad??.05,n=t.k??10,r=t.minSpread??50,o=e.filter(e=>Number.isFinite(e.minX)&&Number.isFinite(e.minY)&&Number.isFinite(e.maxX)&&Number.isFinite(e.maxY)&&Math.abs(e.minX)<=Fa&&Math.abs(e.maxX)<=Fa&&Math.abs(e.minY)<=Fa&&Math.abs(e.maxY)<=Fa);if(!o.length)return{core:null,all:null,outliers:0};const s=Ya(o);if(o.length<4){const e=Za(s,i);return{core:e,all:e,outliers:0}}const a=o.map(e=>(e.minX+e.maxX)/2),l=o.map(e=>(e.minY+e.maxY)/2),c=Ka(a),h=Ka(l),d=o.map((e,t)=>Math.max(Math.abs(a[t]-c),Math.abs(l[t]-h))),u=Math.max(((e,t)=>e.length?e[Math.min(e.length-1,Math.max(0,Math.round(t*(e.length-1))))]:0)([...d].sort((e,t)=>e-t),.75),r),p=d.map(e=>e>n*u),_=p.filter(Boolean).length,m=_&&_<=o.length*Ba?o.filter((e,t)=>!p[t]):o;return{core:Za(Ya(m)||s,i),all:Za(s,i),outliers:m===o?0:_}}function Ja(e,t,i=.05){const n=Xa(Va(e,t),{pad:i});if(n.core)return n.core;const r=e.vb&&4===e.vb.length&&e.vb[2]>0&&e.vb[3]>0?e.vb:[0,0,Ra,Ra];return{x:r[0],y:r[1],w:r[2],h:r[3]}}function Qa(e){const t=Ja(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function el(e){const t=[];for(const i of e.rooms||[]){const e=Ga(i);e&&t.push(e)}const i=Xa(t,{pad:0}).core,n=Ra*ka(e.cellCm??5);return i?Math.max(n,Math.min(Fa,Math.max(i.w,i.h))):n}function tl(e,t,i,n=1){const r=Number(i),o=Number.isFinite(n)&&n>0?n:1;return!Number.isFinite(r)||r<=0?e*o:e*el(t)*o/r}const il=[1,2,5,10,20,50,100,200,500,1e3];function nl(e,t,i=7){if(!(e>0&&t>0&&Number.isFinite(t)))return null;const n=il.find(n=>e*n*t>=i);if(void 0===n)return null;const r=il.find(e=>e>=5*n)??5*n;return{fine:n,coarse:r}}function rl(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}function ol(e,t,i,n){const r=i["rl_"+(e.id||"")];if(r&&r.s===t)return{x:r.x*Ra,y:r.y*Ra};const o=function(e){if(e.poly){const t=e.poly.length;return[e.poly.reduce((e,t)=>e+t[0],0)/t,e.poly.reduce((e,t)=>e+t[1],0)/t]}return[e.x+e.w/2,e.y+.1*Math.min(e.w,e.h)]}(e);return La({x:o[0],y:o[1]})}const sl=["furniture","appliance","sanitary","other"],al=[{id:"sofa",group:"furniture",w:220,h:90,g:[["r",0,0,1,1],["l",.09,.26,.91,.26],["l",.09,.26,.09,1],["l",.91,.26,.91,1],["l",.5,.26,.5,1]]},{id:"armchair",group:"furniture",w:90,h:85,g:[["r",0,0,1,1],["l",.14,.28,.86,.28],["l",.14,.28,.14,1],["l",.86,.28,.86,1]]},{id:"coffee_table",group:"furniture",w:110,h:60,g:[["r",0,0,1,1],["r",.08,.14,.84,.72]]},{id:"table_dining",group:"furniture",w:140,h:80,g:[["r",0,0,1,1],["r",.06,.11,.88,.78]]},{id:"table_round",group:"furniture",w:120,h:120,g:[["e",.5,.5,.5,.5],["e",.5,.5,.41,.41]]},{id:"chair",group:"furniture",w:45,h:45,g:[["r",0,0,1,.18],["r",.06,.18,.88,.8]]},{id:"desk",group:"furniture",w:120,h:60,g:[["r",0,0,1,1],["r",.63,.07,.31,.86],["l",.63,.5,.94,.5]]},{id:"bed_double",group:"furniture",w:160,h:200,g:[["r",0,0,1,1],["r",0,0,1,.07],["r",.06,.1,.4,.15],["r",.54,.1,.4,.15],["l",0,.33,1,.33]]},{id:"bed_single",group:"furniture",w:90,h:200,g:[["r",0,0,1,1],["r",0,0,1,.07],["r",.15,.1,.7,.15],["l",0,.33,1,.33]]},{id:"nightstand",group:"furniture",w:45,h:40,g:[["r",0,0,1,1],["r",.12,.14,.76,.33],["r",.12,.53,.76,.33]]},{id:"wardrobe",group:"furniture",w:100,h:60,g:[["r",0,0,1,1],["l",0,.72,1,.72],["l",.5,.72,.5,1]]},{id:"bookshelf",group:"furniture",w:80,h:30,g:[["r",0,0,1,1],["l",.34,0,.34,1],["l",.67,0,.67,1]]},{id:"fridge",group:"appliance",w:60,h:65,g:[["r",0,0,1,1],["l",0,.36,1,.36],["l",.83,.44,.83,.64]]},{id:"stove",group:"appliance",w:60,h:60,g:[["r",0,0,1,1],["e",.29,.31,.15,.15],["e",.71,.31,.15,.15],["e",.29,.71,.15,.15],["e",.71,.71,.15,.15]]},{id:"dishwasher",group:"appliance",w:60,h:60,g:[["r",0,0,1,1],["r",.1,.12,.8,.76],["e",.5,.5,.27,.27],["e",.5,.5,.13,.13]]},{id:"washer",group:"appliance",w:60,h:60,g:[["r",0,0,1,1],["l",.08,.17,.92,.17],["e",.5,.57,.3,.3],["e",.5,.57,.14,.14]]},{id:"dryer",group:"appliance",w:60,h:60,g:[["r",0,0,1,1],["l",.08,.17,.92,.17],["e",.5,.57,.3,.3],["p",.36,.5,.5,.64,.64,.5]]},{id:"tv",group:"appliance",w:120,h:30,g:[["r",0,0,1,.42],["l",.5,.42,.5,.72],["l",.3,.72,.7,.72]]},{id:"ac",group:"appliance",w:90,h:25,g:[["r",0,0,1,1],["l",.05,.55,.95,.55],["l",.05,.79,.95,.79]]},{id:"water_heater",group:"appliance",w:45,h:45,g:[["e",.5,.5,.5,.5],["e",.5,.5,.31,.31]]},{id:"toilet",group:"sanitary",w:40,h:70,g:[["r",.06,0,.88,.2],["e",.5,.58,.37,.35],["e",.5,.58,.22,.2]]},{id:"bathtub",group:"sanitary",w:170,h:75,g:[["r",0,0,1,1],["r",.05,.11,.77,.78],["e",.89,.5,.045,.1]]},{id:"shower",group:"sanitary",w:90,h:90,g:[["r",0,0,1,1],["l",0,0,1,1],["l",1,0,0,1],["e",.5,.5,.08,.08]]},{id:"sink",group:"sanitary",w:60,h:45,g:[["r",0,0,1,1],["e",.5,.6,.34,.3],["e",.5,.15,.07,.07]]},{id:"kitchen_sink",group:"sanitary",w:80,h:60,g:[["r",0,0,1,1],["r",.06,.24,.44,.64],["r",.54,.24,.4,.64],["e",.5,.12,.06,.06]]},{id:"bidet",group:"sanitary",w:40,h:55,g:[["e",.5,.5,.44,.5],["e",.5,.5,.26,.3]]},{id:"stairs",group:"other",w:100,h:280,g:[["r",0,0,1,1],["l",0,.111,1,.111],["l",0,.222,1,.222],["l",0,.333,1,.333],["l",0,.444,1,.444],["l",0,.556,1,.556],["l",0,.667,1,.667],["l",0,.778,1,.778],["l",0,.889,1,.889],["l",.5,.93,.5,.06],["p",.38,.16,.5,.06,.62,.16]]},{id:"fireplace",group:"other",w:120,h:40,g:[["r",0,0,1,1],["p",.22,1,.22,.42,.78,.42,.78,1]]},{id:"plant",group:"other",w:40,h:40,g:[["e",.5,.5,.22,.22],["l",.5,.28,.5,.02],["l",.5,.72,.5,.98],["l",.28,.5,.02,.5],["l",.72,.5,.98,.5],["l",.34,.34,.13,.13],["l",.66,.66,.87,.87],["l",.66,.34,.87,.13],["l",.34,.66,.13,.87]]},{id:"rug",group:"other",w:200,h:140,g:[["r",0,0,1,1],["r",.06,.09,.88,.82]]}],ll=new Map(al.map(e=>[e.id,e]));function cl(e){return e&&ll.get(e)||null}function hl(e){return al.filter(t=>t.group===e)}function dl(e){const t=cl(e);return t?{w:t.w,h:t.h}:{w:60,h:60}}function ul(e,t,i=Ea,n=1e3){const r=Number(t)>0?Number(t):5;return(Number(e)||0)/r*i/n}const pl=5e-4,_l=Pa;function ml(e){return Number.isFinite(e)?Math.max(pl,Math.min(_l,e)):pl}function gl(e){return Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1}const fl=e=>{const t=Math.round(1e3*e)/1e3;return Object.is(t,-0)?"0":String(t)};function vl(e,t,i){const n=cl(e);if(!(n&&t>0&&i>0))return"";const r=e=>fl(e*t),o=e=>fl(e*i),s=[];for(const e of n.g)if("r"===e[0]){const[,t,i,n,a]=e;s.push(`M${r(t)} ${o(i)}H${r(t+n)}V${o(i+a)}H${r(t)}Z`)}else if("l"===e[0]){const[,t,i,n,a]=e;s.push(`M${r(t)} ${o(i)}L${r(n)} ${o(a)}`)}else if("e"===e[0]){const[,n,a,l,c]=e;s.push(`M${r(n-l)} ${o(a)}A${fl(l*t)} ${fl(c*i)} 0 0 1 ${r(n+l)} ${o(a)}A${fl(l*t)} ${fl(c*i)} 0 0 1 ${r(n-l)} ${o(a)}Z`)}else{const t=e.slice(1);if(t.length<4)continue;let i=`M${r(t[0])} ${o(t[1])}`;for(let e=2;e+1{let t=(e%360+360)%360;return t>180&&(t-=360),t};function bl(e,t,i,n,r,o=0){let s=null,a=r;for(const r of n){const[n,l,c,h]=r,d=c-n,u=h-l,p=d*d+u*u;if(!p)continue;const _=Math.sqrt(p);let m=((e-n)*d+(t-l)*u)/p;m=Math.max(0,Math.min(1,m));let g=n+m*d,f=l+m*u;const v=Math.hypot(e-g,t-f);if(!(v0){const e=Math.round(m*_/o)*o;g=n+e/_*d,f=l+e/_*u}s={cx:g+y*(i/2),cy:f+b*(i/2),angle:yl(180*Math.atan2(-y,b)/Math.PI),dist:v}}return s}const wl=15e3,kl=2e3,xl=new WeakMap;function $l(e,t){let i=xl.get(e);if(!i){const t=new Set;i={hiddenAt:"hidden"===e.visibilityState?Date.now():0,token:0,subscribers:t,onVisibility:()=>{const t=xl.get(e);if(!t)return;const i=Date.now();if("hidden"===e.visibilityState){t.hiddenAt||(t.hiddenAt=i);const e={kind:"hidden",token:t.token,at:i,hiddenFor:0,long:!1};for(const i of[...t.subscribers])i(e);return}const n=t.hiddenAt?Math.max(0,i-t.hiddenAt):0;t.hiddenAt=0,t.token++;const r={kind:"visible",token:t.token,at:i,hiddenFor:n,long:n>=wl};for(const e of[...t.subscribers])e(r)},onPageShow:t=>{const i=xl.get(e);if(!i)return;const n=Date.now();i.token++;const r={kind:"pageshow",token:i.token,at:n,hiddenFor:0,long:!!t.persisted,persisted:!!t.persisted};for(const e of[...i.subscribers])e(r)}},xl.set(e,i),e.addEventListener("visibilitychange",i.onVisibility),e.defaultView?.addEventListener("pageshow",i.onPageShow)}return i.subscribers.add(t),()=>{const i=xl.get(e);i&&(i.subscribers.delete(t),i.subscribers.size||(e.removeEventListener("visibilitychange",i.onVisibility),e.defaultView?.removeEventListener("pageshow",i.onPageShow),xl.delete(e)))}}const Sl={now:()=>Date.now(),setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e),requestAnimationFrame:e=>window.requestAnimationFrame(e),cancelAnimationFrame:e=>window.cancelAnimationFrame(e)};class Ml{constructor(e,t=Sl){this.onChange=e,this.clock=t,this._state="steady",this._token=0,this._frameFingerprint="",this._hasCompleteFrame=!1,this._overlayPhase="none",this._recoveryReason=null,this._overlayTimer=0,this._overlayRaf=0,this._overlayOpaqueAt=0,this._barrierRafs=new Set,this._trace=[],this._disposed=!1}get state(){return this._state}get token(){return this._token}get frameFingerprint(){return this._frameFingerprint}get hasCompleteFrame(){return this._hasCompleteFrame}get overlayPhase(){return this._overlayPhase}get overlayVisible(){return"none"!==this._overlayPhase}get overlayBlocksInteraction(){return this.overlayVisible}get recoveryReason(){return this._recoveryReason}get trace(){return this._trace.map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}note(e,t={}){this.record(e,void 0,t)}record(e,t,i={}){this._trace.push({at:this.clock.now(),token:this._token,event:e,state:this._state,...t?{reason:t}:{},...i}),this._trace.length>80&&this._trace.splice(0,this._trace.length-80)}changed(){this._disposed||this.onChange()}adoptCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-adopted"),this.changed())}markCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-complete"),this.changed())}refreshCompleteFrame(e){!this._disposed&&this._hasCompleteFrame&&"steady"===this._state&&e&&e!==this._frameFingerprint&&(this._frameFingerprint=e,this.record("frame-refreshed"))}visibility(e){return"hidden"===e.kind?(this.record("visibility-hidden"),this._token):e.long||"visible"!==e.kind&&"pageshow"!==e.kind?this.beginCandidate("pageshow"===e.kind?"pageshow":"long-resume"):(this.record("pageshow"===e.kind?"pageshow-noop":"visibility-visible-quick"),this._token)}beginCandidate(e,t="plan"){return this._token++,this._recoveryReason=t,this._hasCompleteFrame?(this._state="connection"===t?"offline-stale":"holding",this.clearOverlay()):this.overlayVisible?this._state="overlay-visible":(this._state="overlay-pending",this.scheduleOverlay(t)),this.record("candidate-start",e),this.changed(),this._token}connectionLost(){return this.beginCandidate("connection-lost","connection")}candidateReady(e){return!this._disposed&&e===this._token&&(this._state="candidate-ready",this.record("candidate-ready"),this.changed(),!0)}async commitAfterPaint(e,t){if(this._disposed||e!==this._token)return!1;let i=!0;const n=(async()=>{for(await t.updateComplete();i&&!this._disposed&&e===this._token;)if(t.stageValid()&&t.assetsReady()){if(await this.nextFrame(),e!==this._token||!t.stageValid()||!t.assetsReady())continue;if(await this.nextFrame(),e===this._token&&t.stageValid()&&t.assetsReady())return!0}else await this.nextFrame();return!1})();let r=0;const o=new Promise(e=>{r=this.clock.setTimeout(()=>e({ready:!1,timedOut:!0}),kl)}),s=await Promise.race([n.then(e=>({ready:e,timedOut:!1})),o]);return i=!1,this.clock.clearTimeout(r),!this._disposed&&e===this._token&&(!(!s.ready&&!s.timedOut)&&(s.ready?(this._hasCompleteFrame=!0,this._frameFingerprint=t.frameFingerprint(),this.record("paint-barrier"),this.finishOverlayAfterCommit(),!0):(this.record("paint-barrier-timeout"),this._hasCompleteFrame?(this._state="connection"===this._recoveryReason?"offline-stale":"steady",this.clearOverlay()):(this._state="recovery-error","opaque"!==this._overlayPhase&&this.showOverlayNow()),this.changed(),!1)))}retry(e=this._recoveryReason||"plan"){return this.beginCandidate("retry",e)}nextFrame(){return new Promise(e=>{const t=this.clock.requestAnimationFrame(()=>{this._barrierRafs.delete(t),e()});this._barrierRafs.add(t)})}scheduleOverlay(e){this.clearOverlayTimer(),this._recoveryReason=e,this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._hasCompleteFrame||"overlay-pending"!==this._state&&"candidate-ready"!==this._state||(this._state="overlay-visible",this._overlayPhase="entering",this.record("overlay-enter"),this.changed(),this._overlayRaf=this.clock.requestAnimationFrame(()=>{this._overlayRaf=0,"entering"===this._overlayPhase&&(this._overlayPhase="fading-in",this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,"fading-in"===this._overlayPhase&&(this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-opaque"),this.changed())},150))}))},150)}showOverlayNow(){this.clearOverlayTimer(),this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-error")}finishOverlayAfterCommit(){if(this.clearOverlayTimer(),"none"===this._overlayPhase||"entering"===this._overlayPhase||"fading-in"===this._overlayPhase)return this.clearOverlay(),this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),void this.changed();const e=Math.max(0,this._overlayOpaqueAt+250-this.clock.now());this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="leaving",this.record("overlay-leave"),this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="none",this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),this.changed()},180)},e)}clearOverlayTimer(){this._overlayTimer&&this.clock.clearTimeout(this._overlayTimer),this._overlayTimer=0}clearOverlay(){this.clearOverlayTimer(),this._overlayRaf&&this.clock.cancelAnimationFrame(this._overlayRaf),this._overlayRaf=0,this._overlayPhase="none",this._overlayOpaqueAt=0}dispose(){this._disposed=!0,this._token++,this.clearOverlay();for(const e of this._barrierRafs)this.clock.cancelAnimationFrame(e);this._barrierRafs.clear()}}function Rl(e){let t=2166136261,i=2654435769;const n=new WeakSet,r=e=>{for(let n=0;n>>0)+(i>>>2)}},o=e=>{if(null===e)return void r("n");const t=typeof e;if("string"===t)return void r(`s${e.length}:${e}`);if("number"===t)return void r(`d${Number.isNaN(e)?"NaN":String(e)}`);if("boolean"===t)return void r(e?"t":"f");if("undefined"===t)return void r("u");if("object"!==t)return void r(`${t}:${String(e)}`);const i=e;if(n.has(i))r("[cycle]");else{if(n.add(i),Array.isArray(e)){r("[");for(const t of e)o(t);return r("]"),void n.delete(i)}r("{");for(const t of Object.keys(e).sort())r(t),o(e[t]);r("}"),n.delete(i)}};return o(e),`${(t>>>0).toString(16).padStart(8,"0")}${(i>>>0).toString(16).padStart(8,"0")}`}function Tl(e){return Rl(e)}const Cl=new WeakMap;class Dl{constructor(e,t=()=>Date.now()){this.onUpdate=e,this.now=t,this.fallbackAuthority={},this.referenceOwner={},this.referenced=new Set,this.queued=new Set,this.disposed=!1,this.sharedUpdate=()=>{this.disposed||this.onUpdate()}}bind(e){const t=((e,t)=>{const i=e?.connection||e?.callWS||t;return!i||"object"!=typeof i&&"function"!=typeof i?t:i})(e,this.fallbackAuthority);return this.shared&&this.authority===t||(this.shared&&(this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner)),this.authority=t,this.shared=(e=>{let t=Cl.get(e);return t||(t={signed:{},queued:new Set,inFlight:new Map,retry:new Map,listeners:new Set,settlers:new Set,references:new Map},Cl.set(e,t)),t})(t),this.disposed||(this.shared.listeners.add(this.sharedUpdate),this.shared.references.set(this.referenceOwner,new Set(this.referenced)))),this.shared}start(e,t){this.disposed=!1,this.referenced=new Set(t());const i=this.bind(e());i.listeners.add(this.sharedUpdate),i.references.set(this.referenceOwner,new Set(this.referenced)),this.stopTimer(),this.resignTimer=setInterval(()=>this.resign(e(),t()),288e5)}dispose(){if(this.disposed=!0,this.stopTimer(),clearTimeout(this.batchTimer),this.shared){this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner);for(const e of this.queued)this.shared.queued.delete(e)}this.queued.clear()}invalidate(e){const t=this.bind(e);clearTimeout(this.batchTimer),this.queued.clear(),t.queued.clear(),t.inFlight.clear(),t.retry.clear(),t.signed={}}stopTimer(){void 0!==this.resignTimer&&clearInterval(this.resignTimer),this.resignTimer=void 0}display(e,t){const i=Mn(t);if(!i.startsWith("/api/houseplan/content/"))return i;const n=this.bind(e);this.referenced.add(i),n.references.set(this.referenceOwner,new Set(this.referenced));const r=n.signed[i],o=r?this.now()-r.at:1/0;return o<$n?r.url:o{const t=[...this.queued];this.queued.clear();for(const e of t)i.queued.delete(e);this.sign(e,t)},30))}sign(e,t){if(!t.length||!e?.callWS)return;const i=this.bind(e);for(const n of function(e,t){const i=Math.max(1,Math.floor(t)),n=[];for(let t=0;t{const n=i.inFlight.get(e);return!(void 0!==n&&t-n<15e3)&&(i.inFlight.set(e,t),!0)});r.length&&e.callWS({type:"houseplan/content/sign",paths:r}).then(e=>{const t=this.now();let n=0,o=!1;for(const s of r){const r=e?.urls?.[s];if("string"==typeof r&&r){const e=i.signed[s];e?.loaded&&e.url!==r?(e.pending={url:r,at:t},this.preloadReplacement(i,s,r,t)):(i.signed[s]={url:r,at:t,loaded:e?.url===r&&!!e.loaded},o=!0),i.retry.delete(s),n++}else this.backOff(i,s)}if(n&&(this.trimShared(i),o))for(const e of[...i.listeners])e()}).catch(()=>{for(const e of r)this.backOff(i,e)}).finally(()=>{for(const e of r)i.inFlight.get(e)===t&&i.inFlight.delete(e);for(const e of[...i.settlers])e()})}}preloadReplacement(e,t,i,n){const r=()=>{const r=e.signed[t];if(r?.pending?.url===i){e.signed[t]={url:i,at:n,loaded:!0},e.retry.delete(t),this.trimShared(e);for(const t of[...e.listeners])t()}},o=()=>{const n=e.signed[t];n?.pending?.url===i&&(delete n.pending,this.backOff(e,t))};if("undefined"==typeof Image)return void r();const s=new Image;s.onload=()=>{("function"==typeof s.decode?s.decode():Promise.resolve()).then(r).catch(o)},s.onerror=o,s.src=i}preloadCurrentImage(e,t,i){if(i.loaded)return Promise.resolve(!0);if(i.preload)return i.preload;if("undefined"==typeof Image)return i.loaded=!0,Promise.resolve(!0);const n=i.url;return i.preload=new Promise(r=>{const o=new Image;let s=!1;const a=o=>{if(s)return;s=!0,clearTimeout(l);const a=e.signed[t];if(a===i&&delete a.preload,o&&a===i&&a.url===n){a.loaded=!0;for(const t of[...e.listeners])t();r(!0)}else o||a!==i||this.backOff(e,t),r(!1)};o.onload=()=>{("function"==typeof o.decode?o.decode():Promise.resolve()).then(()=>a(!0)).catch(()=>a(!1))},o.onerror=()=>a(!1);const l=setTimeout(()=>a(!1),kl);o.src=n}),i.preload}prepareImage(e,t){const i=Mn(t);if(!i.startsWith("/api/houseplan/content/"))return Promise.resolve(!0);const n=this.bind(e),r=()=>{const t=n.signed[i];if(t&&this.now()-t.atthis.now()&&!n.inFlight.has(i)&&!n.queued.has(i)?Promise.resolve(!1):null},o=r();return o?(s=o,new Promise(e=>{let t=!1;const i=i=>{t||(t=!0,clearTimeout(n),e(i))},n=setTimeout(()=>i(!1),kl);s.then(i).catch(()=>i(!1))})):new Promise(e=>{let t=!1,i=null;const o=i=>{t||(t=!0,clearTimeout(a),n.settlers.delete(s),e(i))},s=()=>{t||i||(i=r(),i&&i.then(o).catch(()=>o(!1)))},a=setTimeout(()=>o(!1),kl);n.settlers.add(s),s()});var s}backOff(e,t){const i=e.retry.get(t)?.delay||0,n=Math.min(6e4,i?2*i:2e3);e.retry.set(t,{notBefore:this.now()+n,delay:n})}trimShared(e){const t=Object.entries(e.signed);if(t.length<=512)return;const i=new Set(e.inFlight.keys());for(const t of e.references.values())for(const e of t)i.add(e);for(const[e,n]of t)(n.pending||n.preload)&&i.add(e);t.sort((e,t)=>t[1].at-e[1].at);const n=t.filter(([e])=>i.has(e));for(const e of t){if(n.length>=512)break;i.has(e[0])||n.push(e)}e.signed=Object.fromEntries(n)}resign(e,t){const i=this.bind(e);this.referenced=new Set(t),i.references.set(this.referenceOwner,new Set(this.referenced));const n=this.now(),r=new Set;for(const e of i.references.values())for(const t of e)r.add(t);const o={};for(const[e,t]of Object.entries(i.signed))r.has(e)&&n-t.at!!o[e]&&!o[e].pending))}markLoaded(e,t,i){const n=Mn(t);if(!n.startsWith("/api/houseplan/content/"))return;const r=this.bind(e).signed[n];if(r&&(!i||r.url===i)&&!r.loaded){r.loaded=!0;for(const t of[...this.bind(e).listeners])t()}}isReady(e,t){const i=Mn(t);if(!i.startsWith("/api/houseplan/content/"))return!0;const n=this.bind(e).signed[i];return!!n&&this.now()-n.ate.id===t)}var Ol="M11,18H13V16H11V18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6Z";function zl(e,t,i){return[e[0]*t+e[1]*i+e[2],e[3]*t+e[4]*i+e[5]]}function Pl(e,t){let i=0;for(const[n,r]of t){const t=zl(e,n[0],n[1]);i=Math.max(i,Math.hypot(t[0]-r[0],t[1]-r[1]))}return i}const Fl=e=>{if(null==e||""===e)return null;const t=Number(e);return Number.isFinite(t)?t:null},Il=e=>{const t=e,i=Fl(Array.isArray(t)?t[0]:t?.x),n=Fl(Array.isArray(t)?t[1]:t?.y);return null==i||null==n?null:[i,n]};function El(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Il(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}if(t.length<3)return null;let i=0,n=0,r=0;for(let e=0;ee+t[0],0)/t.length,t.reduce((e,t)=>e+t[1],0)/t.length]:[n/(3*i),r/(3*i)]}function Nl(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Il(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}const i=El(t);if(!i)return null;const n=t.map(e=>e[0]),r=t.map(e=>e[1]);return{centroid:i,bbox:[Math.min(...n),Math.min(...r),Math.max(...n),Math.max(...r)]}}function Hl(e){let t=e;if(t&&"object"==typeof t&&!Array.isArray(t)){const e=t;t=e.path??e.points??t}if(!Array.isArray(t)||!t.length)return[];let i=(t.some(e=>(e=>Array.isArray(e)?e.length>=2&&!Array.isArray(e[0])&&("object"!=typeof e[0]||null==e[0]):!!e&&"object"==typeof e&&("x"in e||"y"in e))(e))?[t]:t.filter(Array.isArray)).map(e=>e.map(Il).filter(e=>null!=e)).filter(e=>e.length>=2);i.length>64&&(i=i.slice(-64));const n=i.reduce((e,t)=>e+t.length,0);if(n<=4e3)return i.map(e=>e.slice());const r=4e3-2*i.length,o=i.map(e=>e.length-2),s=o.reduce((e,t)=>e+t,0),a=o.map(e=>r*e/s),l=a.map(Math.floor);let c=r-l.reduce((e,t)=>e+t,0);const h=a.map((e,t)=>({index:t,fraction:e-Math.floor(e)})).sort((e,t)=>t.fraction-e.fraction||e.index-t.index);for(let e=0;efunction(e,t){if(t>=e.length)return e.slice();if(t<=2)return[e[0],e[e.length-1]];const i=[];for(let n=0;ne.slice()),i=t[t.length-1];return i?(i.length>2?i.pop():t.pop(),t):[]}function jl(e,t){return"default"!==e?e:null!=t?String(t):"default"}function Bl(e){if(!e)return null;const t=e.vacuum_position||e.robot_position||null,i=t&&null!=Fl(t.x)&&null!=Fl(t.y)?{x:Fl(t.x),y:Fl(t.y),a:Fl(t.a??t.angle??t.theta)}:null,n=Hl(e.path?.path??e.path?.points??e.path),r=[],o=e.rooms,s=Array.isArray(o)?o.map((e,t)=>[String(e?.id??t),e]):o&&"object"==typeof o?Object.entries(o):[];for(const[e,t]of s){if(!t||"object"!=typeof t)continue;const i=String(t.name??t.label??"").trim(),n=[[Fl(t.cx),Fl(t.cy)],[Fl(t.center?.x),Fl(t.center?.y)],[Fl(t.x),Fl(t.y)]].find(([e,t])=>null!=e&&null!=t);let o=n?.[0]??null,s=n?.[1]??null;const a=Nl(t.outline),l=Fl(t.x0),c=Fl(t.y0),h=Fl(t.x1),d=Fl(t.y1),u=(null!=l&&null!=c&&null!=h&&null!=d?[Math.min(l,h),Math.min(c,d),Math.max(l,h),Math.max(c,d)]:null)||a?.bbox||null;if(null!=o&&null!=s||!a||([o,s]=a.centroid),null!=o&&null!=s||!u||(o=(u[0]+u[2])/2,s=(u[1]+u[3])/2),i&&null!=o&&null!=s){const t={id:e,name:i,cx:o,cy:s};u&&([t.x0,t.y0,t.x1,t.y1]=u),r.push(t)}}const a=function(e){return String(e.map_name??e.current_map??e.map_index??e.selected_map??"default")}(e);return i||r.length||n.length?{pos:i,path:n,rooms:r,mapId:a}:null}function Wl(e,t,i){return![e,t,i].every(Number.isFinite)||e<0||t<=0||i<=0?Number.POSITIVE_INFINITY:e/t*i}const Ul=40;function Gl(e,t,i){if(!e||!t)return null;const n=t.attributes||{},r=e.split(".")[0]||"",o=null!=i?.platform?String(i.platform):null,s=!!Il(n.vacuum_position??n.robot_position),a=!(!n.rooms||"object"!=typeof n.rooms),l=Hl(n.path?.path??n.path?.points??n.path).length>0,c=[n.map_name,n.current_map,n.map_index,n.selected_map].some(e=>null!=e),h="xiaomi_cloud_map_extractor"===o,d=a||l||c;let u=null;if(s?u="compatible":h?u="known_xcme_incomplete":d?u="partial":"camera"===r&&(u="camera"),!u)return null;const p=s?"camera"===r?300:200:h?100:d?50:0;return{entityId:e,name:String(n.friendly_name||e),platform:o,category:u,hasPosition:s,hasRooms:a,hasPath:l,hasMapId:c,score:p}}const Vl=e=>e.toLowerCase().replace(/[\s_\-.,]+/g,"");function Kl(e,t){const i=new Set(t.map(Vl).filter(Boolean)),n=new Set;for(const t of e){const e=Vl(t.name||"");e&&i.has(e)&&n.add(e)}return n.size}function Yl(e,t){const i=new Map(t.map(e=>[Vl(e.name),e])),n=[],r=[];for(const t of e){const e=i.get(Vl(t.name));e&&(n.push([[t.cx,t.cy],[e.cx,e.cy]]),r.push(t.name))}if(n.length<3)return null;const o=function(e){if(e.length<3)return null;let t=0,i=0,n=0,r=0,o=0,s=0,a=0,l=0,c=0,h=0,d=0,u=0;for(const[[p,_],[m,g]]of e){if(![p,_,m,g].every(Number.isFinite))return null;t+=p*p,i+=p*_,n+=p,r+=_*_,o+=_,s+=1,a+=p*m,l+=_*m,c+=m,h+=p*g,d+=_*g,u+=g}const p=[t,i,n,i,r,o,n,o,s],_=e=>{const[t,i,n,r,o,s,a,l,c]=p,h=t*(o*c-s*l)-i*(r*c-s*a)+n*(r*l-o*a);if(!Number.isFinite(h)||Math.abs(h)<1e-9)return null;const d=[(o*c-s*l)/h,(n*l-i*c)/h,(i*s-n*o)/h,(s*a-r*c)/h,(t*c-n*a)/h,(n*r-t*s)/h,(r*l-o*a)/h,(i*a-t*l)/h,(t*o-i*r)/h];return[d[0]*e[0]+d[1]*e[1]+d[2]*e[2],d[3]*e[0]+d[4]*e[1]+d[5]*e[2],d[6]*e[0]+d[7]*e[1]+d[8]*e[2]]},m=_([a,l,c]),g=_([h,d,u]);if(!m||!g)return null;const f=[m[0],m[1],m[2],g[0],g[1],g[2]];return f.every(Number.isFinite)?f:null}(n);return o?{matrix:o,matched:r,residual:Pl(o,n)}:null}function Zl(e,t,i){const n=e[e.length-1];if(n&&n[0]===t[0]&&n[1]===t[1])return e;if(e.push(t),e.length<=600)return e;let r=function(e,t){if(e.length<3)return e.slice();const i=new Uint8Array(e.length);i[0]=i[e.length-1]=1;const n=[[0,e.length-1]];for(;n.length;){const[r,o]=n.pop(),[s,a]=e[r],[l,c]=e[o],h=l-s,d=c-a,u=Math.hypot(h,d)||1e-9;let p=0,_=-1;for(let t=r+1;tp&&(p=i,_=t)}_>0&&p>t&&(i[_]=1,n.push([r,_],[_,o]))}const r=[];for(let t=0;t600&&(r=r.filter((e,t)=>t%2==0||t===r.length-1)),r}function Xl(e){return"cleaning"===e||"returning"===e||"on"===e}const Jl={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function Ql(e){const[t,i]=Jl[e.rot]||[1,0],n=e.mir?-1:1;return[e.s*t*n,-e.s*i,e.ox,e.s*i*n,e.s*t,e.oy]}function ec(e){const t=e[0]*e[4]-e[1]*e[3];if(!Number.isFinite(t)||Math.abs(t)<1e-12)return null;const i=t<0,n=Math.sqrt(Math.abs(t));let r=180*Math.atan2(-e[1],e[4])/Math.PI;return r=(90*Math.round(r/90)%360+360)%360,{ox:e[2],oy:e[5],s:n,rot:r,mir:i}}function tc(e,t){const i=[],n=[];for(const t of e)null!=t.x0?(i.push(t.x0,t.x1),n.push(t.y0,t.y1)):(i.push(t.cx),n.push(t.cy));if(!i.length)return{ox:t[0]+t[2]/2,oy:t[1]+t[3]/2,s:t[2]/1e4,rot:0,mir:!0};const r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1,c={ox:0,oy:0,s:.6*Math.min(t[2],t[3])/l,rot:0,mir:!0},h=Ql(c),[d,u]=zl(h,(r+o)/2,(s+a)/2);return c.ox=t[0]+t[2]/2-d,c.oy=t[1]+t[3]/2-u,c}function ic(e,t,i,n){const[r,o]=zl(Ql(t),i,n),s=Ql({...e,ox:0,oy:0}),[a,l]=zl(s,i,n);return{...e,ox:r-a,oy:o-l}}function nc(e){const t=e?.trail_mode;return"never"===t||"cleaning"===t||"always"===t?t:!1===e?.trail?"never":"cleaning"}const rc={availability:"available",status:"alarm",activity:"none"},oc=new Set(["motion","vibration","sound"]),sc=new Set(["occupancy","presence"]),ac=new Set(["door","window","garage_door","opening"]),lc=new Set(["running","power"]),cc=new Set(["smoke","gas","carbon_monoxide","moisture","safety","tamper","problem"]);const hc=new Set(["running","working","washing","rinsing","spinning","drying","heating","cooling","cleaning","cooking","playing","recording","pumping","irrigating","humidifying","dehumidifying","fan","preheating","defrosting"]),dc=new Set([...hc,"start","started","run","active","in_progress","wash","rinse","spin","dry"]),uc=new Set(["off","idle","paused","standby","docked","finished","complete","completed","stopped","ready","sleeping","stop","end","done","inactive"]),pc=new Set(["heat","cool","heat_cool","auto","dry","fan_only"]),_c=e=>""===e||"unknown"===e||"unavailable"===e||"__missing__"===e,mc=e=>String(e??"").trim().toLowerCase(),gc=e=>mc(e).replace(/[\s-]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),fc=new Map([["run_state",0],["job_state",0],["operation_state",0],["activity_state",0],["machine_state",1],["running_state",1],["status",2],["device_status",2],["machine_status",2]]),vc=new Set(["wifi","connection","signal","battery"]);function yc(e,t){const i=e?.entities?.[t]||{};if("config"===i.entity_category)return null;const n=String(t||"").split(".").slice(1).join("."),r=[i.translation_key,i.original_name,i.name],o=[...r,n];r.some(e=>mc(e))||o.push(e?.states?.[t]?.attributes?.friendly_name);const s=o.map(gc).filter(Boolean);if(s.some(e=>e.split("_").some(e=>vc.has(e))))return null;let a=null;for(const e of s)for(const[t,i]of fc)(e===t||e.endsWith(`_${t}`))&&(a=null==a?i:Math.min(a,i));return a}const bc=(e,t)=>null!=yc(e,t);function wc(e,t){if(!t.startsWith("switch."))return!1;const i=e?.entities?.[t]||{},n=e?.states?.[t],r=t.slice(7).toLowerCase();if(/(?:^|_)(?:main_)?power$/.test(r))return!0;if([i.translation_key,i.original_name,i.name].map(mc).some(e=>["power","main power","power switch","питание"].includes(e)))return!0;const o=mc(n?.attributes?.friendly_name);return/(?:^|[\s._-])(?:main[\s._-]+)?power$/.test(o)||/(?:^|[\s._-])питание$/.test(o)}function kc(e){for(const t of["hvac_action","action","current_operation","run_state","job_state","operation","activity"]){const i=mc(e?.[t]);if(hc.has(i)||uc.has(i))return i}return""}function xc(e,t){const i=e?.states?.[t],n=i?mc(i.state):"__missing__",r=String(t||"").split(".")[0],o=mc(i?.attributes?.device_class),s={eid:t,state:n,availability:_c(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===s.availability)return s;if(function(e,t,i){return"alarm_control_panel"===e?"triggered"===i:"on"===i&&In(e,t)}(r,o,n))return{...s,status:"alarm"};if("binary_sensor"===r)return oc.has(o)?{...s,edge:"rising"}:sc.has(o)?{...s,activity:"on"===n?"presence":"none"}:ac.has(o)?{...s,status:"on"===n?"open":"neutral",edge:"rising"}:"moving"===o?{...s,activity:"on"===n?"transition":"none"}:lc.has(o)&&"on"===n?{...s,status:"working",activity:"running"}:s;if("cover"===r)return{...s,activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("lock"===r)return{...s,status:"unlocked"===n||"open"===n?"open":"neutral",activity:"locking"===n||"unlocking"===n?"transition":"none",edge:"terminal_transition"};if("valve"===r)return{...s,status:["open","opening","closing"].includes(n)?"open":"neutral",activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("climate"===r){const e=kc(i.attributes),t=Array.isArray(i.attributes?.hvac_modes)?i.attributes.hvac_modes.map(mc):[],r=!uc.has(n)&&(pc.has(n)||hc.has(n)||t.includes(n));return(e?hc.has(e):r)?{...s,status:"working",activity:"running"}:s}if(["light","switch","fan","humidifier"].includes(r))return"on"===n?{...s,status:"working",activity:"running"}:s;if("media_player"===r)return"off"===n?{...s,availability:"unavailable"}:s;if("vacuum"===r)return"cleaning"===n?{...s,status:"working",activity:"running"}:"returning"===n?{...s,status:"working",activity:"transition"}:s;if("script"===r)return"on"===n?{...s,status:"working",activity:"running"}:s;if("automation"===r)return s;if("button"===r||"event"===r)return{...s,edge:"change"};const a=kc(i.attributes);return hc.has(a)||hc.has(n)&&!uc.has(n)?{...s,status:"working",activity:"running"}:s}function $c(e,t,i){const n=i.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category),r=t.find(t=>wc(e,t));if(!(n.length>1&&!!r))return t.map(t=>xc(e,t));const o=t.find(t=>t!==r&&bc(e,t)),s=xc(e,r);return"unavailable"===s.availability||"off"===s.state?t.map(t=>({eid:t,state:e?.states?.[t]?mc(e.states[t].state):"__missing__",availability:"unavailable",status:"neutral",activity:"none",edge:"none"})):t.map(t=>{if(t===o)return function(e,t){const i=e?.states?.[t],n=i?mc(i.state):"__missing__",r={eid:t,state:n,availability:_c(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===r.availability)return r;const o=kc(i?.attributes);return hc.has(o)||dc.has(n)&&!uc.has(n)?{...r,status:"working",activity:"running"}:r}(e,t);return{...t===r?s:xc(e,t),status:"neutral",activity:"none",edge:"none"}})}function Sc(e){if(!e.length)return{availability:"available",status:"neutral",activity:"none"};const t=e.filter(e=>"available"===e.availability);if(!t.length)return{availability:"unavailable",status:"neutral",activity:"none"};if(t.some(e=>"alarm"===e.status))return rc;const i=t.some(e=>"working"===e.status)?"working":t.some(e=>"open"===e.status)?"open":"neutral",n=t.some(e=>"transition"===e.activity)?"transition":t.some(e=>"presence"===e.activity)?"presence":t.some(e=>"running"===e.activity)?"running":"none";return{availability:"available",status:i,activity:n}}function Mc(e,t){if(!(e=>!!e&&!_c(e))(e)||"unavailable"===t.availability||e===t.state)return null;if("rising"===t.edge)return"off"===e&&"on"===t.state?"event":null;if("change"===t.edge)return"event";if("terminal_transition"===t.edge){const i=new Set([e,t.state]);if(i.has("closed")&&i.has("open")||i.has("locked")&&i.has("unlocked"))return"transition"}return null}const Rc=(e,t=0)=>{const i=Number(e);return Number.isInteger(i)&&i>=0?i:t},Tc=(e,t)=>{const i={rev:0,configRev:Rc(t),off:new Set};if(null==e)return{snapshot:i,valid:!1};const n=e.off;return!Number.isInteger(e.rev)||Number(e.rev)<0||!Number.isInteger(e.config_rev)||Number(e.config_rev)<0||!Array.isArray(n)||n.some(e=>"string"!=typeof e||!e)?{snapshot:i,valid:!1}:{snapshot:{rev:Number(e.rev),configRev:Number(e.config_rev),off:new Set(n)},valid:!0}};function Cc(e,t=0){return Tc(e,t).snapshot}function Dc(e,t,i,n){const r=Tc(t,i);return n&&r.valid&&r.snapshot.configRev===i?e.configRev===i&&r.snapshot.rev{try{const[i,n]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),r=jc(i,"id"),o=jc(n,"entity_id");if(!r||!o)throw new Error("invalid_registry_response");t.devices=r,t.entities=o,t.authoritative=!0,t.access="full",t.lastSuccess=Date.now(),t.error=void 0}catch(e){t.authoritative=!1,t.access="limited",t.error=function(e){if(e&&"object"==typeof e){const t=e;return String(t.message||t.code||t.error||"registry_unavailable")}return String(e||"registry_unavailable")}(e)}finally{t.revision++,t.loading=void 0,function(e){for(const t of[...e.listeners])try{t()}catch{}}(t)}})()),t.loading}function Wc(e,t){void 0===t.reloadTimer&&(t.reloadTimer=globalThis.setTimeout(()=>{t.reloadTimer=void 0,Bc(e,t)},80))}async function Uc(e,t){if(t.subscribing||t.unsubDevice&&t.unsubEntity)return t.subscribing;const i=e?.connection?.subscribeEvents;return"function"==typeof i?(t.subscribing=(async()=>{try{t.unsubDevice||(t.unsubDevice=await i.call(e.connection,()=>Wc(e,t),"device_registry_updated")),t.unsubEntity||(t.unsubEntity=await i.call(e.connection,()=>Wc(e,t),"entity_registry_updated"))}catch{}finally{0===t.refs&&(t.unsubDevice?.(),t.unsubEntity?.(),t.unsubDevice=void 0,t.unsubEntity=void 0),t.subscribing=void 0}})(),t.subscribing):void 0}function Gc(e,t){const i=qc(e);if(!i)return()=>{};const n=0===i.refs;i.refs++,i.listeners.add(t),("pending"===i.access||n)&&Bc(e,i),Uc(e,i);let r=!1;return()=>{r||(r=!0,i.listeners.delete(t),i.refs=Math.max(0,i.refs-1),i.refs>0||(i.unsubDevice?.(),i.unsubEntity?.(),i.unsubDevice=void 0,i.unsubEntity=void 0,void 0!==i.reloadTimer&&globalThis.clearTimeout(i.reloadTimer),i.reloadTimer=void 0))}}function Vc(e){const t=qc(e);if(!t)return{revision:0,authoritative:!1,access:"limited",devices:e?.devices||{},entities:e?.entities||{},lastSuccess:0,error:"registry_unavailable"};let i=e?.devices||{},n=e?.entities||{};if(t.authoritative){const r=t.liveDevices!==i||t.liveEntities!==n,o=void 0!==t.liveDevices||void 0!==t.liveEntities;if(r&&(t.liveDevices=i,t.liveEntities=n,t.projectedRevision=void 0,o&&Wc(e,t)),t.projectedRevision!==t.revision||!t.projectedDevices||!t.projectedEntities){const e={...t.devices},r={...t.entities};for(const[t,n]of Object.entries(i))Object.prototype.hasOwnProperty.call(e,t)||(e[t]=n);for(const[e,t]of Object.entries(n))Object.prototype.hasOwnProperty.call(r,e)||(r[e]=t);t.projectedDevices=e,t.projectedEntities=r,t.projectedRevision=t.revision}i=t.projectedDevices,n=t.projectedEntities}return{revision:t.revision,authoritative:t.authoritative,access:t.access,devices:i,entities:n,lastSuccess:t.lastSuccess,error:t.error}}function Kc(e){if(!e||"object"!=typeof e&&"function"!=typeof e)return 0;let t=Ec.get(e);return t||(t=Nc++,Ec.set(e,t)),t}function Yc(e,t=Vc(e)){return[t.revision,t.access,Kc(t.devices),Kc(t.entities)].join(":")}function Zc(e){return!!e&&null==e.disabled_by}function Xc(e,t=Vc(e)){const i={},n={},r={};for(const[e,n]of Object.entries(t.devices||{}))Zc(n)&&(i[e]=n);for(const[e,i]of Object.entries(t.entities||{})){if(!Zc(i))continue;const r=i.device_id?t.devices?.[i.device_id]:null;t.authoritative&&i.device_id&&!r||(r&&!Zc(r)||(n[e]=i))}for(const[i,n]of Object.entries(e?.states||{})){const e=t.entities?.[i];if(e&&!Zc(e))continue;const o=e?.device_id?t.devices?.[e.device_id]:null;t.authoritative&&e?.device_id&&!o||(o&&!Zc(o)||(r[i]=n))}return{...e,devices:i,entities:n,states:r}}function Jc(e,t=Vc(e)){return{...e,devices:t.devices||{},entities:t.entities||{}}}function Qc(e,t){const i=[];for(const[n,r]of Object.entries(e||{}))r?.device_id===t&&i.push(n);return i}function eh(){if(Lc)return Lc;if("undefined"==typeof localStorage)return{};try{const e=JSON.parse(localStorage.getItem(Hc)||"{}");if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Date.now(),i={};for(const[n,r]of Object.entries(e))!r||"active"!==r.kind&&"ha_disabled"!==r.kind||!Number.isFinite(r.ts)||t-r.ts>7776e6||(i[n]=r);return Lc=i,Lc}catch{return{}}}function th(e,t,i=Vc(e)){if(!t||"virtual"===t)return{kind:"active",enabledEntityIds:[],allEntityIds:[]};const n=t.indexOf(":");if(n<1)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const r=t.slice(0,n),o=t.slice(n+1);if("device"!==r&&"entity"!==r||!o)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const s=i.devices||{},a=i.entities||{};if(i.authoritative){if("device"===r){const e=s[o];if(!e)return{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[]};const t=Qc(a,o);if(!Zc(e))return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:t};const i=t.filter(e=>Zc(a[e]));return t.length&&!i.length?{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:t}:{kind:"active",enabledEntityIds:i,allEntityIds:t}}const t=a[o];return t&&!Zc(t)?{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!s[t.device_id]?{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!Zc(s[t.device_id])?{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]}:t||e?.states?.[o]?{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}:{kind:"orphaned",reason:"entity_missing",enabledEntityIds:[],allEntityIds:[]}}const l=function(e){return eh()[e]||null}(t);if("device"===r){const t=s[o],i=Qc(a,o);if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:i};const n=i.filter(e=>{const t=a[e];return null==t?.disabled_by&&(!t.device_id||null==s[t.device_id]?.disabled_by)});if(i.length&&!n.length&&i.every(e=>null!=a[e]?.disabled_by))return{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:i};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"device",enabledEntityIds:[],allEntityIds:i};if(t||n.some(t=>!!e?.states?.[t]))return{kind:"active",enabledEntityIds:n,allEntityIds:i}}else{const t=a[o];if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]};if(t?.device_id&&null!=s[t.device_id]?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"entity",enabledEntityIds:[],allEntityIds:[o]};if(t||e?.states?.[o])return{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}}return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]}}function ih(e){const t={};for(const[i,n]of Object.entries(e.entities)){if(!n?.device_id||!Zc(n))continue;const r=e.devices?.[n.device_id];r&&!Zc(r)||(t[n.device_id]=t[n.device_id]||[]).push(i)}return t}function nh(e,t){const i=new Map;for(const n of e){if(!0===n?.removed)continue;const e=n?.binding||"";if(!e.startsWith("entity:"))continue;const r=e.slice(7);if(!r)continue;const o=t?.entities?.[r]?.device_id;if(!o)continue;const s=i.get(o)||new Set;s.add(r),i.set(o,s)}return{byDevice:i}}function rh(e,t,i,n){const r=n.byDevice.get(t);return r?.size?{partial:!0,entityIds:i.filter(t=>!r.has(t)&&!e?.entities?.[t]?.hidden)}:{partial:!1,entityIds:[...i]}}function oh(e,t,i){if(t.identifiers?.[0]?.[0])return t.identifiers[0][0];for(const t of i){const i=e.entities[t]?.platform;if(i)return i}return""}function sh(e,t){if(/_device_temperature$/.test(t))return!1;if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_temperature$/.test(t);const n=i.attributes||{};return"temperature"===n.device_class||/°C|°F/.test(n.unit_of_measurement||"")||/_temperature$/.test(t)}const ah=["vacuum","lawn_mower","climate","media_player","light","cover","lock","valve","alarm_control_panel","water_heater","fan","humidifier","siren","camera","remote"],lh=e=>[...e.filter(e=>!e.reg?.hidden),...e.filter(e=>!!e.reg?.hidden)];function ch(e,t){const i=t.map(t=>({eid:t,reg:e?.entities?.[t]})).filter(e=>!!e.reg);if(!i.length)return[];const n=i.filter(e=>!e.reg.entity_category),r=n.length?n:i;for(const e of ah){const t=r.filter(t=>t.eid.startsWith(e+"."));if(t.length)return lh(t).map(e=>e.eid)}const o=r.filter(t=>function(e,t){if(!t.startsWith("binary_sensor."))return!1;const i=mc(e?.states?.[t]?.attributes?.device_class||e?.entities?.[t]?.device_class||e?.entities?.[t]?.original_device_class);return oc.has(i)||sc.has(i)||ac.has(i)||lc.has(i)||"moving"===i||cc.has(i)}(e,t.eid));if(o.length)return lh(o).map(e=>e.eid);const s=r.filter(e=>e.eid.startsWith("switch."));if(s.length){const t=lh(s),n=t.find(t=>wc(e,t.eid));if(s.length>1&&n){const t=i.filter(t=>t.eid!==n.eid&&"config"!==t.reg?.entity_category&&null!=yc(e,t.eid)),r=t.filter(e=>!e.reg?.entity_category),o=r.length?r:t;for(const t of[0,1,2]){const i=lh(o.filter(i=>yc(e,i.eid)===t));if(i.length)return[i[0].eid,n.eid]}}return[(n||t[0]).eid]}const a=[];for(const e of Ie)a.push(...lh(r.filter(t=>t.eid.startsWith(e+"."))));return a.push(...lh(r.filter(e=>!Ie.includes(e.eid.split(".")[0])))),a.map(e=>e.eid)}function hh(e,t,i){const n=t.map(t=>({eid:t,reg:e.entities[t],st:e.states[t]})).filter(e=>e.reg),r=[n.filter(e=>!e.reg.hidden&&!e.reg.entity_category),n.filter(e=>!e.reg.entity_category),n.filter(e=>!e.reg.hidden),n];if("mdi:thermometer"===i||"mdi:air-filter"===i)for(const t of r){const i=t.find(t=>sh(e,t.eid));if(i)return i.eid}const o=ch(e,t);return o.find(yn)||o[0]}function dh(e,t,i=[]){return[...new Set(uh(e,t,i))].filter(e=>yn(e))}function uh(e,t,i=[]){const n=e?.startsWith("entity:")?new Set([e.slice(7)]):new Set(i);return(t||[]).filter(e=>"string"==typeof e&&!n.has(e))}function ph(e,t){if("string"==typeof t)return e.area===t;const i=e.marker?.room_id;return i?!!t.id&&i===t.id:!!t.area&&e.area===t.area}function _h(e){const t=e.marker?.binding?.startsWith("entity:")?e.marker.binding.slice(7):null,i=e.entities.filter(yn),n=e.primary&&yn(e.primary)?e.primary:null;return[...new Set([t,n,...i].filter(e=>!!e&&yn(e)))]}function mh(e){const t=_h(e),i=e.marker?.light_entity;return i&&t.includes(i)?i:t[0]||null}function gh(e,t){if(!1===t.marker?.is_light)return[];if(!0===t.marker?.is_light){return[{eid:mh(t),via:"forced"}]}const i=t.primary||ch(e,t.entities)[0];return i&&!i.startsWith("light.")?[]:t.entities.filter(t=>t.startsWith("light.")&&!!e.states?.[t]).map(e=>({eid:e,via:"light"}))}const fh=new WeakMap,vh=new WeakMap;function yh(e){return e.map(e=>[e.id||"",!0===e.hidden?1:0,e.primary||"",[...e.entities].join(","),void 0===e.controls?"":[...e.controls].join(","),e.marker?.id||"",e.marker?.binding||"",e.marker?.is_light,e.marker?.tap_action||"",!0===e.marker?.removed?1:0,e.marker?.light_entity||"",null==e.marker?.controls?"":[...e.marker.controls].join(",")].join("")).join("")}function bh(e){const t=yh(e),i=fh.get(e);if(i?.fingerprint===t)return i;const n=e.filter(e=>!e.hidden),r=new Map,o=new Map;for(const t of e){o.set(t,uh(t.marker?.binding,t.marker?.controls??t.controls,t.entities));const e=t.hidden||!0!==t.marker?.is_light?null:t.marker?.id||t.id;e&&r.set(String(e),t)}const s=new Map;for(const t of e){const e=o.get(t)||[],i=new Set(void 0===t.controls?e.filter(yn):t.controls.filter(yn)),n=mh(t),a=i.size?[...i]:n?[n]:[];for(const i of e){if(!i.startsWith("marker:"))continue;const e=i.slice(7);if(!e||e===String(t.marker?.id||t.id||""))continue;if(!r.has(e))continue;const n=s.get(e)||{markerId:e,controllers:[],driverEids:[]};n.controllers.push({device:t,driverEids:[...a]}),n.driverEids=[...new Set([...n.driverEids,...a])],s.set(e,n)}}const a={fingerprint:t,visible:n,markerById:r,persistedByDevice:o,incomingByMarker:s};return fh.set(e,a),a}function wh(e){return bh(e).incomingByMarker}function kh(e,t){const i=dh(t.marker?.binding,t.controls??t.marker?.controls,t.entities),n=uh(t.marker?.binding,t.marker?.controls??t.controls,t.entities);return(null!=t.marker?.is_light||!i.length&&!n.some(e=>e.startsWith("marker:")))&&gh(e,t).length>0}function xh(e,t){return gh(e,t).some(e=>!!e.eid)}function $h(e,t,i,n){const r="always"===e||"auto"===e&&t,o=r&&!i;return{sourceExists:r,fromSourceEnabled:r&&i,manualEnabled:r,radiusEnabled:r,passive:o,effectiveMode:o&&"auto"===n?"fixed":n}}function Sh(e,t){const i=dh(t.marker?.binding,t.controls??t.marker?.controls,t.entities).map(e=>({eid:e,via:"controls"})),n=kh(e,t)?gh(e,t):[];for(const e of n)e.eid&&i.some(t=>t.eid===e.eid)||i.push(e);return i}function Mh(e,t,i,n){if(null!=i)return Mh(e,t,null,n).filter(e=>ph(e.device,i));const r=yh(t),o=function(e,t){const i=new Set;for(const e of t){for(const t of e.entities)i.add(t);for(const t of e.controls||e.marker?.controls||[])"string"!=typeof t||t.startsWith("marker:")||i.add(t)}return[...i].sort().map(t=>`${t}:${e?.states?.[t]?.state??""}`).join("|")}(e,t),s=Oc(n),a=vh.get(t);if(a?.graphFingerprint===r&&a.stateFingerprint===o&&a.virtualLightFingerprint===s&&a.registry===e?.entities)return a.sources;const{visible:l,markerById:c,persistedByDevice:h,incomingByMarker:d}=bh(t),u=null==i?l:l.filter(e=>ph(e,i)),p=new Map,_=new Map;for(const t of u){const i=Sh(e,t).filter(e=>"controls"!==e.via);for(const n of i){const i=!0===t.marker?.is_light?String(t.marker?.id||t.id||""):"",r=i?`marker:${i}`:`entity:${n.eid}`,o=n.eid?[n.eid]:[],s={key:r,eid:n.eid||"",stateEids:o,serviceEids:o,device:t,via:n.via,castsGlow:!0,passive:!n.eid,on:!n.eid||"on"===e.states?.[n.eid]?.state};p.set(t,[...p.get(t)||[],s]),n.eid&&_.set(n.eid,s)}}const m=new Map;for(const e of t){const t=h.get(e)||[],i=new Set(void 0===e.controls?t.filter(yn):e.controls);m.set(e,i)}for(const t of p.values())for(const i of t){if(!i.passive)continue;const t=i.key.slice(7),r=d.get(t);i.on=!r||r.driverEids.some(t=>"on"===e.states?.[t]?.state),!r&&zc(i.device.marker)&&(i.on=Pc(i.device.marker,n))}const g=new Map,f=e=>{const t=g.get(e.key);(!t||e.castsGlow&&!t.castsGlow)&&g.set(e.key,e)};for(const t of l){const n=h.get(t)||[],r=null==i||ph(t,i);for(const i of n){if(i.startsWith("marker:")){const e=c.get(i.slice(7)),t=e?p.get(e):null;if(t)for(const e of t)f(e);continue}if(!yn(i)||!m.get(t)?.has(i))continue;const n=_.get(i);n?f(n):r&&f({key:`entity:${i}`,eid:i,stateEids:[i],serviceEids:[i],device:t,via:"controls",castsGlow:!1,passive:!1,on:"on"===e.states?.[i]?.state})}for(const e of p.get(t)||[])f(e)}const v=[...g.values()];return vh.set(t,{graphFingerprint:r,stateFingerprint:o,virtualLightFingerprint:s,registry:e?.entities,sources:v}),v}function Rh(e){const t=e.filter(e=>e.castsGlow);return t.find(e=>e.on)||t[0]||null}function Th(e){return e.length?e.some(e=>e.on)?"on":"off":"none"}function Ch(e,t){const i=[];for(const n of t){const t=e.states[n];if(!t)continue;const r=(t.attributes?.unit_of_measurement||"").toLowerCase();if(/_(linkquality|lqi)$/.test(n)||"lqi"===r){const e=parseFloat(t.state);isNaN(e)||i.push(e);continue}const o=t.attributes?.linkquality??t.attributes?.lqi;if(null!=o){const e=parseFloat(o);isNaN(e)||i.push(e)}}return Mi(i)}function Dh(e,t){for(const i of t){if(!sh(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(10*n)/10}return null}function Ah(e,t){for(const i of t){if(!i.startsWith("climate."))continue;const t=e.states[i];if(!t||"unavailable"===t.state||"unknown"===t.state)continue;const n=parseFloat(t.attributes?.current_temperature);if(Number.isFinite(n))return Math.round(10*n)/10}return null}function Oh(e,t){if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_humidity$/.test(t);const n=i.attributes||{};return"humidity"===n.device_class||"%"===n.unit_of_measurement&&/_humidity$/.test(t)||/_humidity$/.test(t)}function zh(e,t){for(const i of t){if(!Oh(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(n)}return null}function Ph(e,t){if(!t)return[];const i=[];for(const[t,n]of Object.entries(e.entities)){if(!t.startsWith("light.")||n.hidden||!Zc(n))continue;let r=null;if("group"===n.platform)r=n.area_id||null;else{if(!n.device_id)continue;{const t=e.devices[n.device_id];if(!Zc(t))continue;if("Group"!==t?.model)continue;r=t.area_id||n.area_id||null}}if(!r)continue;const o=e.states[t];i.push({eid:t,name:n.name||o?.attributes?.friendly_name||t,area:r})}return i}function Fh(e,t,i,n,r){const o=Fe(t,i,r);if(o!==Pe)return o;const s=[];for(const t of n){const i=e.states[t]?.attributes?.device_class;i&&s.push(i)}return function(e){for(const t of e){const e=ze[t];if(e)return e}return null}(s)??Pe}function Ih(e,t){return e.map(e=>{if(!Array.isArray(e.controls))return e;const i=e.controls.filter(e=>!("string"==typeof e&&e.startsWith("marker:")&&t.has(e.slice(7))));return i.length===e.controls.length?e:{...e,controls:i.length?i:null}})}function Eh(e,t,i){if(!t||!i||t===i)return[...e];const n=`marker:${t}`,r=`marker:${i}`;return e.map(e=>{const t=Array.isArray(e.controls)?e.controls.map(e=>e===n?r:e):e.controls,i="derived_marker_state"===e.value_badge?.source?.kind&&e.value_badge.source.ref===n?{...e.value_badge,source:{...e.value_badge.source,ref:r}}:e.value_badge;return t===e.controls&&i===e.value_badge?e:{...e,controls:t,value_badge:i}})}function Nh(e,t,i){if(!t||t===i)return!0;const n=new Map;for(const t of e)n.set(t.id,(t.controls||[]).filter(e=>"string"==typeof e&&e.startsWith("marker:")).map(e=>e.slice(7)));const r=new Set,o=[i];for(;o.length;){const e=o.pop();if(e===t)return!0;r.has(e)||(r.add(e),o.push(...n.get(e)||[]))}return!1}function Hh(e,t,i,n){const r=new Set([t]),o=e.filter(e=>{const o=e.id===t||!n&&e.binding===i;return o&&r.add(e.id),!o});return{markers:n?o:[...o,{id:t,binding:i,removed:!0,hidden:!0}],cleanupIds:r}}function Lh(e){const t=new Set,i=new Set,n=new Set;for(const r of e||[]){const e=String(r.binding||"").indexOf(":");if(e<1)continue;const o=r.binding.slice(0,e),s=r.binding.slice(e+1);s&&(!0===r?.removed?"device"===o?t.add(s):"entity"===o&&i.add(s):"entity"===o&&n.add(s))}return{devices:t,entities:i,liveEntities:n}}function qh(e,t,i){if(i.liveEntities.has(t))return!1;if(i.entities.has(t))return!0;const n=e?.entities?.[t]?.device_id;return!!n&&i.devices.has(n)}function jh(e,t,i,n,r){const o=dh(t.binding,t.controls,e.entities).filter(e=>!qh(i,e,n)).filter(e=>"active"===th(i,"entity:"+e,r).kind);e.marker=t,e.controls=o,e.userHidden=!0===t.hidden,e.hidden=e.userHidden||"ha_disabled"===e.bindingStatus?.kind,t.name&&(e.name=t.name),t.icon&&(e.icon=t.icon),null!=t.model&&(e.model=t.model),e.link=t.link??null,e.description=t.description??null,e.pdfs=t.pdfs||[],e.tapAction=t.tap_action??null}function Bh(e,t,i,n){if("string"==typeof e.room_id&&e.room_id.length>0&&null===e.area)return{area:"",space:e.space||n};const r=e.area||t||"";return{area:r,space:r&&i[r]||e.space||n}}function Wh(e){const t=e.hass,i=e.registry||Vc(t),n=Xc(t,i),r=Jc(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,showAll:c,firstSpaceId:h,loc:d,iconRules:u}=e,p=!1!==a.group_lights,_=Lh(s),m=Ph(n,p).filter(e=>!qh(n,e.eid,_)),g=new Set(m.map(e=>e.area)),f=ih(n),v=function(e){const t={};for(const[i,n]of Object.entries(e.entities||{}))n?.device_id&&(t[n.device_id]=t[n.device_id]||[]).push(i);return t}(r),y=nh(s,r),b=new Set;for(const e of s){const[t,i]=e.binding.split(":");"device"!==t&&"entity"!==t||!i||b.add(e.binding)}const w=(e,t)=>s.find(i=>i.binding===e+":"+t),k={},x=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(b.has("device:"+e.id))continue;const s=th(t,"device:"+e.id,i);if("active"!==s.kind)continue;const h=w("device",e.id);if(h&&h.hidden&&!a.filter_seeded)continue;const _=rh(n,e.id,f[e.id]||[],y);if(_.partial&&!_.entityIds.length)continue;const m=_.entityIds,v=_.partial?{kind:"active",enabledEntityIds:m,allEntityIds:m}:s,$=oh(n,e,m),S=!a.filter_seeded;if(S&&!c){if(l.has($))continue;if("Group"===e.model)continue;if(/scene/i.test(e.model||""))continue;if(/bridge/i.test((e.model||"")+(e.name||"")))continue;if("myheat"===$&&e.via_device_id)continue}const M=(e.name_by_user||e.name||d("device.unnamed")).trim(),R=M+"|"+r;let T=Fh(n,M,e.model,m,u);if(m.some(e=>e.startsWith("lock."))&&(T="mdi:lock"),S&&!c&&p&&"mdi:lightbulb"===T&&g.has(r))continue;k[R]=(k[R]||0)+1;const C=k[R]>1?M+" "+k[R]:M,D={id:e.id,name:C,model:e.model||"",area:r,space:o[r],icon:T,entities:m,allEntities:v.allEntityIds,bindingStatus:v,bindingKind:"device",bindingRef:e.id,pdfs:[]};D.primary=hh(n,m,T),"mdi:thermometer"!==T&&"mdi:air-filter"!==T||(D.temp=Dh(n,m)),D.primary&&Oh(n,D.primary)&&(D.hum=zh(n,m)),x.push(D)}for(const e of m)o[e.area]&&(b.has("entity:"+e.eid)||x.push({id:"lg_"+e.eid,name:e.name,model:d("device.light_group"),area:e.area,space:o[e.area],icon:"mdi:lightbulb-group",entities:[e.eid],allEntities:[e.eid],bindingStatus:{kind:"active",enabledEntityIds:[e.eid],allEntityIds:[e.eid]},primary:e.eid,bindingKind:"entity",bindingRef:e.eid,pdfs:[]}));for(const e of s){if(e.removed)continue;const[s,l]=e.binding.split(":"),c="device"===s||"entity"===s?th(t,e.binding,i):null;if(!e.hidden||a.filter_seeded||"ha_disabled"===c?.kind)if("device"===s){const t=c;if("unverified"===t.kind)continue;const s=r.devices[l],{area:a,space:p}=Bh(e,s?.area_id,o,h),m="active"===t.kind?t.enabledEntityIds:[];let g=s?Fh(n,s.name_by_user||s.name||"",s.model,m,u):"mdi:help-circle";m.some(e=>e.startsWith("lock."))&&(g="mdi:lock");const f={id:e.id,name:s?.name_by_user||s?.name||d("device.fallback"),model:s?.model||"",area:a,space:p,icon:g,entities:m,allEntities:t.allEntityIds.length?t.allEntityIds:s&&v[s.id]||[],bindingStatus:t,bindingKind:"device",bindingRef:l};f.primary=hh(n,m,g),"mdi:thermometer"!==g&&"mdi:air-filter"!==g||(f.temp=Dh(n,m)),f.primary&&Oh(n,f.primary)&&(f.hum=zh(n,m)),jh(f,e,r,_,i),x.push(f)}else if("entity"===s){if(qh(r,l,_))continue;const t=c;if("unverified"===t.kind)continue;const s=r.entities[l],a=s?.area_id||s?.device_id&&r.devices[s.device_id]?.area_id||"",{area:d,space:p}=Bh(e,a,o,h),m=n.states[l],g=s?.name||m?.attributes?.friendly_name||l;let f=Fh(n,g,"",[l],u);l.startsWith("lock.")&&(f="mdi:lock");const v={id:e.id,name:g,model:"",area:d,space:p,icon:f,entities:"active"===t.kind?[l]:[],allEntities:[l],bindingStatus:t,primary:"active"===t.kind?l:void 0,bindingKind:"entity",bindingRef:l};"mdi:thermometer"!==f&&"mdi:air-filter"!==f||!v.entities.length||(v.temp=Dh(n,v.entities)),v.entities.length&&Oh(n,l)&&(v.hum=zh(n,v.entities)),jh(v,e,r,_,i),x.push(v)}else{const t=e.area||"",n=e.space||t&&o[t]||h,s={id:e.id,name:e.name||d("device.virtual"),model:e.model||"",area:t,space:n,icon:e.icon||"mdi:map-marker",entities:[],allEntities:[],bindingStatus:{kind:"active",enabledEntityIds:[],allEntityIds:[]},bindingKind:"virtual",virtual:!0};jh(s,e,r,_,i),x.push(s)}}return x}function Uh(e){const{marker:t,siblingMarkers:i=[],...n}=e;return Wh({...n,markers:[...i.filter(e=>e.id!==t.id),t]}).find(e=>e.id===t.id)||null}function Gh(e,t,i,n){if(!t)return null;if(function(e,t,i){if(!t)return!1;const n=t.indexOf(":");if(n<1)return!1;const r=t.slice(0,n),o=t.slice(n+1),s=Lh(i);return"device"===r?s.devices.has(o):"entity"===r&&qh(e,o,s)}(e,t,n))return null;const r=t.indexOf(":");if(r<0)return null;const o=t.slice(0,r),s=t.slice(r+1);if(!s)return null;if("entity"===o){const t=parseFloat(e.states[s]?.state);return Number.isFinite(t)?"temp"===i?Math.round(10*t)/10:Math.round(t):null}if("device"===o){const t=Object.entries(e.entities).filter(([,e])=>e.device_id===s).map(([e])=>e);return"temp"===i?Dh(e,t):zh(e,t)}return null}const Vh=new RegExp(["water","voda","coolant","flow_?temp","return_?temp","target","setpoint","chip","cpu","processor","board","core_temp","device_temp","batter","akkum","freezer","fridge","oven","kettle","boiler"].join("|"),"i");function Kh(e,t,i){const n=[];for(const r of t){if(r.area!==i||r.virtual)continue;const t=Ch(e,r.entities);null!=t&&n.push(t)}return Mi(n)}function Yh(e,t,i){const n=[];for(const r of t){if(r.area!==i)continue;if("mdi:thermometer"!==r.icon&&"mdi:air-filter"!==r.icon)continue;const t=Dh(e,r.entities);null!=t&&n.push(t)}return n.length?Math.round(n.reduce((e,t)=>e+t,0)/n.length*10)/10:null}const Zh={offStates:["off"],unknownUsesToggle:!0},Xh={light:Zh,switch:Zh,fan:Zh,humidifier:Zh,input_boolean:Zh,automation:Zh,remote:Zh,group:Zh,climate:{...Zh,featureMasks:{turn_on:256,turn_off:128,toggle:384}},media_player:{...Zh,featureMasks:{turn_on:128,turn_off:256,toggle:384}},siren:{...Zh,featureMasks:{turn_on:1,turn_off:2,toggle:3}},vacuum:{...Zh,featureMasks:{turn_on:1,turn_off:2,toggle:3}},water_heater:{...Zh,featureMasks:{turn_on:8,turn_off:8,toggle:8}},camera:{...Zh,featureMasks:{turn_on:1,turn_off:1,toggle:1}}};function Jh(e){return e.slice(0,e.indexOf("."))}function Qh(e,t,i){if(!e?.services||"object"!=typeof e.services)return!1;const n=e.services?.[t];return!!n&&Object.prototype.hasOwnProperty.call(n,i)}function ed(e,t,i){return Qh(e,t,i)?{domain:t,service:i}:Qh(e,"homeassistant",i)?{domain:"homeassistant",service:i}:null}function td(e,t){return e?.entities?.[t]||null}function id(e,t,i){const n=e?.states?.[i],r=td(t,i);return n?.attributes?.friendly_name||r?.name||r?.original_name||i}function nd(e,t){const i=td(e,t);if(null!=i?.disabled_by)return!0;const n=i?.device_id?e?.devices?.[i.device_id]:null;return null!=n?.disabled_by}function rd(e,t){const i=e?.attributes?.supported_features;if(null==i||""===i)return!1;const n=Number(i);return Number.isFinite(n)&&(n&t)===t}function od(e,t,i){const n=Jh(i);if("lock"===n||"alarm_control_panel"===n)return!0;if("cover"!==n)return!1;const r=e?.states?.[i],o=td(t,i),s=String(r?.attributes?.device_class||o?.device_class||o?.original_device_class||"");return Fi.has(s)}function sd(e,t,i,n,r){return{ref:i,entityId:n,name:n?id(e,t,n):null,reason:r}}function ad(e,t,i,n,r,o=null){return{target:null,skipped:sd(e,t,i,n,r),semantics:o,nextEffect:null,command:null}}function ld(e,t,i,n,r=i){const o=Jh(i);if("cover"!==o&&"valve"!==o)return function(e,t,i,n,r=i){const o=Jh(i),s=e?.states?.[i];if(nd(t,i))return ad(e,t,r,i,"ha-disabled","power");if(od(e,t,i))return ad(e,t,r,i,"secure");if(!s)return ad(e,t,r,i,"missing","power");if("unavailable"===s.state)return ad(e,t,r,i,"unavailable","power");const a=Xh[o];if(!a)return ad(e,t,r,i,"unsupported");let l,c;if("unknown"===s.state||""===s.state){if(!a.unknownUsesToggle)return ad(e,t,r,i,"unsupported","power");l="toggle",c="toggle"}else a.offStates.includes(String(s.state))?(l="turn-on",c="turn_on"):(l="turn-off",c="turn_off");const h=a.featureMasks?.[c];if(h&&!rd(s,h))return ad(e,t,r,i,"unsupported","power");const d=ed(e,o,c);return d?{target:{entityId:i,name:id(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:"power",nextEffect:l,command:{...d,data:{entity_id:i}}}:ad(e,t,r,i,"unsupported","power")}(e,t,i,n,r);if(nd(t,i))return ad(e,t,r,i,"ha-disabled",o);if(od(e,t,i))return ad(e,t,r,i,"secure",o);const s=e?.states?.[i];if(!s)return ad(e,t,r,i,"missing",o);if("unavailable"===s.state)return ad(e,t,r,i,"unavailable",o);const a=function(e,t,i){const n=String(i?.state||""),r="closed"===n?{service:`open_${t}`,effect:"open",feature:1}:"open"===n?{service:`close_${t}`,effect:"close",feature:2}:"opening"===n||"closing"===n?{service:`stop_${t}`,effect:"stop",feature:8}:null;return r&&rd(i,r.feature)&&Qh(e,t,r.service)?r:rd(i,3)&&Qh(e,t,"toggle")?{service:"toggle",effect:"toggle"}:null}(e,o,s);if(!a)return ad(e,t,r,i,"unsupported",o);return{target:{entityId:i,name:id(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:o,nextEffect:a.effect,command:{domain:o,service:a.service,data:{entity_id:i}}}}function cd(e){return"entity"===e.bindingKind?e.bindingRef&&yn(e.bindingRef)?[e.bindingRef]:[]:"virtual"===e.bindingKind?[]:_h(e)}function hd(e){const t=e.marker?.toggle_entity;return t&&cd(e).includes(t)?t:null}function dd(e,t,i){const n=function(e,t){if("entity"===e.bindingKind&&e.bindingRef){const t=e.marker?.light_entity?mh(e):null;return[...new Set([t,e.bindingRef].filter(e=>!!e))]}const i=e.entities.length?e.entities:e.allEntities||[],n=e.marker?.light_entity||e.primary&&yn(e.primary)?mh(e):null;return[...new Set([n,...ch(t,i)].filter(e=>!!e))]}(i,t);if(!n.length)return null;const r="entity"===i.bindingKind?"binding":"device-role";if("binding"===r)return ld(e,t,n[0],r);let o=null,s=null;for(const i of n){const n=ld(e,t,i,r);if(n.command)return n;const a=n.skipped?.reason;if("missing"===a||"unavailable"===a||"secure"===a)return n;"ha-disabled"!==a?o||=n:s||=n}return o||s}function ud(e){const t=e.skipped?.reason;return"missing"===t?"unavailable":t||"unsupported"}function pd(e,t){return{origin:e,kind:"none",semantics:null,targets:[],skippedTargets:[],noneReason:t,nextEffect:null,command:null}}function _d(e,t){return"cover"===e||"toggle"===e?"toggle":"more-info"===e||"run"===e||"info"===e?e:(null==e||""===e)&&"light"===t?"toggle":"info"}function md(e,t){return{origin:e,kind:"single",semantics:t.semantics,targets:t.target?[t.target]:[],skippedTargets:t.skipped?[t.skipped]:[],noneReason:t.command?null:ud(t),nextEffect:t.nextEffect,command:t.command}}function gd(e,t,i,n=[]){const r=new Map,o=[],s=new Set,a=e=>{const t=`${e.ref}\n${e.entityId||""}\n${e.reason}`;s.has(t)||(s.add(t),o.push(e))};for(const e of n)a(e);for(const n of i){const i=ld(e,t,n.entityId,n.via,n.ref);i.target?r.set(n.entityId,r.get(n.entityId)||i.target):i.skipped&&a(i.skipped)}const l=[...r.values()];if(!l.length)return{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:o.length&&o.every(e=>"secure"===e.reason)?"secure":"configured-targets-missing",nextEffect:null,command:null};const c=l.some(e=>"on"===e.state)?"turn_off":"turn_on",h=ed(e,"homeassistant",c);return h?{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:null,nextEffect:"turn_on"===c?"turn-on":"turn-off",command:{...h,data:{entity_id:l.map(e=>e.entityId)}}}:{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:[],skippedTargets:[...o,...l.map(i=>sd(e,t,i.entityId,i.entityId,"unsupported"))],noneReason:"unsupported",nextEffect:null,command:null}}function fd(e){return String(e.marker?.id||e.id||"")}function vd(e){const{hass:t,device:i}=e,n=e.registryHass||t,r=function(e){return"toggle"===e.tapAction?"explicit-toggle":"cover"===e.tapAction?"legacy-cover":!e.tapAction&&e.primary?.startsWith("light.")?"default-light":null}(i);if(!r)return null;const o=i.marker;if("explicit-toggle"===r&&zc(o)){const t=String(o?.id||i.id||""),n=wh(e.devices).get(t);if(n)return function(e,t){const i=e.registryHass||e.hass;return gd(e.hass,i,t.driverEids.map(e=>({entityId:e,via:"control-marker-driver",ref:`marker:${t.markerId}`})))}(e,n);const s=Pc(o,e.virtualLights);return{origin:r,kind:"single",semantics:"power",targets:[{entityId:"",name:i.name,state:s?"on":"off",via:"virtual-light"}],skippedTargets:[],noneReason:null,nextEffect:s?"turn-off":"turn-on",command:null,operation:{kind:"virtual-light",markerId:o.id}}}if("explicit-toggle"===r){if(uh(i.marker?.binding,i.marker?.controls??i.controls,i.entities).length)return function(e,t=null){const{hass:i,device:n,devices:r}=e,o=e.registryHass||i,s=uh(n.marker?.binding,n.marker?.controls??n.controls,n.entities),a=e.lightSources||Mh(i,r,null,e.virtualLights),l=new Map;for(const e of a){if(!e.key.startsWith("marker:"))continue;const t=l.get(e.key)||[];t.push(e),l.set(e.key,t)}const c=wh(r),h=new Map;for(const e of r){const t=String(e.marker?.id||e.id||"");t&&h.set(t,e)}const d=[],u=[];t&&d.push({entityId:t,via:"entity"===n.bindingKind?"binding":"device-role",ref:t});for(const e of s){if(!e.startsWith("marker:")){yn(e)?d.push({entityId:e,via:"control-entity",ref:e}):u.push(sd(i,o,e,e.includes(".")?e:null,"unsupported"));continue}const t=l.get(e)||[];if(!t.length){const t=h.get(e.slice(7));if("ha_disabled"===t?.bindingStatus?.kind){const n=t.bindingStatus.allEntityIds[0]||null;u.push({ref:e,entityId:n,name:t.name||(n?id(i,o,n):null),reason:"ha-disabled"})}else u.push(sd(i,o,e,null,"missing"));continue}const r=[...new Set(t.flatMap(e=>e.serviceEids))];if(r.length){for(const t of r)d.push({entityId:t,via:"control-entity",ref:e});continue}const s=t.some(e=>e.passive),a=e.slice(7),p=fd(n),_=c.get(a)?.controllers.find(e=>fd(e.device)===p);if(s&&_?.driverEids.length)for(const t of _.driverEids)d.push({entityId:t,via:"control-marker-driver",ref:e});else u.push(sd(i,o,e,null,s?"missing":"unsupported"))}return gd(i,o,d,u)}(e,hd(i))}if("legacy-cover"===r){const e=i.entities.find(e=>e.startsWith("cover."))||i.allEntities?.find(e=>e.startsWith("cover."));return e?md(r,ld(t,n,e,"device-role")):pd(r,"no-actionable-entity")}const s=hd(i),a=s?ld(t,n,s,"entity"===i.bindingKind?"binding":"device-role"):dd(t,n,i);return a?md(r,a):pd(r,i.virtual||"virtual"===i.bindingKind?"no-actionable-entity":"no-binding")}function yd(e){if(!e)return[];const t=Array.isArray(e.data.entity_id)?e.data.entity_id:[e.data.entity_id];return[...new Set(t)].sort()}function bd(e){return e?e.operation?e.operation:e.command?{kind:"ha-service",command:e.command}:null:null}const wd=new Set(["missing","ha-disabled","unavailable"]);function kd(e,t){if(!bd(e)||!e.nextEffect||!e.targets.length)return[];const i="group"===e.kind,n=i?e.targets.filter(e=>"on"===e.state).length:0,r=i?0===n?t.groupAllOff():t.groupCurrent(n,e.targets.length):t.state(e.targets[0]);let o;return o="toggle"===e.nextEffect?t.expectedByHa():i&&"turn-on"===e.nextEffect?t.groupAllOn():i&&"turn-off"===e.nextEffect?t.groupAllOff():t.effect(e.nextEffect),[t.current(r),t.expected(o),...e.skippedTargets.length?[t.unavailable(e.skippedTargets.length)]:[]]}function xd(e,t){const i=bd(e),n=bd(t);return!(!i||!n||i.kind!==n.kind)&&("virtual-light"===i.kind&&"virtual-light"===n.kind?i.markerId===n.markerId:"ha-service"===i.kind&&"ha-service"===n.kind&&function(e,t){const i=yd(e),n=yd(t);return i.length===n.length&&i.every((e,t)=>e===n[t])}(i.command,n.command))}function $d(e,t){const i=e.targets[0]||e.skippedTargets[0],n=[];return"group"===e.kind?e.targets.length&&n.push(t.group(e.targets)):i&&n.push(t.single(i)),e.nextEffect&&e.targets.length&&n.push("group"===e.kind?t.groupCurrentNext(e.targets,e.nextEffect):t.currentNext(e.targets[0],e.nextEffect)),e.skippedTargets.length&&n.push(t.skipped(e.skippedTargets)),!e.command&&e.noneReason&&n.push(t.none(e.noneReason)),n}const Sd=e=>!!e&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function Md(e,t=5,i=5){return vo(e.cm,t,i)/2}function Rd(e,t,i=1,n=5,r=5,o=0){const s=e.host;if(!s||"partition"!==s.kind||"string"!=typeof s.id||!s.id)return{resolved:null,reason:"invalid-host"};const a=t.find(e=>e.id===s.id);if(!a)return{resolved:null,reason:"missing-partition"};if(!Sd(a.a)||!Sd(a.b)||!Number.isFinite(s.t)||s.t<0||s.t>1)return{resolved:null,reason:"invalid-position"};const l=a.b[0]-a.a[0],c=a.b[1]-a.a[1],h=Math.hypot(l,c),d=Number(e.length)*i;if(!(h>1e-9&&d>0&&Number.isFinite(d)))return{resolved:null,reason:"invalid-length"};const u=s.t*h;if(u-d/2h-o+1e-9)return{resolved:null,reason:"does-not-fit"};const p=l/h,_=c/h;let m=180*Math.atan2(c,l)/Math.PI;return m>=90?m-=180:m<-90&&(m+=180),{reason:null,resolved:{opening:e,host:s,partition:a,center:[a.a[0]+l*s.t,a.a[1]+c*s.t],angle:m,length:d,depth:vo(a.cm,n,r),t:s.t,axis:{a:[a.a[0],a.a[1]],b:[a.b[0],a.b[1]],ux:p,uy:_,length:h}}}}function Td(e,t,i=1,n=5,r=5){return Rd(e,t,i,n,r,0)}function Cd(e,t,i=1,n=5,r=5){const o=e.host,s="partition"===o?.kind?t.find(e=>e.id===o.id):void 0;if(!s)return Td(e,t,i,n,r);const a=Rd(e,t,i,n,r,Md(s,n,r));return"does-not-fit"===a.reason?{resolved:null,reason:"does-not-fit-jamb"}:a}function Dd(e,t){return!e||(e.length!==t.length||e.host?.kind!==t.host?.kind||e.host?.id!==t.host?.id||e.host?.t!==t.host?.t)}function Ad(e){const{center:t,length:i,axis:n,host:r}=e,o=i/2;return{hostId:r.id,a:[t[0]-n.ux*o,t[1]-n.uy*o],b:[t[0]+n.ux*o,t[1]+n.uy*o],depth:e.depth}}function Od(e,t=!1){const i=t?1:-1,n=e.depth/2;return{ox:-e.axis.uy*i*n,oy:e.axis.ux*i*n,cm:e.partition.cm,side:i}}function zd(e,t,i){return e.flatMap(e=>!Sd(e.a)||!Sd(e.b)||Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])<=1e-9?[]:[{roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`partition:${e.id}`,kind:"outer",cm:e.cm,open:!1,half:vo(e.cm,t,i)/2,partitionHost:{kind:"partition",id:e.id}}])}function Pd(e,t,i){const{center:n,length:r,axis:o}=e,s=r/2,a=t.flatMap(e=>{if(!e.kind||e.open)return[];const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],a=Math.hypot(t,r);if(!(a>i))return[];const l=t/a,c=r/a;if(Math.abs(o.ux*c-o.uy*l)>1e-6)return[];if(Math.abs((n[0]-e.a[0])*c-(n[1]-e.a[1])*l)>i)return[];const h=e=>(e[0]-n[0])*o.ux+(e[1]-n[1])*o.uy,d=h(e.a),u=h(e.b),p=Math.max(-s,Math.min(d,u)),_=Math.min(s,Math.max(d,u));return _>=p-i?[[p,_]]:[]});if(!a.length)return!1;a.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let l=-s;for(const[e,t]of a){if(e>l+i)return!1;if(l=Math.max(l,t),l>=s-i)return!0}return!1}function Fd(e,t,i=1e-9){const n=e.length/(2*e.axis.length),r=e.t-n,o=e.t+n;return t.some(t=>{if(t.host.id!==e.host.id||t.opening.id===e.opening.id)return!1;const n=t.length/(2*t.axis.length);return Math.max(r,t.t-n)[]);for(let i=0;i=1-1e-9||u<=1e-9||u>=1-1e-9||(t[i].push(d),t[s].push(u))}}const i=[];for(let n=0;ne-t),1];for(let e=1;e{const i=t[2]-t[0],n=t[3]-t[1],r=i*i+n*n;if(!(r>0))return Math.hypot(e[0]-t[0],e[1]-t[1]);const o=Math.max(0,Math.min(1,((e[0]-t[0])*i+(e[1]-t[1])*n)/r));return Math.hypot(e[0]-(t[0]+o*i),e[1]-(t[1]+o*n))},qd=(e,t,i,n)=>{const r=n[2]-n[0],o=n[3]-n[1],s=t*o-i*r;if(Math.abs(s)<1e-12)return 1/0;const a=n[0]-e[0],l=n[1]-e[1],c=(a*o-l*r)/s;if(!(c>1e-9))return 1/0;const h=(a*i-l*t)/s;return h<-1e-9||h>1+1e-9?1/0:c};function jd(e,t,i,n=96){if(!(t>0&&Number.isFinite(e[0])&&Number.isFinite(e[1])))return[];const r=[];for(const n of i){if(!n||n.length<4)continue;if(![n[0],n[1],n[2],n[3]].every(Number.isFinite))continue;const i=Ld(e,n);if(i<1e-7)return[];i>t||r.push(n)}const o=[],s=Math.max(12,Math.round(n));for(let e=0;ee-t);const l=[];let c=Number.NEGATIVE_INFINITY;for(const i of o){if(i-c<1e-9)continue;c=i;const n=Math.cos(i),o=Math.sin(i);let s=t;for(const t of r){const i=qd(e,n,o,t);i=3?l:[]}const Bd=[o` + :host { + --hp-bg: var(--card-background-color, #16212e); + --hp-line: var(--divider-color, #2b3d4f); + --hp-txt: var(--primary-text-color, #e6edf3); + --hp-muted: var(--secondary-text-color, #8aa0b3); + --hp-accent: var(--primary-color, #3ea6ff); + --hp-on: #ffd45c; + --hp-open: #ff9f43; + /* design tokens (UI chrome only). The icon/plan scale math stays on + --icon-size/--dev-size cqw units and never uses these. */ + /* spacing scale, fact-based; stray 3/5/7/9/13/14px values are unified + onto the nearest step (max +-2px, the whole point of the pass) */ + --sp-1: 2px; + --sp-2: 4px; + --sp-3: 6px; + --sp-4: 8px; + --sp-5: 12px; + --sp-6: 16px; + /* px radii of dialogs/buttons/plates (the 22% badge radius is scale math) */ + --rad-s: 6px; + --rad-m: 8px; + --rad-l: 12px; + /* font tiers: fine print+labels / body+buttons / title */ + --fs-s: 12px; + --fs-m: 13px; + --fs-l: 15px; + /* elevation: badge / floating panel (menu, tip, toast) / dialog */ + --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.45); + --shadow-2: 0 6px 22px rgba(0, 0, 0, 0.45); + --shadow-3: 0 8px 30px rgba(0, 0, 0, 0.5); + } + ha-card { + overflow: visible; /* overflow:hidden breaks position:sticky on the header */ + } + .empty { + padding: 40px 24px; + color: var(--hp-txt); + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-4); + } + .empty .big { + --mdc-icon-size: 56px; + color: var(--hp-accent); + opacity: 0.7; + } + .empty .muted { + color: var(--hp-muted); + font-size: var(--fs-m); + margin: 0; + } + .empty .btn { + margin-top: var(--sp-4); + } + @keyframes fixedfloor-spin { + to { transform: rotate(360deg); } + } + .spacer { + flex: 1; + } + .bootveil { + position: absolute; + inset: 0; + z-index: 40; + display: flex; + align-items: center; + justify-content: center; + background: var(--hp-bg, #16212e); + opacity: 1; + transition: opacity 0.15s ease; + pointer-events: none; + } + .bootveil.off { + opacity: 0; + } + .bootveil .boothouse { + position: static; /* the main .zoomwrap SVG is pinned to inset:0 — not this icon */ + width: 56px; + height: 56px; + fill: var(--hp-accent); + opacity: 0.85; + animation: hp-boot-pulse 1.3s ease-in-out infinite; + } + @keyframes hp-boot-pulse { + 0%, 100% { opacity: 0.3; transform: scale(0.94); } + 50% { opacity: 0.9; transform: scale(1); } + } + @media (prefers-reduced-motion: reduce) { + .bootveil .boothouse { + animation: none; + opacity: 0.7; + } + } + @keyframes hp-pulse-short { + 0% { transform: scale(1); opacity: 0.55; } + 70% { opacity: 0.22; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + /* Alternate identity: a rapid retrigger restarts the browser timeline. */ + @keyframes hp-pulse-short-b { + 0% { transform: scale(1); opacity: 0.55; } + 70% { opacity: 0.22; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + @keyframes hp-pulse-continuous { + 0% { transform: scale(1); opacity: 0.55; } + 65% { opacity: 0.18; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + @keyframes hp-pulse-alarm { + 0% { transform: scale(1); opacity: 0.72; } + 100% { transform: scale(1.5); opacity: 0; } + } + /* Space changes keep their direction, but travel only a few percent: the + motion explains what changed without making the whole plan fly around. */ + @keyframes hp-slide-left { + 0% { transform: translateX(4%); opacity: 0.72; } + 100% { transform: translateX(0); opacity: 1; } + } + @keyframes hp-slide-right { + 0% { transform: translateX(-4%); opacity: 0.72; } + 100% { transform: translateX(0); opacity: 1; } + } + @keyframes hp-sunfade-in { + from { opacity: 0; } + to { opacity: 1; } + } + @keyframes hp-sunfade-out { + from { opacity: 1; } + to { opacity: 0; } + } + .sr-only { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; + } + .toast { + position: fixed; + pointer-events: none; + left: 50%; + bottom: 22px; + transform: translateX(-50%); + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + color: var(--hp-txt); + padding: var(--sp-4) var(--sp-6); + border-radius: var(--rad-l); + font-size: var(--fs-m); + box-shadow: var(--shadow-2); + z-index: 120; + max-width: 90vw; + } +`,o` + .fixedfloor-loading { + animation: fixedfloor-spin 1.1s linear infinite; + } + .fixedfloor-error p { + max-width: 42rem; + margin: 0; + overflow-wrap: anywhere; + } + @media (prefers-reduced-motion: reduce) { + .fixedfloor-loading { animation: none; } + } + .stage.noplan { + background: #ffffff; + } + /* Editors always keep the white drawing sheet — even when a backdrop + image is loaded. Without this, a picture plan painted the theme card + colour under the grid (owner 2026-08-05). View keeps the historical + theme / .noplan split. */ + .stage.mode-plan, + .stage.mode-devices, + .stage.mode-decor { + background: #ffffff; + } + .stage { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + touch-action: none; /* custom pinch/pan gestures */ + background: var(--ha-card-background, var(--card-background-color, #111)); + } + .zoomwrap { + position: absolute; + inset: 0; + z-index: 1; + } + .stage.mode-transition, + .stage.mode-transition .zoomwrap { + transition: none !important; + } + .stage.mode-transition .hp-view-only-layer, + .stage.mode-transition .hp-editor-only-layer { + pointer-events: none; + will-change: opacity; + } + .stage.mode-transition .hp-paper { + fill: var(--hp-mode-paper) !important; + } + /* Four-phase environment (#146): constant layers cross-fade because CSS + gradients themselves are not reliably interpolated. Everything stays + behind the plan; the plan tree is never dimmed, tinted or faded. */ + .hp-day-cycle-env { + position: absolute; + inset: 0; + z-index: 0; + overflow: hidden; + pointer-events: none; + isolation: isolate; + } + .hp-day-cycle-bg { + position: absolute; + inset: 0; + opacity: 0; + overflow: hidden; + transition: opacity 1100ms cubic-bezier(.22, .61, .36, 1); + } + .hp-day-cycle-bg.active { opacity: 1; } + .hp-day-cycle-sun { + position: absolute; + left: var(--hp-day-cycle-sun-x); + top: var(--hp-day-cycle-sun-y); + width: clamp(140px, 25cqw, 250px); + height: clamp(140px, 25cqw, 250px); + transform: translate(-50%, -50%); + border-radius: 50%; + filter: blur(10px); + opacity: var(--hp-day-cycle-sun-opacity); + transition: + left 1100ms cubic-bezier(.22, .61, .36, 1), + top 1100ms cubic-bezier(.22, .61, .36, 1), + opacity 1100ms cubic-bezier(.22, .61, .36, 1); + } + .stage.mode-transition .hp-day-cycle-env { transition: none; } + .stage.daycycle .hp-paperg, + .hp-static-stage.daycycle .hp-paperg { + filter: + drop-shadow(0 0 1px var(--hp-day-cycle-outline-near)) + drop-shadow(0 0 5px var(--hp-day-cycle-outline-mid)) + drop-shadow(0 0 10px var(--hp-day-cycle-outline-far)); + transition: filter 1100ms cubic-bezier(.22, .61, .36, 1); + } + @media (prefers-reduced-motion: reduce) { + .hp-day-cycle-bg, + .hp-day-cycle-sun, + .stage.daycycle .hp-paperg, + .hp-static-stage.daycycle .hp-paperg { + transition: none; + } + } + .sunlayer { + pointer-events: none; + } + .compass { + width: 120px; + height: 120px; + flex: none; + touch-action: none; + cursor: grab; + user-select: none; + } + .compass:active { + cursor: grabbing; + } + .compass .cring { + fill: rgba(255, 255, 255, 0.04); + stroke: var(--divider-color, #444); + stroke-width: 2; + } + .compass .ctick { + stroke: var(--secondary-text-color, #9aa4ad); + stroke-width: 2; + } + .compass .ctick.minor { + stroke-width: 1; + opacity: 0.6; + } + .compass .cneedle line { + stroke: var(--primary-color, #3ea6ff); + stroke-width: 2.5; + stroke-linecap: round; + } + .compass .cneedle path { + fill: var(--primary-color, #3ea6ff); + } + .compass .cneedle text { + fill: var(--text-primary-color, #fff); + font-size: 11px; + font-weight: 700; + } + .compass .cdeg { + fill: var(--secondary-text-color, #9aa4ad); + font-size: 13px; + } + .compass.unset .cneedle { + opacity: 0.35; + } + /* HP-1552: first-open boot veil — the plan hides until the stage height settles */ + .stage.hpboot .zoomwrap, + .stage.hpboot .zoombadge { + visibility: hidden; + } + /* AUD-1552-02: post-veil grace — HA chrome landing after the cap moves + the stage height smoothly; the viewport ResizeObserver refits the plan + along the transition, so a late panel glides instead of jumping. */ + .stage.hpsettle { + transition: height 0.25s ease; + } + @media (prefers-reduced-motion: reduce) { + .stage.hpsettle { + transition: none; + } + } + .zoomctl { + display: inline-flex; + gap: var(--sp-1); + background: rgba(127, 127, 127, 0.12); + border-radius: var(--rad-m); + padding: var(--sp-1); + } + .zoomctl .zb { + border: none; + padding: var(--sp-3) var(--sp-4); + } + .zoomctl .zb[disabled] { + opacity: 0.4; + pointer-events: none; + } + .projection-toggle { + min-width: 44px; + min-height: 44px; + justify-content: center; + padding: var(--sp-3); + } + /* docs/CANVAS.md §5: the plane has no edges, so you can pan until nothing + is on screen. One pointer home, one click back. */ + .homearrow { + position: absolute; + z-index: 12; + transform: translate(-50%, -50%); + width: 40px; + height: 40px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + background: var(--card-background-color, var(--hp-bg)); + color: var(--hp-accent); + border: 1px solid var(--hp-accent); + opacity: 0.9; + padding: 0; + } + .homearrow ha-icon { + --mdc-icon-size: 22px; + line-height: 1; + } + .zoombadge { + position: absolute; + z-index: 12; + left: var(--sp-4); + bottom: var(--sp-4); + background: var(--card-background-color, var(--hp-bg)); + opacity: 0.92; + color: var(--hp-txt); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-m); + padding: var(--sp-1) var(--sp-4); + font-size: var(--fs-s); + font-weight: 600; + pointer-events: none; + } + /* Only the plan canvas owns the whole zoom wrapper. Context trays now live + inside .stage as well, and may contain small SVG previews (furniture in + particular); the old descendant-wide stage-SVG selector stretched every + preview over the tray and stacked them into one blocking artefact. The + vacuum trail/fit overlays have their own explicit geometry below. */ + .zoomwrap > svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + } + .plan-svg { z-index: 1; } + .iso-underlay-svg { z-index: 0; overflow: visible; } + .iso-shadows-svg { z-index: 3; overflow: visible; } + .iso-walls-svg { + z-index: 4; + overflow: visible; + } + .iso-underlay-svg, + .iso-shadows-svg, + .iso-walls-svg, + .iso-underlay, + .iso-shadows, + .iso-walls, + .iso-openings { + pointer-events: none; + } + .iso-side-hi { stop-color: #b9bdbe; } + .iso-side-lo { stop-color: #969c9f; } + .iso-top-hi { stop-color: #fafaf7; } + .iso-top-lo { stop-color: #e2e4e2; } + .iso-wall-side { + fill: url(#hp-iso-wall-side) #a8acae; + stroke: #92989b; + stroke-width: 0.7; + vector-effect: non-scaling-stroke; + } + .iso-wall-top { + fill: url(#hp-iso-wall-top) #f3f3f1; + stroke: #d7d9d8; + stroke-width: 0.8; + vector-effect: non-scaling-stroke; + } + .iso-floor-side { + fill: #858b8d; + stroke: #71787b; + stroke-width: 0.7; + vector-effect: non-scaling-stroke; + } + .iso-opening-panel { + fill: #d7d9d7; + fill-opacity: 0.96; + stroke: #7f878b; + stroke-width: 0.9; + vector-effect: non-scaling-stroke; + } + .iso-opening-panel.iso-window { + fill: #dfeff4; + fill-opacity: 0.72; + stroke: #8aa7b1; + } + .iso-ambient-shadow { + fill: rgba(15, 21, 25, 0.22); + filter: url(#hp-iso-ambient-shadow); + } + .iso-contact-shadow { + fill: none; + stroke: rgba(22, 28, 31, 0.25); + stroke-width: 3; + filter: url(#hp-iso-contact-shadow); + vector-effect: non-scaling-stroke; + } + .iso-leaf-shadow { + fill: none; + stroke: rgba(18, 23, 27, 0.24); + stroke-width: 4; + filter: url(#hp-iso-leaf-shadow); + vector-effect: non-scaling-stroke; + } + @media (prefers-color-scheme: dark) { + .iso-side-hi { stop-color: #4c555a; } + .iso-side-lo { stop-color: #343c40; } + .iso-top-hi { stop-color: #687176; } + .iso-top-lo { stop-color: #50585d; } + .iso-wall-side { stroke: #30373b; } + .iso-wall-top { stroke: #7b858a; } + .iso-floor-side { fill: #2d3438; stroke: #20272a; } + .iso-opening-panel { fill: #626b70; stroke: #899399; } + .iso-opening-panel.iso-window { fill: #75919b; stroke: #abc6ce; } + .iso-ambient-shadow { fill: rgba(0, 0, 0, 0.34); } + .iso-contact-shadow, .iso-leaf-shadow { stroke: rgba(0, 0, 0, 0.38); } + } + @media (forced-colors: active) { + .iso-wall-side, .iso-wall-top, .iso-floor-side, .iso-opening-panel { + fill: Canvas; + stroke: CanvasText; + forced-color-adjust: auto; + } + .iso-ambient-shadow, .iso-contact-shadow, .iso-leaf-shadow { display: none; } + } + @supports not (filter: blur(1px)) { + .iso-ambient-shadow, .iso-contact-shadow, .iso-leaf-shadow { display: none; } + } + /* Opaque plan paper (owner 2026-08-03): the scene bg_color / daynight sky + shows ONLY around the plan, never through it. The colour is the + pre-bg_color canvas — the theme card background under an image plan, + plain white for a hand-drawn one (.stage.noplan). On drawn plans the + paper is per-room shapes following the room contours — fill only, + never a stroke, so the paper cannot poke past a wall. Night dimming + comes from the .zoomwrap brightness filter, never from alpha + (docs/SUN.md). */ + .hp-paper { + fill: var(--ha-card-background, var(--card-background-color, #111)); + stroke: none; + } + .stage.noplan .hp-paper, + .stage.mode-plan .hp-paper, + .stage.mode-devices .hp-paper, + .stage.mode-decor .hp-paper { + fill: #ffffff; + } + /* Owner 2026-08-04: «углы границ комнат всё ещё с зубцами». A miter join + on a 30-45° corner shoots a spike far past the wall (and flips to an + ugly bevel once past the miter limit) — the same defect the decor lines + had before they got round caps. Every room border, in EVERY renderer + that reuses these styles (plan view, plan editor, static space-card), + joins its walls with a ROUND join instead: the corner reads as the + stroke's own radius, never as a tooth. The linecap matters only for the + open outlines below, but it costs nothing to state it here. */ + .room { + transition: 0.12s; + cursor: default; /* v1.40.1: rooms are not clickable — the label's link icon is */ + stroke-linejoin: round; + stroke-linecap: round; + } + .room.overlay { + fill: transparent; + stroke: transparent; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + :host([data-pointer-hover]) .stage.mode-view .room.overlay:not(.styled):hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + .room.yard { + fill: rgba(75, 140, 90, 0.14); + stroke: #4b8c5a; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + :host([data-pointer-hover]) .stage.mode-view .room.yard:not(.styled):hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + .room.styled { + stroke: var(--room-stroke, transparent); + stroke-opacity: var(--room-stroke-op, 0); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + fill: var(--room-fill, transparent); + fill-opacity: var(--room-fill-op, 0); + } + .glow-base-layer, + .glow-base-tunnels, + .glow-pools-frame, + .glow-pools, + .glow-spot { + pointer-events: none; + } + /* The parent isolates all source spots from the room data fill, Glow base, + paper and backdrop. A spot is one circle clipped to the floor its lamp + can see, so the whole spot screen-blends as a single primitive — there is + no mask left to be dropped on a promoted layer. Per-stop alpha already + contains the shared 0.7 ceiling; the spot opacity below only animates + between 0 and 1 and is never another persistent alpha ceiling. */ + .glow-pools-frame, + .glow-pools, + .glow-spot { + isolation: isolate; + } + .glow-pools.blend-screen .glow-spot { + mix-blend-mode: screen; + } + .glow-spot { + opacity: 1; + transition: opacity 500ms ease; + } + .glow-spot.is-entering, + .glow-spot.is-leaving { + opacity: 0; + } + @media (prefers-reduced-motion: reduce) { + .glow-spot { + transition: none; + } + } + /* The explicit late room-hover layer owns the wash and halo. Keeping CSS + filters off room paths prevents Chromium from recompositing the sibling + screen-blended Glow layer for one bright frame on every hover. */ + :host([data-pointer-hover]) .stage.mode-view .room.styled:hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + /* doors, windows & gates */ + .op-leaf { + transition: transform 0.6s ease; + } + .op-arc { + stroke-width: calc(1.5px * var(--hp-cell-visual-scale, 1)); + transition: stroke-dashoffset 0.6s ease; + } + /* hover affordance: a rounded outline hugging the wall strip + a grab cursor */ + .op-outline { + fill: none; + stroke: var(--hp-accent); + stroke-width: calc(1.5px * var(--hp-cell-visual-scale, 1)); + opacity: 0; + transition: opacity 0.15s; + pointer-events: none; + } + :host([data-pointer-hover]) .stage.markup g.opening:hover .op-outline { + opacity: 0.9; + } + /* openings are pure status graphics outside Plan mode: no cursor, no hover, + no hit target — View must not interact with them at all */ + .op-hit { + fill: transparent; + pointer-events: none; + cursor: default; + } + .stage.markup .op-hit { + pointer-events: auto; + cursor: grab; + touch-action: none; /* drags, not scrolls, on touch */ + } + .stage.markup .op-hit:active { + cursor: grabbing; + } + .stage.markup .opening.orphan { + pointer-events: auto; + cursor: pointer; + color: var(--error-color, #db4437); + } + .stage.markup .opening.orphan circle { + fill: var(--hp-bg); + stroke: currentColor; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + .stage.markup .opening.orphan text { + fill: currentColor; + font-weight: 800; + font-size: calc(12px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + /* HP-1550-04: in the resize tool the wall handles own the hit test — the + transparent .op-hit of a door at the midpoint of a wall used to sit ON + TOP of the handle and made that wall ungrabbable for both rooms. + Openings are not editable in this tool (they ride along with the wall), + so their hit area goes fully inert; every other Plan tool is untouched. */ + .stage.markup.tool-resize .op-hit { + pointer-events: none; + cursor: default; + } + .stage.mode-view .oplock { + pointer-events: auto; + cursor: pointer; + } + @media (prefers-reduced-motion: reduce) { + .op-leaf, .op-arc { transition: none; } + } + .roomlabel { + pointer-events: none; /* draggable only in plan mode (rule below) */ + position: absolute; + transform: translate(-50%, -50%); + font-size: calc(var(--rl-icon-size, var(--icon-size, 2.5cqw)) * 0.5 * var(--rl-scale, 1) * var(--rl-font, 1) * var(--rl-space, 1)); + font-weight: 700; + letter-spacing: 0.04em; + white-space: nowrap; + cursor: grab; + user-select: none; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.15em; + text-align: center; + } + .rlname { + display: inline-flex; + align-items: center; + gap: 0.25em; + font-size: calc(1em * var(--rl-name, 1)); + } + .zoomwrap.slide-left { animation: hp-slide-left 0.18s cubic-bezier(0.2, 0.7, 0.2, 1); } + .zoomwrap.slide-right { animation: hp-slide-right 0.18s cubic-bezier(0.2, 0.7, 0.2, 1); } + @media (prefers-reduced-motion: reduce) { + .zoomwrap.slide-left, + .zoomwrap.slide-right { animation: none; } + } + /* The name is the anchor: the label box is centred on the room point, so + anything that takes part in its layout SHIFTS THE NAME. The gear button + and the metrics hang below as absolutes — the name renders in exactly + the same place in view mode and in the plan editor (owner's request), + and the button sits at the very bottom of the card. */ + /* Standalone, centred on the room, sized from the device icon: icon-size + already rescales with the view, so the button zooms WITH the plan + instead of keeping a constant screen size (owner's spec). */ + .rlgearbtn { + --gear-h: calc(var(--icon-size, 2.5cqw) * 0.77); /* owner: half the previous size */ + position: absolute; + /* dead-centred on the room, both axes (owner's spec) */ + transform: translate(-50%, -50%); + display: inline-flex; + align-items: center; + gap: 0.35em; + height: var(--gear-h); + padding: 0 calc(var(--gear-h) * 0.38); + border: 0; + border-radius: 999px; + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + font: inherit; + font-size: calc(var(--gear-h) * 0.42); + font-weight: 600; + line-height: 1; + white-space: nowrap; + cursor: pointer; + pointer-events: auto; + opacity: 0.92; + box-shadow: var(--shadow-1); + z-index: 2; + } + .rlgearbtn { transition: opacity 0.15s, filter 0.15s; } + :host([data-pointer-hover]) .rlgearbtn:hover { opacity: 1; filter: brightness(1.18); } + .rlgearbtn ha-icon { --mdc-icon-size: calc(var(--gear-h) * 0.55); display: inline-flex; } + .rlgear { + --mdc-icon-size: 0.9em; + display: inline-flex; + margin-right: 0.2em; + opacity: 0.6; + cursor: pointer; + pointer-events: auto; + } + :host([data-pointer-hover]) .rlgear:hover { opacity: 1; } + .rlgo { + --mdc-icon-size: 0.85em; + display: inline-flex; + opacity: 0.55; + } + .stage.mode-view .rlgo { + pointer-events: auto; + cursor: pointer; + } + :host([data-pointer-hover]) .stage.mode-view .rlgo:hover { opacity: 1; } + .roomlabel .rlmetrics { + position: absolute; /* below the name, outside the centring math */ + top: calc(100% + 0.15em); + left: 50%; + transform: translateX(-50%); + white-space: nowrap; + display: flex; + align-items: center; + gap: 0.55em; + font-size: calc(0.75em * var(--rl-meta, 1)); /* feedback: 0.62 was unreadable on a tablet */ + font-weight: 600; + letter-spacing: 0.02em; + opacity: 0.9; + } + .roomlabel .rlm { + display: inline-flex; + align-items: center; + gap: 0.12em; + } + .roomlabel .rlm ha-icon { + --mdc-icon-size: 1.05em; + display: inline-flex; + } + .roomlabel .rlm.lit { opacity: 1; } + .rlhandle { + display: none; + position: absolute; + width: 9px; + height: 9px; + border-radius: 2px; + background: var(--hp-accent); + border: 1px solid var(--card-background-color, #fff); + z-index: 2; + } + .rlhandle.tl { left: -6px; top: -6px; cursor: nwse-resize; } + .rlhandle.br { right: -6px; bottom: -6px; cursor: nwse-resize; } + .rlhandle.tr { right: -6px; top: -6px; cursor: nesw-resize; } + .rlhandle.bl { left: -6px; bottom: -6px; cursor: nesw-resize; } + :host([data-pointer-hover]) .stage.markup .roomlabel:hover .rlhandle { display: block; } + .stage.markup .roomlabel { pointer-events: auto; } + .roomlabel:active { cursor: grabbing; } + .measurelayer { + position: absolute; + inset: 0; + pointer-events: none; + } + .alignline { + stroke: var(--hp-accent); + stroke-width: calc(1.2px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(4px * var(--hp-cell-visual-scale, 1)) + calc(4px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + opacity: 0.9; + } + .aligndot { + fill: var(--hp-accent); + pointer-events: none; + } + .measurelabel.on45 { + color: #4bd28f; + border-color: #4bd28f; + } + .measurelabel { + position: absolute; + transform: translate(12px, -150%); + font-size: var(--fs-s); + font-weight: 600; + padding: 1px var(--sp-3); + border-radius: var(--rad-s); + background: rgba(0, 0, 0, 0.72); + color: #fff; + white-space: nowrap; + pointer-events: none; + user-select: none; + z-index: 3; + } + .measurelabel.opdimension { + transform: translate( + calc(-50% + var(--op-label-shift-x, 0px)), + calc(-50% + var(--op-label-shift-y, -12px)) + ); + border: 1px solid var(--hp-open, #ff9800); + } + /* decor (background) layer */ + .decorlayer .dshape { pointer-events: none; } + .stage.mode-decor .decorlayer .dshape { + pointer-events: visiblePainted; + cursor: pointer; + } + .stage.mode-decor.dtool-select .decorlayer .dshape { cursor: move; } + /* …but a DRAWING tool owns the canvas: existing shapes stop being targets + entirely, so a new line can start exactly on the end of an old one + instead of grabbing it (owner, 2026-08-04). Same for the picture tool — + a shape lying over the plan must not block the picture's own drag. + Only select (move) and erase (delete) keep the shapes clickable. */ + .stage.mode-decor.dtool-line .decorlayer .dshape, + .stage.mode-decor.dtool-rect .decorlayer .dshape, + .stage.mode-decor.dtool-ellipse .decorlayer .dshape, + .stage.mode-decor.dtool-text .decorlayer .dshape, + .stage.mode-decor.dtool-furniture .decorlayer .dshape, + .stage.mode-decor.dtool-backdrop .decorlayer .dshape { pointer-events: none; } + /* the furniture tool is a stamp: the press must reach the stage even when + it lands on a sofa that is already there (docs/FURNITURE.md §4) */ + .stage.mode-decor.dtool-furniture { cursor: copy; } + /* ONE exception (owner, 2026-08-04): under the TEXT tool an existing LABEL + is a target again — pressing it opens its editor instead of starting a + new label on top of the old one. Only labels: a line or a rectangle + under the text tool stays inert, so the press reaches the stage and a + new label is created there. */ + .stage.mode-decor.dtool-text .decorlayer .dshape.dtext, + .stage.mode-decor.dtool-select .decorlayer .dshape.dtext, + .stage.mode-decor.dtool-erase .decorlayer .dshape.dtext { + /* A label is one logical decor object. SVG's visiblePainted would hit + only the ink of individual glyphs, so spaces, counters and the area + inside its selection glow behaved like empty canvas. */ + pointer-events: visiblePainted; + pointer-events: bounding-box; + } + .stage.mode-decor.dtool-text .decorlayer .dshape.dtext { + cursor: text; + } + /* Erasing a hairline must not require pixel-perfect aim. The duplicate + geometry is invisible and exists only while Erase is active. A + non-scaling stroke keeps the target comfortably wide at every zoom. */ + .decorlayer .derasehit { + fill: none; + stroke: transparent; + stroke-width: 16px; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .stage.mode-decor.dtool-erase .decorlayer .derasehit { + pointer-events: stroke; + } + /* A dashed line must remain selectable across its gaps. This proxy also + makes the only entry to line-style properties — double click in Select — + practical for hairlines at every zoom. */ + .decorlayer .dselecthit { + fill: none; + stroke: transparent; + stroke-width: 16px; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .stage.mode-decor.dtool-select .decorlayer .dselecthit { + pointer-events: stroke; + cursor: move; + } + .decorlayer .dsel { + filter: drop-shadow(0 0 3px var(--hp-accent)); + } + .decorlayer .ddraft { + stroke-dasharray: + calc(6px * var(--hp-cell-visual-scale, 1)) + calc(5px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .decorlayer text { + font-weight: 600; + user-select: none; + dominant-baseline: middle; + text-anchor: middle; + } + .stage.mode-decor { + outline: 2px solid #26a69a; + outline-offset: -2px; + } + /* backdrop transform frame (docs/BACKDROP.md §2). Editor chrome: the + outline never takes a pointer, the four corner handles do — and they are + finger-sized (r = 2 % of the visible view), because this is dragged on a + tablet as often as with a mouse. */ + .bdframe .bdbox { + fill: none; + stroke: var(--hp-accent); + stroke-width: 2; + stroke-dasharray: 10 7; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.9; + } + /* the HIT circle: invisible, finger-sized, the only thing that takes a + pointer. The visible bead is .bdknob, a quarter of its radius — the same + visual/hit split .dthandle + .dtknob and .rszhandle + .rszicon use. */ + .bdframe .bdhandle { + fill: transparent; + stroke: none; + pointer-events: all; + touch-action: none; + } + .bdframe .bdknob { + fill: var(--hp-accent); + stroke: #fff; + stroke-width: 1; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + :host([data-pointer-hover]) .bdframe .bdhandle:hover + .bdknob { + fill: #fff; + stroke: var(--hp-accent); + } + .bdframe .bd-nwse { cursor: nwse-resize; } + .bdframe .bd-nesw { cursor: nesw-resize; } + /* the picture itself is the drag target for a move (grab, then grabbing) */ + .stage.mode-decor.bdgrab { cursor: grab; } + .stage.mode-decor.bdgrabbing, + .stage.mode-decor.bdgrabbing .bdframe .bdhandle { cursor: grabbing; } + .measurelabel.bdmeasure { + transform: translate(-50%, -50%); + border: 1px solid var(--hp-accent); + } + /* the selected decor object's frame — same chrome rules as the backdrop's: + the outline never takes a pointer, the handles always do, and they are + finger-sized because this is dragged on a tablet too */ + .dtframe .dtbox { + fill: none; + stroke: var(--hp-accent); + stroke-width: 1.5; + stroke-dasharray: 7 5; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.85; + } + .dtframe .dtstem, + .bdframe .dtstem { + stroke: var(--hp-accent); + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.85; + } + /* the HIT circle: invisible, finger-sized, the only thing that takes a + pointer. The visible bead is .dtknob, a quarter of its radius — the + same visual/hit split .rszhandle + .rszicon use. */ + .dtframe .dthandle { + fill: transparent; + stroke: none; + pointer-events: all; + touch-action: none; + } + .dtframe .dtknob { + fill: var(--hp-accent); + stroke: #fff; + stroke-width: 1; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + :host([data-pointer-hover]) .dtframe .dthandle:hover + .dtknob { + fill: #fff; + stroke: var(--hp-accent); + } + .dtframe .dt-nwse { cursor: nwse-resize; } + .dtframe .dt-nesw { cursor: nesw-resize; } + .dtframe .dtrot { cursor: grab; } + .dtframe .dtendpoint { cursor: crosshair; } + .bdframe .dtrot { cursor: grab; } + .dtarea { + resize: vertical; + min-height: 3.4em; + font: inherit; + line-height: 1.35; + } + .stage.mode-decor.dtool-line, .stage.mode-decor.dtool-rect, + .stage.mode-decor.dtool-ellipse, .stage.mode-decor.dtool-text { + cursor: crosshair; + } + .stage.mode-decor.dtool-erase, + .stage.mode-decor.dtool-erase .decorlayer .dshape { + cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Crect x='7' y='2' width='10' height='18' rx='2' fill='%23fff' stroke='%23111' stroke-width='1.5'/%3E%3Cpath d='M7 13h10v5a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2z' fill='%23ff9f43' stroke='%23111' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E") 5 22, pointer; + } + .stage.mode-decor .room, .stage.mode-decor .devlayer { pointer-events: none; } + .stage.mode-decor .oplock { pointer-events: none; } + /* Backdrop-editor de-emphasis is a shared mode-transition coordinate. + It multiplies whole presentation groups and never changes Glow source + alpha, additive blending, or the underlying resolved state. */ + .stage .room, + .stage .devlayer, + .stage .opening, + .stage .room-outline, + .stage .wallbodies, + .stage .opening-tunnels, + .stage .glow-base-layer, + .stage .glow-pools-frame, + .stage .zero-walls { + opacity: var(--hp-mode-architecture-opacity, 1); + } + .opening-preview { + opacity: 0.5; + pointer-events: none; + } + .opening-preview[data-kind="passage"] { + opacity: 1; + } + .passage-preview-cut { + fill: var(--wall-fill, #ffffff); + fill-opacity: 0.35; + stroke: none; + pointer-events: none; + } + .passage-preview-boundary { + stroke: var(--hp-open, #ff9800); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .opening-preview .op-leaf, + .opening-preview .op-arc { + transition: none; + } + .opening-preview-dot { + fill: var(--hp-open, #ff9800); + pointer-events: none; + } + .opening-dimensions, + .opening-dimension { + pointer-events: none; + } + .opening-dimension-line, + .opening-dimension-tick { + fill: none; + stroke: var(--hp-open, #ff9800); + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .opening-dimension-tick { + stroke-width: 2; + } + .stage.edit .room { + pointer-events: none; + } + .stage.markup { + cursor: crosshair; + } + /* room-picking stages: merge (both clicks) and split before a room is chosen */ + .stage.markup.tool-merge, + .stage.markup.tool-split.pickstage, + .stage.markup.tool-delroom { + cursor: pointer; + } + .stage.markup.tool-wallthick { cursor: default; } + .stage.markup.tool-wallthick.wallhot { cursor: pointer; } + /* Solid wall colour sits under the hatch (owner: both, not either/or). */ + .wallbody-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: var(--wall-fill-op, 1); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .wallbody { + fill: url(#hp-wall-hatch); + fill-rule: evenodd; + stroke: var(--room-stroke, var(--hp-muted)); + stroke-width: calc(0.6px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + /* Thin-on-screen: hatch collapses into noise — fill alone, stroke from fill path's sibling. */ + .wallbody.solid { + fill: none; + } + .wallthick-hover { + fill: var(--accent-color, #03a9f4); + fill-opacity: 0.38; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .wallthick-hover.isopen { + fill: var(--error-color, #f44336); + stroke: var(--error-color, #f44336); + } + .zero-wall { + stroke: var(--zero-wall-stroke, var(--hp-muted)); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(7px * var(--hp-cell-visual-scale, 1)) + calc(7px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: butt; + pointer-events: none; + opacity: 0.9; + } + .zero-walls.solid .zero-wall { + stroke-dasharray: none; + } + /* Rooms with zero/thick stretches: the polygon's own stroke is fully off. + The trimmed .room-outline draws normal walls; View hover gets its own + top overlay after the wall bodies. */ + .room.noedge { + stroke-opacity: 0 !important; + } + /* rooms with open boundaries draw their walls as separate M..L subpaths, + so a corner between two of them is two stroke ENDS meeting: round caps + fill it in the same way a round join fills a closed contour's corner + (owner 2026-08-04 — no teeth anywhere on a room border). */ + .room-outline { + fill: none; + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + /* Plan editor: trimmed outlines use the markup blue */ + .room-outline.outlined { + stroke: rgba(62, 166, 255, 0.55); + stroke-opacity: 1; + } + /* The wash is rendered directly above the resolved room fill but below + tunnels, Glow, sun and walls. Black at 22% reproduces the old + brightness(.78) contract without filtering/promoting an SVG ancestor or + changing the room's hue. The halo/outline are rendered again late, above + the wall bodies. */ + .room-hover-fill { + fill: #000; + fill-opacity: 0.22; + pointer-events: none; + } + .room-hover-halo { + fill: none; + stroke: var(--hp-accent); + stroke-opacity: 0.28; + stroke-width: calc(8px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .room-hover-outline { + fill: none; + stroke: var(--hp-accent); + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .stage.markup .room { + pointer-events: none; + } + .stage.markup .devlayer .dev { + display: none; /* in plan mode the icons do not get in the way; labels stay */ + } + /* mode frames: the edit modes are visible at a glance */ + .stage.mode-plan { + outline: 2px solid #ffc14d; + outline-offset: -2px; + } + .stage.mode-devices { + outline: 2px solid var(--hp-accent); + outline-offset: -2px; + } + .room.outlined { + stroke: rgba(62, 166, 255, 0.55); + fill: rgba(62, 166, 255, 0.06); + } + /* AFTER .outlined: same specificity — source order decides (gotcha x4) */ + .room.picked { + stroke: #ffc14d; + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + fill: rgba(255, 193, 77, 0.25); + } + /* Owner 2026-08-04: the grid is a HINT, not content — at full strength the + dots argued with the plan on white paper. Both levels are muted, the + hierarchy is kept (major still denser than fine). */ + .griddot { + fill: var(--hp-accent); + opacity: 0.35; + stroke: rgba(0, 0, 0, 0.35); + stroke-width: 0.4; + } + /* docs/CANVAS.md §7: every coarse node (5x/10x the live step) keeps a + bigger, more opaque dot, so zoomed far out the grid still reads as a + grid instead of a grey wash. */ + .griddot.major { + opacity: 0.5; + stroke-width: 0; + } + /* the contour being drawn in the Plan editor: each wall is its own , + so the round cap IS the corner (matches the finished .room border) */ + .seg { + stroke: var(--hp-accent); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: round; + stroke-linejoin: round; + } + .pathline { + stroke: #ffc14d; + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + } + .preview { + stroke: #ffc14d; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(6px * var(--hp-cell-visual-scale, 1)) + calc(5px * var(--hp-cell-visual-scale, 1)); + opacity: 0.7; + } + .active-axis { + stroke: #ffc14d; + stroke-width: 2; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .active-vertex { + fill: #ffc14d; + stroke: #171006; + stroke-width: 2; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .wall-repair-preview { + stroke: #d93025; + stroke-width: 4; + stroke-linecap: round; + stroke-dasharray: 5 4; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .drawwall-preview-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: calc(var(--wall-fill-op, 1) * 0.55); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .drawwall-preview { + fill: url(#hp-wall-hatch); + fill-opacity: 0.55; + fill-rule: evenodd; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(0.5px * var(--hp-cell-visual-scale, 1)); + stroke-opacity: 0.7; + pointer-events: none; + } + .drawwall-zero-preview { + fill: none; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: butt; + stroke-linejoin: round; + opacity: 0.72; + pointer-events: none; + } + .drawwall-zero-preview.dashed { + stroke-dasharray: + calc(7px * var(--hp-cell-visual-scale, 1)) + calc(7px * var(--hp-cell-visual-scale, 1)); + } + .vertex { + fill: #ffc14d; + stroke: #4a2800; + stroke-width: calc(1px * var(--hp-cell-visual-scale, 1)); + } + .vertex.first { + fill: #4bd28f; + stroke: #04121f; + } + .plan-snap-overlay, + .plan-snap-overlay *, + .hidden-wall-diagnostic, + .hidden-wall-diagnostic * { + pointer-events: none; + } + .plan-snap-line, + .hidden-wall-line { + fill: none; + stroke: color-mix(in srgb, var(--hp-accent) 82%, white 18%); + /* Explicit non-scaling-stroke in the SVG keeps this one screen pixel. */ + stroke-width: 1; + stroke-linecap: round; + opacity: 0.92; + } + .plan-snap-node, + .hidden-wall-node { + fill: var(--ha-card-background, var(--card-background-color, #fff)); + stroke: color-mix(in srgb, var(--hp-accent) 88%, #07131c 12%); + stroke-width: 1; + vector-effect: non-scaling-stroke; + } + .plan-snap-node.active { + fill: #ffc14d; + stroke: #171006; + stroke-width: 2; + } + .plan-snap-node.active.dynamic { + fill: #4bd28f; + stroke: #04121f; + } + .plan-snap-node.conflict { + fill: #fff; + stroke: #d93025; + stroke-width: 3; + } + @media (prefers-color-scheme: dark) { + .plan-snap-line { + stroke: color-mix(in srgb, var(--hp-accent) 72%, white 28%); + } + .hidden-wall-line { + stroke: color-mix(in srgb, var(--hp-accent) 72%, white 28%); + } + .plan-snap-node, + .hidden-wall-node { + fill: #17242c; + stroke: #9bdcf5; + } + .plan-snap-node.active { + fill: #ffc14d; + stroke: #fff4d6; + } + .plan-snap-node.active.dynamic { + fill: #4bd28f; + stroke: #eafff4; + } + } + @media (forced-colors: active) { + .plan-snap-line, + .hidden-wall-line { + stroke: CanvasText; + opacity: 1; + forced-color-adjust: auto; + } + .plan-snap-node, + .hidden-wall-node { + fill: Canvas; + stroke: CanvasText; + forced-color-adjust: auto; + } + .plan-snap-node.active, + .plan-snap-node.active.dynamic { + fill: Highlight; + stroke: HighlightText; + forced-color-adjust: auto; + } + } + /* RGB lights: the bulb takes the light's actual color */ + /* v1.52.0: the RGB tint of the icon/border is gone — a lamp's colour + lives ONLY in its glow spot (owner's rule). The ripple-color fallback + keeps using the light colour; that is set inline via --ripple-color. */ + /* Sun wedges (docs/SUN.md). The layer is present ONLY above the 3° + threshold; crossing it fades the whole layer in or out over EXACTLY + 2 s (owner 2026-08-03 — RAY_FADE_MS in src/sun.ts must match). The + geometry is untouched: this is a plain opacity animation on the group, + so overlapping wedges keep their own blending while it plays. */ + .sunlayer { + animation: hp-sunfade-in 2s linear both; + } + .sunlayer.out { + animation: hp-sunfade-out 2s linear both; + } + @media (prefers-reduced-motion: reduce) { + /* no fade at all: the rays are simply there or simply gone */ + .sunlayer, .sunlayer.out { animation: none; } + .sunlayer.out { opacity: 0; } + } + .devlayer { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 6; + } + .stage.mode-devices .dev { cursor: grab; } + .stage.mode-devices .dev:active { cursor: grabbing; } + .physical-hit { + fill: transparent; + stroke: transparent; + pointer-events: none; + cursor: grab; + } + .stage.tool-select .physical-hit { pointer-events: all; } + .physical-hit:active { cursor: grabbing; } + line.physical-hit { cursor: pointer; } + .physical-hit.selected { + fill: rgba(255, 193, 77, 0.24); + stroke: transparent; + } + line.physical-hit.selected { + stroke: transparent; + } + .physical-drag { + fill: rgba(255, 193, 77, 0.38); + stroke: #ffc14d; + stroke-width: 2.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .physical-chrome { pointer-events: none; } + .physical-chrome .frame, + .physical-chrome .stem { + fill: none; + stroke: #ffc14d; + stroke-width: 2; + vector-effect: non-scaling-stroke; + } + .physical-chrome .frame { fill: rgba(255, 193, 77, 0.22); } + .physical-chrome polyline.frame { fill: none; } + .physical-chrome .move-dot { + fill: #ffc14d; + stroke: #24262d; + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + } + .physical-chrome .rotate-handle { + fill: #24262d; + stroke: #ffc14d; + stroke-width: 2.5; + vector-effect: non-scaling-stroke; + pointer-events: all; + cursor: crosshair; + } + .drawwall.invalid input { border-color: var(--error-color, #db4437); } + .drawwall .rangehint { margin-inline-start: 4px; font-size: 0.78em; opacity: 0.72; } + .drawwall.invalid .rangehint { color: var(--error-color, #db4437); opacity: 1; } + .stage.markup.tool-partition, + .stage.markup.tool-column { cursor: crosshair; } + /* room resize tool (docs/RESIZE.md) */ + /* wall handle: invisible finger-sized hit circle (HP-1550-04 hit priority + kept), the visible glyph lives in the sibling .rszicon */ + .rszhandle { + fill: transparent; + stroke: none; + pointer-events: all; + cursor: grab; + touch-action: none; + } + .rszhandle:active { cursor: grabbing; } + .rszhandle.disabled, + .rszhandle.disabled:active { + cursor: not-allowed; + } + /* wall-with-arrows glyph: accent ink over a bg halo, readable on any plan */ + .rszicon { pointer-events: none; } + .rszicon path { + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; + } + .rszhalo { stroke: var(--hp-bg); stroke-width: 6; } + .rszink { stroke: var(--hp-accent); stroke-width: 2; } + :host([data-pointer-hover]) .rszhandle:hover + .rszicon .rszink { stroke-width: 3; } + .rszicon.disabled { opacity: 0.38; } + :host([data-pointer-hover]) .rszhandle.disabled:hover + .rszicon .rszink { stroke-width: 2; } + .rszmeasurelayer, + .rszmeasurelayer * { pointer-events: none; } + .rszmeasurehalo, + .rszmeasureink, + .rszleader { + fill: none; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + } + .rszmeasurehalo { + stroke: var(--hp-bg); + stroke-width: 7px; + opacity: 0.9; + } + .rszmeasureink { + stroke: var(--hp-accent); + stroke-width: 3px; + } + .rszleader { + stroke: var(--hp-accent); + stroke-width: 2px; + opacity: 0.95; + } + /* the decor draft badge rides the MIDDLE of the shape, so it is centred + horizontally and lifted clear of the line instead of trailing the + cursor the way a wall badge does (owner 2026-08-04) */ + .measurelabel.dmeasure { + transform: translate(-50%, -160%); + } + .measurelabel.rszarea { + transform: translate( + calc(-50% + var(--rsz-label-x, 0px)), + calc(-50% + var(--rsz-label-y, 0px)) + ); + background: rgba(0, 0, 0, 0.6); + border: 1px solid var(--hp-accent); + } + /* width and depth of a piece of furniture while its corner is dragged — + centred on the edge they measure (docs/FURNITURE.md §6) */ + .measurelabel.furnmeasure { + transform: translate(-50%, -50%); + border: 1px solid var(--hp-accent); + } + .alignmsg { margin: 0 0 8px; font-size: 13px; line-height: 1.45; } +`,o` + /* Unified device activity: alarm, short event and continuous state all + share this one renderer. No static rings are allowed. */ + .dev ha-icon { + position: relative; + z-index: 1; + } + .device-pulse { + position: absolute; + left: 50%; + top: 50%; + width: var(--dev-size); + height: var(--dev-size); + transform: translate(-50%, -50%); + pointer-events: none; + z-index: 0; + } + .device-pulse i { + position: absolute; + inset: 0; + border-radius: 50%; + border: 2px solid var(--ripple-color, var(--hp-accent)); + opacity: 0; + } + /* A witnessed edge: exactly three waves over the 3.3 s runtime window. */ + .device-pulse.short i { + animation: hp-pulse-short 1.1s cubic-bezier(.22,.61,.36,1) 1 forwards; + } + .device-pulse.short i:nth-child(2) { animation-delay: 1.1s; } + .device-pulse.short i:nth-child(3) { animation-delay: 2.2s; } + .device-pulse.short.gen2 i { animation-name: hp-pulse-short-b; } + .device-pulse.continuous i:nth-child(n + 2), + .device-pulse.alarm i:nth-child(n + 3) { display: none; } + .device-pulse.continuous i:first-child { + animation: hp-pulse-continuous 3.6s cubic-bezier(.45,.05,.55,.95) infinite; + } + .device-pulse.alarm i { + border-width: 3px; + border-color: #F0410C; + animation: hp-pulse-alarm 2.4s cubic-bezier(.22,.61,.36,1) infinite; + } + .device-pulse.alarm i:nth-child(2) { animation-delay: 1.2s; } + .activity-dot { + position: absolute; + right: 8%; + bottom: 8%; + width: 18%; + height: 18%; + min-width: 4px; + min-height: 4px; + border-radius: 50%; + background: var(--ripple-color, var(--hp-accent)); + border: 1px solid color-mix(in srgb, var(--hp-bg) 82%, transparent); + pointer-events: none; + z-index: 3; + } + .kioskdots { + position: absolute; + left: 50%; + bottom: var(--sp-5); + transform: translateX(-50%); + display: flex; + gap: var(--sp-4); + z-index: 5; + pointer-events: none; + } + .kdot { + width: 9px; + height: 9px; + border-radius: 50%; + background: var(--hp-muted); + opacity: 0.55; + } + .kdot.on { background: var(--hp-accent); opacity: 1; } + .dev.valonly { + /* Saved coordinates remain the centre of a Text shell. The shell may + expand, while the invisible anchor stays one core diameter wide. */ + width: var(--dev-size, var(--icon-size, 2.5cqw)); + } + .dev.valonly .device-core { + width: max-content; + min-width: var(--dev-size, var(--icon-size, 2.5cqw)); + padding-inline: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.16); + border-radius: calc(var(--dev-size, var(--icon-size, 2.5cqw)) / 2); + } + .dev .valtext { + overflow: visible; + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * var(--value-font-scale, .45)); + font-weight: 600; + white-space: nowrap; + } + @media (prefers-reduced-motion: reduce) { + .device-pulse { display: none; } + } + .dev .newdot { + position: absolute; + top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * -0.12); + right: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * -0.12); + width: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.34); + height: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.34); + border-radius: 50%; + background: #f0301f; + border: 2px solid var(--card-background-color, var(--hp-bg)); + pointer-events: none; + z-index: 2; + } + .dev { + position: absolute; + /* The surface resolves compatibility icon_size units once. The shared + face receives an effective base and only applies the per-device size. */ + --dev-size: calc(var(--device-base-size, 2.25cqw) * var(--dev-scale, 1)); + /* 101.5/80 is the package shell/core ratio, including its stroke. */ + --device-shell-size: calc(var(--dev-size) * 1.26875); + --device-shell-inset: calc(var(--dev-size) * 0.134375); + --device-shell-stroke-ratio: 0.01875; + --device-shell-border-width: max(1px, calc(var(--dev-size) * var(--device-shell-stroke-ratio))); + --device-core-bg: var(--card-background-color, #fff); + --device-core-fg: var(--primary-text-color, #252525); + --device-core-bg: light-dark(#fff, #252525); + --device-core-fg: light-dark(#252525, #fff); + --device-face-bg: var(--device-core-bg); + --device-face-fg: var(--device-core-fg); + --device-shell-base-stroke: light-dark(#BCBCBC, rgb(37 37 37 / 75%)); + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: 0 0 0 0 transparent; + --device-ring-color: transparent; + --device-ring-width: 0px; + /* The saved point is the exact centre of the icon core. */ + width: var(--dev-size); + height: var(--dev-size); + margin: calc(var(--dev-size) / -2) 0 0 calc(var(--dev-size) / -2); + border: 0; + background: transparent; + display: block; + color: var(--device-core-fg); + cursor: pointer; + pointer-events: auto; + transition: opacity 0.2s; + box-shadow: none; + outline: none; + z-index: 2; + } + .dev.theme-light { + --device-core-bg: #fff; + --device-core-fg: #000; + --device-shell-base-stroke: #BCBCBC; + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: 0 0 0 0 transparent; + } + .dev.theme-dark { + --device-core-bg: #252525; + --device-core-fg: #fff; + --device-shell-base-stroke: rgb(37 37 37 / 75%); + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .0375) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: + inset 0 calc(var(--dev-size) * 0.0125) calc(var(--dev-size) * 0.0125) rgb(255 255 255 / 70%); + } + .dev::before { + content: ''; + position: absolute; + left: 50%; + top: 50%; + width: max(44px, var(--device-shell-size)); + height: max(44px, var(--device-shell-size)); + transform: translate(-50%, -50%); + border-radius: 50%; + pointer-events: auto; + z-index: 3; + } + .device-shell { + position: absolute; + box-sizing: border-box; + display: flex; + align-items: center; + gap: calc(var(--dev-size) * 0.1); + padding: 0; + min-width: var(--dev-size); + min-height: var(--dev-size); + border: 0; + background: transparent; + box-shadow: none; + transition: opacity .2s; + pointer-events: none; + } + .device-shell-frame { + position: absolute; + z-index: 0; + box-sizing: border-box; + inset: calc(var(--device-shell-inset) / -1); + border: var(--device-shell-border-width) solid var(--device-shell-stroke); + /* A saturating radius is resolved from the final border box. Using a + second fractional length here lets border-box and radius quantise on + different sides of a device pixel at some zoom/DPR combinations. */ + border-radius: 9999px; + background: transparent; + box-shadow: var(--device-shell-shadow); + transition: border-color .15s, box-shadow .15s, opacity .2s; + pointer-events: auto; + /* Normative production fallback: never add a per-marker backdrop blur. */ + backdrop-filter: none; + } + .device-shell:not(.with-values) { + left: 0; + top: 0; + } + .device-shell:not(.with-values):not(.text-shell) .device-shell-frame { + border-radius: 50%; + } + .device-shell.with-values.pos-right { + left: 0; + top: 50%; + transform: translateY(-50%); + } + .device-shell.with-values.pos-left { + right: 0; + top: 50%; + transform: translateY(-50%); + flex-direction: row-reverse; + } + .device-shell.with-values.pos-bottom { + left: 50%; + top: 0; + transform: translateX(-50%); + flex-direction: column; + } + .device-shell.with-values.pos-top { + left: 50%; + bottom: 0; + transform: translateX(-50%); + flex-direction: column-reverse; + } + .device-core { + position: relative; + z-index: 1; + box-sizing: border-box; + flex: 0 0 auto; + width: var(--dev-size); + height: var(--dev-size); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background: var(--device-face-bg); + color: var(--device-face-fg); + box-shadow: + var(--device-core-inset-shadow), + 0 0 0 var(--device-ring-width) var(--device-ring-color); + line-height: 0; + transition: background .15s, color .15s, box-shadow .15s, opacity .2s; + pointer-events: none; + } + .device-sections { + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: center; + gap: calc(var(--dev-size) * .08); + min-width: 0; + pointer-events: none; + } + .device-shell.pos-top .device-sections, + .device-shell.pos-bottom .device-sections { + flex-direction: row; + } + .dev ha-icon { + /* from --dev-size, NOT --icon-size: the per-device size multiplier must + scale the GLYPH with its badge. Pinned to the base size, "make this + icon bigger" grew an empty box around a default-size glyph (user + report via the owner, 2026-07-29). */ + --mdc-icon-size: calc(var(--dev-size, var(--device-base-size, 2.25cqw)) * 0.55); + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + } + .dev.on { + --device-face-bg: #F0A00C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0A00C; + } + .dev.theme-light.on { --device-face-fg: #fff; } + .dev.theme-dark.on { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .0375; + } + .dev.open { + --device-face-bg: var(--hp-open); + --device-face-fg: light-dark(#fff, #252525); + } + .dev.theme-light.open { --device-face-fg: #fff; } + .dev.theme-dark.open { --device-face-fg: #252525; } + .dev.lock-locked { + --device-face-bg: #66D17A; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #66D17A; + } + .dev.theme-light.lock-locked { --device-face-fg: #fff; } + .dev.theme-dark.lock-locked { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + .dev.lock-unlocked { + --device-face-bg: #F0410C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0410C; + } + .dev.theme-light.lock-unlocked { --device-face-fg: #fff; } + .dev.theme-dark.lock-unlocked { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + /* Interaction wins ordinary state colours. Alarm keeps priority through + the more-specific rule below. Unavailable has no visual hover. */ + :host([data-pointer-hover]) .dev:not(.unavail):hover { + --device-face-bg: #0C82F0; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: var(--device-shell-base-stroke); + } + :host([data-pointer-hover]) .dev.theme-light:not(.unavail):hover { --device-face-fg: #fff; } + :host([data-pointer-hover]) .dev.theme-dark:not(.unavail):hover { --device-face-fg: #252525; } + :host([data-pointer-hover]) .dev:hover, + .dev:focus-visible { z-index: 5; } + .dev.unavail { + opacity: 0.35; + --device-face-bg: #B5BAC1; + --device-shell-stroke: var(--device-shell-base-stroke); + } + .dev.virtual .device-shell-frame { + border-style: dashed; + } + /* "hide from plan" flag, shown only in the device editor with the + "show hidden devices" toggle on (docs/FILTERING.md). BLUE, so a hidden + device cannot be mistaken for an unavailable one (translucent dark) — + and no live-state paint at all: a ghost is configuration, not status + (owner's request). */ + .dev.ghost { + opacity: 0.6; + color: var(--hp-accent); + } + .dev.ghost .device-shell-frame { + border-style: dashed; + border-color: var(--hp-accent); + box-shadow: none; + } + .dev.ghost .device-core { + background: rgba(62, 166, 255, 0.22); /* fallback for old WebViews */ + background: color-mix(in srgb, var(--hp-accent) 30%, var(--card-background-color, #1c2530)); + color: var(--hp-accent); + } + /* HA-disabled is not a user hide: neutral grey + a power-off badge keeps + the two ghosts distinguishable without relying on colour alone. */ + .dev.ghost.ha-disabled { + opacity: 0.62; + color: var(--secondary-text-color, #9aa0aa); + } + .dev.ghost.ha-disabled .device-shell-frame { + border-color: var(--secondary-text-color, #9aa0aa); + } + .dev.ghost.ha-disabled .device-core { + background: rgba(120, 124, 134, 0.2); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 24%, var(--card-background-color, #1c2530)); + color: var(--secondary-text-color, #9aa0aa); + } + .dev .habadge { + position: absolute; + right: -18%; + bottom: -18%; + display: grid; + place-items: center; + width: 46%; + height: 46%; + min-width: 12px; + min-height: 12px; + border-radius: 50%; + background: var(--card-background-color, #242832); + border: 1px solid currentColor; + } + .dev .habadge ha-icon { width: 72%; height: 72%; } + .dev.sel { + --device-ring-color: #F0A00C; + --device-ring-width: calc(var(--dev-size) * 0.0375); + } + .dev:focus-visible { + --device-ring-color: #0C82F0; + --device-ring-width: calc(var(--dev-size) * 0.0375); + } + .dev:not(.on):not(.open):not(.alarm):not(.lock-locked):not(.lock-unlocked):not(.unavail):focus-visible { + --device-face-fg: #0C82F0; + } + /* Alert stays above focus, selection, hover and ordinary semantic paint. */ + .dev.alarm, + :host([data-pointer-hover]) .dev.alarm:hover, + .dev.alarm:focus-visible { + --device-face-bg: #F0410C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0410C; + } + .dev.theme-light.alarm { --device-face-fg: #fff; } + .dev.theme-dark.alarm { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + .dev .value-badge { + position: relative; + z-index: 2; + box-sizing: border-box; + width: max-content; + min-width: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * .7875); + height: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * .7875); + display: flex; + align-items: center; + justify-content: center; + overflow: visible; + background: var(--device-core-bg); + border: 0; + border-radius: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.39375); + padding: 0 calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.14); + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * var(--value-font-scale, .45)); + font-weight: 600; + line-height: 1; + color: var(--device-core-fg); + white-space: nowrap; + pointer-events: none; + } + .dev .value-badge.unavailable, + .dev .value-badge.missing { opacity: 0.66; } + .dev .lqi { + position: absolute; + top: calc(50% + var(--device-shell-size) / 2 + var(--dev-size) * .05); + left: 50%; + transform: translateX(-50%); + margin-top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.05); + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.38); + font-weight: 600; + line-height: 1; + text-shadow: 0 0 3px rgba(0, 0, 0, 0.9), 0 0 2px rgba(0, 0, 0, 0.9); + white-space: nowrap; + pointer-events: none; + } + .dev .lqi.below-value-badge { + margin-top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.8875); + } + .temprange { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + margin-left: auto; + color: var(--hp-muted); + font-size: var(--fs-s); + } + /* live vacuum: a round puck, no badge plate, soft pulse (docs/VACUUM.md) */ + .vacpuck { + position: absolute; + /* the base badge, but round and 20% smaller — the owner's wording: + «иконка похожа на иконку базы, только круглая и чуть меньше» */ + --puck-size: calc(var(--device-base-size, 2.25cqw) * 0.8); + width: var(--puck-size); + height: var(--puck-size); + border-radius: 50%; + transform: translate(-50%, -50%); + --vac-core-bg: light-dark(#fff, #252525); + --vac-core-fg: light-dark(#252525, #fff); + background: var(--vac-core-bg); + border: 1px solid #BCBCBC; + box-shadow: + 0 1px 2px rgb(37 40 45 / 12%), + 0 4px 8px -1.07px rgb(37 40 45 / 18%); + color: var(--vac-core-fg); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 6; + /* glide between sparse position updates; .jump disables it so the robot + never appears to drive through walls after a data gap */ + transition: left 1.2s linear, top 1.2s linear; + animation: vacpulse 2.2s ease-out infinite; + } + .vacpuck.theme-light { --vac-core-bg: #fff; --vac-core-fg: #252525; } + .vacpuck.theme-dark { --vac-core-bg: #252525; --vac-core-fg: #fff; } + .vacpuck.jump { transition: none; } + .vacpuck.stale { opacity: 0.45; animation: none; } + .vacpuck ha-icon { + --mdc-icon-size: calc(var(--puck-size) * 0.68); + color: var(--vac-core-fg); + /* same centering recipe as .dev ha-icon: without flex + line-height 0 + the glyph sits on its text baseline and appears to float around the + circle (owner report 2026-07-31) */ + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + width: var(--mdc-icon-size); + height: var(--mdc-icon-size); + } + @keyframes vacpulse { + 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--hp-accent) 45%, transparent); } + 70% { box-shadow: 0 0 0 12px transparent; } + 100% { box-shadow: 0 0 0 0 transparent; } + } + @media (prefers-reduced-motion: reduce) { + .vacpuck { animation: none; } + } + .vactrail { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 5; + overflow: visible; + } + .vactrail polyline, + .vactrail path { + fill: none; + stroke-linejoin: round; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + } + /* dark halo + light core: neutral, and one of the two always contrasts + with whatever fill is underneath */ + .vactrail g.prev { opacity: 0.4; } + .vactrail .case { + stroke: rgba(0, 0, 0, 0.4); + stroke-width: 2.25; + } + .vactrail .core { + stroke: rgba(255, 255, 255, 0.82); + stroke-width: 0.9; + } + .devicepreview-empty { + min-height: 82px; + margin: 4px 0 14px; + padding: var(--sp-4); + display: flex; + align-items: center; + justify-content: center; + gap: var(--sp-3); + border: 1px dashed var(--hp-line); + border-radius: var(--rad-m); + color: var(--hp-muted); + text-align: center; + } +`,o` + .hdr { + position: sticky; + top: var(--header-height, 56px); + z-index: 20; + background: var(--card-background-color, var(--hp-bg)); + border-radius: var(--ha-card-border-radius, 12px) var(--ha-card-border-radius, 12px) 0 0; + } + .tabs { + display: flex; + gap: var(--sp-2); + background: rgba(127, 127, 127, 0.12); + padding: var(--sp-2); + border-radius: var(--rad-l); + flex-wrap: wrap; + } + .tab { + border: 0; + background: transparent; + color: var(--hp-muted); + display: inline-flex; + align-items: center; + padding: var(--sp-3) var(--sp-5); + border-radius: var(--rad-m); + font-size: var(--fs-m); + font-weight: 600; + cursor: pointer; + transition: 0.15s; + font-family: inherit; + } + :host([data-pointer-hover]) .tab:hover { + color: var(--hp-txt); + } + .tab.active { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + /* docs/CANVAS.md §4.1: objects an order of magnitude away from the plan + do not decide the opening view — one quiet chip says so and offers to + take them in. Never a modal (owner). */ + .farhint { + position: absolute; + left: 50%; + transform: translateX(-50%); + bottom: var(--sp-4); + z-index: 12; + display: flex; + align-items: center; + gap: var(--sp-2); + max-width: calc(100% - var(--sp-8)); + background: var(--card-background-color, var(--hp-bg)); + opacity: 0.94; + color: var(--hp-txt); + border: 1px solid var(--divider-color, #33404d); + border-radius: var(--rad-m); + padding: var(--sp-1) var(--sp-3); + font-size: var(--fs-s); + } + .farhint ha-icon { + --mdc-icon-size: 18px; + color: var(--hp-warn, #e2a03f); + flex: none; + } + .farhint span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .dropbtn { + display: flex; + align-items: center; + gap: var(--sp-4); + width: 100%; + text-align: left; + border: 1px solid var(--hp-muted); + border-radius: var(--rad-m); + background: transparent; + color: var(--hp-txt); + padding: var(--sp-4) 10px; + cursor: pointer; + font-family: inherit; + font-size: var(--fs-m); + margin-top: var(--sp-3); + } + .dropbtn .ref { color: var(--hp-muted); font-size: var(--fs-s); margin-left: auto; } + .dropbtn ha-icon { --mdc-icon-size: 18px; margin-left: var(--sp-2); } + .dropbtn.open { border-color: var(--hp-accent); } + .droppanel { + border: 1px solid var(--hp-accent); + border-top: none; + border-radius: 0 0 var(--rad-m) var(--rad-m); + padding: var(--sp-3); + margin-top: -4px; + } + .hdr.kioskhide { display: none; } + .decorbar .dcolor { + width: 30px; height: 26px; padding: 0; border: none; background: none; cursor: pointer; + } + .decorbar .dwidth { + font-family: inherit; font-size: var(--fs-s); border-radius: var(--rad-s); + background: var(--hp-bg2, transparent); color: var(--hp-txt); border: 1px solid var(--hp-muted); + padding: var(--sp-2) var(--sp-3); + } + .decorbar .bdhint { + font-size: var(--fs-s); + color: var(--hp-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .decorbar .dfill { + display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-s); cursor: pointer; + } + .decorbar .dfill input[type="checkbox"] { + width: 16px; + height: 16px; + flex: none; + margin: 0; + padding: 0; + } + .decorbar hp-color-opacity { flex: 0 0 auto; } + .modes { + display: inline-flex; + gap: var(--sp-1); + background: rgba(127, 127, 127, 0.12); + border-radius: var(--rad-l); + padding: var(--sp-2); + } + .modetab { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + border: 0; + background: transparent; + color: var(--hp-muted); + padding: var(--sp-3) 10px; /* 10px h-padding kept: +2px would wrap the header modes row */ + border-radius: var(--rad-m); + font-size: var(--fs-m); + font-weight: 600; + cursor: pointer; + font-family: inherit; + transition: background-color 0.14s ease, color 0.14s ease, transform 0.14s ease; + } + .modetab:active { transform: scale(0.97); } + .modetab ha-icon { --mdc-icon-size: 15px; } + /* issue #220: a tab can be dragged to a new position in the editors */ + .tab[data-reorderable] { cursor: grab; } + .tab.dragging { cursor: grabbing; opacity: 0.55; } + .tab.drop-before { box-shadow: inset 2px 0 0 0 var(--primary-color, #03a9f4); } + .tab.drop-after { box-shadow: inset -2px 0 0 0 var(--primary-color, #03a9f4); } + .modetab .closex { + --mdc-icon-size: 13px; + box-sizing: border-box; + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + min-width: 24px; + min-height: 24px; + /* Keep the old 13 × 13 flex footprint (+2 px left margin) while the + pointer target grows around it. Header width, height and wrapping do + not move; only near-misses that used to hit the active tab reach X. */ + margin: -5.5px -5.5px -5.5px -3.5px; + opacity: 0.75; + cursor: pointer; + border-radius: var(--rad-s); + } + :host([data-pointer-hover]) .modetab .closex:hover { opacity: 1; } + .editbar .barclose { + box-sizing: border-box; + width: 40px; + height: 40px; + padding: 0; + margin: 0; + min-width: 40px; + min-height: 40px; + justify-content: center; + gap: 0; + line-height: 0; + } + .editbar .barclose ha-icon { flex: none; margin: 0; } + .modetab.active { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + @media (max-width: 720px) { + .modetab .ml { display: none; } + } + .editbar { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: stretch; + border-bottom: 1px solid var(--hp-line); + font-size: var(--fs-m); + } + .editbar-tools { + display: flex; + align-items: center; + gap: 10px; + padding: var(--sp-4) var(--sp-5); + flex-wrap: wrap; + min-width: 0; + outline: none; + } + .editbar-end { + display: flex; + align-items: center; + padding: var(--sp-4) var(--sp-5); + border-inline-start: 1px solid var(--hp-line); + background: var(--card-background-color, var(--hp-bg)); + position: relative; + z-index: 2; + } + .tab .tabedit { + --mdc-icon-size: 13px; + display: inline-flex; + align-items: center; + margin-left: var(--sp-3); + opacity: 0.4; + } + :host([data-pointer-hover]) .tab:hover .tabedit { + opacity: 0.9; + } + .tab.tabadd { + padding: var(--sp-3) var(--sp-4); + } + .tab.tabadd ha-icon { + --mdc-icon-size: 15px; + } + .rhint { + font-size: var(--fs-s); + color: var(--hp-muted); + margin-bottom: var(--sp-3); + } + .togglehint { + overflow-wrap: anywhere; + } + .togglehint > div + div { + margin-top: var(--sp-1); + } + /* Keep the last editor bar mounted while the row collapses. This makes + both entering and leaving an editor change the card geometry gradually; + the header ResizeObserver keeps the stage fitted throughout. */ + .editorchrome { + display: block; + height: 0; + opacity: 0; + visibility: hidden; + overflow: hidden; + } + .editorchrome:not(.open) { + pointer-events: none; + } + .editorchrome.open { + height: auto; + opacity: 1; + visibility: visible; + overflow: visible; + } + .editorchrome.transitioning { + overflow: hidden; + will-change: height; + pointer-events: none; + } + /* The toolbar is already visible while its height is interpolating. Its + explicit navigation control must remain usable even though all editing + tools stay frozen until the transition settles. */ + .editorchrome.transitioning .barclose { + pointer-events: auto; + } + .editorchrome-inner { + min-height: 0; + transform-origin: top center; + } + .editorchrome.transitioning .editorchrome-inner { + will-change: opacity; + } + @media (prefers-reduced-motion: reduce) { + .modetab { transition: none; } + } + .editbar .warn { + color: #ffc14d; + } + .editbar .sname { + font-weight: 600; + } + .editbar input { + width: 74px; + background: transparent; + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + } + .editbar label, + .editbar .hint { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editbar .drawwall { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .editbar .wallsgroup { + display: inline-flex; + align-items: center; + gap: 10px; + white-space: nowrap; + } + .editbar .drawwall input { + width: 4.2em; + } + .editbar .drawwall .opl { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .menuwrap { + position: fixed; + inset: 0; + z-index: 80; + } + .menu { + position: fixed; + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-l); + box-shadow: var(--shadow-2); + min-width: 210px; + max-width: 300px; + overflow: hidden; + transform: translate(0, 8px); + } + .menu .hd { + padding: var(--sp-4) var(--sp-5); + font-weight: 600; + font-size: var(--fs-m); + border-bottom: 1px solid var(--hp-line); + display: flex; + align-items: center; + gap: var(--sp-3); + } + .menu .hd ha-icon, + .menu .it.all ha-icon { + color: var(--hp-accent); + --mdc-icon-size: 16px; + } + .menu .it { + padding: var(--sp-4) var(--sp-5); + font-size: var(--fs-m); + cursor: pointer; + display: flex; + align-items: center; + gap: var(--sp-4); + } + .menu .it ha-icon { + --mdc-icon-size: 16px; + color: var(--hp-muted); + } + :host([data-pointer-hover]) .menu .it:hover { + background: rgba(127, 127, 127, 0.15); + } + .menu .it.all { + color: var(--hp-accent); + font-weight: 600; + } + .tip { + position: fixed; + pointer-events: none; + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + color: var(--hp-txt); + padding: var(--sp-3) 10px; + border-radius: var(--rad-m); + font-size: var(--fs-m); + box-shadow: var(--shadow-2); + z-index: 60; + max-width: 260px; + } + .tip .m { + color: var(--hp-muted); + font-size: var(--fs-s); + display: block; + } +`,o` + .head { + display: flex; + align-items: center; + gap: 10px; + padding: 10px var(--sp-5); + border-bottom: 1px solid var(--hp-line); + flex-wrap: wrap; + } + .title { + font-size: var(--fs-l); + font-weight: 600; + display: flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .title ha-icon { + color: var(--hp-accent); + --mdc-icon-size: 18px; + } + @media (max-width: 620px) { + .head { gap: var(--sp-3); padding: var(--sp-4) 10px; } + .head .count { display: none; } + .head .title { font-size: var(--fs-m); } + } + .count { + font-size: var(--fs-s); + color: var(--hp-muted); + } + .btn { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + background: transparent; + color: var(--hp-txt); + padding: var(--sp-3) 10px; + border-radius: var(--rad-m); + cursor: pointer; + transition: 0.15s; + font-family: inherit; + font-size: var(--fs-m); + } + .btn ha-icon { + --mdc-icon-size: 17px; + } + :host([data-pointer-hover]) .btn:hover { + border-color: var(--hp-accent); + } + .btn.on { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + border-color: var(--hp-accent); + } + .btn.ghost { + border: none; + } + .btn[disabled] { + opacity: 0.5; + pointer-events: none; + } + /* the compass dial in the general settings (docs/SUN.md) */ + .sunrow { + display: flex; + align-items: center; + gap: var(--sp-5); + margin: var(--sp-3) 0; + } + .suncol { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--sp-3); + min-width: 0; + } + .recoveryoverlay { + position: absolute; + inset: 0; + /* Above the contextual editor tray (70): recovery is the one state in + which every stage-editing surface must be inert. Dialogs live outside + the stage and retain their own higher card-level stacking context. */ + z-index: 75; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--sp-4); + padding: var(--sp-6); + box-sizing: border-box; + /* The final solid layer guarantees an opaque recovery surface even when + a custom HA theme exposes its card colour as rgba(). */ + background: + linear-gradient(var(--ha-card-background, var(--card-background-color, #111)), + var(--ha-card-background, var(--card-background-color, #111))), + #111; + color: var(--primary-text-color, #fff); + text-align: center; + pointer-events: auto; + transition: opacity 0.15s ease; + } + .recoveryoverlay.phase-entering, + .recoveryoverlay.phase-leaving { + opacity: 0; + } + .recoveryoverlay.phase-fading-in, + .recoveryoverlay.phase-opaque { + opacity: 1; + } + .recoveryoverlay ha-icon { + --mdc-icon-size: 44px; + color: var(--hp-accent); + } + .editorloading { + position: absolute; + z-index: 74; + left: 50%; + top: 50%; + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-5); + border: 1px solid color-mix(in srgb, var(--hp-accent) 45%, transparent); + border-radius: 999px; + background: color-mix(in srgb, + var(--ha-card-background, var(--card-background-color, #111)) 92%, transparent); + color: var(--primary-text-color); + box-shadow: 0 6px 22px rgb(0 0 0 / 18%); + transform: translate(-50%, -50%); + pointer-events: none; + animation: editor-loading-in 0.15s ease both; + } + .editorloading ha-icon { + --mdc-icon-size: 22px; + color: var(--hp-accent); + animation: editor-loading-spin 0.9s linear infinite; + } + @keyframes editor-loading-in { + from { opacity: 0; transform: translate(-50%, calc(-50% + 4px)); } + to { opacity: 1; transform: translate(-50%, -50%); } + } + @keyframes editor-loading-spin { to { transform: rotate(360deg); } } + @media (prefers-reduced-motion: reduce) { + .recoveryoverlay, + .editorloading, + .editorloading ha-icon { + transition: none; + animation: none; + } + } + .oplock { + --oplock-size: calc(var(--icon-size, 2.5cqw) * 0.62); + --oplock-core-size: calc(var(--oplock-size) / 1.26875); + --oplock-stroke-ratio: 0.01875; + --oplock-stroke-width: max(1px, calc(var(--oplock-core-size) * var(--oplock-stroke-ratio))); + --oplock-core-bg: light-dark(#fff, #252525); + --oplock-core-fg: light-dark(#252525, #fff); + --oplock-shell-stroke: light-dark(#BCBCBC, rgb(37 37 37 / 75%)); + --oplock-shell-shadow: + 0 calc(var(--oplock-core-size) * .025) calc(var(--oplock-core-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--oplock-core-size) * .1) calc(var(--oplock-core-size) * .175) + calc(var(--oplock-core-size) * -.025) rgb(37 40 45 / 18%); + --oplock-core-shadow: 0 0 0 0 transparent; + pointer-events: none; /* inert while editing; clickable in View (rule below) */ + position: absolute; + transform: translate(-50%, -50%); + width: var(--oplock-size); + height: var(--oplock-size); + display: grid; + place-items: center; + border: 0; + background: transparent; + z-index: 1; + } + .oplock.theme-light { + --oplock-core-bg: #fff; + --oplock-core-fg: #252525; + --oplock-shell-stroke: #BCBCBC; + } + .oplock.theme-dark { + --oplock-core-bg: #252525; + --oplock-core-fg: #fff; + --oplock-shell-stroke: rgb(37 37 37 / 75%); + --oplock-core-shadow: + inset 0 calc(var(--oplock-core-size) * .0125) + calc(var(--oplock-core-size) * .0125) rgb(255 255 255 / 70%); + } + .oplock-shell { + box-sizing: border-box; + width: 100%; + height: 100%; + border: var(--oplock-stroke-width) solid var(--oplock-shell-stroke); + border-radius: 50%; + background: transparent; + box-shadow: var(--oplock-shell-shadow); + display: grid; + place-items: center; + pointer-events: none; + backdrop-filter: none; + } + .oplock-core { + width: var(--oplock-core-size); + height: var(--oplock-core-size); + border-radius: 50%; + background: var(--oplock-core-bg); + color: var(--oplock-core-fg); + box-shadow: var(--oplock-core-shadow); + display: grid; + place-items: center; + pointer-events: none; + } + .oplock ha-icon { + --mdc-icon-size: calc(var(--oplock-core-size) * 0.55); + display: flex; + line-height: 0; + } + .oplock.locked { + --oplock-core-bg: #66D17A; + --oplock-core-fg: light-dark(#fff, #252525); + --oplock-shell-stroke: #66D17A; + } + .oplock.theme-light.locked { --oplock-core-fg: #fff; } + .oplock.theme-dark.locked { + --oplock-core-fg: #252525; + --oplock-stroke-ratio: .025; + } + .oplock.unlocked { + --oplock-core-bg: #F0410C; + --oplock-core-fg: light-dark(#fff, #252525); + --oplock-shell-stroke: #F0410C; + } + .oplock.theme-light.unlocked { --oplock-core-fg: #fff; } + .oplock.theme-dark.unlocked { + --oplock-core-fg: #252525; + --oplock-stroke-ratio: .025; + } + .oplock.unknown { --oplock-core-fg: var(--hp-muted); } + .btn.lockact { + width: 100%; + justify-content: center; + display: flex; + align-items: center; + gap: var(--sp-3); + margin-top: var(--sp-4); + } + .btn.lockact.warn { + color: var(--error-color, #d33); + border-color: var(--error-color, #d33); + } + .oprow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) 0; + } + .oprow b { margin-left: auto; } + .oprow.ok b { color: #66d17a; } + .oprow.warn b { color: var(--hp-open); } + .bindharow { + display: flex; + align-items: center; + gap: var(--sp-5); + flex-wrap: wrap; + } + .bindharow .entcheck { opacity: 0.9; } + .ctrlchips { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-2) 0; } + .ctrlchip { + display: inline-flex; align-items: center; gap: var(--sp-2); + background: var(--hp-accent); color: var(--text-primary-color, #fff); + border-radius: var(--rad-l); padding: var(--sp-2) var(--sp-4); font-size: var(--fs-s); + } + .ctrlchip ha-icon { --mdc-icon-size: 14px; cursor: pointer; } + .ctrllist { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-2); } + .ctrlopt { + display: flex; align-items: center; gap: var(--sp-4); text-align: left; + border: 0; background: transparent; color: var(--hp-txt); + padding: var(--sp-3) var(--sp-4); border-radius: var(--rad-s); cursor: pointer; font-family: inherit; font-size: var(--fs-m); + } + :host([data-pointer-hover]) .ctrlopt:hover { + background: var(--secondary-background-color, rgba(128,128,128,0.15)); + } + .ctrlopt .sub { color: var(--hp-muted); font-size: var(--fs-s); margin-left: auto; } + .ctrlopt ha-icon { --mdc-icon-size: 16px; } + .ctrlstates { display: flex; flex-direction: column; gap: var(--sp-2); } + .ctrlstate { display: inline-flex; align-items: center; gap: var(--sp-3); color: var(--hp-muted); } + .ctrlstate.on { color: var(--hp-txt); } + .ctrlstate ha-icon { --mdc-icon-size: 15px; } + .cardpreview { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-2); + margin: var(--sp-4) 0 var(--sp-1); + padding: 10px; + border: 1px dashed var(--hp-muted); + border-radius: var(--rad-m); + } + .cardpreview .cpname { font-weight: 700; letter-spacing: 0.04em; } + .cardpreview .cpmeta { + display: inline-flex; + align-items: center; + gap: 0.3em; + font-weight: 600; + opacity: 0.85; + } + .cardpreview .cpmeta ha-icon { --mdc-icon-size: 1.05em; } + .iconauto { + display: flex; + align-items: center; + gap: var(--sp-3); + font-size: var(--fs-s); + margin: var(--sp-2) 0 0; + } + .iconauto ha-icon { --mdc-icon-size: 18px; } + .iconauto span { flex: 1; } + .iconauto .btn { min-height: 32px; padding: 0 var(--sp-3); } + hp-dialog .dfill { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + cursor: pointer; + } + .wallthick-dlg { + position: absolute; + z-index: 40; + min-width: 200px; + transform: translate(-50%, 8px); + padding: 10px 12px; + border-radius: 10px; + background: var(--card-background-color, #fff); + box-shadow: 0 8px 28px rgba(0,0,0,.22); + display: flex; + flex-direction: column; + gap: 8px; + pointer-events: auto; + } + .wallthick-dlg .row { + display: flex; + align-items: center; + gap: 8px; + } + .wallthick-dlg input[type="number"] { + width: 5.5em; + padding: 4px 6px; + border: 1px solid var(--divider-color, #ccc); + border-radius: 6px; + background: var(--input-fill, transparent); + color: var(--primary-text-color); + } + .areasel, + .namein { + background: var(--hp-bg); + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + font-family: inherit; + } + .namein { + width: 130px; + } + .habindingbanner { + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-4); + margin-bottom: var(--sp-4); + border: 1px solid var(--warning-color, #ff9800); + border-radius: var(--rad-m); + background: color-mix(in srgb, var(--warning-color, #ff9800) 12%, transparent); + color: var(--primary-text-color, #f1f3f6); + } + .habindingbanner > span { flex: 1; min-width: 0; } + .habindingbanner > ha-icon { color: var(--warning-color, #ff9800); flex: 0 0 auto; } + .habindingbanner.limited { + border-color: var(--secondary-text-color, #9aa0aa); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 10%, transparent); + } + .habindingbanner.limited > ha-icon { color: var(--secondary-text-color, #9aa0aa); } + .srcrow { + display: flex; + align-items: center; + gap: var(--sp-4); + font-size: var(--fs-m); + cursor: pointer; + padding: var(--sp-1) 0; + } + .dispsection { + margin-top: var(--sp-5) !important; + padding-top: var(--sp-4); + border-top: 1px solid var(--hp-line); + font-weight: 600; + color: var(--hp-txt) !important; + } + .colorrow { + display: flex; + align-items: center; + gap: var(--sp-4); + } + .gsrow > hp-color-opacity { + min-width: min(100%, 210px); + justify-content: space-between; + } + .ripple-colorrow > hp-color-opacity { + width: 100%; + justify-content: space-between; + } + .ripple-sizerow > .opl { + min-width: 0; + } + .colorrow input[type='range'] { flex: 1; } + .colorrow .tempin { width: 70px; flex: none; } + /* beat the generic hp-dialog .body .namein { width:100% } rule */ + hp-dialog .body .temprange .tempin { width: 56px; flex: none; padding: var(--sp-2) var(--sp-3); } + hp-dialog .body .colorrow .tempin { width: 72px; flex: none; } + .srcrow { flex-wrap: nowrap; } + /* native HA controls (rendered only when the HA frontend defines them; + old HA and the smoke env keep the plain inputs). ha-switch is taller + than a checkbox - cap its footprint so .srcrow keeps its rhythm. */ + .srcrow ha-switch { flex: none; } + .colorrow ha-slider { flex: 1; min-width: 0; } + .srcrow > span:first-of-type { white-space: nowrap; } + .colorrow .opl { color: var(--hp-muted); font-size: var(--fs-s); } + .colorrow .opv { font-size: var(--fs-s); min-width: 34px; text-align: right; } + .markerlightgroup { + min-width: 0; + margin: var(--sp-5) 0 0; + padding: var(--sp-4); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + } + .markerlightgroup legend { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-1); + padding: 0 var(--sp-2); + color: var(--hp-txt); + font-weight: 600; + } + .markerlightgroup legend > span { min-width: 0; overflow-wrap: anywhere; } + .markerlightgroup[disabled] > :not(legend) { opacity: .62; } + .markerhelpfield { margin-top: var(--sp-4); } + .markerhelplabel { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-1); + margin-bottom: var(--sp-1); + } + .markerhelplabel > label { min-width: 0; overflow-wrap: anywhere; } + .markerradios { display: grid; gap: var(--sp-1); min-width: 0; } + .markerlightgroup .srcrow > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + } + .markerglowvalue { margin: var(--sp-3) 0; flex-wrap: wrap; } + .markerglowvalue hp-color-opacity { flex: none; } + .markerlightdisabled { + display: flex; + align-items: center; + gap: var(--sp-2); + margin-top: var(--sp-2) !important; + } + .markerlightdisabled ha-icon { --mdc-icon-size: 18px; flex: none; } + .markerbadgetechnical { + min-width: 0; + margin: var(--sp-1) 0 var(--sp-2) !important; + overflow-wrap: anywhere; + } + .markerbadgetechnical code { white-space: normal; } + .planrow { + display: flex; + align-items: center; + gap: 10px; + } + /* the "already uploaded" picker: a plan is never deleted for being + unreferenced, so it has to be findable again */ + .savedplans { + display: flex; + flex-direction: column; + gap: var(--sp-3); + max-height: 240px; + overflow: auto; + margin: var(--sp-3) 0 var(--sp-1); + padding: var(--sp-3); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: var(--hp-bg2, rgba(255, 255, 255, 0.03)); + /* The same collapse that ate .candlist (v1.53.1): a scroll box is a + flex item whose automatic minimum size is ZERO (overflow != visible), + so inside hp-dialog .body — a flex column taller than its 66vh cap — + it shrank to a 14px sliver: the rows were in the DOM, the owner saw + a thin rounded stripe under the "Already uploaded" button. Don't + shrink, and keep a floor even when the box is empty or loading. */ + flex: 0 0 auto; + min-height: 2.6em; + } + .savedplan { + display: flex; + align-items: center; + gap: 10px; + } + .savedplan.cur { outline: 1px solid var(--hp-accent); border-radius: var(--rad-s); } + .savedplan img { + width: 56px; + height: 40px; + object-fit: contain; + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + background: #fff; + flex: none; + } + .savedmeta { display: flex; flex-direction: column; min-width: 0; flex: 1; } + .savedmeta b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .savedmeta .muted { font-size: var(--fs-s); } + .savedplan .btn.danger ha-icon { color: #f25a4a; } + .savedplan .btn[disabled] { opacity: 0.4; pointer-events: none; } + .planprev { + max-width: 120px; + max-height: 70px; + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + background: #fff; + } + .planname { + font-size: var(--fs-m); + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .planname.muted { + color: var(--hp-muted); + } + .filebtn { + cursor: pointer; + } + .fileupload { display: inline-flex; min-width: 0; } + .fileupload > input { display: none; } + .btn.danger { + border-color: #b3402a; + color: #ff7a5c; + } + hp-dialog .row .spacer { + flex: 1; + } + hp-dialog .body { + max-height: 66vh; + overflow-y: auto; + } + .descin { + width: 100%; + box-sizing: border-box; + background: var(--hp-bg); + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + font-family: inherit; + resize: vertical; + /* flex column of the dialog body squeezes textareas — keep a usable height */ + min-height: 92px; + flex-shrink: 0; + line-height: 1.35; + } + .bindsel { + display: flex; + flex-direction: column; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + padding: var(--sp-4); + } + .bindsel .opt { + display: flex; + align-items: center; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + background: transparent; + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + cursor: pointer; + font-size: var(--fs-m); + font-family: inherit; + } + .bindsel .opt.on { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + border-color: var(--hp-accent); + } + .curbind { + display: flex; + align-items: center; + gap: var(--sp-3); + font-size: var(--fs-m); + color: var(--hp-txt); + flex-wrap: wrap; + } + .curbind .ref { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .vacbox .vacbtns { display: flex; gap: var(--sp-4); margin: var(--sp-3) 0; flex-wrap: wrap; } + .vacdiag { display: grid; gap: 4px; margin-bottom: var(--sp-3); } + .vacdiag > div { display: flex; justify-content: space-between; gap: var(--sp-5); } + .vacdiag > div > span { color: var(--secondary-text-color); } + .vacdiag > div > b { text-align: right; overflow-wrap: anywhere; } + .vacpicker { margin: var(--sp-3) 0; } + .vacsource-warning { display: grid; gap: 8px; } + .vacsource-warning .btn { justify-self: start; } + .vacpicker > summary { display: inline-flex; width: auto; list-style: none; cursor: pointer; } + .vacpicker > summary::-webkit-details-marker { display: none; } + .vacsource-list { display: grid; gap: 6px; margin-top: 8px; } + .vacsource-list details { padding: 6px 0 0; } + .vacsource-list details > summary { cursor: pointer; font-weight: 600; } + .vacsource { display: flex; align-items: center; justify-content: space-between; gap: 12px; + width: 100%; min-width: 0; padding: 9px 10px; border: 1px solid var(--divider-color); + border-radius: 10px; color: var(--primary-text-color); background: var(--secondary-background-color); + text-align: left; cursor: pointer; } + .vacsource.on { border-color: var(--accent-color); box-shadow: inset 3px 0 var(--accent-color); } + .vacsource > span:first-child { min-width: 0; display: grid; gap: 2px; } + .vacsource small { color: var(--secondary-text-color); overflow-wrap: anywhere; } + .vacsource-meta { color: var(--secondary-text-color); text-align: right; font-size: 0.82em; } + .vacxcme pre { margin: 8px 0 0; white-space: pre-wrap; user-select: text; } + .vacfit { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + z-index: 12; + overflow: visible; + touch-action: none; + cursor: grab; + /* the devlayer is pointer-events: none and every child opts back in — + without this line real clicks flew straight through the overlay + (owner: «уголки не кликабельны»; synthetic smoke events bypass + hit-testing, which is why they lied) */ + pointer-events: auto; + } + .vacfit:active { cursor: grabbing; } + .vacfit polygon { + fill: color-mix(in srgb, var(--hp-accent) 16%, transparent); + stroke: var(--hp-accent); + stroke-width: 2; + vector-effect: non-scaling-stroke; + stroke-dasharray: 6 4; + } + .vacfit text { + fill: var(--hp-accent); + font-size: 26px; + text-anchor: middle; + dominant-baseline: middle; + pointer-events: none; + user-select: none; + } + /* ---- the furniture palette (docs/FURNITURE.md §3) ------------------- */ + .furnpalette { + display: flex; + flex-direction: column; + max-height: 38vh; + border-top: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12)); + background: var(--card-background-color, var(--hp-bg)); + font-size: 0.85em; + } + .furnhd { + display: flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + font-weight: 600; + opacity: 0.9; + } + .furnhd .spacer { flex: 1; } + .furnbody { + overflow: auto; + padding: 0 8px 6px; + } + .furngroup { + margin: 6px 0 3px; + font-size: 0.85em; + text-transform: uppercase; + letter-spacing: 0.04em; + opacity: 0.6; + } + .furnrow { + display: flex; + flex-wrap: wrap; + gap: 4px; + } + .furnitem { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; + width: 74px; + padding: 4px 2px; + border: 1px solid transparent; + border-radius: 8px; + background: rgba(127, 127, 127, 0.08); + color: inherit; + font: inherit; + font-size: 0.8em; + line-height: 1.15; + text-align: center; + cursor: pointer; + } + :host([data-pointer-hover]) .furnitem:hover { background: rgba(127, 127, 127, 0.18); } + .furnitem.on { + border-color: var(--hp-accent); + background: rgba(38, 166, 154, 0.18); + } + .furnprev { + width: 40px; + height: 40px; + color: var(--primary-text-color, currentColor); + } + .furnsize { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 6px; + padding: 6px 8px; + border-top: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12)); + } + .furnsize label { + display: flex; + align-items: baseline; + gap: 3px; + opacity: 0.8; + } + .furnsize .furnunit { opacity: 0.6; font-size: 0.85em; } + .furnsize input { + width: 5.5em; + padding: 3px 5px; + } + .furnhint { opacity: 0.6; } + .vacfitdot { fill: var(--hp-accent); pointer-events: none; } + /* hit target: invisible and finger-sized; .vacfitknob is the visible bead */ + .vacfithandle { + fill: transparent; + stroke: none; + cursor: nwse-resize; + } + .vacfitknob { + fill: var(--hp-bg); + stroke: var(--hp-accent); + stroke-width: 2; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .vaccalbar { + position: fixed; + left: 50%; + bottom: 24px; + transform: translateX(-50%); + display: flex; + gap: var(--sp-5); + align-items: center; + background: var(--hp-bg); + color: var(--hp-txt); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-l); + padding: 10px var(--sp-5); + z-index: 60; + box-shadow: var(--shadow-2); + } + .candlist { + max-height: 160px; + overflow-y: auto; + border-top: 1px solid var(--hp-line); + /* A scrollable box is a flex item that HAPPILY collapses: inside the + dialog body (a flex column) this list rendered its rows into a 1px + sliver — the DOM had 26 candidates and the user saw nothing. In the + binding dropdown it sits inside .droppanel (block context) and never + showed the bug. Field report, 2026-07-30. */ + flex: 0 0 auto; + min-height: 2.6em; + } + .cand { + display: flex; + justify-content: space-between; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + cursor: pointer; + border-radius: var(--rad-s); + font-size: var(--fs-m); + } + :host([data-pointer-hover]) .cand:hover { + background: rgba(127, 127, 127, 0.15); + } + .cand.sel { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + .cand .cs { + color: var(--hp-muted); + font-size: var(--fs-s); + white-space: nowrap; + } + .opening-entity-candidate { + width: 100%; + border: 0; + background: transparent; + color: inherit; + font: inherit; + text-align: left; + } + .opening-entity-candidate.sel { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + .opening-entity-empty { cursor: default; } + .cand.sel .cs { + color: var(--text-primary-color, #fff); + opacity: 0.85; + } + .cand.muted { + color: var(--hp-muted); + cursor: default; + } + .pdfedit { + display: flex; + flex-wrap: wrap; + gap: var(--sp-3); + align-items: center; + } + .pdftag { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: var(--sp-2) var(--sp-3); + font-size: var(--fs-s); + } + .pdftag a { + color: var(--hp-txt); + text-decoration: none; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .pdftag .x { + --mdc-icon-size: 15px; + cursor: pointer; + color: var(--hp-muted); + } + :host([data-pointer-hover]) .pdftag .x:hover { + color: #ff7a5c; + } + .entlist { + display: flex; + flex-direction: column; + gap: var(--sp-2); + margin-bottom: 10px; + } + .entrow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + border-radius: var(--rad-m); + background: var(--secondary-background-color, rgba(128, 128, 128, 0.12)); + } + .entrow ha-icon { --mdc-icon-size: 20px; color: var(--hp-muted); } + .entrow.on ha-icon { color: var(--hp-accent); } + .entrow .en { flex: 1; font-size: var(--fs-m); } + .entrow .ev { font-size: var(--fs-m); color: var(--hp-muted); } + .entbtn { + min-width: 74px; + min-height: 32px; + padding: var(--sp-2) var(--sp-5); + border: 1px solid var(--hp-muted); + border-radius: 999px; + background: transparent; + color: var(--hp-txt); + font: inherit; + font-size: var(--fs-m); + cursor: pointer; + } + .entbtn.on { + background: var(--hp-accent); + border-color: var(--hp-accent); + color: var(--text-primary-color, #fff); + font-weight: 600; + } + .inforow { + display: flex; + gap: 10px; + font-size: var(--fs-m); + margin: var(--sp-2) 0; + } + .inforow .k { + color: var(--hp-muted); + min-width: 84px; + } + .inforow a { + color: var(--hp-accent); + word-break: break-all; + } + .infodesc { + font-size: var(--fs-m); + white-space: pre-wrap; + margin-top: var(--sp-3); + } + .infodesc.muted { + color: var(--hp-muted); + } + .pdflist { + display: flex; + flex-direction: column; + gap: var(--sp-2); + } + .pdf { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + color: var(--hp-accent); + text-decoration: none; + } + ha-icon-picker { + display: block; + } + .floorrow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-2); + font-size: var(--fs-m); + cursor: pointer; + } + .floorrow .floorlvl { + color: var(--hp-muted); + font-size: var(--fs-s); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: 0 var(--sp-3); + } + .rtest { + display: flex; + align-items: center; + gap: var(--sp-4); + margin-bottom: var(--sp-4); + } + .rtest .namein { flex: 1; } + .rtest ha-icon { color: var(--hp-accent); } + .rtesticon { font-size: var(--fs-s); color: var(--hp-muted); } + .rrow { + display: flex; + align-items: center; + gap: var(--sp-3); + margin: var(--sp-1) 0; + } + .rrow .rpat { flex: 2; } + .rrow .ricon { flex: 1.4; } + .rrow .rpat.bad { border-color: #ff7a5c; } + .rrow .rprev { --mdc-icon-size: 18px; color: var(--hp-txt); min-width: 18px; } + .rrow .ract { + --mdc-icon-size: 16px; + color: var(--hp-muted); + cursor: pointer; + } + :host([data-pointer-hover]) .rrow .ract:hover { color: var(--hp-txt); } + :host([data-pointer-hover]) .rrow .ract.del:hover { color: #ff7a5c; } + .gsrow .gsl { + min-width: 150px; + font-size: var(--fs-m); + color: var(--hp-muted); + } + .optimize-live { + display: grid; + justify-items: start; + gap: var(--sp-2); + margin-bottom: var(--sp-3); + } + .optimize-live .alignmsg, .optimize-live .rhint { margin-bottom: 0; } + .optimize-cleanup { min-height: 44px; } + .optimize-selected { color: var(--hp-txt); } + .optimize-details { + margin-top: var(--sp-3); + color: var(--hp-muted); + font-size: var(--fs-s); + overflow-wrap: anywhere; + } + .optimize-details > summary { + width: fit-content; + color: var(--hp-txt); + cursor: pointer; + font-weight: 600; + } + .optimize-details > summary:focus-visible { + outline: 2px solid var(--hp-accent); + outline-offset: 3px; + border-radius: var(--rad-s); + } + .optimize-details ul { margin: var(--sp-3) 0; padding-inline-start: 22px; } + .optimize-details li + li { margin-top: var(--sp-1); } + .btn.alignall { width: 100%; justify-content: center; } + .backupactions { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--sp-3); + } + .backupactions .btn { justify-content: center; min-width: 0; } + .backupupload { display: inline-flex; min-width: 0; } + .backupupload > .btn { width: 100%; justify-content: center; } + .backupupload input { display: none; } + .backupbody { min-width: 0; } + .backupplanonly { margin-inline-start: var(--sp-4) !important; align-items: flex-start !important; } + .backupplanonly > span:first-of-type { display: grid; gap: 2px; white-space: normal; } + .backupplanonly small { color: var(--secondary-text-color); line-height: 1.35; } + .backupplanonlystatus { color: var(--hp-accent) !important; font-weight: 700; } + .backupfile, .backupsummary, .backupcontent { + display: flex; + flex-direction: column; + min-width: 0; + gap: var(--sp-1); + } + .backupfile b, .backupcontent span { + overflow-wrap: anywhere; + } + .backupfile span, .backupsummary span, .backupcontent span { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .backupcounts { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--sp-2) var(--sp-4); + font-size: var(--fs-s); + } + .backupwarn, .backuperror { + border-radius: var(--rad-s); + padding: var(--sp-3); + font-size: var(--fs-s); + line-height: 1.45; + overflow-wrap: anywhere; + } + .backupwarn { background: color-mix(in srgb, var(--hp-accent) 12%, transparent); } + .backuperror { background: rgba(179, 64, 42, .16); color: #ff7a5c; } + .backupdetails { + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: var(--sp-2) var(--sp-3); + font-size: var(--fs-s); + } + .backupdetails summary { cursor: pointer; font-weight: 700; } + .backupdetails > div { display: grid; gap: var(--sp-1); padding-block-start: var(--sp-2); } + .backupdetails code { overflow-wrap: anywhere; color: var(--hp-muted); } + .backupchoices { + display: flex; + flex-direction: column; + gap: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + min-width: 0; + } + .backupchoices label { margin: 0 !important; display: flex; gap: var(--sp-2); } + .backupconfirm { align-items: flex-start !important; } + .backupconfirm > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + } + @media (max-width: 520px) { + .backupactions, .backupcounts { grid-template-columns: 1fr; } + } + .aboutver { + font-size: var(--fs-s); + color: var(--hp-muted); + margin: var(--sp-2) 0 var(--sp-3); + } + .aboutlink { + display: flex; + align-items: center; + gap: var(--sp-3); + width: fit-content; + color: var(--hp-accent); + text-decoration: none; + font-size: var(--fs-m); + padding: var(--sp-1) 0; + } + :host([data-pointer-hover]) .aboutlink:hover { text-decoration: underline; } + .aboutlink ha-icon { --mdc-icon-size: 18px; line-height: 1; } + hp-dialog .body { + padding: var(--sp-5) var(--sp-6); + display: flex; + flex-direction: column; + gap: var(--sp-3); + } + hp-dialog .tapconfirm-body { + min-width: 0; + overflow-x: hidden; + } + hp-dialog .tapconfirm-body p { + max-width: 100%; + min-width: 0; + margin: 0; + overflow-wrap: anywhere; + white-space: normal; + } + hp-dialog .tapconfirm-line { + color: var(--hp-muted); + } + hp-dialog .body label { + font-size: var(--fs-s); + color: var(--hp-muted); + margin-top: var(--sp-3); + } + hp-dialog .body .namein, + hp-dialog .body .areasel { + width: 100%; + box-sizing: border-box; + } + /* Room settings contains long radio labels, two source pickers and live + previews, so it deliberately uses hp-dialog's medium width. Keep its + content shrinkable as well: the generic srcrow rule is nowrap because + compact switch rows need it, but here that created a horizontal scroll + box even on a wide desktop viewport. */ + hp-dialog.roomdialog .body { + min-width: 0; + overflow-x: hidden; + } + hp-dialog.roomdialog .body > * { + min-width: 0; + max-width: 100%; + box-sizing: border-box; + } + hp-dialog.roomdialog .srcrow { + min-width: 0; + align-items: flex-start; + } + hp-dialog.roomdialog .srcrow > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + line-height: 1.35; + } + hp-dialog.roomdialog .dropbtn > b, + hp-dialog.roomdialog .dropbtn > .ref { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + hp-dialog .row { + display: flex; + justify-content: flex-end; + gap: var(--sp-4); + width: 100%; + min-width: 0; + box-sizing: border-box; + padding: var(--sp-5) var(--sp-6); + border-top: 1px solid var(--hp-line); + } + /* Stable destructive/commit footer contract. A flex spacer cannot react + when translated labels no longer fit: justify-content then overflows + the destructive button through the left inset. Two real groups wrap + as units instead — destructive actions stay left, while Cancel/Save + move together to a right-aligned second row when necessary. */ + hp-dialog .row.dialog-action-footer { + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + row-gap: var(--sp-4); + } + hp-dialog .dialog-action-group { + display: flex; + flex: 0 1 auto; + flex-wrap: wrap; + align-items: center; + gap: var(--sp-4); + max-width: 100%; + min-width: 0; + } + hp-dialog .dialog-action-group .btn { + flex: 0 0 auto; + min-height: 44px; + } + hp-dialog .dialog-action-danger { + margin-right: auto; + } + hp-dialog .dialog-action-commit { + margin-left: auto; + justify-content: flex-end; + } + hp-dialog .row.markerfooter { + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + } + hp-dialog .row.roomfooter { + align-items: center; + flex-wrap: wrap; + } + /* Device info can have Edit + Open in HA + Close. It uses a wide dialog; + wrapping remains as a phone fallback, but without a flex spacer (which + used to strand Edit alone on the first line). */ + hp-dialog .row.infofooter { + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + gap: var(--sp-3); + } + hp-dialog .row.infofooter .btn { + flex-shrink: 0; + } + hp-dialog .row.infofooter .infofooter-close { + margin-left: auto; + } + @media (max-width: 480px) { + hp-dialog .row.infofooter { + padding: var(--sp-4) var(--sp-5); + } + } + .markeractions, + .markersaveactions { + display: flex; + align-items: center; + gap: var(--sp-4); + } + .markeractions:empty { display: none; } + .markersaveactions { margin-left: auto; } + .device-inbox { + display: flex; + flex-direction: column; + gap: var(--sp-4); + padding: var(--sp-5) var(--sp-6); + min-width: 0; + } + .device-inbox-dialog { --hp-dialog-wide-width: 920px; } + .device-inbox-head { + display: grid; + grid-template-columns: minmax(180px, 1fr) auto; + align-items: center; + gap: var(--sp-4); + } + .device-inbox-search { + width: 100%; + min-width: 0; + box-sizing: border-box; + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: transparent; + color: var(--hp-txt); + font: inherit; + padding: 11px 14px; + } + .device-inbox-tabs { + display: flex; + gap: var(--sp-2); + overflow-x: auto; + scrollbar-width: thin; + padding-bottom: var(--sp-1); + } + .device-inbox-tabs button { + flex: 0 0 auto; + border: 1px solid var(--hp-line); + border-radius: 999px; + background: transparent; + color: var(--hp-txt); + font: inherit; + padding: 8px 12px; + cursor: pointer; + } + .device-inbox-tabs button.on { + border-color: var(--hp-accent); + background: color-mix(in srgb, var(--hp-accent) 18%, transparent); + } + .device-inbox-tabs button span { color: var(--hp-muted); margin-inline-start: 4px; } + .device-inbox-filters { + display: flex; + flex-wrap: wrap; + gap: var(--sp-4) var(--sp-6); + color: var(--hp-muted); + } + .device-inbox-filters label { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + cursor: pointer; + } + .device-inbox-results { display: grid; gap: var(--sp-3); min-width: 0; } + .device-inbox-row { + display: grid; + grid-template-columns: 42px minmax(180px, 1fr) minmax(180px, auto); + align-items: center; + gap: var(--sp-4); + min-width: 0; + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + padding: var(--sp-4); + background: color-mix(in srgb, var(--hp-txt) 3%, transparent); + } + .device-inbox-icon { --mdc-icon-size: 28px; color: var(--hp-txt); justify-self: center; } + .device-inbox-copy { min-width: 0; } + .device-inbox-name { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); } + .device-inbox-new { + border-radius: 999px; + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + font-size: var(--fs-s); + padding: 2px 7px; + } + .device-inbox-meta, + .device-inbox-reason, + .device-inbox-copy code { + display: block; + color: var(--hp-muted); + font-size: var(--fs-s); + overflow-wrap: anywhere; + white-space: normal; + } + .device-inbox-status { color: var(--error-color, #db4437); margin-inline-start: var(--sp-2); } + .device-inbox-actions { + display: flex; + justify-content: flex-end; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-2); + } + .device-inbox-actions .btn { min-height: 36px; padding: 7px 10px; } + .device-inbox-menu { position: relative; } + .device-inbox-menu summary { list-style: none; cursor: pointer; } + .device-inbox-menu summary::-webkit-details-marker { display: none; } + .device-inbox-menu-items { + position: absolute; + z-index: 2; + inset-inline-end: 0; + top: calc(100% + var(--sp-1)); + display: grid; + gap: var(--sp-1); + min-width: 180px; + padding: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: var(--hp-panel, var(--card-background-color, #fff)); + box-shadow: 0 8px 24px rgba(0, 0, 0, .22); + } + .device-inbox-menu-items .btn { justify-content: flex-start; width: 100%; } + .device-inbox-empty { color: var(--hp-muted); text-align: center; padding: var(--sp-8); } + .device-inbox-more { align-self: center; } + @media (max-width: 680px) { + .device-inbox { padding: var(--sp-4); } + .device-inbox-head { grid-template-columns: minmax(0, 1fr); } + .device-inbox-head .btn { justify-self: stretch; } + .device-inbox-tabs { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + overflow-x: visible; + } + .device-inbox-tabs button { + min-width: 0; + overflow-wrap: anywhere; + } + .device-inbox-row { grid-template-columns: 36px minmax(0, 1fr); } + .device-inbox-actions { grid-column: 1 / -1; justify-content: flex-start; } + } +`];var Wd={"editor.context_actions":"Actions: {object}","editor.tool_options":"Tool options: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Tool group: {group}","editor.group_active":"{group} — active: {item}","editor.disabled_action":"{action} is unavailable: {reason}","editor.loading":"Loading editor…","editor.loading_aria":"The plan editor is loading","editor.load_failed":"Could not load the editor.","editor.refresh_advice":"Refresh the page and try again.","color_picker.title":"Color picker","color_picker.hue":"Hue","color_picker.saturation":"Saturation","color_picker.value":"Brightness","color_picker.hex":"Hex color","color_picker.invalid_hex":"Enter a 3- or 6-digit hex color","btn.properties":"Properties","btn.keep_as_walls":"Keep as walls","btn.delete_room_keep_walls":"Delete room, keep walls","btn.delete_room_with_walls":"Delete room and walls","title.markup_select":"Select and edit walls, columns and saved outlines","title.markup_column":"Column: click a grid point to place a square column","markup.partition":"Partition","markup.column":"Column","markup.hint_column":"click a grid point to place a square column","history.draft_segment":"Add room-draft segment","history.draft_merge":"Join unfinished room outlines","history.draft_segment_delete":"Remove room-draft segment","history.partition_add":"Add partition","history.column_add":"Add column","history.physical_edit":"Change physical object","history.physical_delete":"Delete physical object","history.physical_move":"Move physical object","history.contour_to_partitions":"Convert contour to closed walls","history.wall_chain_finish":"Finish wall chain","history.wall_face_batch":"Create rooms from walls","toast.column_duplicate":"A column with the same centre and outer size already exists","confirm.delete_draft":"Delete the whole unfinished room contour?","confirm.delete_draft_segment":"Delete this draft segment? The remaining contour may split in two.","physical.partition_properties":"Partition properties","physical.column_properties":"Column properties","physical.draft_properties":"Draft segment properties","physical.shape":"Shape","physical.square":"Square","physical.circle":"Circle","physical.diameter":"Diameter","physical.side":"Side","physical.rotation":"Rotation angle","physical.length":"Length","physical.allowed_range":"Allowed: {min}–{max} {unit}","physical.delete_segment":"Delete segment","physical.delete_draft":"Delete entire outline","physical.column_size_title":"Outer side of the square column placed by the click (1–150 cm).","card.title":"House plan","count.devices":"{n} dev.","empty.no_spaces":"No spaces yet.","empty.add_first":"Add the first space and upload a floor plan.","empty.install":'Install the House Plan integration and add it in "Devices & services".',"btn.add_space":"Add space","btn.cancel":"Cancel","btn.save":"Save","btn.close":"Close","btn.delete":"Delete","btn.edit":"Edit","btn.open_in_ha":"Open in HA","btn.reset":"Reset","btn.attach":"Attach…","btn.upload":"Upload…","btn.replace":"Replace…","title.zoom_in":"Zoom in","title.zoom_out":"Zoom out","title.zoom_fit":"Fit all","title.add_device":"Add a device to the plan","title.show_all":"Show hidden and disabled devices as service markers (this tab only)","title.markup":"Room markup: grid, lines, outlines","title.configure_space":"Configure space","title.add_space":"Add space","title.markup_add":"Walls: draw a continuous chain; Shift locks to 45°. Changing tool or leaving the editor finishes it as independent walls","title.markup_merge":"Merge: click one room, then the neighbour it shares a wall with","title.markup_split":"Split a room: click the room, then two points on its walls","title.markup_delroom":"Delete room: click inside a room and confirm","title.need_plan":"Upload a floor-plan image","markup.add":"Walls","markup.merge":"Merge","markup.split":"Split","markup.resize":"Resize","title.markup_resize":"Resize rooms: drag an available horizontal or vertical wall handle","markup.hint_resize":"drag an available wall handle · the wall stops at the first unsafe position · Esc cancels · Ctrl+Z — undo","resize.disabled.diagonal":"This wall is angled; Resize supports only horizontal and vertical walls","resize.disabled.side-angle":"An adjoining wall is angled; Resize requires both adjoining walls to meet this wall at right angles","resize.disabled.duplicate-physical-wall":"A separate partition, unfinished outline, or column overlaps this wall; remove or move it before resizing","resize.disabled.partial-shared":"A neighbouring room uses only part of this wall, so it cannot be moved safely as one shared wall","resize.disabled.unequal-shared":"The neighbouring room uses different endpoints or wall length, so the walls cannot move together safely","resize.disabled.multiple-rooms":"Moving this wall would affect more than two rooms","resize.disabled.thickness-conflict":"The wall thickness cannot be preserved safely","resize.disabled.opening-conflict":"An opening on this wall cannot be moved safely","resize.disabled.invalid-geometry":"This wall cannot be resized without changing the plan structure","resize.limit_stopped":"Wall stopped: the next step would break a junction limit","resize.commit_failed":"Resize was cancelled because the final plan did not pass the geometry check","resize.preview_failed":"Resize stopped at the last safe position because the plan geometry could not be preserved","markup.opening":"Opening","markup.delete_room":"Delete room","history.undo":"Undo","history.redo":"Redo","history.undo_named":"Undo: {name} (Ctrl+Z)","history.redo_named":"Redo: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Nothing to undo","history.redo_empty":"Nothing to redo","history.undone":"Undone: {name}","history.redone":"Redone: {name}","history.add_room":"Create room","history.split_room":"Split room","history.merge_rooms":"Merge rooms","history.resize_room":"Resize room","history.wall_thickness":"Change wall thickness","history.add_opening":"Add door or window opening","history.edit_opening":"Edit opening","history.move_opening":"Move opening","history.delete_opening":"Delete opening","history.delete_room":"Delete room","history.delete_room_keep_walls":"Delete room, keep walls","history.delete_room_with_walls":"Delete room and walls","history.decor_add":"Add decor object","history.decor_edit":"Edit decor object","history.decor_move":"Move decor object","history.decor_transform":"Transform decor object","history.decor_delete":"Delete decor object","history.backdrop_transform":"Transform plan backdrop","title.markup_opening":"Openings: click a wall to place, click an opening to edit","opening.new":"New opening","opening.edit":"Opening","opening.door":"Door","opening.window":"Window","opening.gate":"Gate","opening.passage":"Open passage","opening.passage_binding_warning":"Saving will remove the open/close sensor and lock.","opening.invalid_passage_fields":"The open passage on plan “{room}” has unsupported settings: {fields}.","opening.type_label":"Type","opening.length_label":"Length, cm","opening.contact_label":"Open/close sensor","opening.lock_label":"Lock","opening.none":"— none —","opening.search_ph":"Search: name or entity id…","opening.invert":"Invert open/closed","opening.flip_h":"Hinge on the other jamb","opening.flip_v":"Opens to the other side","opening.open":"Open","opening.closed":"Closed","opening.locked":"Locked","opening.unlocked":"Unlocked","opening.state_unknown":"unavailable","opening.no_entities":"No sensors bound — a static symbol on the plan.","toast.opening_no_wall":"Click next to a room wall or independent wall","opening.host_partition":"Independent wall","opening.partition_orphan":"The independent wall for this opening no longer exists","opening.partition_jamb_margin":"Leave at least {distance} between the opening and the end of the wall","opening.rebind_partition":"Attach to another independent wall","confirm.delete_partition_openings_title":"Delete wall and openings?","confirm.delete_partition_openings_body":"This wall contains {count} opening(s). They will be deleted together.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Delete","markup.hint_points":"points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room","markup.hint_start":"click a grid dot to start a wall chain","tip.lqi":"average zigbee signal:","tip.area":"area: {value}","info.device_header":"Device on the plan","info.model":"Model","info.state":"State","info.link":"Link","info.manuals":"Manuals","info.none":"No additional information","marker.new_device":"New device","marker.name_label":"Name (shown on the plan)","marker.name_ph":"Name","marker.binding_label":"Bind to an HA device","marker.binding_disabled":"disabled in Home Assistant","marker.virtual_option":"Virtual device (no binding)","marker.search_ph":"Search device / group…","marker.nothing_found":"nothing found","marker.room_label":"Room","marker.room_override":" (override placement)","marker.room_choose":"— select a room —","marker.room_auto":"— by device area (auto) —","marker.icon_label":"Icon","marker.icon_ph":"mdi:… (empty = auto)","marker.display_label":"Display","display.badge":"Icon + state","display.icon_ripple":"Icon + state and activity","display.static_icon":"Always static icon","marker.display_hint":"Icon + state changes the plate for work, open, alarm and unavailable states. Icon + state and activity additionally shows a short pulse for events and a continuous pulse for ongoing work, movement or presence. Value + state replaces the icon with one unambiguous HA value. A static icon never reacts to device states.","marker.display_hint_badge":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon_ripple":"The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.","marker.display_hint_value":"One unambiguous Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.","marker.display_hint_static_icon":"The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.","marker.static_alarm_warning":"This device can report alarms. Static display hides the marker's visual alarm indication.","marker.preview.title":"Display preview","marker.preview.actual":"Now","marker.preview.example":"Example","marker.preview.integration":"Provided by","marker.preview.source":"Display source","marker.preview.current_state":"Current state","marker.preview.result":"On the plan","marker.preview.details":"Source details","marker.preview.select_source":"Choose a Home Assistant device or entity to see its actual display.","marker.preview.unknown_provider":"Unknown integration","marker.preview.virtual_provider":"House Plan · virtual device","marker.preview.no_source":"No active source","marker.preview.no_state":"No current state","marker.preview.mixed_states":"Several different states","marker.preview.multiple_sources":"{n} sources","marker.preview.more_sources":"+{n} more","marker.preview.scaled":"The preview is scaled to {n}% to fit. The saved size is unchanged.","marker.preview.demo_activity":"Show activity example","marker.preview.demo_notice":"Temporary activity example; the actual device state is unchanged.","marker.preview.demo_short":"Show short activity","marker.preview.demo_continuous":"Show continuous activity","marker.preview.stop_continuous":"Stop continuous activity","marker.preview.demo_short_notice":"Short activity example; the actual device state is unchanged.","marker.preview.demo_continuous_notice":"Continuous activity example; the actual device state is unchanged.","marker.preview.demo_already_visible":"The current state already shows a real activity or alarm effect.","marker.preview.reduced_motion":"System reduced-motion is enabled, so ordinary activity is shown as a dot.","marker.preview.reason.neutral":"Neutral dark plate","marker.preview.reason.working":"Yellow plate: the device is working now","marker.preview.reason.working_activity":"Yellow plate and activity effect: the device is working now","marker.preview.reason.open":"Orange plate: physically open or unlocked","marker.preview.reason.cover_icon_state":"Neutral plate; the cover entity controls the displayed state and icon","marker.preview.reason.presence":"Activity effect while presence is detected","marker.preview.reason.event":"Short activity effect after a detected event","marker.preview.reason.transition":"Activity effect while the device is moving or changing state","marker.preview.reason.media_neutral":"Media devices stay on a neutral dark plate while available","marker.preview.reason.unavailable":"Subdued neutral plate: unavailable or off","marker.preview.reason.alarm":"Red alarm plate; alarm indication is always shown","marker.preview.reason.live_states_disabled":"Live-state styling is disabled for this card","marker.preview.reason.value_no_state":"No usable state value; the icon is shown instead","marker.preview.reason.value_ambiguous_sources":"Several possible value sources; the icon is shown instead","marker.preview.reason.value_non_scalar":"The source did not return a simple value; the icon is shown instead","marker.preview.reason.value_virtual":"A virtual device has no Home Assistant value; the icon is shown instead","marker.preview.reason.vacuum_live_plan_only":"Live vacuum position and trail are available only on the full plan","marker.preview.reason.hidden_design_preview":"The device is hidden on the plan; this design preview remains visible","marker.preview.reason.composite_power_source":"State comes from the device Power entity; auxiliary switches are ignored","marker.preview.reason.activity_display_disabled":"The selected display mode does not show ordinary activity effects","marker.preview.reason.ha_disabled":"The Home Assistant binding is disabled and will be hidden on the plan","marker.preview.reason.orphaned":"The saved Home Assistant binding can no longer be found","marker.preview.reason.static_icon":"Static mode: device state does not change the icon","marker.activity_color":"Activity pulse color","marker.ripple_size":"Activity pulse size","marker.activity_alarm_note":"Color and size affect ordinary activity only and do not change red alarms.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Recent event","marker.pulse_a11y_presence":"Presence detected","marker.pulse_a11y_transition":"Changing state","marker.pulse_a11y_running":"Working","marker.state_a11y_neutral":"Default state","marker.state_a11y_working":"Working","marker.state_a11y_open":"Open","marker.state_a11y_locked":"Locked","marker.state_a11y_unlocked":"Unlocked","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Unavailable","marker.lqi_a11y_low":"LQI {value}, low signal","marker.lqi_a11y_mid":"LQI {value}, medium signal","marker.lqi_a11y_high":"LQI {value}, high signal","marker.size_label":"Icon size / rotation","marker.angle_label":"Rotate","marker.model_label":"Model","marker.model_ph":"e.g. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Description","marker.desc_ph":"Notes, specs…","marker.manuals_label":"Manuals (PDF etc.)","marker.sub_device":"device","marker.sub_z2m_group":" · Z2M group","marker.sub_group":"group","marker.sub_helper":"helper","space.new":"New space","space.header":"Space","space.title_label":"Title","space.title_ph":"e.g. Garage","space.plan_label":"Floor plan (background)","space.no_plan":"no plan image","space.plan_alt":"plan","room.new":"New room","room.name_label":"Display name","room.name_ph":"e.g. Terrace","room.area_label":"Home Assistant area (unassigned)","room.no_area_option":"— no area —","room.default_name":"Room","device.unnamed":"unnamed","device.light_group":"light group","device.fallback":"device","device.virtual":"virtual device","confirm.delete_room":'Delete room "{name}"?',"confirm.delete_room_title":'Delete room "{name}"?',"confirm.delete_room_body":"Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.","confirm.merge_rooms":'Merge rooms "{a}" and "{b}"?',"confirm.remove_marker":'Delete "{name}" from the plan? The device will disappear completely and stop contributing to plan data. You can add it again later.',"confirm.erase_decor":"Erase the {kind} object? You can undo this action from the editor history.","confirm.delete_space":'Delete space "{title}" with all its rooms and markup?',"space.delete_blocked":"This space is still used by {n} device(s). Move them to another space or delete them first.","toast.pos_save_failed":"Failed to save position: {err}","toast.no_entity":"The device has no suitable entity","toast.ha_disabled_action":"A Home Assistant object that is disabled cannot be used on the plan.","toast.ha_disabled_show_device":"A device disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_show_entity":"An entity disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_add":"A disabled Home Assistant object cannot be added to the plan. Enable it in Home Assistant first.","toast.ha_binding_unverified":"The object status could not be verified through the Home Assistant registry. Display and actions are temporarily unavailable.","toast.markup_needs_server":"Markup is available after the config is moved to the server","toast.space_order_changed":"Order changed. If any card pins its floor by number, check those panels.","toast.conflict":"Config was changed in another window — data refreshed, repeat your last action","toast.cfg_save_failed":"Failed to save config: {err}","toast.room_overlap":"The outline overlaps room “{name}” — rooms must not overlap","toast.contour_min_edges":"Draw at least two edges before closing the outline","toast.contour_cannot_close":"The outline cannot close because it is degenerate or intersects itself","toast.merge_not_adjacent":"Only rooms that share a wall can be merged","toast.rooms_merged":"Rooms merged into “{name}”","toast.split_pick_wall":"Start the cut on the room’s wall","toast.split_bad_cut":"The cut must run wall to wall inside the room, without crossing walls or itself","merge.header":"Merge rooms","merge.hint":"The merged room keeps one name and one area. The other area is released — its devices leave the plan until another room claims it.","merge.keep":"Keep","merge.no_area":"no area","room.split_header":"New room from the split","toast.room_saved":"Room saved ({n}). Devices added: {added}. Outline the next one or exit markup.","toast.room_saved_no_area":"Room saved ({n}, no area). Outline the next one or exit markup.","toast.marker_needs_server":"Device editing is available after the config is moved to the server","toast.virtual_name_required":"Enter a name for the virtual device","toast.marker_saved":"Device saved","toast.marker_removed":"Device deleted from the plan","toast.integration_missing":"The House Plan integration is not installed — management unavailable","toast.plan_formats":"Supported formats: SVG, PNG, JPG, WebP","toast.plan_required":"Upload a floor plan — it is required","toast.space_added_onboard":"Space added. Outline the rooms: click grid dots and close the contour.","toast.space_added":"Space added","toast.space_saved":"Space saved","toast.space_deleted":"Space deleted","toast.delete_failed":"Delete failed: {err}","toast.error":"Error: {err}","toast.toggle_target_unavailable":"Target “{name}” is unavailable — no action was performed","toast.toggle_targets_unavailable":"Targets are unavailable: {names}. No action was performed","toast.file_failed":'File "{name}" was not uploaded: {err}',"toast.files_attached":"Files attached: {n}","err.unknown":"unknown error","err.code":"code {code}","err.too_large":"file larger than {mb} MB","err.bad_ext":"unsupported type (PDF/image expected)","err.unauthorized":"administrator rights required","editor.title":"Title","editor.default_floor":"Initial space","editor.default_floor_missing":"Initial space “{id}” no longer exists. Choose another space.","editor.floor":"Fixed space","editor.floor_none":"— not fixed —","editor.floor_index":"YAML index {index} (preserved)","fixed_floor.loading":"Loading the fixed space…","fixed_floor.invalid_title":"The fixed space is unavailable","fixed_floor.invalid_body":"Check floor in the card configuration. The configured value is: {value}","editor.icon_size":"Icon size, % of plan width","editor.show_temperature":"Show temperature","editor.live_states":"Live states (on/off, open…)","editor.show_signal":"Show zigbee signal (LQI)","editor.language":"Interface language","editor.lang_auto":"Auto (HA profile)","editor.lang_en":"English","editor.lang_ru":"Русский","title.icon_rules":"Icon rules: which MDI icon devices get by name","rules.title":"Icon rules","rules.hint":"Rules are checked top-down against “device name + model” (case-insensitive regex); the first match wins. When nothing matches, the entity device class decides, then the generic chip icon.","rules.pattern_ph":"regex, e.g. plug|socket","rules.icon_ph":"mdi:power-socket-de","rules.add":"Add rule","rules.reset":"Reset to defaults","rules.test_ph":"Try a device name…","rules.invalid":"invalid regex","rules.saved":"Icon rules saved","btn.up":"Up","btn.down":"Down","tap.info":"Device card","tap.more_info":"HA more-info dialog","tap.toggle":"Toggle state","marker.tap_label":"Tap action for this device","tap.toggle_note":"The resolved state is shown below. Secure devices are never toggled from the plan.","import.title":"Create spaces from HA floors","import.hint":"Your Home Assistant already knows these floors. Pick the ones to turn into plan spaces — you will upload a floor-plan image for each one next. Rooms are then outlined by hand on the plan.","import.start":"Create {n} space(s)","import.manual":"Start from scratch","import.progress":"Floor {i} of {n}","import.done":"Spaces created. Outline the rooms: click grid dots and close the contour.","btn.skip":"Skip","space.scale_label":"Scale (grid cell size)","space.scale_unit":"cm per cell","space.scale_unit_imperial":"in per cell","space.display_section":"Display","space.show_borders":"Always show room borders","space.zero_wall_style":"Zero-thickness walls","space.zero_wall_dashed":"Dashed","space.zero_wall_solid":"Solid","space.zero_wall_help":"Dashed walls let light through. Solid walls block light even at zero thickness.","space.show_names":"Show room names (drag to move)","space.room_color":"Border & name color","space.opacity":"Opacity","space.fill_label":"Room fill","fill.none":"None","fill.lqi":"Zigbee signal","fill.light":"Lights","fill.custom":"Custom color","space.custom_fill":"Fill color","space.source_file":"I have a floor-plan image","space.source_draw":"No image — I'll outline rooms by hand","space.orientation":"Canvas","orient.landscape":"Landscape","orient.portrait":"Portrait","orient.square":"Square","fill.temp":"Temperature","space.temp_min":"Comfort from","space.temp_max":"to","tip.temp_avg":"average temperature:","tip.hum_avg":"average humidity:","space_card.button":"Open the space plan","space_card.not_found":"Space “{id}” not found","space_card.loading":"Loading…","continuity.restore_plan":"Restoring floor plan…","continuity.restore_connection":"Restoring device connection…","continuity.retry":"Try again","editor.space":"Space","editor.show_button":"Show button","editor.button_label":"Button label","editor.button_target":"Target dashboard path","marker.sub_entity":"entity","title.general_settings":"General settings","gs.title":"General settings","gs.hint":"Fill colors apply to every space; each color has its own opacity. Which fill mode a space uses is set in that space's dialog.","gs.light_group":"Fill: lights","gs.light_on":"Lights on","gs.light_off":"All lights off","gs.temp_group":"Fill: temperature","gs.temp_cold":"Cold","gs.temp_ok":"Comfortable","gs.temp_hot":"Hot","gs.lqi_group":"Fill: zigbee signal","gs.lqi_low":"Weak signal","gs.lqi_high":"Strong signal","gs.reset":"Reset to defaults","gs.saved":"General settings saved","space.show_lqi":"Show zigbee signal (LQI) next to devices","space.hide_decor":"Hide the decorative layer","space.hide_decor_tip":"Lines, shapes, labels and furniture stay where they are — visible in the backdrop editor, not on the plan.","space.hide_openings":"Hide openings","space.hide_openings_tip":"Door, window and gate symbols are not drawn, but the openings keep working: light passes through, the sun comes in at a window, contact sensors still open them. The plan editor always shows them.","gs.light_none":"No light sources","mode.plan":"Plan editor","mode.devices":"Device editor","display.value":"Value + state","marker.subarea":"no area, manual","device.new":"New device — open its editor to dismiss","opening.unlock_action":"Unlock","opening.lock_action":"Lock","opening.lock_pending":"Working…","title.close_editor":"Close editor (back to view)","devbar.add":"Add","devbar.show_all":"Hidden and disabled","devbar.rules":"Icon rules","device_inbox.button":"Devices","device_inbox.title":"Devices on the plan","device_inbox.search":"Search devices, entities and integrations…","device_inbox.add_virtual":"Add virtual device","device_inbox.tab_on_plan":"On plan","device_inbox.tab_available":"Available","device_inbox.tab_hidden":"Hidden","device_inbox.tab_readd":"Available again","device_inbox.only_new":"New only","device_inbox.show_entities":"Show entities","device_inbox.show_hidden":"Show hidden on plan","device_inbox.new":"New","device_inbox.find":"Find on plan","device_inbox.edit":"Edit","device_inbox.hide":"Hide","device_inbox.show":"Show","device_inbox.add":"Add","device_inbox.readd":"Add again","device_inbox.hide_available":"Hide from list","device_inbox.show_more":"Show more","device_inbox.more_actions":"More actions","device_inbox.find_hidden_hint":"Enable “Show hidden on plan” first","device_inbox.show_disabled":"Activate this binding in Home Assistant before showing it","device_inbox.empty_on_plan":"No matching devices are on the plan yet.","device_inbox.empty_available":"No devices are available to add.","device_inbox.empty_hidden":"There are no hidden devices.","device_inbox.empty_readd":"No removed devices are available to add again.","device_inbox.reason_visible_auto":"Discovered automatically","device_inbox.reason_visible_explicit":"Added explicitly","device_inbox.reason_manual_hidden":"Hidden by user","device_inbox.reason_automatic_hidden":"Hidden automatically","device_inbox.reason_service_entry":"Service-only registry entry","device_inbox.reason_excluded_integration":"Integration excluded by device filters","device_inbox.reason_excluded_domain":"Non-spatial entity type","device_inbox.reason_grouped_light":"Represented by a room light group","device_inbox.reason_represented_by_parent":"Represented by its parent device","device_inbox.reason_removed":"Previously removed from the plan","device_inbox.reason_available":"Available to add to the plan","device_inbox.reason_no_bound_room":"HA area is not linked to a plan room","device_inbox.status_ha_disabled":"Disabled in Home Assistant","device_inbox.status_orphaned":"Binding is no longer present in Home Assistant","device_inbox.status_unverified":"Home Assistant registry is temporarily unavailable","device_inbox.saved":"Device list updated","space.roomcard_section":"Room card shows:","space.label_temp":"Temperature","space.label_hum":"Humidity","space.label_lqi":"Average Zigbee signal","space.label_light":"Lights on/off","roomcard.light_on":"On","roomcard.light_off":"Off","roomcard.light_partial":"{on} of {total}","toast.split_pick_inside":"Intermediate cut points must be inside the room","mode.decor":"Background editor","decor.select":"Select","decor.line":"Line","decor.rect":"Rectangle","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Erase","decor.erase_confirm_title":"Erase object?","decor.color":"Color","decor.width":"Line width","decor.line_style":"Line style","decor.line_style_solid":"Solid","decor.line_style_dashed":"Dashed","decor.fill":"Fill","decor.fill_color":"Fill color","decor.length":"Length","decor.size":"Size","decor.angle":"Rotation angle, °","decor.text_size":"Text size","decor.backdrop_properties":"Plan backdrop properties","decor.text_title":"Text label","decor.object_title":"Edit {kind}","decor.text_label":"Text","decor.live_group":"Insert HA variable","decor.live_entity":"Entity","decor.live_entity_ph":"choose an entity","decor.live_attr":"Value","decor.live_attr_ph":"choose state or attribute","decor.live_state":"State","decor.backdrop":"Backdrop image","decor.backdrop_hint":"Drag to move; pull a corner to resize; use the top handle to rotate. Shift changes proportions or frees the angle.","decor.backdrop_reset":"Reset the picture","decor.backdrop_reset_done":"The picture is back at its original place and size","marker.icon_auto":"Auto: {icon} (by icon rules; pick one to override)","marker.icon_pin_auto":"Pin","mode.plan_tip":"Plan editor — the geometry of the home: draw and split/merge rooms, bind them to HA areas, place doors, windows and gates, move room cards, set the scale","mode.devices_tip":"Device editor — everything about icons: drag to position, click to edit binding/icon/display, add virtual devices, icon rules","mode.decor_tip":"Background editor — purely visual decor under the plan: lines, rectangles, ovals and text labels that never react to clicks","space.glow_enabled":"Light-source glow","gs.glow_group":"Light-source glow","gs.glow_base":"House darkness","gs.glow_light":"Default light color / intensity","gs.wall_group":"Walls","gs.wall_fill":"Wall fill","gs.glow_radius":"Glow radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Controls other light sources","marker.controls_hint":"With tap action “Toggle”, a click flips every source added here. The marker’s own bound entity is controlled directly and cannot be added; use the switch below to classify it as a light.","marker.controls_filter":"Search lights and switches…","info.controls":"Controls","marker.glow_radius_label":"Glow radius","marker.glow_radius.help":"Sets the glow radius in metres or feet; an empty value uses the radius from general settings.","marker.glow_radius.help.aria":"Help: glow radius","markup.wallthick":"Thickness","markup.select":"Select","title.markup_wallthick":"Thickness — click a wall to set its thickness from 0 to 100 cm.","markup.hint_wallthick":"click a wall · Esc closes without applying","wallthick.field":"Thickness","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Apply to all walls of this room","markup.draw_wall_title":"Thickness of each new wall segment (0–100 cm). Shared walls keep the existing value.","room.queue_progress":"Room {current} of {total}","toast.wall_rooms_saved":"Created rooms: {n}","toast.wall_chain_saved":"Wall chain saved","toast.wallthick_pick":"Click a wall","toast.wallthick_set":"Wall thickness set","toast.wallthick_cleared":"Wall thickness removed","toast.physical_range":"Enter a value from {min} to {max} {unit}","toast.zero_wall_opening_conflict":"Remove the opening on this wall segment first.","toast.zero_wall_ambiguous":"The wall segment is ambiguous. Simplify or adjust the junction.","toast.zero_wall_migration_blocked":"The space was not converted: {reason}. No data was changed.","toast.physical_angle":"Enter a rotation angle from 0° up to, but not including, 90°","toast.physical_limit":"The space has reached the limit for this type of geometry","toast.geometry_unsafe":"Change canceled: wall geometry could not be built safely.","junction.limit_angle":"The angle between walls is too sharp: {actual}°, minimum {limit}°.","junction.limit_valence":"Too many walls meet in one node: {actual}, maximum {limit}.","junction.limit_length":"The wall segment is too short: {actual} cm, minimum {limit} cm.","junction.limit_distance":"Walls and nodes are too close: {actual} cm, minimum {limit} cm.","junction.limit_clearance":"No room interior is left: {actual} cm², minimum {limit} cm².","junction.limit_check_failed":"The junction check could not run — the change was not saved","toast.wall_model_migration_blocked":"The wall model could not be updated: {reason}. The plan was not changed. Run “Optimize plans”; if the error repeats, fix the conflicting wall geometry.","toast.wall_model_client_outdated":"Update the card and reload the page before editing the plan.","wall_model.reason.invalid-room":"invalid room contour","wall_model.reason.zero-length":"zero-length wall segment","wall_model.reason.third-owner":"wall shared by more than two rooms","wall_model.reason.duplicate-id":"conflicting wall identifiers","wall_model.reason.thickness-conflict":"conflicting wall thickness values","wall_model.reason.opening-host":"opening cannot be assigned to one wall","toast.delete_room_pick":"Click inside the room you want to delete","toast.plan_snap_ambiguous":"Zoom in to choose the wall node","toast.wall_repair_ambiguous":"The room outline has more than one possible connection. Zoom in and connect it explicitly.","toast.wall_repair_too_large":"The gap is larger than 2 cm. Connect the walls before creating the room.","toast.wall_repair_changed":"The wall geometry changed. Try creating the room again.","toast.opening_on_zero_wall":"Openings cannot sit on a zero-thickness wall","marker.from_ha_option":"Pick from the HA list","marker.show_entities":"Show entities","marker.show_entities_tip":"Adds not only devices to the list, but all their entities too","marker.pick_ph":"Choose a device…","room.open_area":"Open the HA area","view.volumetric":"Volumetric view","view.flat":"Flat view","kiosk.title":"This screen's sizes","kiosk.hint":"Stored on this device only — every wall tablet or TV can have its own comfortable sizes.","kiosk.icon_scale":"Device icon size","kiosk.font_scale":"Room card text size","editor.kiosk":"Wall device (kiosk) mode","editor.cycle":"Auto-switch spaces every N seconds (kiosk, 0 = off)","room.settings_title":"Room settings","room.settings_section":"Room settings (override the space)","room.fill_label":"Fill in THIS room","fill.inherit":"As the space","room.custom_fill_space":"Space color","room.custom_fill_own":"Room color","room.temp_src_label":"Temperature source","room.hum_src_label":"Humidity source","room.src_average":"Average over the room's sensors (default)","room.src_pick":"A specific HA device or entity","room.src_ph":"Choose a source…","toast.room_updated":"Room updated","space.card_font":"Room-card font size (whole space)","room.sizes_section":"Font sizes","room.name_scale":"Room name size","room.label_scale":"Metrics size","preview.room_name":"Living room","toast.cfg_reload_failed":"Could not reload the plan from the server: {err}","room.settings_short":"Room settings","room.unnamed":"Unnamed room","marker.use_climate_temp":"Include the device temperature in the room","marker.use_climate_temp_tip":"Adds an air conditioner or thermostat current_temperature to the room average. Configure the external value badge separately below.","marker.value_badge_title":"Value badge","marker.value_badge.help":"Shows one selected value next to the icon. It does not affect room metrics, light, Glow or the tap action.","marker.value_badge.help.aria":"Help: device value badge","marker.value_badge_enabled":"Show a value badge","marker.value_badge_source":"Value","marker.value_badge_source.help":"Choose a specific state, supported attribute, or derived value of this device.","marker.value_badge_source.help.aria":"Help: value badge source","marker.value_badge_position":"Position","marker.value_badge_position.help":"The chosen side stays fixed and does not flip automatically at a plan edge.","marker.value_badge_position.help.aria":"Help: value badge position","marker.value_badge_right":"Right","marker.value_badge_bottom":"Below","marker.value_badge_left":"Left","marker.value_badge_top":"Above","marker.value_badge_empty":"This device has no available values","marker.value_badge_static":"A static icon does not show live values. The setting is preserved.","marker.value_badge_missing":"Source unavailable","marker.value_badge_missing_hint":"The saved source is currently unavailable. Keep it, disable the badge, or choose another value.","marker.value_badge_duplicate":"The same value is already shown inside the icon.","marker.value_badge_state":"State · {name}","marker.value_badge_marker_state":"Light-source state · {name}","marker.value_badge_lqi":"Average Zigbee signal quality","marker.value_badge_attr_current_temperature":"Current temperature · {name}","marker.value_badge_attr_temperature":"Target temperature · {name}","marker.value_badge_attr_current_humidity":"Current humidity · {name}","marker.value_badge_attr_humidity":"Humidity · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Speed · {name}","marker.value_badge_attr_brightness":"Brightness · {name}","marker.value_badge_attr_volume_level":"Volume · {name}","marker.value_badge_attr_battery_level":"Battery · {name}","marker.value_badge_attr_fan_speed":"Fan speed · {name}","marker.light_role_label":"Is this device a light source?","marker.light_role.help":"Controls whether this marker itself is a spatial light source. Linked lights above remain independent room-light controls.","marker.light_role.help.aria":"Help: whether this device is a light source","marker.light_role_auto_yes":"Auto (light source)","marker.light_role_auto_no":"Auto (not a light source)","marker.light_role_always":"Always a light source","marker.light_role_never":"Never a light source","marker.light_entity_label":"Leading light entity","marker.light_entity.help":"For a composite device, choose the entity whose state, colour and brightness represent this plan source. The automatic fallback remains compatible with older plans.","marker.light_entity.help.aria":"Help: leading light entity","marker.light_entity_auto":"Automatic ({entity})","marker.light_entity_none":"no controllable entity","marker.light_entity_missing":"The saved entity {entity} is unavailable. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.toggle_entity_label":"Entity to toggle","marker.toggle_entity.help":"For a composite device, choose the exact own light or switch operated by a tap. Automatic keeps the previous target rules and is independent from the leading light entity.","marker.toggle_entity.help.aria":"Help: entity to toggle","marker.toggle_entity_auto":"Automatic ({entity})","marker.toggle_entity_none":"no own controllable entity","marker.toggle_entity_missing":"The saved entity {entity} is no longer among this marker’s selectable channels. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.glow_color_label":"Glow colour and brightness","marker.glow_mode.help":"Use live source values, override only its colour, or fix both colour and brightness. The minimum is 1%; to disable the source, choose “Never”.","marker.glow_mode.help.aria":"Help: glow colour and brightness","marker.glow_mode_auto":"From source","marker.glow_mode_color":"Set colour","marker.glow_mode_fixed":"Set colour and brightness","marker.glow_color":"Glow colour","marker.glow_brightness":"Brightness","marker.glow_disabled_never":"Glow settings are unavailable because this marker is explicitly not a light source.","marker.glow_disabled_auto":"Auto mode found no spatial light source for this marker.","marker.glow_disabled_no_entity":"No active controllable Home Assistant entity is available for this spatial source.","marker.glow_passive_hint":"This source has no own Home Assistant data. Set its colour and brightness manually; its radius remains available.","marker.control_broken":"Saved source is missing or no longer marked as a light","marker.control_missing_label":"Missing plan light","marker.control_passive":"passive source","toast.marker_control_cycle":"This link would create a circular chain of light controls.","toast.marker_binding_required":"Choose a Home Assistant device before linking another light source.","confirm.unlock":"Unlock “{name}”?","toast.files_migrate_failed":"Attachments could not be moved to the new binding, links keep pointing at the old files: {err}","space.pick_saved":"Already uploaded","space.pick_saved_hint":"Plans stored on the server, including ones you detached earlier","space.no_saved":"No plans stored on the server yet.","space.loading":"Loading…","space.used_by":"in use: {list}","space.in_use":"A space still uses this plan — detach it first","btn.use":"Use","confirm.delete_plan":'Delete the plan file "{name}" from the server? This cannot be undone.',"toast.plans_list_failed":"Could not list the stored plans: {err}","toast.plan_delete_failed":"Could not delete the plan: {err}","marker.hide":"Hide","marker.hide_tip":'The device will disappear from the plan after saving but will still count toward the room signal. Restore it through the "Devices" catalog in the device editor.',"marker.show":"Show","marker.show_tip":"The device will appear on the plan again after saving.","marker.hidden_ghost":"Device hidden by the user","marker.ha_disabled_device":"The device is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_entity":"The entity is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_all_entities":"The device has no active Home Assistant entities, so it is hidden from the plan.","marker.ha_registry_limited":"The full Home Assistant registry is unavailable to this user. The unverified object cannot be shown or used for now.","marker.delete_tip":"Completely delete the device from the plan and every aggregate. You can add it again later.","tap.run":"Run automation/script/scene","tap.cover":"Open/close (curtains/blinds)","marker.run_target_label":"What to run","marker.run_search_ph":"Search: automation, script or scene…","marker.run_target_gone":"Target {id} not found — pick again","marker.tap_confirm":"Ask for confirmation","marker.tap_confirm_tip":"Show a confirmation dialog before acting — a guard against accidental taps.","marker.toggle_hint_single":"Target: {name} ({id}).","marker.virtual_light_target":"Virtual light: {name}.","marker.virtual_light_current":"Manual state: {state} → {effect}.","marker.virtual_light_state_on":"on","marker.virtual_light_state_off":"off","marker.toggle_hint_group":"Will toggle {count} source(s): {names}.","marker.toggle_hint_current":"Now: {state} → {effect}.","marker.toggle_hint_group_current":"Currently on: {on} of {count} → {effect}.","marker.toggle_hint_skipped":"Will be skipped ({count}): {targets}.","marker.toggle_effect_turn_on":"will turn on","marker.toggle_effect_turn_off":"will turn off","marker.toggle_effect_open":"will open","marker.toggle_effect_close":"will close","marker.toggle_effect_stop":"will stop","marker.toggle_effect_toggle":"state will toggle","marker.toggle_skip_missing":"not found","marker.toggle_skip_ha_disabled":"disabled in HA","marker.toggle_skip_unavailable":"unavailable","marker.toggle_skip_unsupported":"toggle is unsupported","marker.toggle_skip_secure":"blocked for security","marker.toggle_none_no_binding":"This device has no binding, so there is no state to toggle. Tapping will do nothing.","marker.toggle_none_no_actionable_entity":"This device has no state that can be toggled. Tapping will do nothing.","marker.toggle_none_configured_targets_missing":"The configured targets are unavailable. The device's own entity will not be substituted for them.","marker.toggle_none_ha_disabled":"The target is disabled in Home Assistant and cannot be used on the plan.","marker.toggle_none_unavailable":"The target is currently unavailable. Tapping will do nothing.","marker.toggle_none_unsupported":"Home Assistant exposes no safe toggle operation for this entity. Tapping will do nothing.","marker.toggle_none_secure":"Toggling locks, alarms and secure gates from the plan is blocked for security.","run.automation":"automation","run.script":"script","run.scene":"scene","confirm.tap_run":'Run "{name}"?',"confirm.tap_toggle":'Toggle "{name}"?',"confirm.tap_cover":'Open/close "{name}"?',"confirm.current_state":"Current state: {state}","confirm.expected_state":"After switching: {state}","confirm.group_current":"on {on} of {total}","confirm.group_all_on":"all are on","confirm.group_all_off":"all are off","confirm.unavailable_targets":"Unavailable: {count}","confirm.expected_by_ha":"Home Assistant will determine the state","confirm.state_on":"On","confirm.state_off":"Off","confirm.state_open":"Open","confirm.state_closed":"Closed","confirm.state_opening":"Opening","confirm.state_closing":"Closing","confirm.state_stopped":"Stopped","confirm.state_unknown":"Unknown","toast.run_started":"Started: {name}","toast.run_target_missing":"Run target not found — check the device settings","toast.run_target_required":"Pick an automation, script or scene","toast.tap_target_changed":"The action target changed. Try again.","toast.virtual_light_toggle_failed":"Could not toggle the virtual light: {err}","toast.value_badge_source_required":"Choose a value for the badge","btn.run":"Run","vac.section":"Robot vacuum: live position","vac.autocal":"Set up automatically","vac.live":"Live position on the plan","vac.trail":"Show the robot's path","vac.cal_maps":"Calibrated maps: {maps}","vac.autocal_no_rooms":"The integration reports no room list — open “Fit manually”","vac.autocal_no_match":"Room names did not match (need ≥3 in common) — open “Fit manually”","vac.autocal_done":"Done: bound via {rooms} rooms. Start a cleanup and check","vac.cal_need_pos":"The robot is not reporting coordinates — start a cleanup and pause it","vac.cal_done":"Calibration saved. Start a cleanup and check","vac.cal_cancelled":"Calibration cancelled","vac.fit":"Fit manually","vac.fit_hint":"Drag the robot map into place, stretch by the corners","vac.fit_rotate":"Rotate 90°","vac.fit_mirror":"Mirror","vac.trail_never":"Never","vac.trail_cleaning":"While cleaning","vac.trail_always":"Always","gs.bg_group":"Stage background","gs.bg_color":"Background around the plan","gs.bg_default":"Theme default","gs.bg_theme":"theme default","gs.bg_mode":"Plan background","gs.bg_static":"Static color","gs.bg_daynight":"Follows the Sun","gs.bg_daynight_hint":"The background moves through dawn, day, dusk and night using sun.sun, or your local clock when sun data is unavailable. No compass is needed for the background.","gs.sun_group":"Sun","gs.sun_missing":"The sun.sun entity was not found — the background follows your local clock; window rays are unavailable.","gs.north":"North on the plan","gs.north_ph":"not set","gs.north_hint":"Set north only for window rays (1° steps, 15° with Shift); the Sun background works without it.","gs.north_clear":"Clear","gs.north_letter":"N","gs.sun_rays":"Sunlight through windows","gs.about_group":"About","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · docs & issues","gs.about_telegram":"Telegram chat","space.bg_color":"Background around the plan","space.bg_inherit":"Inherit general","space.bg_inherited":"inherits general settings","space.bg_mode":"Plan background","space.north":"North on the plan (override)","space.north_inherited":"inherited: {v}","space.sun_rays":"Sunlight through windows","space.sun_inherit":"Inherit general","space.sun_on":"On","space.sun_off":"Off","canvas.far_objects":"{n} object(s) far from the plan","canvas.show_far":"Show","canvas.home_tip":"The plan is over there — click to fit it","gs.grid_group":"Plan maintenance","gs.grid_hint":"Updates data models, aligns plan elements to the grid and merges redundant wall fragments. An exact report is shown before anything is stored.","gs.align_all":"Optimize plans","gs.align_title":"Optimize plans","gs.align_none":"All plans already use the current optimized data model.","gs.optimize_no_automatic_changes":"There are no automatic changes to apply. Review the items below.","gs.align_count":"{n} of {total} elements will move, by at most {cm} cm.","gs.align_where":"The largest shift is in “{s}”.","gs.align_turned":"Openings whose angle is corrected: {n}.","gs.align_removed_drafts":"Invalid outlines collapsed by the grid and removed: {n}.","gs.optimize_redundant_drafts":"Saved wall chains hidden by solid room walls and removed: {n}.","gs.align_preflight_failed":"Could not safely verify the geometry of the following spaces: {spaces}{more}.","gs.align_preflight_hint":"Plans were not changed. Copy the diagnostics with the button below and attach them to the bug report together with a space export.","gs.preflight_reason_prepare-exception":"Could not prepare the space geometry (exception while building the model)","gs.preflight_reason_wall-null":"The wall body did not build (the union came back empty)","gs.preflight_reason_wall-degraded-extra":"The wall body degraded with extra geometry","gs.preflight_reason_wall-failed-core":"The wall body core failed to assemble","gs.preflight_reason_wall-exception":"Wall construction threw an exception","gs.preflight_reason_floor-null":"The floor outline did not build","gs.preflight_reason_floor-exception":"Floor construction threw an exception","gs.preflight_copy":"Copy diagnostics","gs.preflight_copied":"Diagnostics copied","gs.preflight_update_hint":"The card and integration versions differ — update House Plan and retry.","gs.align_preflight_space":"Space {n}","gs.align_preflight_more":", and {n} more","gs.optimize_changes":"Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.","gs.zero_walls_migrated":"Virtual wall spans converted: {n}.","gs.wall_segments_migrated":"Wall segments stabilised: {n}.","gs.optimize_lattice_summary":"Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.","gs.optimize_lattice_space":"{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.","gs.optimize_coincident_partitions":"Hidden independent wall sections absorbed into room walls: {n}.","gs.optimize_openings_rehosted":"Openings reattached to room walls: {n}.","gs.optimize_walls_straightened":"Walls straightened: {n}; maximum movement: {cm} cm.","gs.optimize_walls_straightened_where":"Largest wall correction: {s}.","gs.optimize_walls_straighten_skipped":"Near-axis walls left unchanged because they could not be repaired safely: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} spaces → no data fill + independent Glow; {rooms} rooms → inherited data fill + independent Glow.","gs.optimize_references":"References repaired: spaces — {spaces}; rooms — {rooms}; positions — {positions}; devices detached from missing spaces — {detached}.","gs.optimize_reference_more":", and {n} more","gs.optimize_orphans_removed":"Forgotten records removed: {total} — room labels: {rooms}; devices: {devices}; group markers: {groups}. They belonged to spaces deleted earlier.","gs.optimize_live_positions":"Old positions in deleted spaces belong to existing objects: {n}{names}. They will be kept.","gs.optimize_live_positions_remove":"Old positions in deleted spaces belong to existing objects: {n}{names}. They are selected for removal.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Remove old positions","gs.optimize_live_keep":"Keep old positions","gs.optimize_live_selected":"Old positions will be removed after Optimize is applied.","gs.optimize_unverified":"Could not safely verify positions: {n}. They were left unchanged.","gs.optimize_registry_limited":"Full administrator access to the Home Assistant registries is required for a safe check.","gs.optimize_vacuum_warning":"Vacuum room mappings that still need review: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"And {n} more records.","gs.optimize_detail_removed":"will be removed","gs.optimize_detail_live":"will be kept","gs.optimize_detail_unverified":"not verified","gs.optimize_detail_room_label":"room label","gs.optimize_detail_device":"device","gs.optimize_detail_group":"group marker","gs.optimize_detail_unknown":"unknown owner","gs.optimize_detail_item":"{status}: {kind} {id}; old space {space}","gs.align_warn":"Elements deliberately placed between grid nodes will move. One undo is available after the operation, only until the next plan edit.","gs.align_run":"Optimize","gs.align_done":"Plans optimized: {n} elements moved, {m} records maintained, {r} references repaired","gs.optimize_undo":"Undo last optimization","gs.optimize_undone":"The last optimization was undone","decor.furniture":"Furniture","furn.title":"Furniture library","furn.symbol":"Symbol","furn.group_furniture":"Furniture","furn.group_appliance":"Appliances","furn.group_sanitary":"Plumbing","furn.group_other":"Other","furn.width":"Width","furn.depth":"Depth","furn.pick_hint":"Pick a symbol, then click on the plan.","furn.place_hint":"Click on the plan — the piece lands against the nearest wall. Shift places it free.","furn.sym_sofa":"Sofa","furn.sym_armchair":"Armchair","furn.sym_coffee_table":"Coffee table","furn.sym_table_dining":"Dining table","furn.sym_table_round":"Round table","furn.sym_chair":"Chair","furn.sym_desk":"Desk","furn.sym_bed_double":"Double bed","furn.sym_bed_single":"Single bed","furn.sym_nightstand":"Nightstand","furn.sym_wardrobe":"Wardrobe","furn.sym_bookshelf":"Bookshelf","furn.sym_fridge":"Fridge","furn.sym_stove":"Cooker","furn.sym_dishwasher":"Dishwasher","furn.sym_washer":"Washing machine","furn.sym_dryer":"Tumble dryer","furn.sym_tv":"TV","furn.sym_ac":"Air conditioner","furn.sym_water_heater":"Water heater","furn.sym_toilet":"Toilet","furn.sym_bathtub":"Bathtub","furn.sym_shower":"Shower","furn.sym_sink":"Washbasin","furn.sym_kitchen_sink":"Kitchen sink","furn.sym_bidet":"Bidet","furn.sym_stairs":"Stairs","furn.sym_fireplace":"Fireplace","furn.sym_plant":"Plant","furn.sym_rug":"Rug","common.yes":"Yes","common.no":"No","vac.diag_source":"Source","vac.diag_platform":"Integration","vac.diag_status":"Status","vac.diag_position":"Position","vac.diag_rooms":"Rooms","vac.diag_rooms_value":"{total} · {matched} names match · {readiness}","vac.autocal_ready":"auto-calibration available","vac.autocal_not_ready":"need 3 matching names","vac.diag_path":"Integration path","vac.diag_map":"Map ID","vac.source_none":"not selected","vac.source_status_ok":"Ready","vac.source_status_missing":"Missing","vac.source_status_disabled":"Disabled in Home Assistant","vac.source_status_unavailable":"Unavailable","vac.source_status_unverified":"Cannot verify with current permissions","vac.source_status_unsupported":"No position data","vac.source_status_none":"No source","vac.source_banner_missing":"The saved source no longer exists. It was not replaced automatically; choose another source or restore it in Home Assistant.","vac.source_banner_disabled":"The saved source is disabled in Home Assistant. Enable it there or choose another source.","vac.source_banner_unverified":"Current Home Assistant permissions cannot verify this saved source. It remains pinned and will not be replaced automatically.","vac.choose_source":"Choose source","vac.source_auto":"Automatic","vac.source_auto_hint":"Use a compatible entity from this device","vac.all_cameras":"All cameras","vac.all_cameras_warn":"A camera may not provide robot data. Choose one only if it is your vacuum map.","vac.all_cameras_empty":"No other camera entities found.","vac.platform_unknown":"unknown integration","vac.cap_position":"position","vac.cap_rooms_short":"rooms","vac.cap_path":"path","vac.cap_map":"map ID","vac.cap_none":"no robot data detected","vac.xcme_hint":"Enable these Xiaomi Cloud Map Extractor attributes:","vac.documentation":"Documentation","vac.residual_title":"Check automatic calibration","vac.residual_message":"The matched rooms disagree by up to {error}. Apply this approximate calibration, refine it manually, or cancel without changing the saved setup.","vac.apply_proposal":"Apply","gs.backup_group":"Backup and transfer","gs.backup_hint":"Download a portable JSON backup or preview and import a backup made by House Plan.","backup.export_open":"Export","backup.import_open":"Import","backup.export_title":"Export House Plan","backup.import_title":"Import House Plan","backup.export_hint":"Choose whether the backup should contain the whole House Plan configuration or only the current space.","backup.full":"Full backup","backup.current_space":"Current space","backup.current_space_title":"Current space: {title}","backup.no_current_space":"No current space","backup.plan_only":"Plan only","backup.plan_only_hint":"Keep rooms, walls, openings, decor and room-label positions without devices or Home Assistant bindings.","backup.plan_only_preview":"This file contains the plan only","backup.privacy_warning":"The archive keeps names, Home Assistant identifiers and exact coordinates. Internal plans and attachments are referenced, not embedded; runtime states and vacuum trails are not included.","backup.download":"Download JSON","backup.export_done":"Backup downloaded","backup.reading":"Checking the backup…","backup.revalidated":"The plan changed after this preview. The summary was refreshed; review it and confirm again.","backup.error.unauthorized":"You do not have permission to export or import this plan.","backup.error.not_ready":"House Plan is not ready yet. Try again in a moment.","backup.error.too_large":"The backup exceeds the 8 MiB limit.","backup.error.invalid_json":"The selected file is not valid JSON.","backup.error.invalid_format":"The selected file is not a House Plan backup.","backup.error.unsupported_export_version":"This backup format is not supported by the installed version.","backup.error.future_model":"The backup was created by a newer House Plan data model.","backup.error.invalid_config":"The backup contains an invalid House Plan configuration.","backup.error.wall_model_migration_blocked":"The backup wall model could not be upgraded safely. Optimize the source plan first, then export it again.","backup.error.invalid_layout":"The backup contains invalid object positions.","backup.error.invalid_content":"The backup contains invalid or inconsistent content references.","backup.error.space_not_found":"The selected space no longer exists.","backup.error.capacity_exceeded":"Adding this backup would exceed the plan limits.","backup.error.preview_expired":"The preview expired. Select the backup file again.","backup.error.preview_owner_mismatch":"This preview belongs to another Home Assistant user.","backup.error.conflict":"The plan changed after the preview. Review the refreshed summary.","backup.error.content_confirmation_required":"Confirm that unavailable local content may be detached.","backup.error.commit_failed":"The backup could not be applied safely. The previous plan was restored or is pending recovery.","backup.error.missing_plan":"A referenced plan file disappeared after the preview. Review the backup again.","backup.error.missing_content":"A referenced local attachment disappeared after the preview. Review the backup again.","backup.error.marker_control_missing":"A linked plan light is missing from the backup.","backup.error.marker_control_not_light":"A linked plan target is no longer marked as a light source.","backup.error.marker_control_self":"A light source cannot control itself.","backup.error.marker_control_cycle":"The backup contains a circular chain of light controls.","backup.error.duplicate_marker_control":"The backup contains a duplicate plan-light link.","backup.error.no_backup":"There is no import or optimization snapshot to restore.","backup.same_source":"Created on this Home Assistant instance","backup.foreign_source":"Created on another Home Assistant instance","backup.created":"Created: {value}","backup.versions":"Card {card}; integration {integration}; data model {model}","backup.count_spaces":"Spaces: {n}","backup.count_rooms":"Rooms: {n}","backup.count_walls":"Walls: {n}","backup.count_openings":"Openings: {n}","backup.count_decor":"Decor objects: {n}","backup.count_markers":"Devices: {n}","backup.count_layout":"Positions: {n}","backup.bindings":"Bindings — devices: {device}, entities: {entity}, virtual: {virtual}; positions without a space: {legacy}","backup.binding_status":"Target status — active: {active}, disabled: {disabled}, missing: {missing}","backup.missing_areas":"Areas missing on the target: {areas}","backup.dropped_marker_links":"Plan-light links outside this transferred space were omitted: {n}.","backup.repaired_target_refs":"Existing references restored by this space import: {n}.","backup.preserved_unresolved_refs":"References that could not be restored unambiguously were preserved: {n}.","backup.preserved_unresolved_hint":"No data was guessed or deleted. After the import, run Optimize plans to inspect the remaining references.","backup.import_details":"Import reference details","backup.import_detail.incoming_remapped":"References updated inside the imported copy: {n}","backup.import_detail.target_repaired":"Existing references restored: {n}","backup.import_detail.preserved_unresolved":"Unresolved references preserved: {n}","backup.import_detail.collisions":"Destination conflicts preserved safely: {n}","backup.import_detail.dropped_links":"Incoming links omitted by transfer rules: {n}","backup.import_detail.bounded_lineages":"Overly nested identifiers left bounded: {n}","backup.replace_warning":"This replaces the current configuration and layout. Uploaded files are never deleted. One undo remains available until the next plan edit.","backup.foreign_bookkeeping":"Instance-specific known/new-device bookkeeping will not be imported.","backup.final_name":"New space name","backup.target_settings":"The target instance's global settings remain unchanged.","backup.duplicates":"Bindings already present: {n}","backup.skip":"Skip duplicate devices","backup.virtual_copy":"Add safe static virtual copies","backup.content":"Referenced content","backup.content_available":"available locally","backup.content_external":"external link","backup.content_detach_required":"will be detached","backup.confirm_detach":"I understand that unavailable internal plans and attachments will be detached from the imported configuration.","backup.replace":"Replace","backup.add":"Add space","backup.space_done":"Space imported: {rooms} rooms, {markers} devices, {refs} existing references restored","backup.full_done":"Backup restored: {spaces} spaces, {rooms} rooms, {markers} devices","backup.undo_import":"Undo last full import","backup.import_undone":"Full import undone"};const Ud=[{code:"en",nativeLabel:"English",dictionary:Wd},{code:"ru",nativeLabel:"Русский",dictionary:{"editor.context_actions":"Действия: {object}","editor.tool_options":"Параметры инструмента: {tool}","editor.palette":"Палитра: {tool}","editor.open_group":"Группа инструментов: {group}","editor.group_active":"{group} — активно: {item}","editor.disabled_action":"{action} недоступно: {reason}","editor.loading":"Загружаем редактор…","editor.loading_aria":"Редактор плана загружается","editor.load_failed":"Не удалось загрузить редактор.","editor.refresh_advice":"Обновите страницу и повторите попытку.","color_picker.title":"Выбор цвета","color_picker.hue":"Оттенок","color_picker.saturation":"Насыщенность","color_picker.value":"Яркость","color_picker.hex":"Цвет HEX","color_picker.invalid_hex":"Введите цвет HEX из 3 или 6 цифр","btn.properties":"Свойства","btn.keep_as_walls":"Оставить стенами","btn.delete_room_keep_walls":"Удалить комнату, оставить стены","btn.delete_room_with_walls":"Удалить комнату и стены","title.markup_select":"Выбор и редактирование стен, колонн и сохранённых контуров","title.markup_column":"Колонна: кликните точку сетки для квадратной колонны","markup.partition":"Перегородка","markup.column":"Колонна","markup.hint_column":"кликните точку сетки, чтобы поставить квадратную колонну","history.draft_segment":"Добавление сегмента черновика комнаты","history.draft_merge":"Соединение незавершённых контуров комнаты","history.draft_segment_delete":"Удаление сегмента черновика комнаты","history.partition_add":"Добавление перегородки","history.column_add":"Добавление колонны","history.physical_edit":"Изменение физического объекта","history.physical_delete":"Удаление физического объекта","history.physical_move":"Перемещение физического объекта","history.contour_to_partitions":"Преобразование контура в замкнутые стены","history.wall_chain_finish":"Завершение цепочки стен","history.wall_face_batch":"Создание комнат из стен","toast.column_duplicate":"Колонна с тем же центром и внешним размером уже существует","confirm.delete_draft":"Удалить весь незавершённый контур комнаты?","confirm.delete_draft_segment":"Удалить этот сегмент черновика? Оставшийся контур может разделиться на два.","physical.partition_properties":"Свойства перегородки","physical.column_properties":"Свойства колонны","physical.draft_properties":"Свойства сегмента черновика","physical.shape":"Форма","physical.square":"Квадрат","physical.circle":"Круг","physical.diameter":"Диаметр","physical.side":"Сторона","physical.rotation":"Угол поворота","physical.length":"Длина","physical.allowed_range":"Допустимо: {min}–{max} {unit}","physical.delete_segment":"Удалить сегмент","physical.delete_draft":"Удалить весь контур","physical.column_size_title":"Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).","card.title":"План дома","count.devices":"{n} устр.","empty.no_spaces":"Пространств пока нет.","empty.add_first":"Добавьте первое пространство и загрузите план этажа.","empty.install":"Установите интеграцию House Plan и добавьте запись в «Устройства и службы».","btn.add_space":"Добавить пространство","btn.cancel":"Отмена","btn.save":"Сохранить","btn.close":"Закрыть","btn.delete":"Удалить","btn.edit":"Редактировать","btn.open_in_ha":"Открыть в HA","btn.reset":"Сброс","btn.attach":"Прикрепить…","btn.upload":"Загрузить…","btn.replace":"Заменить…","title.zoom_in":"Приблизить","title.zoom_out":"Отдалить","title.zoom_fit":"Вписать всё","title.add_device":"Добавить устройство на план","title.show_all":"Показать скрытые и деактивированные устройства служебными маркерами (только в этой вкладке)","title.markup":"Разметка комнат: сетка, линии, контуры","title.configure_space":"Настроить пространство","title.add_space":"Добавить пространство","title.markup_add":"Стены: рисуйте непрерывную цепочку; Shift фиксирует 45°. Смена инструмента или выход завершает её как независимые стены","title.markup_merge":"Объединить: клик по одной комнате, затем по соседней с общей стеной","title.markup_split":"Разделить комнату: клик по комнате, затем две точки на её стенах","title.markup_delroom":"Удалить комнату: кликните внутри комнаты и подтвердите удаление","title.need_plan":"Загрузите подложку (план этажа)","markup.add":"Стены","markup.merge":"Объединить","markup.split":"Разделить","markup.resize":"Размер","title.markup_resize":"Изменение размера комнат: тяните доступную ручку горизонтальной или вертикальной стены","markup.hint_resize":"тяните доступную ручку стены · стена упирается в первую небезопасную позицию · Esc — отмена · Ctrl+Z — отмена шага","resize.disabled.diagonal":"Стена расположена под углом: Resize поддерживает только горизонтальные и вертикальные стены","resize.disabled.side-angle":"Примыкающая стена расположена под углом: для Resize обе примыкающие стены должны образовывать прямой угол","resize.disabled.duplicate-physical-wall":"Стену перекрывает отдельная перегородка, незавершённый контур или колонна; удалите или переместите её перед изменением размера","resize.disabled.partial-shared":"Соседняя комната использует только часть этой стены, поэтому её нельзя безопасно двигать как одну общую стену","resize.disabled.unequal-shared":"У соседней комнаты другие конечные точки или длина стены, поэтому стены нельзя безопасно двигать вместе","resize.disabled.multiple-rooms":"Перемещение затронуло бы больше двух комнат","resize.disabled.thickness-conflict":"Толщину стены нельзя безопасно сохранить","resize.disabled.opening-conflict":"Проём на этой стене нельзя безопасно переместить","resize.disabled.invalid-geometry":"Эту стену нельзя переместить без изменения структуры плана","resize.limit_stopped":"Стена остановлена: дальше нарушается ограничение стыков","resize.commit_failed":"Изменение размера отменено: итоговый план не прошёл проверку геометрии","resize.preview_failed":"Стена остановлена в последней безопасной позиции: геометрию плана нельзя сохранить без потерь","markup.opening":"Проём","markup.delete_room":"Удалить комнату","history.undo":"Отменить","history.redo":"Повторить","history.undo_named":"Отменить: {name} (Ctrl+Z)","history.redo_named":"Повторить: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Нет операций для отмены","history.redo_empty":"Нет операций для повтора","history.undone":"Отменено: {name}","history.redone":"Повторено: {name}","history.add_room":"Создание комнаты","history.split_room":"Разделение комнаты","history.merge_rooms":"Объединение комнат","history.resize_room":"Изменение размера комнаты","history.wall_thickness":"Изменение толщины стены","history.add_opening":"Добавление дверного или оконного проёма","history.edit_opening":"Изменение проёма","history.move_opening":"Перемещение проёма","history.delete_opening":"Удаление проёма","history.delete_room":"Удаление комнаты","history.delete_room_keep_walls":"Удаление комнаты с сохранением стен","history.delete_room_with_walls":"Удаление комнаты и её стен","history.decor_add":"Добавление объекта декора","history.decor_edit":"Изменение объекта декора","history.decor_move":"Перемещение объекта декора","history.decor_transform":"Трансформация объекта декора","history.decor_delete":"Удаление объекта декора","history.backdrop_transform":"Трансформация подложки плана","title.markup_opening":"Проёмы: клик по стене — добавить, клик по проёму — редактировать","opening.new":"Новый проём","opening.edit":"Проём","opening.door":"Дверь","opening.window":"Окно","opening.gate":"Ворота","opening.passage":"Открытый проём","opening.passage_binding_warning":"При сохранении датчик открытия и замок будут удалены.","opening.invalid_passage_fields":"У открытого проёма на плане «{room}» есть недопустимые параметры: {fields}.","opening.type_label":"Тип","opening.length_label":"Длина, см","opening.contact_label":"Датчик открытия","opening.lock_label":"Замок","opening.none":"— нет —","opening.search_ph":"Поиск: имя или entity_id…","opening.invert":"Инвертировать открыто/закрыто","opening.flip_h":"Петли с другой стороны","opening.flip_v":"Открывается в другую сторону","opening.open":"Открыто","opening.closed":"Закрыто","opening.locked":"Заперто","opening.unlocked":"Не заперто","opening.state_unknown":"недоступно","opening.no_entities":"Датчики не привязаны — статичный символ на плане.","toast.opening_no_wall":"Кликните рядом со стеной комнаты или независимой стеной","opening.host_partition":"Независимая стена","opening.partition_orphan":"Независимая стена этого проёма больше не существует","opening.partition_jamb_margin":"Оставьте от края проёма до торца стены минимум {distance}","opening.rebind_partition":"Привязать к другой независимой стене","confirm.delete_partition_openings_title":"Удалить стену и проёмы?","confirm.delete_partition_openings_body":"В стене есть проёмы: {count}. Они будут удалены вместе со стеной.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Удалить","markup.hint_points":"точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната","markup.hint_start":"кликните точку сетки, чтобы начать цепочку стен","tip.lqi":"средний сигнал zigbee:","tip.area":"площадь: {value}","info.device_header":"Устройство на плане","info.model":"Модель","info.state":"Состояние","info.link":"Ссылка","info.manuals":"Инструкции","info.none":"Нет дополнительной информации","marker.new_device":"Новое устройство","marker.name_label":"Имя (отображается на плане)","marker.name_ph":"Название","marker.binding_label":"Привязка к устройству HA","marker.binding_disabled":"деактивировано в Home Assistant","marker.virtual_option":"Виртуальное устройство (без привязки)","marker.search_ph":"Поиск устройства / группы…","marker.nothing_found":"ничего не найдено","marker.room_label":"Комната","marker.room_override":" (переопределить размещение)","marker.room_choose":"— выберите комнату —","marker.room_auto":"— по зоне устройства (авто) —","marker.icon_label":"Иконка","marker.icon_ph":"mdi:… (пусто = авто)","marker.display_label":"Отображение","display.badge":"Значок + состояние","display.icon_ripple":"Значок + состояние и активность","display.static_icon":"Всегда статичный значок","marker.display_hint":"Значок + состояние меняет подложку при работе, открытии, тревоге и недоступности. Значок + состояние и активность дополнительно показывает короткую пульсацию для событий и постоянную — для работы, движения или присутствия. Значение + состояние заменяет значок одним однозначным значением HA. Статичный значок не реагирует на состояния устройства.","marker.display_hint_badge":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon_ripple":"Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.","marker.display_hint_value":"Значок заменяется одним однозначным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.","marker.display_hint_static_icon":"Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.","marker.static_alarm_warning":"Это устройство может сообщать о тревогах. Статичный режим скрывает визуальную тревогу маркера.","marker.preview.title":"Предпросмотр отображения","marker.preview.actual":"Сейчас","marker.preview.example":"Пример","marker.preview.integration":"Интеграция","marker.preview.source":"Источник отображения","marker.preview.current_state":"Текущее состояние","marker.preview.result":"На плане","marker.preview.details":"Подробнее об источниках","marker.preview.select_source":"Выберите устройство или сущность Home Assistant, чтобы увидеть фактическое отображение.","marker.preview.unknown_provider":"Интеграция неизвестна","marker.preview.virtual_provider":"House Plan · виртуальное устройство","marker.preview.no_source":"Нет активного источника","marker.preview.no_state":"Нет текущего состояния","marker.preview.mixed_states":"Несколько разных состояний","marker.preview.multiple_sources":"Источников: {n}","marker.preview.more_sources":"ещё {n}","marker.preview.scaled":"Предпросмотр уменьшен до {n}%, чтобы поместиться. Сохранённый размер не изменится.","marker.preview.demo_activity":"Показать пример активности","marker.preview.demo_notice":"Временный пример активности; фактическое состояние устройства не меняется.","marker.preview.demo_short":"Показать краткую активность","marker.preview.demo_continuous":"Показать постоянную активность","marker.preview.stop_continuous":"Остановить постоянную активность","marker.preview.demo_short_notice":"Пример краткой активности; фактическое состояние устройства не меняется.","marker.preview.demo_continuous_notice":"Пример постоянной активности; фактическое состояние устройства не меняется.","marker.preview.demo_already_visible":"Текущее состояние уже показывает реальную активность или тревогу.","marker.preview.reduced_motion":"В системе включено уменьшение движения, поэтому обычная активность показана точкой.","marker.preview.reason.neutral":"Нейтральная тёмная подложка","marker.preview.reason.working":"Жёлтая подложка: устройство сейчас работает","marker.preview.reason.working_activity":"Жёлтая подложка и эффект активности: устройство сейчас работает","marker.preview.reason.open":"Оранжевая подложка: физически открыто или разблокировано","marker.preview.reason.cover_icon_state":"Нейтральная подложка; состояние и значок определяет сущность шторы или заслонки","marker.preview.reason.presence":"Эффект активности, пока обнаружено присутствие","marker.preview.reason.event":"Короткий эффект активности после события","marker.preview.reason.transition":"Эффект активности во время движения или смены состояния","marker.preview.reason.media_neutral":"Медиаустройство остаётся на нейтральной тёмной подложке, пока доступно","marker.preview.reason.unavailable":"Приглушённая нейтральная подложка: отключено или недоступно","marker.preview.reason.alarm":"Красная тревожная подложка; тревога отображается всегда","marker.preview.reason.live_states_disabled":"Оформление по живым состояниям отключено в настройках карточки","marker.preview.reason.value_no_state":"Нет подходящего значения состояния — вместо него показан значок","marker.preview.reason.value_ambiguous_sources":"Подходит несколько источников значения — вместо него показан значок","marker.preview.reason.value_non_scalar":"Источник вернул не простое значение — вместо него показан значок","marker.preview.reason.value_virtual":"У виртуального устройства нет значения HA — вместо него показан значок","marker.preview.reason.vacuum_live_plan_only":"Живая позиция и след пылесоса доступны только на полном плане","marker.preview.reason.hidden_design_preview":"Устройство скрыто на плане, но его оформление видно в предпросмотре","marker.preview.reason.composite_power_source":"Состояние берётся из сущности питания устройства; вспомогательные переключатели не учитываются","marker.preview.reason.activity_display_disabled":"Выбранный режим отображения не показывает обычные эффекты активности","marker.preview.reason.ha_disabled":"Привязка отключена в Home Assistant, поэтому устройство будет скрыто на плане","marker.preview.reason.orphaned":"Сохранённая привязка Home Assistant больше не найдена","marker.preview.reason.static_icon":"Статичный режим: состояние устройства не меняет значок","marker.activity_color":"Цвет пульсации активности","marker.ripple_size":"Размер пульсации активности","marker.activity_alarm_note":"Цвет и размер относятся только к обычной активности и не влияют на красную тревогу.","marker.pulse_a11y_alarm":"Тревога","marker.pulse_a11y_event":"Недавнее событие","marker.pulse_a11y_presence":"Обнаружено присутствие","marker.pulse_a11y_transition":"Изменение состояния","marker.pulse_a11y_running":"Работает","marker.state_a11y_neutral":"Обычное состояние","marker.state_a11y_working":"Работает","marker.state_a11y_open":"Открыто","marker.state_a11y_locked":"Заблокировано","marker.state_a11y_unlocked":"Разблокировано","marker.state_a11y_alarm":"Тревога","marker.state_a11y_unavailable":"Недоступно","marker.lqi_a11y_low":"LQI {value}, слабый сигнал","marker.lqi_a11y_mid":"LQI {value}, средний сигнал","marker.lqi_a11y_high":"LQI {value}, сильный сигнал","marker.size_label":"Размер / поворот значка","marker.angle_label":"Поворот","marker.model_label":"Модель","marker.model_ph":"напр. Aqara T&H","marker.link_label":"Ссылка","marker.desc_label":"Описание","marker.desc_ph":"Заметки, характеристики…","marker.manuals_label":"Инструкции (PDF и т.п.)","marker.sub_device":"устройство","marker.sub_z2m_group":" · Z2M-группа","marker.sub_group":"группа","marker.sub_helper":"хелпер","space.new":"Новое пространство","space.header":"Пространство","space.title_label":"Название","space.title_ph":"Например: Гараж","space.plan_label":"Подложка (план)","space.no_plan":"нет подложки","space.plan_alt":"план","room.new":"Новая комната","room.name_label":"Отображаемое имя","room.name_ph":"Например: Терраса","room.area_label":"Зона Home Assistant (свободные)","room.no_area_option":"— без зоны —","room.default_name":"Комната","device.unnamed":"без имени","device.light_group":"группа света","device.fallback":"устройство","device.virtual":"виртуальное устройство","confirm.delete_room":"Удалить комнату «{name}»?","confirm.delete_room_title":"Удалить комнату «{name}»?","confirm.delete_room_body":"Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.","confirm.merge_rooms":"Слить комнаты «{a}» и «{b}»?","confirm.remove_marker":"Удалить «{name}» с плана? Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.","confirm.erase_decor":"Стереть объект «{kind}»? Действие можно отменить из истории редактора.","confirm.delete_space":"Удалить пространство «{title}» со всеми комнатами и разметкой?","space.delete_blocked":"Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.","toast.pos_save_failed":"Не удалось сохранить позицию: {err}","toast.no_entity":"У устройства нет подходящей сущности","toast.ha_disabled_action":"Деактивированный объект Home Assistant нельзя использовать на плане.","toast.ha_disabled_show_device":"Деактивированное в Home Assistant устройство нельзя показать на плане. Сначала активируйте его в Home Assistant.","toast.ha_disabled_show_entity":"Деактивированную в Home Assistant сущность нельзя показать на плане. Сначала активируйте её в Home Assistant.","toast.ha_disabled_add":"Деактивированный объект Home Assistant нельзя добавить на план. Сначала активируйте его в Home Assistant.","toast.ha_binding_unverified":"Статус объекта не удалось подтвердить по реестру Home Assistant. Отображение и действия временно недоступны.","toast.markup_needs_server":"Разметка доступна после переноса конфига на сервер","toast.space_order_changed":"Порядок изменён. Если где-то этаж карточки задан номером, проверьте такие панели.","toast.conflict":"Конфиг изменён в другом окне — данные обновлены, повторите последнее действие","toast.cfg_save_failed":"Не удалось сохранить конфиг: {err}","toast.room_overlap":"Контур накладывается на комнату «{name}» — комнаты не должны накладываться","toast.contour_min_edges":"Чтобы замкнуть контур, сначала нарисуйте минимум две грани","toast.contour_cannot_close":"Контур нельзя замкнуть: он вырожден или пересекает сам себя","toast.merge_not_adjacent":"Объединять можно только комнаты с общей стеной","toast.rooms_merged":"Комнаты объединены в «{name}»","toast.split_pick_wall":"Начните разрез на стене комнаты","toast.split_bad_cut":"Разрез — от стены до стены внутри комнаты, без пересечения стен и самого себя","merge.header":"Объединение комнат","merge.hint":"У объединённой комнаты одно имя и одна зона. Вторая зона освобождается — её устройства уйдут с плана, пока их не заберёт другая комната.","merge.keep":"Оставить","merge.no_area":"без зоны","room.split_header":"Новая комната после разделения","toast.room_saved":"Комната сохранена ({n}). Устройств добавлено: {added}. Обведите следующую или выйдите из разметки.","toast.room_saved_no_area":"Комната сохранена ({n}, без зоны). Обведите следующую или выйдите из разметки.","toast.marker_needs_server":"Редактирование устройств доступно после переноса конфига на сервер","toast.virtual_name_required":"Укажите имя виртуального устройства","toast.marker_saved":"Устройство сохранено","toast.marker_removed":"Устройство удалено с плана","toast.integration_missing":"Интеграция House Plan не установлена — управление недоступно","toast.plan_formats":"Поддерживаются SVG, PNG, JPG, WebP","toast.plan_required":"Загрузите подложку — план этажа обязателен","toast.space_added_onboard":"Пространство добавлено. Обведите комнаты: кликайте по точкам сетки и замкните контур.","toast.space_added":"Пространство добавлено","toast.space_saved":"Пространство сохранено","toast.space_deleted":"Пространство удалено","toast.delete_failed":"Ошибка удаления: {err}","toast.error":"Ошибка: {err}","toast.toggle_target_unavailable":"Цель «{name}» недоступна — действие не выполнено","toast.toggle_targets_unavailable":"Цели недоступны: {names}. Действие не выполнено","toast.file_failed":"Файл «{name}» не загружен: {err}","toast.files_attached":"Прикреплено файлов: {n}","err.unknown":"неизвестная ошибка","err.code":"код {code}","err.too_large":"файл больше {mb} МБ","err.bad_ext":"недопустимый тип (нужен PDF/изображение)","err.unauthorized":"нужны права администратора","editor.title":"Заголовок","editor.default_floor":"Стартовое пространство","editor.default_floor_missing":"Стартовое пространство «{id}» больше не существует. Выберите другое.","editor.floor":"Закреплённое пространство","editor.floor_none":"— не закреплять —","editor.floor_index":"YAML-индекс {index} (сохранён)","fixed_floor.loading":"Загружаем закреплённое пространство…","fixed_floor.invalid_title":"Закреплённое пространство недоступно","fixed_floor.invalid_body":"Проверьте floor в конфигурации карточки. Настроенное значение: {value}","editor.icon_size":"Размер иконок, % ширины плана","editor.show_temperature":"Показывать температуру","editor.live_states":"Живые состояния (вкл/выкл, открыто…)","editor.show_signal":"Показывать сигнал zigbee (LQI)","editor.language":"Язык интерфейса","editor.lang_auto":"Авто (профиль HA)","editor.lang_en":"English","editor.lang_ru":"Русский","title.icon_rules":"Правила иконок: какая MDI-иконка достаётся устройству по имени","rules.title":"Правила иконок","rules.hint":"Правила проверяются сверху вниз по строке «имя устройства + модель» (regex без учёта регистра); срабатывает первое совпадение. Если ничего не подошло — решает device class сущности, затем — иконка-заглушка.","rules.pattern_ph":"regex, напр. розетк|plug","rules.icon_ph":"mdi:power-socket-de","rules.add":"Добавить правило","rules.reset":"Сбросить к умолчаниям","rules.test_ph":"Проверьте имя устройства…","rules.invalid":"некорректный regex","rules.saved":"Правила иконок сохранены","btn.up":"Вверх","btn.down":"Вниз","tap.info":"Карточка устройства","tap.more_info":"Диалог HA (more-info)","tap.toggle":"Переключить состояние","marker.tap_label":"Действие по нажатию для этого устройства","tap.toggle_note":"Под селектором показано, какое состояние изменится. Защищённые устройства не переключаются с плана.","import.title":"Создать пространства из этажей HA","import.hint":"Home Assistant уже знает эти этажи. Отметьте, какие превратить в пространства плана — далее для каждого попросим картинку плана. Комнаты затем обводятся вручную по плану.","import.start":"Создать: {n}","import.manual":"Начать с нуля","import.progress":"Этаж {i} из {n}","import.done":"Пространства созданы. Обведите комнаты: кликайте по точкам сетки и замкните контур.","btn.skip":"Пропустить","space.scale_label":"Масштаб (размер клетки сетки)","space.scale_unit":"см на клетку","space.scale_unit_imperial":"дюйм на клетку","space.display_section":"Отображение","space.show_borders":"Всегда отображать границы комнат","space.zero_wall_style":"Стены нулевой толщины","space.zero_wall_dashed":"Пунктирные","space.zero_wall_solid":"Сплошные","space.zero_wall_help":"Пунктирные стены пропускают свет. Сплошные стены блокируют свет, даже при нулевой толщине.","space.show_names":"Отображать названия комнат (перетаскиваются)","space.room_color":"Цвет границ и названий","space.opacity":"Прозрачность","space.fill_label":"Заливка комнат","fill.none":"Нет","fill.lqi":"По силе зигби-сигнала","fill.light":"По освещению","fill.custom":"Свой цвет","space.custom_fill":"Цвет заливки","space.source_file":"У меня есть картинка плана","space.source_draw":"Нет подложки — нарисую комнаты вручную","space.orientation":"Холст","orient.landscape":"Альбомный","orient.portrait":"Портретный","orient.square":"Квадрат","fill.temp":"По температуре","space.temp_min":"Комфорт от","space.temp_max":"до","tip.temp_avg":"средняя температура:","tip.hum_avg":"средняя влажность:","space_card.button":"Перейти к пространству","space_card.not_found":"Пространство «{id}» не найдено","space_card.loading":"Загрузка…","continuity.restore_plan":"Восстанавливаем план…","continuity.restore_connection":"Восстанавливаем подключение к устройствам…","continuity.retry":"Повторить","editor.space":"Пространство","editor.show_button":"Показывать кнопку","editor.button_label":"Текст кнопки","editor.button_target":"Путь дашборда (куда вести)","marker.sub_entity":"сущность","title.general_settings":"Общие настройки","gs.title":"Общие настройки","gs.hint":"Цвета заливок действуют на все пространства; у каждого цвета своя прозрачность. Какой режим заливки использует пространство — задаётся в его диалоге.","gs.light_group":"Заливка: освещение","gs.light_on":"Свет включён","gs.light_off":"Весь свет выключен","gs.temp_group":"Заливка: температура","gs.temp_cold":"Холодно","gs.temp_ok":"Комфорт","gs.temp_hot":"Жарко","gs.lqi_group":"Заливка: зигби-сигнал","gs.lqi_low":"Слабый сигнал","gs.lqi_high":"Сильный сигнал","gs.reset":"Сбросить к умолчаниям","gs.saved":"Общие настройки сохранены","space.show_lqi":"Показывать зигби-сигнал (LQI) у устройств","space.hide_decor":"Скрыть декоративный слой","space.hide_decor_tip":"Линии, фигуры, надписи и мебель остаются на месте — их видно в редакторе подложки, но не на плане.","space.hide_openings":"Скрыть проёмы","space.hide_openings_tip":"Двери, окна и ворота не рисуются, но продолжают работать: свет проходит, солнце светит в окна, датчики открытия срабатывают. В редакторе плана проёмы видно всегда.","gs.light_none":"Нет источников света","mode.plan":"Редактор плана","mode.devices":"Редактор устройств","display.value":"Значение + состояние","marker.subarea":"без зоны, вручную","device.new":"Новое устройство — откройте его редактор, чтобы снять отметку","opening.unlock_action":"Открыть замок","opening.lock_action":"Закрыть замок","opening.lock_pending":"Выполняется…","title.close_editor":"Закрыть редактор (вернуться к просмотру)","devbar.add":"Добавить","devbar.show_all":"Скрытые и деактивированные","devbar.rules":"Правила иконок","device_inbox.button":"Устройства","device_inbox.title":"Устройства на плане","device_inbox.search":"Поиск по устройствам, сущностям и интеграциям…","device_inbox.add_virtual":"Добавить виртуальное устройство","device_inbox.tab_on_plan":"На плане","device_inbox.tab_available":"Доступны","device_inbox.tab_hidden":"Скрытые","device_inbox.tab_readd":"Доступны снова","device_inbox.only_new":"Только новые","device_inbox.show_entities":"Показывать сущности","device_inbox.show_hidden":"Показывать скрытые на плане","device_inbox.new":"Новое","device_inbox.find":"Найти на плане","device_inbox.edit":"Настроить","device_inbox.hide":"Скрыть","device_inbox.show":"Показать","device_inbox.add":"Добавить","device_inbox.readd":"Добавить заново","device_inbox.hide_available":"Скрыть из списка","device_inbox.show_more":"Показать ещё","device_inbox.more_actions":"Другие действия","device_inbox.find_hidden_hint":"Сначала включите «Показывать скрытые на плане»","device_inbox.show_disabled":"Перед показом активируйте эту привязку в Home Assistant","device_inbox.empty_on_plan":"На плане пока нет подходящих устройств.","device_inbox.empty_available":"Нет доступных устройств для добавления.","device_inbox.empty_hidden":"Скрытых устройств нет.","device_inbox.empty_readd":"Нет удалённых устройств, доступных для повторного добавления.","device_inbox.reason_visible_auto":"Найдено автоматически","device_inbox.reason_visible_explicit":"Добавлено явно","device_inbox.reason_manual_hidden":"Скрыто пользователем","device_inbox.reason_automatic_hidden":"Скрыто автоматически","device_inbox.reason_service_entry":"Служебная запись реестра","device_inbox.reason_excluded_integration":"Интеграция исключена фильтрами устройств","device_inbox.reason_excluded_domain":"Непространственный тип сущности","device_inbox.reason_grouped_light":"Представлено группой света комнаты","device_inbox.reason_represented_by_parent":"Представлено родительским устройством","device_inbox.reason_removed":"Ранее удалено с плана","device_inbox.reason_available":"Можно добавить на план","device_inbox.reason_no_bound_room":"Зона HA не связана с комнатой плана","device_inbox.status_ha_disabled":"Отключено в Home Assistant","device_inbox.status_orphaned":"Привязка больше не найдена в Home Assistant","device_inbox.status_unverified":"Реестр Home Assistant временно недоступен","device_inbox.saved":"Список устройств обновлён","space.roomcard_section":"В карточке комнаты:","space.label_temp":"Температура","space.label_hum":"Влажность","space.label_lqi":"Средний Zigbee-сигнал","space.label_light":"Свет вкл/выкл","roomcard.light_on":"Вкл","roomcard.light_off":"Выкл","roomcard.light_partial":"{on} из {total}","toast.split_pick_inside":"Промежуточные точки разреза — внутри комнаты","mode.decor":"Редактор подложки","decor.select":"Выбрать","decor.line":"Линия","decor.rect":"Прямоугольник","decor.ellipse":"Овал","decor.text":"Надпись","decor.erase":"Стереть","decor.erase_confirm_title":"Стереть объект?","decor.color":"Цвет","decor.width":"Толщина линии","decor.line_style":"Стиль линии","decor.line_style_solid":"Сплошная","decor.line_style_dashed":"Пунктирная","decor.fill":"Заливка","decor.fill_color":"Цвет заливки","decor.length":"Длина","decor.size":"Размер","decor.angle":"Угол поворота, °","decor.text_size":"Размер текста","decor.backdrop_properties":"Свойства картинки-подложки","decor.text_title":"Надпись","decor.object_title":"Редактирование: {kind}","decor.text_label":"Текст","decor.live_group":"Вставить переменную HA","decor.live_entity":"Сущность","decor.live_entity_ph":"выберите сущность","decor.live_attr":"Значение","decor.live_attr_ph":"выберите состояние или атрибут","decor.live_state":"Состояние","decor.backdrop":"Картинка-подложка","decor.backdrop_hint":"Тяните картинку — перемещение; угол — размер; верхнюю ручку — поворот. Shift меняет пропорции или снимает шаг угла.","decor.backdrop_reset":"Вернуть картинку","decor.backdrop_reset_done":"Картинка вернулась на своё место и в свой размер","marker.icon_auto":"Авто: {icon} (по правилам иконок; выберите свою, чтобы заменить)","marker.icon_pin_auto":"Закрепить","mode.plan_tip":"Редактор плана — геометрия дома: рисование и объединение/разделение комнат, привязка к зонам HA, двери, окна и ворота, карточки комнат, масштаб","mode.devices_tip":"Редактор устройств — всё про значки: перетаскивание, клик — настройка привязки/иконки/отображения, виртуальные устройства, правила иконок","mode.decor_tip":"Редактор подложки — чисто визуальный декор под планом: линии, прямоугольники, овалы и надписи, не реагирующие на клики","space.glow_enabled":"Свечение источников света","gs.glow_group":"Свечение источников света","gs.glow_base":"Темнота дома","gs.glow_light":"Цвет света по умолчанию / интенсивность","gs.wall_group":"Стены","gs.wall_fill":"Цвет заливки стен","gs.glow_radius":"Радиус свечения","gs.unit_m":"м","gs.unit_ft":"фут","marker.controls_label":"Управляет другими источниками света","marker.controls_hint":"При действии «Переключить» клик разом переключает все добавленные здесь источники. Собственная сущность маркера управляется напрямую и сюда не добавляется; чтобы считать её светом, включите флаг ниже.","marker.controls_filter":"Поиск ламп и выключателей…","info.controls":"Управляет","marker.glow_radius_label":"Радиус свечения","marker.glow_radius.help":"Задаёт радиус свечения в метрах или футах; пустое значение использует радиус из общих настроек.","marker.glow_radius.help.aria":"Подсказка: радиус свечения","markup.wallthick":"Толщина","markup.select":"Выбрать","title.markup_wallthick":"Толщина — клик по стене задаёт толщину от 0 до 100 см.","markup.hint_wallthick":"клик по стене · Esc закрывает без применения","wallthick.field":"Толщина","wallthick.unit_cm":"см","wallthick.unit_in":"дюйм","wallthick.apply_room":"Применить ко всем стенам комнаты","markup.draw_wall_title":"Толщина каждого нового сегмента стены (0–100 см). Общие стены сохраняют существующее значение.","room.queue_progress":"Комната {current} из {total}","toast.wall_rooms_saved":"Создано комнат: {n}","toast.wall_chain_saved":"Цепочка стен сохранена","toast.wallthick_pick":"Кликните по стене","toast.wallthick_set":"Толщина стены задана","toast.wallthick_cleared":"Толщина стены убрана","toast.physical_range":"Введите значение от {min} до {max} {unit}","toast.zero_wall_opening_conflict":"Сначала удалите проём на этом участке стены.","toast.zero_wall_ambiguous":"Не удалось однозначно выбрать участок стены. Уточните геометрию узла.","toast.zero_wall_migration_blocked":"Пространство не преобразовано: {reason}. Данные не изменены.","toast.physical_angle":"Введите угол поворота от 0° до 90°, не включая 90°","toast.physical_limit":"В пространстве достигнут лимит объектов этого типа","toast.geometry_unsafe":"Изменение отменено: геометрию стен нельзя безопасно построить.","junction.limit_angle":"Слишком острый угол между стенами: {actual}°, минимум {limit}°.","junction.limit_valence":"Слишком много стен в одном узле: {actual}, максимум {limit}.","junction.limit_length":"Слишком короткий участок стены: {actual} см, минимум {limit} см.","junction.limit_distance":"Стены и узлы слишком близко: {actual} см, минимум {limit} см.","junction.limit_clearance":"Внутри комнаты не остаётся места: {actual} см², минимум {limit} см².","junction.limit_check_failed":"Проверку стыков выполнить не удалось — изменение не сохранено","toast.wall_model_migration_blocked":"Не удалось обновить модель стен: {reason}. План не изменён. Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.","toast.wall_model_client_outdated":"Обновите карточку и перезагрузите страницу перед редактированием плана.","wall_model.reason.invalid-room":"некорректный контур комнаты","wall_model.reason.zero-length":"отрезок стены нулевой длины","wall_model.reason.third-owner":"стена принадлежит более чем двум комнатам","wall_model.reason.duplicate-id":"конфликт идентификаторов стен","wall_model.reason.thickness-conflict":"конфликт значений толщины стены","wall_model.reason.opening-host":"проём нельзя однозначно привязать к стене","toast.delete_room_pick":"Кликните внутри комнаты, которую нужно удалить","toast.plan_snap_ambiguous":"Увеличьте масштаб, чтобы выбрать узел стены","toast.wall_repair_ambiguous":"У контура несколько возможных соединений. Увеличьте масштаб и соедините стены явно.","toast.wall_repair_too_large":"Разрыв больше 2 см. Соедините стены перед созданием комнаты.","toast.wall_repair_changed":"Геометрия стен изменилась. Попробуйте создать комнату ещё раз.","toast.opening_on_zero_wall":"Проёмы на стене нулевой толщины запрещены","marker.from_ha_option":"Выбрать из списка HA","marker.show_entities":"Показывать сущности","marker.show_entities_tip":"Добавляет в список не только устройства, но и все их сущности","marker.pick_ph":"Выберите устройство…","room.open_area":"Открыть зону в HA","view.volumetric":"Объёмный вид","view.flat":"Плоский вид","kiosk.title":"Размеры на этом экране","kiosk.hint":"Хранится только на этом устройстве — у каждого настенного планшета или ТВ свои удобные размеры.","kiosk.icon_scale":"Размер значков устройств","kiosk.font_scale":"Размер текста карточек комнат","editor.kiosk":"Режим настенного устройства (киоск)","editor.cycle":"Автосмена пространств каждые N секунд (киоск, 0 = выкл)","room.settings_title":"Настройки комнаты","room.settings_section":"Настройки комнаты (переопределяют пространство)","room.fill_label":"Заливка в ЭТОЙ комнате","fill.inherit":"Как у пространства","room.custom_fill_space":"Цвет пространства","room.custom_fill_own":"Цвет комнаты","room.temp_src_label":"Источник температуры","room.hum_src_label":"Источник влажности","room.src_average":"Средняя по датчикам комнаты (по умолчанию)","room.src_pick":"Конкретное устройство или сущность HA","room.src_ph":"Выберите источник…","toast.room_updated":"Комната обновлена","space.card_font":"Размер шрифта карточек комнат (всё пространство)","room.sizes_section":"Размеры шрифтов","room.name_scale":"Размер названия","room.label_scale":"Размер подписей","preview.room_name":"Гостиная","toast.cfg_reload_failed":"Не удалось перечитать план с сервера: {err}","room.settings_short":"Настройки комнаты","room.unnamed":"Комната без имени","marker.use_climate_temp":"Учитывать температуру устройства в комнате","marker.use_climate_temp_tip":"Добавляет current_temperature кондиционера или термостата в среднюю температуру комнаты. Внешний бейдж со значением настраивается отдельно ниже.","marker.value_badge_title":"Бейдж со значением","marker.value_badge.help":"Показывает одно выбранное значение рядом со значком. Не влияет на комнатные показатели, свет, Glow и действие по нажатию.","marker.value_badge.help.aria":"Подсказка: бейдж со значением устройства","marker.value_badge_enabled":"Отображать бейдж со значением","marker.value_badge_source":"Значение","marker.value_badge_source.help":"Выберите конкретное состояние, поддерживаемый атрибут или производное значение этого устройства.","marker.value_badge_source.help.aria":"Подсказка: источник значения бейджа","marker.value_badge_position":"Расположение","marker.value_badge_position.help":"Выбранная сторона сохраняется постоянно и не переворачивается автоматически у края плана.","marker.value_badge_position.help.aria":"Подсказка: расположение бейджа","marker.value_badge_right":"Справа","marker.value_badge_bottom":"Снизу","marker.value_badge_left":"Слева","marker.value_badge_top":"Сверху","marker.value_badge_empty":"У этого устройства нет доступных значений","marker.value_badge_static":"Статичный значок не показывает живые значения. Настройка сохранится.","marker.value_badge_missing":"Источник недоступен","marker.value_badge_missing_hint":"Сохранённый источник сейчас недоступен. Можно сохранить его, отключить бейдж или выбрать другой.","marker.value_badge_duplicate":"То же значение уже показано внутри значка.","marker.value_badge_state":"Состояние · {name}","marker.value_badge_marker_state":"Состояние источника света · {name}","marker.value_badge_lqi":"Качество Zigbee-сигнала (среднее)","marker.value_badge_attr_current_temperature":"Текущая температура · {name}","marker.value_badge_attr_temperature":"Целевая температура · {name}","marker.value_badge_attr_current_humidity":"Текущая влажность · {name}","marker.value_badge_attr_humidity":"Влажность · {name}","marker.value_badge_attr_current_position":"Положение · {name}","marker.value_badge_attr_percentage":"Скорость · {name}","marker.value_badge_attr_brightness":"Яркость · {name}","marker.value_badge_attr_volume_level":"Громкость · {name}","marker.value_badge_attr_battery_level":"Заряд батареи · {name}","marker.value_badge_attr_fan_speed":"Скорость вентилятора · {name}","marker.light_role_label":"Является источником света","marker.light_role.help":"Определяет, является ли сам маркер пространственным источником света. Привязанные выше лампы остаются независимыми источниками для комнаты.","marker.light_role.help.aria":"Подсказка: является ли устройство источником света","marker.light_role_auto_yes":"Автоматически (источник света)","marker.light_role_auto_no":"Автоматически (не источник света)","marker.light_role_always":"Всегда источник света","marker.light_role_never":"Никогда не источник света","marker.light_entity_label":"Ведущая сущность света","marker.light_entity.help":"Для составного устройства выберите сущность, состояние, цвет и яркость которой представляют этот источник на плане. Автоматический вариант сохраняет совместимость со старыми планами.","marker.light_entity.help.aria":"Подсказка: ведущая сущность света","marker.light_entity_auto":"Автоматически ({entity})","marker.light_entity_none":"нет управляемой сущности","marker.light_entity_missing":"Сохранённая сущность {entity} недоступна. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.toggle_entity_label":"Переключаемая сущность","marker.toggle_entity.help":"Для составного устройства выберите собственную лампу или переключатель, которой управляет нажатие. Автоматический вариант сохраняет прежние правила цели и не зависит от ведущей сущности света.","marker.toggle_entity.help.aria":"Подсказка: переключаемая сущность","marker.toggle_entity_auto":"Автоматически ({entity})","marker.toggle_entity_none":"нет собственной управляемой сущности","marker.toggle_entity_missing":"Сохранённой сущности {entity} больше нет среди выбираемых каналов этого маркера. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.glow_color_label":"Цвет и яркость свечения","marker.glow_mode.help":"Используйте данные источника, задайте только цвет или зафиксируйте цвет и яркость. Минимум — 1%; чтобы отключить источник, выберите «Никогда».","marker.glow_mode.help.aria":"Подсказка: цвет и яркость свечения","marker.glow_mode_auto":"Из источника","marker.glow_mode_color":"Задать цвет","marker.glow_mode_fixed":"Задать цвет и яркость","marker.glow_color":"Цвет свечения","marker.glow_brightness":"Яркость","marker.glow_disabled_never":"Настройки свечения недоступны: маркер явно исключён из источников света.","marker.glow_disabled_auto":"В автоматическом режиме у этого маркера не найден пространственный источник света.","marker.glow_disabled_no_entity":"Для пространственного источника нет активной управляемой сущности Home Assistant.","marker.glow_passive_hint":"У источника нет собственных данных Home Assistant. Задайте цвет и яркость вручную; радиус остаётся доступным.","marker.control_broken":"Сохранённый источник отсутствует или больше не отмечен как источник света","marker.control_missing_label":"Отсутствующий источник на плане","marker.control_passive":"пассивный источник","toast.marker_control_cycle":"Такая связь создаст циклическую цепочку управления светом.","toast.marker_binding_required":"Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.","confirm.unlock":"Открыть замок «{name}»?","toast.files_migrate_failed":"Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}","space.pick_saved":"Уже загруженные","space.pick_saved_hint":"Планы, сохранённые на сервере, включая отцеплённые ранее","space.no_saved":"На сервере пока нет сохранённых планов.","space.loading":"Загрузка…","space.used_by":"используется: {list}","space.in_use":"План используется пространством — сначала отцепите его","btn.use":"Выбрать","confirm.delete_plan":"Удалить файл плана «{name}» с сервера? Действие необратимо.","toast.plans_list_failed":"Не удалось получить список планов: {err}","toast.plan_delete_failed":"Не удалось удалить план: {err}","marker.hide":"Скрыть","marker.hide_tip":"Устройство исчезнет с плана после сохранения, но продолжит участвовать в расчёте сигнала комнаты. Вернуть его можно через каталог «Устройства» в редакторе устройств.","marker.show":"Показать","marker.show_tip":"Устройство снова появится на плане после сохранения.","marker.hidden_ghost":"Устройство скрыто пользователем","marker.ha_disabled_device":"Устройство деактивировано в Home Assistant и скрыто с плана.","marker.ha_disabled_entity":"Сущность деактивирована в Home Assistant и скрыта с плана.","marker.ha_disabled_all_entities":"У устройства нет активных сущностей Home Assistant, поэтому оно скрыто с плана.","marker.ha_registry_limited":"Полный реестр Home Assistant недоступен этому пользователю. Неподтверждённый объект временно нельзя показывать или использовать.","marker.delete_tip":"Полностью удалить устройство с плана и из всех расчётов. Позже его можно добавить заново.","tap.run":"Запустить автоматизацию/скрипт/сцену","tap.cover":"Открыть/закрыть (шторы/жалюзи)","marker.run_target_label":"Что запускать","marker.run_search_ph":"Поиск: автоматизация, скрипт или сцена…","marker.run_target_gone":"Цель {id} не найдена — выберите заново","marker.tap_confirm":"Спрашивать подтверждение","marker.tap_confirm_tip":"Перед выполнением показать диалог подтверждения — защита от случайных нажатий.","marker.toggle_hint_single":"Цель: {name} ({id}).","marker.virtual_light_target":"Виртуальный свет: {name}.","marker.virtual_light_current":"Ручное состояние: {state} → {effect}.","marker.virtual_light_state_on":"включён","marker.virtual_light_state_off":"выключен","marker.toggle_hint_group":"Переключатся источники ({count}): {names}.","marker.toggle_hint_current":"Сейчас: {state} → {effect}.","marker.toggle_hint_group_current":"Сейчас включено {on} из {count} → {effect}.","marker.toggle_hint_skipped":"Не будут затронуты ({count}): {targets}.","marker.toggle_effect_turn_on":"включится","marker.toggle_effect_turn_off":"выключится","marker.toggle_effect_open":"откроется","marker.toggle_effect_close":"закроется","marker.toggle_effect_stop":"остановится","marker.toggle_effect_toggle":"состояние переключится","marker.toggle_skip_missing":"не найдено","marker.toggle_skip_ha_disabled":"деактивировано в HA","marker.toggle_skip_unavailable":"недоступно","marker.toggle_skip_unsupported":"переключение не поддерживается","marker.toggle_skip_secure":"заблокировано из соображений безопасности","marker.toggle_none_no_binding":"У устройства нет привязки, состояние переключать нечем. По нажатию ничего не произойдёт.","marker.toggle_none_no_actionable_entity":"У устройства нет состояния, которое можно переключить. По нажатию ничего не произойдёт.","marker.toggle_none_configured_targets_missing":"Настроенные цели сейчас недоступны. Собственная сущность устройства не будет подставлена вместо них.","marker.toggle_none_ha_disabled":"Цель деактивирована в Home Assistant и не может использоваться на плане.","marker.toggle_none_unavailable":"Цель сейчас недоступна. По нажатию ничего не произойдёт.","marker.toggle_none_unsupported":"Для этой сущности Home Assistant не предоставляет безопасного переключения. По нажатию ничего не произойдёт.","marker.toggle_none_secure":"Переключение замков, сигнализации и защитных ворот с плана заблокировано из соображений безопасности.","run.automation":"автоматизация","run.script":"скрипт","run.scene":"сцена","confirm.tap_run":"Запустить «{name}»?","confirm.tap_toggle":"Переключить «{name}»?","confirm.tap_cover":"Открыть/закрыть «{name}»?","confirm.current_state":"Текущее состояние: {state}","confirm.expected_state":"После переключения: {state}","confirm.group_current":"включено {on} из {total}","confirm.group_all_on":"все включены","confirm.group_all_off":"все выключены","confirm.unavailable_targets":"Недоступно: {count}","confirm.expected_by_ha":"Состояние определит Home Assistant","confirm.state_on":"Включено","confirm.state_off":"Выключено","confirm.state_open":"Открыто","confirm.state_closed":"Закрыто","confirm.state_opening":"Открывается","confirm.state_closing":"Закрывается","confirm.state_stopped":"Остановлено","confirm.state_unknown":"Неизвестно","toast.run_started":"Запущено: {name}","toast.run_target_missing":"Цель запуска не найдена — проверьте настройки устройства","toast.run_target_required":"Выберите автоматизацию, скрипт или сцену","toast.tap_target_changed":"Цель действия изменилась. Повторите попытку.","toast.virtual_light_toggle_failed":"Не удалось переключить виртуальный свет: {err}","toast.value_badge_source_required":"Выберите значение для бейджа","btn.run":"Выполнить","vac.section":"Робот-пылесос: живая позиция","vac.autocal":"Настроить автоматически","vac.live":"Живая позиция на плане","vac.trail":"Показывать путь робота","vac.cal_maps":"Откалиброваны карты: {maps}","vac.autocal_no_rooms":"Интеграция не отдаёт список комнат — откройте «Подогнать вручную»","vac.autocal_no_match":"Не совпали имена комнат (нужно ≥3 общих) — откройте «Подогнать вручную»","vac.autocal_done":"Готово: привязка по {rooms} комнатам. Запустите уборку и проверьте","vac.cal_need_pos":"Робот сейчас не отдаёт координаты — запустите уборку и поставьте на паузу","vac.cal_done":"Калибровка сохранена. Запустите уборку и проверьте","vac.cal_cancelled":"Калибровка отменена","vac.fit":"Подогнать вручную","vac.fit_hint":"Перетащите карту робота на место, растяните за уголки","vac.fit_rotate":"Повернуть 90°","vac.fit_mirror":"Отразить","vac.trail_never":"Не показывать никогда","vac.trail_cleaning":"Во время уборки","vac.trail_always":"Показывать всегда","gs.bg_group":"Фон сцены","gs.bg_color":"Цвет фона вокруг плана","gs.bg_default":"Как в теме","gs.bg_theme":"по умолчанию — из темы","gs.bg_mode":"Фон плана","gs.bg_static":"Статичный цвет","gs.bg_daynight":"Следует за Солнцем","gs.bg_daynight_hint":"Фон проходит рассвет, день, закат и ночь по данным sun.sun, а при их недоступности — по локальным часам. Компас для фона не нужен.","gs.sun_group":"Солнце","gs.sun_missing":"Сущность sun.sun не найдена — фон следует локальным часам, а оконные лучи недоступны.","gs.north":"Север на плане","gs.north_ph":"не задан","gs.north_hint":"Север нужен только для оконных лучей (шаг 1°, с Shift 15°); солнечный фон работает без него.","gs.north_clear":"Сбросить","gs.north_letter":"С","gs.sun_rays":"Солнце в окнах","gs.about_group":"О карточке","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · документация и issues","gs.about_telegram":"Чат в Telegram","space.bg_color":"Цвет фона вокруг плана","space.bg_inherit":"Наследовать общий","space.bg_inherited":"наследуется из общих настроек","space.bg_mode":"Фон плана","space.north":"Север на плане (переопределение)","space.north_inherited":"наследуется: {v}","space.sun_rays":"Солнце в окнах","space.sun_inherit":"Наследовать общий","space.sun_on":"Вкл","space.sun_off":"Выкл","canvas.far_objects":"Объектов далеко от плана: {n}","canvas.show_far":"Показать","canvas.home_tip":"План там — нажмите, чтобы вписать","gs.grid_group":"Обслуживание планов","gs.grid_hint":"Обновляет модели данных, выравнивает элементы по сетке и объединяет лишние фрагменты стен. Перед записью будет показан точный отчёт.","gs.align_all":"Оптимизировать планы","gs.align_title":"Оптимизировать планы","gs.align_none":"Все планы уже используют актуальную и оптимальную модель данных.","gs.optimize_no_automatic_changes":"Автоматических изменений нет. Проверьте пункты ниже.","gs.align_count":"Сдвинется элементов: {n} из {total}, максимум на {cm} см.","gs.align_where":"Наибольший сдвиг — в пространстве «{s}».","gs.align_turned":"Проёмов с исправлением угла: {n}.","gs.align_removed_drafts":"Схлопнувшиеся на сетке некорректные контуры удалены: {n}.","gs.optimize_redundant_drafts":"Сохранённые цепочки стен, полностью скрытые стенами комнат, удалены: {n}.","gs.align_preflight_failed":"Не удалось безопасно проверить геометрию следующих пространств: {spaces}{more}.","gs.align_preflight_hint":"Планы не изменены. Скопируйте диагностику кнопкой ниже и приложите её к отчёту об ошибке вместе с экспортом пространства.","gs.preflight_reason_prepare-exception":"Не удалось подготовить геометрию пространства (исключение при сборке модели)","gs.preflight_reason_wall-null":"Тело стен не построилось (объединение вернуло пустоту)","gs.preflight_reason_wall-degraded-extra":"Тело стен деградировало с лишней геометрией","gs.preflight_reason_wall-failed-core":"Ядро тела стен не собралось","gs.preflight_reason_wall-exception":"Построение стен упало с исключением","gs.preflight_reason_floor-null":"Контур пола не построился","gs.preflight_reason_floor-exception":"Построение пола упало с исключением","gs.preflight_copy":"Скопировать диагностику","gs.preflight_copied":"Диагностика скопирована","gs.preflight_update_hint":"Версии карточки и интеграции различаются — обновите House Plan и повторите.","gs.align_preflight_space":"Пространство {n}","gs.align_preflight_more":" и ещё {n}","gs.optimize_changes":"Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.","gs.zero_walls_migrated":"Преобразовано виртуальных участков: {n}.","gs.wall_segments_migrated":"Стабилизировано сегментов стен: {n}.","gs.optimize_lattice_summary":"Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.","gs.optimize_lattice_space":"{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.","gs.optimize_coincident_partitions":"Скрытые участки независимых стен поглощены стенами комнат: {n}.","gs.optimize_openings_rehosted":"Проёмы перепривязаны к стенам комнат: {n}.","gs.optimize_walls_straightened":"Выпрямлено стен: {n}; максимальное перемещение: {cm} см.","gs.optimize_walls_straightened_where":"Максимальная правка стены: {s}.","gs.optimize_walls_straighten_skipped":"Оставлено почти осевых стен, которые нельзя безопасно выпрямить: {n}.","gs.optimize_glow_migration":"Старый Glow: пространств — {spaces} → без заливки данных + независимый Glow; комнат — {rooms} → наследуемая заливка + независимый Glow.","gs.optimize_references":"Исправлено ссылок: пространства — {spaces}; комнаты — {rooms}; позиции — {positions}; устройств отвязано от отсутствующих пространств — {detached}.","gs.optimize_reference_more":", и ещё {n}","gs.optimize_orphans_removed":"Убрано забытых записей: {total} — подписи комнат: {rooms}; устройства: {devices}; групповые метки: {groups}. Все они принадлежали пространствам, удалённым ранее.","gs.optimize_live_positions":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они будут сохранены.","gs.optimize_live_positions_remove":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они выбраны для удаления.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Убрать старые позиции","gs.optimize_live_keep":"Сохранить старые позиции","gs.optimize_live_selected":"Старые позиции будут убраны после применения оптимизации.","gs.optimize_unverified":"Не удалось безопасно проверить позиций: {n}. Они оставлены без изменений.","gs.optimize_registry_limited":"Для безопасной проверки нужен полный доступ администратора к реестрам Home Assistant.","gs.optimize_vacuum_warning":"Сопоставления комнат пылесоса требуют проверки: {n}.","gs.optimize_details":"Подробности","gs.optimize_details_more":"И ещё записей: {n}.","gs.optimize_detail_removed":"будет удалено","gs.optimize_detail_live":"будет сохранено","gs.optimize_detail_unverified":"не проверено","gs.optimize_detail_room_label":"подпись комнаты","gs.optimize_detail_device":"устройство","gs.optimize_detail_group":"групповая метка","gs.optimize_detail_unknown":"неизвестный владелец","gs.optimize_detail_item":"{status}: {kind} {id}; прежнее пространство {space}","gs.align_warn":"Элементы, намеренно поставленные между узлами, будут сдвинуты. После операции доступна одна отмена — только до следующего изменения плана.","gs.align_run":"Оптимизировать","gs.align_done":"Планы оптимизированы: сдвинуто элементов — {n}, обслужено записей — {m}, исправлено ссылок — {r}","gs.optimize_undo":"Отменить последнюю оптимизацию","gs.optimize_undone":"Последняя оптимизация отменена","decor.furniture":"Мебель","furn.title":"Библиотека мебели","furn.symbol":"Символ","furn.group_furniture":"Мебель","furn.group_appliance":"Техника","furn.group_sanitary":"Сантехника","furn.group_other":"Прочее","furn.width":"Ширина","furn.depth":"Глубина","furn.pick_hint":"Выберите символ и кликните по плану.","furn.place_hint":"Кликните по плану — предмет встанет к ближайшей стене. Shift — свободно.","furn.sym_sofa":"Диван","furn.sym_armchair":"Кресло","furn.sym_coffee_table":"Журнальный столик","furn.sym_table_dining":"Обеденный стол","furn.sym_table_round":"Круглый стол","furn.sym_chair":"Стул","furn.sym_desk":"Письменный стол","furn.sym_bed_double":"Двуспальная кровать","furn.sym_bed_single":"Односпальная кровать","furn.sym_nightstand":"Тумбочка","furn.sym_wardrobe":"Шкаф","furn.sym_bookshelf":"Стеллаж","furn.sym_fridge":"Холодильник","furn.sym_stove":"Плита","furn.sym_dishwasher":"Посудомоечная машина","furn.sym_washer":"Стиральная машина","furn.sym_dryer":"Сушильная машина","furn.sym_tv":"Телевизор","furn.sym_ac":"Кондиционер","furn.sym_water_heater":"Бойлер","furn.sym_toilet":"Унитаз","furn.sym_bathtub":"Ванна","furn.sym_shower":"Душ","furn.sym_sink":"Раковина","furn.sym_kitchen_sink":"Кухонная мойка","furn.sym_bidet":"Биде","furn.sym_stairs":"Лестница","furn.sym_fireplace":"Камин","furn.sym_plant":"Растение","furn.sym_rug":"Ковёр","common.yes":"Да","common.no":"Нет","vac.diag_source":"Источник","vac.diag_platform":"Интеграция","vac.diag_status":"Статус","vac.diag_position":"Позиция","vac.diag_rooms":"Комнаты","vac.diag_rooms_value":"{total} · совпало имён: {matched} · {readiness}","vac.autocal_ready":"автокалибровка доступна","vac.autocal_not_ready":"нужно 3 совпавших имени","vac.diag_path":"Путь интеграции","vac.diag_map":"ID карты","vac.source_none":"не выбран","vac.source_status_ok":"Готов","vac.source_status_missing":"Не найден","vac.source_status_disabled":"Деактивирован в Home Assistant","vac.source_status_unavailable":"Недоступен","vac.source_status_unverified":"Нельзя проверить с текущими правами","vac.source_status_unsupported":"Нет данных позиции","vac.source_status_none":"Нет источника","vac.source_banner_missing":"Сохранённый источник больше не существует. Он не заменён автоматически: выберите другой или восстановите его в Home Assistant.","vac.source_banner_disabled":"Сохранённый источник деактивирован в Home Assistant. Активируйте его там или выберите другой.","vac.source_banner_unverified":"Текущих прав Home Assistant недостаточно для проверки источника. Привязка сохранена и не будет заменена автоматически.","vac.choose_source":"Выбрать источник","vac.source_auto":"Автоматически","vac.source_auto_hint":"Использовать совместимую сущность этого устройства","vac.all_cameras":"Все камеры","vac.all_cameras_warn":"Камера может не отдавать данные робота. Выбирайте её только если это карта вашего пылесоса.","vac.all_cameras_empty":"Других сущностей камеры не найдено.","vac.platform_unknown":"интеграция неизвестна","vac.cap_position":"позиция","vac.cap_rooms_short":"комнаты","vac.cap_path":"путь","vac.cap_map":"ID карты","vac.cap_none":"данные робота не обнаружены","vac.xcme_hint":"Включите атрибуты Xiaomi Cloud Map Extractor:","vac.documentation":"Документация","vac.residual_title":"Проверьте автокалибровку","vac.residual_message":"Совпавшие комнаты расходятся максимум на {error}. Примените приблизительную калибровку, подгоните её вручную либо отмените без изменения сохранённых настроек.","vac.apply_proposal":"Применить","gs.backup_group":"Резервная копия и перенос","gs.backup_hint":"Скачайте переносимую JSON-копию или проверьте и импортируйте копию, созданную House Plan.","backup.export_open":"Экспорт","backup.import_open":"Импорт","backup.export_title":"Экспорт House Plan","backup.import_title":"Импорт House Plan","backup.export_hint":"Выберите, должна ли копия содержать всю конфигурацию House Plan или только текущее пространство.","backup.full":"Полная копия","backup.current_space":"Текущее пространство","backup.current_space_title":"Текущее пространство: {title}","backup.no_current_space":"Нет текущего пространства","backup.plan_only":"Только планировка","backup.plan_only_hint":"Сохранить комнаты, стены, проёмы, декор и позиции подписей комнат без устройств и привязок Home Assistant.","backup.plan_only_preview":"Файл содержит только планировку","backup.privacy_warning":"Архив сохраняет названия, идентификаторы Home Assistant и точные координаты. Внутренние планы и вложения указываются ссылками, но не вкладываются; текущие состояния и маршруты пылесосов не включаются.","backup.download":"Скачать JSON","backup.export_done":"Резервная копия скачана","backup.reading":"Проверяем резервную копию…","backup.revalidated":"После предпросмотра план изменился. Сводка обновлена — проверьте её и подтвердите ещё раз.","backup.error.unauthorized":"У вас нет прав на экспорт или импорт этого плана.","backup.error.not_ready":"House Plan ещё не готов. Повторите попытку через несколько секунд.","backup.error.too_large":"Размер резервной копии превышает 8 МиБ.","backup.error.invalid_json":"Выбранный файл не является корректным JSON.","backup.error.invalid_format":"Выбранный файл не является резервной копией House Plan.","backup.error.unsupported_export_version":"Эта версия формата резервной копии не поддерживается установленной версией.","backup.error.future_model":"Резервная копия создана в более новой версии модели данных House Plan.","backup.error.invalid_config":"Резервная копия содержит некорректную конфигурацию House Plan.","backup.error.wall_model_migration_blocked":"Не удалось безопасно обновить модель стен из резервной копии. Сначала оптимизируйте исходный план и повторите экспорт.","backup.error.invalid_layout":"Резервная копия содержит некорректные позиции объектов.","backup.error.invalid_content":"Резервная копия содержит некорректные или несогласованные ссылки на файлы.","backup.error.space_not_found":"Выбранное пространство больше не существует.","backup.error.capacity_exceeded":"Добавление этой копии превысит ограничения размера плана.","backup.error.preview_expired":"Время предпросмотра истекло. Выберите файл резервной копии заново.","backup.error.preview_owner_mismatch":"Этот предпросмотр принадлежит другому пользователю Home Assistant.","backup.error.conflict":"После предпросмотра план изменился. Проверьте обновлённую сводку.","backup.error.content_confirmation_required":"Подтвердите отсоединение недоступных локальных файлов.","backup.error.commit_failed":"Не удалось безопасно применить копию. Предыдущий план восстановлен или ожидает восстановления.","backup.error.missing_plan":"После предпросмотра исчез связанный файл плана. Проверьте копию ещё раз.","backup.error.missing_content":"После предпросмотра исчез связанный локальный файл. Проверьте копию ещё раз.","backup.error.marker_control_missing":"В резервной копии отсутствует связанный источник света на плане.","backup.error.marker_control_not_light":"Связанная цель больше не отмечена как источник света.","backup.error.marker_control_self":"Источник света не может управлять самим собой.","backup.error.marker_control_cycle":"Резервная копия содержит циклическую цепочку управления светом.","backup.error.duplicate_marker_control":"Резервная копия содержит повторяющуюся связь с источником света.","backup.error.no_backup":"Нет снимка импорта или оптимизации, который можно восстановить.","backup.same_source":"Создано на этом экземпляре Home Assistant","backup.foreign_source":"Создано на другом экземпляре Home Assistant","backup.created":"Создано: {value}","backup.versions":"Карточка {card}; интеграция {integration}; модель данных {model}","backup.count_spaces":"Пространств: {n}","backup.count_rooms":"Комнат: {n}","backup.count_walls":"Стен: {n}","backup.count_openings":"Проёмов: {n}","backup.count_decor":"Объектов декора: {n}","backup.count_markers":"Устройств: {n}","backup.count_layout":"Позиций: {n}","backup.bindings":"Привязки — устройства: {device}, сущности: {entity}, виртуальные: {virtual}; позиций без пространства: {legacy}","backup.binding_status":"Статус на целевом экземпляре — активных: {active}, деактивированных: {disabled}, отсутствующих: {missing}","backup.missing_areas":"На целевом экземпляре отсутствуют зоны: {areas}","backup.dropped_marker_links":"Связи с источниками света вне переносимого пространства пропущены: {n}.","backup.repaired_target_refs":"Существующих ссылок восстановлено этим импортом: {n}.","backup.preserved_unresolved_refs":"Неоднозначные ссылки сохранены без изменений: {n}.","backup.preserved_unresolved_hint":"House Plan ничего не угадывал и не удалял. После импорта запустите «Оптимизировать планы», чтобы проверить оставшиеся ссылки.","backup.import_details":"Подробности восстановления ссылок","backup.import_detail.incoming_remapped":"Ссылок обновлено внутри импортируемой копии: {n}","backup.import_detail.target_repaired":"Существующих ссылок восстановлено: {n}","backup.import_detail.preserved_unresolved":"Неразрешимых ссылок сохранено: {n}","backup.import_detail.collisions":"Конфликтов назначения безопасно сохранено: {n}","backup.import_detail.dropped_links":"Входящих связей пропущено по правилам переноса: {n}","backup.import_detail.bounded_lineages":"Чрезмерно вложенных идентификаторов ограничено: {n}","backup.replace_warning":"Текущая конфигурация и расположение будут заменены. Загруженные файлы не удаляются. Одну отмену можно выполнить до следующего изменения плана.","backup.foreign_bookkeeping":"Служебные списки известных и новых устройств другого экземпляра импортированы не будут.","backup.final_name":"Название нового пространства","backup.target_settings":"Глобальные настройки целевого экземпляра не изменятся.","backup.duplicates":"Уже существующих привязок: {n}","backup.skip":"Пропустить повторяющиеся устройства","backup.virtual_copy":"Добавить безопасные статичные виртуальные копии","backup.content":"Связанное содержимое","backup.content_available":"доступно локально","backup.content_external":"внешняя ссылка","backup.content_detach_required":"будет отвязано","backup.confirm_detach":"Я понимаю, что недоступные внутренние планы и вложения будут отвязаны от импортируемой конфигурации.","backup.replace":"Заменить","backup.add":"Добавить пространство","backup.space_done":"Пространство импортировано: комнат — {rooms}, устройств — {markers}, существующих ссылок восстановлено — {refs}","backup.full_done":"Копия восстановлена: пространств — {spaces}, комнат — {rooms}, устройств — {markers}","backup.undo_import":"Отменить последний полный импорт","backup.import_undone":"Полный импорт отменён"}}],Gd=Wd;function Vd(e){return"string"==typeof e?e.trim().replaceAll("_","-").toLowerCase():""}const Kd=new Map(Ud.map(e=>[Vd(e.code),e]));function Yd(e){return Kd.get(Vd(e))}function Zd(e,t){const i=[{value:"",label:e},...Ud.map(({code:e,nativeLabel:t})=>({value:e,label:t}))],n="string"==typeof t?t:"";return n&&!i.some(e=>e.value===n)&&i.push({value:n,label:Yd(n)?.nativeLabel??n}),i}function Xd(e,t){return function(e,t,i,n){const r=new Map(i.map(e=>[Vd(e),e])),o=r.get(Vd(e));if(o)return o;const s=Vd(t),a=r.get(s);return a||(r.get(s.split("-")[0]||"")??n)}(t,e?.locale?.language||e?.language,Ud.map(({code:e})=>e),"en")}function Jd(e,t,i){const n=Yd(e)?.dictionary;return Vi(n?.[t]??Gd[t]??t,i)}function Qd(e,t){const i=Yd(e)?.dictionary[t]??Gd[t];return"string"==typeof i&&i.trim().length>0}function eu(e){const t=e.length/2,i=e.face.cm>0?e.face.cm/e.cellCm*e.gridPitch/2:xa(4,e.cellCm),n="gate"===e.type?Math.sin(10*Math.PI/180)*t:0;return{half:t,jambHalf:i,gateDepth:n,outlineHalf:Math.max(xa(16,e.cellCm),i+xa(8,e.cellCm),n+xa(8,e.cellCm)),hitHalf:Math.max(xa(20,e.cellCm),i+xa(10,e.cellCm),n+xa(12,e.cellCm))}}function tu(e){if("passage"===e.type)return W``;const t=Math.max(0,Math.min(1,e.amount)),{half:i,jambHalf:n}=eu(e),r=ka(e.cellCm),o=1.75*r,s=e.flipH?-1:1,a=e.flipV?-1:1,l="gate"===e.type?1:a;e.type,e.flipV,e.angle,e.face;let c;if("window"===e.type){const o=Math.PI/2*i,s=e.face.cm>0?W``:W``;c=W` + + + + + + + + + + + + + + ${s} + `}else if("gate"===e.type){const n=10*e.face.side*t;c=W` + + + + + + + + + + + + `}else{const n=Math.PI/2*e.length;c=W` + + + + + + + + `}return W` + + + ${c} + `}const iu={climate:["current_temperature","temperature","current_humidity","humidity"],water_heater:["current_temperature","temperature"],cover:["current_position"],valve:["current_position"],fan:["percentage"],humidifier:["current_humidity","humidity"],light:["brightness"],media_player:["volume_level"],vacuum:["battery_level","fan_speed"],lawn_mower:["battery_level","fan_speed"]};function nu(e){return e?e.sourceLabel?`${e.sourceLabel}: ${e.fullText}`:e.fullText:""}const ru=new WeakMap;function ou(e){return e?"entity_state"===e.kind?`state:${e.entity_id}`:"entity_attribute"===e.kind?`attr:${e.entity_id}:${e.attribute}`:"derived_marker_state"===e.kind?`marker:${e.ref}`:"derived:lqi":""}function su(e){if("derived:lqi"===e)return{kind:"derived_lqi"};if(e.startsWith("state:"))return{kind:"entity_state",entity_id:e.slice(6)};if(e.startsWith("attr:")){const t=e.slice(5),i=t.lastIndexOf(":");if(i>0)return{kind:"entity_attribute",entity_id:t.slice(0,i),attribute:t.slice(i+1)}}return e.startsWith("marker:marker:")?{kind:"derived_marker_state",ref:e.slice(7)}:null}function au(e,t){const i=e?.entities?.[t],n=e?.states?.[t];return String(i?.name||i?.original_name||n?.attributes?.friendly_name||t)}function lu(e){return e.replaceAll("_"," ")}function cu(e,t=1){const i=Number(e);return Number.isFinite(i)?`${Math.round(i*t)} %`:null}function hu(e){if("derived_lqi"===e.kind)return"lqi";if("entity_attribute"===e.kind){if(e.attribute.includes("temperature"))return"temperature";if(e.attribute.includes("humidity"))return"humidity"}return"default"}function du(e,t,i,n=[]){let r=null,o="",s="available";if("entity_state"===i.kind){o=au(e,i.entity_id);const t=e?.states?.[i.entity_id];if(t)if(pu(e,i.entity_id))if(["unknown","unavailable"].includes(String(t.state).toLowerCase()))s="unavailable";else{const n=qi(e,i.entity_id);r=n?ji(n,String(t.attributes?.unit_of_measurement||"")):null,r||(s="unavailable")}else s="unavailable";else s="missing"}else if("entity_attribute"===i.kind){o=`${lu(i.attribute)} · ${au(e,i.entity_id)}`;const t=e?.states?.[i.entity_id];t?pu(e,i.entity_id)?(r=function(e,t,i){const n=e?.states?.[t];if(!n||!(i in(n.attributes||{})))return null;const r=qi(e,t,i);if(r?.formatted)return r.text;const o=n.attributes?.[i];if("brightness"===i)return cu(o,100/255);if("volume_level"===i)return cu(o,100);if(["current_position","percentage","current_humidity","humidity","battery_level"].includes(i))return cu(o);if("current_temperature"===i||"temperature"===i){const t=Number(o);if(!Number.isFinite(t))return null;const i=String(e?.config?.unit_system?.temperature||"°C");return`${Math.round(10*t)/10} ${i}`}return r?.text||(["string","number","boolean"].includes(typeof o)?String(o):null)}(e,i.entity_id,i.attribute),null==r&&(s="unavailable")):s="unavailable":s="missing"}else if("derived_lqi"===i.kind){o="LQI";const i=Ch(e,t.entities);null==i?s="unavailable":r=String(i)}else{o="Light state";const t=n.find(e=>e.ref===i.ref);if(t){const i=t.on?"on":"off",n=e?.localize?.(`state.default.${i}`);r="string"==typeof n&&n?n:i,o=t.name||o}else s="missing"}const a=e?.localize?.("state.default.unavailable")||"Unavailable";return{source:i,sourceLabel:o,text:r??"—",fullText:r??a,availability:s,isLqi:"derived_lqi"===i.kind,tone:hu(i)}}function uu(e,t){if(!0===t.marker?.use_climate_temp){const i=t.entities.find(t=>t.startsWith("climate.")&&Number.isFinite(Number(e?.states?.[t]?.attributes?.current_temperature)));return i?{kind:"entity_attribute",entity_id:i,attribute:"current_temperature"}:null}if("mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon){const i=t.entities.find(t=>sh(e,t)&&Number.isFinite(Number(e?.states?.[t]?.state)));if(i)return{kind:"entity_state",entity_id:i}}return t.primary&&Oh(e,t.primary)&&Number.isFinite(Number(e?.states?.[t.primary]?.state))?{kind:"entity_state",entity_id:t.primary}:null}function pu(e,t){const i=e?.entities?.[t];if(i&&!Zc(i))return!1;const n=i?.device_id?e?.devices?.[i.device_id]:null;return!n||Zc(n)}function _u(e,t){return pu(e,t)&&!!e?.states?.[t]}function mu(e,t,i=[t]){const n=function(e,t){const i=e=>[e.id,e.primary,e.hidden?1:0,e.userHidden?1:0,e.entities.join(","),(e.controls||[]).join(","),e.marker?.binding||"",!0===e.marker?.is_light?1:0,e.marker?.light_entity||"",(e.marker?.controls||[]).join(",")].join("|");return`${i(e)}\n${t.map(i).join("\n")}`}(t,i),r=ru.get(t);if(r&&r.states===(e?.states||null)&&r.entities===(e?.entities||null)&&r.devices===(e?.devices||null)&&r.signature===n)return r.result;const o=new Set(t.entities);for(const e of t.controls||[])e.startsWith("marker:")||o.add(e);const s=[],a=Mh(e,i),l=a.filter(e=>e.key.startsWith("marker:")).map(e=>({ref:e.key,on:e.on,name:e.device?.name||e.key})),c=i=>{const n=ou(i);if(s.some(e=>e.key===n))return;const r=du(e,t,i,l),o="entity_attribute"===i.kind?`${i.entity_id} · ${i.attribute}`:"entity_state"===i.kind?i.entity_id:"derived_marker_state"===i.kind?i.ref:"LQI";s.push({key:n,source:i,label:r.sourceLabel,technical:o,value:r.text,available:"available"===r.availability})};for(const t of[...o].sort()){if(!_u(e,t))continue;const i=t.split(".")[0],n=e?.entities?.[t];if("button"===i||"event"===i||"config"===n?.entity_category)continue;c({kind:"entity_state",entity_id:t});const r=e?.states?.[t];for(const e of iu[i]||[])e in(r?.attributes||{})&&c({kind:"entity_attribute",entity_id:t,attribute:e})}const h=new Set((t.marker?.controls||t.controls||[]).filter(e=>e.startsWith("marker:")));!0===t.marker?.is_light&&t.marker.id&&h.add(`marker:${t.marker.id}`);const d=new Set(a.map(e=>e.key));for(const e of[...h].sort())d.has(e)&&c({kind:"derived_marker_state",ref:e});return t.virtual||null==Ch(e,t.entities)||c({kind:"derived_lqi"}),ru.set(t,{states:e?.states||null,entities:e?.entities||null,devices:e?.devices||null,signature:n,result:s}),s}function gu(e,t,i){const n=uu(e,t);if(n&&i.some(e=>e.key===ou(n)))return n;const r=t.primary&&i.find(e=>e.key===`state:${t.primary}`);if(r)return r.source;const o=[e=>e.technical.includes("temperature"),e=>e.technical.includes("humidity"),e=>e.technical.includes("battery")];for(const e of o){const t=i.find(e);if(t)return t.source}return i.find(e=>"derived_lqi"!==e.source.kind)?.source||i[0]?.source||null}function fu(e){return e.touched?{value_badge:{enabled:e.enabled,source:e.source,position:e.position}}:e.originalHas?{value_badge:e.original}:{}}function vu(e,t,i){return{kind:"none",reason:"none",generation:e,expiresAt:null,color:t,diameterScale:i,animated:!1,reducedMotionIndicator:"none"}}function yu(e,t,i,n,r=null){return{kind:t,reason:"short"===t?"event":"running",generation:Math.max(1,Math.trunc(i)),expiresAt:"short"===t?r:null,color:e.color,diameterScale:n?1:e.diameterScale,animated:!n,reducedMotionIndicator:n?"dot":"none"}}const bu={availability:"available",status:"neutral",activity:"none"};function wu(e){return e<=40?"low":e<180?"mid":"high"}function ku(e){return Ut(e)}function xu(e){return"static_icon"===e.display?"neutral":"alarm"===e.visual.status?"alarm":"unavailable"===e.visual.availability?"unavailable":e.lockState?e.lockState:"working"===e.visual.status?"working":"open"===e.visual.status?"open":"neutral"}const $u={sourceKind:"none",decisionIds:["source.skipped_static_fast_path"],visualSources:[],criticalSources:[],samples:[]};function Su(e,t){const i=e?.entities?.[t],n=e?.states?.[t];return String(i?.name||i?.original_name||n?.attributes?.friendly_name||t)}function Mu(e,t){const i=e?.states?.[t];if(!i)return"";if("function"==typeof e?.formatEntityState)try{const t=e.formatEntityState(i);if("string"==typeof t&&t)return t}catch{}return String(i.state??"")}function Ru(e,t){if(t.virtual||"virtual"===t.bindingKind||"virtual"===t.marker?.binding)return"available";return(t.entities||[]).some(t=>{const i=String(e?.states?.[t]?.state??"").trim().toLowerCase();return""!==i&&"unknown"!==i&&"unavailable"!==i})?"available":"unavailable"}function Tu(e,t,i,n){return{eid:t,role:i,name:Su(e,t),state:String(e?.states?.[t]?.state??""),stateText:Mu(e,t),integrationDomain:e?.entities?.[t]?.platform||null,sample:n||xc(e,t)}}function Cu(e,t,i=[t],n,r=e){const o=t.hidden&&t.userHidden?{...t,hidden:!1}:t;let s="none",a=[];const l=[],c=[...o.entities,...o.allEntities||[]].some(e=>e.startsWith("cover."))?{...o,tapAction:"cover"}:o,h=(d=vd({hass:e,devices:i,device:c,lightSources:n,registryHass:r}),"cover"!==d?.semantics?null:d.targets[0]?.entityId||d.skippedTargets[0]?.entityId||null);var d;const u=Mh(e,[o]),p=uh(o.marker?.binding,o.marker?.controls??o.controls,o.entities),_=new Set(p.filter(e=>e.startsWith("marker:"))),m=!0===o.marker?.is_light||_.size>0?n||Mh(e,i):u,g=m.filter(e=>e.device.id===o.id&&"controls"!==e.via),f=u.filter(e=>"controls"!==e.via),v=g.length?g:f,y=zc(o.marker),b=y?[...v]:[...u.filter(e=>"controls"===e.via),...v];if(_.size)for(const e of m){if(!_.has(e.key))continue;e.stateEids.length>0&&b.some(t=>t.stateEids.some(t=>e.stateEids.includes(t)))||b.some(t=>t.key===e.key)||b.push({...e,via:"controls",castsGlow:!1})}const w=ch(r,o.entities),k=!!h&&("cover"===o.tapAction||o.primary?.startsWith("cover.")||w.some(e=>e.startsWith("cover.")));if(h&&!k&&l.push("source.cover_capability_bypassed"),k)s="cover",l.push("source.cover"),a=[Tu(e,h,"cover")];else if(b.length)s=!y&&b.some(e=>"controls"===e.via)?"controls":"light",y?l.push("source.manual_virtual_light"):l.push("controls"===s?"source.controls":"source.owned_light"),"controls"!==s||!o.virtual&&"virtual"!==o.bindingKind||l.push("source.virtual_controller"),a=b.map(i=>{const n="controls"===i.via?"control":"forced"===i.via?"forced_light":"light";if(!i.passive)return Tu(e,i.eid,n);const r=i.on?"on":"off";return{eid:i.key,role:n,name:t.name,state:r,stateText:r,integrationDomain:null,sample:{eid:i.key,state:r,availability:"available",status:i.on?"working":"neutral",activity:"none",edge:"none"}}});else{const t=ch(r,o.entities),i=t.length?t:o.entities.filter(t=>!!e?.states?.[t]);if(i.length){s="device_role",l.push("source.device_role");const t=$c(r===e?e:{...r,states:e?.states||{}},i,o.entities),n=i.some(e=>bc(r,e));a=t.map(t=>{const i=n?wc(r,t.eid)?"power_gate":bc(r,t.eid)?"lifecycle":"device_role":"device_role";return Tu(e,t.eid,i,t)})}else o.primary?(s="primary",l.push("source.primary_fallback"),a=[Tu(e,o.primary,"primary")]):l.push("source.none")}p.length>0&&"controls"!==s&&"light"!==s&&"cover"!==s&&l.push("source.filtered_saved_controls");const x=[];for(const t of o.entities||[]){const i=xc(e,t);"alarm"!==i.status||a.some(e=>e.eid===t)||x.push(Tu(e,t,"critical",i))}return x.length&&l.push("source.critical_sibling"),{sourceKind:s,decisionIds:l,visualSources:a,criticalSources:x,samples:[...a,...x].map(e=>e.sample)}}function Du(e,t,i,n){if(t.virtual)return{source:null,text:null,fallback:"value_virtual"};if(n){const i=function(e,t){if(!0!==t.marker?.use_climate_temp)return null;for(const i of t.entities){if(!i.startsWith("climate."))continue;const t=Number(e?.states?.[i]?.attributes?.current_temperature);if(Number.isFinite(t))return{eid:i,text:Math.round(10*t)/10+"°"}}return null}(e,t);if(i)return{source:{kind:"temperature",eid:i.eid,attribute:"current_temperature",text:i.text},text:i.text,fallback:null};const n=function(e,t){if("mdi:thermometer"!==t.icon&&"mdi:air-filter"!==t.icon)return null;for(const i of t.entities){if(!sh(e,i))continue;const t=Number(e?.states?.[i]?.state);if(Number.isFinite(t))return{eid:i,text:Math.round(10*t)/10+"°"}}return null}(e,t);if(n)return{source:{kind:"temperature",eid:n.eid,text:n.text},text:n.text,fallback:null};const r=function(e,t){if(!t.primary||!Oh(e,t.primary))return null;const i=Number(e?.states?.[t.primary]?.state);return Number.isFinite(i)?{eid:t.primary,text:`${Math.round(i)}%`}:null}(e,t);if(r)return{source:{kind:"humidity",eid:r.eid,text:r.text},text:r.text,fallback:null}}const r=i.visualSources.filter(e=>!e.eid.startsWith("marker:"));let o=r.map(e=>e.eid);const s=r.find(e=>"power_gate"===e.role);if(s&&(o=[s.eid]),!o.length&&i.visualSources.some(e=>e.eid.startsWith("marker:"))&&(o=ch(e,t.entities),!o.length&&t.primary&&e?.states?.[t.primary]&&(o=[t.primary])),o=[...new Set(o)],1!==o.length)return{source:null,text:null,fallback:o.length?"value_ambiguous_sources":"value_no_state"};const a=o[0],l=function(e,t){const i=e?.states?.[t];if(!i||null==i.state||""===String(i.state).trim())return{text:"",fallback:"value_no_state"};const n=i.state;if(!["string","number","boolean"].includes(typeof n))return{text:"",fallback:"value_non_scalar"};const r=String(n).trim().toLowerCase();if("unknown"===r||"unavailable"===r)return{text:"",fallback:"value_no_state"};const o=qi(e,t);return o?{text:ji(o,String(i.attributes?.unit_of_measurement||"")),fallback:null}:{text:"",fallback:"value_no_state"}}(e,a);return l.fallback?{source:null,text:null,fallback:l.fallback}:{source:{kind:"entity",eid:a,text:l.text},text:l.text,fallback:null}}function Au(e,t,i){const n=e.marker?.binding||(e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:e.virtual?"virtual":""),r=[...t.visualSources.map(e=>`${e.role}:${e.eid}`),...t.criticalSources.map(e=>`critical:${e.eid}`)].sort(),o=i?`${i.kind}:${i.eid}:${i.attribute||""}`:"none";return[n,t.sourceKind,...r,`value:${o}`].join("\n")}function Ou(e,t,i){return Au(t,i||Cu(e,t),null).replace(/\nvalue:none$/,"")}function zu(e){if(e.effectiveHidden)return[];if("static_icon"===e.display)return["static-icon"];const t=[],{visual:i}=e;return"alarm"===e.pulse.kind?t.push("alarm"):"unavailable"===i.availability?t.push("unavail"):"working"===i.status?t.push("on"):"open"===i.status&&t.push("open"),e.lockState&&t.push(`lock-${e.lockState}`),"none"!==e.pulse.reason&&"alarm"!==e.pulse.reason&&t.push("activity-"+e.pulse.reason),e.pulse.generation%2==0&&(t.push("pulse-gen2"),"short"===e.pulse.kind&&t.push("activity-gen2")),t}function Pu(e,t,i){const n=Ai(t.marker?.display),r="static_icon"===n,o=r&&!1===i.sourceDetails?$u:Cu(e,t,i.lightDevices||[t],i.lightSources,i.registryHass||e),s=t.bindingStatus,a="ha_disabled"===s?.kind,l="orphaned"===s?.kind,c=a?"ha_disabled":l?"orphaned":"active",h=!0===t.userHidden||!0===t.marker?.hidden,d=Sc(o.samples),u=o.visualSources.find(e=>e.eid.startsWith("lock.")),p=u?["unlocked","open"].includes(u.state.toLowerCase())?"unlocked":"locked"===u.state.toLowerCase()?"locked":null:null,_=!zc(t.marker)&&uh(t.marker?.binding,t.marker?.controls??t.controls,t.entities).length>0,m="controls"===o.sourceKind||_&&"light"!==o.sourceKind&&"cover"!==o.sourceKind,g=r&&!1===i.sourceDetails?{source:null,text:null,fallback:null}:Du(e,t,o,i.showTemperature),f=Au(t,o,g.source),v=Ou(e,t,o),y=i.activityRuntime,b=i.now??Date.now(),w=y?.expiresAt||(y?.flashTs?y.flashTs+3300:0),k=y?.sources===v&&y.flashTs&&y.flashKind&&w>b?y.flashKind:null,x=function(e){const t=[],i="ha_disabled"===e.bindingLifecycle||"orphaned"===e.bindingLifecycle;let n=!1;"ha_disabled"===e.bindingLifecycle?(n=!0,t.push("lifecycle.ha_disabled_hidden")):e.userHidden&&!e.designPreview?(n=!0,t.push("lifecycle.user_hidden")):e.userHidden?t.push("lifecycle.user_hidden_preview"):"orphaned"===e.bindingLifecycle?t.push("lifecycle.orphaned_diagnostic"):t.push("lifecycle.active");const r="static_icon"===e.display;let o=e.controllerFace?{...e.sourceVisual,availability:e.controllerAvailability}:e.sourceVisual;t.push(e.controllerFace?"available"===e.controllerAvailability?"availability.controller_available":"availability.controller_unavailable":"availability.source"),n?(o=bu,t.push("face.hidden")):r?(o=bu,t.push("face.static")):"alarm"===e.sourceVisual.status||e.liveStates?t.push("face.dynamic"):(o=bu,t.push("face.live_states_disabled")),!r&&!n&&e.liveStates&&"alarm"!==e.sourceVisual.status&&e.shortActivity&&(o={...o,activity:e.shortActivity},t.push(`activity.short_${e.shortActivity}`)),"alarm"===o.status?t.push("status.alarm"):"unavailable"===o.availability?t.push("status.unavailable"):"working"===o.status?t.push("status.working"):"open"===o.status?t.push("status.open"):t.push("status.neutral");const s="value"===e.display&&!n&&e.valueAvailable?"value":"icon";t.push("value"===s?"content.value":"value"===e.display?"content.value_fallback_icon":"content.icon"),"value"===e.display&&!e.valueAvailable&&e.valueFallback&&t.push(`content.${e.valueFallback}`);const a=e.liveStates&&!r&&!n,l=!r&&!n,c=!n&&!i&&!r&&"available"===o.availability&&("alarm"===o.status||e.liveStates&&"icon_ripple"===e.display),h=l&&e.vacuumLiveRequested;return t.push(a?"diagnostics.dynamic_icon":"diagnostics.base_icon"),t.push(l?"diagnostics.metrics_enabled":"diagnostics.metrics_suppressed"),t.push(c?"activity.pulse_eligible":"activity.pulse_suppressed"),t.push(h?"diagnostics.vacuum_live":"diagnostics.vacuum_static"),{effectiveHidden:n,bindingUnavailable:i,visual:o,face:s,dynamicIcon:a,metrics:l,liveColor:a,pulseEligible:c,vacuumLive:h,decisionIds:t}}({bindingLifecycle:c,userHidden:h,designPreview:!0===i.designPreview,display:n,liveStates:i.liveStates,sourceVisual:d,controllerFace:m,controllerAvailability:m?Ru(e,t):"available",shortActivity:k,valueAvailable:null!=g.text,valueFallback:g.fallback,vacuumLiveRequested:!0===t.marker?.vacuum?.live}),{effectiveHidden:$,visual:S}=x,M="icon_ripple"===n&&!$&&i.liveStates&&"alarm"!==S.status?S.activity:"none",R=x.metrics&&i.showTemperature?!0===t.marker?.use_climate_temp?Ah(e,t.entities):"mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon?Dh(e,t.entities):null:null,T=x.metrics&&i.showTemperature&&t.primary&&Oh(e,t.primary)?zh(e,t.entities):null,C=x.metrics&&i.showSignal&&!t.virtual?Ch(e,t.entities):null,D=i.lightSources||("derived_marker_state"===t.marker?.value_badge?.source?.kind?Mh(e,i.lightDevices||[t]):[]),A=function(e,t,i){const n=null!=t.marker?.value_badge;if(i.effectiveHidden||"static_icon"===i.display)return null;const r=t.marker?.value_badge;if(n)return r?.enabled?r.source?{configured:!0,enabled:!0,position:r.position||"right",...du(e,t,r.source,i.markerStates)}:{configured:!0,enabled:!0,source:null,sourceLabel:"",text:"—",fullText:e?.localize?.("state.default.unavailable")||"Unavailable",position:r.position||"right",availability:"missing",isLqi:!1,tone:"default"}:null;if(!i.showTemperature||"value"===i.display)return null;const o=uu(e,t);if(!o)return null;let s=null,a="default";if("entity_attribute"===o.kind&&"current_temperature"===o.attribute){const i=Ah(e,t.entities);null!=i&&(s=`${i}°`),a="temperature"}else if("mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon){const i=Dh(e,t.entities);null!=i&&(s=`${i}°`),a="temperature"}else{const i=zh(e,t.entities);null!=i&&(s=`${i}%`),a="humidity"}return null==s?null:{configured:!1,enabled:!0,source:o,position:"right",sourceLabel:"entity_attribute"===o.kind?`${lu(o.attribute)} · ${au(e,o.entity_id)}`:"entity_state"===o.kind?au(e,o.entity_id):"",text:s,fullText:s,availability:"available",isLqi:!1,tone:a}}(e,t,{showTemperature:i.showTemperature,showSignal:i.showSignal,display:n,effectiveHidden:$,markerStates:D.filter(e=>e.key.startsWith("marker:")).map(e=>({ref:e.key,on:e.on,name:e.device.name}))}),O=o.visualSources.find(e=>!e.eid.startsWith("marker:")),z="cover"===o.sourceKind?O?.eid:t.primary||O?.eid,P=z?e?.states?.[z]:null,F=x.dynamicIcon?dn(t.icon,z?.split(".")[0],P?.attributes?.device_class,P?.state,!!t.marker?.icon):t.icon,I=x.liveColor&&o.visualSources.filter(e=>!e.eid.startsWith("marker:")).map(t=>function(e){return e&&"on"===e.state?Wt(e.attributes?.rgb_color):null}(e?.states?.[t.eid])).find(e=>!!e)||null,E=Number(t.marker?.size)>0?Number(t.marker.size):1,N=Number(t.marker?.angle)||0,H=Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,L=qt(t.marker?.ripple_color,null),q=r?null:L||I||null,j=function(e){const{display:t,visual:i,semanticActivity:n,liveStates:r,effectiveHidden:o,bindingUnavailable:s=!1,reducedMotion:a=!1}=e,l=Math.max(1,Math.trunc(e.shortGeneration||1)),c=Number.isFinite(e.diameterScale)?Math.max(1,Number(e.diameterScale)):1.5,h=e.color||function(e,t){return"presence"===t?"#1DC21D":"running"===t||"working"===e.status||"open"===e.status?"#F0A00C":"#0C82F0"}(i,n);if(o||s||"unavailable"===i.availability||"static_icon"===t)return vu(l,h,c);if("alarm"===i.status)return{kind:"alarm",reason:"alarm",generation:l,expiresAt:null,color:"#F0410C",diameterScale:1.5,animated:!a,reducedMotionIndicator:"none"};if(!r||"icon_ripple"!==t)return vu(l,h,c);const d=e.now??Date.now(),u=e.shortExpiresAt||null;return e.shortReason&&null!=u&&u>d?{kind:"short",reason:e.shortReason,generation:l,expiresAt:u,color:h,diameterScale:a?1:c,animated:!a,reducedMotionIndicator:a?"dot":"none"}:"presence"===n||"transition"===n||"running"===n?{kind:"continuous",reason:n,generation:l,expiresAt:null,color:h,diameterScale:a?1:c,animated:!a,reducedMotionIndicator:a?"dot":"none"}:vu(l,h,c)}({display:n,visual:S,semanticActivity:d.activity,shortReason:y?.sources===v?y?.flashKind:null,shortGeneration:y?.gen,shortExpiresAt:y?.sources===v?w:null,now:b,liveStates:i.liveStates,effectiveHidden:$,bindingUnavailable:x.bindingUnavailable,reducedMotion:i.reducedMotion,color:q,diameterScale:H}),B="value"===x.face?g.text:null,W="ha_disabled"===s?.kind?s.reason:null,U="ha_disabled"===(G={lifecycle:c,display:n,liveStates:i.liveStates,sourceKind:o.sourceKind,primaryDomain:(t.primary||"").split(".")[0],visual:S,activity:M}).lifecycle?"ha_disabled":"orphaned"===G.lifecycle?"orphaned":"static_icon"===G.display?"static_icon":"alarm"===G.visual.status?"alarm":G.liveStates?"unavailable"===G.visual.availability?"unavailable":"cover"===G.sourceKind?"cover_icon_state":"presence"===G.activity?"presence":"event"===G.activity?"event":"transition"===G.activity?"transition":"working"===G.visual.status?"icon_ripple"===G.display&&"none"!==G.activity?"working_activity":"working":"open"===G.visual.status?"open":"media_player"===G.primaryDomain?"media_neutral":"neutral":"live_states_disabled";var G;const V=[];i.designPreview&&h&&V.push("hidden_design_preview"),r||!0!==t.marker?.vacuum?.live||V.push("vacuum_live_plan_only");const K=o.visualSources.some(t=>"power_gate"===t.role||wc(e,t.eid)),Y=t.entities.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category).length;K&&Y>1&&V.push("composite_power_source"),"icon_ripple"!==n&&"static_icon"!==n&&"alarm"!==d.status&&"none"!==d.activity&&V.push("activity_display_disabled");const Z={binding:t.marker?.binding||(t.bindingKind&&t.bindingRef?`${t.bindingKind}:${t.bindingRef}`:t.virtual?"virtual":""),sourceKind:o.sourceKind,visualSources:o.visualSources,criticalSources:o.criticalSources,valueSource:g.source,sourceSignature:f,decisionIds:[...o.decisionIds,...x.decisionIds,...A?["diagnostics.value_badge"]:[],...null==C?[]:[`diagnostics.lqi_${wu(C)}`],`pulse.${j.kind}_${j.reason}`],visual:S,lockState:p,display:n,icon:F,valueText:B,valueFullText:B,fallbackReason:"value"!==n||B?null:g.fallback,activity:M,activityGeneration:y?.gen||1,pulse:j,classes:[],tempText:null==R?null:String(R),humText:null==T?null:String(T),valueBadge:A,lqiText:null==C||A?.isLqi?null:String(C),lqiColor:null==C?null:ku(C),lqiBand:null==C?null:wu(C),lightColor:I,scale:E,angle:N,rippleScale:H,rippleColor:q,userHidden:h,effectiveHidden:$,haDisabled:a,disabledReason:W,orphaned:l,vacuumLive:x.vacuumLive,explanation:{reason:U,notices:V}};return{...Z,classes:zu(Z)}}function Fu(e,t=new WeakMap){if(null===e||"object"!=typeof e)return e;const i=e,n=t.get(i);if(n)return n;if(Array.isArray(e)){const n=[];t.set(i,n);for(const i of e)n.push(Fu(i,t));return Object.freeze(n)}const r={};t.set(i,r);for(const[i,n]of Object.entries(e))"function"!=typeof n&&(r[i]=Fu(n,t));return Object.freeze(r)}function Iu(e){const t=new Map(e);let i;return i=Object.freeze({get size(){return t.size},get:e=>t.get(e),has:e=>t.has(e),entries:()=>t.entries(),keys:()=>t.keys(),values:()=>t.values(),forEach:(e,n)=>t.forEach((t,r)=>e.call(n,t,r,i)),[Symbol.iterator]:()=>t[Symbol.iterator]()}),i}function Eu(e){const t=new Set(e.entityIds||[]),i=new Set(e.deviceIds||[]),n=new Set(e.areaIds||[]);for(const n of e.devices){for(const e of n.entities||[])t.add(e);n.primary&&t.add(n.primary);for(const e of n.controls||[])t.add(e);n.marker?.vacuum?.source&&t.add(n.marker.vacuum.source),"device"===n.bindingKind&&n.bindingRef&&i.add(n.bindingRef),"entity"===n.bindingKind&&n.bindingRef&&t.add(n.bindingRef)}const r={},o={};for(const[o,s]of Object.entries(e.hass?.entities||{})){const a=s?.device_id?e.hass?.devices?.[s.device_id]:null;(t.has(o)||s?.device_id&&i.has(s.device_id)||n.has(s?.area_id)||n.has(a?.area_id))&&(t.add(o),r[o]=s,s?.device_id&&i.add(s.device_id))}for(const t of i){const i=e.hass?.devices?.[t];i&&(o[t]=i)}const s={};for(const i of t){const t=e.hass?.states?.[i];t&&(s[i]=t)}const a=Object.freeze({states:Fu(s),entities:Fu(r),devices:Fu(o),config:Fu(e.hass?.config),locale:Fu(e.hass?.locale),themes:Fu(e.hass?.themes)});return Object.freeze({sourceSequence:e.sourceSequence,capturedAt:e.capturedAt??Date.now(),hass:a,devices:Fu([...e.devices]),positions:Iu([...e.positions||[]].map(([e,t])=>[e,Object.freeze({x:t.x,y:t.y})])),presentations:Iu([...e.presentations].map(([e,t])=>[e,Fu(t)])),facts:Iu([...e.facts||[]].map(([e,t])=>[e,Fu(t)]))})}const Nu=(e,t)=>`${e}:${t?1:0}`;function Hu(e){return"boolean"==typeof e?.themes?.darkMode?e.themes.darkMode?"theme-dark":"theme-light":""}function Lu(e){const t=[];if(1!==e.scale&&t.push(`--dev-scale:${e.scale}`),"none"!==e.pulse.kind){t.push(`--ripple-scale:${e.pulse.diameterScale}`);const r=(i=e.pulse.color,n=null,"string"==typeof i&&(Lt.test(i)||Bt.test(i))?i:n);r&&t.push(`--ripple-color:${r}`)}var i,n;return t}function qu(e){const t=[...String(e)].reduce((e,t)=>/\s/.test(t)?e+.35:e+(t.codePointAt(0)>255?1:.62),0);return t<=8?.45:Math.max(.25,Math.round(3.6/t*1e3)/1e3)}function ju(e,t){const i=e.pulse,n=i.generation%2==0,r=function(e){const t=e.valueBadge;if(!t||!1!==t.configured)return[];const i=[];return null!=e.tempText&&"temperature"!==t.tone&&i.push({kind:"temperature",text:e.tempText,suffix:"°"}),null!=e.humText&&"humidity"!==t.tone&&i.push({kind:"humidity",text:e.humText,suffix:"%"}),i}(e),o=e.valueBadge,s=o?.position||"right",a=!!o||r.length>0,l=["device-shell",null!=e.valueText?"text-shell":"",a?`with-values pos-${s}`:"",r.length?"with-legacy":""].filter(Boolean).join(" ");return B` + ${"none"!==i.kind&&"dot"!==i.reducedMotionIndicator?B``:G} + ${"dot"===i.reducedMotionIndicator?B``:G} + ${t.newDevice?B``:G} + ${e.haDisabled?B``:G} + + ${null!=e.lqiText?B`${e.lqiText}`:G} + `}function Bu(e){return!Number.isFinite(e)||e<=0?2.25:e/2.5*2.25}function Wu({openings:e,geometries:t,fillsByRoomId:i,idPrefix:n="data",groupClass:r="opening-tunnels",dataLayer:o="data"}){const s=e.map((e,r)=>{const o=t[r];if(!o)return G;const s=o.faces.find(e=>-1===e.side),a=o.faces.find(e=>1===e.side);if(!s||!a)return G;const l=i.get(s.roomId)||null,c=i.get(a.roomId)||null;if(!l&&!c)return G;const h=`${s.d} ${a.d}`,d=!!l&&!!c&&l.color===c.color&&l.opacity===c.opacity,u=`translate(${e.rx} ${e.ry}) rotate(${e.angle})`;if(d)return W``;const p=o.maxY-o.minY;if(!(p>0))return G;const _=`${(100*Math.max(0,Math.min(1,-o.minY/p))).toFixed(6)}%`,m=l||{color:"#000000",opacity:0},g=c||{color:"#000000",opacity:0},f=`hp-opening-tunnel-${n.replace(/[^a-zA-Z0-9_-]/g,"-")}-${r}`;return W``});return W``}function Uu(e,t,i){const n=i>0?i:1;return{a:[e[0]/n,e[1]/n],b:[t[0]/n,t[1]/n]}}function Gu(e,t){const i=t>0?t:1;return[e.a[0]*i,e.a[1]*i,e.b[0]*i,e.b[1]*i]}function Vu(e){return Array.isArray(e)&&e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1]))}function Ku(e){if(!Array.isArray(e))return[];const t=[];for(const i of e){if(!i||"object"!=typeof i)continue;const e=i;if(!Vu(e.a)||!Vu(e.b))continue;const n=[Number(e.a[0]),Number(e.a[1])],r=[Number(e.b[0]),Number(e.b[1])];Math.hypot(r[0]-n[0],r[1]-n[1])<.001||t.push({a:n,b:r})}return t}function Yu(e,t,i,n,r=!0){const o=(e||[]).filter(e=>e?.id),s=Ku(t);if(s.length)return function(e,t,i,n){const r=Ku(e);if(!r.length)return[];const o=function(e,t){const i=[],n=(e||[]).filter(e=>e?.id);for(let e=0;e4*n||o>4*n)continue;const s=(e[0]-r)*u+(e[1]-l)*p,c=(e[2]-r)*u+(e[3]-l)*p,h=Math.max(0,Math.min(s,c)),m=Math.min(d,Math.max(s,c));if(m-he.lo-t.lo||e.hi-t.hi);const i=[];for(const e of t){const t=i[i.length-1];t&&e.lo<=t.hi+a?t.hi=Math.max(t.hi,e.hi):i.push({...e})}for(const t of i){const i=[r+u*t.lo,l+p*t.lo],n=[r+u*t.hi,l+p*t.hi];Math.hypot(n[0]-i[0],n[1]-i[1])i.pair===e&&Math.abs(i.ux*s-i.uy*o)<=1e-6&&Math.abs((t[0]-i.origin[0])*i.uy-(t[1]-i.origin[1])*i.ux)<=c&&Math.abs((t[2]-i.origin[0])*i.uy-(t[3]-i.origin[1])*i.ux)<=c);h||(h={pair:e,origin:[t[0],t[1]],ux:o,uy:s,ranges:[]},l.push(h));const d=(t[0]-h.origin[0])*h.ux+(t[1]-h.origin[1])*h.uy,u=(t[2]-h.origin[0])*h.ux+(t[3]-h.origin[1])*h.uy;h.ranges.push({lo:Math.min(d,u),hi:Math.max(d,u)})}const h=[];for(const e of l){e.ranges.sort((e,t)=>e.lo-t.lo||e.hi-t.hi);const t=[];for(const i of e.ranges){const e=t[t.length-1];e&&i.lo<=e.hi+a?e.hi=Math.max(e.hi,i.hi):t.push({...i})}for(const n of t){const t=[e.origin[0]+e.ux*n.lo,e.origin[1]+e.uy*n.lo],r=[e.origin[0]+e.ux*n.hi,e.origin[1]+e.uy*n.hi];Math.hypot(r[0]-t[0],r[1]-t[1])>=a&&h.push(Uu(t,r,i))}}return h}(s,e,i,n).map(e=>Gu(e,i));if(!r)return[];const a=[],l=(e,t)=>(e.open_to||[]).includes(t.id)||(t.open_to||[]).includes(e.id);for(let e=0;er)&&zo([o[0],o[1]],[o[2],o[3]],i))return!0;return!1}const Xu=e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1])),Ju=(e,t,i)=>[Number(e[0])*i,Number(e[1])*i,Number(t[0])*i,Number(t[1])*i],Qu=e=>{const t=`${Number(e[0]).toFixed(9)},${Number(e[1]).toFixed(9)}`,i=`${Number(e[2]).toFixed(9)},${Number(e[3]).toFixed(9)}`;return t<=i?`${t}|${i}`:`${i}|${t}`},ep=e=>{const t=new Map;for(const i of e.flat())!Array.isArray(i)||i.length<4||!i.every(Number.isFinite)||Math.hypot(i[2]-i[0],i[3]-i[1])<=1e-9||t.set(Qu(i),[...i]);return[...t.values()]};function tp(e){return"solid"===e?.zero_wall_style?"solid":"dashed"}function ip(e,t=1,i){const n=[];for(const r of Array.isArray(e?.wall_segments)?e.wall_segments:[])0===Number(r?.cm)&&Xu(r?.a)&&Xu(r?.b)&&(i&&!i.has(String(r.id||""))||n.push(Ju(r.a,r.b,t)));return ep([n])}function np(e,t=1){const i=[];for(const n of Array.isArray(e?.partitions)?e.partitions:[])0===Number(n?.cm)&&Xu(n?.a)&&Xu(n?.b)&&i.push(Ju(n.a,n.b,t));for(const n of Array.isArray(e?.room_drafts)?e.room_drafts:[]){const e=Array.isArray(n?.points)?n.points:[];for(let r=0;r+1e?.host?.kind===t.kind&&e.host.id===t.id)}const ap=new WeakMap,lp=new WeakMap;function cp(e){const t=za(e.cfg),i={};for(const t of e.cfg.spaces||[])for(const e of t.rooms||[])e.area&&(i[e.area]=t.id);const n=e.cfg.settings?.exclude_integrations?new Set(e.cfg.settings.exclude_integrations):Te,r=De(e.cfg.settings?.icon_rules?.length?e.cfg.settings.icon_rules:Ce);return Wh({hass:e.hass,registry:e.registry,areaToSpace:i,markers:e.cfg.markers||[],settings:e.cfg.settings||{},excluded:n,showAll:!!e.cfg.settings?.show_all,firstSpaceId:t[0]?.id||"",loc:t=>Jd(e.lang,t),iconRules:r})}function hp(e){const t=za(e.cfg).find(t=>t.id===e.spaceId);if(!t)return null;const i=tn(e.cfg.spaces.find(t=>t.id===e.spaceId)),n=on(e.cfg.settings),r=e.iconSize??2.5,o=r>8?2.5:r,s=Bu(o),a=e.registry?Xc(e.hass,e.registry):e.hass,l=e.registry?Jc(e.hass,e.registry):e.hass,c=(e.devices||cp(e)).filter(t=>t.space===e.spaceId),h=c.filter(e=>!e.hidden),d=function(e,t,i){const n={},r=i/100*el(t)*1.3;for(const i of t.rooms){if(!i.area)continue;const t=e.filter(e=>e.area===i.area);if(!t.length)continue;const o=rl(i),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(t.length*a/Math.max(l,1)))),h=a/c,d=l/Math.max(Math.ceil(t.length/c),1),u=t.map((e,t)=>({x:o.x+s+h*(t%c+.5),y:o.y+s+d*(Math.floor(t/c)+.5)}));Ti(u,o,r,.5*s),t.forEach((e,t)=>n[e.id]=La(u[t]))}return n}(c,t,o),u=[];for(const t of h){const i=e.layout[t.id];if(i&&i.s===e.spaceId){const e=i.x*Ra,t=i.y*Ra;u.push({minX:e,minY:t,maxX:e,maxY:t})}}const p=e.cfg.spaces.find(t=>t.id===e.spaceId)||{},_=Array.isArray(p.walls)?p.walls:[],m=Number(p.cell_cm)>0?Number(p.cell_cm):5,g=op(p,t,Ra,.02*Ea),f=(p.openings||[]).flatMap(e=>{if("partition"!==e.host?.kind)return[];const i=Td(e,t.partitions,Ra,m,Ea).resolved;return i?[i]:[]}),v=Rl({partitions:t.partitions,roomDrafts:t.room_drafts,columns:t.wall_columns,cellCm:m,hostedOpenings:f.map(e=>({id:e.opening.id,host:e.host,length:e.length,type:e.opening.type}))}),y=function(e,t,i,n){let r=lp.get(e);r||(r=new Map,lp.set(e,r));const o=r.get(t);if(o?.fingerprint===i)return o.value;const s=n();return r.set(t,{fingerprint:i,value:s}),s}(e.cfg,t.id,v,()=>ca(t,m,Ea,2e-4*Ea,f.map(Ad)).all);for(const e of y){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);t.length&&u.push({minX:Math.min(...t),minY:Math.min(...i),maxX:Math.max(...t),maxY:Math.max(...i)})}for(const e of g.lines)u.push({minX:Math.min(e[0],e[2]),minY:Math.min(e[1],e[3]),maxX:Math.max(e[0],e[2]),maxY:Math.max(e[1],e[3])});const b=Ja(t,u),w=[b.x,b.y,b.w,b.h],k=new Map(t.rooms.map(t=>{const r=Rn(i.fill,t);return[t,an(r,"lqi"===r&&t.area?Kh(a,c,t.area):null,"light"===r?Th(Mh(a,c,t,e.virtualLights)):"none","temp"===r&&t.area?Yh(a,c,t.area):null,i.tempMin,i.tempMax,n,en(i.customFill,t))]})),x=new Map;for(const e of t.rooms)e.id&&x.set(e.id,k.get(e)||null);const $=function(e,t=1e3){const i=[];for(const[n,r]of(e||[]).entries()){if("passage"!==r?.type)continue;const e={...r,id:String(r.id||`passage-${n}`),type:"passage",rx:Number(r.x)*t,ry:Number(r.y)*t,rlen:Number(r.length)*t};[e.rx,e.ry,e.rlen,e.angle].every(Number.isFinite)&&e.rlen>0&&i.push(e)}return i}((p.openings||[]).flatMap(e=>{if(!e.host||"wall"===e.host.kind)return[e];const t=f.find(t=>t.opening.id===e.id);return t?[Id(e,t,Ra)]:[]}),Ra),S=gs(t.rooms,_,g.contour,Na,m,Ea,Ra),M=f.filter(e=>Pd(e,S,2e-4*Ea)).map(e=>({x:e.center[0],y:e.center[1],angle:e.angle,length:e.length})),R=t.rooms.filter(e=>e.area||i.showBorders||"none"!==Rn(i.fill,e)).map(e=>{let n="room "+(t.bg?"overlay":"yard"),r="";const o=Rn(i.fill,e);if(i.showBorders||"none"!==o){n+=" styled";const t=[`--room-stroke:${i.color}`,`--room-stroke-op:${i.showBorders&&!g.contour.length?i.opacity:0}`],o=k.get(e)||null;o?(n+=" filled",t.push(`--room-fill:${o.color}`,`--room-fill-op:${o.opacity.toFixed(3)}`)):t.push("--room-fill:transparent","--room-fill-op:0"),r=t.join(";")}const s=e.id||G,a=e.area||G,l=e.poly?W``:W``;return l}),T=t.rooms.filter(e=>{const t=k.get(e);return Tn(i.glow,e)&&(!t||t.opacity<=0)}).map(e=>e.poly?W``:W``),C=new Map;for(const e of t.rooms)if(e.id){const t=k.get(e)||null;C.set(e.id,Tn(i.glow,e)&&(!t||t.opacity<=0)?{color:n.glow_base.c,opacity:n.glow_base.a,mode:"glow"}:null)}const D=Mh(a,h,null,e.virtualLights),A=h.map(n=>{const r=function(e,t,i,n,r){const o=t[e.id];return o&&o.s===e.space?{x:o.x*Ra,y:o.y*Ra}:n[e.id]?n[e.id]:La(Qa(r))}(n,e.layout,e.cfg,d,t),o=(r.x-w[0])/w[2]*100,s=(r.y-w[1])/w[3]*100,c=i.showLqi??!1!==e.showSignal,u=e.presentations?.get(Nu(n.id,c))||Pu(a,n,{liveStates:!1!==e.liveStates,showTemperature:!1!==e.showTemperature,showSignal:c,activityRuntime:e.activityRuntime?.get(n.id),sourceDetails:!1,lightDevices:h,lightSources:D,registryHass:l,reducedMotion:e.reducedMotion}),p=[`left:${o}%`,`top:${s}%`,...Lu(u)],_=xu(u),m=[n.name,Jd(e.lang,`marker.state_a11y_${_}`),"none"!==u.pulse.kind?Jd(e.lang,`marker.pulse_a11y_${u.pulse.reason}`):"",u.valueFullText||u.valueText||"",nu(u.valueBadge),null!=u.lqiText&&u.lqiBand?Jd(e.lang,`marker.lqi_a11y_${u.lqiBand}`,{value:u.lqiText}):""].filter(Boolean).join(", ");return B``}),O=i.showNames?t.rooms.filter(e=>e.name).map(n=>{const r=ol(n,t.id,e.layout,e.cfg),o=(r.x-w[0])/w[2]*100,s=(r.y-w[1])/w[3]*100,a=Math.min(1,i.opacity+.25);return B`
${n.name}
`}):[],z=t.bg?e.displayUrl?e.displayUrl(t.bg.href):t.bg.href:"",P=e.cfg.spaces.find(t=>t.id===e.spaceId)?.settings||{},F="daynight"===sr(e.cfg?.settings,P)?Yn(a,e.dayCycleNow??new Date):null,I=nn(e.cfg?.settings,i),E=!!(_.length||y.length&&i.showBorders),N=E?Rl($.length?{rooms:t.rooms,walls:_,extras:y,cellCm:m,zero:g.contour,passages:$.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),hostedCompositeOpenings:M}:{rooms:t.rooms,walls:_,extras:y,cellCm:m,zero:g.contour}):"",H=E?function(e,t,i,n){let r=ap.get(e);r||(r=new Map,ap.set(e,r));const o=r.get(t);if(o?.fingerprint===i)return o.value;const s=n();return r.set(t,{fingerprint:i,value:s}),s}(e.cfg,t.id,N,()=>Hs(t.rooms,_,g.contour,[...$.filter(e=>"partition"!==e.host?.kind).map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),...M],Na,m,Ea,Ra,y)):null,L=$.length&&_.length?function(e,t,i,n,r,o,s,a=1){return[r,o,s,a].every(Number.isFinite)&&o>0&&a>0&&i?.length?Zs(Bs(e,i,n,r,o,s,a),t):t.map(()=>null)}(t.rooms,$.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),_,g.contour,Na,m,Ea,Ra):$.map(()=>null),q=$.length?Wu({openings:$,geometries:L,fillsByRoomId:x,idPrefix:`${t.id}-static-data`,groupClass:"opening-tunnels static-opening-tunnels",dataLayer:"data"}):G,j=$.length?Wu({openings:$,geometries:L,fillsByRoomId:C,idPrefix:`${t.id}-static-glow`,groupClass:"opening-tunnels glow-base-tunnels static-opening-tunnels",dataLayer:"glow-base"}):G,U=_.length&&H?.paperD?[{path:H.paperD}]:Xt(t.rooms),V=i.showBorders?H:null,K=e.stageWidth&&w[2]?e.stageWidth/w[2]:1,Y=_o(m),Z=!!V&&(po(V.depthUnits,K)||mo(Y,K)),X=i.color||"#607d8b",J=i.hideOpenings?[]:f.map(e=>{const t=e.opening,i="passage"!==t.type&&t.contact?a.states?.[t.contact]?.state:null,n=ii(t.type,i,!!t.invert),r=n>0&&!!t.contact,o="gate"===t.type?!t.flip_v:!!t.flip_v,s={type:t.type,length:e.length,angle:e.angle,amount:n,flipH:!!t.flip_h,flipV:!!t.flip_v,base:X,tone:r?"var(--hp-open)":X,cellCm:m,gridPitch:Ea,face:Od(e,o)};return W` + ${tu(s)} + `});return B` +
+ ${dr(F)} + + ${V?W` + + + + `:G} + ${U.map(e=>"path"in e?W``:"poly"in e?W``:W``)} + ${z?W`e.assetLoaded?.(t.bg.href,z)} + transform=${t.bg.angle?`rotate(${t.bg.angle} ${t.bg.x+t.bg.w/2} ${t.bg.y+t.bg.h/2})`:G} + preserveAspectRatio="none" />`:G} + ${R} + ${i.showBorders&&g.contour.length?W``:G} + ${q} + ${T.length?W``:G} + ${j} + ${V?W` + ${V.paths.map(e=>W` + + `)} + `:G} + ${i.showBorders&&g.lines.length?W``:G} + ${J} + + ${""} +
${A}${O}
+
+ `}let dp=null,up=null,pp=0,_p=-1,mp=null,gp=[];const fp=new Set,vp=(e,t)=>{"function"==typeof e&&t.push(e)};function yp(){if(dp)return dp;try{const e=JSON.parse(localStorage.getItem("houseplan_card_cfg_v1")||"null");if(e&&e.config&&Array.isArray(e.config.spaces)){const t=e.layout||{};return{config:e.config,rev:e.rev||0,configFingerprint:e.config_fingerprint||Rl(e.config),layout:t,layoutRev:e.layout_rev||0,layoutFingerprint:e.layout_fingerprint||Rl(t),virtualLights:Cc(e.virtual_lights,e.rev||0)}}}catch{}return null}function bp(e,t=!1){if(t&&(dp=null,pp++,up))return up.catch(()=>null).then(()=>bp(e,!1));if(dp)return Promise.resolve(dp);if(up)return _p!==pp?up.catch(()=>null).then(()=>bp(e,!1)):up;return _p=pp,up=async function(e,t){const[i,n]=await Promise.all([e.callWS({type:"houseplan/config/get"}),e.callWS({type:"houseplan/layout/get"})]),r=i?.rev??0,o=dp?Dc(dp.virtualLights,i?.virtual_lights,r,!!i&&"virtual_lights"in i):Cc(i?.virtual_lights,r),s={config:i?.config??null,rev:r,configFingerprint:Rl(i?.config??null),layout:n?.layout??{},layoutRev:n?.rev??0,layoutFingerprint:Rl(n?.layout??{}),virtualLights:o};t===pp&&(dp=s);const a=e.connection;if(a?.subscribeEvents&&mp!==a){for(const e of gp)e();gp=[],mp=a;const e=()=>{dp=null,pp++,fp.forEach(e=>e())},t=[];try{if(vp(await a.subscribeEvents(e,"houseplan_config_updated"),t),vp(await a.subscribeEvents(e,"houseplan_layout_updated"),t),vp(await a.subscribeEvents(e=>{if(dp){const t=Fc(dp.virtualLights,e?.data);if(t===dp.virtualLights)return;dp={...dp,virtualLights:t}}else pp++;fp.forEach(e=>e())},"houseplan_virtual_light_updated"),t),mp===a)gp=t;else for(const e of t)e()}catch{for(const e of t)e();mp===a&&(mp=null)}}return s}(e,pp).finally(()=>{up=null,_p=-1}),up}const wp=3300;function kp(e,t){return{sources:e,last:Object.fromEntries(t.map(e=>[e.eid,e.state])),flashTs:0,flashKind:null,timer:0,gen:0,expiresAt:0,alarmActive:"alarm"===Sc(t).status}}function xp(e,t,i,n){n(e.timer);const r=kp(t,i);Object.assign(e,r)}function $p(e,t,i,n,r){e.flashTs&&i-e.flashTs"transition"===e.activity)&&(i(e.timer),e.flashTs=0,e.flashKind=null,e.expiresAt=0);if("alarm"===Sc(t).status){e.alarmActive||(i(e.timer),e.flashTs=0,e.flashKind=null,e.expiresAt=0);for(const i of t)e.last[i.eid]=i.state;return e.alarmActive=!0,null}if(e.alarmActive){for(const i of t)e.last[i.eid]=i.state;return e.alarmActive=!1,null}let n=null;for(const i of t){const t=Mc(e.last[i.eid],i);("event"===t||!n&&t)&&(n=t),e.last[i.eid]=i.state}return n}class Mp{constructor(e,t=()=>{}){this._host=e,this._onGateChange=t,this._modality="unknown",this._gate=!1,this._media=null,this._connected=!1,this._onMediaChange=()=>this._syncGate()}get modality(){return this._modality}get hoverEnabled(){return this._gate}connect(e=globalThis.window){this._connected||(this._connected=!0,this._modality="unknown",this._media="function"==typeof e?.matchMedia?e.matchMedia("(any-hover: hover) and (any-pointer: fine)"):null,this._media?.addEventListener?.("change",this._onMediaChange),this._setGate(!1))}disconnect(){this._media?.removeEventListener?.("change",this._onMediaChange),this._media=null,this._connected=!1,this._modality="unknown",this._setGate(!1)}note(e){return this._modality=function(e,t){const i="mouse"===(n=t.pointerType)||"touch"===n||"pen"===n?n:null;var n;return i?"mouse"===i&&t.sourceCapabilities?.firesTouchEvents?e:i:e}(this._modality,e),this._syncGate(),this._modality}suspend(){this._setGate(!1)}_syncGate(){var e,t;this._setGate((e=this._modality,t=!!this._media?.matches,"mouse"===e&&t))}_setGate(e){this._gate!==e&&(this._gate=e,this._host.toggleAttribute("data-pointer-hover",e),this._onGateChange(e))}}class Rp extends he{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id}))}catch{this._spaces=[]}finally{this._spacesLoading=!1}}}get _lang(){return Xd(this.hass,this._config?.language)}get _schema(){const e=this._spaces||[];return[e.length?{name:"space",selector:{select:{mode:"dropdown",options:e}}}:{name:"space",selector:{text:{}}},{name:"title",selector:{text:{}}},{name:"show_button",selector:{boolean:{}}},{name:"button_label",selector:{text:{}}},{name:"button_target",selector:{text:{}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}}]}render(){if(!this.hass||!this._config)return G;this._loadSpaces();const e=this._lang,t={space:Jd(e,"editor.space"),title:Jd(e,"editor.title"),show_button:Jd(e,"editor.show_button"),button_label:Jd(e,"editor.button_label"),button_target:Jd(e,"editor.button_target"),icon_size:Jd(e,"editor.icon_size"),show_temperature:Jd(e,"editor.show_temperature"),live_states:Jd(e,"editor.live_states"),show_signal:Jd(e,"editor.show_signal")};return B`t[e.name]||e.name} + @value-changed=${this._valueChanged} + >`}_valueChanged(e){const t={...this._config||{},...e.detail.value};delete t.aspect_ratio;const i=new Event("config-changed",{bubbles:!0,composed:!0});i.detail={config:t},this.dispatchEvent(i)}}Rp.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-space-card-editor")||customElements.define("houseplan-space-card-editor",Rp);const Tp=e=>{history.pushState(null,"",e),((e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)})(window,"location-changed",{replace:!1})};class Cp extends he{constructor(){super(...arguments),this._snap=null,this._loading=!1,this._reloadQueued=!1,this._forceReloadQueued=!1,this._reloadRetryTimer=0,this._dayCycleTimer=0,this._dayCycleClockKey="",this._stageWidth=0,this._pendingStageWidth=0,this._stageWidthRaf=0,this._haRegistryConnection=null,this._haRegistryRevision=-1,this._devices=[],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._connHooked=null,this._connectionWasLost=!1,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotActivity="",this._capturedSnapshotVirtual="",this._activityRuntime=new Map,this._reducedMotion=!1,this._pointerModality=new Mp(this),this._onMotionChange=e=>{this._reducedMotion=e.matches,this._capturedSnapshotSequence=-1,this.requestUpdate()},this._onHaRegistryUpdate=()=>{const e=Vc(this.hass).revision;e!==this._haRegistryRevision&&(this._haRegistryRevision=e,this._refreshDevices(),this._capturedSnapshotSequence=-1,this.requestUpdate())},this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=Zn(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),"hidden"!==e.kind){if(!e.long){const e=Date.now();let t=!1;for(const i of this._activityRuntime.values())!i.flashKind||(i.expiresAt||i.flashTs+3300)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&(this._capturedSnapshotSequence=-1,this.requestUpdate()))}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._load(!0)}else this._pointerModality.suspend()},this._onConnLost=()=>{this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost()},this._onConnReady=()=>{!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._load(!0)},this._onAssetLoaded=(e,t)=>{this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()},this._loadedOnce=!1,this._signer=new Dl(()=>this.requestUpdate()),this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._load(!0)},this._goToSpace=()=>{const e=(this._config?.button_target||"/plan-doma").replace(/#.*$/,"");Tp(`${e}#space=${encodeURIComponent(this._config.space)}`)}}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRevision=-1,this._haRegistryRelease=Gc(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}_newContinuityController(){return new Ml(()=>{this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}_dayCycleState(e=new Date){const t=this._snap?.config;if(!t||!this._config)return null;const i=t.spaces?.find(e=>e.id===this._config?.space)?.settings||{};return"daynight"!==sr(t.settings,i)?null:Yn(this._renderDeviceSnapshot?.hass||this.hass,e)}_syncDayCycleClock(){const e=this._dayCycleState();this._dayCycleClockKey=e?Zn(e):"";const t="clock"===e?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;t&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!t&&this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(e){"hidden"!==e.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}static getConfigElement(){return document.createElement("houseplan-space-card-editor")}static getStubConfig(e){const t=yp();return{type:"custom:houseplan-space-card",space:za(t?.config||null)[0]?.id||"",show_button:!0,live_states:!0,show_temperature:!0,show_signal:!0}}setConfig(e){if(!e||!e.space)throw new Error('houseplan-space-card: "space" is required');this._config={show_button:!0,button_target:"/plan-doma",live_states:!0,show_temperature:!0,show_signal:!0,...e},this._snap=this._snap||yp()}connectedCallback(){var e;this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this.hass&&this._ensureHaRegistryAuthority(),this._continuityUnsub?.(),this._continuityUnsub=$l(this.ownerDocument,this._pageVisibility),this._unsub=(e=()=>{this._beginContinuityCandidate("config-event",!1),this._reloadQueued=!0,this._load()},fp.add(e),()=>fp.delete(e)),this._signer.start(()=>this.hass,()=>this._referenced())}disconnectedCallback(){this._pointerModality.disconnect(),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._unsub?.(),this._unsub=void 0,window.clearTimeout(this._reloadRetryTimer),this._reloadRetryTimer=0,this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._stageObserver?.disconnect(),this._stageObserver=void 0,this._observedStage=void 0,this._stageWidthRaf&&cancelAnimationFrame(this._stageWidthRaf),this._stageWidthRaf=0,this._pendingStageWidth=0,this._signer.dispose(),this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null;for(const e of this._activityRuntime.values())window.clearTimeout(e.timer);this._activityRuntime.clear(),this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}willUpdate(e){e.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._hookConnection()),!this.hass||this._loading||this._snap&&!e.has("hass")||this._snap&&this._loadedOnce||this._load(),(e.has("hass")||e.has("_snap")||e.has("_config")||!this._devices.length)&&this._refreshDevices(),this._captureRenderDeviceSnapshot(),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._frameFingerprint())}_stampActivity(e,t){$p(e,t,Date.now(),window.clearTimeout.bind(window),e=>window.setTimeout(()=>this.requestUpdate(),e))}_syncActivity(e,t,i=this.hass){if(!1===this._config?.live_states){for(const e of this._activityRuntime.values())window.clearTimeout(e.timer);return void this._activityRuntime.clear()}const n=new Set,r=Mh(t,e,null,this._snap?.virtualLights);for(const o of e){if(o.hidden)continue;if("icon_ripple"!==Ai(o.marker?.display))continue;n.add(o.id);const s=Cu(t,o,e,r,i),a=s.samples,l=Ou(t,o,s);let c=this._activityRuntime.get(o.id);if(!c||c.sources!==l){c&&window.clearTimeout(c.timer),c=kp(l,a),this._activityRuntime.set(o.id,c);continue}const h=Sp(c,a,window.clearTimeout.bind(window));h&&this._stampActivity(c,h)}for(const[e,t]of this._activityRuntime)n.has(e)||(window.clearTimeout(t.timer),this._activityRuntime.delete(e))}_refreshDevices(){if(!this.hass||!this._snap?.config||!this._config)return;const e=Vc(this.hass),t=cp({hass:this.hass,registry:e,cfg:this._snap.config,lang:this._lang});this._syncActivity(t,Xc(this.hass,e),this.hass),this._devices=t}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRuntime.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+3300)>e?1:0)).join("|"),i=this._snap?.virtualLights?`${this._snap.virtualLights.configRev}:${this._snap.virtualLights.rev}`:"";if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotActivity===t&&this._capturedSnapshotVirtual===i)return;const n=Xc(this.hass,Vc(this.hass)),r=new Map,o=new Set(["sun.sun"]),s=new Set,a=new Set,l=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void o.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?s.add(n):"entity"===i&&o.add(n)},c=za(this._snap?.config||null).find(e=>e.id===this._config?.space);for(const e of c?.rooms||[])e.area&&a.add(e.area),l(e.settings?.temp_source),l(e.settings?.hum_source);const h=this._snap?.config?.spaces?.find(e=>e.id===this._config?.space);for(const e of h?.openings||[])for(const t of ni(e))o.add(t);const d=Mh(n,this._devices,null,this._snap?.virtualLights);for(const e of this._devices)for(const t of[!1,!0])r.set(Nu(e.id,t),Pu(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRuntime.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:d,registryHass:this.hass,reducedMotion:this._reducedMotion}));const u=Eu({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,entityIds:o,deviceIds:s,areaIds:a});this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotActivity=t,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=u:(this._visibleDeviceSnapshot=u,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}_beginContinuityCandidate(e,t,i="plan"){return this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._continuity.beginCandidate(e,i)}_backdropRaw(){return this._snap?.config&&this._config&&za(this._snap.config).find(e=>e.id===this._config.space)?.bg?.href||""}_candidateBackdrop(e){return e&&this._config&&za(e).find(e=>e.id===this._config.space)?.bg?.href||""}_assetsReady(){const e=this._backdropRaw();return!e||this._signer.isReady(this.hass,e)}_frameFingerprint(){const e=this._snap;return Tl([e?.rev||0,e?.configFingerprint||Rl(e?.config),e?.layoutRev||0,e?.layoutFingerprint||Rl(e?.layout),e?.virtualLights?`${e.virtualLights.configRev}:${e.virtualLights.rev}`:"",this._config?.space||"",this._stageWidth,this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_stageValid(){const e=this._observedStage;return!!e&&e.clientWidth>0&&e.clientHeight>0}_settleContinuityFrame(){if(!this._stageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state){if(this._assetsReady())return this._renderSnapshotAt=Date.now(),void this._continuity.markCompleteFrame(this._frameFingerprint());this._beginContinuityCandidate("asset-wait",!0,"asset")}if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._stageValid(),assetsReady:()=>this._assetsReady(),frameFingerprint:()=>this._frameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}updated(){const e=this.renderRoot.querySelector(".hp-static-stage")||void 0;if(e!==this._observedStage)if(this._stageObserver?.disconnect(),this._observedStage=e,e){const t=()=>{const i=e.clientWidth;if(!(i<=0||Math.abs(i-this._stageWidth)<=.5)){if(this._stageWidth<=0)return this._stageWidth=i,void this.requestUpdate();this._pendingStageWidth=i,this._stageWidthRaf||(this._stageWidthRaf=requestAnimationFrame(()=>{this._stageWidthRaf=0;const e=this._pendingStageWidth;this._pendingStageWidth=0,!e||!this._observedStage||this._observedStage.clientWidth<=0||(Math.abs(this._observedStage.clientWidth-e)>.5?t():Math.abs(e-this._stageWidth)<=.5||(this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._stageWidth=e,this.requestUpdate()))}))}};this._stageObserver=new ResizeObserver(t),this._stageObserver.observe(e),t()}else this._stageObserver=void 0;this._syncDayCycleClock(),this._settleContinuityFrame()}async _load(e=!1){if(this.hass){if(this._loading)return this._reloadQueued=!0,void(this._forceReloadQueued||=e);this._loading=!0,this._reloadQueued=!1;try{const t=await bp(this.hass,e),i=!this._snap||this._snap.configFingerprint!==t.configFingerprint,n=!this._snap||this._snap.layoutFingerprint!==t.layoutFingerprint,r=!this._snap||this._snap.virtualLights!==t.virtualLights;if(i&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(t.config)))return this._continuity.note("asset-failed"),window.clearTimeout(this._reloadRetryTimer),void(this._reloadRetryTimer=window.setTimeout(()=>{this._load(!0)},1e3));window.clearTimeout(this._reloadRetryTimer),this._reloadRetryTimer=0,(i||n)&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),i||n||r?this._snap=t:this._snap&&(this._snap.rev=t.rev,this._snap.layoutRev=t.layoutRev),i&&this._continuity.note("config-candidate",{configRev:t.rev}),n&&this._continuity.note("layout-candidate",{layoutRev:t.layoutRev}),r&&(this._capturedSnapshotSequence=-1),this._loadedOnce=!0,this._connectionWasLost=!1,this._continuityDataReady=!0,this._refreshDevices()}catch{}finally{if(this._loading=!1,this._continuityDataReady=!0,this.requestUpdate(),this._reloadQueued){const e=this._forceReloadQueued;this._reloadQueued=!1,this._forceReloadQueued=!1,this._load(e)}}}}get _lang(){return Xd(this.hass,this._config?.language)}getCardSize(){const e=za(this._snap?.config||null).find(e=>e.id===this._config?.space);if(e){const t=e.vb[3]/e.vb[2];return Math.max(3,Math.round(8*t))+(!1===this._config?.show_button?0:1)}return 6}_errorCard(e){return B` +
${e}
+
`}_referenced(){return Sn(this._snap?.config)}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return G;const e="connection"===this._continuity.recoveryReason;return B`
+ + ${Jd(this._lang,e?"continuity.restore_connection":"continuity.restore_plan")} + ${"recovery-error"===this._continuity.state?B``:G} +
`}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}render(){if(!this._config)return G;const e=this._snap?.config;if(!e)return this._errorCard(Jd(this._lang,"space_card.loading"));const t=this._config.space,i=this._renderDeviceSnapshot,n=hp({hass:i?.hass||this.hass,cfg:e,layout:this._snap?.layout||{},spaceId:t,iconSize:this._config.icon_size,stageWidth:this._stageWidth,lang:this._lang,displayUrl:e=>this._signer.display(this.hass,e),assetLoaded:this._onAssetLoaded,registry:i?{revision:i.sourceSequence,authoritative:!1,access:"limited",entities:{...i.hass.entities},devices:{...i.hass.devices},lastSuccess:i.capturedAt}:Vc(this.hass),devices:[...i?.devices||this._devices],presentations:i?.presentations,activityRuntime:this._activityRuntime,reducedMotion:this._reducedMotion,virtualLights:this._snap?.virtualLights,liveStates:!1!==this._config.live_states,showTemperature:!1!==this._config.show_temperature,showSignal:!1!==this._config.show_signal,inert:this._continuity.overlayBlocksInteraction});if(!n)return this._errorCard(Jd(this._lang,"space_card.not_found",{id:t}));const r=za(e).find(e=>e.id===t),o=void 0!==this._config.title?this._config.title:r?.title||"",s=!1!==this._config.show_button,a=this._config.button_label||Jd(this._lang,"space_card.button"),l=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null;return B` + this._pointerModality.note(e)} + @pointerdown=${e=>this._pointerModality.note(e)} + @pointermove=${e=>this._pointerModality.note(e)}> + ${o?B`
${o}
`:G} +
+ ${n} + ${this._renderRecoveryOverlay()} +
+ ${s?B`
+ +
`:G} +
+ `}}Cp.properties={hass:{attribute:!1},_config:{state:!0},_snap:{state:!0},_continuityEpoch:{state:!0}},Cp.styles=[Bd,o` + .hp-static-title { + font-weight: 700; + padding: 10px 14px 6px; + font-size: 16px; + color: var(--primary-text-color); + } + .hp-static-body { + position: relative; + } + .hp-static-stage { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + pointer-events: none; /* kill ALL interaction on the schematic (§4) */ + background: var(--ha-card-background, var(--card-background-color, #111)); + } + .hp-static-stage svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + z-index: 1; + } + /* Opaque plan paper — the scene bg_color/day-cycle environment shows only AROUND + the plan (owner 2026-08-03). The static card keeps its historical + canvas colour: the theme card background. Drawn plans paper the room + contours (per-room shapes, fill only, no stroke) — same contract as + the full card. */ + .hp-paper { + fill: var(--ha-card-background, var(--card-background-color, #111)); + stroke: none; + } + .wallbody-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: var(--wall-fill-op, 1); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .wallbody { + fill: url(#hp-wall-hatch); + fill-rule: evenodd; + stroke: var(--room-stroke, var(--hp-muted, #607d8b)); + stroke-width: calc(0.6px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .wallbody.solid { + fill: none; + } + .hp-static-stage .devlayer { + position: absolute; + inset: 0; + z-index: 2; + } + .hp-static-foot { + padding: 8px 12px 12px; + pointer-events: auto; /* the button stays clickable */ + } + .hp-static-btn { + width: 100%; + padding: 9px 14px; + border: none; + border-radius: 10px; + background: var(--primary-color, #3ea6ff); + color: var(--text-primary-color, #fff); + font-size: 14px; + font-weight: 600; + cursor: pointer; + } + :host([data-pointer-hover]) .hp-static-btn:hover { + filter: brightness(1.08); + } + .hp-static-error { + padding: 24px; + text-align: center; + color: var(--secondary-text-color, #9aa4ad); + } + `],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",Cp),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-space-card"===e.type)||window.customCards.push({type:"houseplan-space-card",name:"House Plan — Space (static)",description:"Read-only live schematic of a single houseplan space, with a deep-link button.",preview:!1,documentation:"https://github.com/Matysh/houseplan-card"});const Dp=o` + :host { + --hp-editor-tray-bg-fallback: color-mix(in srgb, var(--card-background-color, var(--hp-bg)) 94%, var(--hp-line)); + --hp-editor-tray-bg: color-mix(in srgb, var(--card-background-color, var(--hp-bg)) 86%, transparent); + --hp-editor-tray-border: color-mix(in srgb, var(--hp-line) 82%, var(--hp-accent)); + --hp-editor-tray-blur: 8px; + --hp-editor-tray-shadow: var(--shadow-2); + } + + /* Contextual editor controls float over the stage. Their appearance must + never alter stage height, viewport fitting or the pinned close action. */ + .editor-secondary-host { + position: absolute; + inset: var(--sp-2) var(--sp-4) auto; + z-index: 70; + display: flex; + justify-content: flex-end; + pointer-events: none; + } + .editor-secondary-host.kind-palette, + .editor-secondary-host.kind-group { + justify-content: flex-start; + } + .editor-secondary { + pointer-events: none; + max-width: 100%; + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-4); + color: var(--hp-txt); + background: var(--card-background-color, var(--hp-bg)); + background: var(--hp-editor-tray-bg-fallback); + border: 1px solid var(--hp-line); + border-color: var(--hp-editor-tray-border); + border-radius: var(--rad-l); + box-shadow: var(--hp-editor-tray-shadow); + opacity: 0; + visibility: hidden; + transform: translateY(-4px); + transition: + opacity 0.1s ease, + transform 0.1s cubic-bezier(0.2, 0.7, 0.2, 1), + visibility 0s linear 0.1s; + touch-action: auto; + } + .editor-secondary-host.open .editor-secondary { + pointer-events: auto; + opacity: 1; + visibility: visible; + transform: translateY(0); + transition-duration: 0.14s, 0.14s, 0s; + transition-delay: 0s; + } + .editor-secondary-host.blocked .editor-secondary { pointer-events: none; } + @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { + .editor-secondary { + background: var(--hp-editor-tray-bg); + -webkit-backdrop-filter: blur(var(--hp-editor-tray-blur)); + backdrop-filter: blur(var(--hp-editor-tray-blur)); + } + } + .editor-secondary-content, + .editor-group-items { + display: flex; + align-items: center; + gap: var(--sp-3); + min-width: 0; + } + .editor-context-label { + max-width: 14rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-inline-end: var(--sp-4); + border-inline-end: 1px solid var(--hp-line); + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editor-secondary.kind-palette { + width: min(760px, 100%); + align-items: stretch; + padding: 0; + overflow: hidden; + } + .editor-secondary.kind-palette .editor-secondary-content, + .editor-secondary.kind-palette .furnpalette { + width: 100%; + } + .editor-secondary.kind-palette .furnpalette { + max-height: 38vh; + border: 0; + background: transparent; + } + .editor-group-launcher .group-chevron { + --mdc-icon-size: 16px; + transition: transform 0.14s ease; + } + .editor-group-launcher[aria-expanded="true"] .group-chevron { transform: rotate(180deg); } + + .editor-secondary .bdhint { + font-size: var(--fs-s); + color: var(--hp-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .editor-secondary .dfill { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + font-size: var(--fs-s); + cursor: pointer; + } + .editor-secondary .dfill input[type="checkbox"] { + width: 16px; + height: 16px; + flex: none; + margin: 0; + padding: 0; + } + .editor-secondary hp-color-opacity { flex: 0 0 auto; } + .editor-secondary input { + width: 74px; + background: transparent; + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + } + .editor-secondary label, + .editor-secondary .hint { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editor-secondary .drawwall { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .editor-secondary .drawwall input { width: 4.2em; } + .editor-secondary .drawwall .opl { + color: var(--hp-muted); + font-size: var(--fs-s); + } + + @container (min-width: 560px) and (max-width: 899px) { + .editor-secondary-content, + .editor-group-items { + flex-wrap: wrap; + justify-content: flex-end; + } + } + @container (max-width: 559px) { + .editor-secondary-host { inset-inline: var(--sp-4); } + .editor-secondary { max-width: 100%; } + .editor-secondary-content, + .editor-group-items { + overflow-x: auto; + scrollbar-width: thin; + } + .editor-secondary-content > *, + .editor-group-items > * { flex: none; } + .editor-context-label { display: none; } + } + @media (prefers-reduced-motion: reduce) { + .editor-secondary { transition: none; } + .editor-group-launcher .group-chevron { transition: none; } + } +`;function Ap(e){return e instanceof Error?e.name||"Error":typeof e}function Op(e){return Rl({id:e?.id??"",cell_cm:e?.cell_cm,rooms:e?.rooms||[],walls:e?.walls||[],wall_segments:e?.wall_segments||[],open_spans:e?.open_spans||[],openings:e?.openings||[],partitions:e?.partitions||[],room_drafts:e?.room_drafts||[],wall_columns:e?.wall_columns||[]})}function zp(e,t,i={}){const n=(Array.isArray(e?.spaces)?e.spaces:[]).find(e=>String(e?.id||"")===String(t||"")),r=Op(n);if(!n)return{spaceId:String(t||""),displayName:"",status:"failed",reason:"prepare-exception",fingerprint:r,ok:!1};const o=Hp({...e,spaces:[n]},{...i,fingerprint:()=>r}).spaces[0]||{spaceId:String(t||""),displayName:"",status:"failed",reason:"prepare-exception"};return{...o,fingerprint:r,ok:"failed"!==o.status}}function Pp(e,t,i,n=Ea,r=1e3){return(Array.isArray(e?.openings)?e.openings:[]).flatMap(e=>{const o={...e,rx:Number(e.x)*r,ry:Number(e.y)*r,rlen:Number(e.length)*r};if(!e.host||"wall"===e.host.kind)return[o];const s=Td(e,t.partitions,r,i,n);return s.resolved?[{...e,rx:s.resolved.center[0],ry:s.resolved.center[1],rlen:s.resolved.length,angle:s.resolved.angle,partitionHost:s.resolved}]:[]})}function Fp(e,t=()=>!0){return e.flatMap(e=>e.host&&e.partitionHost&&t(e)?[Ad(e.partitionHost)]:[])}function Ip(e,t,i,n,r,o,s=Ea,a=1e3){const l=gs(t.rooms,[...i],n,r,o,s,a);return e.flatMap(e=>{const t={x:e.rx,y:e.ry,angle:Number(e.angle)||0,length:e.rlen};return e.host&&"wall"!==e.host.kind?e.partitionHost&&Pd(e.partitionHost,l,2e-4*s)?[t]:[]:[t]})}function Ep(e,t){const i=Na,n=Ea,r=Ra,o=Number.isFinite(Number(t.cellCm))&&Number(t.cellCm)>0?Number(t.cellCm):5,s=Array.isArray(e?.walls)?e.walls:[],a=function(e,t,i=Ea,n=1e3){return Yu(t.rooms,e?.open_spans,n,.02*i)}(e,t,n,r),l=function(e,t,i=Ea){if(!t.length)return[];const n=e.filter(e=>e?.id),r=.02*i,o=[];for(let e=0;e{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return h.some(e=>Pn(t,e)<4*r)}).map(e=>[...e]);d.length&&o.push({a:s,b:a,segs:d})}return o}(t.rooms,a,n).flatMap(e=>e.segs),c=Pp(e,t,o,n,r),h=Fp(c),d=ca(t,o,n,2e-4*n,h).all;return{space:t,walls:s,openCuts:l,openings:c,roomOpenings:Ip(c,t,s,l,i,o,n,r),partitionCuts:h,physicalBodies:d,wallKeyPitch:i,cellCm:o,gridPitch:n,coordScale:r}}function Np(e,t,i){const n="string"==typeof e?.title?e.title.trim():"",r=null==e?.id?"":String(e.id).trim();return{spaceId:r,displayName:n||r||i(t+1)}}function Hp(e,t={}){const i=(t.fingerprint||Rl)(e),n=Array.isArray(e?.spaces)?e.spaces:[],r=t.fallbackSpaceName||(e=>`Space ${e}`),o=t.prepareSpace||Ep,s=t.wallPass||Ns,a=t.floorPass||Ps,l=[];for(let i=0;i0||d.physicalBodies.length>0;if(!d.space.rooms.length&&!u){l.push({...h,status:"not-applicable"});continue}let p=null;if(u){try{p=s(d.space.rooms,d.walls,d.openCuts,d.roomOpenings,d.wallKeyPitch,d.cellCm,d.gridPitch,d.coordScale,d.physicalBodies)}catch(e){l.push({...h,status:"failed",reason:"wall-exception",detail:Ap(e)});continue}if(null==p){l.push({...h,status:"failed",reason:"wall-null"});continue}if("degraded-extra"===p.status){l.push({...h,status:"failed",reason:"wall-degraded-extra"});continue}if("failed-core"===p.status){l.push({...h,status:"failed",reason:"wall-failed-core"});continue}t.captureWallGeometry?.(d,p)}if(d.space.rooms.length&&null==p?.paperGeom){let e;try{e=a(d.space.rooms,d.walls,d.openCuts,d.wallKeyPitch,d.cellCm,d.gridPitch,d.coordScale)}catch(e){l.push({...h,status:"failed",reason:"floor-exception",detail:Ap(e)});continue}if(null==e){l.push({...h,status:"failed",reason:"floor-null"});continue}}l.push({...h,status:"ok"})}const c=l.filter(e=>"failed"===e.status);return{fingerprint:i,spaces:l,failures:c,ok:0===c.length}}function Lp(e,t){return e.catch(()=>{}).then(t)}class qp{constructor(e=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(e))}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(e){this._undo.push(e),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const e=this._undo.pop()??null;return e&&this._redo.push(e),e}redo(){const e=this._redo.pop()??null;return e&&this._undo.push(e),e}clear(){this._undo=[],this._redo=[]}}const jp=new WeakMap;const Bp=(e,t,i)=>255===e[i+3]&&t.every((t,n)=>Math.abs(e[i+n]-t)<=2);async function Wp(e){const t=e.defaultView;if(!t||!t.CSS?.supports?.("mix-blend-mode","screen"))return!1;const i=[128,32,16],n=[16,64,128],r=[9,19,29],o=`\n \n \n \n \n \n `,s=t.URL.createObjectURL(new Blob([o],{type:"image/svg+xml"}));try{const o=await new Promise((e,i)=>{const n=new t.Image,r=t.setTimeout(()=>i(new Error("SVG blend probe timeout")),1e3);n.onload=()=>{t.clearTimeout(r),e(n)},n.onerror=()=>{t.clearTimeout(r),i(new Error("SVG blend probe failed"))},n.src=s}),a=e.createElement("canvas");a.width=4,a.height=1;const l=a.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 Bp(c,i,0)&&Bp(c,function(e,t){return[0,1,2].map(i=>Math.round(255-(255-e[i])*(255-t[i])/255))}(i,n),4)&&Bp(c,n,8)&&Bp(c,r,12)}catch{return!1}finally{t.URL.revokeObjectURL(s)}}const Up={now:()=>performance.now(),requestFrame:e=>requestAnimationFrame(e),cancelFrame:e=>cancelAnimationFrame(e)},Gp=e=>Math.max(0,Math.min(1,e)),Vp=(e,t,i)=>e+(t-e)*i,Kp=(e,t,i)=>{const n=1-e;return 3*n*n*e*t+3*n*e*e*i+e*e*e};function Yp(e,t){return{centerX:e.x+e.w/2,centerY:e.y+e.h/2,pixelsPerUnit:t>0&&e.w>0?t/e.w:1,viewBox:{...e}}}function Zp(e,t,i){const n=Math.max(1e-9,e.pixelsPerUnit),r=Math.max(1e-9,t/n),o=Math.max(1e-9,i/n);return{x:e.centerX-r/2,y:e.centerY-o/2,w:r,h:o}}function Xp(e){const t=e.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(t);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const n=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(t)?.[1];return n?[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16),8===n.length?parseInt(n.slice(6,8),16)/255:1]:null}function Jp(e,t,i){const n=Xp(e),r=Xp(t);if(!n||!r)return i<.5?e:t;const o=Gp(i);return`rgba(${Math.round(Vp(n[0],r[0],o))}, ${Math.round(Vp(n[1],r[1],o))}, ${Math.round(Vp(n[2],r[2],o))}, ${Vp(n[3],r[3],o).toFixed(3)})`}function Qp(e,t,i){const n=(e=>{const t=Gp(e);if(0===t||1===t)return t;let i=0,n=1,r=t;for(let e=0;e<12;e++)r=(i+n)/2,Kp(r,.2,.2){const t=this._state;if(!t||t.token!==r)return;const i=Gp((e-t.startedAt)/t.duration);t.presented=i>=1?t.to:Qp(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i<1?this._raf=this._clock.requestFrame(s):(this._raf=0,this._hooks.settled(t),this._state?.token===r&&(this._state=null))};return this._raf=this._clock.requestFrame(s),r}cancel(e=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=t.to,this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}}class t_{constructor(e){this.options=e,this._state="idle",this._inFlight=null}get state(){return this._state}ensure(){return"ready"===this._state?Promise.resolve(!0):"failed"===this._state?Promise.resolve(!1):(this._inFlight||(this._setState("loading"),this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}async _loadWithRetry(){let e=new Error("Editor runtime did not load");for(const t of[0,1])try{const e=await this.options.load(t);if(e.fingerprint!==this.options.expectedFingerprint)throw new Error(`Editor runtime fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${e.fingerprint}`);const i=e.create();return this.options.install(i),this._setState("ready"),!0}catch(t){e=t}return this._setState("failed"),this.options.failed?.(e),!1}_setState(e){e!==this._state&&(this._state=e,this.options.stateChanged?.(e))}}const i_="houseplan_card_labs_v1",n_=Object.freeze([Object.freeze({id:"iso",issue:89,since:"1.62.0",expires:"1.65.0",summary:"Volumetric plan renderer"})]);function r_(e){const t=/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/.exec(String(e||"").trim());if(!t)return null;const i=t.slice(1).map(Number);return i.every(e=>Number.isSafeInteger(e))?i:null}function o_(e,t){for(let i=0;i<3;i++)if(e[i]!==t[i])return e[i]e.split(",")).map(e=>e.trim()).filter(Boolean)}function d_(e,t,i,n=n_){const r=function(e,t=n_){const i=r_(e),n=new Map;if(!i||!a_(t))return n;for(const e of t){const t=r_(e.since),r=r_(e.expires);o_(i,t)>=0&&o_(i,r)<0&&n.set(e.id,e)}return n}(i,n),o=new Set(a_(n)?n.map(e=>e.id):[]),s=new Set(function(e){if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>"string"==typeof e):[]}catch{return[]}}(t).filter(e=>r.has(e)));let a=!1;const l=e=>{if("off"===e)return s.clear(),void(a=!0);const t=e.startsWith("-"),i=t?e.slice(1):e;o.has(i)&&(a=!0,t||!r.has(i)?s.delete(i):s.add(i))};for(const t of h_(new URLSearchParams(String(e.search||"").replace(/^\?/,""))))l(t);for(const t of h_(l_(e.hash)))l(t);const c=Object.freeze([...s].sort());return{active:c,space:c_(e.hash),persist:a?JSON.stringify(c):void 0,knownUrlOperation:a}}let u_={active:Object.freeze([]),space:""},p_="",__=!1,m_="";const g_=new Set;function f_(){if("undefined"==typeof window)return u_;const e=d_(window.location,function(){try{return window.localStorage.getItem(i_)}catch{return null}}(),p_);void 0!==e.persist&&function(e){try{window.localStorage.setItem(i_,e)}catch{}}(e.persist),u_={active:e.active,space:e.space},window.__hpLabs=e.active;for(const e of g_)e(u_);return u_}function v_(){f_()}function y_(e){return p_=e,"undefined"==typeof window?u_:(__||(__=!0,window.addEventListener("hashchange",v_),window.addEventListener("popstate",v_)),f_())}const b_=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])});function w_(e){return[e.rotDeg,e.tiltDeg,e.xyScale,e.zScale,e.origin[0],e.origin[1]].every(Number.isFinite)&&Math.abs(e.xyScale)>1e-12&&Math.abs(Math.cos(e.tiltDeg*Math.PI/180))>1e-12}function k_(e,t,i=b_){if(!(w_(i)&&Number.isFinite(e[0])&&Number.isFinite(e[1])&&Number.isFinite(t)))throw new Error("invalid isometric projection input");const n=i.rotDeg*Math.PI/180,r=i.tiltDeg*Math.PI/180,o=e[0]-i.origin[0],s=e[1]-i.origin[1],a=(o*Math.cos(n)-s*Math.sin(n))*i.xyScale,l=(o*Math.sin(n)+s*Math.cos(n))*i.xyScale;return[i.origin[0]+a,i.origin[1]+l*Math.cos(r)-t*i.zScale*Math.sin(r)]}function x_(e,t=b_){if(!w_(t)||!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=(e[0]-t.origin[0])/t.xyScale,o=(e[1]-t.origin[1])/(t.xyScale*Math.cos(n));return[t.origin[0]+r*Math.cos(i)+o*Math.sin(i),t.origin[1]-r*Math.sin(i)+o*Math.cos(i)]}function $_(e=b_){return`matrix(${function(e=b_){if(!w_(e))throw new Error("invalid isometric camera");const t=e.rotDeg*Math.PI/180,i=e.tiltDeg*Math.PI/180,n=e.xyScale*Math.cos(t),r=-e.xyScale*Math.sin(t),o=e.xyScale*Math.sin(t)*Math.cos(i),s=e.xyScale*Math.cos(t)*Math.cos(i);return[n,o,r,s,e.origin[0]-n*e.origin[0]-r*e.origin[1],e.origin[1]-o*e.origin[0]-s*e.origin[1]]}(e).map(e=>Number(e.toFixed(12))).join(" ")})`}function S_(e,t=b_){const{rect:i,wallHeight:n}=e,r=e.openingHeight??n,o=e.floorDepth??0;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||n<0||r<0||o<0)throw new Error("invalid isometric frame");const s=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],a=Math.max(n,r),l=s.flatMap(e=>[k_(e,-o,t),k_(e,a,t)]),c=l.map(e=>e[0]),h=l.map(e=>e[1]),d=Math.min(...c),u=Math.min(...h);return{x:d,y:u,w:Math.max(...c)-d,h:Math.max(...h)-u}}const M_=e=>`${Number(e[0].toFixed(4))} ${Number(e[1].toFixed(4))}`;function R_(e){let t=0;for(let i=0;iArray.isArray(e)&&Number.isFinite(e[0])&&Number.isFinite(e[1])).map(e=>[Number(e[0]),Number(e[1])]),i=t[t.length-1];return t.length>1&&t[0][0]===i[0]&&t[0][1]===i[1]&&t.pop(),t}(e);if(i.length<3)return[];const n=!t;return R_(i)>0===n?i:[...i].reverse()}function C_(e,t,i){return e.length?`M ${e.map(e=>M_(k_(e,i,t))).join(" L ")} Z`:""}function D_(e,t,i){const n=t[1]-e[1],r=-(t[0]-e[0]),o=i.rotDeg*Math.PI/180;return n*Math.sin(o)+r*Math.cos(o)}function A_(e,t,i=b_){if(!Number.isFinite(t)||t<0)throw new Error("invalid floor edge height");const n=(e||[]).map(e=>(e||[]).map((e,t)=>function(e,t){const i=T_(e,t);if(!i.length)return i;let n=0;for(let e=1;e0)).filter(e=>e.length>=3&&Math.abs(R_(e))>=1e-9)).filter(e=>e.length&&R_(e[0])>0);n.sort((e,t)=>{const i=e[0][0],n=t[0][0];return i[0]-n[0]||i[1]-n[1]||Math.abs(R_(t[0]))-Math.abs(R_(e[0]))});const r=[],o=[];let s=0;for(let e=0;ee.depth-t.depth||e.component-t.component||e.edge-t.edge),{footprintPath:r.join(" "),sides:o,componentCount:n.length,edgeCount:s}}function O_(e,t){return e^=Math.round(64*(Number.isFinite(t)?t:0)),Math.imul(e,16777619)>>>0}const z_=e=>e.every(Number.isFinite);function P_(e,t,i,n){const r=e[0]*i,o=e[1]*n,s=t*Math.PI/180;return[r*Math.cos(s)-o*Math.sin(s),r*Math.sin(s)+o*Math.cos(s)]}function F_(e,t,i,n,r,o,s){const a=e.flipH?-1:1,l="gate"===e.type?1:e.flipV?-1:1,c=(e.type,e.flipV,e.angle,e.face,{ox:0,oy:0}),h=function(e,t){return[e[0]+t[0],e[1]+t[1]]}([e.x+c.ox,e.y+c.oy],P_(i,e.angle,a,l));return{leaf:t,hinge:h,closedVector:P_(n,e.angle,a,l),quarterVector:P_([-n[1],n[0]],e.angle,a,l),turnDeg:r,bottom:o,top:s}}const I_=e=>`${Number(e[0].toFixed(4))} ${Number(e[1].toFixed(4))}`;function E_(e,t,i=b_){const n=Math.max(0,Math.min(1,Number.isFinite(t)?t:0));return e.leaves.map(t=>{const r=function(e,t){const i=e.turnDeg*t*Math.PI/180;return[e.hinge[0]+e.closedVector[0]*Math.cos(i)+e.quarterVector[0]*Math.sin(i),e.hinge[1]+e.closedVector[1]*Math.cos(i)+e.quarterVector[1]*Math.sin(i)]}(t,n),o=k_(t.hinge,t.bottom,i),s=k_(r,t.bottom,i),a=k_(r,t.top,i),l=k_(t.hinge,t.top,i);return{id:e.id,sourceIndex:e.sourceIndex,type:e.type,leaf:t.leaf,d:`M ${I_(o)} L ${I_(s)} L ${I_(a)} L ${I_(l)} Z`,shadowD:`M ${I_(k_(t.hinge,0,i))} L ${I_(k_(r,0,i))}`,depth:Math.max(o[1],s[1])}})}const N_={window:120,door:90,passage:90,gate:300};function H_(e){return N_[e]}function L_(e,t){return{type:e,lengthCm:H_(e),flipH:!1,flipV:!1,revision:t}}function q_(e,t){const i=Math.max(0,e.renderedLength)/2,n=Math.max(0,e.target.physicalHalfWidth),r=n+.18*Math.max(0,t),o=e=>({x1:e,y1:-r,x2:e,y2:r});return{rect:{x:-i,y:n?-n:0,width:2*i,height:2*n},boundaries:[o(-i),o(i)]}}function j_(e,t){const i=[e[0],e[1]],n=[t[0],t[1]];return function(e,t){return e[0]-t[0]||e[1]-t[1]}(i,n)<=0?{a:i,b:n}:{a:n,b:i}}function B_(e){const t=new Map;return e.forEach((e,i)=>{if(!e.kind||e.open)return;const n=j_(e.a,e.b);if(Math.hypot(n.b[0]-n.a[0],n.b[1]-n.a[1])<=1e-9)return;const r=function(e,t){const i=e=>(Math.abs(e)<=5e-10?0:Math.round(1e6*e)/1e6).toFixed(6);return`${i(e[0])},${i(e[1])}>${i(t[0])},${i(t[1])}`}(n.a,n.b),o=t.get(r);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,e.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(e.partitionHost&&(o.partitionHost&&o.partitionHost.id!==e.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=e.partitionHost));t.set(r,{segmentKey:r,a:n.a,b:n.b,physicalHalfWidth:Math.max(0,e.half||0),sourceOrder:i,...e.partitionHost?{partitionHost:e.partitionHost}:{}})}),[...t.values()]}function W_(e,t){if(Math.abs(e.distance-t.distance)>1e-9)return e.distance-t.distance;if(Math.abs(e.perpendicular-t.perpendicular)>1e-9)return e.perpendicular-t.perpendicular;return(e.target.segmentKeyt.target.segmentKey?1:0)||e.target.sourceOrder-t.target.sourceOrder}function U_(e){const t=B_(e.intervals).map(t=>{const i=function(e,t){const i=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,a=(e[0]-t.a[0])*o+(e[1]-t.a[1])*s,l=Math.max(0,Math.min(r,a)),c=t.a[0]+l*o,h=t.a[1]+l*s;return{along:l,length:r,x:c,y:h,distance:Math.hypot(e[0]-c,e[1]-h),perpendicular:Math.abs((e[0]-t.a[0])*s-(e[1]-t.a[1])*o)}}(e.pointer,t);return{target:t,...i,envelope:Math.max(e.baseTolerance,t.physicalHalfWidth+e.bodyPointerPadding)}}).filter(e=>e.distance<=e.envelope+1e-9).filter(t=>!function(e,t,i,n,r){const o=t.b[0]-t.a[0],s=t.b[1]-t.a[1],a=Math.hypot(o,s);if(!(a>1e-9))return!1;const l=o/a,c=s/a;for(const o of i){if(!o.open&&o.kind)continue;const i=j_(o.a,o.b),s=i.b[0]-i.a[0],a=i.b[1]-i.a[1],h=Math.hypot(s,a);if(!(h>1e-9))continue;const d=s/h,u=a/h;if(Math.abs(l*u-c*d)>1e-6)continue;if(Math.abs((i.a[0]-t.a[0])*c-(i.a[1]-t.a[1])*l)>r)continue;const p=(e[0]-i.a[0])*d+(e[1]-i.a[1])*u,_=1e-9;if(!(p<=_||p>=h-_)&&Math.abs((e[0]-i.a[0])*u-(e[1]-i.a[1])*d)<=n+1e-9)return!0}return!1}(e.pointer,t.target,e.intervals,t.envelope,Math.max(1e-9,Math.min(e.baseTolerance,.04*e.gridStep)))),i=t.filter(t=>!!t.target.partitionHost&&e.renderedLength+2*t.target.physicalHalfWidth>t.length+1e-9).sort(W_),n=t.filter(t=>!t.target.partitionHost||e.renderedLength+2*t.target.physicalHalfWidth<=t.length+1e-9).sort(W_);let r=n[0];if(!r)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=n.filter(e=>Math.abs(e.distance-r.distance)<=1e-9&&Math.abs(e.perpendicular-r.perpendicular)<=1e-9),s=o.filter(e=>e.target.partitionHost);if(s.length){if(1!==new Set(s.map(e=>e.target.partitionHost.id)).size||s.some(e=>e.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const e=s[0],t=e.target.b[0]-e.target.a[0],i=e.target.b[1]-e.target.a[1],n=Math.hypot(t,i),a=t/n,l=i/n;if(!o.every(t=>{const i=t.target.b[0]-t.target.a[0],n=t.target.b[1]-t.target.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,c=Math.abs(a*s-l*o)<=1e-6,h=Math.abs((t.target.a[0]-e.target.a[0])*l-(t.target.a[1]-e.target.a[1])*a);return c&&h<=1e-9}))return{candidate:null,jambBlockedTarget:null};r=e}if(r.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:a,length:l}=r,c=a.b[0]-a.a[0],h=a.b[1]-a.a[1],d=c/l,u=h/l,p=a.partitionHost?a.physicalHalfWidth:0,_=Math.min(Math.max(0,e.renderedLength)/2+p,l/2);let m=r.along;const g=Math.max(e.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=a.a[0]+d*m,y=a.a[1]+u*m,b=Math.max(0,e.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),$=Math.max(0,l-k),S=[a.a[0]+d*(w-x/2),a.a[1]+u*(w-x/2)],M=[a.a[0]+d*(k+$/2),a.a[1]+u*(k+$/2)];let R=180*Math.atan2(h,c)/Math.PI;R>=90?R-=180:R<-90&&(R+=180);const T=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:e.preset.revision,geometryRevision:e.geometryRevision,pointer:[e.pointer[0],e.pointer[1]],type:e.preset.type,lengthCm:e.preset.lengthCm,flipH:e.preset.flipH,flipV:e.preset.flipV,x:v,y:y,angle:R,renderedLength:e.renderedLength,target:a,...a.partitionHost?{host:{...a.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:S},{distance:$,midpoint:M}],guide:T?{x:v,y:y,angle:R}:null}},jambBlockedTarget:null}}function G_(e,t,i,n,r=1e-6){return e.presetRevision===i&&e.geometryRevision===n&&Math.hypot(e.pointer[0]-t[0],e.pointer[1]-t[1])<=r}function V_(e){return!(!e.canEdit||e.kiosk||e.fixedFloor)&&("view"!==e.mode&&("mouse"===e.pointerType&&e.spaceCount>1))}const K_="1.68.1",Y_="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479",Z_=1500,X_=(e,t)=>{if(!e.has(t))return{hit:!1};const i=e.get(t);return e.delete(t),e.set(t,i),{hit:!0,value:i}},J_=(e,t,i,n)=>{for(e.delete(t),e.set(t,i);e.size>n;){const t=e.keys().next().value;if(void 0===t)break;e.delete(t)}},Q_=new Map;let em=0;const tm=e=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(e??{})}`;let im=1e4;const nm="houseplan_card_layout_v1",rm="houseplan_card_cfg_v1",om="houseplan_card_zoom_v1",sm="houseplan_card_nav_v1",am="houseplan_card_kiosk_v1",lm="houseplan_card_view_v1",cm="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",hm=1e3,dm=[[0,1],[45,.88],[70,.62],[86,.32],[100,0]],um=(e,t)=>{const i=Math.min(e.x,t.x),n=Math.min(e.y,t.y);return{x:i,y:n,w:Math.max(e.x+e.w,t.x+t.w)-i,h:Math.max(e.y+e.h,t.y+t.h)-n}},pm=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),_m=(e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)},mm=e=>{history.pushState(null,"",e),_m(window,"location-changed",{replace:!1})},gm=(e,t)=>{let i,n=null;const r=(...r)=>{clearTimeout(i),n=r,i=window.setTimeout(()=>{i=void 0;const t=n;n=null,t&&e(...t)},t)};return r.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const t=n;n=null,t&&e(...t)},r.cancel=()=>{clearTimeout(i),i=void 0,n=null},r.pending=()=>void 0!==i,r},fm=e=>{try{e.target?.setPointerCapture?.(e.pointerId)}catch{}};class vm extends he{constructor(){super(...arguments),this._editorRuntime=null,this._onboardingRuntime=null,this._editorRuntimeLoadingVisible=!1,this._editorModeRequest=0,this._warmModeRequest=0,this._editorRuntimeLoader=new t_({expectedFingerprint:Y_,load:async e=>{const t=0===e?await import("./houseplan-editor-runtime-Bk__jFmU.js"):await import((()=>{const e=new URL("./houseplan-editor-runtime-Bk__jFmU.js",import.meta.url);return e.searchParams.set("hp_retry",K_),e.href})());return{fingerprint:t.EDITOR_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanEditorRuntime(this)}},install:e=>{this._editorRuntime=e},stateChanged:e=>this._editorRuntimeStateChanged(e),failed:e=>{console.error("[houseplan] unable to load editor runtime",e),this._showToast(`${this._t("editor.load_failed")} ${this._t("editor.refresh_advice")}`)}}),this._onboardingRuntimeLoader=new t_({expectedFingerprint:Y_,load:async e=>{const t=0===e?await import("./houseplan-onboarding-runtime-Dor16U6K.js"):await import((()=>{const e=new URL("./houseplan-onboarding-runtime-Dor16U6K.js",import.meta.url);return e.searchParams.set("hp_retry",K_),e.href})());return{fingerprint:t.ONBOARDING_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanOnboardingRuntime(this)}},install:e=>{this._onboardingRuntime=e},failed:e=>{console.error("[houseplan] unable to load onboarding runtime",e),this._showToast(`${this._t("editor.load_failed")} ${this._t("editor.refresh_advice")}`)}}),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=Cc(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._tip=null,this._hoverRoom=null,this._pointerModality=new Mp(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...ur},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=e=>{this._reducedMotion=e.matches,this._cancelDevicePressFeedback(),e.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:e.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 e_({frame:e=>this._applyModeTransitionFrame(e),settled:e=>this._settleModeTransition(e)}),this._editorSecondaryCopy={groupActive:(e,t)=>this._t("editor.group_active",{group:e,item:t}),openGroup:e=>this._t("editor.open_group",{group:e}),disabledAction:(e,t)=>this._t("editor.disabled_action",{action:e,reason:t})},this._tool="draw",this._geometryHistory=new qp(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._wallUnionCacheValue=null,this._wallUnionPool=new Map,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._innerContourCache=new Map,this._glowClipCache=new Map,this._glowGeometryWarnings=new Set,this._lightBarrierCache=null,this._lightBarrierPool=new Map,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._rszLimitViolation=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:e=>this._guardTouchGesture(e)},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._deviceInbox=null,this._deviceInboxReturn=null,this._deviceInboxMemo=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=e=>this._onKey(e),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++em,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=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),"hidden"===e.kind)return this._clearTransientHover(!0),this._cancelDevicePressFeedback(),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,!e.long){const e=Date.now();let t=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+wp)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&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=e=>{const t=this._effectiveProjection();this._labs=e;const i=this._effectiveProjection();this._convertProjectionView(t,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const e=this._hashSpace();if(e&&this._model.find(t=>t.id===e)&&e!==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(e),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 e=Vc(this.hass);e.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=e.revision,this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,function(e){const t=qc(e);t&&(Wc(e,t),Uc(e,t))}(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 Dl(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=gm(()=>{if(this._serverStorage){const e=[...this._dirtyPos];this._dirtyPos.clear();for(const t of e){const e=ro(this._layout[t]);e&&(this._layout={...this._layout,[t]:e},this._sentPos.set(t,e),this.hass.callWS({type:"houseplan/layout/update",device_id:t,pos:e}).then(e=>this._noteLayoutRev(e)).catch(e=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(e)}))).finally(()=>{this._sentPos.get(t)===e&&this._sentPos.delete(t)}))}this._cacheSnapshot()}else this._layout=oo(Ur(this._layout)),localStorage.setItem(nm,JSON.stringify(this._layout))},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>this._editorRuntimeOrThrow()._undoGeometry(),this._redoGeometry=()=>this._editorRuntimeOrThrow()._redoGeometry(),this._saveConfigDebounced=gm(()=>{this._serverCfg&&this._writeConfig().catch(e=>{const t=!0===e?.physicalGeometryRolledBack;"geometry-unsafe"!==e?.code&&("wall_model_client_outdated"===e?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===e?.code?(this._showToast(this._t("toast.conflict")),t||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)})),t&&this._reloadRejectedPhysicalWrite())})},500),this._draftSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>this._editorRuntimeOrThrow()._savePhysicalDialog(),this._deletePhysicalSelection=()=>this._editorRuntimeOrThrow()._deletePhysicalSelection(),this._confirmPartitionDelete=()=>this._editorRuntimeOrThrow()._confirmPartitionDelete(),this._deleteDraftWhole=()=>this._editorRuntimeOrThrow()._deleteDraftWhole(),this._deleteDraftSegment=()=>this._editorRuntimeOrThrow()._deleteDraftSegment(),this._confirmRoomDelete=e=>this._editorRuntimeOrThrow()._confirmRoomDelete(e),this._rebindPartitionOpening=()=>this._editorRuntimeOrThrow()._rebindPartitionOpening(),this._keepClosedAsPartitions=()=>this._editorRuntimeOrThrow()._keepClosedAsPartitions(),this._toggleServerPlans=async()=>this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._toggleServerPlans():this._editorRuntimeOrThrow()._toggleServerPlans(),this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=Zn(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(this._editorRuntime)return this._editorRuntime._openSettingsDialog();this._ensureEditorRuntime().then(e=>{e&&this._openSettingsDialog()})},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._editorRuntimeOrThrow()._openAlignDialog(),this._toggleOptimizeLivePositions=()=>this._editorRuntimeOrThrow()._toggleOptimizeLivePositions(),this._optimizeUndoBusy=!1,this._openBackupExport=()=>this._editorRuntimeOrThrow()._openBackupExport(),this._openRulesDialog=()=>this._editorRuntimeOrThrow()._openRulesDialog(),this._climateCache=null,this._gearPtCache=new WeakMap}_editorRuntimeOrThrow(){if(!this._editorRuntime)throw new Error("Houseplan editor runtime is not loaded");return this._editorRuntime}async _ensureEditorRuntime(){return this._editorRuntimeLoader.ensure()}async _ensureOnboardingRuntime(){return this._onboardingRuntimeLoader.ensure()}_editorRuntimeStateChanged(e){clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,"loading"!==e?(this._editorRuntimeLoadingVisible=!1,this.requestUpdate()):this._editorRuntimeLoadingTimer=window.setTimeout(()=>{this._editorRuntimeLoadingVisible=!0,this.requestUpdate()},150)}async _requestMode(e,t=!0,i=!1){const n=++this._editorModeRequest;if(i&&(this._warmModeRequest=n,this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._pendingRefitSize=null),"view"===e||await this._ensureEditorRuntime()){if(n===this._editorModeRequest&&this.isConnected)return i?(this._adoptMode(e),this._warmRevivePending&&(clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmReviveDialog()),this.requestUpdate(),void this.updateComplete.then(()=>requestAnimationFrame(()=>requestAnimationFrame(()=>{if(this._warmModeRequest!==n||n!==this._editorModeRequest)return;const e=this._stageEl;this._lastValidStageSize=e&&e.clientWidth>0&&e.clientHeight>0?[e.clientWidth,e.clientHeight]:null,this._pendingRefitSize=null,this._warmModeRequest=0})))):void this._setMode(e,t);this._warmModeRequest===n&&(this._warmModeRequest=0)}else this._warmModeRequest===n&&(this._warmModeRequest=0)}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(e,t){const i=String(e||"").trim();if(!i)return t;const n=document.createElement("span");n.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(n);const r=getComputedStyle(n).color||t;return n.remove(),r}_currentModeVisual(e=this._mode){const t=this._modeTransition.presented||this._modeTransitionVisual;if(t)return{...t,viewport:{...t.viewport,viewBox:{...t.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const n=this.renderRoot.querySelector(".editorchrome"),r=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),s=this.renderRoot.querySelector(".hp-backdrop"),a=this.renderRoot.querySelector(".zoomwrap"),l=a?getComputedStyle(a).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:e,editorChromeHeight:"view"===e?0:n?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:Yp(r,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"===e?.35:1,backdropOpacity:s&&Number(getComputedStyle(s).opacity)||1,viewWeight:"view"===e?1:0,editorWeight:"view"===e?0:1,toolbarContentOpacity:"view"===e?0:1}}_viewForModeTarget(e,t,i,n,r){const o=Ri(this._baseVb(),n/Math.max(1,r)),s=Math.min(vm.ZOOM_MAX,Math.max(vm.ZOOM_MIN,e)),a=o.w/s,l=o.h/s,c=t??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-a/2,y:h-l/2,w:a,h:l},o)}_targetStageColor(e){return"view"!==e?"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(e){return"view"===e&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(e){return 1}_applyModeTransitionFrame(e){e.targetMode===this._mode&&(this._modeTransitionVisual=e.presented,this._view={...e.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(e){if(e.targetMode!==this._mode)return;const t=this._modeTransitionRequest;this._view={...e.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[e.to.stageWidth,e.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._modeTransitionBusy||e.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-e.to.stageWidth)>.5||Math.abs(i.clientHeight-e.to.stageHeight)>.5)){const e=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}const n=this.renderRoot.activeElement;(!n||!n.isConnected||!!n.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(e=!0){const t=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(e),e&&t||(this._modeTransitionVisual=null)}_adoptMode(e){this._cancelModeTransition(!1),this._mode=e,"view"!==e&&(this._editorChromeMode=e)}_commitViewModeAtomic(e,t,i,n){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=t,e){const r=this._stageEl?.clientWidth||e.stageWidth,o=Math.max(1,e.stageHeight+e.editorChromeHeight);this._view=this._viewForModeTarget(t,i,n,r,o),this._lastValidStageSize=[r,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(e,t,i,n,r,o){this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._mode!==i)return void(e===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const s=this.renderRoot.querySelector(".editorchrome"),a=s?.querySelector(".editorchrome-inner"),l="view"===i?0:a?.scrollHeight||a?.getBoundingClientRect().height||0,c=Math.max(1,t.stageHeight+t.editorChromeHeight),h=Math.max(1,c-l),d=this._stageEl?.clientWidth||t.stageWidth;if(d<=0||h<=0)return this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._applyView(n,r,o),void this.requestUpdate();const u=this._viewForModeTarget(n,r,o,d,h),p={presentedMode:i,editorChromeHeight:l,stageWidth:d,stageHeight:h,viewport:Yp(u,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(t,p,i,this._reducedMotion||_?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(e=this._model,t=this._loadOk){const i=this._config?.floor,n=function(e){if(!e.hasFloor)return{kind:"absent"};const t=e.floor;if("string"==typeof t)return t.length?e.spaceIds.includes(t)?{kind:"valid",id:t,source:"id"}:{kind:"invalid",reason:"unknown-id",value:t}:{kind:"invalid",reason:"empty-id",value:t};if("number"==typeof t){if(!Number.isFinite(t))return{kind:"invalid",reason:"non-finite-index",value:t};if(!Number.isInteger(t))return{kind:"invalid",reason:"fractional-index",value:t};if(t<0)return{kind:"invalid",reason:"negative-index",value:t};const i=e.spaceIds[t];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:t}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:t}}({spaceIds:e.map(e=>e.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||t?n:"number"==typeof i?"valid"===n.kind||"invalid"===n.kind&&"out-of-range-index"===n.reason?{kind:"pending",value:i}:n:"valid"===n.kind||"invalid"===n.kind&&"unknown-id"!==n.reason?n:{kind:"pending",value:i}}_canCommitSpace(e,t=!1){if(t||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===e}_commitSpace(e,t=!1){return!!this._canCommitSpace(e,t)&&(e!==this._space&&(this._clearTransientHover(!0),this._cancelDevicePressFeedback()),this._space=e,!0)}_slideTo(e,t){if(e===this._space)return!0;if(!this._canCommitSpace(e))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(e),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=t,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return V_({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(e,t){V_({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:e.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(fm(e),this._tabDragRelease=e=>this._tabPointerUp(e),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:t,pointerId:e.pointerId,x:e.clientX,y:e.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(e,t,i){const n=this._model.map(e=>e.id),r=n.indexOf(i);if(r<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const s of o){const o=s.dataset.id||"";if(!o||o===i)continue;const a=s.getBoundingClientRect();if(ea.right||ta.bottom)continue;const l=n.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,n;const r=this._tabDropTargetAt(e.clientX,e.clientY,t.id);t.moved&&t.targetId===r?.targetId&&t.placement===r?.placement||(this._tabDrag={...t,moved:!0,targetId:r?.targetId||null,placement:r?.placement||null})}_tabPointerUp(e){const t=this._tabDrag;if(t&&t.pointerId!==e.pointerId)return;const i="pointerup"===e.type&&t?.moved?this._tabDropTargetAt(e.clientX,e.clientY,t.id):null;"pointerup"===e.type&&t?.moved&&this._suppressNextTabClick(),this._endTabDrag(),t?.moved&&i&&this._commitTabOrder(t.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(e){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(e)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(e,t){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const n=this._model.map(e=>e.id),r=function(e,t,i){const n=e.indexOf(t),r=e.indexOf(i);if(n<0||r<0||n===r)return e;const o=e.slice();return o.splice(n,1),o.splice(r,0,t),o}(n,e,t);if(r===n)return;const o=new Map(this._devices.map(e=>[String(e.id),String(e.area||"")])),s=function(e,t,i,n=()=>""){if(!i)return[];const r=[];for(const o of e){if(!o||!0===o.removed)continue;const e="string"==typeof o.id?o.id:"";if(!e)continue;if("string"==typeof o.space&&o.space)continue;const s=("string"==typeof o.area?o.area:"")||n(e)||"";s&&t[s]||r.push({id:e,space:i})}return r}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),n[0]||"",e=>o.get(e)||"");if(s.length){const e=new Map(s.map(e=>[e.id,e.space]));for(const t of i.markers||[]){const i=e.get(String(t.id));i&&(t.space=i)}}i.spaces=function(e,t){const i=new Map(t.map((e,t)=>[e,t]));return e.map((e,t)=>({space:e,index:t})).sort((e,t)=>(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)||e.index-t.index).map(e=>e.space)}(i.spaces||[],r),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(e){if(this._endTabDrag(),e===this._space)return;const t=this._model.map(e=>e.id),i=t.indexOf(this._space),n=t.indexOf(e);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(e,i>=0&&n0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const e=this._model.map(e=>e.id),t=e.indexOf(this._space);this._slideTo(e[(t+1)%e.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}get _wallUnionCache(){return this._wallUnionCacheValue}set _wallUnionCache(e){this._wallUnionCacheValue=e,null===e&&this._wallUnionPool.clear()}_newContinuityController(){return new Ml(()=>{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(lm,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(e){const t=this._view;if(!t)return null;const i=[t.x+t.w/2,t.y+t.h/2],n="iso"===e?x_(i):i;return{x:n[0],y:n[1]}}_convertProjectionView(e,t){if(e===t)return;const i=this._logicalViewCenter(e);this._view=null;const n=i?"iso"===t?k_([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,n?.[0],n?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(e){if(!this._labsIso||"view"!==this._mode)return;const t=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:e},"iso"===e){const e=this._isoSceneKey();e&&this._isoFallback.delete(e)}this._saveViewPreference();const i=this._effectiveProjection();this._convertProjectionView(t,i)}_hashSpace(){return c_(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 e=(t=this.ownerDocument,jp.get(t)?.resolved);var t;void 0!==e&&(this._glowScreenBlend=e),this._continuityUnsub?.(),this._continuityUnsub=$l(this.ownerDocument,this._pageVisibility),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(e=>{for(const t of e)for(const e of t.addedNodes)this._syncPointerHoverSubtree(e)}),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(e){const t=jp.get(e);if(t)return t.promise;const i={promise:Promise.resolve(!1)};return i.promise=Wp(e).catch(()=>!1).then(e=>(i.resolved=e,e)),jp.set(e,i),i.promise}(this.ownerDocument).then(e=>{e!==this._glowScreenBlend&&(this._glowScreenBlend=e,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>Sn(this._serverCfg)),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(e,t){g_.add(t);const i=y_(e);return"undefined"==typeof window&&t(i),()=>{g_.delete(t)}}(K_,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},Z_)),!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._warmModeRequest=0,this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const e of this._activityRt.values())clearTimeout(e.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),clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,this._editorRuntimeLoadingVisible=!1,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 e of this._glowFadeTimers.values())clearTimeout(e);for(const e of this._glowEnterRafs.values())cancelAnimationFrame(e);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(e){if("Escape"===e.key&&this._vacFit)return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void e.stopPropagation();if("Escape"===e.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._closeMarkerDialog();if(this._deviceInbox)return void(this._deviceInbox=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 e.preventDefault(),void this._editorSecondary?.closeGroup(!0)}const t=e.composedPath?.()||[e.target],i=t.some(e=>e?.matches?.('input, textarea, select, [contenteditable="true"]')),n=t.some(e=>e?.classList?.contains?.("editor-secondary")),r=e.ctrlKey||e.metaKey,o=e.key.toLowerCase(),s=/^[a-z]$/.test(o),a="z"===o||!s&&"KeyZ"===e.code,l="y"===o||!s&&"KeyY"===e.code,c=r&&(a&&e.shiftKey||l),h=r&&a&&!e.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;return c?(e.preventDefault(),void this._redoGeometry()):h?(e.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry()):"Delete"!==e.key&&"Backspace"!==e.key||!this._decorSel||i||n?void("Escape"===e.key&&(e.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"))):(e.preventDefault(),void this._decorDeleteSel())}if(this._markup&&(!h&&!c||!i)){if(("Delete"===e.key||"Backspace"===e.key)&&this._physicalSel&&!i&&!n)return e.preventDefault(),void this._deletePhysicalSelection();if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._resize?.dragging?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"===e.key)return this._physicalDrag||this._physicalRotate?(e.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(e.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(e.preventDefault(),void this._finishWallChain()):this._physicalSel?(e.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():("exit-tool"===this._resize?.escapeIdle()&&(this._tool="draw"),void this.requestUpdate())):"split"===this._tool?(e.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?(e.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(e.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(e.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 e=this._geometrySnapshot();this._path=this._path.slice(0,-1),this._draftSegmentCms=this._draftSegmentCms.slice(0,-1);const t=this._curSpaceCfg,i=(t.room_drafts||[]).findIndex(e=>e.id===this._activeDraftId);if(i>=0){const n=Array.isArray(t.room_drafts[i]?.segments)?t.room_drafts[i].segments:[];this._path.length<2?(t.room_drafts.splice(i,1),t.room_drafts.length||delete t.room_drafts,this._activeDraftId=null):t.room_drafts[i]={id:this._activeDraftId,points:this._path.map(e=>[e[0]/hm,e[1]/hm]),segments:this._draftSegmentCms.map((e,t)=>({...n[t]||{},cm:e}))},this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),e)}return}this._path=this._path.slice(0,-1)}}_undoActiveDraftPoint(){const e=this._activeDraftId,t=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 n=e?this._spaceModel()?.room_drafts.find(t=>t.id===e):null;n?(this._activeDraftId=n.id,this._path=n.points.map(e=>[...e]),this._draftSegmentCms=this._adoptDraftCms(this._path,n.segments.map(e=>e.cm),n.id),this._resumeDraftBySpace[this._space]=n.id):(this._activeDraftId=null,this._path=t?[t]:[],this._draftSegmentCms=[],e&&this._resumeDraftBySpace[this._space]===e&&delete this._resumeDraftBySpace[this._space]),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:i.name}))}static async getConfigElement(){return await import("./editor-DMlizeQy.js"),document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(e){for(const e of Q_.values())for(const t of e)clearTimeout(t.evict);Q_.clear(),im=e&&e>0?e:1e4}static _warmBootStats(){let e=0,t=0;const i=[];for(const n of Q_.values())for(const r of n)e++,r.dlg&&(t++,i.push(r.dlg.kind));return{keys:Q_.size,slots:e,dlgs:t,drafts:i}}setConfig(e){const t=this._config,i=!!t&&Object.prototype.hasOwnProperty.call(t,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...e};(i!==this._hasFixedFloor||t?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&e.default_floor&&this._commitSpace(e.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(om)||"{}")||{}}catch{this._zoomBySpace={}}try{const e=JSON.parse(localStorage.getItem(lm)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(e).filter(e=>"flat"===e[1]||"iso"===e[1]))}catch{this._viewPreference={}}this._labs=y_(K_);try{const e=JSON.parse(localStorage.getItem(am)||"null");this._kioskScale={icon:Dn(e?.icon),font:Dn(e?.font)}}catch{}try{const e=JSON.parse(localStorage.getItem(rm)||"null");e&&e.config&&Array.isArray(e.config.spaces)&&(this._serverCfg=e.config,this._cfgEpoch++,this._cfgRev=e.rev||0,this._cfgContentFingerprint=e.config_fingerprint||Rl(e.config),this._layout=e.layout||{},this._layoutRev=e.layout_rev||0,this._layoutContentFingerprint=e.layout_fingerprint||Rl(this._layout),this._virtualLights=Cc(e.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 e=tm(this._config);if(this._warmKey===e&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const t=this.parentNode,i=this._warmIdx(t),n=Q_.get(e);if(!n||!n.length)return;const r=n.find(e=>e.owner===this._warmGen);if(r)return this._warmLongReturn=!!r.freed&&Date.now()-r.freed>=wl,clearTimeout(r.evict),r.evict=0,r.freed=0,r.live=!0,this._warmSlot=r,this._warmKey=e,r.frameFingerprint&&this._continuity.adoptCompleteFrame(r.frameFingerprint),void(!this._devices.length&&r.devices?.length&&(this._devices=[...r.devices]));const{slot:o,sure:s}=((e,t,i,n)=>{const r=e=>{const t=!!i&&e.place?.deref()===i;return t&&e.idx===n?4:e.live?0:t?3:2};let o=null,s=0,a=0,l=null;for(const i of e){if(i.owner===t)continue;l=i;const e=r(i);e<=0||(e>s?(o=i,s=e,a=1):e===s&&a++)}return!o||a>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(n,this._warmGen,t,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=wl,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},Z_)),this._warmKey=e,s?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=t?new WeakRef(t):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:t?new WeakRef(t):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},n.push(this._warmSlot),this._warmTrim(n)))}_warmIdx(e){const t=e?.children;if(!t)return-1;for(let e=0;e4;){const t=e.findIndex(e=>!e.live);if(t<0)break;clearTimeout(e[t].evict),e.splice(t,1)}}_warmScheduleEvict(e,t){if(clearTimeout(e.evict),!(e.dlg||e.vp&&"view"!==e.vp.mode))return;const i=e.freed,n=e.owner;e.evict=window.setTimeout(()=>{if(e.evict=0,e.freed!==i||e.owner!==n)return;var r;e.dlg=null,e.vp=(r=e.vp)&&"view"!==r.mode?{...r,mode:"view",zoom:r.snap?.space===r.space?r.snap.zoom:r.zoom,view:null,snap:null,tool:"draw",decorTool:"select",showHidden:!1,selId:null,rszSel:null,decorSel:null}:r,e.frameFingerprint="";const o=Q_.get(t);if(!e.live&&o&&o.length>1){const t=o.indexOf(e);t>=0&&o.splice(t,1)}},im+250)}_warmAdoptViewport(e){const t=this._warmVp;if(!t||this._warmSlot?.path!==location.pathname)return void(this._warmVp=null);const i=this._fixedFloorState();if(this._hashApplied||!this._model.find(e=>e.id===t.space)||"valid"===i.kind&&i.id!==t.space||this._hasFixedFloor&&"valid"!==i.kind)return void(this._warmVp=null);this._commitSpace(t.space,!0),this._navApplied=!0;const n="view"!==t.mode&&this._canEdit&&!e.kiosk?t.mode:"view";this._adoptMode("view"),this._pendingNavMode="view"===t.mode||this._canEdit||e.kiosk?null:t.mode,this._zoom=t.zoom;const r=this._effectiveProjection(),o=r===t.projection&&this._labsIso===t.activeLabsIso;if(this._view=o&&t.view?{...t.view}:null,this._viewModeSnap=o&&t.snap?{...t.snap}:null,!o&&t.logicalCenter){const e="iso"===r?k_([t.logicalCenter.x,t.logicalCenter.y],0):[t.logicalCenter.x,t.logicalCenter.y];this._applyView(t.zoom,e[0],e[1])}var s;this._tool="opening"===(s=function(e){return"partition"===e?"draw":e}(s=t.tool))?"draw":"string"==typeof s&&pm.has(s)?s:"draw",this._decorTool=t.decorTool,this._showHidden=t.showHidden,this._showFar!==t.showFar&&(this._showFar=t.showFar,this._frame=null),this._selId=t.selId,this._resize?.restoreSelection(t.rszSel),this._decorSel=t.decorSel,this._warmVpArmed=!0,"view"!==n&&this._requestMode(n,!1,!0)}_warmPatch(e,t=!1){if(this._config?.kiosk)return;const i=tm(this._config);if(!this._warmSlot||this._warmKey===i){if(!this._warmSlot){if(!t)return;const e=this.parentNode;this._warmKey=i,this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:this._warmIdx(e),live:!0,hdrH:this._hdrH,stageH:0,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0};const n=Q_.get(i)||[];for(n.push(this._warmSlot),Q_.set(i,n),this._warmTrim(n);Q_.size>8;){const e=Q_.keys().next().value;if(void 0===e||e===i)break;for(const t of Q_.get(e)||[])clearTimeout(t.evict);Q_.delete(e)}}Object.assign(this._warmSlot,e)}}_warmViewportState(){const e=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:e,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(e),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._resize?.selectedRoomId,decorSel:this._decorSel}}_warmDialogState(){const e=(e,t)=>({kind:e,space:this._space,mode:this._mode,data:t});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?e("openingInfo",this._openingInfo.id):this._infoCard?e("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:e("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:e("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:e("marker",this._markerDialog):this._openingDialog?e("opening",this._openingDialog):this._backdropDialog?e("backdrop",this._backdropDialog):this._decorShapeDialog?e("decorShape",this._decorShapeDialog):this._decorTextDialog?e("decorText",this._decorTextDialog):this._roomDialog?e("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:e("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const e={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices};if(this._warmRevivePending||(e.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const t=this.parentNode;e.place=t?new WeakRef(t):null,e.idx=this._warmIdx(t)}this._warmPatch(e)}_warmReviveDialog(){const e=this._warmSlot;if(this._warmReviveTimer=void 0,!e||!e.dlg)return void(this._warmRevivePending=!1);const t=e.dlg,i=e.freed;if(t.mode===this._mode||"view"===t.mode||this._warmVp?.mode!==t.mode||this._editorRuntime){if(this._warmRevivePending=!1,e.dlg=null,e.freed=0,clearTimeout(e.evict),e.evict=0,i&&!(Date.now()-i>im)&&t.space===this._space&&t.mode===this._mode){switch(t.kind){case"space":this._spaceDialog={...t.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...t.data,busy:!1};break;case"settings":this._settingsDialog={...t.data,busy:!1};break;case"rules":this._rulesDialog={...t.data,busy:!1};break;case"opening":this._openingDialog={...t.data};break;case"backdrop":this._backdropDialog={...t.data};break;case"decorShape":this._decorShapeDialog={...t.data};break;case"decorText":{this._decorTextDialog={...t.data};const e=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:e,end:e};break}case"room":{const e=t.data;this._roomEditId=e.editId,this._roomFill=e.fill,this._roomCustomFill=e.customFill||null,this._roomTempSrc=e.tempSrc,this._roomHumSrc=e.humSrc,this._roomSrcOpen=e.srcOpen,this._roomSrcFilter=e.srcFilter,this._roomNameScale=e.nameScale,this._roomLabelScale=e.labelScale,this._areaSel=e.areaSel,this._nameSel=e.nameSel,this._pendingSplit=e.pendingSplit,this._wallFaceBatch=e.wallFaceBatch||null,this._path=e.path,this._wallFaceBatch&&(this._activeDraftId=this._wallFaceBatch.activeDraftId,this._draftSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const e=this._devices.find(e=>e.id===t.data);e&&(this._infoCard=e);break}case"openingInfo":{const e=(this._curSpaceCfg?.openings||[]).find(e=>e.id===t.data);e&&(this._openingInfo=e);break}}this.requestUpdate()}}else this._warmRevivePending=!0}_cacheSnapshot(){if(this._serverCfg)try{this._cfgContentFingerprint=Rl(this._serverCfg),this._layoutContentFingerprint=Rl(this._layout),this._virtualLights=function(e,t,i){if(e.configRev===i)return e;const n=new Set((Array.isArray(t?.markers)?t.markers:[]).filter(zc).map(e=>e.id));return{...e,configRev:i,off:new Set([...e.off].filter(e=>n.has(e)))}}(this._virtualLights,this._serverCfg,this._cfgRev),localStorage.setItem(rm,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:Ac(this._virtualLights)}))}catch{}}_beginContinuityCandidate(e,t,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(e,i))}_continuityStageValid(){const e=this._stageEl;return!!e&&e.clientWidth>0&&e.clientHeight>0}_continuityAssetsReady(){if(!this._model.length)return!1;const e=this._model.length?this._spaceModel():null;return!e?.bg?.href||this._signer.isReady(this.hass,e.bg.href)}_initialSpaceSelection(e,t=this._loadOk){const i=this._fixedFloorState(e,t);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(e){const t=new Set(e.spaceIds.filter(e=>!!e));if(!t.size)return{id:null,source:"none"};const i=[["hash",!1===e.acceptHash?null:e.hashSpace],["current",e.preserveCurrent?e.currentSpace:null],["saved",e.savedSpace],["default",e.defaultSpace],["first",e.spaceIds[0]]];for(const[e,n]of i)if(n&&t.has(n))return{id:n,source:e};return{id:null,source:"none"}}({spaceIds:e.map(e=>e.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(e,t=this._loadOk){const i=this._initialSpaceSelection(e,t);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(e,t=this._space){const i=za(e),n=this._fixedFloorState(i,!0);if(this._hasFixedFloor&&"valid"!==n.kind)return"";const r=this._initialSpaceSelection(i,!0).id||(i.some(e=>e.id===t)?t:i[0]?.id);return i.find(e=>e.id===r)?.bg?.href||""}_visualFrameFingerprint(){const e=this._stageEl,t=e?[e.clientWidth,e.clientHeight]:[0,0];return Tl([this._cfgRev,this._cfgContentFingerprint||Rl(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||Rl(this._layout),this._space,this._mode,this._view,t,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 e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(e,t){this._signer.markLoaded(this.hass,e,t),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 e="connection"===this._continuity.recoveryReason;return B`
e.stopPropagation()} + @click=${e=>e.stopPropagation()} + @wheel=${e=>e.stopPropagation()}> + + ${this._t(e?"continuity.restore_connection":"continuity.restore_plan")} + ${"recovery-error"===this._continuity.state?B``:G} +
`}_renderEditorRuntimeLoading(){return this._editorRuntimeLoadingVisible?B`
+ + ${this._t("editor.loading")} +
`:G}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}getCardSize(){return 12}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const e=this._serverCfg?.spaces||[];let t=e.length+":";for(const i of e){t+=(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 e of i.rooms||[]){const i=e.poly?.[0],n=e.poly?.[e.poly.length-1];t+=(e.poly?.length||0)+"."+(e.id||"")+"."+(e.open_to||[]).join("+")+"."+(e.area||"")+"."+JSON.stringify(e.settings||0)+"."+(e.x??"")+","+(e.y??"")+","+(e.w??"")+","+(e.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(n?n[0]+"/"+n[1]:"")+";"}}return t}get _model(){if(!this._serverCfg)return[];const e=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===e)return this._modelCache.model;const t=this._buildModel();return this._modelCache={key:e,model:t},t}_buildModel(){if(!this._serverCfg)return[];const e=this._renderCfg;return za(e).map((t,i)=>{const n=e.spaces[i]?.plan_url;return t.bg&&n?{...t,bg:{...t.bg,href:n}}:t})}_spaceModel(){return this._hasFixedFloor?Al(this._model,this._space):(e=this._model,t=this._space,e.find(e=>e.id===t)??e[0]);var e,t}_spaceModelById(e){return Al(this._model,e)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0;for(const e of this._pointers.keys())for(const t of this.renderRoot.querySelectorAll("*"))try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}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._deviceInbox=null,this._deviceInboxReturn=null,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 e={};for(const t of this._model)for(const i of t.rooms)i.area&&(e[i.area]={space:t.id,room:i});return e}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._showHidden||!this._settings.filter_seeded&&!!this._settings.show_all}_seedHiddenDevices(){if(!this._serverCfg||!this._norm||!this._canEdit)return;const e=this._serverCfg,t=function(e){const t=e.hass,i=e.registry||Vc(t),n=Xc(t,i),r=Jc(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,iconRules:c}=e,h=!1!==a.group_lights,d=Lh(s),u=Ph(n,h).filter(e=>!qh(n,e.eid,d)),p=new Set(u.map(e=>e.area)),_=ih(n),m=nh(s,r),g=new Set(s.map(e=>e.binding)),f=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(g.has("device:"+e.id))continue;if("active"!==th(t,"device:"+e.id,i).kind)continue;const s=rh(n,e.id,_[e.id]||[],m);if(s.partial&&!s.entityIds.length)continue;const a=s.entityIds,d=oh(n,e,a);let u=l.has(d)||"Group"===e.model||/scene/i.test(e.model||"")||/bridge/i.test((e.model||"")+(e.name||""))||"myheat"===d&&!!e.via_device_id;if(!u&&h&&p.has(r)){const t=(e.name_by_user||e.name||"").trim();"mdi:lightbulb"===Fh(n,t,e.model,a,c)&&(u=!0)}u&&f.push("device:"+e.id)}return f}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!t.length&&e.settings?.filter_seeded)return;e.markers=e.markers||[];const i=[];for(const n of t){const t="h"+n.slice(n.indexOf(":")+1);e.markers.push({id:t,binding:n,hidden:!0}),i.push(n.slice(n.indexOf(":")+1))}const n={...e.settings||{},filter_seeded:!0};delete n.show_all,i.length&&Array.isArray(n.new_device_ids)&&(n.new_device_ids=n.new_device_ids.filter(e=>!i.includes(e))),e.settings=n,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const e=this._settings.icon_rules;if(!e||!Array.isArray(e)||!e.length)return;const t=JSON.stringify(e);return t!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=t,this._rulesCompiled=De(e)),this._rulesCompiled}get _fillColors(){return on(this._settings)}get _excluded(){const e=this._settings.exclude_integrations;return e?new Set(e):Te}willUpdate(e){e.has("_serverCfg")&&this._cfgEpoch++,this._syncEmptySpaceState(),e.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._editorRuntime&&this._dtMeasure();const e=this._stageEl;e&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>this._refitView()),this._roViewport.observe(e)),e&&this._booting&&!this._bootTimer&&this._bootWatch();const t=this.renderRoot.querySelector(".hdr");if(t&&e&&!this._roHdr){const i=()=>{const t=this.renderRoot.querySelector("ha-card");if(!t)return;const i=e.getBoundingClientRect().top-t.getBoundingClientRect().top,n=Math.min(Math.max(t.getBoundingClientRect().top,0),120),r=Math.round(i+n);r>=0&&r!==this._hdrH&&(this._hdrH=r),r>=0&&!this._booting&&!this._config?.kiosk&&e.clientHeight>0&&this._warmPatch({hdrH:r,stageH:e.clientHeight})};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(t),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(e&&!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 e=function(e){const t=e?.floors;if(!t||"object"!=typeof t)return[];const i=[];for(const e of Object.values(t))e&&e.floor_id&&i.push({id:e.floor_id,name:e.name||e.floor_id,level:e.level??null});return i.sort((e,t)=>{const i=e.level??1e9,n=t.level??1e9;return i!==n?i-n:e.name.localeCompare(t.name)}),i}(this.hass);e.length?this._importDialog={floors:e.map(e=>({...e,checked:!0}))}:this._openSpaceDialog("create")}}_adoptStructuralResponses(e,t,i){const n=e?.config,r=n&&Array.isArray(n.spaces)?n:null,o=Rl(r),s=o!==(this._cfgContentFingerprint||Rl(this._serverCfg));if(s&&(this._geometryHistory.clear(),this._pendingPhysicalWrites.clear(),this._serverCfg&&this._clearGeometryGesture(),this._serverCfg=r,this._cfgContentFingerprint=o),this._cfgRev=e?.rev??this._cfgRev,e&&("virtual_lights"in e||"config"in e)){const t=Dc(this._virtualLights,e.virtual_lights,this._cfgRev,"virtual_lights"in e);Oc(t)!==Oc(this._virtualLights)&&(this._virtualLights=t,this._capturedSnapshotVirtual="")}let a=!1;if(void 0!==t||void 0!==i){const e=i??t?.layout??{},n=Rl(e);a=n!==(this._layoutContentFingerprint||Rl(this._layout)),a&&(this._layout=e,this._layoutContentFingerprint=n),this._layoutRev=t?.rev??this._layoutRev}return this._canOptimizeUndo=!(!e?.can_optimize_undo&&!t?.can_optimize_undo),this._haIntegrationVersion="string"==typeof e?.integration_version?e.integration_version:this._haIntegrationVersion,this._undoKind=e?.undo_kind||t?.undo_kind||null,"boolean"==typeof e?.can_write&&(this._serverCanWrite=e.can_write),s&&this._continuity.note("config-candidate",{configRev:this._cfgRev}),a&&this._continuity.note("layout-candidate",{layoutRev:this._layoutRev}),{configChanged:s,layoutChanged:a}}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const e=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(e,!1),!0}async _loadFromServer(){this._loading=!0,this._loadTries++;const e=this._space,t=!!this._view;try{const[i,n]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]),r=i?.config&&Array.isArray(i.config.spaces)?i.config:null,o=Rl(r)!==(this._cfgContentFingerprint||Rl(this._serverCfg))||Rl(n?.layout??{})!==(this._layoutContentFingerprint||Rl(this._layout));if(o){if(!await this._signer.prepareImage(this.hass,this._candidateBackdrop(r)))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&&!n?.can_optimize_undo),this._haIntegrationVersion="string"==typeof i?.integration_version?i.integration_version:this._haIntegrationVersion,this._adoptStructuralResponses(i,n),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:t&&this._space===e||this._restoreZoom(),this._loadOk=!0,this.hass.callWS({type:"houseplan/trail/get"}).then(e=>{this._vacSrvTrails=e?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(e){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(nm)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const e=this.hass?.connection;if(!e)return;if(e!==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=e),this._liveSyncAttempt)return;const t=this._liveSyncGeneration,i=[],n=(n,r,o,s)=>{n()||i.push(async()=>{const i=await e.subscribeEvents(s,o);t===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===e&&!n()?r(i):i?.()})};if(n(()=>this._unsubCfg,e=>{this._unsubCfg=e},"houseplan_config_updated",e=>{const t=Number(e?.data?.rev??-1);t!==this._cfgRev&&this._reloadConfigOnly(!1,t)}),n(()=>this._unsubTrail,e=>{this._unsubTrail=e},"houseplan_trail_updated",async()=>{try{const e=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=e?.trails||{},this.requestUpdate()}catch{}}),n(()=>this._unsubLayout,e=>{this._unsubLayout=e},"houseplan_layout_updated",e=>this._onLayoutEvent(Number(e?.data?.rev??-1))),n(()=>this._unsubVirtual,e=>{this._unsubVirtual=e},"houseplan_virtual_light_updated",e=>{const t=Fc(this._virtualLights,e?.data);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const r=function(e){return Promise.allSettled(e.map(e=>Promise.resolve().then(e)))}(i).then(()=>{});this._liveSyncAttempt=r,r.finally(()=>{this._liveSyncAttempt===r&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(e=!1,t){if(!e){if(void 0!==t&&t<=this._cfgRev)return;if(this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(()=>this._reloadConfigOnly(!1,t),400))}this._beginContinuityCandidate("config-reload",!1);try{const e=await this.hass.callWS({type:"houseplan/config/get"}),t=e?.config&&Array.isArray(e.config.spaces)?e.config:null;if(Rl(t)!==(this._cfgContentFingerprint||Rl(this._serverCfg))&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(t)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0);const i=this._space;this._adoptStructuralResponses(e),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._space!==i&&this._restoreZoom(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}catch(e){this._showToast(this._t("toast.cfg_reload_failed",{err:this._errText(e)}))}finally{this._continuityDataReady=!0,this.requestUpdate()}}_scheduleLoadRetry(e=!1){if(void 0!==this._loadRetryTimer)return;const t=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!e&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},t)}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._haRegistryRelease=Gc(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return Vc(this.hass)}get _planHass(){const e=this._haRegistry,t=Yc(this.hass,e),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===t)return i.active;const n=Xc(this.hass,e),r=Jc(this.hass,e);return this._planHassMemo={hass:this.hass,sig:t,active:n,full:r},n}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRt.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+wp)>e?1:0)).join("|"),i=Oc(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===t)return;const n=this._planHass,r=new Map,o=new Map,s=new Set(["sun.sun"]);this._vacFit?.source&&s.add(this._vacFit.source);const a=new Set,l=new Set,c=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void s.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?a.add(n):"entity"===i&&s.add(n)};for(const e of this._model)for(const t of e.rooms)t.area&&l.add(t.area),c(t.settings?.temp_source),c(t.settings?.hum_source);for(const e of this._serverCfg?.spaces||[])for(const t of e.openings||[])for(const e of ni(t))s.add(e);for(const e of this._serverCfg?.spaces||[])for(const t of e.decor||[])if("text"===t.kind){for(const e of String(t.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const t=Hi(e[1]);t?.entity&&s.add(t.entity)}t.entity&&s.add(t.entity),o.set(`decor:${e.id}:${t.id}`,Wi(t.text,t,n,e=>!!n.entities?.[e]&&!!n.states?.[e]&&!qh(n,e,Lh(this._markers))))}const h=Mh(n,this._devices,null,this._virtualLights);for(const e of this._devices){for(const t of[!1,!0])r.set(Nu(e.id,t),Pu(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(e)){const t=this._vacSource(e,n),i=t?Bl(n?.states?.[t]?.attributes):null,r=this._vacRt.get(e.id);o.set(`vacuum:${e.id}`,{source:t,telemetry:i,mapId:i?this._vacMapId(e,i,n):null,runtime:r?{trail:r.trail,lastTs:r.lastTs,moving:r.moving,jump:r.jump}:null,server:this._vacSrvTrails[e.id]||null})}}const d=Eu({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,positions:(u=this._model.length>0,p=this._devices,_=e=>this._livePos(e),u?new Map(p.map(e=>[e.id,_(e)])):new Map),facts:o,entityIds:s,deviceIds:a,areaIds:l});var u,p,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=t,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(e){return th(this.hass,e,this._haRegistry)}houseplanDiagnostics(){const e=function(e){const t=Vc(e);return{access:t.access,authoritative:t.authoritative,revision:t.revision,lastSuccess:t.lastSuccess,error:t.error}}(this.hass),t={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const e of this._markers)e.removed||"virtual"===e.binding||t[this._bindingStatus(e.binding).kind]++;return{registry:{...e,lastSuccessAgeMs:e.lastSuccess?Math.max(0,Date.now()-e.lastSuccess):null},bindings:t}}_openBindingInHa(e){const[t,i]=e.split(":");if(i)if("device"!==t){if("entity"===t){const e=this._fullRegistryHass.entities?.[i];e?.device_id&&mm("/config/devices/device/"+encodeURIComponent(e.device_id))}}else mm("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(e){const[t,i]=e.split(":");return!!i&&("device"===t||"entity"===t&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const e=this._markerDialog;if(!e)return;const t="ha"===e.bindingMode?this._bindingStatus(e.binding):null,i=e.hideFromPlan||"ha_disabled"===t?.kind;i&&"ha_disabled"===t?.kind?this._showToast(this._t("entity"===t.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===t?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...e,hideFromPlan:!i}}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}_display(e){return this._signer.display(this.hass,e)}_resign(){this._signer.resign(this.hass,Sn(this._serverCfg))}_onLayoutEvent(e){e<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{e<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(e){const t=e?.rev;"number"==typeof t&&t>this._layoutRev&&(this._layoutRev=t)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const e=new Map;for(const t of this._dirtyPos)this._layout[t]&&e.set(t,this._layout[t]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[t,i]of this._sentPos)e.set(t,i);try{const t=await this.hass.callWS({type:"houseplan/layout/get"}),i={...t?.layout||{}};for(const[t,n]of e)i[t]=n;const n=Rl(i);n!==(this._layoutContentFingerprint||Rl(this._layout))&&(this._layout=i,this._layoutContentFingerprint=n),this._layoutRev=t?.rev??this._layoutRev,this._canOptimizeUndo=!!t?.can_optimize_undo,this._haIntegrationVersion="string"==typeof t?.integration_version?t.integration_version:this._haIntegrationVersion,this._undoKind=t?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_maybeRebuildDevices(){const e=this.hass;if(!e?.devices||!e?.entities||!e?.areas)return;const t=this._haRegistry,i=Yc(e,t)+":"+Object.keys(e.areas).length+":"+(this._norm?"n":"l")+":"+Xd(e,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const n=new Map(this._devices.map(e=>[e.id,e.bindingStatus?.kind||"active"]));this._devices=Wh({hass:e,registry:t,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:e=>this._t(e),iconRules:this._iconRules});const r=this._markers.filter(e=>!e.removed&&"virtual"!==e.binding).map(e=>e.binding).sort(),o=t.revision+":"+r.join("|");if(t.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const n of r)i.set(n,th(e,n,t));!function(e){if("undefined"==typeof localStorage||!e.size)return;const t=eh(),i=Date.now();for(const[n,r]of e)"active"===r.kind?t[n]={kind:"active",ts:i}:"ha_disabled"===r.kind&&(t[n]={kind:"ha_disabled",reason:r.reason,ts:i});const n=Object.fromEntries(Object.entries(t).sort((e,t)=>t[1].ts-e[1].ts).slice(0,1500));Lc=n;try{localStorage.setItem(Hc,JSON.stringify(n))}catch{}}(i),this._haBindingCacheKey=o}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),this._syncActivityRuntime();const s=new Set(this._devices.filter(e=>!e.hidden).map(e=>e.id));for(const e of this._vacRt.keys())s.has(e)||this._vacRt.delete(e);if(this._infoCard){const e=this._devices.find(e=>e.id===this._infoCard.id);this._infoCard=e&&"ha_disabled"!==e.bindingStatus?.kind?e:null}const a=this._devices.some(e=>"ha_disabled"===e.bindingStatus?.kind&&"ha_disabled"!==n.get(e.id));a&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(e=>e.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._drag&&"ha_disabled"===this._devices.find(e=>e.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)&&(_m(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const e=this._devices.filter(e=>!e.marker&&!e.virtual).map(e=>e.id).sort(),t=e.join(",");if(t===this._newSyncKey)return;this._newSyncKey=t;const i=this._settings,{fresh:n,known:r}=function(e,t){if(!Array.isArray(t))return{fresh:[],known:[...e]};const i=new Set(t),n=e.filter(e=>!i.has(e));return{fresh:n,known:n.length?[...t,...n]:t}}(e,i.known_devices);if(!Array.isArray(i.known_devices)||n.length){const e=[...new Set([...i.new_device_ids||[],...n])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:r,new_device_ids:e}},this._saveConfig()}}get _newIds(){const e=this._settings.new_device_ids;return new Set(Array.isArray(e)?e:[])}_ackNewDevice(e){if(!this._newIds.has(e)||!this._serverCfg)return;const t=this._settings;this._serverCfg={...this._serverCfg,settings:{...t,new_device_ids:(t.new_device_ids||[]).filter(t=>t!==e)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(e){if(!e)return null;const t=[];for(const i of this._renderDevices){if(i.area!==e||i.virtual)continue;const n=Ch(this._renderPlanHass,i.entities);null!=n&&t.push(n)}return Mi(t)}_roomBounds(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}_defaultPositions(){const e={},t=this._config?.icon_size??2.5;for(const i of this._model){const n=t/100*el(i)*1.3;for(const t of i.rooms){if(!t.area)continue;const r=this._devices.filter(e=>e.area===t.area&&e.space===i.id);if(!r.length)continue;const o=this._roomBounds(t),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(r.length*a/Math.max(l,1)))),h=Math.ceil(r.length/c),d=a/c,u=l/Math.max(h,1),p=r.map((e,t)=>({x:o.x+s+d*(t%c+.5),y:o.y+s+u*(Math.floor(t/c)+.5)}));Ti(p,o,n,.5*s),r.forEach((t,i)=>e[t.id]=La(p[i]))}}return e}_pos(e){const t=this._renderDeviceSnapshot?.positions.get(e.id);return t?{x:t.x,y:t.y}:this._livePos(e)}_livePos(e){const t=this._spaceModelById(e.space),i=this._layout[e.id];if(i)if(this._norm){if(i.s===e.space)return{x:i.x*hm,y:i.y*hm}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[e.id]?this._defPos[e.id]:t?La(Qa(t)):{x:500,y:500}}_savePos(e,t,i){if(this._spaceModelById(e.space)){if(this._norm){const n=this._gridPitch,r=Math.round(t/n)*n,o=Math.round(i/n)*n,s=this._layout[e.id]?.k;this._layout={...this._layout,[e.id]:{s:e.space,x:ja(r/hm),y:ja(o/hm),...s?{k:s}:{}}}}else this._layout={...this._layout,[e.id]:{x:Math.round(t),y:Math.round(i)}};this._dirtyPos.add(e.id),this._persistLayout()}}_visualSamples(e){return Cu(this._renderPlanHass,e,this._renderDevices,void 0,this._fullRegistryHass).samples}_devicePresentation(e,t=!1!==this._config?.show_signal,i=!1){const n=i?null:this._renderDeviceSnapshot?.presentations.get(Nu(e.id,t));return n||Pu(this._renderPlanHass,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,designPreview:i,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(e){return this._devicePresentation(e).visual}_stateClass(e,t=this._deviceVisual(e)){const i=this._devicePresentation(e);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===t.status||t.activity,zu({...i,visual:t}).join(" "))}_liveTemp(e){if(!this._config?.show_temperature)return null;if(!0===e.marker?.use_climate_temp){const t=Ah(this._renderPlanHass,e.entities);if(null!=t)return t}return"mdi:thermometer"!==e.icon&&"mdi:air-filter"!==e.icon?null:Dh(this._renderPlanHass,e.entities)}_bindingEntities(e){if("virtual"===e||!e)return[];const t=this._bindingStatus(e);return"active"===t.kind?t.enabledEntityIds:t.allEntityIds}_bindingHasClimate(e){return this._bindingEntities(e).some(e=>e.startsWith("climate."))}_bindingHasAlarm(e){return this._bindingEntities(e).some(e=>{const t=this._planHass?.states?.[e]||this.hass?.states?.[e],i=this._fullRegistryHass.entities[e]||this.hass?.entities?.[e];return In(e.split(".")[0],t?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_liveHum(e){return this._config?.show_temperature&&e.primary&&Oh(this.hass,e.primary)?zh(this.hass,e.entities):null}_deviceBindingActive(e,t=!0){if(e.virtual||"virtual"===e.bindingKind)return!0;if(!e.bindingKind||!e.bindingRef)return!1;const i=this._bindingStatus(`${e.bindingKind}:${e.bindingRef}`);return"active"===i.kind||(t&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(e){e?this._planEntityAvailable(e)?(this._nativeMoreInfoEntity=e,_m(this,"hass-more-info",{entityId:e})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(e,t){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==e)for(const i of[t,this._stageEl])try{i?.hasPointerCapture?.(e)&&i.releasePointerCapture(e)}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(e,t){"view"===this._mode&&(e.preventDefault(),e.stopPropagation(),this._deviceBindingActive(t)&&(t.primary?this._openMoreInfo(t.primary):this._infoCard=t))}_clickDevice(e,t){if(e.stopPropagation(),this._drag?.moved||this._suppressClick||this._holdFired)return;if("plan"===this._mode)return;if("devices"===this._mode)return void this._openMarkerDialog(t);const i=this._devices.find(e=>e.id===t.id);if(!i)return;const n=_d(i.tapAction,i.primary?.split(".")[0]),r=(e,t)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:e,exec:t}:t()};if("toggle"===n){const e=this._toggleIntent(i);if(!e)return;if(!bd(e))return void this._showUnavailableToggleTargets(e);const t=e=>{const t=bd(e);if(!t)return;if("virtual-light"===t.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:t.markerId}).then(e=>{const t=Fc(this._virtualLights,e);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(e=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(e)})));const{command:n}=t;this._startDevicePressFeedback(i.id),this.hass.callService(n.domain,n.service,n.data).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)})))},n=((o=e).targets.length?o.targets:o.skippedTargets).map(e=>e.name||e.entityId||e.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const r=this._toggleConfirmationLines(e);if(!r.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:n}),lines:r,initialIntent:e,deviceId:i.id,exec:()=>{const n=this._devices.find(e=>e.id===i.id),r=n?this._toggleIntent(n):null;r&&!bd(r)&&this._showUnavailableToggleTargets(r)||(r&&xd(e,r)?t(r):this._showToast(this._t("toast.tap_target_changed")))}}}else t(e);return}var o;if("info"===n)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===n){const e=i.marker?.tap_target||"",t=function(e){const t=String(e||"").split(".")[0];return"automation"===t?{domain:"automation",service:"trigger"}:"script"===t?{domain:"script",service:"turn_on"}:"scene"===t?{domain:"scene",service:"turn_on"}:null}(e),n=this.hass.states[e];if(!t||!n)return void this._showToast(this._t("toast.run_target_missing"));const o=n.attributes?.friendly_name||e;return void r(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(e)&&(this._startDevicePressFeedback(i.id),this.hass.callService(t.domain,t.service,{entity_id:e}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)}))))})}"more-info"===n&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(e){const t=function(e){if(!e||"group"!==e.kind||bd(e)||"configured-targets-missing"!==e.noneReason)return[];if(!e.skippedTargets.length||e.skippedTargets.some(e=>!wd.has(e.reason)&&"secure"!==e.reason))return[];const t=[],i=new Set;for(const n of e.skippedTargets){if(!wd.has(n.reason))continue;const e=String(n.name||n.entityId||n.ref||"").trim();e&&!i.has(e)&&(i.add(e),t.push(e))}return t}(e);return!!t.length&&(this._showToast(1===t.length?this._t("toast.toggle_target_unavailable",{name:t[0]}):this._t("toast.toggle_targets_unavailable",{names:t.join(", ")})),!0)}_keyDevice(e,t){"Enter"!==e.key&&" "!==e.key||"view"!==this._mode&&"devices"!==this._mode||(e.preventDefault(),this._clickDevice(e,t))}_startDevicePressFeedback(e){const t=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(t=>t.dataset.id===e),i=t?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const n=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),r=Number.isFinite(n)?Math.max(.95,Math.min(1,n)):1;this._devicePressAnimations.get(e)?.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(r)},{scale:"0.95",offset:.5},{scale:"1"}],s=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(e,s);const a=()=>{this._devicePressAnimations.get(e)===s&&this._devicePressAnimations.delete(e)};s.addEventListener("finish",a,{once:!0}),s.addEventListener("cancel",a,{once:!0})}_cancelDevicePressFeedback(){for(const e of this._devicePressAnimations.values())e.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const e=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(e=>e.dataset.id||""));for(const[t,i]of this._devicePressAnimations)e.has(t)||(i.cancel(),this._devicePressAnimations.delete(t))}_t(e,t){return Jd(Xd(this.hass,this._config?.language),e,t)}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(e){return this._editorRuntimeOrThrow()._help(e)}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(e){const t=[];for(const i of this._devices){if(i.space!==e.id||i.hidden)continue;const n=this._pos(i);t.push({minX:n.x,minY:n.y,maxX:n.x,maxY:n.y})}if(e.id===this._space){for(const e of this._openingsR){const i=Number(e.angle)*Math.PI/180,n=Math.cos(i)*e.rlen/2,r=Math.sin(i)*e.rlen/2,o=Ua([[e.rx-n,e.ry-r],[e.rx+n,e.ry+r]]);o&&t.push(o)}const i=this._decorH;for(const e of this._decorList){const n=Ua("line"===e.kind?[[e.x1*hm,e.y1*i],[e.x2*hm,e.y2*i]]:"text"===e.kind?[[e.x*hm,e.y*i]]:wr({x:e.x*hm,y:e.y*i,w:e.w*hm,h:e.h*i,angle:e.angle}));n&&t.push(n)}for(const i of this._physicalBodiesR(e)){const e=Ua(i);e&&t.push(e)}}return Va(e,t)}_frameOf(){const e=this._spaceModel();if(!e){this._frame=null;const e={x:0,y:0,w:hm,h:hm};return{rect:e,all:e,outliers:0}}const t=this._frame,i="view"!==this._mode;if(t&&t.id===e.id&&this._bdDrag)return t;if(t&&t.id===e.id&&t.model===e&&t.layout===this._layout&&t.devs===this._devices&&t.far===this._showFar&&t.grow===i)return t;const n=Xa(this._contentItems(e));let r=n.all||Ja(e),o=this._showFar?r:n.core||Ja(e);return t&&t.id===e.id&&i&&t.grow&&(o=um(t.rect,o),r=um(t.all,r)),this._frame={id:e.id,model:e,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:r,outliers:n.outliers},this._frame}_isoSource(){const e=this._spaceModel();if(!e)return null;const t=this._spaceWalls,i=this._openCuts(),n=this._openingsR.map((e,t)=>({id:String(e.id||t),sourceIndex:t,type:e.type,x:e.rx,y:e.ry,angle:Number(e.angle)||0,length:e.rlen>0?e.rlen:900,flipH:!!e.flip_h,flipV:!!e.flip_v})),r=xa(64,this._cellCm),o=xa(10,this._cellCm),s=`${e.id}|${function(e){let t=2166136261;const i=e=>{if("number"!=typeof e)if("string"!=typeof e)if("boolean"!=typeof e)if(Array.isArray(e)){t=O_(t,e.length);for(const t of e)i(t)}else{if(e&&"object"==typeof e){const t=e;for(const e of Object.keys(t).sort())i(e),i(t[e]);return}t=O_(t,-1)}else t=O_(t,e?1:0);else for(const i of e)t=O_(t,i.codePointAt(0)||0);else t=O_(t,e)};return i(e),t.toString(36)}({rooms:e.rooms,walls:t,openCuts:i,openings:n,partitions:e.partitions,roomDrafts:e.room_drafts,columns:e.wall_columns,cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,camera:b_,wallHeight:r,floorEdgeHeight:o,algorithm:3})}`;return{key:s,build:()=>{const o=ca(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e)).all,s=this._roomWallOpeningInputs(this._openingsR,e),a=t.length||o.length?Ns(e.rooms,t,i,s,this._wallKeyPitch,this._cellCm,this._gridPitch,hm,o):null;if(a&&("failed-core"===a.status||"not-applicable"===a.status))throw new Error("wall boolean geometry failed");const l=a?.paperGeom??Ps(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm);if(!l)throw new Error("floor boolean geometry failed");const c=a?.openingIndex||Bs(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm),h=n.map(e=>{const i=this._openingsR[e.sourceIndex],n="gate"===e.type?!e.flipV:e.flipV,o=i?.partitionHost?Od(i.partitionHost,n):t.length||"gate"===e.type?Vs(c,{x:e.x,y:e.y,angle:e.angle,length:e.length,flip_v:n}):{ox:0,oy:0,cm:0,side:-1};return function(e,t=64){if(!(z_([e.x,e.y,e.angle,e.length,e.face.ox,e.face.oy,t])&&e.length>0&&t>0))throw new Error("invalid isometric opening input");const i=e.length/2;let n;if("passage"===e.type)n=[];else if("gate"===e.type){const r=10*e.face.side;n=[F_(e,0,[-i,0],[i,0],r,0,.88*t),F_(e,1,[i,0],[-i,0],-r,0,.88*t)]}else n="window"===e.type?[F_(e,0,[-i,0],[i,0],-90,.27*t,.78*t),F_(e,1,[i,0],[-i,0],90,.27*t,.78*t)]:[F_(e,0,[-i,0],[e.length,0],-90,0,.92*t)];return{id:e.id,sourceIndex:e.sourceIndex,type:e.type,leaves:Object.freeze(n.map(e=>Object.freeze(e)))}}({...e,face:o},r)});return{walls:a?.components.flatMap(e=>e.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 e=this._isoSource();if(!e)return null;const t=this._isoGeometryCache.get(e.key);if(t)return{key:e.key,...t};const i=this._frameOf().rect,n=e.build(),r=xa(64,this._cellCm),o=xa(10,this._cellCm),s=function(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)for(const e of o.leaves){const o=Math.hypot(e.closedVector[0],e.closedVector[1]);t=Math.min(t,e.hinge[0]-o),i=Math.min(i,e.hinge[1]-o),n=Math.max(n,e.hinge[0]+o),r=Math.max(r,e.hinge[1]+o)}return z_([t,i,n,r])?{x:t,y:i,w:n-t,h:r-i}:null}(n.openings),a=S_({rect:s?um(i,s):i,wallHeight:r,openingHeight:r,floorDepth:o}),l=function(e,t=b_,i=64){if(!Number.isFinite(i)||i<0)throw new Error("invalid wall height");const n=[],r=[],o=[];let s=0;for(let a=0;a<(e||[]).length;a++){const l=e[a];for(let e=0;e<(l||[]).length;e++){const c=T_(l[e],e>0);if(!(c.length<3||Math.abs(R_(c))<1e-9)){n.push(C_(c,t,i)),s+=c.length;for(let n=0;ne.depth-t.depth||e.polygon-t.polygon||e.ring-t.ring||e.edge-t.edge),{topPath:n.join(" "),sides:r,contactPath:o.join(" "),edgeCount:s}}(n.walls,b_,r),c={geometry:l,floor:A_(n.floor,o),openings:n.openings,frame:a};return J_(this._isoGeometryCache,e.key,c,8),{key:e.key,...c}}_effectiveProjection(){if("iso"!==this._desiredProjection||!this._model.length)return"flat";const e=this._isoSceneKey()||`${this._space}|invalid`;if(this._isoFallback.has(e))return"flat";try{const e=this._isoScene();return e?(t="iso",i=e.key,n=this._isoFallback,"iso"===t&&i&&!n.has(i)?"iso":"flat"):"flat"}catch(t){if(!this._isoFallback.has(e)){this._isoFallback.add(e);const i=e.split("|");console.warn(`HOUSEPLAN ISO FALLBACK: #89, space ${this._space}, fingerprint ${i[i.length-1]}, ${t instanceof Error?t.message:"renderer error"}`)}return"flat"}var t,i,n}_scenePoint(e){return"iso"===this._renderProjection?k_(e,0):e}_floorView(e){if("iso"!==this._renderProjection)return e;const t=x_([e.x,e.y]),i=x_([e.x+e.w,e.y+e.h]);return{x:t[0],y:t[1],w:i[0]-t[0],h:i[1]-t[1]}}_baseVb(){if("iso"===this._effectiveProjection()){if(!this._spaceDisplayForRender().showBorders){const e=S_({rect:this._frameOf().rect,wallHeight:xa(64,this._cellCm)});return[e.x,e.y,e.w,e.h]}const e=this._isoScene()?.frame??this._frameOf().rect;return[e.x,e.y,e.w,e.h]}const e=this._frameOf().rect;return[e.x,e.y,e.w,e.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:B`
+ + ${this._t("canvas.far_objects",{n:this._outliers})} + +
`}_renderHomeArrow(){if(this._booting)return G;const e=this._view;if(!e||!e.w||!e.h)return G;const t=this._baseVb(),i=t[0],n=t[1],r=t[2],o=t[3];if(!(i+r<=e.x||i>=e.x+e.w||n+o<=e.y||n>=e.y+e.h))return G;const s=Math.atan2(n+o/2-(e.y+e.h/2),i+r/2-(e.x+e.w/2)),a=50+38*Math.cos(s),l=50+38*Math.sin(s);return B``}_stageAspect(){const e=this._stageEl,t=this._baseVb();return e&&e.clientHeight?e.clientWidth/e.clientHeight:t[2]/t[3]}_viewOr(e){return this._view&&this._view.w?this._view:Ri(e,this._stageAspect())}_roomLabelReferenceViewWidth(e){if(!this._markup)return e.w;const t=this._stageEl,i=this.renderRoot.querySelector(".editorchrome");if(!t||t.clientWidth<=0||t.clientHeight<=0)return e.w;const n=t.clientHeight+(i?.getBoundingClientRect().height||0);return n<=0?e.w:this._viewForModeTarget(this._zoom,void 0,void 0,t.clientWidth,n).w}_screenToVb(e,t){const i=this._stageEl,n=this._viewOr(this._baseVb()),r=i?.clientWidth||1,o=i?.clientHeight||1;return[n.x+e/r*n.w,n.y+t/o*n.h]}_clampView(e,t){const i=(e,t,i,n)=>{const r=1*Math.max(t,n),o=i-r,s=i+n-t+r;return Math.max(Math.min(o,s),Math.min(Math.max(o,s),e))};return{w:e.w,h:e.h,x:i(e.x,e.w,t.x,t.w),y:i(e.y,e.h,t.y,t.h)}}_applyView(e,t,i){const n=this._baseVb(),r=Ri(n,this._stageAspect()),o=Math.min(vm.ZOOM_MAX,Math.max(vm.ZOOM_MIN,e)),s=r.w/o,a=r.h/o,l=this._viewOr(n),c=t??l.x+l.w/2,h=i??l.y+l.h/2,d=this._clampView({x:c-s/2,y:h-a/2,w:s,h:a},r);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 e=()=>{if(!this._booting)return;const t=Date.now(),i=this._stageEl?this._stageEl.clientHeight:0;i!==this._bootLastH&&(this._bootLastH=i,this._bootLastChange=t);const n=t-this._bootStart;n>=1200||n>=700&&i>0&&t-this._bootLastChange>=250?this._bootSettled():this._bootTimer=window.setTimeout(e,100)};this._bootTimer=window.setTimeout(e,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 e=this._stageEl?.clientHeight??0;!this._config?.kiosk&&e>0&&this._warmPatch({hdrH:this._hdrH,stageH:e,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},Z_)}_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||this._warmModeRequest)return;const e=this._stageEl;if(!e||"visible"!==document.visibilityState||e.clientWidth<=0||e.clientHeight<=0)return void(this._viewportInvalidAt||(this._viewportInvalidAt=Date.now()));const t=[e.clientWidth,e.clientHeight],i=this._lastValidStageSize,n=!!i&&Math.abs(i[0]-t[0])<=.5&&Math.abs(i[1]-t[1])<=.5,r=this._viewportInvalidAt?Date.now()-this._viewportInvalidAt:0;if(this._viewportInvalidAt=0,!i)return this._lastValidStageSize=t,void(this._view||this._applyView(this._zoom));n?this._pendingRefitSize=null:(this._pendingRefitSize=t,this._refitRaf||(this._refitRaf=requestAnimationFrame(()=>{this._refitRaf=0;const e=this._pendingRefitSize;this._pendingRefitSize=null;const t=this._stageEl;if(!e||!t||t.clientWidth<=0||t.clientHeight<=0)return;if(Math.abs(t.clientWidth-e[0])>.5||Math.abs(t.clientHeight-e[1])>.5)return void this._refitView();const i=this._lastValidStageSize;if(i&&Math.abs(i[0]-e[0])<=.5&&Math.abs(i[1]-e[1])<=.5)return;this._lastValidStageSize=e;const n=this._view;r>=wl?this._beginContinuityCandidate("stage-size-restored",!0,"stage-size"):this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._applyView(this._zoom,n?n.x+n.w/2:void 0,n?n.y+n.h/2:void 0)})))}_zoomAt(e,t,i){const n=this._stageEl;if(!n)return;const r=Ri(this._baseVb(),this._stageAspect()),o=Math.min(vm.ZOOM_MAX,Math.max(vm.ZOOM_MIN,i));"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1));const s=n.clientWidth,a=n.clientHeight,l=this._screenToVb(e,t),c=r.w/o,h=r.h/o;this._zoom=o,this._view=this._clampView({x:l[0]-e/s*c,y:l[1]-t/a*h,w:c,h:h},r)}_onWheel(e){const t=this._stageEl;if(!t)return;e.preventDefault();const i=t.getBoundingClientRect(),n=e.deltaY<0?1.15:1/1.15;this._zoomAt(e.clientX-i.left,e.clientY-i.top,this._zoom*n),this._saveZoom()}_stepZoom(e){const t=this._stageEl;t&&(this._zoomAt(t.clientWidth/2,t.clientHeight/2,this._zoom*(e>0?1.4:1/1.4)),this._saveZoom())}_resetZoom(){const e=this._baseVb();"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=1,this._view=Ri(e,this._stageAspect()),this._saveZoom()}_saveZoom(){if("view"===this._mode){this._zoomBySpace={...this._zoomBySpace,[this._space]:this._zoom};try{localStorage.setItem(om,JSON.stringify(this._zoomBySpace))}catch{}}}_restoreZoom(){const e=this._zoomBySpace[this._space]||1;this._zoom=e;const t=this._stageEl;if(t&&t.clientHeight){const t=this._baseVb();return this._applyView(e,t[0]+t[2]/2,t[1]+t[3]/2),void this.requestUpdate()}this._view=null,requestAnimationFrame(()=>{if(!this._stageEl)return;const t=this._baseVb();this._applyView(e,t[0]+t[2]/2,t[1]+t[3]/2),this.requestUpdate()})}_stagePointerDown(e){if(this._vacFit)return;if(this._kiosk&&(this._cyclePausedUntil=Date.now()+6e4,0===this._pointers.size?(this._swipeStart={x:e.clientX,y:e.clientY,id:e.pointerId},e.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&&e.target.closest?.(".roomlabel, .rlhandle, .rszhandle, .dev, .oplock, .op-hit, button"))return;if("devices"===this._mode&&e.target.closest(".dev"))return;if("decor"===this._mode&&this._decorPointerDown(e))return;this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY});const t=this._viewOr(this._baseVb());if(1===this._pointers.size)this._panStart={sx:e.clientX,sy:e.clientY,vx:t.x,vy:t.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 e=[...this._pointers.values()],t=Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y);this._pinchStart={dist:t,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(e){if(this._physicalRotate?.pid!==e.pointerId)if(this._physicalDrag?.pid!==e.pointerId)if(this._dtDrag?.pid!==e.pointerId)if(this._bdDrag?.pid!==e.pointerId){if(this._decorDraft?.pid===e.pointerId){const t=this._decorDraft;let i=this._decorSnap(this._svgPoint(e),e.pointerType);if(e.shiftKey&&("rect"===t.kind||"ellipse"===t.kind)){const e=i[0]-t.a[0],n=i[1]-t.a[1],r=Math.max(Math.abs(e),Math.abs(n));i=this._snap([t.a[0]+(e<0?-r:r),t.a[1]+(n<0?-r:r)])}return void(this._decorDraft={...t,b:i})}if(this._decorMove?.pid!==e.pointerId)if(this._pointers.has(e.pointerId)){if(this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY}),this._markup&&1===this._pointers.size&&this._markupMove(e),this._pinchStart&&this._pointers.size>=2){"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const e=[...this._pointers.values()],t=Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y)/(this._pinchStart.dist||1),i=this._stageEl.getBoundingClientRect(),n=(e[0].x+e[1].x)/2-i.left,r=(e[0].y+e[1].y)/2-i.top;this._zoomAt(n,r,this._pinchStart.zoom*t),this._suppressClick=!0,this._saveZoom()}else if(this._panStart){const t=e.clientX-this._panStart.sx,i=e.clientY-this._panStart.sy;Math.abs(t)+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(t)+Math.abs(i)>8&&(this._panLock=this._swipeZone&&Math.abs(t)>1.5*Math.abs(i)?"swipe":"pan");const n=this._stageEl;if("pan"===this._panLock&&n){const e=this._baseVb(),r=this._viewOr(e),o=Ri(e,this._stageAspect());this._view=this._clampView({x:this._panStart.vx-t/(n.clientWidth||1)*r.w,y:this._panStart.vy-i/(n.clientHeight||1)*r.h,w:r.w,h:r.h},o)}}}else this._markupMove(e);else this._decorMoveUpdate(e)}else this._bdMove(e);else this._dtMove(e);else this._physicalMove(e);else this._physicalRotateMove(e)}_stagePointerLeave(e){this._markup&&("opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover())}_stagePointerUp(e){if(this._kiosk){clearTimeout(this._kioskHoldTimer);const t=this._swipeStart;if(this._swipeStart=null,t&&t.id===e.pointerId){const i=e.clientX-t.x,n=e.clientY-t.y;if(Math.abs(i)+Math.abs(n)<8){const e=Date.now();e-this._lastTap<350&&this._resetZoom(),this._lastTap=e}const r="pan"===this._panLock?null:function(e,t,i,n,r,o=60){if(i>1.001||n.length<2)return null;if(Math.abs(e)e.id),this._space);r&&this._slideTo(r,i<0?"left":"right")&&(this._saveNav(),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._showKioskDots())}}if(this._physicalDrag?.pid===e.pointerId)return void this._physicalUp(e);if(this._physicalRotate?.pid===e.pointerId)return void this._physicalRotateUp(e);if(this._dtDrag?.pid===e.pointerId)return void this._dtUp();if(this._bdDrag?.pid===e.pointerId)return void this._bdUp();if(this._decorDraft?.pid===e.pointerId)return void this._decorCommitDraft();if(this._decorMove?.pid===e.pointerId)return this._decorMove.moved&&(this._recordGeometry(this._t("history.decor_move"),this._decorMove.before),this._saveConfig()),void(this._decorMove=null);const t=!!this._pinchStart||!!this._panStart;this._pointers.delete(e.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null,setTimeout(()=>this._suppressClick=!1,0)),t&&0===this._pointers.size&&this.requestUpdate()}_clickRoom(e){!this._suppressClick&&e.area&&mm("/config/areas/area/"+e.area)}_pointerDown(e,t){if("plan"===this._mode)return;if("view"===this._mode){this._holdFired=!1,clearTimeout(this._holdTimer);const i=e.pointerId,n=e.currentTarget;return void(this._holdTimer=window.setTimeout(()=>{this._holdFired=!0,this._interruptViewGesture(i,n),this._infoCard=t},600))}if("ha_disabled"===t.bindingStatus?.kind)return;e.preventDefault();const i=this._pos(t);this._drag={id:t.id,sx:e.clientX,sy:e.clientY,ox:i.x,oy:i.y,moved:!1},fm(e),this._tip=null}_pointerMove(e,t){if(!this._drag||this._drag.id!==t.id)return;const i=this.renderRoot.querySelector(".stage");if(!i)return;const n=this._baseVb(),r=i.getBoundingClientRect(),o=this._viewOr(n),s=(e.clientX-this._drag.sx)/r.width*o.w,a=(e.clientY-this._drag.sy)/r.height*o.h;Math.abs(e.clientX-this._drag.sx)+Math.abs(e.clientY-this._drag.sy)>3&&(this._drag.moved=!0,clearTimeout(this._holdTimer));const l=qa(this._drag.ox+s),c=qa(this._drag.oy+a);this._savePos(t,l,c)}_pointerUp(e,t){if(clearTimeout(this._holdTimer),!this._drag||this._drag.id!==t.id)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&(this._selId=t.id,window.setTimeout(()=>this._drag=null,0))}_showToast(e){for(const e of this.renderRoot.querySelectorAll("hp-dialog"))e.closeTransientOverlays("toast");this._toast=e,clearTimeout(this._toastTimer),this._toastTimer=window.setTimeout(()=>{this._toast=""},3500)}_syncPointerHoverTargets(){const e=this._pointerModality.hoverEnabled;for(const t of this.renderRoot.querySelectorAll(cm))t.toggleAttribute("data-pointer-hover",e)}_syncPointerHoverSubtree(e){if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e,i=this._pointerModality.hoverEnabled;t.matches(cm)&&t.toggleAttribute("data-pointer-hover",i);for(const e of t.querySelectorAll(cm))e.toggleAttribute("data-pointer-hover",i)}_clearTransientHover(e=!1){e&&this._pointerModality.suspend(),this._tip&&(this._tip=null),this._hoverRoom&&(this._hoverRoom=null)}_notePointer(e){const t=this._pointerModality.modality,i=this._pointerModality.note(e);"touch"!==i&&"pen"!==i||t===i&&!this._tip&&!this._hoverRoom||this._clearTransientHover()}_guardTouchGesture(e){if(this._editorSecondary?.handleOutsideDismiss(e))return;if("click"===e.type){if(!this._suppressClick&&!this._touchSequenceMultitouch&&Date.now()>this._touchClickBlockUntil)return;return e.preventDefault(),void e.stopImmediatePropagation()}const t=e;if(this._notePointer(t),"touch"===t.pointerType)if("pointerdown"!==e.type){if("pointermove"===e.type){const e=this._touchContacts.get(t.pointerId);if(!e)return;const i={...e,x:t.clientX,y:t.clientY};if(this._touchContacts.set(t.pointerId,i),this._touchSequenceMultitouch&&"view"===this._mode&&!this._vacFit&&this._pinchStart&&[...this._touchContacts.values()].every(e=>e.inStage)){this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY});const e=[...this._touchContacts.values()];if(e.length>=2&&this._stageEl){const[t,i]=e,n=Math.hypot(t.x-i.x,t.y-i.y)/(this._pinchStart.dist||1),r=this._stageEl.getBoundingClientRect();this._zoomAt((t.x+i.x)/2-r.left,(t.y+i.y)/2-r.top,this._pinchStart.zoom*n),this._saveZoom()}}return}if("pointerup"===e.type||"pointercancel"===e.type||"lostpointercapture"===e.type){if(this._clearTransientHover(),this._touchContacts.delete(t.pointerId),this._touchSequenceMultitouch){if(this._touchClickBlockUntil=Date.now()+500,this._pointers.delete(t.pointerId),!this._vacFit&&this._pointers.size>=2){const[e,t]=[...this._pointers.values()];this._pinchStart={dist:Math.hypot(e.x-t.x,e.y-t.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(t.pointerId,{x:t.clientX,y:t.clientY,inStage:!!t.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 e=[...this._touchContacts.values()];if("view"===this._mode&&!this._vacFit&&e.every(e=>e.inStage)){this._pointers=new Map([...this._touchContacts].map(([e,t])=>[e,{x:t.x,y:t.y}]));const[t,i]=e;this._pinchStart={dist:Math.hypot(t.x-i.x,t.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(e,t,i,n,r,o){this._notePointer(e),this._pointerModality.hoverEnabled&&(this._drag||(this._tip={x:e.clientX,y:e.clientY,title:t,meta:i,lqi:n,temp:r,hum:o}))}get _gridPitch(){return Ea}get _cellCm(){const e=Number(this._curSpaceCfg?.cell_cm);return Number.isFinite(e)&&e>0?e:5}_fmtLen(e,t){const i=function(e,t,i,n){return Math.hypot(t[0]-e[0],t[1]-e[1])/i*n}(e,t,this._gridPitch,this._cellCm);return Kt(i,"mi"===this.hass?.config?.unit_system?.length)}get _curSpaceCfg(){const e=this._resize?.preview;return e&&e.space===this._space?e.sp:this._serverCfg?.spaces.find(e=>e.id===this._space)}get _renderCfg(){const e=this._resize?.preview;return e&&this._serverCfg?{...this._serverCfg,spaces:this._serverCfg.spaces.map(t=>t.id===e.space?e.sp:t)}:this._serverCfg}get _spaceH(){return this._curSpaceCfg,hm}get _segments(){const e=this._curSpaceCfg,t=this._spaceH;return Jt(e?.rooms||[]).map(e=>[e[0]*hm,e[1]*t,e[2]*hm,e[3]*t])}_savedNav(){if(this._hasFixedFloor)return null;try{return JSON.parse(localStorage.getItem(sm)||"null")}catch{return null}}_saveNav(){if(!this._hasFixedFloor)try{localStorage.setItem(sm,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._deviceInbox=null,this._deviceInboxReturn=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 e=this._warmSlot;e?.owner===this._warmGen&&(e.vp=this._warmViewportState(),e.dlg=null,e.frameFingerprint="",clearTimeout(e.evict),e.evict=0),this._saveNav()}_setMode(e,t=!0){return this._warmModeRequest=0,this._editorRuntime?this._editorRuntime._setMode(e,t):"view"===e?void this._editorModeRequest++:void this._requestMode(e,t)}_primeDrawWallField(){return this._editorRuntimeOrThrow()._primeDrawWallField()}get _drawWallFieldValue(){return null===this._drawWallField?fo(15,this._imperial):this._drawWallField}get _drawWallCm(){const e=(e=>{const t=String(e??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(t))return null;const i=Number(t);return Number.isFinite(i)?i:null})(this._drawWallFieldValue);if(null==e||e<0)return null;const t=this._imperial?2.54*e:e,i="column"===this._tool?Xs:100;return t>=("column"===this._tool?1:0)&&t<=i?t:null}get _drawWallMaxCm(){return"column"===this._tool?Xs:100}_showPhysicalRange(e=this._drawWallMaxCm,t=0){return this._editorRuntimeOrThrow()._showPhysicalRange(e,t)}_draftSegmentCount(e=this._curSpaceCfg){return this._editorRuntimeOrThrow()._draftSegmentCount(e)}_mergeSpacePartitions(e,t){return this._editorRuntimeOrThrow()._mergeSpacePartitions(e,t)}_finishWallChain(){return this._editorRuntimeOrThrow()._finishWallChain()}_activateMarkupTool(e){return this._editorRuntimeOrThrow()._activateMarkupTool(e)}_limitReached(e){return this._editorRuntimeOrThrow()._limitReached(e)}_svgPoint(e){return this._editorRuntimeOrThrow()._svgPoint(e)}_snap(e){return this._editorRuntimeOrThrow()._snap(e)}_snapDrawPoint(e,t=!1){return this._editorRuntimeOrThrow()._snapDrawPoint(e,t)}_planSnapOpeningCuts(e,t){return this._editorRuntimeOrThrow()._planSnapOpeningCuts(e,t)}_planSnapGeometrySnapshot(){return this._editorRuntimeOrThrow()._planSnapGeometrySnapshot()}_hiddenWallDiagnosticSnapshot(){return this._editorRuntimeOrThrow()._hiddenWallDiagnosticSnapshot()}_planStructuralGeometrySnapshot(){return this._editorRuntimeOrThrow()._planStructuralGeometrySnapshot()}_planSnapContextKey(e){return this._editorRuntimeOrThrow()._planSnapContextKey(e)}_resolvePlanDrawPoint(e,t){return this._editorRuntimeOrThrow()._resolvePlanDrawPoint(e,t)}get _activePlanSnapCandidate(){if(!this._markup||"draw"!==this._tool)return null;const e=this._planSnapHover;if(!e)return null;const t=this._planSnapGeometrySnapshot();return e.contextKey===this._planSnapContextKey(t.key)?e.candidate:null}get _activePlanSnapConflicts(){if(!this._markup||"draw"!==this._tool)return[];const e=this._planSnapHover;if(!e)return[];const t=this._planSnapGeometrySnapshot();return e.contextKey===this._planSnapContextKey(t.key)?e.conflicts:[]}_clearPlanSnapHover(e=!0){return this._editorRuntime?this._editorRuntimeOrThrow()._clearPlanSnapHover(e):(this._planSnapHover=null,void(e&&(this._cursorPt=null)))}_samePt(e,t){return oi(e,t)}_dropLegacySegments(){return this._editorRuntimeOrThrow()._dropLegacySegments()}_rollbackRejectedPhysicalWrites(e){return this._editorRuntimeOrThrow()._rollbackRejectedPhysicalWrites(e)}async _reloadRejectedPhysicalWrite(){return this._editorRuntimeOrThrow()._reloadRejectedPhysicalWrite()}get _cfgWriting(){return this._writesPending>0}async _sendConfigCandidate(e){const t=so(e),i=await this.hass.callWS({type:"houseplan/config/set",config:t,expected_rev:this._cfgRev});this._cfgRev=i?.rev??this._cfgRev+1}_writeConfig(){if(this._editorRuntime)return this._editorRuntime._writeConfig();this._writesPending++,this._writeChain=Lp(this._writeChain,async()=>{if(!this._serverCfg)return;const e=so(this._serverCfg),t=Rl(e);t!==Rl(this._serverCfg)&&(this._serverCfg=e),this._cfgContentFingerprint=t,await this._sendConfigCandidate(e)});return this._writeChain.finally(()=>{this._writesPending--})}_saveConfig(){this._cfgEpoch++,this._saveConfigDebounced()}_geometrySnapshotFromConfig(e,t){return this._editorRuntimeOrThrow()._geometrySnapshotFromConfig(e,t)}_geometrySnapshot(e=this._space){return this._editorRuntimeOrThrow()._geometrySnapshot(e)}_recordGeometry(e,t){return this._editorRuntimeOrThrow()._recordGeometry(e,t)}_restoreGeometryStateInConfig(e,t,i=!1){return this._editorRuntimeOrThrow()._restoreGeometryStateInConfig(e,t,i)}_restoreGeometryStateLocal(e){return this._editorRuntimeOrThrow()._restoreGeometryStateLocal(e)}_wallModelBlockerLabel(e){return this._editorRuntimeOrThrow()._wallModelBlockerLabel(e)}_hasLegacyZeroWallFields(e=this._serverCfg){return this._editorRuntimeOrThrow()._hasLegacyZeroWallFields(e)}_showWallModelMigrationBlocked(e){return this._editorRuntimeOrThrow()._showWallModelMigrationBlocked(e)}_limitSegmentsOf(e){return this._editorRuntimeOrThrow()._limitSegmentsOf(e)}_junctionLimitViolations(e,t,i){return this._editorRuntimeOrThrow()._junctionLimitViolations(e,t,i)}_junctionLimitLabel(e){return this._editorRuntimeOrThrow()._junctionLimitLabel(e)}_junctionLimitsIntroduced(e,t,i){return this._editorRuntimeOrThrow()._junctionLimitsIntroduced(e,t,i)}_commitPhysicalGeometry(e,t,i=[]){return this._editorRuntimeOrThrow()._commitPhysicalGeometry(e,t,i)}_clearGeometryGesture(){return this._editorRuntime?this._editorRuntimeOrThrow()._clearGeometryGesture():(this._path=[],this._planSnapHover=null,this._cursorPt=null,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingPreset=null,this._openingRebindId=null,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._resize?.reset(),this._decorDraft=null,this._decorMove=null,this._dtDrag=null,void(this._bdDrag=null))}_stagePointerCancel(e){if(this._editorRuntime)return this._editorRuntime._stagePointerCancel(e)}_applyGeometryState(e,t=!1){return this._editorRuntimeOrThrow()._applyGeometryState(e,t)}_roomAt(e){return this._editorRuntimeOrThrow()._roomAt(e)}_overlapRoom(e){return this._editorRuntimeOrThrow()._overlapRoom(e)}_pointInRoom(e,t){return t.poly?si(e,t.poly):null!=t.x&&e[0]>=t.x&&e[0]<=t.x+t.w&&e[1]>=t.y&&e[1]<=t.y+t.h}_contourSelfIntersects(e){return this._editorRuntimeOrThrow()._contourSelfIntersects(e)}_canAppendRoomDraftPoint(){return this._editorRuntimeOrThrow()._canAppendRoomDraftPoint()}_markupClick(e){if(this._editorRuntime)return this._editorRuntime._markupClick(e)}_draftEndAt(e,t){return this._editorRuntimeOrThrow()._draftEndAt(e,t)}_mergeDraftEndpoint(e){return this._editorRuntimeOrThrow()._mergeDraftEndpoint(e)}_adoptDraftCms(e,t,i){return this._editorRuntimeOrThrow()._adoptDraftCms(e,t,i)}_draftSegmentsForPath(e,t,i){return this._editorRuntimeOrThrow()._draftSegmentsForPath(e,t,i)}_persistActiveDraftSegment(){return this._editorRuntimeOrThrow()._persistActiveDraftSegment()}_activeWallSourceKey(e){return this._editorRuntimeOrThrow()._activeWallSourceKey(e)}_wallGraphSources(e){return this._editorRuntimeOrThrow()._wallGraphSources(e)}_wallFaceGraph(e,t){return this._editorRuntimeOrThrow()._wallFaceGraph(e,t)}_offerWallFaces(e,t=this._path.length-2,i){return this._editorRuntimeOrThrow()._offerWallFaces(e,t,i)}_beginWallFaceBatch(e){return this._editorRuntimeOrThrow()._beginWallFaceBatch(e)}_offerExistingWallFace(e){return this._editorRuntimeOrThrow()._offerExistingWallFace(e)}_columnClick(e){return this._editorRuntimeOrThrow()._columnClick(e)}_openPhysicalDialog(e,t,i){return this._editorRuntimeOrThrow()._openPhysicalDialog(e,t,i)}_physicalDown(e,t,i){return this._editorRuntimeOrThrow()._physicalDown(e,t,i)}_clampPhysicalDelta(e,t,i){return this._editorRuntimeOrThrow()._clampPhysicalDelta(e,t,i)}_physicalMove(e){return this._editorRuntimeOrThrow()._physicalMove(e)}_physicalUp(e){return this._editorRuntimeOrThrow()._physicalUp(e)}_registerPhysicalTap(e,t,i){return this._editorRuntimeOrThrow()._registerPhysicalTap(e,t,i)}_cancelPhysicalGesture(){return this._editorRuntimeOrThrow()._cancelPhysicalGesture()}_physicalRotateDown(e,t){return this._editorRuntimeOrThrow()._physicalRotateDown(e,t)}_physicalRotateMove(e){return this._editorRuntimeOrThrow()._physicalRotateMove(e)}_physicalRotateUp(e){return this._editorRuntimeOrThrow()._physicalRotateUp(e)}_rszRooms(){return this._editorRuntimeOrThrow()._rszRooms()}_rszOpenings(){return this._editorRuntimeOrThrow()._rszOpenings()}_rszObstacles(){return this._editorRuntimeOrThrow()._rszObstacles()}_rszOptsFor(e,t){return this._editorRuntimeOrThrow()._rszOptsFor(e,t)}_rszResolution(e,t,i){return this._editorRuntimeOrThrow()._rszResolution(e,t,i)}_rszSnapshot(){return this._editorRuntimeOrThrow()._rszSnapshot()}_rszResetController(){return this._editorRuntimeOrThrow()._rszResetController()}_rszProjectPreview(e,t,i,n,r){return this._editorRuntimeOrThrow()._rszProjectPreview(e,t,i,n,r)}_rszAcceptPreview(e,t){return this._editorRuntimeOrThrow()._rszAcceptPreview(e,t)}_rszSpaceCandidateGeometry(e,t){return this._editorRuntimeOrThrow()._rszSpaceCandidateGeometry(e,t)}_rszSpaceCandidateRenderable(e,t){return this._editorRuntimeOrThrow()._rszSpaceCandidateRenderable(e,t)}_rszCandidateRenderable(e){return this._editorRuntimeOrThrow()._rszCandidateRenderable(e)}_rszEdgeDown(e,t,i){return this._editorRuntimeOrThrow()._rszEdgeDown(e,t,i)}_rszReasonText(e){return this._editorRuntimeOrThrow()._rszReasonText(e)}_rszDisabledActivate(e,t){return this._editorRuntimeOrThrow()._rszDisabledActivate(e,t)}_rszDisabledKey(e,t){return this._editorRuntimeOrThrow()._rszDisabledKey(e,t)}_rszMove(e){return this._editorRuntimeOrThrow()._rszMove(e)}_rszUp(e){return this._editorRuntimeOrThrow()._rszUp(e)}_rszCancelDrag(e){return this._editorRuntimeOrThrow()._rszCancelDrag(e)}_rszPointerCancel(e){return this._editorRuntimeOrThrow()._rszPointerCancel(e)}_rszEdgeLabels(e,t,i=this._resize?.rooms){return this._editorRuntimeOrThrow()._rszEdgeLabels(e,t,i)}_rszInnerSpanCms(e,t,i){return this._editorRuntimeOrThrow()._rszInnerSpanCms(e,t,i)}_renderResizeMeasurements(){return this._editorRuntimeOrThrow()._renderResizeMeasurements()}_renderResizeLayer(e){return this._editorRuntimeOrThrow()._renderResizeLayer(e)}get _openingsR(){const e=this._curSpaceCfg,t=this._spaceH,i=this._spaceModel();return i?(e?.openings||[]).flatMap(e=>{const n={...e,rx:e.x*hm,ry:e.y*t,rlen:e.length*hm};if(!e.host||"wall"===e.host.kind)return[n];const r=Td(e,i.partitions,hm,this._cellCm,this._gridPitch);if(!r.resolved)return"plan"===this._mode?[{...n,orphanReason:r.reason||"invalid-host"}]:[];let[o,s]=r.resolved.center;const a=this._physicalDrag;return a?.moved&&"partition"===a.kind&&a.id===e.host.id&&(o+=a.delta[0],s+=a.delta[1]),[{...e,rx:o,ry:s,rlen:r.resolved.length,angle:r.resolved.angle,partitionHost:r.resolved}]}):[]}_partitionOpeningCuts(e=this._spaceModel(),t=()=>!0){if(!e)return[];return Fp(Pp(this._curSpaceCfg?.id===e.id?this._curSpaceCfg:null,e,this._cellCm,this._gridPitch,hm),t)}_roomWallOpeningInputs(e=this._openingsR,t=this._spaceModel()){if(!t)return[];const i=this._openCuts();return Ip(e,t,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm)}_openingFace(e,t,i){return e.partitionHost?Od(e.partitionHost,i):Vs(t,{x:e.rx,y:e.ry,angle:e.angle,length:e.rlen,flip_v:i})}_cmToUnits(e){return e/this._cellCm*this._gridPitch}get _decorList(){const e=this._curSpaceCfg;return Array.isArray(e?.decor)?e.decor:[]}get _decorH(){return hm}_decorResolvedStyle(e){return function(e,t,i,n=ur){const r="rect"===e?.kind||"ellipse"===e?.kind,o=e,s=qt(o?.color,n.color);return{color:s,opacity:pr(o?.opacity,n.opacity),widthCm:yr(e,t,i,n.widthCm),fill:!!r&&!0===o?.fill,fillColor:qt(o?.fill_color,o?.fill?s:n.fillColor),fillOpacity:r&&o?.fill?pr(o?.fill_opacity,.25):n.fillOpacity}}(e,this._cellCm,this._gridPitch,ur)}_decorWidthUnits(e){return((e,t,i,n=ur.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return fr(r,t,i);const o=Number(e?.width);return Number.isFinite(o)&&o>0?o:fr(n,t,i)})(e,this._cellCm,this._gridPitch,ur.widthCm)}_decorTextSizeCm(e){if("text"===e?.kind){const t=Number(e.size_cm);return Number.isFinite(t)&&t>0?t:vr(20*Gi(e),this._cellCm,this._gridPitch)}return vr(20,this._cellCm,this._gridPitch)}_decorTextUnits(e){if("text"!==e.kind)return 20;const t=Number(e.size_cm);return Number.isFinite(t)&&t>0?fr(t,this._cellCm,this._gridPitch):20*Gi(e)}_decorSmallField(e){return Math.round(100*(this._imperial?e/2.54:e))/100}_decorSmallCm(e){const t=this._imperial?2.54*e:e;return Number.isFinite(t)?Math.max(.1,Math.min(100,t)):.1}_decorTextCm(e){const t=this._imperial?2.54*e:e;return Number.isFinite(t)?Math.max(.1,Math.min(2e3,t)):.1}_decorLargeField(e){return Math.round(100*(this._imperial?e/30.48:e/100))/100}_decorLargeCm(e){const t=this._imperial?30.48*e:100*e;return Number.isFinite(t)?Math.max(.1,Math.min(Pa*this._cellCm,t)):.1}_angleField(e){const t=Number(e);return Number.isFinite(t)?String(Number(t.toFixed(3))):"0"}_decorBoxOf(e){return"rect"!==e.kind&&"ellipse"!==e.kind&&"furniture"!==e.kind?null:{x:e.x*hm,y:e.y*this._decorH,w:e.w*hm,h:e.h*this._decorH,angle:_r(e.angle)||void 0}}_decorSnapGeometry(e){return this._editorRuntimeOrThrow()._decorSnapGeometry(e)}_decorSnap(e,t="mouse",i){return this._editorRuntimeOrThrow()._decorSnap(e,t,i)}_replaceDecor(e,t){return this._editorRuntimeOrThrow()._replaceDecor(e,t)}_cancelDecorGesture(){return this._editorRuntimeOrThrow()._cancelDecorGesture()}_decorPointerDown(e){return this._editorRuntimeOrThrow()._decorPointerDown(e)}_decorCommitDraft(){return this._editorRuntimeOrThrow()._decorCommitDraft()}_decorShapeDown(e,t){return this._editorRuntimeOrThrow()._decorShapeDown(e,t)}_decorMoveUpdate(e){return this._editorRuntimeOrThrow()._decorMoveUpdate(e)}_decorShapeDbl(e,t){if(this._editorRuntime)return this._editorRuntime._decorShapeDbl(e,t)}_openDecorProperties(e){return this._editorRuntimeOrThrow()._openDecorProperties(e)}_decorOpenText(e){return this._editorRuntimeOrThrow()._decorOpenText(e)}_decorRememberTextSelection(e){return this._editorRuntimeOrThrow()._decorRememberTextSelection(e)}_decorInsertLiveVariable(e){return this._editorRuntimeOrThrow()._decorInsertLiveVariable(e)}_decorSaveText(){return this._editorRuntimeOrThrow()._decorSaveText()}_decorSaveShape(){return this._editorRuntimeOrThrow()._decorSaveShape()}get _dtSel(){return"decor"===this._mode&&"select"===this._decorTool&&this._decorSel&&this._decorList.find(e=>e.id===this._decorSel)||null}_dtPivot(e){return this._editorRuntimeOrThrow()._dtPivot(e)}_dtApply(e,t){return this._editorRuntimeOrThrow()._dtApply(e,t)}_dtStart(e,t,i,n){return this._editorRuntimeOrThrow()._dtStart(e,t,i,n)}_dtMove(e){return this._editorRuntimeOrThrow()._dtMove(e)}_dtUp(){return this._editorRuntimeOrThrow()._dtUp()}_dtMeasure(){return this._editorRuntimeOrThrow()._dtMeasure()}_deleteDecor(e){return this._editorRuntimeOrThrow()._deleteDecor(e)}_decorDeleteSel(){return this._editorRuntimeOrThrow()._decorDeleteSel()}_confirmDecorErase(){return this._editorRuntimeOrThrow()._confirmDecorErase()}get _furnWalls(){const e=this._rawPhysicalBodiesR().flatMap(e=>e.map((t,i)=>{const n=e[(i+1)%e.length];return[t[0],t[1],n[0],n[1]]}));return[...this._segments,...e]}get _furnWallReach(){return 6*this._gridPitch}_furnFieldValue(e){return this._editorRuntimeOrThrow()._furnFieldValue(e)}_furnFieldToCm(e){return this._editorRuntimeOrThrow()._furnFieldToCm(e)}_furnPick(e){return this._editorRuntimeOrThrow()._furnPick(e)}_furnPlace(e,t=!1){return this._editorRuntimeOrThrow()._furnPlace(e,t)}_furnMoveUpdate(e){return this._editorRuntimeOrThrow()._furnMoveUpdate(e)}_decorApplyBox(e,t){return this._editorRuntimeOrThrow()._decorApplyBox(e,t)}get _furnLive(){const e=this._dtDrag;if(!e||"scale"!==e.kind||!e.orig)return null;const t=this._decorList.find(t=>t.id===e.id);if(!t||"furniture"!==t.kind)return null;const i=hm,n=this._decorH,r=t.w*i,o=t.h*n,s=function(e,t,i,n,r){const o=e+i/2,s=t+n/2,a=(Number(r)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(e,t)=>{const i=e-o,n=t-s;return[o+i*l-n*c,s+i*c+n*l]};return[h(e,t),h(e+i,t),h(e+i,t+n),h(e,t+n)]}(t.x*i,t.y*n,r,o,Number(t.angle)||0),a=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],l=a(s[0],s[1]),c=a(s[0],s[3]);return[{x:l[0],y:l[1],text:this._fmtLen([0,0],[r,0])},{x:c[0],y:c[1],text:this._fmtLen([0,0],[0,o])}]}_renderFurnPalette(){return this._editorRuntimeOrThrow()._renderFurnPalette()}get _bdBase(){const e=this._curSpaceCfg;return e?.plan_url?{...Ta(e.plan_aspect,hm)}:null}get _bdRect(){const e=this._curSpaceCfg;return e?.plan_url?Aa(e,hm):null}get _bdParams(){const e=this._curSpaceCfg,t=Number(e?.plan_x),i=Number(e?.plan_y),n=Number(e?.plan_scale),r=Number(e?.plan_scale_x),o=Number(e?.plan_scale_y),s=Number.isFinite(n)&&n>0?n:1;return{dx:Number.isFinite(t)?t:0,dy:Number.isFinite(i)?i:0,sx:Number.isFinite(r)&&r>0?r:s,sy:Number.isFinite(o)&&o>0?o:s,angle:_r(e?.plan_angle)}}_openBackdropDialog(e){if(this._editorRuntime)return this._editorRuntime._openBackdropDialog(e)}_saveBackdropDialog(){return this._editorRuntimeOrThrow()._saveBackdropDialog()}get _bdActive(){return"decor"===this._mode&&!!this._bdRect&&"backdrop"===this._decorTool}get _bdMovable(){return"decor"===this._mode&&"backdrop"===this._decorTool&&!!this._bdRect}_bdApply(e,t,i,n,r){return this._editorRuntimeOrThrow()._bdApply(e,t,i,n,r)}_bdStart(e,t,i=!1){return this._editorRuntimeOrThrow()._bdStart(e,t,i)}_bdMove(e){return this._editorRuntimeOrThrow()._bdMove(e)}get _bdMoved(){if("decor"!==this._mode||!this._bdRect)return!1;const e=this._bdParams;return 0!==e.dx||0!==e.dy||1!==e.sx||1!==e.sy||0!==e.angle}_bdReset(){return this._editorRuntimeOrThrow()._bdReset()}_bdUp(){return this._editorRuntimeOrThrow()._bdUp()}get _bdLive(){if(!this._bdDrag)return null;const e=this._bdRect;return e?{x:e.x+e.w/2,y:e.y+e.h/2,text:`${this._fmtLen([0,0],[e.w,0])} × ${this._fmtLen([0,0],[0,e.h])}`}:null}_renderBackdropFrame(e){return this._editorRuntime?this._editorRuntimeOrThrow()._renderBackdropFrame(e):G}_renderTextFrame(e){const t=this._dtSel,i=this._dtBox;if(!t||!i||i.id!==t.id)return G;const n=.018*Math.max(e.w,e.h),r=n/4;if("line"===t.kind){const e=[t.x1*hm,t.y1*this._decorH],i=[t.x2*hm,t.y2*this._decorH];return W` + + ${[e,i].map((e,t)=>W`this._dtStart(e,"scale",void 0,t)}> + `)} + `}const[o,s]=this._dtPivot(t),a=Number(t.angle)||0,l=2.2*n;return W` + + + this._dtStart(e,"rotate")}> + + ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([e,t,o])=>W`this._dtStart(i,"scale",[e,t])}>`)} + `}_renderDecorLayer(){const e=hm,t=this._decorH,i="decor"===this._mode,n=i&&"erase"===this._decorTool,r=this._decorList.map(r=>{const o="dshape"+(i&&this._decorSel===r.id?" dsel":""),s=this._decorResolvedStyle(r),a=this._decorWidthUnits(r),l=e=>this._decorShapeDown(e,r),c=e=>this._decorShapeDbl(e,r);if("line"===r.kind)return W` + ${i&&"select"===this._decorTool?W``:G} + ${n?W``:G}`;if("rect"===r.kind){const i=(r.x+r.w/2)*e,h=(r.y+r.h/2)*t,d=_r(r.angle);return W` + ${n?W``:G}`}if("ellipse"===r.kind){const i=(r.x+r.w/2)*e,h=(r.y+r.h/2)*t,d=_r(r.angle);return W` + ${n?W``:G}`}if("furniture"===r.kind){const i=r.w*e,h=r.h*t,d=vl(r.symbol,i,h);if(!d)return G;const u=Number(r.angle)||0,p=r.x*e+i/2,_=r.y*t+h/2,m=`${u?`rotate(${u} ${p} ${_}) `:""}translate(${r.x*e} ${r.y*t})`;return W` + ${n?W``:G}`}if("text"===r.kind){const i=this._decorTextUnits(r),n=this._renderDeviceSnapshot?.facts.get(`decor:${this._space}:${r.id}`),a=function(e){return String(e??"").replace(/\r\n?/g,"\n").split("\n")}("string"==typeof n?n:Wi(r.text,r,this._renderPlanHass,e=>this._renderEntityAvailable(e))),h=r.x*e,d=r.y*t,u=Number(r.angle)||0,p=d-(a.length-1)*i*1.2/2;return W`${a.map((e,t)=>W`${e}`)}`}return G});let o=G;const s=this._decorDraft;if(s){const e=this._decorStyle,t=fr(e.widthCm,this._cellCm,this._gridPitch);if("line"===s.kind)o=W``;else{const i=Math.min(s.a[0],s.b[0]),n=Math.min(s.a[1],s.b[1]),r=Math.abs(s.b[0]-s.a[0]),a=Math.abs(s.b[1]-s.a[1]);o="rect"===s.kind?W``:W``}}return W`${r}${o}`}get _editorToolbarGroups(){return"plan"!==this._mode?[]:[{id:"opening",label:this._t("markup.opening"),icon:"mdi:door",activeItemId:"opening"===this._tool?this._openingPreset?.type:void 0,items:[{id:"window",label:this._t("opening.window"),icon:"mdi:window-closed-variant",role:"tool",invoke:()=>this._activateOpeningPlacement("window")},{id:"door",label:this._t("opening.door"),icon:"mdi:door-open",role:"tool",invoke:()=>this._activateOpeningPlacement("door")},{id:"passage",label:this._t("opening.passage"),icon:"mdi:arch",role:"tool",invoke:()=>this._activateOpeningPlacement("passage")},{id:"gate",label:this._t("opening.gate"),icon:"mdi:gate",role:"tool",invoke:()=>this._activateOpeningPlacement("gate")}]}]}_renderEditorGroupLauncher(e){return this._editorRuntimeOrThrow()._renderEditorGroupLauncher(e)}get _editorSecondaryContextId(){const e=`editor:${this._mode}:${this._space}:${this._cfgEpoch}`,t=this._editorSecondary?.activeGroup(this._editorToolbarGroups);if(t)return`${e}:group:${t.id}:${this._editorSecondary?.groupGeneration}`;if("plan"===this._mode){const t=this._physicalSel;return t?`${e}:selection:${t.kind}:${t.id}:${t.segment??""}`:`${e}:tool:${this._tool}:${this._path.length}`}return"decor"===this._mode?"furniture"===this._decorTool?`${e}:palette:furniture:${this._furnPalette?.symbol||"none"}`:"select"===this._decorTool&&this._decorSel?`${e}:selection:decor:${this._decorSel}`:`${e}:tool:${this._decorTool}:${this._bdMoved?1:0}:${this._bdDrag?1:0}`:`${e}:none`}_runEditorContext(e,t){return this._editorRuntimeOrThrow()._runEditorContext(e,t)}_renderEditorGroupModel(e){return this._editorRuntimeOrThrow()._renderEditorGroupModel(e)}_renderDrawWallControl(){return this._editorRuntimeOrThrow()._renderDrawWallControl()}_renderPlanSecondary(){return this._editorRuntimeOrThrow()._renderPlanSecondary()}_renderDecorSecondary(){return this._editorRuntimeOrThrow()._renderDecorSecondary()}_withBackdropReset(e){return this._editorRuntimeOrThrow()._withBackdropReset(e)}get _editorSecondaryDialogBlocked(){return!!(this._tapConfirm||this._vacCalConfirm||this._roomDialog||this._mergeDialog||this._openingDialog||this._physicalDialog||this._openingInfo||this._decorTextDialog||this._decorShapeDialog||this._backdropDialog||this._decorEraseConfirm||this._spaceDialog||this._markerDialog||this._deviceInbox||this._infoCard||this._rulesDialog||this._settingsDialog||this._alignDialog||this._importDialog||this._kioskDialog||this._backupExportDialog||this._backupImportDialog||this._wallDialog)}_renderEditorSecondary(){return this._editorRuntimeOrThrow()._renderEditorSecondary()}_renderDecorBar(){return this._editorRuntimeOrThrow()._renderDecorBar()}_renderDecorEraseConfirm(){return this._editorRuntimeOrThrow()._renderDecorEraseConfirm()}_renderDecorTextDialog(){return this._editorRuntimeOrThrow()._renderDecorTextDialog()}_renderDecorShapeDialog(){return this._editorRuntimeOrThrow()._renderDecorShapeDialog()}_renderBackdropDialog(){return this._editorRuntimeOrThrow()._renderBackdropDialog()}_cssPxToRender(e){return this._editorRuntimeOrThrow()._cssPxToRender(e)}_renderZeroWalls(e){if(e&&!e.showBorders&&!this._editing)return W``;const t=this._zeroWalls();if(!t.lines.length)return W``;const i=e?.color||"var(--hp-muted)";return W` + ${t.lines.map(e=>W``)} + `}_zeroWalls(){const e=this._spaceModel();return e?op(this._curSpaceCfg,e,hm,.02*this._gridPitch):{style:tp(this._curSpaceCfg),lines:[],contour:[],barriers:[],transmissive:[]}}_openCuts(){return this._zeroWalls().contour}_deleteRoomClick(e){return this._editorRuntimeOrThrow()._deleteRoomClick(e)}get _wallKeyPitch(){return Na}get _spaceWalls(){const e=this._curSpaceCfg?.walls;return Array.isArray(e)?e:[]}_cfgOpenCuts(){const e=this._curSpaceCfg,t=this._spaceModel();if(!e||!t)return[];const i=ip(e,1),n=rp(e,t.rooms,hm,.02*this._gridPitch).map(e=>e.map(e=>e/hm)),r=new Set;return[...i,...n].filter(e=>{const t=e.map(e=>Number(e).toFixed(9)).join(","),i=[e[2],e[3],e[0],e[1]].map(e=>Number(e).toFixed(9)).join(","),n=t[e[0]/hm,e[1]/hm,e[2]/hm,e[3]/hm]))}_paperShapes(e){if(!this._spaceWalls.length)return Xt(e);const t=this._wallUnionGeometry();return t?.paperD?[{path:t.paperD}]:Xt(e)}_wallUnionGeometry(){const e=this._spaceModel();if(!e)return null;const t=this._spaceWalls,i=this._physicalBodiesR();if(!t.length&&!i.length)return null;const n=`${this._space}|${this._cfgEpoch}|${e.rooms.length}`;if(!this._wallUnionCache||this._wallUnionCache.key!==n){const r=X_(this._wallUnionPool,n);if(r.hit)this._wallUnionCache=r.value;else{const r=this._openCuts(),o=this._roomWallOpeningInputs(),s=Hs(e.rooms,t,r,o,this._wallKeyPitch,this._cellCm,this._gridPitch,hm,i);s&&Object.defineProperty(s,"sourceFingerprint",{value:Rl([this._curSpaceCfg,this._cellCm,this._gridPitch]),enumerable:!1});const a={key:n,value:s};J_(this._wallUnionPool,n,a,8),this._wallUnionCache=a}}return this._wallUnionCache.value}_thickWallCuts(){const e=this._spaceModel();if(!e)return[];const t=this._spaceWalls;if(!t.length)return[];const i=this._openCuts();return qs(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm).map(e=>[e.a[0],e.a[1],e.b[0],e.b[1]])}_innerRoomContour(e,t,i=this._openCuts(),n=this._wallUnionGeometry()?.roomGeom,r=this._wallUnionGeometry()?.multiWallNodes){const o=i.map(e=>e.join(",")).join(";"),s=`${e.id}|${this._cfgEpoch}|${t}|${o}`,a=X_(this._innerContourCache,s);if(a.hit)return a.value;const l=ks(e.rooms,t,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,hm,n,r);return J_(this._innerContourCache,s,l,600),l}_wallThickHit(e){return this._editorRuntimeOrThrow()._wallThickHit(e)}get _wallThickHover(){if(!this._markup||"wallthick"!==this._tool||!this._cursorPt||this._wallDialog)return null;const e=this._wallThickHit(this._cursorPt);if(!e)return null;const t=function(e,t,i){const n=Number.isFinite(e)&&e>0?e:0,r=Number.isFinite(t)&&t>0?t:5,o=Number.isFinite(i)&&i>0?i:0;return n>0?vo(n,r,o)/2:xa(1.5*o,r)}(e.cm,this._cellCm,this._gridPitch);let i="";for(const n of e.segs)i+=(i?" ":"")+Ko([[n[0],n[1]],[n[2],n[3]]],t,!1);return{segs:e.segs,open:e.open,d:i}}_wallThickClick(e){return this._editorRuntimeOrThrow()._wallThickClick(e)}_wallThickApply(e){return this._editorRuntimeOrThrow()._wallThickApply(e)}_wallHatchDefs(e){const t=_o(this._cellCm);return W` + + + + `}_resolvedRoomFills(e,t){const i=new Map,n=new Map;for(const r of e.rooms){const e=this._roomDialog&&r.id===this._roomEditId?this._roomFill||t.fill:Rn(t.fill,r),o=this._roomDialog&&r.id===this._roomEditId?this._roomCustomFill||t.customFill:en(t.customFill,r),s=an(e,"lqi"===e&&r.area?this._roomLqi(r.area):null,"light"===e?Th(Mh(this._renderPlanHass,this._renderDevices,r,this._virtualLights)):"none","temp"===e?this._roomTemp(r):null,t.tempMin,t.tempMax,this._fillColors,o);i.set(r,s),r.id&&n.set(r.id,s)}return{byRoom:i,byId:n}}_spaceDisplayForRender(){const e=tn(this._curSpaceCfg),t=this._spaceDialog;return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,showBorders:t.showBorders,showNames:t.showNames,hideDecor:t.hideDecor,hideOpenings:t.hideOpenings,color:t.roomColor,opacity:t.roomOpacity,fill:t.fillMode,customFill:t.customFill?Qi(t.customFill):Ji,glow:t.glowEnabled,tempMin:t.tempMin,tempMax:t.tempMax,showLqi:t.showLqi,cardFontScale:t.cardFontScale,labelTemp:t.labelTemp,labelHum:t.labelHum,labelLqi:t.labelLqi,labelLight:t.labelLight}:e}_openingWallIndexFor(e,t){const i=e.rooms.map(e=>`${e.id}:${e.poly?.map(e=>e.join(",")).join("/")||`${e.x},${e.y},${e.w},${e.h}`}`).join(";"),n=this._spaceWalls.map(e=>`${e.key}:${e.a?.join(",")||""}:${e.b?.join(",")||""}:${e.cm}`).join(";"),r=t.map(e=>e.join(",")).join(";"),o=[e.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,n,r].join("|");let s=this._openingWallIndexCache.get(o);return s||(s=Bs(e.rooms,this._spaceWalls,t,this._wallKeyPitch,this._cellCm,this._gridPitch,hm)),J_(this._openingWallIndexCache,o,s,4),{key:o,value:s}}_renderOpeningTunnelFills(e,t,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return W``;if("glow-base"===i&&![...t.byRoom.values()].some(Boolean))return W``;const n=this._openCuts(),r=this._openingsR.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),o=r.map(e=>`${e.x},${e.y},${e.angle},${e.length}`).join(";"),s=this._openingWallIndexFor(e,n),a=`${s.key}|${o}`;return this._openingTunnelCache&&this._openingTunnelCache.key===a||(this._openingTunnelCache={key:a,value:Zs(s.value,r)}),Wu({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:t.byId,idPrefix:`${e.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(e,t,i){const n=new Map,r=new Map,o=this._fillColors.glow_base;for(const s of e.rooms){const e=i.byRoom.get(s),a=Tn(t.glow,s)&&(!e||e.opacity<=0)?{color:o.c,opacity:o.a,mode:"glow"}:null;n.set(s,a),s.id&&r.set(s.id,a)}return{byRoom:n,byId:r}}_renderGlowBaseRooms(e,t){if(this._markup||![...t.byRoom.values()].some(Boolean))return W``;const i=new Map(e.rooms.map(e=>[e,Zt(e)])),n=this._openCuts(),r=this._wallUnionGeometry()?.roomGeom,o=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z",s=e.rooms.map(s=>{const a=t.byRoom.get(s)||null,l=i.get(s)||null;if(!a||!l)return G;const c=this._spaceWalls.length&&s.id&&this._innerRoomContour(e,s.id,n,r)||l,h=vi(c,e.rooms.filter(e=>e!==s).map(e=>i.get(e)).filter(e=>!!e)),d=this._cleanFloor(s,c,e).path;return d||h.length?W``:s.poly||c!==l?W``:W``});return W``}_renderWallBodies(e){if("iso"===this._renderProjection)return W``;if(e&&!e.showBorders&&("view"===this._mode||"devices"===this._mode))return W``;const t=this._wallUnionGeometry();if(!t)return W``;const i=this._stageEl,n=this._viewOr(this._baseVb()),r=i&&i.clientWidth&&n.w?i.clientWidth/n.w:1,o=e?.color||"#607d8b",s=po(t.depthUnits,r)||mo(_o(this._cellCm),r),a=this._fillColors.wall_fill;return W` + ${t.paths.map(e=>W` + + `)} + `}_isoDecorationLayers(e){const t="undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("filter","blur(1px)"),i="function"==typeof matchMedia&&matchMedia("(forced-colors: active)").matches;return function(e){const t=!!e.showBorders;return{structural:t,panels:t&&!e.hideOpenings,shadows:t&&e.filtersSupported&&!e.forcedColors,materialNuance:t&&!e.forcedColors,floorSymbols:!e.hideOpenings&&!t}}({showBorders:e.showBorders,hideOpenings:e.hideOpenings,filtersSupported:t,forcedColors:i})}_isoOpeningPanels(e){if(!e.panels)return[];const t=this._isoScene();if(!t)return[];return t.openings.flatMap(e=>{const t=this._openingsR[e.sourceIndex];return t?E_(e,this._openingAmt(t)):[]}).sort((e,t)=>e.depth-t.depth||e.sourceIndex-t.sourceIndex||e.leaf-t.leaf)}_renderIsoDefs(e,t){const i=ka(this._cellCm);return W` + ${"walls"===t&&e.materialNuance?W` + + + + + + `:G} + ${"underlay"===t&&e.shadows?W` + + + `:G} + ${"shadows"===t&&e.shadows?W` + + + + + + `:G} + `}_renderIsoUnderlay(e){if(!e.structural)return W``;const t=this._isoScene()?.floor;return t?W``:W``}_renderIsoShadows(e,t){if(!e.shadows)return W``;const i=this._isoScene()?.geometry;return i?W``:W``}_renderIsoWalls(e,t){if("iso"!==this._renderProjection)return W``;if(!e.structural)return W``;const i=this._isoScene();return i?W` + ${this._renderIsoDefs(e,"walls")} + ${i.geometry.sides.map(e=>W``)} + + ${e.panels?W``:G} + `:W``}_roomHoverPaths(e){const t=this._hoverRoom;if("view"!==this._mode||!t||t.space!==e.id)return null;const i=e.rooms.find(e=>e===t.room||!!e.id&&e.id===t.room.id);if(!i)return null;const n=Zt(i);if(!n)return null;const r=e.rooms.filter(e=>e!==i).map(e=>({room:e,poly:Zt(e)})).filter(e=>!!e.poly),o=vi(n,r.map(e=>e.poly)),s=this._openCuts(),a=.02*this._gridPitch,l=s.filter(e=>{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return n.some((e,i)=>Pn(t,[e[0],e[1],...n[(i+1)%n.length]])<=4*a)}),c=this._spaceWalls,h=this._wallUnionGeometry()?.roomGeom,d=c.length&&i.id&&this._innerRoomContour(e,i.id,s,h)||n,u=[{axis:n,face:d}];for(const t of o){const i=r.find(e=>e.poly===t)?.room;let n=t;if(c.length&&i?.id){const r=ms(e.rooms,i.id,c,s,this._wallKeyPitch,this._cellCm,this._gridPitch,hm);r&&(n=js(r.poly,r.offsets)||t)}u.push({axis:t,face:n})}const p=this._roomWallOpeningInputs(this._openingsR,e).map(e=>{const t=e.angle*Math.PI/180,i=Math.cos(t)*e.length/2,n=Math.sin(t)*e.length/2;return[e.x-i,e.y-n,e.x+i,e.y+n]}),_=l.concat(p),m=u.map(({axis:e,face:t})=>{const i=_.map(i=>((e,t,i)=>{const n=e[2]-e[0],r=e[3]-e[1],o=Math.hypot(n,r);if(o.05)&&Pn([c,h],[i[0],i[1],n[0],n[1]])<=4*a){d=!0;break}}if(!d)return null;let u=null;for(let e=0;e.05)continue;const p=Pn([c,h],[t[0],t[1],n[0],n[1]]);(!u||p!!e);return i.length?kn(t,i,a).map(e=>`M ${e[0]} ${e[1]} L ${e[2]} ${e[3]}`).join(" "):`M ${t.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return null;const g=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;return{fillD:[this._cleanFloor(i,d,e).path||g(d),...o.map(g)].join(" "),outlineD:m}}_renderRoomHoverFill(e){return e?W` + + `:W``}_renderRoomHoverOutline(e){return e?W` + + + `:W``}_renderWallThickUi(){return this._editorRuntime?this._editorRuntimeOrThrow()._renderWallThickUi():W``}_renderWallThickDialog(){return this._editorRuntimeOrThrow()._renderWallThickDialog()}_openingAt(e){return this._editorRuntimeOrThrow()._openingAt(e)}_resolveOpeningPlacement(e){return this._editorRuntimeOrThrow()._resolveOpeningPlacement(e)}_activateOpeningPlacement(e){return this._editorRuntimeOrThrow()._activateOpeningPlacement(e)}_clearOpeningPlacement(e){return this._editorRuntime?this._editorRuntimeOrThrow()._clearOpeningPlacement(e):(this._openingHoverCandidate=null,this._openingJambBlockCm=null,void(e&&(this._openingPreset=null,this._openingRebindId=null)))}_openingClick(e){return this._editorRuntimeOrThrow()._openingClick(e)}_editOpening(e){if(this._editorRuntime)return this._editorRuntimeOrThrow()._editOpening(e)}_opPointerDown(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerDown(e,t)}_opPointerMove(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerMove(e,t)}_opRuler(e,t){return this._editorRuntimeOrThrow()._opRuler(e,t)}_opPointerUp(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerUp(e,t)}_opClick(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opClick(e,t)}_saveOpening(){return this._editorRuntimeOrThrow()._saveOpening()}_deleteOpening(){return this._editorRuntimeOrThrow()._deleteOpening()}_contactCandidates(){return this._editorRuntimeOrThrow()._contactCandidates()}_lockCandidates(){return this._editorRuntimeOrThrow()._lockCandidates()}_toggleOpeningEntityPicker(e){return this._editorRuntimeOrThrow()._toggleOpeningEntityPicker(e)}_filterOpeningEntities(e,t){return this._editorRuntimeOrThrow()._filterOpeningEntities(e,t)}_selectOpeningEntity(e,t){return this._editorRuntimeOrThrow()._selectOpeningEntity(e,t)}_mergeClick(e){return this._editorRuntimeOrThrow()._mergeClick(e)}_commitMerge(){return this._editorRuntimeOrThrow()._commitMerge()}_splitClick(e){return this._editorRuntimeOrThrow()._splitClick(e)}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])&&(null!=this._closingWallCm||!this._activeDraftId)}_markupMove(e){if(this._markup&&this._editorRuntime)return this._editorRuntime._markupMove(e)}get _openingPreview(){const e=this._openingPreset;if("opening"!==this._tool||!e||!this._cursorPt)return null;const t=this._cursorPt,i=this._openingHoverCandidate;if(i&&G_(i,[t[0],t[1]],e.revision,this._cfgEpoch))return i;if(this._openingAt(t))return this._openingHoverCandidate=null,null;const n=this._resolveOpeningPlacement(t);return this._openingHoverCandidate=n,n}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){return this._editorRuntimeOrThrow()._saveRoom()}_decideWallFace(e){return this._editorRuntimeOrThrow()._decideWallFace(e)}_wallSourceCmAt(e,t,i){return this._editorRuntimeOrThrow()._wallSourceCmAt(e,t,i)}_activePathWithRepair(e,t){return this._editorRuntimeOrThrow()._activePathWithRepair(e,t)}_validateWallRepair(e,t){return this._editorRuntimeOrThrow()._validateWallRepair(e,t)}_applyWallRepair(e,t){return this._editorRuntimeOrThrow()._applyWallRepair(e,t)}_applyWallFaceBatch(){return this._editorRuntimeOrThrow()._applyWallFaceBatch()}_commitRoom(){return this._editorRuntimeOrThrow()._commitRoom()}_cancelPath(){return this._editorRuntimeOrThrow()._cancelPath()}_resumeLastDraft(){return this._editorRuntimeOrThrow()._resumeLastDraft()}_roomDialogCancel(){return this._editorRuntimeOrThrow()._roomDialogCancel()}get _freeAreas(){const e=new Set;for(const t of this._serverCfg?.spaces||[])for(const i of t.rooms||[])i.area&&e.add(i.area);for(const t of this._wallFaceBatch?.decisions||[])t.create&&t.area&&e.add(t.area);return Object.values(this.hass?.areas||{}).filter(t=>!e.has(t.area_id)).sort((e,t)=>(e.name||"").localeCompare(t.name||""))}_openDeviceInbox(){return this._editorRuntimeOrThrow()._openDeviceInbox()}_closeMarkerDialog(){return this._editorRuntimeOrThrow()._closeMarkerDialog()}_deviceInboxCandidates(e){return this._editorRuntimeOrThrow()._deviceInboxCandidates(e)}_deviceInboxRows(){return this._editorRuntimeOrThrow()._deviceInboxRows()}_deviceForInboxRow(e){return this._editorRuntimeOrThrow()._deviceForInboxRow(e)}_openInboxMarker(e,t=!1){return this._editorRuntimeOrThrow()._openInboxMarker(e,t)}async _setInboxHidden(e,t){return this._editorRuntimeOrThrow()._setInboxHidden(e,t)}_findInboxDevice(e){return this._editorRuntimeOrThrow()._findInboxDevice(e)}_deviceInboxTabKey(e){return this._editorRuntimeOrThrow()._deviceInboxTabKey(e)}_openMarkerDialog(e){if(this._editorRuntime)return this._editorRuntime._openMarkerDialog(e);this._ensureEditorRuntime().then(t=>{t&&this._openMarkerDialog(e)})}_runCandidates(){return this._editorRuntimeOrThrow()._runCandidates()}_bindingCandidates(){return this._editorRuntimeOrThrow()._bindingCandidates()}_physicalBodiesR(e=this._spaceModel()){if(!e)return[];const t=`${e.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===t)return this._physicalBodiesCache.all;const i=ca(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e));return this._physicalBodiesCache={key:t,...i},i.all}_rawPhysicalBodiesR(e=this._spaceModel()){if(!e)return[];this._physicalBodiesR(e);const t=this._physicalBodiesCache;return t?[...t.drafts,...t.partitions,...t.columns]:[]}_cleanFloor(e,t,i=this._spaceModel()){if(!i)return{floor:t,geom:null,path:"",area:ma([[[...t,t[0]]]])};const n=e.id||`#${i.rooms.indexOf(e)}`,r=`${i.id}|${this._cfgEpoch}|${n}`;if(!this._resize?.preview){const e=X_(this._cleanFloorCache,r);if(e.hit)return e.value}const o=t.map(e=>e[0]),s=t.map(e=>e[1]),a=[Math.min(...o),Math.min(...s),Math.max(...o),Math.max(...s)],l=this._physicalBodiesR(i).filter(e=>{const t=e.map(e=>e[0]),i=e.map(e=>e[1]);return Math.max(...t)>=a[0]&&Math.min(...t)<=a[2]&&Math.max(...i)>=a[1]&&Math.min(...i)<=a[3]}),c=l.length?_a(t,l):null,h={floor:t,geom:c,path:c?ra(c):"",area:ma(c||[[[...t,t[0]]]])};return this._resize?.preview||J_(this._cleanFloorCache,r,h,600),h}_autoIconForBinding(e){if("virtual"===e)return"mdi:map-marker";const[t,i]=e.split(":");if(!i)return"";const n=this._fullRegistryHass,r=this._bindingStatus(e),o="active"===r.kind?r.enabledEntityIds:r.allEntityIds;if("device"===t){const e=n.devices?.[i];if(!e)return"mdi:help-circle";const t=o;return t.some(e=>e.startsWith("lock."))?"mdi:lock":Fh(n,e.name_by_user||e.name||"",e.model,t,this._iconRules)}if("entity"===t){const e=n.entities?.[i],t=this.hass.states?.[i],r=e?.name||t?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":Fh(n,r,"",[i],this._iconRules)}return""}_allRoomsFlat(){const e=[];for(const t of this._serverCfg?.spaces||[])for(const i of t.rooms||[])i.area?e.push({value:t.id+"#"+i.area,label:(t.title||t.id)+" · "+i.name}):i.id&&e.push({value:t.id+"#@"+i.id,label:(t.title||t.id)+" · "+i.name+" · "+this._t("marker.subarea")});return e}_errText(e){if(!e)return this._t("err.unknown");if("string"==typeof e)return e;if("invalid_passage_fields"===e.code){const t=String(e.message||e.error||"").match(/space=([^;]*);\s*opening=([^;]*);\s*fields=([^;]*)/);if(t){const e=this._serverCfg?.spaces?.find(e=>String(e.id)===t[1]),i={contact:"opening.contact_label",lock:"opening.lock_label",invert:"opening.invert",flip_h:"opening.flip_h",flip_v:"opening.flip_v"},n=t[3].split(",").filter(Boolean).map(e=>i[e]?this._t(i[e]):e).join(", ");return this._t("opening.invalid_passage_fields",{room:e?.title||t[1],fields:n})}}if("invalid_partition_opening_jamb_margin"===e.code){const t=String(e.message||e.error||"").match(/margin_cm=([^;]*)/),i=t?Number(t[1]):NaN;if(Number.isFinite(i))return this._t("opening.partition_jamb_margin",{distance:Kt(i,this._imperial)})}if(e.message)return e.message;if(e.error)return e.error;if(null!=e.code)return this._t("err.code",{code:e.code});try{return JSON.stringify(e)}catch{return String(e)}}_backupErrorText(e){return this._editorRuntimeOrThrow()._backupErrorText(e)}async _pickMarkerFiles(e){return this._editorRuntimeOrThrow()._pickMarkerFiles(e)}_removeMarkerPdf(e){return this._editorRuntimeOrThrow()._removeMarkerPdf(e)}_markerLightFields(e){return this._editorRuntimeOrThrow()._markerLightFields(e)}_markerTapActionFields(e){return this._editorRuntimeOrThrow()._markerTapActionFields(e)}_markerToggleEntityFields(e){return this._editorRuntimeOrThrow()._markerToggleEntityFields(e)}async _saveMarker(){return this._editorRuntimeOrThrow()._saveMarker()}async _deleteMarker(){return this._editorRuntimeOrThrow()._deleteMarker()}_normPos(e,t,i){return{s:e,x:t/hm,y:i/hm}}_spaceDialogUsesOnboardingRuntime(e){return"create"===e&&!this._editorRuntime&&(!!this._onboardingRuntime||0===(this._serverCfg?.spaces.length||0)||this._importTotal>0||this._importQueue.length>0)}_spaceRuntimeOrThrow(){if(!this._onboardingRuntime)throw new Error("Houseplan onboarding runtime is not loaded");return this._onboardingRuntime}_openSpaceDialog(e,t){return this._spaceDialogUsesOnboardingRuntime(e)?this._onboardingRuntime?void this._onboardingRuntime._openSpaceDialog(e,t):void this._ensureOnboardingRuntime().then(i=>{i&&this._spaceRuntimeOrThrow()._openSpaceDialog(e,t)}):this._editorRuntime?this._editorRuntime._openSpaceDialog(e,t):void this._ensureEditorRuntime().then(i=>{i&&this._openSpaceDialog(e,t)})}async _pickPlanFile(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._pickPlanFile(e):this._editorRuntimeOrThrow()._pickPlanFile(e)}_useServerPlan(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._useServerPlan(e):this._editorRuntimeOrThrow()._useServerPlan(e)}async _readPlanAspect(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._readPlanAspect(e):this._editorRuntimeOrThrow()._readPlanAspect(e)}async _deleteServerPlan(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._deleteServerPlan(e):this._editorRuntimeOrThrow()._deleteServerPlan(e)}_renderServerPlans(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime(e.mode)?this._onboardingRuntime._renderServerPlans(e):this._editorRuntimeOrThrow()._renderServerPlans(e)}async _saveSpaceDialog(){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._saveSpaceDialog():this._editorRuntimeOrThrow()._saveSpaceDialog()}async _deleteSpace(){return this._editorRuntimeOrThrow()._deleteSpace()}async _saveConfigNow(){return this._editorRuntimeOrThrow()._saveConfigNow()}_startImport(){return this._onboardingRuntime?this._onboardingRuntime._startImport():this._editorRuntimeOrThrow()._startImport()}_openNextImport(){return this._onboardingRuntime?this._onboardingRuntime._openNextImport():this._editorRuntimeOrThrow()._openNextImport()}_skipImport(){return this._onboardingRuntime?this._onboardingRuntime._skipImport():this._editorRuntimeOrThrow()._skipImport()}_renderImportDialog(){return this._onboardingRuntime?this._onboardingRuntime._renderImportDialog():this._editorRuntimeOrThrow()._renderImportDialog()}_sunGlobal(){const e=this._settingsDialog;return e?{...this._settings,north_deg:e.northDeg??void 0,bg_mode:e.bgMode,sun_rays:e.sunRays}:this._settings}_sunSpace(){const e=this._spaceDialog,t=this._curSpaceCfg?.settings||{};return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,north_deg:e.northDeg??void 0,bg_mode:e.bgMode??void 0,sun_rays:e.sunRays??void 0}:t}_effNorth(){return or(this._sunGlobal(),this._sunSpace())}_effBgMode(){return sr(this._sunGlobal(),this._sunSpace())}_dayCycleState(e=new Date){return(this._modeTransitionVisual?.viewWeight??("view"===this._mode?1:0))<=0||"daynight"!==this._effBgMode()?null:Yn(this._renderPlanHass,e)}_syncDayCycleClock(){const e=this._dayCycleState();this._dayCycleClockKey=e?Zn(e):"";const t="clock"===e?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;t&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!t&&this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(e){"hidden"!==e.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_effSunRays(){return ar(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?lr(this._renderPlanHass):null}_renderSunRays(e){const t=W``,i=this._modeTransitionVisual?.viewWeight??0;if(this._editing&&i<=0||!this._effSunRays())return this._sunFadeReset(),t;const n=this._effNorth(),r=null!==n?lr(this._renderPlanHass):null;if(!r||r.elevation<=0)return this._sunFadeReset(),t;if(o=r.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return t;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const s=this._zeroWalls(),a=s.barriers.map(e=>e.join(",")).join(";"),l=`${e.id}|${r.azimuth}|${r.elevation}|${n}|${this._cfgEpoch}|${s.style}|${a}`;if(!this._sunRaysCache||this._sunRaysCache.key!==l){const t=e.rooms.map(e=>({id:e.id||"",poly:Zt(e)})).filter(e=>!!e.id&&!!e.poly),i=this._openingsR.filter(e=>"window"===e.type&&"partition"!==e.host?.kind).map(e=>({id:e.id,x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),o=this._spaceWalls,a=this._openCuts(),c=this._openingWallIndexFor(e,a).value,h={},d={},u=this._wallUnionGeometry()?.roomGeom;if(o.length){for(const i of t){const t=this._innerRoomContour(e,i.id,a,u);t&&(h[i.id]=t)}for(const e of i){const t=Vs(c,{x:e.x,y:e.y,angle:e.angle,length:e.length});t.cm>0&&(d[e.id]=vo(t.cm,this._cellCm,this._gridPitch))}}let p=nr(t,i,r.azimuth,r.elevation,n,o.length?h:void 0,o.length?d:void 0);const _=[...this._physicalBodiesR(e),...s.barriers.map(e=>[[e[0],e[1]],[e[2],e[3]]])];_.length&&(p=p.map(e=>{const t=function(e,t,i){return i>0?e.map(e=>function(e){const t=[...e].sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(t.length<=2)return t;const i=(e,t,i)=>(t[0]-e[0])*(i[1]-e[1])-(t[1]-e[1])*(i[0]-e[0]),n=[];for(const e of t){for(;n.length>=2&&i(n[n.length-2],n[n.length-1],e)<=0;)n.pop();n.push(e)}const r=[];for(let e=t.length-1;e>=0;e--){const n=t[e];for(;r.length>=2&&i(r[r.length-2],r[r.length-1],n)<=0;)r.pop();r.push(n)}return n.slice(0,-1).concat(r.slice(0,-1))}([...e,...e.map(e=>[e[0]+t[0]*i,e[1]+t[1]*i])])).filter(e=>e.length>=3):e}(_,e.dir,e.len),i=e.polys.map(e=>_a(e,t));return{...e,paths:i.map(ra).filter(Boolean),polys:i.flatMap(fa)}}).filter(e=>e.paths?.length||e.polys.length)),this._sunRaysCache={key:l,rays:p,rims:p.map(e=>function(e,t=1e-4){const[i,n]=e.dir,r=-n,o=i,s=[];for(const a of[e.a,e.b]){const l=[];for(const s of e.polys)for(let e=0;et)continue;if(Math.abs((h[0]-a[0])*r+(h[1]-a[1])*o)>t)continue;const d=(c[0]-a[0])*i+(c[1]-a[1])*n,u=(h[0]-a[0])*i+(h[1]-a[1])*n;Math.abs(u-d)<=t||l.push(de[0]-t[0]);const c=[];for(const e of l){const i=c[c.length-1];i&&e[0]<=i[1]+t?i[1]=Math.max(i[1],e[1]):c.push([e[0],e[1]])}for(const[e,t]of c)s.push([[a[0]+i*e,a[1]+n*e],[a[0]+i*t,a[1]+n*t]])}return s}(e))}}const c=this._sunRaysCache.rays,h=this._sunRaysCache.rims;if(!c.length)return t;const d=(u=function(e){const t=Math.min(90,Math.max(-90,Number(e)||0));let i=Xn[Xn.length-1][1];for(let e=1;e + ${c.map((e,t)=>{const i=(e.a[0]+e.b[0])/2,n=(e.a[1]+e.b[1])/2,r=i+e.normal[0]*e.depth,o=n+e.normal[1]*e.depth;return W` + ${p.map(([e,t])=>W``)} + + + ${_.map(([e,t])=>W``)} + `})} + + + ${c.map((e,t)=>e.paths?.length?e.paths.map(e=>W``):e.polys.map(e=>W``))} + ${c.map((e,t)=>(h[t]||[]).map(e=>W``))} + `}_sunFadeReset(){this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunShown=!1,this._sunOut=!1}_compassPoint(e){const t=e.currentTarget.getBoundingClientRect(),i=e.clientX-(t.left+t.width/2),n=e.clientY-(t.top+t.height/2);if(Math.hypot(i,n)<5)return;let r=Math.round(180*Math.atan2(i,-n)/Math.PI);e.shiftKey&&(r=15*Math.round(r/15)),r=(r%360+360)%360,this._settingsDialog={...this._settingsDialog,northDeg:r}}_renderCompass(){const e=this._settingsDialog.northDeg;return B`{e.currentTarget.setPointerCapture(e.pointerId),this._compassDrag=!0,this._compassPoint(e)}} + @pointermove=${e=>{this._compassDrag&&this._compassPoint(e)}} + @pointerup=${()=>this._compassDrag=!1} + @pointercancel=${()=>this._compassDrag=!1}> + + ${[0,45,90,135,180,225,270,315].map(e=>W``)} + + + + ${this._t("gs.north_letter")} + + ${null===e?"—":e+"°"} + `}_stageBg(e){const t=this._settingsDialog,i=this._spaceDialog,n=t?t.bgColor||"":nn(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":e.bgColor||"")||n}_stageBgHex(){const e=this._stageEl;if(e){const t=getComputedStyle(e).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(t)return"#"+t.slice(1,4).map(e=>(+e).toString(16).padStart(2,"0")).join("")}return"#111111"}_preflightDiagnostics(e,t){return this._editorRuntimeOrThrow()._preflightDiagnostics(e,t)}_reportPreflightFailure(e,t){return this._editorRuntimeOrThrow()._reportPreflightFailure(e,t)}_preflightVersionsDiffer(){return this._editorRuntimeOrThrow()._preflightVersionsDiffer()}async _copyPreflightDiagnostics(){return this._editorRuntimeOrThrow()._copyPreflightDiagnostics()}_checkOptimizeGeometry(e){return this._editorRuntimeOrThrow()._checkOptimizeGeometryImpl(e)}_checkSpacePhysicalGeometry(e,t,i){return this._editorRuntimeOrThrow()._checkSpacePhysicalGeometryImpl(e,t,i)}_optimizeReferenceContext(e){return this._editorRuntimeOrThrow()._optimizeReferenceContext(e)}_previewAlignDialog(e){return this._editorRuntimeOrThrow()._previewAlignDialog(e)}async _runAlignToGrid(){return this._editorRuntimeOrThrow()._runAlignToGrid()}async _undoPlanOptimization(){return this._editorRuntimeOrThrow()._undoPlanOptimization()}async _runBackupExport(){return this._editorRuntimeOrThrow()._runBackupExport()}async _pickBackupImport(e){return this._editorRuntimeOrThrow()._pickBackupImport(e)}async _setBackupDuplicatePolicy(e){return this._editorRuntimeOrThrow()._setBackupDuplicatePolicy(e)}async _applyBackupImport(){return this._editorRuntimeOrThrow()._applyBackupImport()}_renderBackupExportDialog(){return this._editorRuntimeOrThrow()._renderBackupExportDialog()}_renderBackupImportDialog(){return this._editorRuntimeOrThrow()._renderBackupImportDialog()}_setFillColor(e,t){return this._editorRuntimeOrThrow()._setFillColor(e,t)}async _saveSettingsDialog(){return this._editorRuntimeOrThrow()._saveSettingsDialog()}_boolInput(e,t,i=!1){return this._editorRuntimeOrThrow()._boolInput(e,t,i)}_rangeInput(e,t,i,n,r,o=!1,s){return this._editorRuntimeOrThrow()._rangeInput(e,t,i,n,r,o,s)}_renderColorRow(e,t){return this._editorRuntimeOrThrow()._renderColorRow(e,t)}get _glowRadiusCm(){const e=Number(this._settings.glow_radius_cm);return Number.isFinite(e)&&e>0?e:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const e=this._glowRadiusCm;return this._imperial?String(Math.round(e/30.48*10)/10):String(e/100)}_glowTransition(e,t){let i=this._glowRenderedSources.get(e);if(t){const t=this._glowFadeTimers.get(e);if(null!=t&&(clearTimeout(t),this._glowFadeTimers.delete(e)),null==i){this._suspendGlowFeatherForTransition(),i=++this._glowSourceSeq,this._glowRenderedSources.set(e,i),this._glowEnteringSources.add(e);const t=requestAnimationFrame(()=>{this._glowEnterRafs.get(e)===t&&(this._glowEnterRafs.delete(e),this._glowEnteringSources.delete(e),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(e,t)}return{domId:i,entering:this._glowEnteringSources.has(e),leaving:!1}}if(null==i)return null;const n=this._glowEnterRafs.get(e);if(null!=n&&cancelAnimationFrame(n),this._glowEnterRafs.delete(e),this._glowEnteringSources.delete(e),!this._glowFadeTimers.has(e)){this._suspendGlowFeatherForTransition();const t=window.setTimeout(()=>{this._glowFadeTimers.get(e)===t&&(this._glowFadeTimers.delete(e),this._glowRenderedSources.delete(e),this._glowLastAppearance.delete(e),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(e,t)}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 e=Math.max(0,this._glowFeatherSuspendUntil-Date.now())+17,t=()=>{this._glowFeatherResumeTimer=0,Date.now()=128){const e=this._glowGeometryWarnings.values().next().value;e&&this._glowGeometryWarnings.delete(e)}this._glowGeometryWarnings.add(r),console.warn(`HOUSEPLAN GLOW GEOMETRY FALLBACK: #218, space ${e}, room ${i}, phase ${n}`)}}_lightBarriers(e,t){const i=Rl([this._curSpaceCfg,this._cellCm,this._gridPitch]),n=`${e.id}|${i}`,r=X_(this._lightBarrierPool,n);if(r.hit)return this._lightBarrierCache=r.value,r.value.value;const o=this._zeroWalls(),s=this._openCuts(),a=[...o.transmissive],l=Math.max(this._cmToUnits(10),.5*this._gridPitch),c=e=>t.some(t=>this._pointInRoom(e,t.r)),h=this._openingsR.filter(e=>{if("door"!==(t=String(e.type))&&"gate"!==t&&"passage"!==t)return!1;var t;const i=e.angle*Math.PI/180,n=-Math.sin(i),r=Math.cos(i);return c([e.rx+n*l,e.ry+r*l])&&c([e.rx-n*l,e.ry-r*l])}),d=this._roomWallOpeningInputs(h,e);for(const e of d){const t=e.angle*Math.PI/180,i=Math.cos(t)*e.length/2,n=Math.sin(t)*e.length/2;a.push([e.x-i,e.y-n,e.x+i,e.y+n])}const u=new Set(h.filter(e=>e.partitionHost).map(e=>e.id)),p=[e.id,this._cfgEpoch,this._cellCm,this._gridPitch,[...u].sort().join(",")].join("|");this._lightPhysicalBodiesCache?.key!==p&&(this._lightPhysicalBodiesCache={key:p,all:ca(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e,e=>u.has(e.id))).all});const _=this._lightPhysicalBodiesCache.all,m=this._spaceWalls,g=.02*this._gridPitch,f=[],v=this._wallUnionGeometry(),y=v?.sourceFingerprint,b=v&&y===i?function(e,t=[],i=[],n={}){if("failed-core"===e.status||"not-applicable"===e.status)return null;const r=e.roomComponents?.length?e.roomComponents:$s(e.roomGeom)?[{id:"room-primary",geom:e.roomGeom}]:[];let o=r[0]?.geom||null;const s=r.slice(1).map(e=>({...e}));try{for(const i of t){if(!(i.length>0&&e.openingIndex))continue;const t=Gs(e.openingIndex,i,!0);if(!t.negative&&!t.positive)continue;const n=i.angle*Math.PI/180,r=Math.cos(n),a=Math.sin(n),l=-a,c=r,h=i.length/2,d=e.openingPadUnits??1.25*Math.max(e.depthUnits,1),u=xs([[i.x-r*h-l*d,i.y-a*h-c*d],[i.x+r*h-l*d,i.y+a*h-c*d],[i.x+r*h+l*d,i.y+a*h+c*d],[i.x-r*h+l*d,i.y-a*h+c*d]]);o&&(o=Ht(o,u));for(const e of s)e.geom=Ht(e.geom,u)}const r=[...s];let a=s.length;const l=n.mergeExtra||((e,t)=>e?Et(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(yi(t))<=1e-9){a++;continue}const n=[xs(t)];try{const t=l(o,n,e);if(!$s(t))throw new Error("invalid extra union");o=t}catch{a++,$s(n)&&r.push({id:`policy-extra-${e}`,geom:n})}}r.sort((e,t)=>Fs(e.geom).localeCompare(Fs(t.geom)));const c=o||[];return{status:a?"degraded-extra":"ok",geom:c,components:[...$s(c)?[{id:"primary",geom:c}]:[],...r.map((e,t)=>({...e,id:`isolated-${t}`}))]}}catch{return null}}(v,d,_):null,w=b||(m.length||_.length?Ns(e.rooms,m,s,d,this._wallKeyPitch,this._cellCm,this._gridPitch,hm,_):null);if(!w||"ok"!==w.status&&"degraded-extra"!==w.status)for(const e of _)f.push(...Hd(e));else for(const e of w.components)for(const t of ga(e.geom))f.push(...Hd(t));for(const{poly:e}of t)for(const t of a.length?kn(e,a,g):Hd(e))f.push(t);for(const e of o.barriers)f.push(e);const k={occluders:Nd(f),floor:t.map(e=>e.poly),fingerprint:i,masonryGeometry:!w||"ok"!==w.status&&"degraded-extra"!==w.status?[]:w.components.flatMap(e=>e.geom),opaqueBodies:_},x={key:n,value:k};return J_(this._lightBarrierPool,n,x,8),this._lightBarrierCache=x,k}_renderGlowLayer(e,t){const i=this._fillColors,n=this._glowRadiusCm/this._cellCm*this._gridPitch,r=e.rooms.map(e=>({r:e,poly:Zt(e)})).filter(e=>!!e.poly),o=r.filter(({r:e})=>Tn(t.glow,e));if(!o.length)return this._forgetGlowSpace(e.id),W``;const{occluders:s,floor:a,fingerprint:l,masonryGeometry:c,opaqueBodies:h}=this._lightBarriers(e,r),d=Mh(this._renderPlanHass,this._renderDevices,null,this._virtualLights).filter(t=>t.device.space===e.id),u=new Map;for(const e of d){if(!e.device.id)continue;const t=u.get(e.device.id)||[];t.push(e),u.set(e.device.id,t)}const p=[],_=new Set;for(const t of this._renderDevices){if(t.space!==e.id)continue;const o=Rh(u.get(t.id)||[]);if(!o)continue;const d=`${e.id}|${t.id}`;_.add(d);const m=fn(o.passive?{state:o.on?"on":"off",attributes:{}}:this._renderPlanHass.states[o.eid],t.marker?.glow_color,i.glow_light.c),g=Number(t.marker?.glow_radius_cm),f=Number.isFinite(g)&&g>0?g/this._cellCm*this._gridPitch:n,v=this._pos(t);if(ya([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:vn(m.bri,i.glow_light.a)});const b=this._glowLastAppearance.get(d);if(!b)continue;let w=null;const k=`${e.id}|${l}|${v.x.toFixed(4)},${v.y.toFixed(4)}|${f.toFixed(4)}`,x=X_(this._glowClipCache,k);if(x.hit)w=x.value;else{const t=jd([v.x,v.y],f,s,96);w={lit:t.length>=3?pa([t],a,{onBoundsFailure:({boundIndex:t,phase:i})=>{const n=r[t]?.r;this._warnGlowGeometryFallback(e.id,l,n?.id||`#${t}`,i)}}):[]},J_(this._glowClipCache,k,w,256)}p.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=`${e.id}|`;for(const e of this._glowRenderedSources.keys())e.startsWith(m)&&!_.has(e)&&this._forgetGlowSource(e);if(!p.length)return W``;const g=this._spaceWalls,f=o.length===r.length?[]:this._openCuts(),v=this._wallUnionGeometry()?.roomGeom,y=o.length===r.length?null:o.map(({r:t,poly:i})=>{const n=g.length&&t.id&&this._innerRoomContour(e,t.id,f,v)||i,o=this._cleanFloor(t,n,e).path,s=vi(n,r.filter(e=>e.r!==t).map(e=>e.poly)),a=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z";return[o||a(n),...s.map(a)].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=p.reduce((e,t)=>({x:Math.min(e.x,t.pos.x-t.r-S),y:Math.min(e.y,t.pos.y-t.r-S),maxX:Math.max(e.maxX,t.pos.x+t.r+S),maxY:Math.max(e.maxY,t.pos.y+t.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,W` + ${$e(p,e=>e.key,e=>{const t=e.domId,i=e.geometry;return W` + ${""} + + ${dm.map(([t,i])=>W` + `)} + + ${""} + ${i?W` + + + `:G}`})} + ${y?W`${y.map(e=>W``)}`:G} + ${""} + + + + + ${""} + + + ${$e(p,e=>e.key,e=>{const t=e.domId;return W` + + + `})} + + `}_renderAlignDialog(){return this._editorRuntimeOrThrow()._renderAlignDialog()}_renderSettingsDialog(){return this._editorRuntimeOrThrow()._renderSettingsDialog()}_rulesSet(e){return this._editorRuntimeOrThrow()._rulesSet(e)}async _saveRules(){return this._editorRuntimeOrThrow()._saveRules()}_renderRulesDialog(){return this._editorRuntimeOrThrow()._renderRulesDialog()}_saveKioskScale(e){this._kioskScale={...this._kioskScale,...e};try{localStorage.setItem(am,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const e=this._kioskScale,t=(t,i)=>{const n=Math.round(100*e[t]);return B` +
+ {const i=Number(e.target.value);Number.isFinite(i)&&this._saveKioskScale({[t]:i/100})}} aria-label=${i} /> + ${n}% +
`};return B`this._kioskDialog=!1}> +
+
${this._t("kiosk.hint")}
+ ${t("icon",this._t("kiosk.icon_scale"))} + ${t("font",this._t("kiosk.font_scale"))} +
+
+ + + +
+
`}_fixedFloorValue(e){if("string"==typeof e)return e||"''";try{const t=JSON.stringify(e);return(void 0===t?String(e):t).slice(0,160)}catch{return String(e).slice(0,160)}}render(){const e=!!this._importDialog||!(!this._spaceDialog||!this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)),t="view"!==this._mode||!!(this._roomDialog||this._mergeDialog||this._openingDialog||this._physicalDialog||this._partitionDeleteDialog||this._roomDeleteDialog||this._decorTextDialog||this._decorShapeDialog||this._backdropDialog||this._decorEraseConfirm||this._spaceDialog&&!this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)||this._deviceInbox||this._markerDialog||this._rulesDialog||this._settingsDialog||this._alignDialog||this._backupExportDialog||this._backupImportDialog||this._kioskDialog||this._vacFit||this._vacCalConfirm);if(e&&!this._onboardingRuntime&&this._ensureOnboardingRuntime(),t&&!this._editorRuntime&&this._ensureEditorRuntime(),!this._config||!this.hass)return G;const i=this._model,n=this.houseplanDiagnostics(),r=this._fixedFloorState(i);if("pending"===r.kind)return B` +
+
${this._config.title||this._t("card.title")}
+
+
+ +

${this._t("fixed_floor.loading")}

+
+
`;if("invalid"===r.kind)return B` +
+
${this._config.title||this._t("card.title")}
+
+ +
`;if(!i.length)return B` +
+
${this._config.title||this._t("card.title")}
+
+
+ +

${this._t("empty.no_spaces")}

+ ${this._serverStorage?B`

${this._t("empty.add_first")}

+ `:B`

${this._t("empty.install")}

`} +
+ ${this._spaceDialog&&(this._onboardingRuntime||this._editorRuntime)?this._renderSpaceDialog():G} + ${this._importDialog&&this._onboardingRuntime?this._renderImportDialog():G} + ${this._toast?B``:G} +
`;const o=this._spaceModel();if(!o)return G;const s="valid"===r.kind?[o]:i,a=o.vb,l=this._effectiveProjection();this._renderProjection=l,this._labs.active.length&&function(e){p_||y_(e);const t=u_,i=t.active.join(",");if(!i||i===m_)return;m_=i;const n=new Map(n_.map(e=>[e.id,e])),r=t.active.map(e=>{const t=n.get(e);return`${e} (#${t.issue}, expires ${t.expires})`}).join(", ");console.info(`HOUSEPLAN LABS: ${r}`)}(K_);const c="iso"===l,h="devices"===this._mode&&this._showAll,d=this._renderDevices.filter(e=>e.space===o.id&&(!e.hidden||h)),u=this._renderDeviceSnapshot,p=this._spaceDisplayForRender(),_=c?this._isoDecorationLayers(p):null,m=_?this._isoOpeningPanels(_):[],g=this._resolvedRoomFills(o,p),f=this._resolvedGlowBase(o,p,g),v=p.showLqi??this._config.show_signal??!0,y=this._config.icon_size??2.5,b=y>8?2.5:y,w=Bu(b),k=this._viewOr(this._baseVb()),x=this._floorView(k),$=this._editing?"":this._stageBg(p),S=this._opMeasureView,M=this._decorMeasure,R=this._bdLive,T=this._furnLive,C="view"===this._mode?this._editorChromeMode:this._mode,D=this._roomHoverPaths(o),A=o.bg?this._display(o.bg.href):"",O=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null,z=this._modeTransitionVisual,P=this._dayCycleState(),F=z?.viewWeight??("view"===this._mode?1:0),I=this._modeTransition.state?.from.presentedMode,E=!this._markup||!!z&&("view"===z.presentedMode||"devices"===z.presentedMode||"view"===I||"devices"===I),N=z?.stageColor||$,H=z?.sceneBrightness??1;return B` + this._notePointer(e)} + @pointerdown=${this._touchGestureGuard} + @pointermove=${this._touchGestureGuard} + @pointerup=${this._touchGestureGuard} + @pointercancel=${this._touchGestureGuard} + @lostpointercapture=${this._touchGestureGuard} + @click=${this._touchGestureGuard}> +
+
+
+ + ${this._config.title||this._t("card.title")} +
+
this._tabPointerMove(e)}> + ${s.map(e=>B``)} + ${""} + ${!this._canEdit||this._kiosk||this._hasFixedFloor?G:B``} +
+ ${this._canEdit?B`
+ ${[["plan","mdi:floor-plan"],["devices","mdi:tune-variant"],["decor","mdi:draw"]].map(([e,t])=>B``)} +
`:G} + ${this._t("count.devices",{n:d.filter(e=>!e.hidden).length})} + + ${this._labsIso&&"view"===this._mode&&!this._kiosk?B``:G} +
+ + ${""} + + +
+ ${this._norm&&this._canEdit?B``:G} +
+ ${this._canEdit&&!this._kiosk?B`
+
+ ${this._editorRuntime?"plan"===C?this._renderMarkupBar():"devices"===C?this._renderDevicesBar():this._renderDecorBar():G} +
+
`:G} +
+ +
this._markupClick(e)} + @wheel=${e=>this._onWheel(e)} + @pointerdown=${e=>{this._notePointer(e),this._stagePointerDown(e)}} + @pointermove=${e=>this._stagePointerMove(e)} + @pointerleave=${e=>this._stagePointerLeave(e)} + @pointerup=${e=>this._stagePointerUp(e)} + @pointercancel=${e=>this._stagePointerCancel(e)}> + ${dr(P,F)} + ${this._editorRuntime?this._renderEditorSecondary():G} +
+ ${c&&_?.structural?W``:G} + + + ${""} + ${this._wallHatchDefs(p.color)}${W`${this._paperShapes(o.rooms).map(e=>"path"in e?W``:"poly"in e?W``:W``)}`} + ${this._editing?this._renderMarkupDefs(a):G} + ${""} + ${this._editing&&!this._markup&&this._gridLevels()?W``:G} + ${o.bg&&A?W`this._onBackdropLoaded(o.bg.href,A)} + transform=${o.bg.angle?`rotate(${o.bg.angle} ${o.bg.x+o.bg.w/2} ${o.bg.y+o.bg.h/2})`:G} + @dblclick=${e=>this._openBackdropDialog(e)} + preserveAspectRatio="none" />`:G} + ${(()=>{const e=this._openCuts(),t=this._thickWallCuts(),i=this._wallUnionGeometry()?.roomGeom,n=new Map,r=e=>(n.has(e)||n.set(e,Zt(e)),n.get(e));return o.rooms.filter(e=>e.area||"view"===this._mode||this._markup||p.showBorders).map(n=>{let s="room "+(o.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||n.id!==this._mergeSel&&n.id!==this._splitSel?.roomId||(s+=" picked");let a="";const l=Rn(p.fill,n);if(!this._markup&&(p.showBorders||"none"!==l)){s+=" styled";const e=[];e.push(`--room-stroke:${p.color}`,`--room-stroke-op:${p.showBorders?p.opacity:0}`);const t=g.byRoom.get(n)||null;t?(s+=" filled",e.push(`--room-fill:${t.color}`,`--room-fill-op:${t.opacity}`)):e.push("--room-fill:transparent","--room-fill-op:0"),a=e.join(";")}let c;const h=e=>{"view"===this._mode&&(void 0===c&&(c=this._roomArea(n)),this._showTip(e,n.name||this._t("room.unnamed"),c?this._t("tip.area",{value:c}):"",v?this._roomLqi(n.area):null,this._roomTemp(n),this._roomHum(n)))},d=r(n),u=this._markup&&(n.id===this._mergeSel||n.id===this._splitSel?.roomId),_=d&&!u?e.filter(e=>{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return d.some((e,i)=>Pn(t,[e[0],e[1],...d[(i+1)%d.length]])<=.08*this._gridPitch)}):[],m=u?[]:t,f=_.concat(m);f.length&&(s+=" noedge");const y=this._spaceWalls.length&&n.id&&d&&this._innerRoomContour(o,n.id,e,i)||d,b=y?vi(y,(w=n,o.rooms.filter(e=>e!==w).map(r).filter(Boolean))):[];var w;const k=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z",x=y?this._cleanFloor(n,y,o).path:"",$=n.id||G,S=n.area||G,M=x&&y?W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`:b.length&&y?W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`:y&&y!==d?W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`:n.poly?W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`:W`{this._notePointer(e),this._pointerModality.hoverEnabled&&(this._hoverRoom={space:o.id,room:n})}} + @pointermove=${h} + @pointerleave=${()=>this._clearTransientHover()}>`,R=f.length&&d?kn(d,f,.02*this._gridPitch):null,T=R?W``:G;return W`${M}${T}`})})()} + ${this._renderRoomHoverFill(D)} + ${this._renderOpeningTunnelFills(o,g)} + ${this._renderGlowBaseRooms(o,f)} + ${this._renderOpeningTunnelFills(o,f,"glow-base")} + ${""} + ${p.hideDecor&&"decor"!==this._mode?G:this._renderDecorLayer()} + ${E?this._renderGlowLayer(o,p):G} + ${this._renderSunRays(o)} + ${this._editing?W`${this._renderAlignGuides()}`:G} + ${this._markup?W`${this._renderMarkupLayer(a)}`:G} + ${""} + ${""} + ${this._editing?G:this._renderZeroWalls(p)} + ${this._renderWallBodies(p)} + ${this._markup&&"resize"===this._tool?this._renderResizeMeasurements():G} + ${this._renderRoomHoverOutline(D)} + ${""} + ${this._editing?this._renderZeroWalls(p):G} + ${this._markup?W`${this._renderHiddenWallDiagnosticOverlay()}`:G} + ${this._markup?W`${this._renderOpeningPlacementPreview()}`:G} + ${S?this._renderOpeningDimensionGuides(S):G} + ${S?.guide?this._renderOpeningCenterTick(S.guide):G} + ${""} + ${""} + ${this._markup?W`${this._renderActiveChainInk()}`:G} + ${this._markup?W`${this._renderPlanSnapOverlay()}`:G} + ${p.hideOpenings&&!this._markup||_&&!_.floorSymbols?G:this._renderOpenings(p)} + ${this._renderWallThickUi()} + ${this._markup&&"resize"===this._tool?this._renderResizeLayer(k):G} + ${""} + ${this._renderBackdropFrame(k)} + ${this._renderTextFrame(k)} + + + ${c&&_?.structural?W` + `:G} + ${""} +
+ ${d.map(e=>this._renderDevice(e,k,v))} + ${this._renderVacuums(d,k)} + ${this._renderVacFit(k)} + ${this._renderOpeningLocks(k)} + ${p.showNames||this._markup?o.rooms.map(e=>this._renderRoomLabel(e,o,k,p)):G} + ${this._markup?o.rooms.map(e=>this._renderRoomGear(e,o,k)):G} +
+ ${this._measureAnchor?B`
${this._renderMeasureLabel(k)}
`:G} + ${this._resize?.liveLabels?B`
${this._resize?.liveLabels?.map(e=>B`
${e.text}
`)}
`:G} + ${S?B`
${S.labels.map(e=>B`
${e.text}
`)}
`:G} + ${this._wallDialog?B`
${this._renderWallThickDialog()}
`:G} + ${M?B`
${M.text}
`:G} + ${T?B`
${T.map(e=>B`
${e.text}
`)}
`:G} + ${R?B`
${R.text}
`:G} +
+ ${this._zoom>1?B`
${Math.round(100*this._zoom)}%
`:G} + ${this._renderFarHint()} + ${this._renderHomeArrow()} + ${this._renderEditorRuntimeLoading()} + ${this._renderRecoveryOverlay()} + ${this._booting||this._bootFading?B``:G} +
+ + ${this._roomDialog&&this._editorRuntime?this._renderRoomDialog():G} + ${this._mergeDialog&&this._editorRuntime?this._renderMergeDialog():G} + ${this._openingDialog&&this._editorRuntime?this._renderOpeningDialog():G} + ${this._physicalDialog&&this._editorRuntime?this._renderPhysicalDialog():G} + ${this._partitionDeleteDialog&&this._editorRuntime?this._renderPartitionDeleteDialog():G} + ${this._roomDeleteDialog&&this._editorRuntime?this._renderRoomDeleteDialog():G} + ${this._openingInfo?this._renderOpeningInfoCard():G} + ${this._decorTextDialog&&this._editorRuntime?this._renderDecorTextDialog():G} + ${this._decorShapeDialog&&this._editorRuntime?this._renderDecorShapeDialog():G} + ${this._backdropDialog&&this._editorRuntime?this._renderBackdropDialog():G} + ${this._decorEraseConfirm&&this._editorRuntime?this._renderDecorEraseConfirm():G} + ${this._spaceDialog&&(this._onboardingRuntime||this._editorRuntime)?this._renderSpaceDialog():G} + ${this._deviceInbox&&this._editorRuntime?this._renderDeviceInbox():G} + ${this._markerDialog&&this._editorRuntime?this._renderMarkerDialog():G} + ${this._vacCalConfirm?B`this._vacCalConfirm=null}> +
+

${this._t("vac.residual_message",{error:this._vacCalConfirm.error})}

+
+
+ + + + +
+
`:G} + ${this._infoCard?this._renderInfoCard():G} + ${this._rulesDialog&&this._editorRuntime?this._renderRulesDialog():G} + ${this._settingsDialog&&this._editorRuntime?this._renderSettingsDialog():G} + ${this._alignDialog&&this._editorRuntime?this._renderAlignDialog():G} + ${this._backupExportDialog&&this._editorRuntime?this._renderBackupExportDialog():G} + ${this._backupImportDialog&&this._editorRuntime?this._renderBackupImportDialog():G} + ${this._importDialog&&this._onboardingRuntime?this._renderImportDialog():G} + ${this._tip?B`
+ ${this._tip.title}${this._tip.meta?B`${this._tip.meta}`:G} + ${null!=this._tip.temp?B`${this._t("tip.temp_avg")} ${this._tip.temp}°`:G} + ${null!=this._tip.hum?B`${this._t("tip.hum_avg")} ${this._tip.hum}%`:G} + ${null!=this._tip.lqi?B`${this._t("tip.lqi")} + ${this._tip.lqi}`:G} +
`:G} + ${this._kiosk&&!this._hasFixedFloor&&this._kioskDots&&this._model.length>1?B`
+ ${this._model.map(e=>B``)} +
`:G} + ${this._kioskDialog?this._renderKioskDialog():G} + ${this._vacFit?B`
+ ${this._t("vac.fit_hint")} + + + + +
`:G} + ${this._tapConfirm?B`this._tapConfirm=null}> +
+ ${"run"===this._tapConfirm.kind?B`

${this._tapConfirm.text}

`:this._tapConfirm.lines.map((e,t)=>B` +

${e}

`)} +
+
+ + + +
+
`:G} + ${this._toast?B``:G} +
+ `}_vacCandidateStatus(e,t,i=this._planHass){const n=this._bindingStatus("entity:"+e);if("ha_disabled"===n.kind)return"disabled";if("orphaned"===n.kind)return"missing";if("unverified"===n.kind)return"unverified";const r=i?.states?.[e];return"unavailable"===r?.state?"unavailable":t?.hasPosition?"ok":"unsupported"}_vacOpenAllCameras(e){const t=this._haRegistry.entities||{},i=[];for(const[e,n]of Object.entries(this.hass?.states||{})){if(!e.startsWith("camera."))continue;const r=Gl(e,n,t[e]);r&&i.push(r)}this._vacAllCameraCache={devId:e.id,candidates:i},this._vacAllCamerasFor=e.id}_vacSourceResolution(e,t=!1,i=this._planHass){const n=e.marker?.vacuum,r="string"==typeof n?.source&&!!n.source,o=new Set(e.entities||[]),s=new Set(o);r&&s.add(n.source);const a=i?.entities||{},l=[];for(const e of s){const t=i?.states?.[e],o=Gl(e,t,a[e]);o?l.push(o):r&&e===n.source&&l.push({entityId:e,name:String(t?.attributes?.friendly_name||e),platform:a[e]?.platform?String(a[e].platform):null,category:e.startsWith("camera.")?"camera":"partial",hasPosition:!1,hasRooms:!1,hasPath:!1,hasMapId:!1,score:0})}if(t&&this._vacAllCameraCache?.devId===e.id){const e=new Set(l.map(e=>e.entityId));for(const t of this._vacAllCameraCache.candidates)e.has(t.entityId)||l.push(t)}const c={};for(const e of l)c[e.entityId]=this._vacCandidateStatus(e.entityId,e,i);return function(e,t,i,n){const r="string"==typeof e&&e.length>0,o=new Set(t),s=Array.from(i).sort((t,i)=>r&&t.entityId===e?-1:r&&i.entityId===e?1:i.score-t.score||t.entityId.localeCompare(i.entityId));if(r){const t=s.find(t=>t.entityId===e);return{entityId:e,status:n[e]||(t?.hasPosition?"ok":"unverified"),pinned:!0,candidates:s}}const a=s.find(e=>o.has(e.entityId)&&e.hasPosition&&"ok"===n[e.entityId]);return a?{entityId:a.entityId,status:"ok",pinned:!1,candidates:s}:{entityId:null,status:"none",pinned:!1,candidates:s}}(n?.source,o,l,c)}_vacSource(e,t=this._planHass){if(!1===e.marker?.vacuum?.live)return null;const i=this._vacSourceResolution(e,!1,t);return"ok"===i.status||"unsupported"===i.status?i.entityId:null}_vacEntity(e){return e.primary?.startsWith("vacuum.")?e.primary:(e.entities||[]).find(e=>e.startsWith("vacuum."))||null}_isVacDev(e){return!!this._vacEntity(e)}_activitySourceKey(e){return this._activitySnapshot(e).sourceKey}_activitySnapshot(e,t=Mh(this._planHass,this._devices,null,this._virtualLights)){const i=Cu(this._planHass,e,this._devices,t,this._fullRegistryHass);return{samples:i.samples,sourceKey:Ou(this._planHass,e,i)}}_stampActivity(e,t,i){let n=this._activityRt.get(e);n||(n=kp(i||"",[]),this._activityRt.set(e,n)),null!=i&&(n.sources=i),$p(n,t,Date.now(),window.clearTimeout.bind(window),e=>window.setTimeout(()=>this.requestUpdate(),e))}_syncActivityRuntime(){const e=new Map;if(!this.hass)return e;if(!1===this._config?.live_states){for(const e of this._activityRt.values())clearTimeout(e.timer);return this._activityRt.clear(),e}const t=new Set,i=Mh(this._planHass,this._devices,null,this._virtualLights);for(const n of this._devices){if(n.hidden)continue;if("icon_ripple"!==Ai(n.marker?.display))continue;t.add(n.id);const r=this._activitySnapshot(n,i);e.set(n.id,r);const{samples:o,sourceKey:s}=r;let a=this._activityRt.get(n.id);a?a.sources!==s&&xp(a,s,o,window.clearTimeout.bind(window)):(a=kp(s,o),this._activityRt.set(n.id,a))}for(const[e,i]of this._activityRt)t.has(e)||(clearTimeout(i.timer),this._activityRt.delete(e));return e}_activityTick(){if(!this.hass)return;const e=this._syncActivityRuntime();for(const t of this._devices){if(t.hidden)continue;if("icon_ripple"!==Ai(t.marker?.display))continue;const i=e.get(t.id)||this._activitySnapshot(t),{samples:n,sourceKey:r}=i,o=this._activityRt.get(t.id);if(!o||o.sources!==r)continue;const s=Sp(o,n,window.clearTimeout.bind(window));s&&this._stampActivity(t.id,s,r)}}_vacTick(){if(this.hass)for(const e of this._devices){if(e.hidden||!this._isVacDev(e))continue;if("static_icon"===Ai(e.marker?.display)){this._vacRt.delete(e.id);continue}const t=this._vacSource(e);if(!t)continue;const i=this._vacEntity(e),n=Xl(this.hass.states[i||""]?.state),r=Bl(this.hass.states[t]?.attributes);let o=this._vacRt.get(e.id);o||(o={trail:[],lastKey:"",lastTs:0,moving:!1,jump:!1,endedTs:0,lastPos:null},this._vacRt.set(e.id,o)),n&&!o.moving&&(o.trail=[],o.lastPos=null);const s="never"!==nc(e.marker?.vacuum)&&!r?.path.length;!n&&o.moving&&(o.endedTs=Date.now(),s&&o.lastPos&&(o.trail=Zl(o.trail,o.lastPos,40)),o.lastPos=null),o.moving=n;const a=r?.pos;if(n&&a){const e=a.x+":"+a.y;if(e!==o.lastKey){const t=Date.now();o.jump=o.lastTs>0&&t-o.lastTs>1e4,o.lastKey=e,o.lastTs=t,s&&o.lastPos&&(o.trail=Zl(o.trail,o.lastPos,40)),o.lastPos=[a.x,a.y]}}}}_vacEnsureMarker(e){const t=this._serverCfg;if(!t)return null;t.markers=t.markers||[];const i=t.markers.find(t=>t.id===e.id);if(i)return i;if("device"!==e.bindingKind&&"entity"!==e.bindingKind||!e.bindingRef)return null;const n={id:e.id,binding:e.bindingKind+":"+e.bindingRef,space:e.space||null,area:e.area||null,hidden:!!e.hidden};return t.markers.push(n),n}_renderVacSection(e){return this._editorRuntimeOrThrow()._renderVacSection(e)}_vacMapId(e,t,i=this._planHass){return this._editorRuntimeOrThrow()._vacMapId(e,t,i)}_vacSaveMatrix(e,t,i,n){return this._editorRuntimeOrThrow()._vacSaveMatrix(e,t,i,n)}_vacPlanRoomAnchors(e){return this._editorRuntimeOrThrow()._vacPlanRoomAnchors(e)}_vacAutoCalibrate(e){return this._editorRuntimeOrThrow()._vacAutoCalibrate(e)}_vacApplyCalibrationProposal(e){return this._editorRuntimeOrThrow()._vacApplyCalibrationProposal(e)}_vacStartFit(e){return this._editorRuntimeOrThrow()._vacStartFit(e)}_vacFitSave(){return this._editorRuntimeOrThrow()._vacFitSave()}_vacFitTurn(e){return this._editorRuntimeOrThrow()._vacFitTurn(e)}_vacGhostCentre(e){return this._editorRuntimeOrThrow()._vacGhostCentre(e)}_vacDelta(e,t,i){return this._editorRuntimeOrThrow()._vacDelta(e,t,i)}_vacFitPointer(e,t){return this._editorRuntimeOrThrow()._vacFitPointer(e,t)}_renderVacFit(e){return this._editorRuntime?this._editorRuntimeOrThrow()._renderVacFit(e):G}_vacRafLoop(){this._vacRaf=requestAnimationFrame(()=>{const e=this.renderRoot,t=this._stageEl,i=this._vacLastView,n=e?.querySelectorAll?.(".vacpuck")||[];if(!t||!i||!n.length)return void(this._vacRaf=0);const r=t.getBoundingClientRect();for(const t of n){const n=t.getAttribute("data-mid"),o=t.getBoundingClientRect(),s=i.x+(o.left+o.width/2-r.left)/r.width*i.w,a=i.y+(o.top+o.height/2-r.top)/r.height*i.h;for(const t of e.querySelectorAll(`line.tip[data-mid="${n}"]`))t.setAttribute("x2",s.toFixed(1)),t.setAttribute("y2",a.toFixed(1))}this._vacRafLoop()})}_renderVacuums(e,t){if(this._markup||"decor"===this._mode)return G;const i=this._space+"|"+t.x+"|"+t.y+"|"+t.w+"|"+t.h,n=this._vacJumpOnce||i!==this._vacViewKey;this._vacViewKey=i,this._vacJumpOnce=!1;const r=[],o=[];for(const i of e){if(i.hidden||!this._isVacDev(i))continue;if("static_icon"===Ai(i.marker?.display))continue;const e=this._renderDeviceSnapshot?.facts.get(`vacuum:${i.id}`),s=e?.source??this._vacSource(i,this._renderPlanHass);if(!s)continue;const a=e?.telemetry??Bl(this._renderPlanHass?.states[s]?.attributes);if(!a)continue;const l=String(e?.mapId??this._vacMapId(i,a,this._renderPlanHass)),c=i.marker?.vacuum?.calibration?.[l];if(!c||6!==c.length)continue;const h=e?.runtime??this._vacRt.get(i.id),d=h?.moving??!1,u=nc(i.marker?.vacuum),p="always"===u||"cleaning"===u&&d,_=e?.server??this._vacSrvTrails[i.id],m=_?.current?.map_id===l&&Array.isArray(_.current.points)?_.current:null,g=_?.previous?.map_id===l&&Array.isArray(_.previous.points)?_.previous:null;if("always"===u&&g&&g.points.length>1){const e=g.points.map(([e,t])=>{const[i,n]=zl(c,e,t),r=this._scenePoint([i,n]);return r[0].toFixed(1)+","+r[1].toFixed(1)}).join(" ");o.push(W``)}if(p){const e=Ll(a,m,h?.trail||[]),t=!d||"integration"!==e.source&&"server"!==e.source?e.path:ql(e.path);if(t.length){const e=t.map(e=>e.map(([e,t],i)=>{const[n,r]=zl(c,e,t),o=this._scenePoint([n,r]);return`${i?"L":"M"} ${o[0].toFixed(1)} ${o[1].toFixed(1)}`}).join(" ")).join(" ");o.push(W``);const n=t[t.length-1];if(d&&n?.length>=2){const e=n[n.length-1],[t,r]=zl(c,e[0],e[1]),s=this._scenePoint([t,r]),a=s[0].toFixed(1),l=s[1].toFixed(1);o.push(W``)}}}if(!d||!a.pos)continue;const[f,v]=zl(c,a.pos.x,a.pos.y),y=this._scenePoint([f,v]),b=(y[0]-t.x)/t.w*100,w=(y[1]-t.y)/t.h*100,k=h&&h.lastTs>0&&Date.now()-h.lastTs>6e4,x=i.marker?.icon||i.icon||"mdi:robot-vacuum";r.push(B`
{e.stopPropagation();const t=this._vacEntity(i);t&&this._openMoreInfo(t)}}> + +
`)}return this._vacLastView=t,r.length&&!this._vacRaf&&this._vacRafLoop(),r.length||o.length?B` + ${o.length?W`${o}`:G} + ${r}`:G}_renderDevice(e,t,i=!0){const n=this._pos(e),r=this._scenePoint([n.x,n.y]),o=(r[0]-t.x)/t.w*100,s=(r[1]-t.y)/t.h*100,a=this._devicePresentation(e,i),l=[`left:${o}%`,`top:${s}%`,...Lu(a)],c=a.disabledReason,h=a.haDisabled?this._t(`marker.ha_disabled_${c}`):e.userHidden?this._t("marker.hidden_ghost"):e.name,d=xu(a),u="view"===this._mode||"devices"===this._mode,p=[h,a.haDisabled?"":this._t(`marker.state_a11y_${d}`),"none"!==a.pulse.kind?this._t(`marker.pulse_a11y_${a.pulse.reason}`):"",a.valueFullText||a.valueText||"",nu(a.valueBadge),null!=a.lqiText&&a.lqiBand?this._t(`marker.lqi_a11y_${a.lqiBand}`,{value:a.lqiText}):""].filter(Boolean).join(", "),_=[e.model,a.valueBadge?.fullText||"",null!=a.lqiText?"LQI "+a.lqiText:""].filter(Boolean).join(" · ");return B`
this._clickDevice(t,e)} + @keydown=${t=>this._keyDevice(t,e)} + @contextmenu=${t=>this._ctxDevice(t,e)} + @pointerover=${t=>this._showTip(t,e.name,a.haDisabled?h:_)} + @pointerleave=${()=>this._clearTransientHover()} + @pointerdown=${t=>this._pointerDown(t,e)} + @pointermove=${t=>{this._pointerMove(t,e),this._showTip(t,e.name,a.haDisabled?h:_)}} + @pointerup=${t=>this._pointerUp(t,e)} + @pointercancel=${t=>this._pointerUp(t,e)} + > + ${ju(a,{newDevice:this._newIds.has(e.id),newDeviceTitle:this._t("device.new"),disabledTitle:a.haDisabled?h:""})} +
`}_roomArea(e){const t=Zt(e);if(!t)return null;const i=this._spaceModel();if(!i)return null;const n=this._spaceWalls.length&&e.id&&this._innerRoomContour(i,e.id)||t,r=this._cleanFloor(e,n),o=this._cellCm/this._gridPitch;return Hn(r.area*o*o/1e4,"mi"===this._renderPlanHass?.config?.unit_system?.length)}_roomTemp(e){const t=e.settings?.temp_source;return t?Gh(this._renderPlanHass,t,"temp",this._markers):e.area?this._climate().get(e.area)?.temp??null:null}_roomHum(e){const t=e.settings?.hum_source;return t?Gh(this._renderPlanHass,t,"hum",this._markers):e.area?this._climate().get(e.area)?.hum??null:null}_climate(){const e=this._serverCfg?.markers,t=this._renderPlanHass,i=this._climateCache;if(i&&i.h===t&&i.r===this._iconRules&&i.mk===e)return i.m;const n=function(e,t,i){const n=new Map;if(!e?.entities)return n;const r=Lh(i),o=new Set;for(const e of i||[]){if(e?.removed||!0!==e?.use_climate_temp)continue;const t=(e.binding||"").indexOf(":");t>0&&o.add(e.binding.slice(t+1))}const s=new Map;for(const[t,i]of Object.entries(e.entities)){if(i.device_id&&r.devices.has(i.device_id)&&!r.liveEntities.has(t)||!i.device_id&&r.entities.has(t)&&!r.liveEntities.has(t))continue;const n=i.device_id?e.devices?.[i.device_id]:null,a=i.area_id||n?.area_id||null;if(!a)continue;if(i.entity_category)continue;if(!(o.size>0&&t.startsWith("climate.")&&(o.has(t)||i.device_id&&o.has(i.device_id)))){if(Te.has(i.platform))continue;if(Vh.test(t))continue}let l=s.get(a);l||(l=new Map,s.set(a,l));const c=i.device_id||t;let h=l.get(c);if(!h){const r=e.states?.[t];h={name:(n?n.name_by_user||n.name:i.name||r?.attributes?.friendly_name||t)||t,model:n?.model,ents:[]},l.set(c,h)}h.ents.push(t)}for(const[i,r]of s){const s=[],a=[];for(const[i,n]of r){const r=Fh(e,n.name,n.model,n.ents,t),l="mdi:thermometer"===r||"mdi:air-filter"===r;if(l){const t=Dh(e,n.ents);null!=t&&s.push(t)}if(o.size>0&&(o.has(i)||n.ents.some(e=>o.has(e)))){const t=Ah(e,n.ents);null!=t&&s.push(t)}if(l||"mdi:water-percent"===r){const t=zh(e,n.ents);null!=t&&a.push(t)}}(s.length||a.length)&&n.set(i,{temp:s.length?Math.round(s.reduce((e,t)=>e+t,0)/s.length*10)/10:null,hum:a.length?Math.round(a.reduce((e,t)=>e+t,0)/a.length):null})}return n}(t,this._iconRules,e);return this._climateCache={h:t,r:this._iconRules,mk:e,m:n},n}_resetRoomDialogFields(){return this._editorRuntimeOrThrow()._resetRoomDialogFields()}_openRoomEdit(e){return this._editorRuntimeOrThrow()._openRoomEdit(e)}_roomSettingsFromDialog(){return this._editorRuntimeOrThrow()._roomSettingsFromDialog()}_saveRoomEdit(){return this._editorRuntimeOrThrow()._saveRoomEdit()}_roomSrcCandidates(){return this._editorRuntimeOrThrow()._roomSrcCandidates()}_roomSrcLabel(e){return this._editorRuntimeOrThrow()._roomSrcLabel(e)}_labelPos(e,t){const i=this._layout["rl_"+(e.id||"")];if(i&&i.s===t)return{x:i.x*hm,y:i.y*hm};const n=this._roomCenter(e),r=this._gridPitch;return{x:qa(Gt(n[0],r)),y:qa(Gt(n[1],r))}}_labelDown(e,t,i){if(this._editorRuntime)return this._editorRuntimeOrThrow()._labelDown(e,t,i)}_labelMove(e,t,i){if(this._editorRuntime)return this._editorRuntimeOrThrow()._labelMove(e,t,i)}_labelUp(e){if(this._editorRuntime)return this._editorRuntimeOrThrow()._labelUp(e)}_labelScale(e){const t=this._layout["rl_"+(e.id||"")]?.k;return"number"==typeof t&&Number.isFinite(t)?Math.min(3,Math.max(.5,t)):1}_rlResizeDown(e,t,i){return this._editorRuntimeOrThrow()._rlResizeDown(e,t,i)}_rlResizeMove(e){return this._editorRuntimeOrThrow()._rlResizeMove(e)}_rlResizeUp(){return this._editorRuntimeOrThrow()._rlResizeUp()}_renderRoomGear(e,t,i){return this._editorRuntimeOrThrow()._renderRoomGear(e,t,i)}_renderRoomLabel(e,t,i,n){if(!e.name&&!this._markup)return G;const r=this._labelPos(e,t.id),o=this._scenePoint([r.x,r.y]),s=(o[0]-i.x)/i.w*100,a=(o[1]-i.y)/i.h*100,l=Math.min(1,n.opacity+.25),c=this._labelScale(e),h=[];if(e.area||e.settings?.temp_source||e.settings?.hum_source||n.labelLight){if(n.labelTemp){const t=this._roomTemp(e);null!=t&&h.push(B`${t}°`)}if(n.labelHum){const t=this._roomHum(e);null!=t&&h.push(B`${t}%`)}if(n.labelLqi&&e.area){const t=this._roomLqi(e.area);null!=t&&h.push(B`${t}`)}if(n.labelLight){const t=(d=Mh(this._renderPlanHass,this._renderDevices,e,this._virtualLights)).length?{on:d.filter(e=>e.on).length,total:d.length}:null;if(t){const e=0===t.on?this._t("roomcard.light_off"):t.on===t.total?this._t("roomcard.light_on"):this._t("roomcard.light_partial",{on:t.on,total:t.total});h.push(B`${e}`)}}}var d;const u=!!e.area,p=!this._markup;return B`
this._labelDown(i,e,t.id)} + @pointermove=${i=>this._labelMove(i,e,t.id)} + @pointerup=${()=>this._labelUp(e)} + @pointercancel=${()=>this._labelUp(e)} + >${e.name||(this._markup?this._t("room.unnamed"):"")}${u?B`{t.stopPropagation(),this._clickRoom(e)}:G} + @pointerdown=${p?e=>e.stopPropagation():G}>`:G} + ${h.length?B`${h}`:G} + ${"plan"===this._mode?["tl","tr","bl","br"].map(i=>B`this._rlResizeDown(i,e,t.id)} + @pointermove=${e=>this._rlResizeMove(e)} + @pointerup=${()=>this._rlResizeUp()} + @pointercancel=${()=>this._rlResizeUp()}>`):G} +
`}get _measureAnchor(){return this._markup&&this._cursorPt?"draw"===this._tool&&this._path.length&&!this._contourClosed?this._path[this._path.length-1]:"split"===this._tool&&this._splitSel?.pts?.length?this._splitSel.pts[this._splitSel.pts.length-1]:null:null}_renderMeasureLabel(e){const t=this._measureAnchor,i=this._cursorPt,n=(i[0]-e.x)/e.w*100,r=(i[1]-e.y)/e.h*100,o=On(t,i),s=Math.round(10*o)/10,a=function(e,t,i=.001){if(e.length<2||t.length<2)return!1;const n=Math.abs(t[0]-e[0]),r=Math.abs(t[1]-e[1]);if(!Number.isFinite(n)||!Number.isFinite(r)||Math.hypot(n,r)<=i)return!1;const o=Math.max(n,r,1);return n<=i*o||r<=i*o||Math.abs(n-r)<=i*o}(t,i,2e-4*this._gridPitch);return B`
+ ${this._fmtLen(t,i)} · ${s}°
`}get _decorMeasure(){const e=this._decorDraft;if(!e||"decor"!==this._mode)return null;const[t,i]=e.a,[n,r]=e.b;if(Math.abs(t-n)<1e-6&&Math.abs(i-r)<1e-6)return null;const o=(t+n)/2,s=(i+r)/2;if("line"===e.kind){const t=On(e.a,e.b);return{x:o,y:s,on45:zn(t),text:`${this._fmtLen(e.a,e.b)} · ${Math.round(10*t)/10}°`}}const a=this._fmtLen([t,i],[n,i]),l=this._fmtLen([n,i],[n,r]);if("ellipse"===e.kind){const e=this._fmtLen([0,0],[Math.abs(n-t)/2,0]),a=this._fmtLen([0,0],[0,Math.abs(r-i)/2]);return{x:o,y:s,on45:!1,text:Math.abs(Math.abs(n-t)-Math.abs(r-i))<1e-6?`R ${e}`:`Rx ${e} × Ry ${a}`}}return{x:o,y:s,on45:!1,text:`${a} × ${l} · ${Hn(vr(Math.abs(n-t),this._cellCm,this._gridPitch)*vr(Math.abs(r-i),this._cellCm,this._gridPitch)/1e4,this._imperial)}`}}get _alignPoint(){if(this._markup){if("draw"===this._tool&&this._path.length&&!this._contourClosed&&this._cursorPt)return this._cursorPt;if("split"===this._tool&&this._splitSel?.pts?.length&&this._cursorPt)return this._cursorPt;if(this._drag?.id.startsWith("rl_")&&this._drag.moved){const e=this._drag.id.slice(3),t=this._spaceModel()?.rooms.find(t=>t.id===e);return t?(()=>{const e=this._labelPos(t,this._space);return[e.x,e.y]})():null}return null}if("devices"===this._mode&&this._drag?.moved){const e=this._devices.find(e=>e.id===this._drag.id);return e?(()=>{const t=this._pos(e);return[t.x,t.y]})():null}if("decor"===this._mode){if(this._decorDraft)return this._decorDraft.b;if(this._decorMove){const e=this._decorList.find(e=>e.id===this._decorMove.id);if(!e)return null;const t=hm,i=this._decorH;return"line"===e.kind?[e.x1*t,e.y1*i]:[e.x*t,e.y*i]}return null}return null}_alignCandidates(){return this._editorRuntimeOrThrow()._alignCandidates()}_renderAlignGuides(){return this._editorRuntimeOrThrow()._renderAlignGuides()}_renderOpeningCenterTick(e){return this._editorRuntimeOrThrow()._renderOpeningCenterTick(e)}_renderOpeningDimensionGuides(e){return this._editorRuntimeOrThrow()._renderOpeningDimensionGuides(e)}_roomCenter(e){if(e.poly){const t=e.poly.length;return[e.poly.reduce((e,t)=>e+t[0],0)/t,e.poly.reduce((e,t)=>e+t[1],0)/t]}return[e.x+e.w/2,e.y+.1*Math.min(e.w,e.h)]}_openingAmt(e){const t=e.contact&&this._renderOpeningEntityAvailable(e.contact)?this._renderPlanHass.states[e.contact]?.state:null;return ii(e.type,t,!!e.invert)}_planEntityAvailable(e){return!!e&&(!qh(this._fullRegistryHass,e,Lh(this._markers))&&"active"===this._bindingStatus("entity:"+e).kind)}_renderEntityAvailable(e){return!!e&&(!qh(this._renderPlanHass,e,Lh(this._markers))&&(!!this._renderPlanHass.entities?.[e]&&!!this._renderPlanHass.states?.[e]))}_openingEntityAvailable(e){return function(e,t,i=Vc(e)){return!!t&&"active"===th(e,`entity:${t}`,i).kind}(this.hass,e,this._haRegistry)}_renderOpeningEntityAvailable(e){return t=this._renderPlanHass,!!(i=e)&&!!t?.states?.[i];var t,i}_renderOpeningPlacementPreview(){return this._editorRuntimeOrThrow()._renderOpeningPlacementPreview()}_renderOpenings(e){const t=this._openingsR;if(!t.length)return W``;const i=this._spaceModel();if(!i)return W``;const n=e.color,r=this._spaceWalls,o=this._openCuts(),s=this._openingWallIndexFor(i,o).value;return W`${t.map(e=>{if(e.orphanReason)return W`{t.stopPropagation(),this._editOpening(e)}}> + + ! + `;const t=this._openingAmt(e),i=t>0&&!!e.contact&&this._renderOpeningEntityAvailable(e.contact)?"var(--hp-open)":n,o="gate"===e.type?!e.flip_v:e.flip_v,a=e.partitionHost||r.length||"gate"===e.type?this._openingFace(e,s,!!o):{ox:0,oy:0,cm:0,side:-1},l={type:e.type,length:e.rlen,angle:e.angle,amount:t,flipH:!!e.flip_h,flipV:!!e.flip_v,base:n,tone:i,cellCm:this._cellCm,gridPitch:this._gridPitch,face:a},{half:c,outlineHalf:h,hitHalf:d}=eu(l),u=xa(10,this._cellCm),p=xa(12,this._cellCm);return W` + ${tu(l)} + + this._opClick(t,e)} + @pointerdown=${t=>this._opPointerDown(t,e)} + @pointermove=${t=>this._opPointerMove(t,e)} + @pointerup=${t=>this._opPointerUp(t,e)} + @pointercancel=${t=>this._opPointerUp(t,e)}> + `})}`}_renderOpeningLocks(e){const t=this._openingsR.filter(e=>!e.orphanReason&&("door"===e.type||"gate"===e.type)&&e.lock&&this._renderOpeningEntityAvailable(e.lock));if(!t.length)return B``;const i=this._spaceModel();if(!i)return B``;const n=this._openCuts(),r=this._openingWallIndexFor(i,n).value;return B`${t.map(t=>{const i=this._renderPlanHass.states[t.lock]?.state,n="locked"===i,o=n||["unlocked","open","opening","unlocking","locking"].includes(String(i)),s=(t.angle+90)*Math.PI/180,a="gate"===t.type?this._openingFace(t,r,!t.flip_v):null,l=xa(16,this._cellCm),c=a?-l*a.side:l*(t.flip_v?-1:1),h=t.rx+Math.cos(s)*c,d=t.ry+Math.sin(s)*c,u=this._scenePoint([h,d]),p=(u[0]-e.x)/e.w*100,_=(u[1]-e.y)/e.h*100;return B`
{e.stopPropagation(),"view"===this._mode&&(this._openingInfo=t)}}> + +
`})}`}_lockAction(e,t){if(this._openingEntityAvailable(e)){if("unlock"===t){const t=this.hass?.states?.[e]?.attributes?.friendly_name||e;if(!confirm(this._t("confirm.unlock",{name:t})))return}this.hass?.callService?.("lock",t,{entity_id:e})}}_renderOpeningInfoCard(){const e=this._openingInfo,t="passage"!==e.type&&e.contact&&this._openingEntityAvailable(e.contact)?e.contact:null,i=("door"===e.type||"gate"===e.type)&&e.lock&&this._openingEntityAvailable(e.lock)?e.lock:null,n=t?this.hass.states[t]?.state:null,r=this._openingAmt(e),o=i?this.hass.states[i]?.state:null,s="door"===e.type?"opening.door":"gate"===e.type?"opening.gate":"passage"===e.type?"opening.passage":"opening.window",a="door"===e.type?"mdi:door":"gate"===e.type?"mdi:gate":"passage"===e.type?"mdi:arch":"mdi:window-closed-variant",l="gate"===e.type?r>0?"mdi:gate-open":"mdi:gate":r>0?"mdi:door-open":"mdi:door-closed",c=(e,t,i,n="")=>B`
${t}${i}
`;return B`this._openingInfo=null}> +
+ ${t?c(l,this._t("opening.contact_label"),"unavailable"===n||null==n?this._t("opening.state_unknown"):this._t(r>0?"opening.open":"opening.closed"),r>0?"warn":"ok"):G} + ${i?c("locked"===o?"mdi:lock":"mdi:lock-open-variant",this._t("opening.lock_label"),"locked"===o?this._t("opening.locked"):["unlocked","open"].includes(String(o))?this._t("opening.unlocked"):this._t("opening.state_unknown"),"locked"===o?"ok":"warn"):G} + ${i&&("locked"===o||["unlocked","open"].includes(String(o)))?B``:i&&["locking","unlocking"].includes(String(o))?B``:G} + ${t||i?G:B`

${this._t("opening.no_entities")}

`} +
+
+ + +
+
`}_renderOpeningDialog(){return this._editorRuntimeOrThrow()._renderOpeningDialog()}_gridLevels(){return this._editorRuntimeOrThrow()._gridLevels()}_renderMarkupDefs(e){return this._editorRuntimeOrThrow()._renderMarkupDefs(e)}_renderPhysicalEditorLayer(){return this._editorRuntimeOrThrow()._renderPhysicalEditorLayer()}_renderHiddenWallDiagnosticOverlay(){return this._editorRuntimeOrThrow()._renderHiddenWallDiagnosticOverlay()}_renderPlanSnapOverlay(){return this._editorRuntimeOrThrow()._renderPlanSnapOverlay()}_syncPlanSnapActiveMarker(e){return this._editorRuntimeOrThrow()._syncPlanSnapActiveMarker(e)}_syncPlanSnapConflictMarkers(e){return this._editorRuntimeOrThrow()._syncPlanSnapConflictMarkers(e)}_planSnapPhysicalSegment(e){return this._editorRuntimeOrThrow()._planSnapPhysicalSegment(e)}_drawPreviewJoinPatchD(e,t){return this._editorRuntimeOrThrow()._drawPreviewJoinPatchD(e,t)}_renderMarkupLayer(e){return this._editorRuntimeOrThrow()._renderMarkupLayer(e)}_renderActiveChainInk(){return this._editorRuntimeOrThrow()._renderActiveChainInk()}_renderPartitionDeleteDialog(){return this._editorRuntimeOrThrow()._renderPartitionDeleteDialog()}_renderRoomDeleteDialog(){return this._editorRuntimeOrThrow()._renderRoomDeleteDialog()}_renderPhysicalDialog(){return this._editorRuntimeOrThrow()._renderPhysicalDialog()}_renderMarkupBar(){return this._editorRuntimeOrThrow()._renderMarkupBar()}_renderDevicesBar(){return this._editorRuntimeOrThrow()._renderDevicesBar()}_renderDeviceInbox(){return this._editorRuntimeOrThrow()._renderDeviceInbox()}_cardEntities(e){const t=this._planHass,i=[],n=new Set,r=e=>{if(!e||n.has(e)||!t.states[e])return;const r=t.entities[e];if("config"===r?.entity_category||"diagnostic"===r?.entity_category)return;n.add(e);const o=e.split(".")[0];["light","switch","fan","humidifier","siren","input_boolean"].includes(o)?i.push({eid:e,kind:"toggle"}):["cover","valve","lock","climate","media_player","vacuum","water_heater"].includes(o)?i.push({eid:e,kind:"open"}):["sensor","binary_sensor","number","select"].includes(o)&&i.push({eid:e,kind:"value"})};for(const i of Mh(t,this._devices,null,this._virtualLights))if(i.device.id===e.id)for(const e of[...i.serviceEids,...i.stateEids])r(e);e.primary&&r(e.primary);for(const t of e.entities)r(t);return i.slice(0,12)}_cardToggle(e){const t=e.split(".")[0];"lock"!==t&&"alarm_control_panel"!==t&&this._planEntityAvailable(e)&&this.hass.callService("homeassistant","toggle",{entity_id:e}).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)})))}_renderInfoCard(){const e=this._infoCard,t=e.primary?this.hass.states[e.primary]:void 0,i=t?qi(this.hass,e.primary)?.text??t.state:null,n=(e.controls??e.marker?.controls??[]).filter(yn).filter(e=>this._planEntityAvailable(e));return B` +
+ ${(()=>{const t=this._cardEntities(e);return t.length?B`
+ ${t.map(({eid:e,kind:t})=>{const i=this.hass.states[e],n=this.hass.entities[e]?.name||i?.attributes?.friendly_name||e,r=i?qi(this.hass,e)?.text??i.state:"",o="on"===i?.state||["open","unlocked","playing","cleaning"].includes(i?.state);return B`
+ + ${n} + ${"toggle"===t?B``:"open"===t?B``:B`${r}`} +
`})} +
`:G})()} + ${e.model?B`
${this._t("info.model")}${e.model}
`:G} + ${i&&!this._cardEntities(e).length?B`
${this._t("info.state")}${i}
`:G} + ${Ci(e.link)?B`
${this._t("info.link")} + ${e.link}
`:G} + ${e.description?B`
${e.description}
`:G} + ${e.pdfs&&e.pdfs.length?B`
${this._t("info.manuals")} + ${e.pdfs.map(e=>B` + ${e.name}`)}
`:G} + ${n.length?B`
${this._t("info.controls")} + + ${n.map(e=>{const t=this.hass.states[e],i="on"===t?.state;return B` + + ${t?.attributes?.friendly_name||e}`})} +
`:G} + ${e.model||i||e.link||e.description||e.pdfs&&e.pdfs.length||n.length?G:B`
${this._t("info.none")}
`} +
+
+ + ${e.primary?B``:G} + +
+
`}_markerValueBadgeFields(e){return this._editorRuntimeOrThrow()._markerValueBadgeFields(e)}_markerDraft(e){return this._editorRuntimeOrThrow()._markerDraft(e)}_markerPreviewDevice(e){return this._editorRuntimeOrThrow()._markerPreviewDevice(e)}_markerPreviewDevices(e){return this._editorRuntimeOrThrow()._markerPreviewDevices(e)}_toggleIntent(e,t=this._devices){return this._editorRuntimeOrThrow()._toggleIntent(e,t)}_toggleIntentForDialog(e){return this._editorRuntimeOrThrow()._toggleIntentForDialog(e)}_toggleStateText(e,t){return this._editorRuntimeOrThrow()._toggleStateText(e,t)}_toggleConfirmationStateText(e){return this._editorRuntimeOrThrow()._toggleConfirmationStateText(e)}_toggleConfirmationLines(e){return this._editorRuntimeOrThrow()._toggleConfirmationLines(e)}_toggleHintLines(e){return this._editorRuntimeOrThrow()._toggleHintLines(e)}_effectiveStoredTapAction(e,t){return this._editorRuntimeOrThrow()._effectiveStoredTapAction(e,t)}_effectiveMarkerTapAction(e,t=this._markerPreviewDevice(e)){return this._editorRuntimeOrThrow()._effectiveMarkerTapAction(e,t)}_announceToggleDraft(e){return this._editorRuntimeOrThrow()._announceToggleDraft(e)}_valueBadgeForBinding(e,t){return this._editorRuntimeOrThrow()._valueBadgeForBinding(e,t)}_markerSpatialSource(e){return this._editorRuntimeOrThrow()._markerSpatialSource(e)}_markerAutoHasSpatialSource(e){return this._editorRuntimeOrThrow()._markerAutoHasSpatialSource(e)}_setMarkerLightRole(e){return this._editorRuntimeOrThrow()._setMarkerLightRole(e)}_controlRefInfo(e){return this._editorRuntimeOrThrow()._controlRefInfo(e)}_valueBadgeCandidateLabel(e){return this._editorRuntimeOrThrow()._valueBadgeCandidateLabel(e)}_controlCandidates(e){return this._editorRuntimeOrThrow()._controlCandidates(e)}_addControlRef(e,t){return this._editorRuntimeOrThrow()._addControlRef(e,t)}_setMarkerGlowMode(e){return this._editorRuntimeOrThrow()._setMarkerGlowMode(e)}_renderMarkerDialog(){return this._editorRuntimeOrThrow()._renderMarkerDialog()}_renderSpaceDialog(){return this._onboardingRuntime&&this._spaceDialog&&this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)?this._onboardingRuntime._renderSpaceDialog():this._editorRuntimeOrThrow()._renderSpaceDialog()}_renderMergeDialog(){return this._editorRuntimeOrThrow()._renderMergeDialog()}_renderCardPreview(e,t,i){const n=18*e;return B`
+ + ${this._t("preview.room_name")} + + 22.4° · + 45% · + ${this._t("roomcard.light_partial",{on:1,total:3})} + +
`}_renderRoomSource(e){return this._editorRuntimeOrThrow()._renderRoomSource(e)}_renderRoomDialog(){return this._editorRuntimeOrThrow()._renderRoomDialog()}}vm.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_editorRuntimeLoadingVisible:{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},_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},_deviceInbox:{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}},vm.ZOOM_MAX=8,vm.ZOOM_MIN=1/3,vm.styles=[Bd,Dp],customElements.get("houseplan-card")||customElements.define("houseplan-card",vm),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-card"===e.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${K_} `,"background:#3ea6ff;color:#04121f;font-weight:700","");export{Ao as $,G as A,Qt as B,Ia as C,le as D,U as E,Zt as F,Na as G,Td as H,Id as I,gs as J,lo as K,Pd as L,Md as M,No as N,vs as O,Cd as P,Bs as Q,Gs as R,vo as S,oi as T,ao as U,xo as V,Ku as W,Yu as X,ss as Y,Wr as Z,zo as _,o as a,ts as a$,no as a0,oo as a1,qr as a2,rp as a3,Ra as a4,Fo as a5,Ea as a6,Oo as a7,Ca as a8,Da as a9,ea as aA,Al as aB,op as aC,Rl as aD,Lp as aE,_s as aF,Ns as aG,ks as aH,Op as aI,hi as aJ,si as aK,$i as aL,va as aM,sa as aN,oa as aO,Pa as aP,Io as aQ,Eo as aR,Ls as aS,Kt as aT,tl as aU,ma as aV,_a as aW,Nn as aX,Hn as aY,pi as aZ,is as a_,Ui as aa,Gi as ab,Hi as ac,Li as ad,za as ae,ms as af,ns as ag,qs as ah,qo as ai,Xs as aj,ba as ak,sp as al,Qs as am,fs as an,ar as ao,sr as ap,or as aq,nn as ar,Ce as as,Qd as at,k_ as au,fo as av,qa as aw,Gt as ax,Vt as ay,Cr as az,B as b,Yi as b$,W as b0,Pp as b1,Fp as b2,kr as b3,Mr as b4,Sr as b5,vr as b6,ja as b7,_r as b8,gr as b9,Fd as bA,wi as bB,li as bC,ei as bD,ci as bE,Lo as bF,Si as bG,mn as bH,mu as bI,gu as bJ,uh as bK,_d as bL,Ai as bM,Ii as bN,En as bO,Cn as bP,Eh as bQ,ro as bR,Hh as bS,Ih as bT,tn as bU,Qi as bV,Ji as bW,Sa as bX,tp as bY,Xi as bZ,Zi as b_,br as ba,On as bb,pr as bc,fr as bd,mr as be,xr as bf,gl as bg,dl as bh,ml as bi,ul as bj,bl as bk,sl as bl,hl as bm,Ho as bn,_o as bo,xa as bp,eu as bq,zd as br,U_ as bs,Od as bt,Vs as bu,L_ as bv,G_ as bw,Zu as bx,ti as by,Dd as bz,he as c,co as c$,Ki as c0,$a as c1,Hp as c2,zp as c3,rn as c4,Kr as c5,lr as c6,De as c7,Fe as c8,Ae as c9,vd as cA,kd as cB,$d as cC,Rh as cD,Mh as cE,kh as cF,_h as cG,yn as cH,dh as cI,Nh as cJ,gn as cK,Pu as cL,ou as cM,xh as cN,$h as cO,mh as cP,cd as cQ,Oi as cR,Di as cS,su as cT,Ci as cU,Ma as cV,zi as cW,Pi as cX,so as cY,cl as cZ,vl as c_,Bl as ca,Kl as cb,Vi as cc,nc as cd,jl as ce,El as cf,Yl as cg,Wl as ch,Ul as ci,ec as cj,tc as ck,Ql as cl,ic as cm,zl as cn,Dn as co,An as cp,ii as cq,q_ as cr,tu as cs,H_ as ct,nl as cu,ys as cv,Vo as cw,Ko as cx,fu as cy,Uh as cz,Bd as d,ri as d0,Fa as d1,Zd as d2,vm as d3,pe as e,Hu as f,Lu as g,ui as h,_e as i,Tr as j,fi as k,Xd as l,Ol as m,Nt as n,yi as o,gi as p,Lh as q,ju as r,qt as s,Jd as t,qh as u,nu as v,yu as w,Jt as x,wn as y,Pn as z}; diff --git a/dist/houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js b/dist/houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js new file mode 100644 index 00000000..cb04dde5 --- /dev/null +++ b/dist/houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js @@ -0,0 +1,2572 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";import{e as t,i as e,E as s,D as i,b as o,A as a,a as n,c as r,s as l,m as h,d as c,l as d,t as p,w as _,f as u,g as m,v as g,r as f,h as b,j as y,p as v,k as $,n as w,o as k,q as x,u as S,x as M,y as D,z as C,B as P,G as I,C as T,F as R,H as F,I as N,J as z,K as A,L as O,M as L,N as E,O as B,P as H,Q as G,R as W,S as j,T as q,U,V as K,W as V,X as J,Y,Z as X,_ as Z,$ as Q,a0 as tt,a1 as et,a2 as st,a3 as it,a4 as ot,a5 as at,a6 as nt,a7 as rt,a8 as lt,a9 as ht,aa as ct,ab as dt,ac as pt,ad as _t,ae as ut,af as mt,ag as gt,ah as ft,ai as bt,aj as yt,ak as vt,al as $t,am as wt,an as kt,ao as xt,ap as St,aq as Mt,ar as Dt,as as Ct,at as Pt,au as It,av as Tt,aw as Rt,ax as Ft,ay as Nt,az as zt,aA as At,aB as Ot,aC as Lt,aD as Et,aE as Bt,aF as Ht,aG as Gt,aH as Wt,aI as jt,aJ as qt,aK as Ut,aL as Kt,aM as Vt,aN as Jt,aO as Yt,aP as Xt,aQ as Zt,aR as Qt,aS as te,aT as ee,aU as se,aV as ie,aW as oe,aX as ae,aY as ne,aZ as re,a_ as le,a$ as he,b0 as ce,b1 as de,b2 as pe,b3 as _e,b4 as ue,b5 as me,b6 as ge,b7 as fe,b8 as be,b9 as ye,ba as ve,bb as $e,bc as we,bd as ke,be as xe,bf as Se,bg as Me,bh as De,bi as Ce,bj as Pe,bk as Ie,bl as Te,bm as Re,bn as Fe,bo as Ne,bp as ze,bq as Ae,br as Oe,bs as Le,bt as Ee,bu as Be,bv as He,bw as Ge,bx as We,by as je,bz as qe,bA as Ue,bB as Ke,bC as Ve,bD as Je,bE as Ye,bF as Xe,bG as Ze,bH as Qe,bI as ts,bJ as es,bK as ss,bL as is,bM as os,bN as as,bO as ns,bP as rs,bQ as ls,bR as hs,bS as cs,bT as ds,bU as ps,bV as _s,bW as us,bX as ms,bY as gs,bZ as fs,b_ as bs,b$ as ys,c0 as vs,c1 as $s,c2 as ws,c3 as ks,c4 as xs,c5 as Ss,c6 as Ms,c7 as Ds,c8 as Cs,c9 as Ps,ca as Is,cb as Ts,cc as Rs,cd as Fs,ce as Ns,cf as zs,cg as As,ch as Os,ci as Ls,cj as Es,ck as Bs,cl as Hs,cm as Gs,cn as Ws,co as js,cp as qs,cq as Us,cr as Ks,cs as Vs,ct as Js,cu as Ys,cv as Xs,cw as Zs,cx as Qs,cy as ti,cz as ei,cA as si,cB as ii,cC as oi,cD as ai,cE as ni,cF as ri,cG as li,cH as hi,cI as ci,cJ as di,cK as pi,cL as _i,cM as ui,cN as mi,cO as gi,cP as fi,cQ as bi,cR as yi,cS as vi,cT as $i,cU as wi,cV as ki,cW as xi,cX as Si,cY as Mi,cZ as Di,c_ as Ci,c$ as Pi,d0 as Ii,d1 as Ti}from"./houseplan-card-OQuczTJf.js";import{i as Ri,c as Fi,a as Ni,s as zi,t as Ai}from"./space-deletion-7mvB_XVT.js";const Oi={},Li=t(class extends e{constructor(){super(...arguments),this.ot=Oi}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 s}else if(this.ot===e)return s;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}}),Ei=(t,e,s)=>Math.min(s,Math.max(e,Number.isFinite(t)?t:e));function Bi(t){return Number.isFinite(t)?(t%360+360)%360:0}function Hi(t){if("string"!=typeof t)return null;const e=t.trim().replace(/^#/,""),s=/^[0-9a-fA-F]{3}$/.test(e)?e.split("").map(t=>`${t}${t}`).join(""):e;return/^[0-9a-fA-F]{6}$/.test(s)?`#${s.toLowerCase()}`:null}function Gi(t){const e=Hi(t);return e?{r:Number.parseInt(e.slice(1,3),16),g:Number.parseInt(e.slice(3,5),16),b:Number.parseInt(e.slice(5,7),16)}:null}function Wi(t){const e=Ei(t.r,0,255)/255,s=Ei(t.g,0,255)/255,i=Ei(t.b,0,255)/255,o=Math.max(e,s,i),a=o-Math.min(e,s,i);let n=0;return a>0&&(n=o===e?(s-i)/a%6*60:o===s?60*((i-e)/a+2):60*((e-s)/a+4)),{h:Bi(n),s:0===o?0:a/o*100,v:100*o}}function ji(t){return function(t){const e=t=>Math.round(Ei(t,0,255)).toString(16).padStart(2,"0");return`#${e(t.r)}${e(t.g)}${e(t.b)}`}(function(t){const e=Bi(t.h),s=Ei(t.s,0,100)/100,i=Ei(t.v,0,100)/100,o=i*s,a=o*(1-Math.abs(e/60%2-1)),n=i-o;let r;return r=e<60?[o,a,0]:e<120?[a,o,0]:e<180?[0,o,a]:e<240?[0,a,o]:e<300?[a,0,o]:[o,0,a],{r:Math.round(255*(r[0]+n)),g:Math.round(255*(r[1]+n)),b:Math.round(255*(r[2]+n))}}(t))}function qi(t){const e=t.visualViewport;return e&&Number.isFinite(e.width)&&Number.isFinite(e.height)?{left:Number(e.offsetLeft)||0,top:Number(e.offsetTop)||0,width:Math.max(0,Number(e.width)||0),height:Math.max(0,Number(e.height)||0)}:{left:0,top:0,width:t.innerWidth,height:t.innerHeight}}function Ui(t,e,s,i=7,o=8){const a=s.left+o,n=s.top+o,r=Math.max(a,s.left+s.width-o),l=Math.max(n,s.top+s.height-o),h=Math.max(0,r-a),c=Math.max(0,l-n),d=Math.min(Math.max(0,e.width),h),p=Math.min(Math.max(0,e.height),c);let _=t.left;_+d>r&&(_=t.right-d),_=Math.min(Math.max(a,_),Math.max(a,r-d));const u=t.bottom+i,m=t.top-i-p;let g="bottom",f=u;return u+p>l&&m>=n?(g="top",f=Math.min(Math.max(n,m),Math.max(n,l-p))):f=Math.min(Math.max(n,u),Math.max(n,l-p)),{left:Math.round(_),top:Math.round(f),side:g,maxWidth:Math.round(h),maxHeight:Math.round(c)}}class Ki{constructor(t,e,s){this.owner=t,this.name=e,this.keydown=s,this.host=null,this.root=null}window(){return this.owner.ownerDocument.defaultView}dialog(){return this.owner.closest("hp-dialog")}usesPopover(t=!1){const e=this.window();return!t&&!!e&&function(t){const e=t.HTMLElement?.prototype;return"function"==typeof e?.showPopover&&"function"==typeof e?.hidePopover}(e)}get hasFallback(){return!!this.host}containsPath(t){return t.includes(this.owner)||!!this.host&&t.includes(this.host)}ownsActiveElement(){let t=this.owner.ownerDocument.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return!(!t||t!==this.owner&&!this.owner.shadowRoot?.contains(t)&&!this.root?.contains(t))}renderFallback(t,e){const s=this.ensureFallback();return s?(i(o`${t}`,s),s):null}surface(t,e){return e?this.owner.shadowRoot?.querySelector(t)||null:this.root?.querySelector(t)||null}destroy(){this.root&&i(a,this.root),this.host?.remove(),this.host=null,this.root=null}ensureFallback(){if(this.root?.isConnected)return this.root;const t=this.dialog()?.overlayPortal()||this.owner.ownerDocument.body;if(!t)return null;const e=this.owner.ownerDocument.createElement("div");return e.dataset.hpOverlay=this.name,e.style.display="contents",this.keydown&&e.addEventListener("keydown",this.keydown,!0),t.append(e),this.host=e,this.root=e.attachShadow({mode:"open"}),this.root}}const Vi={title:"Color picker",hue:"Hue",saturation:"Saturation",value:"Brightness",hex:"Hex color",invalidHex:"Enter a 3- or 6-digit hex color"};class Ji extends r{constructor(){super(...arguments),this.label="",this.opacityLabel="Opacity",this.color="#607d8b",this.opacity=1,this.disabled=!1,this.showOpacity=!0,this.pickerLabels=Vi,this._open=!1,this._pickerRaf=0,this._emitRaf=0,this._forceFallback=!1,this._overlayDispose=null,this._hue=0,this._saturation=0,this._value=0,this._hexDraft="#607d8b",this._hexInvalid=!1,this._lastValidColor="#607d8b",this._activePointerId=null,this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closePicker(!1,"outside")},this._keyDown=t=>{this._open&&"Escape"===t.key&&(t.preventDefault(),t.stopImmediatePropagation(),this._closePicker(this._floating.ownsActiveElement(),"escape"))},this._floating=new Ki(this,"color-opacity",this._keyDown),this._queuePickerPosition=()=>{if(!this._open)return;this._pickerRaf&&cancelAnimationFrame(this._pickerRaf);const t=this._window();t&&(this._pickerRaf=t.requestAnimationFrame(()=>{this._pickerRaf=0,this._positionPicker()||this._closePicker()}))}}connectedCallback(){super.connectedCallback(),this._syncFromColor(this.color,!1),this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.addEventListener("resize",this._queuePickerPosition),t?.addEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.addEventListener("resize",this._queuePickerPosition),t?.visualViewport?.addEventListener("scroll",this._queuePickerPosition),this.addEventListener("keydown",this._keyDown,!0)}disconnectedCallback(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.removeEventListener("resize",this._queuePickerPosition),t?.removeEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.removeEventListener("resize",this._queuePickerPosition),t?.visualViewport?.removeEventListener("scroll",this._queuePickerPosition),this.removeEventListener("keydown",this._keyDown,!0),this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._pickerRaf=0,this._emitRaf=0,this._closePicker(!1,"disconnect"),super.disconnectedCallback()}updated(t){if(t.has("color")){const t=Hi(this.color);t&&t!==this._lastValidColor&&this._syncFromColor(t,this._open)}this.disabled&&this._open?this._closePicker():this._open&&(this._supportsPopover()||this._renderFallback(),(t.has("color")||t.has("opacity")||t.has("showOpacity")||t.has("label")||t.has("opacityLabel")||t.has("pickerLabels"))&&this._queuePickerPosition())}_window(){return this._floating.window()}_supportsPopover(){return this._floating.usesPopover(this._forceFallback)}_dialog(){return this._floating.dialog()}async _toggle(){this.disabled||(this._open?this._closePicker():(this._forceFallback=!1,this._syncFromColor(this.color,!1),this._hexInvalid=!1,this._activePointerId=null,this._open=!0,await this.updateComplete,this._open&&(this._supportsPopover()||this._renderFallback(),this._positionPicker()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closePicker("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closePicker())))}_closePicker(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;const s=this._overlayDispose;this._overlayDispose=null,s?.();const i=this.renderRoot.querySelector(".picker");if(i?.hidePopover)try{i.matches(":popover-open")&&i.hidePopover()}catch{}this._open=!1,this._cancelQueuedEmit(),this._activePointerId=null,this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_surface(){return this._floating.surface(".picker",this._supportsPopover())}_renderFallback(){const t=Ji.styles.cssText;this._floating.renderFallback(this._pickerTemplate(!1),t)}_positionPicker(){if(!this._open)return!1;const t=this._window(),e=this.renderRoot.querySelector(".trigger");let s=this._surface();if(!t||!e?.isConnected||!s?.isConnected)return!1;const i=qi(t);if(s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden",this._supportsPopover()&&s.showPopover)try{s.matches(":popover-open")||s.showPopover()}catch{if(this._forceFallback=!0,this._renderFallback(),s=this._surface(),!s?.isConnected)return!1;s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden"}const o=e.getBoundingClientRect(),a=s.getBoundingClientRect();if(!(o.width&&o.height&&a.width&&a.height))return!1;const n=Ui(o,a,i);return s.style.left=`${n.left}px`,s.style.top=`${n.top}px`,s.dataset.side=n.side,s.style.visibility="",!0}_labels(){const t=this.pickerLabels||Vi;return{title:t.title||Vi.title,hue:t.hue||Vi.hue,saturation:t.saturation||Vi.saturation,value:t.value||Vi.value,hex:t.hex||Vi.hex,invalidHex:t.invalidHex||Vi.invalidHex}}_syncFromColor(t,e){const s=Hi(l(t,"#607d8b"))||"#607d8b",i=Gi(s);if(!i)return;const o=Wi(i);(!e||o.s>1e-4)&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._hexDraft=s,this._hexInvalid=!1,this._lastValidColor=s}_cancelQueuedEmit(t=!1){this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._emitRaf=0,t&&this._syncFromColor(this._lastValidColor,!0)}_queueHsvEmit(){if(this._emitRaf)return;const t=this._window();t?this._emitRaf=t.requestAnimationFrame(()=>{this._emitRaf=0,this._emitHsv()}):this._emitHsv()}_emitHsv(){this._emit(ji({h:this._hue,s:this._saturation,v:this._value}),this.opacity)}_setHue(t){this._hue=Math.min(359,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setSaturation(t){this._saturation=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setValue(t){this._value=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setOpacity(t){this._emit(this._lastValidColor,t)}_shiftRangeKey(t,e,s,i,o){if(!t.shiftKey)return;const a="ArrowRight"===t.key||"ArrowUp"===t.key?10:"ArrowLeft"===t.key||"ArrowDown"===t.key?-10:0;a&&(t.preventDefault(),t.stopPropagation(),o(Math.min(i,Math.max(s,e+a))))}_setSvFromPointer(t,e){const s=t.currentTarget.getBoundingClientRect();s.width&&s.height&&(this._saturation=Math.min(100,Math.max(0,(t.clientX-s.left)/s.width*100)),this._value=Math.min(100,Math.max(0,100*(1-(t.clientY-s.top)/s.height))),e?(this._cancelQueuedEmit(),this._emitHsv()):this._queueHsvEmit())}_svPointerDown(t){if(t.preventDefault(),t.stopPropagation(),null===this._activePointerId){this._activePointerId=t.pointerId;try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}this._setSvFromPointer(t,!0)}}_svPointerMove(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!1))}_svPointerUp(t){if(t.pointerId===this._activePointerId){t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!0),this._activePointerId=null;try{t.currentTarget.releasePointerCapture(t.pointerId)}catch{}}}_svPointerCancel(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._activePointerId=null,this._cancelQueuedEmit(!0))}_svLostPointerCapture(t){t.pointerId===this._activePointerId&&(this._activePointerId=null,this._cancelQueuedEmit(!0))}_hexInput(t){const e=t.target.value;this._hexDraft=e,this._hexInvalid=!1;const s=Hi(e),i=s?Gi(s):null;if(!s||!i)return;const o=Wi(i);o.s>1e-4&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._emit(s,this.opacity,!0)}_commitHex(){const t=Hi(this._hexDraft);if(!t)return this._hexDraft=this._lastValidColor,void(this._hexInvalid=!0);this._hexDraft=t,this._hexInvalid=!1,t!==this._lastValidColor&&this._emit(t,this.opacity)}_hexKeyDown(t){"Enter"===t.key&&(t.preventDefault(),t.stopPropagation(),this._commitHex())}_emit(t,e,s=!1){const i=Hi(t)||this._lastValidColor,o=Number.isFinite(e)?e:Number(this.opacity)||0,a=Math.min(1,Math.max(0,o));this.color=i,this.opacity=a,this._lastValidColor=i,s||(this._hexDraft=i),this._hexInvalid=!1,this.dispatchEvent(new CustomEvent("hp-color-opacity-change",{detail:{color:i,opacity:a},bubbles:!0,composed:!0}))}_pickerTemplate(t){const e=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),s=ji({h:this._hue,s:this._saturation,v:this._value}),i=ji({h:this._hue,s:100,v:100}),n=this._labels(),r=Math.round(this._hue),l=Math.round(this._saturation),h=Math.round(this._value);return o` + `}render(){const t=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),e=l(this.color,"#607d8b"),s=this.showOpacity?`${this.label||"Color"}: ${e}, ${t}%`:`${this.label||"Color"}: ${e}`;return o` + ${this.label?o`${this.label}`:a} + + ${this._open&&!this.disabled&&this._supportsPopover()?this._pickerTemplate(!0):a} + `}}Ji.properties={label:{type:String},opacityLabel:{type:String,attribute:"opacity-label"},color:{type:String},opacity:{type:Number},disabled:{type:Boolean,reflect:!0},showOpacity:{type:Boolean,attribute:"show-opacity"},pickerLabels:{attribute:!1},_open:{state:!0},_hue:{state:!0},_saturation:{state:!0},_value:{state:!0},_hexDraft:{state:!0},_hexInvalid:{state:!0}},Ji.styles=n` + :host { + position: relative; + display: inline-flex; + align-items: center; + gap: 6px; + min-width: 0; + } + .label { + font-size: 12px; + color: var(--secondary-text-color, #9aa4ad); + white-space: nowrap; + } + .trigger { + width: 40px; + height: 40px; + flex: none; + box-sizing: border-box; + padding: 3px; + border: 1px solid var(--divider-color, #666); + border-radius: 7px; + background: + linear-gradient(45deg, #b8b8b8 25%, transparent 25%) 0 0 / 10px 10px, + linear-gradient(45deg, transparent 75%, #b8b8b8 75%) 0 0 / 10px 10px, + linear-gradient(45deg, transparent 75%, #b8b8b8 75%) 5px -5px / 10px 10px, + linear-gradient(45deg, #b8b8b8 25%, #eee 25%) 5px 5px / 10px 10px; + cursor: pointer; + } + :host([data-pointer-hover]) .trigger:hover { + border-color: var(--primary-color, #03a9f4); + } + .trigger[aria-expanded='true'] { + border-color: var(--primary-color, #03a9f4); + outline: none; + box-shadow: 0 0 0 1px var(--primary-color, #03a9f4); + } + .trigger:focus-visible { + border-color: var(--primary-color, #03a9f4); + outline: 2px solid var(--primary-color, #03a9f4); + outline-offset: 2px; + } + .swatch { + display: block; + width: 100%; + height: 100%; + border-radius: 3px; + box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.18); + pointer-events: none; + } + .picker { + /* The popover attribute promotes this surface into the browser top layer, outside + hp-dialog's scrolling/clipping body. JS supplies viewport coordinates. */ + position: fixed; + z-index: 2147483647; + inset: auto; + top: 0; + left: 0; + width: min(292px, calc(100vw - 16px)); + max-height: calc(100vh - 16px); + margin: 0; + box-sizing: border-box; + display: grid; + gap: 10px; + padding: 12px; + overflow: auto; + color: var(--primary-text-color, #fff); + background: var(--card-background-color, #202126); + border: 1px solid var(--primary-color, #03a9f4); + border-radius: 10px; + box-shadow: 0 10px 28px rgb(0 0 0 / 0.34); + } + .picker[popover]:not(:popover-open) { + /* Keep the author-level display:grid from exposing the surface for one + frame before showPopover() promotes it into the top layer. */ + display: none; + } + .picker-head, + .row, + .control-head { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; + } + .picker-head { + justify-content: space-between; + } + .caption { + flex: 1; + min-width: 0; + overflow: hidden; + color: var(--secondary-text-color, #9aa4ad); + font-size: 12px; + text-overflow: ellipsis; + white-space: nowrap; + } + .preview { + width: 52px; + height: 30px; + flex: none; + box-sizing: border-box; + padding: 3px; + border: 1px solid var(--divider-color, #666); + border-radius: 7px; + background: + linear-gradient(45deg, #b8b8b8 25%, transparent 25%) 0 0 / 10px 10px, + linear-gradient(45deg, transparent 75%, #b8b8b8 75%) 0 0 / 10px 10px, + linear-gradient(45deg, transparent 75%, #b8b8b8 75%) 5px -5px / 10px 10px, + linear-gradient(45deg, #b8b8b8 25%, #eee 25%) 5px 5px / 10px 10px; + } + .preview > span { + display: block; + width: 100%; + height: 100%; + border-radius: 3px; + } + .sv-field { + position: relative; + width: 100%; + height: 132px; + overflow: hidden; + box-sizing: border-box; + border: 1px solid var(--divider-color, #666); + border-radius: 8px; + background: + linear-gradient(to top, #000, transparent), + linear-gradient(to right, #fff, var(--hp-picker-hue, #f00)); + cursor: crosshair; + touch-action: none; + user-select: none; + } + .sv-thumb { + position: absolute; + left: var(--hp-picker-saturation, 0%); + top: var(--hp-picker-value, 100%); + width: 14px; + height: 14px; + box-sizing: border-box; + border: 2px solid #fff; + border-radius: 50%; + box-shadow: 0 0 0 1px rgb(0 0 0 / .65), 0 1px 3px rgb(0 0 0 / .5); + transform: translate(-50%, -50%); + pointer-events: none; + } + .control { + display: grid; + gap: 2px; + min-width: 0; + } + .control-value { + flex: none; + color: var(--secondary-text-color, #9aa4ad); + font-size: 12px; + } + input[type='range'] { + width: auto; + height: 40px; + min-width: 0; + flex: 1; + margin: -5px 0; + accent-color: var(--primary-color, #03a9f4); + touch-action: none; + } + .hue-range { + accent-color: var(--hp-picker-hue, #f00); + --hp-picker-hue-track: linear-gradient(to right, + #f00 0%, #ff0 16.667%, #0f0 33.333%, #0ff 50%, + #00f 66.667%, #f0f 83.333%, #f00 100%); + --hp-picker-hue-thumb-shadow: + 0 0 0 2px var(--card-background-color, #202126), + 0 0 0 3px var(--primary-text-color, #fff); + } + .hue-range::-webkit-slider-runnable-track { + height: 10px; + box-sizing: border-box; + border: 1px solid var(--divider-color, #666); + border-radius: 999px; + background: var(--hp-picker-hue-track); + } + .hue-range::-moz-range-track { + height: 10px; + box-sizing: border-box; + border: 1px solid var(--divider-color, #666); + border-radius: 999px; + background: var(--hp-picker-hue-track); + } + .hue-range::-moz-range-progress { + height: 10px; + border: 0; + border-radius: 999px; + background: transparent; + } + .hue-range::-webkit-slider-thumb { + border-radius: 50%; + box-shadow: var(--hp-picker-hue-thumb-shadow); + } + .hue-range::-moz-range-thumb { + border-radius: 50%; + box-shadow: var(--hp-picker-hue-thumb-shadow); + } + input[type='text'], + input[type='number'] { + min-height: 40px; + box-sizing: border-box; + border: 1px solid var(--divider-color, #666); + border-radius: 6px; + padding: 6px 8px; + color: var(--primary-text-color, #fff); + background: var(--input-fill-color, transparent); + font: inherit; + } + input[type='text'] { + width: 100%; + } + input[type='number'] { + width: 50px; + flex: none; + } + input:focus-visible, + .sv-field:focus-visible { + outline: 2px solid var(--primary-color, #03a9f4); + outline-offset: 1px; + } + input[aria-invalid='true'] { + border-color: var(--error-color, #db4437); + } + .error { + color: var(--error-color, #db4437); + font-size: 11px; + line-height: 1.25; + } + .pct { + color: var(--secondary-text-color, #9aa4ad); + font-size: 12px; + } + :host([disabled]) { + opacity: .5; + pointer-events: none; + } + @media (prefers-reduced-motion: reduce) { + .picker { transition: none !important; } + } + @media (forced-colors: active) { + .hue-range::-webkit-slider-runnable-track { + border-color: ButtonText; + background: Canvas; + } + .hue-range::-moz-range-track { + border-color: ButtonText; + background: Canvas; + } + .hue-range::-webkit-slider-thumb { + box-shadow: none; + } + .hue-range::-moz-range-thumb { + box-shadow: none; + } + } + `,customElements.get("hp-color-opacity")||customElements.define("hp-color-opacity",Ji);let Yi=0;class Xi extends r{constructor(){super(...arguments),this.text="",this.ariaLabel="",this.pointerHover=!1,this._open=!1,this._openTimer=0,this._closeTimer=0,this._positionRaf=0,this._forceFallback=!1,this._hoverOwned=!1,this._overlayDispose=null,this._scrollDialog=null,this._descriptionId="hp-help-description-"+ ++Yi,this._surfacePointerEnter=()=>{const t=this._window();this._closeTimer&&t?.clearTimeout(this._closeTimer),this._closeTimer=0},this._surfacePointerLeave=()=>{this._scheduleClose()},this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closeHelp(!1,"outside")},this._dialogScroll=t=>{const e=this._floating.containsPath(t.composedPath()),s=t.target,i=this._dialog(),o=s instanceof Node&&(s===i||s instanceof Element&&s.contains(this));var a;this._open&&(a=o,!e&&a)&&this._closeHelp(!1,"scroll")},this._keyDown=t=>{if(!this._open||t.defaultPrevented)return;if("Escape"===t.key)return t.preventDefault(),t.stopImmediatePropagation(),void this._closeHelp(this._floating.ownsActiveElement(),"escape");const e=this.renderRoot.querySelector(".trigger");if(!e||!t.composedPath().includes(e))return;const s=this._surface();if(!s||s.scrollHeight<=s.clientHeight)return;const i=Math.max(40,.8*s.clientHeight),o={ArrowDown:40,ArrowUp:-40,PageDown:i,PageUp:-i};if("Home"===t.key)s.scrollTop=0;else if("End"===t.key)s.scrollTop=s.scrollHeight;else{if(!(t.key in o))return;s.scrollBy({top:o[t.key],behavior:"auto"})}t.preventDefault(),t.stopImmediatePropagation()},this._floating=new Ki(this,"help",this._keyDown),this._queuePosition=()=>{if(!this._open||this._positionRaf)return;const t=this._window();t&&(this._positionRaf=t.requestAnimationFrame(()=>{this._positionRaf=0,this._position()||this._closeHelp()}))}}connectedCallback(){super.connectedCallback(),this.addEventListener("keydown",this._keyDown,!0)}willUpdate(){this.toggleAttribute("data-has-content",this._hasContent())}disconnectedCallback(){const t=this.ownerDocument.defaultView;this._unsubscribeOpenListeners(),this.removeEventListener("keydown",this._keyDown,!0),this._clearTimers(),this._positionRaf&&t?.cancelAnimationFrame(this._positionRaf),this._positionRaf=0,this._closeHelp(!1,"disconnect"),super.disconnectedCallback()}updated(t){if(t.has("pointerHover")&&!this.pointerHover){const t=this._window();this._openTimer&&t?.clearTimeout(this._openTimer),this._openTimer=0,this._hoverOwned&&this._closeHelp(!1,"outside")}this._hasContent()||!this._open?this._open&&t.has("text")&&(this._usesPopover()||this._renderFallback(),this._queuePosition()):this._closeHelp()}_window(){return this._floating.window()}_dialog(){return this._floating.dialog()}_usesPopover(){return this._floating.usesPopover(this._forceFallback)}_hasContent(){return t=this.text,e=this.ariaLabel,"string"==typeof t&&t.trim().length>0&&"string"==typeof e&&e.trim().length>0;var t,e}_clearTimers(){const t=this._window();this._openTimer&&t?.clearTimeout(this._openTimer),this._closeTimer&&t?.clearTimeout(this._closeTimer),this._openTimer=0,this._closeTimer=0}_scheduleOpen(){const t=this._window();this.pointerHover&&t&&!this._open&&!this._openTimer&&(this._closeTimer&&t.clearTimeout(this._closeTimer),this._closeTimer=0,this._openTimer=t.setTimeout(()=>{this._openTimer=0,this.isConnected&&(this._hoverOwned=!0,this._openHelp())},300))}_scheduleClose(){const t=this._window(),e=this.renderRoot.querySelector(".trigger");t&&!e?.matches(":focus-visible")&&(this._openTimer&&t.clearTimeout(this._openTimer),this._closeTimer&&t.clearTimeout(this._closeTimer),this._openTimer=0,this._closeTimer=t.setTimeout(()=>{this._closeTimer=0,this.isConnected&&this._closeHelp()},150))}_triggerPointerEnter(t){this.pointerHover&&"mouse"===t.pointerType&&this._scheduleOpen()}_triggerPointerLeave(t){"mouse"===t.pointerType&&this._scheduleClose()}_triggerFocus(){queueMicrotask(()=>{const t=this.renderRoot.querySelector(".trigger");t?.matches(":focus-visible")&&(this._hoverOwned=!1,this._openHelp())})}_triggerBlur(){this._scheduleClose()}_triggerClick(){this._open?this._closeHelp():(this._hoverOwned=!1,this._openHelp())}_subscribeOpenListeners(){this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("keydown",this._keyDown,!0);const t=this._window();t?.addEventListener("resize",this._queuePosition),t?.addEventListener("orientationchange",this._queuePosition),t?.visualViewport?.addEventListener("resize",this._queuePosition),t?.visualViewport?.addEventListener("scroll",this._queuePosition),this._scrollDialog=this._dialog(),this._scrollDialog?.addEventListener("scroll",this._dialogScroll,!0)}_unsubscribeOpenListeners(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("keydown",this._keyDown,!0);const t=this._window();t?.removeEventListener("resize",this._queuePosition),t?.removeEventListener("orientationchange",this._queuePosition),t?.visualViewport?.removeEventListener("resize",this._queuePosition),t?.visualViewport?.removeEventListener("scroll",this._queuePosition),this._scrollDialog?.removeEventListener("scroll",this._dialogScroll,!0),this._scrollDialog=null}async _openHelp(){!this._open&&this._hasContent()&&(this._clearTimers(),this._forceFallback=!1,this._open=!0,this._subscribeOpenListeners(),await this.updateComplete,this._open&&(this._usesPopover()||this._renderFallback(),this._position()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closeHelp("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closeHelp()))}_closeHelp(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;this._clearTimers();const s=this._overlayDispose;this._overlayDispose=null,s?.();const i=this.renderRoot.querySelector(".tooltip");if(i?.hidePopover)try{i.matches(":popover-open")&&i.hidePopover()}catch{}this._open=!1,this._hoverOwned=!1,this._unsubscribeOpenListeners(),this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_tooltipTemplate(t){return o``}_renderFallback(){const t=Xi.styles.cssText;this._floating.renderFallback(this._tooltipTemplate(!1),t)}_surface(){return this._floating.surface(".tooltip",this._usesPopover())}_position(){if(!this._open)return!1;const t=this._window(),e=this.renderRoot.querySelector(".trigger");let s=this._surface();if(!t||!e?.isConnected||!s?.isConnected)return!1;const i=qi(t);if(s.style.maxWidth=`${Math.max(0,Math.min(320,i.width-16))}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden",this._usesPopover()&&s.showPopover)try{s.matches(":popover-open")||s.showPopover()}catch{if(this._forceFallback=!0,this._renderFallback(),s=this._surface(),!s?.isConnected)return!1;s.style.visibility="hidden"}const o=e.getBoundingClientRect(),a=s.getBoundingClientRect();if(!(o.width&&o.height&&a.width&&a.height))return!1;const n=Ui(o,a,i);return s.style.left=`${n.left}px`,s.style.top=`${n.top}px`,s.dataset.side=n.side,s.style.visibility="",!0}render(){if(!this._hasContent())return a;const t=this.ariaLabel.trim();return o` + ${this.text} + + ${this._usesPopover()?this._tooltipTemplate(!0):a} + `}}Xi.properties={text:{type:String},ariaLabel:{type:String,attribute:"aria-label"},pointerHover:{type:Boolean,attribute:"data-pointer-hover",reflect:!0},_open:{state:!0},_forceFallback:{state:!0}},Xi.styles=n` + :host { + display: none; + flex: none; + vertical-align: middle; + } + + :host([data-has-content]) { + display: inline-flex; + } + + .trigger { + width: 32px; + height: 32px; + display: inline-flex; + align-items: center; + justify-content: center; + flex: none; + box-sizing: border-box; + padding: 0; + color: var(--secondary-text-color, #9aa4ad); + background: transparent; + border: 0; + border-radius: 50%; + cursor: help; + -webkit-tap-highlight-color: transparent; + } + + .trigger svg { + display: block; + width: 18px; + height: 18px; + fill: currentColor; + } + + :host([data-pointer-hover]) .trigger:hover, + .trigger:focus-visible, + .trigger[aria-expanded='true'] { + color: var(--primary-text-color, #fff); + background: rgb(127 127 127 / 0.18); + outline: none; + } + + .trigger:focus-visible { + box-shadow: 0 0 0 2px var(--primary-color, #03a9f4); + } + + .tooltip { + position: fixed; + z-index: 2147483647; + inset: auto; + top: 0; + left: 0; + width: max-content; + max-width: min(320px, calc(100vw - 16px)); + max-height: calc(100vh - 16px); + margin: 0; + box-sizing: border-box; + padding: 9px 11px; + overflow: auto; + color: var(--primary-text-color, #fff); + background: var(--card-background-color, #202126); + border: 1px solid var(--divider-color, rgb(255 255 255 / 0.2)); + border-radius: 9px; + box-shadow: 0 8px 24px rgb(0 0 0 / 0.32); + font: 400 13px/1.4 system-ui, sans-serif; + text-align: start; + white-space: normal; + overflow-wrap: anywhere; + opacity: 1; + transform: translateY(0); + transition: opacity 120ms ease, transform 120ms ease; + } + + .tooltip[data-side='top'] { + transform-origin: bottom center; + } + + .tooltip[data-side='bottom'] { + transform-origin: top center; + } + + .tooltip[popover]:not(:popover-open) { + display: none; + } + + @starting-style { + .tooltip { + opacity: 0; + transform: translateY(3px); + } + } + + .sr-only { + /* Keep the accessibility-only description outside every dialog scroll + container's overflow geometry. Toggling the hidden attribute on the former + absolutely-positioned node made some browsers add a vertical + scrollbar while help was open, even though the visible tooltip was + already in the Popover top layer / fixed fallback portal. */ + position: fixed; + inset: 0 auto auto 0; + width: 1px; + height: 1px; + padding: 0; + margin: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + clip-path: inset(50%); + white-space: nowrap; + border: 0; + } + + @media (pointer: coarse) { + .trigger { + width: 40px; + height: 40px; + } + } + + @media (prefers-reduced-motion: reduce) { + .tooltip { + transition: none; + } + } + `,customElements.get("hp-help")||customElements.define("hp-help",Xi);const Zi=new WeakMap;function Qi(t){const e=function(t){const e=t?.connection||t;return!e||"object"!=typeof e&&"function"!=typeof e?null:e}(t);if(!e)return null;let s=Zi.get(e);return s||(s={revision:0,loaded:!1,configEntries:{},manifests:{},listeners:new Set,refs:0},Zi.set(e,s)),s}function to(t){t.revision++;for(const e of[...t.listeners])try{e()}catch{}}function eo(t,e){const s=Qi(t);if(!s)return()=>{};s.refs++,s.listeners.add(e),async function(t,e){e.loading||"function"!=typeof t?.callWS?e.loading:e.loaded&&e.loadedAt&&Date.now()-e.loadedAt<3e5||(e.loading=(async()=>{const[s,i]=await Promise.allSettled([t.callWS({type:"config_entries/get"}),t.callWS({type:"manifest/list"})]);"fulfilled"===s.status&&Array.isArray(s.value)&&(e.configEntries=Object.fromEntries(s.value.filter(t=>"string"==typeof t?.entry_id).map(t=>[t.entry_id,t]))),"fulfilled"===i.status&&Array.isArray(i.value)&&(e.manifests=Object.fromEntries(i.value.filter(t=>"string"==typeof t?.domain).map(t=>[t.domain,t]))),e.loaded=!0,e.loadedAt=Date.now(),e.loading=void 0,to(e)})().catch(()=>{e.loaded=!0,e.loadedAt=Date.now(),e.loading=void 0,to(e)}),e.loading)}(t,s),async function(t,e){if(e.unsubscribe||e.subscribing)return e.subscribing;const s=t?.connection?.subscribeMessage;"function"==typeof s&&(e.subscribing=(async()=>{try{e.unsubscribe=await s.call(t.connection,t=>{const s=Array.isArray(t)?t:Array.isArray(t?.entries)?t.entries:t?[t]:[];let i=!1;const o={...e.configEntries};for(const t of s){const e=t?.entry||t?.data?.entry||("string"==typeof t?.entry_id?t:null),s=e?.entry_id;if("string"!=typeof s)continue;const a=t?.type||t?.action||t?.data?.action;"removed"===a||"remove"===a?delete o[s]:o[s]=e,i=!0}i&&(e.configEntries=o,to(e))},{type:"config_entries/subscribe"})}catch{}finally{0===e.refs&&(e.unsubscribe?.(),e.unsubscribe=void 0),e.subscribing=void 0}})(),e.subscribing)}(t,s);let i=!1;return()=>{i||(i=!0,s.listeners.delete(e),s.refs=Math.max(0,s.refs-1),s.refs||(s.unsubscribe?.(),s.unsubscribe=void 0))}}function so(t){const e=Qi(t);return e?{revision:e.revision,loaded:e.loaded,configEntries:e.configEntries,manifests:e.manifests}:{revision:0,loaded:!1,configEntries:{},manifests:{}}}function io(t,e,s=so(t),i){const o=s.manifests[e];return function(t,e){if("function"!=typeof t?.localize)return"";try{const s=`component.${e}.title`,i=t.localize(s);return"string"==typeof i&&i!==s?i:""}catch{return""}}(t,e)||String(o?.name||"")||String(i||"")||e.replace(/_/g," ")}function oo(t,e,s,i,o){const a=String(e||"").trim();if(!a)return null;const n=o?i.configEntries[o]:null;return{domain:a,label:io(t,a,i,n?.title),configEntryId:o,configEntryTitle:n?.title,confidence:s}}function ao(t){const e={"registry-owner":0,"entity-platform":1,"identifier-fallback":2},s=new Set;return t.filter(t=>!!t).sort((t,s)=>e[t.confidence]-e[s.confidence]||t.label.localeCompare(s.label)||t.domain.localeCompare(s.domain)).filter(t=>{const e=`${t.domain}\n${t.configEntryId||""}`;return!s.has(e)&&(s.add(e),!0)})}function no(t,e,s,i=so(t)){const o=s.entities?.[e]||t?.entities?.[e];if(!o)return null;const a=o.config_entry_id||void 0,n=a?i.configEntries[a]?.domain:"";return oo(t,o.platform||n,"entity-platform",i,a)}class ro extends r{constructor(){super(...arguments),this.deviceName="",this._metadataConnection=null,this._demoUntil=0,this._demoTimer=0,this._demoGeneration=1,this._demoKind=null,this._reducedMotion=!1,this._onMotionChange=t=>{this._reducedMotion=t.matches,this.requestUpdate()},this._startShortDemo=()=>{const t=this.presentation;t&&"icon_ripple"===t.display&&"none"===t.pulse.kind&&(this._demoGeneration++,this._demoKind="short",this._demoUntil=Date.now()+3300,window.clearTimeout(this._demoTimer),this._demoTimer=window.setTimeout(()=>{this._demoUntil=0,this._demoTimer=0,this._demoKind=null,this.requestUpdate()},3330),this.requestUpdate())},this._toggleContinuousDemo=()=>{const t=this.presentation;t&&"icon_ripple"===t.display&&"none"===t.pulse.kind&&("continuous"===this._demoKind?this._clearDemo():(this._clearDemo(),this._demoGeneration++,this._demoKind="continuous",this._demoUntil=Number.POSITIVE_INFINITY),this.requestUpdate())}}connectedCallback(){super.connectedCallback(),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this._ensureMetadata()}disconnectedCallback(){this._metadataRelease?.(),this._metadataRelease=void 0,this._metadataConnection=null,this._clearDemo(),this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,super.disconnectedCallback()}willUpdate(t){t.has("hass")&&this._ensureMetadata();const e=this.presentation,s=t.get("presentation");t.has("presentation")&&s?.binding!==e?.binding&&this._clearDemo(),e&&this._demoKind&&("icon_ripple"!==e.display||"none"!==e.pulse.kind)&&this._clearDemo()}_ensureMetadata(){const t=this.hass?.connection||null;t&&t!==this._metadataConnection&&(this._metadataRelease?.(),this._metadataConnection=t,this._metadataRelease=eo(this.hass,()=>this.requestUpdate()))}_clearDemo(){window.clearTimeout(this._demoTimer),this._demoTimer=0,this._demoUntil=0,this._demoKind=null}get _lang(){return d(this.hass)}_t(t,e){return p(this._lang,t,e)}_providerText(t){return"houseplan"===t.domain?this._t("marker.preview.virtual_provider"):t.label.toLowerCase()===t.domain.toLowerCase()?t.domain:`${t.label} (${t.domain})`}_providers(){return this.presentation&&this.registry?function(t,e,s,i=so(t)){if("virtual"===e)return[{domain:"houseplan",label:"House Plan",confidence:"registry-owner"}];const o=e.indexOf(":");if(o<1)return[];const a=e.slice(0,o),n=e.slice(o+1);if("entity"===a){const e=no(t,n,s,i);return e?[e]:[]}if("device"!==a)return[];const r=s.devices?.[n]||t?.devices?.[n];if(!r)return[];const l=[r.config_entry_id,...Array.isArray(r.config_entries)?r.config_entries:[]].filter(t=>"string"==typeof t&&!!t).map(e=>{const s=i.configEntries[e];return oo(t,s?.domain,"registry-owner",i,e)});if(l.some(Boolean))return ao(l);const h=[];for(const[e,o]of Object.entries(s.entities||{}))o?.device_id===n&&null==o?.disabled_by&&h.push(no(t,e,s,i));return h.some(Boolean)?ao(h):ao((Array.isArray(r.identifiers)?r.identifiers:[]).map(e=>{const s=Array.isArray(e)?e[0]:null;return oo(t,s,"identifier-fallback",i)}))}(this.hass,this.presentation.binding,this.registry,so(this.hass)):[]}_providerSummary(t){if(!t.length)return this._t("marker.preview.unknown_provider");const e=t.slice(0,2).map(t=>this._providerText(t)),s=t.length-e.length;return e.join(", ")+(s>0?` · ${this._t("marker.preview.more_sources",{n:s})}`:"")}_sourceSummary(t){const e=t.visualSources;return e.length?1===e.length?`${e[0].name} · ${e[0].eid} · ${this._sourceProvider(e[0].eid)}`:2===e.length?e.map(t=>t.name).join(" · "):this._t("marker.preview.multiple_sources",{n:e.length}):this._t("marker.preview.no_source")}_stateSummary(t){if(!t.visualSources.length)return this._t("marker.preview.no_state");if(1===t.visualSources.length)return t.visualSources[0].stateText||this._t("marker.preview.no_state");const e=[...new Set(t.visualSources.map(t=>t.stateText).filter(Boolean))];return 1===e.length?e[0]:this._t("marker.preview.mixed_states")}_reason(t){return this._t(`marker.preview.reason.${t}`)}_sourceProvider(t){if(!this.registry)return this._t("marker.preview.unknown_provider");const e=no(this.hass,t,this.registry,so(this.hass));return e?this._providerText(e):this._t("marker.preview.unknown_provider")}render(){const t=this.presentation;if(!t)return a;const e=!!this._demoKind&&this._demoUntil>Date.now()&&"icon_ripple"===t.display&&"none"===t.pulse.kind,s=e?(()=>{const e=_(t.pulse,this._demoKind,this._demoGeneration,this._reducedMotion,"short"===this._demoKind?this._demoUntil:null);return{...t,pulse:e,classes:[...t.classes.filter(t=>!t.startsWith("pulse-")),`pulse-${e.kind}`,...e.generation%2==0?["pulse-gen2"]:[]]}})():t,i=this._providers(),n="none"!==t.pulse.kind,r=s.scale*(s.pulse.animated?s.pulse.diameterScale:1);let l=-r/2,h=r/2,c=-r/2,d=r/2;if(s.valueBadge){const t=s.scale*Math.min(4,Math.max(.9,.29*s.valueBadge.text.length+.28)),e=.7*s.scale,i=.6*s.scale;"right"===s.valueBadge.position&&(h=Math.max(h,i+t)),"left"===s.valueBadge.position&&(l=Math.min(l,-i-t)),"top"===s.valueBadge.position&&(c=Math.min(c,-i-e)),"bottom"===s.valueBadge.position&&(d=Math.max(d,i+e))}if(null!=s.lqiText){const t=s.scale*("bottom"===s.valueBadge?.position?1.55:.95);d=Math.max(d,t)}const p=Math.min(1,2.35/Math.max(1,h-l),2.35/Math.max(1,d-c)),b=Math.round(100*p),y=[`left:calc(50% - ${54*((l+h)/2)*p}px)`,`top:calc(50% - ${54*((c+d)/2)*p}px)`,p<1?`transform:scale(${p})`:""].filter(Boolean).join(";"),v=["dev",u(this.hass),...s.classes,"virtual"===s.binding?"virtual":"",s.haDisabled?"ghost ha-disabled":"",null!=s.valueText?"valonly":""].filter(Boolean).join(" "),$=m(s).join(";"),w=e?this._t("continuous"===this._demoKind?"marker.preview.demo_continuous_notice":"marker.preview.demo_short_notice"):this._reason(t.explanation.reason),k=[this.deviceName,this._providerSummary(i),this._stateSummary(t),w,t.valueFullText||"",g(t.valueBadge),null!=t.lqiText&&t.lqiBand?this._t(`marker.lqi_a11y_${t.lqiBand}`,{value:t.lqiText}):""].filter(Boolean).join(". ");return o`
+
+ ${this._t("marker.preview.title")} + + ${this._t(e?"marker.preview.example":"marker.preview.actual")} + +
+
+ +
+
${this._t("marker.preview.integration")}${this._providerSummary(i)}
+
${this._t("marker.preview.source")}${this._sourceSummary(t)}
+
${this._t("marker.preview.current_state")}${this._stateSummary(t)}
+
${this._t("marker.preview.result")}${w}
+ ${t.fallbackReason?o`

${this._reason(t.fallbackReason)}

`:a} + ${t.explanation.notices.map(t=>o`

${this._reason(t)}

`)} + ${p<1?o`

${this._t("marker.preview.scaled",{n:b})}

`:a} + ${e&&this._reducedMotion?o`

${this._t("marker.preview.reduced_motion")}

`:a} +
+
+ ${t.visualSources.length||t.criticalSources.length?o`
+ ${this._t("marker.preview.details")} +
+ ${[...t.visualSources,...t.criticalSources].map(t=>o` +
+ ${t.name}${t.eid} + ${t.stateText||t.state} + ${this._sourceProvider(t.eid)} +
`)} +
+
`:a} + ${"icon_ripple"===t.display?o`
+ + +
`:a} +
`}}ro.properties={hass:{attribute:!1},presentation:{attribute:!1},registry:{attribute:!1},deviceName:{attribute:!1}},ro.styles=[c,n` + :host { display: block; min-width: 0; } + .devicepreview { + margin: 4px 0 14px; + padding: 14px; + border: 1px solid var(--divider-color, rgba(127, 127, 127, 0.28)); + border-radius: 14px; + background: color-mix(in srgb, var(--card-background-color, #20232b) 92%, var(--primary-color, #03a9f4)); + color: var(--primary-text-color, #fff); + overflow: hidden; + } + .previewhead { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; } + .previewbadge { + padding: 3px 9px; + border-radius: 999px; + color: var(--secondary-text-color, #9aa0aa); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 12%, transparent); + font-size: 12px; + font-weight: 700; + } + .previewbadge.example { color: var(--warning-color, #ffb300); } + .previewgrid { display: grid; grid-template-columns: minmax(170px, 0.8fr) minmax(240px, 1.2fr); gap: 16px; align-items: stretch; } + .previewstage { + position: relative; + min-height: 168px; + border-radius: 12px; + background: var(--secondary-background-color, rgba(0, 0, 0, 0.16)); + overflow: hidden; + pointer-events: none; + container-type: inline-size; + --icon-size: 54px; + --device-base-size: 48.6px; + } + .previewfit { position: absolute; left: 50%; top: 50%; transform-origin: center; } + .previewstage .dev { left: 0; top: 0; cursor: default; } + :host([data-pointer-hover]) .previewstage .dev:hover { z-index: 2; } + .previewfacts { min-width: 0; display: grid; align-content: start; gap: 8px; } + .previewfacts > div { display: grid; grid-template-columns: minmax(115px, 0.8fr) minmax(0, 1.3fr); gap: 8px; } + .previewfacts span { color: var(--secondary-text-color, #9aa0aa); } + .previewfacts b { min-width: 0; overflow-wrap: anywhere; } + .previewnotice { margin: 2px 0 0; color: var(--secondary-text-color, #9aa0aa); font-size: 13px; } + .previewdetails { margin-top: 12px; } + .previewdetails summary { cursor: pointer; color: var(--secondary-text-color, #9aa0aa); } + .previewtable { display: grid; gap: 8px; margin-top: 9px; } + .previewsource { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 3px 10px; font-size: 13px; } + .previewsource > * { min-width: 0; overflow-wrap: anywhere; } + .previewsource code { color: var(--secondary-text-color, #9aa0aa); } + .previewdemo { + min-height: 40px; + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + border: 1px solid var(--divider-color, rgba(127, 127, 127, 0.35)); + border-radius: 10px; + background: transparent; + color: inherit; + cursor: pointer; + } + .previewdemos { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; } + .previewdemo:focus-visible { outline: 2px solid var(--primary-color, #03a9f4); outline-offset: 2px; } + .previewdemo:disabled { opacity: 0.5; cursor: not-allowed; } + @media (max-width: 640px) { + .previewgrid { grid-template-columns: minmax(0, 1fr); } + .previewstage { min-height: 142px; } + .previewfacts > div { grid-template-columns: minmax(0, 1fr); gap: 2px; } + } + `],customElements.get("hp-device-preview")||customElements.define("hp-device-preview",ro);const lo=(t,e)=>[t[0]-e[0],t[1]-e[1]],ho=(t,e)=>[t[0]+e[0],t[1]+e[1]],co=(t,e)=>t[0]*e[0]+t[1]*e[1],po=t=>Math.hypot(t[0],t[1]);function _o(t){let e=0;for(let s=0;st[1]!=l>t[1]&&t[0]<(r-a)*(t[1]-n)/(l-n)+a&&(s=!s)}return s}([r[0]+n[0]*l,r[1]+n[1]*l],t)&&(n=[-n[0],-n[1]]),n}function go(t){const e=t.length;if(e<3)return!1;for(let s=0;s(t[0]-o[0])*r[1]-(t[1]-o[1])*r[0],h=t=>(t[0]-o[0])*r[0]+(t[1]-o[1])*r[1],c=s,d=n-s;for(const e of t){const t=Math.abs(l(e));if(t<=s)continue;const o=h(e);o<=c||o>=d||tMath.abs(n+(t-p)/g*(r-n));i=Math.min(i,f(u),f(m))}}return i}function bo(t,e,s){if($(t,e,s))return!0;if(v(t,e,s)||v(e,t,s))return!1;let i=0;try{const s=w([[...t.map(t=>[t[0],t[1]]),[t[0][0],t[0][1]]]],[[...e.map(t=>[t[0],t[1]]),[e[0][0],e[0][1]]]]);for(const t of s)t?.[0]&&(i+=k(t[0]))}catch{return!1}return i>Math.max(1e-7,s*s)}function yo(t,e,s){for(const i of e)for(let e=0;es)continue;const h=(t.x-o[0])*l[0]+(t.y-o[1])*l[1];if(h-t.length/2>=-s&&h+t.length/2<=r+s)return!0}return!1}function vo(t,e,s){const i=Math.abs(e[0]-t[0]),o=Math.abs(e[1]-t[1]);return i<=s&&o>s?"v":o<=s&&i>s?"h":null}function $o(t,e,s){return Math.abs(t[0]-e[0])<=s&&Math.abs(t[1]-e[1])<=s}function wo(t,e,s,i,o){return $o(t,s,o)&&$o(e,i,o)||$o(t,i,o)&&$o(e,s,o)}function ko(t,e,s,i,o){const a=vo(t,e,o);return a&&vo(s,i,o)===a?"h"===a?Math.abs(t[1]-s[1])>o||Math.abs(t[1]-i[1])>o?0:Math.max(0,Math.min(Math.max(t[0],e[0]),Math.max(s[0],i[0]))-Math.max(Math.min(t[0],e[0]),Math.min(s[0],i[0]))):Math.abs(t[0]-s[0])>o||Math.abs(t[0]-i[0])>o?0:Math.max(0,Math.min(Math.max(t[1],e[1]),Math.max(s[1],i[1]))-Math.max(Math.min(t[1],e[1]),Math.min(s[1],i[1]))):0}function xo(t,e,s,i){const o=t.length,a=vo(t[(e-1+o)%o],t[e],i),n=vo(t[(e+1)%o],t[(e+2)%o],i),r="h"===s?"v":"h";return a===r&&n===r}function So(t){let e=1/0,s=1/0,i=-1/0,o=-1/0;for(const a of t)e=Math.min(e,a[0]),s=Math.min(s,a[1]),i=Math.max(i,a[0]),o=Math.max(o,a[1]);return[e,s,i,o]}function Mo(t,e,s){const i=So(t),o=So(e);return i[2]o}const Co=(t,e)=>"h"===e?t[0]:t[1],Po=(t,e)=>"h"===e?t[1]:t[0];function Io(t,e,s,i,o){const a=t.find(t=>t.id===e);if(!a)return null;const n=a.poly[s],r=a.poly[(s+1)%a.poly.length],l=vo(n,r,o);if(!l)return null;const h=0===i?r:n,c=0===i?n:r,d=Co(h,l),p=Co(c,l),_=Po(h,l),u=function(t,e,s,i){const o=[];for(const a of t)for(let t=0;ti||Math.abs(Po(r,e)-s)>i)continue;const l=Co(n,e),h=Co(r,e),c=Math.min(l,h),d=Math.max(l,h);d-c>i&&o.push({roomId:a.id,edge:t,lo:c,hi:d})}return o.sort((t,e)=>t.lo-e.lo||t.hi-e.hi||t.roomId.localeCompare(e.roomId)||t.edge-e.edge)}(t,l,_,o),m=function(t,e,s,i){const o=[e,s];for(const a of t){const t=Math.max(e,a.lo),n=Math.min(s,a.hi);n-t>i&&o.push(t,n)}const a=[...new Set(o)].sort((t,e)=>t-e),n=[];for(let e=0;e+1r>t.lo-i&&rt.roomId))].sort();n.push({lo:s,hi:o,owners:l})}return n}(u,Math.min(d,p),Math.max(d,p),o);return!m.length||m.some(t=>t.owners.length<1||t.owners.length>2)?null:{roomId:e,edge:s,movedEndpoint:i,axis:l,line:_,fixed:d,moving:p,intervals:u,baseline:m}}function To(t,e,s){const i=[];for(const o of t.intervals){const a=e.polys[o.roomId];if(!a){i.push(o);continue}if(o.edge<0||o.edge>=a.length)continue;const n=a[o.edge],r=a[(o.edge+1)%a.length];if(vo(n,r,s)!==t.axis||Math.abs(Po(n,t.axis)-t.line)>s||Math.abs(Po(r,t.axis)-t.line)>s)continue;const l=Co(n,t.axis),h=Co(r,t.axis),c=Math.min(l,h),d=Math.max(l,h);d-c>s&&i.push({...o,lo:c,hi:d})}return i}function Ro(t,e,s){return new Set(t.filter(t=>e>t.lo-s&&et.roomId)).size}function Fo(t,e,s){for(const i of e.sideOwnership){const e=t.polys[i.roomId];if(!e)return!1;const o=e[i.edge],a=e[(i.edge+1)%e.length];if(vo(o,a,s)!==i.axis)return!1;const n=Co(0===i.movedEndpoint?o:a,i.axis),r=To(i,t,s),l=(i.moving>=i.fixed?i.baseline[i.baseline.length-1]:i.baseline[0]).owners.length;if(l<1||l>2)return!1;const h=Math.min(i.fixed,i.moving,n),c=Math.max(i.fixed,i.moving,n),d=[h,c,i.fixed,i.moving,n];for(const t of i.intervals)d.push(t.lo,t.hi);for(const t of r)d.push(t.lo,t.hi);const p=[...new Set(d.filter(t=>t>=h&&t<=c))].sort((t,e)=>t-e),_=Math.min(i.fixed,i.moving),u=Math.max(i.fixed,i.moving),m=Math.min(i.fixed,n),g=Math.max(i.fixed,n);for(let t=0;t+1_-s&&am-s&&a2||d>2)return!1;if(n&&h){if(c!==d)return!1}else if(!n&&h){if(d!==l||c>0&&c!==d)return!1}else if(2===c?2!==d:d>1)return!1}}return!0}function No(t,e,s,i){const o=[s.n[0]*i,s.n[1]*i],a={polys:{},openings:{},movedSpans:{}};for(const e of s.roomIds){const i=t.find(t=>t.id===e),n=s.edgeByRoom[e];if(!i||null==n)continue;const r=(n+1)%i.poly.length;a.polys[e]=i.poly.map((t,e)=>e===n||e===r?ho(t,o):[...t]),a.movedSpans[e]=[[ho(i.poly[n],o),ho(i.poly[r],o)]]}for(const t of e)s.movingOpeningIds.includes(t.id)&&(a.openings[t.id]=[t.x+o[0],t.y+o[1]]);return a}function zo(t,e,s,i,o,a,n,r){if(!function(t,e,s,i){if(uo([t.x,t.y],e,s)>2*i)return!1;const o=po(lo(s,e));if(o<=i)return!1;const a=[(s[0]-e[0])/o,(s[1]-e[1])/o],n=(t.x-e[0])*a[0]+(t.y-e[1])*a[1];return n>=-i&&n<=o+i}(t,e,s,r))return!0;if(uo([t.x,t.y],i,o)>2*r)return!1;const l=0===a?i:o;return po(lo([t.x,t.y],l))>=t.length/2+n-r}function Ao(t,e,s,i){const o=i.movingHalf||0;return"circle"===t.kind?uo(t.center,e,s)2)return!1;const r=No(t,e,s,i);if(Object.keys(r.polys).length!==s.roomIds.length)return!1;if(!Fo(r,s,a))return!1;const l=new Set(s.roomIds),h=t=>r.polys[t.id]||t.poly;for(const i of s.roomIds){const l=t.find(t=>t.id===i),h=r.polys[i],c=s.edgeByRoom[i];if(!l||!h||h.length!==s.topology[i]||h.length!==l.poly.length||!go(h))return!1;const d=l.poly.length,p=(c-1+d)%d,_=[p,c,(c+1)%d];for(const t of _)if(y(h[t],h[(t+1)%d]))return!1;const u=_o(l.poly),m=_o(h);if(Math.abs(m)t.id===e),i=r.polys[e];for(const o of t){if(o.id===e||l.has(o.id))continue;const t=h(o);if(!Mo(s.poly,o.poly,a)||!Mo(i,t,a))if(v(s.poly,o.poly,a)){if(!v(i,t,a))return!1}else if(v(o.poly,s.poly,a)){if(!v(t,i,a))return!1}else if(v(i,t,a)||v(t,i,a)||bo(i,t,a))return!1}}t.find(t=>t.id===s.roomId);const c=r.polys[s.roomId],d=s.edgeByRoom[s.roomId],p=c[d],_=c[(d+1)%c.length];if(Math.abs(i)>a)for(const t of o.obstacles||[])if(Ao(t,p,_,o))return!1;for(const t of e){if(!s.movingOpeningIds.includes(t.id))continue;const e=r.openings[t.id];if(!e||t.hosted)return!1;if(!yo({...t,x:e[0],y:e[1]},[c],2*a))return!1}return!0}const Lo=new WeakMap,Eo=t=>"number"==typeof t&&Number.isFinite(t),Bo=(t,e)=>{const s=new Map;for(const i of t||[])!Eo(i?.cm)||!e&&i.cm<=0||s.set(i.cm,(s.get(i.cm)||0)+1);return s},Ho=t=>[String(t),"см"].join(" ");function Go(t,e,s={}){if(s.allowClear)return[];const i=!0===s.exactMultiplicity,o=Bo(t,i),a=Bo(e,i),n=[];for(const[t,e]of o){const s=a.get(t)||0;0===s?n.push({invariant:"wall_records",kind:"lost",owner:Ho(t),reference:`было ${e}`,detail:"записи этой толщины исчезли целиком"}):i&&s!==e&&n.push({invariant:"wall_records",kind:"count",owner:Ho(t),reference:`было ${e}, стало ${s}`,detail:"изменилось число записей этой толщины"})}if(i)for(const[t,e]of a)o.has(t)||n.push({invariant:"wall_records",kind:"count",owner:Ho(t),reference:`было 0, стало ${e}`,detail:"появились записи новой толщины"});return n}class Wo{constructor(){this._selectedRoomId=null,this._session=null,this._eligibility=null}get dragging(){return null!==this._session}ownsPointer(t){return this._session?.pointerId===t}get selectedRoomId(){return this._selectedRoomId}get snapshotIdentity(){return this._session?.snapshotIdentity||null}get activePointerId(){return this._session?.pointerId??null}get moved(){return!0===this._session?.moved}get delta(){return this._session?.delta||0}get rooms(){return this._session?.rooms||null}get openings(){return this._session?.openings||null}get plan(){return this._session?.plan||null}get preview(){return this._session?.accepted?.preview||null}get liveLabels(){return this._session?.accepted?.labels||null}selectRoom(t){this._selectedRoomId=t}restoreSelection(t){this._selectedRoomId=t}escapeIdle(){return this._selectedRoomId?(this._selectedRoomId=null,"selection-cleared"):"exit-tool"}resolve(t,e,s){this._eligibility&&this._eligibility.context===t||(this._eligibility={context:t,values:new Map});const i=this._eligibility.values.get(e);if(i)return i;const o=s();return this._eligibility.values.set(e,o),o}begin(t){return!this._session&&(this._session={pointerId:t.pointerId,start:[...t.start],roomId:t.roomId,plan:t.plan,options:t.options,rooms:t.rooms,openings:t.openings,snapshotIdentity:t.snapshotIdentity,before:t.before,moved:!1,delta:0,changedRoomIds:[...t.plan.roomIds],rejectionNotified:!1,wallUnionBefore:t.wallUnionBefore,accepted:null},!0)}move(t){const e=this._session;if(!e||e.pointerId!==t.pointerId)return{kind:"no-op"};const s=(i=e.start,o=t.point,a=e.plan.n,[i?.[0],i?.[1],o?.[0],o?.[1],a?.[0],a?.[1]].every(Number.isFinite)?(o[0]-i[0])*a[0]+(o[1]-i[1])*a[1]:0);var i,o,a;const n=t.snap([e.plan.a[0]+e.plan.n[0]*s,e.plan.a[1]+e.plan.n[1]*s]),r=(n[0]-e.plan.a[0])*e.plan.n[0]+(n[1]-e.plan.a[1])*e.plan.n[1],l=function(t,e,s,i,o,a){if(!Number.isFinite(i)||Math.abs(i)<1e-9)return 0;const n=Math.sign(i),r=Math.abs(i),l=Math.max(Math.abs(o),1e-6);let h=Lo.get(s);h&&h.opts===a||(h={opts:a,values:new Map},Lo.set(s,h));const c=h.values;let d=0;for(let i=Math.min(l,r),o=0;o<4096&&i<=r+1e-9;o++,i=Math.min(r,i+l)){const o=n*i,h=`${o.toFixed(9)}|${l.toFixed(9)}`;let p=c.get(h);if(void 0===p&&(p=Oo(t,e,s,o,a),c.size<4096&&c.set(h,p)),!p)break;if(d=o,Math.abs(i-r)<=1e-9)break}return d}(e.rooms,e.openings,e.plan,r,t.step,e.options);if(e.moved&&l===e.delta)return{kind:"no-op"};const h=No(e.rooms,e.openings,e.plan,l);let c;try{if(c=t.project(e.snapshotIdentity,h.polys,h.openings,e.changedRoomIds,e.rooms),!c.ok)return this._projectionRejected(e);if(Go(c.value.beforeWalls,c.value.afterWalls,{exactMultiplicity:!0}).length)return this._projectionRejected(e)}catch{return this._projectionRejected(e)}const d=e.accepted,p={preview:c.value.preview,labels:null,artifact:c.value.artifact,beforeWalls:c.value.beforeWalls,afterWalls:c.value.afterWalls};e.accepted=p;try{t.publish(p.preview,p.artifact),p.labels=t.measure(h,e.plan)}catch{e.accepted=d;try{t.publish(d?.preview||null,d?.artifact||null)}catch{}return this._projectionRejected(e)}return e.moved=!0,e.delta=l,{kind:"accepted",preview:c.value.preview,labels:p.labels,artifact:c.value.artifact}}finish(t){const e=this._session;if(!e||e.pointerId!==t.pointerId)return{kind:"no-op"};const s=e.accepted;let i;if(e.moved&&Math.abs(e.delta)>1e-9&&s)if(t.currentSnapshotIdentity!==e.snapshotIdentity)i={kind:"rejected",reason:"stale-snapshot"};else if(Oo(e.rooms,e.openings,e.plan,e.delta,e.options))if(Go(s.beforeWalls,s.afterWalls,{exactMultiplicity:!0}).length)i={kind:"rejected",reason:"wall-records"};else{let o=!1;try{o=t.validatePreview(s.preview)}catch{o=!1}i=o?{kind:"commit",preview:s.preview,before:e.before}:{kind:"rejected",reason:"invalid-candidate"}}else i={kind:"rejected",reason:"invalid-topology"};else i={kind:"no-op"};return this._session=null,"commit"===i.kind&&(this._eligibility=null),i}cancel(t,e){const s=this._session;return!s||void 0!==e&&s.pointerId!==e?{kind:"no-op"}:(this._session=null,this._eligibility=null,{kind:"cancelled",restoreWallUnion:t===s.snapshotIdentity?s.wallUnionBefore:null})}reset(){this._selectedRoomId=null,this._session=null,this._eligibility=null}_projectionRejected(t){const e=!t.rejectionNotified;return t.rejectionNotified=!0,{kind:"rejected",notify:e}}}const jo=(t,e)=>[(t[0]-e.x)/Math.max(1e-9,e.w)*e.stageWidth,(t[1]-e.y)/Math.max(1e-9,e.h)*e.stageHeight];function qo(t){const{poly:e,edge:s,text:i,view:o}=t,a=e[s],n=e[(s+1)%e.length],r=[(a[0]+n[0])/2,(a[1]+n[1])/2],l=function(t,e){const s=t[e],i=t[(e+1)%t.length],o=i[0]-s[0],a=i[1]-s[1],n=Math.hypot(o,a)||1;return(t=>{let e=0;for(let s=0;s=0?[-a/n,o/n]:[a/n,-o/n]}(e,s),h=Math.hypot(n[0]-a[0],n[1]-a[1])||1,c=[(n[0]-a[0])/h,(n[1]-a[1])/h],d=jo(r,o),p=jo(t.gearCenter,o),_=Math.max(34,7.2*i.length+12),u=Math.abs(l[0])>=Math.abs(l[1])?Math.max(28,_/2+4):Math.max(28,13),m=d[0]+l[0]*u,g=d[1]+l[1]*u,f=e=>{return s=m+c[0]*e,i=g+c[1]*e,o=_,a=18,n=p[0],r=p[1],l=t.gearWidthPx,h=t.gearHeightPx,2*Math.abs(s-n)=Math.abs(c[1])?c[0]:c[1])>0?-1:1,e=Math.max(o.stageWidth,o.stageHeight,64);for(let s=4;s<=e;s+=4){const e=s*t;if(!f(e)){b=e;break}const i=-e;if(!f(i)){b=i;break}}}const y=l[0]*u+c[0]*b,v=l[1]*u+c[1]*b,$=Math.hypot(y,v)||1,w=v/$*12,k=[r[0]+y/$*12*o.w/Math.max(1,o.stageWidth),r[1]+w*o.h/Math.max(1,o.stageHeight)];return{anchor:r,offsetXPx:y,offsetYPx:v,tangentOffsetPx:b,side:Math.abs(l[0])>=Math.abs(l[1])?l[0]<0?"left":"right":l[1]<0?"above":"below",leader:{a:r,b:k}}}const Uo=1e-9,Ko=1e7,Vo=t=>{const e=Math.sign(t)*Math.floor(Math.abs(t)*Ko+.5)/Ko;return Object.is(e,-0)?0:e},Jo=t=>`${Vo(t[0])},${Vo(t[1])}`,Yo=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),Xo=(t,e)=>Math.atan2(e[1]-t[1],e[0]-t[0]),Zo=t=>Array.isArray(t)&&t.length>=2&&t.every(t=>Number.isFinite(t)),Qo=t=>(t||[]).filter(t=>Zo(t?.a)&&Zo(t?.b)&&Yo(t.a,t.b)>Uo);function ta(t,{minAngleDeg:e=15,maxValence:s=6}={}){const i=new Map;for(const e of Qo(t))for(const[t,s]of[[e.a,e.b],[e.b,e.a]]){const e=i.get(Jo(t))||[];e.push(Xo(t,s)),i.set(Jo(t),e)}const o=[];for(const[t,a]of i){if(a.length>s&&o.push({rule:"valence",subject:t,actual:a.length,limit:s}),a.length<2)continue;const i=[...a].sort((t,e)=>t-e);let n=1/0;for(let t=0;tUo&&s(180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI%180+180)%180,sa=(t,e,s=1)=>{const i=Math.abs(ea(t)-ea(e));return Math.min(i,180-i)<=s},ia=t=>{const e=new Map;for(const s of t)for(const t of[s.a,s.b]){const i=e.get(Jo(t));i?i.push(s):e.set(Jo(t),[s])}return e};function oa(t,e,s){const i=Qo(e),o=s??ia(i),a=new Set([t]);let n=Yo(t.a,t.b);const r=[t.a,t.b];for(;r.length;){const e=r.pop();for(const s of o.get(Jo(e))||[])a.has(s)||sa(s,t)&&Number(s.cm||0)===Number(t.cm||0)&&(a.add(s),n+=Yo(s.a,s.b),r.push(s.a,s.b))}return n}function aa(t,e,s,{minLengthCm:i=20}={}){const o=[],a=Qo(t),n=ia(a);for(const t of a){const r=oa(t,a,n)/s*(e||1),l=Math.max(i,Number(t.cm)>0?Number(t.cm):0);r{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o,n=a<=Uo?0:Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))};function ra(t,e,s,{minDistanceCm:i=5}={}){const o=Qo(t),a=new Map;for(const t of o)a.set(Jo(t.a),t.a),a.set(Jo(t.b),t.b);const n=((t,e,s)=>t/(e||1)*s)(i,e,s),r=n>Uo?n:1,l=(t,e)=>`${Math.floor(t/r)},${Math.floor(e/r)}`,h=new Map;for(const[t,e]of a){const s=l(e[0],e[1]),i=h.get(s);i?i.push([t,e]):h.set(s,[[t,e]])}const c=new Map;for(const t of o){const e=Math.min(t.a[0],t.b[0])-n,s=Math.max(t.a[0],t.b[0])+n,i=Math.min(t.a[1],t.b[1])-n,o=Math.max(t.a[1],t.b[1])+n;for(let a=Math.floor(e/r);a<=Math.floor(s/r);a++)for(let e=Math.floor(i/r);e<=Math.floor(o/r);e++){const s=`${a},${e}`,i=c.get(s);i?i.push(t):c.set(s,[t])}}const d=[];for(const[t,o]of a){const a=Math.floor(o[0]/r),l=Math.floor(o[1]/r);for(let r=-1;r<=1;r++)for(let c=-1;c<=1;c++)for(const[p,_]of h.get(`${a+r},${l+c}`)||[]){if(t>=p)continue;const a=Yo(o,_);a<=2e-7||a{const i=a[(s+1)%a.length];return t+(e[0]*i[1]-i[0]*e[1])},0))/2,r=(s||1)/i,l=n*r*r;return lt.removed).map(t=>t.binding)),c=new Set;for(const t of s)t.id!==n&&("device"===t.bindingKind&&t.bindingRef&&c.add(`device:${t.bindingRef}`),"entity"===t.bindingKind&&t.bindingRef&&c.add(`entity:${t.bindingRef}`));const d=new Set;for(const t of s)"device"===t.bindingKind&&t.name&&d.add(`${t.name.trim()}|${t.area||""}`);const p=[];for(const t of Object.values(e?.devices||{})){if(!t||"service"===t.entry_type)continue;const e=`device:${t.id}`;if(c.has(e))continue;const s=String(t.name_by_user||t.name||t.id).trim();e!==a&&!h.has(e)&&d.has(`${s}|${t.area_id||""}`)||p.push({value:e,label:s,sub:(t.model||r.device)+("Group"===t.model?r.z2mGroup:""),kind:"device",ref:t.id,areaId:t.area_id||"",model:t.model||""})}for(const[t,s]of Object.entries(e?.entities||{})){const i=`entity:${t}`;if(c.has(i))continue;if(S(e,t,l)&&!h.has(i))continue;const o=ha.has(s?.platform),a="group"===s?.platform;if(!o&&!a)continue;if(s?.hidden&&!h.has(i))continue;const n=e?.states?.[t];p.push({value:i,label:s?.name||n?.attributes?.friendly_name||t,sub:`${t.split(".")[0]} · ${a?r.group:r.helper}`,kind:"entity",ref:t,areaId:s?.area_id||s?.device_id&&e?.devices?.[s.device_id]?.area_id||"",model:"",parentDeviceId:s?.device_id||void 0})}if(o){const t=new Set(p.map(t=>t.value));for(const[s,i]of Object.entries(e?.entities||{})){const o=`entity:${s}`;if(c.has(o)||t.has(o)||i?.hidden&&!h.has(o))continue;const a=!!i?.device_id&&l.devices.has(i.device_id);if(S(e,s,l)&&!h.has(o)&&!a)continue;const n=e?.states?.[s],d=i?.device_id?e?.devices?.[i.device_id]:null,_=d?String(d.name_by_user||d.name||""):"";p.push({value:o,label:i?.name||n?.attributes?.friendly_name||s,sub:`${s.split(".")[0]} · ${r.entity}${_?` · ${_}`:""}`,kind:"entity",ref:s,areaId:i?.area_id||d?.area_id||"",model:"",parentDeviceId:i?.device_id||void 0})}}return p.sort((t,e)=>t.label.localeCompare(e.label)||t.value.localeCompare(e.value))}const da={kind:"active",enabledEntityIds:[],allEntityIds:[]};function pa(t){return t.startsWith("entity:")?"entity":"device"}function _a(t){const e=t.binding.indexOf(":"),s=e>=0?t.binding.slice(e+1):"",i=Object.keys(t).filter(t=>!["id","binding","hidden"].includes(t));return t.id===`h${s}`&&0===i.length}const ua=.001;function ma(t){return!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1])}function ga(t){return`${t[0].toFixed(6)},${t[1].toFixed(6)}`}function fa(t,e,s){return Math.abs(t[0]-e[0])"room"!==t.kind&&s.some(s=>s!==t&&function(t,e,s){const i=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(i,o);if(!(a>s))return!1;const n=i/a,r=o/a,l=e=>Math.abs((e[0]-t.a[0])*r-(e[1]-t.a[1])*n);if(l(e.a)>s||l(e.b)>s)return!1;const h=(e.a[0]-t.a[0])*n+(e.a[1]-t.a[1])*r,c=(e.b[0]-t.a[0])*n+(e.b[1]-t.a[1])*r;return Math.min(a,Math.max(h,c))-Math.max(0,Math.min(h,c))>s}(t,s,e))),o=i.map(t=>{const[e,s]=ba(t.a,t.b);return{a:e,b:s,key:`hidden|${va(t,e,s)}`,sourceKind:t.kind,sourceId:t.id}}).sort((t,e)=>t.key.localeCompare(e.key)),a=i.flatMap(t=>[t.a,t.b].map((e,s)=>({point:[e[0],e[1]],key:`hidden|${ya(t)}|endpoint-${s}`,sourceKind:t.kind,sourceId:t.id}))).sort((t,e)=>t.key.localeCompare(e.key));return{segments:o,endpoints:a}}function xa(t){const e=t.epsilon??ua,s=t.roomCuts||[],i=new Map;for(const e of t.partitionCuts||[]){if("string"!=typeof e.hostId||!e.hostId||!ma(e.a)||!ma(e.b))continue;const t=i.get(e.hostId)||[];t.push([e.a[0],e.a[1],e.b[0],e.b[1]]),i.set(e.hostId,t)}const o=[];for(const[e,i]of M(t.space.rooms).entries())i.length<4||o.push({a:[i[0],i[1]],b:[i[2],i[3]],kind:"room",id:`room-edge-${e}`,cuts:s});for(const e of t.space.room_drafts||[])if(e.id!==t.activeDraftId)for(let t=0;t+1wa(s,t,e)))continue;const t=ga(s);n.has(t)||n.set(t,{point:[s[0],s[1]],key:t})}}}return{segments:[...a.values()].sort((t,e)=>t.key.localeCompare(e.key)),endpoints:[...n.values()].sort((t,e)=>t.key.localeCompare(e.key))}}function Sa(t,e,s){return e.some(e=>ma(e)&&fa(t,e,s))}function Ma(t,e,s){if(!s)return!0;const i=t-s.distance;return i<-1e-9||Math.abs(i)<=1e-9&&e.localeCompare(s.key)<0}function Da(t,e,s){const i=s.epsilon??ua,o=s.excludePoints||[],a=[...t.endpoints,...(s.extraEndpoints||[]).filter(t=>ma(t.point)).map(t=>({point:[t.point[0],t.point[1]],key:t.key}))],n=new Map;for(const t of a){if(Sa(t.point,o,i))continue;const e=ga(t.point),s=n.get(e);(!s||t.key.localeCompare(s.key)<0)&&n.set(e,t)}return[...n.values()].map(t=>({kind:"endpoint",point:[...t.point],key:t.key,distance:Math.hypot(e[0]-t.point[0],e[1]-t.point[1])})).filter(t=>t.distance<=s.tolerance).sort((t,e)=>t.distance-e.distance||t.key.localeCompare(e.key))}function Ca(t,e){if(!t.length)return null;if(e>0){const s=new Set;for(let i=0;i1)return{kind:"ambiguous",candidate:null,conflicts:t.filter(t=>s.has(t.key)).map(t=>({point:[...t.point],key:t.key}))}}return{kind:"resolved",candidate:t[0],conflicts:[]}}function Pa(t,e,s){const i=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(i,o);if(!(a>0))return[...t.a];const n=i/a,r=o/a,l=Math.max(0,Math.min(a,(e[0]-t.a[0])*n+(e[1]-t.a[1])*r)),h=s>0?Math.max(0,Math.min(a,Math.round(l/s)*s)):l;return[t.a[0]+n*h,t.a[1]+r*h]}function Ia(t,e,s){if(!(ma(e)&&ma(s.anchor)&&s.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const i=s.epsilon??ua,o=function(t,e){const s=e[0]-t[0],i=e[1]-t[1];if(!(Math.hypot(s,i)>Number.EPSILON))return null;const o=Math.round(Math.atan2(i,s)/(Math.PI/4))*(Math.PI/4);return[Math.cos(o),Math.sin(o)]}(s.anchor,e);if(!o)return{kind:"none",candidate:null,conflicts:[]};const a=Da(t,e,s).filter(t=>function(t,e,s,i){const o=t[0]-e[0],a=t[1]-e[1];return o*s[0]+a*s[1]>i&&Math.abs(o*s[1]-a*s[0])<=i*Math.max(Math.hypot(o,a),1)}(t.point,s.anchor,o,i)),n=Ca(a,s.distinguishTolerance||0);if(n)return n;let r=null;for(const a of t.segments){const t=a.b[0]-a.a[0],n=a.b[1]-a.a[1],l=a.a[0]-s.anchor[0],h=a.a[1]-s.anchor[1],c=o[0]*n-o[1]*t;let d=null;if(Math.abs(c)<=i*Math.max(Math.hypot(t,n),1)){if(Math.abs(l*o[1]-h*o[0])>i*Math.max(Math.hypot(l,h),1))continue;const t=[a.a,a.b].map(t=>({point:t,along:(t[0]-s.anchor[0])*o[0]+(t[1]-s.anchor[1])*o[1]})).filter(t=>t.along>i).sort((t,e)=>t.along-e.along);t.length&&(d=[...t[0].point])}else{const e=(l*n-h*t)/c,a=(l*o[1]-h*o[0])/c;e>i&&a>=-i&&a<=1+i&&(d=[s.anchor[0]+o[0]*e,s.anchor[1]+o[1]*e])}if(!d)continue;const p=Math.hypot(e[0]-d[0],e[1]-d[1]);p>s.tolerance||Sa(d,s.excludePoints||[],i)||!Ma(p,a.key,r)||(r={kind:"line",point:d,key:a.key,distance:p,segment:a})}return r?{kind:"resolved",candidate:r,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}const Ta=.001;function Ra(t,e,s,i){const o=Number.isFinite(t)&&t>0?Math.floor(t):0,a=t=>"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,n=a(s),r=a(i)??0,l=[];let h=null;for(let t=0;t=2&&Number.isFinite(t[0])&&Number.isFinite(t[1])}function za(t,e,s,i){return t*i-e*s}function Aa(t){let e=0;for(let s=0;st.localeCompare(e)),e[0]}function Ha(t,e,s){const i=[...t];for(let t=!0;t&&i.length>=3;){t=!1;for(let o=0;o=0){i.splice(o,1),t=!0;break}}}return i}function Ga(t,e){const s=t.map(t=>Math.max(0,Math.min(1,t))).sort((t,e)=>t-e),i=[];for(const t of s)(!i.length||Math.abs(t-i[i.length-1])>e)&&i.push(t);return i}function Wa(t,e){return[t.a[0]+(t.b[0]-t.a[0])*e,t.a[1]+(t.b[1]-t.a[1])*e]}function ja(t,e,s){const i=function(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;return o>0?((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o:0}(t,e);if(i<-s||i>1+s)return null;const o=Wa(e,i);return Math.hypot(o[0]-t[0],o[1]-t[1])<=s?Math.max(0,Math.min(1,i)):null}function qa(t,e,s,i,o){const a=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=e.b[0]-e.a[0],l=e.b[1]-e.a[1],h=e.a[0]-t.a[0],c=e.a[1]-t.a[1],d=za(a,n,r,l),p=Math.max(Math.hypot(a,n),Math.hypot(r,l),1);if(Math.abs(d)>o*p){const t=za(h,c,r,l)/d,e=za(h,c,a,n)/d;return void(t>=-o&&t<=1+o&&e>=-o&&e<=1+o&&(s.push(Math.max(0,Math.min(1,t))),i.push(Math.max(0,Math.min(1,e)))))}if(!(Math.abs(za(h,c,a,n))>o*p)){for(const i of[e.a,e.b]){const e=ja(i,t,o);null!=e&&s.push(e)}for(const s of[t.a,t.b]){const t=ja(s,e,o);null!=t&&i.push(t)}}}function Ua(t){let e=t+1|0;return e^=e<<13,e^=e>>>17,e^=e<<5,e>>>0}function Ka(t,e){return t.minY-e.minY||t.index-e.index}function Va(t){return t.subtreeMaxY=Math.max(t.item.maxY,t.left?.subtreeMaxY??-1/0,t.right?.subtreeMaxY??-1/0),t}function Ja(t){const e=t.right;return t.right=e.left,e.left=Va(t),Va(e)}function Ya(t){const e=t.left;return t.left=e.right,e.right=Va(t),Va(e)}function Xa(t,e){return t?(Ka(e,t.item)<0?(t.left=Xa(t.left,e),t.left.priority0)t.right=Za(t.right,e);else{if(!t.left)return t.right;if(!t.right)return t.left;t.left.priority=e&&Qa(t.left,e,s,i),t.item.minY<=s&&t.item.maxY>=e&&i.push(t.item),t.item.minY<=s&&Qa(t.right,e,s,i))}function tn(t,e=.001){const s=Number.isFinite(e)&&e>0?e:Ta,i=t.filter(t=>Na(t.a)&&Na(t.b)&&"string"==typeof t.key&&t.key.length>0&&Math.hypot(t.b[0]-t.a[0],t.b[1]-t.a[1])>s),o=i.map(()=>[0,1]);!function(t,e,s){const i=t.map((t,e)=>({index:e,minX:Math.min(t.a[0],t.b[0])-s,maxX:Math.max(t.a[0],t.b[0])+s,minY:Math.min(t.a[1],t.b[1])-s,maxY:Math.max(t.a[1],t.b[1])+s})),o=[...i].sort((t,e)=>t.minX-e.minX||t.minY-e.minY||t.index-e.index),a=[...i].sort((t,e)=>t.maxX-e.maxX||t.index-e.index),n=new Set;let r=null,l=0;for(const i of o){for(;lt.index-e.index);for(const a of o)qa(t[a.index],t[i.index],e[a.index],e[i.index],s);n.add(i.index),r=Xa(r,i)}}(i,o,s);const a=new Map;for(let t=0;t({key:t,a:e.a,b:e.b,sourceKeys:[...e.sourceKeys].sort((t,e)=>t.localeCompare(e))})).sort((t,e)=>t.key.localeCompare(e.key))}function en(t,e=.001){const s=Number.isFinite(e)&&e>0?e:Ta,i=tn(t,s),o=new Map,a=new Map,n=new Map(i.map(t=>[t.key,t]));for(const t of i){const e=La(t.a,s),i=La(t.b,s);o.set(e,t.a),o.set(i,t.b),a.has(e)||a.set(e,new Set),a.has(i)||a.set(i,new Set),a.get(e).add(i),a.get(i).add(e)}const r=new Map;for(const[t,e]of a){const s=o.get(t);r.set(t,[...e].sort((t,e)=>{const i=o.get(t),a=o.get(e);return Math.atan2(i[1]-s[1],i[0]-s[0])-Math.atan2(a[1]-s[1],a[0]-s[0])||t.localeCompare(e)}))}const l=new Set,h=new Map,c=(t,e)=>`${t}>${e}`;for(const t of i){const e=[La(t.a,s),La(t.b,s)];for(const[t,a]of[e,[e[1],e[0]]]){if(l.has(c(t,a)))continue;const e=[],d=[];let p=t,_=a,u=!1;for(let s=0;s<=2*i.length+2;s++){const s=c(p,_);if(l.has(s)){u=p===t&&_===a;break}l.add(s),e.push(p),d.push(Ea(p,_));const i=r.get(_)||[],o=i.indexOf(p);if(o<0||!i.length)break;if(p=_,_=i[(o-1+i.length)%i.length],p===t&&_===a){u=!0;break}}if(!u||new Set(e).size<3||new Set(e).size!==e.length)continue;const m=e.map(t=>o.get(t)),g=Aa(m);if(!(g>s*s))continue;const f=Ba(Ha(e,o,s)),b=new Set;for(const t of d)for(const e of n.get(t)?.sourceKeys||[])b.add(e);const y={ring:m,key:f,area:g,atomKeys:[...d],sourceKeys:[...b].sort((t,e)=>t.localeCompare(e))};h.has(f)||h.set(f,y)}}return{atoms:i,faces:[...h.values()].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key))}}function sn(t,e,s=.001){if(!Na(e))return null;const i=t.faces.filter(t=>{if(t.ring.some((i,o)=>function(t,e,s,i){const o=s[0]-e[0],a=s[1]-e[1],n=o*o+a*a;if(!(n>0))return Math.hypot(t[0]-e[0],t[1]-e[1])<=i;const r=((t[0]-e[0])*o+(t[1]-e[1])*a)/n;return!(r<0||r>1)&&Math.hypot(e[0]+o*r-t[0],e[1]+a*r-t[1])<=i}(e,i,t.ring[(o+1)%t.ring.length],s)))return!1;let i=!1;for(let s=0,o=t.ring.length-1;se[1]!=n[1]>e[1]&&e[0]<(n[0]-a[0])*(e[1]-a[1])/(n[1]-a[1])+a[0]&&(i=!i)}return i});return[...i].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key))[0]||null}function on(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o,n=a>0?Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a)):0;return Math.hypot(e[0]+i*n-t[0],e[1]+o*n-t[1])}function an(t,e,s=.5){let i=Math.abs(t-e)%180;return i>90&&(i=180-i),i<=s}function nn(t,e,s,i){const o=t.filter(t=>"outer"===t.kind&&!t.open&&t.cm>0).map(t=>({interval:t,reusePartitionId:e.find(e=>function(t,e,s){return!(Math.abs(t.cm-e.cm)>1e-6)&&(an(180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI,180*Math.atan2(e.b[1]-e.a[1],e.b[0]-e.a[0])/Math.PI,.001)&&on(e.a,t.a,t.b)<=s&&on(e.b,t.a,t.b)<=s)}(e,t,i))?.id||null})),a=new Map;for(const e of s){if("partition"===e.host?.kind)continue;const s=t.map(t=>{const s=180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI;return{interval:t,distance:an(e.angle,s)?on([e.x,e.y],t.a,t.b):1/0}}).filter(t=>t.distance<=i).sort((t,e)=>t.distance-e.distance||t.interval.key.localeCompare(e.interval.key)),o=s[0]?.interval;"outer"===o?.kind&&!o.open&&o.cm>0&&a.set(e.id,o.key)}return{materialize:o,openingIntervals:a,removeOpeningIds:[...a.keys()].sort((t,e)=>t.localeCompare(e))}}function rn(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;return o>0?Math.max(0,Math.min(1,((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o)):0}const ln=t=>!t.key.startsWith("static:room|");function hn(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;if(!(o>0))return null;const a=((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o,n=[e.a[0]+s*a,e.a[1]+i*a];return{point:n,t:a,distance:Math.hypot(n[0]-t[0],n[1]-t[1])}}function cn(t,e){return e>0?Math.hypot(t[0]-Math.round(t[0]/e)*e,t[1]-Math.round(t[1]/e)*e):0}function dn(t,e,s){if(ln(t.source)!==ln(e.source))return ln(t.source)?t:e;const i=cn(t.point,s),o=cn(e.point,s);return Math.abs(i-o)>1e-9?i>o?t:e:function(t,e){return t[0]-e[0]||t[1]-e[1]}(t.point,e.point)>0?t:e}function pn(t){return[t.from[0],t.from[1],t.to[0],t.to[1],t.targetKind].map(t=>"number"==typeof t?t.toFixed(6):t).join("|")}function _n(t,e){return t.map(t=>t.key!==e.sourceKey?t:{...t,[e.endpoint]:[...e.to]})}function un(t,e){const s=e.epsilon??.001;if(!(e.maxDistance>=0)||!e.point&&!e.requiredSourceKey)return{kind:"none"};const i=new Map,o=t.flatMap(t=>[{source:t,endpoint:"a",point:t.a},{source:t,endpoint:"b",point:t.b}]);for(let t=0;ts)||l>e.maxDistance)continue;const h=dn(n,r,e.gridStep||0),c=h===n?r:n;if(!ln(h.source))continue;const d={sourceKey:h.source.key,endpoint:h.endpoint,from:[h.point[0],h.point[1]],to:[c.point[0],c.point[1]],targetSourceKey:c.source.key,targetKind:"endpoint",distance:l};i.set(pn(d),d)}for(const a of o)if(ln(a.source))for(const o of t){if(o===a.source)continue;const t=hn(a.point,o);if(!t||t.t<=s||t.t>=1-s||!(t.distance>s)||t.distance>e.maxDistance)continue;const n={sourceKey:a.source.key,endpoint:a.endpoint,from:[a.point[0],a.point[1]],to:t.point,targetSourceKey:o.key,targetKind:"line",distance:t.distance};i.set(pn(n),n)}const a=[];for(const o of i.values()){const i=en(_n(t,o),s),n=e.point?sn(i,e.point,s):i.faces.find(t=>!e.requiredSourceKey||t.sourceKeys.includes(e.requiredSourceKey))||null;n&&a.push({proposal:o,face:n})}if(a.sort((t,e)=>t.proposal.distance-e.proposal.distance||pn(t.proposal).localeCompare(pn(e.proposal))),!a.length)return{kind:"none"};return new Set(a.map(t=>`${pn(t.proposal)}|${t.face.key}`)).size>1?{kind:"ambiguous",proposals:a.map(t=>t.proposal)}:{kind:"repair",...a[0]}}const mn=(t,e)=>(t.composedPath?.()||[t.target]).some(t=>(t=>!!t&&"function"==typeof t.matches)(t)&&e(t));class gn{constructor(t){this.host=t,this._openGroupId=null,this._groupGeneration=0,this._renderedContext="",this._focusOwned=!1,this._currentModel=null,this._blocked=!1,this._dismissPointerTarget=null,this._globalDismissListening=!1,this._globalDismissGuard=t=>{this.handleOutsideDismiss(t)}}get hasOpenGroup(){return null!==this._openGroupId}get groupGeneration(){return this._groupGeneration}activeGroup(t){return this._openGroupId&&t.find(t=>t.id===this._openGroupId)||null}reset(){this._openGroupId=null,this._contentAnimation?.cancel(),this._contentAnimation=void 0,this._renderedContext="",this._focusOwned=!1,this._currentModel=null,this._blocked=!1,this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}closeForNavigation(){const t="palette"===this._currentModel?.kind?this._currentModel.dismiss:void 0,e=!!this._openGroupId||!!t;this._openGroupId=null,t?.(),t&&(this._currentModel=null),this._clearDismissClick(),e&&this.host.requestUpdate(),this._syncGlobalDismissListener()}openPalette(){this._openGroupId&&this.closeGroup(!1)}toggleGroup(t,e){this._openGroupId!==e?t.some(t=>t.id===e)&&("palette"===this._currentModel?.kind&&this._currentModel.dismiss?.(),this._groupGeneration+=1,this._openGroupId=e,this.host.clearTip(),this.host.requestUpdate(),this._syncGlobalDismissListener()):this.closeGroup(!1)}closeGroup(t){const e=this._openGroupId;this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener(),t&&e&&this.host.updateComplete().then(()=>{const t=this.host.root(),s=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===e&&null!==t.offsetParent);(s||t.querySelector(".editbar-tools"))?.focus?.()})}renderGroupLauncher(t,e,s){const i=this._openGroupId===t.id,a=t.items.find(e=>e.id===t.activeItemId&&!e.disabled);return o``}renderGroupModel(t,e,s){const i=t.items.find(t=>!t.disabled)?.id,n=t.items.some(e=>e.id===t.activeItemId&&!e.disabled)?t.activeItemId:void 0;return{contextId:e,kind:"group",ariaLabel:s.openGroup(t.label),visibleLabel:t.label,content:o`
this._groupKeydown(t)}> + ${t.items.map(e=>o``)} +
`}}runContext(t,e,s){t===e&&s()}render(t,e){this._currentModel=t,this._blocked=e;const s=t?.kind||"hidden";return o`
+ +
`}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"),s=this._renderedContext,i=e?.dataset.contextId||"";if(i&&s&&i!==s&&!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=i,s&&i!==s&&this._focusOwned){const s=i?e?.querySelector('[tabindex="0"], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'):t.querySelector(".editbar-tools");s?.focus?.(),this._focusOwned=!!i}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 o=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===this._openGroupId);o&&null!==o.offsetParent||this.closeGroup(!0)}handleOutsideDismiss(t){if(mn(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 s=mn(t,t=>t.classList.contains("editor-secondary")),i=mn(t,t=>!!t.dataset.editorGroup),o=mn(t,t=>!!t.dataset.editorPalette),a=mn(t,t=>t.classList.contains("stage"));if(!(s||i||o||"stay-open-on-canvas"===e?.dismissPolicy&&a))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,s){if(t.id!==this._openGroupId)return;const i=t.items.find(t=>t.id===e);if(!i||i.disabled)return;const o="toggle"===i.role&&"stay-open"===i.closePolicy,a=0===s.detail;o||(this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener()),i.invoke(),!o&&a&&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 s=e.indexOf(this.host.root().activeElement),i="Home"===t.key?0:"End"===t.key?e.length-1:"ArrowLeft"===t.key?s<=0?e.length-1:s-1:(s+1)%e.length;e[i]?.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 fn=t=>t.stopPropagation(),bn=1e-6*I,yn=6*I;function vn(t){return Number.isFinite(t)?Math.round(t/I)*I:t}const $n=(t,e,s,i)=>Math.hypot(s-t,i-e),wn=(t,e,s,i,o,a,n,r)=>Math.hypot(Math.max(Math.abs(o-t),Math.abs(o+n-(t+s))),Math.max(Math.abs(a-e),Math.abs(a+r-(e+i)))),kn=(t,e,s,i,o,a,n)=>{const r=Math.max(Number(i)||0,0)/2,l=Math.PI/180,h=Math.cos(s*l)*r,c=Math.sin(s*l)*r,d=Math.cos(n*l)*r,p=Math.sin(n*l)*r,_=Math.max($n(t+h,e+c,o+d,a+p),$n(t-h,e-c,o-d,a-p)),u=Math.max($n(t+h,e+c,o-d,a-p),$n(t-h,e-c,o+d,a+p));return Math.min(_,u)},xn=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function Sn(t,e){const s=JSON.parse(JSON.stringify(t||[])),i=JSON.parse(JSON.stringify(e||{}));let o=0,a=0,n=0,r=0,l="",h=0,c=0,d=0;const p=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=bn&&c++},_=(t,e)=>{p(t[0],e[0]),p(t[1],e[1])},u={};let m=5;for(const t of s){const e=xn(t);null!=t?.id&&(u[String(t.id)]=e),e>m&&(m=e)}const g=(t,e,s,i=!1)=>{if(!(t>bn||i))return;o++,t>n&&(n=t);const a=t*T*e;a>r&&(r=a,l=s)};for(const t of s){const e=xn(t),s=null!=t?.id?String(t.id):"";for(const i of t.rooms||[]){a++;let t=0;if(i.poly?.length)i.poly=i.poly.map(e=>{const s=[vn(e[0]),vn(e[1])];return t=Math.max(t,$n(e[0],e[1],s[0],s[1])),_(e,s),s});else if(null!=i.x&&null!=i.y){const e=i.x,s=i.y,o=i.w||0,a=i.h||0,n=vn(e+o),r=vn(s+a),l=vn(e),h=vn(s),c=Math.max(I,n-l),d=Math.max(I,r-h);t=wn(e,s,o,a,l,h,c,d),i.x=l,i.y=h,i.w=c,i.h=d,p(e,l),p(s,h),p(e+o,l+c),p(s+a,h+d)}g(t,e,s)}for(const i of t.room_drafts||[]){a++;let t=0;const o=i.points||[],n=o.map(e=>{const s=[vn(e[0]),vn(e[1])];return t=Math.max(t,$n(e[0],e[1],s[0],s[1])),s}),r=n.length?[n[0]]:[],l=n.length?[[o[0],n[0]]]:[],h=[];for(let t=0;t+1=2)for(const[t,e]of l)_(t,e);g(t,e,s)}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 i of t.partitions||[]){a++;const o=[i.a[0],i.a[1]],n=[i.b[0],i.b[1]],r=[vn(o[0]),vn(o[1])],l=[vn(n[0]),vn(n[1])];let h=Math.max($n(o[0],o[1],r[0],r[1]),$n(n[0],n[1],l[0],l[1]));const c=$n(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).every(t=>{const e=Number(t.length),s=Number(t.host.t),i=s*c;return Number.isFinite(e)&&e>0&&Number.isFinite(s)&&s>=0&&s<=1&&i-e/2>=-bn&&i+e/2<=c+bn});c>bn&&d?(i.a=r,i.b=l,_(o,r),_(n,l)):h=0,g(h,e,s)}for(const i of t.wall_columns||[]){a++;const t=[i.center[0],i.center[1]],o=[vn(t[0]),vn(t[1])],n=$n(t[0],t[1],o[0],o[1]);i.center=o,_(t,o),g(n,e,s)}for(const i of t.decor||[]){a++;let t=0;if("line"===i.kind){const e=[i.x1,i.y1],s=[i.x2,i.y2],o=[vn(e[0]),vn(e[1])],a=[vn(s[0]),vn(s[1])];t=Math.max($n(e[0],e[1],o[0],o[1]),$n(s[0],s[1],a[0],a[1])),i.x1=o[0],i.y1=o[1],i.x2=a[0],i.y2=a[1],_(e,o),_(s,a)}else{const e=i.x,s=i.y,o=i.w,a=i.h,n=vn(e),r=vn(s);if(null!=i.w&&null!=i.h){const l=vn(e+o),h=vn(s+a),c=Math.max(I,l-n),d=Math.max(I,h-r);t=wn(e,s,o,a,n,r,c,d),i.w=c,i.h=d,p(e+o,n+c),p(s+a,r+d)}else t=$n(e,s,n,r);i.x=n,i.y=r,p(e,n),p(s,r)}g(t,e,s)}for(const i of t.openings||[]){if(a++,"partition"===i.host?.kind){const o=(t.partitions||[]).find(t=>t.id===i.host.id),a=Number(i.host.t);if(!o||!Number.isFinite(a)||a<0||a>1)continue;const n=o.b[0]-o.a[0],r=o.b[1]-o.a[1];if(Math.hypot(n,r)<=bn)continue;const l=o.a[0]+n*a,c=o.a[1]+r*a;let d=180*Math.atan2(r,n)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(i.angle),_=!(Number.isFinite(p)&&p===d),u=kn(i.x,i.y,Number.isFinite(p)?p:d,Number(i.length)||0,l,c,d);i.x=l,i.y=c,i.angle=d,_&&h++,g(u,e,s,_);continue}const o=P([i.x,i.y],t.rooms||[],yn,{step:I,length:Number(i.length)||0});if(!o)continue;const n=Number(i.angle),r=!(Number.isFinite(n)&&n===o.angle),l=kn(i.x,i.y,Number.isFinite(n)?n:o.angle,Number(i.length)||0,o.x,o.y,o.angle);i.x=o.x,i.y=o.y,i.angle=o.angle,r&&h++,g(l,e,s,r)}}for(const[t,e]of Object.entries(i)){if(!e||"object"!=typeof e)continue;const s=e;if("number"!=typeof s.x||"number"!=typeof s.y)continue;a++;const o=vn(s.x),n=vn(s.y),r=$n(s.x,s.y,o,n);i[t]={...s,x:o,y:n},p(s.x,o),p(s.y,n);const l="string"==typeof s.s?s.s:"";g(r,u[l]??m,l)}return{spaces:s,layout:i,report:{moved:o,coordsCanonicalized:c,total:a,maxShift:n,maxShiftCm:r,maxSpace:l,rotated:h,removedDrafts:d},changed:o>0||c>0}}function Mn(t,e){const s=e.base+t*e.span;return Math.min(1,Math.max(0,s))}const Dn=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Cn=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function Pn(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(a<=0)return Cn(t,e);let n=((t[0]-e[0])*i+(t[1]-e[1])*o)/a;return n=Math.max(0,Math.min(1,n)),Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))}function In(t,e,s,i,o){for(const i of e)if(i&&!s.has(i.id)&&Dn(i.a)&&Dn(i.b)&&(Cn(t,i.a)<=o||Cn(t,i.b)<=o))return!0;for(const e of i?.roomPolygons||[])for(let s=0;s0&&r>0))return null;if(Math.abs(o[0]/n*(a[1]/r)-o[1]/n*(a[0]/r))>s)return null;for(const[s,o]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(Cn(s,o)<=i)return[(s[0]+o[0])/2,(s[1]+o[1])/2];return null}function Rn(t,e){const s=.05*(Number(e.pitch)>0?Number(e.pitch):1),i=new Map;let o=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&Dn(t.a)&&Dn(t.b));if(o.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const a=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let n=0;for(let t=0;tCn(e,t.at)>s);let c=h[0]??r.a,d=h[h.length-1]??l.b;if(h.length<2&&(c=r.a,d=l.b),d[0]0?(d[0]-c[0])/_:0,m=_>0?(d[1]-c[1])/_:0,g=t=>_>0?((t[0]-c[0])*u+(t[1]-c[1])*m)/_:0;for(const t of[r,l]){const e=g(t.a),s=g(t.b)-e;for(const[o,a]of i)a.toId===t.id&&i.set(o,{fromId:a.fromId,toId:p.id,base:e+a.base*s,span:a.span*s});i.set(t.id,{fromId:t.id,toId:p.id,base:e,span:s})}a&&a.add(p.id),o=o.filter((e,s)=>s!==t.i&&s!==t.j),o.splice(t.i,0,p),n++}return{partitions:o,merged:n,openingMoves:[...i.values()]}}function Fn(t,e,s,i){if(!t?.length||!s.length)return 0;const o=new Map(s.map(t=>[t.fromId,t]));let a=0;for(const s of t){const t=s?.host;if(!t||"partition"!==t.kind)continue;const n=o.get(t.id);if(!n)continue;s.host={...t,id:n.toId,t:Mn(t.t,n)},a++;const r=F(s,e,i.coordScale,i.cellCm,i.gridPitch).resolved;r&&Object.assign(s,N(s,r,i.coordScale))}return a}function Nn(t,e){const s=e?.excludeDraftId||null;return{roomPolygons:(t?.rooms||[]).map(t=>R(t)).filter(t=>!!t),columns:t?.wall_columns||[],draftEnds:(t?.room_drafts||[]).flatMap(t=>{if(s&&t?.id===s)return[];const e=t?.points||[];return e.length?[e[0],e[e.length-1]]:[]})}}const zn=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),An=(t,e)=>t[0]-e[0]||t[1]-e[1],On=(t,e,s,i)=>[t[0]+e*i,t[1]+s*i],Ln=(t,e,s,i)=>(t[0]-e[0])*s+(t[1]-e[1])*i,En=(t,e,s,i,o)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o))return null;const l=a/r,h=n/r,c=e=>Math.abs((e[0]-t[0])*h-(e[1]-t[1])*l);if(c(s)>o||c(i)>o)return null;const d=Ln(s,t,l,h),p=Ln(i,t,l,h),_=Math.max(0,Math.min(d,p)),u=Math.min(r,Math.max(d,p));return u-_>o?{lo:_,hi:u}:null},Bn=(t,e,s)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>s,Hn=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},Gn=(t,e,s,i)=>{const o=t.b[0]-t.a[0],a=t.b[1]-t.a[1],n=Math.hypot(o,a);if(!(n>i))return!0;const r=o/n,l=a/n,h=j(t.cm,s.cellCm,s.gridPitch)/2;return e.some(e=>{const o=e?.center;if(!zn(o))return!0;const a=Ln(o,t.a,r,l),c=Math.abs((o[0]-t.a[0])*l-(o[1]-t.a[1])*r),d=j(Number(e.cm),s.cellCm,s.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||a>=-d-i&&a<=n+d+i&&c<=h+d+i})},Wn=(t,e,s)=>{if(t.host){const i=F(t,e,s.coordScale,s.cellCm,s.gridPitch).resolved;return i?{center:i.center,angle:i.angle,length:i.length}:null}const i=Number(t.x)*s.coordScale,o=Number(t.y)*s.coordScale,a=Number(t.angle),n=Number(t.length)*s.coordScale;return[i,o,a,n].every(Number.isFinite)&&n>0?{center:[i,o],angle:a,length:n}:null},jn=(t,e,s)=>{const i=t.angle*Math.PI/180,o=Math.cos(i),a=Math.sin(i),n=e.angle*Math.PI/180,r=Math.cos(n),l=Math.sin(n);if(Math.abs(o*l-a*r)>1e-6)return!1;const h=e.center[0]-t.center[0],c=e.center[1]-t.center[1];if(Math.abs(h*a-c*o)>s)return!1;const d=h*o+c*a;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]}),Un=(t,e,s,i)=>{const o=`~r-${(t=>{let e=2166136261;for(let s=0;s>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${s[0].toFixed(9)},${s[1].toFixed(9)}`)}`,a=`${t.slice(0,Math.max(1,64-o.length))}${o}`;let n=a;for(let t=2;i.has(n);t++){const e=`-${t}`;n=`${a.slice(0,64-e.length)}${e}`}return i.add(n),n},Kn=(t,e)=>{const s=[];for(const i of t){const t=s[s.length-1];!(t&&Math.abs(t.hi-i.lo)<=e&&t.safe===i.safe)||i.safe&&t.signature!==i.signature?s.push({lo:i.lo,hi:i.hi,a:i.a,b:i.b,safe:i.safe,signature:i.signature,roomIds:i.roomIds,finalCm:i.finalCm}):(t.hi=i.hi,t.b=i.b)}return s};function Vn(t,e,s,i,o){const a=s||[],n=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l=Array.isArray(t?.room_drafts)?t.room_drafts:[],h={walls:a,partitions:n,openings:r,roomDrafts:l,partitionsReconciled:0,openingsRehosted:0,removedDrafts:0};if(!n.length&&!l.length)return h;const c=Math.max(2e-4*o.gridPitch,1e-9);let d=a,p=n,_=r;const u=z(e.rooms,d,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),m=((t,e,s,i)=>{const o=new Map(t.map(t=>[t.id,t])),a=new Set;for(const t of e){if(!o.get(t.id)||!Array.isArray(t.points)||t.points.length<2||t.segments.length!==t.points.length-1)continue;let e=!0;for(let o=0;o+10)){e=!1;break}const l=Math.hypot(n[0]-a[0],n[1]-a[1]);if(!(l>i)){e=!1;break}const h=s.flatMap(t=>{const e=t.cm>0?t.cm:A;if(t.open||"outer"!==t.kind&&"shared"!==t.kind||e+it.lo-e.lo||t.hi-e.hi);let c=0;for(const t of h){if(t.lo>c+i)break;if(c=Math.max(c,t.hi),c>=l-i)break}c!m.has(t.id));let f=0,b=0;const y=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...n].sort((t,e)=>t.id.localeCompare(e.id))){if(!p.some(e=>e.id===t.id))continue;if(!Hn(t))continue;const s=y.get(t.id);if(!(s&&zn(s.a)&&zn(s.b)&&Number.isFinite(s.cm)&&s.cm>0))continue;const[a,n]=An(s.a,s.b)<=0?[[s.a[0],s.a[1]],[s.b[0],s.b[1]]]:[[s.b[0],s.b[1]],[s.a[0],s.a[1]]],r=n[0]-a[0],l=n[1]-a[1],h=Math.hypot(r,l);if(!(h>c))continue;const u=r/h,g=l/h,v=z(e.rooms,d,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),$=v.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=En(a,n,t.a,t.b,c);return e?[{interval:t,range:e}]:[]});if(!$.length)continue;const w=_.filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).map(t=>({opening:t,resolved:F(t,e.partitions,o.coordScale,o.cellCm,o.gridPitch).resolved}));if(w.some(t=>!t.resolved))continue;const k=[0,h];for(const{range:t}of $)k.push(t.lo,t.hi);const x=k.slice(),S=new Map;for(const{opening:t,resolved:e}of w){const s=Ln(e.center,a,u,g),i={lo:s-e.length/2,hi:s+e.length/2};S.set(t.id,i),x.push(Math.max(0,i.lo),Math.min(h,i.hi))}const M=[...new Set(x.filter(t=>Number.isFinite(t)&&t>=-c&&t<=h+c).map(t=>Math.max(0,Math.min(h,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),D=p.map(t=>qn(t,o.coordScale)).filter(t=>t.id!==s.id),C=e.room_drafts.filter(t=>!m.has(t.id)),P=[];for(let t=0;t+1c))continue;const r=On(a,u,g,i),l=On(a,u,g,n),h=$.filter(({range:t})=>t.lo<=i+c&&t.hi>=n-c).map(({interval:t})=>t),d=new Map;for(const t of h)d.set(t.roomId,t);const p=[...d.values()],_=new Set(p.map(t=>t.kind)),m=new Set(p.map(t=>t.cm>0?t.cm:A)),f=p[0]?.kind,b=[...d.keys()].sort(),y=1===_.size&&1===m.size&&("outer"===f&&1===b.length||"shared"===f&&2===b.length),v={id:s.id,a:r,b:l,cm:s.cm},w=D.some(t=>!!En(r,l,t.a,t.b,c)),k=C.some(t=>t.points.some((e,s)=>s+10?p[0].cm:A:0,I=y?Math.max(S,s.cm):s.cm;P.push({lo:i,hi:n,a:r,b:l,safe:x,signature:x?`${f}|${b.join(",")}|${I}`:"",roomIds:b,roomCm:S,finalCm:I})}if(!P.some(t=>t.safe))continue;const I=new Map;for(const{opening:t,resolved:e}of w){const i=S.get(t.id),a=k.some(t=>t>i.lo+c&&tBn(t,i,c)),r=new Set(n.filter(t=>t.safe).map(t=>t.signature));if(!a&&n.length>0&&n.every(t=>t.safe)&&1===r.size&&O(e,v,c)){I.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=L(s,o.cellCm,o.gridPitch),h={lo:i.lo-l,hi:i.hi+l};for(const t of P)Bn(t,h,c)&&(t.safe=!1,t.signature="")}let T=!0;for(;T;){T=!1;for(const[t,e]of[...I.entries()]){const i=S.get(t),a=P.filter(t=>Bn(t,i,c));if(a.length>0&&a.every(t=>t.safe)&&a.every(t=>t.signature===e.signature))continue;I.delete(t);const n=L(s,o.cellCm,o.gridPitch),r={lo:i.lo-n,hi:i.hi+n};for(const t of P)Bn(t,r,c)&&(t.safe=!1,t.signature="");T=!0}}const R=Kn(P,c),j=R.filter(t=>t.safe),q=R.filter(t=>!t.safe);if(!j.length)continue;if(p.length-1+q.length>2e3)continue;let U=d;for(const t of j){const[e,i]=An(s.a,s.b)<=0?[t.a,t.b]:[t.b,t.a];U=E(U,e,i,t.finalCm,o.pitch,o.coordScale)}if(U=B(e.rooms,U,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),U.length>500)continue;const K=new Set(p.map(t=>t.id));K.delete(s.id);const V=q.map((t,e)=>{const i=[t.a[0]/o.coordScale,t.a[1]/o.coordScale],a=[t.b[0]/o.coordScale,t.b[1]/o.coordScale],n=0===e?s.id:Un(s.id,i,a,K);return K.add(n),{id:n,a:i,b:a,cm:s.cm}}),J=p.findIndex(t=>t.id===s.id),Y=p.slice();Y.splice(J,1,...V);const X=Y.map(t=>qn(t,o.coordScale)),Z=new Map;let Q=!0;for(const{opening:t,resolved:e}of w){const s=I.get(t.id);if(s){const e=N(t,s.resolved,o.coordScale),{host:i,...a}=e;Z.set(t.id,a);continue}const i=S.get(t.id),a=V[q.findIndex(t=>t.lo<=i.lo+c&&t.hi>=i.hi-c)],n=a&&X.find(t=>t.id===a.id);if(!a||!n){Q=!1;break}const r=n.b[0]-n.a[0],l=n.b[1]-n.a[1],h=Math.hypot(r,l),d=Ln(e.center,n.a,r/h,l/h),p={...N(t,e,o.coordScale),host:{kind:"partition",id:a.id,t:d/h}};if(!H(p,X,o.coordScale,o.cellCm,o.gridPitch).resolved){Q=!1;break}Z.set(t.id,p)}if(!Q)continue;const tt=_.map(t=>Z.get(t.id)||t),et=[...I.keys()].map(t=>Z.get(t)),st=et.map(t=>Wn(t,X,o));if(st.some(t=>!t))continue;let it=!1;for(let t=0;tt.id));for(const t of tt){if(ot.has(t.id))continue;const e=Wn(t,X,o);e&&st.some(t=>jn(t,e,c))&&(it=!0)}if(it)continue;const at=G(e.rooms,U,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale);[...I.entries()].every(([t,e])=>{const s=Z.get(t),i=W(at,{x:s.x*o.coordScale,y:s.y*o.coordScale,angle:s.angle,length:s.length*o.coordScale},!0),a=[i.negative,i.positive].filter(t=>!!t?.full),n=e.signature.split("|")[1].split(","),r=new Set(a.map(t=>t.roomId));return a.length===n.length&&r.size===n.length&&n.every(t=>r.has(t))})&&(d=U,p=Y,_=tt,f+=j.length,b+=I.size)}return{walls:d,partitions:p,openings:_,roomDrafts:g,partitionsReconciled:f,openingsRehosted:b,removedDrafts:m.size}}const Jn=t=>JSON.parse(JSON.stringify(t)),Yn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Xn=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function Zn(t,e){let s=String(e??"");const i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=new RegExp(`^${i}_(.+)_([0-9a-f]{8})$`);let a=0;for(;a<16;a++){const t=o.exec(s);if(!t)return{root:s,layers:a,bounded:!1};s=t[1]}return{root:s,layers:a,bounded:o.test(s)}}const Qn=(t,e,s)=>{const i=t.get(e)||[];i.push(s),t.set(e,i)};const tr=1e-9;class er extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const sr=t=>JSON.parse(JSON.stringify(t)),ir=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),or=t=>[Number(t[0]),Number(t[1])],ar=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,nr=(t,e)=>{const s=ar(t),i=ar(e);return sar(t)<=ar(e)?[or(t),or(e)]:[or(e),or(t)],lr=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),hr=t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],s=[];for(let i=1;i{const s=new Set,i=t=>{const e=Number(t);if(!Number.isFinite(e))return;const i=e/I;Math.abs(i-Math.round(i))>=X&&s.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of R(e)||[])i(t[0]),i(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])i(t?.a?.[0]),i(t?.a?.[1]),i(t?.b?.[0]),i(t?.b?.[1]);for(const t of e)i(t?.[0]),i(t?.[1]);return s.size},dr=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;return a>1e-18?((t[0]-e[0])*i+(t[1]-e[1])*o)/a:0},pr=(t,e,s)=>{const i=Math.max(0,Math.min(1,dr(t,e,s)));return Math.hypot(t[0]-(e[0]+(s[0]-e[0])*i),t[1]-(e[1]+(s[1]-e[1])*i))},_r=(t,e,s,i,o=tr)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(r<=o)return 0;const l=e=>Math.abs((e[0]-t[0])*n-(e[1]-t[1])*a)/r;if(l(s)>o||l(i)>o)return 0;const h=dr(s,t,e),c=dr(i,t,e);return Math.max(0,Math.min(1,Math.max(h,c))-Math.max(0,Math.min(h,c)))*r},ur=t=>{const e=(new TextEncoder).encode(t),s=8*e.length,i=64*Math.ceil((e.length+9)/64),o=new Uint8Array(i);o.set(e),o[e.length]=128;const a=new DataView(o.buffer);a.setUint32(i-8,Math.floor(s/4294967296),!1),a.setUint32(i-4,s>>>0,!1);const n=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),h=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,o=h(s,17)^h(s,19)^s>>>10;l[t]=l[t-16]+i+l[t-7]+o>>>0}let[e,s,i,o,c,d,p,_]=r;for(let t=0;t<64;t++){const a=_+(h(c,6)^h(c,11)^h(c,25))+(c&d^~c&p)+n[t]+l[t]>>>0,r=e&s^e&i^s&i;_=p,p=d,d=c,c=o+a>>>0,o=i,i=s,s=e,e=a+((h(e,2)^h(e,13)^h(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+s>>>0,r[2]=r[2]+i>>>0,r[3]=r[3]+o>>>0,r[4]=r[4]+c>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+_>>>0}const c=new Uint8Array(32),d=new DataView(c.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let s=0,i=0,o="";for(const a of t)for(i=i<<8|a,s+=8;s>=5;)o+=e[i>>>s-5&31],s-=5;return s&&(o+=e[i<<5-s&31]),o},gr=(t,e,s,i,o="")=>{const[a,n]=rr(e,s),r=`${t}|${ar(a)}|${ar(n)}|${[...i].sort().join(",")}${o}`;return`wall-${mr(ur(r)).slice(0,20)}`};let fr=0;const br=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),s=`wall-${e||mr(ur(`${Date.now()}|${fr++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(s))return s}throw new er("duplicate-id","id factory exhausted")},yr=t=>{const e=new Map;for(const s of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(s&&"string"==typeof s.id&&ir(s.a)&&ir(s.b)){if(e.has(s.id))throw new er("duplicate-id",s.id);e.set(s.id,s)}return e},vr=(t,e,s)=>{const i=(s,i)=>{const o=t[0]-s[0],a=t[1]-s[1];return Math.abs(e[0]-i[0]-o)<=tr&&Math.abs(e[1]-i[1]-a)<=tr?[o,a]:null};return i(s.a,s.b)||i(s.b,s.a)},$r=(t,e)=>{const s=Array.isArray(t.rooms)?t.rooms:[],i=V(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),o=i.length?i:J(s,null,1,.04*I,!0),a=[];for(const t of s){const s=R(t),i=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(s&&i.length===s.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&&o.some(e=>pr([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*I)):[],l=r.map(t=>{const e=Number(t.angle)*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Number(t.length)/2,o=[Number(t.x),Number(t.y)];return{a:[o[0]-s[0]*i,o[1]-s[1]*i],b:[o[0]+s[0]*i,o[1]+s[1]*i]}}),h=(t,e)=>r.some(s=>{const i=[Number(s.x),Number(s.y)];if(!Z(t,e,Number(s.angle)))return!1;if(pr(i,t,e)>.02*I)return!1;const o=lr(t,e),a=dr(i,t,e)*o,n=Number(s.length)/2;return a+n>=-tr&&a-n<=o+tr}),c=new Map,d=[];for(const i of s){const r=String(i?.id||""),p=R(i);if(!r||!p||p.length<3)throw new er("invalid-room",r);const _=Y(s,r,n,I,1,[...t.walls||[],...l]);if(!_||_.poly.length<3)throw new er("invalid-room",r);const u=Array.isArray(i.wall_ids)?i.wall_ids:[],m=u.length===p.length;let g=null,f=m;if(f)for(let t=0;ttr||Math.abs(i[1]-g[1])>tr)){f=!1;break}g=i}const b=[];for(let t=0;t<_.poly.length;t++){const s=_.poly[t],i=_.poly[(t+1)%_.poly.length];if(lr(s,i)<=tr)throw new er("zero-length",r);const n=nr(s,i);let l=c.get(n);if(!l){const[t,e]=rr(s,i);l={key:n,a:t,b:e,owners:new Set,preferredIds:new Set,positionalIds:new Set,preferredCarriers:new Map,parentKeys:new Set,zeroWall:!1},c.set(n,l)}if(l.owners.add(r),l.owners.size>2)throw new er("third-owner",n);const d=m?u[_.parent[t]]:void 0;if("string"==typeof d&&d){const o=e.get(d);f||!o||_r(s,i,o.a,o.b)>tr?l.preferredIds.add(d):l.positionalIds.add(d),l.preferredCarriers.set(d,{a:or(p[_.parent[t]]),b:or(p[(_.parent[t]+1)%p.length])})}const g=_.parent[t];l.parentKeys.add(K(p[g],p[(g+1)%p.length],I));const y=[(s[0]+i[0])/2,(s[1]+i[1])/2],v=t=>t.some(t=>pr(y,[t[0],t[1]],[t[2],t[3]])<=.04*I);l.zeroWall||=v(a)||v(o)&&!h(s,i),b.push(n)}const y={...i};delete y.wall_ids,d.push({...y,poly:_.poly.map(t=>[t[0],t[1]]),wall_ids:b})}return{atoms:[...c.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},wr=(t,e,s,i,o)=>{const a=new Map([...s.values()].map(t=>[nr(t.a,t.b),t])),n=(t=>{const e=new Map;for(const s of t)"wall"===s.host?.kind&&e.set(s.host.id,(e.get(s.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=o?.get(t.key);if(e){const i=s.get(e);if(!i)throw new er("duplicate-id",e);r.set(t,i);continue}if(t.preferredIds.size>1)throw new er("duplicate-id",[...t.preferredIds].sort().join(","));const i=[...t.preferredIds][0],l=i?s.get(i):void 0;if(l){r.set(t,l);continue}const h=i?t.preferredCarriers.get(i):void 0;if(i&&h){r.set(t,{id:i,a:h.a,b:h.b,cm:0});continue}const c=a.get(t.key);if(c){r.set(t,c);continue}const d=[...s.values()].filter(e=>_r(t.a,t.b,e.a,e.b)>tr),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(n.get(e.id)||0)-(n.get(t.id)||0)||lr(e.a,e.b)-lr(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=s.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const s=l.get(e.id)||[];s.push(t),l.set(e.id,s)}for(const[t,e]of l){const i=s.get(t)||r.get(e[0]);if(!i)throw new er("duplicate-id",t);const o=[(i.a[0]+i.b[0])/2,(i.a[1]+i.b[1])/2];e.sort((t,e)=>{const s=pr(o,t.a,t.b)<=tr?0:1,a=pr(o,e.a,e.b)<=tr?0:1;if(s!==a)return s-a;return(pr(i.a,t.a,t.b)<=tr?0:1)-(pr(i.a,e.a,e.b)<=tr?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const h=(t=>{const e=new Set;for(const s of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(s)?s:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(s?.segments)?s.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(h.has(t.id))throw new er("duplicate-id",t.id);h.add(t.id)}const c=e.filter(t=>!t.id);if(i){const e=c.map(e=>{const[s,i]=rr(e.a,e.b),o=`${String(t.id||"")}|${ar(s)}|${ar(i)}|${[...e.owners].sort().join(",")}`,a=mr(ur(o));return{atom:e,seed:o,digest:a,base:`wall-${a.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),s=new Map;for(const t of e){const e=s.get(t.digest);if(e&&e!==t.seed)throw new er("duplicate-id",t.digest);s.set(t.digest,t.seed);let i=1,o=t.base;for(;h.has(o);)o=`${t.base}-${++i}`;t.atom.id=o,h.add(o)}}else for(const t of c)t.id=br(h),h.add(t.id)},kr=(t,e)=>{if("partition"===t.host?.kind)return null;const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=e=>{if(!(Number(e.cm)>0))return!1;const i=dr(s,e.a,e.b),o=lr(e.a,e.b),a=Number(t.length)/2;return i>=-tr&&i<=1+tr&&pr(s,e.a,e.b)<=.02*I&&Z(e.a,e.b,Number(t.angle))&&Number.isFinite(a)&&a>=0&&i*o-a>=-tr&&i*o+a<=o+tr},o="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,a=o&&i(o)?[o]:e.filter(i);if(1!==a.length)return null;const n=a[0];return{kind:"wall",id:n.id,t:Math.max(0,Math.min(1,dr(s,n.a,n.b)))}},xr=(t,e)=>{const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=Number(t.length)/2,o=e.filter(e=>{if(!(Number(e.cm)>0))return!1;const o=dr(s,e.a,e.b),a=lr(e.a,e.b);return o>=-tr&&o<=1+tr&&pr(s,e.a,e.b)<=.02*I&&Z(e.a,e.b,Number(t.angle))&&Number.isFinite(i)&&i>=0&&o*a-i>=-tr&&o*a+i<=a+tr}),a=(e=>{if(!e.length)return null;const i="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null;return i||[...e].sort((t,e)=>pr(s,t.a,t.b)-pr(s,e.a,e.b)||Number(e.cm)-Number(t.cm)||(t.ide.id?1:0))[0]})(o);return a?{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,dr(s,a.a,a.b)))}:null},Sr=(t,e,s)=>{const i=yr(t),{atoms:o,rooms:a}=$r(t,i);wr(t,o,i,e,s);const n=o.map(e=>{const s=e.id?i.get(e.id):void 0,o=((t,e,s)=>{if(e.zeroWall)return 0;const i=Array.isArray(t.walls)?t.walls:[],o=K(e.a,e.b,I),a=i.filter(t=>Number(t.cm)>0&&(!(t.key!==o&&!e.parentKeys.has(t.key))||!(!ir(t.a)||!ir(t.b))&&_r(e.a,e.b,t.a,t.b)>=lr(e.a,e.b)-tr)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(a.map(t=>t.toFixed(9))).size>1)throw new er("thickness-conflict",e.key);if(a.length)return a[0];const n=Q(i,e.a,e.b,I,1);return n>0?n:Number(s?.cm)>0?Number(s.cm):0})(t,e,s);return{...s||{},id:e.id,a:[...e.a],b:[...e.b],cm:o}}),r=new Map(o.map(t=>[t.key,t.id]));for(const t of a)t.wall_ids=t.wall_ids.map(t=>r.get(t));t.rooms=a,t.wall_segments=n,t.walls=n.filter(t=>t.cm>0).map(t=>({key:K(t.a,t.b,I),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 s=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&&s.add(t.id);for(const i of Array.isArray(t.room_drafts)?t.room_drafts:[]){const o=Array.isArray(i.segments)?i.segments:[];for(let a=0;a{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;if(!t.host&&!s){const s=kr(t,e);s&&(t.host=s);continue}const i=kr(t,e)??(s?xr(t,e):null);if(i)t.host=i;else{if(!s)throw new er("opening-host",t.id);delete t.host}}})(t,n,e),n.reduce((t,e)=>t+(i.has(e.id)?0:1),0)};function Mr(t,e={}){const s=JSON.stringify(t),i=sr(t);U(i);let o=0;const a=Number(i?.model_version||0)<9;for(const t of Array.isArray(i?.spaces)?i.spaces:[]){const s=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0;o+=Sr(t,a,s)}return i.model_version=9,U(i),{config:i,changed:s!==JSON.stringify(i),migratedSegments:o}}const Dr=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Cr(t,e){const s=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const i=new Map;for(const e of t)Dr(e)&&"string"==typeof e.id&&e.id&&i.set(e.id,e);const o=e.map((e,o)=>{if(Dr(e)&&"string"==typeof e.id&&e.id){const t=i.get(e.id);return t?s(t,e):sr(e)}return o[e,e in t?s(t[e],i):sr(i)]);for(const e of Object.keys(t))delete t[e];for(const[e,s]of i)t[e]=s;return t}return sr(e)};return s(t,e)}const Pr=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Ir=(t,e,s)=>Math.min(s,Math.max(e,t)),Tr=t=>ut({spaces:[t]})[0],Rr=(t,e,s)=>{const i=s>0?s:1,o=t=>`${(t[0]/i).toFixed(12)},${(t[1]/i).toFixed(12)}`,a=o(t),n=o(e);return a0?n:1,l=Math.max(i*r*.02,1e-9),h=[];for(const e of t||[])for(const t of R(e)||[])h.push([t[0],t[1]]);const c=[];for(const t of s||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&c.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 n of t||[]){if(!n?.id)continue;const _=mt(t,n.id,e,s,i,o,a,r);if(_)for(let t=0;t<_.orig.length;t++){const e=[];for(let s=0;s<_.parent.length;s++)_.parent[s]===t&&e.push(s);for(let t=1;t+10&&u>0&&n===m&&u!==n))continue;const g=_.poly[i],f=_.poly[(i+1)%_.poly.length],b=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(b>l&&b<.5*a-1e-9*a))continue;if(d(g,c)||d(f,c))continue;if(d(g,h)&&d(f,h))continue;const y=Rr(g,f,r),v=p.get(y);v?v.targets.add(n):p.set(y,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([n])})}}}let _=e.slice();const u=(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 s=[Number(t.a[0])*r,Number(t.a[1])*r],i=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...s,...i].every(Number.isFinite)&&(u(s,e.a)&&u(i,e.b)||u(s,e.b)&&u(i,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>Rr(t.a,t.b,r).localeCompare(Rr(e.a,e.b,r)))){const e=[...t.targets][0],s=_.filter(e=>m(e,t));if(new Set(s.map(t=>t.cm)).size>1)continue;let o=!1;_=_.map(s=>m(s,t)?(o=!0,s.cm===e?s:{...s,cm:e}):s),o||(_=E(_,t.a,t.b,e,i,r))}return _}const Nr=t=>{const e=[];for(const s of t||[]){const t=R(s);if(t?.length)for(let s=0;s"string"==typeof t?.id?t.id:"").filter(Boolean),c=new Set(h),d=new Map;for(const t of h){const e=Zn("space",t);e.layers>0&&Xn("space",e.root)&&Qn(d,e.root,t)}const p=new Map,_=new Map,u=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s=new Map;for(const i of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof i?.id?i.id:"";if(!t)continue;const o=Zn("room",t);o.layers>0&&Xn("room",o.root)&&Qn(s,o.root,t),_.has(t)||_.set(t,e),u.has(t)||u.set(t,String(i.name||""));const a="string"==typeof i.area?i.area:"";if(a){const s=m.get(a)||[];s.push({spaceId:e,roomId:t}),m.set(a,s)}}p.set(e,s)}const g=new Set(_.keys()),f=new Map,b=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?b.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:[]},v=new Set,$=t=>c.has(t)?null:(()=>{const e=Zn("space",t).root;if(!Xn("space",e))return null;const s=d.get(e)||[];return 1===s.length?s[0]:null})(),w=(t,e)=>{const s=Zn("room",t).root;if(!Xn("room",s))return null;const i=p.get(e)?.get(s)||[];return 1===i.length?i[0]:null},k=t=>{const e=s.effectiveAreaByMarker?.[t]||"",i=e&&m.get(e)||[];return 1===i.length?i[0]:null},x=(t,e,s)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const i=e?w(t.room_id,e):null;i?(t.room_id=i,y.roomRefsRemapped++):s?(t.room_id=s.roomId,y.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const i=t.vacuum?.segment_map;if(i&&"object"==typeof i&&!Array.isArray(i))for(const t of Object.keys(i)){const s=i[t];if("string"!=typeof s||!s||g.has(s))continue;const o=e?w(s,e):null;o?(i[t]=o,y.roomRefsRemapped++):y.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s="string"==typeof t.space?t.space:"",i=s&&!c.has(s),a=o[e],n="string"==typeof a?.s?a.s:"",r=n&&!c.has(n),l=!0===t.removed;let h=s&&c.has(s)?s:null,d=null,p=!1;if(i){const i=$(s);i?(t.space=i,h=i,p=!0,y.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,h=null,y.markersDetached++):(d=k(e),d?(t.space=d.spaceId,h=d.spaceId,y.spaceRefsRemapped++):(delete t.space,h=null,y.markersDetached++))}l&&!p||x(t,h,d),r&&p&&n===s&&h&&(o[e]={...a,s:h},y.positionsRemapped++,v.add(e))}for(const t of Object.keys(o)){if(v.has(t))continue;const e=o[t],s="string"==typeof e?.s?e.s:"";if(!s||c.has(s))continue;const i=$(s);if(i){if(t.startsWith("rl_")){const s=t.slice(3),a=w(s,i);if(a){const s=`rl_${a}`;Yn(o,s)||(o[s]={...e,s:i}),delete o[t],y.roomRefsRemapped++,y.positionsRemapped++;continue}}o[t]={...e,s:i},y.positionsRemapped++}}const S=s.ownerRoster,M=!0===S?.authoritative,D=new Set(S?.deviceIds||[]),C=new Set(S?.entityIds||[]),P=new Set(Array.isArray(i.settings?.known_devices)?i.settings.known_devices.filter(t=>"string"==typeof t):[]),I=(t,e="")=>{const s=String(S?.names?.[t]||e||"").trim();return s&&s!==t?s:""},T=(t,e,s,i="",o)=>({id:t,spaceId:e,kind:s,name:I(t,i),...o?{reason:o}:{}}),R=t=>{"room_label"===t?y.orphanRoomLabelsRemoved++:"group"===t?y.orphanGroupPositionsRemoved++:y.orphanDevicePositionsRemoved++},F=new Set;for(const[t,e]of Object.entries(o)){const i="string"==typeof e?.s?e.s:"";if(!i||c.has(i))continue;let a,n;const r=f.get(t),l=b.get(t);if(r)a=T(t,i,"device",String(r.name||"")),n="live";else if(l)a=T(t,i,"device",String(l.name||"")),n="absent";else if(t.startsWith("rl_")){const e=t.slice(3);a=T(t,i,"room_label",u.get(e)||""),n=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);a=T(t,i,"group"),n=C.has(e)?"live":M?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")}else D.has(t)?(a=T(t,i,"device"),n="live"):P.has(t)?(a=T(t,i,"device"),n=M?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")):(a=T(t,i,"unknown","","unknown_owner"),n="unverified");if("absent"!==n){if("live"===n){if(y.liveMissingPositions.push(a),!0===s.removeLiveMissingPositions){delete o[t],y.liveMissingPositionsRemoved++,R(a.kind),y.removedPositions.push(a);continue}}else y.unverifiedPositions.push(a);y.positionsUnresolved++,F.add(i)}else delete o[t],R(a.kind),y.removedPositions.push(a)}return y.deadSpaceIds=[...F].sort((t,e)=>t.localeCompare(e)),{config:i,layout:o,report:y,changed:JSON.stringify(i)!==a||JSON.stringify(o)!==n}}(t,e,s),n=a.config,r=tt(n,a.layout);U(n),et(a.layout);const l=JSON.stringify(t||{}),h=JSON.stringify(e||{}),c=Number.isInteger(Number(n.model_version))?Number(n.model_version):0,d=(t=>{let e=0,s=0,i=0;for(const s of t.markers||[]){if("ripple"===s.display&&(s.display="icon_ripple",e++),Array.isArray(s.controls)){const t="string"==typeof s.binding&&s.binding.startsWith("entity:")?s.binding.slice(7):"",i=t?s.controls.filter(e=>e!==t):s.controls;JSON.stringify(i)!==JSON.stringify(s.controls)&&(s.controls=i.length?i:null,e++)}const t=s.vacuum;t&&Pr(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const o of t.spaces||[]){const t=o.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,s++);for(const t of o.rooms||[]){const s=t.settings;"glow"===s?.fill_mode&&("boolean"!=typeof s.glow&&(s.glow=!0),delete s.fill_mode,e++,i++)}if(Pr(o,"segments")&&(delete o.segments,e++),Pr(o,"plan_scale")){const t=Number(o.plan_scale);Number.isFinite(t)&&t>=lt&&t<=ht&&(Pr(o,"plan_scale_x")||(o.plan_scale_x=t),Pr(o,"plan_scale_y")||(o.plan_scale_y=t),delete o.plan_scale,e++)}const a=Number(o.cell_cm);Pr(o,"cell_cm")&&(!Number.isFinite(a)||a<.1||a>1e3)&&(o.cell_cm=Number.isFinite(a)&&a>0?Ir(a,.1,1e3):5,e++);const n=Number(o.cell_cm),r=Number.isFinite(n)&&n>0?n:5;for(const t of o.wall_columns||[])if("circle"===t.shape)Pr(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Pr(t,"angle")){const s=((Number(t.angle)||0)%90+90)%90;t.angle!==s&&(t.angle=s,e++)}for(const t of o.decor||[]){if(Pr(t,"width")){const s=Number(t.width);(Pr(t,"width_cm")||Number.isFinite(s))&&(Pr(t,"width_cm")||(t.width_cm=Number(Ir(s/nt*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Pr(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Pr(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(Ir(ct*dt(t)/nt*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Pr(t,"scale")||Pr(t,"size"))&&(delete t.scale,delete t.size,e++);let s=String(t.text??"");const i=[...s.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!pt(t[1]));if(!(Pr(t,"entity")||Pr(t,"attr")||Pr(t,"unit")))continue;const o=String(t.unit??"").trim(),a="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||o?"":_t(t.entity,a);if(i||n){if(n){const e=s.indexOf("{}");s=e>=0?s.slice(0,e)+n+s.slice(e+2):`${s}${s?" ":""}${n}`,t.text=s}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:s,glowRooms:i}})(n);let p=d.total;const _=(u=n.spaces||[],JSON.parse(JSON.stringify(u)));var u;const m=Sn(n.spaces||[],a.layout);let g=0,f=0,b=0,y="";const v=m.spaces.map(t=>{const e=st(t);g+=e.report.wallsStraightened,f+=e.report.wallsStraightenSkipped;const s=Number(t?.cell_cm)>0?Number(t.cell_cm):5,i=e.report.maxStraightenShift/I*s;return i>b&&(b=i,y=String(t?.id||"")),e.space}),$=g?Sn(v,m.layout):{...m,spaces:v};n.spaces=$.spaces;const w=g?{...m.report,moved:m.report.moved+$.report.moved,coordsCanonicalized:m.report.coordsCanonicalized+$.report.coordsCanonicalized,maxShift:Math.max(m.report.maxShift,$.report.maxShift),maxShiftCm:Math.max(m.report.maxShiftCm,$.report.maxShiftCm),maxSpace:$.report.maxShiftCm>m.report.maxShiftCm?$.report.maxSpace:m.report.maxSpace,rotated:m.report.rotated+$.report.rotated,removedDrafts:m.report.removedDrafts+$.report.removedDrafts}:{...m.report};let k=0,x=0,S=0,M=0,D=0,C=0,P=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),a=Tr(e),r=Tr(s);if(!a||!r)continue;const l=Nr(a.rooms),h=Nr(r.rooms),c=.02*nt,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:K(t.a,t.b,I),cm:0})),p=new Set(d.map(t=>t.key)),u=it(e,a.rooms,ot,c);x+=u.length;for(const t of u){const e=[t[0]/ot,t[1]/ot],s=[t[2]/ot,t[3]/ot],i=K(e,s,I);p.has(i)||(p.add(i),d.push({key:i,a:e,b:s,cm:0}))}const m=d.length,g=at(d,l,h,I,ot),f=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(!(a>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const n=Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))},b=g.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*ot),s=t.b.map(t=>t*ot);return h.some(([t,i])=>f(e,t,i)<=4*c&&f(s,t,i)<=4*c)});S+=Math.max(0,m-b.length);const y=(s.wall_segments||[]).filter(t=>Number(t.cm)>0);s.wall_segments=[...y,...b.map(({key:t,...e})=>e)];const v=b.map(t=>[t.a[0]*ot,t.a[1]*ot,t.b[0]*ot,t.b[1]*ot]),$=Array.isArray(e.walls)?e.walls.length:0;let w=at(e.walls,l,h,I,ot);w=Fr(r.rooms,w,v,I,Number(s.cell_cm)>0?Number(s.cell_cm):5,nt,ot),w=B(r.rooms,w,v,I,Number(s.cell_cm)>0?Number(s.cell_cm):5,nt,ot),w=rt(w,s.rooms||[],I,1,v.map(t=>[t[0]/ot,t[1]/ot,t[2]/ot,t[3]/ot])),k+=Math.max(0,$-w.length),w.length?s.walls=w:delete s.walls;const R=Rn(s.partitions||[],{pitch:I,geometry:Nn(s)});R.merged&&(M+=R.merged,s.partitions=R.partitions,Fn(s.openings,s.partitions,R.openingMoves,{coordScale:ot,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:nt}));const F=Tr(s);if(F){const t=o(s,F,s.walls||[],v,{pitch:I,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:nt,coordScale:ot});t.partitionsReconciled&&(D+=t.partitionsReconciled,C+=t.openingsRehosted,t.partitions.length?s.partitions=t.partitions:delete s.partitions,t.openings.length?s.openings=t.openings:delete s.openings,t.walls.length?s.walls=t.walls:delete s.walls),t.removedDrafts&&(P+=t.removedDrafts,t.roomDrafts.length?s.room_drafts=t.roomDrafts:delete s.room_drafts)}JSON.stringify({zero:(s.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:s.walls||[]})!==i&&T++}let R=0;c<=9&&(R=function(t){const e=Mr(t);return Cr(t,e.config),{...e,config:t}}(n).migratedSegments);const F=U(n),N=et($.layout),z=JSON.stringify(F)!==l||JSON.stringify(N)!==h;c<9&&z&&(F.model_version=9);const A=JSON.stringify(F)!==l||JSON.stringify(N)!==h,O=Number.isInteger(Number(F.model_version))?Number(F.model_version):c,L=A?w:{...w,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0,removedDrafts:0},E=A?a.report:{...a.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:F,layout:N,report:{...L,modelFrom:c,modelTo:O,migrated:A?p:0,glowSpacesMigrated:A?d.glowSpaces:0,glowRoomsMigrated:A?d.glowRooms:0,canonicalized:A?T:0,wallSegmentsMigrated:A?R:0,legacyZeroWallsMigrated:A?x:0,wallsMerged:A?k:0,spansMerged:A?S:0,partitionsMerged:A?M:0,partitionsReconciled:A?D:0,openingsRehosted:A?C:0,redundantDraftsRemoved:A?P:0,wallsStraightened:A?g:0,wallsStraightenSkipped:f,maxStraightenShiftCm:A?b:0,maxStraightenSpace:A?y:"",latticeCoordinatesCanonicalized:A?r.canonicalized:0,latticeCoordinatesFar:A?r.far:0,latticeMaxShift:A?r.maxShift:0,latticeMaxShiftCm:A?r.maxShiftCm:0,latticeSpaces:A?r.spaces:[],...E},changed:A}}const Ar=(t,e)=>t[0]*e[1]-t[1]*e[0],Or=(t,e)=>t[0]*e[0]+t[1]*e[1],Lr=(t,e)=>[t[0]-e[0],t[1]-e[1]],Er=(t,e,s)=>[t[0]+e[0]*s,t[1]+e[1]*s];function Br(t,e,s){return Math.abs(Ar(t,e))<=s}function Hr(t,e,s){return Math.abs(Ar(Lr(t,e),s))}function Gr(t,e,s,i,o){const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o&&s>0))return[];const l=[a/r,n/r];return function(t,e,s){const i=e.map(([e,s])=>[Math.max(0,Math.min(e,s)),Math.min(t,Math.max(e,s))]).filter(([t,e])=>e>t+s).sort((t,e)=>t[0]-e[0]||t[1]-e[1]),o=[];for(const t of i){const e=o[o.length-1];!e||t[0]>e[1]+s?o.push([...t]):e[1]=Math.max(e[1],t[1])}const a=[];let n=0;for(const[t,e]of o)t>n+s&&a.push([n,t]),n=Math.max(n,e);return t>n+s&&a.push([n,t]),a}(r,i.flatMap(e=>{const i=e.b[0]-e.a[0],a=e.b[1]-e.a[1],n=Math.hypot(i,a);if(!(n>o&&Br(l,[i/n,a/n],1e-6)))return[];if(Hr(e.a,t,l)>1.1*Math.max(s,o)||Hr(e.b,t,l)>1.1*Math.max(s,o))return[];return[[Or(Lr(e.a,t),l),Or(Lr(e.b,t),l)]]}),o).flatMap(([e,i])=>{const o=bt({a:Er(t,l,e),b:Er(t,l,i),halfDepth:s});return o?[o]:[]})}function Wr(t){const e=t.coordScale??1,s=Math.max(t.epsilon??2e-4*t.gridPitch,1e-9),i=[];for(const s of t.rooms||[]){if(!s?.id)continue;const o=mt(t.rooms,s.id,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e);if(!o||o.poly.length<3)continue;const a=gt(o.poly,o.offsets);!a||a.length<3||i.push({roomId:s.id,profile:o,inner:a})}i.sort((t,e)=>t.roomId.localeCompare(e.roomId));const o=(t.roomOpenings||[]).map(t=>{const e=t.angle*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Math.max(0,t.length)/2;return{a:Er([t.x,t.y],s,-i),b:Er([t.x,t.y],s,i)}}),a=[];for(const i of ft(t.rooms,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e))for(const t of Gr(i.a,i.b,i.depthUnits/2,o,s))a.push({body:t});const n=new Map;for(const e of t.partitionCuts||[]){const t=n.get(e.hostId)||[];t.push(e),n.set(e.hostId,t)}for(const e of t.partitions||[]){const i=j(e.cm,t.cellCm,t.gridPitch)/2;for(const t of Gr(e.a,e.b,i,n.get(e.id)||[],s))a.push({body:t,partitionId:e.id})}return{rooms:i,boundaries:a,epsilon:s}}function jr(t,e,s,i){const o=t.profile.offsets[e];if(!(o>0))return null;const a=function(t,e){const s=t[e],i=t[(e+1)%t.length],o=i[0]-s[0],a=i[1]-s[1],n=Math.hypot(o,a)||1;return function(t){let e=0;for(let s=0;s=0?[-a/n,o/n]:[a/n,-o/n]}(t.profile.poly,e),n=Er(s.center,a,o),r=[];for(let e=0;ei&&Br(s.axis,[l[0]/h,l[1]/h],1e-6)))continue;if(Hr(o,n,s.axis)>i||Hr(a,n,s.axis)>i)continue;const c=Or(Lr(o,n),s.axis),d=Or(Lr(a,n),s.axis);r.push([Math.min(c,d),Math.max(c,d)])}const l=function(t,e){t.sort((t,e)=>t[0]-e[0]||t[1]-e[1]);const s=[];for(const i of t){const t=s[s.length-1];!t||i[0]>t[1]+e?s.push([...i]):t[1]=Math.max(t[1],i[1])}return s}(r,i).find(([t,e])=>t<=i&&e>=-i);if(!l)return null;const[h,c]=l,d=Er(n,s.axis,-s.half),p=Er(n,s.axis,s.half),_=Math.max(0,-s.half-h),u=Math.max(0,c-s.half),m=_>0?Er(n,s.axis,h):d,g=u>0?Er(n,s.axis,c):p,f=Or(a,s.normal)>=0?1:-1,b=(e,i,o)=>({from:e,to:i,label:[(e[0]+i[0])/2,(e[1]+i[1])/2],axis:s.axis,labelNormal:a,distance:o,roomId:t.roomId,roomSide:f,source:"room-face"});return{left:b(d,m,_),right:b(p,g,u)}}function qr(t){const e=Er(t.center,t.axis,-t.half),s=Er(t.center,t.axis,t.half),i=Er(t.center,t.axis,Math.min(-t.half,t.targetLo)),o=Er(t.center,t.axis,Math.max(t.half,t.targetHi)),a=(e,s)=>({from:e,to:s,label:[(e[0]+s[0])/2,(e[1]+s[1])/2],axis:t.axis,labelNormal:t.normal,distance:Math.hypot(s[0]-e[0],s[1]-e[1]),source:"host-end"});return[a(e,i),a(s,o)]}function Ur(t,e,s,i){const o=Lr(s,e),a=Or(o,o);if(!(a>i*i))return Math.hypot(...Lr(t,e))<=i;const n=Or(Lr(t,e),o)/a;if(n<-i||n>1+i)return!1;const r=Er(e,o,Math.max(0,Math.min(1,n)));return Math.hypot(...Lr(t,r))<=i}function Kr(t,e,s){let i=!1;for(let o=0,a=e.length-1;ot[1]!=h>t[1]&&t[0]<(l-n)*(t[1]-r)/(h-r)+n&&(i=!i)}return i}function Vr(t,e,s,i,o,a){const n=Lr(i,s),r=Ar(e,n);if(Math.abs(r)<=a)return null;const l=Lr(s,t),h=Ar(l,n)/r,c=Ar(l,e)/r;return h<-a||h>o+a||c<-a||c>1+a?null:Math.max(0,Math.min(o,h))}function Jr(t,e,s){const i=qr(s),o="partition"===t.host?.kind?t.host.id:void 0;return[{base:i[0],direction:[-s.axis[0],-s.axis[1]]},{base:i[1],direction:s.axis}].map(({base:t,direction:s})=>{const i=t.distance,a=function(t,e,s,i,o,a){let n=null;for(const r of i)if(!o||r.partitionId!==o){if(Kr(t,r.body,a))return 0;for(let i=0;iOr(Lr(t,o),s));return{center:o,axis:s,normal:i,half:Math.max(0,t.renderedLength)/2,targetLo:Math.min(...a),targetHi:Math.max(...a)}}(t),i=e.rooms.flatMap(t=>{const i=function(t,e,s){const{profile:i}=t;let o=null;for(let t=0;t0))continue;const a=i.poly[t],n=i.poly[(t+1)%i.poly.length],r=Lr(n,a),l=Math.hypot(r[0],r[1]);if(!(l>s&&Br(e.axis,[r[0]/l,r[1]/l],1e-6)))continue;if(Hr(a,e.center,e.axis)>s||Hr(n,e.center,e.axis)>s)continue;const h=Or(Lr(a,e.center),e.axis),c=Or(Lr(n,e.center),e.axis),d=Math.min(h,c),p=Math.max(h,c);if(d>-e.half+s||p0?d:p<0?-p:0);(!o||_2)return qr(s);if(i.length){const t=i.map(({room:t,edge:i})=>jr(t,i,s,e.epsilon));if(t.some(t=>!t))return qr(s);const o=t;return[...o.map(t=>t.left),...o.map(t=>t.right)]}return Jr(t,e,s)}const Xr="1.68.1",Zr={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon"},Qr={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon"},tl=2e3,el=1e3,sl=t=>{const e=String(t??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e))return null;const s=Number(e);return Number.isFinite(s)?s:null},il=(t,e,s,i)=>{for(t.delete(e),t.set(e,s);t.size>i;){const e=t.keys().next().value;if(void 0===e)break;t.delete(e)}},ol=1e3,al=2e3,nl=t=>{try{t.target?.setPointerCapture?.(t.pointerId)}catch{}},rl="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";class ll{constructor(t){this.host=t,this._junctionBaselineCache=new WeakMap,this._undoGeometry=()=>{if(this.host._physicalDrag||this.host._physicalRotate)return void this._cancelPhysicalGesture();if(this.host._decorDraft)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)return void this._cancelDecorGesture();if(this.host._resize.dragging)return void this._rszCancelDrag();const t=this.host._geometryHistory.undo();t&&(this._applyGeometryState(t.before,!0)?this.host._showToast(this.host._t("history.undone",{name:t.name})):this.host._geometryHistory.clear())},this._redoGeometry=()=>{if(this.host._physicalDrag||this.host._physicalRotate)return void this._cancelPhysicalGesture();if(this.host._decorDraft)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)return void this._cancelDecorGesture();if(this.host._resize.dragging)return void this._rszCancelDrag();const t=this.host._geometryHistory.redo();t&&(this._applyGeometryState(t.after,!0)?this.host._showToast(this.host._t("history.redone",{name:t.name})):this.host._geometryHistory.clear())},this._savePhysicalDialog=()=>{const t=this.host._physicalDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=sl(t.cm);if(null==i)return void this._showPhysicalRange("column"===t.kind?yt:100,"column"===t.kind?1:0);const o=this.host._imperial?2.54*i:i,a="column"===t.kind?yt:100,n="column"===t.kind?1:0;if(!Number.isFinite(o)||oa)return void this._showPhysicalRange(a,n);if("column"===t.kind){const e=s.wall_columns.find(e=>e.id===t.id);if(!e)return;const i=sl(t.angle||"0");if("circle"!==t.shape&&(null==i||i<0||i>=90))return void this.host._showToast(this.host._t("toast.physical_angle"));const a="circle"===t.shape?{id:t.id,shape:"circle",center:e.center,cm:o}:{id:t.id,shape:"square",center:e.center,cm:o,angle:i};if(s.wall_columns.some(e=>e.id!==t.id&&vt(e,a,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"))}const r=this._geometrySnapshot();if("partition"===t.kind){const s=(e.partitions||[]).find(e=>e.id===t.id);if(s&&0===o&&$t(e.openings,{kind:"partition",id:t.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));s&&(s.cm=o)}else if("column"===t.kind){const s=(e.wall_columns||[]).find(e=>e.id===t.id);s&&(s.cm=wt(o),s.shape="circle"===t.shape?"circle":"square","square"===s.shape?s.angle=sl(t.angle||"0"):delete s.angle)}else{const s=(e.room_drafts||[]).find(e=>e.id===t.id);s?.segments?.[t.segment||0]&&(s.segments[t.segment||0].cm=o)}const l=this._commitPhysicalGeometry(this.host._t("history.physical_edit"),r);this.host._physicalDialog=null,l||this.host.requestUpdate()},this._deletePhysicalSelection=()=>{const t=this.host._physicalSel,e=this.host._curSpaceCfg;if(!t||!e)return;if("draft"===t.kind)return void this._deleteDraftWhole();const s=this._geometrySnapshot();if("partition"===t.kind){const s=(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(s.length)return void(this.host._partitionDeleteDialog={id:t.id,openings:s.map(t=>JSON.parse(JSON.stringify(t)))})}const i="partition"===t.kind?"partitions":"column"===t.kind?"wall_columns":"room_drafts";e[i]=(e[i]||[]).filter(e=>e.id!==t.id),e[i].length||delete e[i],this.host._activeDraftId===t.id&&this._cancelPath(),this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._confirmPartitionDelete=()=>{const t=this.host._partitionDeleteDialog,e=this.host._curSpaceCfg;if(!t||!e)return;const s=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.host._partitionDeleteDialog=null,this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._deleteDraftWhole=()=>{const t="draft"===this.host._physicalDialog?.kind?this.host._physicalDialog.id:"draft"===this.host._physicalSel?.kind?this.host._physicalSel.id:null,e=this.host._curSpaceCfg;if(!t||!e||!confirm(this.host._t("confirm.delete_draft")))return;const s=this._geometrySnapshot();e.room_drafts=(e.room_drafts||[]).filter(e=>e.id!==t),e.room_drafts.length||delete e.room_drafts,this.host._activeDraftId===t&&this._cancelPath(),this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._deleteDraftSegment=()=>{const t=this.host._physicalDialog,e=this.host._curSpaceCfg;if(!t||"draft"!==t.kind||!e)return;if(!confirm(this.host._t("confirm.delete_draft_segment")))return;const s=(e.room_drafts||[]).findIndex(e=>e.id===t.id);if(s<0)return;const i=e.room_drafts[s],o=Math.max(0,Math.min(i.segments.length-1,t.segment||0)),a=[],n=i.points.slice(0,o+1),r=i.points.slice(o+1);if(n.length>=2&&a.push({id:i.id,points:n,segments:i.segments.slice(0,o)}),r.length>=2&&a.push({id:a.length?`${i.id}-${Date.now().toString(36)}`:i.id,points:r,segments:i.segments.slice(o+1)}),2===a.length&&e.room_drafts.length>=200)return void this.host._showToast(this.host._t("toast.physical_limit"));const l=this._geometrySnapshot();e.room_drafts.splice(s,1,...a),e.room_drafts.length||delete e.room_drafts,this.host._activeDraftId===i.id&&this._cancelPath(),this.host._physicalDialog=null,this.host._physicalSel=a.length?{kind:"draft",id:a[0].id}:null,this._commitPhysicalGeometry(this.host._t("history.draft_segment_delete"),l)},this._confirmRoomDelete=t=>{const e=this.host._roomDeleteDialog,s=this.host._curSpaceCfg,i=this.host._spaceModel();if(!e||!s||!i)return;const o=i.rooms.find(t=>t.id===e.roomId);if(!o)return void(this.host._roomDeleteDialog=null);const a=this.host._openCuts(),n=nn(z(i.rooms,this.host._spaceWalls,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol).filter(t=>t.roomId===o.id),i.partitions,this.host._openingsR.map(t=>({...t,x:t.rx,y:t.ry})),.02*this.host._gridPitch),r=new Set(n.materialize.filter(t=>!t.reusePartitionId).map(t=>t.interval.key)).size;if(t&&(s.partitions||[]).length+r>al)return void this.host._showToast(this.host._t("toast.physical_limit"));const l=this._geometrySnapshot(),h=kt(i.rooms,this.host._spaceWalls,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol);if(t){s.partitions||=[];const t=new Map,e=new Map,i=t=>{const e=(s.wall_segments||[]).find(e=>{const s=[Number(e.a?.[0])*ol,Number(e.a?.[1])*ol],i=[Number(e.b?.[0])*ol,Number(e.b?.[1])*ol];return this._samePt(t.a,s)&&this._samePt(t.b,i)||this._samePt(t.a,i)&&this._samePt(t.b,s)});return"string"==typeof e?.id&&e.id?e.id:null},o=Date.now().toString(36);for(const a of n.materialize){let n=a.reusePartitionId?s.partitions.find(t=>t.id===a.reusePartitionId):e.get(a.interval.key);n||(n={id:i(a.interval)||`partition-room-${o}-${e.size}`,a:[a.interval.a[0]/ol,a.interval.a[1]/ol],b:[a.interval.b[0]/ol,a.interval.b[1]/ol],cm:a.interval.cm},s.partitions.push(n),e.set(a.interval.key,n)),t.set(a.interval.key,n)}for(const e of s.openings||[]){const s=n.openingIntervals.get(e.id),i=s?t.get(s):null,o=this.host._openingsR.find(t=>t.id===e.id);if(!i||!o)continue;const a={a:[i.a[0]*ol,i.a[1]*ol],b:[i.b[0]*ol,i.b[1]*ol]};e.host={kind:"partition",id:i.id,t:rn([o.rx,o.ry],a)}}}else if(n.removeOpeningIds.length){const t=new Set(n.removeOpeningIds);s.openings=(s.openings||[]).filter(e=>!t.has(e.id)),s.openings.length||delete s.openings}s.rooms=s.rooms.filter(t=>t.id!==o.id),this.host._cfgEpoch++;const c=this.host._normalizeWalls(h,this.host._openCuts());c.length?s.walls=c:delete s.walls,this.host._roomDeleteDialog=null,this._commitPhysicalGeometry(this.host._t(t?"history.delete_room_keep_walls":"history.delete_room_with_walls"),l),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate()},this._rebindPartitionOpening=()=>{const t=this.host._openingDialog;if(!t?.id)return;const e=t.id;this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingRebindId=e,this.host._openingPreset={type:t.type,lengthCm:t.lengthCm,flipH:t.flipH,flipV:t.flipV,revision:++this.host._openingPresetRevision},this.host._openingDialog=null,this.host._openingHoverCandidate=null)},this._deviceInboxTabKey=t=>{if("ArrowLeft"!==t.key&&"ArrowRight"!==t.key)return;const e=this.host._deviceInbox;if(!e)return;const s=["on_plan","available","hidden","readd"],i="ArrowRight"===t.key?1:-1,o=(s.indexOf(e.tab)+i+s.length)%s.length;this.host._deviceInbox={...e,tab:s[o],limit:100,onlyNew:!1},t.preventDefault()},this._keepClosedAsPartitions=()=>{if(this.host._wallFaceBatch)return void this._decideWallFace(!1);if(!this.host._contourClosed||this.host._pendingSplit||!this.host._curSpaceCfg)return;const t=this.host._curSpaceCfg,e=this.host._path.slice(0,-1);if((t.partitions||[]).length+e.length>al)return void this.host._showToast(this.host._t("toast.physical_limit"));const s=this._geometrySnapshot(),i=Ra(e.length,[...this.host._draftSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,A);t.partitions||=[];const o=Date.now().toString(36),a=this.host._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this.host._activeDraftId):null,n=this._draftSegmentsForPath(this.host._path,a,i);for(let s=0;st.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this.host._t("history.contour_to_partitions"),s),this.host._roomDialog=!1,this.host._path=[],delete this.host._resumeDraftBySpace[this.host._space],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null},this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,saved:t?.plans||[],savedBusy:!1})}catch(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}},this._openSettingsDialog=()=>{if(!this.host._norm)return;const t=this.host._glowRadiusCm,e=this.host._imperial?Math.round(t/30.48*10)/10:Math.round(t)/100;this.host._settingsDialog={colors:JSON.parse(JSON.stringify(this.host._fillColors)),glowRadius:e,bgColor:Dt(this.host._settings,{bgColor:null})||null,northDeg:Mt(this.host._settings,{}),bgMode:St(this.host._settings,{}),sunRays:xt(this.host._settings,{}),busy:!1}},this._openAlignDialog=()=>this._previewAlignDialog(!1),this._toggleOptimizeLivePositions=()=>{const t=this.host._alignDialog;t&&!t.busy&&t.report.liveMissingPositions.length&&this._previewAlignDialog(!t.removeLiveMissingPositions)},this._openBackupExport=()=>{this.host._settingsDialog=null,this.host._backupExportDialog={kind:"full",planOnly:!1,busy:!1,error:""}},this._openRulesDialog=()=>{if(!this.host._norm)return;const t=this.host._settings.icon_rules,e=(t&&t.length?t:Ct).map(t=>({...t}));this.host._rulesDialog={rules:e,test:"",busy:!1}},t._editorSecondary=new gn({root:()=>t.renderRoot,requestUpdate:()=>t.requestUpdate(),updateComplete:()=>t.updateComplete,clearTip:()=>{t._tip=null}}),t._resize=new Wo}_help(t){const e=`${t}.aria`,s=d(this.host.hass,this.host._config?.language);return Pt(s,t)&&Pt(s,e)?o``:a}_setMode(t,e=!0){this.host._endTabDrag(),this.host._pendingNavMode=null;const s=this.host._spaceModel();if(!s)return this.host._cancelModeTransition(!1),void(this.host._mode="view");if(this.host._kiosk&&"view"!==t)return;if(this.host._mode===t){if(!e&&"view"===t&&this.host._modeTransitionBusy){const e=this.host._currentModeVisual(t),s=this.host._modeTransitionTargetZoom,i=this.host._modeTransitionTargetCenterX,o=this.host._modeTransitionTargetCenterY;this.host._cancelModeTransition(!1),this.host._commitViewModeAtomic(e,s,i,o)}return}if(this.host._bootSoftCancel(),("plan"===t||"decor"===t)&&!this.host._norm)return void this.host._showToast(this.host._t("toast.markup_needs_server"));if(this.host._wallFaceBatch&&this._roomDialogCancel(),"plan"===this.host._mode&&"draw"===this.host._tool&&!this._finishWallChain())return;this.host._clearTransientHover(!0),this.host._cancelDevicePressFeedback();const i=this.host._mode,o=this.host._effectiveProjection(),a=this.host._currentModeVisual(i),n=this.host._modeTransitionBusy,r=a&&"view"!==i&&"view"!==t?{...a,toolbarContentOpacity:this.host._reducedMotion?1:.35}:a;this.host._cancelModeTransition(!1),this.host._editorSecondary.closeForNavigation(),(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)&&this._cancelDecorGesture();const l=!s.bg&&"view"===t!=("view"===i),h=n&&"view"===i&&"view"!==t?this.host._modeTransitionEditorCamera:null;let c=h?.zoom??(n?this.host._modeTransitionTargetZoom:this.host._zoom),d=h?h.centerX:n?this.host._modeTransitionTargetCenterX:r?.viewport.centerX,p=h?h.centerY:n?this.host._modeTransitionTargetCenterY:r?.viewport.centerY;if("view"===i&&"view"!==t&&!n){const e=this.host._view;if(this.host._viewModeSnap={space:this.host._space,zoom:this.host._zoom,cx:e?this.host._logicalViewCenter(o)?.x:void 0,cy:e?this.host._logicalViewCenter(o)?.y:void 0},"iso"===o){const e=this.host._logicalViewCenter("iso");d=e?.x,p=e?.y,this.host._view=null,this.host._mode=t,this.host._applyView(this.host._zoom,e?.x,e?.y)}l&&(c=1,d=void 0,p=void 0)}if("plan"===i&&this.host._activeDraftId&&(this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId),this.host._mode=t,"devices"===i&&"devices"!==t&&(this.host._showHidden=!1,this.host._deviceInbox=null,this.host._deviceInboxReturn=null,this.host._deviceInboxMemo=null),this.host._editorChromeMode="view"===t?i:t,"view"===t){"view"===i||n||(this.host._modeTransitionEditorCamera={zoom:this.host._zoom,centerX:r?.viewport.centerX,centerY:r?.viewport.centerY});const t=this.host._viewModeSnap;if(t&&t.space===this.host._space){c=t.zoom;const e=this.host._labsIso&&"iso"===this.host._viewPreference[this.host._space]?"iso":"flat",s=null!=t.cx&&null!=t.cy&&"iso"===e?It([t.cx,t.cy],0):null;d=s?.[0]??t.cx,p=s?.[1]??t.cy}else t&&(c=this.host._zoomBySpace[this.host._space]||1,d=void 0,p=void 0)}else this.host._modeTransitionEditorCamera={zoom:c,centerX:d,centerY:p};this.host._modeTransitionTargetZoom=c,this.host._modeTransitionTargetCenterX=d,this.host._modeTransitionTargetCenterY=p,("iso"===o||"view"===t&&this.host._labsIso&&"iso"===this.host._viewPreference[this.host._space])&&(this.host._modeTransitionForceAtomic=!0);const _=++this.host._modeTransitionRequest;e?r?(this.host._modeTransitionPreparing=!0,this.host._modeTransitionVisual=r,this.host._prepareModeTransition(_,r,t,c,d,p)):(this.host._modeTransitionPreparing=!1,this.host._modeTransitionVisual=null,this.host._zoom=c,this.host._view=null,requestAnimationFrame(()=>{this.host.isConnected&&_===this.host._modeTransitionRequest&&this.host._mode===t&&(this.host._applyView(c,d,p),"view"===t&&(this.host._viewModeSnap=null,this.host._modeTransitionEditorCamera=null),this.host.requestUpdate())})):"view"===t&&this.host._commitViewModeAtomic(r,c,d,p),this.host._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this.host._tool="draw",this.host._mergeSel=null,this.host._mergeDialog=null,this.host._splitSel=null,this.host._pendingSplit=null,this.host._selId=null,this.host._physicalSel=null,this.host._physicalDialog=null,this.host._physicalDrag=null,this._rszResetController(),this.host._tip=null,this.host._hoverRoom=null,this.host._decorDraft=null,this.host._decorSel=null,this.host._decorMove=null,this.host._backdropDialog=null,this.host._decorTool="select",this.host._bdDrag=null,this.host._dtDrag=null,this.host._dtBox=null,"plan"===t&&(this._primeDrawWallField(),this._resumeLastDraft()),this.host._saveNav()}_primeDrawWallField(){null===this.host._drawWallField&&(this.host._drawWallField=Tt(A,this.host._imperial))}_showPhysicalRange(t=this.host._drawWallMaxCm,e=0){this.host._showToast(this.host._t("toast.physical_range",{min:Tt(e,this.host._imperial),max:Tt(t,this.host._imperial),unit:this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}))}_draftSegmentCount(t=this.host._curSpaceCfg){return(t?.room_drafts||[]).reduce((t,e)=>t+(Array.isArray(e.segments)?e.segments.length:0),0)}_mergeSpacePartitions(t,e){const s=t?.partitions||[];if(s.length<2)return 0;const i=Rn(s,{pitch:I,seedIds:e,geometry:Nn(t,{excludeDraftId:this.host._activeDraftId})});return i.merged?(t.partitions=i.partitions,Fn(t.openings,t.partitions,i.openingMoves,{coordScale:ol,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch}),i.merged):0}_finishWallChain(){if("draw"!==this.host._tool||this.host._wallFaceBatch||this.host._roomDialog)return!0;const t=this.host._curSpaceCfg;if(!t||this.host._path.length<2)return this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),!0;const e=Fa(this.host._path,Ra(this.host._path.length-1,this.host._draftSegmentCms,this.host._drawWallCm,A)),s=e.length;if((t.partitions||[]).length+s>al)return this.host._showToast(this.host._t("toast.physical_limit")),!1;const i=this._geometrySnapshot();t.partitions||=[];const o=Date.now().toString(36),a=[],n=this.host._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this.host._activeDraftId):null,r=this._draftSegmentsForPath(this.host._path,n,e.map(t=>t.cm));for(let i=0;it.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this.host._t("history.wall_chain_finish"),i),delete this.host._resumeDraftBySpace[this.host._space],this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),!0}_activateMarkupTool(t){t!==this.host._tool&&(this.host._wallFaceBatch&&this._roomDialogCancel(),("draw"!==this.host._tool||this._finishWallChain())&&(this._cancelPath(),"resize"===this.host._tool&&(this.host._resize.dragging?this._rszCancelDrag():this.host._resize.reset()),this.host._tool=t,"draw"===t&&this._resumeLastDraft(),"resize"===t&&this.host._resize.selectRoom(null),"wallthick"===t&&(this.host._wallDialog=null)))}_limitReached(t){const e=this.host._curSpaceCfg;if(!e)return!0;const s="draft"===t?(e.room_drafts||[]).length>=200:"partition"===t?(e.partitions||[]).length>=al:(e.wall_columns||[]).length>=500;return s&&this.host._showToast(this.host._t("toast.physical_limit")),s}_svgPoint(t){const e=this.host.renderRoot.querySelector(".stage").getBoundingClientRect();return this.host._screenToVb(t.clientX-e.left,t.clientY-e.top)}_snap(t){const e=this.host._gridPitch;return[Rt(Ft(t[0],e)),Rt(Ft(t[1],e))]}_snapDrawPoint(t,e=!1){const s=this.host._path[this.host._path.length-1],i=e&&s?Nt(s,t,this.host._gridPitch,Ti):t;return this._snap(i)}_planSnapOpeningCuts(t,e){if(!this.host._openingsR.length)return[];const s=this.host._openingWallIndexFor(t,e).value,i=[];for(const e of this.host._roomWallOpeningInputs(this.host._openingsR,t)){const t=W(s,e);if(!t.negative&&!t.positive)continue;const o=e.angle*Math.PI/180,a=Math.cos(o)*e.length/2,n=Math.sin(o)*e.length/2;i.push([e.x-a,e.y-n,e.x+a,e.y+n])}return i}_planSnapGeometrySnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|empty`,value:{segments:[],endpoints:[]}};const e=[this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._planSnapGeometryCache?.key===e)return this.host._planSnapGeometryCache;const s=this.host._openCuts(),i=xa({space:t,activeDraftId:this.host._activeDraftId,roomCuts:this._planSnapOpeningCuts(t,s),partitionCuts:this._partitionOpeningCuts(t),epsilon:2e-4*this.host._gridPitch});return this.host._planSnapGeometryCache={key:e,value:i},this.host._planSnapGeometryCache}_hiddenWallDiagnosticSnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|hidden-empty`,value:{segments:[],endpoints:[]}};const e=["hidden",this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._hiddenWallDiagnosticCache?.key===e)return this.host._hiddenWallDiagnosticCache;const s=ka({space:t,activeDraftId:this.host._activeDraftId,epsilon:2e-4*this.host._gridPitch});return this.host._hiddenWallDiagnosticCache={key:e,value:s},this.host._hiddenWallDiagnosticCache}_planStructuralGeometrySnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|structural-empty`,value:{segments:[],endpoints:[]}};const e=["structural",this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._planStructuralGeometryCache?.key===e)return this.host._planStructuralGeometryCache;const s=xa({space:t,activeDraftId:this.host._activeDraftId,epsilon:2e-4*this.host._gridPitch});return this.host._planStructuralGeometryCache={key:e,value:s},this.host._planStructuralGeometryCache}_planSnapContextKey(t){const e=this.host._path[0],s=this.host._path[this.host._path.length-1];return[t,this.host._tool,this.host._path.length,e?`${e[0]},${e[1]}`:"",s?`${s[0]},${s[1]}`:""].join("|")}_resolvePlanDrawPoint(t,e){const s=this._planSnapGeometrySnapshot(),i=this.host._path[this.host._path.length-1],o="draw"===this.host._tool&&this.host._path.length>=3?[{point:this.host._path[0],key:"closure:first-point"}]:[],a={tolerance:this._cssPxToRender(12),distinguishTolerance:this._cssPxToRender(8),gridStep:this.host._gridPitch,excludePoints:i?[i]:[],extraEndpoints:o,epsilon:2e-4*this.host._gridPitch},n=e&&i?Ia(s.value,t,{...a,anchor:i}):function(t,e,s){if(!(ma(e)&&s.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const i=s.epsilon??ua,o=s.excludePoints||[],a=Ca(Da(t,e,s),s.distinguishTolerance||0);if(a)return a;let n=null;for(const a of t.segments){const t=[a.a[0],a.a[1],a.b[0],a.b[1]],r=C([e[0],e[1]],t);if(r>s.tolerance)continue;const l=Pa(a,e,s.gridStep);!Sa(l,o,i)&&Ma(r,a.key,n)&&(n={kind:"line",point:l,key:a.key,distance:r,segment:a})}return n?{kind:"resolved",candidate:n,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}(s.value,t,a),r="resolved"===n.kind?n.candidate:null,l=r?[...r.point]:this._snapDrawPoint(t,e),h=i?zt(i,l):l;return{point:h,candidate:r&&q(h,r.point)?r:null,conflicts:"ambiguous"===n.kind?n.conflicts:[],ambiguous:"ambiguous"===n.kind,contextKey:this._planSnapContextKey(s.key)}}_clearPlanSnapHover(t=!0){this.host._planSnapHover=null,this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers([]),t&&(this.host._cursorPt=null)}_samePt(t,e){return q(t,e)}_dropLegacySegments(){for(const t of this.host._serverCfg?.markers||[])"ripple"===t.display&&(t.display="icon_ripple");for(const t of this.host._serverCfg?.spaces||[]){delete t.segments;const e=new Set,s=t=>"string"==typeof t&&t.length>=1&&t.length<=64&&!e.has(t),i=t=>(e.add(t),!0),o=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(Number(t))&&Math.abs(Number(t))<=Xt);if(Array.isArray(t.partitions)&&(t.partitions=t.partitions.filter(t=>t&&s(t.id)&&o(t.a)&&o(t.b)&&Math.hypot(t.a[0]-t.b[0],t.a[1]-t.b[1])>1e-9&&i(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&&s(t.id)&&o(t.center)&&i(t.id)).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[Number(t.center[0]),Number(t.center[1])],cm:wt(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:At(t.angle)}})),t.wall_columns.length||delete t.wall_columns),Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t&&s(t.id)&&Array.isArray(t.points)&&t.points.length>=2&&t.points.every(o)&&i(t.id)).map(t=>{const e=hr(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=Ot(ut({spaces:[t]}),t.id),s=e?Lt(t,e,ol,.02*nt).contour.map(t=>t.map(t=>t/ol)):V(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]);t.walls=rt(t.walls,t.rooms||[],I,1,s),t.walls.length||delete t.walls}}}_rollbackRejectedPhysicalWrites(t){if(!this.host._serverCfg||!t.length)return!1;let e=!1;for(const[s]of t){const t=this.host._pendingPhysicalWrites.get(s);t&&(e=this._restoreGeometryStateInConfig(this.host._serverCfg,t.before)||e,this.host._pendingPhysicalWrites.delete(s))}return!!e&&(this._clearGeometryGesture(),this.host._geometryHistory.clear(),this.host._cfgEpoch++,this.host._modelCache=null,this.host._wallUnionCache=null,this.host._physicalBodiesCache=null,this.host._frame=null,this.host._regSignature="",this.host._cfgContentFingerprint=Et(this.host._serverCfg),this.host._maybeRebuildDevices(),this.host.requestUpdate(),!0)}async _reloadRejectedPhysicalWrite(){const t=this.host._writeChain;await t.catch(()=>{}),await this.host._reloadConfigOnly(!0)}_writeConfig(){this.host._writesPending++,this.host._writeChain=Bt(this.host._writeChain,async()=>{if(!this.host._serverCfg)return;this._dropLegacySegments();const t=Mi(this.host._serverCfg),e=Et(t),s=[...this.host._pendingPhysicalWrites.entries()];for(const[e,i]of s){const s=t.spaces.find(t=>t.id===e),o=jt(s);if(o===i.fingerprint)continue;let a=!1;try{a=this.host._checkSpacePhysicalGeometry(t,e).ok}catch{a=!1}if(!a)throw this._restoreGeometryStateLocal(i.before),this.host._pendingPhysicalWrites.delete(e),this.host._geometryHistory.clear(),this.host._showToast(this.host._t("toast.geometry_unsafe")),Object.assign(new Error("unsafe wall geometry"),{code:"geometry-unsafe"});i.fingerprint=o}e!==Et(this.host._serverCfg)&&(this.host._serverCfg=t),this.host._cfgContentFingerprint=e;try{await this.host._sendConfigCandidate(t)}catch(t){if(!this._rollbackRejectedPhysicalWrites(s))throw t;const e=t&&"object"==typeof t?t:Object.assign(new Error(String(t)),{cause:t});throw e.physicalGeometryRolledBack=!0,e}for(const[t,e]of s)this.host._pendingPhysicalWrites.get(t)?.fingerprint===e.fingerprint&&this.host._pendingPhysicalWrites.delete(t)});return this.host._writeChain.finally(()=>{this.host._writesPending--})}_saveConfig(){this.host._cfgEpoch++,this.host._saveConfigDebounced()}_geometrySnapshotFromConfig(t,e){const s=t?.spaces?.find(t=>t.id===e);if(!s)return null;const i=t=>JSON.parse(JSON.stringify(t)),o={};for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==s[t]&&(o[t]=s[t]);return{spaceId:e,rooms:i(s.rooms||[]),...Array.isArray(s.openings)?{openings:i(s.openings)}:{},...Array.isArray(s.walls)?{walls:i(s.walls)}:{},...Array.isArray(s.wall_segments)?{wall_segments:i(s.wall_segments)}:{},...Array.isArray(s.open_spans)?{open_spans:i(s.open_spans)}:{},...Array.isArray(s.room_drafts)?{room_drafts:i(s.room_drafts)}:{},...Array.isArray(s.partitions)?{partitions:i(s.partitions)}:{},...Array.isArray(s.wall_columns)?{wall_columns:i(s.wall_columns)}:{},...Array.isArray(s.decor)?{decor:i(s.decor)}:{},plan_transform:o}}_geometrySnapshot(t=this.host._space){return this._geometrySnapshotFromConfig(this.host._serverCfg,t)}_recordGeometry(t,e){if(!e)return;const s=this._geometrySnapshot(e.spaceId);s&&JSON.stringify(e)!==JSON.stringify(s)&&(this.host._geometryHistory.push({name:t,before:e,after:s}),this.host.requestUpdate())}_restoreGeometryStateInConfig(t,e,s=!1){const i=t?.spaces?.find(t=>t.id===e.spaceId);if(!i)return!1;const o=t=>JSON.parse(JSON.stringify(t)),a=new Map((i.rooms||[]).map(t=>[t.id,t]));if(i.rooms=o(e.rooms),s)for(const t of i.rooms){const e=a.get(t.id);!Array.isArray(t.wall_ids)&&Array.isArray(e?.wall_ids)&&e.wall_ids.length===t.poly?.length&&(t.wall_ids=o(e.wall_ids))}const n=(t,e)=>{void 0!==e?i[t]=o(e):s&&"wall_segments"===t||delete i[t]},r=new Map((i.openings||[]).map(t=>[t.id,t])),l=new Map((i.room_drafts||[]).map(t=>[t.id,t]));if(n("openings",e.openings),n("walls",e.walls),n("wall_segments",e.wall_segments),n("open_spans",e.open_spans),n("room_drafts",e.room_drafts),n("partitions",e.partitions),n("wall_columns",e.wall_columns),n("decor",e.decor),s){for(const t of i.openings||[]){const e=r.get(t.id);t.host||"wall"!==e?.host?.kind||(t.host=o(e.host))}for(const t of i.room_drafts||[]){const e=l.get(t.id);for(let s=0;s<(t.segments||[]).length;s++)!t.segments[s]?.id&&e?.segments?.[s]?.id&&(t.segments[s].id=e.segments[s].id)}}for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete i[t];return Object.assign(i,o(e.plan_transform||{})),!0}_restoreGeometryStateLocal(t){return!!this._restoreGeometryStateInConfig(this.host._serverCfg,t)&&(this.host._cfgEpoch++,this.host._modelCache=null,this.host._wallUnionCache=null,this.host._physicalBodiesCache=null,this.host._frame=null,this.host.requestUpdate(),!0)}_wallModelBlockerLabel(t){const e=t instanceof er?t.reason:"invalid-room";return this.host._t(`wall_model.reason.${e}`)}_hasLegacyZeroWallFields(t=this.host._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.host._showToast(this.host._t(e,{reason:this._wallModelBlockerLabel(t)}))}_limitSegmentsOf(t){const e=[];for(const s of t?.wall_segments||[])s?.a&&s?.b&&e.push({id:String(s.id||""),a:s.a,b:s.b,cm:Number(s.cm)});for(const s of t?.partitions||[])s?.a&&s?.b&&e.push({id:String(s.id||""),a:s.a,b:s.b,cm:Number(s.cm)});for(const s of t?.room_drafts||[]){const t=Array.isArray(s?.points)?s.points:[],i=Array.isArray(s?.segments)?s.segments:[];for(let o=0;o+1t?.id===e);if(!i)return[];const o=Number(i.cell_cm)>0?Number(i.cell_cm):5,a=this._limitSegmentsOf(i),n=[...ta(a),...aa(a,o,I),...ra(a,o,I)];let r=null;try{r=Ht(i.rooms||[],i.walls||[],[],I,o,I,1)}catch{r=null}let l="ok"===s?.status||"degraded-extra"===s?.status?s.roomGeom:null;if(!l&&r&&r.nodes.length)try{const t=Gt(i.rooms||[],i.walls||[],[],[],I,o,I,1);l="ok"===t?.status||"degraded-extra"===t?.status?t.roomGeom:null}catch{l=null}for(const t of i.rooms||[]){const e=String(t?.id||"");if(!e)continue;let s=null;try{s=Wt(i.rooms||[],e,i.walls||[],[],I,o,I,1,l??void 0,r)}catch{s=null}n.push(...la(e,s,o,I))}return n}_junctionLimitLabel(t){const e=t=>String(Math.round(10*t)/10);return this.host._t(`junction.limit_${t.rule}`,{actual:e(t.actual),limit:e(t.limit)})}_junctionLimitsIntroduced(t,e,s,i){let o;const a=(e?.spaces||[]).find(t=>t?.id===s);let n="";try{n=jt(a)}catch{n=""}const r=e&&"object"==typeof e?this._junctionBaselineCache.get(e):void 0;if(r&&n&&r.fingerprint===n&&r.spaceId===s&&(o=r.violations),!o){try{const t=Number(e?.model_version||0)>=9?e:Mr(e).config;o=this.host._junctionLimitViolations(t,s)}catch{return[]}e&&"object"==typeof e&&n&&this._junctionBaselineCache.set(e,{spaceId:s,fingerprint:n,violations:o})}let l=[];try{l=this.host._junctionLimitViolations(t,s,i)}catch{return[{rule:"check_failed",subject:s,actual:0,limit:0}]}return function(t,e){const s=new Map;for(const t of e||[])s.set(t.rule,(s.get(t.rule)||0)+1);const i=new Map;for(const e of t||[])i.set(e.rule,[...i.get(e.rule)||[],e]);const o=[];for(const[t,e]of i){const i=e.length-(s.get(t)||0);i>0&&o.push(...e.slice(0,i))}return o}(l,o)}_commitPhysicalGeometry(t,e,s=[]){if(!e||!this.host._serverCfg)return!1;const i=this.host._serverCfg,o=this._geometrySnapshotFromConfig(i,e.spaceId),a=i.spaces.find(t=>t.id===e.spaceId);if(!a||jt(e)===jt(a))return!1;let n,r=!1;try{r=this.host._checkSpacePhysicalGeometry(i,e.spaceId).ok}catch{r=!1}if(!r)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;let l=e;try{if(Number(i.model_version||0)<9){const t=JSON.parse(JSON.stringify(i));if(!this._restoreGeometryStateInConfig(t,e))throw new er("invalid-room",e.spaceId);const s=Mr(t).config;l=this._geometrySnapshotFromConfig(s,e.spaceId)||e;const a=JSON.parse(JSON.stringify(s));if(!o||!this._restoreGeometryStateInConfig(a,o,!0))throw new er("invalid-room",e.spaceId);const r=s.spaces.find(t=>t.id===e.spaceId),h=a.spaces.find(t=>t.id===e.spaceId);if(!Array.isArray(o.wall_segments)&&JSON.stringify(e.rooms)===JSON.stringify(o.rooms))for(const t of h?.wall_segments||[])t.cm=Q(o.walls,t.a,t.b,I,1);const c=((t,e,s)=>{const i=new Map,o=new Map((t?.rooms||[]).map(t=>[t.id,t])),a=new Map((e||[]).map(t=>[t.id,t])),{rooms:n}=$r(s,yr(t));for(const t of n){const e=a.get(t.id),n=o.get(t.id),r=R(e),l=(s.rooms||[]).find(e=>e.id===t.id),h=R(l),c=R(n);if(r&&h&&c&&r.length===h.length&&c.length===n?.wall_ids?.length&&t.poly.length===t.wall_ids.length)for(let e=0;e{const o=[];for(let a=0;atr||pr(r,s,i)>tr)continue;const l=dr(n,s,i),h=dr(r,s,i);l<-tr||h>1+tr||h<=l+tr||o.push({start:l,id:e[a]})}return o.sort((t,e)=>t.start-e.start)},o=s(c,n.wall_ids,r[e],r[(e+1)%r.length]),a=s(t.poly,t.wall_ids,h[e],h[(e+1)%h.length]);if(o.length&&o.length===a.length)for(let t=0;tt.id===e.spaceId),i=this.host._path.length>=2?this.host._path.map(t=>[t[0]/ol,t[1]/ol]):[];i.push(...s.map(t=>[t[0],t[1]])),h=cr(t)<=cr(l,i)&&this.host._checkSpacePhysicalGeometry(n,e.spaceId).ok}catch{h=!1}if(!h)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;const c=JSON.parse(JSON.stringify(i));this._restoreGeometryStateInConfig(c,e);const d=this._junctionLimitsIntroduced(n,c,e.spaceId);if(d.length)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this._junctionLimitLabel(d[0])),!1;Cr(i,n),this._recordGeometry(t,l);const p=i.spaces.find(t=>t.id===e.spaceId),_=this.host._pendingPhysicalWrites.get(e.spaceId);return this.host._pendingPhysicalWrites.set(e.spaceId,{before:_?.before||l,fingerprint:jt(p)}),this._saveConfig(),!0}_clearGeometryGesture(){this.host._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!1),this.host._mergeSel=null,this.host._mergeDialog=null,this.host._splitSel=null,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._wallRepairDiagnostic=null,this.host._roomDeleteDialog=null,this.host._wallDialog=null,this.host._physicalDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this.host._openingDialog=null,this._rszResetController(),this.host._decorDraft=null,this.host._decorMove=null,this.host._dtDrag=null,this.host._bdDrag=null}_stagePointerCancel(t){if(clearTimeout(this.host._kioskHoldTimer),this.host._swipeStart?.id===t.pointerId&&(this.host._swipeStart=null),this.host._physicalDrag?.pid===t.pointerId||this.host._physicalRotate?.pid===t.pointerId)return void this._cancelPhysicalGesture();if(this.host._decorDraft?.pid===t.pointerId)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove?.pid===t.pointerId||this.host._dtDrag?.pid===t.pointerId||this.host._bdDrag?.pid===t.pointerId)return void this._cancelDecorGesture();"opening"===this.host._tool?(this.host._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this.host._tool&&this._clearPlanSnapHover();const e=!!this.host._pinchStart||!!this.host._panStart;this.host._pointers.delete(t.pointerId),this.host._pointers.size<2&&(this.host._pinchStart=null),0===this.host._pointers.size&&(this.host._panStart=null,this.host._panLock=null),e&&0===this.host._pointers.size&&this.host.requestUpdate()}_applyGeometryState(t,e=!1){if(!this.host._canCommitSpace(t.spaceId))return!1;const s=this._geometrySnapshot(t.spaceId);if(!s||!this._restoreGeometryStateLocal(t))return!1;const i=this.host._serverCfg,o=jt(s)!==jt(t);if(o){let o=!1;try{const s=i?this.host._checkSpacePhysicalGeometry(i,t.spaceId):null;o=!!s?.ok||!(!e||"wall-degraded-extra"!==s?.reason)}catch{o=!1}if(!o)return this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1}let a;try{a=Mr(i).config}catch(t){return this._restoreGeometryStateLocal(s),this._showWallModelMigrationBlocked(t),!1}if(o){let o=!1;try{const s=a?this.host._checkSpacePhysicalGeometry(a,t.spaceId):null;o=!!s?.ok||!(!e||"wall-degraded-extra"!==s?.reason)}catch{o=!1}if(!o)return this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;Cr(i,a);const n=i?.spaces.find(e=>e.id===t.spaceId),r=this.host._pendingPhysicalWrites.get(t.spaceId);this.host._pendingPhysicalWrites.set(t.spaceId,{before:r?.before||s,fingerprint:jt(n)})}else Cr(i,a);return this._clearGeometryGesture(),this.host._space!==t.spaceId&&(this.host._commitSpace(t.spaceId),this.host._saveNav(),this.host._restoreZoom()),this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this._saveConfig(),this.host.requestUpdate(),!0}_roomAt(t){return this.host._spaceModel()?.rooms.find(e=>{const s=R(e);return!!s&&qt(t,s)})}_overlapRoom(t){return this.host._spaceModel()?.rooms.find(e=>{const s=R(e);return!!s&&$(t,s)})}_pointInRoom(t,e){return e.poly?Ut(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(!go(t))return!0;const e=t.length,s=.001;for(let i=0;i=500)return this.host._showToast(this.host._t("toast.physical_limit")),!1;const t=this.host._curSpaceCfg;return!(!this.host._activeDraftId&&(t?.room_drafts||[]).length>=200||this._draftSegmentCount(t)>=2e3||(t?.partitions||[]).length+this.host._path.length>al)||(this.host._showToast(this.host._t("toast.physical_limit")),!1)}_markupClick(t){if(this.host._vacFit)return;if(!this.host._markup)return;const e=this.host._spaceModel();if(!e)return void this._clearGeometryGesture();if(this.host._suppressClick)return;if(this.host._drag||this.host._rlResize)return;const s=t.composedPath?.()||[];if(s.some(t=>t?.classList?.contains?.("roomlabel")||t?.classList?.contains?.("rlhandle")))return;if(s.some(t=>t?.classList?.contains?.("physical-hit")))return;const i=this._svgPoint(t);if("select"===this.host._tool)return void(this.host._physicalSel=null);if("resize"===this.host._tool){if(this.host._resize.dragging||s.some(t=>t?.classList?.contains?.("rszhandle")))return;const t=[...e.rooms].reverse().find(t=>this._pointInRoom(i,t));return this.host._resize.selectRoom(t?.id||null),void this.host.requestUpdate()}if("delroom"===this.host._tool)return void this._deleteRoomClick(i);if("opening"===this.host._tool)return void this._openingClick(i);if("merge"===this.host._tool)return void this._mergeClick(i);if("wallthick"===this.host._tool)return void this._wallThickClick(i);if("split"===this.host._tool)return void this._splitClick(i);if("column"===this.host._tool)return void this._columnClick(i);this.host._wallRepairDiagnostic=null;const o=this._resolvePlanDrawPoint(i,t.shiftKey);if(o.ambiguous)return this.host._planSnapHover={contextKey:o.contextKey,candidate:null,conflicts:o.conflicts},this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers(o.conflicts),void this.host._showToast(this.host._t("toast.plan_snap_ambiguous"));let a=o.point;if(t.ctrlKey||t.metaKey){if(t.preventDefault(),this.host._path.length<3)return;a=zt(this.host._path[this.host._path.length-1],this.host._path[0])}if(!this.host._path.length){if(!t.shiftKey&&!o.candidate&&this._offerExistingWallFace(i))return;const e=this._draftEndAt(a);return e?(this.host._activeDraftId=e.draft.id,this.host._resumeDraftBySpace[this.host._space]=e.draft.id,this.host._path=e.reverse?[...e.draft.points].reverse().map(t=>[...t]):e.draft.points.map(t=>[...t]),void(this.host._draftSegmentCms=this._adoptDraftCms(this.host._path,e.reverse?[...e.draft.segments].reverse().map(t=>t.cm):e.draft.segments.map(t=>t.cm),e.draft.id))):(this.host._activeDraftId=null,this.host._draftSegmentCms=[],void(this.host._path=[a]))}const n=this.host._path[this.host._path.length-1];if(this._samePt(a,n))return;const r=this._draftEndAt(a,this.host._activeDraftId||void 0);if(r)return void this._mergeDraftEndpoint(r);if(!this._canAppendRoomDraftPoint())return;const l=this.host._drawWallCm;if(null==l)return void this._showPhysicalRange(100);const h=this.host._path.map(t=>[...t]);this.host._path=[...this.host._path,a],this.host._draftSegmentCms=[...this.host._draftSegmentCms,l],this._persistActiveDraftSegment(),this._offerWallFaces(h)}_draftEndAt(t,e){const s=this.host._spaceModel();if(!s)return null;const i=this.host._viewOr(this.host._baseVb()),o=Math.max(.15*this.host._gridPitch,this.host._stageEl?.clientWidth?i.w/this.host._stageEl.clientWidth*12:0);for(const i of s.room_drafts||[]){if(i.id===e)continue;if(i.points.length<2)continue;const s=i.points[0],a=i.points[i.points.length-1];if(Math.hypot(t[0]-a[0],t[1]-a[1])<=o)return{draft:i,reverse:!1};if(Math.hypot(t[0]-s[0],t[1]-s[1])<=o)return{draft:i,reverse:!0}}return null}_mergeDraftEndpoint(t){const e=this.host._curSpaceCfg;if(!e||!this.host._path.length)return;const s=this.host._path.map(t=>[...t]),i=this._wallGraphSources(s),o=Array.isArray(e.room_drafts)?e.room_drafts:[],a=this.host._activeDraftId?o.find(t=>t.id===this.host._activeDraftId):null,n=o.find(e=>e.id===t.draft.id);if(!n)return;const r=t.reverse?t.draft.points.map(t=>[...t]):[...t.draft.points].reverse().map(t=>[...t]),l=t.reverse?(n.segments||[]).map(t=>({...t})):[...n.segments||[]].reverse().map(t=>({...t})),h=this.host._path[this.host._path.length-1],c=this._samePt(h,r[0]),d=c?null:this.host._drawWallCm;if(!c&&null==d)return void this._showPhysicalRange(100);const p=this._draftSegmentsForPath(this.host._path,a,this.host._draftSegmentCms),_=[...this.host._path.map(t=>[...t]),...c?r.slice(1):r],u=[...p,...null==d?[]:[{cm:d}],...l],m=_.length>=4&&this._samePt(_[0],_[_.length-1]),g=_,f=u;if(g.length>500)return void this.host._showToast(this.host._t("toast.physical_limit"));const b=(a?.segments?.length||0)+(n.segments?.length||0);if(this._draftSegmentCount(e)-b+f.length>2e3)return void this.host._showToast(this.host._t("toast.physical_limit"));if(m){const t=g.slice(0,-1);if(this._contourSelfIntersects(t)||k(t)<=1e-6)return void this.host._showToast(this.host._t("toast.contour_cannot_close"));const e=this._overlapRoom(t);if(e)return void this.host._showToast(this.host._t("toast.room_overlap",{name:e.name||""}))}const y=this._geometrySnapshot(),v=this.host._activeDraftId||t.draft.id,$={...a||n,id:v,points:g.map(t=>[t[0]/ol,t[1]/ol]),segments:f};e.room_drafts=o.filter(e=>e.id!==t.draft.id&&(!this.host._activeDraftId||e.id!==this.host._activeDraftId)),e.room_drafts.push($),this.host._activeDraftId=v,this.host._resumeDraftBySpace[this.host._space]=v,this.host._path=g,this.host._draftSegmentCms=this._adoptDraftCms(g,f.map(t=>Number(t.cm)),v),this.host._physicalSel=null,this._commitPhysicalGeometry(this.host._t("history.draft_merge"),y),null!=d&&this._offerWallFaces(s,s.length-1,i)}_adoptDraftCms(t,e,s){const i=Math.max(0,t.length-1),o=Ra(i,e,this.host._drawWallCm,A);return e.length!==i&&console.debug(`[houseplan] draft ${s??"?"}: восстановлено толщин ${i-e.length} (#234)`),o}_draftSegmentsForPath(t,e,s){const i=Array.isArray(e?.points)?e.points.map(t=>[Number(t?.[0])*ol,Number(t?.[1])*ol]):[],o=Array.isArray(e?.segments)?e.segments:[];return Ra(Math.max(0,t.length-1),s,this.host._drawWallCm,A).map((e,s)=>{const a=t[s],n=t[s+1],r=i.findIndex((t,e)=>{if(e+1>=i.length)return!1;const s=i[e+1];return this._samePt(a,t)&&this._samePt(n,s)||this._samePt(a,s)&&this._samePt(n,t)});return{...r>=0?o[r]:{},cm:e}})}_persistActiveDraftSegment(){if(this.host._path.length<2||!this.host._curSpaceCfg)return;const t=this._geometrySnapshot(),e=this.host._curSpaceCfg;e.room_drafts||=[],this.host._activeDraftId||(this.host._activeDraftId="draft-"+Date.now().toString(36)),this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId;const s=e.room_drafts.findIndex(t=>t.id===this.host._activeDraftId),i={...s>=0?e.room_drafts[s]:{},id:this.host._activeDraftId,points:this.host._path.map(t=>[t[0]/ol,t[1]/ol]),segments:this._draftSegmentsForPath(this.host._path,s>=0?e.room_drafts[s]:null,this.host._draftSegmentCms)};s>=0?e.room_drafts[s]=i:e.room_drafts.push(i),this._commitPhysicalGeometry(this.host._t("history.draft_segment"),t)}_activeWallSourceKey(t){return`active:${this.host._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 s=0;s+1t.key===s);if(i>=0){const[t]=this.host._wallFaceGraphCache.splice(i,1);return this.host._wallFaceGraphCache.push(t),t.value}const o=en(t,e);return this.host._wallFaceGraphCache.push({key:s,value:o}),this.host._wallFaceGraphCache.length>4&&this.host._wallFaceGraphCache.shift(),o}_offerWallFaces(t,e=this.host._path.length-2,s){if(this.host._path.length<2||this.host._wallFaceBatch||this.host._roomDialog)return;const i=this.host._spaceModel();if(!i)return;const o=this._activeWallSourceKey(e),a=2e-4*this.host._gridPitch;let n,r;try{const e=s||this._wallGraphSources(t);r=this._wallGraphSources(this.host._path),n=function(t,e,s){const i=new Set(t.faces.map(t=>t.key));return e.faces.filter(t=>!i.has(t.key)&&t.sourceKeys.includes(s))}(this._wallFaceGraph(e,a),this._wallFaceGraph(r,a),o)}catch{return}if(!n.length){const t=un(r,{requiredSourceKey:o,maxDistance:j(2,this.host._cellCm,this.host._gridPitch),gridStep:this.host._gridPitch,epsilon:a});return"ambiguous"===t.kind?(this.host._wallRepairDiagnostic=t.proposals[0]||null,void this.host._showToast(this.host._t(0===this.host._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 i.rooms){const e=R(t);if(!t.id||!e)continue;const s=Kt(e,this.host._path,.02*this.host._gridPitch);if(!s)continue;const[i,o]=s,a=k(i)>=k(o)?i:o,r=a===i?o:i,l=[...n].sort((t,e)=>Math.abs(t.area-k(r))-Math.abs(e.area-k(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:a,newPoly:r},consumeAllActive:!0}])}const l=n.filter(t=>!(t.ring.length<3||this._contourSelfIntersects(t.ring))&&!this._overlapRoom(t.ring));l.length&&this._beginWallFaceBatch(l)}_beginWallFaceBatch(t){this.host._wallRepairDiagnostic=null,this.host._wallFaceBatch={candidates:[...t].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key)),index:0,decisions:[],activePath:this.host._path.map(t=>[...t]),activeCms:[...this.host._draftSegmentCms],activeDraftId:this.host._activeDraftId},this._clearPlanSnapHover(),this.host._nameSel="",this.host._areaSel="",this._resetRoomDialogFields(),this.host._roomDialog=!0}_offerExistingWallFace(t){if(this.host._path.length||this.host._wallFaceBatch||this.host._roomDialog)return!1;const e=2e-4*this.host._gridPitch;try{let s,i=sn(this._wallFaceGraph(this._wallGraphSources([]),e),t,e);if(!i){const o=un(this._wallGraphSources([]),{point:t,maxDistance:j(2,this.host._cellCm,this.host._gridPitch),gridStep:this.host._gridPitch,epsilon:e});if("ambiguous"===o.kind)return this.host._wallRepairDiagnostic=o.proposals[0]||null,this.host._showToast(this.host._t(0===this.host._drawWallCm?"toast.zero_wall_ambiguous":"toast.wall_repair_ambiguous")),!0;if("repair"===o.kind)i=o.face,s=o.proposal;else if("none"===o.kind){const s=un(this._wallGraphSources([]),{point:t,maxDistance:this._cssPxToRender(12),gridStep:this.host._gridPitch,epsilon:e});if("repair"===s.kind)return this.host._wallRepairDiagnostic=s.proposal,this.host._showToast(this.host._t("toast.wall_repair_too_large")),!0}}return!(!i||i.ring.length<3||this._contourSelfIntersects(i.ring)||this._overlapRoom(i.ring))&&(this._beginWallFaceBatch([{...i,existing:!s,repair:s}]),!0)}catch{return!1}}_columnClick(t){const e=this._snap(t),s=this.host._drawWallCm;if(null==s)return void this._showPhysicalRange(yt,1);if(!this.host._curSpaceCfg||this._limitReached("column"))return;const i=this.host._spaceModel();if(!i)return;const o={id:"column-"+Date.now().toString(36),shape:"square",center:e,cm:wt(s),angle:0},a=(i.wall_columns||[]).find(t=>vt(t,o,.02*this.host._gridPitch));if(a)return clearTimeout(this.host._duplicateColumnTimer),this.host._duplicateColumnId=a.id,this.host._duplicateColumnTimer=window.setTimeout(()=>{this.host._duplicateColumnId=null},900),void this.host._showToast(this.host._t("toast.column_duplicate"));const n=this._geometrySnapshot(),r=this.host._curSpaceCfg;r.wall_columns||=[],r.wall_columns.push({...o,center:[e[0]/ol,e[1]/ol]}),this._commitPhysicalGeometry(this.host._t("history.column_add"),n)}_openPhysicalDialog(t,e,s){const i=this.host._spaceModel();if(i)if("partition"===t){const s=i.partitions.find(t=>t.id===e);s&&(this.host._physicalDialog={kind:t,id:e,cm:Tt(s.cm,this.host._imperial),length:this.host._fmtLen(s.a,s.b)})}else if("column"===t){const s=i.wall_columns.find(t=>t.id===e);s&&(this.host._physicalDialog={kind:t,id:e,cm:Tt(s.cm,this.host._imperial),shape:s.shape,angle:this.host._angleField("square"===s.shape?At(s.angle):0)})}else{const o=i.room_drafts.find(t=>t.id===e),a=Math.max(0,Math.min(o?.segments.length?o.segments.length-1:0,s||0));o?.segments[a]&&(this.host._physicalDialog={kind:t,id:e,segment:a,cm:Tt(o.segments[a].cm,this.host._imperial),length:this.host._fmtLen(o.points[a],o.points[a+1])})}}_physicalDown(t,e,s){const i=this.host._spaceModel();if(!i)return;t.stopPropagation(),nl(t);const o=this._svgPoint(t),a=[];for(const t of[...i.wall_columns].reverse())Vt(o,Jt(t,this.host._cellCm,this.host._gridPitch))&&a.push({kind:"column",id:t.id});for(const t of[...i.partitions].reverse()){const e=Yt(t.a,t.b,t.cm,this.host._cellCm,this.host._gridPitch);e&&Vt(o,e)&&a.push({kind:"partition",id:t.id})}a.some(t=>t.kind===e&&t.id===s)||a.unshift({kind:e,id:s});const n=a.map(t=>`${t.kind}:${t.id}`).sort().join("|"),r=performance.now(),l=this.host._physicalPickCycle,h=a.length>1&&l?.signature===n&&r-l.at>380&&r-l.at<=1200&&Math.hypot(t.clientX-l.x,t.clientY-l.y)<=10?(l.index+1)%a.length:Math.max(0,a.findIndex(t=>t.kind===e&&t.id===s));this.host._physicalPickCycle={signature:n,index:h,x:t.clientX,y:t.clientY,at:r},e=a[h].kind,s=a[h].id;const c="partition"===e?i.partitions.find(t=>t.id===s):i.wall_columns.find(t=>t.id===s);c&&(this.host._physicalSel={kind:e,id:s},this.host._physicalDrag={pid:t.pointerId,kind:e,id:s,start:this._svgPoint(t),startClient:[t.clientX,t.clientY],before:this._geometrySnapshot(),moved:!1,base:JSON.parse(JSON.stringify(c)),delta:[0,0]})}_clampPhysicalDelta(t,e,s){const i="partition"===t?[e.a,e.b]:[e.center],o=i.map(t=>t[0]),a=i.map(t=>t[1]);return[Math.max(-Xt*ol-Math.min(...o),Math.min(Xt*ol-Math.max(...o),s[0])),Math.max(-Xt*ol-Math.min(...a),Math.min(Xt*ol-Math.max(...a),s[1]))]}_physicalMove(t){const e=this.host._physicalDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const s=this._svgPoint(t),i="partition"===e.kind?e.base.a:e.base.center,o=this._snap([i[0]+s[0]-e.start[0],i[1]+s[1]-e.start[1]]),a=this._clampPhysicalDelta(e.kind,e.base,[o[0]-i[0],o[1]-i[1]]);this.host._physicalDrag={...e,delta:a,moved:e.moved||Math.hypot(t.clientX-e.startClient[0],t.clientY-e.startClient[1])>=5}}_physicalUp(t){const e=this.host._physicalDrag;if(!e||e.pid!==t.pointerId)return;if(t.stopPropagation(),this.host._physicalDrag=null,!e.moved)return void this._registerPhysicalTap(e.kind,e.id);const s=this.host._spaceModel();if(!this.host._curSpaceCfg||!s)return;const i=this.host._curSpaceCfg;if("partition"===e.kind){const t=(i.partitions||[]).find(t=>t.id===e.id),s=e.base;if(t){const o={...s,a:[s.a[0]+e.delta[0],s.a[1]+e.delta[1]],b:[s.b[0]+e.delta[0],s.b[1]+e.delta[1]]};t.a=[o.a[0]/ol,o.a[1]/ol],t.b=[o.b[0]/ol,o.b[1]/ol];for(const t of i.openings||[]){if("partition"!==t.host?.kind||t.host.id!==e.id)continue;const s=F(t,[o],ol,this.host._cellCm,this.host._gridPitch).resolved;s&&Object.assign(t,N(t,s,ol))}}}else{const t=(i.wall_columns||[]).find(t=>t.id===e.id),o=e.base,a={...o,center:[o.center[0]+e.delta[0],o.center[1]+e.delta[1]]};if(s.wall_columns.some(t=>t.id!==e.id&&vt(t,a,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"));t&&(t.center=[(o.center[0]+e.delta[0])/ol,(o.center[1]+e.delta[1])/ol])}this._commitPhysicalGeometry(this.host._t("history.physical_move"),e.before)}_registerPhysicalTap(t,e,s){const i=performance.now(),o=this.host._physicalLastTap?.kind===t&&this.host._physicalLastTap.id===e&&this.host._physicalLastTap.segment===s&&i-this.host._physicalLastTap.at<=360;this.host._physicalLastTap={kind:t,id:e,segment:s,at:i},o&&(this.host._physicalLastTap=null,this._openPhysicalDialog(t,e,s))}_cancelPhysicalGesture(){this.host._physicalDrag=null,this.host._physicalRotate=null,this.host.requestUpdate()}_physicalRotateDown(t,e){if("square"!==e.shape||!this.host._spaceModel())return;t.preventDefault(),t.stopPropagation(),nl(t);const s=this._svgPoint(t);this.host._physicalSel={kind:"column",id:e.id},this.host._physicalRotate={pid:t.pointerId,id:e.id,center:[...e.center],startAngle:180*Math.atan2(s[1]-e.center[1],s[0]-e.center[0])/Math.PI,baseAngle:At(e.angle),angle:At(e.angle),before:this._geometrySnapshot(),moved:!1}}_physicalRotateMove(t){const e=this.host._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation();const s=this._svgPoint(t),i=180*Math.atan2(s[1]-e.center[1],s[0]-e.center[0])/Math.PI,o=e.baseAngle+i-e.startAngle,a=At(t.shiftKey?o:5*Math.round(o/5));this.host._physicalRotate={...e,angle:a,moved:e.moved||Math.abs(o-e.baseAngle)>=.5}}_physicalRotateUp(t){const e=this.host._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation(),this.host._physicalRotate=null;const s=this.host._spaceModel();if(!e.moved||!this.host._curSpaceCfg||!s)return;const i=s.wall_columns.find(t=>t.id===e.id);if(!i||"square"!==i.shape)return;const o={...i,angle:e.angle};if(s.wall_columns.some(t=>t.id!==e.id&&vt(t,o,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"));const a=this.host._curSpaceCfg.wall_columns?.find(t=>t.id===e.id);a&&(a.angle=e.angle,this._commitPhysicalGeometry(this.host._t("history.physical_edit"),e.before))}_rszRooms(){const t=[],e=this.host._spaceModel();if(!e)return t;for(const s of e.rooms){const e=s.id?R(s):null;e&&t.push({id:s.id,poly:e,wall_ids:Array.isArray(s.wall_ids)?[...s.wall_ids]:void 0})}return s=t,i=Math.max(1e-12,1e-12*this.host._gridPitch),s.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 s=!0;for(;s&&e.length>3;){s=!1;for(let t=0;t0){e.splice(t,1),s=!0;break}}}return{...t,poly:e}});var s,i}_rszOpenings(){return this.host._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.host._spaceModel();if(!t)return[];const e=[];for(const s of t.partitions||[])e.push({kind:"segment",a:[...s.a],b:[...s.b],half:j(s.cm,this.host._cellCm,this.host._gridPitch)/2});for(const s 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]*ol,t.a[1]*this.host._spaceH],b:[t.b[0]*ol,t.b[1]*this.host._spaceH]})),o=Math.abs(t[0]-e[0])<=.05*this.host._gridPitch?"v":Math.abs(t[1]-e[1])<=.05*this.host._gridPitch?"h":null,a=i.filter(s=>!!o&&("h"===o?!(Math.abs(s.a[1]-t[1])>.05*this.host._gridPitch||Math.abs(s.b[1]-t[1])>.05*this.host._gridPitch)&&Math.min(Math.max(t[0],e[0]),Math.max(s.a[0],s.b[0]))-Math.max(Math.min(t[0],e[0]),Math.min(s.a[0],s.b[0]))>.05*this.host._gridPitch:!(Math.abs(s.a[0]-t[0])>.05*this.host._gridPitch||Math.abs(s.b[0]-t[0])>.05*this.host._gridPitch)&&Math.min(Math.max(t[1],e[1]),Math.max(s.a[1],s.b[1]))-Math.max(Math.min(t[1],e[1]),Math.min(s.a[1],s.b[1]))>.05*this.host._gridPitch)),n=new Set(a.map(t=>Number(t.wall.cm)).filter(t=>t>0));return{minDim:this.host._cmToUnits(30),eps:.05*this.host._gridPitch,step:this.host._gridPitch,movingHalf:s>0?j(s,this.host._cellCm,this.host._gridPitch)/2:0,obstacles:this._rszObstacles(),thicknessConflict:n.size>1}}_rszResolution(t,e,s){const i=this.host._resize.snapshotIdentity||s||this._rszSnapshot(),o=`${this.host._space}|${this.host._cellCm}|${this.host._gridPitch}|${i}`,a=`${t}:${e}`;return this.host._resize.resolve(o,a,()=>{const s=[...this.host._resize.rooms||this._rszRooms()],i=s.find(e=>e.id===t),o=i?.poly?.[e]||[0,0],a=i?.poly?.[(e+1)%(i?.poly?.length||1)]||[0,0];return function(t,e,s,i,o){const{eps:a}=o,n=t.find(t=>t.id===s);if(!n||i<0||i>=(n.poly?.length||0)||n.poly.length<4||!go(n.poly))return{enabled:!1,reason:"invalid-geometry"};const r=n.poly[i],l=n.poly[(i+1)%n.poly.length],h=vo(r,l,a);if(!h)return{enabled:!1,reason:"diagonal"};if(!xo(n.poly,i,h,a))return{enabled:!1,reason:"side-angle"};if(o.thicknessConflict)return{enabled:!1,reason:"thickness-conflict"};for(const t of o.obstacles||[])if(Do(t,r,l,o))return{enabled:!1,reason:"duplicate-physical-wall"};const c=po(lo(l,r)),d=[],p=new Set;let _=!1,u=!1;for(const e of t)if(e.id!==s)for(let t=0;t1||d.length>1)return{enabled:!1,reason:"multiple-rooms"};const m={[s]:i},g=[s];if(1===d.length){const t=d[0];if(!go(t.room.poly))return{enabled:!1,reason:"invalid-geometry"};if(!xo(t.room.poly,t.edge,h,a))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(!(uo([t.x,t.y],r,l)>2*a)){if(t.hosted||t.length>c+2*a)return{enabled:!1,reason:"opening-conflict"};f.push(t.id)}const b=Object.fromEntries(g.map(e=>[e,t.find(t=>t.id===e).poly.length])),y=[];for(const e of g){const s=t.find(t=>t.id===e),i=m[e],o=(i-1+s.poly.length)%s.poly.length,n=(i+1)%s.poly.length,r=Io(t,e,o,1,a),l=Io(t,e,n,0,a);if(!r||!l)return{enabled:!1,reason:"partial-shared"};y.push(r,l)}const v={roomId:s,edge:i,a:[...r],b:[...l],n:mo(n.poly,i),roomIds:g,edgeByRoom:m,topology:b,movingOpeningIds:f,sideOwnership:y};if(!Oo(t,e,v,0,o))return{enabled:!1,reason:"invalid-geometry"};const $=Math.abs(Number(o.step));if(Number.isFinite($)&&$>a){const s=[-$,$];if(!s.some(s=>Oo(t,e,v,s,o))){if(!s.some(s=>Fo(No(t,e,v,s),v,a)))return{enabled:!1,reason:"partial-shared"};const i={...o,obstacles:[]};return s.some(s=>Oo(t,e,v,s,i))?{enabled:!1,reason:"duplicate-physical-wall"}:e.length&&s.some(e=>Oo(t,[],v,e,o))?{enabled:!1,reason:"opening-conflict"}:{enabled:!1,reason:"invalid-geometry"}}}return{enabled:!0,plan:v}}(s,[...this.host._resize.openings||this._rszOpenings()],t,e,this._rszOptsFor(o,a))})}_rszSnapshot(){return JSON.stringify(this._geometrySnapshot()||{spaceId:this.host._space,rooms:[],openings:[],walls:[],open_spans:[]})}_rszResetController(){const t=null!==this.host._resize.preview;this.host._resize.reset(),t&&this.host._cfgEpoch++}_rszProjectPreview(t,e,s,i,o){this.host._rszLimitViolation=null;const a=this.host._serverCfg?.spaces.find(t=>t.id===this.host._space);if(!a||!this.host._serverCfg)return{ok:!1,reason:"missing-context"};const n=JSON.parse(t),r={...a,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]?r[t]=n[t]:delete r[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]?r[t]=n.plan_transform[t]:delete r[t];const l=this.host._spaceH;for(const[t,s]of Object.entries(e)){const e=r.rooms.find(e=>e.id===t);e&&(e.poly=s.map(t=>[t[0]/ol,t[1]/l]),delete e.x,delete e.y,delete e.w,delete e.h)}for(const[t,e]of Object.entries(s)){const s=(r.openings||[]).find(e=>e.id===t);s&&(s.x=e[0]/ol,s.y=e[1]/l)}const h=[],c=[];for(const t of i){const e=o.find(e=>e.id===t),s=r.rooms.find(e=>e.id===t);if(!e||!s?.poly)continue;const i=s.poly.map(t=>[t[0]*ol,t[1]*l]);if(e.poly.length!==i.length)continue;const a=Array.isArray(e.wall_ids)?e.wall_ids:[];for(let t=0;tt.id===s):null;o&&(o.a=[i[t][0]/ol,i[t][1]/ol],o.b=[i[(t+1)%i.length][0]/ol,i[(t+1)%i.length][1]/ol])}}if(h.length&&Array.isArray(r.walls)&&r.walls.length){const t=Zt(r.walls,h,c,this.host._wallKeyPitch,ol,"fixed-topology");if(t.rejected)return{ok:!1,reason:"wall-metadata"};r.walls=t.walls}const d=[];for(const t of r.rooms||[]){const e=R(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=p(t);_.set(e,(_.get(e)||0)+1)}const u=[];for(const t of r.walls||[]){const e=p(t),s=_.get(e)||0;s?_.set(e,s-1):u.push(t)}if(Qt(u,d,this.host._wallKeyPitch,ol,n.walls||[]).length)return{ok:!1,reason:"wall-metadata"};const m=this._rszSpaceCandidateGeometry(this.host._space,r);if(!m.ok)return{ok:!1,reason:"physical-geometry"};const g={...this.host._serverCfg,spaces:(this.host._serverCfg?.spaces||[]).map(t=>t?.id===this.host._space?r:t)},f=this._junctionLimitsIntroduced(g,this.host._serverCfg,this.host._space,m.wallGeometry);return f.length?(this.host._rszLimitViolation=f[0],{ok:!1,reason:"junction-limit"}):{ok:!0,value:{preview:{space:this.host._space,sp:r},beforeWalls:n.walls||[],afterWalls:r.walls||[],artifact:m.wallGeometry}}}_rszAcceptPreview(t,e){if(this.host._cfgEpoch++,!t||!e)return;const s=te(e);if(!s)return;const i=`${this.host._space}|${this.host._cfgEpoch}|${t.sp.rooms.length}`;Object.defineProperty(s,"sourceFingerprint",{value:Et([t.sp,this.host._cellCm,this.host._gridPitch]),enumerable:!1});const o={key:i,value:s};il(this.host._wallUnionPool,i,o,8),this.host._wallUnionCache=o}_rszSpaceCandidateGeometry(t,e){if(!this.host._serverCfg)return{ok:!1,wallGeometry:null};const s={...this.host._serverCfg,spaces:this.host._serverCfg.spaces.map(s=>s.id===t?e:s)};let i=null;try{return{ok:this.host._checkSpacePhysicalGeometry(s,t,t=>{i=t}).ok,wallGeometry:i}}catch{return{ok:!1,wallGeometry:null}}}_rszSpaceCandidateRenderable(t,e){if(!this.host._serverCfg)return!1;try{const s={...this.host._serverCfg,spaces:this.host._serverCfg.spaces.map(s=>s.id===t?e:s)};return this.host._checkSpacePhysicalGeometry(s,t).ok}catch{return!1}}_rszCandidateRenderable(t){return!!t&&t.space===this.host._space&&this._rszSpaceCandidateRenderable(t.space,t.sp)}_rszEdgeDown(t,e,s){if("resize"!==this.host._tool||this.host._resize.dragging)return;t.stopPropagation(),t.preventDefault();const i=this._rszRooms(),o=this._rszResolution(e,s);if(!o.enabled)return void this.host._showToast(this._rszReasonText(o.reason));nl(t);const a=o.plan,n=this._svgPoint(t),r=`${this.host._space}|${this.host._cfgEpoch}|${i.length}`,l=this.host._wallUnionCache?.key===r?this.host._wallUnionCache.value:null,h=this._rszSnapshot();this.host._resize.begin({pointerId:t.pointerId,start:[n[0],n[1]],roomId:e,plan:a,options:this._rszOptsFor(a.a,a.b),rooms:i,openings:this._rszOpenings(),snapshotIdentity:h,before:JSON.parse(h),wallUnionBefore:l})}_rszReasonText(t){return this.host._t(`resize.disabled.${t}`)}_rszDisabledActivate(t,e){t.stopPropagation(),t.preventDefault(),this.host._showToast(this._rszReasonText(e))}_rszDisabledKey(t,e){"Enter"!==t.key&&" "!==t.key||this._rszDisabledActivate(t,e)}_rszMove(t){if(!this.host._resize.ownsPointer(t.pointerId))return;t.stopPropagation();const e=this._svgPoint(t),s=this.host._resize.move({pointerId:t.pointerId,point:[e[0],e[1]],step:this.host._gridPitch,snap:t=>{const e=this._snap(t);return[e[0],e[1]]},project:(t,e,s,i,o)=>this._rszProjectPreview(t,e,s,i,o),publish:(t,e)=>this._rszAcceptPreview(t,e),measure:(t,e)=>this._rszEdgeLabels(t,e)});if("rejected"===s.kind)return s.notify&&this.host._showToast(this.host._rszLimitViolation?`${this.host._t("resize.limit_stopped")} — `+this._junctionLimitLabel(this.host._rszLimitViolation):this.host._t("resize.preview_failed")),void this.host.requestUpdate();"accepted"===s.kind&&this.host.requestUpdate()}_rszUp(t){if(!this.host._resize.ownsPointer(t.pointerId))return;t.stopPropagation();const e=this.host._resize.finish({pointerId:t.pointerId,currentSnapshotIdentity:this._rszSnapshot(),validatePreview:t=>this._rszCandidateRenderable(t)});if("no-op"===e.kind)return this.host._cfgEpoch++,void this.host.requestUpdate();if("rejected"===e.kind)return this.host._cfgEpoch++,this.host._showToast(this.host._t("resize.commit_failed")),void this.host.requestUpdate();const s=e.preview,i=this.host._serverCfg?.spaces.find(t=>t.id===s.space);i&&(i.rooms=s.sp.rooms,i.openings=s.sp.openings,Array.isArray(s.sp.walls)&&(s.sp.walls.length?i.walls=s.sp.walls:delete i.walls),Array.isArray(s.sp.wall_segments)&&(i.wall_segments=s.sp.wall_segments)),this.host._suppressClick=!0,setTimeout(()=>this.host._suppressClick=!1,0),this._commitPhysicalGeometry(this.host._t("history.resize_room"),e.before),this.host.requestUpdate()}_rszCancelDrag(t){const e=this.host._resize.cancel(this._rszSnapshot(),t);if("no-op"!==e.kind){if(this.host._cfgEpoch++,e.restoreWallUnion){const t=this.host._spaceModel();if(t){const s=`${this.host._space}|${this.host._cfgEpoch}|${t.rooms.length}`,i={key:s,value:e.restoreWallUnion};il(this.host._wallUnionPool,s,i,8),this.host._wallUnionCache=i}}this.host.requestUpdate()}}_rszPointerCancel(t){this.host._resize.ownsPointer(t.pointerId)&&(t.stopPropagation(),this._rszCancelDrag(t.pointerId))}_rszEdgeLabels(t,e,s=this.host._resize.rooms){const i=s,o=[],a=t.polys[e.roomId]||i?.find(t=>t.id===e.roomId).poly;if(!a||!i)return o;const n=a.length,r=this._rszInnerSpanCms(e.roomId,a,t.polys);for(const t of function(t,e){const s=t.length;return[(e-1+s)%s,(e+1)%s]}(a,e.edge)){const e=a[t],s=a[(t+1)%n],i=r?.[t];o.push({kind:"length",x:(e[0]+s[0])/2,y:(e[1]+s[1])/2,text:null==i?this.host._fmtLen(e,s):ee(i,"mi"===this.host.hass?.config?.unit_system?.length),edge:{a:[e[0],e[1]],b:[s[0],s[1]]}})}const l="mi"===this.host.hass?.config?.unit_system?.length,h=e.roomIds,c=this.host._spaceWalls,d=this.host._physicalBodiesR(),p=this.host._baseVb(),_=this.host._view&&this.host._view.w>0&&this.host._view.h>0?this.host._view:{x:p[0],y:p[1],w:p[2],h:p[3]},[u,m]=this.host._lastValidStageSize||[_.w,_.h],g={..._,stageWidth:Math.max(1,u),stageHeight:Math.max(1,m)},f=this.host._spaceModel(),b=this.host._config?.icon_size??2.5,y=f?se(b>8?2.5:b,f,_.w,this.host._kiosk?this.host._kioskScale.icon:1)*g.stageWidth/100:24,v=Math.max(10,.77*y),$=this.host._t("room.settings_short"),w=v*(1.457+.66*Math.max(1,$.length)*.42);for(const s of h){const a=t.polys[s]||i.find(t=>t.id===s).poly,n=c.length&&f&&this.host._innerRoomContour(f,s)||a,r=d.length?ie(oe(n,d))*Math.pow(this.host._cellCm/this.host._gridPitch,2)/1e4:ae(n,this.host._gridPitch,this.host._cellCm),h=ne(r,l),p=qo({poly:a,edge:e.edgeByRoom[s],text:h,view:g,gearCenter:re(a),gearWidthPx:w,gearHeightPx:v});o.push({kind:"area",roomId:s,x:p.anchor[0],y:p.anchor[1],text:h,placement:p})}return o}_rszInnerSpanCms(t,e,s){const i=Object.keys(s).length?Object.entries(s).map(([t,e])=>({id:t,poly:e})):this.host._spaceModel()?.rooms;if(!i?.length)return null;const o=this.host._spaceWalls;if(!o.length)return null;const a=this.host._openCuts(),n=le(i,t,o,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol);if(!n||n.length!==e.length)return null;const r=this.host._cellCm/this.host._gridPitch;return e.map((t,s)=>he(e,s,n)*r)}_renderResizeMeasurements(){const t=this.host._resize.liveLabels;if(!t?.length)return a;const e=t.filter(t=>"length"===t.kind),s=t.filter(t=>"area"===t.kind);return ce``}_renderResizeLayer(t){const e=Math.max(.013*t.w,5),s=e/2,i=t=>t.toFixed(1),o=`M ${i(-.7*s)} 0 H ${i(.7*s)} M 0 ${i(-.22*s)} V ${i(-s)} M ${i(-.32*s)} ${i(-.6*s)} L 0 ${i(-s)} L ${i(.32*s)} ${i(-.6*s)} M 0 ${i(.22*s)} V ${i(s)} M ${i(-.32*s)} ${i(.6*s)} L 0 ${i(s)} L ${i(.32*s)} ${i(.6*s)}`,a=[],n=this._rszRooms(),r=this.host._resize.snapshotIdentity||this._rszSnapshot();for(const t of n)for(let s=0;sthis._rszEdgeDown(e,t.id,s)} + @pointermove=${t=>this._rszMove(t)} + @pointerup=${t=>this._rszUp(t)} + @pointercancel=${t=>this._rszPointerCancel(t)} + @lostpointercapture=${t=>this._rszPointerCancel(t)} + @click=${_?t=>this._rszDisabledActivate(t,p.reason):null} + @keydown=${_?t=>this._rszDisabledKey(t,p.reason):null}> + ${u} + `),a.push(ce``)}return ce`${a}`}_partitionOpeningCuts(t=this.host._spaceModel(),e=()=>!0){if(!t)return[];const s=this.host._curSpaceCfg?.id===t.id?this.host._curSpaceCfg:null,i=de(s,t,this.host._cellCm,this.host._gridPitch,ol);return pe(i,e)}_decorSnapGeometry(t){const e=this.host._spaceModel();if(!e)return{points:[],segments:[]};const s=t||"",i=this.host._decorSnapCache;if(i&&i.epoch===this.host._cfgEpoch&&i.space===this.host._space&&i.height===this.host._decorH&&i.exclude===s)return i.geometry;const o=[];for(const e of this.host._decorList)if(e.id!==t)if("line"===e.kind){const t=[e.x1*ol,e.y1*this.host._decorH],s=[e.x2*ol,e.y2*this.host._decorH];o.push({points:[t,s,[(t[0]+s[0])/2,(t[1]+s[1])/2]],segments:[{a:t,b:s}]})}else if("text"===e.kind)o.push({points:[[e.x*ol,e.y*this.host._decorH]],segments:[]});else{const t=this.host._decorBoxOf(e);t&&o.push(_e(t))}for(const t of e.rooms){const e=R(t);e?.length&&o.push({points:e.flatMap((t,s)=>{const i=e[(s+1)%e.length];return[t,[(t[0]+i[0])/2,(t[1]+i[1])/2]]}),segments:e.map((t,s)=>({a:t,b:e[(s+1)%e.length]}))})}const a=ue(o);return this.host._decorSnapCache={epoch:this.host._cfgEpoch,space:this.host._space,height:this.host._decorH,exclude:s,geometry:a},a}_decorSnap(t,e="mouse",s){const i=this.host._stageEl,o=this.host._viewOr(this.host._baseVb()),a="touch"===e||"pen"===e?14:8,n=i?o.w/Math.max(1,i.clientWidth)*a:this.host._gridPitch;return me(t,this._decorSnapGeometry(s),n,t=>this._snap(t)).point}_replaceDecor(t,e){const s=this.host._curSpaceCfg;s&&(s.decor=this.host._decorList.map(s=>s.id===t?{...s,...e}:s),this.host.requestUpdate())}_cancelDecorGesture(){const t=this.host._decorMove?.before||this.host._dtDrag?.before||this.host._bdDrag?.before,e=t&&this.host._serverCfg?.spaces.find(e=>e.id===t.spaceId);if(t&&e){const s=t=>JSON.parse(JSON.stringify(t));void 0!==t.decor?e.decor=s(t.decor):delete e.decor;for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete e[t];Object.assign(e,s(t.plan_transform||{})),this.host._cfgEpoch++}this.host._decorMove=null,this.host._dtDrag=null,this.host._bdDrag=null,this.host.requestUpdate()}_decorPointerDown(t){const e=this.host._decorTool;if("select"===e||"erase"===e?t.target.closest?.(".dshape"):null)return!0;if("line"===e||"rect"===e||"ellipse"===e){t.preventDefault();const s=this._decorSnap(this._svgPoint(t),t.pointerType);return this.host._decorDraft={kind:e,a:s,b:s,pid:t.pointerId},nl(t),!0}if("text"===e){const e=this._decorSnap(this._svgPoint(t),t.pointerType);return this.host._decorTextDialog={x:fe(e[0]/ol),y:fe(e[1]/this.host._decorH),text:"",color:this.host._decorStyle.color,opacity:this.host._decorStyle.opacity,angle:"0",sizeCm:ge(ct,this.host._cellCm,this.host._gridPitch)},this.host._decorTextSelection={start:0,end:0},!0}if("furniture"===e)return!!this.host._furnPalette&&(t.preventDefault(),this._furnPlace(this._svgPoint(t),t.shiftKey),!0);if("select"===e&&(this.host._decorSel=null),this.host._bdMovable){const e=this.host._bdRect,s=this._svgPoint(t),i=e.x+e.w/2,o=e.y+e.h/2,a=-be(e.angle)*Math.PI/180,n=s[0]-i,r=s[1]-o,l=[i+n*Math.cos(a)-r*Math.sin(a),o+n*Math.sin(a)+r*Math.cos(a)];if(l[0]>=e.x&&l[0]<=e.x+e.w&&l[1]>=e.y&&l[1]<=e.y+e.h)return t.preventDefault(),this._bdStart(t)}return!1}_decorCommitDraft(){const t=this.host._decorDraft;if(this.host._decorDraft=null,!t)return;const e=.5*this.host._gridPitch;if(!ye(t.kind,t.a,t.b,e))return;const s=ol,i=this.host._decorH,o=this.host._decorStyle,a=this._geometrySnapshot(),n="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),r=fe;let l;if("line"===t.kind)l={id:n,kind:"line",x1:r(t.a[0]/s),y1:r(t.a[1]/i),x2:r(t.b[0]/s),y2:r(t.b[1]/i),...ve(o,!1)};else{const e=r(Math.min(t.a[0],t.b[0])/s),a=r(Math.min(t.a[1],t.b[1])/i),h=Math.abs(t.b[0]-t.a[0])/s,c=Math.abs(t.b[1]-t.a[1])/i;l={id:n,kind:t.kind,x:e,y:a,w:h,h:c,...ve(o,!0)}}this.host._curSpaceCfg.decor=[...this.host._decorList,l],this.host._decorSel=n,this._recordGeometry(this.host._t("history.decor_add"),a),this._saveConfig(),this.host.requestUpdate()}_decorShapeDown(t,e){if("decor"!==this.host._mode)return;const s=this.host._decorTool;if("text"===s){if("text"!==e.kind)return;return t.stopPropagation(),t.preventDefault(),void this._decorOpenText(e)}"select"!==s&&"erase"!==s||(t.stopPropagation(),t.preventDefault(),"erase"!==s?(this.host._decorSel=e.id,this.host._decorMove={id:e.id,start:this._svgPoint(t),orig:JSON.parse(JSON.stringify(e)),pid:t.pointerId,moved:!1,before:this._geometrySnapshot()},nl(t)):this.host._decorEraseConfirm={id:e.id,kind:e.kind})}_decorMoveUpdate(t){const e=this.host._decorMove;if("furniture"===e.orig?.kind)return void this._furnMoveUpdate(t);const s=this._svgPoint(t),i=e.orig,o=("line"===i.kind?i.x1:i.x)*ol,a=("line"===i.kind?i.y1:i.y)*this.host._decorH,n=this._decorSnap([o+(s[0]-e.start[0]),a+(s[1]-e.start[1])],t.pointerType,e.id);let r=(n[0]-o)/ol,l=(n[1]-a)/this.host._decorH;const h=e.orig,c="line"===h.kind?Math.min(h.x1,h.x2):h.x,d="line"===h.kind?Math.min(h.y1,h.y2):h.y,p="line"===h.kind?Math.abs(h.x2-h.x1):h.w||0,_="line"===h.kind?Math.abs(h.y2-h.y1):h.h||0,u=Xt;r=Math.max(-u-c,Math.min(u-c-p,r)),l=Math.max(-u-d,Math.min(u-d-_,l)),(r||l)&&(e.moved=!0);this.host._curSpaceCfg.decor=this.host._decorList.map(t=>{if(t.id!==e.id)return t;const s=e.orig;return"line"===t.kind?{...t,x1:s.x1+r,y1:s.y1+l,x2:s.x2+r,y2:s.y2+l}:{...t,x:s.x+r,y:s.y+l}}),this.host.requestUpdate()}_decorShapeDbl(t,e){"decor"===this.host._mode&&"select"===this.host._decorTool&&(t.preventDefault(),t.stopPropagation(),this.host._decorMove=null,this.host._decorSel=e.id,this._openDecorProperties(e))}_openDecorProperties(t){if("decor"!==this.host._mode||"select"!==this.host._decorTool)return;if("text"===t.kind)return void this._decorOpenText(t);if(!["line","rect","ellipse","furniture"].includes(t.kind))return;const e=this.host._decorResolvedStyle(t),s="line"===t.kind?t:null,i=this.host._decorBoxOf(t);this.host._decorShapeDialog={id:t.id,kind:t.kind,color:e.color,opacity:e.opacity,widthCm:e.widthCm,angle:this.host._angleField(be(s?$e([s.x1*ol,s.y1*this.host._decorH],[s.x2*ol,s.y2*this.host._decorH]):t.angle)),...s?{lengthCm:ge(Math.hypot((s.x2-s.x1)*ol,(s.y2-s.y1)*this.host._decorH),this.host._cellCm,this.host._gridPitch),lineStyle:"dashed"===s.line_style?"dashed":"solid"}:{},...i?{sizeWCm:ge(i.w,this.host._cellCm,this.host._gridPitch),sizeHCm:ge(i.h,this.host._cellCm,this.host._gridPitch)}:{},..."furniture"===t.kind?{symbol:t.symbol}:{},..."rect"===t.kind||"ellipse"===t.kind?{fill:e.fill,fillColor:e.fillColor,fillOpacity:e.fillOpacity}:{}}}_decorOpenText(t){if("text"!==t.kind)return;let e=String(t.text??"");const s=[...e.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!pt(t[1])),i=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,a=s||i?"":_t(t.entity,o),n=!(!String(t.entity??"").trim()||s||a&&!i);if(a&&!n){const t=e.indexOf("{}");e=t>=0?e.slice(0,t)+a+e.slice(t+2):`${e}${e?" ":""}${a}`}this.host._decorTextDialog={id:t.id,x:t.x,y:t.y,text:e,color:l(t.color,this.host._decorStyle.color),opacity:we(t.opacity,this.host._decorStyle.opacity),angle:this.host._angleField(t.angle),sizeCm:this.host._decorTextSizeCm(t),pickerEntity:t.entity||"",preserveLegacy:n||void 0},this.host._decorTextSelection={start:e.length,end:e.length}}_decorRememberTextSelection(t){this.host._decorTextSelection={start:t.selectionStart??t.value.length,end:t.selectionEnd??t.value.length}}_decorInsertLiveVariable(t){const e=this.host._decorTextDialog;if(!e)return;const s=_t(e.pickerEntity,t);if(!s)return;const i=e.text,o=Math.max(0,Math.min(i.length,this.host._decorTextSelection.start)),a=Math.max(o,Math.min(i.length,this.host._decorTextSelection.end));if(i.length-(a-o)+s.length>200)return;const n=i.slice(0,o)+s+i.slice(a),r=o+s.length;this.host._decorTextSelection={start:r,end:r},this.host._decorTextDialog={...e,text:n,preserveLegacy:void 0},this.host.updateComplete.then(()=>{const t=this.host.renderRoot.querySelector("textarea.dtarea");t&&(t.focus(),t.setSelectionRange(r,r))})}_decorSaveText(){const t=this.host._decorTextDialog,e=String(t?.text??"").replace(/\r\n?/g,"\n").trim();if(!t||!e)return void(this.host._decorTextDialog=null);const s=this._geometrySnapshot(),i=this.host._curSpaceCfg,o={color:t.color,opacity:we(t.opacity),size_cm:Number(Math.max(.1,Math.min(tl,t.sizeCm)).toFixed(4)),...be(t.angle)?{angle:be(t.angle)}:{}};if(t.id)i.decor=this.host._decorList.map(s=>{if(s.id!==t.id)return s;if("text"!==s.kind)return s;if(t.preserveLegacy){const{angle:t,size:i,scale:a,...n}=s;return{...n,text:e,...o}}const{entity:i,attr:a,unit:n,...r}=s,{angle:l,size:h,scale:c,...d}=r;return{...d,text:e,...o}});else{const s="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5);i.decor=[...this.host._decorList,{id:s,kind:"text",x:t.x,y:t.y,text:e,...o}],this.host._decorSel=s}this.host._decorTextDialog=null,this._recordGeometry(this.host._t(t.id?"history.decor_edit":"history.decor_add"),s),this._saveConfig(),this.host.requestUpdate()}_decorSaveShape(){const t=this.host._decorShapeDialog;if(!t)return;const e=this._geometrySnapshot(),s={color:t.color,opacity:we(t.opacity),widthCm:Math.max(.1,Math.min(100,Number(t.widthCm)||.1)),fill:!!t.fill,fillColor:t.fillColor||t.color,fillOpacity:we(t.fillOpacity,.25)};this.host._curSpaceCfg.decor=this.host._decorList.map(e=>{if(e.id!==t.id)return e;const i="rect"===t.kind||"ellipse"===t.kind,o=ve(s,i);if("line"===e.kind){const s=(e.x1+e.x2)/2*ol,i=(e.y1+e.y2)/2*this.host._decorH,a=ke(Math.max(.1,Number(t.lengthCm)||.1),this.host._cellCm,this.host._gridPitch),n=be(t.angle)*Math.PI/180,r=Math.cos(n)*a/2,l=Math.sin(n)*a/2,h=this._snap([s-r,i-l]),c=this._snap([s+r,i+l]),{width:d,line_style:p,..._}=e;return{..._,...o,x1:fe(h[0]/ol),y1:fe(h[1]/this.host._decorH),x2:fe(c[0]/ol),y2:fe(c[1]/this.host._decorH),..."dashed"===t.lineStyle?{line_style:"dashed"}:{}}}if("rect"===e.kind||"ellipse"===e.kind||"furniture"===e.kind){const s=e.w*ol,i=e.h*this.host._decorH,a=Math.max(this.host._gridPitch,Ft(ke(Number(t.sizeWCm),this.host._cellCm,this.host._gridPitch),this.host._gridPitch)),n=Math.max(this.host._gridPitch,Ft(ke(Number(t.sizeHCm),this.host._cellCm,this.host._gridPitch),this.host._gridPitch)),r=e.x*ol+s/2,l=e.y*this.host._decorH+i/2,h=be(t.angle),c=xe({x:r-a/2,y:l-n/2},h,t=>this._snap(t)),{width:d,angle:p,..._}=e;return{..._,...o,x:fe(c[0]/ol),y:fe(c[1]/this.host._decorH),w:a/ol,h:n/this.host._decorH,..."furniture"===e.kind&&t.symbol?{symbol:t.symbol}:{},...h?{angle:h}:{}}}return e}),this.host._decorStyle={...s,fill:"rect"===t.kind||"ellipse"===t.kind?s.fill:this.host._decorStyle.fill,fillColor:"rect"===t.kind||"ellipse"===t.kind?s.fillColor:this.host._decorStyle.fillColor,fillOpacity:"rect"===t.kind||"ellipse"===t.kind?s.fillOpacity:this.host._decorStyle.fillOpacity},this.host._decorShapeDialog=null,this._recordGeometry(this.host._t("history.decor_edit"),e),this._saveConfig(),this.host.requestUpdate()}_dtPivot(t){return"line"===t.kind?[(t.x1+t.x2)/2*ol,(t.y1+t.y2)/2*this.host._decorH]:"furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind?[(t.x+t.w/2)*ol,(t.y+t.h/2)*this.host._decorH]:[t.x*ol,t.y*this.host._decorH]}_dtApply(t,e){const s=this.host._curSpaceCfg;s&&(s.decor=this.host._decorList.map(s=>{if(s.id!==t)return s;const i={...s};"text"===s.kind&&void 0!==e.textSizeCm&&(delete i.size,delete i.scale);const o={...i};return void 0!==e.textSizeCm&&(o.size_cm=Number(Math.max(.1,Math.min(tl,e.textSizeCm)).toFixed(4))),void 0!==e.angle&&(e.angle?o.angle=Number(e.angle.toFixed(2)):delete o.angle),o}),this.host._cfgEpoch++,this.host.requestUpdate())}_dtStart(t,e,s,i){const o=this.host._dtSel;if(!o)return;t.stopPropagation(),t.preventDefault();const[a,n]=this._dtPivot(o),r=this._svgPoint(t),l=this.host._decorBoxOf(o);this.host._dtDrag={id:o.id,kind:e,pid:t.pointerId,ax:a,ay:n,r0:Math.hypot(r[0]-a,r[1]-n),a0:180*Math.atan2(r[1]-n,r[0]-a)/Math.PI,textSizeCm0:"text"===o.kind?this.host._decorTextSizeCm(o):1,angle0:"line"===o.kind?0:Number(o.angle)||0,sgx:s?.[0],sgy:s?.[1],orig:l||void 0,origShape:JSON.parse(JSON.stringify(o)),before:this._geometrySnapshot(),lineEnd:i,moved:!1},nl(t)}_dtMove(t){const e=this.host._dtDrag;if(!e)return;const s=this._svgPoint(t);if(void 0!==e.lineEnd&&"line"===e.origShape.kind){const i=this._decorSnap(s,t.pointerType,e.id),o=fe(i[0]/ol),a=fe(i[1]/this.host._decorH),n=e.origShape,r=0===e.lineEnd?n.x1:n.x2,l=0===e.lineEnd?n.y1:n.y2;return(Math.abs(o-r)>1e-9||Math.abs(a-l)>1e-9)&&(e.moved=!0),void this._replaceDecor(e.id,0===e.lineEnd?{x1:o,y1:a}:{x2:o,y2:a})}if("scale"===e.kind&&e.orig){const i=Se(e.orig,e.sgx??1,e.sgy??1,s[0],s[1],!t.shiftKey,this.host._gridPitch,this.host._gridPitch),o=Math.abs(i.x-e.orig.x)>1e-6||Math.abs(i.y-e.orig.y)>1e-6||Math.abs(i.w-e.orig.w)>1e-6||Math.abs(i.h-e.orig.h)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._decorApplyBox(e.id,i)}if("scale"===e.kind){const t=Math.hypot(s[0]-e.ax,s[1]-e.ay);if(e.r0<1e-6)return;const i=Math.max(.1,Math.min(tl,e.textSizeCm0*(t/e.r0))),o=Math.abs(i-e.textSizeCm0)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._dtApply(e.id,{textSizeCm:i})}const i=180*Math.atan2(s[1]-e.ay,s[0]-e.ax)/Math.PI;let o=e.angle0+(i-e.a0);t.shiftKey||(o=5*Math.round(o/5)),o=(o%360+360)%360,o>180&&(o-=360);const a=Math.abs(o-e.angle0)>1e-6;(a||e.moved)&&(e.moved||=a,this._dtApply(e.id,{angle:o}))}_dtUp(){const t=this.host._dtDrag;this.host._dtDrag=null,t?.moved&&(this._recordGeometry(this.host._t("history.decor_transform"),t.before),this._saveConfig()),this.host.requestUpdate()}_dtMeasure(){const t=this.host._dtSel;if(!t)return void(this.host._dtBox&&(this.host._dtBox=null,this.host.requestUpdate()));let e;if("line"===t.kind){const s=t.x1*ol,i=t.y1*this.host._decorH,o=t.x2*ol,a=t.y2*this.host._decorH;e={id:t.id,x:Math.min(s,o),y:Math.min(i,a),w:Math.abs(o-s),h:Math.abs(a-i)}}else if("furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind)e={id:t.id,x:t.x*ol,y:t.y*this.host._decorH,w:t.w*ol,h:t.h*this.host._decorH};else{const s=this.host.renderRoot.querySelector(`text.dtext[data-id="${t.id}"]`);if(!s||"function"!=typeof s.getBBox)return;let i;try{i=s.getBBox()}catch{return}if(!i||!i.width&&!i.height)return;e={id:t.id,x:i.x,y:i.y,w:i.width,h:i.height}}const s=this.host._dtBox;s&&s.id===e.id&&Math.abs(s.x-e.x)<.01&&Math.abs(s.y-e.y)<.01&&Math.abs(s.w-e.w)<.01&&Math.abs(s.h-e.h)<.01||(this.host._dtBox=e,this.host.requestUpdate())}_deleteDecor(t){if(!this.host._decorList.some(e=>e.id===t))return;const e=this._geometrySnapshot();this.host._curSpaceCfg.decor=this.host._decorList.filter(e=>e.id!==t),this.host._decorSel===t&&(this.host._decorSel=null),this._recordGeometry(this.host._t("history.decor_delete"),e),this._saveConfig(),this.host.requestUpdate()}_decorDeleteSel(){this.host._decorSel&&this._deleteDecor(this.host._decorSel)}_confirmDecorErase(){const t=this.host._decorEraseConfirm;this.host._decorEraseConfirm=null,t&&this._deleteDecor(t.id)}_furnFieldValue(t){return Math.round(100*(this.host._imperial?t/30.48:t/100))/100}_furnFieldToCm(t){return Me(this.host._imperial?30.48*t:100*t)}_furnPick(t){const e=De(t);this.host._furnPalette={symbol:t,w:e.w,h:e.h}}_furnPlace(t,e=!1){const s=this.host._furnPalette,i=this.host._curSpaceCfg;if(!s||!i)return;const o=ol,a=this.host._decorH,n=Ce(Pe(s.w,this.host._cellCm,this.host._gridPitch,o)),r=Ce(Pe(s.h,this.host._cellCm,this.host._gridPitch,o)),l=this._geometrySnapshot(),h=this._decorSnap(t);let c=h[0],d=h[1],p=0;const _=e?null:Ie(c,d,r*a,this.host._furnWalls,this.host._furnWallReach,this.host._gridPitch);_&&(c=_.cx,d=_.cy,p=_.angle);const u="df"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),m={id:u,kind:"furniture",symbol:s.symbol,x:fe(c/o-n/2),y:fe(d/a-r/2),w:n,h:r,...ve(this.host._decorStyle,!1)};p&&(m.angle=Number(p.toFixed(2))),i.decor=[...this.host._decorList,m],this.host._decorSel=u,this.host._decorTool="select",this.host._furnPalette=null,this._recordGeometry(this.host._t("history.decor_add"),l),this._saveConfig(),this.host.requestUpdate()}_furnMoveUpdate(t){const e=this.host._decorMove;if("furniture"!==e.orig.kind)return;const s=e.orig,i=this.host._curSpaceCfg;if(!i)return;const o=ol,a=this.host._decorH,n=this._svgPoint(t),r=(s.x+s.w/2)*o+(n[0]-e.start[0]),l=(s.y+s.h/2)*a+(n[1]-e.start[1]);let h,c,d=Number(s.angle)||0;const p=t.shiftKey?null:Ie(r,l,s.h*a,this.host._furnWalls,this.host._furnWallReach,this.host._gridPitch);if(p)h=p.cx/o-s.w/2,c=p.cy/a-s.h/2,d=p.angle;else{const i=this._decorSnap([r-s.w/2*o,l-s.h/2*a],t.pointerType,e.id);h=i[0]/o,c=i[1]/a}h=fe(h),c=fe(c),(Math.abs(h-s.x)>1e-9||Math.abs(c-s.y)>1e-9||Math.abs(d-(Number(s.angle)||0))>1e-9)&&(e.moved=!0),i.decor=this.host._decorList.map(t=>{if(t.id!==e.id)return t;const s={...t,x:h,y:c};return d?s.angle=Number(d.toFixed(2)):delete s.angle,s}),this.host.requestUpdate()}_decorApplyBox(t,e){const s=this.host._curSpaceCfg;if(!s)return;const i=ol,o=this.host._decorH;s.decor=this.host._decorList.map(s=>{if(s.id!==t)return s;const a=xe(e,s.angle,t=>this._snap(t));return{...s,x:fe(a[0]/i),y:fe(a[1]/o),w:Math.max(this.host._gridPitch/i,Math.min(2*Xt,e.w/i)),h:Math.max(this.host._gridPitch/o,Math.min(2*Xt,e.h/o))}}),this.host._cfgEpoch++,this.host.requestUpdate()}_renderFurnPalette(){const t=this.host._furnPalette,e=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return o`
t.stopPropagation()}> +
+ ${this.host._t("furn.title")} + + +
+
+ ${Te.map(e=>o` +
${this.host._t(`furn.group_${e}`)}
+
+ ${Re(e).map(e=>o``)} +
`)} +
+ ${t?o`
+ + this.host._furnPalette={...t,w:this._furnFieldToCm(Number(e.target.value))}} /> + + this.host._furnPalette={...t,h:this._furnFieldToCm(Number(e.target.value))}} /> + ${this.host._t("furn.place_hint")} +
`:o`
${this.host._t("furn.pick_hint")}
`} +
`}_openBackdropDialog(t){if(!this.host._bdMovable||!this.host._bdRect)return;t?.preventDefault(),t?.stopPropagation(),this.host._bdDrag=null;const e=this.host._bdRect;this.host._backdropDialog={widthCm:ge(e.w,this.host._cellCm,this.host._gridPitch),heightCm:ge(e.h,this.host._cellCm,this.host._gridPitch),angle:this.host._angleField(e.angle)}}_saveBackdropDialog(){const t=this.host._backdropDialog,e=this.host._bdBase,s=this.host._bdRect;if(!t||!e||!s)return;const i=be(t.angle),o=this._geometrySnapshot(),a=Math.min(e.w*ht,Math.max(e.w*lt,Ft(ke(t.widthCm,this.host._cellCm,this.host._gridPitch),this.host._gridPitch))),n=Math.min(e.h*ht,Math.max(e.h*lt,Ft(ke(t.heightCm,this.host._cellCm,this.host._gridPitch),this.host._gridPitch))),r=s.x+s.w/2,l=s.y+s.h/2,h=xe({x:r-a/2,y:l-n/2},i,t=>this._snap(t));this._bdApply((h[0]-e.x)/ol,(h[1]-e.y)/ol,a/e.w,n/e.h,i),this.host._backdropDialog=null,this._recordGeometry(this.host._t("history.backdrop_transform"),o),this._saveConfig()}_bdApply(t,e,s,i,o){const a=this.host._curSpaceCfg;if(!a)return;a.plan_x=Number(fe(t).toFixed(6)),a.plan_y=Number(fe(e).toFixed(6)),delete a.plan_scale,a.plan_scale_x=Number(Math.min(ht,Math.max(lt,s)).toFixed(6)),a.plan_scale_y=Number(Math.min(ht,Math.max(lt,i)).toFixed(6));const n=be(o);n?a.plan_angle=Number(n.toFixed(2)):delete a.plan_angle,this.host._cfgEpoch++,this.host.requestUpdate()}_bdStart(t,e,s=!1){const i=this.host._bdBase,o=this.host._bdRect;if(!i||!o)return!1;const a=this._svgPoint(t),n=e?e[0]:0,r=e?e[1]:0,l=n>0?o.x:o.x+o.w,h=r>0?o.y:o.y+o.h;return this.host._bdDrag={kind:s?"rotate":e?"scale":"move",pid:t.pointerId,sx:a[0],sy:a[1],base:i,p0:this.host._bdParams,fx:l,fy:h,sgx:n,sgy:r,rect0:{x:o.x,y:o.y,w:o.w,h:o.h,angle:o.angle},before:this._geometrySnapshot(),moved:!1},nl(t),!0}_bdMove(t){const e=this.host._bdDrag;if(!e)return;const s=this._svgPoint(t),i=e.base;if("move"===e.kind){const t=e.rect0.x,o=e.rect0.y,a=this._snap([t+(s[0]-e.sx),o+(s[1]-e.sy)]),n=Math.abs(a[0]-t)>1e-9||Math.abs(a[1]-o)>1e-9;if(!n&&!e.moved)return;return e.moved||=n,void this._bdApply((a[0]-i.x)/ol,(a[1]-i.y)/ol,e.p0.sx,e.p0.sy,e.p0.angle)}if("rotate"===e.kind){const i=e.rect0.x+e.rect0.w/2,o=e.rect0.y+e.rect0.h/2,a=180*Math.atan2(e.sy-o,e.sx-i)/Math.PI;let n=e.p0.angle+(180*Math.atan2(s[1]-o,s[0]-i)/Math.PI-a);t.shiftKey||(n=5*Math.round(n/5)),n=be(n);const r=Math.abs(n-e.p0.angle)>1e-9;if(!r&&!e.moved)return;return e.moved||=r,void this._bdApply(e.p0.dx,e.p0.dy,e.p0.sx,e.p0.sy,n)}const o=Se(e.rect0,e.sgx,e.sgy,s[0],s[1],!t.shiftKey,this.host._gridPitch,Math.min(i.w,i.h)*lt),a=o.w/Math.max(1e-9,i.w),n=o.h/Math.max(1e-9,i.h),r=Math.abs(a-e.p0.sx)>1e-9||Math.abs(n-e.p0.sy)>1e-9||Math.abs(o.x-e.rect0.x)>1e-9||Math.abs(o.y-e.rect0.y)>1e-9;if(!r&&!e.moved)return;e.moved||=r;const l=xe(o,e.p0.angle,t=>this._snap(t));this._bdApply((l[0]-i.x)/ol,(l[1]-i.y)/ol,a,n,e.p0.angle)}_bdReset(){const t=this.host._curSpaceCfg;if(!t)return;const e=this._geometrySnapshot();delete t.plan_x,delete t.plan_y,delete t.plan_scale,delete t.plan_scale_x,delete t.plan_scale_y,delete t.plan_angle,this.host._bdDrag=null,this._recordGeometry(this.host._t("history.backdrop_transform"),e),this._saveConfig(),this.host._showToast(this.host._t("decor.backdrop_reset_done")),this.host.requestUpdate()}_bdUp(){const t=this.host._bdDrag;this.host._bdDrag=null,t?.moved&&(this._recordGeometry(this.host._t("history.backdrop_transform"),t.before),this._saveConfig()),this.host.requestUpdate()}_renderBackdropFrame(t){const e=this.host._bdRect;if(!this.host._bdActive||!e)return a;const s=.02*Math.max(t.w,t.h),i=s/4,o=e.x+e.w/2,n=e.y+e.h/2,r=be(e.angle),l=2.2*s;return ce` + + + {t.stopPropagation(),t.preventDefault(),this._bdStart(t,void 0,!0)}}> + + ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([t,o,a])=>{const n=t<0?e.x:e.x+e.w,r=o<0?e.y:e.y+e.h;return ce`{e.stopPropagation(),e.preventDefault(),this._bdStart(e,[t,o])}}>`})} + `}_renderEditorGroupLauncher(t){return this.host._editorSecondary.renderGroupLauncher(t,this.host._editorToolbarGroups,this.host._editorSecondaryCopy)}_runEditorContext(t,e){this.host._editorSecondary.runContext(t,this.host._editorSecondaryContextId,e)}_renderEditorGroupModel(t){return this.host._editorSecondary.renderGroupModel(t,this.host._editorSecondaryContextId,this.host._editorSecondaryCopy)}_renderDrawWallControl(){const t="column"===this.host._tool?1:0;return o``}_renderPlanSecondary(){const t=this.host._editorSecondaryContextId,e=this.host._physicalSel;if(e){if(!("partition"===e.kind?!!this.host._curSpaceCfg.partitions?.some(t=>t.id===e.id):"column"===e.kind?!!this.host._curSpaceCfg.wall_columns?.some(t=>t.id===e.id):!!this.host._curSpaceCfg.room_drafts?.some(t=>t.id===e.id)))return null;const s="partition"===e.kind?this.host._t("markup.partition"):"column"===e.kind?this.host._t("markup.column"):this.host._t("markup.add");return{contextId:t,kind:"selection",ariaLabel:this.host._t("editor.context_actions",{object:s}),visibleLabel:s,content:o` + + `}}const s="draw"===this.host._tool||"column"===this.host._tool,i="column"===this.host._tool?"markup.hint_column":"resize"===this.host._tool?"markup.hint_resize":"wallthick"===this.host._tool?"markup.hint_wallthick":null,n="draw"===this.host._tool?this.host._t(this.host._path.length?"markup.hint_points":"markup.hint_start",this.host._path.length?{n:this.host._path.length}:void 0):"";if(!s&&!i&&!n)return null;const r="draw"===this.host._tool&&this.host._path.length>0;return{contextId:t,kind:r?"operation":"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t("draw"===this.host._tool?"markup.add":"column"===this.host._tool?"markup.column":"resize"===this.host._tool?"markup.resize":"markup.wallthick")}),content:o` + ${s?this._renderDrawWallControl():a} + ${n?o`${n}`:a} + ${i?o`${this.host._t(i)}`:a} + ${"draw"===this.host._tool&&this.host._path.length?o``:a}`}}_renderDecorSecondary(){const t=this.host._editorSecondaryContextId;if("furniture"===this.host._decorTool)return{contextId:t,kind:"palette",ariaLabel:this.host._t("editor.palette",{tool:this.host._t("decor.furniture")}),launcherId:"furniture",dismissPolicy:this.host._furnPalette?"stay-open-on-canvas":"outside",dismiss:()=>{"furniture"===this.host._decorTool&&(this.host._furnPalette=null,this.host._decorTool="select",this.host.requestUpdate())},content:this._renderFurnPalette()};const e=this.host._dtSel;if(e){const s=this.host._t(`decor.${e.kind}`);return{contextId:t,kind:"selection",ariaLabel:this.host._t("editor.context_actions",{object:s}),visibleLabel:s,content:o` + + `}}const s="line"===this.host._decorTool||"rect"===this.host._decorTool||"ellipse"===this.host._decorTool,i="rect"===this.host._decorTool||"ellipse"===this.host._decorTool,n="backdrop"===this.host._decorTool&&!!this.host._bdRect;return s||n?{contextId:t,kind:"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t(s?`decor.${this.host._decorTool}`:"decor.backdrop")}),content:o` + ${s?o` + this.host._decorStyle={...this.host._decorStyle,...t.detail}}> + + ${i?o` + this.host._decorStyle={...this.host._decorStyle,fillColor:t.detail.color,fillOpacity:t.detail.opacity}}>`:a} + `:a} + ${n?o`${this.host._t("decor.backdrop_hint")}`:a}`}:null}_withBackdropReset(t){if(!this.host._bdMoved||this.host._bdDrag||"palette"===t?.kind)return t;const e=this.host._editorSecondaryContextId,s=o``;return t?{...t,kind:"selection"===t.kind?"mixed":t.kind,content:o`${t.content}${s}`}:{contextId:e,kind:"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t("decor.backdrop")}),content:s}}_renderEditorSecondary(){if(!this.host._editing)return a;const t=this.host._editorSecondary.activeGroup(this.host._editorToolbarGroups),e=t?this._renderEditorGroupModel(t):"plan"===this.host._mode?this._renderPlanSecondary():"decor"===this.host._mode?this._withBackdropReset(this._renderDecorSecondary()):null;return this.host._editorSecondary.render(e,this.host._editorSecondaryDialogBlocked)}_renderDecorBar(){const t=[["select","mdi:cursor-default-outline","decor.select"],...this.host._bdRect?[["backdrop","mdi:image-move","decor.backdrop"]]:[],["line","mdi:vector-line","decor.line"],["rect","mdi:rectangle-outline","decor.rect"],["ellipse","mdi:ellipse-outline","decor.ellipse"],["text","mdi:format-text","decor.text"],["furniture","mdi:sofa-outline","decor.furniture"],["erase","mdi:eraser","decor.erase"]],e=this.host._geometryHistory.undoName,s=this.host._geometryHistory.redoName;return o`
+
+ ${t.map(([t,e,s])=>o``)} + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} + + +
+
+ +
+
`}_renderDecorEraseConfirm(){const t=this.host._decorEraseConfirm,e=this.host._t(`decor.${t.kind}`);return o`this.host._decorEraseConfirm=null}> +

${this.host._t("confirm.erase_decor",{kind:e})}

+
+ + + +
+
`}_renderDecorTextDialog(){const t=this.host._decorTextDialog,e=(t.pickerEntity||"").trim(),s=e?this.host.hass?.states?.[e]:null;return o`this.host._decorTextDialog=null}> +
+ + ${""} + + this.host._decorTextDialog={...t,...e.detail}}> + +
this.host._decorTextDialog={...t,sizeCm:this.host._decorTextCm(Number(e.target.value))}} /> + ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
+ + this.host._decorTextDialog={...t,angle:e.target.value}} /> + + + this.host._decorTextDialog={...t,pickerEntity:e.target.value}} /> + + ${Object.keys(this.host.hass?.states||{}).map(t=>o``)} + + ${e?o` + + + `:a} +
+
+ + + +
+
`}_renderDecorShapeDialog(){const t=this.host._decorShapeDialog,e="rect"===t.kind||"ellipse"===t.kind,s=this.host._t("decor."+t.kind),i=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return o`this.host._decorShapeDialog=null}> +
+ ${"furniture"===t.kind?o` + + `:a} + this.host._decorShapeDialog={...t,...e.detail}}> + +
this.host._decorShapeDialog={...t,widthCm:this.host._decorSmallCm(Number(e.target.value))}} />${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
+ ${"line"===t.kind?o` + +
+ + +
+ +
this.host._decorShapeDialog={...t,lengthCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ${i}
`:o` + +
this.host._decorShapeDialog={...t,sizeWCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ×this.host._decorShapeDialog={...t,sizeHCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ${i}
`} + + this.host._decorShapeDialog={...t,angle:e.target.value}} /> + ${e?o` + this.host._decorShapeDialog={...t,fillColor:e.detail.color,fillOpacity:e.detail.opacity}}>`:a} +
+
+ + + +
+
`}_renderBackdropDialog(){const t=this.host._backdropDialog,e=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return o`this.host._backdropDialog=null}> +
+ +
this.host._backdropDialog={...t,widthCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ×this.host._backdropDialog={...t,heightCm:this.host._decorLargeCm(Number(e.target.value))}} /> + ${e}
+ + this.host._backdropDialog={...t,angle:e.target.value}} /> +
+
+ + +
+
`}_cssPxToRender(t){const e=this.host._stageEl,s=this.host._viewOr(this.host._baseVb());return e?.clientWidth&&e.clientHeight?Math.max(s.w/e.clientWidth,s.h/e.clientHeight)*t:this.host._gridPitch/8*t}_deleteRoomClick(t){const e=this.host._spaceModel();if(!e)return;const s=[...e.rooms].reverse().find(e=>this._pointInRoom(t,e));s?s.id&&(this.host._roomDeleteDialog={roomId:s.id,name:s.name}):this.host._showToast(this.host._t("toast.delete_room_pick"))}_wallThickHit(t){const e=this.host._spaceModel();if(!e)return null;const s=6*this.host._gridPitch,i=this.host._openCuts();let o=null;const a=(t,e,i)=>{e>s||(!o||e100)return void this._showPhysicalRange(100);if("room"!==e.source.kind){const t=this._geometrySnapshot();if("partition"===e.source.kind){const t=(s.partitions||[]).find(t=>t.id===e.source.id);if(!t)return;if(0===n&&$t(s.openings,{kind:"partition",id:t.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));t.cm=n}else{const t=(s.room_drafts||[]).find(t=>t.id===e.source.id),i=t?.segments?.[e.source.segment];if(!i)return;i.cm=n}this.host._wallDialog=null;return this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),t)&&this.host._showToast(this.host._t("toast.wallthick_set")),void this.host.requestUpdate()}const r=this._geometrySnapshot(),l=n>0?n:null;if(0===n){const i=.02*this.host._gridPitch,o=[e.a[0],e.a[1],e.b[0],e.b[1]],a=(s.rooms||[]).find(t=>t.id===e.roomId),n=new Set(t&&a&&Array.isArray(a.wall_ids)?a.wall_ids:(s.wall_segments||[]).filter(t=>{const e=[Number(t.a?.[0])*ol,Number(t.a?.[1])*ol],s=[Number(t.b?.[0])*ol,Number(t.b?.[1])*ol];return C(e,o)<=i&&C(s,o)<=i}).map(t=>String(t.id))),r=(s.openings||[]).some(t=>{if("partition"===t.host?.kind)return!1;if("wall"===t.host?.kind&&n.has(t.host.id))return!0;if(t.host)return!1;const e=[Number(t.x)*ol,Number(t.y)*ol];return e.every(Number.isFinite)&&C(e,o)<=i});if(r)return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"))}let h,c=this.host._openCuts();if(n>0&&c.length){const o=[];if(t&&e.roomId){const t=(s.rooms||[]).find(t=>t.id===e.roomId),a=new Set(Array.isArray(t?.wall_ids)?t.wall_ids:[]);for(const t of s.wall_segments||[])a.has(t.id)&&o.push([Number(t.a?.[0])*ol,Number(t.a?.[1])*ol,Number(t.b?.[0])*ol,Number(t.b?.[1])*ol]);if(!o.length){const t=i.rooms.find(t=>t.id===e.roomId),s=t?R(t):null;for(let t=0;s&&t!o.some(e=>C([t[0],t[1]],e)<=a&&C([t[2],t[3]],e)<=a&&C([e[0],e[1]],t)<=a&&C([e[2],e[3]],t)<=a))}h=t&&e.roomId?Fe(s.walls,i.rooms,e.roomId,l,this.host._wallKeyPitch,c,ol):E(s.walls,e.a,e.b,l,this.host._wallKeyPitch,ol),h=this.host._normalizeWalls(h,c);for(const t of s.wall_segments||[])t.cm=Q(h,t.a,t.b,I,1);h.length?s.walls=h:delete s.walls,this.host._wallDialog=null,this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),r)&&this.host._showToast(this.host._t(0===n?"toast.wallthick_cleared":"toast.wallthick_set")),this.host.requestUpdate()}_wallHatchDefs(t){if(!this.host._spaceWalls.length&&!this.host._physicalBodiesR().length&&!this.host._markup)return ce``;const e=Ne(this.host._cellCm);return ce` + + + + `}_renderWallThickUi(){const t=this.host._wallThickHover;return t&&t.d?ce``:ce``}_renderWallThickDialog(){const t=this.host._wallDialog;return t?o`
t.stopPropagation()}> +
+ + {this.host._wallDialog={...t,value:e.target.value}}} + @keydown=${t=>{"Enter"===t.key&&(t.preventDefault(),this._wallThickApply(!1))}} /> + ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")} +
+
+ ${"room"===t.source.kind?o``:a} + + +
+
`:o``}_openingAt(t){if(!this.host._openingsR.length)return null;const e=this.host._openingsR.flatMap(e=>{const s=e.angle*Math.PI/180,i=t[0]-e.rx,o=t[1]-e.ry,a=i*Math.cos(s)+o*Math.sin(s);return Math.abs(a)>e.rlen/2+ze(12,this.host._cellCm)?[]:[{o:e,localY:-i*Math.sin(s)+o*Math.cos(s)}]});if(!e.length)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i).value;return e.find(({o:t,localY:e})=>{const s="gate"===t.type?!t.flip_v:t.flip_v,i=t.partitionHost||this.host._spaceWalls.length||"gate"===t.type?this.host._openingFace(t,o,!!s):{ox:0,oy:0,cm:0,side:-1},a=Ae({type:t.type,length:t.rlen,angle:t.angle,amount:this.host._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,face:i});return Math.abs(e)<=a.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this.host._openingPreset;if("opening"!==this.host._tool||!e)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i),a=`${o.key}|partitions:${this.host._cfgEpoch}`;this.host._openingPlacementIntervalsCache&&this.host._openingPlacementIntervalsCache.key===a||(this.host._openingPlacementIntervalsCache={key:a,value:[...z(s.rooms,this.host._spaceWalls,i,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol),...Oe(s.partitions,this.host._cellCm,this.host._gridPitch)]}),this.host._openingDimensionContextCache&&this.host._openingDimensionContextCache.key===a||(this.host._openingDimensionContextCache={key:a,value:Wr({rooms:s.rooms,walls:this.host._spaceWalls,openCuts:i,partitions:s.partitions,roomOpenings:this.host._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(s),pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:ol,epsilon:2e-4*this.host._gridPitch})});const n=Le({pointer:[t[0],t[1]],preset:e,geometryRevision:this.host._cfgEpoch,renderedLength:this.host._cmToUnits(e.lengthCm),intervals:this.host._openingPlacementIntervalsCache.value,baseTolerance:1.5*this.host._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this.host._pointerModality.modality||"pen"===this.host._pointerModality.modality?10:6),gridStep:this.host._gridPitch});this.host._openingJambBlockCm=n.jambBlockedTarget?n.jambBlockedTarget.physicalHalfWidth/this.host._gridPitch*this.host._cellCm:null;const r=n.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let h;if(r.host){const t=F({id:"preview",type:r.type,x:r.x/ol,y:r.y/ol,angle:r.angle,length:r.renderedLength/ol,host:r.host},s.partitions,ol,this.host._cellCm,this.host._gridPitch).resolved;h=t?Ee(t,l):{ox:0,oy:0,cm:0,side:-1}}else h=Be(o.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const c="mi"===this.host.hass?.config?.unit_system?.length,d=Yr(r,this.host._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:ee(t.distance/this.host._gridPitch*this.host._cellCm,c),dimension:t}));return{...r,face:h,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingPreset=He(t,++this.host._openingPresetRevision),this.host._openingHoverCandidate=null,this.host._cursorPt=null)}_clearOpeningPlacement(t){this.host._openingHoverCandidate=null,this.host._openingJambBlockCm=null,t&&(this.host._openingPreset=null,this.host._openingRebindId=null)}_openingClick(t){const e=this.host._spaceModel();if(!e)return;const s=this.host._openingRebindId?null:this._openingAt(t);if(s)return void this._editOpening(s);const i=this.host._openingPreset;if(!i)return;const o=this.host._openingHoverCandidate,a=o&&Ge(o,[t[0],t[1]],i.revision,this.host._cfgEpoch)?o:this._resolveOpeningPlacement(t);if(!a){if(null!=this.host._openingJambBlockCm)return void this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:ee(this.host._openingJambBlockCm,this.host._imperial)}));const s=1.5*this.host._gridPitch,i=P(t,e.rooms,s);return i&&We(i.x,i.y,i.angle,this.host._openCuts(),s)?void this.host._showToast(this.host._t("toast.opening_on_zero_wall")):void this.host._showToast(this.host._t("toast.opening_no_wall"))}const n=this.host._openingRebindId?this.host._curSpaceCfg?.openings?.find(t=>t.id===this.host._openingRebindId):null;this.host._openingDialog={...n?{id:n.id,type:n.type,lengthCm:Math.round(n.length*ol/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:n.contact||"",lock:n.lock||"",invert:!!n.invert,flipH:!!n.flip_h,flipV:!!n.flip_v}:{type:a.type,lengthCm:a.lengthCm,contact:"",lock:"",invert:!1,flipH:a.flipH,flipV:a.flipV},...a.host?{host:a.host}:{},x:a.x,y:a.y,angle:a.angle},this.host._openingRebindId=null,this.host._openingHoverCandidate=null,this.host._cursorPt=null}_editOpening(t){this.host._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this.host._gridPitch*this.host._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.host._mode&&this.host._spaceModel()&&"resize"!==this.host._tool){t.preventDefault(),t.stopPropagation();try{nl(t)}catch{}this.host._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this.host._opDrag.sx)+Math.abs(t.clientY-this.host._opDrag.sy)<=3)return;const s=this.host._spaceModel();if(!s)return;const i=this._svgPoint(t),o=this.host._curSpaceCfg,a=o?.openings?.find(t=>t.id===e.id);if(!a)return;if("partition"===a.host?.kind){const t=s.partitions.find(t=>t.id===a.host.id);if(!t)return;const e=t.b[0]-t.a[0],o=t.b[1]-t.a[1],n=Math.hypot(e,o);if(!(n>1e-9))return;const r=e/n,l=o/n;if(Math.abs((i[0]-t.a[0])*l-(i[1]-t.a[1])*r)>4*this.host._gridPitch)return;const h=a.length*ol/2+L(t,this.host._cellCm,this.host._gridPitch);let c=(i[0]-t.a[0])*r+(i[1]-t.a[1])*l;if(c=Math.round(c/this.host._gridPitch)*this.host._gridPitch,c=Math.max(h,Math.min(n-h,c)),n<2*h-1e-9)return;const d=c/n,p=(t.a[0]+r*c)/ol,_=(t.a[1]+l*c)/this.host._spaceH;let u=180*Math.atan2(o,e)/Math.PI;u>=90?u-=180:u<-90&&(u+=180);const m=a.host.t!==d||a.x!==p||a.y!==_||a.angle!==u;return this.host._opDrag.moved=!0,m&&(this.host._opDrag.dirty=!0),a.host={...a.host,t:d},a.x=p,a.y=_,a.angle=u,this.host._opMeasure=null,m&&this.host._cfgEpoch++,void this.host.requestUpdate()}const n=P(i,s.rooms,4*this.host._gridPitch);if(!n)return;this.host._opDrag.moved=!0;const r=this._opRuler(n,a.length*ol);this.host._opMeasure=r.measure;const l=r.x/ol,h=r.y/this.host._spaceH,c=a.x!==l||a.y!==h||a.angle!==n.angle;if(c&&(this.host._opDrag.dirty=!0),a.x=l,a.y=h,a.angle=n.angle,Number(this.host._serverCfg?.model_version||0)>=9){const t=kr(a,o?.wall_segments||[]);t?a.host=t:delete a.host}c&&this.host._cfgEpoch++,this.host.requestUpdate()}_opRuler(t,e){const s=this.host._spaceModel()?.rooms||[],i=this.host._gridPitch/2;let o=t.x,a=t.y,n=je([o,a],t.angle,e,s,i);if(n&&n.centered&&(o!==n.wallCenter[0]||a!==n.wallCenter[1]))[o,a]=n.wallCenter,n=je([o,a],t.angle,e,s,i);else if(n){const[r,l]=n.wallA,[h,c]=n.wallB,d=h-r,p=c-l,_=Math.hypot(d,p);if(_>0){const h=this.host._gridPitch,c=Math.min(e/2,_/2);let u=Math.round(((o-r)*d+(a-l)*p)/_/h)*h;u=Math.max(c,Math.min(_-c,u)),o=r+u/_*d,a=l+u/_*p,n=je([o,a],t.angle,e,s,i)||n}}if(!n)return{x:o,y:a,angle:t.angle,measure:null};const r="mi"===this.host.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:ee(t/this.host._gridPitch*this.host._cellCm,r)});return{x:o,y:a,angle:t.angle,measure:{labels:[l(n.sideA,n.midA),l(n.sideB,n.midB)],guide:n.centered?{x:n.wallCenter[0],y:n.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;const s=this.host._opDrag,i=s.moved;this.host._opMeasure=null,i&&s.dirty&&this._commitPhysicalGeometry(this.host._t("history.move_opening"),s.before),i?window.setTimeout(()=>this.host._opDrag=null,0):this.host._opDrag=null}_opClick(t,e){"plan"===this.host._mode&&"resize"===this.host._tool||(t.stopPropagation(),this.host._opDrag?.moved||"plan"===this.host._mode&&this._editOpening(e))}_saveOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=this._geometrySnapshot(),o=this.host._spaceH,a=(e.openings||[]).find(e=>e.id===t.id),n={...a||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/ol,y:t.y/o,angle:t.angle,length:a&&!t.lengthTouched?a.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/ol,...t.host?{host:{...t.host}}:{}};if("partition"===n.host?.kind){const t=qe(a,n)?H(n,s.partitions,ol,this.host._cellCm,this.host._gridPitch):F(n,s.partitions,ol,this.host._cellCm,this.host._gridPitch);if(!t.resolved){const e=s.partitions.find(t=>t.id===n.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=L(e,this.host._cellCm,this.host._gridPitch);this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:ee(t/this.host._gridPitch*this.host._cellCm,this.host._imperial)}))}else this.host._showToast(this.host._t("opening.partition_orphan"));return}const i=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===n.id)return[];const e=F(t,s.partitions,ol,this.host._cellCm,this.host._gridPitch).resolved;return e?[e]:[]});if(Ue(t.resolved,i))return void this.host._showToast(this.host._t("toast.opening_no_wall"));Object.assign(n,N(n,t.resolved,ol))}else if(Number(this.host._serverCfg?.model_version||0)>=9){const t=kr(n,e.wall_segments||[]);if(!t)return void this.host._showToast(this.host._t("toast.opening_no_wall"));n.host=t}else delete n.host;"passage"===t.type?(delete n.contact,delete n.lock,delete n.invert,delete n.flip_h,delete n.flip_v):(n.contact=t.contact||null,n.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,n.invert=t.invert||void 0,n.flip_h="gate"!==t.type&&t.flipH||void 0,n.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===n.id);r>=0?e.openings[r]=n:e.openings.push(n),this._commitPhysicalGeometry(this.host._t(t.id?"history.edit_opening":"history.add_opening"),i),this.host._openingDialog=null,this.host.requestUpdate()}_deleteOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg;if(!t?.id||!e?.openings)return;const s=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this.host._t("history.delete_opening"),s),this.host._openingDialog=null,this.host.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.host.hass.states)){if(!this.host._openingEntityAvailable(e))continue;const s=e.split(".")[0];if("binary_sensor"!==s&&"cover"!==s)continue;const i=this.host.hass.states[e],o=["door","window","opening","garage_door","garage"].includes(i?.attributes?.device_class||"");("cover"!==s||o)&&t.push([e,i?.attributes?.friendly_name||e,o?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.host.hass.states).filter(t=>t.startsWith("lock.")&&this.host._openingEntityAvailable(t)).map(t=>({value:t,label:this.host.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this.host._openingDialog;if(!e)return;const s="contact"===t?!e.contactOpen:!e.lockOpen;this.host._openingDialog={...e,contactOpen:"contact"===t&&s,lockOpen:"lock"===t&&s}}_filterOpeningEntities(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contactFilter:e}:{...s,lockFilter:e})}_selectOpeningEntity(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contact:e,contactOpen:!1,contactFilter:""}:{...s,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms,i=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;const o=i.id;if(!this.host._mergeSel||this.host._mergeSel===o)return void(this.host._mergeSel=this.host._mergeSel===o?null:o);const a=s.find(t=>t.id===this.host._mergeSel),n=a?R(a):null,r=R(i),l=n&&r?Ke(n,r):null;if(!l)return this.host._showToast(this.host._t("toast.merge_not_adjacent")),void(this.host._mergeSel=null);this.host._mergeDialog={aId:this.host._mergeSel,bId:o,poly:l,pick:"a"},this.host._mergeSel=null}_commitMerge(){const t=this.host._mergeDialog,e=this.host._curSpaceCfg;if(!t||!e||!this.host._spaceModel())return;const s=this._geometrySnapshot(),i=this.host._spaceH,o="a"===t.pick?t.aId:t.bId,a="a"===t.pick?t.bId:t.aId,n=e.rooms.find(t=>t.id===o);if(!n)return void(this.host._mergeDialog=null);n.poly=t.poly.map(t=>[t[0]/ol,t[1]/i]),delete n.x,delete n.y,delete n.w,delete n.h,e.rooms=e.rooms.filter(t=>t.id!==a);const r=this._commitPhysicalGeometry(this.host._t("history.merge_rooms"),s);this.host._mergeDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),r&&this.host._showToast(this.host._t("toast.rooms_merged",{name:n.name||""}))}_splitClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms;if(!this.host._splitSel){const e=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this.host._splitSel={roomId:e.id,pts:[]})}const i=s.find(t=>t.id===this.host._splitSel.roomId),o=i?R(i):null;if(!i||!o)return void(this.host._splitSel=null);const a=.02*this.host._gridPitch,n=6*this.host._gridPitch,r=Ve(t,o),l=r&&Je(r,o,this.host._gridPitch)||r,h=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=n?l:null,c=!!h&&Ye(h,o,a),d=this.host._splitSel.pts;if(!d.length)return c?void(this.host._splitSel={...this.host._splitSel,pts:[h]}):void this.host._showToast(this.host._t("toast.split_pick_wall"));if(!c){const e=this._snap(t);return qt(e,o,a)?void(this.host._splitSel={...this.host._splitSel,pts:[...d,e]}):void this.host._showToast(this.host._t("toast.split_pick_inside"))}const p=Kt(o,[...d,h],a);if(!p)return void this.host._showToast(this.host._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[_,u]=p,m=k(_)>=k(u)?_:u,g=m===_?u:_;this.host._pendingSplit={roomId:i.id,mainPoly:m,newPoly:g},this.host._cursorPt=null,this.host._nameSel="",this.host._areaSel="",this.host._roomDialog=!0}_markupMove(t){if(!this.host._markup)return;if("column"===this.host._tool)return void(this.host._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this.host._tool||"wallthick"===this.host._tool)return void(this.host._cursorPt=this._svgPoint(t));const e="draw"===this.host._tool&&!this.host._contourClosed,s="split"===this.host._tool&&!!this.host._splitSel?.pts?.length;if(!e&&!s)return;const i=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(i,t.shiftKey);return this.host._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this.host._path.length?void(this.host._cursorPt=e.point):void this._syncPlanSnapActiveMarker(e.candidate)}this.host._cursorPt=this._snap(i)}_saveRoom(){(this.host._areaSel||this.host._nameSel.trim())&&(this.host._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this.host._wallFaceBatch;if(!e)return;const s=e.candidates[e.index];if(!s)return;if(!t&&(s.existing||s.repair)&&1===e.candidates.length)return this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate();const i=t?{candidate:s,create:!0,name:this.host._nameSel.trim(),area:this.host._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:s,create:!1},o=[...e.decisions,i],a=e.index+1;if(a"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,o=.02*this.host._gridPitch,a=this.host._spaceModel();if(!a)return A;for(const e of this._planSnapGeometrySnapshot().value.segments){if("room"===e.sourceKind||C(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>o)continue;if("partition"===e.sourceKind)return i(a.partitions.find(t=>t.id===e.sourceId)?.cm)??A;const s=e.sourceId.lastIndexOf(":"),n=s>=0?e.sourceId.slice(0,s):e.sourceId,r=s>=0?Number(e.sourceId.slice(s+1)):-1;return i(a.room_drafts.find(t=>t.id===n)?.segments[r]?.cm)??A}const n=Ra(Math.max(0,e.length-1),s,this.host._drawWallCm,A);for(let s=0;s+1[...t]);if(!e?.sourceKey.startsWith("active:"))return s;const i=/:(\d+)$/.exec(e.sourceKey),o=i?Number(i[1])+("b"===e.endpoint?1:0):-1;return o>=0&&oe.key===t.sourceKey),a=i.find(e=>e.key===t.targetSourceKey);if(!o||!a)return!1;const n="a"===t.endpoint?o.a:o.b;return!(Math.hypot(n[0]-t.from[0],n[1]-t.from[1])>s)&&(!(C(t.to,[a.a[0],a.a[1],a.b[0],a.b[1]])>s)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const s=t.sourceKey.slice(17).split("|")[0];return!!s&&e.some(t=>"partition"===t.host?.kind&&t.host.id===s)}(t,this.host._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const s=this.host._curSpaceCfg;if(!s||!this._validateWallRepair(t,e.activePath))return!1;const i=e=>{e[0]=t.to[0]/ol,e[1]=t.to[1]/ol};if(t.sourceKey.startsWith("active:")){const o=/:(\d+)$/.exec(t.sourceKey),a=o?Number(o[1])+("b"===t.endpoint?1:0):-1;if(a<0||a>=e.activePath.length)return!1;e.activePath[a]=[...t.to];const n=(s.room_drafts||[]).find(t=>t.id===e.activeDraftId);return n?.points?.[a]&&i(n.points[a]),!0}if(!t.sourceKey.startsWith("static:"))return!1;const[o,a]=t.sourceKey.slice(7).split("|");if("partition"===o){const e=(s.partitions||[]).find(t=>t.id===a);if(!e)return!1;const o=[e.a[0]*ol,e.a[1]*ol],n=[e.b[0]*ol,e.b[1]*ol],r=Math.hypot(o[0]-t.from[0],o[1]-t.from[1])<=2e-4*this.host._gridPitch?e.a:Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this.host._gridPitch?e.b:null;return!!r&&(i(r),!0)}if("draft"===o){const e=a.lastIndexOf(":"),o=e>=0?a.slice(0,e):"",n=e>=0?Number(a.slice(e+1)):-1,r=(s.room_drafts||[]).find(t=>t.id===o);if(!r?.points?.[n]||!r?.points?.[n+1])return!1;const l=[n,n+1].find(e=>Math.hypot(r.points[e][0]*ol-t.from[0],r.points[e][1]*ol-t.from[1])<=2e-4*this.host._gridPitch);return null!=l&&(i(r.points[l]),!0)}return!1}_applyWallFaceBatch(){const t=this.host._wallFaceBatch,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=(t,e)=>{this.host._showToast(this.host._t(t,e)),this._roomDialogCancel()},o=t.decisions.filter(t=>t.create),a=o.map(t=>t.candidate.ring),n=s.rooms;for(let t=0;ts.id!==e&&!!R(s)&&$(a[t],R(s)));if(s)return void i("toast.room_overlap",{name:s.name||""})}if((e.rooms||[]).length+o.length>400)return void i("toast.physical_limit");if(o.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void i("toast.contour_cannot_close");const r=o.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void i("toast.wall_repair_changed");const l=this._activePathWithRepair(t.activePath,r[0]),h=2e-4*this.host._gridPitch,c=new Map;for(let e=0;et.candidate.atomKeys)),e=o.some(t=>t.candidate.consumeAllActive);for(const s of tn(this._wallGraphSources(l),h)){const i=s.sourceKeys.find(t=>c.has(t));!i||e||t.has(s.key)||d.push({a:s.a,b:s.b,cm:c.get(i)})}}else d.push(...Fa(l,Ra(l.length-1,t.activeCms,this.host._drawWallCm,A)));if((e.partitions||[]).length+d.length>al)return void i("toast.physical_limit");const p=o.map(t=>t.candidate.ring.map(()=>"")),_=t.activeDraftId?(e.room_drafts||[]).find(e=>e.id===t.activeDraftId):null,u=this._draftSegmentsForPath(t.activePath,_,t.activeCms),m=(t,e)=>{const s=`${t[0].toFixed(9)},${t[1].toFixed(9)}`,i=`${e[0].toFixed(9)},${e[1].toFixed(9)}`;return s<=i?`${s}|${i}`:`${i}|${s}`};for(let e=0;et.candidate.ring.forEach((s,i)=>{const o=t.candidate.ring[(i+1)%t.candidate.ring.length];C(s,n)<=h&&C(o,n)<=h&&r.push({kind:"room",owner:e,edge:i,a:s,b:o})})),d.forEach((t,e)=>{C(t.a,n)<=h&&C(t.b,n)<=h&&r.push({kind:"partition",owner:e,edge:0,a:t.a,b:t.b})});const l=[(i[0]+a[0])/2,(i[1]+a[1])/2];r.sort((t,e)=>{const s=[t.a[0],t.a[1],t.b[0],t.b[1]],o=[e.a[0],e.a[1],e.b[0],e.b[1]];return(C(l,s)<=h?0:1)-(C(l,o)<=h?0:1)||(C(i,s)<=h?0:1)-(C(i,o)<=h?0:1)||m(t.a,t.b).localeCompare(m(e.a,e.b))});const c=r[0];if(!c)continue;const _=m(c.a,c.b);for(const t of r)m(t.a,t.b)===_&&("room"===t.kind?p[t.owner][t.edge]=s:d[t.owner].id=s)}const g=this._geometrySnapshot();if(r[0]&&!this._applyWallRepair(r[0],t))return void i("toast.wall_repair_changed");const f=o.some(t=>!!t.candidate.split),b=f?kt(s.rooms,e.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol):null,y=f&&Array.isArray(e.walls)?e.walls:null;for(const t of o){const s=t.candidate.split;if(!s)continue;const o=e.rooms.find(t=>t.id===s.roomId);if(!o)return void i("toast.contour_cannot_close");o.poly=s.mainPoly.map(t=>[t[0]/ol,t[1]/this.host._spaceH]),delete o.x,delete o.y,delete o.w,delete o.h}const v=Date.now().toString(36),w=[];if(o.forEach((t,s)=>{const i=t.area?this.host.hass.areas[t.area]?.name:"",o={id:`r${v}-${s}`,name:t.name||i||this.host._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/ol,t[1]/this.host._spaceH]),...p[s].some(Boolean)?{wall_ids:p[s]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(o),w.push({room:o,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,s)=>e.partitions.push({id:t.id||`partition-${v}-${s}`,a:[t.a[0]/ol,t.a[1]/ol],b:[t.b[0]/ol,t.b[1]/ol],cm:t.cm}))),f){const t=this.host._normalizeWalls(b,this.host._openCuts());t.length?e.walls=t:y?.length?e.walls=y:delete e.walls}if(w.length){this.host._cfgEpoch++;const s=this.host._openCuts(),i=this.host._spaceModel();if(!i)return;let o=e.walls;for(const{room:e,decision:a}of w){const n=a.candidate.ring,r=this._wallSourceCmAt(n[0],t.activePath,t.activeCms);o=Xe(o,i.rooms,e.id,r,this.host._wallKeyPitch,s,ol);for(const a of z(i.rooms,o,s,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol)){if(a.roomId!==e.id||"outer"!==a.kind)continue;const s=[(a.a[0]+a.b[0])/2,(a.a[1]+a.b[1])/2];o=E(o,a.a,a.b,this._wallSourceCmAt(s,t.activePath,t.activeCms),this.host._wallKeyPitch,ol)}}const a=this.host._normalizeWalls(o,s);a.length?e.walls=a:delete e.walls}if(!this._commitPhysicalGeometry(this.host._t("history.wall_face_batch"),g))return;delete this.host._resumeDraftBySpace[this.host._space],this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices();const x=new Set(o.map(t=>t.area).filter(t=>!!t));if(x.size){const t={...this.host._layout};for(const e of this.host._devices){if(!x.has(e.area||"")||e.space!==this.host._space)continue;if(this.host._layout[e.id])continue;const s=this.host._defPos[e.id];s&&(t[e.id]={s:this.host._space,x:s.x/ol,y:s.y/ol},this.host._dirtyPos.add(e.id))}this.host._layout=t,this.host._persistLayout()}this.host._showToast(this.host._t(o.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:o.length}))}_commitRoom(){const t=this.host._curSpaceCfg,e=this.host._spaceModel();if(!t||!e)return;const s=this._geometrySnapshot(),i=this.host._spaceH,o=!!this.host._pendingSplit,a=o?kt(e.rooms,t.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol):null,n=o&&Array.isArray(t.walls)?t.walls:null;let r;if(this.host._pendingSplit){const e=t.rooms.find(t=>t.id===this.host._pendingSplit.roomId);if(!e)return this.host._pendingSplit=null,this.host._splitSel=null,void(this.host._roomDialog=!1);e.poly=this.host._pendingSplit.mainPoly.map(t=>[t[0]/ol,t[1]/i]),delete e.x,delete e.y,delete e.w,delete e.h,r=this.host._pendingSplit.newPoly}else{if(!this.host._contourClosed)return;r=this.host._path.slice(0,-1)}const l=this.host._areaSel?this.host.hass.areas[this.host._areaSel]?.name:"",h={id:"r"+Date.now().toString(36),name:this.host._nameSel||l||this.host._t("room.default_name"),area:this.host._areaSel||null,poly:r.map(t=>[t[0]/ol,t[1]/i]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(!o&&this.host._activeDraftId){const e=Array.isArray(t.room_drafts)?t.room_drafts.find(t=>t.id===this.host._activeDraftId):null,s=Ra(r.length,[...this.host._draftSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,A),i=this._draftSegmentsForPath(this.host._path,e,s);i.length===r.length&&i.every(t=>!!t.id)&&(h.wall_ids=i.map(t=>t.id))}if(t.rooms.push(h),!o&&this.host._activeDraftId&&Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),o){const e=this.host._normalizeWalls(a,this.host._openCuts());e.length?t.walls=e:n?.length?t.walls=n:delete t.walls}if(!o){const e=Ra(r.length,[...this.host._draftSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,A),s=e[0];if(null!=s){this.host._cfgEpoch++;const i=this.host._openCuts(),o=this.host._spaceModel();if(!o)return;let a=Xe(t.walls,o.rooms,h.id,s,this.host._wallKeyPitch,i,ol);for(const t of z(o.rooms,a,i,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol)){if(t.roomId!==h.id||"outer"!==t.kind)continue;const s=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],i=r.findIndex((t,e)=>{const i=r[(e+1)%r.length];return C(s,[t[0],t[1],i[0],i[1]])<=.02*this.host._gridPitch});i>=0&&(a=E(a,t.a,t.b,e[i],this.host._wallKeyPitch,ol))}a=this.host._normalizeWalls(a,i),a.length?t.walls=a:delete t.walls}}const c=this._commitPhysicalGeometry(this.host._t(o?"history.split_room":"history.add_room"),s);this.host._path=[],delete this.host._resumeDraftBySpace[this.host._space],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this.host._pendingSplit=null,this.host._splitSel=null;const d=this.host._areaSel;if(this.host._areaSel="",this.host._nameSel="",this.host._roomDialog=!1,this.host._regSignature="",this.host._maybeRebuildDevices(),!c)return;let p=0;if(d){const t=ol,e={...this.host._layout};for(const s of this.host._devices){if(s.area!==d||s.space!==this.host._space)continue;if(p++,this.host._layout[s.id])continue;const i=this.host._defPos[s.id];i&&(e[s.id]={s:this.host._space,x:i.x/ol,y:i.y/t},this.host._dirtyPos.add(s.id))}this.host._layout=e,this.host._persistLayout()}const _=this.host._model.find(t=>t.id===this.host._space)?.rooms.length||0;this.host._showToast(d?this.host._t("toast.room_saved",{n:_,added:p}):this.host._t("toast.room_saved_no_area",{n:_}))}_cancelPath(){this.host._wallRepairDiagnostic=null,this.host._activeDraftId&&(this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId),this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),this.host._roomDialog=!1,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._splitSel=null,this.host._mergeSel=null,this.host._mergeDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this._clearOpeningPlacement(!0)}_resumeLastDraft(){const t=this.host._resumeDraftBySpace[this.host._space];if(!t)return;const e=this.host._spaceModel()?.room_drafts.find(e=>e.id===t);e?(this.host._activeDraftId=t,this.host._path=e.points.map(t=>[...t]),this.host._draftSegmentCms=this._adoptDraftCms(this.host._path,e.segments.map(t=>t.cm),e.id),this._clearPlanSnapHover()):delete this.host._resumeDraftBySpace[this.host._space]}_roomDialogCancel(){if(this.host._roomDialog=!1,this.host._roomEditId)return this.host._roomEditId=null,this.host._nameSel="",void(this.host._areaSel="");if(this.host._wallFaceBatch){const t=this.host._wallFaceBatch;return this.host._wallFaceBatch=null,this.host._path=t.activePath.map(t=>[...t]),this.host._draftSegmentCms=[...t.activeCms],this.host._activeDraftId=t.activeDraftId,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate()}if(this.host._pendingSplit)return this.host._pendingSplit=null,void(this.host._splitSel=null);this.host._undoPoint()}_openDeviceInbox(){this.host._deviceInboxReturn=null,this.host._deviceInbox=this.host._deviceInbox||{tab:"on_plan",search:"",showEntities:!1,onlyNew:!1,limit:100}}_closeMarkerDialog(){if(this.host._markerDialog=null,this.host._deviceInboxReturn){const t={...this.host._deviceInboxReturn};this.host._deviceInbox=t,this.host._deviceInboxReturn=null,t.anchor&&this.host.updateComplete.then(()=>requestAnimationFrame(()=>{const e=`.device-inbox-row[data-binding="${CSS.escape(t.anchor)}"]`;this.host.renderRoot.querySelector(e)?.scrollIntoView({block:"nearest"})}))}}_deviceInboxCandidates(t){return ca({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:t,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}})}_deviceInboxRows(){const t=this.host._deviceInbox||this.host._deviceInboxReturn,e=!!t?.showEntities,s=[this.host._haRegistry.revision,this.host._cfgRev,this.host._cfgEpoch,this.host._regSignature,this.host._newSyncKey,e?1:0,this.host._showAll?1:0,d(this.host.hass,this.host._config?.language)].join("|");if(this.host._deviceInboxMemo?.key===s)return this.host._deviceInboxMemo.rows;const i=this._deviceInboxCandidates(e),o=new Set(i.map(t=>t.value));for(const t of this.host._markers)t.binding&&"virtual"!==t.binding&&o.add(t.binding);for(const t of this.host._devices)t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&o.add(`${t.bindingKind}:${t.bindingRef}`);const a=new Map;for(const t of o)a.set(t,this.host._bindingStatus(t));const n=this.host._areaToSpace,r={};for(const[t,e]of Object.entries(this.host.hass?.areas||{}))r[t]=n[t]?.room?.name||e?.name||t;for(const[t,e]of Object.entries(n))r[t]=e.room.name||r[t]||t;const l=Object.fromEntries(this.host._model.map(t=>[t.id,t.title])),h=Object.fromEntries(Object.entries(n).map(([t,e])=>[t,e.space])),c={},p=new Map;for(const[t,e]of Object.entries(this.host._fullRegistryHass.entities||{})){const s=String(e?.platform||"").trim();if(s&&(c[`entity:${t}`]=s),s&&e?.device_id){const t=p.get(e.device_id)||new Set;t.add(s),p.set(e.device_id,t)}}for(const[t,e]of p)c[`device:${t}`]=[...e].sort().join(", ");const _={};for(const[t,e]of Object.entries(this.host._fullRegistryHass.devices||{})){const s=`device:${t}`,i=p.get(t)||new Set,o=Array.isArray(e?.identifiers?.[0])?String(e.identifiers[0][0]||""):"",a=[o,...i].some(t=>this.host._excluded.has(t));"service"===e?.entry_type?_[s]="service_entry":a?_[s]="excluded_integration":"Group"===e?.model?_[s]="grouped_light":/scene/i.test(e?.model||"")?_[s]="excluded_domain":(/bridge/i.test(`${e?.model||""}${e?.name||""}`)||"myheat"===o&&e?.via_device_id)&&(_[s]="represented_by_parent")}const u=function(t){const{devices:e,markers:s,candidates:i,statuses:o,newDeviceIds:a,showHiddenOnPlan:n,areaNames:r={},spaceNames:l={},spaceByArea:h={},integrationByBinding:c={},reasonByBinding:d={}}=t,p=new Map;for(const t of e)!t.virtual&&t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&p.set(`${t.bindingKind}:${t.bindingRef}`,t);const _=new Map,u=new Map;for(const t of s)t?.binding&&"virtual"!==t.binding&&(t.removed?u.set(t.binding,t):_.set(t.binding,t));const m=new Map(i.map(t=>[t.value,t])),g=new Set([...p.keys(),..._.keys(),...m.keys(),...[...u.keys()].filter(t=>m.has(t))]),f=[];for(const t of g){const e=p.get(t),s=_.get(t),i=s?void 0:u.get(t),g=m.get(t);let b;if(i&&g)b="readd";else if(!0===s?.hidden)b="hidden";else if(e||s)b="on_plan";else{if(!g)continue;b="available"}const y=e?.bindingStatus||o.get(t)||da,v=s||i,$=pa(t),w=e?.area||g?.areaId||v?.area||"",k=e?.space||v?.space||h[w]||"",x=e?.name||v?.name||g?.label||t,S=e?.model||v?.model||g?.model||"",M=!!g?.parentDeviceId&&p.has(`device:${g.parentDeviceId}`),D="readd"===b?"removed":"hidden"===b?s&&_a(s)?d[t]||"automatic_hidden":"manual_hidden":"on_plan"===b?s?"visible_explicit":"visible_auto":d[t]||(M?"represented_by_parent":w&&k?"available":"no_bound_room"),C=!!e&&(!e.hidden||n),P="active"===y.kind,I=C&&(P||"ha_disabled"===y.kind&&n),T=[x,S,c[t],r[w],l[k],t,g?.sub].filter(Boolean).join(" ").toLocaleLowerCase();f.push({key:t,binding:t,category:b,status:y,reason:D,deviceId:e?.id,markerId:v?.id,name:x,icon:e?.icon||v?.icon||("entity"===$?"mdi:code-braces":"mdi:devices"),model:S,integration:c[t]||"",areaId:w,areaName:r[w]||"",spaceId:k,spaceName:l[k]||"",kind:$,isNew:!!e&&a.has(e.id),searchText:T,canFind:I,canEdit:!!e||!!s,canHide:"on_plan"===b&&P,canShow:"hidden"===b&&P,canAdd:("available"===b||"readd"===b)&&P})}const b=t=>"active"===t.status.kind?1:0;return f.sort((t,e)=>t.category.localeCompare(e.category)||Number(e.isNew)-Number(t.isNew)||b(t)-b(e)||t.name.localeCompare(e.name)||t.binding.localeCompare(e.binding))}({devices:this.host._devices,markers:this.host._markers,candidates:i,statuses:a,newDeviceIds:this.host._newIds,showHiddenOnPlan:this.host._showAll,areaNames:r,spaceNames:l,spaceByArea:h,integrationByBinding:c,reasonByBinding:_});return this.host._deviceInboxMemo={key:s,rows:u},u}_deviceForInboxRow(t){const e=t.deviceId?this.host._devices.find(e=>e.id===t.deviceId):null;if(e)return e;const s=t.markerId?this.host._markers.find(e=>e.id===t.markerId):null;return!s||s.removed?null:{id:s.id,name:t.name,model:t.model,area:t.areaId,space:t.spaceId||this.host._space,hidden:!0===s.hidden||"ha_disabled"===t.status.kind,userHidden:!0===s.hidden,bindingStatus:t.status,icon:t.icon,entities:"active"===t.status.kind?t.status.enabledEntityIds:[],allEntities:t.status.allEntityIds,primary:"active"===t.status.kind?t.status.enabledEntityIds[0]:void 0,marker:s,bindingKind:t.kind,bindingRef:t.binding.slice(t.binding.indexOf(":")+1),pdfs:s.pdfs||[]}}_openInboxMarker(t,e=!1){const s=this.host._deviceInbox;if(s){if(this.host._deviceInboxReturn={...s,anchor:t.key},this.host._deviceInbox=null,!e){const e=this._deviceForInboxRow(t);return void(e?this._openMarkerDialog(e):this._closeMarkerDialog())}this._openMarkerDialog(),this.host._markerDialog?this.host._markerDialog={...this.host._markerDialog,bindingMode:"ha",binding:t.binding,bindingOpen:!1,showEntities:"entity"===t.kind,name:""}:this._closeMarkerDialog()}}async _setInboxHidden(t,e){const s=this.host._deviceInbox,i=this.host._serverCfg;if(!s||!i||s.busy||"active"!==t.status.kind)return;const o=i.markers||[],a=o.find(e=>!e.removed&&e.binding===t.binding);if(!e&&!a)return;const n=a?.id||Ze(t.binding,t.markerId,()=>`m_${Date.now().toString(36)}`),r=a?{...a,hidden:e}:{id:n,binding:t.binding,hidden:!0};i.markers=[...o.filter(e=>e.id!==n&&(e.binding!==t.binding||!0===e.removed)),r],this.host._deviceInbox={...s,busy:t.key,anchor:t.key};try{await this._saveConfigNow(),this.host._regSignature="",this.host._deviceInboxMemo=null,this.host._maybeRebuildDevices(),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("device_inbox.saved"))}catch(t){this.host._serverCfg===i&&(i.markers=o),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_findInboxDevice(t){if(!t.canFind)return;const e=this._deviceForInboxRow(t);if(!e)return;if(this.host._deviceInbox=null,e.space&&e.space!==this.host._space){if(!this.host._commitSpace(e.space))return;this.host._restoreZoom()}const s=()=>{const t=this.host._devices.find(t=>t.id===e.id)||e,s=this.host._pos(t);this.host._applyView(this.host._zoom,s.x,s.y),this.host._selId=t.id,this.host.requestUpdate(),window.setTimeout(()=>{this.host._selId===t.id&&(this.host._selId=null,this.host.requestUpdate())},1500)};requestAnimationFrame(()=>requestAnimationFrame(s))}_openMarkerDialog(t){if(this.host._vacAllCamerasFor=null,this.host._vacAllCameraCache=null,t&&this.host._ackNewDevice(t.id),this.host._norm)if(t){const e=t.marker,s=Object.prototype.hasOwnProperty.call(e||{},"is_light"),i=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),o=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),a=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),n=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),r=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),h=Qe(e?.glow_color),c=this.host._devicePresentation(t,!0).valueBadge,d=ts(this.host._planHass,t,this.host._devices),p=es(this.host._planHass,t,d);this.host._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.host._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:os(t.marker?.display),rippleColor:l(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:is(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:n,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:ss(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:s,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:i,originalLightEntity:e?.light_entity,glowMode:null!=h?.bri?"fixed":h?"color":"auto",glowColor:h?.c||this.host._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(h?.bri??1))),glowColorDrafted:!!h,glowBrightnessDrafted:null!=h?.bri,glowTouched:!1,originalHasGlowColor:o&&(!!h||null===e?.glow_color),originalGlowColor:h||(null===e?.glow_color?null:void 0),valueBadgeEnabled:a?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||p,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:a,originalValueBadge:e?.value_badge,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this.host._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.host._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.host._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.host._showToast(this.host._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of as)for(const[s,i]of Object.entries(this.host.hass.states))s.startsWith(e+".")&&this.host._planEntityAvailable(s)&&t.push({value:s,label:i?.attributes?.friendly_name||s,sub:this.host._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=ca({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:!!this.host._markerDialog?.showEntities,currentBinding:this.host._markerDialog?.binding,currentDeviceId:this.host._markerDialog?.devId,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}}),e=(this.host._markerDialog?.bindingFilter||"").toLowerCase().trim(),s=e?t.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(e)):t;return s.sort((t,e)=>t.label.localeCompare(e.label)),s.slice(0,200)}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,s=this.host._t(t);if(s!==t)return s}return this.host._errText(t)}async _pickMarkerFiles(t){const e=t.target,s=e.files?[...e.files]:[];if(e.value="",!s.length||!this.host._markerDialog)return;const i=this.host._markerDialog.uploadId||this.host._markerDialog.devId||"new",o=[];for(const t of s)try{const e=new FormData;e.append("marker_id",i),e.append("file",t,t.name);const s=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}),a=await s.json().catch(()=>({}));if(!s.ok||a.error){const t={too_large:this.host._t("err.too_large",{mb:a.max_mb||50}),bad_ext:this.host._t("err.bad_ext"),unauthorized:this.host._t("err.unauthorized")};throw new Error(t[a.error]||a.error||"HTTP "+s.status)}o.push({name:a.name||t.name,url:a.url})}catch(e){this.host._showToast(this.host._t("toast.file_failed",{name:t.name,err:this.host._errText(e)}))}o.length&&this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:[...this.host._markerDialog.pdfs,...o]},this.host._showToast(this.host._t("toast.files_attached",{n:o.length})))}_removeMarkerPdf(t){this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:this.host._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 s={c:l(t.glowColor,this.host._fillColors.glow_light.c)};"fixed"===t.glowMode&&(s.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=s}}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.host._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.host._showToast(this.host._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this.host._showToast(this.host._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this.host._showToast(this.host._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this.host._bindingStatus(t.binding),s=t.devId?this.host._markers.find(e=>e.id===t.devId):null,i=!s||s.binding!==t.binding;if("active"!==e.kind&&i)return void this.host._showToast(this.host._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===s?.hidden&&!t.hideFromPlan)return this.host._markerDialog={...t,hideFromPlan:!0},void this.host._showToast(this.host._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const s=this.host._serverCfg;if(!s)return;const i=s.markers||[],o=ns(t.room);let a=o?.space||null;const n=o?.area||null,r=o?.roomId||null,l=Ze(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),h=t.devId,c=h?this.host._devices.find(t=>t.id===h):null,d=o?.space||c?.space||null,p=d?this.host._spaceModelById(d):this.host._spaceModel();if(!p)return;const _=p.id;"virtual"!==t.binding||a||(a=_),this.host._markerDialog={...t,busy:!0};try{const o="virtual"===t.binding?[]:i.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=o.length>0,u=ss(t.binding,t.controls,this.host._bindingEntities(t.binding)),m=i.find(t=>t.id===l||t.id===h)?.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:u.length?u:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=sl(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._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=a,g.area=n,g.room_id=r);const f=c?.marker?.room_id??null,b=!!t.room&&null!=c&&(c.space!==a||c.area!==n||f!==r);let y=!1;const v=t.uploadId||h;if(v&&v!==l&&g.pdfs?.length)try{const t=await this.host.hass.callWS({type:"houseplan/files/migrate",from_id:v,to_id:l}),e=t?.mapping||{};g.pdfs=rs(g.pdfs,v,l,e),y=Object.keys(e).length>0}catch(t){this.host._showToast(this.host._t("toast.files_migrate_failed",{err:this.host._errText(t)}))}s.markers=i,h&&h!==l&&(s.markers=ls(s.markers,h,l)),h&&h!==l&&"derived_marker_state"===g.value_badge?.source?.kind&&g.value_badge.source.ref===`marker:${h}`&&(g.value_badge.source={kind:"derived_marker_state",ref:`marker:${l}`}),s.markers=s.markers.filter(t=>t.id!==l&&t.id!==h&&("virtual"===g.binding||t.binding!==g.binding)),s.markers.push(g);let $=null;const w=h?this.host._layout[h]:null,k=w?{s:w.s||c?.space||this.host._space,x:w.x,y:w.y}:h&&c&&this.host._defPos[h]?this.host._normPos(c.space,this.host._defPos[h].x,this.host._defPos[h].y):null;if(!d&&k&&k.s===_)l===h&&this.host._layout[l]&&!b||($={s:k.s,x:k.x,y:k.y},this.host._layout={...this.host._layout,[l]:$});else if(d||!this.host._layout[l]||b){let t=p.vb[0]+p.vb[2]/2,e=p.vb[1]+p.vb[3]/2;const s=r?p.rooms.find(t=>t.id===r):n?p.rooms.find(t=>t.area===n):void 0;s&&([t,e]=this.host._roomCenter(s)),$=this.host._normPos(_,t,e),this.host._layout={...this.host._layout,[l]:$}}if(await this._saveConfigNow(),$){const t=hs($);this.host._layout={...this.host._layout,[l]:t},this.host._noteLayoutRev(await this.host.hass.callWS({type:"houseplan/layout/update",device_id:l,pos:t}))}const x=new Set(o);h&&h!==l&&x.add(h),x.delete(l);for(const t of x)delete this.host._layout[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{});y&&v&&await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:v}).catch(()=>{}),this._closeMarkerDialog(),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_saved"))}catch(t){this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteMarker(){const t=this.host._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this.host._devices.find(e=>e.id===t.devId):null,s=this.host._markers.find(e=>e.id===t.devId);if(!e&&!s)return;const i=t.name||this.host._t("device.fallback");if(!confirm(this.host._t("confirm.remove_marker",{name:i})))return;const o=this.host._serverCfg;o.markers=o.markers||[];const a=o.markers,n=e?.id||s.id,r=e?"virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"":s.binding;if(!r)return;const l=cs(o.markers,n,r,"virtual"===r);o.markers=ds(l.markers,l.cleanupIds);const h=l.cleanupIds;this.host._markerDialog={...t,busy:!0};try{await this._saveConfigNow();for(const t of h){delete this.host._layout[t],delete this.host._defPos[t],this.host._dirtyPos.delete(t),this.host._sentPos.delete(t);const e=this.host._activityRt.get(t);e&&clearTimeout(e.timer),this.host._activityRt.delete(t),this.host._vacRt.delete(t),delete this.host._vacSrvTrails[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this.host._deviceInboxReturn&&(this.host._deviceInboxReturn={...this.host._deviceInboxReturn,tab:"readd",anchor:r}),this._closeMarkerDialog(),this.host._infoCard?.id===n&&this.host._closeInfoCard(),this.host._selId===n&&(this.host._selId=null),this.host._drag?.id===n&&(this.host._drag=null),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_removed"))}catch(t){this.host._serverCfg===o&&(o.markers=a),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_openSpaceDialog(t,e){if(this.host._serverStorage&&this.host._serverCfg)if("edit"===t){const s=this.host._serverCfg.spaces.find(t=>t.id===e);if(!s)return;const i=ps(s),o=s.settings?.custom_fill&&"object"==typeof s.settings.custom_fill?_s(s.settings.custom_fill):null,a="none"===i.fill?{...o||us,a:0}:o;this.host._spaceDialog={mode:t,spaceId:e,title:s.title,planUrl:s.plan_url||null,planFile:null,source:s.plan_url?"file":"draw",showBorders:i.showBorders,showNames:i.showNames,zeroWallStyle:gs(s),displayTouched:!0,hideDecor:i.hideDecor,hideOpenings:i.hideOpenings,roomColor:i.color,roomOpacity:i.opacity,fillMode:"none"===i.fill?"custom":i.fill,customFill:a,glowEnabled:i.glow,bgColor:i.bgColor,bgMode:"static"===s.settings?.bg_mode||"daynight"===s.settings?.bg_mode?s.settings.bg_mode:null,northDeg:Mt({},s.settings),sunRays:"boolean"==typeof s.settings?.sun_rays?s.settings.sun_rays:null,tempMin:i.tempMin,tempMax:i.tempMax,showLqi:i.showLqi??this.host._config?.show_signal??!0,cardFontScale:i.cardFontScale,labelTemp:i.labelTemp,labelHum:i.labelHum,labelLqi:i.labelLqi,labelLight:i.labelLight,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,cellCmInput:ms(Number(s.cell_cm)>0?Number(s.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1}}else this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...Ri(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:vs,roomOpacity:ys,fillMode:"custom",customFill:{...us,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:bs,tempMax:fs,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:$s(this.host._imperial),cellCmInput:ms($s(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1};else this.host._showToast(this.host._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,s=e.files?.[0];if(!s||!this.host._spaceDialog)return;const i={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[s.type]||(s.name.toLowerCase().endsWith(".svg")?"svg":"");if(!i)return void this.host._showToast(this.host._t("toast.plan_formats"));const o=new Uint8Array(await s.arrayBuffer());let a="";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.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:i,b64:n,aspect:l,name:s.name}}}_useServerPlan(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this.host._display(t);if(e){const s=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:0),s.onerror=()=>t(0),s.src=e}),i=this.host._spaceDialog;return i&&i.planUrl===t&&Number.isFinite(s)&&s>0?(this.host._spaceDialog={...i,savedAspect:s},s):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this.host._spaceDialog;e?.saved&&(this.host._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`
${this.host._t("space.loading")}
`;const e=t.saved||[];if(!e.length)return o`
${this.host._t("space.no_saved")}
`;return o`
+ ${e.map(e=>{return o` +
+ +
+ ${e.name} + ${s=e.size,s>=1048576?(s/1048576).toFixed(1)+" MB":Math.round(s/1024)+" KB"}${e.used_by.length?" · "+this.host._t("space.used_by",{list:e.used_by.join(", ")}):""} +
+ + +
`;var s})} +
`}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const e="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const s="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let i=null;if("file"===t.source&&t.planFile){i={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:s,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let o=t.savedAspect||null;!i&&"file"===t.source&&t.planUrl&&!o&&this.host._aspectJob&&(o=await this.host._aspectJob||null);const a=this.host._serverCfg;let n;if("create"===t.mode)n=Fi(s,t.title.trim()),a.spaces.push(n);else{if(n=a.spaces.find(t=>t.id===s),!n)throw new Error("space "+s+" is gone from the config");n.title=t.title.trim()}i?(n.plan_url=i.url,n.plan_aspect=i.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==n.plan_url&&(n.plan_url=t.planUrl,n.plan_aspect=o),"draw"===t.source&&(n.plan_url=null,n.plan_aspect=null,delete n.plan_x,delete n.plan_y,delete n.plan_scale,delete n.plan_scale_x,delete n.plan_scale_y,delete n.plan_angle),n.settings={...n.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):bs,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):fs,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},n.zero_wall_style=t.zeroWallStyle,n.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(el,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(n.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length?this._openNextImport():e||this.host._importTotal>0?(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._showToast(this.host._t(e&&!this.host._importTotal?"toast.space_added_onboard":"import.done"))):(this.host._showToast("create"===t.mode?this.host._t("toast.space_added"):this.host._t("toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?this._setMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._saveNav())))}catch(t){"conflict"!==t?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this.host._serverCfg;if(!e)return;const s=e.spaces.find(e=>e.id===t.spaceId),i=Ni(e,this.host._layout||{},t.spaceId||""),o=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(!i.count||o){if(confirm(this.host._t("confirm.delete_space",{title:s.title}))){this.host._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain;const e=await this.host.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev}),[s,i]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._adoptStructuralResponses(s,i),this.host._cfgRev=e?.config_rev??this.host._cfgRev,this.host._layoutRev=e?.layout_rev??this.host._layoutRev,this.host._spaceDialog=null,this.host._space===t.spaceId&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(e){"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const s=this.host._serverCfg;if(this.host._spaceDialog&&s){const e=Ni(s,this.host._layout||{},t.spaceId||""),i=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:i?0:e.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(e)}))}}}else this.host._spaceDialog={...t,deleteBlockers:i.count}}async _saveConfigNow(){this.host._cfgEpoch++;try{await this._writeConfig()}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this.host._reloadConfigOnly(),t}}_startImport(){const t=this.host._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,e.length?(this.host._importQueue=e,this.host._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();void 0!==t&&(this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...Ri(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:vs,roomOpacity:ys,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:bs,tempMax:fs,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:$s(this.host._imperial),cellCmInput:ms($s(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._showToast(this.host._t("import.done")))}_renderImportDialog(){const t=this.host._importDialog,e=t.floors.filter(t=>t.checked).length;return o`this.host._importDialog=null}> +
+
${this.host._t("import.hint")}
+ ${t.floors.map((e,s)=>o``)} +
+
+ + + +
+
`}_preflightDiagnostics(t,e){const s=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:Xr,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:s.has(t.spaceId)?jt(s.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this.host._reportedPreflightFingerprint||(this.host._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this.host._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==Xr}async _copyPreflightDiagnostics(){const t=this.host._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this.host._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.preflight_copied"))}catch{this.host._preflightClipboardFallback=e}}_checkOptimizeGeometryImpl(t){return ws(t,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometryImpl(t,e,s){return ks(t,e,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)}),captureWallGeometry:s?(t,e)=>s(e):void 0})}_optimizeReferenceContext(t){const e=this.host._haRegistry,s=this.host._fullRegistryHass,i={},o=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,s]of Object.entries(e.devices||{}))i[t]=o(s?.name_by_user,s?.name,s?.model);for(const[t,s]of Object.entries(e.entities||{}))i[`lg_${t}`]=o(this.host.hass?.states?.[t]?.attributes?.friendly_name,s?.name,s?.original_name);for(const t of this.host._devices)i[t.id]=o(t.name,i[t.id]);for(const t of this.host._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),a=e>0?t.binding.slice(0,e):"",n=e>0?t.binding.slice(e+1):"",r="device"===a?s?.devices?.[n]:"entity"===a?s?.entities?.[n]:null;i[t.id]=o(t.name,"device"===a?r?.name_by_user:null,r?.name,"entity"===a?this.host.hass?.states?.[n]?.attributes?.friendly_name:null,i[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this.host._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.host.hass?.states||{})])],names:i},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this.host._norm||!this.host._serverCfg)return;const e=this.host._serverCfg.spaces||[];let s;try{s=zr(this.host._serverCfg,this.host._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const i=s.changed?this.host._checkOptimizeGeometry(s.config):null;i&&this._reportPreflightFailure(i,s.config);const o=Math.ceil(10*s.report.maxShiftCm)/10,a=e.find(t=>null!=t?.id&&String(t.id)===s.report.maxSpace),n=e.length>1&&a?String(a.title||a.id):"";this.host._preflightClipboardFallback=null,this.host._alignDialog={report:s.report,config:s.config,layout:s.layout,cm:o,where:n,preflight:i,changed:s.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this.host._alignDialog;if(!t||t.busy||!this.host._serverCfg||!t.changed||!t.preflight?.ok)return;const e=Et(t.config);if(t.preflight.fingerprint!==e){const e=this.host._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this.host._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this.host._alignDialog={...t,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),await this.host._writeChain;const e=await this.host.hass.callWS({type:"houseplan/plan/optimize",config:t.config,layout:t.layout,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});this.host._serverCfg=t.config,this.host._layout=t.layout,this.host._geometryHistory.clear(),this.host._cfgRev=e?.config_rev??this.host._cfgRev+1,this.host._layoutRev=e?.layout_rev??this.host._layoutRev+1,this.host._canOptimizeUndo=!!e?.can_undo,this.host._undoKind=e?.can_undo?"optimize":null,this.host._dirtyPos.clear(),this.host._sentPos.clear(),this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._cacheSnapshot(),this.host._alignDialog=null,this.host._preflightClipboardFallback=null,this.host.requestUpdate(),this.host._showToast(this.host._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.host._alignDialog&&(this.host._alignDialog={...this.host._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this.host._showToast(this.host._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _undoPlanOptimization(){if(!this.host._canOptimizeUndo||this.host._optimizeUndoBusy)return;const t=this.host._undoKind;this._clearGeometryGesture(),this.host._optimizeUndoBusy=!0,this.host.requestUpdate();try{await this.host.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[e,s]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._serverCfg=e?.config||this.host._serverCfg,this.host._cfgRev=e?.rev??this.host._cfgRev,this.host._layout=s?.layout||this.host._layout,this.host._geometryHistory.clear(),this.host._layoutRev=s?.rev??this.host._layoutRev,this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._cacheSnapshot(),this.host.requestUpdate(),this.host._showToast(this.host._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}finally{this.host._optimizeUndoBusy=!1,this.host.requestUpdate()}}async _runBackupExport(){const t=this.host._backupExportDialog;if(t&&!t.busy){this.host._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.host.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this.host._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:Xr}),s=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),i=URL.createObjectURL(s),o=document.createElement("a");o.href=i,o.download=e.filename||`houseplan-${t.kind}.json`,o.style.display="none",document.body.append(o),o.click(),o.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),0),this.host._backupExportDialog=null,this.host._showToast(this.host._t("backup.export_done"))}catch(t){this.host._backupExportDialog&&(this.host._backupExportDialog={...this.host._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,s=e.files?.[0];if(e.value="",s){this.host._settingsDialog=null,this.host._backupImportDialog={filename:s.name,size:s.size,token:"",preview:null,expectedConfigRev:this.host._cfgRev,expectedLayoutRev:this.host._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),await this.host._writeChain,this.host._persistLayout.pending()&&this.host._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:s,headers:{"content-type":"application/json"}},i=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error)throw Object.assign(new Error(o.message||o.error||`HTTP ${i.status}`),{code:o.error});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,token:o.token,preview:o.preview,expectedConfigRev:o.expected_config_rev,expectedLayoutRev:o.expected_layout_rev,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this.host._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this.host._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const s=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,preview:{...e.preview,...s.preview},expectedConfigRev:s.expected_config_rev,expectedLayoutRev:s.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this.host._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this.host._backupImportDialog={...t,busy:!0,error:""};const e=this.host._space;try{const s=await this.host.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}),[i,o]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._adoptStructuralResponses(i,o),this.host._geometryHistory.clear(),this.host._dirtyPos.clear(),this.host._sentPos.clear(),this.host._defPos={},this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._visibleDeviceSnapshot=null,this.host._candidateDeviceSnapshot=null,this.host._stagedDeviceSnapshotToken=-1,this.host._capturedSnapshotConfigEpoch=-1,this.host._regSignature="",this.host._signer.invalidate(this.host.hass),this.host._resign(),this.host._maybeRebuildDevices();const a=this.host._serverCfg?.spaces||[],n="space"===s.kind&&s.space_id?s.space_id:a.some(t=>t.id===e)?e:a[0]?.id||this.host._space;this.host._hasFixedFloor?this.host._adoptInitialSpace(this.host._model,!0):this.host._commitSpace(n),this.host._backupImportDialog=null,this.host._cacheSnapshot(),this.host.requestUpdate();const r="space"===s.kind?t.preview.counts:s.counts;this.host._showToast(this.host._t("space"===s.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(s.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this.host._backupImportDialog?.token)try{const t=this.host._backupImportDialog,e=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this.host._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this.host._t("backup.revalidated")})}catch(e){t=e}this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this.host._backupExportDialog,e=(this.host._serverCfg?.spaces||[]).find(t=>t.id===this.host._space);return o`this.host._backupExportDialog=null}> +
+
${this.host._t("backup.export_hint")}
+ + + ${"space"===t.kind&&e?o``:a} +
${this.host._t("backup.privacy_warning")}
+ ${t.error?o``:a} +
+
+ + + +
+
`}_renderBackupImportDialog(){const t=this.host._backupImportDialog,e=t.preview,s=e?.counts||{},i=e?.reference_report||{},n=t=>Object.values(t||{}).reduce((t,e)=>t+(Number(e)||0),0),r=[["incoming_remapped",n(i.remapped?.incoming)],["target_repaired",n(i.remapped?.target)],["preserved_unresolved",n(i.preservedUnresolved)],["collisions",n(i.collisions)],["dropped_links",n(i.droppedIncomingLinks)],["bounded_lineages",Number(i.boundedLineages)||0]].filter(([,t])=>t>0);return o`this.host._backupImportDialog=null}> +
+
${t.filename}${(t.size/1024).toFixed(1)} KB
+ ${t.busy&&!e?o`
${this.host._t("backup.reading")}
`:a} + ${t.error?o``:a} + ${e?o` +
+ ${this.host._t("full"===e.kind?"backup.full":"backup.current_space")} + ${e.plan_only?o`${this.host._t("backup.plan_only_preview")}`:a} + ${this.host._t("same"===e.source?"backup.same_source":"backup.foreign_source")} + ${this.host._t("backup.created",{value:e.created_at||"—"})} + ${this.host._t("backup.versions",{card:e.card_version||"—",integration:e.integration_version||"—",model:String(e.model_version??"—")})} +
+
+ ${this.host._t("backup.count_spaces",{n:"full"===e.kind?`${e.current_counts?.spaces||0} → ${s.spaces||0}`:String(s.spaces||0)})} + ${this.host._t("backup.count_rooms",{n:"full"===e.kind?`${e.current_counts?.rooms||0} → ${s.rooms||0}`:String(s.rooms||0)})} + ${this.host._t("backup.count_walls",{n:"full"===e.kind?`${e.current_counts?.walls||0} → ${s.walls||0}`:String(s.walls||0)})} + ${this.host._t("backup.count_openings",{n:"full"===e.kind?`${e.current_counts?.openings||0} → ${s.openings||0}`:String(s.openings||0)})} + ${this.host._t("backup.count_decor",{n:"full"===e.kind?`${e.current_counts?.decor||0} → ${s.decor||0}`:String(s.decor||0)})} + ${this.host._t("backup.count_markers",{n:"full"===e.kind?`${e.current_counts?.markers||0} → ${s.markers||0}`:String(s.markers||0)})} + ${this.host._t("backup.count_layout",{n:"full"===e.kind?`${e.current_counts?.layout||0} → ${s.layout||0}`:String(s.layout||0)})} +
+ ${e.bindings?o`
${this.host._t("backup.bindings",{device:String(e.bindings.device||0),entity:String(e.bindings.entity||0),virtual:String(e.bindings.virtual||0),legacy:String(e.legacy_positions||0)})}
${this.host._t("backup.binding_status",{active:String(e.bindings.active||0),disabled:String(e.bindings.disabled||0),missing:String(e.bindings.missing||0)})}
`:a} + ${e.missing_areas?.length?o`
${this.host._t("backup.missing_areas",{areas:e.missing_areas.join(", ")})}
`:a} + ${e.dropped_marker_links?o`
${this.host._t("backup.dropped_marker_links",{n:String(e.dropped_marker_links)})}
`:a} + ${e.repaired_target_refs?o`
${this.host._t("backup.repaired_target_refs",{n:String(e.repaired_target_refs)})}
`:a} + ${e.preserved_unresolved_refs?o` +
${this.host._t("backup.preserved_unresolved_refs",{n:String(e.preserved_unresolved_refs)})}
${this.host._t("backup.preserved_unresolved_hint")}
+ `:a} + ${r.length?o`
+ ${this.host._t("backup.import_details")} +
+ ${r.map(([t,e])=>o`${this.host._t(`backup.import_detail.${t}`,{n:String(e)})}`)} + ${(i.examples||[]).slice(0,8).map(t=>o` + ${t.owner} → ${t.reference} + `)} +
+
`:a} + ${"full"===e.kind?o` +
${this.host._t("backup.replace_warning")}
+ ${"foreign"===e.source?o`
${this.host._t("backup.foreign_bookkeeping")}
`:a}`:o` +
${this.host._t("backup.final_name")}${e.space_title}
+
${this.host._t("backup.target_settings")}
+ ${e.duplicates?o`
${this.host._t("backup.duplicates",{n:String(e.duplicates)})} + + +
`:a}`} + ${e.content?.length?o`
+ ${this.host._t("backup.content")} + ${e.content.map(t=>o`${t.url} · ${this.host._t("available"===t.state?"backup.content_available":"external"===t.state?"backup.content_external":"backup.content_detach_required")}`)} +
`:a} + ${e.confirmation_required?o``:a} + `:a} +
+
+ + + ${e?o``:a} +
+
`}_setFillColor(t,e){const s=this.host._settingsDialog;this.host._settingsDialog={...s,colors:{...s.colors,[t]:{...s.colors[t],...e}}}}async _saveSettingsDialog(){const t=this.host._settingsDialog;if(t&&!t.busy){this.host._settingsDialog={...t,busy:!0};try{const e=this.host._serverCfg,s=JSON.stringify(t.colors)===JSON.stringify(xs),i={...e.settings};s?delete i.fill_colors:i.fill_colors=t.colors;const o=this.host._imperial?30.48*t.glowRadius:100*t.glowRadius;Number.isFinite(o)&&o>0&&300!==Math.round(o)?i.glow_radius_cm=Math.round(o):delete i.glow_radius_cm,t.bgColor?i.bg_color=t.bgColor:delete i.bg_color,null!==t.northDeg&&Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359?i.north_deg=t.northDeg:delete i.north_deg,i.bg_mode=t.bgMode,t.sunRays?i.sun_rays=!0:delete i.sun_rays,delete i.weather_entity,this.host._serverCfg={...e,settings:i},await this._saveConfigNow(),this.host._settingsDialog=null,this.host.requestUpdate(),this.host._showToast(this.host._t("gs.saved"))}catch(t){this.host._settingsDialog&&(this.host._settingsDialog={...this.host._settingsDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}}_boolInput(t,e,s=!1){const i=t=>e(!!t.target.checked);return customElements.get("ha-switch")?o``:o``}_rangeInput(t,e,s,i,n,r=!1,l){const h=t=>{const e=Number(t.target.value);Number.isFinite(e)&&n(e)};return customElements.get("ha-slider")?o``:o``}_renderColorRow(t,e){const s=this.host._settingsDialog.colors[t];return o`
+ {this._setFillColor(t,{c:e.detail.color,a:e.detail.opacity})}}> +
`}_renderAlignDialog(){const t=this.host._alignDialog,e=t.report,s=t.changed&&!t.preflight?.ok,i=t.preflight?.failures||[],n=i.slice(0,3).map(t=>t.displayName),r=n.length?n.join(", "):this.host._t("gs.align_preflight_space",{n:"1"}),l=Math.max(0,i.length-n.length),h=l?this.host._t("gs.align_preflight_more",{n:String(l)}):"",c=e.spaceRefsRemapped+e.roomRefsRemapped+e.positionsRemapped+e.markersDetached,d=e.migrated+e.canonicalized+e.coordsCanonicalized+e.wallSegmentsMigrated+e.wallsMerged+e.spansMerged+e.partitionsMerged+e.partitionsReconciled+e.openingsRehosted+e.redundantDraftsRemoved,p=e.moved+e.rotated+e.removedDrafts+e.coordsCanonicalized+e.wallsStraightened,_=Math.ceil(10*e.maxStraightenShiftCm)/10,u=(this.host._serverCfg?.spaces||[]).find(t=>String(t?.id||"")===e.maxStraightenSpace),m=(this.host._serverCfg?.spaces||[]).length>1&&u?String(u.title||u.id):"",g=e.orphanRoomLabelsRemoved+e.orphanDevicePositionsRemoved+e.orphanGroupPositionsRemoved,f=e.liveMissingPositions.map(t=>t.name).filter(Boolean),b=f.slice(0,3).join(", "),y=Math.max(0,f.length-3),v=b?this.host._t("gs.optimize_live_names",{names:b,more:y?this.host._t("gs.optimize_reference_more",{n:String(y)}):""}):"",$=e.unverifiedPositions.some(t=>"registry_unavailable"===t.reason),w=t=>e.removedPositions.some(e=>e.id===t.id)?this.host._t("gs.optimize_detail_removed"):e.liveMissingPositions.some(e=>e.id===t.id)?this.host._t("gs.optimize_detail_live"):this.host._t("gs.optimize_detail_unverified"),k=t=>this.host._t("room_label"===t?"gs.optimize_detail_room_label":"group"===t?"gs.optimize_detail_group":"device"===t?"gs.optimize_detail_device":"gs.optimize_detail_unknown"),x=[...e.removedPositions,...e.liveMissingPositions.filter(t=>!e.removedPositions.some(e=>e.id===t.id)),...e.unverifiedPositions],S=x.slice(0,10),M=Math.max(0,x.length-S.length);return o`{this.host._alignDialog=null,this.host._preflightClipboardFallback=null}}> +
+ ${s?o` +

${this.host._t("gs.align_preflight_failed",{spaces:r,more:h})}

+ ${i.slice(0,10).map(t=>o`

+ ${t.displayName}: ${this.host._t(`gs.preflight_reason_${t.reason}`)} +

`)} + ${i.length>10?o`

+ ${this.host._t("gs.align_preflight_more",{n:String(i.length-10)})} +

`:a} +
${this.host._t("gs.align_preflight_hint")}
+ ${this._preflightVersionsDiffer()?o` +
${this.host._t("gs.preflight_update_hint")}
`:a} +
+ +
+ ${this.host._preflightClipboardFallback?o`
+ ${this.host._t("gs.preflight_copy")} +
${this.host._preflightClipboardFallback}
+
`:a}`:t.changed?o` + ${e.moved?o`

${this.host._t("gs.align_count",{n:String(e.moved),total:String(e.total),cm:String(t.cm)})}

`:a} + ${e.latticeCoordinatesCanonicalized?o` +

${this.host._t("gs.optimize_lattice_summary",{n:String(e.latticeCoordinatesCanonicalized),cm:Ss(e.latticeMaxShiftCm)})}

+ ${e.latticeSpaces.map(t=>o`

${this.host._t("gs.optimize_lattice_space",{space:t.space,n:String(t.canonicalized),far:String(t.far)})}

`)} + `:a} + ${t.where?o`

${this.host._t("gs.align_where",{s:t.where})}

`:a} + ${e.rotated?o`

${this.host._t("gs.align_turned",{n:String(e.rotated)})}

`:a} + ${e.removedDrafts?o`

${this.host._t("gs.align_removed_drafts",{n:String(e.removedDrafts)})}

`:a} + ${e.redundantDraftsRemoved?o`

${this.host._t("gs.optimize_redundant_drafts",{n:String(e.redundantDraftsRemoved)})}

`:a} + ${e.wallSegmentsMigrated?o`

${this.host._t("gs.wall_segments_migrated",{n:String(e.wallSegmentsMigrated)})}

`:a} + ${e.legacyZeroWallsMigrated?o`

${this.host._t("gs.zero_walls_migrated",{n:String(e.legacyZeroWallsMigrated)})}

`:a} + ${d?o`

${this.host._t("gs.optimize_changes",{m:String(e.migrated),c:String(e.canonicalized),p:String(e.coordsCanonicalized),w:String(e.wallsMerged),s:String(e.spansMerged),i:String(e.partitionsMerged)})}

`:a} + ${e.partitionsReconciled?o`

${this.host._t("gs.optimize_coincident_partitions",{n:String(e.partitionsReconciled)})}

`:a} + ${e.openingsRehosted?o`

${this.host._t("gs.optimize_openings_rehosted",{n:String(e.openingsRehosted)})}

`:a} + ${e.wallsStraightened?o`

${this.host._t("gs.optimize_walls_straightened",{n:String(e.wallsStraightened),cm:String(_)})}

`:a} + ${m?o`

${this.host._t("gs.optimize_walls_straightened_where",{s:m})}

`:a} + ${e.glowSpacesMigrated||e.glowRoomsMigrated?o`

${this.host._t("gs.optimize_glow_migration",{spaces:String(e.glowSpacesMigrated),rooms:String(e.glowRoomsMigrated)})}

`:a} + ${p?o`
${this.host._t("gs.align_warn")}
`:a}`:o`

${this.host._t(e.liveMissingPositions.length||e.unverifiedPositions.length||e.nestedRefsUnresolved?"gs.optimize_no_automatic_changes":"gs.align_none")}

`} + ${!s&&e.wallsStraightenSkipped?o`

${this.host._t("gs.optimize_walls_straighten_skipped",{n:String(e.wallsStraightenSkipped)})}

`:a} + ${c?o`

${this.host._t("gs.optimize_references",{spaces:String(e.spaceRefsRemapped),rooms:String(e.roomRefsRemapped),positions:String(e.positionsRemapped),detached:String(e.markersDetached)})}

`:a} + ${g?o`

${this.host._t("gs.optimize_orphans_removed",{total:String(g),rooms:String(e.orphanRoomLabelsRemoved),devices:String(e.orphanDevicePositionsRemoved),groups:String(e.orphanGroupPositionsRemoved)})}

`:a} + ${e.liveMissingPositions.length?o`
+

${this.host._t(t.removeLiveMissingPositions?"gs.optimize_live_positions_remove":"gs.optimize_live_positions",{n:String(e.liveMissingPositions.length),names:v})}

+ + ${t.removeLiveMissingPositions?o`
+ ${this.host._t("gs.optimize_live_selected")} +
`:a} +
`:a} + ${e.unverifiedPositions.length?o``:a} + ${e.nestedRefsUnresolved?o``:a} + ${x.length?o`
+ ${this.host._t("gs.optimize_details")} +
    + ${S.map(t=>o`
  • ${this.host._t("gs.optimize_detail_item",{status:w(t),kind:k(t.kind),id:t.id,space:t.spaceId})}
  • `)} +
+ ${M?o`
${this.host._t("gs.optimize_details_more",{n:String(M)})}
`:a} +
`:a} +
+
+ + + ${t.changed&&t.preflight?.ok?o` + `:a} +
+
`}_renderSettingsDialog(){return o`this.host._settingsDialog=null}> +
+
${this.host._t("gs.hint")}
+ + ${this._renderColorRow("light_on","gs.light_on")} + ${this._renderColorRow("light_off","gs.light_off")} + ${this._renderColorRow("light_none","gs.light_none")} + + ${this._renderColorRow("temp_cold","gs.temp_cold")} + ${this._renderColorRow("temp_ok","gs.temp_ok")} + ${this._renderColorRow("temp_hot","gs.temp_hot")} + + ${this._renderColorRow("lqi_low","gs.lqi_low")} + ${this._renderColorRow("lqi_high","gs.lqi_high")} + + ${this._renderColorRow("glow_base","gs.glow_base")} + ${this._renderColorRow("glow_light","gs.glow_light")} +
+ ${this.host._t("gs.glow_radius")} + {const e=sl(t.target.value);null!=e&&e>0&&(this.host._settingsDialog={...this.host._settingsDialog,glowRadius:e})}} /> + ${this.host._imperial?this.host._t("gs.unit_ft"):this.host._t("gs.unit_m")} +
+ + ${this._renderColorRow("wall_fill","gs.wall_fill")} + +
+ ${this.host._t("gs.bg_mode")} + +
+ ${"static"===this.host._settingsDialog.bgMode?o`
+ {this.host._settingsDialog={...this.host._settingsDialog,bgColor:t.detail.color}}}> + ${this.host._settingsDialog.bgColor?o``:o`${this.host._t("gs.bg_theme")}`} +
`:o`
${this.host._t("gs.bg_daynight_hint")}
`} + + ${Ms(this.host.hass)?a:o`
${this.host._t("gs.sun_missing")}
`} +
+ ${this.host._renderCompass()} +
+ ${this.host._t("gs.north")} +
+ {const e=t.target.value.trim(),s=""===e?null:Math.round(Number(e));this.host._settingsDialog={...this.host._settingsDialog,northDeg:null!==s&&Number.isFinite(s)?Math.min(359,Math.max(0,s)):null}}} /> + ${null!==this.host._settingsDialog.northDeg?o``:a} +
+ ${null===this.host._settingsDialog.northDeg?o`
${this.host._t("gs.north_hint")}
`:a} +
+
+ + ${this.host._canEdit?o` + +
${this.host._t("gs.backup_hint")}
+
+ + + + this._pickBackupImport(t)} /> + + ${this.host._canOptimizeUndo&&"import"===this.host._undoKind?o` + `:a} +
`:a} + +
${this.host._t("gs.grid_hint")}
+
+ +
+ ${this.host._canOptimizeUndo&&"import"!==this.host._undoKind?o`
+ +
`:a} + +
${this.host._t("gs.about_version",{v:Xr})}
+ + ${this.host._t("gs.about_github")} + + ${this.host._t("gs.about_telegram")} +
+
+ + + + +
+
`}_rulesSet(t){this.host._rulesDialog={...this.host._rulesDialog,rules:t}}async _saveRules(){const t=this.host._rulesDialog;if(!t||t.busy)return;const e=t.rules.filter(t=>t.pattern.trim()&&t.icon.trim());this.host._rulesDialog={...t,busy:!0};try{const t=this.host._serverCfg,s=JSON.stringify(e)===JSON.stringify(Ct),i={...t.settings};s?delete i.icon_rules:i.icon_rules=e,this.host._serverCfg={...t,settings:i},await this._saveConfigNow(),this.host._rulesDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("rules.saved"))}catch(t){this.host._rulesDialog&&(this.host._rulesDialog={...this.host._rulesDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_renderRulesDialog(){const t=this.host._rulesDialog,e=Ds(t.rules),s=t.test.trim()?Cs(t.test,"",e):null,i=(e,s)=>{const i=[...t.rules],o=e+s;o<0||o>=i.length||([i[e],i[o]]=[i[o],i[e]],this._rulesSet(i))};return o`this.host._rulesDialog=null}> +
+
${this.host._t("rules.hint")}
+
+ this.host._rulesDialog={...t,test:e.target.value}} /> + ${s?o`${s}`:a} +
+ ${t.rules.map((e,s)=>{const a=""!==e.pattern.trim()&&!Ps(e.pattern);return o`
+ {const o=[...t.rules];o[s]={...e,pattern:i.target.value},this._rulesSet(o)}} /> + {const o=[...t.rules];o[s]={...e,icon:i.target.value},this._rulesSet(o)}} /> + + i(s,-1)}> + i(s,1)}> + this._rulesSet(t.rules.filter((t,e)=>e!==s))}> +
`})} + +
+
+ + + + +
+
`}_saveKioskScale(t){this.host._kioskScale={...this.host._kioskScale,...t};try{localStorage.setItem("houseplan_card_kiosk_v1",JSON.stringify(this.host._kioskScale))}catch{}this.host.requestUpdate()}_renderKioskDialog(){const t=this.host._kioskScale,e=(e,s)=>o` +
+ ${this._rangeInput(50,300,5,Math.round(100*t[e]),t=>this._saveKioskScale({[e]:t/100}))} + ${Math.round(100*t[e])}% +
`;return o`this.host._kioskDialog=!1}> +
+
${this.host._t("kiosk.hint")}
+ ${e("icon",this.host._t("kiosk.icon_scale"))} + ${e("font",this.host._t("kiosk.font_scale"))} +
+
+ + + +
+
`}_renderVacSection(t){const e=this.host._devices.find(e=>e.id===t.devId);if(!e||!this.host._isVacDev(e))return a;const s=e.marker?.vacuum||{},i=this.host._vacAllCamerasFor===e.id,n=this.host._vacSourceResolution(e,i),r=n.entityId,l=n.candidates.find(t=>t.entityId===r)||null,h=r?Is(this.host.hass?.states[r]?.attributes):null,c=!1!==s.live&&("ok"===n.status||"unsupported"===n.status),d=this._vacPlanRoomAnchors(e.space),p=h?Ts(h.rooms,d.map(t=>t.name)):0,_=!!(c&&h&&p>=3),u=Object.keys(s.calibration||{}),m=t=>{const s=this.host._vacEnsureMarker(e);s&&(s.vacuum={...s.vacuum||{},...t},this.host._regSignature="",this.host._maybeRebuildDevices(),this._saveConfig(),this.host.requestUpdate())},g=new Set(e.entities||[]),f=n.candidates.filter(t=>g.has(t.entityId)||t.entityId===s.source),b=i?n.candidates.filter(t=>t.entityId.startsWith("camera.")&&!f.some(e=>e.entityId===t.entityId)):[],y=t=>[t.hasPosition?this.host._t("vac.cap_position"):"",t.hasRooms?this.host._t("vac.cap_rooms_short"):"",t.hasPath?this.host._t("vac.cap_path"):"",t.hasMapId?this.host._t("vac.cap_map"):""].filter(Boolean).join(" · ")||this.host._t("vac.cap_none"),v=t=>o` + `,$=n.candidates.some(t=>g.has(t.entityId)&&"known_xcme_incomplete"===t.category)||!!n.pinned&&!!r?.startsWith("camera.")&&!l?.hasPosition;return o` + +
+
+
${this.host._t("vac.diag_source")}${r||this.host._t("vac.source_none")}
+ ${l?.platform?o`
${this.host._t("vac.diag_platform")}${l.platform}
`:a} +
${this.host._t("vac.diag_status")}${this.host._t(`vac.source_status_${n.status}`)}
+
${this.host._t("vac.diag_position")}${h?.pos?this.host._t("common.yes"):this.host._t("common.no")}
+
${this.host._t("vac.diag_rooms")}${Rs(this.host._t("vac.diag_rooms_value"),{total:String(h?.rooms.length||0),matched:String(p),readiness:this.host._t(p>=3?"vac.autocal_ready":"vac.autocal_not_ready")})}
+
${this.host._t("vac.diag_path")}${h?.path.length?this.host._t("common.yes"):this.host._t("common.no")}
+
${this.host._t("vac.diag_map")}${h?.mapId??"default"}
+
+ ${"missing"===n.status||"disabled"===n.status||"unverified"===n.status?o`
+ ${this.host._t(`vac.source_banner_${n.status}`)} + +
`:a} + ${$?o`
+ ${this.host._t("vac.xcme_hint")} +
attributes:
+  - vacuum_position
+  - rooms
+  - path
+  - map_name
+
`:a} +
+ ${this.host._t("vac.choose_source")} +
+ + ${f.map(v)} +
{t.currentTarget.open?this.host._vacOpenAllCameras(e):(this.host._vacAllCamerasFor=null,this.host._vacAllCameraCache=null)}}> + ${this.host._t("vac.all_cameras")} +
${this.host._t("vac.all_cameras_warn")}
+ ${i?b.length?b.map(v):o`
${this.host._t("vac.all_cameras_empty")}
`:a} +
+
+
+
+ ${_?o``:a} + ${c?o``:a} + ${this.host._t("vac.documentation")} +
+ ${h?o` + + + + ${u.length?o`
${Rs(this.host._t("vac.cal_maps"),{maps:u.join(", ")})}
`:a} + `:a} +
`}_vacMapId(t,e,s=this.host._planHass){const i=this.host._vacEntity(t),o=i?s?.states?.[i]?.attributes?.selected_map:null;return Ns(e.mapId,o)}_vacSaveMatrix(t,e,s,i){const o=this.host._devices.find(e=>e.id===t),a=o?this.host._vacEnsureMarker(o):this.host._serverCfg?.markers?.find(e=>e.id===t);if(!a)return!1;const n={...a.vacuum||{}};return n.source=e,n.calibration={...n.calibration||{},[s]:i.map(t=>Number(t.toFixed(6)))},a.vacuum=n,this.host._regSignature="",this.host._maybeRebuildDevices(),this._saveConfig(),this.host.requestUpdate(),!0}_vacPlanRoomAnchors(t){return(this.host._spaceModelById(t)?.rooms||[]).map(t=>({room:t,poly:R(t)})).filter(({room:t,poly:e})=>t.name&&e).map(({room:t,poly:e})=>{const s=zs(e);return s?{name:String(t.name),cx:s[0],cy:s[1]}:null}).filter(Boolean)}_vacAutoCalibrate(t){const e=this.host._vacSource(t),s=e?Is(this.host.hass?.states[e]?.attributes):null;if(!e||!s||s.rooms.length<3)return void this.host._showToast(this.host._t("vac.autocal_no_rooms"));const i=this._vacPlanRoomAnchors(t.space),o=As(s.rooms,i);if(!o)return void this.host._showToast(this.host._t("vac.autocal_no_match"));const a=this.host._serverCfg?.spaces?.find(e=>e.id===t.space),n=Number(a?.cell_cm),r=Number.isFinite(n)&&n>0?n:5,l=Os(o.residual,this.host._gridPitch,r),h=this._vacMapId(t,s);l>Ls?this.host._vacCalConfirm={markerId:t.id,source:e,mapId:h,matrix:o.matrix,rooms:o.matched.length,error:ee(l,"mi"===this.host.hass?.config?.unit_system?.length)}:this._vacSaveMatrix(t.id,e,h,o.matrix)&&this.host._showToast(Rs(this.host._t("vac.autocal_done"),{rooms:String(o.matched.length)}))}_vacApplyCalibrationProposal(t){const e=this.host._vacCalConfirm;if(e){if(this.host._vacCalConfirm=null,t){const t=this.host._devices.find(t=>t.id===e.markerId),s=Es(e.matrix);if(!t||!s)return;if(this.host._markerDialog=null,t.space!==this.host._space&&!this.host._commitSpace(t.space))return;return void(this.host._vacFit={markerId:e.markerId,source:e.source,mapId:e.mapId,p:s,drag:null})}this._vacSaveMatrix(e.markerId,e.source,e.mapId,e.matrix)&&this.host._showToast(Rs(this.host._t("vac.autocal_done"),{rooms:String(e.rooms)}))}}_vacStartFit(t){const e=this.host._vacSource(t),s=e?Is(this.host.hass?.states[e]?.attributes):null;if(!e||!s)return void this.host._showToast(this.host._t("vac.cal_need_pos"));const i=this._vacMapId(t,s),o=t.marker?.vacuum?.calibration?.[i],a=this.host._spaceModelById(t.space);if(!a)return;const n=a.vb,r=o&&6===o.length&&Es(o)||Bs(s.rooms,n);this.host._markerDialog=null,(t.space===this.host._space||this.host._commitSpace(t.space))&&(this.host._vacFit={markerId:t.id,source:e,mapId:i,p:r,drag:null})}_vacFitSave(){const t=this.host._vacFit;if(!t)return;const e=this._vacSaveMatrix(t.markerId,t.source,t.mapId,Hs(t.p));this.host._vacFit=null,e&&this.host._showToast(this.host._t("vac.cal_done"))}_vacFitTurn(t){const e=this.host._vacFit;if(!e)return;const s=Is(this.host.hass?.states[e.source]?.attributes),i=this._vacGhostCentre(s?.rooms||[]),o={...e.p,...t};this.host._vacFit={...e,p:Gs(o,e.p,i[0],i[1])}}_vacGhostCentre(t){const e=[],s=[];for(const i of t)e.push(i.x0??i.cx,i.x1??i.cx),s.push(i.y0??i.cy,i.y1??i.cy);return e.length?[(Math.min(...e)+Math.max(...e))/2,(Math.min(...s)+Math.max(...s))/2]:[0,0]}_vacDelta(t,e,s){const i=this.host._stageEl,o=i?.clientWidth||1,a=i?.clientHeight||1;return[e/o*t.w,s/a*t.h]}_vacFitPointer(t,e){const s=this.host._vacFit;if(!s)return;if(t.stopPropagation(),"pointerdown"===t.type){const e=t.target,i=e.getAttribute?.("data-corner");try{t.currentTarget.setPointerCapture?.(t.pointerId)}catch{}return void(this.host._vacFit={...s,drag:i?{kind:"scale",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:Number(i.split(",")[0]),fy:Number(i.split(",")[1])}:{kind:"move",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:0,fy:0}})}const i=s.drag;if(i){if("pointermove"===t.type){const[o,a]=this._vacDelta(e,t.clientX-i.sx,t.clientY-i.sy);if("move"===i.kind)this.host._vacFit={...s,p:{...i.p0,ox:i.p0.ox+o,oy:i.p0.oy+a}};else{const t=Is(this.host.hass?.states[s.source]?.attributes),e=this._vacGhostCentre(t?.rooms||[]),n=Hs(i.p0),[r,l]=Ws(n,e[0],e[1]),[h,c]=Ws(n,i.fx,i.fy),d=Math.hypot(r-h,l-c)||1,[p,_]=[2*r-h,2*l-c],u=Math.hypot(p+2*o-h,_+2*a-c)/2,m=Math.max(.05,u/d),g={...i.p0,s:i.p0.s*m};this.host._vacFit={...s,p:Gs(g,i.p0,i.fx,i.fy)}}return}"pointerup"!==t.type&&"pointercancel"!==t.type||(this.host._vacFit={...s,drag:null})}}_renderVacFit(t){const e=this.host._vacFit;if(!e)return a;const s=Is(this.host._renderPlanHass?.states?.[e.source]?.attributes);if(!s)return a;const i=Hs(e.p),n=[],r=[],l=[];for(const t of s.rooms){if(null==t.x0)continue;const e=[[t.x0,t.y0],[t.x1,t.y0],[t.x1,t.y1],[t.x0,t.y1]].map(([t,e])=>Ws(i,t,e));e.forEach(([t,e])=>{r.push(t),l.push(e)});const[s,o]=Ws(i,t.cx,t.cy);n.push(ce` + ${t.name}`)}let h=a;if(s.pos){const[e,o]=Ws(i,s.pos.x,s.pos.y);h=ce``}const c=[];if(r.length){const e=(()=>{const t=i[0]*i[4]-i[1]*i[3];return(e,s)=>[(i[4]*(e-i[2])-i[1]*(s-i[5]))/t,(-i[3]*(e-i[2])+i[0]*(s-i[5]))/t]})(),s=Math.min(...r),o=Math.max(...r),a=Math.min(...l),n=Math.max(...l),h=.022*t.w,d=h/4;for(const[t,i,r,l]of[[s,a,o,n],[o,a,s,n],[o,n,s,a],[s,n,o,a]]){const s=e(r,l);c.push(ce` + `)}}return o`this._vacFitPointer(e,t)} + @pointermove=${e=>this._vacFitPointer(e,t)} + @pointerup=${e=>this._vacFitPointer(e,t)} + @pointercancel=${e=>this._vacFitPointer(e,t)}>${n}${h}${c}`}_resetRoomDialogFields(){this.host._roomEditId=null,this.host._roomFill="",this.host._roomCustomFill=null,this.host._roomTempSrc="",this.host._roomHumSrc="",this.host._roomSrcOpen=null,this.host._roomSrcFilter="",this.host._roomNameScale=1,this.host._roomLabelScale=1}_openRoomEdit(t){if(!t.id)return;this.host._roomEditId=t.id,this.host._nameSel=t.name||"",this.host._areaSel=t.area||"",this.host._roomFill="glow"===t.settings?.fill_mode?"":t.settings?.fill_mode||"";const e=t.settings?.custom_fill;this.host._roomCustomFill=e&&"object"==typeof e?_s(e,ps(this.host._curSpaceCfg).customFill):null,this.host._roomTempSrc=t.settings?.temp_source||"",this.host._roomHumSrc=t.settings?.hum_source||"",this.host._roomNameScale=js(t.settings?.name_scale),this.host._roomLabelScale=js(t.settings?.label_scale),this.host._roomSrcOpen=null,this.host._roomSrcFilter="",this.host._roomDialog=!0}_roomSettingsFromDialog(){const t={};return this.host._roomFill&&(t.fill_mode=this.host._roomFill),this.host._roomCustomFill&&(t.custom_fill=this.host._roomCustomFill),this.host._roomTempSrc&&(t.temp_source=this.host._roomTempSrc),this.host._roomHumSrc&&(t.hum_source=this.host._roomHumSrc),1!==this.host._roomNameScale&&(t.name_scale=this.host._roomNameScale),1!==this.host._roomLabelScale&&(t.label_scale=this.host._roomLabelScale),Object.keys(t).length?t:null}_saveRoomEdit(){const t=this.host._curSpaceCfg,e=t?.rooms.find(t=>t.id===this.host._roomEditId);if(!e)return this.host._roomDialog=!1,void(this.host._roomEditId=null);e.name=this.host._nameSel.trim()||e.name,e.area=this.host._areaSel||null;const s=e.settings||{},i={...s};this.host._roomFill?i.fill_mode=this.host._roomFill:delete i.fill_mode,this.host._roomCustomFill?i.custom_fill=this.host._roomCustomFill:delete i.custom_fill,"glow"===s.fill_mode&&"boolean"!=typeof s.glow&&(i.glow=!0),this.host._roomTempSrc?i.temp_source=this.host._roomTempSrc:delete i.temp_source,this.host._roomHumSrc?i.hum_source=this.host._roomHumSrc:delete i.hum_source,1!==this.host._roomNameScale?i.name_scale=this.host._roomNameScale:delete i.name_scale,1!==this.host._roomLabelScale?i.label_scale=this.host._roomLabelScale:delete i.label_scale,Object.keys(i).length?e.settings=i:delete e.settings,this._saveConfig(),this.host._roomDialog=!1,this.host._roomEditId=null,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._showToast(this.host._t("toast.room_updated"))}_roomSrcCandidates(){const t=this.host._planHass,e=x(this.host._markers),s=this.host._roomSrcFilter.trim().toLowerCase(),i=[];for(const o of Object.values(t.devices)){if("service"===o.entry_type)continue;if(e.devices.has(o.id))continue;const t=(o.name_by_user||o.name||o.id).trim();s&&!t.toLowerCase().includes(s)||i.push({value:"device:"+o.id,label:t,sub:o.model||this.host._t("marker.sub_device")})}for(const[o,a]of Object.entries(t.entities)){if(!o.startsWith("sensor.")||a.hidden)continue;if(S(t,o,e))continue;const n=a.name||t.states[o]?.attributes?.friendly_name||o;s&&!(n+" "+o).toLowerCase().includes(s)||i.push({value:"entity:"+o,label:n,sub:o})}return i.sort((t,e)=>t.label.localeCompare(e.label)),i.slice(0,200)}_roomSrcLabel(t){const e=t.indexOf(":"),s=t.slice(0,e),i=t.slice(e+1);return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i}_labelPos(t,e){const s=this.host._layout["rl_"+(t.id||"")];if(s&&s.s===e)return{x:s.x*ol,y:s.y*ol};const i=this._snap(this.host._roomCenter(t));return{x:i[0],y:i[1]}}_labelDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=this._labelPos(e,s);this.host._drag={id:"rl_"+(e.id||""),sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},nl(t),this.host._tip=null}_labelMove(t,e,s){const i="rl_"+(e.id||"");if(!this.host._drag||this.host._drag.id!==i)return;const o=this.host._stageEl;if(!o)return;const a=this.host._spaceModelById(s);if(!a)return;const n=a.vb,r=o.getBoundingClientRect(),l=this.host._viewOr(n),h=(t.clientX-this.host._drag.sx)/r.width*l.w,c=(t.clientY-this.host._drag.sy)/r.height*l.h;Math.abs(t.clientX-this.host._drag.sx)+Math.abs(t.clientY-this.host._drag.sy)>3&&(this.host._drag.moved=!0);const d=Rt(this.host._drag.ox+h),p=Rt(this.host._drag.oy+c);this.host._savePos({id:i,space:s},d,p)}_labelUp(t){const e="rl_"+(t.id||"");if(!this.host._drag||this.host._drag.id!==e)return;const s=this.host._drag.moved;this.host._drag=s?this.host._drag:null,s&&window.setTimeout(()=>this.host._drag=null,0)}_labelScale(t){const e=this.host._layout["rl_"+(t.id||"")]?.k;return"number"==typeof e&&Number.isFinite(e)?Math.min(3,Math.max(.5,e)):1}_rlResizeDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=t.target.closest(".roomlabel");if(!i)return;const o=i.getBoundingClientRect(),a=o.left+o.width/2,n=o.top+o.height/2,r=Math.max(8,Math.hypot(t.clientX-a,t.clientY-n));this.host._rlResize={id:"rl_"+(e.id||""),space:s,k0:this._labelScale(e),cx:a,cy:n,d0:r},nl(t)}_rlResizeMove(t){const e=this.host._rlResize;if(!e)return;t.stopPropagation();const s=Math.max(8,Math.hypot(t.clientX-e.cx,t.clientY-e.cy)),i=Math.min(3,Math.max(.5,e.k0*(s/e.d0))),o=this.host._layout[e.id];if(o)this.host._layout={...this.host._layout,[e.id]:{...o,k:i}};else{const t=e.id.slice(3),s=this.host._spaceModelById(e.space);if(!s)return;const o=s.rooms.find(e=>e.id===t);if(!o)return;const a=this._labelPos(o,e.space);this.host._layout={...this.host._layout,[e.id]:{s:e.space,x:a.x/ol,y:a.y/ol,k:i}}}this.host._dirtyPos.add(e.id)}_rlResizeUp(){this.host._rlResize&&(this.host._rlResize=null,this.host._persistLayout())}_renderRoomGear(t,e,s){if(!t.id)return a;let i=null;if(t.poly?(i=this.host._gearPtCache.get(t.poly)||null,i||(i=re(t.poly),this.host._gearPtCache.set(t.poly,i))):null!=t.x&&null!=t.y&&(i=[t.x+(t.w||0)/2,t.y+(t.h||0)/2]),!i)return a;const n=(i[0]-s.x)/s.w*100,r=(i[1]-s.y)/s.h*100;return o``}_alignCandidates(){const t=[],e=this.host._spaceModel();if(this.host._markup){if(!e)return t;if(this.host._drag?.id.startsWith("rl_")){const s=this.host._drag.id.slice(3);for(const i of e.rooms){if(!i.name||i.id===s)continue;const e=this._labelPos(i,this.host._space);t.push([e.x,e.y])}return t}for(const s of e.rooms){const e=R(s);if(e)for(const s of e)t.push(s)}if("draw"===this.host._tool)for(const e of this.host._path)t.push(e);if("split"===this.host._tool&&this.host._splitSel?.pts)for(const e of this.host._splitSel.pts)t.push(e);return t}if("devices"===this.host._mode){for(const e of this.host._devices){if(e.space!==this.host._space||e.id===this.host._drag?.id||"ha_disabled"===e.bindingStatus?.kind)continue;const s=this.host._pos(e);t.push([s.x,s.y])}return t}if("decor"===this.host._mode){const e=this.host._decorMove?.id;return t.push(...this._decorSnapGeometry(e).points),this.host._decorDraft&&t.push(this.host._decorDraft.a),t}return t}_renderAlignGuides(){const t=this.host._alignPoint;if(!t)return ce``;const e=this.host._drag?.id.startsWith("rl_")?.5*this.host._gridPitch:.05*this.host._gridPitch,s=qs(t,this._alignCandidates(),e);if(!s.length)return ce``;const i=this.host._gridPitch,o=1.5*i;return ce` + ${s.map(e=>{const[s,a,n,r]="x"===e.axis?[e.at,e.from[1],e.at,t[1]+Math.sign(t[1]-e.from[1])*o]:[e.from[0],e.at,t[0]+Math.sign(t[0]-e.from[0])*o,e.at];return ce` + `})} + `}_renderOpeningCenterTick(t){const e=(t.angle+90)*Math.PI/180,s=ze(15,this.host._cellCm);return ce``}_renderOpeningDimensionGuides(t){const e=t.labels.flatMap(t=>t.dimension?[t.dimension]:[]);if(!e.length)return ce``;const s=this._cssPxToRender(4);return ce``}_renderOpeningPlacementPreview(){const t=this.host._openingPreview;if(!t)return ce``;const e={type:t.type,length:t.renderedLength,angle:t.angle,amount:Us(t.type,null),flipH:t.flipH,flipV:t.flipV,base:"var(--hp-open)",tone:"var(--hp-open)",cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,face:t.face},s="passage"===t.type?Ks(t,ze(this.host._gridPitch,this.host._cellCm)):null;return ce` + `}_renderOpeningDialog(){const t=this.host._openingDialog,e=this.host._spaceModel()?.partitions||[],s=t.id?this.host._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,i={id:t.id||"preview",type:t.type,x:t.x/ol,y:t.y/this.host._spaceH,angle:t.angle,length:s&&!t.lengthTouched?s.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/ol,...t.host?{host:t.host}:{}},n=qe(s,i),r=t.host?n?H(i,e,ol,this.host._cellCm,this.host._gridPitch):F(i,e,ol,this.host._cellCm,this.host._gridPitch):null,l="does-not-fit-jamb"===r?.reason,h=t.host?e.find(e=>e.id===t.host.id):null,c=h?ee(h.cm/2,this.host._imperial):"",d=!!t.host&&!r?.resolved&&!l,p="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",_=(e,s)=>{const i="contact"===e?t.contact:t.lock,n="contact"===e?!!t.contactOpen:!!t.lockOpen,r="contact"===e?t.contactFilter||"":t.lockFilter||"",l=s.find(t=>t.value===i),h=l?.label||this.host.hass.states[i]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[i]?.name||i,c=Ii(s,r);return o` + + ${n?o`
+ this._filterOpeningEntities(e,t.target.value)} /> +
+ + ${c.map(t=>o` + `)} + ${c.length?a:o`
${this.host._t("marker.nothing_found")}
`} +
+
`:a}`};return o`this.host._openingDialog=null}> +
+ ${t.host?o` +
+ ${d||l?o``:a} + ${d?this.host._t("opening.partition_orphan"):l?this.host._t("opening.partition_jamb_margin",{distance:c}):this.host._t("opening.host_partition")} +
`:a} + + + + + + + + {const s=sl(e.target.value);null!=s&&(this.host._openingDialog={...t,lengthCm:s,lengthTouched:!0})}} /> + + ${"passage"===t.type&&(t.contact||t.lock)?o`
+ + ${this.host._t("opening.passage_binding_warning")} +
`:a} + + ${"passage"!==t.type?o` + ${_("contact",this._contactCandidates())} + ${t.contact?o``:a}`:a} + + ${"door"===t.type||"gate"===t.type?o` + ${_("lock",this._lockCandidates())}`:a} + + ${"gate"!==t.type&&"passage"!==t.type?o``:a} + ${"passage"!==t.type?o``:a} +
+ +
`}_gridLevels(){const t=this.host._stageEl,e=this.host._viewOr(this.host._baseVb()),s=t&&t.clientWidth&&e.w?t.clientWidth/e.w:1;return Ys(this.host._gridPitch,s)}_renderMarkupDefs(t){const e=this._gridLevels();if(!e)return ce``;const s=this.host._gridPitch*e.fine,i=this.host._gridPitch*e.coarse,o=this.host._gridPitch*e.fine*.14;return ce` + + + + + + + + + + + + + + `}_renderPhysicalEditorLayer(){const t=this.host._spaceModel();if(!t)return ce``;const e=this.host._gridPitch,s=this.host._viewOr(this.host._baseVb()),i=this.host._stageEl,o=i?.clientWidth?s.w/i.clientWidth:e/8,n=Math.max(.22*e,8*o),r=Math.max(n,12*o),l=t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`,h=(t,e)=>this.host._physicalSel?.kind===t&&this.host._physicalSel.id===e||"column"===t&&this.host._duplicateColumnId===e,c=(t.room_drafts||[]).flatMap(t=>t.points.slice(0,-1).map((e,s)=>{const i=t.points[s+1],a=Number(t.segments[s]?.cm),n=j(Number.isFinite(a)?a:15,this.host._cellCm,this.host._gridPitch);return ce`{this.host._physicalSel={kind:"draft",id:t.id,segment:s},this._registerPhysicalTap("draft",t.id,s)}}>`})),d=(t.partitions||[]).map(t=>{const e=Yt(t.a,t.b,t.cm,this.host._cellCm,this.host._gridPitch);return e?ce`this._physicalDown(e,"partition",t.id)} + @pointermove=${t=>this._physicalMove(t)} + @pointerup=${t=>this._physicalUp(t)}>`:ce`this._physicalDown(e,"partition",t.id)} + @pointermove=${t=>this._physicalMove(t)} + @pointerup=${t=>this._physicalUp(t)}>`}),p=(t.wall_columns||[]).map(t=>{const e=this.host._physicalRotate?.id===t.id?{...t,angle:this.host._physicalRotate.angle}:t,s=Jt(e,this.host._cellCm,this.host._gridPitch);return ce`this._physicalDown(e,"column",t.id)} + @pointermove=${t=>this._physicalMove(t)} + @pointerup=${t=>this._physicalUp(t)}>`}),_=this.host._physicalDrag,u=(()=>{if(!_?.moved)return a;if("partition"===_.kind&&0===Number(_.base.cm)){const t=_.base;return ce``}const t="partition"===_.kind?Yt(_.base.a,_.base.b,_.base.cm,this.host._cellCm,this.host._gridPitch):Jt(_.base,this.host._cellCm,this.host._gridPitch);return t?ce``:a})(),m=(()=>{const s=this.host._physicalSel;if(!s)return a;if("draft"===s.kind){const e=t.room_drafts.find(t=>t.id===s.id);return e?ce` + t.join(",")).join(" ")}> + ${e.points.map(t=>ce``)} + `:a}if("partition"===s.kind){const e=t.partitions.find(t=>t.id===s.id);if(!e)return a;const i=Yt(e.a,e.b,e.cm,this.host._cellCm,this.host._gridPitch),o=(e.a[0]+e.b[0])/2,r=(e.a[1]+e.b[1])/2;return ce` + ${i?ce``:ce``} + + + + `}const i=t.wall_columns.find(t=>t.id===s.id);if(!i)return a;const h=this.host._physicalRotate?.id===i.id?{...i,angle:this.host._physicalRotate.angle}:i,c=Jt(h,this.host._cellCm,this.host._gridPitch);if("square"!==h.shape)return ce` + + + `;const d=j(h.cm,this.host._cellCm,this.host._gridPitch),p=At(h.angle)*Math.PI/180,_=Math.sin(p),u=-Math.cos(p),m=[h.center[0]+_*d/2,h.center[1]+u*d/2],g=[m[0]+_*Math.max(e,24*o),m[1]+u*Math.max(e,24*o)];return ce` + + + + this._physicalRotateDown(t,i)} + @pointermove=${t=>this._physicalRotateMove(t)} + @pointerup=${t=>this._physicalRotateUp(t)}> + `})();return ce`${c}${d}${p}${u}${m}`}_renderHiddenWallDiagnosticOverlay(){if(!this.host._markup)return ce``;const t=this._hiddenWallDiagnosticSnapshot().value;if(!t.segments.length)return ce``;const e=j(5,this.host._cellCm,this.host._gridPitch);return ce``}_renderPlanSnapOverlay(){if(!this.host._markup)return ce``;const t=this._planSnapGeometrySnapshot().value,e=this.host._activePlanSnapCandidate,s=new Set(this.host._activePlanSnapConflicts.map(t=>t.key)),i=j(5,this.host._cellCm,this.host._gridPitch),o=j(10,this.host._cellCm,this.host._gridPitch);return ce``}_syncPlanSnapActiveMarker(t){const e=this.host.renderRoot?.querySelector('[data-hp="plan-snap-active-marker"]');if(e){if(e.setAttribute("class",`plan-snap-node${t?" active":""}${"line"===t?.kind?" dynamic":""}`),e.setAttribute("data-active",t?"true":"false"),e.setAttribute("visibility",t?"visible":"hidden"),!t)return e.removeAttribute("data-kind"),void e.removeAttribute("data-key");e.setAttribute("data-kind",t.kind),e.setAttribute("data-key",t.key),e.setAttribute("cx",String(t.point[0])),e.setAttribute("cy",String(t.point[1])),e.setAttribute("r",String(j(10,this.host._cellCm,this.host._gridPitch)))}}_syncPlanSnapConflictMarkers(t){const e=new Set(t.map(t=>t.key));for(const t of this.host.renderRoot?.querySelectorAll('.plan-snap-node[data-kind="endpoint"]')||[])t.setAttribute("class","plan-snap-node"+(e.has(t.dataset.key||"")?" conflict":""))}_planSnapPhysicalSegment(t){let e=0;const s=this.host._spaceModel();if(!s)return null;if("partition"===t.sourceKind)e=Number(s.partitions.find(e=>e.id===t.sourceId)?.cm)||0;else if("draft"===t.sourceKind){const i=/^(.*):(\d+)$/.exec(t.sourceId),o=i?s.room_drafts.find(t=>t.id===i[1]):null;e=o&&i&&Number(o.segments[Number(i[2])]?.cm)||0}else e=Xs(s.rooms,this.host._spaceWalls,this.host._openCuts(),[t.a[0],t.a[1],t.b[0],t.b[1]],this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,ol);return e>0?{a:[...t.a],b:[...t.b],halfDepth:j(e,this.host._cellCm,this.host._gridPitch)/2}:null}_drawPreviewJoinPatchD(t,e){if(t.length<2)return"";const s=[];for(let i=0;i+10&&s.push({a:t[i],b:t[i+1],halfDepth:e[i]});if(!s.length)return"";const i=2e-4*this.host._gridPitch,o=this._planSnapGeometrySnapshot().value.segments.filter(e=>t.some(t=>C(t,[e.a[0],e.a[1],e.b[0],e.b[1]])<=i)).map(t=>this._planSnapPhysicalSegment(t)).filter(t=>!!t);return Zs([...s,...o],i).map(t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`).join(" ")}_renderMarkupLayer(t){const e=this.host._openCuts(),s=this.host._thickWallCuts(),i=e.concat(s),o=i.length?D(this.host._segments,i,.02*this.host._gridPitch):this.host._segments,n=this.host._path,r=this.host._gridPitch,l=this.host._viewOr(this.host._baseVb()),h="draw"===this.host._tool?this.host._drawWallCm:null,c=(()=>"draw"===this.host._tool&&n.length&&null!=h?this.host._contourClosed?n:this.host._cursorPt?[...n,this.host._cursorPt]:n.length>=2?n:null:null)(),d=c?Ra(c.length-1,this.host._contourClosed?[...this.host._draftSegmentCms,this.host._closingWallCm??void 0]:this.host._draftSegmentCms,h,A).map(t=>j(t,this.host._cellCm,this.host._gridPitch)/2):[],p=c?Qs(c,j(h,this.host._cellCm,this.host._gridPitch)/2,this.host._contourClosed,d):"",_=c?this._drawPreviewJoinPatchD(c,d):"",u=this.host._wallFaceBatch?.candidates[this.host._wallFaceBatch.index]?.repair||this.host._wallRepairDiagnostic;return ce` + ${this._gridLevels()?ce``:a} + ${o.map(t=>ce``)} + ${this._renderPhysicalEditorLayer()} + ${"column"===this.host._tool&&this.host._cursorPt&&this.host._drawWallCm?ce`{const t={shape:"square",center:this.host._cursorPt,cm:this.host._drawWallCm};return`M ${Jt(t,this.host._cellCm,this.host._gridPitch).map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`})()}>`:a} + ${p?ce` + `:a} + ${c&&0===h?ce`t.join(",")).join(" ")}>`:a} + ${_?ce` + `:a} + ${u?ce``:a} + ${"split"===this.host._tool&&this.host._splitSel?.pts?.length?ce`${this.host._splitSel.pts.length>1?ce``:a} + ${this.host._splitSel.pts.map((t,e)=>ce``)} + ${this.host._cursorPt?ce``:a}`:a} + `}_renderActiveChainInk(){const t=this.host._path,e=this.host._gridPitch;return ce` + ${t.length>1?ce``:a} + ${t.length&&this.host._cursorPt&&"draw"===this.host._tool&&!this.host._contourClosed?ce` + ${this.host._activePlanSnapCandidate||this.host._activePlanSnapConflicts.length?a:ce``}`:a} + ${t.map((t,s)=>ce``)} + `}_renderPartitionDeleteDialog(){const t=this.host._partitionDeleteDialog,e="mi"===this.host.hass?.config?.unit_system?.length;return o`this.host._partitionDeleteDialog=null}> +
+

${this.host._t("confirm.delete_partition_openings_body",{count:t.openings.length})}

+
    + ${t.openings.map(t=>o`
  • ${this.host._t("confirm.delete_partition_openings_item",{type:this.host._t(`opening.${t.type}`),length:ee(t.length*ol/this.host._gridPitch*this.host._cellCm,e)})}
  • `)} +
+
+
+ + + +
+
`}_renderRoomDeleteDialog(){const t=this.host._roomDeleteDialog;return o`this.host._roomDeleteDialog=null}> +
+

${this.host._t("confirm.delete_room_body")}

+
+
+ + + + +
+
`}_renderPhysicalDialog(){const t=this.host._physicalDialog,e="column"===t.kind;return o`this.host._physicalDialog=null}> +
+ ${e?o` + `:a} + +
this.host._physicalDialog={...t,cm:e.target.value}} /> + ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
+ ${e&&"square"===t.shape?o` + + this.host._physicalDialog={...t,angle:e.target.value}} />`:a} + ${t.length?o`
${this.host._t("physical.length")}: ${t.length}
`:a} +
+ +
`}_renderMarkupBar(){const t=this.host._geometryHistory.undoName,e=this.host._geometryHistory.redoName,s=t?this.host._t("history.undo_named",{name:t}):this.host._t("history.undo_empty"),i=e?this.host._t("history.redo_named",{name:e}):this.host._t("history.redo_empty");return o`
+
+ + + + + + + + + + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} + + + + +
+
+ +
+
`}_renderDevicesBar(){return o`
+
+ + + + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} +
+
+ +
+
`}_renderDeviceInbox(){const t=this.host._deviceInbox,e=this._deviceInboxRows(),s=Object.fromEntries(["on_plan","available","hidden","readd"].map(t=>[t,e.filter(e=>e.category===t).length])),i=function(t,e,s,i=!1){const o=s.trim().toLocaleLowerCase();return t.filter(t=>t.category===e&&(!i||t.isNew)&&(!o||t.searchText.includes(o)))}(e,t.tab,t.search,"on_plan"===t.tab&&t.onlyNew),n=i.slice(0,t.limit),r=t=>this.host._t(`device_inbox.tab_${t}`),l=`device_inbox.empty_${t.tab}`;return o`this.host._deviceInbox=null}> +
+
+ this.host._deviceInbox={...t,search:e.target.value,limit:100}} /> + +
+
this._deviceInboxTabKey(t)}> + ${["on_plan","available","hidden","readd"].map(e=>o` + `)} +
+
+ ${"on_plan"===t.tab?o``:a} + ${"available"===t.tab?o``:a} + +
+
+ ${n.length?n.map(t=>{const e="on_plan"===t.category?t.canFind?o``:o``:"hidden"===t.category?o``:o``,s="active"===t.status.kind?"":this.host._t(`device_inbox.status_${t.status.kind}`);return o`
+ +
+
${t.name} + ${t.isNew?o`${this.host._t("device_inbox.new")}`:a} +
+
+ ${[t.model,t.integration,t.spaceName,t.areaName].filter(Boolean).join(" · ")} +
+
+ ${this.host._t(`device_inbox.reason_${t.reason}`)} + ${s?o`${s}`:a} +
+ ${t.binding} +
+
+ ${e} + ${t.canEdit||t.canHide||"available"===t.category||"hidden"===t.category||this.host._bindingHasHaPage(t.binding)?o` +
+ + + +
+ ${t.canEdit&&("on_plan"!==t.category||t.canFind)?o``:a} + ${t.canHide?o``:a} + ${"available"===t.category?o``:a} + ${"hidden"===t.category?o``:a} + ${this.host._bindingHasHaPage(t.binding)?o``:a} +
+
`:a} +
+
`}):o`
${this.host._t(l)}
`} +
+ ${i.length>n.length?o``:a} +
+
+ +
+
`}_markerValueBadgeFields(t){return ti({touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition})}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=ns(t.room),s=Ze(t.binding,t.devId,()=>"__hp_device_preview__"),i=this.host._markers.find(e=>e.id===s||e.id===t.devId),o=ss(t.binding,t.controls,this.host._bindingEntities(t.binding)),a=this._effectiveStoredTapAction(t),n={id:s,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"===a&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:o.length?o:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=sl(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._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:i?.vacuum||null};return("virtual"===t.binding||t.room)&&(n.space=e?.space||("virtual"===t.binding?this.host._space:null),n.area=e?.area||null,n.room_id=e?.roomId||null),n}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const s=`${this.host._haRegistry.revision}\n${Et(this.host._markers)}\n${JSON.stringify(e)}`;if(this.host._markerPreviewMemo?.key===s)return this.host._markerPreviewMemo.device;const i=ei({hass:this.host.hass,registry:this.host._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this.host._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this.host._markers,settings:this.host._settings,excluded:this.host._excluded,showAll:this.host._showAll,firstSpaceId:this.host._model[0]?.id||this.host._space,loc:t=>this.host._t(t),iconRules:this.host._iconRules});return this.host._markerPreviewMemo={key:s,device:i},i}_markerPreviewDevices(t){const e=this.host._markerPreviewDevicesMemo;if(e?.base===this.host._devices&&e.preview===t)return e.devices;const s=[...this.host._devices.filter(e=>e.id!==t.id),t];return this.host._markerPreviewDevicesMemo={base:this.host._devices,preview:t,devices:s},s}_toggleIntent(t,e=this.host._devices){return si({hass:this.host._planHass,registryHass:this.host._fullRegistryHass,devices:e,device:t,virtualLights:this.host._virtualLights})}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s=this._markerPreviewDevices(e);return this._toggleIntent(e,s)}_toggleStateText(t,e){const s=this.host._planHass?.states?.[t]||this.host.hass?.states?.[t];try{return s&&"function"==typeof this.host.hass?.formatEntityState?this.host.hass.formatEntityState(s):e}catch{return e}}_toggleConfirmationStateText(t){const e=String(t.state||"unknown"),s=t.entityId?this._toggleStateText(t.entityId,e):e;if(s.trim().toLocaleLowerCase()!==e.trim().toLocaleLowerCase())return s;const i={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 i?this.host._t(i):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 ii(t,{state:t=>this._toggleConfirmationStateText(t),current:t=>this.host._t("confirm.current_state",{state:t}),expected:t=>this.host._t("confirm.expected_state",{state:t}),groupCurrent:(t,e)=>this.host._t("confirm.group_current",{on:t,total:e}),groupAllOn:()=>this.host._t("confirm.group_all_on"),groupAllOff:()=>this.host._t("confirm.group_all_off"),unavailable:t=>this.host._t("confirm.unavailable_targets",{count:t}),effect:t=>this.host._t(e[t]),expectedByHa:()=>this.host._t("confirm.expected_by_ha")})}_toggleHintLines(t){if(!t)return[];const e=t=>this.host._t(`marker.toggle_effect_${t.replace("-","_")}`),s=t=>this.host._t(`marker.toggle_skip_${t.replace("-","_")}`);return oi(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this.host._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),s=t.name||e;return this.host._t("marker.toggle_hint_single",{name:s,id:e})},group:t=>this.host._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,s)=>"virtual-light"===t.via?this.host._t("marker.virtual_light_current",{state:this.host._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(s)}):this.host._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(s)}),groupCurrentNext:(t,s)=>this.host._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(s)}),skipped:t=>this.host._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${s(t.reason)})`}).join(", ")}),none:t=>this.host._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:is(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),s=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},i="toggle"===s.tapAction?this._toggleHintLines(this._toggleIntentForDialog(s)).join(" "):"";return{...s,tapHintAnnouncement:i}}_valueBadgeForBinding(t,e){const s={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},i=this._markerPreviewDevice(s);if(!i)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const o=[...this.host._devices.filter(t=>t.id!==i.id),i],a=ts(this.host._planHass,i,o),n=es(this.host._planHass,i,a);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!n,valueBadgeSource:n,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s={...e,hidden:!1};return ai(ni(this.host._planHass,[...this.host._devices.filter(t=>t.id!==s.id),s],null,this.host._virtualLights).filter(t=>t.device.id===s.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},s=this._markerPreviewDevice(e);return!!s&&ri(this.host._planHass,{...s})}_setMarkerLightRole(t){const e=this.host._markerDialog;e&&(this.host._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.host.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this.host._planEntityAvailable(t)};const e=t.slice(7),s=this.host._markers.find(t=>t.id===e),i=this.host._devices.find(t=>t.id===e);if(!s||s.removed||!0!==s.is_light)return{label:this.host._t("marker.control_missing_label"),sub:`${this.host._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const o=this.host._serverCfg?.spaces.find(t=>t.id===(i?.space||s.space)),a=!!i&&li(i).length>0;return{label:s.name||i?.name||e,sub:[o?.title||i?.space||s.space,s.room_id||i?.area,a?"":this.host._t("marker.control_passive")].filter(Boolean).join(" · "),icon:s.icon||i?.icon||"mdi:lightbulb-outline",warning:!0===s.hidden||!0===i?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this.host._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this.host._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this.host._t("marker.value_badge_state",{name:t.label});const s=this.host.hass.states[e.entity_id]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this.host._t(`marker.value_badge_attr_${e.attribute}`,{name:s})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",s=[],i=new Set;for(const t of this.host._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this.host._bindingStatus(t.binding).kind)continue;const o=this.host._devices.find(e=>e.id===t.id);if(!o||o.hidden)continue;const a=this._controlRefInfo(`marker:${t.id}`);for(const t of li(o))i.add(t);s.push({value:`marker:${t.id}`,label:a.label,sub:a.sub,icon:a.icon,search:`${a.label} ${a.sub} ${t.id} ${li(o).join(" ")}`.toLowerCase()})}const o=Object.keys(this.host.hass.states||{}).filter(e=>hi(e)&&!i.has(e)&&ci(t.binding,[e],this.host._bindingEntities(t.binding)).length>0&&this.host._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()}}),a=t.controlsFilter.trim().toLowerCase();return[...s,...o].filter(e=>!t.controls.includes(e.value)&&(!a||e.search.includes(a))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const s=this._markerDraft(t)?.id||t.devId||"";if(!s)return void this.host._showToast(this.host._t("toast.marker_binding_required"));const i=e.slice(7),o=this._markerDraft(t),a=o?[...this.host._markers.filter(t=>t.id!==s),o]:this.host._markers;if(di(a,s,i))return void this.host._showToast(this.host._t("toast.marker_control_cycle"))}this.host._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this.host._markerDialog;if(!e)return;if("auto"===t)return void(this.host._markerDialog={...e,glowMode:t,glowTouched:!0});const s=this._markerSpatialSource(e),i=pi(s?this.host._planHass.states[s.eid]:void 0,null,this.host._fillColors.glow_light.c),o=!e.glowColorDrafted,a="fixed"===t&&!e.glowBrightnessDrafted;this.host._markerDialog={...e,glowMode:t,glowColor:o?i.c:e.glowColor,glowBrightness:a?Math.max(1,Math.round(100*i.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderMarkerDialog(){const t=this.host._markerDialog,e="virtual"===t.bindingMode,s=this._bindingCandidates();this.host._bindingEntities(t.binding);const i=e?null:this.host._bindingStatus(t.binding),n=!e&&this.host._bindingHasHaPage(t.binding),r=this._markerPreviewDevice(t),l=this._effectiveMarkerTapAction(t,r),h=r?ps(this.host._serverCfg?.spaces.find(t=>t.id===r.space)):null,c=r?this._markerPreviewDevices(r):this.host._devices,d="toggle"===l&&r?this._toggleIntent(r,c):null,p=this._toggleHintLines(d),_=r?_i(this.host._planHass,r,{liveStates:!1!==this.host._config?.live_states,showTemperature:!1!==this.host._config?.show_temperature,showSignal:h?.showLqi??!1!==this.host._config?.show_signal,designPreview:!0,activityRuntime:this.host._activityRt.get(r.id),lightDevices:c,registryHass:this.host._fullRegistryHass,reducedMotion:this.host._reducedMotion}):null,u=r?ts(this.host._planHass,r,c):[],m=r?es(this.host._planHass,r,u):null,g=t.valueBadgeTouched?t.valueBadgeEnabled:!!_?.valueBadge,f=t.valueBadgeTouched?t.valueBadgeSource:_?.valueBadge?.source||t.valueBadgeSource,b=t.valueBadgeTouched?t.valueBadgePosition:_?.valueBadge?.position||t.valueBadgePosition,y=ui(f),v=!!f&&!u.some(t=>t.key===y),$=u.find(t=>t.key===y),w=_?.valueSource?_.valueSource.attribute?`attr:${_.valueSource.eid}:${_.valueSource.attribute}`:`state:${_.valueSource.eid}`:"",k=this._markerAutoHasSpatialSource(t),x=!!r&&mi(this.host._planHass,{...r}),S=gi(t.lightRole,k,x,t.glowMode),M=!S.sourceExists,D=!S.fromSourceEnabled,C=S.passive,P=S.effectiveMode,I="never"===t.lightRole?this.host._t("marker.glow_disabled_never"):"auto"!==t.lightRole||k?C?this.host._t("marker.glow_passive_hint"):this.host._t("marker.glow_disabled_no_entity"):this.host._t("marker.glow_disabled_auto"),T=r?li(r):[],R=r&&fi(r)||"",F=!!t.lightEntity&&!T.includes(t.lightEntity),N=r?bi(r):[],z=!!t.toggleEntity&&!N.includes(t.toggleEntity),A="toggle"===l?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,O=A?[...A.targets,...A.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",L=(()=>{if(e)return null;const i=s.find(e=>e.value===t.binding);if(i)return i.label;const[o,a]=t.binding.split(":");return"device"===o?this.host._fullRegistryHass.devices[a]?.name_by_user||this.host._fullRegistryHass.devices[a]?.name||a:this.host._fullRegistryHass.entities[a]?.name||this.host.hass.states[a]?.attributes?.friendly_name||a})();return o`this._closeMarkerDialog()}> +
+ ${"ha_disabled"===i?.kind?o`
+ + ${this.host._t(`marker.ha_disabled_${i.reason}`)} + ${n?o``:a} +
`:"unverified"===i?.kind&&t.binding?o`
+ + ${this.host._t("marker.ha_registry_limited")} +
`:a} + + this.host._markerDialog={...t,name:e.target.value}} /> + + +
+ +
+ + +
+ ${"ha"===t.bindingMode?o` + ${t.bindingOpen?o`
+ this.host._markerDialog={...t,bindingFilter:e.target.value}} /> +
+ ${s.map(e=>o`
{const s={...t,binding:e.value,bindingOpen:!1,controls:ss(e.value,t.controls,this.host._bindingEntities(e.value)),autoIcon:this.host._autoIconForBinding(e.value)};this.host._markerDialog=this._announceToggleDraft({...s,...this._valueBadgeForBinding(s,e.value)})}}> + ${e.label}${e.sub} +
`)} + ${s.length?a:o`
${this.host._t("marker.nothing_found")}
`} +
+
`:a}`:a} +
+ + + + + ${this._renderVacSection(t)} + + + + ${"toggle"===l&&(N.length>1||z)?o`
+
+ + ${this._help("marker.toggle_entity.help")} +
+ + ${z?o`

+ + ${this.host._t("marker.toggle_entity_missing",{entity:t.toggleEntity,fallback:O||this.host._t("marker.toggle_entity_none")})} +

`:a} +
`:a} + ${"toggle"===l?o`
+ ${p.map(t=>o`
${t}
`)} +
+
${t.tapHintAnnouncement}
`:a} + ${"run"===l?(()=>{const e=t.runFilter.trim().toLowerCase(),s=this._runCandidates().filter(t=>!e||t.label.toLowerCase().includes(e)||t.value.includes(e)),i=t.tapTarget?this._runCandidates().find(e=>e.value===t.tapTarget):null;return o` + + ${t.tapTarget&&!i?o`
${this.host._t("marker.run_target_gone",{id:t.tapTarget})}
`:a} + {t.target.select()}} + @input=${e=>this.host._markerDialog={...t,runFilter:e.target.value,tapTarget:""}} /> + ${i?a:o`
+ ${s.slice(0,40).map(e=>o`
this.host._markerDialog={...t,tapTarget:e.value,runFilter:""}}> + ${e.label}${e.sub} +
`)} + ${s.length?a:o`
${this.host._t("marker.nothing_found")}
`} +
`}`})():a} + ${"run"===l||"toggle"===l?o``:a} + + +
${this.host._t("marker.controls_hint")}
+ ${t.controls.length?o`
+ ${t.controls.map(e=>{const s=this._controlRefInfo(e);return o` + ${s.label} + this.host._markerDialog=this._announceToggleDraft({...t,controls:t.controls.filter(t=>t!==e)})}> + `})} +
`:a} + this.host._markerDialog={...t,controlsFilter:e.target.value}} /> + ${t.controlsFilter.trim()?o`
+ ${this._controlCandidates(t).map(e=>o``)} +
`:a} + + ${this.host._bindingHasClimate(t.binding)?o``:a} +
+ ${this.host._t("marker.light_role_label")}${this._help("marker.light_role.help")} +
+ + + +
+
+ + ${"always"===t.lightRole&&(T.length>1||F)?o`
+
+ + ${this._help("marker.light_entity.help")} +
+ + ${F?o`

+ + ${this.host._t("marker.light_entity_missing",{entity:t.lightEntity,fallback:R||"—"})} +

`:a} +
`:a} + +
+ ${this.host._t("marker.glow_color_label")}${this._help("marker.glow_mode.help")} +
+ + + +
+ ${"auto"!==P?o`
+ {this.host._markerDialog={...t,glowMode:P,glowColor:e.detail.color,glowColorDrafted:!0,glowTouched:!0}}}> + ${"fixed"===P?o` + ${this.host._t("marker.glow_brightness")} + ${this._rangeInput(1,100,1,t.glowBrightness,e=>{this.host._markerDialog={...t,glowMode:P,glowBrightness:e,glowBrightnessDrafted:!0,glowTouched:!0}},M,this.host._t("marker.glow_brightness"))} + ${Math.round(t.glowBrightness)}%`:a} +
`:a} +
+
+
+ + ${this._help("marker.glow_radius.help")} +
+
+ this.host._markerDialog={...t,glowRadius:e.target.value}} /> + ${this.host._imperial?this.host._t("gs.unit_ft"):this.host._t("gs.unit_m")} +
+
+ ${M||C?o`

+ ${I} +

`:a} + + + ${customElements.get("ha-icon-picker")?o`{const s=e.detail.value||"";(t.icon||s!==t.autoIcon)&&(this.host._markerDialog={...t,icon:s})}}>`:o`this.host._markerDialog={...t,icon:e.target.value}} />`} + ${!t.icon&&t.autoIcon?o`

+ ${this.host._t("marker.icon_auto",{icon:t.autoIcon})} +

`:a} + + + +

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

+ ${"static_icon"===t.display&&this.host._bindingHasAlarm(t.binding)?o`
+ + ${this.host._t("marker.static_alarm_warning")} +
`:a} +
+ ${this.host._t("marker.value_badge_title")}${this._help("marker.value_badge.help")} + + ${"static_icon"===t.display?o`

+ ${this.host._t("marker.value_badge_static")} +

`:u.length||t.valueBadgeSource?a:o`

+ ${this.host._t("marker.value_badge_empty")} +

`} + ${g?o` +
+ + ${this._help("marker.value_badge_source.help")} +
+ + ${$?o`

${$.technical}

`:a} + ${v?o`

+ ${this.host._t("marker.value_badge_missing_hint")} +

`:a} + ${"value"===t.display&&y===w?o`

+ ${this.host._t("marker.value_badge_duplicate")} +

`:a} +
+ + ${this._help("marker.value_badge_position.help")} +
+ + `:a} +
+ ${_?o` + `:o`
+ + ${this.host._t("marker.preview.select_source")} +
`} + ${"icon_ripple"===t.display?o`
+ {this.host._markerDialog={...t,rippleColor:e.detail.color}}}> +
+
+ ${this.host._t("marker.ripple_size")} + ${this._rangeInput(1,8,.5,t.rippleSize,e=>this.host._markerDialog={...t,rippleSize:e})} + ×${t.rippleSize} +
+

${this.host._t("marker.activity_alarm_note")}

`:a} + + +
+ ${this._rangeInput(.5,3,.1,t.size,e=>this.host._markerDialog={...t,size:e})} + ×${t.size.toFixed(1)} + ${this.host._t("marker.angle_label")} + ${""} + ${this._rangeInput(0,355,5,t.angle,e=>this.host._markerDialog={...t,angle:e})} + ${t.angle}° +
+ + + this.host._markerDialog={...t,model:e.target.value}} /> + + + this.host._markerDialog={...t,link:e.target.value}} /> + + + + + +
+ ${t.pdfs.map(t=>o` + ${t.name} + this._removeMarkerPdf(t.url)}>`)} + + + this._pickMarkerFiles(t)} /> + +
+
+
+
+ ${t.devId?o``:a} + ${t.devId?o``:a} +
+
+ + +
+
+
`}_renderSpaceDialog(){const t=this.host._spaceDialog,e=this.host._importTotal>0&&"create"===t.mode?this.host._t("import.progress",{i:this.host._importTotal-this.host._importQueue.length,n:this.host._importTotal}):"",s=()=>{this.host._spaceDialog=null,this.host._importQueue=[],this.host._importTotal=0};return o` +
+ + this.host._spaceDialog={...t,title:e.target.value}} /> + + + ${"file"===t.source?o`
+ ${t.planFile?o`${t.planFile.name}`:t.planUrl?o`${this.host._t("space.plan_alt")}`:o`${this.host._t("space.no_plan")}`} + + + this._pickPlanFile(t)} /> + + +
+ ${t.pickSaved?this._renderServerPlans(t):a}`:a} + + + +
+ {const s=e.target.value,i=sl(s),o=null==i?null:ki(i,this.host._imperial);this.host._spaceDialog={...t,cellCmInput:s,cellCmTouched:!0,cellCm:null!=o&&o>0?Math.max(.1,Math.min(el,o)):t.cellCm}}} /> + ${this.host._t(this.host._imperial?"space.scale_unit_imperial":"space.scale_unit")} +
+ + + + + +
${this.host._t("space.zero_wall_help")}
+ + + ${""} + +
${this.host._t("space.hide_decor_tip")}
+ +
${this.host._t("space.hide_openings_tip")}
+ + ${[["labelTemp","space.label_temp"],["labelHum","space.label_hum"],["labelLqi","space.label_lqi"],["labelLight","space.label_light"]].map(([e,s])=>o``)} + +
+ ${this._rangeInput(50,300,5,Math.round(100*t.cardFontScale),e=>this.host._spaceDialog={...t,cardFontScale:e/100})} + ${Math.round(100*t.cardFontScale)}% +
+ ${this.host._renderCardPreview(t.cardFontScale,1,1)} +
+ {this.host._spaceDialog={...t,roomColor:e.detail.color,roomOpacity:e.detail.opacity}}}> +
+ + + ${"static"===(t.bgMode??St(this.host._settings,{}))?o`
+ {this.host._spaceDialog={...t,bgColor:e.detail.color}}}> + ${t.bgColor?o``:o`${this.host._t("space.bg_inherited")}`} +
`:a} + +
+ {const s=e.target.value.trim(),i=""===s?null:Math.round(Number(s));this.host._spaceDialog={...t,northDeg:null!==i&&Number.isFinite(i)?Math.min(359,Math.max(0,i)):null}}} /> + ${null===t.northDeg?this.host._t("space.north_inherited",{v:null===Mt(this.host._settings,{})?"—":String(Mt(this.host._settings,{}))+"°"}):"°"} +
+ + + + ${xi.map(t=>[t,"fill."+t]).map(([e,s])=>o` + ${"custom"===e&&"custom"===t.fillMode?o`
+ ${this.host._t("space.custom_fill")} + {this.host._spaceDialog={...t,customFill:{c:e.detail.color,a:e.detail.opacity}}}}> + ${t.customFill?o``:a} +
`:a}`)} + + ${t.deleteBlockers?o``:a} +
+ +
`}_renderMergeDialog(){const t=this.host._mergeDialog,e=this.host._spaceModel()?.rooms||[],s=(s,i)=>{const a=e.find(t=>t.id===s),n=a?.area?this.host.hass.areas[a.area]?.name:null;return o``};return o`this.host._mergeDialog=null}> +
+

${this.host._t("merge.hint")}

+ + ${s(t.aId,"a")} + ${s(t.bId,"b")} +
+
+ + + +
+
`}_renderRoomSource(t){const e="temp"===t?this.host._roomTempSrc:this.host._roomHumSrc,s=e=>{"temp"===t?this.host._roomTempSrc=e:this.host._roomHumSrc=e,this.host.requestUpdate()},i=this.host._roomSrcOpen===t;return o` + + + + ${e||i?o` + ${i?o`
+ {this.host._roomSrcFilter=t.target.value,this.host.requestUpdate()}} /> +
+ ${this._roomSrcCandidates().map(t=>o`
{s(t.value),this.host._roomSrcOpen=null}}> + ${t.label}${t.sub} +
`)} +
+
`:a}`:a}`}_renderRoomDialog(){const t=!!this.host._roomEditId,e=t?null:this.host._wallFaceBatch,s=e&&e.candidates.length>1?this.host._t("room.queue_progress",{current:e.index+1,total:e.candidates.length}):"",i=!!this.host._areaSel||!!this.host._nameSel.trim(),n=ps(this.host._curSpaceCfg),r=this.host._roomFill||n.fill,l=this.host._roomCustomFill||n.customFill,h=[...this.host._freeAreas];if(t&&this.host._areaSel&&!h.some(t=>t.area_id===this.host._areaSel)){const t=this.host.hass.areas[this.host._areaSel];t&&h.unshift(t)}return o`this._roomDialogCancel()}> +
+ ${s?o`

+ ${s} +

`:a} + + this.host._nameSel=t.target.value} /> + + + + + + ${[["","fill.inherit"],...Si.map(t=>[t,"fill."+t])].map(([t,e])=>o``)} + ${"custom"===r?o`
+ ${this.host._roomCustomFill?this.host._t("room.custom_fill_own"):this.host._t("room.custom_fill_space")} + {this.host._roomCustomFill={c:t.detail.color,a:t.detail.opacity}}}> + ${this.host._roomCustomFill?o``:a} +
`:a} + ${this._renderRoomSource("temp")} + ${this._renderRoomSource("hum")} + + + +
+ ${this._rangeInput(50,300,5,Math.round(100*this.host._roomNameScale),t=>{this.host._roomNameScale=t/100,this.host.requestUpdate()})} + ${Math.round(100*this.host._roomNameScale)}% +
+ +
+ ${this._rangeInput(50,300,5,Math.round(100*this.host._roomLabelScale),t=>{this.host._roomLabelScale=t/100,this.host.requestUpdate()})} + ${Math.round(100*this.host._roomLabelScale)}% +
+ ${this.host._renderCardPreview(ps(this.host._curSpaceCfg).cardFontScale,this.host._roomNameScale,this.host._roomLabelScale)} +
+
+ + + ${t?o``:o`${this.host._pendingSplit?a:o``} + `} +
+
`}}export{rl as EDITOR_RUNTIME_FINGERPRINT,ll as HouseplanEditorRuntime}; diff --git a/dist/houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js b/dist/houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js new file mode 100644 index 00000000..8c2b8480 --- /dev/null +++ b/dist/houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js @@ -0,0 +1,217 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";import{bU as t,bV as s,bW as e,bX as o,aq as a,bY as l,c1 as i,bZ as h,b_ as n,b$ as c,c0 as r,b as p,A as _,cV as d,ap as u,ar as g,cW as m}from"./houseplan-card-OQuczTJf.js";import{i as b,c as $,a as v,s as f,t as y}from"./space-deletion-7mvB_XVT.js";const w=1e3,D=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},S="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";class C{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_openSpaceDialog(p,_){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===p){const i=this.host._serverCfg.spaces.find(t=>t.id===_);if(!i)return;const h=t(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?s(i.settings.custom_fill):null,c="none"===h.fill?{...n||e,a:0}:n;return void(this.host._spaceDialog={mode:p,spaceId:_,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:h.showBorders,showNames:h.showNames,zeroWallStyle:l(i),displayTouched:!0,hideDecor:h.hideDecor,hideOpenings:h.hideOpenings,roomColor:h.color,roomOpacity:h.opacity,fillMode:"none"===h.fill?"custom":h.fill,customFill:c,glowEnabled:h.glow,bgColor:h.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:a({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:h.tempMin,tempMax:h.tempMax,showLqi:h.showLqi??this.host._config?.show_signal??!0,cardFontScale:h.cardFontScale,labelTemp:h.labelTemp,labelHum:h.labelHum,labelLqi:h.labelLqi,labelLight:h.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:o(Number(i.cell_cm)>0?Number(i.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const d=i(this.host._imperial);this.host._spaceDialog={mode:p,title:"",planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:{...e,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:d,cellCmInput:o(d,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;const o={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[e.type]||(e.name.toLowerCase().endsWith(".svg")?"svg":"");if(!o)return void this.host._showToast(this.host._t("toast.plan_formats"));const a=new Uint8Array(await e.arrayBuffer());let l="";for(let t=0;t{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:1.414),s.onerror=()=>t(1.414),s.src=h});URL.revokeObjectURL(h),this.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:o,b64:i,aspect:n,name:e.name}}}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`
${this.host._t("space.loading")}
`;const s=t.saved||[];if(!s.length)return p`
${this.host._t("space.no_saved")}
`;return p`
+ ${s.map(s=>{return p` +
+ +
+ ${s.name} + ${e=s.size,e>=1048576?`${(e/1048576).toFixed(1)} MB`:`${Math.round(e/1024)} KB`}${s.used_by.length?` · ${this.host._t("space.used_by",{list:s.used_by.join(", ")})}`:""} +
+ + +
`;var e})} +
`}async _saveConfigNow(){this.host._cfgEpoch++;try{await this.host._writeConfig()}catch(t){const s=t;throw s?.physicalGeometryRolledBack?await this.host._reloadRejectedPhysicalWrite():"conflict"===s?.code&&await this.host._reloadConfigOnly(),t}}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const s="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const e="create"===t.mode?`s${Date.now().toString(36)}`:t.spaceId;let o=null;if("file"===t.source&&t.planFile){o={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:e,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let a=t.savedAspect||null;!o&&"file"===t.source&&t.planUrl&&!a&&this.host._aspectJob&&(a=await this.host._aspectJob||null);const l=this.host._serverCfg;let i=l.spaces.find(t=>t.id===e);if("create"===t.mode)i=$(e,t.title.trim()),l.spaces.push(i);else{if(!i)throw new Error(`space ${e} is gone from the config`);i.title=t.title.trim()}if(!i)throw new Error(`space ${e} is unavailable`);if(o?(i.plan_url=o.url,i.plan_aspect=o.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==i.plan_url&&(i.plan_url=t.planUrl,i.plan_aspect=a),"draw"===t.source&&(i.plan_url=null,i.plan_aspect=null,delete i.plan_x,delete i.plan_y,delete i.plan_scale,delete i.plan_scale_x,delete i.plan_scale_y,delete i.plan_angle),i.settings={...i.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):n,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):h,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},i.zero_wall_style=t.zeroWallStyle,i.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(w,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(i.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length)this._openNextImport();else if(s||this.host._importTotal>0){const t=this.host._importTotal>0;this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),await this.host._requestMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._showToast(this.host._t(s&&!t?"toast.space_added_onboard":"import.done"))}else this.host._showToast(this.host._t("create"===t.mode?"toast.space_added":"toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?await this.host._requestMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._saveNav()))}catch(t){const s=t;"conflict"!==s?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const s=this.host._serverCfg;if(!s)return;const e=s.spaces.find(s=>s.id===t.spaceId);if(!e)return;const o=v(s,this.host._layout||{},t.spaceId||""),a=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;if(!o.count||a){if(confirm(this.host._t("confirm.delete_space",{title:e.title}))){this.host._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain;const s=await this.host.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev}),[e,o]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._adoptStructuralResponses(e,o),this.host._cfgRev=s?.config_rev??this.host._cfgRev,this.host._layoutRev=s?.layout_rev??this.host._layoutRev,this.host._spaceDialog=null,this.host._space===t.spaceId&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(s){const e=s;"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const o=this.host._serverCfg;if(this.host._spaceDialog&&o){const s=v(o,this.host._layout||{},t.spaceId||""),e=1===o.spaces.length&&o.spaces[0]?.id===t.spaceId;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:e?0:s.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(s)}))}}}else this.host._spaceDialog={...t,deleteBlockers:o.count}}_startImport(){const t=this.host._importDialog;if(!t)return;const s=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,s.length?(this.host._importQueue=s,this.host._importTotal=s.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();if(void 0===t)return;const s=i(this.host._imperial);this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:s,cellCmInput:o(s,this.host._imperial),cellCmTouched:!1,busy:!1}}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this.host._requestMode("plan").then(()=>{this.host._showToast(this.host._t("import.done"))}))}_renderImportDialog(){const t=this.host._importDialog,s=t.floors.filter(t=>t.checked).length;return p`this.host._importDialog=null}> +
+
${this.host._t("import.hint")}
+ ${t.floors.map((s,e)=>p``)} +
+
+ + + +
+
`}_boolInput(t,s){return p`s(t.target.checked)} />`}_rangeInput(t,s,e,o,a){return p`a(Number(t.target.value))} />`}_renderSpaceDialog(){return this._renderSpaceDialogBody(this.host._spaceDialog)}_renderSpaceDialogBody(t){const s=this.host._importTotal>0&&"create"===t.mode?this.host._t("import.progress",{i:this.host._importTotal-this.host._importQueue.length,n:this.host._importTotal}):"",l=()=>{this.host._spaceDialog=null,this.host._importQueue=[],this.host._importTotal=0};return p` +
+ + this.host._spaceDialog={...t,title:s.target.value}} /> + + + ${"file"===t.source?p`
+ ${t.planFile?p`${t.planFile.name}`:t.planUrl?p`${this.host._t("space.plan_alt")}`:p`${this.host._t("space.no_plan")}`} + + + this._pickPlanFile(t)} /> + + +
+ ${t.pickSaved?this._renderServerPlans(t):_}`:_} + + + +
+ {const e=s.target.value,o=D(e),a=null==o?null:d(o,this.host._imperial);this.host._spaceDialog={...t,cellCmInput:e,cellCmTouched:!0,cellCm:null!=a&&a>0?Math.max(.1,Math.min(w,a)):t.cellCm}}} /> + ${this.host._t(this.host._imperial?"space.scale_unit_imperial":"space.scale_unit")} +
+ + + + + +
${this.host._t("space.zero_wall_help")}
+ + + +
${this.host._t("space.hide_decor_tip")}
+ +
${this.host._t("space.hide_openings_tip")}
+ + ${[["labelTemp","space.label_temp"],["labelHum","space.label_hum"],["labelLqi","space.label_lqi"],["labelLight","space.label_light"]].map(([s,e])=>p``)} + +
+ ${this._rangeInput(50,300,5,Math.round(100*t.cardFontScale),s=>{this.host._spaceDialog={...t,cardFontScale:s/100}})} + ${Math.round(100*t.cardFontScale)}% +
+ ${this.host._renderCardPreview(t.cardFontScale,1,1)} +
+ {this.host._spaceDialog={...t,roomColor:s.detail.color,roomOpacity:s.detail.opacity}}}> +
+ + + ${"static"===(t.bgMode??u(this.host._settings,{}))?p` +
+ {this.host._spaceDialog={...t,bgColor:s.detail.color}}}> + ${t.bgColor?p``:p`${this.host._t("space.bg_inherited")}`} +
`:_} + +
+ {const e=s.target.value.trim(),o=""===e?null:Math.round(Number(e));this.host._spaceDialog={...t,northDeg:null!==o&&Number.isFinite(o)?Math.min(359,Math.max(0,o)):null}}} /> + ${null===t.northDeg?this.host._t("space.north_inherited",{v:null===a(this.host._settings,{})?"—":`${a(this.host._settings,{})}°`}):"°"} +
+ + + + ${m.map(t=>[t,`fill.${t}`]).map(([s,o])=>p` + ${"custom"===s&&"custom"===t.fillMode?p` +
+ ${this.host._t("space.custom_fill")} + {this.host._spaceDialog={...t,customFill:{c:s.detail.color,a:s.detail.opacity}}}}> + ${t.customFill?p``:_} +
`:_}`)} + + ${t.deleteBlockers?p``:_} +
+ +
`}}export{C as HouseplanOnboardingRuntime,S as ONBOARDING_RUNTIME_FINGERPRINT}; diff --git a/dist/houseplan-assets/space-deletion-7mvB_XVT.js b/dist/houseplan-assets/space-deletion-7mvB_XVT.js new file mode 100644 index 00000000..8496f87c --- /dev/null +++ b/dist/houseplan-assets/space-deletion-7mvB_XVT.js @@ -0,0 +1 @@ +function e(e,o){return{id:e,title:o,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function o(e="file"){const o="draw"===e;return{source:e,showBorders:o,showNames:o,displayTouched:!1}}function r(e,o){if(e.displayTouched)return{...e,source:o};const r="draw"===o;return{...e,source:o,showBorders:r,showNames:r}}function s(e,o,r){return{...e,[o]:r,displayTouched:!0}}function t(e,o,r){const s=(e?.spaces||[]).find(e=>e?.id===r),t=new Set((s?.rooms||[]).map(e=>String(e?.id||"")).filter(Boolean)),n=[...new Set((e?.markers||[]).filter(e=>!0!==e?.removed&&"string"==typeof e?.id).filter(e=>e.space===r||"string"==typeof e.room_id&&t.has(e.room_id)||o?.[e.id]?.s===r).map(e=>e.id))].sort((e,o)=>e.localeCompare(o));return{markerIds:n,count:n.length}}globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479";export{t as a,e as c,o as i,r as s,s as t};