From d2bc9082807452c88e735c72d4a06d1ff873eaa9 Mon Sep 17 00:00:00 2001 From: Matysh Date: Tue, 11 Aug 2026 01:14:59 +0300 Subject: [PATCH] Release v1.61.0-beta.6 candidate --- README.md | 5 +- README.ru.md | 3 +- custom_components/houseplan/const.py | 2 +- .../houseplan/frontend/houseplan-card.js | 1001 +++++++++-------- custom_components/houseplan/manifest.json | 2 +- demo/golden/README.md | 8 +- demo/golden/baselines/baseline-manifest.json | 35 +- .../baselines/device-dialog-desktop-en.png | Bin 322729 -> 371076 bytes .../baselines/device-dialog-mobile-ru.png | Bin 77747 -> 106448 bytes .../baselines/hover-nested-room-dark.png | Bin 24398 -> 22686 bytes .../golden/baselines/hover-over-glow-dark.png | Bin 139133 -> 159396 bytes .../large-house-warm-remount-dark.png | Bin 124760 -> 129967 bytes .../baselines/large-house-zoom-040-dark.png | Bin 53095 -> 54464 bytes .../baselines/large-house-zoom-250-dark.png | Bin 113108 -> 118030 bytes .../baselines/lighting-custom-glow-dark.png | Bin 141739 -> 169293 bytes .../baselines/lighting-custom-glow-light.png | Bin 142058 -> 169590 bytes .../baselines/lighting-glow-sun-dark.png | Bin 137470 -> 159586 bytes ...ighting-manual-auto-spill-overlap-dark.png | Bin 172923 -> 188150 bytes ...lighting-opaque-glow-two-doorways-dark.png | Bin 0 -> 125004 bytes .../baselines/lighting-temp-glow-dark.png | Bin 134151 -> 165617 bytes .../baselines/lighting-temp-glow-light.png | Bin 134199 -> 165663 bytes .../lighting-temp-glow-room-override-dark.png | Bin 128806 -> 160521 bytes demo/golden/harness.mjs | 56 +- demo/golden/matrix.mjs | 25 +- demo/smoke_free_walls.mjs | 90 ++ demo/smoke_glow.mjs | 417 ++++++- demo/smoke_glow_blending.mjs | 3 + demo/smoke_openwall.mjs | 45 +- demo/srv/assets/houseplan-card.js | 1001 +++++++++-------- dist/houseplan-card.js | 1001 +++++++++-------- docs/ARCHITECTURE.md | 70 +- docs/CHANGELOG.md | 29 + docs/CHANGELOG.ru.md | 30 + docs/DEVELOPMENT.md | 16 + docs/LIGHT.md | 126 +++ docs/RELEASE-NOTES.md | 10 +- docs/STATUS.md | 13 +- docs/TESTING-DEMO.md | 2 +- docs/TESTING.md | 62 +- docs/USER-GUIDE.ru.md | 12 +- docs/specs/019-glow-additive-blending.md | 33 +- docs/specs/020-glow-open-door-spill.md | 8 + docs/specs/055-independent-glow-overlay.md | 5 +- docs/specs/067-light-source-controls.md | 15 +- ...026-08-10-plan-visual-continuity-design.md | 765 +++++++++++++ package-lock.json | 4 +- package.json | 2 +- src/houseplan-card.ts | 515 +++++++-- src/hp-dialog.ts | 7 + src/light-visibility.ts | 162 +++ src/logic.ts | 23 + src/physical-geometry.ts | 76 +- src/styles.ts | 103 +- src/wall-thickness.ts | 68 +- test/golden-matrix.test.mjs | 70 +- test/light-visibility.test.mjs | 103 ++ test/logic.test.mjs | 14 +- test/release-contract.test.mjs | 8 + tsconfig.test.json | 1 + 59 files changed, 4417 insertions(+), 1629 deletions(-) create mode 100644 demo/golden/baselines/lighting-opaque-glow-two-doorways-dark.png create mode 100644 docs/LIGHT.md create mode 100644 docs/superpowers/specs/2026-08-10-plan-visual-continuity-design.md create mode 100644 src/light-visibility.ts create mode 100644 test/light-visibility.test.mjs diff --git a/README.md b/README.md index 19eff9a9..7a27f03c 100755 --- a/README.md +++ b/README.md @@ -44,8 +44,9 @@ right on your Lovelace dashboard. you drag, so the drawing and the photo of your plan finally line up. - 💡 **Lights toggle on click** out of the box; wall-switch markers can control whole groups of lights (works for dumb switches and stateless remotes too). -- 🌒 **“Light sources” fill** — a dark house where every lit lamp casts a pool - of its own color that spills through doorways and open zone boundaries. +- 🌒 **“Light sources” fill** — a dark house where every lit lamp lights exactly + the floor it can see: through doorways and open boundaries, stopped by walls, + columns and partitions, which cast real shadows. - ☀️ **The sun on the plan** — set the compass and the backdrop lives with the day (white noon → golden hour → deep night), while windows on exterior walls cast real wedges of sunlight into the rooms; optional cloud cover diff --git a/README.ru.md b/README.ru.md index 099e79d9..a7c6d200 100644 --- a/README.ru.md +++ b/README.ru.md @@ -43,7 +43,8 @@ - 💡 **Свет переключается кликом** из коробки; значок выключателя может управлять группой ламп (в т.ч. «тупые» выключатели и кнопки-пульты). - 🌒 **Заливка «Свет по источникам»** — тёмный дом, где каждая горящая лампа - даёт пятно своего цвета, проникающее через дверные проёмы и открытые зоны. + освещает ровно тот пол, который видит: через проёмы и открытые границы, + а стены, колонны и перегородки его не пропускают и дают настоящие тени. - ☀️ **Солнце на плане** — задайте компас, и фон живёт вместе с днём (белый полдень → золотой час → глубокая ночь), а окна внешних стен пускают в комнаты настоящие клинья солнечного света; облачность — опционально, от diff --git a/custom_components/houseplan/const.py b/custom_components/houseplan/const.py index aac850eb..c3d1bbbd 100755 --- a/custom_components/houseplan/const.py +++ b/custom_components/houseplan/const.py @@ -45,7 +45,7 @@ PLAN_ORPHAN_TTL_S = 3600 SCHEDULED_GRACE_S = 30 * 24 * 3600 FILES_DIR = "houseplan/files" CONF_ADMIN_ONLY = "admin_only" -VERSION = "1.61.0-beta.5" +VERSION = "1.61.0-beta.6" DEFAULT_CONFIG: dict = { "spaces": [], diff --git a/custom_components/houseplan/frontend/houseplan-card.js b/custom_components/houseplan/frontend/houseplan-card.js index eb1264c2..6655bb0d 100755 --- a/custom_components/houseplan/frontend/houseplan-card.js +++ b/custom_components/houseplan/frontend/houseplan-card.js @@ -1,7 +1,7 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe5164d616bf18f84cac66f0f69e6890";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),s=new WeakMap;let o=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const i=this.t;if(e&&void 0===t){const e=void 0!==i&&1===i.length;e&&(t=s.get(i)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&s.set(i,t))}return t}toString(){return this.cssText}};const n=(t,...e)=>{const s=1===t.length?t[0]:e.reduce((e,i,s)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+t[s+1],t[0]);return new o(s,t,i)},r=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return(t=>new o("string"==typeof t?t:t+"",void 0,i))(e)})(t):t,{is:a,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:p}=Object,u=globalThis,_=u.trustedTypes,m=_?_.emptyScript:"",g=u.reactiveElementPolyfillSupport,f=(t,e)=>t,v={toAttribute(t,e){switch(e){case Boolean:t=t?m:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let i=t;switch(e){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},y=(t,e)=>!a(t,e),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),u.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=b){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const i=Symbol(),s=this.getPropertyDescriptor(t,i,e);void 0!==s&&l(this.prototype,t,s)}}static getPropertyDescriptor(t,e,i){const{get:s,set:o}=c(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:s,set(e){const n=s?.call(this);o?.call(this,e),this.requestUpdate(t,n,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(f("elementProperties")))return;const t=p(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(f("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(f("properties"))){const t=this.properties,e=[...h(t),...d(t)];for(const i of e)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const i=this._$Eu(t,e);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const t of i)e.unshift(r(t))}else void 0!==t&&e.push(r(t));return e}static _$Eu(t,e){const i=e.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const i of e.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,s)=>{if(e)i.adoptedStyleSheets=s.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of s){const s=document.createElement("style"),o=t.litNonce;void 0!==o&&s.setAttribute("nonce",o),s.textContent=e.cssText,i.appendChild(s)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,i){this._$AK(t,i)}_$ET(t,e){const i=this.constructor.elementProperties.get(t),s=this.constructor._$Eu(t,i);if(void 0!==s&&!0===i.reflect){const o=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(e,i.type);this._$Em=t,null==o?this.removeAttribute(s):this.setAttribute(s,o),this._$Em=null}}_$AK(t,e){const i=this.constructor,s=i._$Eh.get(t);if(void 0!==s&&this._$Em!==s){const t=i.getPropertyOptions(s),o="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:v;this._$Em=s;const n=o.fromAttribute(e,t.type);this[s]=n??this._$Ej?.get(s)??n,this._$Em=null}}requestUpdate(t,e,i,s=!1,o){if(void 0!==t){const n=this.constructor;if(!1===s&&(o=this[t]),i??=n.getPropertyOptions(t),!((i.hasChanged??y)(o,e)||i.useDefault&&i.reflect&&o===this._$Ej?.get(t)&&!this.hasAttribute(n._$Eu(t,i))))return;this.C(t,e,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:i,reflect:s,wrapped:o},n){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,n??e??this[t]),!0!==o||void 0!==n)||(this._$AL.has(t)||(this.hasUpdated||i||(e=void 0),this._$AL.set(t,e)),!0===s&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,i]of t){const{wrapped:t}=i,s=this[e];!0!==t||this._$AL.has(e)||void 0===s||this.C(e,void 0,i,s)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[f("elementProperties")]=new Map,w[f("finalized")]=new Map,g?.({ReactiveElement:w}),(u.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,$=t=>t,x=k.trustedTypes,S=x?x.createPolicy("lit-html",{createHTML:t=>t}):void 0,M="$lit$",C=`lit$${Math.random().toFixed(9).slice(2)}$`,D="?"+C,T=`<${D}>`,P=document,R=()=>P.createComment(""),z=t=>null===t||"object"!=typeof t&&"function"!=typeof t,A=Array.isArray,I="[ \t\n\f\r]",E=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,N=/-->/g,F=/>/g,O=RegExp(`>|${I}(?:([^\\s"'>=/]+)(${I}*=${I}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,H=/"/g,q=/^(?:script|style|textarea|title)$/i,U=t=>(e,...i)=>({_$litType$:t,strings:e,values:i}),j=U(1),B=U(2),G=Symbol.for("lit-noChange"),W=Symbol.for("lit-nothing"),V=new WeakMap,K=P.createTreeWalker(P,129);function Y(t,e){if(!A(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(e):e}const J=(t,e)=>{const i=t.length-1,s=[];let o,n=2===e?"":3===e?"":"",r=E;for(let e=0;e"===l[0]?(r=o??E,c=-1):void 0===l[1]?c=-2:(c=r.lastIndex-l[2].length,a=l[1],r=void 0===l[3]?O:'"'===l[3]?H:L):r===H||r===L?r=O:r===N||r===F?r=E:(r=O,o=void 0);const d=r===O&&t[e+1].startsWith("/>")?" ":"";n+=r===E?i+T:c>=0?(s.push(a),i.slice(0,c)+M+i.slice(c)+C+d):i+C+(-2===c?e:d)}return[Y(t,n+(t[i]||"")+(2===e?"":3===e?"":"")),s]};class Z{constructor({strings:t,_$litType$:e},i){let s;this.parts=[];let o=0,n=0;const r=t.length-1,a=this.parts,[l,c]=J(t,e);if(this.el=Z.createElement(l,i),K.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(s=K.nextNode())&&a.length0){s.textContent=x?x.emptyScript:"";for(let i=0;iA(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==W&&z(this._$AH)?this._$AA.nextSibling.data=t:this.T(P.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:i}=t,s="number"==typeof i?this._$AC(t):(void 0===i.el&&(i.el=Z.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===s)this._$AH.p(e);else{const t=new Q(s,this),i=t.u(this.options);t.p(e),this.T(i),this._$AH=t}}_$AC(t){let e=V.get(t.strings);return void 0===e&&V.set(t.strings,e=new Z(t)),e}k(t){A(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let i,s=0;for(const o of t)s===e.length?e.push(i=new tt(this.O(R()),this.O(R()),this,this.options)):i=e[s],i._$AI(o),s++;s2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=W}_$AI(t,e=this,i,s){const o=this.strings;let n=!1;if(void 0===o)t=X(this,t,e,0),n=!z(t)||t!==this._$AH&&t!==G,n&&(this._$AH=t);else{const s=t;let r,a;for(t=o[0],r=0;r{const s=i?.renderBefore??e;let o=s._$litPart$;if(void 0===o){const t=i?.renderBefore??null;s._$litPart$=o=new tt(e.insertBefore(R(),t),t,void 0,i??{})}return o._$AI(t),o})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return G}}lt._$litElement$=!0,lt.finalized=!0,at.litElementHydrateSupport?.({LitElement:lt});const ct=at.litElementPolyfillSupport;ct?.({LitElement:lt}),(at.litElementVersions??=[]).push("4.2.2");const ht=new WeakMap;let dt=0;class pt extends lt{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._titleId="hp-dialog-title-"+ ++dt,this._focusInitial=()=>{const t=this.querySelector("[autofocus]")||this._focusableElements()[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=t=>{if("Escape"===t.key)return t.preventDefault(),t.stopImmediatePropagation(),void this._requestClose();if("Tab"!==t.key||this._useHaDialog)return;const e=this.renderRoot.querySelector(".close"),i=e?[e,...this._focusableElements()]:this._focusableElements();if(!i.length)return t.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const s=this._deepActiveElement(),o=i[0],n=i[i.length-1];!t.shiftKey||s!==o&&i.includes(s)?t.shiftKey||s!==n||(t.preventDefault(),o.focus()):(t.preventDefault(),n.focus())},this._onFallbackCancel=t=>{t.preventDefault(),this._requestClose()},this._onFallbackClick=t=>{this.dismissOnScrim&&t.target===t.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const t=this.getRootNode();this._focusRoot=t;const e=ht.get(t)||{dialogs:new Set,opener:this._opener};e.dialogs.add(this),ht.set(t,e),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const t=this._focusRoot,e=this._opener;this._opener=null,this._focusRoot=null;const i=t?ht.get(t):void 0;i?.dialogs.delete(this),super.disconnectedCallback(),t&&i&&requestAnimationFrame(()=>{const i=ht.get(t);if(!i)return;if(!i.dialogs.size)return i.opener?.isConnected&&i.opener.focus({preventScroll:!0}),void ht.delete(t);const s=e?.closest("hp-dialog");e?.isConnected&&s&&i.dialogs.has(s)&&e.focus({preventScroll:!0})})}firstUpdated(t){if(super.firstUpdated(t),!this._useHaDialog){const t=this.renderRoot.querySelector("dialog");t&&!t.open&&t.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let t=document.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t&&t!==document.body?t:null}_focusableElements(){const t=["[autofocus]","a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[contenteditable="true"]','[tabindex]:not([tabindex="-1"])'].join(",");return Array.from(this.querySelectorAll(t)).filter(t=>{const e=getComputedStyle(t);return!t.hidden&&"none"!==e.display&&"hidden"!==e.visibility})}render(){const t=j` - ${this.icon?j``:W} +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="258d82cce98d0b96a77008ecb76a90516f96fbc26ab50eb69b49466b3c7bab33";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),s=new WeakMap;let o=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const i=this.t;if(e&&void 0===t){const e=void 0!==i&&1===i.length;e&&(t=s.get(i)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&s.set(i,t))}return t}toString(){return this.cssText}};const n=(t,...e)=>{const s=1===t.length?t[0]:e.reduce((e,i,s)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+t[s+1],t[0]);return new o(s,t,i)},r=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return(t=>new o("string"==typeof t?t:t+"",void 0,i))(e)})(t):t,{is:a,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:p}=Object,u=globalThis,_=u.trustedTypes,m=_?_.emptyScript:"",g=u.reactiveElementPolyfillSupport,f=(t,e)=>t,v={toAttribute(t,e){switch(e){case Boolean:t=t?m:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let i=t;switch(e){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},y=(t,e)=>!a(t,e),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),u.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=b){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const i=Symbol(),s=this.getPropertyDescriptor(t,i,e);void 0!==s&&l(this.prototype,t,s)}}static getPropertyDescriptor(t,e,i){const{get:s,set:o}=c(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:s,set(e){const n=s?.call(this);o?.call(this,e),this.requestUpdate(t,n,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(f("elementProperties")))return;const t=p(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(f("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(f("properties"))){const t=this.properties,e=[...h(t),...d(t)];for(const i of e)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const i=this._$Eu(t,e);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const t of i)e.unshift(r(t))}else void 0!==t&&e.push(r(t));return e}static _$Eu(t,e){const i=e.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const i of e.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,s)=>{if(e)i.adoptedStyleSheets=s.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of s){const s=document.createElement("style"),o=t.litNonce;void 0!==o&&s.setAttribute("nonce",o),s.textContent=e.cssText,i.appendChild(s)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,i){this._$AK(t,i)}_$ET(t,e){const i=this.constructor.elementProperties.get(t),s=this.constructor._$Eu(t,i);if(void 0!==s&&!0===i.reflect){const o=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(e,i.type);this._$Em=t,null==o?this.removeAttribute(s):this.setAttribute(s,o),this._$Em=null}}_$AK(t,e){const i=this.constructor,s=i._$Eh.get(t);if(void 0!==s&&this._$Em!==s){const t=i.getPropertyOptions(s),o="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:v;this._$Em=s;const n=o.fromAttribute(e,t.type);this[s]=n??this._$Ej?.get(s)??n,this._$Em=null}}requestUpdate(t,e,i,s=!1,o){if(void 0!==t){const n=this.constructor;if(!1===s&&(o=this[t]),i??=n.getPropertyOptions(t),!((i.hasChanged??y)(o,e)||i.useDefault&&i.reflect&&o===this._$Ej?.get(t)&&!this.hasAttribute(n._$Eu(t,i))))return;this.C(t,e,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:i,reflect:s,wrapped:o},n){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,n??e??this[t]),!0!==o||void 0!==n)||(this._$AL.has(t)||(this.hasUpdated||i||(e=void 0),this._$AL.set(t,e)),!0===s&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,i]of t){const{wrapped:t}=i,s=this[e];!0!==t||this._$AL.has(e)||void 0===s||this.C(e,void 0,i,s)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[f("elementProperties")]=new Map,w[f("finalized")]=new Map,g?.({ReactiveElement:w}),(u.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,$=t=>t,x=k.trustedTypes,S=x?x.createPolicy("lit-html",{createHTML:t=>t}):void 0,M="$lit$",C=`lit$${Math.random().toFixed(9).slice(2)}$`,D="?"+C,T=`<${D}>`,P=document,R=()=>P.createComment(""),A=t=>null===t||"object"!=typeof t&&"function"!=typeof t,z=Array.isArray,I="[ \t\n\f\r]",E=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,N=/-->/g,F=/>/g,O=RegExp(`>|${I}(?:([^\\s"'>=/]+)(${I}*=${I}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,H=/"/g,q=/^(?:script|style|textarea|title)$/i,U=t=>(e,...i)=>({_$litType$:t,strings:e,values:i}),B=U(1),j=U(2),G=Symbol.for("lit-noChange"),W=Symbol.for("lit-nothing"),V=new WeakMap,K=P.createTreeWalker(P,129);function Y(t,e){if(!z(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(e):e}const J=(t,e)=>{const i=t.length-1,s=[];let o,n=2===e?"":3===e?"":"",r=E;for(let e=0;e"===l[0]?(r=o??E,c=-1):void 0===l[1]?c=-2:(c=r.lastIndex-l[2].length,a=l[1],r=void 0===l[3]?O:'"'===l[3]?H:L):r===H||r===L?r=O:r===N||r===F?r=E:(r=O,o=void 0);const d=r===O&&t[e+1].startsWith("/>")?" ":"";n+=r===E?i+T:c>=0?(s.push(a),i.slice(0,c)+M+i.slice(c)+C+d):i+C+(-2===c?e:d)}return[Y(t,n+(t[i]||"")+(2===e?"":3===e?"":"")),s]};class Z{constructor({strings:t,_$litType$:e},i){let s;this.parts=[];let o=0,n=0;const r=t.length-1,a=this.parts,[l,c]=J(t,e);if(this.el=Z.createElement(l,i),K.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(s=K.nextNode())&&a.length0){s.textContent=x?x.emptyScript:"";for(let i=0;iz(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==W&&A(this._$AH)?this._$AA.nextSibling.data=t:this.T(P.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:i}=t,s="number"==typeof i?this._$AC(t):(void 0===i.el&&(i.el=Z.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===s)this._$AH.p(e);else{const t=new Q(s,this),i=t.u(this.options);t.p(e),this.T(i),this._$AH=t}}_$AC(t){let e=V.get(t.strings);return void 0===e&&V.set(t.strings,e=new Z(t)),e}k(t){z(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let i,s=0;for(const o of t)s===e.length?e.push(i=new tt(this.O(R()),this.O(R()),this,this.options)):i=e[s],i._$AI(o),s++;s2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=W}_$AI(t,e=this,i,s){const o=this.strings;let n=!1;if(void 0===o)t=X(this,t,e,0),n=!A(t)||t!==this._$AH&&t!==G,n&&(this._$AH=t);else{const s=t;let r,a;for(t=o[0],r=0;r{const s=i?.renderBefore??e;let o=s._$litPart$;if(void 0===o){const t=i?.renderBefore??null;s._$litPart$=o=new tt(e.insertBefore(R(),t),t,void 0,i??{})}return o._$AI(t),o})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return G}};ct._$litElement$=!0,ct.finalized=!0,lt.litElementHydrateSupport?.({LitElement:ct});const ht=lt.litElementPolyfillSupport;ht?.({LitElement:ct}),(lt.litElementVersions??=[]).push("4.2.2");const dt=2;let pt=class{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,i){this._$Ct=t,this._$AM=e,this._$Ci=i}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}};const{I:ut}=rt,_t=t=>t,mt=()=>document.createComment(""),gt=(t,e,i)=>{const s=t._$AA.parentNode,o=void 0===e?t._$AB:e._$AA;if(void 0===i){const e=s.insertBefore(mt(),o),n=s.insertBefore(mt(),o);i=new ut(e,n,t,t.options)}else{const e=i._$AB.nextSibling,n=i._$AM,r=n!==t;if(r){let e;i._$AQ?.(t),i._$AM=t,void 0!==i._$AP&&(e=t._$AU)!==n._$AU&&i._$AP(e)}if(e!==o||r){let t=i._$AA;for(;t!==e;){const e=_t(t).nextSibling;_t(s).insertBefore(t,o),t=e}}}return i},ft=(t,e,i=t)=>(t._$AI(e,i),t),vt={},yt=(t,e=vt)=>t._$AH=e,bt=t=>{t._$AR(),t._$AA.remove()},wt=(t,e,i)=>{const s=new Map;for(let o=e;o<=i;o++)s.set(t[o],o);return s},kt=(t=>(...e)=>({_$litDirective$:t,values:e}))(class extends pt{constructor(t){if(super(t),t.type!==dt)throw Error("repeat() can only be used in text expressions")}dt(t,e,i){let s;void 0===i?i=e:void 0!==e&&(s=e);const o=[],n=[];let r=0;for(const e of t)o[r]=s?s(e,r):r,n[r]=i(e,r),r++;return{values:n,keys:o}}render(t,e,i){return this.dt(t,e,i).values}update(t,[e,i,s]){const o=(t=>t._$AH)(t),{values:n,keys:r}=this.dt(e,i,s);if(!Array.isArray(o))return this.ut=r,n;const a=this.ut??=[],l=[];let c,h,d=0,p=o.length-1,u=0,_=n.length-1;for(;d<=p&&u<=_;)if(null===o[d])d++;else if(null===o[p])p--;else if(a[d]===r[u])l[u]=ft(o[d],n[u]),d++,u++;else if(a[p]===r[_])l[_]=ft(o[p],n[_]),p--,_--;else if(a[d]===r[_])l[_]=ft(o[d],n[_]),gt(t,l[_+1],o[d]),d++,_--;else if(a[p]===r[u])l[u]=ft(o[p],n[u]),gt(t,o[d],o[p]),p--,u++;else if(void 0===c&&(c=wt(r,u,_),h=wt(a,d,p)),c.has(a[d]))if(c.has(a[p])){const e=h.get(r[u]),i=void 0!==e?o[e]:null;if(null===i){const e=gt(t,o[d]);ft(e,n[u]),l[u]=e}else l[u]=ft(i,n[u]),gt(t,o[d],i),o[e]=null;u++}else bt(o[p]),p--;else bt(o[d]),d++;for(;u<=_;){const e=gt(t,l[_+1]);ft(e,n[u]),l[u++]=e}for(;d<=p;){const t=o[d++];null!==t&&bt(t)}return this.ut=r,yt(t,l),G}}),$t=new WeakMap;let xt=0;class St extends ct{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._titleId="hp-dialog-title-"+ ++xt,this._focusInitial=()=>{const t=this.querySelector("[autofocus]")||this._focusableElements()[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=t=>{if("Escape"===t.key)return t.preventDefault(),t.stopImmediatePropagation(),void this._requestClose();if("Tab"!==t.key||this._useHaDialog)return;const e=this.renderRoot.querySelector(".close"),i=e?[e,...this._focusableElements()]:this._focusableElements();if(!i.length)return t.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const s=this._deepActiveElement(),o=i[0],n=i[i.length-1];!t.shiftKey||s!==o&&i.includes(s)?t.shiftKey||s!==n||(t.preventDefault(),o.focus()):(t.preventDefault(),n.focus())},this._onFallbackCancel=t=>{t.preventDefault(),this._requestClose()},this._onFallbackClick=t=>{this.dismissOnScrim&&t.target===t.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const t=this.getRootNode();this._focusRoot=t;const e=$t.get(t)||{dialogs:new Set,opener:this._opener};e.dialogs.add(this),$t.set(t,e),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const t=this._focusRoot,e=this._opener;this._opener=null,this._focusRoot=null;const i=t?$t.get(t):void 0;i?.dialogs.delete(this),super.disconnectedCallback(),t&&i&&requestAnimationFrame(()=>{const i=$t.get(t);if(!i)return;if(!i.dialogs.size)return i.opener?.isConnected&&i.opener.focus({preventScroll:!0}),void $t.delete(t);const s=e?.closest("hp-dialog");e?.isConnected&&s&&i.dialogs.has(s)&&e.focus({preventScroll:!0})})}firstUpdated(t){if(super.firstUpdated(t),!this._useHaDialog){const t=this.renderRoot.querySelector("dialog");t&&!t.open&&t.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let t=document.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t&&t!==document.body?t:null}_focusableElements(){const t=["[autofocus]","a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[contenteditable="true"]','[tabindex]:not([tabindex="-1"])'].join(",");return Array.from(this.querySelectorAll(t)).filter(t=>{const e=getComputedStyle(t);return!t.hidden&&"none"!==e.display&&"hidden"!==e.visibility})}render(){const t=B` + ${this.icon?B``:W} ${this.title} - `;return this._useHaDialog?j``;return this._useHaDialog?B`${t} - `:j``:B` - `}}pt.properties={title:{type:String},icon:{type:String},wide:{type:Boolean,reflect:!0},dismissOnScrim:{type:Boolean,attribute:"dismiss-on-scrim"},hass:{attribute:!1}},pt.styles=n` + `}}St.properties={title:{type:String},icon:{type:String},wide:{type:Boolean,reflect:!0},dismissOnScrim:{type:Boolean,attribute:"dismiss-on-scrim"},hass:{attribute:!1}},St.styles=n` :host { display: contents; color: var(--primary-text-color, #e6e7eb); @@ -43,6 +43,13 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 --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; } @@ -184,21 +191,21 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 display: flex; flex-direction: column; } - `,customElements.get("hp-dialog")||customElements.define("hp-dialog",pt);const ut=/^#[0-9a-fA-F]{6}$/;function _t(t,e){return"string"==typeof t&&ut.test(t)?t:e}const mt="(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])",gt=new RegExp(`^rgb\\(${mt}, ${mt}, ${mt}\\)$`);function ft(t){if(!Array.isArray(t)||t.length<3)return null;const e=t.slice(0,3);if(!e.every(t=>"number"==typeof t&&Number.isFinite(t)))return null;const[i,s,o]=e.map(t=>Math.round(Math.min(255,Math.max(0,t))));return`rgb(${i}, ${s}, ${o})`}class vt extends lt{constructor(){super(...arguments),this.label="",this.opacityLabel="Opacity",this.color="#607d8b",this.opacity=1,this.disabled=!1,this.showOpacity=!0,this._open=!1,this._pickerRaf=0,this._outsidePointerDown=t=>{this._open&&!t.composedPath().includes(this)&&this._closePicker()},this._keyDown=t=>{this._open&&"Escape"===t.key&&(t.preventDefault(),t.stopImmediatePropagation(),this._closePicker(!0))},this._queuePickerPosition=()=>{this._open&&(this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._pickerRaf=requestAnimationFrame(()=>{this._pickerRaf=0,this._positionPicker()}))}}connectedCallback(){super.connectedCallback(),document.addEventListener("pointerdown",this._outsidePointerDown,!0),document.addEventListener("scroll",this._queuePickerPosition,!0),window.addEventListener("resize",this._queuePickerPosition),this.addEventListener("keydown",this._keyDown,!0)}disconnectedCallback(){document.removeEventListener("pointerdown",this._outsidePointerDown,!0),document.removeEventListener("scroll",this._queuePickerPosition,!0),window.removeEventListener("resize",this._queuePickerPosition),this.removeEventListener("keydown",this._keyDown,!0),this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._pickerRaf=0,super.disconnectedCallback()}_toggle(){this.disabled||(this._open?this._closePicker():(this._open=!0,this.updateComplete.then(()=>this._positionPicker())))}_closePicker(t=!1){const e=this.renderRoot.querySelector(".picker");if(e?.hidePopover)try{e.matches(":popover-open")&&e.hidePopover()}catch{}this._open=!1,t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_positionPicker(){if(!this._open)return;const t=this.renderRoot.querySelector(".trigger"),e=this.renderRoot.querySelector(".picker");if(!t||!e)return;if(e.style.visibility="hidden",e.showPopover)try{e.matches(":popover-open")||e.showPopover()}catch{}const i=t.getBoundingClientRect(),s=e.getBoundingClientRect(),o=Math.max(8,window.innerWidth-s.width-8);let n=i.left;n+s.width>window.innerWidth-8&&(n=i.right-s.width),n=Math.min(o,Math.max(8,n));const r=i.bottom+7,a=i.top-7-s.height;let l=r;l=r+s.height>window.innerHeight-8&&a>=8?a:Math.min(Math.max(8,l),Math.max(8,window.innerHeight-s.height-8)),e.style.left=`${Math.round(n)}px`,e.style.top=`${Math.round(l)}px`,e.style.visibility=""}_emit(t,e){const i=Number.isFinite(e)?e:Number(this.opacity)||0,s=Math.min(1,Math.max(0,i));this.color=t,this.opacity=s,this.dispatchEvent(new CustomEvent("hp-color-opacity-change",{detail:{color:t,opacity:s},bubbles:!0,composed:!0}))}render(){const t=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),e=_t(this.color,"#607d8b"),i=this.showOpacity?`${this.label||"Color"}: ${e}, ${t}%`:`${this.label||"Color"}: ${e}`;return j` - ${this.label?j`${this.label}`:W} + `,customElements.get("hp-dialog")||customElements.define("hp-dialog",St);const Mt=/^#[0-9a-fA-F]{6}$/;function Ct(t,e){return"string"==typeof t&&Mt.test(t)?t:e}const Dt="(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])",Tt=new RegExp(`^rgb\\(${Dt}, ${Dt}, ${Dt}\\)$`);function Pt(t){if(!Array.isArray(t)||t.length<3)return null;const e=t.slice(0,3);if(!e.every(t=>"number"==typeof t&&Number.isFinite(t)))return null;const[i,s,o]=e.map(t=>Math.round(Math.min(255,Math.max(0,t))));return`rgb(${i}, ${s}, ${o})`}class Rt extends ct{constructor(){super(...arguments),this.label="",this.opacityLabel="Opacity",this.color="#607d8b",this.opacity=1,this.disabled=!1,this.showOpacity=!0,this._open=!1,this._pickerRaf=0,this._outsidePointerDown=t=>{this._open&&!t.composedPath().includes(this)&&this._closePicker()},this._keyDown=t=>{this._open&&"Escape"===t.key&&(t.preventDefault(),t.stopImmediatePropagation(),this._closePicker(!0))},this._queuePickerPosition=()=>{this._open&&(this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._pickerRaf=requestAnimationFrame(()=>{this._pickerRaf=0,this._positionPicker()}))}}connectedCallback(){super.connectedCallback(),document.addEventListener("pointerdown",this._outsidePointerDown,!0),document.addEventListener("scroll",this._queuePickerPosition,!0),window.addEventListener("resize",this._queuePickerPosition),this.addEventListener("keydown",this._keyDown,!0)}disconnectedCallback(){document.removeEventListener("pointerdown",this._outsidePointerDown,!0),document.removeEventListener("scroll",this._queuePickerPosition,!0),window.removeEventListener("resize",this._queuePickerPosition),this.removeEventListener("keydown",this._keyDown,!0),this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._pickerRaf=0,super.disconnectedCallback()}_toggle(){this.disabled||(this._open?this._closePicker():(this._open=!0,this.updateComplete.then(()=>this._positionPicker())))}_closePicker(t=!1){const e=this.renderRoot.querySelector(".picker");if(e?.hidePopover)try{e.matches(":popover-open")&&e.hidePopover()}catch{}this._open=!1,t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_positionPicker(){if(!this._open)return;const t=this.renderRoot.querySelector(".trigger"),e=this.renderRoot.querySelector(".picker");if(!t||!e)return;if(e.style.visibility="hidden",e.showPopover)try{e.matches(":popover-open")||e.showPopover()}catch{}const i=t.getBoundingClientRect(),s=e.getBoundingClientRect(),o=Math.max(8,window.innerWidth-s.width-8);let n=i.left;n+s.width>window.innerWidth-8&&(n=i.right-s.width),n=Math.min(o,Math.max(8,n));const r=i.bottom+7,a=i.top-7-s.height;let l=r;l=r+s.height>window.innerHeight-8&&a>=8?a:Math.min(Math.max(8,l),Math.max(8,window.innerHeight-s.height-8)),e.style.left=`${Math.round(n)}px`,e.style.top=`${Math.round(l)}px`,e.style.visibility=""}_emit(t,e){const i=Number.isFinite(e)?e:Number(this.opacity)||0,s=Math.min(1,Math.max(0,i));this.color=t,this.opacity=s,this.dispatchEvent(new CustomEvent("hp-color-opacity-change",{detail:{color:t,opacity:s},bubbles:!0,composed:!0}))}render(){const t=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),e=Ct(this.color,"#607d8b"),i=this.showOpacity?`${this.label||"Color"}: ${e}, ${t}%`:`${this.label||"Color"}: ${e}`;return B` + ${this.label?B`${this.label}`:W} - ${this._open&&!this.disabled?j` + ${this._open&&!this.disabled?B` - ${t.visualSources.length||t.criticalSources.length?j`
+ ${t.visualSources.length||t.criticalSources.length?B`
${this._t("marker.preview.details")}
- ${[...t.visualSources,...t.criticalSources].map(t=>j` + ${[...t.visualSources,...t.criticalSources].map(t=>B`
${t.name}${t.eid} ${t.stateText||t.state} @@ -3248,14 +3316,14 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
`)}
`:W} - ${"icon_ripple"===t.display?j``:W} - `}}sn.properties={hass:{attribute:!1},presentation:{attribute:!1},registry:{attribute:!1},deviceName:{attribute:!1}},sn.styles=[yt,n` + `}}pn.properties={hass:{attribute:!1},presentation:{attribute:!1},registry:{attribute:!1},deviceName:{attribute:!1}},pn.styles=[At,n` :host { display: block; min-width: 0; } .devicepreview { margin: 4px 0 14px; @@ -3321,48 +3389,48 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 .previewstage { min-height: 142px; } .previewfacts > div { grid-template-columns: minmax(0, 1fr); gap: 2px; } } - `],customElements.get("hp-device-preview")||customElements.define("hp-device-preview",sn);const on=(t,e)=>[t[0]-e[0],t[1]-e[1]],nn=(t,e)=>[t[0]+e[0],t[1]+e[1]],rn=(t,e)=>t[0]*e[0]+t[1]*e[1],an=t=>Math.hypot(t[0],t[1]);function ln(t){let e=0;for(let i=0;it[1]!=l>t[1]&&t[0]<(a-n)*(t[1]-r)/(l-r)+n&&(i=!i)}return i}([a[0]+r[0]*l,a[1]+r[1]*l],t)&&(r=[-r[0],-r[1]]),r}function dn(t,e,i,s){const o=s||hn(t,e),n=(e+1)%t.length;return t.map((t,s)=>s===e||s===n?[t[0]+o[0]*i,t[1]+o[1]*i]:[...t])}function pn(t,e,i,s){const o=[],n=on(i,e),r=an(n);if(rs||h>s)continue;const d=rn(on(n,e),a),p=rn(on(l,e),a),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));_-u>s&&o.push([[e[0]+a[0]*u,e[1]+a[1]*u],[e[0]+a[0]*_,e[1]+a[1]*_]])}return o}function un(t,e,i,s,o){const n=pn(t,e,i,o);if(!n.length)return null;const r=t=>n.some(([e,i])=>cn(t,e,i)<=o),a=t.length,l=[];for(let n=0;no||f>o)continue;const v=rn(on(e,c),u),y=rn(on(i,c),u),b=Math.max(0,Math.min(v,y)),w=Math.min(p,Math.max(v,y));if(!(w-b<=o)){if(b>o&&bo&&wan(on(i,t[(s+1)%t.length]))>e);for(let t=0;t<2;t++)i=i.filter((t,s)=>{const o=i[(s-1+i.length)%i.length],n=i[(s+1)%i.length],r=(t[0]-o[0])*(n[1]-o[1])-(t[1]-o[1])*(n[0]-o[0]),a=an(on(n,o))||1;return Math.abs(r)/a>e});return i.length>=3?i:t}function mn(t){const e=t.length;if(e<3)return!1;for(let i=0;i(t[0]-o[0])*a[1]-(t[1]-o[1])*a[0],c=t=>(t[0]-o[0])*a[0]+(t[1]-o[1])*a[1],h=i,d=r-i;for(const e of t){const t=Math.abs(l(e));if(t<=i)continue;const o=c(e);o<=h||o>=d||tMath.abs(r+(t-p)/g*(a-r));s=Math.min(s,f(_),f(m))}}return s}function fn(t,e,i){if(ei(t,e,i))return!0;if(ti(t,e,i)||ti(e,t,i))return!1;let s=0;try{const i=Re([[...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 i)t?.[0]&&(s+=si(t[0]))}catch{return!1}return s>Math.max(1e-7,i*i)}function vn(t,e,i,s,o){const n=[i.n[0]*s,i.n[1]*s],r={polys:{},openings:{},movedSpans:{}};if(Math.abs(s)<1e-9)return r;for(const e of t){if(e.id===i.roomId){r.polys[e.id]=dn(e.poly,i.edge,s,i.n),r.movedSpans[e.id]=[[nn(i.a,n),nn(i.b,n)]];continue}const t=pn(e.poly,i.a,i.b,o);if(!t.length)continue;const a=un(e.poly,i.a,i.b,n,o);a&&(r.polys[e.id]=a,r.movedSpans[e.id]=t.map(([t,e])=>[nn(t,n),nn(e,n)]))}for(const t of e)cn([t.x,t.y],i.a,i.b)<=o&&(r.openings[t.id]=[t.x+n[0],t.y+n[1]]);return r}function yn(t,e,i){for(const s of e)for(let e=0;ei)continue;const c=(t.x-o[0])*l[0]+(t.y-o[1])*l[1];if(c-t.length/2>=-i&&c+t.length/2<=a+i)return!0}return!1}function bn(t,e,i){return t.filter(t=>e.some(e=>{for(let s=0;sa.polys[t.id]||t.poly;for(const e of l){const s=t.find(t=>t.id===e),o=a.polys[e];if(!mn(o))return!1;const l=ln(s.poly),h=ln(o);if(Math.abs(h)t.find(t=>t.id===e).poly),d=t.map(c);for(const t of bn(e,h,2*r)){const e=a.openings[t.id];if(!yn(e?{...t,x:e[0],y:e[1]}:t,d,2*r))return!1}return!0}function kn(t,e,i,s,o,n){const r=t=>[s[0]+(t[0]-s[0])*o,s[1]+(t[1]-s[1])*o],a={poly:t.poly.map(r),openings:{}};for(const s of e){let e=!1;for(let i=0;i{for(let e=0;et.id===i);if(!l)return!1;const c=t.filter(t=>t.id!==i).map(t=>t.poly),h=kn(l,e,c,s,o,2*a),d=h.poly,p=function(t){const e=function(t){const e=[...t].sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(e.length<3)return e;const i=(t,e,i)=>(e[0]-t[0])*(i[1]-t[1])-(e[1]-t[1])*(i[0]-t[0]),s=[];for(const t of e){for(;s.length>=2&&i(s[s.length-2],s[s.length-1],t)<=0;)s.pop();s.push(t)}const o=[];for(let t=e.length-1;t>=0;t--){const s=e[t];for(;o.length>=2&&i(o[o.length-2],o[o.length-1],s)<=0;)o.pop();o.push(s)}return s.pop(),o.pop(),s.concat(o)}(t);if(e.length<3)return 0;let i=1/0;for(let t=0;tt.id===i?d:t.poly);for(const t of bn(e,[l.poly],2*a)){const e=h.openings[t.id];if(!yn(e?{...t,x:e[0],y:e[1]}:t,u,2*a))return!1}return!0}function xn(t,e,i){const s=i/e;return si(t)*s*s/1e4}function Sn(t,e){return e?`${Math.round(10.7639*t)} ft²`:`${(Math.round(10*t)/10).toFixed(1)} m²`}const Mn=[[-90,"#070c14"],[-12,"#070c14"],[-4,"#131a28"],[0,"#4a3527"],[10,"#e8ddcf"],[30,"#ffffff"],[90,"#ffffff"]],Cn=t=>Math.min(1,Math.max(0,t));function Dn(t){const e=Math.min(90,Math.max(-90,Number(t)||0));let i=Mn[Mn.length-1][1];for(let t=1;t{const n=[t.x+o[0]*i*s,t.y+o[1]*i*s];return e.find(t=>t.poly.length>=3&&Be(n,t.poly))||null},r=n(1),a=n(-1);return r&&a?null:r||a?r?{normal:[-o[0],-o[1]],roomId:r.id}:{normal:o,roomId:a.id}:null}function Pn(t,e,i){return i>0&&t[0]*e[0]+t[1]*e[1]>.05}function Rn(t,e,i,s){return[[t[0],t[1]],[e[0],e[1]],[e[0]+i[0]*s,e[1]+i[1]*s],[t[0]+i[0]*s,t[1]+i[1]*s]]}function zn(t,e){try{const i=Re([[...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]]]]),s=[];for(const t of i){const e=t?.[0];!Array.isArray(e)||e.length<4||s.push(e.slice(0,e.length-1).map(t=>[t[0],t[1]]))}return s}catch{return[]}}function An(t,e,i,s,o,n,r){if(!(s>0))return[];const a=function(t,e){const i=function(t,e){return function(t){const e=t%360;return e<0?e+360:e}(t-e)}(t,e)*Math.PI/180;return[Math.sin(i),-Math.cos(i)]}(i,o),l=[-a[0],-a[1]],c=function(t){const e=Math.min(90,Math.max(0,t));return.7*(.8+1.7*Math.pow(1-e/90,1.6))}(s),h=[];for(const i of e){if(!(i.length>0))continue;const e=Tn(i,t);if(!e||!Pn(e.normal,a,s))continue;const o=t.find(t=>t.id===e.roomId);if(!o)continue;const d=n&&n[e.roomId]||o.poly,p=i.angle*Math.PI/180,u=i.length/2,_=[-e.normal[0],-e.normal[1]],m=Math.max(0,r?.[i.id]||0),g=i.x+_[0]*m/2,f=i.y+_[1]*m/2,v=Math.cos(p)*u,y=Math.sin(p)*u,b=[g-v,f-y],w=[g+v,f+y],k=c*i.length,$=zn(Rn(b,w,l,k),d);if(!$.length)continue;const x=l[0]*_[0]+l[1]*_[1];h.push({openingId:i.id,roomId:e.roomId,polys:$,a:b,b:w,dir:l,len:k,normal:_,depth:k*x})}return h}function In(t){return Math.round(10*(Number(t)||0))/10}const En=t=>"number"==typeof t&&Number.isInteger(t)&&t>=0&&t<=359?t:null;function Nn(t,e){const i=En(e?.north_deg);return null!==i?i:En(t?.north_deg)}function Fn(t,e){const i=t=>"static"===t||"daynight"===t?t:null;return i(e?.bg_mode)??i(t?.bg_mode)??"static"}function On(t,e){const i=e?.sun_rays;return"boolean"==typeof i?i:!0===t?.sun_rays}function Ln(t){const e=t?.states?.["sun.sun"]?.attributes,i=Number(e?.azimuth),s=Number(e?.elevation);return Number.isFinite(i)&&Number.isFinite(s)?{azimuth:i,elevation:s}:null}const Hn={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},qn=(t,e=1)=>{const i=Number(t);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):e},Un=t=>{let e=Number(t);return Number.isFinite(e)?(e=(e%360+360)%360,e>180?e-360:e):0};function jn(t,e,i){return Un(e)?[t.x,t.y]:i([t.x,t.y])}const Bn=(t,e,i)=>{const s=Number(t),o=Number.isFinite(e)&&e>0?e:5;return Number.isFinite(s)&&s>0?s/o*i:0},Gn=(t,e,i)=>{const s=Number(t),o=Number.isFinite(e)&&e>0?e:5;return Number.isFinite(s)&&i>0?s/i*o:0},Wn=(t,e,i,s=Hn.widthCm)=>{const o=Number(t?.width_cm);if(Number.isFinite(o)&&o>0)return o;const n=Number(t?.width);return Number.isFinite(n)&&n>0?Gn(n,e,i):s};function Vn(t,e){return{color:t.color,opacity:qn(t.opacity),width_cm:Math.max(.1,Math.min(100,Number(t.widthCm)||.1)),...e?{fill:t.fill,fill_color:t.fillColor,fill_opacity:qn(t.fillOpacity,.25)}:{}}}function Kn(t){const e=t.x+t.w/2,i=t.y+t.h/2,s=Un(t.angle)*Math.PI/180,o=Math.cos(s),n=Math.sin(s),r=(t,s)=>{const r=t-e,a=s-i;return[e+r*o-a*n,i+r*n+a*o]};return[r(t.x,t.y),r(t.x+t.w,t.y),r(t.x+t.w,t.y+t.h),r(t.x,t.y+t.h)]}function Yn(t){const e=Kn(t),i=(t,e)=>[(t[0]+e[0])/2,(t[1]+e[1])/2],s=[(e[0][0]+e[2][0])/2,(e[0][1]+e[2][1])/2];return{points:[...e,i(e[0],e[1]),i(e[1],e[2]),i(e[2],e[3]),i(e[3],e[0]),s],segments:e.map((t,i)=>({a:t,b:e[(i+1)%4]}))}}function Jn(t,e,i,s,o,n,r,a){const l=Un(t.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),p=Math.cos(l),u=t.x+t.w/2,_=t.y+t.h/2,m=e>0?-t.w/2:t.w/2,g=i>0?-t.h/2:t.h/2,f=u+m*c+g*d,v=_+m*h+g*p,y=s-f,b=o-v;let w=(y*c+b*h)*(e>0?1:-1),k=(y*d+b*p)*(i>0?1:-1),$=null;if(n){const e=w/Math.max(t.w,a),i=k/Math.max(t.h,a);$=Math.max(a/Math.max(t.w,a),a/Math.max(t.h,a),e,i),w=t.w*$,k=t.h*$}if(r>0)if(n){const e=Math.max(1,Math.round(t.w/r)),i=Math.max(1,Math.round(t.h/r));if(Math.abs(t.w-e*r)<1e-6&&Math.abs(t.h-i*r)<1e-6){const s=(t,e)=>{let i=Math.abs(t),s=Math.abs(e);for(;s;)[i,s]=[s,i%s];return Math.max(1,i)},o=1/s(e,i),n=Math.max(a/t.w,a/t.h),r=Math.max(n,Math.round(($??1)/o)*o);w=t.w*r,k=t.h*r}else{t.w>=t.h?(w=Math.round(w/r)*r,k=w*(t.h/Math.max(t.w,a))):(k=Math.round(k/r)*r,w=k*(t.w/Math.max(t.h,a)))}}else w=Math.round(w/r)*r,k=Math.round(k/r)*r;w=Math.max(a,w),k=Math.max(a,k);return{x:f+(e>0?w/2:-w/2)*c+(i>0?k/2:-k/2)*d-w/2,y:v+(e>0?w/2:-w/2)*h+(i>0?k/2:-k/2)*p-k/2,w:w,h:k,angle:Un(t.angle)||void 0}}const Zn=(t,e,i)=>{const s=i[0]-e[0],o=i[1]-e[1],n=s*s+o*o;if(n<1e-12)return[...e];const r=Math.max(0,Math.min(1,((t[0]-e[0])*s+(t[1]-e[1])*o)/n));return[e[0]+s*r,e[1]+o*r]};const Xn=15;function Qn(t,e){return Number.isFinite(t)&&t>0&&Number.isFinite(e)&&e>0&&t*e<3}function tr(t){return Number.isFinite(t)?Math.max(1,Math.min(100,t)):1}function er(t,e){return!Number.isFinite(t)||t<=0?"":String(e?Math.round(t/2.54*100)/100:Math.round(100*t)/100)}function ir(t,e,i){const s=Number(e)>0?Number(e):5;return tr(t)/s*i}function sr(t,e){return e>0&&Number.isFinite(t)?Math.round(t/e)*e:t}function or(t,e){let i=e[0]-t[0],s=e[1]-t[1];const o=Math.hypot(i,s);return o<1e-12?[1,0]:(i/=o,s/=o,(i<-1e-12||Math.abs(i)<=1e-12&&s<0)&&(i=-i,s=-s),[i,s])}function nr(t,e,i){const s=sr((t[0]+e[0])/2,i),o=sr((t[1]+e[1])/2,i),[n,r]=or(t,e);let a=Math.atan2(r,n);a<0&&(a+=Math.PI);const l=Math.round(1800*a)/1800,c=i>0&&i<.01?6:i<1?4:2;return`${s.toFixed(c)},${o.toFixed(c)}@${l.toFixed(4)}`}function rr(t,e,i,s){return 1===s?nr(t,e,i):nr([t[0]/s,t[1]/s],[e[0]/s,e[1]/s],i)}function ar(t,e){if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return null;const i=[Number(t.a[0]),Number(t.a[1]),Number(t.b[0]),Number(t.b[1])];if(!i.every(Number.isFinite))return null;const s=e>0?e:1;return[[i[0]*s,i[1]*s],[i[2]*s,i[3]*s]]}function lr(t,e,i,s,o){const n=o>0?o:1;return{key:rr(t,e,s,n),cm:tr(i),a:[t[0]/n,t[1]/n],b:[e[0]/n,e[1]/n]}}function cr(t,e){const i=e>0?e:1,s=[];for(const e of t){const t=e.key.lastIndexOf("@");if(t<0)continue;const[o,n]=e.key.slice(0,t).split(",").map(Number),r=Number(e.key.slice(t+1));[o,n,r].every(Number.isFinite)&&s.push({w:e,x:o*i,y:n*i,ang:r})}return s}function hr(t,e){const[i,s]=or(t,e);let o=Math.atan2(s,i);return o<0&&(o+=Math.PI),o}function dr(t,e){let i=Math.abs(t-e);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function pr(t,e,i,s,o=1){if(!t?.length)return null;const n=rr(e,i,s,o),r=t.find(t=>t.key===n);if(r)return r;const a=o>0?o:1,l=(e[0]+i[0])/2,c=(e[1]+i[1])/2,h=hr(e,i),d=Math.max(.5*s,1e-9)*a;for(const e of cr(t,a))if(dr(e.ang,h)&&Math.hypot(e.x-l,e.y-c)<=d)return e.w;return null}function ur(t,e,i,s,o=1){const n=pr(t,e,i,s,o);return n&&n.cm>0?tr(n.cm):0}function _r(t,e,i,s=1,o=[]){if(!t?.length)return[];const n=new Set,r=Le(e);for(const t of r)n.add(rr([t[0],t[1]],[t[2],t[3]],i,s));const a=e||[],l=Math.max(i*s*.02,1e-9);for(let t=0;t(n.has(t.key)||(t=>{const e=ar(t,s);if(!e)return!1;const[i,n]=e,a=n[0]-i[0],c=n[1]-i[1],h=Math.hypot(a,c);if(h<=l)return!1;if(!r.some(t=>{const e=[t[0],t[1]],s=[t[2],t[3]];return dr(hr(i,n),hr(e,s))&&Ir(i[0],i[1],e[0],e[1],s[0],s[1])<=l&&Ir(n[0],n[1],e[0],e[1],s[0],s[1])<=l}))return!1;const d=(o||[]).some(t=>{const e=[t[0],t[1]],s=[t[2],t[3]];if(!dr(hr(i,n),hr(e,s)))return!1;const o=t=>Math.abs((t[0]-i[0])*c-(t[1]-i[1])*a)/h;if(o(e)>l||o(s)>l)return!1;const r=h*h,d=((e[0]-i[0])*a+(e[1]-i[1])*c)/r,p=((s[0]-i[0])*a+(s[1]-i[1])*c)/r;return Math.min(1,Math.max(d,p))-Math.max(0,Math.min(d,p))>l/h});return!d})(t))&&t.cm>=1&&t.cm<=100)}function mr(t,e,i,s=8){const[o,n]=or(t,e);let r=Math.atan2(n,o);r<0&&(r+=Math.PI);let a=i*Math.PI/180%Math.PI;a<0&&(a+=Math.PI);let l=Math.abs(r-a);return l>Math.PI/2&&(l=Math.PI-l),l<=s*Math.PI/180}function gr(t,e,i,s,o=1){if(!t?.length)return[];if(e.length!==i.length)return t.slice();const n=new Map;for(let t=0;t0?o:1,a=Math.max(.5*s,1e-9)*r,l=new Set,c=[];for(const o of t){let t="",h=null;const d=ar(o,r);if(d)for(let o=0;oa||Ir(d[1][0],d[1][1],n[0],n[1],l[0],l[1])>a)continue;const u=l[0]-n[0],_=l[1]-n[1],m=u*u+_*_;if(m<1e-18)continue;const g=t=>{const e=Math.max(0,Math.min(1,((t[0]-n[0])*u+(t[1]-n[1])*_)/m));return[c[0]+(p[0]-c[0])*e,c[1]+(p[1]-c[1])*e]};h=[g(d[0]),g(d[1])],t=rr(h[0],h[1],s,r);break}if(d||(t=n.get(o.key)||""),!t){const n=cr([o],r)[0];if(n)for(let o=0;o1.000001)continue;if(Ir(n.x,n.y,l[0],l[1],c[0],c[1])>a)continue;const g=h[0]+(d[0]-h[0])*Math.max(0,Math.min(1,m)),f=h[1]+(d[1]-h[1])*Math.max(0,Math.min(1,m)),[v,y]=or(h,d),b=Math.max(s*r,1e-6);t=rr([g-v*b,f-y*b],[g+v*b,f+y*b],s,r);break}}t||(t=o.key),l.has(t)||(l.add(t),c.push(h?lr(h[0],h[1],o.cm,s,r):{...o,key:t,cm:tr(o.cm)}))}return c}function fr(t,e,i,s,o,n=1){const r=rr(e,i,o,n),a=(t||[]).filter(t=>t.key!==r);return null==s||s<1?a:[...a,lr(e,i,s,o,n)]}function vr(t,e,i,s,o,n=[],r=1){let a=t?t.slice():[];for(const t of function(t,e,i,s,o=1,n=[]){const r=Dr(t,e,i,s,o,n);if(!r)return[];const a=[];for(let t=0;t0)||!t||t.length<2)return"";if(i&&t.length>=3){let i=t;const s=t[t.length-1];if(t.length>=4&&Math.hypot(t[0][0]-s[0],t[0][1]-s[1])<1e-9&&(i=t.slice(0,-1)),i.length>=3){const t=i.map(()=>e),s=Or(i,t),o=Sr(i,t);if(s&&o)return`${Mr(s)} ${Mr(Cr(o))}`}}let s="";for(let i=0;i.05)&&Ir(r,a,t[0],t[1],t[2],t[3])<=n)return!0}return!1}function wr(t,e){return Math.max(t*(e>0?e:1)*.04,1e-9)}function kr(t,e){const i=t[e],s=t[(e+1)%t.length],o=s[0]-i[0],n=s[1]-i[1],r=Math.hypot(o,n)||1;let a=-n/r,l=o/r;const c=[(i[0]+s[0])/2,(i[1]+s[1])/2];return function(t,e){let i=!1;for(let s=0,o=e.length-1;st[1]!=l>t[1]&&t[0]<(a-n)*(t[1]-r)/(l-r+0)+n&&(i=!i)}return i}([c[0]+.001*a,c[1]+.001*l],t)||(a=-a,l=-l),[a,l]}function $r(t,e){const i=t[0]*e[1]-t[1]*e[0],s=t[0]*e[0]+t[1]*e[1];return Math.abs(i)<1e-9&&s>0}function xr(t,e,i,s){const o=e[0]*s[1]-e[1]*s[0];if(Math.abs(o)<1e-12)return null;const n=[i[0]-t[0],i[1]-t[1]],r=(n[0]*s[1]-n[1]*s[0])/o;return[t[0]+r*e[0],t[1]+r*e[1]]}function Sr(t,e){const i=t?.length||0;if(i<3||e.length!==i)return null;if(e.every(t=>!(t>0)))return t.map(t=>[t[0],t[1]]);const s=[];for(let o=0;o0||d>0)){s.push([t[o][0],t[o][1]]);continue}if($r(b,w)){const e=t[o],i=[e[0]+p*h,e[1]+u*h],n=[e[0]+_*d,e[1]+m*d];s.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&s.push(n);continue}const x=xr(k,b,$,w),S=Math.max(h,d,1e-9);if(x){if(Math.hypot(x[0]-t[o][0],x[1]-t[o][1])<=4*S){s.push(x);continue}}h>0&&s.push([t[o][0]+p*h,t[o][1]+u*h]),d>0&&s.push([t[o][0]+_*d,t[o][1]+m*d]),h>0||d>0||s.push([t[o][0],t[o][1]])}return s.length>=3?s:null}function Mr(t,e=!0){if(!t.length)return"";let i=`M ${t[0][0]} ${t[0][1]}`;for(let e=1;et?.id===e),a=Fe(r);if(!a||a.length<3)return null;const l=wr(s,o),c=[];for(const i of t||[]){if(!i||i.id===e)continue;const t=Fe(i);if(t)for(const e of ss(a,t,l))c.push([e[0],e[1]],[e[2],e[3]])}for(const t of i||[])c.push([t[0],t[1]],[t[2],t[3]]);for(const t of n||[]){const e=ar(t,o);e&&c.push(e[0],e[1])}const h=[],d=[];for(let t=0;tl)continue;const r=((t[0]-e[0])*(i[0]-e[0])+(t[1]-e[1])*(i[1]-e[1]))/(s*s);r<=o||r>=1-o||(n.some(t=>Math.abs(t-r)*s<=2*l)||n.push(r))}n.sort((t,e)=>t-e);for(const s of n)h.push([e[0]+(i[0]-e[0])*s,e[1]+(i[1]-e[1])*s]),d.push(t)}return{poly:h,parent:d,orig:a}}function Tr(t,e,i,s){const o=e.poly.length,n=new Array(o).fill(0);if(!t?.length)return n;const r=new Set,a=[];for(let l=0;l0?(n[l]=tr(c.cm),r.add(c.key)):a.push(l)}if(!a.length)return n;const l=s>0?s:1,c=Math.max(.5*i,1e-9)*l,h=cr(t,l).filter(t=>t.w.cm>0),d=new Map;for(const t of a){const i=e.parent[t],s=d.get(i);s?s.push(t):d.set(i,[t])}for(const[t,i]of d){const s=e.orig[t],o=e.orig[(t+1)%e.orig.length],a=hr(s,o),d=(s[0]+o[0])/2,p=(s[1]+o[1])/2;let u=null;const _=Math.hypot(o[0]-s[0],o[1]-s[1]);for(const t of h){if(r.has(t.w.key))continue;if(!dr(t.ang,a))continue;const e=ar(t.w,l);let i=!1,n=0;if(e){if(!dr(hr(e[0],e[1]),a))continue;if(Ir(s[0],s[1],e[0][0],e[0][1],e[1][0],e[1][1])>c||Ir(o[0],o[1],e[0][0],e[0][1],e[1][0],e[1][1])>c)continue;i=!0,n=Math.max(0,Math.hypot(e[1][0]-e[0][0],e[1][1]-e[0][1])-_)}else{if(Ir(t.x,t.y,s[0],s[1],o[0],o[1])>c)continue;n=Math.hypot(t.x-d,t.y-p)}(!u||i&&!u.exact||i===u.exact&&nt?.id===e),o=Fe(s);if(!o)return[];const n=[];for(const s of t||[]){if(!s||s.id===e)continue;const t=Fe(s);if(t)for(const e of ss(o,t,i))n.push(e)}return n}(t,e,wr(o,a)),h=function(t,e,i,s,o){const n=wr(s,o),r=[];for(let a=0;aIr(h,d,t[0],t[1],t[2],t[3])<=n);r.push(p?"shared":"outer")}return r}(l.poly,c,s,o,a),d=Tr(i,l,o,a),p=d.map((t,e)=>h[e]&&t>0?ir(t,n,r)/2:0);return{...l,kinds:h,cms:d,offsets:p}}function Rr(t,e,i,s,o,n,r=1){const a=[];for(const l of t||[]){if(!l?.id)continue;const c=Pr(t,l.id,e,i,s,o,n,r);if(c)for(let t=0;t0&&!l.has(c.key)&&(l.add(c.key),a.push(c));const c=[];for(const a of t||[]){if(!a?.id)continue;const l=Pr(t,a.id,e,i,s,o,n,r);if(l)for(let t=0;t0)||null===l.kinds[i]){t++;continue}let n=t;for(;n+10&&c.push({a:[h[0],h[1]],b:[d[0],d[1]],key:rr(h,d,s,r),cm:o,len:p}),t=n+1}}}c.sort((t,e)=>e.len-t.len||t.key.localeCompare(e.key));const h=[],d=new Set,p=new Set,u=4*wr(s,r);for(const t of c){const e=a.filter(e=>!p.has(e.key)&&e.cm===t.cm&&dr(hr(e.a,e.b),hr(t.a,t.b))&&Ir(e.a[0],e.a[1],t.a[0],t.a[1],t.b[0],t.b[1])<=u&&Ir(e.b[0],e.b[1],t.a[0],t.a[1],t.b[0],t.b[1])<=u);if(e.length){for(const t of e)p.add(t.key);d.has(t.key)||(d.add(t.key),h.push(lr(t.a,t.b,t.cm,s,r)))}}for(const t of a)p.has(t.key)||d.has(t.key)||(d.add(t.key),h.push(lr(t.a,t.b,t.cm,s,r)));return h}function Ar(t,e,i,s,o,n,r,a=1){const l=wr(o,a),c=(s[0]+s[2])/2,h=(s[1]+s[3])/2,d=hr([s[0],s[1]],[s[2],s[3]]);let p=null;for(const s of Rr(t,e,i,o,n,r,a)){if(!dr(hr(s.a,s.b),d))continue;const t=Ir(c,h,s.a[0],s.a[1],s.b[0],s.b[1]);t>4*l||(!p||tt?.id===e),c=Fe(l);if(!c||c.length<3)return null;if(!i?.length)return c.map(t=>[t[0],t[1]]);const h=Pr(t,e,i,s,o,n,r,a);return h&&h.offsets.some(t=>t>0)&&Sr(h.poly,h.offsets)||c.map(t=>[t[0],t[1]])}function Nr(t){const e=t.map(t=>[t[0],t[1]]);return e.push([t[0][0],t[0][1]]),[e]}function Fr(t,e,i,s=[],o,n,r,a=1,l=[]){if(!e?.length&&!l.length)return null;const c=[];let h=0;for(const s of t||[]){if(!s?.id)continue;const l=Pr(t,s.id,e,i,o,n,r,a);if(!l||l.poly.length<3||!l.offsets.some(t=>t>0))continue;for(const t of l.offsets)t>0&&(h=Math.max(h,2*t));const d=Or(l.poly,l.offsets),p=Sr(l.poly,l.offsets);d&&c.push({outset:d,inset:p})}for(const t of l){const e=t.map(t=>t[0]),i=t.map(t=>t[1]);if(e.length){const s=Math.min(Math.max(...e)-Math.min(...e),Math.max(...i)-Math.min(...i)),o=Math.min(...t.map((e,i)=>{const s=t[(i+1)%t.length];return Math.hypot(s[0]-e[0],s[1]-e[1])}));h=Math.max(h,t.length>16?s:o)}}const d=function(t,e,i,s,o,n,r){if(!e?.length||!i?.length)return[];const a=4*wr(s,r),l=new Map;for(const a of Rr(t,e,i,s,o,n,r))!a.open&&a.half>0&&!l.has(a.key)&&l.set(a.key,a);const c=[...l.values()];if(c.length<2)return[];const h=[];for(const t of i)for(const e of[[t[0],t[1]],[t[2],t[3]]])h.some(t=>Math.hypot(t[0]-e[0],t[1]-e[1])<=a)||h.push(e);const d=[],p=(t,e)=>{let i=0,s=0;if(Math.hypot(t.a[0]-e[0],t.a[1]-e[1])<=a)i=t.b[0]-t.a[0],s=t.b[1]-t.a[1];else{if(!(Math.hypot(t.b[0]-e[0],t.b[1]-e[1])<=a))return null;i=t.a[0]-t.b[0],s=t.a[1]-t.b[1]}const o=Math.hypot(i,s);return o>a?[i/o,s/o]:null};for(const t of h){const e=c.map(e=>({iv:e,u:p(e,t)})).filter(t=>!!t.u);for(let i=0;i4*_||d.push(r>0?[t.slice(),h,u,p]:[t.slice(),p,u,h])}}return d}(t,e,i,o,n,r,a),p=s.length?Hr(t,e,i,o,n,r,a):null;try{const t=t=>{const e=Nr(t.outset);return t.inset?ze(e,Nr(t.inset)):e};let e=c.length?t(c[0]):null;for(let i=1;i0))continue;const i=jr(p,t,!0);if(!i.negative&&!i.positive)continue;const s=t.angle*Math.PI/180,n=Math.cos(s),r=Math.sin(s),l=-r,c=n,d=t.length/2,u=1.25*Math.max(h,o*a),_=[[t.x-n*d-l*u,t.y-r*d-c*u],[t.x+n*d-l*u,t.y+r*d-c*u],[t.x+n*d+l*u,t.y+r*d+c*u],[t.x-n*d+l*u,t.y-r*d+c*u]];e&&(e=ze(e,Nr(_)))}for(const t of l)t.length<3||(e=e?Pe(e,Nr(t)):[Nr(t)]);const i=function(t){if(!t)return"";let e="";for(const i of t)if(Array.isArray(i))for(const t of i){if(!Array.isArray(t)||t.length<4)continue;const i=t.slice(0,t.length-1);i.length<3||(e+=(e?" ":"")+Mr(i.map(t=>[t[0],t[1]])))}return e}(e);return i?{d:i,depthUnits:h,fillRule:"evenodd"}:null}catch{const s=function(t,e,i,s,o,n,r=1){if(!e?.length)return[];const a=[];for(const l of t||[]){if(!l?.id)continue;const c=Pr(t,l.id,e,i,s,o,n,r);if(!c||c.poly.length<3||!c.offsets.some(t=>t>0))continue;const h=Or(c.poly,c.offsets),d=Sr(c.poly,c.offsets);if(!h||!d)continue;const p=`${Mr(h)} ${Mr(Cr(d))}`;let u="",_="outer",m=0,g=0;for(let t=0;t0){u=rr(c.poly[t],c.poly[(t+1)%c.poly.length],s,r),_=c.kinds[t]||"outer",m=c.cms[t],g=ir(m,o,n);break}a.push({d:p,key:u,kind:_,cm:m,depthUnits:g})}return a}(t,e,i,o,n,r,a),c=l.map(t=>Mr(t)).join(" ");return s.length||c?{d:[s.map(t=>t.d).join(" "),c].filter(Boolean).join(" "),depthUnits:h,fillRule:"nonzero"}:null}}function Or(t,e){const i=t?.length||0;if(i<3||e.length!==i)return null;if(e.every(t=>!(t>0)))return t.map(t=>[t[0],t[1]]);Cr(t),e.slice().reverse();const s=[];for(let o=0;o0||a>0)){s.push([t[o][0],t[o][1]]);continue}if($r(b,w)){const e=t[o],i=[e[0]-l*r,e[1]-c*r],n=[e[0]-h*a,e[1]-d*a];s.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&s.push(n);continue}const x=xr(k,b,$,w),S=Math.max(r,a,1e-9);if(x){if(Math.hypot(x[0]-t[o][0],x[1]-t[o][1])<=4*S){s.push(x);continue}}r>0&&s.push([t[o][0]-l*r,t[o][1]-c*r]),a>0&&s.push([t[o][0]-h*a,t[o][1]-d*a])}return s.length>=3?s:null}function Lr(t,e,i,s,o,n,r=1){const a=[];for(const l of t||[]){const c=Fe(l);if(c&&c.length>=3){const h=Pr(t,l.id,e,i,s,o,n,r),d=h&&h.offsets.some(t=>t>0)?Or(h.poly,h.offsets):null,p=d||c;a.push({poly:p.map(t=>t.join(",")).join(" ")})}else l&&null!=l.x&&null!=l.y&&null!=l.w&&null!=l.h&&a.push({rect:{x:l.x,y:l.y,w:l.w,h:l.h,rx:.03*Math.min(l.w,l.h)}})}return a}function Hr(t,e,i,s,o,n,r=1){const a=[];for(const l of t||[]){if(!l?.id)continue;const c=Pr(t,l.id,e,i,s,o,n,r);if(!c)continue;const h=Math.abs(si(c.poly));for(let t=0;t[Math.max(e,t.x0),Math.min(i,t.x1)]).filter(t=>t[1]-t[0]>s).sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(!o.length)return{coverage:0,full:!1};let n=o[0][0],r=o[0][1],a=0,l=n<=e+s;for(let t=1;t=i-s,{coverage:a,full:l}}function Ur(t,e){return Number(e.full)-Number(t.full)||t.faceDistance-e.faceDistance||t.area-e.area||t.roomId.localeCompare(e.roomId)}function jr(t,e,i=!1){const s=Number(e?.x),o=Number(e?.y),n=Number(e?.angle),r=Number(e?.length);if(!([s,o,n,r].every(Number.isFinite)&&r>0))return{negative:null,positive:null};const a=n*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,p=r/2,u=Math.max(1e-9,t.adjacencyEps),_=new Map;let m=0;for(const e of t.edges){if(i&&!(e.half>0))continue;if(!mr(e.a,e.b,n))continue;const[t,r]=or(e.a,e.b);if(Math.abs((s-e.a[0])*r-(o-e.a[1])*t)>u)continue;const a=(e.a[0]-s)*l+(e.a[1]-o)*c,g=(e.b[0]-s)*l+(e.b[1]-o)*c,f=Math.max(-p,Math.min(a,g)),v=Math.min(p,Math.max(a,g));if(v-f<=u)continue;const y=e.inward[0]*h+e.inward[1]*d>=0?1:-1,b=((e.a[0]+e.b[0])/2-s)*h+((e.a[1]+e.b[1])/2-o)*d,w=Math.abs(b+y*e.half),k=`${y}|${e.roomId}`,$={x0:f,x1:v,half:e.half,cm:e.cm,key:e.key,axis:[t,r]},x=_.get(k);x?(x.pieces.push($),x.faceDistance=Math.min(x.faceDistance,w)):_.set(k,{roomId:e.roomId,side:y,order:m++,pieces:[$],faceDistance:w,area:e.area,coverage:0,full:!1})}for(const t of _.values()){const e=qr(t.pieces,-p,p,u);t.coverage=e.coverage,t.full=e.full}const g=t=>{const e=[..._.values()].filter(e=>e.side===t&&e.coverage>u);return e.sort(Ur),e[0]||null};return{negative:g(-1),positive:g(1)}}function Br(t,e){const i=jr(t,e),s=[i.negative,i.positive].filter(t=>!!t).sort((t,e)=>t.order-e.order);if(!s.length)return{ox:0,oy:0,cm:0,side:-1};const o=s[0],n=e.flip_v?-o.side:o.side,r=(-1===n?i.negative:i.positive)||o,a=[...r.pieces].sort((t,e)=>(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))-(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))||e.x1-e.x0-(t.x1-t.x0)||t.key.localeCompare(e.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:n};const l=e.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*n*a.half,oy:h*n*a.half,cm:a.cm,side:n}}function Gr(t,e){const i=1e-9,s=[];for(const t of[...e].filter(t=>t.x1>t.x0&&t.half>0).sort((t,e)=>t.x0-e.x0||t.x1-e.x1||t.half-e.half)){const e=s[s.length-1];e&&t.x0<=e.x1+i&&Math.abs(t.half-e.half)<=i?e.x1=Math.max(e.x1,t.x1):s.push({...t})}const o=[];for(let e=0;e=o-l?i.push([s,o]):(t>s+l&&i.push([s,Math.min(o,t)]),et[0]-e[0]||t[1]-e[1]),b=[];for(const t of y){const e=b[b.length-1];e&&t[0]<=e[1]+l?e[1]=Math.max(e[1],t[1]):b.push([t[0],t[1]])}s.set(g,b)}return a}function Vr(t,e){const i=new Map;return e.map(e=>function(t,e,i){const s=jr(t,e,!0),o=s.negative,n=s.positive;if(!o&&!n)return null;let r;if(o&&n)r=[{candidate:o,side:-1},{candidate:n,side:1}];else{const t=o||n;r=[{candidate:t,side:-1},{candidate:t,side:1}]}const a=r.map(({candidate:t,side:s})=>({candidate:t,side:s,pieces:Wr(e,s,t.pieces,i)})),l=a.map(({candidate:t,side:e,pieces:i})=>({side:e,roomId:t.roomId,d:Gr(e,i)})),c=a.flatMap(({pieces:t})=>t);if(!c.length)return null;const h=Math.max(...c.map(t=>t.half));return{faces:l,minY:-h,maxY:h,wallKey:[...new Set(c.map(t=>t.key))].sort().join("|")}}(t,e,i))}const Kr=150;function Yr(t){return Number.isFinite(t)?Math.max(1,Math.min(Kr,t)):1}function Jr(t){return((Number.isFinite(Number(t))?Number(t):0)%90+90)%90}const Zr=t=>{const e=t.map(t=>[t[0],t[1]]);return!e.length||e[0][0]===e[e.length-1][0]&&e[0][1]===e[e.length-1][1]||e.push([...e[0]]),[e]};function Xr(t){const e=[];for(const i of t||[])for(const t of i||[]){const i=(t||[]).filter(t=>Array.isArray(t)&&t.length>=2);i.length<4||e.push(`M ${i.slice(0,-1).map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`)}return e.join(" ")}function Qr(t,e,i,s,o){const n=e[0]-t[0],r=e[1]-t[1],a=Math.hypot(n,r);if(!(a>1e-9))return null;const l=ir(i,s,o)/2,c=-r/a*l,h=n/a*l;return[[t[0]+c,t[1]+h],[e[0]+c,e[1]+h],[e[0]-c,e[1]-h],[t[0]-c,t[1]-h]]}function ta(t,e,i){const s=Number(e)>0?Number(e):5,o=Yr(t.cm)/s*i,n=t.center[0],r=t.center[1];if("circle"===t.shape){const t=o/2;return Array.from({length:96},(e,i)=>{const s=i/96*Math.PI*2;return[n+Math.cos(s)*t,r+Math.sin(s)*t]})}const a=o/2,l=Jr(t.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l);return[[-a,-a],[a,-a],[a,a],[-a,a]].map(([t,e])=>[n+t*c-e*h,r+t*h+e*c])}function ea(t,e,i){const s=[];for(let o=0;o+1t.length>=3).map(t=>Zr(t));return e.length?Pe(e[0],...e.slice(1)):null}catch{return null}}(e);if(i)return ze(Zr(t),i)}catch{}let i=[Zr(t)];for(const t of e)if(!(t.length<3))try{i=ze(i,Zr(t))}catch{}return i}function sa(t){let e=0;for(const i of t||[])if(i?.length){e+=si(i[0]||[]);for(let t=1;t=4&&e.push(t.slice(0,-1).map(t=>[t[0],t[1]]))}return e}function na(t,e,i){if(!(i>0))return[];const s=Math.max(1e-9,1e-9*i);if(t.some(t=>ra(e,t)||(t=>t.some((i,o)=>{const n=t[(o+1)%t.length],r=n[0]-i[0],a=n[1]-i[1],l=r*r+a*a;if(!(l>0))return Math.hypot(e[0]-i[0],e[1]-i[1])<=s;const c=Math.max(0,Math.min(1,((e[0]-i[0])*r+(e[1]-i[1])*a)/l));return Math.hypot(e[0]-(i[0]+c*r),e[1]-(i[1]+c*a))<=s}))(t)))return[Array.from({length:128},(t,s)=>{const o=s/128*Math.PI*2;return[e[0]+Math.cos(o)*i*1.01,e[1]+Math.sin(o)*i*1.01]})];const o=[];for(const n of t)if(!(n.length<2)){o.push(n);for(let t=0;ts&&u>s))continue;const _=Math.max(-1,Math.min(1,(l*h+c*d)/(p*u))),m=Math.sqrt(Math.max(0,(1+_)/2)),g=Math.max(2*i,1.02*i/Math.max(m,.001)),f=[e[0]+l/p*g,e[1]+c/p*g],v=[e[0]+h/u*g,e[1]+d/u*g];o.push([r,a,v,f])}}return o}function ra(t,e){let i=!1;for(let s=0,o=e.length-1;st[1]!=l>t[1]&&t[0]<(a-n)*(t[1]-r)/(l-r||1e-12)+n&&(i=!i)}return i}function aa(t,e,i){if(Math.hypot(t.center[0]-e.center[0],t.center[1]-e.center[1])>i)return!1;if(Math.abs(Yr(t.cm)-Yr(e.cm))>1e-6)return!1;if(t.shape!==e.shape)return!0;if("circle"===t.shape||"circle"===e.shape)return!0;const s=Math.abs(Jr(t.angle)-Jr(e.angle));return Math.min(s,90-s)<=1e-6}const la=1e3;function ca(t,e){const i=Number(t),s=Number.isFinite(i)&&i>0?i:1,o=s>=1?e:e*s,n=s>=1?e/s:e;return{x:(e-o)/2,y:(e-n)/2,w:o,h:n}}const ha=.01,da=100;function pa(t,e=1e3){const i=ca(t?.plan_aspect,e),s=Number(t?.plan_scale),o=Number.isFinite(s)&&s>0?Math.min(da,Math.max(ha,s)):1,n=Number(t?.plan_scale_x),r=Number(t?.plan_scale_y),a=Number.isFinite(n)&&n>0?Math.min(da,Math.max(ha,n)):o,l=Number.isFinite(r)&&r>0?Math.min(da,Math.max(ha,r)):o,c=Number(t?.plan_x),h=Number(t?.plan_y),d=Un(t?.plan_angle);return{x:i.x+(Number.isFinite(c)?$a(c):0)*e,y:i.y+(Number.isFinite(h)?$a(h):0)*e,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function ua(t){if(null==t.x||null==t.y)return{x:t.x,y:t.y,w:t.w,h:t.h};const e=Number(t.w)||0,i=Number(t.h)||0;return{x:e<0?t.x+e:t.x,y:i<0?t.y+i:t.y,w:Math.abs(e),h:Math.abs(i)}}function _a(t){return t&&Array.isArray(t.spaces)?t.spaces.map(t=>{const e=la,i=function(t){return Array.isArray(t)&&4===t.length&&t.every(t=>Number.isFinite(t))&&t[2]>1e-6&&t[3]>1e-6?t:[0,0,1,1]}(t.view_box);return{id:t.id,title:t.title,vb:[i[0]*la,i[1]*e,i[2]*la,i[3]*e],bg:t.plan_url?{href:hs(t.plan_url),...pa(t,la)}:null,rooms:(t.rooms||[]).map(t=>{const i={...t,...ua(t)};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*la:void 0,y:null!=i.y?i.y*e:void 0,w:null!=i.w?i.w*la:void 0,h:null!=i.h?i.h*e:void 0,poly:i.poly?i.poly.map(t=>[t[0]*la,t[1]*e]):void 0}}),room_drafts:(t.room_drafts||[]).map(t=>({id:t.id,points:(t.points||[]).map(t=>[t[0]*la,t[1]*e]),segments:(t.segments||[]).map(t=>({cm:Number(t.cm)}))})),partitions:(t.partitions||[]).map(t=>({id:t.id,a:[t.a[0]*la,t.a[1]*e],b:[t.b[0]*la,t.b[1]*e],cm:Number(t.cm)})),wall_columns:(t.wall_columns||[]).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[t.center[0]*la,t.center[1]*e],cm:Number(t.cm),..."circle"===t.shape?{}:{angle:Jr(t.angle)}}))}}):[]}const ma=5e3,ga=ma*la,fa=240,va=la/fa,ya=1/fa;function ba(t){if(!Number.isFinite(t))return t;const e=Math.round(t*fa/la)*la/fa;return Math.abs(e-t)<=1e-9*va?t:e}function wa(t){return{x:ba(t.x),y:ba(t.y)}}function ka(t){return Number.isFinite(t)?Math.min(ga,Math.max(-ga,t)):0}function $a(t){return Number.isFinite(t)?Math.min(ma,Math.max(-ma,t)):0}const xa=1/3,Sa=200;function Ma(t){let e=1/0,i=1/0,s=-1/0,o=-1/0;for(const n of t){const t=Number(n[0]),r=Number(n[1]);Number.isFinite(t)&&Number.isFinite(r)&&(ts&&(s=t),r>o&&(o=r))}return e>s?null:{minX:e,minY:i,maxX:s,maxY:o}}function Ca(t){return t.poly&&t.poly.length?Ma(t.poly):null==t.x||null==t.y?null:Ma([[t.x,t.y],[t.x+(t.w||0),t.y+(t.h||0)]])}function Da(t,e){const i=[];for(const e of t.rooms||[]){const t=Ca(e);t&&i.push(t)}if(t.bg){const e=Ma(Kn(t.bg));e&&i.push(e)}for(const t of e||[])if(Array.isArray(t)){const e=Ma([t]);e&&i.push(e)}else i.push(t);return i}const Ta=t=>{if(!t.length)return 0;const e=[...t].sort((t,e)=>t-e),i=e.length>>1;return e.length%2?e[i]:(e[i-1]+e[i])/2},Pa=t=>{let e=1/0,i=1/0,s=-1/0,o=-1/0;for(const n of t)n.minXs&&(s=n.maxX),n.maxY>o&&(o=n.maxY);return e>s||i>o?null:{x:e,y:i,w:s-e,h:o-i}};function Ra(t,e){let{x:i,y:s,w:o,h:n}=t;o<30&&(i=i+o/2-100,o=Sa),n<30&&(s=s+n/2-100,n=Sa);const r=Math.max(o,n)*e;return{x:i-r,y:s-r,w:o+2*r,h:n+2*r}}function za(t,e={}){const i=e.pad??.05,s=e.k??10,o=e.minSpread??50,n=t.filter(t=>Number.isFinite(t.minX)&&Number.isFinite(t.minY)&&Number.isFinite(t.maxX)&&Number.isFinite(t.maxY)&&Math.abs(t.minX)<=ga&&Math.abs(t.maxX)<=ga&&Math.abs(t.minY)<=ga&&Math.abs(t.maxY)<=ga);if(!n.length)return{core:null,all:null,outliers:0};const r=Pa(n);if(n.length<4){const t=Ra(r,i);return{core:t,all:t,outliers:0}}const a=n.map(t=>(t.minX+t.maxX)/2),l=n.map(t=>(t.minY+t.maxY)/2),c=Ta(a),h=Ta(l),d=n.map((t,e)=>Math.max(Math.abs(a[e]-c),Math.abs(l[e]-h))),p=Math.max(((t,e)=>t.length?t[Math.min(t.length-1,Math.max(0,Math.round(e*(t.length-1))))]:0)([...d].sort((t,e)=>t-e),.75),o),u=d.map(t=>t>s*p),_=u.filter(Boolean).length,m=_&&_<=n.length*xa?n.filter((t,e)=>!u[e]):n;return{core:Ra(Pa(m)||r,i),all:Ra(r,i),outliers:m===n?0:_}}function Aa(t,e,i=.05){const s=za(Da(t,e),{pad:i});if(s.core)return s.core;const o=t.vb&&4===t.vb.length&&t.vb[2]>0&&t.vb[3]>0?t.vb:[0,0,la,la];return{x:o[0],y:o[1],w:o[2],h:o[3]}}function Ia(t){const e=Aa(t);return{x:e.x+e.w/2,y:e.y+e.h/2}}function Ea(t){const e=[];for(const i of t.rooms||[]){const t=Ca(i);t&&e.push(t)}const i=za(e,{pad:0}).core;return i?Math.max(la,Math.min(ga,Math.max(i.w,i.h))):la}function Na(t,e,i,s=1){const o=Number(i),n=Number.isFinite(s)&&s>0?s:1;return!Number.isFinite(o)||o<=0?t*n:t*Ea(e)*n/o}const Fa=[1,2,5,10,20,50,100,200,500,1e3];function Oa(t){if(t.poly&&t.poly.length){const e=t.poly.map(t=>t[0]),i=t.poly.map(t=>t[1]),s=Math.min(...e),o=Math.min(...i);return{x:s,y:o,w:Math.max(...e)-s,h:Math.max(...i)-o}}return{x:t.x??0,y:t.y??0,w:t.w??0,h:t.h??0}}function La(t){if(t.poly){const e=t.poly.length;return[t.poly.reduce((t,e)=>t+e[0],0)/e,t.poly.reduce((t,e)=>t+e[1],0)/e]}return[t.x+t.w/2,t.y+.1*Math.min(t.w,t.h)]}const Ha=["furniture","appliance","sanitary","other"],qa=[{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]]}],Ua=new Map(qa.map(t=>[t.id,t]));function ja(t){return t&&Ua.get(t)||null}function Ba(t){return qa.filter(e=>e.group===t)}function Ga(t,e,i=va,s=1e3){const o=Number(e)>0?Number(e):5;return(Number(t)||0)/o*i/s}const Wa=5e-4,Va=ma;function Ka(t){return Number.isFinite(t)?Math.max(Wa,Math.min(Va,t)):Wa}const Ya=t=>{const e=Math.round(1e3*t)/1e3;return Object.is(e,-0)?"0":String(e)};function Ja(t,e,i){const s=ja(t);if(!(s&&e>0&&i>0))return"";const o=t=>Ya(t*e),n=t=>Ya(t*i),r=[];for(const t of s.g)if("r"===t[0]){const[,e,i,s,a]=t;r.push(`M${o(e)} ${n(i)}H${o(e+s)}V${n(i+a)}H${o(e)}Z`)}else if("l"===t[0]){const[,e,i,s,a]=t;r.push(`M${o(e)} ${n(i)}L${o(s)} ${n(a)}`)}else if("e"===t[0]){const[,s,a,l,c]=t;r.push(`M${o(s-l)} ${n(a)}A${Ya(l*e)} ${Ya(c*i)} 0 0 1 ${o(s+l)} ${n(a)}A${Ya(l*e)} ${Ya(c*i)} 0 0 1 ${o(s-l)} ${n(a)}Z`)}else{const e=t.slice(1);if(e.length<4)continue;let i=`M${o(e[0])} ${n(e[1])}`;for(let t=2;t+1{let e=(t%360+360)%360;return e>180&&(e-=360),e};function Xa(t,e,i,s,o,n=0){let r=null,a=o;for(const o of s){const[s,l,c,h]=o,d=c-s,p=h-l,u=d*d+p*p;if(!u)continue;const _=Math.sqrt(u);let m=((t-s)*d+(e-l)*p)/u;m=Math.max(0,Math.min(1,m));let g=s+m*d,f=l+m*p;const v=Math.hypot(t-g,e-f);if(!(v0){const t=Math.round(m*_/n)*n;g=s+t/_*d,f=l+t/_*p}r={cx:g+y*(i/2),cy:f+b*(i/2),angle:Za(180*Math.atan2(-y,b)/Math.PI),dist:v}}return r}function Qa(t,e,i){const s=i;return{a:[t[0]/s,t[1]/s],b:[e[0]/s,e[1]/s]}}function tl(t,e){const i=e;return[t.a[0]*i,t.a[1]*i,t.b[0]*i,t.b[1]*i]}function el(t){return Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1]))}function il(t){if(!Array.isArray(t))return[];const e=[];for(const i of t){if(!i||"object"!=typeof i)continue;const t=i;if(!el(t.a)||!el(t.b))continue;const s=[Number(t.a[0]),Number(t.a[1])],o=[Number(t.b[0]),Number(t.b[1])];Math.hypot(o[0]-s[0],o[1]-s[1])<.001||e.push({a:s,b:o})}return e}function sl(t,e){const i=e[0],s=e[1],o=e[2]-i,n=e[3]-s,r=o*o+n*n;if(r<1e-18){return{q:[i,s],t:0,d:Math.hypot(t[0]-i,t[1]-s)}}let a=((t[0]-i)*o+(t[1]-s)*n)/r;a=Math.max(0,Math.min(1,a));const l=[i+a*o,s+a*n];return{q:l,t:a,d:Math.hypot(t[0]-l[0],t[1]-l[1])}}function ol(t,e){return sl(t,e).q}function nl(t,e,i,s,o){const n=sl(t,e).q;let r=n,a=1/0;for(const t of i){const e=Math.hypot(n[0]-t[0],n[1]-t[1]);e<=o&&e0?s:1,m=Math.round(u/_)*_,g=Math.max(0,Math.min(p,m))/p;return[l+h*g,c+d*g]}function rl(t,e){const i=[],s=(t||[]).filter(t=>t?.id);for(let t=0;tt?.id),r=il(e);if(r.length)return ml(r,t,i,s).map(t=>tl(t,i));if(!o)return[];const a=[],l=(t,e)=>(t.open_to||[]).includes(e.id)||(e.open_to||[]).includes(t.id);for(let t=0;tQa([t[0],t[1]],[t[2],t[3]],e))}function cl(t,e,i,s){for(const e of t||[])e.open_to&&delete e.open_to;if(!i.length)return;const o=(e||[]).filter(t=>t?.id);new Map(o.map(t=>[t.id,t]));const n=new Map((t||[]).filter(t=>t?.id).map(t=>[t.id,t])),r=(t,e)=>{const i=n.get(t),s=n.get(e);i&&s&&((i.open_to||[]).includes(e)||(i.open_to=[...i.open_to||[],e]),(s.open_to||[]).includes(t)||(s.open_to=[...s.open_to||[],t]))};for(let t=0;tgs(i,t)<4*s)){r(o[t].id,o[e].id);break}}}for(const e of t||[])e.open_to&&!e.open_to.length&&delete e.open_to}function hl(t,e,i,s=0){const o=e[2]-e[0],n=e[3]-e[1],r=Math.hypot(o,n);if(!(r>1e-9))return null;const a=o/r,l=n/r,c=(t[0]-e[0])*a+(t[1]-e[1])*l;if(c<-s||c>r+s)return null;return Math.abs((t[0]-e[0])*l-(t[1]-e[1])*a)>i?null:gs(t,e)}function dl(t,e,i){const s=t[2]-t[0],o=t[3]-t[1],n=e[2]-e[0],r=e[3]-e[1],a=Math.hypot(s,o),l=Math.hypot(n,r);return a>1e-9&&l>1e-9&&(!(Math.abs(s/a*(r/l)-o/a*(n/l))>1e-6)&&(gs([e[0],e[1]],t)<=4*i||gs([t[0],t[1]],e)<=4*i))}function pl(t,e,i){if(!t.length)return null;t.sort((t,e)=>t.distance-e.distance);const s=t[0];for(let o=1;oe)break;if(n.semantic!==s.semantic||!dl(s.seg,n.seg,i))return"ambiguous"}return s}function ul(t,e,i,s,o=1,n=15){const r=function(t,e,i,s,o=1,n=15){const[r,a]=or([e[0],e[1]],[e[2],e[3]]);let l=0,c=1/0;const h=[(e[0]+e[2])/2,(e[1]+e[3])/2];for(const e of i){const[i,n]=or([e[0],e[1]],[e[2],e[3]]);if(Math.abs(r*n-a*i)>.05)continue;const d=ur(t,[e[0],e[1]],[e[2],e[3]],s,o);if(!(d>0))continue;const p=[(e[0]+e[2])/2,(e[1]+e[3])/2],u=Math.hypot(p[0]-h[0],p[1]-h[1]);u0?l:n}(t,e,i,s,o,n);return fr(t,[e[0],e[1]],[e[2],e[3]],r,s,o)}function _l(t,e,i){const s=[[t[0],t[1]],[t[2],t[3]]],o=[(t[0]+t[2])/2,(t[1]+t[3])/2];for(const n of e)if(!(gs(o,n)>Math.hypot(t[2]-t[0],t[3]-t[1])&&gs([n[0],n[1]],t)>i))for(const e of[[n[0],n[1]],[n[2],n[3]]])gs(e,t)<=2*i&&s.push(e);return s}function ml(t,e,i,s){const o=il(t);if(!o.length)return[];const n=rl(e,s);if(!n.length)return[];const r=[],a=Math.max(4*s,1e-6);for(const t of o){const e=tl(t,i),o=e[0],l=e[1],c=e[2]-o,h=e[3]-l,d=Math.hypot(c,h);if(d4*s||n>4*s)continue;const r=(t[0]-o)*p+(t[1]-l)*u,c=(t[2]-o)*p+(t[3]-l)*u,h=Math.max(0,Math.min(r,c)),m=Math.min(d,Math.max(r,c));if(m-ht.lo-e.lo||t.hi-e.hi);const i=[];for(const t of e){const e=i[i.length-1];e&&t.lo<=e.hi+a?e.hi=Math.max(e.hi,t.hi):i.push({...t})}for(const e of i){const i=[o+p*e.lo,l+u*e.lo],s=[o+p*e.hi,l+u*e.hi];Math.hypot(s[0]-i[0],s[1]-i[1])i.pair===t&&Math.abs(i.ux*r-i.uy*n)<=1e-6&&Math.abs((e[0]-i.origin[0])*i.uy-(e[1]-i.origin[1])*i.ux)<=c&&Math.abs((e[2]-i.origin[0])*i.uy-(e[3]-i.origin[1])*i.ux)<=c);h||(h={pair:t,origin:[e[0],e[1]],ux:n,uy:r,ranges:[]},l.push(h));const d=(e[0]-h.origin[0])*h.ux+(e[1]-h.origin[1])*h.uy,p=(e[2]-h.origin[0])*h.ux+(e[3]-h.origin[1])*h.uy;h.ranges.push({lo:Math.min(d,p),hi:Math.max(d,p)})}const h=[];for(const t of l){t.ranges.sort((t,e)=>t.lo-e.lo||t.hi-e.hi);const e=[];for(const i of t.ranges){const t=e[e.length-1];t&&i.lo<=t.hi+a?t.hi=Math.max(t.hi,i.hi):e.push({...i})}for(const s of e){const e=[t.origin[0]+t.ux*s.lo,t.origin[1]+t.uy*s.lo],o=[t.origin[0]+t.ux*s.hi,t.origin[1]+t.uy*s.hi];Math.hypot(o[0]-e[0],o[1]-e[1])>=a&&h.push(Qa(e,o,i))}}return h}function gl(t,e,i,s){const o=il(t);if(!o.length)return[];if(e.length!==i.length)return o;const n=[];for(const t of o){const o=tl(t,s),r=[o[0],o[1]],a=[o[2],o[3]];let l=r,c=a;for(let t=0;t{const e=sl(t,[s[0],s[1],o[0],o[1]]);if(e.d>.001)return t;const i=h[0]-n[0],r=h[1]-n[1];return[n[0]+i*e.t,n[1]+r*e.t]};if(sl([(r[0]+a[0])/2,(r[1]+a[1])/2],[s[0],s[1],o[0],o[1]]).d<.01){l=d(r),c=d(a);break}}n.push(Qa(l,c,s))}return n}class fl{constructor(t,e=()=>Date.now()){this.onUpdate=t,this.now=e,this.signed={},this.queued=new Set,this.inFlight=new Map,this.retry=new Map,this.disposed=!1}start(t,e){this.disposed=!1,this.stopTimer(),this.resignTimer=setInterval(()=>this.resign(t(),e()),288e5)}dispose(){this.disposed=!0,this.stopTimer(),clearTimeout(this.batchTimer),this.queued.clear(),this.inFlight.clear()}stopTimer(){void 0!==this.resignTimer&&clearInterval(this.resignTimer),this.resignTimer=void 0}display(t,e){const i=hs(e);if(!i.startsWith("/api/houseplan/content/"))return i;const s=this.signed[i],o=s?this.now()-s.at:1/0;return o{const e=[...this.queued];this.queued.clear(),this.sign(t,e)},30))}sign(t,e){if(e.length&&t?.callWS)for(const i of function(t,e){const i=Math.max(1,Math.floor(e)),s=[];for(let e=0;e{if(this.disposed)return;const e=this.now(),s={...this.signed};let o=0;for(const n of i){const i=t?.urls?.[n];"string"==typeof i&&i?(s[n]={url:i,at:e},this.retry.delete(n),o++):this.backOff(n)}o&&(this.signed=s,this.onUpdate())}).catch(()=>{for(const t of i)this.backOff(t)}).finally(()=>{for(const t of i)this.inFlight.get(t)===e&&this.inFlight.delete(t)})}}backOff(t){const e=this.retry.get(t)?.delay||0,i=Math.min(6e4,e?2*e:2e3);this.retry.set(t,{notBefore:this.now()+i,delay:i})}resign(t,e){const i=this.now(),s={};for(const[t,o]of Object.entries(this.signed))e.has(t)&&i-o.at{if(null==t||""===t)return null;const e=Number(t);return Number.isFinite(e)?e:null},wl=t=>{const e=t,i=bl(Array.isArray(e)?e[0]:e?.x),s=bl(Array.isArray(e)?e[1]:e?.y);return null==i||null==s?null:[i,s]};function kl(t){if(!Array.isArray(t))return null;const e=[];for(const i of t){const t=wl(i);if(!t)return null;e.push(t)}if(e.length>1){const t=e[0],i=e[e.length-1];t[0]===i[0]&&t[1]===i[1]&&e.pop()}if(e.length<3)return null;let i=0,s=0,o=0;for(let t=0;tt+e[0],0)/e.length,e.reduce((t,e)=>t+e[1],0)/e.length]:[s/(3*i),o/(3*i)]}function $l(t){if(!Array.isArray(t))return null;const e=[];for(const i of t){const t=wl(i);if(!t)return null;e.push(t)}if(e.length>1){const t=e[0],i=e[e.length-1];t[0]===i[0]&&t[1]===i[1]&&e.pop()}const i=kl(e);if(!i)return null;const s=e.map(t=>t[0]),o=e.map(t=>t[1]);return{centroid:i,bbox:[Math.min(...s),Math.min(...o),Math.max(...s),Math.max(...o)]}}function xl(t){let e=t;if(e&&"object"==typeof e&&!Array.isArray(e)){const t=e;e=t.path??t.points??e}if(!Array.isArray(e)||!e.length)return[];let i=(e.some(t=>(t=>Array.isArray(t)?t.length>=2&&!Array.isArray(t[0])&&("object"!=typeof t[0]||null==t[0]):!!t&&"object"==typeof t&&("x"in t||"y"in t))(t))?[e]:e.filter(Array.isArray)).map(t=>t.map(wl).filter(t=>null!=t)).filter(t=>t.length>=2);i.length>64&&(i=i.slice(-64));if(i.reduce((t,e)=>t+e.length,0)<=4e3)return i.map(t=>t.slice());const s=4e3-2*i.length,o=i.map(t=>t.length-2),n=o.reduce((t,e)=>t+e,0),r=o.map(t=>s*t/n),a=r.map(Math.floor);let l=s-a.reduce((t,e)=>t+e,0);const c=r.map((t,e)=>({index:e,fraction:t-Math.floor(t)})).sort((t,e)=>e.fraction-t.fraction||t.index-e.index);for(let t=0;tfunction(t,e){if(e>=t.length)return t.slice();if(e<=2)return[t[0],t[t.length-1]];const i=[];for(let s=0;st.slice()),i=e[e.length-1];return i?(i.length>2?i.pop():e.pop(),e):[]}function Cl(t){if(!t)return null;const e=t.vacuum_position||t.robot_position||null,i=e&&null!=bl(e.x)&&null!=bl(e.y)?{x:bl(e.x),y:bl(e.y),a:bl(e.a??e.angle??e.theta)}:null,s=xl(t.path?.path??t.path?.points??t.path),o=[],n=t.rooms,r=Array.isArray(n)?n.map((t,e)=>[String(t?.id??e),t]):n&&"object"==typeof n?Object.entries(n):[];for(const[t,e]of r){if(!e||"object"!=typeof e)continue;const i=String(e.name??e.label??"").trim(),s=[[bl(e.cx),bl(e.cy)],[bl(e.center?.x),bl(e.center?.y)],[bl(e.x),bl(e.y)]].find(([t,e])=>null!=t&&null!=e);let n=s?.[0]??null,r=s?.[1]??null;const a=$l(e.outline),l=bl(e.x0),c=bl(e.y0),h=bl(e.x1),d=bl(e.y1),p=(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!=n&&null!=r||!a||([n,r]=a.centroid),null!=n&&null!=r||!p||(n=(p[0]+p[2])/2,r=(p[1]+p[3])/2),i&&null!=n&&null!=r){const e={id:t,name:i,cx:n,cy:r};p&&([e.x0,e.y0,e.x1,e.y1]=p),o.push(e)}}const a=function(t){return String(t.map_name??t.current_map??t.map_index??t.selected_map??"default")}(t);return i||o.length||s.length?{pos:i,path:s,rooms:o,mapId:a}:null}function Dl(t,e,i){if(!t||!e)return null;const s=e.attributes||{},o=t.split(".")[0]||"",n=null!=i?.platform?String(i.platform):null,r=!!wl(s.vacuum_position??s.robot_position),a=!(!s.rooms||"object"!=typeof s.rooms),l=xl(s.path?.path??s.path?.points??s.path).length>0,c=[s.map_name,s.current_map,s.map_index,s.selected_map].some(t=>null!=t),h="xiaomi_cloud_map_extractor"===n,d=a||l||c;let p=null;if(r?p="compatible":h?p="known_xcme_incomplete":d?p="partial":"camera"===o&&(p="camera"),!p)return null;const u=r?"camera"===o?300:200:h?100:d?50:0;return{entityId:t,name:String(s.friendly_name||t),platform:n,category:p,hasPosition:r,hasRooms:a,hasPath:l,hasMapId:c,score:u}}const Tl=t=>t.toLowerCase().replace(/[\s_\-.,]+/g,"");function Pl(t,e){const i=new Map(e.map(t=>[Tl(t.name),t])),s=[],o=[];for(const e of t){const t=i.get(Tl(e.name));t&&(s.push([[e.cx,e.cy],[t.cx,t.cy]]),o.push(e.name))}if(s.length<3)return null;const n=function(t){if(t.length<3)return null;let e=0,i=0,s=0,o=0,n=0,r=0,a=0,l=0,c=0,h=0,d=0,p=0;for(const[[u,_],[m,g]]of t){if(![u,_,m,g].every(Number.isFinite))return null;e+=u*u,i+=u*_,s+=u,o+=_*_,n+=_,r+=1,a+=u*m,l+=_*m,c+=m,h+=u*g,d+=_*g,p+=g}const u=[e,i,s,i,o,n,s,n,r],_=t=>{const[e,i,s,o,n,r,a,l,c]=u,h=e*(n*c-r*l)-i*(o*c-r*a)+s*(o*l-n*a);if(!Number.isFinite(h)||Math.abs(h)<1e-9)return null;const d=[(n*c-r*l)/h,(s*l-i*c)/h,(i*r-s*n)/h,(r*a-o*c)/h,(e*c-s*a)/h,(s*o-e*r)/h,(o*l-n*a)/h,(i*a-e*l)/h,(e*n-i*o)/h];return[d[0]*t[0]+d[1]*t[1]+d[2]*t[2],d[3]*t[0]+d[4]*t[1]+d[5]*t[2],d[6]*t[0]+d[7]*t[1]+d[8]*t[2]]},m=_([a,l,c]),g=_([h,d,p]);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}(s);return n?{matrix:n,matched:o,residual:yl(n,s)}:null}function Rl(t,e,i){const s=t[t.length-1];if(s&&s[0]===e[0]&&s[1]===e[1])return t;if(t.push(e),t.length<=600)return t;let o=function(t,e){if(t.length<3)return t.slice();const i=new Uint8Array(t.length);i[0]=i[t.length-1]=1;const s=[[0,t.length-1]];for(;s.length;){const[o,n]=s.pop(),[r,a]=t[o],[l,c]=t[n],h=l-r,d=c-a,p=Math.hypot(h,d)||1e-9;let u=0,_=-1;for(let e=o+1;eu&&(u=i,_=e)}_>0&&u>e&&(i[_]=1,s.push([o,_],[_,n]))}const o=[];for(let e=0;e600&&(o=o.filter((t,e)=>e%2==0||e===o.length-1)),o}function zl(t){return"cleaning"===t||"returning"===t||"on"===t}const Al={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function Il(t){const[e,i]=Al[t.rot]||[1,0],s=t.mir?-1:1;return[t.s*e*s,-t.s*i,t.ox,t.s*i*s,t.s*e,t.oy]}function El(t){const e=t[0]*t[4]-t[1]*t[3];if(!Number.isFinite(e)||Math.abs(e)<1e-12)return null;const i=e<0,s=Math.sqrt(Math.abs(e));let o=180*Math.atan2(-t[1],t[4])/Math.PI;return o=(90*Math.round(o/90)%360+360)%360,{ox:t[2],oy:t[5],s:s,rot:o,mir:i}}function Nl(t,e,i,s){const[o,n]=vl(Il(e),i,s),r=Il({...t,ox:0,oy:0}),[a,l]=vl(r,i,s);return{...t,ox:o-a,oy:n-l}}function Fl(t){const e=t?.trail_mode;return"never"===e||"cleaning"===e||"always"===e?e:!1===t?.trail?"never":"cleaning"}class Ol extends lt{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1}setConfig(t){this._config=t}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const t=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(t?.config?.spaces||[]).map(t=>({value:t.id,label:t.title||t.id}))}catch{this._spaces=[]}finally{this._spacesLoading=!1}}}get _lang(){return tn(this.hass,this._config?.language)}get _schema(){const t=this._spaces||[],e=this._lang;return[{name:"title",selector:{text:{}}},t.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:t}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:[{value:"",label:en(e,"editor.lang_auto")},{value:"en",label:en(e,"editor.lang_en")},{value:"ru",label:en(e,"editor.lang_ru")}]}}},{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 W;this._loadSpaces();const t=this._lang,e={title:en(t,"editor.title"),default_floor:en(t,"editor.default_floor"),language:en(t,"editor.language"),icon_size:en(t,"editor.icon_size"),show_temperature:en(t,"editor.show_temperature"),live_states:en(t,"editor.live_states"),show_signal:en(t,"editor.show_signal"),kiosk:en(t,"editor.kiosk"),cycle:en(t,"editor.cycle")};return j`[t[0]-e[0],t[1]-e[1]],_n=(t,e)=>[t[0]+e[0],t[1]+e[1]],mn=(t,e)=>t[0]*e[0]+t[1]*e[1],gn=t=>Math.hypot(t[0],t[1]);function fn(t){let e=0;for(let i=0;it[1]!=l>t[1]&&t[0]<(a-n)*(t[1]-r)/(l-r)+n&&(i=!i)}return i}([a[0]+r[0]*l,a[1]+r[1]*l],t)&&(r=[-r[0],-r[1]]),r}function bn(t,e,i,s){const o=s||yn(t,e),n=(e+1)%t.length;return t.map((t,s)=>s===e||s===n?[t[0]+o[0]*i,t[1]+o[1]*i]:[...t])}function wn(t,e,i,s){const o=[],n=un(i,e),r=gn(n);if(rs||h>s)continue;const d=mn(un(n,e),a),p=mn(un(l,e),a),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));_-u>s&&o.push([[e[0]+a[0]*u,e[1]+a[1]*u],[e[0]+a[0]*_,e[1]+a[1]*_]])}return o}function kn(t,e,i,s,o){const n=wn(t,e,i,o);if(!n.length)return null;const r=t=>n.some(([e,i])=>vn(t,e,i)<=o),a=t.length,l=[];for(let n=0;no||f>o)continue;const v=mn(un(e,c),u),y=mn(un(i,c),u),b=Math.max(0,Math.min(v,y)),w=Math.min(p,Math.max(v,y));if(!(w-b<=o)){if(b>o&&bo&&wgn(un(i,t[(s+1)%t.length]))>e);for(let t=0;t<2;t++)i=i.filter((t,s)=>{const o=i[(s-1+i.length)%i.length],n=i[(s+1)%i.length],r=(t[0]-o[0])*(n[1]-o[1])-(t[1]-o[1])*(n[0]-o[0]),a=gn(un(n,o))||1;return Math.abs(r)/a>e});return i.length>=3?i:t}function xn(t){const e=t.length;if(e<3)return!1;for(let i=0;i(t[0]-o[0])*a[1]-(t[1]-o[1])*a[0],c=t=>(t[0]-o[0])*a[0]+(t[1]-o[1])*a[1],h=i,d=r-i;for(const e of t){const t=Math.abs(l(e));if(t<=i)continue;const o=c(e);o<=h||o>=d||tMath.abs(r+(t-p)/g*(a-r));s=Math.min(s,f(_),f(m))}}return s}function Mn(t,e,i){if(ui(t,e,i))return!0;if(pi(t,e,i)||pi(e,t,i))return!1;let s=0;try{const i=je([[...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 i)t?.[0]&&(s+=mi(t[0]))}catch{return!1}return s>Math.max(1e-7,i*i)}function Cn(t,e,i,s,o){const n=[i.n[0]*s,i.n[1]*s],r={polys:{},openings:{},movedSpans:{}};if(Math.abs(s)<1e-9)return r;for(const e of t){if(e.id===i.roomId){r.polys[e.id]=bn(e.poly,i.edge,s,i.n),r.movedSpans[e.id]=[[_n(i.a,n),_n(i.b,n)]];continue}const t=wn(e.poly,i.a,i.b,o);if(!t.length)continue;const a=kn(e.poly,i.a,i.b,n,o);a&&(r.polys[e.id]=a,r.movedSpans[e.id]=t.map(([t,e])=>[_n(t,n),_n(e,n)]))}for(const t of e)vn([t.x,t.y],i.a,i.b)<=o&&(r.openings[t.id]=[t.x+n[0],t.y+n[1]]);return r}function Dn(t,e,i){for(const s of e)for(let e=0;ei)continue;const c=(t.x-o[0])*l[0]+(t.y-o[1])*l[1];if(c-t.length/2>=-i&&c+t.length/2<=a+i)return!0}return!1}function Tn(t,e,i){return t.filter(t=>e.some(e=>{for(let s=0;sa.polys[t.id]||t.poly;for(const e of l){const s=t.find(t=>t.id===e),o=a.polys[e];if(!xn(o))return!1;const l=fn(s.poly),h=fn(o);if(Math.abs(h)t.find(t=>t.id===e).poly),d=t.map(c);for(const t of Tn(e,h,2*r)){const e=a.openings[t.id];if(!Dn(e?{...t,x:e[0],y:e[1]}:t,d,2*r))return!1}return!0}function Rn(t,e,i,s,o,n){const r=t=>[s[0]+(t[0]-s[0])*o,s[1]+(t[1]-s[1])*o],a={poly:t.poly.map(r),openings:{}};for(const s of e){let e=!1;for(let i=0;i{for(let e=0;et.id===i);if(!l)return!1;const c=t.filter(t=>t.id!==i).map(t=>t.poly),h=Rn(l,e,c,s,o,2*a),d=h.poly,p=function(t){const e=function(t){const e=[...t].sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(e.length<3)return e;const i=(t,e,i)=>(e[0]-t[0])*(i[1]-t[1])-(e[1]-t[1])*(i[0]-t[0]),s=[];for(const t of e){for(;s.length>=2&&i(s[s.length-2],s[s.length-1],t)<=0;)s.pop();s.push(t)}const o=[];for(let t=e.length-1;t>=0;t--){const s=e[t];for(;o.length>=2&&i(o[o.length-2],o[o.length-1],s)<=0;)o.pop();o.push(s)}return s.pop(),o.pop(),s.concat(o)}(t);if(e.length<3)return 0;let i=1/0;for(let t=0;tt.id===i?d:t.poly);for(const t of Tn(e,[l.poly],2*a)){const e=h.openings[t.id];if(!Dn(e?{...t,x:e[0],y:e[1]}:t,u,2*a))return!1}return!0}function zn(t,e,i){const s=i/e;return mi(t)*s*s/1e4}function In(t,e){return e?`${Math.round(10.7639*t)} ft²`:`${(Math.round(10*t)/10).toFixed(1)} m²`}const En=[[-90,"#070c14"],[-12,"#070c14"],[-4,"#131a28"],[0,"#4a3527"],[10,"#e8ddcf"],[30,"#ffffff"],[90,"#ffffff"]],Nn=t=>Math.min(1,Math.max(0,t));function Fn(t){const e=Math.min(90,Math.max(-90,Number(t)||0));let i=En[En.length-1][1];for(let t=1;t{const n=[t.x+o[0]*i*s,t.y+o[1]*i*s];return e.find(t=>t.poly.length>=3&&si(n,t.poly))||null},r=n(1),a=n(-1);return r&&a?null:r||a?r?{normal:[-o[0],-o[1]],roomId:r.id}:{normal:o,roomId:a.id}:null}function Ln(t,e,i){return i>0&&t[0]*e[0]+t[1]*e[1]>.05}function Hn(t,e,i,s){return[[t[0],t[1]],[e[0],e[1]],[e[0]+i[0]*s,e[1]+i[1]*s],[t[0]+i[0]*s,t[1]+i[1]*s]]}function qn(t,e){try{const i=je([[...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]]]]),s=[];for(const t of i){const e=t?.[0];!Array.isArray(e)||e.length<4||s.push(e.slice(0,e.length-1).map(t=>[t[0],t[1]]))}return s}catch{return[]}}function Un(t,e,i,s,o,n,r){if(!(s>0))return[];const a=function(t,e){const i=function(t,e){return function(t){const e=t%360;return e<0?e+360:e}(t-e)}(t,e)*Math.PI/180;return[Math.sin(i),-Math.cos(i)]}(i,o),l=[-a[0],-a[1]],c=function(t){const e=Math.min(90,Math.max(0,t));return.7*(.8+1.7*Math.pow(1-e/90,1.6))}(s),h=[];for(const i of e){if(!(i.length>0))continue;const e=On(i,t);if(!e||!Ln(e.normal,a,s))continue;const o=t.find(t=>t.id===e.roomId);if(!o)continue;const d=n&&n[e.roomId]||o.poly,p=i.angle*Math.PI/180,u=i.length/2,_=[-e.normal[0],-e.normal[1]],m=Math.max(0,r?.[i.id]||0),g=i.x+_[0]*m/2,f=i.y+_[1]*m/2,v=Math.cos(p)*u,y=Math.sin(p)*u,b=[g-v,f-y],w=[g+v,f+y],k=c*i.length,$=qn(Hn(b,w,l,k),d);if(!$.length)continue;const x=l[0]*_[0]+l[1]*_[1];h.push({openingId:i.id,roomId:e.roomId,polys:$,a:b,b:w,dir:l,len:k,normal:_,depth:k*x})}return h}function Bn(t){return Math.round(10*(Number(t)||0))/10}const jn=t=>"number"==typeof t&&Number.isInteger(t)&&t>=0&&t<=359?t:null;function Gn(t,e){const i=jn(e?.north_deg);return null!==i?i:jn(t?.north_deg)}function Wn(t,e){const i=t=>"static"===t||"daynight"===t?t:null;return i(e?.bg_mode)??i(t?.bg_mode)??"static"}function Vn(t,e){const i=e?.sun_rays;return"boolean"==typeof i?i:!0===t?.sun_rays}function Kn(t){const e=t?.states?.["sun.sun"]?.attributes,i=Number(e?.azimuth),s=Number(e?.elevation);return Number.isFinite(i)&&Number.isFinite(s)?{azimuth:i,elevation:s}:null}const Yn={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},Jn=(t,e=1)=>{const i=Number(t);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):e},Zn=t=>{let e=Number(t);return Number.isFinite(e)?(e=(e%360+360)%360,e>180?e-360:e):0};function Xn(t,e,i){return Zn(e)?[t.x,t.y]:i([t.x,t.y])}const Qn=(t,e,i)=>{const s=Number(t),o=Number.isFinite(e)&&e>0?e:5;return Number.isFinite(s)&&s>0?s/o*i:0},tr=(t,e,i)=>{const s=Number(t),o=Number.isFinite(e)&&e>0?e:5;return Number.isFinite(s)&&i>0?s/i*o:0},er=(t,e,i,s=Yn.widthCm)=>{const o=Number(t?.width_cm);if(Number.isFinite(o)&&o>0)return o;const n=Number(t?.width);return Number.isFinite(n)&&n>0?tr(n,e,i):s};function ir(t,e){return{color:t.color,opacity:Jn(t.opacity),width_cm:Math.max(.1,Math.min(100,Number(t.widthCm)||.1)),...e?{fill:t.fill,fill_color:t.fillColor,fill_opacity:Jn(t.fillOpacity,.25)}:{}}}function sr(t){const e=t.x+t.w/2,i=t.y+t.h/2,s=Zn(t.angle)*Math.PI/180,o=Math.cos(s),n=Math.sin(s),r=(t,s)=>{const r=t-e,a=s-i;return[e+r*o-a*n,i+r*n+a*o]};return[r(t.x,t.y),r(t.x+t.w,t.y),r(t.x+t.w,t.y+t.h),r(t.x,t.y+t.h)]}function or(t){const e=sr(t),i=(t,e)=>[(t[0]+e[0])/2,(t[1]+e[1])/2],s=[(e[0][0]+e[2][0])/2,(e[0][1]+e[2][1])/2];return{points:[...e,i(e[0],e[1]),i(e[1],e[2]),i(e[2],e[3]),i(e[3],e[0]),s],segments:e.map((t,i)=>({a:t,b:e[(i+1)%4]}))}}function nr(t,e,i,s,o,n,r,a){const l=Zn(t.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),p=Math.cos(l),u=t.x+t.w/2,_=t.y+t.h/2,m=e>0?-t.w/2:t.w/2,g=i>0?-t.h/2:t.h/2,f=u+m*c+g*d,v=_+m*h+g*p,y=s-f,b=o-v;let w=(y*c+b*h)*(e>0?1:-1),k=(y*d+b*p)*(i>0?1:-1),$=null;if(n){const e=w/Math.max(t.w,a),i=k/Math.max(t.h,a);$=Math.max(a/Math.max(t.w,a),a/Math.max(t.h,a),e,i),w=t.w*$,k=t.h*$}if(r>0)if(n){const e=Math.max(1,Math.round(t.w/r)),i=Math.max(1,Math.round(t.h/r));if(Math.abs(t.w-e*r)<1e-6&&Math.abs(t.h-i*r)<1e-6){const s=(t,e)=>{let i=Math.abs(t),s=Math.abs(e);for(;s;)[i,s]=[s,i%s];return Math.max(1,i)},o=1/s(e,i),n=Math.max(a/t.w,a/t.h),r=Math.max(n,Math.round(($??1)/o)*o);w=t.w*r,k=t.h*r}else{t.w>=t.h?(w=Math.round(w/r)*r,k=w*(t.h/Math.max(t.w,a))):(k=Math.round(k/r)*r,w=k*(t.w/Math.max(t.h,a)))}}else w=Math.round(w/r)*r,k=Math.round(k/r)*r;w=Math.max(a,w),k=Math.max(a,k);return{x:f+(e>0?w/2:-w/2)*c+(i>0?k/2:-k/2)*d-w/2,y:v+(e>0?w/2:-w/2)*h+(i>0?k/2:-k/2)*p-k/2,w:w,h:k,angle:Zn(t.angle)||void 0}}const rr=(t,e,i)=>{const s=i[0]-e[0],o=i[1]-e[1],n=s*s+o*o;if(n<1e-12)return[...e];const r=Math.max(0,Math.min(1,((t[0]-e[0])*s+(t[1]-e[1])*o)/n));return[e[0]+s*r,e[1]+o*r]};const ar=15;function lr(t,e){return Number.isFinite(t)&&t>0&&Number.isFinite(e)&&e>0&&t*e<3}function cr(t){return Number.isFinite(t)?Math.max(1,Math.min(100,t)):1}function hr(t,e){return!Number.isFinite(t)||t<=0?"":String(e?Math.round(t/2.54*100)/100:Math.round(100*t)/100)}function dr(t,e,i){const s=Number(e)>0?Number(e):5;return cr(t)/s*i}function pr(t,e){return e>0&&Number.isFinite(t)?Math.round(t/e)*e:t}function ur(t,e){let i=e[0]-t[0],s=e[1]-t[1];const o=Math.hypot(i,s);return o<1e-12?[1,0]:(i/=o,s/=o,(i<-1e-12||Math.abs(i)<=1e-12&&s<0)&&(i=-i,s=-s),[i,s])}function _r(t,e,i){const s=pr((t[0]+e[0])/2,i),o=pr((t[1]+e[1])/2,i),[n,r]=ur(t,e);let a=Math.atan2(r,n);a<0&&(a+=Math.PI);const l=Math.round(1800*a)/1800,c=i>0&&i<.01?6:i<1?4:2;return`${s.toFixed(c)},${o.toFixed(c)}@${l.toFixed(4)}`}function mr(t,e,i,s){return 1===s?_r(t,e,i):_r([t[0]/s,t[1]/s],[e[0]/s,e[1]/s],i)}function gr(t,e){if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return null;const i=[Number(t.a[0]),Number(t.a[1]),Number(t.b[0]),Number(t.b[1])];if(!i.every(Number.isFinite))return null;const s=e>0?e:1;return[[i[0]*s,i[1]*s],[i[2]*s,i[3]*s]]}function fr(t,e,i,s,o){const n=o>0?o:1;return{key:mr(t,e,s,n),cm:cr(i),a:[t[0]/n,t[1]/n],b:[e[0]/n,e[1]/n]}}function vr(t,e){const i=e>0?e:1,s=[];for(const e of t){const t=e.key.lastIndexOf("@");if(t<0)continue;const[o,n]=e.key.slice(0,t).split(",").map(Number),r=Number(e.key.slice(t+1));[o,n,r].every(Number.isFinite)&&s.push({w:e,x:o*i,y:n*i,ang:r})}return s}function yr(t,e){const[i,s]=ur(t,e);let o=Math.atan2(s,i);return o<0&&(o+=Math.PI),o}function br(t,e){let i=Math.abs(t-e);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function wr(t,e,i,s,o=1){if(!t?.length)return null;const n=mr(e,i,s,o),r=t.find(t=>t.key===n);if(r)return r;const a=o>0?o:1,l=(e[0]+i[0])/2,c=(e[1]+i[1])/2,h=yr(e,i),d=Math.max(.5*s,1e-9)*a;for(const e of vr(t,a))if(br(e.ang,h)&&Math.hypot(e.x-l,e.y-c)<=d)return e.w;return null}function kr(t,e,i,s,o=1){const n=wr(t,e,i,s,o);return n&&n.cm>0?cr(n.cm):0}function $r(t,e,i,s=1,o=[]){if(!t?.length)return[];const n=new Set,r=Xe(e);for(const t of r)n.add(mr([t[0],t[1]],[t[2],t[3]],i,s));const a=e||[],l=Math.max(i*s*.02,1e-9);for(let t=0;t(n.has(t.key)||(t=>{const e=gr(t,s);if(!e)return!1;const[i,n]=e,a=n[0]-i[0],c=n[1]-i[1],h=Math.hypot(a,c);if(h<=l)return!1;if(!r.some(t=>{const e=[t[0],t[1]],s=[t[2],t[3]];return br(yr(i,n),yr(e,s))&&Br(i[0],i[1],e[0],e[1],s[0],s[1])<=l&&Br(n[0],n[1],e[0],e[1],s[0],s[1])<=l}))return!1;const d=(o||[]).some(t=>{const e=[t[0],t[1]],s=[t[2],t[3]];if(!br(yr(i,n),yr(e,s)))return!1;const o=t=>Math.abs((t[0]-i[0])*c-(t[1]-i[1])*a)/h;if(o(e)>l||o(s)>l)return!1;const r=h*h,d=((e[0]-i[0])*a+(e[1]-i[1])*c)/r,p=((s[0]-i[0])*a+(s[1]-i[1])*c)/r;return Math.min(1,Math.max(d,p))-Math.max(0,Math.min(d,p))>l/h});return!d})(t))&&t.cm>=1&&t.cm<=100)}function xr(t,e,i,s=8){const[o,n]=ur(t,e);let r=Math.atan2(n,o);r<0&&(r+=Math.PI);let a=i*Math.PI/180%Math.PI;a<0&&(a+=Math.PI);let l=Math.abs(r-a);return l>Math.PI/2&&(l=Math.PI-l),l<=s*Math.PI/180}function Sr(t,e,i,s,o=1){if(!t?.length)return[];if(e.length!==i.length)return t.slice();const n=new Map;for(let t=0;t0?o:1,a=Math.max(.5*s,1e-9)*r,l=new Set,c=[];for(const o of t){let t="",h=null;const d=gr(o,r);if(d)for(let o=0;oa||Br(d[1][0],d[1][1],n[0],n[1],l[0],l[1])>a)continue;const u=l[0]-n[0],_=l[1]-n[1],m=u*u+_*_;if(m<1e-18)continue;const g=t=>{const e=Math.max(0,Math.min(1,((t[0]-n[0])*u+(t[1]-n[1])*_)/m));return[c[0]+(p[0]-c[0])*e,c[1]+(p[1]-c[1])*e]};h=[g(d[0]),g(d[1])],t=mr(h[0],h[1],s,r);break}if(d||(t=n.get(o.key)||""),!t){const n=vr([o],r)[0];if(n)for(let o=0;o1.000001)continue;if(Br(n.x,n.y,l[0],l[1],c[0],c[1])>a)continue;const g=h[0]+(d[0]-h[0])*Math.max(0,Math.min(1,m)),f=h[1]+(d[1]-h[1])*Math.max(0,Math.min(1,m)),[v,y]=ur(h,d),b=Math.max(s*r,1e-6);t=mr([g-v*b,f-y*b],[g+v*b,f+y*b],s,r);break}}t||(t=o.key),l.has(t)||(l.add(t),c.push(h?fr(h[0],h[1],o.cm,s,r):{...o,key:t,cm:cr(o.cm)}))}return c}function Mr(t,e,i,s,o,n=1){const r=mr(e,i,o,n),a=(t||[]).filter(t=>t.key!==r);return null==s||s<1?a:[...a,fr(e,i,s,o,n)]}function Cr(t,e,i,s,o,n=[],r=1){let a=t?t.slice():[];for(const t of function(t,e,i,s,o=1,n=[]){const r=Fr(t,e,i,s,o,n);if(!r)return[];const a=[];for(let t=0;t0)||!t||t.length<2)return"";if(i&&t.length>=3){let i=t;const s=t[t.length-1];if(t.length>=4&&Math.hypot(t[0][0]-s[0],t[0][1]-s[1])<1e-9&&(i=t.slice(0,-1)),i.length>=3){const t=i.map(()=>e),s=Kr(i,t),o=Ir(i,t);if(s&&o)return`${Er(s)} ${Er(Nr(o))}`}}let s="";for(let i=0;i.05)&&Br(r,a,t[0],t[1],t[2],t[3])<=n)return!0}return!1}function Pr(t,e){return Math.max(t*(e>0?e:1)*.04,1e-9)}function Rr(t,e){const i=t[e],s=t[(e+1)%t.length],o=s[0]-i[0],n=s[1]-i[1],r=Math.hypot(o,n)||1;let a=-n/r,l=o/r;const c=[(i[0]+s[0])/2,(i[1]+s[1])/2];return function(t,e){let i=!1;for(let s=0,o=e.length-1;st[1]!=l>t[1]&&t[0]<(a-n)*(t[1]-r)/(l-r+0)+n&&(i=!i)}return i}([c[0]+.001*a,c[1]+.001*l],t)||(a=-a,l=-l),[a,l]}function Ar(t,e){const i=t[0]*e[1]-t[1]*e[0],s=t[0]*e[0]+t[1]*e[1];return Math.abs(i)<1e-9&&s>0}function zr(t,e,i,s){const o=e[0]*s[1]-e[1]*s[0];if(Math.abs(o)<1e-12)return null;const n=[i[0]-t[0],i[1]-t[1]],r=(n[0]*s[1]-n[1]*s[0])/o;return[t[0]+r*e[0],t[1]+r*e[1]]}function Ir(t,e){const i=t?.length||0;if(i<3||e.length!==i)return null;if(e.every(t=>!(t>0)))return t.map(t=>[t[0],t[1]]);const s=[];for(let o=0;o0||d>0)){s.push([t[o][0],t[o][1]]);continue}if(Ar(b,w)){const e=t[o],i=[e[0]+p*h,e[1]+u*h],n=[e[0]+_*d,e[1]+m*d];s.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&s.push(n);continue}const x=zr(k,b,$,w),S=Math.max(h,d,1e-9);if(x){if(Math.hypot(x[0]-t[o][0],x[1]-t[o][1])<=4*S){s.push(x);continue}}h>0&&s.push([t[o][0]+p*h,t[o][1]+u*h]),d>0&&s.push([t[o][0]+_*d,t[o][1]+m*d]),h>0||d>0||s.push([t[o][0],t[o][1]])}return s.length>=3?s:null}function Er(t,e=!0){if(!t.length)return"";let i=`M ${t[0][0]} ${t[0][1]}`;for(let e=1;et?.id===e),a=Je(r);if(!a||a.length<3)return null;const l=Pr(s,o),c=[];for(const i of t||[]){if(!i||i.id===e)continue;const t=Je(i);if(t)for(const e of us(a,t,l))c.push([e[0],e[1]],[e[2],e[3]])}for(const t of i||[])c.push([t[0],t[1]],[t[2],t[3]]);for(const t of n||[]){const e=gr(t,o);e&&c.push(e[0],e[1])}const h=[],d=[];for(let t=0;tl)continue;const r=((t[0]-e[0])*(i[0]-e[0])+(t[1]-e[1])*(i[1]-e[1]))/(s*s);r<=o||r>=1-o||(n.some(t=>Math.abs(t-r)*s<=2*l)||n.push(r))}n.sort((t,e)=>t-e);for(const s of n)h.push([e[0]+(i[0]-e[0])*s,e[1]+(i[1]-e[1])*s]),d.push(t)}return{poly:h,parent:d,orig:a}}function Or(t,e,i,s){const o=e.poly.length,n=new Array(o).fill(0);if(!t?.length)return n;const r=new Set,a=[];for(let l=0;l0?(n[l]=cr(c.cm),r.add(c.key)):a.push(l)}if(!a.length)return n;const l=s>0?s:1,c=Math.max(.5*i,1e-9)*l,h=vr(t,l).filter(t=>t.w.cm>0),d=new Map;for(const t of a){const i=e.parent[t],s=d.get(i);s?s.push(t):d.set(i,[t])}for(const[t,i]of d){const s=e.orig[t],o=e.orig[(t+1)%e.orig.length],a=yr(s,o),d=(s[0]+o[0])/2,p=(s[1]+o[1])/2;let u=null;const _=Math.hypot(o[0]-s[0],o[1]-s[1]);for(const t of h){if(r.has(t.w.key))continue;if(!br(t.ang,a))continue;const e=gr(t.w,l);let i=!1,n=0;if(e){if(!br(yr(e[0],e[1]),a))continue;if(Br(s[0],s[1],e[0][0],e[0][1],e[1][0],e[1][1])>c||Br(o[0],o[1],e[0][0],e[0][1],e[1][0],e[1][1])>c)continue;i=!0,n=Math.max(0,Math.hypot(e[1][0]-e[0][0],e[1][1]-e[0][1])-_)}else{if(Br(t.x,t.y,s[0],s[1],o[0],o[1])>c)continue;n=Math.hypot(t.x-d,t.y-p)}(!u||i&&!u.exact||i===u.exact&&nt?.id===e),o=Je(s);if(!o)return[];const n=[];for(const s of t||[]){if(!s||s.id===e)continue;const t=Je(s);if(t)for(const e of us(o,t,i))n.push(e)}return n}(t,e,Pr(o,a)),h=function(t,e,i,s,o){const n=Pr(s,o),r=[];for(let a=0;aBr(h,d,t[0],t[1],t[2],t[3])<=n);r.push(p?"shared":"outer")}return r}(l.poly,c,s,o,a),d=Or(i,l,o,a),p=d.map((t,e)=>h[e]&&t>0?dr(t,n,r)/2:0);return{...l,kinds:h,cms:d,offsets:p}}function Hr(t,e,i,s,o,n,r=1){const a=[];for(const l of t||[]){if(!l?.id)continue;const c=Lr(t,l.id,e,i,s,o,n,r);if(c)for(let t=0;t0&&!l.has(c.key)&&(l.add(c.key),a.push(c));const c=[];for(const a of t||[]){if(!a?.id)continue;const l=Lr(t,a.id,e,i,s,o,n,r);if(l)for(let t=0;t0)||null===l.kinds[i]){t++;continue}let n=t;for(;n+10&&c.push({a:[h[0],h[1]],b:[d[0],d[1]],key:mr(h,d,s,r),cm:o,len:p}),t=n+1}}}c.sort((t,e)=>e.len-t.len||t.key.localeCompare(e.key));const h=[],d=new Set,p=new Set,u=4*Pr(s,r);for(const t of c){const e=a.filter(e=>!p.has(e.key)&&e.cm===t.cm&&br(yr(e.a,e.b),yr(t.a,t.b))&&Br(e.a[0],e.a[1],t.a[0],t.a[1],t.b[0],t.b[1])<=u&&Br(e.b[0],e.b[1],t.a[0],t.a[1],t.b[0],t.b[1])<=u);if(e.length){for(const t of e)p.add(t.key);d.has(t.key)||(d.add(t.key),h.push(fr(t.a,t.b,t.cm,s,r)))}}for(const t of a)p.has(t.key)||d.has(t.key)||(d.add(t.key),h.push(fr(t.a,t.b,t.cm,s,r)));return h}function Ur(t,e,i,s,o,n,r,a=1){const l=Pr(o,a),c=(s[0]+s[2])/2,h=(s[1]+s[3])/2,d=yr([s[0],s[1]],[s[2],s[3]]);let p=null;for(const s of Hr(t,e,i,o,n,r,a)){if(!br(yr(s.a,s.b),d))continue;const t=Br(c,h,s.a[0],s.a[1],s.b[0],s.b[1]);t>4*l||(!p||tt?.id===e),c=Je(l);if(!c||c.length<3)return null;if(!i?.length)return c.map(t=>[t[0],t[1]]);const h=Lr(t,e,i,s,o,n,r,a);return h&&h.offsets.some(t=>t>0)&&Ir(h.poly,h.offsets)||c.map(t=>[t[0],t[1]])}function Gr(t){const e=t.map(t=>[t[0],t[1]]);return e.push([t[0][0],t[0][1]]),[e]}function Wr(t,e,i,s=[],o,n,r,a=1,l=[]){if(!e?.length&&!l.length)return null;const c=[];let h=0;for(const s of t||[]){if(!s?.id)continue;const l=Lr(t,s.id,e,i,o,n,r,a);if(!l||l.poly.length<3||!l.offsets.some(t=>t>0))continue;for(const t of l.offsets)t>0&&(h=Math.max(h,2*t));const d=Kr(l.poly,l.offsets),p=Ir(l.poly,l.offsets);d&&c.push({outset:d,inset:p})}for(const t of l){const e=t.map(t=>t[0]),i=t.map(t=>t[1]);if(e.length){const s=Math.min(Math.max(...e)-Math.min(...e),Math.max(...i)-Math.min(...i)),o=Math.min(...t.map((e,i)=>{const s=t[(i+1)%t.length];return Math.hypot(s[0]-e[0],s[1]-e[1])}));h=Math.max(h,t.length>16?s:o)}}const d=function(t,e,i,s,o,n,r){if(!e?.length||!i?.length)return[];const a=4*Pr(s,r),l=new Map;for(const a of Hr(t,e,i,s,o,n,r))!a.open&&a.half>0&&!l.has(a.key)&&l.set(a.key,a);const c=[...l.values()];if(c.length<2)return[];const h=[];for(const t of i)for(const e of[[t[0],t[1]],[t[2],t[3]]])h.some(t=>Math.hypot(t[0]-e[0],t[1]-e[1])<=a)||h.push(e);const d=[],p=(t,e)=>{let i=0,s=0;if(Math.hypot(t.a[0]-e[0],t.a[1]-e[1])<=a)i=t.b[0]-t.a[0],s=t.b[1]-t.a[1];else{if(!(Math.hypot(t.b[0]-e[0],t.b[1]-e[1])<=a))return null;i=t.a[0]-t.b[0],s=t.a[1]-t.b[1]}const o=Math.hypot(i,s);return o>a?[i/o,s/o]:null};for(const t of h){const e=c.map(e=>({iv:e,u:p(e,t)})).filter(t=>!!t.u);for(let i=0;i4*_||d.push(r>0?[t.slice(),h,u,p]:[t.slice(),p,u,h])}}return d}(t,e,i,o,n,r,a),p=s.length?Jr(t,e,i,o,n,r,a):null;try{const t=t=>{const e=Gr(t.outset);return t.inset?Ge(e,Gr(t.inset)):e};let e=c.length?t(c[0]):null;for(let i=1;i0))continue;const i=Qr(p,t,!0);if(!i.negative&&!i.positive)continue;const s=t.angle*Math.PI/180,n=Math.cos(s),r=Math.sin(s),l=-r,c=n,d=t.length/2,u=1.25*Math.max(h,o*a),_=[[t.x-n*d-l*u,t.y-r*d-c*u],[t.x+n*d-l*u,t.y+r*d-c*u],[t.x+n*d+l*u,t.y+r*d+c*u],[t.x-n*d+l*u,t.y-r*d+c*u]];e&&(e=Ge(e,Gr(_)))}for(const t of l)t.length<3||(e=e?Be(e,Gr(t)):[Gr(t)]);return e?{geom:e,depthUnits:h}:null}catch{return null}}function Vr(t,e,i,s=[],o,n,r,a=1,l=[]){if(!e?.length&&!l.length)return null;const c=Wr(t,e,i,s,o,n,r,a,l),h=c?function(t){if(!t)return"";let e="";for(const i of t)if(Array.isArray(i))for(const t of i){if(!Array.isArray(t)||t.length<4)continue;const i=t.slice(0,t.length-1);i.length<3||(e+=(e?" ":"")+Er(i.map(t=>[t[0],t[1]])))}return e}(c.geom):"";if(c&&h)return{d:h,depthUnits:c.depthUnits,fillRule:"evenodd"};const d=function(t,e,i,s,o,n,r=1){if(!e?.length)return[];const a=[];for(const l of t||[]){if(!l?.id)continue;const c=Lr(t,l.id,e,i,s,o,n,r);if(!c||c.poly.length<3||!c.offsets.some(t=>t>0))continue;const h=Kr(c.poly,c.offsets),d=Ir(c.poly,c.offsets);if(!h||!d)continue;const p=`${Er(h)} ${Er(Nr(d))}`;let u="",_="outer",m=0,g=0;for(let t=0;t0){u=mr(c.poly[t],c.poly[(t+1)%c.poly.length],s,r),_=c.kinds[t]||"outer",m=c.cms[t],g=dr(m,o,n);break}a.push({d:p,key:u,kind:_,cm:m,depthUnits:g})}return a}(t,e,i,o,n,r,a),p=l.map(t=>Er(t)).join(" ");if(!d.length&&!p)return null;let u=c?.depthUnits||0;for(const t of d)u=Math.max(u,t.depthUnits);return{d:[d.map(t=>t.d).join(" "),p].filter(Boolean).join(" "),depthUnits:u,fillRule:"nonzero"}}function Kr(t,e){const i=t?.length||0;if(i<3||e.length!==i)return null;if(e.every(t=>!(t>0)))return t.map(t=>[t[0],t[1]]);Nr(t),e.slice().reverse();const s=[];for(let o=0;o0||a>0)){s.push([t[o][0],t[o][1]]);continue}if(Ar(b,w)){const e=t[o],i=[e[0]-l*r,e[1]-c*r],n=[e[0]-h*a,e[1]-d*a];s.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&s.push(n);continue}const x=zr(k,b,$,w),S=Math.max(r,a,1e-9);if(x){if(Math.hypot(x[0]-t[o][0],x[1]-t[o][1])<=4*S){s.push(x);continue}}r>0&&s.push([t[o][0]-l*r,t[o][1]-c*r]),a>0&&s.push([t[o][0]-h*a,t[o][1]-d*a])}return s.length>=3?s:null}function Yr(t,e,i,s,o,n,r=1){const a=[];for(const l of t||[]){const c=Je(l);if(c&&c.length>=3){const h=Lr(t,l.id,e,i,s,o,n,r),d=h&&h.offsets.some(t=>t>0)?Kr(h.poly,h.offsets):null,p=d||c;a.push({poly:p.map(t=>t.join(",")).join(" ")})}else l&&null!=l.x&&null!=l.y&&null!=l.w&&null!=l.h&&a.push({rect:{x:l.x,y:l.y,w:l.w,h:l.h,rx:.03*Math.min(l.w,l.h)}})}return a}function Jr(t,e,i,s,o,n,r=1){const a=[];for(const l of t||[]){if(!l?.id)continue;const c=Lr(t,l.id,e,i,s,o,n,r);if(!c)continue;const h=Math.abs(mi(c.poly));for(let t=0;t[Math.max(e,t.x0),Math.min(i,t.x1)]).filter(t=>t[1]-t[0]>s).sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(!o.length)return{coverage:0,full:!1};let n=o[0][0],r=o[0][1],a=0,l=n<=e+s;for(let t=1;t=i-s,{coverage:a,full:l}}function Xr(t,e){return Number(e.full)-Number(t.full)||t.faceDistance-e.faceDistance||t.area-e.area||t.roomId.localeCompare(e.roomId)}function Qr(t,e,i=!1){const s=Number(e?.x),o=Number(e?.y),n=Number(e?.angle),r=Number(e?.length);if(!([s,o,n,r].every(Number.isFinite)&&r>0))return{negative:null,positive:null};const a=n*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,p=r/2,u=Math.max(1e-9,t.adjacencyEps),_=new Map;let m=0;for(const e of t.edges){if(i&&!(e.half>0))continue;if(!xr(e.a,e.b,n))continue;const[t,r]=ur(e.a,e.b);if(Math.abs((s-e.a[0])*r-(o-e.a[1])*t)>u)continue;const a=(e.a[0]-s)*l+(e.a[1]-o)*c,g=(e.b[0]-s)*l+(e.b[1]-o)*c,f=Math.max(-p,Math.min(a,g)),v=Math.min(p,Math.max(a,g));if(v-f<=u)continue;const y=e.inward[0]*h+e.inward[1]*d>=0?1:-1,b=((e.a[0]+e.b[0])/2-s)*h+((e.a[1]+e.b[1])/2-o)*d,w=Math.abs(b+y*e.half),k=`${y}|${e.roomId}`,$={x0:f,x1:v,half:e.half,cm:e.cm,key:e.key,axis:[t,r]},x=_.get(k);x?(x.pieces.push($),x.faceDistance=Math.min(x.faceDistance,w)):_.set(k,{roomId:e.roomId,side:y,order:m++,pieces:[$],faceDistance:w,area:e.area,coverage:0,full:!1})}for(const t of _.values()){const e=Zr(t.pieces,-p,p,u);t.coverage=e.coverage,t.full=e.full}const g=t=>{const e=[..._.values()].filter(e=>e.side===t&&e.coverage>u);return e.sort(Xr),e[0]||null};return{negative:g(-1),positive:g(1)}}function ta(t,e){const i=Qr(t,e),s=[i.negative,i.positive].filter(t=>!!t).sort((t,e)=>t.order-e.order);if(!s.length)return{ox:0,oy:0,cm:0,side:-1};const o=s[0],n=e.flip_v?-o.side:o.side,r=(-1===n?i.negative:i.positive)||o,a=[...r.pieces].sort((t,e)=>(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))-(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))||e.x1-e.x0-(t.x1-t.x0)||t.key.localeCompare(e.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:n};const l=e.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*n*a.half,oy:h*n*a.half,cm:a.cm,side:n}}function ea(t,e){const i=1e-9,s=[];for(const t of[...e].filter(t=>t.x1>t.x0&&t.half>0).sort((t,e)=>t.x0-e.x0||t.x1-e.x1||t.half-e.half)){const e=s[s.length-1];e&&t.x0<=e.x1+i&&Math.abs(t.half-e.half)<=i?e.x1=Math.max(e.x1,t.x1):s.push({...t})}const o=[];for(let e=0;e=o-l?i.push([s,o]):(t>s+l&&i.push([s,Math.min(o,t)]),et[0]-e[0]||t[1]-e[1]),b=[];for(const t of y){const e=b[b.length-1];e&&t[0]<=e[1]+l?e[1]=Math.max(e[1],t[1]):b.push([t[0],t[1]])}s.set(g,b)}return a}function sa(t,e){const i=new Map;return e.map(e=>function(t,e,i){const s=Qr(t,e,!0),o=s.negative,n=s.positive;if(!o&&!n)return null;let r;if(o&&n)r=[{candidate:o,side:-1},{candidate:n,side:1}];else{const t=o||n;r=[{candidate:t,side:-1},{candidate:t,side:1}]}const a=r.map(({candidate:t,side:s})=>({candidate:t,side:s,pieces:ia(e,s,t.pieces,i)})),l=a.map(({candidate:t,side:e,pieces:i})=>({side:e,roomId:t.roomId,d:ea(e,i)})),c=a.flatMap(({pieces:t})=>t);if(!c.length)return null;const h=Math.max(...c.map(t=>t.half));return{faces:l,minY:-h,maxY:h,wallKey:[...new Set(c.map(t=>t.key))].sort().join("|")}}(t,e,i))}const oa=150;function na(t){return Number.isFinite(t)?Math.max(1,Math.min(oa,t)):1}function ra(t){return((Number.isFinite(Number(t))?Number(t):0)%90+90)%90}const aa=t=>{const e=t.map(t=>[t[0],t[1]]);return!e.length||e[0][0]===e[e.length-1][0]&&e[0][1]===e[e.length-1][1]||e.push([...e[0]]),[e]};function la(t){const e=[];for(const i of t||[])for(const t of i||[]){const i=(t||[]).filter(t=>Array.isArray(t)&&t.length>=2);i.length<4||e.push(`M ${i.slice(0,-1).map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`)}return e.join(" ")}function ca(t,e,i,s,o){const n=e[0]-t[0],r=e[1]-t[1],a=Math.hypot(n,r);if(!(a>1e-9))return null;const l=dr(i,s,o)/2,c=-r/a*l,h=n/a*l;return[[t[0]+c,t[1]+h],[e[0]+c,e[1]+h],[e[0]-c,e[1]-h],[t[0]-c,t[1]-h]]}function ha(t,e,i){const s=Number(e)>0?Number(e):5,o=na(t.cm)/s*i,n=t.center[0],r=t.center[1];if("circle"===t.shape){const t=o/2;return Array.from({length:96},(e,i)=>{const s=i/96*Math.PI*2;return[n+Math.cos(s)*t,r+Math.sin(s)*t]})}const a=o/2,l=ra(t.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l);return[[-a,-a],[a,-a],[a,a],[-a,a]].map(([t,e])=>[n+t*c-e*h,r+t*h+e*c])}function da(t,e,i){const s=[];for(let o=0;o+1t.length>=3).map(t=>aa(t));return e.length?Be(e[0],...e.slice(1)):null}catch{return null}}const ua=t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`;function _a(t){const e=[];for(const i of t||[]){const t=[];for(const e of i||[]){const i=(e||[]).filter(t=>Array.isArray(t)&&t.length>=2);i.length<4||t.push(ua(i.slice(0,-1)))}t.length&&e.push(t.join(" "))}return e}function ma(t,e){const i=pa(t.filter(t=>t.length>=3)),s=pa(e.filter(t=>t.length>=3));if(!i)return[];if(!s)return _a(i);try{return _a(je(i,s))}catch{return _a(i)}}function ga(t,e){if(!e.length)return[aa(t)];try{const i=pa(e);if(i)return Ge(aa(t),i)}catch{}let i=[aa(t)];for(const t of e)if(!(t.length<3))try{i=Ge(i,aa(t))}catch{}return i}function fa(t){let e=0;for(const i of t||[])if(i?.length){e+=mi(i[0]||[]);for(let t=1;t=4&&e.push(t.slice(0,-1).map(t=>[t[0],t[1]]))}return e}function ya(t,e){let i=!1;for(let s=0,o=e.length-1;st[1]!=l>t[1]&&t[0]<(a-n)*(t[1]-r)/(l-r||1e-12)+n&&(i=!i)}return i}function ba(t,e,i){if(Math.hypot(t.center[0]-e.center[0],t.center[1]-e.center[1])>i)return!1;if(Math.abs(na(t.cm)-na(e.cm))>1e-6)return!1;if(t.shape!==e.shape)return!0;if("circle"===t.shape||"circle"===e.shape)return!0;const s=Math.abs(ra(t.angle)-ra(e.angle));return Math.min(s,90-s)<=1e-6}const wa=1e3;function ka(t,e){const i=Number(t),s=Number.isFinite(i)&&i>0?i:1,o=s>=1?e:e*s,n=s>=1?e/s:e;return{x:(e-o)/2,y:(e-n)/2,w:o,h:n}}const $a=.01,xa=100;function Sa(t,e=1e3){const i=ka(t?.plan_aspect,e),s=Number(t?.plan_scale),o=Number.isFinite(s)&&s>0?Math.min(xa,Math.max($a,s)):1,n=Number(t?.plan_scale_x),r=Number(t?.plan_scale_y),a=Number.isFinite(n)&&n>0?Math.min(xa,Math.max($a,n)):o,l=Number.isFinite(r)&&r>0?Math.min(xa,Math.max($a,r)):o,c=Number(t?.plan_x),h=Number(t?.plan_y),d=Zn(t?.plan_angle);return{x:i.x+(Number.isFinite(c)?Na(c):0)*e,y:i.y+(Number.isFinite(h)?Na(h):0)*e,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Ma(t){if(null==t.x||null==t.y)return{x:t.x,y:t.y,w:t.w,h:t.h};const e=Number(t.w)||0,i=Number(t.h)||0;return{x:e<0?t.x+e:t.x,y:i<0?t.y+i:t.y,w:Math.abs(e),h:Math.abs(i)}}function Ca(t){return t&&Array.isArray(t.spaces)?t.spaces.map(t=>{const e=wa,i=function(t){return Array.isArray(t)&&4===t.length&&t.every(t=>Number.isFinite(t))&&t[2]>1e-6&&t[3]>1e-6?t:[0,0,1,1]}(t.view_box);return{id:t.id,title:t.title,vb:[i[0]*wa,i[1]*e,i[2]*wa,i[3]*e],bg:t.plan_url?{href:ys(t.plan_url),...Sa(t,wa)}:null,rooms:(t.rooms||[]).map(t=>{const i={...t,...Ma(t)};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*wa:void 0,y:null!=i.y?i.y*e:void 0,w:null!=i.w?i.w*wa:void 0,h:null!=i.h?i.h*e:void 0,poly:i.poly?i.poly.map(t=>[t[0]*wa,t[1]*e]):void 0}}),room_drafts:(t.room_drafts||[]).map(t=>({id:t.id,points:(t.points||[]).map(t=>[t[0]*wa,t[1]*e]),segments:(t.segments||[]).map(t=>({cm:Number(t.cm)}))})),partitions:(t.partitions||[]).map(t=>({id:t.id,a:[t.a[0]*wa,t.a[1]*e],b:[t.b[0]*wa,t.b[1]*e],cm:Number(t.cm)})),wall_columns:(t.wall_columns||[]).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[t.center[0]*wa,t.center[1]*e],cm:Number(t.cm),..."circle"===t.shape?{}:{angle:ra(t.angle)}}))}}):[]}const Da=5e3,Ta=Da*wa,Pa=240,Ra=wa/Pa,Aa=1/Pa;function za(t){if(!Number.isFinite(t))return t;const e=Math.round(t*Pa/wa)*wa/Pa;return Math.abs(e-t)<=1e-9*Ra?t:e}function Ia(t){return{x:za(t.x),y:za(t.y)}}function Ea(t){return Number.isFinite(t)?Math.min(Ta,Math.max(-Ta,t)):0}function Na(t){return Number.isFinite(t)?Math.min(Da,Math.max(-Da,t)):0}const Fa=1/3,Oa=200;function La(t){let e=1/0,i=1/0,s=-1/0,o=-1/0;for(const n of t){const t=Number(n[0]),r=Number(n[1]);Number.isFinite(t)&&Number.isFinite(r)&&(ts&&(s=t),r>o&&(o=r))}return e>s?null:{minX:e,minY:i,maxX:s,maxY:o}}function Ha(t){return t.poly&&t.poly.length?La(t.poly):null==t.x||null==t.y?null:La([[t.x,t.y],[t.x+(t.w||0),t.y+(t.h||0)]])}function qa(t,e){const i=[];for(const e of t.rooms||[]){const t=Ha(e);t&&i.push(t)}if(t.bg){const e=La(sr(t.bg));e&&i.push(e)}for(const t of e||[])if(Array.isArray(t)){const e=La([t]);e&&i.push(e)}else i.push(t);return i}const Ua=t=>{if(!t.length)return 0;const e=[...t].sort((t,e)=>t-e),i=e.length>>1;return e.length%2?e[i]:(e[i-1]+e[i])/2},Ba=t=>{let e=1/0,i=1/0,s=-1/0,o=-1/0;for(const n of t)n.minXs&&(s=n.maxX),n.maxY>o&&(o=n.maxY);return e>s||i>o?null:{x:e,y:i,w:s-e,h:o-i}};function ja(t,e){let{x:i,y:s,w:o,h:n}=t;o<30&&(i=i+o/2-100,o=Oa),n<30&&(s=s+n/2-100,n=Oa);const r=Math.max(o,n)*e;return{x:i-r,y:s-r,w:o+2*r,h:n+2*r}}function Ga(t,e={}){const i=e.pad??.05,s=e.k??10,o=e.minSpread??50,n=t.filter(t=>Number.isFinite(t.minX)&&Number.isFinite(t.minY)&&Number.isFinite(t.maxX)&&Number.isFinite(t.maxY)&&Math.abs(t.minX)<=Ta&&Math.abs(t.maxX)<=Ta&&Math.abs(t.minY)<=Ta&&Math.abs(t.maxY)<=Ta);if(!n.length)return{core:null,all:null,outliers:0};const r=Ba(n);if(n.length<4){const t=ja(r,i);return{core:t,all:t,outliers:0}}const a=n.map(t=>(t.minX+t.maxX)/2),l=n.map(t=>(t.minY+t.maxY)/2),c=Ua(a),h=Ua(l),d=n.map((t,e)=>Math.max(Math.abs(a[e]-c),Math.abs(l[e]-h))),p=Math.max(((t,e)=>t.length?t[Math.min(t.length-1,Math.max(0,Math.round(e*(t.length-1))))]:0)([...d].sort((t,e)=>t-e),.75),o),u=d.map(t=>t>s*p),_=u.filter(Boolean).length,m=_&&_<=n.length*Fa?n.filter((t,e)=>!u[e]):n;return{core:ja(Ba(m)||r,i),all:ja(r,i),outliers:m===n?0:_}}function Wa(t,e,i=.05){const s=Ga(qa(t,e),{pad:i});if(s.core)return s.core;const o=t.vb&&4===t.vb.length&&t.vb[2]>0&&t.vb[3]>0?t.vb:[0,0,wa,wa];return{x:o[0],y:o[1],w:o[2],h:o[3]}}function Va(t){const e=Wa(t);return{x:e.x+e.w/2,y:e.y+e.h/2}}function Ka(t){const e=[];for(const i of t.rooms||[]){const t=Ha(i);t&&e.push(t)}const i=Ga(e,{pad:0}).core;return i?Math.max(wa,Math.min(Ta,Math.max(i.w,i.h))):wa}function Ya(t,e,i,s=1){const o=Number(i),n=Number.isFinite(s)&&s>0?s:1;return!Number.isFinite(o)||o<=0?t*n:t*Ka(e)*n/o}const Ja=[1,2,5,10,20,50,100,200,500,1e3];function Za(t){if(t.poly&&t.poly.length){const e=t.poly.map(t=>t[0]),i=t.poly.map(t=>t[1]),s=Math.min(...e),o=Math.min(...i);return{x:s,y:o,w:Math.max(...e)-s,h:Math.max(...i)-o}}return{x:t.x??0,y:t.y??0,w:t.w??0,h:t.h??0}}function Xa(t){if(t.poly){const e=t.poly.length;return[t.poly.reduce((t,e)=>t+e[0],0)/e,t.poly.reduce((t,e)=>t+e[1],0)/e]}return[t.x+t.w/2,t.y+.1*Math.min(t.w,t.h)]}const Qa=["furniture","appliance","sanitary","other"],tl=[{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]]}],el=new Map(tl.map(t=>[t.id,t]));function il(t){return t&&el.get(t)||null}function sl(t){return tl.filter(e=>e.group===t)}function ol(t,e,i=Ra,s=1e3){const o=Number(e)>0?Number(e):5;return(Number(t)||0)/o*i/s}const nl=5e-4,rl=Da;function al(t){return Number.isFinite(t)?Math.max(nl,Math.min(rl,t)):nl}const ll=t=>{const e=Math.round(1e3*t)/1e3;return Object.is(e,-0)?"0":String(e)};function cl(t,e,i){const s=il(t);if(!(s&&e>0&&i>0))return"";const o=t=>ll(t*e),n=t=>ll(t*i),r=[];for(const t of s.g)if("r"===t[0]){const[,e,i,s,a]=t;r.push(`M${o(e)} ${n(i)}H${o(e+s)}V${n(i+a)}H${o(e)}Z`)}else if("l"===t[0]){const[,e,i,s,a]=t;r.push(`M${o(e)} ${n(i)}L${o(s)} ${n(a)}`)}else if("e"===t[0]){const[,s,a,l,c]=t;r.push(`M${o(s-l)} ${n(a)}A${ll(l*e)} ${ll(c*i)} 0 0 1 ${o(s+l)} ${n(a)}A${ll(l*e)} ${ll(c*i)} 0 0 1 ${o(s-l)} ${n(a)}Z`)}else{const e=t.slice(1);if(e.length<4)continue;let i=`M${o(e[0])} ${n(e[1])}`;for(let t=2;t+1{let e=(t%360+360)%360;return e>180&&(e-=360),e};function dl(t,e,i,s,o,n=0){let r=null,a=o;for(const o of s){const[s,l,c,h]=o,d=c-s,p=h-l,u=d*d+p*p;if(!u)continue;const _=Math.sqrt(u);let m=((t-s)*d+(e-l)*p)/u;m=Math.max(0,Math.min(1,m));let g=s+m*d,f=l+m*p;const v=Math.hypot(t-g,e-f);if(!(v0){const t=Math.round(m*_/n)*n;g=s+t/_*d,f=l+t/_*p}r={cx:g+y*(i/2),cy:f+b*(i/2),angle:hl(180*Math.atan2(-y,b)/Math.PI),dist:v}}return r}function pl(t,e,i){const s=i;return{a:[t[0]/s,t[1]/s],b:[e[0]/s,e[1]/s]}}function ul(t,e){const i=e;return[t.a[0]*i,t.a[1]*i,t.b[0]*i,t.b[1]*i]}function _l(t){return Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1]))}function ml(t){if(!Array.isArray(t))return[];const e=[];for(const i of t){if(!i||"object"!=typeof i)continue;const t=i;if(!_l(t.a)||!_l(t.b))continue;const s=[Number(t.a[0]),Number(t.a[1])],o=[Number(t.b[0]),Number(t.b[1])];Math.hypot(o[0]-s[0],o[1]-s[1])<.001||e.push({a:s,b:o})}return e}function gl(t,e){const i=e[0],s=e[1],o=e[2]-i,n=e[3]-s,r=o*o+n*n;if(r<1e-18){return{q:[i,s],t:0,d:Math.hypot(t[0]-i,t[1]-s)}}let a=((t[0]-i)*o+(t[1]-s)*n)/r;a=Math.max(0,Math.min(1,a));const l=[i+a*o,s+a*n];return{q:l,t:a,d:Math.hypot(t[0]-l[0],t[1]-l[1])}}function fl(t,e){return gl(t,e).q}function vl(t,e,i,s,o){const n=gl(t,e).q;let r=n,a=1/0;for(const t of i){const e=Math.hypot(n[0]-t[0],n[1]-t[1]);e<=o&&e0?s:1,m=Math.round(u/_)*_,g=Math.max(0,Math.min(p,m))/p;return[l+h*g,c+d*g]}function yl(t,e){const i=[],s=(t||[]).filter(t=>t?.id);for(let t=0;tt?.id),r=ml(e);if(r.length)return Dl(r,t,i,s).map(t=>ul(t,i));if(!o)return[];const a=[],l=(t,e)=>(t.open_to||[]).includes(e.id)||(e.open_to||[]).includes(t.id);for(let t=0;tpl([t[0],t[1]],[t[2],t[3]],e))}function kl(t,e,i,s){for(const e of t||[])e.open_to&&delete e.open_to;if(!i.length)return;const o=(e||[]).filter(t=>t?.id);new Map(o.map(t=>[t.id,t]));const n=new Map((t||[]).filter(t=>t?.id).map(t=>[t.id,t])),r=(t,e)=>{const i=n.get(t),s=n.get(e);i&&s&&((i.open_to||[]).includes(e)||(i.open_to=[...i.open_to||[],e]),(s.open_to||[]).includes(t)||(s.open_to=[...s.open_to||[],t]))};for(let t=0;tSs(i,t)<4*s)){r(o[t].id,o[e].id);break}}}for(const e of t||[])e.open_to&&!e.open_to.length&&delete e.open_to}function $l(t,e,i,s=0){const o=e[2]-e[0],n=e[3]-e[1],r=Math.hypot(o,n);if(!(r>1e-9))return null;const a=o/r,l=n/r,c=(t[0]-e[0])*a+(t[1]-e[1])*l;if(c<-s||c>r+s)return null;return Math.abs((t[0]-e[0])*l-(t[1]-e[1])*a)>i?null:Ss(t,e)}function xl(t,e,i){const s=t[2]-t[0],o=t[3]-t[1],n=e[2]-e[0],r=e[3]-e[1],a=Math.hypot(s,o),l=Math.hypot(n,r);return a>1e-9&&l>1e-9&&(!(Math.abs(s/a*(r/l)-o/a*(n/l))>1e-6)&&(Ss([e[0],e[1]],t)<=4*i||Ss([t[0],t[1]],e)<=4*i))}function Sl(t,e,i){if(!t.length)return null;t.sort((t,e)=>t.distance-e.distance);const s=t[0];for(let o=1;oe)break;if(n.semantic!==s.semantic||!xl(s.seg,n.seg,i))return"ambiguous"}return s}function Ml(t,e,i,s,o=1,n=15){const r=function(t,e,i,s,o=1,n=15){const[r,a]=ur([e[0],e[1]],[e[2],e[3]]);let l=0,c=1/0;const h=[(e[0]+e[2])/2,(e[1]+e[3])/2];for(const e of i){const[i,n]=ur([e[0],e[1]],[e[2],e[3]]);if(Math.abs(r*n-a*i)>.05)continue;const d=kr(t,[e[0],e[1]],[e[2],e[3]],s,o);if(!(d>0))continue;const p=[(e[0]+e[2])/2,(e[1]+e[3])/2],u=Math.hypot(p[0]-h[0],p[1]-h[1]);u0?l:n}(t,e,i,s,o,n);return Mr(t,[e[0],e[1]],[e[2],e[3]],r,s,o)}function Cl(t,e,i){const s=[[t[0],t[1]],[t[2],t[3]]],o=[(t[0]+t[2])/2,(t[1]+t[3])/2];for(const n of e)if(!(Ss(o,n)>Math.hypot(t[2]-t[0],t[3]-t[1])&&Ss([n[0],n[1]],t)>i))for(const e of[[n[0],n[1]],[n[2],n[3]]])Ss(e,t)<=2*i&&s.push(e);return s}function Dl(t,e,i,s){const o=ml(t);if(!o.length)return[];const n=yl(e,s);if(!n.length)return[];const r=[],a=Math.max(4*s,1e-6);for(const t of o){const e=ul(t,i),o=e[0],l=e[1],c=e[2]-o,h=e[3]-l,d=Math.hypot(c,h);if(d4*s||n>4*s)continue;const r=(t[0]-o)*p+(t[1]-l)*u,c=(t[2]-o)*p+(t[3]-l)*u,h=Math.max(0,Math.min(r,c)),m=Math.min(d,Math.max(r,c));if(m-ht.lo-e.lo||t.hi-e.hi);const i=[];for(const t of e){const e=i[i.length-1];e&&t.lo<=e.hi+a?e.hi=Math.max(e.hi,t.hi):i.push({...t})}for(const e of i){const i=[o+p*e.lo,l+u*e.lo],s=[o+p*e.hi,l+u*e.hi];Math.hypot(s[0]-i[0],s[1]-i[1])i.pair===t&&Math.abs(i.ux*r-i.uy*n)<=1e-6&&Math.abs((e[0]-i.origin[0])*i.uy-(e[1]-i.origin[1])*i.ux)<=c&&Math.abs((e[2]-i.origin[0])*i.uy-(e[3]-i.origin[1])*i.ux)<=c);h||(h={pair:t,origin:[e[0],e[1]],ux:n,uy:r,ranges:[]},l.push(h));const d=(e[0]-h.origin[0])*h.ux+(e[1]-h.origin[1])*h.uy,p=(e[2]-h.origin[0])*h.ux+(e[3]-h.origin[1])*h.uy;h.ranges.push({lo:Math.min(d,p),hi:Math.max(d,p)})}const h=[];for(const t of l){t.ranges.sort((t,e)=>t.lo-e.lo||t.hi-e.hi);const e=[];for(const i of t.ranges){const t=e[e.length-1];t&&i.lo<=t.hi+a?t.hi=Math.max(t.hi,i.hi):e.push({...i})}for(const s of e){const e=[t.origin[0]+t.ux*s.lo,t.origin[1]+t.uy*s.lo],o=[t.origin[0]+t.ux*s.hi,t.origin[1]+t.uy*s.hi];Math.hypot(o[0]-e[0],o[1]-e[1])>=a&&h.push(pl(e,o,i))}}return h}function Tl(t,e,i,s){const o=ml(t);if(!o.length)return[];if(e.length!==i.length)return o;const n=[];for(const t of o){const o=ul(t,s),r=[o[0],o[1]],a=[o[2],o[3]];let l=r,c=a;for(let t=0;t{const e=gl(t,[s[0],s[1],o[0],o[1]]);if(e.d>.001)return t;const i=h[0]-n[0],r=h[1]-n[1];return[n[0]+i*e.t,n[1]+r*e.t]};if(gl([(r[0]+a[0])/2,(r[1]+a[1])/2],[s[0],s[1],o[0],o[1]]).d<.01){l=d(r),c=d(a);break}}n.push(pl(l,c,s))}return n}class Pl{constructor(t,e=()=>Date.now()){this.onUpdate=t,this.now=e,this.signed={},this.queued=new Set,this.inFlight=new Map,this.retry=new Map,this.disposed=!1}start(t,e){this.disposed=!1,this.stopTimer(),this.resignTimer=setInterval(()=>this.resign(t(),e()),288e5)}dispose(){this.disposed=!0,this.stopTimer(),clearTimeout(this.batchTimer),this.queued.clear(),this.inFlight.clear()}stopTimer(){void 0!==this.resignTimer&&clearInterval(this.resignTimer),this.resignTimer=void 0}display(t,e){const i=ys(e);if(!i.startsWith("/api/houseplan/content/"))return i;const s=this.signed[i],o=s?this.now()-s.at:1/0;return o{const e=[...this.queued];this.queued.clear(),this.sign(t,e)},30))}sign(t,e){if(e.length&&t?.callWS)for(const i of function(t,e){const i=Math.max(1,Math.floor(e)),s=[];for(let e=0;e{if(this.disposed)return;const e=this.now(),s={...this.signed};let o=0;for(const n of i){const i=t?.urls?.[n];"string"==typeof i&&i?(s[n]={url:i,at:e},this.retry.delete(n),o++):this.backOff(n)}o&&(this.signed=s,this.onUpdate())}).catch(()=>{for(const t of i)this.backOff(t)}).finally(()=>{for(const t of i)this.inFlight.get(t)===e&&this.inFlight.delete(t)})}}backOff(t){const e=this.retry.get(t)?.delay||0,i=Math.min(6e4,e?2*e:2e3);this.retry.set(t,{notBefore:this.now()+i,delay:i})}resign(t,e){const i=this.now(),s={};for(const[t,o]of Object.entries(this.signed))e.has(t)&&i-o.at{if(null==t||""===t)return null;const e=Number(t);return Number.isFinite(e)?e:null},Il=t=>{const e=t,i=zl(Array.isArray(e)?e[0]:e?.x),s=zl(Array.isArray(e)?e[1]:e?.y);return null==i||null==s?null:[i,s]};function El(t){if(!Array.isArray(t))return null;const e=[];for(const i of t){const t=Il(i);if(!t)return null;e.push(t)}if(e.length>1){const t=e[0],i=e[e.length-1];t[0]===i[0]&&t[1]===i[1]&&e.pop()}if(e.length<3)return null;let i=0,s=0,o=0;for(let t=0;tt+e[0],0)/e.length,e.reduce((t,e)=>t+e[1],0)/e.length]:[s/(3*i),o/(3*i)]}function Nl(t){if(!Array.isArray(t))return null;const e=[];for(const i of t){const t=Il(i);if(!t)return null;e.push(t)}if(e.length>1){const t=e[0],i=e[e.length-1];t[0]===i[0]&&t[1]===i[1]&&e.pop()}const i=El(e);if(!i)return null;const s=e.map(t=>t[0]),o=e.map(t=>t[1]);return{centroid:i,bbox:[Math.min(...s),Math.min(...o),Math.max(...s),Math.max(...o)]}}function Fl(t){let e=t;if(e&&"object"==typeof e&&!Array.isArray(e)){const t=e;e=t.path??t.points??e}if(!Array.isArray(e)||!e.length)return[];let i=(e.some(t=>(t=>Array.isArray(t)?t.length>=2&&!Array.isArray(t[0])&&("object"!=typeof t[0]||null==t[0]):!!t&&"object"==typeof t&&("x"in t||"y"in t))(t))?[e]:e.filter(Array.isArray)).map(t=>t.map(Il).filter(t=>null!=t)).filter(t=>t.length>=2);i.length>64&&(i=i.slice(-64));if(i.reduce((t,e)=>t+e.length,0)<=4e3)return i.map(t=>t.slice());const s=4e3-2*i.length,o=i.map(t=>t.length-2),n=o.reduce((t,e)=>t+e,0),r=o.map(t=>s*t/n),a=r.map(Math.floor);let l=s-a.reduce((t,e)=>t+e,0);const c=r.map((t,e)=>({index:e,fraction:t-Math.floor(t)})).sort((t,e)=>e.fraction-t.fraction||t.index-e.index);for(let t=0;tfunction(t,e){if(e>=t.length)return t.slice();if(e<=2)return[t[0],t[t.length-1]];const i=[];for(let s=0;st.slice()),i=e[e.length-1];return i?(i.length>2?i.pop():e.pop(),e):[]}function Hl(t){if(!t)return null;const e=t.vacuum_position||t.robot_position||null,i=e&&null!=zl(e.x)&&null!=zl(e.y)?{x:zl(e.x),y:zl(e.y),a:zl(e.a??e.angle??e.theta)}:null,s=Fl(t.path?.path??t.path?.points??t.path),o=[],n=t.rooms,r=Array.isArray(n)?n.map((t,e)=>[String(t?.id??e),t]):n&&"object"==typeof n?Object.entries(n):[];for(const[t,e]of r){if(!e||"object"!=typeof e)continue;const i=String(e.name??e.label??"").trim(),s=[[zl(e.cx),zl(e.cy)],[zl(e.center?.x),zl(e.center?.y)],[zl(e.x),zl(e.y)]].find(([t,e])=>null!=t&&null!=e);let n=s?.[0]??null,r=s?.[1]??null;const a=Nl(e.outline),l=zl(e.x0),c=zl(e.y0),h=zl(e.x1),d=zl(e.y1),p=(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!=n&&null!=r||!a||([n,r]=a.centroid),null!=n&&null!=r||!p||(n=(p[0]+p[2])/2,r=(p[1]+p[3])/2),i&&null!=n&&null!=r){const e={id:t,name:i,cx:n,cy:r};p&&([e.x0,e.y0,e.x1,e.y1]=p),o.push(e)}}const a=function(t){return String(t.map_name??t.current_map??t.map_index??t.selected_map??"default")}(t);return i||o.length||s.length?{pos:i,path:s,rooms:o,mapId:a}:null}function ql(t,e,i){if(!t||!e)return null;const s=e.attributes||{},o=t.split(".")[0]||"",n=null!=i?.platform?String(i.platform):null,r=!!Il(s.vacuum_position??s.robot_position),a=!(!s.rooms||"object"!=typeof s.rooms),l=Fl(s.path?.path??s.path?.points??s.path).length>0,c=[s.map_name,s.current_map,s.map_index,s.selected_map].some(t=>null!=t),h="xiaomi_cloud_map_extractor"===n,d=a||l||c;let p=null;if(r?p="compatible":h?p="known_xcme_incomplete":d?p="partial":"camera"===o&&(p="camera"),!p)return null;const u=r?"camera"===o?300:200:h?100:d?50:0;return{entityId:t,name:String(s.friendly_name||t),platform:n,category:p,hasPosition:r,hasRooms:a,hasPath:l,hasMapId:c,score:u}}const Ul=t=>t.toLowerCase().replace(/[\s_\-.,]+/g,"");function Bl(t,e){const i=new Map(e.map(t=>[Ul(t.name),t])),s=[],o=[];for(const e of t){const t=i.get(Ul(e.name));t&&(s.push([[e.cx,e.cy],[t.cx,t.cy]]),o.push(e.name))}if(s.length<3)return null;const n=function(t){if(t.length<3)return null;let e=0,i=0,s=0,o=0,n=0,r=0,a=0,l=0,c=0,h=0,d=0,p=0;for(const[[u,_],[m,g]]of t){if(![u,_,m,g].every(Number.isFinite))return null;e+=u*u,i+=u*_,s+=u,o+=_*_,n+=_,r+=1,a+=u*m,l+=_*m,c+=m,h+=u*g,d+=_*g,p+=g}const u=[e,i,s,i,o,n,s,n,r],_=t=>{const[e,i,s,o,n,r,a,l,c]=u,h=e*(n*c-r*l)-i*(o*c-r*a)+s*(o*l-n*a);if(!Number.isFinite(h)||Math.abs(h)<1e-9)return null;const d=[(n*c-r*l)/h,(s*l-i*c)/h,(i*r-s*n)/h,(r*a-o*c)/h,(e*c-s*a)/h,(s*o-e*r)/h,(o*l-n*a)/h,(i*a-e*l)/h,(e*n-i*o)/h];return[d[0]*t[0]+d[1]*t[1]+d[2]*t[2],d[3]*t[0]+d[4]*t[1]+d[5]*t[2],d[6]*t[0]+d[7]*t[1]+d[8]*t[2]]},m=_([a,l,c]),g=_([h,d,p]);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}(s);return n?{matrix:n,matched:o,residual:Al(n,s)}:null}function jl(t,e,i){const s=t[t.length-1];if(s&&s[0]===e[0]&&s[1]===e[1])return t;if(t.push(e),t.length<=600)return t;let o=function(t,e){if(t.length<3)return t.slice();const i=new Uint8Array(t.length);i[0]=i[t.length-1]=1;const s=[[0,t.length-1]];for(;s.length;){const[o,n]=s.pop(),[r,a]=t[o],[l,c]=t[n],h=l-r,d=c-a,p=Math.hypot(h,d)||1e-9;let u=0,_=-1;for(let e=o+1;eu&&(u=i,_=e)}_>0&&u>e&&(i[_]=1,s.push([o,_],[_,n]))}const o=[];for(let e=0;e600&&(o=o.filter((t,e)=>e%2==0||e===o.length-1)),o}function Gl(t){return"cleaning"===t||"returning"===t||"on"===t}const Wl={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function Vl(t){const[e,i]=Wl[t.rot]||[1,0],s=t.mir?-1:1;return[t.s*e*s,-t.s*i,t.ox,t.s*i*s,t.s*e,t.oy]}function Kl(t){const e=t[0]*t[4]-t[1]*t[3];if(!Number.isFinite(e)||Math.abs(e)<1e-12)return null;const i=e<0,s=Math.sqrt(Math.abs(e));let o=180*Math.atan2(-t[1],t[4])/Math.PI;return o=(90*Math.round(o/90)%360+360)%360,{ox:t[2],oy:t[5],s:s,rot:o,mir:i}}function Yl(t,e,i,s){const[o,n]=Rl(Vl(e),i,s),r=Vl({...t,ox:0,oy:0}),[a,l]=Rl(r,i,s);return{...t,ox:o-a,oy:n-l}}function Jl(t){const e=t?.trail_mode;return"never"===e||"cleaning"===e||"always"===e?e:!1===t?.trail?"never":"cleaning"}const Zl=1e-5;function Xl(t){const e=t.map(()=>[]);for(let i=0;i=1-1e-9||p<=1e-9||p>=1-1e-9||(e[i].push(d),e[r].push(p))}}const i=[];for(let s=0;st-e),1];for(let t=1;t{const i=e[2]-e[0],s=e[3]-e[1],o=i*i+s*s;if(!(o>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])*s)/o));return Math.hypot(t[0]-(e[0]+n*i),t[1]-(e[1]+n*s))},ec=(t,e,i,s)=>{const o=s[2]-s[0],n=s[3]-s[1],r=e*n-i*o;if(Math.abs(r)<1e-12)return 1/0;const a=s[0]-t[0],l=s[1]-t[1],c=(a*n-l*o)/r;if(!(c>1e-9))return 1/0;const h=(a*i-l*e)/r;return h<-1e-9||h>1+1e-9?1/0:c};function ic(t,e,i,s=96){if(!(e>0&&Number.isFinite(t[0])&&Number.isFinite(t[1])))return[];const o=[];for(const s of i){if(!s||s.length<4)continue;if(![s[0],s[1],s[2],s[3]].every(Number.isFinite))continue;const i=tc(t,s);i>e||i<1e-7||o.push(s)}const n=[],r=Math.max(12,Math.round(s));for(let t=0;tt-e);const a=[];let l=Number.NEGATIVE_INFINITY;for(const i of n){if(i-l<1e-9)continue;l=i;const s=Math.cos(i),n=Math.sin(i);let r=e;for(const e of o){const i=ec(t,s,n,e);i=3?a:[]}class sc extends ct{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1}setConfig(t){this._config=t}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const t=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(t?.config?.spaces||[]).map(t=>({value:t.id,label:t.title||t.id}))}catch{this._spaces=[]}finally{this._spacesLoading=!1}}}get _lang(){return hn(this.hass,this._config?.language)}get _schema(){const t=this._spaces||[],e=this._lang;return[{name:"title",selector:{text:{}}},t.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:t}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:[{value:"",label:dn(e,"editor.lang_auto")},{value:"en",label:dn(e,"editor.lang_en")},{value:"ru",label:dn(e,"editor.lang_ru")}]}}},{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 W;this._loadSpaces();const t=this._lang,e={title:dn(t,"editor.title"),default_floor:dn(t,"editor.default_floor"),language:dn(t,"editor.language"),icon_size:dn(t,"editor.icon_size"),show_temperature:dn(t,"editor.show_temperature"),live_states:dn(t,"editor.live_states"),show_signal:dn(t,"editor.show_signal"),kiosk:dn(t,"editor.kiosk"),cycle:dn(t,"editor.cycle")};return B`e[t.name]||t.name} @value-changed=${this._valueChanged} - >`}_valueChanged(t){const e={...this._config,...t.detail.value},i=new Event("config-changed",{bubbles:!0,composed:!0});i.detail={config:e},this.dispatchEvent(i)}}function Ll(t){const e=_a(t.cfg),i={};for(const e of t.cfg.spaces||[])for(const t of e.rooms||[])t.area&&(i[t.area]=e.id);const s=t.cfg.settings?.exclude_integrations?new Set(t.cfg.settings.exclude_integrations):kt,o=xt(t.cfg.settings?.icon_rules?.length?t.cfg.settings.icon_rules:$t);return Do({hass:t.hass,registry:t.registry,areaToSpace:i,markers:t.cfg.markers||[],settings:t.cfg.settings||{},excluded:s,showAll:!!t.cfg.settings?.show_all,firstSpaceId:e[0]?.id||"",loc:e=>en(t.lang,e),iconRules:o})}function Hl(t){const e=_a(t.cfg).find(e=>e.id===t.spaceId);if(!e)return null;const i=Fi(t.cfg.spaces.find(e=>e.id===t.spaceId)),s=Hi(t.cfg.settings),o=t.iconSize??2.5,n=o>8?2.5:o,r=t.registry?Js(t.hass,t.registry):t.hass,a=(t.devices||Ll(t)).filter(e=>e.space===t.spaceId),l=a.filter(t=>!t.hidden),c=function(t,e,i){const s={},o=i/100*Ea(e)*1.3;for(const i of e.rooms){if(!i.area)continue;const e=t.filter(t=>t.area===i.area);if(!e.length)continue;const n=Oa(i),r=.1*Math.min(n.w,n.h),a=n.w-2*r,l=n.h-2*r,c=Math.max(1,Math.round(Math.sqrt(e.length*a/Math.max(l,1)))),h=a/c,d=l/Math.max(Math.ceil(e.length/c),1),p=e.map((t,e)=>({x:n.x+r+h*(e%c+.5),y:n.y+r+d*(Math.floor(e/c)+.5)}));hi(p,n,o,.5*r),e.forEach((t,e)=>s[t.id]=wa(p[e]))}return s}(a,e,n),h=[];for(const e of l){const i=t.layout[e.id];if(i&&i.s===t.spaceId){const t=i.x*la,e=i.y*la;h.push({minX:t,minY:e,maxX:t,maxY:e})}}const d=t.cfg.spaces.find(e=>e.id===t.spaceId)||{},p=Array.isArray(d.walls)?d.walls:[],u=Number(d.cell_cm)>0?Number(d.cell_cm):5,_=function(t,e,i){const s=[];for(const o of t.partitions||[]){const t=Qr(o.a,o.b,o.cm,e,i);t&&s.push(t)}for(const o of t.room_drafts||[])s.push(...ea(o,e,i));for(const o of t.wall_columns||[])s.push(ta(o,e,i));return s}(e,u,va);for(const t of _){const e=t.map(t=>t[0]),i=t.map(t=>t[1]);e.length&&h.push({minX:Math.min(...e),minY:Math.min(...i),maxX:Math.max(...e),maxY:Math.max(...i)})}const m=Aa(e,h),g=[m.x,m.y,m.w,m.h],f=new Map(e.rooms.map(t=>{const e=ds(i.fill,t);return[t,Ui(e,"lqi"===e&&t.area?Ro(r,a,t.area):null,"light"===e?fo(mo(r,a,t)):"none","temp"===e&&t.area?zo(r,a,t.area):null,i.tempMin,i.tempMax,s,Ni(i.customFill,t))]})),v=e.rooms.filter(t=>t.area||i.showBorders||"none"!==ds(i.fill,t)).map(t=>{let s="room "+(e.bg?"overlay":"yard"),o="";const n=ds(i.fill,t);if(i.showBorders||"none"!==n){s+=" styled";const e=[`--room-stroke:${i.color}`,`--room-stroke-op:${i.showBorders?i.opacity:0}`],n=f.get(t)||null;n?(s+=" filled",e.push(`--room-fill:${n.color}`,`--room-fill-op:${n.opacity.toFixed(3)}`)):e.push("--room-fill:transparent","--room-fill-op:0"),o=e.join(";")}const r=t.id||W,a=t.area||W,l=t.poly?B``:B``;return l}),y=e.rooms.filter(t=>{const e=f.get(t);return ps(i.glow,t)&&(!e||e.opacity<=0)}).map(t=>t.poly?B``}_valueChanged(t){const e={...this._config,...t.detail.value},i=new Event("config-changed",{bubbles:!0,composed:!0});i.detail={config:e},this.dispatchEvent(i)}}function oc(t){const e=Ca(t.cfg),i={};for(const e of t.cfg.spaces||[])for(const t of e.rooms||[])t.area&&(i[t.area]=e.id);const s=t.cfg.settings?.exclude_integrations?new Set(t.cfg.settings.exclude_integrations):Et,o=Ft(t.cfg.settings?.icon_rules?.length?t.cfg.settings.icon_rules:Nt);return Fo({hass:t.hass,registry:t.registry,areaToSpace:i,markers:t.cfg.markers||[],settings:t.cfg.settings||{},excluded:s,showAll:!!t.cfg.settings?.show_all,firstSpaceId:e[0]?.id||"",loc:e=>dn(t.lang,e),iconRules:o})}function nc(t){const e=Ca(t.cfg).find(e=>e.id===t.spaceId);if(!e)return null;const i=Yi(t.cfg.spaces.find(e=>e.id===t.spaceId)),s=Xi(t.cfg.settings),o=t.iconSize??2.5,n=o>8?2.5:o,r=t.registry?no(t.hass,t.registry):t.hass,a=(t.devices||oc(t)).filter(e=>e.space===t.spaceId),l=a.filter(t=>!t.hidden),c=function(t,e,i){const s={},o=i/100*Ka(e)*1.3;for(const i of e.rooms){if(!i.area)continue;const e=t.filter(t=>t.area===i.area);if(!e.length)continue;const n=Za(i),r=.1*Math.min(n.w,n.h),a=n.w-2*r,l=n.h-2*r,c=Math.max(1,Math.round(Math.sqrt(e.length*a/Math.max(l,1)))),h=a/c,d=l/Math.max(Math.ceil(e.length/c),1),p=e.map((t,e)=>({x:n.x+r+h*(e%c+.5),y:n.y+r+d*(Math.floor(e/c)+.5)}));ki(p,n,o,.5*r),e.forEach((t,e)=>s[t.id]=Ia(p[e]))}return s}(a,e,n),h=[];for(const e of l){const i=t.layout[e.id];if(i&&i.s===t.spaceId){const t=i.x*wa,e=i.y*wa;h.push({minX:t,minY:e,maxX:t,maxY:e})}}const d=t.cfg.spaces.find(e=>e.id===t.spaceId)||{},p=Array.isArray(d.walls)?d.walls:[],u=Number(d.cell_cm)>0?Number(d.cell_cm):5,_=function(t,e,i){const s=[];for(const o of t.partitions||[]){const t=ca(o.a,o.b,o.cm,e,i);t&&s.push(t)}for(const o of t.room_drafts||[])s.push(...da(o,e,i));for(const o of t.wall_columns||[])s.push(ha(o,e,i));return s}(e,u,Ra);for(const t of _){const e=t.map(t=>t[0]),i=t.map(t=>t[1]);e.length&&h.push({minX:Math.min(...e),minY:Math.min(...i),maxX:Math.max(...e),maxY:Math.max(...i)})}const m=Wa(e,h),g=[m.x,m.y,m.w,m.h],f=new Map(e.rooms.map(t=>{const e=bs(i.fill,t);return[t,ts(e,"lqi"===e&&t.area?Ho(r,a,t.area):null,"light"===e?Mo(xo(r,a,t)):"none","temp"===e&&t.area?qo(r,a,t.area):null,i.tempMin,i.tempMax,s,Ki(i.customFill,t))]})),v=e.rooms.filter(t=>t.area||i.showBorders||"none"!==bs(i.fill,t)).map(t=>{let s="room "+(e.bg?"overlay":"yard"),o="";const n=bs(i.fill,t);if(i.showBorders||"none"!==n){s+=" styled";const e=[`--room-stroke:${i.color}`,`--room-stroke-op:${i.showBorders?i.opacity:0}`],n=f.get(t)||null;n?(s+=" filled",e.push(`--room-fill:${n.color}`,`--room-fill-op:${n.opacity.toFixed(3)}`)):e.push("--room-fill:transparent","--room-fill-op:0"),o=e.join(";")}const r=t.id||W,a=t.area||W,l=t.poly?j``:j``;return l}),y=e.rooms.filter(t=>{const e=f.get(t);return ws(i.glow,t)&&(!e||e.opacity<=0)}).map(t=>t.poly?j``:B``),b=e.bg||i.showNames?[]:e.rooms.map(t=>{const e=Xa(t);return j`${t.name}`}),w=l.map(s=>{const o=function(t,e,i,s,o){const n=e[t.id];return n&&n.s===t.space?{x:n.x*la,y:n.y*la}:s[t.id]?s[t.id]:wa(Ia(o))}(s,t.layout,t.cfg,c,e),n=(o.x-g[0])/g[2]*100,a=(o.y-g[1])/g[3]*100,l=Uo(r,s,{liveStates:!1!==t.liveStates,showTemperature:!1!==t.showTemperature,showSignal:i.showLqi??!1!==t.showSignal,activityRuntime:t.activityRuntime?.get(s.id),sourceDetails:!1}),h=[`left:${n}%`,`top:${a}%`,...bt(l)];return j`
${t.name}`}),w=l.map(s=>{const o=function(t,e,i,s,o){const n=e[t.id];return n&&n.s===t.space?{x:n.x*wa,y:n.y*wa}:s[t.id]?s[t.id]:Ia(Va(o))}(s,t.layout,t.cfg,c,e),n=(o.x-g[0])/g[2]*100,a=(o.y-g[1])/g[3]*100,l=Zo(r,s,{liveStates:!1!==t.liveStates,showTemperature:!1!==t.showTemperature,showSignal:i.showLqi??!1!==t.showSignal,activityRuntime:t.activityRuntime?.get(s.id),sourceDetails:!1}),h=[`left:${n}%`,`top:${a}%`,...zt(l)];return B`
- ${wt(l,{})} -
`}),k=i.showNames?e.rooms.filter(t=>t.name).map(s=>{const o=function(t,e,i){const s=i["rl_"+(t.id||"")];if(s&&s.s===e)return{x:s.x*la,y:s.y*la};const o=La(t);return wa({x:o[0],y:o[1]})}(s,e.id,t.layout,t.cfg),n=(o.x-g[0])/g[2]*100,r=(o.y-g[1])/g[3]*100,a=Math.min(1,i.opacity+.25);return j`
`}),k=i.showNames?e.rooms.filter(t=>t.name).map(s=>{const o=function(t,e,i){const s=i["rl_"+(t.id||"")];if(s&&s.s===e)return{x:s.x*wa,y:s.y*wa};const o=Xa(t);return Ia({x:o[0],y:o[1]})}(s,e.id,t.layout,t.cfg),n=(o.x-g[0])/g[2]*100,r=(o.y-g[1])/g[3]*100,a=Math.min(1,i.opacity+.25);return B`
${s.name}
`}):[],$=e.bg?t.displayUrl?t.displayUrl(e.bg.href):e.bg.href:"",x=t.cfg.spaces.find(e=>e.id===t.spaceId)?.settings||{};let S="";if("daynight"===Fn(t.cfg?.settings,x)&&null!==Nn(t.cfg?.settings,x)){const e=Ln(t.hass);e&&(S=Dn(e.elevation).bg)}const M=S||Oi(t.cfg?.settings,i),C=p.length?Lr(e.rooms,p,[],ya,u,va,la):Oe(e.rooms),D=(p.length||_.length)&&i.showBorders?Fr(e.rooms,p,[],[],ya,u,va,la,_):null,T=t.stageWidth&&g[2]?t.stageWidth/g[2]:1,P=!!D&&Qn(D.depthUnits,T),R=i.color||"#607d8b";return j` + style="left:${n}%;top:${r}%;color:${i.color};opacity:${a}">${s.name}
`}):[],$=e.bg?t.displayUrl?t.displayUrl(e.bg.href):e.bg.href:"",x=t.cfg.spaces.find(e=>e.id===t.spaceId)?.settings||{};let S="";if("daynight"===Wn(t.cfg?.settings,x)&&null!==Gn(t.cfg?.settings,x)){const e=Kn(t.hass);e&&(S=Fn(e.elevation).bg)}const M=S||Ji(t.cfg?.settings,i),C=p.length?Yr(e.rooms,p,[],Aa,u,Ra,wa):Ze(e.rooms),D=(p.length||_.length)&&i.showBorders?Vr(e.rooms,p,[],[],Aa,u,Ra,wa,_):null,T=t.stageWidth&&g[2]?t.stageWidth/g[2]:1,P=!!D&&lr(D.depthUnits,T),R=i.color||"#607d8b";return B`
- ${D?B` + ${D?j` `:W} - ${C.map(t=>"poly"in t?B``:B``)} - ${$?B`"poly"in t?j``:j``)} + ${$?j``:W} ${v} - ${y.length?B``:W} + ${y.length?j``:W} ${b} - ${D?B` + ${D?j` @@ -3372,23 +3440,23 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 `:W} ${""} -
${w}${k}
+
${w}${k}
- `}Ol.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",Ol);let ql=null,Ul=null,jl=!1;const Bl=new Set;function Gl(){if(ql)return ql;try{const t=JSON.parse(localStorage.getItem("houseplan_card_cfg_v1")||"null");if(t&&t.config&&Array.isArray(t.config.spaces))return{config:t.config,rev:t.rev||0,layout:t.layout||{}}}catch{}return null}function Wl(t){return ql?Promise.resolve(ql):Ul||(Ul=async function(t){const[e,i]=await Promise.all([t.callWS({type:"houseplan/config/get"}),t.callWS({type:"houseplan/layout/get"})]);if(ql={config:e?.config??null,rev:e?.rev??0,layout:i?.layout??{}},!jl&&t.connection?.subscribeEvents){jl=!0;const e=()=>{ql=null,Bl.forEach(t=>t())};try{await t.connection.subscribeEvents(e,"houseplan_config_updated"),await t.connection.subscribeEvents(e,"houseplan_layout_updated")}catch{jl=!1}}return ql}(t).finally(()=>{Ul=null}),Ul)}class Vl extends lt{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1}setConfig(t){this._config=t}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const t=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(t?.config?.spaces||[]).map(t=>({value:t.id,label:t.title||t.id}))}catch{this._spaces=[]}finally{this._spacesLoading=!1}}}get _lang(){return tn(this.hass,this._config?.language)}get _schema(){const t=this._spaces||[];return[t.length?{name:"space",selector:{select:{mode:"dropdown",options:t}}}:{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 W;this._loadSpaces();const t=this._lang,e={space:en(t,"editor.space"),title:en(t,"editor.title"),show_button:en(t,"editor.show_button"),button_label:en(t,"editor.button_label"),button_target:en(t,"editor.button_target"),icon_size:en(t,"editor.icon_size"),show_temperature:en(t,"editor.show_temperature"),live_states:en(t,"editor.live_states"),show_signal:en(t,"editor.show_signal")};return j`{rc=null,cc.forEach(t=>t())};try{await t.connection.subscribeEvents(e,"houseplan_config_updated"),await t.connection.subscribeEvents(e,"houseplan_layout_updated")}catch{lc=!1}}return rc}(t).finally(()=>{ac=null}),ac)}class pc extends ct{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1}setConfig(t){this._config=t}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const t=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(t?.config?.spaces||[]).map(t=>({value:t.id,label:t.title||t.id}))}catch{this._spaces=[]}finally{this._spacesLoading=!1}}}get _lang(){return hn(this.hass,this._config?.language)}get _schema(){const t=this._spaces||[];return[t.length?{name:"space",selector:{select:{mode:"dropdown",options:t}}}:{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 W;this._loadSpaces();const t=this._lang,e={space:dn(t,"editor.space"),title:dn(t,"editor.title"),show_button:dn(t,"editor.show_button"),button_label:dn(t,"editor.button_label"),button_target:dn(t,"editor.button_target"),icon_size:dn(t,"editor.icon_size"),show_temperature:dn(t,"editor.show_temperature"),live_states:dn(t,"editor.live_states"),show_signal:dn(t,"editor.show_signal")};return B`e[t.name]||t.name} @value-changed=${this._valueChanged} - >`}_valueChanged(t){const e={...this._config||{},...t.detail.value};delete e.aspect_ratio;const i=new Event("config-changed",{bubbles:!0,composed:!0});i.detail={config:e},this.dispatchEvent(i)}}Vl.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-space-card-editor")||customElements.define("houseplan-space-card-editor",Vl);const Kl=t=>{history.pushState(null,"",t),((t,e,i)=>{const s=new Event(e,{bubbles:!0,composed:!0});s.detail=i??{},t.dispatchEvent(s)})(window,"location-changed",{replace:!1})};class Yl extends lt{constructor(){super(...arguments),this._snap=null,this._loading=!1,this._stageWidth=0,this._haRegistryConnection=null,this._haRegistryRevision=-1,this._devices=[],this._activityRuntime=new Map,this._onHaRegistryUpdate=()=>{const t=Ws(this.hass).revision;t!==this._haRegistryRevision&&(this._haRegistryRevision=t,this.requestUpdate())},this._loadedOnce=!1,this._signer=new fl(()=>this.requestUpdate()),this._goToSpace=()=>{const t=(this._config?.button_target||"/plan-doma").replace(/#.*$/,"");Kl(`${t}#space=${encodeURIComponent(this._config.space)}`)}}_ensureHaRegistryAuthority(){const t=this.hass?.connection||null;t&&t!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=t,this._haRegistryRevision=-1,this._haRegistryRelease=Gs(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}static getConfigElement(){return document.createElement("houseplan-space-card-editor")}static getStubConfig(t){const e=Gl();return{type:"custom:houseplan-space-card",space:_a(e?.config||null)[0]?.id||"",show_button:!0,live_states:!0,show_temperature:!0,show_signal:!0}}setConfig(t){if(!t||!t.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,...t},this._snap=this._snap||Gl()}connectedCallback(){var t;super.connectedCallback(),this.hass&&this._ensureHaRegistryAuthority(),this._unsub=(t=()=>{this._loading=!1,this._snap=null,this.requestUpdate()},Bl.add(t),()=>Bl.delete(t)),this._signer.start(()=>this.hass,()=>this._referenced())}disconnectedCallback(){this._unsub?.(),this._unsub=void 0,this._stageObserver?.disconnect(),this._stageObserver=void 0,this._observedStage=void 0,this._signer.dispose(),this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null;for(const t of this._activityRuntime.values())window.clearTimeout(t.timer);this._activityRuntime.clear(),super.disconnectedCallback()}willUpdate(t){t.has("hass")&&this.hass&&this._ensureHaRegistryAuthority(),!this.hass||this._loading||this._snap&&!t.has("hass")||this._snap&&this._loadedOnce||this._load(),this._refreshDevices()}_stampActivity(t,e){t.flashTs&&Date.now()-t.flashTs<3300&&"event"===t.flashKind&&"transition"===e||(t.flashTs=Date.now(),t.flashKind=e,t.gen++,window.clearTimeout(t.timer),t.timer=window.setTimeout(()=>this.requestUpdate(),3360))}_syncActivity(t,e){if(!1===this._config?.live_states){for(const t of this._activityRuntime.values())window.clearTimeout(t.timer);return void this._activityRuntime.clear()}const i=new Set;for(const s of t){if(s.hidden)continue;if("static_icon"===ui(s.marker?.display))continue;i.add(s.id);const t=Fo(e,s),o=t.samples,n=Ho(e,s,!1!==this._config?.show_temperature,t);let r=this._activityRuntime.get(s.id);if(!r||r.sources!==n){r&&window.clearTimeout(r.timer),r={sources:n,last:Object.fromEntries(o.map(t=>[t.eid,t.state])),flashTs:0,flashKind:null,timer:0,gen:0},this._activityRuntime.set(s.id,r);continue}"transition"===r.flashKind&&o.some(t=>"transition"===t.activity)&&(window.clearTimeout(r.timer),r.flashTs=0,r.flashKind=null);let a=null;for(const t of o){const e=Is(r.last[t.eid],t);("event"===e||!a&&e)&&(a=e),r.last[t.eid]=t.state}a&&this._stampActivity(r,a)}for(const[t,e]of this._activityRuntime)i.has(t)||(window.clearTimeout(e.timer),this._activityRuntime.delete(t))}_refreshDevices(){if(!this.hass||!this._snap?.config||!this._config)return;const t=Ws(this.hass),e=Ll({hass:this.hass,registry:t,cfg:this._snap.config,lang:this._lang});this._syncActivity(e,Js(this.hass,t)),this._devices=e}updated(){const t=this.renderRoot.querySelector(".hp-static-stage")||void 0;if(t===this._observedStage)return;if(this._stageObserver?.disconnect(),this._observedStage=t,!t)return void(this._stageObserver=void 0);const e=()=>{const e=t.clientWidth;e>0&&Math.abs(e-this._stageWidth)>.5&&(this._stageWidth=e,this.requestUpdate())};this._stageObserver=new ResizeObserver(e),this._stageObserver.observe(t),e()}async _load(){if(this.hass&&!this._loading){this._loading=!0;try{const t=await Wl(this.hass);this._snap=t,this._loadedOnce=!0}catch{}finally{this._loading=!1,this.requestUpdate()}}}get _lang(){return tn(this.hass,this._config?.language)}getCardSize(){const t=_a(this._snap?.config||null).find(t=>t.id===this._config?.space);if(t){const e=t.vb[3]/t.vb[2];return Math.max(3,Math.round(8*e))+(!1===this._config?.show_button?0:1)}return 6}_errorCard(t){return j`
${t}
`}_referenced(){return cs(this._snap?.config)}render(){if(!this._config)return W;const t=this._snap?.config;if(!t)return j`
${en(this._lang,"space_card.loading")}
`;const e=this._config.space,i=Hl({hass:this.hass,cfg:t,layout:this._snap?.layout||{},spaceId:e,iconSize:this._config.icon_size,stageWidth:this._stageWidth,lang:this._lang,displayUrl:t=>this._signer.display(this.hass,t),registry:Ws(this.hass),devices:this._devices,activityRuntime:this._activityRuntime,liveStates:!1!==this._config.live_states,showTemperature:!1!==this._config.show_temperature,showSignal:!1!==this._config.show_signal});if(!i)return this._errorCard(en(this._lang,"space_card.not_found",{id:e}));const s=_a(t).find(t=>t.id===e),o=void 0!==this._config.title?this._config.title:s?.title||"",n=!1!==this._config.show_button,r=this._config.button_label||en(this._lang,"space_card.button");return j` + >
`}_valueChanged(t){const e={...this._config||{},...t.detail.value};delete e.aspect_ratio;const i=new Event("config-changed",{bubbles:!0,composed:!0});i.detail={config:e},this.dispatchEvent(i)}}pc.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-space-card-editor")||customElements.define("houseplan-space-card-editor",pc);const uc=t=>{history.pushState(null,"",t),((t,e,i)=>{const s=new Event(e,{bubbles:!0,composed:!0});s.detail=i??{},t.dispatchEvent(s)})(window,"location-changed",{replace:!1})};class _c extends ct{constructor(){super(...arguments),this._snap=null,this._loading=!1,this._stageWidth=0,this._haRegistryConnection=null,this._haRegistryRevision=-1,this._devices=[],this._activityRuntime=new Map,this._onHaRegistryUpdate=()=>{const t=eo(this.hass).revision;t!==this._haRegistryRevision&&(this._haRegistryRevision=t,this.requestUpdate())},this._loadedOnce=!1,this._signer=new Pl(()=>this.requestUpdate()),this._goToSpace=()=>{const t=(this._config?.button_target||"/plan-doma").replace(/#.*$/,"");uc(`${t}#space=${encodeURIComponent(this._config.space)}`)}}_ensureHaRegistryAuthority(){const t=this.hass?.connection||null;t&&t!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=t,this._haRegistryRevision=-1,this._haRegistryRelease=to(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}static getConfigElement(){return document.createElement("houseplan-space-card-editor")}static getStubConfig(t){const e=hc();return{type:"custom:houseplan-space-card",space:Ca(e?.config||null)[0]?.id||"",show_button:!0,live_states:!0,show_temperature:!0,show_signal:!0}}setConfig(t){if(!t||!t.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,...t},this._snap=this._snap||hc()}connectedCallback(){var t;super.connectedCallback(),this.hass&&this._ensureHaRegistryAuthority(),this._unsub=(t=()=>{this._loading=!1,this._snap=null,this.requestUpdate()},cc.add(t),()=>cc.delete(t)),this._signer.start(()=>this.hass,()=>this._referenced())}disconnectedCallback(){this._unsub?.(),this._unsub=void 0,this._stageObserver?.disconnect(),this._stageObserver=void 0,this._observedStage=void 0,this._signer.dispose(),this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null;for(const t of this._activityRuntime.values())window.clearTimeout(t.timer);this._activityRuntime.clear(),super.disconnectedCallback()}willUpdate(t){t.has("hass")&&this.hass&&this._ensureHaRegistryAuthority(),!this.hass||this._loading||this._snap&&!t.has("hass")||this._snap&&this._loadedOnce||this._load(),this._refreshDevices()}_stampActivity(t,e){t.flashTs&&Date.now()-t.flashTs<3300&&"event"===t.flashKind&&"transition"===e||(t.flashTs=Date.now(),t.flashKind=e,t.gen++,window.clearTimeout(t.timer),t.timer=window.setTimeout(()=>this.requestUpdate(),3360))}_syncActivity(t,e){if(!1===this._config?.live_states){for(const t of this._activityRuntime.values())window.clearTimeout(t.timer);return void this._activityRuntime.clear()}const i=new Set;for(const s of t){if(s.hidden)continue;if("static_icon"===Si(s.marker?.display))continue;i.add(s.id);const t=Wo(e,s),o=t.samples,n=Yo(e,s,!1!==this._config?.show_temperature,t);let r=this._activityRuntime.get(s.id);if(!r||r.sources!==n){r&&window.clearTimeout(r.timer),r={sources:n,last:Object.fromEntries(o.map(t=>[t.eid,t.state])),flashTs:0,flashKind:null,timer:0,gen:0},this._activityRuntime.set(s.id,r);continue}"transition"===r.flashKind&&o.some(t=>"transition"===t.activity)&&(window.clearTimeout(r.timer),r.flashTs=0,r.flashKind=null);let a=null;for(const t of o){const e=Bs(r.last[t.eid],t);("event"===e||!a&&e)&&(a=e),r.last[t.eid]=t.state}a&&this._stampActivity(r,a)}for(const[t,e]of this._activityRuntime)i.has(t)||(window.clearTimeout(e.timer),this._activityRuntime.delete(t))}_refreshDevices(){if(!this.hass||!this._snap?.config||!this._config)return;const t=eo(this.hass),e=oc({hass:this.hass,registry:t,cfg:this._snap.config,lang:this._lang});this._syncActivity(e,no(this.hass,t)),this._devices=e}updated(){const t=this.renderRoot.querySelector(".hp-static-stage")||void 0;if(t===this._observedStage)return;if(this._stageObserver?.disconnect(),this._observedStage=t,!t)return void(this._stageObserver=void 0);const e=()=>{const e=t.clientWidth;e>0&&Math.abs(e-this._stageWidth)>.5&&(this._stageWidth=e,this.requestUpdate())};this._stageObserver=new ResizeObserver(e),this._stageObserver.observe(t),e()}async _load(){if(this.hass&&!this._loading){this._loading=!0;try{const t=await dc(this.hass);this._snap=t,this._loadedOnce=!0}catch{}finally{this._loading=!1,this.requestUpdate()}}}get _lang(){return hn(this.hass,this._config?.language)}getCardSize(){const t=Ca(this._snap?.config||null).find(t=>t.id===this._config?.space);if(t){const e=t.vb[3]/t.vb[2];return Math.max(3,Math.round(8*e))+(!1===this._config?.show_button?0:1)}return 6}_errorCard(t){return B`
${t}
`}_referenced(){return vs(this._snap?.config)}render(){if(!this._config)return W;const t=this._snap?.config;if(!t)return B`
${dn(this._lang,"space_card.loading")}
`;const e=this._config.space,i=nc({hass:this.hass,cfg:t,layout:this._snap?.layout||{},spaceId:e,iconSize:this._config.icon_size,stageWidth:this._stageWidth,lang:this._lang,displayUrl:t=>this._signer.display(this.hass,t),registry:eo(this.hass),devices:this._devices,activityRuntime:this._activityRuntime,liveStates:!1!==this._config.live_states,showTemperature:!1!==this._config.show_temperature,showSignal:!1!==this._config.show_signal});if(!i)return this._errorCard(dn(this._lang,"space_card.not_found",{id:e}));const s=Ca(t).find(t=>t.id===e),o=void 0!==this._config.title?this._config.title:s?.title||"",n=!1!==this._config.show_button,r=this._config.button_label||dn(this._lang,"space_card.button");return B` - ${o?j`
${o}
`:W} + ${o?B`
${o}
`:W} ${i} - ${n?j`
+ ${n?B`
`:W} - `}}Yl.properties={hass:{attribute:!1},_config:{state:!0},_snap:{state:!0}},Yl.styles=[yt,n` + `}}_c.properties={hass:{attribute:!1},_config:{state:!0},_snap:{state:!0}},_c.styles=[At,n` .hp-static-title { font-weight: 700; padding: 10px 14px 6px; @@ -3463,7 +3531,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 text-align: center; color: var(--secondary-text-color, #9aa4ad); } - `],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",Yl),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-space-card"===t.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 Jl=n` + `],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",_c),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-space-card"===t.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 mc=n` :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); @@ -3634,16 +3702,16 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 .editor-secondary { transition: none; } .editor-group-launcher .group-chevron { transition: none; } } -`,Zl=(t,e)=>(t.composedPath?.()||[t.target]).some(t=>(t=>!!t&&"function"==typeof t.matches)(t)&&e(t));class Xl{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),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(),i=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===e&&null!==t.offsetParent);(i||t.querySelector(".editbar-tools"))?.focus?.()})}renderGroupLauncher(t,e,i){const s=this._openGroupId===t.id,o=t.items.find(e=>e.id===t.activeItemId&&!e.disabled);return j``}renderGroupModel(t,e,i){const s=t.items.find(t=>!t.disabled)?.id,o=t.items.some(e=>e.id===t.activeItemId&&!e.disabled)?t.activeItemId:void 0;return{contextId:e,kind:"group",ariaLabel:i.openGroup(t.label),visibleLabel:t.label,content:j`
`}renderGroupModel(t,e,i){const s=t.items.find(t=>!t.disabled)?.id,o=t.items.some(e=>e.id===t.activeItemId&&!e.disabled)?t.activeItemId:void 0;return{contextId:e,kind:"group",ariaLabel:i.openGroup(t.label),visibleLabel:t.label,content:B`
this._groupKeydown(t)}> - ${t.items.map(e=>j` -
`}_renderHomeArrow(){if(this._booting)return W;const t=this._view;if(!t||!t.w||!t.h)return W;const e=this._frameOf().rect;if(!(e.x+e.w<=t.x||e.x>=t.x+t.w||e.y+e.h<=t.y||e.y>=t.y+t.h))return W;const i=Math.atan2(e.y+e.h/2-(t.y+t.h/2),e.x+e.w/2-(t.x+t.w/2)),s=50+38*Math.cos(i),o=50+38*Math.sin(i);return j``}_stageAspect(){const t=this._stageEl,e=this._baseVb();return t&&t.clientHeight?t.clientWidth/t.clientHeight:e[2]/e[3]}_viewOr(t){return this._view&&this._view.w?this._view:ci(t,this._stageAspect())}_screenToVb(t,e){const i=this._stageEl,s=this._viewOr(this._baseVb()),o=i?.clientWidth||1,n=i?.clientHeight||1;return[s.x+t/o*s.w,s.y+e/n*s.h]}_clampView(t,e){const i=(t,e,i,s)=>{const o=1*Math.max(e,s),n=i-o,r=i+s-e+o;return Math.max(Math.min(n,r),Math.min(Math.max(n,r),t))};return{w:t.w,h:t.h,x:i(t.x,t.w,e.x,e.w),y:i(t.y,t.h,e.y,e.h)}}_applyView(t,e,i){const s=this._baseVb(),o=ci(s,this._stageAspect()),n=Math.min(jc.ZOOM_MAX,Math.max(jc.ZOOM_MIN,t)),r=o.w/n,a=o.h/n,l=this._viewOr(s),c=e??l.x+l.w/2,h=i??l.y+l.h/2;this._zoom=n,this._view=this._clampView({x:c-r/2,y:h-a/2,w:r,h:a},o)}_bootWatch(){clearTimeout(this._bootTimer),this._bootStart=Date.now(),this._bootLastH=-1,this._bootLastChange=this._bootStart;const t=()=>{if(!this._booting)return;const e=Date.now(),i=this._stageEl?this._stageEl.clientHeight:0;i!==this._bootLastH&&(this._bootLastH=i,this._bootLastChange=e);const s=e-this._bootStart;s>=1200||s>=700&&i>0&&e-this._bootLastChange>=250?this._bootSettled():this._bootTimer=window.setTimeout(t,100)};this._bootTimer=window.setTimeout(t,100)}_bootSettled(){if(!this._booting)return;this._refitView(),this._booting=!1;const t=this._stageEl?.clientHeight??0;!this._config?.kiosk&&t>0&&this._warmPatch({hdrH:this._hdrH,stageH:t,vp:this._warmViewportState()},!0),this._bootFading=!0,this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220),this._bootSoft=!0,clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},yc)}_bootSoftCancel(){this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoft=!1)}_beginResumeSettle(){this._kiosk||"view"!==this._mode||this._booting||this._resumeSettling||(this._resumeSettling=!0,this._resumeStarted=performance.now(),this._resumeLastSize="",this._resumeLastChange=this._resumeStarted,this._viewportInvalidAt=0,this.requestUpdate(),this._resumeRaf&&cancelAnimationFrame(this._resumeRaf),this._resumeRaf=requestAnimationFrame(()=>this._resumeSettleTick()))}_resumeSettleTick(){if(this._resumeRaf=0,!this._resumeSettling||!this.isConnected)return;if(this._kiosk||"view"!==this._mode)return this._resumeSettling=!1,void this.requestUpdate();const t=performance.now(),e=this._stageEl,i=!!e&&e.clientWidth>0&&e.clientHeight>0;if(i){const i=`${e.clientWidth}x${e.clientHeight}`;i!==this._resumeLastSize&&(this._resumeLastSize=i,this._resumeLastChange=t)}const s=t-this._resumeStarted;if(i&&s>=220&&t-this._resumeLastChange>=80||s>=750){const t=this._view;return this._resumeSettling=!1,i&&this._applyView(this._zoom,t?t.x+t.w/2:void 0,t?t.y+t.h/2:void 0),void this.requestUpdate()}this._resumeRaf=requestAnimationFrame(()=>this._resumeSettleTick())}_refitView(){const t=this._stageEl;if(!t||"visible"!==document.visibilityState||t.clientWidth<=0||t.clientHeight<=0)return void(this._viewportInvalidAt||(this._viewportInvalidAt=Date.now()));if(this._viewportInvalidAt){const t=Date.now()-this._viewportInvalidAt;if(this._viewportInvalidAt=0,t>=bc&&!this._resumeSettling&&(this._beginResumeSettle(),this._resumeSettling))return}if(this._resumeSettling)return;const e=this._view;this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}_zoomAt(t,e,i){const s=this._stageEl;if(!s)return;const o=ci(this._baseVb(),this._stageAspect()),n=Math.min(jc.ZOOM_MAX,Math.max(jc.ZOOM_MIN,i)),r=s.clientWidth,a=s.clientHeight,l=this._screenToVb(t,e),c=o.w/n,h=o.h/n;this._zoom=n,this._view=this._clampView({x:l[0]-t/r*c,y:l[1]-e/a*h,w:c,h:h},o)}_onWheel(t){const e=this._stageEl;if(!e)return;t.preventDefault();const i=e.getBoundingClientRect(),s=t.deltaY<0?1.15:1/1.15;this._zoomAt(t.clientX-i.left,t.clientY-i.top,this._zoom*s),this._saveZoom()}_stepZoom(t){const e=this._stageEl;e&&(this._zoomAt(e.clientWidth/2,e.clientHeight/2,this._zoom*(t>0?1.4:1/1.4)),this._saveZoom())}_resetZoom(){const t=this._baseVb();this._zoom=1,this._view=ci(t,this._stageAspect()),this._saveZoom()}_saveZoom(){if("view"===this._mode){this._zoomBySpace={...this._zoomBySpace,[this._space]:this._zoom};try{localStorage.setItem(Ac,JSON.stringify(this._zoomBySpace))}catch{}}}_restoreZoom(){const t=this._zoomBySpace[this._space]||1;this._zoom=t;const e=this._stageEl;if(e&&e.clientHeight){const e=this._baseVb();return this._applyView(t,e[0]+e[2]/2,e[1]+e[3]/2),void this.requestUpdate()}this._view=null,requestAnimationFrame(()=>{if(!this._stageEl)return;const e=this._baseVb();this._applyView(t,e[0]+e[2]/2,e[1]+e[3]/2),this.requestUpdate()})}_stagePointerDown(t){if(this._vacFit)return;if(this._kiosk&&(this._cyclePausedUntil=Date.now()+6e4,0===this._pointers.size?(this._swipeStart={x:t.clientX,y:t.clientY,id:t.pointerId},t.target.closest?.(".dev, .roomlabel, .oplock")||(clearTimeout(this._kioskHoldTimer),this._kioskHoldTimer=window.setTimeout(()=>{this._kioskDialog=!0,this._swipeStart=null},3e3))):(this._swipeStart=null,clearTimeout(this._kioskHoldTimer))),this._drag)return;if(this._markup&&t.target.closest?.(".roomlabel, .rlhandle, .rszhandle, .dev, .oplock, .op-hit, button"))return;if("devices"===this._mode&&t.target.closest(".dev"))return;if("decor"===this._mode&&this._decorPointerDown(t))return;this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY});const e=this._viewOr(this._baseVb());if(1===this._pointers.size)this._panStart={sx:t.clientX,sy:t.clientY,vx:e.x,vy:e.y},this._panLock=null,this._suppressClick=!1;else if(2===this._pointers.size){this._cancelBoundaryAnchor();const t=[...this._pointers.values()],e=Math.hypot(t[0].x-t[1].x,t[0].y-t[1].y);this._pinchStart={dist:e,zoom:this._zoom},this._panStart=null,this._panLock=null}}get _swipeZone(){return this._kiosk&&this._zoom<=1.001&&this._model.length>1}_stagePointerMove(t){if(this._physicalRotate?.pid!==t.pointerId)if(this._physicalDrag?.pid!==t.pointerId)if(this._dtDrag?.pid!==t.pointerId)if(this._bdDrag?.pid!==t.pointerId){if(this._decorDraft?.pid===t.pointerId){const e=this._decorDraft;let i=this._decorSnap(this._svgPoint(t),t.pointerType);if(t.shiftKey&&("rect"===e.kind||"ellipse"===e.kind)){const t=i[0]-e.a[0],s=i[1]-e.a[1],o=Math.max(Math.abs(t),Math.abs(s));i=this._snap([e.a[0]+(t<0?-o:o),e.a[1]+(s<0?-o:o)])}return void(this._decorDraft={...e,b:i})}if(this._decorMove?.pid!==t.pointerId)if(this._pointers.has(t.pointerId)){if(this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY}),this._markup&&1===this._pointers.size&&this._markupMove(t),this._pinchStart&&this._pointers.size>=2){const t=[...this._pointers.values()],e=Math.hypot(t[0].x-t[1].x,t[0].y-t[1].y)/(this._pinchStart.dist||1),i=this._stageEl.getBoundingClientRect(),s=(t[0].x+t[1].x)/2-i.left,o=(t[0].y+t[1].y)/2-i.top;this._zoomAt(s,o,this._pinchStart.zoom*e),this._suppressClick=!0,this._saveZoom()}else if(this._panStart){const e=t.clientX-this._panStart.sx,i=t.clientY-this._panStart.sy;Math.abs(e)+Math.abs(i)>4&&(this._suppressClick=!0,clearTimeout(this._holdTimer)),null===this._panLock&&Math.abs(e)+Math.abs(i)>8&&(this._panLock=this._swipeZone&&Math.abs(e)>1.5*Math.abs(i)?"swipe":"pan");const s=this._stageEl;if("pan"===this._panLock&&s){const t=this._baseVb(),o=this._viewOr(t),n=ci(t,this._stageAspect());this._view=this._clampView({x:this._panStart.vx-e/(s.clientWidth||1)*o.w,y:this._panStart.vy-i/(s.clientHeight||1)*o.h,w:o.w,h:o.h},n)}}}else this._markupMove(t);else this._decorMoveUpdate(t)}else this._bdMove(t);else this._dtMove(t);else this._physicalMove(t);else this._physicalRotateMove(t)}_stagePointerUp(t){if(this._kiosk){clearTimeout(this._kioskHoldTimer);const e=this._swipeStart;if(this._swipeStart=null,e&&e.id===t.pointerId){const i=t.clientX-e.x,s=t.clientY-e.y;if(Math.abs(i)+Math.abs(s)<8){const t=Date.now();t-this._lastTap<350&&this._resetZoom(),this._lastTap=t}const o="pan"===this._panLock?null:function(t,e,i,s,o,n=60){if(i>1.001||s.length<2)return null;if(Math.abs(t)t.id),this._space);o&&(this._slideTo(o,i<0?"left":"right"),this._saveNav(),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._showKioskDots())}}if(this._physicalDrag?.pid!==t.pointerId)if(this._physicalRotate?.pid!==t.pointerId)if(this._dtDrag?.pid!==t.pointerId)if(this._bdDrag?.pid!==t.pointerId)if(this._decorDraft?.pid!==t.pointerId){if(this._decorMove?.pid===t.pointerId)return this._decorMove.moved&&(this._recordGeometry(this._t("history.decor_move"),this._decorMove.before),this._saveConfig()),void(this._decorMove=null);this._pointers.delete(t.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null,setTimeout(()=>this._suppressClick=!1,0))}else this._decorCommitDraft();else this._bdUp();else this._dtUp();else this._physicalRotateUp(t);else this._physicalUp(t)}_clickRoom(t){!this._suppressClick&&t.area&&Hc("/config/areas/area/"+t.area)}_pointerDown(t,e){if("plan"===this._mode)return;if("view"===this._mode){this._holdFired=!1,clearTimeout(this._holdTimer);const i=t.pointerId,s=t.currentTarget;return void(this._holdTimer=window.setTimeout(()=>{this._holdFired=!0,this._interruptViewGesture(i,s),this._infoCard=e},600))}if("ha_disabled"===e.bindingStatus?.kind)return;t.preventDefault();const i=this._pos(e);this._drag={id:e.id,sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},Uc(t),this._tip=null}_pointerMove(t,e){if(!this._drag||this._drag.id!==e.id)return;const i=this.renderRoot.querySelector(".stage");if(!i)return;const s=this._baseVb(),o=i.getBoundingClientRect(),n=this._viewOr(s),r=(t.clientX-this._drag.sx)/o.width*n.w,a=(t.clientY-this._drag.sy)/o.height*n.h;Math.abs(t.clientX-this._drag.sx)+Math.abs(t.clientY-this._drag.sy)>3&&(this._drag.moved=!0,clearTimeout(this._holdTimer));const l=ka(this._drag.ox+r),c=ka(this._drag.oy+a);this._savePos(e,l,c)}_pointerUp(t,e){if(clearTimeout(this._holdTimer),!this._drag||this._drag.id!==e.id)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&(this._selId=e.id,window.setTimeout(()=>this._drag=null,0))}_showToast(t){this._toast=t,clearTimeout(this._toastTimer),this._toastTimer=window.setTimeout(()=>{this._toast=""},3500)}get _noHover(){return jc._noHoverMq||jc._touchSeen}_notePointer(t){this._boundaryPointerType=t.pointerType||"mouse","touch"!==t.pointerType&&"pen"!==t.pointerType||(jc._touchSeen=!0,this._tip&&(this._tip=null))}_guardTouchGesture(t){if(this._editorSecondary.handleOutsideDismiss(t))return;if("click"===t.type){if(!this._suppressClick&&!this._touchSequenceMultitouch&&Date.now()>this._touchClickBlockUntil)return;return t.preventDefault(),void t.stopImmediatePropagation()}const e=t;if("touch"===e.pointerType)if(this._notePointer(e),"pointerdown"!==t.type){if("pointermove"===t.type){const t=this._touchContacts.get(e.pointerId);if(!t)return;const i={...t,x:e.clientX,y:e.clientY};if(this._touchContacts.set(e.pointerId,i),this._touchSequenceMultitouch&&"view"===this._mode&&!this._vacFit&&this._pinchStart&&[...this._touchContacts.values()].every(t=>t.inStage)){this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY});const t=[...this._touchContacts.values()];if(t.length>=2&&this._stageEl){const[e,i]=t,s=Math.hypot(e.x-i.x,e.y-i.y)/(this._pinchStart.dist||1),o=this._stageEl.getBoundingClientRect();this._zoomAt((e.x+i.x)/2-o.left,(e.y+i.y)/2-o.top,this._pinchStart.zoom*s),this._saveZoom()}}return}if("pointerup"===t.type||"pointercancel"===t.type){if(this._touchContacts.delete(e.pointerId),this._touchSequenceMultitouch){if(this._touchClickBlockUntil=Date.now()+500,this._pointers.delete(e.pointerId),!this._vacFit&&this._pointers.size>=2){const[t,e]=[...this._pointers.values()];this._pinchStart={dist:Math.hypot(t.x-e.x,t.y-e.y),zoom:this._zoom}}else this._pinchStart=null;0===this._pointers.size&&(this._panStart=null,this._panLock=null)}0===this._touchContacts.size&&(this._touchSequenceMultitouch=!1)}}else if(this._touchContacts.set(e.pointerId,{x:e.clientX,y:e.clientY,inStage:!!e.target?.closest?.(".stage")}),this._touchContacts.size>=2){this._touchSequenceMultitouch=!0,this._touchClickBlockUntil=Number.POSITIVE_INFINITY,clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),this._swipeStart=null;const t=[...this._touchContacts.values()];if("view"===this._mode&&!this._vacFit&&t.every(t=>t.inStage)){this._pointers=new Map([...this._touchContacts].map(([t,e])=>[t,{x:e.x,y:e.y}]));const[e,i]=t;this._pinchStart={dist:Math.hypot(e.x-i.x,e.y-i.y),zoom:this._zoom},this._panStart=null,this._panLock=null}else this._vacFit&&(this._pointers.clear(),this._pinchStart=null,this._panStart=null,this._panLock=null)}}_showTip(t,e,i,s,o){this._noHover||this._drag||(this._tip={x:t.clientX,y:t.clientY,title:e,meta:i,lqi:s,temp:o})}get _gridPitch(){return va}get _cellCm(){const t=Number(this._curSpaceCfg?.cell_cm);return Number.isFinite(t)&&t>0?t:5}_fmtLen(t,e){const i=function(t,e,i,s){return Math.hypot(e[0]-t[0],e[1]-t[1])/i*s}(t,e,this._gridPitch,this._cellCm);return Ee(i,"mi"===this.hass?.config?.unit_system?.length)}get _curSpaceCfg(){const t=this._rszPreview;return t&&t.space===this._space?t.sp:this._serverCfg?.spaces.find(t=>t.id===this._space)}get _renderCfg(){const t=this._rszPreview;return t&&this._serverCfg?{...this._serverCfg,spaces:this._serverCfg.spaces.map(e=>e.id===t.space?t.sp:e)}:this._serverCfg}get _spaceH(){return this._curSpaceCfg,Nc}get _segments(){const t=this._curSpaceCfg,e=this._spaceH;return Le(t?.rooms||[]).map(t=>[t[0]*Nc,t[1]*e,t[2]*Nc,t[3]*e])}_savedNav(){try{return JSON.parse(localStorage.getItem(Ic)||"null")}catch{return null}}_saveNav(){try{localStorage.setItem(Ic,JSON.stringify({space:this._space,mode:this._mode}))}catch{}}_setMode(t){if(this._kiosk&&"view"!==t)return;if(this._mode===t)return;if(this._bootSoftCancel(),("plan"===t||"decor"===t)&&!this._norm)return void this._showToast(this._t("toast.markup_needs_server"));const e=this._mode;this._editorSecondary.closeForNavigation();const i="view"!==e&&"view"!==t,s=i&&this.renderRoot.querySelector(".editorchrome-inner")?.getBoundingClientRect().height||0;i||this._cancelEditorSwapAnimations(),(this._decorMove||this._dtDrag||this._bdDrag)&&this._cancelDecorGesture();const o=!this._spaceModel().bg&&"view"===t!=("view"===this._mode);if("view"===this._mode&&"view"!==t){const t=this._view;this._viewModeSnap={space:this._space,zoom:this._zoom,cx:t?t.x+t.w/2:void 0,cy:t?t.y+t.h/2:void 0}}if("plan"===e&&this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._mode=t,this._editorChromeMode="view"===t?e:t,this._startNavMotion("view"===e?"enter":"view"===t?"exit":"swap"),i&&this._animateEditorSwap(s),o&&(this._zoom=1,this._view=null),"view"===t){const t=this._viewModeSnap;this._viewModeSnap=null,t&&t.space===this._space?(this._zoom=t.zoom,this._view=null,requestAnimationFrame(()=>{this._stageEl&&"view"===this._mode&&this._space===t.space&&(this._applyView(t.zoom,t.cx,t.cy),this._saveZoom(),this.requestUpdate())})):t&&this._restoreZoom()}this._path=[],this._cursorPt=null,this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._tool="draw",this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._selId=null,this._physicalSel=null,this._physicalDialog=null,this._physicalDrag=null,this._rszSel=null,this._rszDrag=null,this._rszLive=null,this._rszPreview=null,this._tip=null,this._hoverRoom=null,this._decorDraft=null,this._decorSel=null,this._decorMove=null,this._backdropDialog=null,this._decorTool="select",this._bdDrag=null,this._dtDrag=null,this._dtBox=null,"plan"===t&&(this._primeDrawWallField(),this._resumeLastDraft()),this._saveNav()}_primeDrawWallField(){null===this._drawWallField&&(this._drawWallField=er(Xn,this._imperial))}get _drawWallFieldValue(){return null===this._drawWallField?er(Xn,this._imperial):this._drawWallField}get _drawWallCm(){const t=wc(this._drawWallFieldValue);if(null==t||t<=0)return null;const e=this._imperial?2.54*t:t,i="column"===this._tool?Kr:100;return e>=1&&e<=i?e:null}get _drawWallMaxCm(){return"column"===this._tool?Kr:100}_showPhysicalRange(t=this._drawWallMaxCm){this._showToast(this._t("toast.physical_range",{max:er(t,this._imperial),unit:this._t(this._imperial?"wallthick.unit_in":"wallthick.unit_cm")}))}_draftSegmentCount(t=this._curSpaceCfg){return(t?.room_drafts||[]).reduce((t,e)=>t+(Array.isArray(e.segments)?e.segments.length:0),0)}_limitReached(t){const e=this._curSpaceCfg;if(!e)return!0;const i="draft"===t?(e.room_drafts||[]).length>=200:"partition"===t?(e.partitions||[]).length>=2e3:(e.wall_columns||[]).length>=500;return i&&this._showToast(this._t("toast.physical_limit")),i}_svgPoint(t){const e=this.renderRoot.querySelector(".stage").getBoundingClientRect();return this._screenToVb(t.clientX-e.left,t.clientY-e.top)}_snap(t){const e=this._gridPitch;return[ka(Ie(t[0],e)),ka(Ie(t[1],e))]}_snapDrawPoint(t,e=!1){const i=this._path[this._path.length-1],s=e&&i?function(t,e,i,s=1/0){if(!(i>0&&t?.every(Number.isFinite)&&e?.every(Number.isFinite)))return[e[0],e[1]];const o=e[0]-t[0],n=e[1]-t[1];if(Math.abs(o)+Math.abs(n)<=1e-12)return[t[0],t[1]];const r=Math.PI/4;let a=Math.atan2(n,o);a<0&&(a+=2*Math.PI);const l=Math.floor(a/r+.5)%8,[c,h]=[[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1],[0,-1],[1,-1]][l],d=c*c+h*h;let p=Math.max(0,Math.round((o*c+n*h)/(i*d)));if(Number.isFinite(s)&&s>=0){const e=(t,e)=>{if(!e)return 1/0;const o=e>0?s-t:t+s;return Math.max(0,Math.floor((o+1e-9*i)/i))};p=Math.min(p,e(t[0],c),e(t[1],h))}return[t[0]+c*p*i,t[1]+h*p*i]}(i,t,this._gridPitch,ga):t;return this._snap(s)}_samePt(t,e){return je(t,e)}_dropLegacySegments(){for(const t of this._serverCfg?.markers||[])"ripple"===t.display&&(t.display="icon_ripple");for(const t of this._serverCfg?.spaces||[]){delete t.segments;const e=new Set,i=t=>"string"==typeof t&&t.length>=1&&t.length<=64&&!e.has(t),s=t=>(e.add(t),!0),o=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(Number(t))&&Math.abs(Number(t))<=ma);if(Array.isArray(t.partitions)&&(t.partitions=t.partitions.filter(t=>t&&i(t.id)&&o(t.a)&&o(t.b)&&Math.hypot(t.a[0]-t.b[0],t.a[1]-t.b[1])>1e-9&&s(t.id)).map(t=>({...t,cm:Math.max(1,Math.min(100,Number(t.cm)||15))})),t.partitions.length||delete t.partitions),Array.isArray(t.wall_columns)&&(t.wall_columns=t.wall_columns.filter(t=>t&&i(t.id)&&o(t.center)&&s(t.id)).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[Number(t.center[0]),Number(t.center[1])],cm:Yr(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:Jr(t.angle)}})),t.wall_columns.length||delete t.wall_columns),Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t&&i(t.id)&&Array.isArray(t.points)&&t.points.length>=2&&t.points.every(o)&&s(t.id)).map(t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],i=[];for(let s=1;st.points.length>=2),t.room_drafts.length||delete t.room_drafts),Array.isArray(t.walls)){const e=il(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]);t.walls=_r(t.walls,t.rooms||[],ya,1,e),t.walls.length||delete t.walls}}}get _cfgWriting(){return this._writesPending>0}_writeConfig(){this._writesPending++,this._writeChain=this._writeChain.catch(()=>{}).then(async()=>{if(!this._serverCfg)return;this._dropLegacySegments();const t=await this.hass.callWS({type:"houseplan/config/set",config:this._serverCfg,expected_rev:this._cfgRev});this._cfgRev=t?.rev??this._cfgRev+1});return this._writeChain.finally(()=>{this._writesPending--})}_saveConfig(){this._cfgEpoch++,this._saveConfigDebounced()}_geometrySnapshot(t=this._space){const e=this._serverCfg?.spaces.find(e=>e.id===t);if(!e)return null;const i=t=>JSON.parse(JSON.stringify(t)),s={};for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==e[t]&&(s[t]=e[t]);return{spaceId:t,rooms:i(e.rooms||[]),...Array.isArray(e.openings)?{openings:i(e.openings)}:{},...Array.isArray(e.walls)?{walls:i(e.walls)}:{},...Array.isArray(e.open_spans)?{open_spans:i(e.open_spans)}:{},...Array.isArray(e.room_drafts)?{room_drafts:i(e.room_drafts)}:{},...Array.isArray(e.partitions)?{partitions:i(e.partitions)}:{},...Array.isArray(e.wall_columns)?{wall_columns:i(e.wall_columns)}:{},...Array.isArray(e.decor)?{decor:i(e.decor)}:{},plan_transform:s}}_recordGeometry(t,e){if(!e)return;const i=this._geometrySnapshot(e.spaceId);i&&JSON.stringify(e)!==JSON.stringify(i)&&(this._geometryHistory.push({name:t,before:e,after:i}),this.requestUpdate())}_clearGeometryGesture(){this._path=[],this._cursorPt=null,this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._wallDialog=null,this._physicalDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._openingDialog=null,this._rszSel=null,this._rszDrag=null,this._rszPreview=null,this._rszLive=null,this._decorDraft=null,this._decorMove=null,this._dtDrag=null,this._bdDrag=null}_cancelBoundaryAnchor(){return!("boundary"!==this._tool||!this._openWallAnchor)&&(this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._cursorPt=null,this.requestUpdate(),!0)}_stagePointerCancel(t){if(clearTimeout(this._kioskHoldTimer),this._swipeStart?.id===t.pointerId&&(this._swipeStart=null),this._physicalDrag?.pid!==t.pointerId&&this._physicalRotate?.pid!==t.pointerId)return this._decorDraft?.pid===t.pointerId?(this._decorDraft=null,void this.requestUpdate()):void(this._decorMove?.pid!==t.pointerId&&this._dtDrag?.pid!==t.pointerId&&this._bdDrag?.pid!==t.pointerId?(this._cancelBoundaryAnchor(),this._pointers.delete(t.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null)):this._cancelDecorGesture());this._cancelPhysicalGesture()}_applyGeometryState(t){const e=this._serverCfg?.spaces.find(e=>e.id===t.spaceId);if(!e)return!1;const i=t=>JSON.parse(JSON.stringify(t));e.rooms=i(t.rooms),void 0!==t.openings?e.openings=i(t.openings):delete e.openings,void 0!==t.walls?e.walls=i(t.walls):delete e.walls,void 0!==t.open_spans?e.open_spans=i(t.open_spans):delete e.open_spans,void 0!==t.room_drafts?e.room_drafts=i(t.room_drafts):delete e.room_drafts,void 0!==t.partitions?e.partitions=i(t.partitions):delete e.partitions,void 0!==t.wall_columns?e.wall_columns=i(t.wall_columns):delete e.wall_columns,void 0!==t.decor?e.decor=i(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];return Object.assign(e,i(t.plan_transform||{})),this._clearGeometryGesture(),this._space!==t.spaceId&&(this._space=t.spaceId,this._saveNav(),this._restoreZoom()),this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate(),!0}_roomAt(t){return this._spaceModel().rooms.find(e=>{const i=Fe(e);return!!i&&Ke(t,i)})}_overlapRoom(t){return this._spaceModel().rooms.find(e=>{const i=Fe(e);return!!i&&ei(t,i)})}_pointInRoom(t,e){return e.poly?Be(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(!mn(t))return!0;const e=t.length,i=.001;for(let s=0;st?.classList?.contains?.("roomlabel")||t?.classList?.contains?.("rlhandle")))return;if(e.some(t=>t?.classList?.contains?.("physical-hit")))return void("boundary"===this._tool&&this._showToast(this._t("toast.boundary_blocked")));const i=this._svgPoint(t);if("select"===this._tool)return void(this._physicalSel=null);if("resize"===this._tool){if(this._rszDrag||e.some(t=>t?.classList?.contains?.("rszhandle")))return;const t=[...this._spaceModel().rooms].reverse().find(t=>this._pointInRoom(i,t));return void(this._rszSel=t?.id||null)}if("delroom"===this._tool)return void this._deleteRoomClick(i);if("opening"===this._tool)return void this._openingClick(i);if("merge"===this._tool)return void this._mergeClick(i);if("wallthick"===this._tool)return void this._wallThickClick(i);if("boundary"===this._tool)return void this._boundaryClick(i);if("split"===this._tool)return void this._splitClick(i);if("partition"===this._tool)return void this._partitionClick(i,t.shiftKey);if("column"===this._tool)return void this._columnClick(i);const s=this._snapDrawPoint(i,t.shiftKey);if(t.ctrlKey||t.metaKey)return t.preventDefault(),void this._closeRoomContour(!0);const o=this._path.length>=3&&this._samePt(s,this._path[0]);if(!this._path.length){const t=this._draftEndAt(s);return t?(this._activeDraftId=t.draft.id,this._resumeDraftBySpace[this._space]=t.draft.id,this._path=t.reverse?[...t.draft.points].reverse().map(t=>[...t]):t.draft.points.map(t=>[...t]),void(this._draftSegmentCms=t.reverse?[...t.draft.segments].reverse().map(t=>t.cm):t.draft.segments.map(t=>t.cm))):(this._activeDraftId=null,this._draftSegmentCms=[],void(this._path=[s]))}const n=this._path[this._path.length-1];if(this._samePt(s,n))return;if(o)return void this._closeRoomContour();const r=this._draftEndAt(s,this._activeDraftId||void 0);if(r)return void this._mergeDraftEndpoint(r);if(null==this._drawWallCm)return void this._showPhysicalRange(100);if(this._path.length>=500)return void this._showToast(this._t("toast.physical_limit"));const a=this._curSpaceCfg;!this._activeDraftId&&(a?.room_drafts||[]).length>=200||this._draftSegmentCount(a)>=2e3?this._showToast(this._t("toast.physical_limit")):(this._path=[...this._path,s],this._persistActiveDraftSegment())}_draftEndAt(t,e){const i=this._viewOr(this._baseVb()),s=Math.max(.15*this._gridPitch,this._stageEl?.clientWidth?i.w/this._stageEl.clientWidth*12:0);for(const i of this._spaceModel().room_drafts||[]){if(i.id===e)continue;if(i.points.length<2)continue;const o=i.points[0],n=i.points[i.points.length-1];if(Math.hypot(t[0]-n[0],t[1]-n[1])<=s)return{draft:i,reverse:!1};if(Math.hypot(t[0]-o[0],t[1]-o[1])<=s)return{draft:i,reverse:!0}}return null}_mergeDraftEndpoint(t){const e=this._curSpaceCfg;if(!e||!this._path.length)return;const i=Array.isArray(e.room_drafts)?e.room_drafts:[],s=this._activeDraftId?i.find(t=>t.id===this._activeDraftId):null,o=i.find(e=>e.id===t.draft.id);if(!o)return;const n=t.reverse?t.draft.points.map(t=>[...t]):[...t.draft.points].reverse().map(t=>[...t]),r=t.reverse?(o.segments||[]).map(t=>({...t})):[...o.segments||[]].reverse().map(t=>({...t})),a=this._path[this._path.length-1],l=this._samePt(a,n[0]),c=l?null:this._drawWallCm;if(!l&&null==c)return void this._showPhysicalRange(100);const h=this._draftSegmentCms.map((t,e)=>({...s?.segments?.[e]||{},cm:t})),d=[...this._path.map(t=>[...t]),...l?n.slice(1):n],p=[...h,...null==c?[]:[{cm:c}],...r],u=d.length>=4&&this._samePt(d[0],d[d.length-1]),_=u?d.slice(0,-1):d,m=u?p.slice(0,-1):p;if(_.length>500)return void this._showToast(this._t("toast.physical_limit"));const g=(s?.segments?.length||0)+(o.segments?.length||0);if(this._draftSegmentCount(e)-g+m.length>2e3)return void this._showToast(this._t("toast.physical_limit"));if(u){if(this._contourSelfIntersects(_)||si(_)<=1e-6)return void this._showToast(this._t("toast.contour_cannot_close"));const t=this._overlapRoom(_);if(t)return void this._showToast(this._t("toast.room_overlap",{name:t.name||""}))}const f=this._geometrySnapshot(),v=this._activeDraftId||t.draft.id,y={...s||o,id:v,points:_.map(t=>[t[0]/Nc,t[1]/Nc]),segments:m};e.room_drafts=i.filter(e=>e.id!==t.draft.id&&(!this._activeDraftId||e.id!==this._activeDraftId)),e.room_drafts.push(y),this._activeDraftId=v,this._resumeDraftBySpace[this._space]=v,this._draftSegmentCms=m.map(t=>Number(t.cm)),this._path=_,this._physicalSel=null,this._recordGeometry(this._t("history.draft_merge"),f),this._saveConfig(),u&&(this._closingWallCm=Number(p[p.length-1]?.cm)||Xn,this._path=[..._,[..._[0]]],this._cursorPt=null,this._nameSel="",this._areaSel="",this._resetRoomDialogFields(),this._roomDialog=!0)}_persistActiveDraftSegment(){if(this._path.length<2||!this._curSpaceCfg)return;const t=this._drawWallCm;if(null==t)return;this._draftSegmentCms=[...this._draftSegmentCms,t];const e=this._geometrySnapshot(),i=this._curSpaceCfg;i.room_drafts||=[],this._activeDraftId||(this._activeDraftId="draft-"+Date.now().toString(36)),this._resumeDraftBySpace[this._space]=this._activeDraftId;const s=i.room_drafts.findIndex(t=>t.id===this._activeDraftId),o={...s>=0?i.room_drafts[s]:{},id:this._activeDraftId,points:this._path.map(t=>[t[0]/Nc,t[1]/Nc]),segments:this._draftSegmentCms.map((t,e)=>({...s>=0?i.room_drafts[s]?.segments?.[e]:{},cm:t}))};s>=0?i.room_drafts[s]=o:i.room_drafts.push(o),this._recordGeometry(this._t("history.draft_segment"),e),this._saveConfig()}_partitionClick(t,e){const i=this._snapDrawPoint(t,e);if(!this._path.length)return void(this._path=[i]);const s=this._path[0];if(this._samePt(s,i))return;const o=this._drawWallCm;if(null==o)return void this._showPhysicalRange(100);if(!this._curSpaceCfg||this._limitReached("partition"))return;const n=this._geometrySnapshot(),r=this._curSpaceCfg;r.partitions||=[];const a="partition-"+Date.now().toString(36);r.partitions.push({id:a,a:[s[0]/Nc,s[1]/Nc],b:[i[0]/Nc,i[1]/Nc],cm:o}),this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._cursorPt=null,this._recordGeometry(this._t("history.partition_add"),n),this._saveConfig()}_columnClick(t){const e=this._snap(t),i=this._drawWallCm;if(null==i)return void this._showPhysicalRange(Kr);if(!this._curSpaceCfg||this._limitReached("column"))return;const s={id:"column-"+Date.now().toString(36),shape:"square",center:e,cm:Yr(i),angle:0},o=(this._spaceModel().wall_columns||[]).find(t=>aa(t,s,.02*this._gridPitch));if(o)return clearTimeout(this._duplicateColumnTimer),this._duplicateColumnId=o.id,this._duplicateColumnTimer=window.setTimeout(()=>{this._duplicateColumnId=null},900),void this._showToast(this._t("toast.column_duplicate"));const n=this._geometrySnapshot(),r=this._curSpaceCfg;r.wall_columns||=[],r.wall_columns.push({...s,center:[e[0]/Nc,e[1]/Nc]}),this._recordGeometry(this._t("history.column_add"),n),this._saveConfig()}_openPhysicalDialog(t,e,i){const s=this._spaceModel();if("partition"===t){const i=s.partitions.find(t=>t.id===e);i&&(this._physicalDialog={kind:t,id:e,cm:er(i.cm,this._imperial),length:this._fmtLen(i.a,i.b)})}else if("column"===t){const i=s.wall_columns.find(t=>t.id===e);i&&(this._physicalDialog={kind:t,id:e,cm:er(i.cm,this._imperial),shape:i.shape,angle:this._angleField("square"===i.shape?Jr(i.angle):0)})}else{const o=s.room_drafts.find(t=>t.id===e),n=Math.max(0,Math.min(o?.segments.length?o.segments.length-1:0,i||0));o?.segments[n]&&(this._physicalDialog={kind:t,id:e,segment:n,cm:er(o.segments[n].cm,this._imperial),length:this._fmtLen(o.points[n],o.points[n+1])})}}_physicalDown(t,e,i){t.stopPropagation(),Uc(t);const s=this._spaceModel(),o=this._svgPoint(t),n=[];for(const t of[...s.wall_columns].reverse())ra(o,ta(t,this._cellCm,this._gridPitch))&&n.push({kind:"column",id:t.id});for(const t of[...s.partitions].reverse()){const e=Qr(t.a,t.b,t.cm,this._cellCm,this._gridPitch);e&&ra(o,e)&&n.push({kind:"partition",id:t.id})}n.some(t=>t.kind===e&&t.id===i)||n.unshift({kind:e,id:i});const r=n.map(t=>`${t.kind}:${t.id}`).sort().join("|"),a=performance.now(),l=this._physicalPickCycle,c=n.length>1&&l?.signature===r&&a-l.at>380&&a-l.at<=1200&&Math.hypot(t.clientX-l.x,t.clientY-l.y)<=10?(l.index+1)%n.length:Math.max(0,n.findIndex(t=>t.kind===e&&t.id===i));this._physicalPickCycle={signature:r,index:c,x:t.clientX,y:t.clientY,at:a},e=n[c].kind,i=n[c].id;const h="partition"===e?s.partitions.find(t=>t.id===i):s.wall_columns.find(t=>t.id===i);h&&(this._physicalSel={kind:e,id:i},this._physicalDrag={pid:t.pointerId,kind:e,id:i,start:this._svgPoint(t),startClient:[t.clientX,t.clientY],before:this._geometrySnapshot(),moved:!1,base:JSON.parse(JSON.stringify(h)),delta:[0,0]})}_clampPhysicalDelta(t,e,i){const s="partition"===t?[e.a,e.b]:[e.center],o=s.map(t=>t[0]),n=s.map(t=>t[1]);return[Math.max(-ma*Nc-Math.min(...o),Math.min(ma*Nc-Math.max(...o),i[0])),Math.max(-ma*Nc-Math.min(...n),Math.min(ma*Nc-Math.max(...n),i[1]))]}_physicalMove(t){const e=this._physicalDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._svgPoint(t),s="partition"===e.kind?e.base.a:e.base.center,o=this._snap([s[0]+i[0]-e.start[0],s[1]+i[1]-e.start[1]]),n=this._clampPhysicalDelta(e.kind,e.base,[o[0]-s[0],o[1]-s[1]]);this._physicalDrag={...e,delta:n,moved:e.moved||Math.hypot(t.clientX-e.startClient[0],t.clientY-e.startClient[1])>=5}}_physicalUp(t){const e=this._physicalDrag;if(!e||e.pid!==t.pointerId)return;if(t.stopPropagation(),this._physicalDrag=null,!e.moved)return void this._registerPhysicalTap(e.kind,e.id);if(!this._curSpaceCfg)return;const i=this._curSpaceCfg;if("partition"===e.kind){const t=(i.partitions||[]).find(t=>t.id===e.id),s=e.base;t&&(t.a=[(s.a[0]+e.delta[0])/Nc,(s.a[1]+e.delta[1])/Nc],t.b=[(s.b[0]+e.delta[0])/Nc,(s.b[1]+e.delta[1])/Nc])}else{const t=(i.wall_columns||[]).find(t=>t.id===e.id),s=e.base,o={...s,center:[s.center[0]+e.delta[0],s.center[1]+e.delta[1]]};if(this._spaceModel().wall_columns.some(t=>t.id!==e.id&&aa(t,o,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"));t&&(t.center=[(s.center[0]+e.delta[0])/Nc,(s.center[1]+e.delta[1])/Nc])}this._recordGeometry(this._t("history.physical_move"),e.before),this._saveConfig()}_registerPhysicalTap(t,e,i){const s=performance.now(),o=this._physicalLastTap?.kind===t&&this._physicalLastTap.id===e&&this._physicalLastTap.segment===i&&s-this._physicalLastTap.at<=360;this._physicalLastTap={kind:t,id:e,segment:i,at:s},o&&(this._physicalLastTap=null,this._openPhysicalDialog(t,e,i))}_cancelPhysicalGesture(){this._physicalDrag=null,this._physicalRotate=null,this.requestUpdate()}_physicalRotateDown(t,e){if("square"!==e.shape)return;t.preventDefault(),t.stopPropagation(),Uc(t);const i=this._svgPoint(t);this._physicalSel={kind:"column",id:e.id},this._physicalRotate={pid:t.pointerId,id:e.id,center:[...e.center],startAngle:180*Math.atan2(i[1]-e.center[1],i[0]-e.center[0])/Math.PI,baseAngle:Jr(e.angle),angle:Jr(e.angle),before:this._geometrySnapshot(),moved:!1}}_physicalRotateMove(t){const e=this._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation();const i=this._svgPoint(t),s=180*Math.atan2(i[1]-e.center[1],i[0]-e.center[0])/Math.PI,o=e.baseAngle+s-e.startAngle,n=Jr(t.shiftKey?o:5*Math.round(o/5));this._physicalRotate={...e,angle:n,moved:e.moved||Math.abs(o-e.baseAngle)>=.5}}_physicalRotateUp(t){const e=this._physicalRotate;if(!e||e.pid!==t.pointerId)return;if(t.preventDefault(),t.stopPropagation(),this._physicalRotate=null,!e.moved||!this._curSpaceCfg)return;const i=this._spaceModel().wall_columns.find(t=>t.id===e.id);if(!i||"square"!==i.shape)return;const s={...i,angle:e.angle};if(this._spaceModel().wall_columns.some(t=>t.id!==e.id&&aa(t,s,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"));const o=this._curSpaceCfg.wall_columns?.find(t=>t.id===e.id);o&&(o.angle=e.angle,this._recordGeometry(this._t("history.physical_edit"),e.before),this._saveConfig())}_rszRooms(){const t=[];for(const e of this._spaceModel().rooms){const i=e.id?Fe(e):null;i&&t.push({id:e.id,poly:i})}return t}_rszOpenings(){return this._openingsR.map(t=>({id:t.id,x:t.rx,y:t.ry,length:t.rlen}))}_rszOpts(){return{minDim:this._cmToUnits(30),eps:.05*this._gridPitch}}_rszSnapshot(){return JSON.stringify(this._geometrySnapshot()||{spaceId:this._space,rooms:[],openings:[],walls:[],open_spans:[]})}_rszApplyPreview(t,e){const i=this._rszDrag,s=this._serverCfg?.spaces.find(t=>t.id===this._space);if(!i||!s)return;const o=JSON.parse(i.snap),n={...s,rooms:o.rooms,openings:o.openings,walls:o.walls,open_spans:o.open_spans};Array.isArray(o.open_spans)&&o.open_spans.length||delete n.open_spans;const r=this._spaceH;for(const[e,i]of Object.entries(t)){const t=n.rooms.find(t=>t.id===e);t&&(t.poly=i.map(t=>[t[0]/Nc,t[1]/r]),delete t.x,delete t.y,delete t.w,delete t.h)}for(const[t,i]of Object.entries(e)){const e=(n.openings||[]).find(e=>e.id===t);e&&(e.x=i[0]/Nc,e.y=i[1]/r)}const a=[],l=[];for(const t of i.changed){const e=i.rooms.find(e=>e.id===t),s=n.rooms.find(e=>e.id===t);if(!e||!s?.poly)continue;const o=s.poly.map(t=>[t[0]*Nc,t[1]*r]);if(e.poly.length===o.length)for(let t=0;tt.id===e);if(!s||!s.poly||s.poly.length<3)return null;if(i<0||i>=s.poly.length)return null;const o=[...s.poly[i]],n=[...s.poly[(i+1)%s.poly.length]];return{roomId:e,edge:i,a:o,b:n,n:hn(s.poly,i)}}(s,e,i);o&&(this._rszDrag={kind:"edge",pid:t.pointerId,roomId:e,plan:o,rooms:s,openings:this._rszOpenings(),snap:this._rszSnapshot(),moved:!1,d:0,k:1,changed:[]})}_rszCornerDown(t,e,i,s){"resize"!==this._tool||this._rszDrag||(t.stopPropagation(),t.preventDefault(),Uc(t),this._rszDrag={kind:"scale",pid:t.pointerId,roomId:e,fixed:s,span0:Math.hypot(i[0]-s[0],i[1]-s[1])||1,rooms:this._rszRooms(),openings:this._rszOpenings(),snap:this._rszSnapshot(),moved:!1,d:0,k:1,changed:[]})}_rszMove(t){const e=this._rszDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._svgPoint(t);if("edge"===e.kind){const t=e.plan,s=(i[0]-t.a[0])*t.n[0]+(i[1]-t.a[1])*t.n[1],o=this._snap([t.a[0]+t.n[0]*s,t.a[1]+t.n[1]*s]);let n=(o[0]-t.a[0])*t.n[0]+(o[1]-t.a[1])*t.n[1];if(n=function(t,e,i,s,o,n){if(!Number.isFinite(s)||Math.abs(s)<1e-9)return 0;const r=Math.sign(s);let a=Math.abs(s);const l=Math.max(o,1e-6);for(let s=0;s<4096&&a>1e-9;s++,a-=l){const s=r*a;if(wn(t,e,i,s,n))return s}return 0}(e.rooms,e.openings,t,n,this._gridPitch,this._rszOpts()),n===e.d&&e.moved)return;e.d=n,e.moved=!0;const r=vn(e.rooms,e.openings,t,n,this._rszOpts().eps);e.changed=Object.keys(r.polys),this._rszApplyPreview(r.polys,r.openings),this._rszLive=this._rszEdgeLabels(r,t)}else{const t=e.fixed,s=this._snap(i);let o=Math.hypot(s[0]-t[0],s[1]-t[1])/(e.span0||1);if(o=Math.max(.05,Math.min(20,o)),o=function(t,e,i,s,o,n){if(!Number.isFinite(o)||o<=0)return 1;if($n(t,e,i,s,o,n))return o;let r=1,a=o;for(let o=0;o<28;o++){const o=(r+a)/2;$n(t,e,i,s,o,n)?r=o:a=o}return r}(e.rooms,e.openings,e.roomId,t,o,this._rszOpts()),o===e.k&&e.moved)return;e.k=o,e.moved=!0;const n=e.rooms.find(t=>t.id===e.roomId),r=e.rooms.filter(t=>t.id!==e.roomId).map(t=>t.poly),a=kn(n,e.openings,r,t,o,2*this._rszOpts().eps);e.changed=[e.roomId],this._rszApplyPreview({[e.roomId]:a.poly},a.openings),this._rszLive=this._rszScaleLabels(a.poly)}this.requestUpdate()}_rszUp(t){const e=this._rszDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._rszPreview;this._rszDrag=null,this._rszLive=null,this._rszPreview=null;if(!(e.moved&&("edge"===e.kind?Math.abs(e.d)>1e-9:Math.abs(e.k-1)>1e-9))||!i)return this._cfgEpoch++,void this.requestUpdate();const s=JSON.parse(e.snap),o=this._curSpaceCfg;if(o){o.rooms=i.sp.rooms,o.openings=i.sp.openings,Array.isArray(i.sp.walls)&&(i.sp.walls.length?o.walls=i.sp.walls:delete o.walls),Array.isArray(i.sp.open_spans)&&i.sp.open_spans.length?o.open_spans=i.sp.open_spans:delete o.open_spans;for(const t of e.changed){const e=o.rooms.find(e=>e.id===t);e?.poly&&(e.poly=_n(e.poly,1e-9))}this._commitOpenSpans(),Array.isArray(o.walls)&&o.walls.length&&(o.walls=_r(o.walls,o.rooms||[],ya,1,this._cfgOpenCuts()),o.walls.length||delete o.walls)}this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._recordGeometry(this._t("history.resize_room"),s),this._saveConfig(),this.requestUpdate()}_rszCancelDrag(){this._rszDrag&&(this._rszDrag=null,this._rszLive=null,this._rszPreview=null,this._cfgEpoch++,this.requestUpdate())}_rszPointerCancel(t){const e=this._rszDrag;e&&e.pid===t.pointerId&&(t.stopPropagation(),this._rszCancelDrag())}_rszEdgeLabels(t,e){const i=this._rszDrag,s=[],o=t.polys[e.roomId]||i.rooms.find(t=>t.id===e.roomId).poly,n=o.length,r=e.edge,a=(r+1)%n;for(const[t,e]of[[o[(r-1+n)%n],o[r]],[o[r],o[a]],[o[a],o[(a+1)%n]]])s.push({x:(t[0]+e[0])/2,y:(t[1]+e[1])/2,text:this._fmtLen(t,e)});const l="mi"===this.hass?.config?.unit_system?.length,c=Object.keys(t.polys).length?Object.keys(t.polys):[e.roomId],h=this._spaceWalls,d=this._openPairs().flatMap(t=>t.segs),p=this._physicalBodiesR();for(const e of c){const o=t.polys[e]||i.rooms.find(t=>t.id===e).poly,n=h.length&&Er(Object.entries(t.polys).map(([t,e])=>({id:t,poly:e})),e,h,d,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)||o,r=Ze(n),a=p.length?sa(ia(n,p))*Math.pow(this._cellCm/this._gridPitch,2)/1e4:xn(n,this._gridPitch,this._cellCm);s.push({x:r[0],y:r[1],text:Sn(a,l),area:!0})}return s}_rszScaleLabels(t){const e="mi"===this.hass?.config?.unit_system?.length,i=t.map(t=>t[0]),s=t.map(t=>t[1]),o=Math.max(...i)-Math.min(...i),n=Math.max(...s)-Math.min(...s),r=this._spaceWalls,a=r.length&&this._rszSel&&Er([{id:this._rszSel,poly:t}],this._rszSel,r,[],this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)||t,l=Ze(a),c=this._physicalBodiesR(),h=c.length?sa(ia(a,c))*Math.pow(this._cellCm/this._gridPitch,2)/1e4:xn(a,this._gridPitch,this._cellCm);return[{x:Math.min(...i),y:Math.min(...s),text:`${this._fmtLen([0,0],[o,0])} × ${this._fmtLen([0,0],[n,0])}`},{x:l[0],y:l[1],text:Sn(h,e),area:!0}]}_renderResizeLayer(t){const e=Math.max(.013*t.w,5),i=e/2,s=t=>t.toFixed(1),o=`M ${s(-.7*i)} 0 H ${s(.7*i)} M 0 ${s(-.22*i)} V ${s(-i)} M ${s(-.32*i)} ${s(-.6*i)} L 0 ${s(-i)} L ${s(.32*i)} ${s(-.6*i)} M 0 ${s(.22*i)} V ${s(i)} M ${s(-.32*i)} ${s(.6*i)} L 0 ${s(i)} L ${s(.32*i)} ${s(.6*i)}`,n=[],r=this._rszRooms();for(const t of r)for(let i=0;i`}_stageAspect(){const t=this._stageEl,e=this._baseVb();return t&&t.clientHeight?t.clientWidth/t.clientHeight:e[2]/e[3]}_viewOr(t){return this._view&&this._view.w?this._view:wi(t,this._stageAspect())}_screenToVb(t,e){const i=this._stageEl,s=this._viewOr(this._baseVb()),o=i?.clientWidth||1,n=i?.clientHeight||1;return[s.x+t/o*s.w,s.y+e/n*s.h]}_clampView(t,e){const i=(t,e,i,s)=>{const o=1*Math.max(e,s),n=i-o,r=i+s-e+o;return Math.max(Math.min(n,r),Math.min(Math.max(n,r),t))};return{w:t.w,h:t.h,x:i(t.x,t.w,e.x,e.w),y:i(t.y,t.h,e.y,e.h)}}_applyView(t,e,i){const s=this._baseVb(),o=wi(s,this._stageAspect()),n=Math.min(ch.ZOOM_MAX,Math.max(ch.ZOOM_MIN,t)),r=o.w/n,a=o.h/n,l=this._viewOr(s),c=e??l.x+l.w/2,h=i??l.y+l.h/2;this._zoom=n,this._view=this._clampView({x:c-r/2,y:h-a/2,w:r,h:a},o)}_bootWatch(){clearTimeout(this._bootTimer),this._bootStart=Date.now(),this._bootLastH=-1,this._bootLastChange=this._bootStart;const t=()=>{if(!this._booting)return;const e=Date.now(),i=this._stageEl?this._stageEl.clientHeight:0;i!==this._bootLastH&&(this._bootLastH=i,this._bootLastChange=e);const s=e-this._bootStart;s>=1200||s>=700&&i>0&&e-this._bootLastChange>=250?this._bootSettled():this._bootTimer=window.setTimeout(t,100)};this._bootTimer=window.setTimeout(t,100)}_bootSettled(){if(!this._booting)return;this._refitView(),this._booting=!1;const t=this._stageEl?.clientHeight??0;!this._config?.kiosk&&t>0&&this._warmPatch({hdrH:this._hdrH,stageH:t,vp:this._warmViewportState()},!0),this._bootFading=!0,this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220),this._bootSoft=!0,clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},Oc)}_bootSoftCancel(){this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoft=!1)}_beginResumeSettle(){this._kiosk||"view"!==this._mode||this._booting||this._resumeSettling||(this._resumeSettling=!0,this._resumeStarted=performance.now(),this._resumeLastSize="",this._resumeLastChange=this._resumeStarted,this._viewportInvalidAt=0,this.requestUpdate(),this._resumeRaf&&cancelAnimationFrame(this._resumeRaf),this._resumeRaf=requestAnimationFrame(()=>this._resumeSettleTick()))}_resumeSettleTick(){if(this._resumeRaf=0,!this._resumeSettling||!this.isConnected)return;if(this._kiosk||"view"!==this._mode)return this._resumeSettling=!1,void this.requestUpdate();const t=performance.now(),e=this._stageEl,i=!!e&&e.clientWidth>0&&e.clientHeight>0;if(i){const i=`${e.clientWidth}x${e.clientHeight}`;i!==this._resumeLastSize&&(this._resumeLastSize=i,this._resumeLastChange=t)}const s=t-this._resumeStarted;if(i&&s>=220&&t-this._resumeLastChange>=80||s>=750){const t=this._view;return this._resumeSettling=!1,i&&this._applyView(this._zoom,t?t.x+t.w/2:void 0,t?t.y+t.h/2:void 0),void this.requestUpdate()}this._resumeRaf=requestAnimationFrame(()=>this._resumeSettleTick())}_refitView(){const t=this._stageEl;if(!t||"visible"!==document.visibilityState||t.clientWidth<=0||t.clientHeight<=0)return void(this._viewportInvalidAt||(this._viewportInvalidAt=Date.now()));if(this._viewportInvalidAt){const t=Date.now()-this._viewportInvalidAt;if(this._viewportInvalidAt=0,t>=Lc&&!this._resumeSettling&&(this._beginResumeSettle(),this._resumeSettling))return}if(this._resumeSettling)return;const e=this._view;this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}_zoomAt(t,e,i){const s=this._stageEl;if(!s)return;const o=wi(this._baseVb(),this._stageAspect()),n=Math.min(ch.ZOOM_MAX,Math.max(ch.ZOOM_MIN,i)),r=s.clientWidth,a=s.clientHeight,l=this._screenToVb(t,e),c=o.w/n,h=o.h/n;this._zoom=n,this._view=this._clampView({x:l[0]-t/r*c,y:l[1]-e/a*h,w:c,h:h},o)}_onWheel(t){const e=this._stageEl;if(!e)return;t.preventDefault();const i=e.getBoundingClientRect(),s=t.deltaY<0?1.15:1/1.15;this._zoomAt(t.clientX-i.left,t.clientY-i.top,this._zoom*s),this._saveZoom()}_stepZoom(t){const e=this._stageEl;e&&(this._zoomAt(e.clientWidth/2,e.clientHeight/2,this._zoom*(t>0?1.4:1/1.4)),this._saveZoom())}_resetZoom(){const t=this._baseVb();this._zoom=1,this._view=wi(t,this._stageAspect()),this._saveZoom()}_saveZoom(){if("view"===this._mode){this._zoomBySpace={...this._zoomBySpace,[this._space]:this._zoom};try{localStorage.setItem(Xc,JSON.stringify(this._zoomBySpace))}catch{}}}_restoreZoom(){const t=this._zoomBySpace[this._space]||1;this._zoom=t;const e=this._stageEl;if(e&&e.clientHeight){const e=this._baseVb();return this._applyView(t,e[0]+e[2]/2,e[1]+e[3]/2),void this.requestUpdate()}this._view=null,requestAnimationFrame(()=>{if(!this._stageEl)return;const e=this._baseVb();this._applyView(t,e[0]+e[2]/2,e[1]+e[3]/2),this.requestUpdate()})}_stagePointerDown(t){if(this._vacFit)return;if(this._kiosk&&(this._cyclePausedUntil=Date.now()+6e4,0===this._pointers.size?(this._swipeStart={x:t.clientX,y:t.clientY,id:t.pointerId},t.target.closest?.(".dev, .roomlabel, .oplock")||(clearTimeout(this._kioskHoldTimer),this._kioskHoldTimer=window.setTimeout(()=>{this._kioskDialog=!0,this._swipeStart=null},3e3))):(this._swipeStart=null,clearTimeout(this._kioskHoldTimer))),this._drag)return;if(this._markup&&t.target.closest?.(".roomlabel, .rlhandle, .rszhandle, .dev, .oplock, .op-hit, button"))return;if("devices"===this._mode&&t.target.closest(".dev"))return;if("decor"===this._mode&&this._decorPointerDown(t))return;this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY});const e=this._viewOr(this._baseVb());if(1===this._pointers.size)this._panStart={sx:t.clientX,sy:t.clientY,vx:e.x,vy:e.y},this._panLock=null,this._suppressClick=!1;else if(2===this._pointers.size){this._cancelBoundaryAnchor();const t=[...this._pointers.values()],e=Math.hypot(t[0].x-t[1].x,t[0].y-t[1].y);this._pinchStart={dist:e,zoom:this._zoom},this._panStart=null,this._panLock=null}}get _swipeZone(){return this._kiosk&&this._zoom<=1.001&&this._model.length>1}_stagePointerMove(t){if(this._physicalRotate?.pid!==t.pointerId)if(this._physicalDrag?.pid!==t.pointerId)if(this._dtDrag?.pid!==t.pointerId)if(this._bdDrag?.pid!==t.pointerId){if(this._decorDraft?.pid===t.pointerId){const e=this._decorDraft;let i=this._decorSnap(this._svgPoint(t),t.pointerType);if(t.shiftKey&&("rect"===e.kind||"ellipse"===e.kind)){const t=i[0]-e.a[0],s=i[1]-e.a[1],o=Math.max(Math.abs(t),Math.abs(s));i=this._snap([e.a[0]+(t<0?-o:o),e.a[1]+(s<0?-o:o)])}return void(this._decorDraft={...e,b:i})}if(this._decorMove?.pid!==t.pointerId)if(this._pointers.has(t.pointerId)){if(this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY}),this._markup&&1===this._pointers.size&&this._markupMove(t),this._pinchStart&&this._pointers.size>=2){const t=[...this._pointers.values()],e=Math.hypot(t[0].x-t[1].x,t[0].y-t[1].y)/(this._pinchStart.dist||1),i=this._stageEl.getBoundingClientRect(),s=(t[0].x+t[1].x)/2-i.left,o=(t[0].y+t[1].y)/2-i.top;this._zoomAt(s,o,this._pinchStart.zoom*e),this._suppressClick=!0,this._saveZoom()}else if(this._panStart){const e=t.clientX-this._panStart.sx,i=t.clientY-this._panStart.sy;Math.abs(e)+Math.abs(i)>4&&(this._suppressClick=!0,clearTimeout(this._holdTimer)),null===this._panLock&&Math.abs(e)+Math.abs(i)>8&&(this._panLock=this._swipeZone&&Math.abs(e)>1.5*Math.abs(i)?"swipe":"pan");const s=this._stageEl;if("pan"===this._panLock&&s){const t=this._baseVb(),o=this._viewOr(t),n=wi(t,this._stageAspect());this._view=this._clampView({x:this._panStart.vx-e/(s.clientWidth||1)*o.w,y:this._panStart.vy-i/(s.clientHeight||1)*o.h,w:o.w,h:o.h},n)}}}else this._markupMove(t);else this._decorMoveUpdate(t)}else this._bdMove(t);else this._dtMove(t);else this._physicalMove(t);else this._physicalRotateMove(t)}_stagePointerUp(t){if(this._kiosk){clearTimeout(this._kioskHoldTimer);const e=this._swipeStart;if(this._swipeStart=null,e&&e.id===t.pointerId){const i=t.clientX-e.x,s=t.clientY-e.y;if(Math.abs(i)+Math.abs(s)<8){const t=Date.now();t-this._lastTap<350&&this._resetZoom(),this._lastTap=t}const o="pan"===this._panLock?null:function(t,e,i,s,o,n=60){if(i>1.001||s.length<2)return null;if(Math.abs(t)t.id),this._space);o&&(this._slideTo(o,i<0?"left":"right"),this._saveNav(),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._showKioskDots())}}if(this._physicalDrag?.pid!==t.pointerId)if(this._physicalRotate?.pid!==t.pointerId)if(this._dtDrag?.pid!==t.pointerId)if(this._bdDrag?.pid!==t.pointerId)if(this._decorDraft?.pid!==t.pointerId){if(this._decorMove?.pid===t.pointerId)return this._decorMove.moved&&(this._recordGeometry(this._t("history.decor_move"),this._decorMove.before),this._saveConfig()),void(this._decorMove=null);this._pointers.delete(t.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null,setTimeout(()=>this._suppressClick=!1,0))}else this._decorCommitDraft();else this._bdUp();else this._dtUp();else this._physicalRotateUp(t);else this._physicalUp(t)}_clickRoom(t){!this._suppressClick&&t.area&&rh("/config/areas/area/"+t.area)}_pointerDown(t,e){if("plan"===this._mode)return;if("view"===this._mode){this._holdFired=!1,clearTimeout(this._holdTimer);const i=t.pointerId,s=t.currentTarget;return void(this._holdTimer=window.setTimeout(()=>{this._holdFired=!0,this._interruptViewGesture(i,s),this._infoCard=e},600))}if("ha_disabled"===e.bindingStatus?.kind)return;t.preventDefault();const i=this._pos(e);this._drag={id:e.id,sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},lh(t),this._tip=null}_pointerMove(t,e){if(!this._drag||this._drag.id!==e.id)return;const i=this.renderRoot.querySelector(".stage");if(!i)return;const s=this._baseVb(),o=i.getBoundingClientRect(),n=this._viewOr(s),r=(t.clientX-this._drag.sx)/o.width*n.w,a=(t.clientY-this._drag.sy)/o.height*n.h;Math.abs(t.clientX-this._drag.sx)+Math.abs(t.clientY-this._drag.sy)>3&&(this._drag.moved=!0,clearTimeout(this._holdTimer));const l=Ea(this._drag.ox+r),c=Ea(this._drag.oy+a);this._savePos(e,l,c)}_pointerUp(t,e){if(clearTimeout(this._holdTimer),!this._drag||this._drag.id!==e.id)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&(this._selId=e.id,window.setTimeout(()=>this._drag=null,0))}_showToast(t){this._toast=t,clearTimeout(this._toastTimer),this._toastTimer=window.setTimeout(()=>{this._toast=""},3500)}get _noHover(){return ch._noHoverMq||ch._touchSeen}_notePointer(t){this._boundaryPointerType=t.pointerType||"mouse","touch"!==t.pointerType&&"pen"!==t.pointerType||(ch._touchSeen=!0,this._tip&&(this._tip=null))}_guardTouchGesture(t){if(this._editorSecondary.handleOutsideDismiss(t))return;if("click"===t.type){if(!this._suppressClick&&!this._touchSequenceMultitouch&&Date.now()>this._touchClickBlockUntil)return;return t.preventDefault(),void t.stopImmediatePropagation()}const e=t;if("touch"===e.pointerType)if(this._notePointer(e),"pointerdown"!==t.type){if("pointermove"===t.type){const t=this._touchContacts.get(e.pointerId);if(!t)return;const i={...t,x:e.clientX,y:e.clientY};if(this._touchContacts.set(e.pointerId,i),this._touchSequenceMultitouch&&"view"===this._mode&&!this._vacFit&&this._pinchStart&&[...this._touchContacts.values()].every(t=>t.inStage)){this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY});const t=[...this._touchContacts.values()];if(t.length>=2&&this._stageEl){const[e,i]=t,s=Math.hypot(e.x-i.x,e.y-i.y)/(this._pinchStart.dist||1),o=this._stageEl.getBoundingClientRect();this._zoomAt((e.x+i.x)/2-o.left,(e.y+i.y)/2-o.top,this._pinchStart.zoom*s),this._saveZoom()}}return}if("pointerup"===t.type||"pointercancel"===t.type){if(this._touchContacts.delete(e.pointerId),this._touchSequenceMultitouch){if(this._touchClickBlockUntil=Date.now()+500,this._pointers.delete(e.pointerId),!this._vacFit&&this._pointers.size>=2){const[t,e]=[...this._pointers.values()];this._pinchStart={dist:Math.hypot(t.x-e.x,t.y-e.y),zoom:this._zoom}}else this._pinchStart=null;0===this._pointers.size&&(this._panStart=null,this._panLock=null)}0===this._touchContacts.size&&(this._touchSequenceMultitouch=!1)}}else if(this._touchContacts.set(e.pointerId,{x:e.clientX,y:e.clientY,inStage:!!e.target?.closest?.(".stage")}),this._touchContacts.size>=2){this._touchSequenceMultitouch=!0,this._touchClickBlockUntil=Number.POSITIVE_INFINITY,clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),this._swipeStart=null;const t=[...this._touchContacts.values()];if("view"===this._mode&&!this._vacFit&&t.every(t=>t.inStage)){this._pointers=new Map([...this._touchContacts].map(([t,e])=>[t,{x:e.x,y:e.y}]));const[e,i]=t;this._pinchStart={dist:Math.hypot(e.x-i.x,e.y-i.y),zoom:this._zoom},this._panStart=null,this._panLock=null}else this._vacFit&&(this._pointers.clear(),this._pinchStart=null,this._panStart=null,this._panLock=null)}}_showTip(t,e,i,s,o){this._noHover||this._drag||(this._tip={x:t.clientX,y:t.clientY,title:e,meta:i,lqi:s,temp:o})}get _gridPitch(){return Ra}get _cellCm(){const t=Number(this._curSpaceCfg?.cell_cm);return Number.isFinite(t)&&t>0?t:5}_fmtLen(t,e){const i=function(t,e,i,s){return Math.hypot(e[0]-t[0],e[1]-t[1])/i*s}(t,e,this._gridPitch,this._cellCm);return Ke(i,"mi"===this.hass?.config?.unit_system?.length)}get _curSpaceCfg(){const t=this._rszPreview;return t&&t.space===this._space?t.sp:this._serverCfg?.spaces.find(t=>t.id===this._space)}get _renderCfg(){const t=this._rszPreview;return t&&this._serverCfg?{...this._serverCfg,spaces:this._serverCfg.spaces.map(e=>e.id===t.space?t.sp:e)}:this._serverCfg}get _spaceH(){return this._curSpaceCfg,eh}get _segments(){const t=this._curSpaceCfg,e=this._spaceH;return Xe(t?.rooms||[]).map(t=>[t[0]*eh,t[1]*e,t[2]*eh,t[3]*e])}_savedNav(){try{return JSON.parse(localStorage.getItem(Qc)||"null")}catch{return null}}_saveNav(){try{localStorage.setItem(Qc,JSON.stringify({space:this._space,mode:this._mode}))}catch{}}_setMode(t){if(this._kiosk&&"view"!==t)return;if(this._mode===t)return;if(this._bootSoftCancel(),("plan"===t||"decor"===t)&&!this._norm)return void this._showToast(this._t("toast.markup_needs_server"));const e=this._mode;this._editorSecondary.closeForNavigation();const i="view"!==e&&"view"!==t,s=i&&this.renderRoot.querySelector(".editorchrome-inner")?.getBoundingClientRect().height||0;i||this._cancelEditorSwapAnimations(),(this._decorMove||this._dtDrag||this._bdDrag)&&this._cancelDecorGesture();const o=!this._spaceModel().bg&&"view"===t!=("view"===this._mode);if("view"===this._mode&&"view"!==t){const t=this._view;this._viewModeSnap={space:this._space,zoom:this._zoom,cx:t?t.x+t.w/2:void 0,cy:t?t.y+t.h/2:void 0}}if("plan"===e&&this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._mode=t,this._editorChromeMode="view"===t?e:t,this._startNavMotion("view"===e?"enter":"view"===t?"exit":"swap"),i&&this._animateEditorSwap(s),o&&(this._zoom=1,this._view=null),"view"===t){const t=this._viewModeSnap;this._viewModeSnap=null,t&&t.space===this._space?(this._zoom=t.zoom,this._view=null,requestAnimationFrame(()=>{this._stageEl&&"view"===this._mode&&this._space===t.space&&(this._applyView(t.zoom,t.cx,t.cy),this._saveZoom(),this.requestUpdate())})):t&&this._restoreZoom()}this._path=[],this._cursorPt=null,this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._tool="draw",this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._selId=null,this._physicalSel=null,this._physicalDialog=null,this._physicalDrag=null,this._rszSel=null,this._rszDrag=null,this._rszLive=null,this._rszPreview=null,this._tip=null,this._hoverRoom=null,this._decorDraft=null,this._decorSel=null,this._decorMove=null,this._backdropDialog=null,this._decorTool="select",this._bdDrag=null,this._dtDrag=null,this._dtBox=null,"plan"===t&&(this._primeDrawWallField(),this._resumeLastDraft()),this._saveNav()}_primeDrawWallField(){null===this._drawWallField&&(this._drawWallField=hr(ar,this._imperial))}get _drawWallFieldValue(){return null===this._drawWallField?hr(ar,this._imperial):this._drawWallField}get _drawWallCm(){const t=Hc(this._drawWallFieldValue);if(null==t||t<=0)return null;const e=this._imperial?2.54*t:t,i="column"===this._tool?oa:100;return e>=1&&e<=i?e:null}get _drawWallMaxCm(){return"column"===this._tool?oa:100}_showPhysicalRange(t=this._drawWallMaxCm){this._showToast(this._t("toast.physical_range",{max:hr(t,this._imperial),unit:this._t(this._imperial?"wallthick.unit_in":"wallthick.unit_cm")}))}_draftSegmentCount(t=this._curSpaceCfg){return(t?.room_drafts||[]).reduce((t,e)=>t+(Array.isArray(e.segments)?e.segments.length:0),0)}_limitReached(t){const e=this._curSpaceCfg;if(!e)return!0;const i="draft"===t?(e.room_drafts||[]).length>=200:"partition"===t?(e.partitions||[]).length>=2e3:(e.wall_columns||[]).length>=500;return i&&this._showToast(this._t("toast.physical_limit")),i}_svgPoint(t){const e=this.renderRoot.querySelector(".stage").getBoundingClientRect();return this._screenToVb(t.clientX-e.left,t.clientY-e.top)}_snap(t){const e=this._gridPitch;return[Ea(Ve(t[0],e)),Ea(Ve(t[1],e))]}_snapDrawPoint(t,e=!1){const i=this._path[this._path.length-1],s=e&&i?function(t,e,i,s=1/0){if(!(i>0&&t?.every(Number.isFinite)&&e?.every(Number.isFinite)))return[e[0],e[1]];const o=e[0]-t[0],n=e[1]-t[1];if(Math.abs(o)+Math.abs(n)<=1e-12)return[t[0],t[1]];const r=Math.PI/4;let a=Math.atan2(n,o);a<0&&(a+=2*Math.PI);const l=Math.floor(a/r+.5)%8,[c,h]=[[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1],[0,-1],[1,-1]][l],d=c*c+h*h;let p=Math.max(0,Math.round((o*c+n*h)/(i*d)));if(Number.isFinite(s)&&s>=0){const e=(t,e)=>{if(!e)return 1/0;const o=e>0?s-t:t+s;return Math.max(0,Math.floor((o+1e-9*i)/i))};p=Math.min(p,e(t[0],c),e(t[1],h))}return[t[0]+c*p*i,t[1]+h*p*i]}(i,t,this._gridPitch,Ta):t;return this._snap(s)}_samePt(t,e){return ii(t,e)}_dropLegacySegments(){for(const t of this._serverCfg?.markers||[])"ripple"===t.display&&(t.display="icon_ripple");for(const t of this._serverCfg?.spaces||[]){delete t.segments;const e=new Set,i=t=>"string"==typeof t&&t.length>=1&&t.length<=64&&!e.has(t),s=t=>(e.add(t),!0),o=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(Number(t))&&Math.abs(Number(t))<=Da);if(Array.isArray(t.partitions)&&(t.partitions=t.partitions.filter(t=>t&&i(t.id)&&o(t.a)&&o(t.b)&&Math.hypot(t.a[0]-t.b[0],t.a[1]-t.b[1])>1e-9&&s(t.id)).map(t=>({...t,cm:Math.max(1,Math.min(100,Number(t.cm)||15))})),t.partitions.length||delete t.partitions),Array.isArray(t.wall_columns)&&(t.wall_columns=t.wall_columns.filter(t=>t&&i(t.id)&&o(t.center)&&s(t.id)).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[Number(t.center[0]),Number(t.center[1])],cm:na(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:ra(t.angle)}})),t.wall_columns.length||delete t.wall_columns),Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t&&i(t.id)&&Array.isArray(t.points)&&t.points.length>=2&&t.points.every(o)&&s(t.id)).map(t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],i=[];for(let s=1;st.points.length>=2),t.room_drafts.length||delete t.room_drafts),Array.isArray(t.walls)){const e=ml(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]);t.walls=$r(t.walls,t.rooms||[],Aa,1,e),t.walls.length||delete t.walls}}}get _cfgWriting(){return this._writesPending>0}_writeConfig(){this._writesPending++,this._writeChain=this._writeChain.catch(()=>{}).then(async()=>{if(!this._serverCfg)return;this._dropLegacySegments();const t=await this.hass.callWS({type:"houseplan/config/set",config:this._serverCfg,expected_rev:this._cfgRev});this._cfgRev=t?.rev??this._cfgRev+1});return this._writeChain.finally(()=>{this._writesPending--})}_saveConfig(){this._cfgEpoch++,this._saveConfigDebounced()}_geometrySnapshot(t=this._space){const e=this._serverCfg?.spaces.find(e=>e.id===t);if(!e)return null;const i=t=>JSON.parse(JSON.stringify(t)),s={};for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==e[t]&&(s[t]=e[t]);return{spaceId:t,rooms:i(e.rooms||[]),...Array.isArray(e.openings)?{openings:i(e.openings)}:{},...Array.isArray(e.walls)?{walls:i(e.walls)}:{},...Array.isArray(e.open_spans)?{open_spans:i(e.open_spans)}:{},...Array.isArray(e.room_drafts)?{room_drafts:i(e.room_drafts)}:{},...Array.isArray(e.partitions)?{partitions:i(e.partitions)}:{},...Array.isArray(e.wall_columns)?{wall_columns:i(e.wall_columns)}:{},...Array.isArray(e.decor)?{decor:i(e.decor)}:{},plan_transform:s}}_recordGeometry(t,e){if(!e)return;const i=this._geometrySnapshot(e.spaceId);i&&JSON.stringify(e)!==JSON.stringify(i)&&(this._geometryHistory.push({name:t,before:e,after:i}),this.requestUpdate())}_clearGeometryGesture(){this._path=[],this._cursorPt=null,this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._wallDialog=null,this._physicalDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._openingDialog=null,this._rszSel=null,this._rszDrag=null,this._rszPreview=null,this._rszLive=null,this._decorDraft=null,this._decorMove=null,this._dtDrag=null,this._bdDrag=null}_cancelBoundaryAnchor(){return!("boundary"!==this._tool||!this._openWallAnchor)&&(this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._cursorPt=null,this.requestUpdate(),!0)}_stagePointerCancel(t){if(clearTimeout(this._kioskHoldTimer),this._swipeStart?.id===t.pointerId&&(this._swipeStart=null),this._physicalDrag?.pid!==t.pointerId&&this._physicalRotate?.pid!==t.pointerId)return this._decorDraft?.pid===t.pointerId?(this._decorDraft=null,void this.requestUpdate()):void(this._decorMove?.pid!==t.pointerId&&this._dtDrag?.pid!==t.pointerId&&this._bdDrag?.pid!==t.pointerId?(this._cancelBoundaryAnchor(),this._pointers.delete(t.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null)):this._cancelDecorGesture());this._cancelPhysicalGesture()}_applyGeometryState(t){const e=this._serverCfg?.spaces.find(e=>e.id===t.spaceId);if(!e)return!1;const i=t=>JSON.parse(JSON.stringify(t));e.rooms=i(t.rooms),void 0!==t.openings?e.openings=i(t.openings):delete e.openings,void 0!==t.walls?e.walls=i(t.walls):delete e.walls,void 0!==t.open_spans?e.open_spans=i(t.open_spans):delete e.open_spans,void 0!==t.room_drafts?e.room_drafts=i(t.room_drafts):delete e.room_drafts,void 0!==t.partitions?e.partitions=i(t.partitions):delete e.partitions,void 0!==t.wall_columns?e.wall_columns=i(t.wall_columns):delete e.wall_columns,void 0!==t.decor?e.decor=i(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];return Object.assign(e,i(t.plan_transform||{})),this._clearGeometryGesture(),this._space!==t.spaceId&&(this._space=t.spaceId,this._saveNav(),this._restoreZoom()),this._modelCache=null,this._frame=null,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate(),!0}_roomAt(t){return this._spaceModel().rooms.find(e=>{const i=Je(e);return!!i&&ri(t,i)})}_overlapRoom(t){return this._spaceModel().rooms.find(e=>{const i=Je(e);return!!i&&ui(t,i)})}_pointInRoom(t,e){return e.poly?si(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(!xn(t))return!0;const e=t.length,i=.001;for(let s=0;st?.classList?.contains?.("roomlabel")||t?.classList?.contains?.("rlhandle")))return;if(e.some(t=>t?.classList?.contains?.("physical-hit")))return void("boundary"===this._tool&&this._showToast(this._t("toast.boundary_blocked")));const i=this._svgPoint(t);if("select"===this._tool)return void(this._physicalSel=null);if("resize"===this._tool){if(this._rszDrag||e.some(t=>t?.classList?.contains?.("rszhandle")))return;const t=[...this._spaceModel().rooms].reverse().find(t=>this._pointInRoom(i,t));return void(this._rszSel=t?.id||null)}if("delroom"===this._tool)return void this._deleteRoomClick(i);if("opening"===this._tool)return void this._openingClick(i);if("merge"===this._tool)return void this._mergeClick(i);if("wallthick"===this._tool)return void this._wallThickClick(i);if("boundary"===this._tool)return void this._boundaryClick(i);if("split"===this._tool)return void this._splitClick(i);if("partition"===this._tool)return void this._partitionClick(i,t.shiftKey);if("column"===this._tool)return void this._columnClick(i);const s=this._snapDrawPoint(i,t.shiftKey);if(t.ctrlKey||t.metaKey)return t.preventDefault(),void this._closeRoomContour(!0);const o=this._path.length>=3&&this._samePt(s,this._path[0]);if(!this._path.length){const t=this._draftEndAt(s);return t?(this._activeDraftId=t.draft.id,this._resumeDraftBySpace[this._space]=t.draft.id,this._path=t.reverse?[...t.draft.points].reverse().map(t=>[...t]):t.draft.points.map(t=>[...t]),void(this._draftSegmentCms=t.reverse?[...t.draft.segments].reverse().map(t=>t.cm):t.draft.segments.map(t=>t.cm))):(this._activeDraftId=null,this._draftSegmentCms=[],void(this._path=[s]))}const n=this._path[this._path.length-1];if(this._samePt(s,n))return;if(o)return void this._closeRoomContour();const r=this._draftEndAt(s,this._activeDraftId||void 0);if(r)return void this._mergeDraftEndpoint(r);if(null==this._drawWallCm)return void this._showPhysicalRange(100);if(this._path.length>=500)return void this._showToast(this._t("toast.physical_limit"));const a=this._curSpaceCfg;!this._activeDraftId&&(a?.room_drafts||[]).length>=200||this._draftSegmentCount(a)>=2e3?this._showToast(this._t("toast.physical_limit")):(this._path=[...this._path,s],this._persistActiveDraftSegment())}_draftEndAt(t,e){const i=this._viewOr(this._baseVb()),s=Math.max(.15*this._gridPitch,this._stageEl?.clientWidth?i.w/this._stageEl.clientWidth*12:0);for(const i of this._spaceModel().room_drafts||[]){if(i.id===e)continue;if(i.points.length<2)continue;const o=i.points[0],n=i.points[i.points.length-1];if(Math.hypot(t[0]-n[0],t[1]-n[1])<=s)return{draft:i,reverse:!1};if(Math.hypot(t[0]-o[0],t[1]-o[1])<=s)return{draft:i,reverse:!0}}return null}_mergeDraftEndpoint(t){const e=this._curSpaceCfg;if(!e||!this._path.length)return;const i=Array.isArray(e.room_drafts)?e.room_drafts:[],s=this._activeDraftId?i.find(t=>t.id===this._activeDraftId):null,o=i.find(e=>e.id===t.draft.id);if(!o)return;const n=t.reverse?t.draft.points.map(t=>[...t]):[...t.draft.points].reverse().map(t=>[...t]),r=t.reverse?(o.segments||[]).map(t=>({...t})):[...o.segments||[]].reverse().map(t=>({...t})),a=this._path[this._path.length-1],l=this._samePt(a,n[0]),c=l?null:this._drawWallCm;if(!l&&null==c)return void this._showPhysicalRange(100);const h=this._draftSegmentCms.map((t,e)=>({...s?.segments?.[e]||{},cm:t})),d=[...this._path.map(t=>[...t]),...l?n.slice(1):n],p=[...h,...null==c?[]:[{cm:c}],...r],u=d.length>=4&&this._samePt(d[0],d[d.length-1]),_=u?d.slice(0,-1):d,m=u?p.slice(0,-1):p;if(_.length>500)return void this._showToast(this._t("toast.physical_limit"));const g=(s?.segments?.length||0)+(o.segments?.length||0);if(this._draftSegmentCount(e)-g+m.length>2e3)return void this._showToast(this._t("toast.physical_limit"));if(u){if(this._contourSelfIntersects(_)||mi(_)<=1e-6)return void this._showToast(this._t("toast.contour_cannot_close"));const t=this._overlapRoom(_);if(t)return void this._showToast(this._t("toast.room_overlap",{name:t.name||""}))}const f=this._geometrySnapshot(),v=this._activeDraftId||t.draft.id,y={...s||o,id:v,points:_.map(t=>[t[0]/eh,t[1]/eh]),segments:m};e.room_drafts=i.filter(e=>e.id!==t.draft.id&&(!this._activeDraftId||e.id!==this._activeDraftId)),e.room_drafts.push(y),this._activeDraftId=v,this._resumeDraftBySpace[this._space]=v,this._draftSegmentCms=m.map(t=>Number(t.cm)),this._path=_,this._physicalSel=null,this._recordGeometry(this._t("history.draft_merge"),f),this._saveConfig(),u&&(this._closingWallCm=Number(p[p.length-1]?.cm)||ar,this._path=[..._,[..._[0]]],this._cursorPt=null,this._nameSel="",this._areaSel="",this._resetRoomDialogFields(),this._roomDialog=!0)}_persistActiveDraftSegment(){if(this._path.length<2||!this._curSpaceCfg)return;const t=this._drawWallCm;if(null==t)return;this._draftSegmentCms=[...this._draftSegmentCms,t];const e=this._geometrySnapshot(),i=this._curSpaceCfg;i.room_drafts||=[],this._activeDraftId||(this._activeDraftId="draft-"+Date.now().toString(36)),this._resumeDraftBySpace[this._space]=this._activeDraftId;const s=i.room_drafts.findIndex(t=>t.id===this._activeDraftId),o={...s>=0?i.room_drafts[s]:{},id:this._activeDraftId,points:this._path.map(t=>[t[0]/eh,t[1]/eh]),segments:this._draftSegmentCms.map((t,e)=>({...s>=0?i.room_drafts[s]?.segments?.[e]:{},cm:t}))};s>=0?i.room_drafts[s]=o:i.room_drafts.push(o),this._recordGeometry(this._t("history.draft_segment"),e),this._saveConfig()}_partitionClick(t,e){const i=this._snapDrawPoint(t,e);if(!this._path.length)return void(this._path=[i]);const s=this._path[0];if(this._samePt(s,i))return;const o=this._drawWallCm;if(null==o)return void this._showPhysicalRange(100);if(!this._curSpaceCfg||this._limitReached("partition"))return;const n=this._geometrySnapshot(),r=this._curSpaceCfg;r.partitions||=[];const a="partition-"+Date.now().toString(36);r.partitions.push({id:a,a:[s[0]/eh,s[1]/eh],b:[i[0]/eh,i[1]/eh],cm:o}),this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._cursorPt=null,this._recordGeometry(this._t("history.partition_add"),n),this._saveConfig()}_columnClick(t){const e=this._snap(t),i=this._drawWallCm;if(null==i)return void this._showPhysicalRange(oa);if(!this._curSpaceCfg||this._limitReached("column"))return;const s={id:"column-"+Date.now().toString(36),shape:"square",center:e,cm:na(i),angle:0},o=(this._spaceModel().wall_columns||[]).find(t=>ba(t,s,.02*this._gridPitch));if(o)return clearTimeout(this._duplicateColumnTimer),this._duplicateColumnId=o.id,this._duplicateColumnTimer=window.setTimeout(()=>{this._duplicateColumnId=null},900),void this._showToast(this._t("toast.column_duplicate"));const n=this._geometrySnapshot(),r=this._curSpaceCfg;r.wall_columns||=[],r.wall_columns.push({...s,center:[e[0]/eh,e[1]/eh]}),this._recordGeometry(this._t("history.column_add"),n),this._saveConfig()}_openPhysicalDialog(t,e,i){const s=this._spaceModel();if("partition"===t){const i=s.partitions.find(t=>t.id===e);i&&(this._physicalDialog={kind:t,id:e,cm:hr(i.cm,this._imperial),length:this._fmtLen(i.a,i.b)})}else if("column"===t){const i=s.wall_columns.find(t=>t.id===e);i&&(this._physicalDialog={kind:t,id:e,cm:hr(i.cm,this._imperial),shape:i.shape,angle:this._angleField("square"===i.shape?ra(i.angle):0)})}else{const o=s.room_drafts.find(t=>t.id===e),n=Math.max(0,Math.min(o?.segments.length?o.segments.length-1:0,i||0));o?.segments[n]&&(this._physicalDialog={kind:t,id:e,segment:n,cm:hr(o.segments[n].cm,this._imperial),length:this._fmtLen(o.points[n],o.points[n+1])})}}_physicalDown(t,e,i){t.stopPropagation(),lh(t);const s=this._spaceModel(),o=this._svgPoint(t),n=[];for(const t of[...s.wall_columns].reverse())ya(o,ha(t,this._cellCm,this._gridPitch))&&n.push({kind:"column",id:t.id});for(const t of[...s.partitions].reverse()){const e=ca(t.a,t.b,t.cm,this._cellCm,this._gridPitch);e&&ya(o,e)&&n.push({kind:"partition",id:t.id})}n.some(t=>t.kind===e&&t.id===i)||n.unshift({kind:e,id:i});const r=n.map(t=>`${t.kind}:${t.id}`).sort().join("|"),a=performance.now(),l=this._physicalPickCycle,c=n.length>1&&l?.signature===r&&a-l.at>380&&a-l.at<=1200&&Math.hypot(t.clientX-l.x,t.clientY-l.y)<=10?(l.index+1)%n.length:Math.max(0,n.findIndex(t=>t.kind===e&&t.id===i));this._physicalPickCycle={signature:r,index:c,x:t.clientX,y:t.clientY,at:a},e=n[c].kind,i=n[c].id;const h="partition"===e?s.partitions.find(t=>t.id===i):s.wall_columns.find(t=>t.id===i);h&&(this._physicalSel={kind:e,id:i},this._physicalDrag={pid:t.pointerId,kind:e,id:i,start:this._svgPoint(t),startClient:[t.clientX,t.clientY],before:this._geometrySnapshot(),moved:!1,base:JSON.parse(JSON.stringify(h)),delta:[0,0]})}_clampPhysicalDelta(t,e,i){const s="partition"===t?[e.a,e.b]:[e.center],o=s.map(t=>t[0]),n=s.map(t=>t[1]);return[Math.max(-Da*eh-Math.min(...o),Math.min(Da*eh-Math.max(...o),i[0])),Math.max(-Da*eh-Math.min(...n),Math.min(Da*eh-Math.max(...n),i[1]))]}_physicalMove(t){const e=this._physicalDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._svgPoint(t),s="partition"===e.kind?e.base.a:e.base.center,o=this._snap([s[0]+i[0]-e.start[0],s[1]+i[1]-e.start[1]]),n=this._clampPhysicalDelta(e.kind,e.base,[o[0]-s[0],o[1]-s[1]]);this._physicalDrag={...e,delta:n,moved:e.moved||Math.hypot(t.clientX-e.startClient[0],t.clientY-e.startClient[1])>=5}}_physicalUp(t){const e=this._physicalDrag;if(!e||e.pid!==t.pointerId)return;if(t.stopPropagation(),this._physicalDrag=null,!e.moved)return void this._registerPhysicalTap(e.kind,e.id);if(!this._curSpaceCfg)return;const i=this._curSpaceCfg;if("partition"===e.kind){const t=(i.partitions||[]).find(t=>t.id===e.id),s=e.base;t&&(t.a=[(s.a[0]+e.delta[0])/eh,(s.a[1]+e.delta[1])/eh],t.b=[(s.b[0]+e.delta[0])/eh,(s.b[1]+e.delta[1])/eh])}else{const t=(i.wall_columns||[]).find(t=>t.id===e.id),s=e.base,o={...s,center:[s.center[0]+e.delta[0],s.center[1]+e.delta[1]]};if(this._spaceModel().wall_columns.some(t=>t.id!==e.id&&ba(t,o,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"));t&&(t.center=[(s.center[0]+e.delta[0])/eh,(s.center[1]+e.delta[1])/eh])}this._recordGeometry(this._t("history.physical_move"),e.before),this._saveConfig()}_registerPhysicalTap(t,e,i){const s=performance.now(),o=this._physicalLastTap?.kind===t&&this._physicalLastTap.id===e&&this._physicalLastTap.segment===i&&s-this._physicalLastTap.at<=360;this._physicalLastTap={kind:t,id:e,segment:i,at:s},o&&(this._physicalLastTap=null,this._openPhysicalDialog(t,e,i))}_cancelPhysicalGesture(){this._physicalDrag=null,this._physicalRotate=null,this.requestUpdate()}_physicalRotateDown(t,e){if("square"!==e.shape)return;t.preventDefault(),t.stopPropagation(),lh(t);const i=this._svgPoint(t);this._physicalSel={kind:"column",id:e.id},this._physicalRotate={pid:t.pointerId,id:e.id,center:[...e.center],startAngle:180*Math.atan2(i[1]-e.center[1],i[0]-e.center[0])/Math.PI,baseAngle:ra(e.angle),angle:ra(e.angle),before:this._geometrySnapshot(),moved:!1}}_physicalRotateMove(t){const e=this._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation();const i=this._svgPoint(t),s=180*Math.atan2(i[1]-e.center[1],i[0]-e.center[0])/Math.PI,o=e.baseAngle+s-e.startAngle,n=ra(t.shiftKey?o:5*Math.round(o/5));this._physicalRotate={...e,angle:n,moved:e.moved||Math.abs(o-e.baseAngle)>=.5}}_physicalRotateUp(t){const e=this._physicalRotate;if(!e||e.pid!==t.pointerId)return;if(t.preventDefault(),t.stopPropagation(),this._physicalRotate=null,!e.moved||!this._curSpaceCfg)return;const i=this._spaceModel().wall_columns.find(t=>t.id===e.id);if(!i||"square"!==i.shape)return;const s={...i,angle:e.angle};if(this._spaceModel().wall_columns.some(t=>t.id!==e.id&&ba(t,s,.02*this._gridPitch)))return void this._showToast(this._t("toast.column_duplicate"));const o=this._curSpaceCfg.wall_columns?.find(t=>t.id===e.id);o&&(o.angle=e.angle,this._recordGeometry(this._t("history.physical_edit"),e.before),this._saveConfig())}_rszRooms(){const t=[];for(const e of this._spaceModel().rooms){const i=e.id?Je(e):null;i&&t.push({id:e.id,poly:i})}return t}_rszOpenings(){return this._openingsR.map(t=>({id:t.id,x:t.rx,y:t.ry,length:t.rlen}))}_rszOpts(){return{minDim:this._cmToUnits(30),eps:.05*this._gridPitch}}_rszSnapshot(){return JSON.stringify(this._geometrySnapshot()||{spaceId:this._space,rooms:[],openings:[],walls:[],open_spans:[]})}_rszApplyPreview(t,e){const i=this._rszDrag,s=this._serverCfg?.spaces.find(t=>t.id===this._space);if(!i||!s)return;const o=JSON.parse(i.snap),n={...s,rooms:o.rooms,openings:o.openings,walls:o.walls,open_spans:o.open_spans};Array.isArray(o.open_spans)&&o.open_spans.length||delete n.open_spans;const r=this._spaceH;for(const[e,i]of Object.entries(t)){const t=n.rooms.find(t=>t.id===e);t&&(t.poly=i.map(t=>[t[0]/eh,t[1]/r]),delete t.x,delete t.y,delete t.w,delete t.h)}for(const[t,i]of Object.entries(e)){const e=(n.openings||[]).find(e=>e.id===t);e&&(e.x=i[0]/eh,e.y=i[1]/r)}const a=[],l=[];for(const t of i.changed){const e=i.rooms.find(e=>e.id===t),s=n.rooms.find(e=>e.id===t);if(!e||!s?.poly)continue;const o=s.poly.map(t=>[t[0]*eh,t[1]*r]);if(e.poly.length===o.length)for(let t=0;tt.id===e);if(!s||!s.poly||s.poly.length<3)return null;if(i<0||i>=s.poly.length)return null;const o=[...s.poly[i]],n=[...s.poly[(i+1)%s.poly.length]];return{roomId:e,edge:i,a:o,b:n,n:yn(s.poly,i)}}(s,e,i);o&&(this._rszDrag={kind:"edge",pid:t.pointerId,roomId:e,plan:o,rooms:s,openings:this._rszOpenings(),snap:this._rszSnapshot(),moved:!1,d:0,k:1,changed:[]})}_rszCornerDown(t,e,i,s){"resize"!==this._tool||this._rszDrag||(t.stopPropagation(),t.preventDefault(),lh(t),this._rszDrag={kind:"scale",pid:t.pointerId,roomId:e,fixed:s,span0:Math.hypot(i[0]-s[0],i[1]-s[1])||1,rooms:this._rszRooms(),openings:this._rszOpenings(),snap:this._rszSnapshot(),moved:!1,d:0,k:1,changed:[]})}_rszMove(t){const e=this._rszDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._svgPoint(t);if("edge"===e.kind){const t=e.plan,s=(i[0]-t.a[0])*t.n[0]+(i[1]-t.a[1])*t.n[1],o=this._snap([t.a[0]+t.n[0]*s,t.a[1]+t.n[1]*s]);let n=(o[0]-t.a[0])*t.n[0]+(o[1]-t.a[1])*t.n[1];if(n=function(t,e,i,s,o,n){if(!Number.isFinite(s)||Math.abs(s)<1e-9)return 0;const r=Math.sign(s);let a=Math.abs(s);const l=Math.max(o,1e-6);for(let s=0;s<4096&&a>1e-9;s++,a-=l){const s=r*a;if(Pn(t,e,i,s,n))return s}return 0}(e.rooms,e.openings,t,n,this._gridPitch,this._rszOpts()),n===e.d&&e.moved)return;e.d=n,e.moved=!0;const r=Cn(e.rooms,e.openings,t,n,this._rszOpts().eps);e.changed=Object.keys(r.polys),this._rszApplyPreview(r.polys,r.openings),this._rszLive=this._rszEdgeLabels(r,t)}else{const t=e.fixed,s=this._snap(i);let o=Math.hypot(s[0]-t[0],s[1]-t[1])/(e.span0||1);if(o=Math.max(.05,Math.min(20,o)),o=function(t,e,i,s,o,n){if(!Number.isFinite(o)||o<=0)return 1;if(An(t,e,i,s,o,n))return o;let r=1,a=o;for(let o=0;o<28;o++){const o=(r+a)/2;An(t,e,i,s,o,n)?r=o:a=o}return r}(e.rooms,e.openings,e.roomId,t,o,this._rszOpts()),o===e.k&&e.moved)return;e.k=o,e.moved=!0;const n=e.rooms.find(t=>t.id===e.roomId),r=e.rooms.filter(t=>t.id!==e.roomId).map(t=>t.poly),a=Rn(n,e.openings,r,t,o,2*this._rszOpts().eps);e.changed=[e.roomId],this._rszApplyPreview({[e.roomId]:a.poly},a.openings),this._rszLive=this._rszScaleLabels(a.poly)}this.requestUpdate()}_rszUp(t){const e=this._rszDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const i=this._rszPreview;this._rszDrag=null,this._rszLive=null,this._rszPreview=null;if(!(e.moved&&("edge"===e.kind?Math.abs(e.d)>1e-9:Math.abs(e.k-1)>1e-9))||!i)return this._cfgEpoch++,void this.requestUpdate();const s=JSON.parse(e.snap),o=this._curSpaceCfg;if(o){o.rooms=i.sp.rooms,o.openings=i.sp.openings,Array.isArray(i.sp.walls)&&(i.sp.walls.length?o.walls=i.sp.walls:delete o.walls),Array.isArray(i.sp.open_spans)&&i.sp.open_spans.length?o.open_spans=i.sp.open_spans:delete o.open_spans;for(const t of e.changed){const e=o.rooms.find(e=>e.id===t);e?.poly&&(e.poly=$n(e.poly,1e-9))}this._commitOpenSpans(),Array.isArray(o.walls)&&o.walls.length&&(o.walls=$r(o.walls,o.rooms||[],Aa,1,this._cfgOpenCuts()),o.walls.length||delete o.walls)}this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._recordGeometry(this._t("history.resize_room"),s),this._saveConfig(),this.requestUpdate()}_rszCancelDrag(){this._rszDrag&&(this._rszDrag=null,this._rszLive=null,this._rszPreview=null,this._cfgEpoch++,this.requestUpdate())}_rszPointerCancel(t){const e=this._rszDrag;e&&e.pid===t.pointerId&&(t.stopPropagation(),this._rszCancelDrag())}_rszEdgeLabels(t,e){const i=this._rszDrag,s=[],o=t.polys[e.roomId]||i.rooms.find(t=>t.id===e.roomId).poly,n=o.length,r=e.edge,a=(r+1)%n;for(const[t,e]of[[o[(r-1+n)%n],o[r]],[o[r],o[a]],[o[a],o[(a+1)%n]]])s.push({x:(t[0]+e[0])/2,y:(t[1]+e[1])/2,text:this._fmtLen(t,e)});const l="mi"===this.hass?.config?.unit_system?.length,c=Object.keys(t.polys).length?Object.keys(t.polys):[e.roomId],h=this._spaceWalls,d=this._openPairs().flatMap(t=>t.segs),p=this._physicalBodiesR();for(const e of c){const o=t.polys[e]||i.rooms.find(t=>t.id===e).poly,n=h.length&&jr(Object.entries(t.polys).map(([t,e])=>({id:t,poly:e})),e,h,d,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)||o,r=ci(n),a=p.length?fa(ga(n,p))*Math.pow(this._cellCm/this._gridPitch,2)/1e4:zn(n,this._gridPitch,this._cellCm);s.push({x:r[0],y:r[1],text:In(a,l),area:!0})}return s}_rszScaleLabels(t){const e="mi"===this.hass?.config?.unit_system?.length,i=t.map(t=>t[0]),s=t.map(t=>t[1]),o=Math.max(...i)-Math.min(...i),n=Math.max(...s)-Math.min(...s),r=this._spaceWalls,a=r.length&&this._rszSel&&jr([{id:this._rszSel,poly:t}],this._rszSel,r,[],this._wallKeyPitch,this._cellCm,this._gridPitch,eh)||t,l=ci(a),c=this._physicalBodiesR(),h=c.length?fa(ga(a,c))*Math.pow(this._cellCm/this._gridPitch,2)/1e4:zn(a,this._gridPitch,this._cellCm);return[{x:Math.min(...i),y:Math.min(...s),text:`${this._fmtLen([0,0],[o,0])} × ${this._fmtLen([0,0],[n,0])}`},{x:l[0],y:l[1],text:In(h,e),area:!0}]}_renderResizeLayer(t){const e=Math.max(.013*t.w,5),i=e/2,s=t=>t.toFixed(1),o=`M ${s(-.7*i)} 0 H ${s(.7*i)} M 0 ${s(-.22*i)} V ${s(-i)} M ${s(-.32*i)} ${s(-.6*i)} L 0 ${s(-i)} L ${s(.32*i)} ${s(-.6*i)} M 0 ${s(.22*i)} V ${s(i)} M ${s(-.32*i)} ${s(.6*i)} L 0 ${s(i)} L ${s(.32*i)} ${s(.6*i)}`,n=[],r=this._rszRooms();for(const t of r)for(let i=0;ithis._rszEdgeDown(e,t.id,i)} @pointermove=${t=>this._rszMove(t)} @pointerup=${t=>this._rszUp(t)} @pointercancel=${t=>this._rszPointerCancel(t)} - @lostpointercapture=${t=>this._rszPointerCancel(t)}>`),n.push(B``)}const a=this._rszSel?r.find(t=>t.id===this._rszSel):null;if(a){const t=a.poly.map(t=>t[0]),i=a.poly.map(t=>t[1]),s=Math.min(...t),o=Math.max(...t),r=Math.min(...i),l=Math.max(...i);n.push(B``);for(const[t,i,c,h]of[[s,r,o,l],[o,r,s,l],[o,l,s,r],[s,l,o,r]])n.push(B`this._rszPointerCancel(t)}>`),n.push(j``)}const a=this._rszSel?r.find(t=>t.id===this._rszSel):null;if(a){const t=a.poly.map(t=>t[0]),i=a.poly.map(t=>t[1]),s=Math.min(...t),o=Math.max(...t),r=Math.min(...i),l=Math.max(...i);n.push(j``);for(const[t,i,c,h]of[[s,r,o,l],[o,r,s,l],[o,l,s,r],[s,l,o,r]])n.push(j`this._rszCornerDown(e,a.id,[t,i],[c,h])} @pointermove=${t=>this._rszMove(t)} @pointerup=${t=>this._rszUp(t)} @pointercancel=${t=>this._rszPointerCancel(t)} - @lostpointercapture=${t=>this._rszPointerCancel(t)}>`),n.push(B``)}return B`${n}`}get _openingsR(){const t=this._curSpaceCfg,e=this._spaceH;return(t?.openings||[]).map(t=>({...t,rx:t.x*Nc,ry:t.y*e,rlen:t.length*Nc}))}_cmToUnits(t){return t/this._cellCm*this._gridPitch}get _decorList(){const t=this._curSpaceCfg;return Array.isArray(t?.decor)?t.decor:[]}get _decorH(){return Nc}_decorResolvedStyle(t){return function(t,e,i,s=Hn){const o="rect"===t?.kind||"ellipse"===t?.kind,n=t,r=_t(n?.color,s.color);return{color:r,opacity:qn(n?.opacity,s.opacity),widthCm:Wn(t,e,i,s.widthCm),fill:!!o&&!0===n?.fill,fillColor:_t(n?.fill_color,n?.fill?r:s.fillColor),fillOpacity:o&&n?.fill?qn(n?.fill_opacity,.25):s.fillOpacity}}(t,this._cellCm,this._gridPitch,Hn)}_decorWidthUnits(t){return((t,e,i,s=Hn.widthCm)=>{const o=Number(t?.width_cm);if(Number.isFinite(o)&&o>0)return Bn(o,e,i);const n=Number(t?.width);return Number.isFinite(n)&&n>0?n:Bn(s,e,i)})(t,this._cellCm,this._gridPitch,Hn.widthCm)}_decorTextSizeCm(t){if("text"===t?.kind){const e=Number(t.size_cm);return Number.isFinite(e)&&e>0?e:Gn(Ti*Pi(t),this._cellCm,this._gridPitch)}return Gn(Ti,this._cellCm,this._gridPitch)}_decorTextUnits(t){if("text"!==t.kind)return Ti;const e=Number(t.size_cm);return Number.isFinite(e)&&e>0?Bn(e,this._cellCm,this._gridPitch):Ti*Pi(t)}_decorSmallField(t){return Math.round(100*(this._imperial?t/2.54:t))/100}_decorSmallCm(t){const e=this._imperial?2.54*t:t;return Number.isFinite(e)?Math.max(.1,Math.min(100,e)):.1}_decorTextCm(t){const e=this._imperial?2.54*t:t;return Number.isFinite(e)?Math.max(.1,Math.min(fc,e)):.1}_decorLargeField(t){return Math.round(100*(this._imperial?t/30.48:t/100))/100}_decorLargeCm(t){const e=this._imperial?30.48*t:100*t;return Number.isFinite(e)?Math.max(.1,Math.min(ma*this._cellCm,e)):.1}_angleField(t){const e=Number(t);return Number.isFinite(e)?String(Number(e.toFixed(3))):"0"}_decorBoxOf(t){return"rect"!==t.kind&&"ellipse"!==t.kind&&"furniture"!==t.kind?null:{x:t.x*Nc,y:t.y*this._decorH,w:t.w*Nc,h:t.h*this._decorH,angle:Un(t.angle)||void 0}}_decorSnapGeometry(t){const e=t||"",i=this._decorSnapCache;if(i&&i.epoch===this._cfgEpoch&&i.space===this._space&&i.height===this._decorH&&i.exclude===e)return i.geometry;const s=[];for(const e of this._decorList)if(e.id!==t)if("line"===e.kind){const t=[e.x1*Nc,e.y1*this._decorH],i=[e.x2*Nc,e.y2*this._decorH];s.push({points:[t,i,[(t[0]+i[0])/2,(t[1]+i[1])/2]],segments:[{a:t,b:i}]})}else if("text"===e.kind)s.push({points:[[e.x*Nc,e.y*this._decorH]],segments:[]});else{const t=this._decorBoxOf(e);t&&s.push(Yn(t))}for(const t of this._spaceModel().rooms){const e=Fe(t);e?.length&&s.push({points:e.flatMap((t,i)=>{const s=e[(i+1)%e.length];return[t,[(t[0]+s[0])/2,(t[1]+s[1])/2]]}),segments:e.map((t,i)=>({a:t,b:e[(i+1)%e.length]}))})}const o=function(t){return{points:t.flatMap(t=>t.points),segments:t.flatMap(t=>t.segments)}}(s);return this._decorSnapCache={epoch:this._cfgEpoch,space:this._space,height:this._decorH,exclude:e,geometry:o},o}_decorSnap(t,e="mouse",i){const s=this._stageEl,o=this._viewOr(this._baseVb()),n="touch"===e||"pen"===e?14:8,r=s?o.w/Math.max(1,s.clientWidth)*n:this._gridPitch;return function(t,e,i,s){const o=s(t);let n=null;for(const o of e.points){const e=s(o),r=Math.hypot(e[0]-t[0],e[1]-t[1]);r<=i&&(!n||rthis._snap(t)).point}_replaceDecor(t,e){const i=this._curSpaceCfg;i&&(i.decor=this._decorList.map(i=>i.id===t?{...i,...e}:i),this.requestUpdate())}_cancelDecorGesture(){const t=this._decorMove?.before||this._dtDrag?.before||this._bdDrag?.before,e=t&&this._serverCfg?.spaces.find(e=>e.id===t.spaceId);if(t&&e){const i=t=>JSON.parse(JSON.stringify(t));void 0!==t.decor?e.decor=i(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,i(t.plan_transform||{})),this._cfgEpoch++}this._decorMove=null,this._dtDrag=null,this._bdDrag=null,this.requestUpdate()}_decorPointerDown(t){const e=this._decorTool;if("select"===e||"erase"===e?t.target.closest?.(".dshape"):null)return!0;if("line"===e||"rect"===e||"ellipse"===e){t.preventDefault();const i=this._decorSnap(this._svgPoint(t),t.pointerType);return this._decorDraft={kind:e,a:i,b:i,pid:t.pointerId},Uc(t),!0}if("text"===e){const e=this._decorSnap(this._svgPoint(t),t.pointerType);return this._decorTextDialog={x:$a(e[0]/Nc),y:$a(e[1]/this._decorH),text:"",color:this._decorStyle.color,opacity:this._decorStyle.opacity,angle:"0",sizeCm:Gn(Ti,this._cellCm,this._gridPitch)},this._decorTextSelection={start:0,end:0},!0}if("furniture"===e)return!!this._furnPalette&&(t.preventDefault(),this._furnPlace(this._svgPoint(t),t.shiftKey),!0);if("select"===e&&(this._decorSel=null),this._bdMovable){const e=this._bdRect,i=this._svgPoint(t),s=e.x+e.w/2,o=e.y+e.h/2,n=-Un(e.angle)*Math.PI/180,r=i[0]-s,a=i[1]-o,l=[s+r*Math.cos(n)-a*Math.sin(n),o+r*Math.sin(n)+a*Math.cos(n)];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._decorDraft;if(this._decorDraft=null,!t)return;const e=.5*this._gridPitch;if(!function(t,e,i,s){const o=Math.abs(i[0]-e[0]),n=Math.abs(i[1]-e[1]);return"line"===t?Math.hypot(o,n)>=s:o>=s&&n>=s}(t.kind,t.a,t.b,e))return;const i=Nc,s=this._decorH,o=this._decorStyle,n=this._geometrySnapshot(),r="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),a=$a;let l;if("line"===t.kind)l={id:r,kind:"line",x1:a(t.a[0]/i),y1:a(t.a[1]/s),x2:a(t.b[0]/i),y2:a(t.b[1]/s),...Vn(o,!1)};else{const e=a(Math.min(t.a[0],t.b[0])/i),n=a(Math.min(t.a[1],t.b[1])/s),c=Math.abs(t.b[0]-t.a[0])/i,h=Math.abs(t.b[1]-t.a[1])/s;l={id:r,kind:t.kind,x:e,y:n,w:c,h:h,...Vn(o,!0)}}this._curSpaceCfg.decor=[...this._decorList,l],this._decorSel=r,this._recordGeometry(this._t("history.decor_add"),n),this._saveConfig(),this.requestUpdate()}_decorShapeDown(t,e){if("decor"!==this._mode)return;const i=this._decorTool;if("text"===i){if("text"!==e.kind)return;return t.stopPropagation(),t.preventDefault(),void this._decorOpenText(e)}"select"!==i&&"erase"!==i||(t.stopPropagation(),t.preventDefault(),"erase"!==i?(this._decorSel=e.id,this._decorMove={id:e.id,start:this._svgPoint(t),orig:JSON.parse(JSON.stringify(e)),pid:t.pointerId,moved:!1,before:this._geometrySnapshot()},Uc(t)):this._decorEraseConfirm={id:e.id,kind:e.kind})}_decorMoveUpdate(t){const e=this._decorMove;if("furniture"===e.orig?.kind)return void this._furnMoveUpdate(t);const i=this._svgPoint(t),s=e.orig,o=("line"===s.kind?s.x1:s.x)*Nc,n=("line"===s.kind?s.y1:s.y)*this._decorH,r=this._decorSnap([o+(i[0]-e.start[0]),n+(i[1]-e.start[1])],t.pointerType,e.id);let a=(r[0]-o)/Nc,l=(r[1]-n)/this._decorH;const c=e.orig,h="line"===c.kind?Math.min(c.x1,c.x2):c.x,d="line"===c.kind?Math.min(c.y1,c.y2):c.y,p="line"===c.kind?Math.abs(c.x2-c.x1):c.w||0,u="line"===c.kind?Math.abs(c.y2-c.y1):c.h||0,_=ma;a=Math.max(-_-h,Math.min(_-h-p,a)),l=Math.max(-_-d,Math.min(_-d-u,l)),(a||l)&&(e.moved=!0);this._curSpaceCfg.decor=this._decorList.map(t=>{if(t.id!==e.id)return t;const i=e.orig;return"line"===t.kind?{...t,x1:i.x1+a,y1:i.y1+l,x2:i.x2+a,y2:i.y2+l}:{...t,x:i.x+a,y:i.y+l}}),this.requestUpdate()}_decorShapeDbl(t,e){"decor"===this._mode&&"select"===this._decorTool&&(t.preventDefault(),t.stopPropagation(),this._decorMove=null,this._decorSel=e.id,this._openDecorProperties(e))}_openDecorProperties(t){if("decor"!==this._mode||"select"!==this._decorTool)return;if("text"===t.kind)return void this._decorOpenText(t);if(!["line","rect","ellipse","furniture"].includes(t.kind))return;const e=this._decorResolvedStyle(t),i="line"===t.kind?t:null,s=this._decorBoxOf(t);this._decorShapeDialog={id:t.id,kind:t.kind,color:e.color,opacity:e.opacity,widthCm:e.widthCm,angle:this._angleField(Un(i?_s([i.x1*Nc,i.y1*this._decorH],[i.x2*Nc,i.y2*this._decorH]):t.angle)),...i?{lengthCm:Gn(Math.hypot((i.x2-i.x1)*Nc,(i.y2-i.y1)*this._decorH),this._cellCm,this._gridPitch),lineStyle:"dashed"===i.line_style?"dashed":"solid"}:{},...s?{sizeWCm:Gn(s.w,this._cellCm,this._gridPitch),sizeHCm:Gn(s.h,this._cellCm,this._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 i=[...e.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!xi(t[1])),s=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||s?"":Si(t.entity,o),r=!(!String(t.entity??"").trim()||i||n&&!s);if(n&&!r){const t=e.indexOf("{}");e=t>=0?e.slice(0,t)+n+e.slice(t+2):`${e}${e?" ":""}${n}`}this._decorTextDialog={id:t.id,x:t.x,y:t.y,text:e,color:_t(t.color,this._decorStyle.color),opacity:qn(t.opacity,this._decorStyle.opacity),angle:this._angleField(t.angle),sizeCm:this._decorTextSizeCm(t),pickerEntity:t.entity||"",preserveLegacy:r||void 0},this._decorTextSelection={start:e.length,end:e.length}}_decorRememberTextSelection(t){this._decorTextSelection={start:t.selectionStart??t.value.length,end:t.selectionEnd??t.value.length}}_decorInsertLiveVariable(t){const e=this._decorTextDialog;if(!e)return;const i=Si(e.pickerEntity,t);if(!i)return;const s=e.text,o=Math.max(0,Math.min(s.length,this._decorTextSelection.start)),n=Math.max(o,Math.min(s.length,this._decorTextSelection.end));if(s.length-(n-o)+i.length>200)return;const r=s.slice(0,o)+i+s.slice(n),a=o+i.length;this._decorTextSelection={start:a,end:a},this._decorTextDialog={...e,text:r,preserveLegacy:void 0},this.updateComplete.then(()=>{const t=this.renderRoot.querySelector("textarea.dtarea");t&&(t.focus(),t.setSelectionRange(a,a))})}_decorSaveText(){const t=this._decorTextDialog,e=String(t?.text??"").replace(/\r\n?/g,"\n").trim();if(!t||!e)return void(this._decorTextDialog=null);const i=this._geometrySnapshot(),s=this._curSpaceCfg,o={color:t.color,opacity:qn(t.opacity),size_cm:Number(Math.max(.1,Math.min(fc,t.sizeCm)).toFixed(4)),...Un(t.angle)?{angle:Un(t.angle)}:{}};if(t.id)s.decor=this._decorList.map(i=>{if(i.id!==t.id)return i;if("text"!==i.kind)return i;if(t.preserveLegacy){const{angle:t,size:s,scale:n,...r}=i;return{...r,text:e,...o}}const{entity:s,attr:n,unit:r,...a}=i,{angle:l,size:c,scale:h,...d}=a;return{...d,text:e,...o}});else{const i="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5);s.decor=[...this._decorList,{id:i,kind:"text",x:t.x,y:t.y,text:e,...o}],this._decorSel=i}this._decorTextDialog=null,this._recordGeometry(this._t(t.id?"history.decor_edit":"history.decor_add"),i),this._saveConfig(),this.requestUpdate()}_decorSaveShape(){const t=this._decorShapeDialog;if(!t)return;const e=this._geometrySnapshot(),i={color:t.color,opacity:qn(t.opacity),widthCm:Math.max(.1,Math.min(100,Number(t.widthCm)||.1)),fill:!!t.fill,fillColor:t.fillColor||t.color,fillOpacity:qn(t.fillOpacity,.25)};this._curSpaceCfg.decor=this._decorList.map(e=>{if(e.id!==t.id)return e;const s="rect"===t.kind||"ellipse"===t.kind,o=Vn(i,s);if("line"===e.kind){const i=(e.x1+e.x2)/2*Nc,s=(e.y1+e.y2)/2*this._decorH,n=Bn(Math.max(.1,Number(t.lengthCm)||.1),this._cellCm,this._gridPitch),r=Un(t.angle)*Math.PI/180,a=Math.cos(r)*n/2,l=Math.sin(r)*n/2,c=this._snap([i-a,s-l]),h=this._snap([i+a,s+l]),{width:d,line_style:p,...u}=e;return{...u,...o,x1:$a(c[0]/Nc),y1:$a(c[1]/this._decorH),x2:$a(h[0]/Nc),y2:$a(h[1]/this._decorH),..."dashed"===t.lineStyle?{line_style:"dashed"}:{}}}if("rect"===e.kind||"ellipse"===e.kind||"furniture"===e.kind){const i=e.w*Nc,s=e.h*this._decorH,n=Math.max(this._gridPitch,Ie(Bn(Number(t.sizeWCm),this._cellCm,this._gridPitch),this._gridPitch)),r=Math.max(this._gridPitch,Ie(Bn(Number(t.sizeHCm),this._cellCm,this._gridPitch),this._gridPitch)),a=e.x*Nc+i/2,l=e.y*this._decorH+s/2,c=Un(t.angle),h=jn({x:a-n/2,y:l-r/2},c,t=>this._snap(t)),{width:d,angle:p,...u}=e;return{...u,...o,x:$a(h[0]/Nc),y:$a(h[1]/this._decorH),w:n/Nc,h:r/this._decorH,..."furniture"===e.kind&&t.symbol?{symbol:t.symbol}:{},...c?{angle:c}:{}}}return e}),this._decorStyle={...i,fill:"rect"===t.kind||"ellipse"===t.kind?i.fill:this._decorStyle.fill,fillColor:"rect"===t.kind||"ellipse"===t.kind?i.fillColor:this._decorStyle.fillColor,fillOpacity:"rect"===t.kind||"ellipse"===t.kind?i.fillOpacity:this._decorStyle.fillOpacity},this._decorShapeDialog=null,this._recordGeometry(this._t("history.decor_edit"),e),this._saveConfig(),this.requestUpdate()}get _dtSel(){return"decor"===this._mode&&"select"===this._decorTool&&this._decorSel&&this._decorList.find(t=>t.id===this._decorSel)||null}_dtPivot(t){return"line"===t.kind?[(t.x1+t.x2)/2*Nc,(t.y1+t.y2)/2*this._decorH]:"furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind?[(t.x+t.w/2)*Nc,(t.y+t.h/2)*this._decorH]:[t.x*Nc,t.y*this._decorH]}_dtApply(t,e){const i=this._curSpaceCfg;i&&(i.decor=this._decorList.map(i=>{if(i.id!==t)return i;const s={...i};"text"===i.kind&&void 0!==e.textSizeCm&&(delete s.size,delete s.scale);const o={...s};return void 0!==e.textSizeCm&&(o.size_cm=Number(Math.max(.1,Math.min(fc,e.textSizeCm)).toFixed(4))),void 0!==e.angle&&(e.angle?o.angle=Number(e.angle.toFixed(2)):delete o.angle),o}),this._cfgEpoch++,this.requestUpdate())}_dtStart(t,e,i,s){const o=this._dtSel;if(!o)return;t.stopPropagation(),t.preventDefault();const[n,r]=this._dtPivot(o),a=this._svgPoint(t),l=this._decorBoxOf(o);this._dtDrag={id:o.id,kind:e,pid:t.pointerId,ax:n,ay:r,r0:Math.hypot(a[0]-n,a[1]-r),a0:180*Math.atan2(a[1]-r,a[0]-n)/Math.PI,textSizeCm0:"text"===o.kind?this._decorTextSizeCm(o):1,angle0:"line"===o.kind?0:Number(o.angle)||0,sgx:i?.[0],sgy:i?.[1],orig:l||void 0,origShape:JSON.parse(JSON.stringify(o)),before:this._geometrySnapshot(),lineEnd:s,moved:!1},Uc(t)}_dtMove(t){const e=this._dtDrag;if(!e)return;const i=this._svgPoint(t);if(void 0!==e.lineEnd&&"line"===e.origShape.kind){const s=this._decorSnap(i,t.pointerType,e.id),o=$a(s[0]/Nc),n=$a(s[1]/this._decorH),r=e.origShape,a=0===e.lineEnd?r.x1:r.x2,l=0===e.lineEnd?r.y1:r.y2;return(Math.abs(o-a)>1e-9||Math.abs(n-l)>1e-9)&&(e.moved=!0),void this._replaceDecor(e.id,0===e.lineEnd?{x1:o,y1:n}:{x2:o,y2:n})}if("scale"===e.kind&&e.orig){const s=Jn(e.orig,e.sgx??1,e.sgy??1,i[0],i[1],!t.shiftKey,this._gridPitch,this._gridPitch),o=Math.abs(s.x-e.orig.x)>1e-6||Math.abs(s.y-e.orig.y)>1e-6||Math.abs(s.w-e.orig.w)>1e-6||Math.abs(s.h-e.orig.h)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._decorApplyBox(e.id,s)}if("scale"===e.kind){const t=Math.hypot(i[0]-e.ax,i[1]-e.ay);if(e.r0<1e-6)return;const s=Math.max(.1,Math.min(fc,e.textSizeCm0*(t/e.r0))),o=Math.abs(s-e.textSizeCm0)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._dtApply(e.id,{textSizeCm:s})}const s=180*Math.atan2(i[1]-e.ay,i[0]-e.ax)/Math.PI;let o=e.angle0+(s-e.a0);t.shiftKey||(o=5*Math.round(o/5)),o=(o%360+360)%360,o>180&&(o-=360);const n=Math.abs(o-e.angle0)>1e-6;(n||e.moved)&&(e.moved||=n,this._dtApply(e.id,{angle:o}))}_dtUp(){const t=this._dtDrag;this._dtDrag=null,t?.moved&&(this._recordGeometry(this._t("history.decor_transform"),t.before),this._saveConfig()),this.requestUpdate()}_dtMeasure(){const t=this._dtSel;if(!t)return void(this._dtBox&&(this._dtBox=null,this.requestUpdate()));let e;if("line"===t.kind){const i=t.x1*Nc,s=t.y1*this._decorH,o=t.x2*Nc,n=t.y2*this._decorH;e={id:t.id,x:Math.min(i,o),y:Math.min(s,n),w:Math.abs(o-i),h:Math.abs(n-s)}}else if("furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind)e={id:t.id,x:t.x*Nc,y:t.y*this._decorH,w:t.w*Nc,h:t.h*this._decorH};else{const i=this.renderRoot.querySelector(`text.dtext[data-id="${t.id}"]`);if(!i||"function"!=typeof i.getBBox)return;let s;try{s=i.getBBox()}catch{return}if(!s||!s.width&&!s.height)return;e={id:t.id,x:s.x,y:s.y,w:s.width,h:s.height}}const i=this._dtBox;i&&i.id===e.id&&Math.abs(i.x-e.x)<.01&&Math.abs(i.y-e.y)<.01&&Math.abs(i.w-e.w)<.01&&Math.abs(i.h-e.h)<.01||(this._dtBox=e,this.requestUpdate())}_deleteDecor(t){if(!this._decorList.some(e=>e.id===t))return;const e=this._geometrySnapshot();this._curSpaceCfg.decor=this._decorList.filter(e=>e.id!==t),this._decorSel===t&&(this._decorSel=null),this._recordGeometry(this._t("history.decor_delete"),e),this._saveConfig(),this.requestUpdate()}_decorDeleteSel(){this._decorSel&&this._deleteDecor(this._decorSel)}_confirmDecorErase(){const t=this._decorEraseConfirm;this._decorEraseConfirm=null,t&&this._deleteDecor(t.id)}get _furnWalls(){const t=this._physicalBodiesR().flatMap(t=>t.map((e,i)=>{const s=t[(i+1)%t.length];return[e[0],e[1],s[0],s[1]]}));return[...this._segments,...t]}get _furnWallReach(){return 6*this._gridPitch}_furnFieldValue(t){return Math.round(100*(this._imperial?t/30.48:t/100))/100}_furnFieldToCm(t){return e=this._imperial?30.48*t:100*t,Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1;var e}_furnPick(t){const e=function(t){const e=ja(t);return e?{w:e.w,h:e.h}:{w:60,h:60}}(t);this._furnPalette={symbol:t,w:e.w,h:e.h}}_furnPlace(t,e=!1){const i=this._furnPalette,s=this._curSpaceCfg;if(!i||!s)return;const o=Nc,n=this._decorH,r=Ka(Ga(i.w,this._cellCm,this._gridPitch,o)),a=Ka(Ga(i.h,this._cellCm,this._gridPitch,o)),l=this._geometrySnapshot(),c=this._decorSnap(t);let h=c[0],d=c[1],p=0;const u=e?null:Xa(h,d,a*n,this._furnWalls,this._furnWallReach,this._gridPitch);u&&(h=u.cx,d=u.cy,p=u.angle);const _="df"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),m={id:_,kind:"furniture",symbol:i.symbol,x:$a(h/o-r/2),y:$a(d/n-a/2),w:r,h:a,...Vn(this._decorStyle,!1)};p&&(m.angle=Number(p.toFixed(2))),s.decor=[...this._decorList,m],this._decorSel=_,this._decorTool="select",this._furnPalette=null,this._recordGeometry(this._t("history.decor_add"),l),this._saveConfig(),this.requestUpdate()}_furnMoveUpdate(t){const e=this._decorMove;if("furniture"!==e.orig.kind)return;const i=e.orig,s=this._curSpaceCfg;if(!s)return;const o=Nc,n=this._decorH,r=this._svgPoint(t),a=(i.x+i.w/2)*o+(r[0]-e.start[0]),l=(i.y+i.h/2)*n+(r[1]-e.start[1]);let c,h,d=Number(i.angle)||0;const p=t.shiftKey?null:Xa(a,l,i.h*n,this._furnWalls,this._furnWallReach,this._gridPitch);if(p)c=p.cx/o-i.w/2,h=p.cy/n-i.h/2,d=p.angle;else{const s=this._decorSnap([a-i.w/2*o,l-i.h/2*n],t.pointerType,e.id);c=s[0]/o,h=s[1]/n}c=$a(c),h=$a(h),(Math.abs(c-i.x)>1e-9||Math.abs(h-i.y)>1e-9||Math.abs(d-(Number(i.angle)||0))>1e-9)&&(e.moved=!0),s.decor=this._decorList.map(t=>{if(t.id!==e.id)return t;const i={...t,x:c,y:h};return d?i.angle=Number(d.toFixed(2)):delete i.angle,i}),this.requestUpdate()}_decorApplyBox(t,e){const i=this._curSpaceCfg;if(!i)return;const s=Nc,o=this._decorH;i.decor=this._decorList.map(i=>{if(i.id!==t)return i;const n=jn(e,i.angle,t=>this._snap(t));return{...i,x:$a(n[0]/s),y:$a(n[1]/o),w:Math.max(this._gridPitch/s,Math.min(2*ma,e.w/s)),h:Math.max(this._gridPitch/o,Math.min(2*ma,e.h/o))}}),this._cfgEpoch++,this.requestUpdate()}get _furnLive(){const t=this._dtDrag;if(!t||"scale"!==t.kind||!t.orig)return null;const e=this._decorList.find(e=>e.id===t.id);if(!e||"furniture"!==e.kind)return null;const i=Nc,s=this._decorH,o=e.w*i,n=e.h*s,r=function(t,e,i,s,o){const n=t+i/2,r=e+s/2,a=(Number(o)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(t,e)=>{const i=t-n,s=e-r;return[n+i*l-s*c,r+i*c+s*l]};return[h(t,e),h(t+i,e),h(t+i,e+s),h(t,e+s)]}(e.x*i,e.y*s,o,n,Number(e.angle)||0),a=(t,e)=>[(t[0]+e[0])/2,(t[1]+e[1])/2],l=a(r[0],r[1]),c=a(r[0],r[3]);return[{x:l[0],y:l[1],text:this._fmtLen([0,0],[o,0])},{x:c[0],y:c[1],text:this._fmtLen([0,0],[0,n])}]}_renderFurnPalette(){const t=this._furnPalette,e=this._t(this._imperial?"gs.unit_ft":"gs.unit_m");return j`
t.stopPropagation()}> + @lostpointercapture=${t=>this._rszPointerCancel(t)}>`),n.push(j``)}return j`${n}`}get _openingsR(){const t=this._curSpaceCfg,e=this._spaceH;return(t?.openings||[]).map(t=>({...t,rx:t.x*eh,ry:t.y*e,rlen:t.length*eh}))}_cmToUnits(t){return t/this._cellCm*this._gridPitch}get _decorList(){const t=this._curSpaceCfg;return Array.isArray(t?.decor)?t.decor:[]}get _decorH(){return eh}_decorResolvedStyle(t){return function(t,e,i,s=Yn){const o="rect"===t?.kind||"ellipse"===t?.kind,n=t,r=Ct(n?.color,s.color);return{color:r,opacity:Jn(n?.opacity,s.opacity),widthCm:er(t,e,i,s.widthCm),fill:!!o&&!0===n?.fill,fillColor:Ct(n?.fill_color,n?.fill?r:s.fillColor),fillOpacity:o&&n?.fill?Jn(n?.fill_opacity,.25):s.fillOpacity}}(t,this._cellCm,this._gridPitch,Yn)}_decorWidthUnits(t){return((t,e,i,s=Yn.widthCm)=>{const o=Number(t?.width_cm);if(Number.isFinite(o)&&o>0)return Qn(o,e,i);const n=Number(t?.width);return Number.isFinite(n)&&n>0?n:Qn(s,e,i)})(t,this._cellCm,this._gridPitch,Yn.widthCm)}_decorTextSizeCm(t){if("text"===t?.kind){const e=Number(t.size_cm);return Number.isFinite(e)&&e>0?e:tr(qi*Ui(t),this._cellCm,this._gridPitch)}return tr(qi,this._cellCm,this._gridPitch)}_decorTextUnits(t){if("text"!==t.kind)return qi;const e=Number(t.size_cm);return Number.isFinite(e)&&e>0?Qn(e,this._cellCm,this._gridPitch):qi*Ui(t)}_decorSmallField(t){return Math.round(100*(this._imperial?t/2.54:t))/100}_decorSmallCm(t){const e=this._imperial?2.54*t:t;return Number.isFinite(e)?Math.max(.1,Math.min(100,e)):.1}_decorTextCm(t){const e=this._imperial?2.54*t:t;return Number.isFinite(e)?Math.max(.1,Math.min(Nc,e)):.1}_decorLargeField(t){return Math.round(100*(this._imperial?t/30.48:t/100))/100}_decorLargeCm(t){const e=this._imperial?30.48*t:100*t;return Number.isFinite(e)?Math.max(.1,Math.min(Da*this._cellCm,e)):.1}_angleField(t){const e=Number(t);return Number.isFinite(e)?String(Number(e.toFixed(3))):"0"}_decorBoxOf(t){return"rect"!==t.kind&&"ellipse"!==t.kind&&"furniture"!==t.kind?null:{x:t.x*eh,y:t.y*this._decorH,w:t.w*eh,h:t.h*this._decorH,angle:Zn(t.angle)||void 0}}_decorSnapGeometry(t){const e=t||"",i=this._decorSnapCache;if(i&&i.epoch===this._cfgEpoch&&i.space===this._space&&i.height===this._decorH&&i.exclude===e)return i.geometry;const s=[];for(const e of this._decorList)if(e.id!==t)if("line"===e.kind){const t=[e.x1*eh,e.y1*this._decorH],i=[e.x2*eh,e.y2*this._decorH];s.push({points:[t,i,[(t[0]+i[0])/2,(t[1]+i[1])/2]],segments:[{a:t,b:i}]})}else if("text"===e.kind)s.push({points:[[e.x*eh,e.y*this._decorH]],segments:[]});else{const t=this._decorBoxOf(e);t&&s.push(or(t))}for(const t of this._spaceModel().rooms){const e=Je(t);e?.length&&s.push({points:e.flatMap((t,i)=>{const s=e[(i+1)%e.length];return[t,[(t[0]+s[0])/2,(t[1]+s[1])/2]]}),segments:e.map((t,i)=>({a:t,b:e[(i+1)%e.length]}))})}const o=function(t){return{points:t.flatMap(t=>t.points),segments:t.flatMap(t=>t.segments)}}(s);return this._decorSnapCache={epoch:this._cfgEpoch,space:this._space,height:this._decorH,exclude:e,geometry:o},o}_decorSnap(t,e="mouse",i){const s=this._stageEl,o=this._viewOr(this._baseVb()),n="touch"===e||"pen"===e?14:8,r=s?o.w/Math.max(1,s.clientWidth)*n:this._gridPitch;return function(t,e,i,s){const o=s(t);let n=null;for(const o of e.points){const e=s(o),r=Math.hypot(e[0]-t[0],e[1]-t[1]);r<=i&&(!n||rthis._snap(t)).point}_replaceDecor(t,e){const i=this._curSpaceCfg;i&&(i.decor=this._decorList.map(i=>i.id===t?{...i,...e}:i),this.requestUpdate())}_cancelDecorGesture(){const t=this._decorMove?.before||this._dtDrag?.before||this._bdDrag?.before,e=t&&this._serverCfg?.spaces.find(e=>e.id===t.spaceId);if(t&&e){const i=t=>JSON.parse(JSON.stringify(t));void 0!==t.decor?e.decor=i(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,i(t.plan_transform||{})),this._cfgEpoch++}this._decorMove=null,this._dtDrag=null,this._bdDrag=null,this.requestUpdate()}_decorPointerDown(t){const e=this._decorTool;if("select"===e||"erase"===e?t.target.closest?.(".dshape"):null)return!0;if("line"===e||"rect"===e||"ellipse"===e){t.preventDefault();const i=this._decorSnap(this._svgPoint(t),t.pointerType);return this._decorDraft={kind:e,a:i,b:i,pid:t.pointerId},lh(t),!0}if("text"===e){const e=this._decorSnap(this._svgPoint(t),t.pointerType);return this._decorTextDialog={x:Na(e[0]/eh),y:Na(e[1]/this._decorH),text:"",color:this._decorStyle.color,opacity:this._decorStyle.opacity,angle:"0",sizeCm:tr(qi,this._cellCm,this._gridPitch)},this._decorTextSelection={start:0,end:0},!0}if("furniture"===e)return!!this._furnPalette&&(t.preventDefault(),this._furnPlace(this._svgPoint(t),t.shiftKey),!0);if("select"===e&&(this._decorSel=null),this._bdMovable){const e=this._bdRect,i=this._svgPoint(t),s=e.x+e.w/2,o=e.y+e.h/2,n=-Zn(e.angle)*Math.PI/180,r=i[0]-s,a=i[1]-o,l=[s+r*Math.cos(n)-a*Math.sin(n),o+r*Math.sin(n)+a*Math.cos(n)];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._decorDraft;if(this._decorDraft=null,!t)return;const e=.5*this._gridPitch;if(!function(t,e,i,s){const o=Math.abs(i[0]-e[0]),n=Math.abs(i[1]-e[1]);return"line"===t?Math.hypot(o,n)>=s:o>=s&&n>=s}(t.kind,t.a,t.b,e))return;const i=eh,s=this._decorH,o=this._decorStyle,n=this._geometrySnapshot(),r="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),a=Na;let l;if("line"===t.kind)l={id:r,kind:"line",x1:a(t.a[0]/i),y1:a(t.a[1]/s),x2:a(t.b[0]/i),y2:a(t.b[1]/s),...ir(o,!1)};else{const e=a(Math.min(t.a[0],t.b[0])/i),n=a(Math.min(t.a[1],t.b[1])/s),c=Math.abs(t.b[0]-t.a[0])/i,h=Math.abs(t.b[1]-t.a[1])/s;l={id:r,kind:t.kind,x:e,y:n,w:c,h:h,...ir(o,!0)}}this._curSpaceCfg.decor=[...this._decorList,l],this._decorSel=r,this._recordGeometry(this._t("history.decor_add"),n),this._saveConfig(),this.requestUpdate()}_decorShapeDown(t,e){if("decor"!==this._mode)return;const i=this._decorTool;if("text"===i){if("text"!==e.kind)return;return t.stopPropagation(),t.preventDefault(),void this._decorOpenText(e)}"select"!==i&&"erase"!==i||(t.stopPropagation(),t.preventDefault(),"erase"!==i?(this._decorSel=e.id,this._decorMove={id:e.id,start:this._svgPoint(t),orig:JSON.parse(JSON.stringify(e)),pid:t.pointerId,moved:!1,before:this._geometrySnapshot()},lh(t)):this._decorEraseConfirm={id:e.id,kind:e.kind})}_decorMoveUpdate(t){const e=this._decorMove;if("furniture"===e.orig?.kind)return void this._furnMoveUpdate(t);const i=this._svgPoint(t),s=e.orig,o=("line"===s.kind?s.x1:s.x)*eh,n=("line"===s.kind?s.y1:s.y)*this._decorH,r=this._decorSnap([o+(i[0]-e.start[0]),n+(i[1]-e.start[1])],t.pointerType,e.id);let a=(r[0]-o)/eh,l=(r[1]-n)/this._decorH;const c=e.orig,h="line"===c.kind?Math.min(c.x1,c.x2):c.x,d="line"===c.kind?Math.min(c.y1,c.y2):c.y,p="line"===c.kind?Math.abs(c.x2-c.x1):c.w||0,u="line"===c.kind?Math.abs(c.y2-c.y1):c.h||0,_=Da;a=Math.max(-_-h,Math.min(_-h-p,a)),l=Math.max(-_-d,Math.min(_-d-u,l)),(a||l)&&(e.moved=!0);this._curSpaceCfg.decor=this._decorList.map(t=>{if(t.id!==e.id)return t;const i=e.orig;return"line"===t.kind?{...t,x1:i.x1+a,y1:i.y1+l,x2:i.x2+a,y2:i.y2+l}:{...t,x:i.x+a,y:i.y+l}}),this.requestUpdate()}_decorShapeDbl(t,e){"decor"===this._mode&&"select"===this._decorTool&&(t.preventDefault(),t.stopPropagation(),this._decorMove=null,this._decorSel=e.id,this._openDecorProperties(e))}_openDecorProperties(t){if("decor"!==this._mode||"select"!==this._decorTool)return;if("text"===t.kind)return void this._decorOpenText(t);if(!["line","rect","ellipse","furniture"].includes(t.kind))return;const e=this._decorResolvedStyle(t),i="line"===t.kind?t:null,s=this._decorBoxOf(t);this._decorShapeDialog={id:t.id,kind:t.kind,color:e.color,opacity:e.opacity,widthCm:e.widthCm,angle:this._angleField(Zn(i?$s([i.x1*eh,i.y1*this._decorH],[i.x2*eh,i.y2*this._decorH]):t.angle)),...i?{lengthCm:tr(Math.hypot((i.x2-i.x1)*eh,(i.y2-i.y1)*this._decorH),this._cellCm,this._gridPitch),lineStyle:"dashed"===i.line_style?"dashed":"solid"}:{},...s?{sizeWCm:tr(s.w,this._cellCm,this._gridPitch),sizeHCm:tr(s.h,this._cellCm,this._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 i=[...e.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!Ni(t[1])),s=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||s?"":Fi(t.entity,o),r=!(!String(t.entity??"").trim()||i||n&&!s);if(n&&!r){const t=e.indexOf("{}");e=t>=0?e.slice(0,t)+n+e.slice(t+2):`${e}${e?" ":""}${n}`}this._decorTextDialog={id:t.id,x:t.x,y:t.y,text:e,color:Ct(t.color,this._decorStyle.color),opacity:Jn(t.opacity,this._decorStyle.opacity),angle:this._angleField(t.angle),sizeCm:this._decorTextSizeCm(t),pickerEntity:t.entity||"",preserveLegacy:r||void 0},this._decorTextSelection={start:e.length,end:e.length}}_decorRememberTextSelection(t){this._decorTextSelection={start:t.selectionStart??t.value.length,end:t.selectionEnd??t.value.length}}_decorInsertLiveVariable(t){const e=this._decorTextDialog;if(!e)return;const i=Fi(e.pickerEntity,t);if(!i)return;const s=e.text,o=Math.max(0,Math.min(s.length,this._decorTextSelection.start)),n=Math.max(o,Math.min(s.length,this._decorTextSelection.end));if(s.length-(n-o)+i.length>200)return;const r=s.slice(0,o)+i+s.slice(n),a=o+i.length;this._decorTextSelection={start:a,end:a},this._decorTextDialog={...e,text:r,preserveLegacy:void 0},this.updateComplete.then(()=>{const t=this.renderRoot.querySelector("textarea.dtarea");t&&(t.focus(),t.setSelectionRange(a,a))})}_decorSaveText(){const t=this._decorTextDialog,e=String(t?.text??"").replace(/\r\n?/g,"\n").trim();if(!t||!e)return void(this._decorTextDialog=null);const i=this._geometrySnapshot(),s=this._curSpaceCfg,o={color:t.color,opacity:Jn(t.opacity),size_cm:Number(Math.max(.1,Math.min(Nc,t.sizeCm)).toFixed(4)),...Zn(t.angle)?{angle:Zn(t.angle)}:{}};if(t.id)s.decor=this._decorList.map(i=>{if(i.id!==t.id)return i;if("text"!==i.kind)return i;if(t.preserveLegacy){const{angle:t,size:s,scale:n,...r}=i;return{...r,text:e,...o}}const{entity:s,attr:n,unit:r,...a}=i,{angle:l,size:c,scale:h,...d}=a;return{...d,text:e,...o}});else{const i="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5);s.decor=[...this._decorList,{id:i,kind:"text",x:t.x,y:t.y,text:e,...o}],this._decorSel=i}this._decorTextDialog=null,this._recordGeometry(this._t(t.id?"history.decor_edit":"history.decor_add"),i),this._saveConfig(),this.requestUpdate()}_decorSaveShape(){const t=this._decorShapeDialog;if(!t)return;const e=this._geometrySnapshot(),i={color:t.color,opacity:Jn(t.opacity),widthCm:Math.max(.1,Math.min(100,Number(t.widthCm)||.1)),fill:!!t.fill,fillColor:t.fillColor||t.color,fillOpacity:Jn(t.fillOpacity,.25)};this._curSpaceCfg.decor=this._decorList.map(e=>{if(e.id!==t.id)return e;const s="rect"===t.kind||"ellipse"===t.kind,o=ir(i,s);if("line"===e.kind){const i=(e.x1+e.x2)/2*eh,s=(e.y1+e.y2)/2*this._decorH,n=Qn(Math.max(.1,Number(t.lengthCm)||.1),this._cellCm,this._gridPitch),r=Zn(t.angle)*Math.PI/180,a=Math.cos(r)*n/2,l=Math.sin(r)*n/2,c=this._snap([i-a,s-l]),h=this._snap([i+a,s+l]),{width:d,line_style:p,...u}=e;return{...u,...o,x1:Na(c[0]/eh),y1:Na(c[1]/this._decorH),x2:Na(h[0]/eh),y2:Na(h[1]/this._decorH),..."dashed"===t.lineStyle?{line_style:"dashed"}:{}}}if("rect"===e.kind||"ellipse"===e.kind||"furniture"===e.kind){const i=e.w*eh,s=e.h*this._decorH,n=Math.max(this._gridPitch,Ve(Qn(Number(t.sizeWCm),this._cellCm,this._gridPitch),this._gridPitch)),r=Math.max(this._gridPitch,Ve(Qn(Number(t.sizeHCm),this._cellCm,this._gridPitch),this._gridPitch)),a=e.x*eh+i/2,l=e.y*this._decorH+s/2,c=Zn(t.angle),h=Xn({x:a-n/2,y:l-r/2},c,t=>this._snap(t)),{width:d,angle:p,...u}=e;return{...u,...o,x:Na(h[0]/eh),y:Na(h[1]/this._decorH),w:n/eh,h:r/this._decorH,..."furniture"===e.kind&&t.symbol?{symbol:t.symbol}:{},...c?{angle:c}:{}}}return e}),this._decorStyle={...i,fill:"rect"===t.kind||"ellipse"===t.kind?i.fill:this._decorStyle.fill,fillColor:"rect"===t.kind||"ellipse"===t.kind?i.fillColor:this._decorStyle.fillColor,fillOpacity:"rect"===t.kind||"ellipse"===t.kind?i.fillOpacity:this._decorStyle.fillOpacity},this._decorShapeDialog=null,this._recordGeometry(this._t("history.decor_edit"),e),this._saveConfig(),this.requestUpdate()}get _dtSel(){return"decor"===this._mode&&"select"===this._decorTool&&this._decorSel&&this._decorList.find(t=>t.id===this._decorSel)||null}_dtPivot(t){return"line"===t.kind?[(t.x1+t.x2)/2*eh,(t.y1+t.y2)/2*this._decorH]:"furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind?[(t.x+t.w/2)*eh,(t.y+t.h/2)*this._decorH]:[t.x*eh,t.y*this._decorH]}_dtApply(t,e){const i=this._curSpaceCfg;i&&(i.decor=this._decorList.map(i=>{if(i.id!==t)return i;const s={...i};"text"===i.kind&&void 0!==e.textSizeCm&&(delete s.size,delete s.scale);const o={...s};return void 0!==e.textSizeCm&&(o.size_cm=Number(Math.max(.1,Math.min(Nc,e.textSizeCm)).toFixed(4))),void 0!==e.angle&&(e.angle?o.angle=Number(e.angle.toFixed(2)):delete o.angle),o}),this._cfgEpoch++,this.requestUpdate())}_dtStart(t,e,i,s){const o=this._dtSel;if(!o)return;t.stopPropagation(),t.preventDefault();const[n,r]=this._dtPivot(o),a=this._svgPoint(t),l=this._decorBoxOf(o);this._dtDrag={id:o.id,kind:e,pid:t.pointerId,ax:n,ay:r,r0:Math.hypot(a[0]-n,a[1]-r),a0:180*Math.atan2(a[1]-r,a[0]-n)/Math.PI,textSizeCm0:"text"===o.kind?this._decorTextSizeCm(o):1,angle0:"line"===o.kind?0:Number(o.angle)||0,sgx:i?.[0],sgy:i?.[1],orig:l||void 0,origShape:JSON.parse(JSON.stringify(o)),before:this._geometrySnapshot(),lineEnd:s,moved:!1},lh(t)}_dtMove(t){const e=this._dtDrag;if(!e)return;const i=this._svgPoint(t);if(void 0!==e.lineEnd&&"line"===e.origShape.kind){const s=this._decorSnap(i,t.pointerType,e.id),o=Na(s[0]/eh),n=Na(s[1]/this._decorH),r=e.origShape,a=0===e.lineEnd?r.x1:r.x2,l=0===e.lineEnd?r.y1:r.y2;return(Math.abs(o-a)>1e-9||Math.abs(n-l)>1e-9)&&(e.moved=!0),void this._replaceDecor(e.id,0===e.lineEnd?{x1:o,y1:n}:{x2:o,y2:n})}if("scale"===e.kind&&e.orig){const s=nr(e.orig,e.sgx??1,e.sgy??1,i[0],i[1],!t.shiftKey,this._gridPitch,this._gridPitch),o=Math.abs(s.x-e.orig.x)>1e-6||Math.abs(s.y-e.orig.y)>1e-6||Math.abs(s.w-e.orig.w)>1e-6||Math.abs(s.h-e.orig.h)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._decorApplyBox(e.id,s)}if("scale"===e.kind){const t=Math.hypot(i[0]-e.ax,i[1]-e.ay);if(e.r0<1e-6)return;const s=Math.max(.1,Math.min(Nc,e.textSizeCm0*(t/e.r0))),o=Math.abs(s-e.textSizeCm0)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._dtApply(e.id,{textSizeCm:s})}const s=180*Math.atan2(i[1]-e.ay,i[0]-e.ax)/Math.PI;let o=e.angle0+(s-e.a0);t.shiftKey||(o=5*Math.round(o/5)),o=(o%360+360)%360,o>180&&(o-=360);const n=Math.abs(o-e.angle0)>1e-6;(n||e.moved)&&(e.moved||=n,this._dtApply(e.id,{angle:o}))}_dtUp(){const t=this._dtDrag;this._dtDrag=null,t?.moved&&(this._recordGeometry(this._t("history.decor_transform"),t.before),this._saveConfig()),this.requestUpdate()}_dtMeasure(){const t=this._dtSel;if(!t)return void(this._dtBox&&(this._dtBox=null,this.requestUpdate()));let e;if("line"===t.kind){const i=t.x1*eh,s=t.y1*this._decorH,o=t.x2*eh,n=t.y2*this._decorH;e={id:t.id,x:Math.min(i,o),y:Math.min(s,n),w:Math.abs(o-i),h:Math.abs(n-s)}}else if("furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind)e={id:t.id,x:t.x*eh,y:t.y*this._decorH,w:t.w*eh,h:t.h*this._decorH};else{const i=this.renderRoot.querySelector(`text.dtext[data-id="${t.id}"]`);if(!i||"function"!=typeof i.getBBox)return;let s;try{s=i.getBBox()}catch{return}if(!s||!s.width&&!s.height)return;e={id:t.id,x:s.x,y:s.y,w:s.width,h:s.height}}const i=this._dtBox;i&&i.id===e.id&&Math.abs(i.x-e.x)<.01&&Math.abs(i.y-e.y)<.01&&Math.abs(i.w-e.w)<.01&&Math.abs(i.h-e.h)<.01||(this._dtBox=e,this.requestUpdate())}_deleteDecor(t){if(!this._decorList.some(e=>e.id===t))return;const e=this._geometrySnapshot();this._curSpaceCfg.decor=this._decorList.filter(e=>e.id!==t),this._decorSel===t&&(this._decorSel=null),this._recordGeometry(this._t("history.decor_delete"),e),this._saveConfig(),this.requestUpdate()}_decorDeleteSel(){this._decorSel&&this._deleteDecor(this._decorSel)}_confirmDecorErase(){const t=this._decorEraseConfirm;this._decorEraseConfirm=null,t&&this._deleteDecor(t.id)}get _furnWalls(){const t=this._physicalBodiesR().flatMap(t=>t.map((e,i)=>{const s=t[(i+1)%t.length];return[e[0],e[1],s[0],s[1]]}));return[...this._segments,...t]}get _furnWallReach(){return 6*this._gridPitch}_furnFieldValue(t){return Math.round(100*(this._imperial?t/30.48:t/100))/100}_furnFieldToCm(t){return e=this._imperial?30.48*t:100*t,Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1;var e}_furnPick(t){const e=function(t){const e=il(t);return e?{w:e.w,h:e.h}:{w:60,h:60}}(t);this._furnPalette={symbol:t,w:e.w,h:e.h}}_furnPlace(t,e=!1){const i=this._furnPalette,s=this._curSpaceCfg;if(!i||!s)return;const o=eh,n=this._decorH,r=al(ol(i.w,this._cellCm,this._gridPitch,o)),a=al(ol(i.h,this._cellCm,this._gridPitch,o)),l=this._geometrySnapshot(),c=this._decorSnap(t);let h=c[0],d=c[1],p=0;const u=e?null:dl(h,d,a*n,this._furnWalls,this._furnWallReach,this._gridPitch);u&&(h=u.cx,d=u.cy,p=u.angle);const _="df"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),m={id:_,kind:"furniture",symbol:i.symbol,x:Na(h/o-r/2),y:Na(d/n-a/2),w:r,h:a,...ir(this._decorStyle,!1)};p&&(m.angle=Number(p.toFixed(2))),s.decor=[...this._decorList,m],this._decorSel=_,this._decorTool="select",this._furnPalette=null,this._recordGeometry(this._t("history.decor_add"),l),this._saveConfig(),this.requestUpdate()}_furnMoveUpdate(t){const e=this._decorMove;if("furniture"!==e.orig.kind)return;const i=e.orig,s=this._curSpaceCfg;if(!s)return;const o=eh,n=this._decorH,r=this._svgPoint(t),a=(i.x+i.w/2)*o+(r[0]-e.start[0]),l=(i.y+i.h/2)*n+(r[1]-e.start[1]);let c,h,d=Number(i.angle)||0;const p=t.shiftKey?null:dl(a,l,i.h*n,this._furnWalls,this._furnWallReach,this._gridPitch);if(p)c=p.cx/o-i.w/2,h=p.cy/n-i.h/2,d=p.angle;else{const s=this._decorSnap([a-i.w/2*o,l-i.h/2*n],t.pointerType,e.id);c=s[0]/o,h=s[1]/n}c=Na(c),h=Na(h),(Math.abs(c-i.x)>1e-9||Math.abs(h-i.y)>1e-9||Math.abs(d-(Number(i.angle)||0))>1e-9)&&(e.moved=!0),s.decor=this._decorList.map(t=>{if(t.id!==e.id)return t;const i={...t,x:c,y:h};return d?i.angle=Number(d.toFixed(2)):delete i.angle,i}),this.requestUpdate()}_decorApplyBox(t,e){const i=this._curSpaceCfg;if(!i)return;const s=eh,o=this._decorH;i.decor=this._decorList.map(i=>{if(i.id!==t)return i;const n=Xn(e,i.angle,t=>this._snap(t));return{...i,x:Na(n[0]/s),y:Na(n[1]/o),w:Math.max(this._gridPitch/s,Math.min(2*Da,e.w/s)),h:Math.max(this._gridPitch/o,Math.min(2*Da,e.h/o))}}),this._cfgEpoch++,this.requestUpdate()}get _furnLive(){const t=this._dtDrag;if(!t||"scale"!==t.kind||!t.orig)return null;const e=this._decorList.find(e=>e.id===t.id);if(!e||"furniture"!==e.kind)return null;const i=eh,s=this._decorH,o=e.w*i,n=e.h*s,r=function(t,e,i,s,o){const n=t+i/2,r=e+s/2,a=(Number(o)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(t,e)=>{const i=t-n,s=e-r;return[n+i*l-s*c,r+i*c+s*l]};return[h(t,e),h(t+i,e),h(t+i,e+s),h(t,e+s)]}(e.x*i,e.y*s,o,n,Number(e.angle)||0),a=(t,e)=>[(t[0]+e[0])/2,(t[1]+e[1])/2],l=a(r[0],r[1]),c=a(r[0],r[3]);return[{x:l[0],y:l[1],text:this._fmtLen([0,0],[o,0])},{x:c[0],y:c[1],text:this._fmtLen([0,0],[0,n])}]}_renderFurnPalette(){const t=this._furnPalette,e=this._t(this._imperial?"gs.unit_ft":"gs.unit_m");return B`
t.stopPropagation()}>
${this._t("furn.title")} @@ -3699,21 +3767,21 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
- ${Ha.map(e=>j` + ${Qa.map(e=>B`
${this._t(`furn.group_${e}`)}
- ${Ba(e).map(e=>j``)}
`)}
- ${t?j`
+ ${t?B`
${this._t("furn.place_hint")} -
`:j`
${this._t("furn.pick_hint")}
`} -
`}get _bdBase(){const t=this._curSpaceCfg;return t?.plan_url?{...ca(t.plan_aspect,Nc)}:null}get _bdRect(){const t=this._curSpaceCfg;return t?.plan_url?pa(t,Nc):null}get _bdParams(){const t=this._curSpaceCfg,e=Number(t?.plan_x),i=Number(t?.plan_y),s=Number(t?.plan_scale),o=Number(t?.plan_scale_x),n=Number(t?.plan_scale_y),r=Number.isFinite(s)&&s>0?s:1;return{dx:Number.isFinite(e)?e:0,dy:Number.isFinite(i)?i:0,sx:Number.isFinite(o)&&o>0?o:r,sy:Number.isFinite(n)&&n>0?n:r,angle:Un(t?.plan_angle)}}_openBackdropDialog(t){if(!this._bdMovable||!this._bdRect)return;t?.preventDefault(),t?.stopPropagation(),this._bdDrag=null;const e=this._bdRect;this._backdropDialog={widthCm:Gn(e.w,this._cellCm,this._gridPitch),heightCm:Gn(e.h,this._cellCm,this._gridPitch),angle:this._angleField(e.angle)}}_saveBackdropDialog(){const t=this._backdropDialog,e=this._bdBase,i=this._bdRect;if(!t||!e||!i)return;const s=Un(t.angle),o=this._geometrySnapshot(),n=Math.min(e.w*da,Math.max(e.w*ha,Ie(Bn(t.widthCm,this._cellCm,this._gridPitch),this._gridPitch))),r=Math.min(e.h*da,Math.max(e.h*ha,Ie(Bn(t.heightCm,this._cellCm,this._gridPitch),this._gridPitch))),a=jn({x:i.x+i.w/2-n/2,y:i.y+i.h/2-r/2},s,t=>this._snap(t));this._bdApply((a[0]-e.x)/Nc,(a[1]-e.y)/Nc,n/e.w,r/e.h,s),this._backdropDialog=null,this._recordGeometry(this._t("history.backdrop_transform"),o),this._saveConfig()}get _bdActive(){return"decor"===this._mode&&!!this._bdRect&&"backdrop"===this._decorTool}get _bdMovable(){return"decor"===this._mode&&"backdrop"===this._decorTool&&!!this._bdRect}_bdApply(t,e,i,s,o){const n=this._curSpaceCfg;if(!n)return;n.plan_x=Number($a(t).toFixed(6)),n.plan_y=Number($a(e).toFixed(6)),delete n.plan_scale,n.plan_scale_x=Number(Math.min(da,Math.max(ha,i)).toFixed(6)),n.plan_scale_y=Number(Math.min(da,Math.max(ha,s)).toFixed(6));const r=Un(o);r?n.plan_angle=Number(r.toFixed(2)):delete n.plan_angle,this._cfgEpoch++,this.requestUpdate()}_bdStart(t,e,i=!1){const s=this._bdBase,o=this._bdRect;if(!s||!o)return!1;const n=this._svgPoint(t),r=e?e[0]:0,a=e?e[1]:0,l=r>0?o.x:o.x+o.w,c=a>0?o.y:o.y+o.h;return this._bdDrag={kind:i?"rotate":e?"scale":"move",pid:t.pointerId,sx:n[0],sy:n[1],base:s,p0:this._bdParams,fx:l,fy:c,sgx:r,sgy:a,rect0:{x:o.x,y:o.y,w:o.w,h:o.h,angle:o.angle},before:this._geometrySnapshot(),moved:!1},Uc(t),!0}_bdMove(t){const e=this._bdDrag;if(!e)return;const i=this._svgPoint(t),s=e.base;if("move"===e.kind){const t=e.rect0.x,o=e.rect0.y,n=this._snap([t+(i[0]-e.sx),o+(i[1]-e.sy)]),r=Math.abs(n[0]-t)>1e-9||Math.abs(n[1]-o)>1e-9;if(!r&&!e.moved)return;return e.moved||=r,void this._bdApply((n[0]-s.x)/Nc,(n[1]-s.y)/Nc,e.p0.sx,e.p0.sy,e.p0.angle)}if("rotate"===e.kind){const s=e.rect0.x+e.rect0.w/2,o=e.rect0.y+e.rect0.h/2,n=180*Math.atan2(e.sy-o,e.sx-s)/Math.PI;let r=e.p0.angle+(180*Math.atan2(i[1]-o,i[0]-s)/Math.PI-n);t.shiftKey||(r=5*Math.round(r/5)),r=Un(r);const a=Math.abs(r-e.p0.angle)>1e-9;if(!a&&!e.moved)return;return e.moved||=a,void this._bdApply(e.p0.dx,e.p0.dy,e.p0.sx,e.p0.sy,r)}const o=Jn(e.rect0,e.sgx,e.sgy,i[0],i[1],!t.shiftKey,this._gridPitch,Math.min(s.w,s.h)*ha),n=o.w/Math.max(1e-9,s.w),r=o.h/Math.max(1e-9,s.h),a=Math.abs(n-e.p0.sx)>1e-9||Math.abs(r-e.p0.sy)>1e-9||Math.abs(o.x-e.rect0.x)>1e-9||Math.abs(o.y-e.rect0.y)>1e-9;if(!a&&!e.moved)return;e.moved||=a;const l=jn(o,e.p0.angle,t=>this._snap(t));this._bdApply((l[0]-s.x)/Nc,(l[1]-s.y)/Nc,n,r,e.p0.angle)}get _bdMoved(){if("decor"!==this._mode||!this._bdRect)return!1;const t=this._bdParams;return 0!==t.dx||0!==t.dy||1!==t.sx||1!==t.sy||0!==t.angle}_bdReset(){const t=this._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._bdDrag=null,this._recordGeometry(this._t("history.backdrop_transform"),e),this._saveConfig(),this._showToast(this._t("decor.backdrop_reset_done")),this.requestUpdate()}_bdUp(){const t=this._bdDrag;this._bdDrag=null,t?.moved&&(this._recordGeometry(this._t("history.backdrop_transform"),t.before),this._saveConfig()),this.requestUpdate()}get _bdLive(){if(!this._bdDrag)return null;const t=this._bdRect;return t?{x:t.x+t.w/2,y:t.y+t.h/2,text:`${this._fmtLen([0,0],[t.w,0])} × ${this._fmtLen([0,0],[0,t.h])}`}:null}_renderBackdropFrame(t){const e=this._bdRect;if(!this._bdActive||!e)return W;const i=.02*Math.max(t.w,t.h),s=i/4,o=e.x+e.w/2,n=e.y+e.h/2,r=Un(e.angle),a=2.2*i;return B` +
`:B`
${this._t("furn.pick_hint")}
`} +
`}get _bdBase(){const t=this._curSpaceCfg;return t?.plan_url?{...ka(t.plan_aspect,eh)}:null}get _bdRect(){const t=this._curSpaceCfg;return t?.plan_url?Sa(t,eh):null}get _bdParams(){const t=this._curSpaceCfg,e=Number(t?.plan_x),i=Number(t?.plan_y),s=Number(t?.plan_scale),o=Number(t?.plan_scale_x),n=Number(t?.plan_scale_y),r=Number.isFinite(s)&&s>0?s:1;return{dx:Number.isFinite(e)?e:0,dy:Number.isFinite(i)?i:0,sx:Number.isFinite(o)&&o>0?o:r,sy:Number.isFinite(n)&&n>0?n:r,angle:Zn(t?.plan_angle)}}_openBackdropDialog(t){if(!this._bdMovable||!this._bdRect)return;t?.preventDefault(),t?.stopPropagation(),this._bdDrag=null;const e=this._bdRect;this._backdropDialog={widthCm:tr(e.w,this._cellCm,this._gridPitch),heightCm:tr(e.h,this._cellCm,this._gridPitch),angle:this._angleField(e.angle)}}_saveBackdropDialog(){const t=this._backdropDialog,e=this._bdBase,i=this._bdRect;if(!t||!e||!i)return;const s=Zn(t.angle),o=this._geometrySnapshot(),n=Math.min(e.w*xa,Math.max(e.w*$a,Ve(Qn(t.widthCm,this._cellCm,this._gridPitch),this._gridPitch))),r=Math.min(e.h*xa,Math.max(e.h*$a,Ve(Qn(t.heightCm,this._cellCm,this._gridPitch),this._gridPitch))),a=Xn({x:i.x+i.w/2-n/2,y:i.y+i.h/2-r/2},s,t=>this._snap(t));this._bdApply((a[0]-e.x)/eh,(a[1]-e.y)/eh,n/e.w,r/e.h,s),this._backdropDialog=null,this._recordGeometry(this._t("history.backdrop_transform"),o),this._saveConfig()}get _bdActive(){return"decor"===this._mode&&!!this._bdRect&&"backdrop"===this._decorTool}get _bdMovable(){return"decor"===this._mode&&"backdrop"===this._decorTool&&!!this._bdRect}_bdApply(t,e,i,s,o){const n=this._curSpaceCfg;if(!n)return;n.plan_x=Number(Na(t).toFixed(6)),n.plan_y=Number(Na(e).toFixed(6)),delete n.plan_scale,n.plan_scale_x=Number(Math.min(xa,Math.max($a,i)).toFixed(6)),n.plan_scale_y=Number(Math.min(xa,Math.max($a,s)).toFixed(6));const r=Zn(o);r?n.plan_angle=Number(r.toFixed(2)):delete n.plan_angle,this._cfgEpoch++,this.requestUpdate()}_bdStart(t,e,i=!1){const s=this._bdBase,o=this._bdRect;if(!s||!o)return!1;const n=this._svgPoint(t),r=e?e[0]:0,a=e?e[1]:0,l=r>0?o.x:o.x+o.w,c=a>0?o.y:o.y+o.h;return this._bdDrag={kind:i?"rotate":e?"scale":"move",pid:t.pointerId,sx:n[0],sy:n[1],base:s,p0:this._bdParams,fx:l,fy:c,sgx:r,sgy:a,rect0:{x:o.x,y:o.y,w:o.w,h:o.h,angle:o.angle},before:this._geometrySnapshot(),moved:!1},lh(t),!0}_bdMove(t){const e=this._bdDrag;if(!e)return;const i=this._svgPoint(t),s=e.base;if("move"===e.kind){const t=e.rect0.x,o=e.rect0.y,n=this._snap([t+(i[0]-e.sx),o+(i[1]-e.sy)]),r=Math.abs(n[0]-t)>1e-9||Math.abs(n[1]-o)>1e-9;if(!r&&!e.moved)return;return e.moved||=r,void this._bdApply((n[0]-s.x)/eh,(n[1]-s.y)/eh,e.p0.sx,e.p0.sy,e.p0.angle)}if("rotate"===e.kind){const s=e.rect0.x+e.rect0.w/2,o=e.rect0.y+e.rect0.h/2,n=180*Math.atan2(e.sy-o,e.sx-s)/Math.PI;let r=e.p0.angle+(180*Math.atan2(i[1]-o,i[0]-s)/Math.PI-n);t.shiftKey||(r=5*Math.round(r/5)),r=Zn(r);const a=Math.abs(r-e.p0.angle)>1e-9;if(!a&&!e.moved)return;return e.moved||=a,void this._bdApply(e.p0.dx,e.p0.dy,e.p0.sx,e.p0.sy,r)}const o=nr(e.rect0,e.sgx,e.sgy,i[0],i[1],!t.shiftKey,this._gridPitch,Math.min(s.w,s.h)*$a),n=o.w/Math.max(1e-9,s.w),r=o.h/Math.max(1e-9,s.h),a=Math.abs(n-e.p0.sx)>1e-9||Math.abs(r-e.p0.sy)>1e-9||Math.abs(o.x-e.rect0.x)>1e-9||Math.abs(o.y-e.rect0.y)>1e-9;if(!a&&!e.moved)return;e.moved||=a;const l=Xn(o,e.p0.angle,t=>this._snap(t));this._bdApply((l[0]-s.x)/eh,(l[1]-s.y)/eh,n,r,e.p0.angle)}get _bdMoved(){if("decor"!==this._mode||!this._bdRect)return!1;const t=this._bdParams;return 0!==t.dx||0!==t.dy||1!==t.sx||1!==t.sy||0!==t.angle}_bdReset(){const t=this._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._bdDrag=null,this._recordGeometry(this._t("history.backdrop_transform"),e),this._saveConfig(),this._showToast(this._t("decor.backdrop_reset_done")),this.requestUpdate()}_bdUp(){const t=this._bdDrag;this._bdDrag=null,t?.moved&&(this._recordGeometry(this._t("history.backdrop_transform"),t.before),this._saveConfig()),this.requestUpdate()}get _bdLive(){if(!this._bdDrag)return null;const t=this._bdRect;return t?{x:t.x+t.w/2,y:t.y+t.h/2,text:`${this._fmtLen([0,0],[t.w,0])} × ${this._fmtLen([0,0],[0,t.h])}`}:null}_renderBackdropFrame(t){const e=this._bdRect;if(!this._bdActive||!e)return W;const i=.02*Math.max(t.w,t.h),s=i/4,o=e.x+e.w/2,n=e.y+e.h/2,r=Zn(e.angle),a=2.2*i;return j` {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,n])=>{const r=t<0?e.x:e.x+e.w,a=o<0?e.y:e.y+e.h;return B`{const r=t<0?e.x:e.x+e.w,a=o<0?e.y:e.y+e.h;return j`{e.stopPropagation(),e.preventDefault(),this._bdStart(e,[t,o])}}>`})} - `}_renderTextFrame(t){const e=this._dtSel,i=this._dtBox;if(!e||!i||i.id!==e.id)return W;const s=.018*Math.max(t.w,t.h),o=s/4;if("line"===e.kind){const t=[e.x1*Nc,e.y1*this._decorH],i=[e.x2*Nc,e.y2*this._decorH];return B` + `}_renderTextFrame(t){const e=this._dtSel,i=this._dtBox;if(!e||!i||i.id!==e.id)return W;const s=.018*Math.max(t.w,t.h),o=s/4;if("line"===e.kind){const t=[e.x1*eh,e.y1*this._decorH],i=[e.x2*eh,e.y2*this._decorH];return j` - ${[t,i].map((t,e)=>B`j`this._dtStart(t,"scale",void 0,e)}> `)} - `}const[n,r]=this._dtPivot(e),a=Number(e.angle)||0,l=2.2*s;return B` + `}const[n,r]=this._dtPivot(e),a=Number(e.angle)||0,l=2.2*s;return j` this._dtStart(t,"rotate")}> - ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([t,e,n])=>B`j`this._dtStart(i,"scale",[t,e])}>`)} - `}_renderDecorLayer(){const t=Nc,e=this._decorH,i="decor"===this._mode,s=i&&"erase"===this._decorTool,o=this._decorList.map(o=>{const n="dshape"+(i&&this._decorSel===o.id?" dsel":""),r=this._decorResolvedStyle(o),a=this._decorWidthUnits(o),l=t=>this._decorShapeDown(t,o),c=t=>this._decorShapeDbl(t,o);if("line"===o.kind)return B``}_renderDecorLayer(){const t=eh,e=this._decorH,i="decor"===this._mode,s=i&&"erase"===this._decorTool,o=this._decorList.map(o=>{const n="dshape"+(i&&this._decorSel===o.id?" dsel":""),r=this._decorResolvedStyle(o),a=this._decorWidthUnits(o),l=t=>this._decorShapeDown(t,o),c=t=>this._decorShapeDbl(t,o);if("line"===o.kind)return j` - ${i&&"select"===this._decorTool?B``:W} - ${s?B``:W}`;if("rect"===o.kind){const i=(o.x+o.w/2)*t,h=(o.y+o.h/2)*e,d=Un(o.angle);return B``:W}`;if("rect"===o.kind){const i=(o.x+o.w/2)*t,h=(o.y+o.h/2)*e,d=Zn(o.angle);return j` - ${s?B``:W}`}if("ellipse"===o.kind){const i=(o.x+o.w/2)*t,h=(o.y+o.h/2)*e,d=Un(o.angle);return B``:W}`}if("ellipse"===o.kind){const i=(o.x+o.w/2)*t,h=(o.y+o.h/2)*e,d=Zn(o.angle);return j` - ${s?B``:W}`}if("furniture"===o.kind){const i=o.w*t,h=o.h*e,d=Ja(o.symbol,i,h);if(!d)return W;const p=Number(o.angle)||0,u=o.x*t+i/2,_=o.y*e+h/2,m=`${p?`rotate(${p} ${u} ${_}) `:""}translate(${o.x*t} ${o.y*e})`;return B``:W}`}if("furniture"===o.kind){const i=o.w*t,h=o.h*e,d=cl(o.symbol,i,h);if(!d)return W;const p=Number(o.angle)||0,u=o.x*t+i/2,_=o.y*e+h/2,m=`${p?`rotate(${p} ${u} ${_}) `:""}translate(${o.x*t} ${o.y*e})`;return j` - ${s?B``:W}`}if("text"===o.kind){const i=this._decorTextUnits(o),s=function(t){return String(t??"").replace(/\r\n?/g,"\n").split("\n")}(function(t,e,i,s=()=>!0){const o=t??"";let n=!1;const r=o.replace(/\{([^{}\r\n]+)\}/g,(t,e)=>{const o=xi(e);return o?(n=!0,s(o.entity||"")?Di(i,o):ki):t});if(n)return r;const a=(e?.entity||"").trim();if(!a)return o;if(!s(a)){const t=o.indexOf($i);return t>=0?o.slice(0,t)+ki+o.slice(t+2):o?`${o} ${ki}`:ki}const l=Di(i,e),c=o.indexOf($i);return c>=0?o.slice(0,c)+l+o.slice(c+2):o?`${o} ${l}`:l}(o.text,o,this.hass,t=>this._planEntityAvailable(t))),a=o.x*t,h=o.y*e,d=Number(o.angle)||0,p=h-(s.length-1)*i*1.2/2;return B``:W}`}if("text"===o.kind){const i=this._decorTextUnits(o),s=function(t){return String(t??"").replace(/\r\n?/g,"\n").split("\n")}(function(t,e,i,s=()=>!0){const o=t??"";let n=!1;const r=o.replace(/\{([^{}\r\n]+)\}/g,(t,e)=>{const o=Ni(e);return o?(n=!0,s(o.entity||"")?Hi(i,o):Ii):t});if(n)return r;const a=(e?.entity||"").trim();if(!a)return o;if(!s(a)){const t=o.indexOf(Ei);return t>=0?o.slice(0,t)+Ii+o.slice(t+2):o?`${o} ${Ii}`:Ii}const l=Hi(i,e),c=o.indexOf(Ei);return c>=0?o.slice(0,c)+l+o.slice(c+2):o?`${o} ${l}`:l}(o.text,o,this.hass,t=>this._planEntityAvailable(t))),a=o.x*t,h=o.y*e,d=Number(o.angle)||0,p=h-(s.length-1)*i*1.2/2;return j`${s.map((t,e)=>B`${t}`)}`}return W});let n=W;const r=this._decorDraft;if(r){const t=this._decorStyle,e=Bn(t.widthCm,this._cellCm,this._gridPitch);if("line"===r.kind)n=B``;else{const i=Math.min(r.a[0],r.b[0]),s=Math.min(r.a[1],r.b[1]),o=Math.abs(r.b[0]-r.a[0]),a=Math.abs(r.b[1]-r.a[1]);n="rect"===r.kind?B``:B``}}return B`${o}${n}`}get _editorToolbarGroups(){return[]}_renderEditorGroupLauncher(t){return this._editorSecondary.renderGroupLauncher(t,this._editorToolbarGroups,this._editorSecondaryCopy)}get _editorSecondaryContextId(){const t=`editor:${this._mode}:${this._space}:${this._cfgEpoch}`,e=this._editorSecondary.activeGroup(this._editorToolbarGroups);if(e)return`${t}:group:${e.id}:${this._editorSecondary.groupGeneration}`;if("plan"===this._mode){const e=this._physicalSel;return e?`${t}:selection:${e.kind}:${e.id}:${e.segment??""}`:`${t}:tool:${this._tool}:${this._path.length}:${this._openWallAnchor?1:0}`}return"decor"===this._mode?"furniture"===this._decorTool?`${t}:palette:furniture:${this._furnPalette?.symbol||"none"}`:"select"===this._decorTool&&this._decorSel?`${t}:selection:decor:${this._decorSel}`:`${t}:tool:${this._decorTool}:${this._bdMoved?1:0}:${this._bdDrag?1:0}`:`${t}:none`}_runEditorContext(t,e){this._editorSecondary.runContext(t,this._editorSecondaryContextId,e)}_renderEditorGroupModel(t){return this._editorSecondary.renderGroupModel(t,this._editorSecondaryContextId,this._editorSecondaryCopy)}_renderDrawWallControl(){return j``}return W});let n=W;const r=this._decorDraft;if(r){const t=this._decorStyle,e=Qn(t.widthCm,this._cellCm,this._gridPitch);if("line"===r.kind)n=j``;else{const i=Math.min(r.a[0],r.b[0]),s=Math.min(r.a[1],r.b[1]),o=Math.abs(r.b[0]-r.a[0]),a=Math.abs(r.b[1]-r.a[1]);n="rect"===r.kind?j``:j``}}return j`${o}${n}`}get _editorToolbarGroups(){return[]}_renderEditorGroupLauncher(t){return this._editorSecondary.renderGroupLauncher(t,this._editorToolbarGroups,this._editorSecondaryCopy)}get _editorSecondaryContextId(){const t=`editor:${this._mode}:${this._space}:${this._cfgEpoch}`,e=this._editorSecondary.activeGroup(this._editorToolbarGroups);if(e)return`${t}:group:${e.id}:${this._editorSecondary.groupGeneration}`;if("plan"===this._mode){const e=this._physicalSel;return e?`${t}:selection:${e.kind}:${e.id}:${e.segment??""}`:`${t}:tool:${this._tool}:${this._path.length}:${this._openWallAnchor?1:0}`}return"decor"===this._mode?"furniture"===this._decorTool?`${t}:palette:furniture:${this._furnPalette?.symbol||"none"}`:"select"===this._decorTool&&this._decorSel?`${t}:selection:decor:${this._decorSel}`:`${t}:tool:${this._decorTool}:${this._bdMoved?1:0}:${this._bdDrag?1:0}`:`${t}:none`}_runEditorContext(t,e){this._editorSecondary.runContext(t,this._editorSecondaryContextId,e)}_renderEditorGroupModel(t){return this._editorSecondary.renderGroupModel(t,this._editorSecondaryContextId,this._editorSecondaryCopy)}_renderDrawWallControl(){return B``}_renderPlanSecondary(){const t=this._editorSecondaryContextId,e=this._physicalSel;if(e){if(!("partition"===e.kind?!!this._curSpaceCfg.partitions?.some(t=>t.id===e.id):"column"===e.kind?!!this._curSpaceCfg.wall_columns?.some(t=>t.id===e.id):!!this._curSpaceCfg.room_drafts?.some(t=>t.id===e.id)))return null;const i="partition"===e.kind?this._t("markup.partition"):"column"===e.kind?this._t("markup.column"):this._t("markup.add");return{contextId:t,kind:"selection",ariaLabel:this._t("editor.context_actions",{object:i}),visibleLabel:i,content:j` + ${this._t("physical.allowed_range",{max:hr(this._drawWallMaxCm,this._imperial),unit:this._t(this._imperial?"wallthick.unit_in":"wallthick.unit_cm")})} + `}_renderPlanSecondary(){const t=this._editorSecondaryContextId,e=this._physicalSel;if(e){if(!("partition"===e.kind?!!this._curSpaceCfg.partitions?.some(t=>t.id===e.id):"column"===e.kind?!!this._curSpaceCfg.wall_columns?.some(t=>t.id===e.id):!!this._curSpaceCfg.room_drafts?.some(t=>t.id===e.id)))return null;const i="partition"===e.kind?this._t("markup.partition"):"column"===e.kind?this._t("markup.column"):this._t("markup.add");return{contextId:t,kind:"selection",ariaLabel:this._t("editor.context_actions",{object:i}),visibleLabel:i,content:B` `}}const i="draw"===this._tool||"partition"===this._tool||"column"===this._tool,s="partition"===this._tool?"markup.hint_partition":"column"===this._tool?"markup.hint_column":"resize"===this._tool?"markup.hint_resize":"wallthick"===this._tool?"markup.hint_wallthick":"boundary"===this._tool?this._boundaryHintKey:null,o="draw"===this._tool?this._t(this._path.length?"markup.hint_points":"markup.hint_start",this._path.length?{n:this._path.length}:void 0):"";if(!i&&!s&&!o)return null;const n="draw"===this._tool&&this._path.length>0||"boundary"===this._tool&&!!this._openWallAnchor;return{contextId:t,kind:n?"operation":"tool",ariaLabel:this._t("editor.tool_options",{tool:this._t("draw"===this._tool?"markup.add":"partition"===this._tool?"markup.partition":"column"===this._tool?"markup.column":"resize"===this._tool?"markup.resize":"wallthick"===this._tool?"markup.wallthick":"markup.boundary")}),content:j` + `}}const i="draw"===this._tool||"partition"===this._tool||"column"===this._tool,s="partition"===this._tool?"markup.hint_partition":"column"===this._tool?"markup.hint_column":"resize"===this._tool?"markup.hint_resize":"wallthick"===this._tool?"markup.hint_wallthick":"boundary"===this._tool?this._boundaryHintKey:null,o="draw"===this._tool?this._t(this._path.length?"markup.hint_points":"markup.hint_start",this._path.length?{n:this._path.length}:void 0):"";if(!i&&!s&&!o)return null;const n="draw"===this._tool&&this._path.length>0||"boundary"===this._tool&&!!this._openWallAnchor;return{contextId:t,kind:n?"operation":"tool",ariaLabel:this._t("editor.tool_options",{tool:this._t("draw"===this._tool?"markup.add":"partition"===this._tool?"markup.partition":"column"===this._tool?"markup.column":"resize"===this._tool?"markup.resize":"wallthick"===this._tool?"markup.wallthick":"markup.boundary")}),content:B` ${i?this._renderDrawWallControl():W} - ${o?j`${o}`:W} - ${s?j`${o}`:W} + ${s?B`${this._t(s)}`:W} - ${"draw"===this._tool&&this._path.length?j``:W}`}}_renderDecorSecondary(){const t=this._editorSecondaryContextId;if("furniture"===this._decorTool)return{contextId:t,kind:"palette",ariaLabel:this._t("editor.palette",{tool:this._t("decor.furniture")}),launcherId:"furniture",dismissPolicy:this._furnPalette?"stay-open-on-canvas":"outside",dismiss:()=>{"furniture"===this._decorTool&&(this._furnPalette=null,this._decorTool="select",this.requestUpdate())},content:this._renderFurnPalette()};const e=this._dtSel;if(e){const i=this._t(`decor.${e.kind}`);return{contextId:t,kind:"selection",ariaLabel:this._t("editor.context_actions",{object:i}),visibleLabel:i,content:j` + `:W}`}}_renderDecorSecondary(){const t=this._editorSecondaryContextId;if("furniture"===this._decorTool)return{contextId:t,kind:"palette",ariaLabel:this._t("editor.palette",{tool:this._t("decor.furniture")}),launcherId:"furniture",dismissPolicy:this._furnPalette?"stay-open-on-canvas":"outside",dismiss:()=>{"furniture"===this._decorTool&&(this._furnPalette=null,this._decorTool="select",this.requestUpdate())},content:this._renderFurnPalette()};const e=this._dtSel;if(e){const i=this._t(`decor.${e.kind}`);return{contextId:t,kind:"selection",ariaLabel:this._t("editor.context_actions",{object:i}),visibleLabel:i,content:B` `}}const i="line"===this._decorTool||"rect"===this._decorTool||"ellipse"===this._decorTool,s="rect"===this._decorTool||"ellipse"===this._decorTool,o="backdrop"===this._decorTool&&!!this._bdRect;return i||o?{contextId:t,kind:"tool",ariaLabel:this._t("editor.tool_options",{tool:this._t(i?`decor.${this._decorTool}`:"decor.backdrop")}),content:j` - ${i?j` + `}}const i="line"===this._decorTool||"rect"===this._decorTool||"ellipse"===this._decorTool,s="rect"===this._decorTool||"ellipse"===this._decorTool,o="backdrop"===this._decorTool&&!!this._bdRect;return i||o?{contextId:t,kind:"tool",ariaLabel:this._t("editor.tool_options",{tool:this._t(i?`decor.${this._decorTool}`:"decor.backdrop")}),content:B` + ${i?B` this._decorStyle={...this._decorStyle,...t.detail}}> @@ -3825,19 +3893,19 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 @input=${t=>this._decorStyle={...this._decorStyle,widthCm:this._decorSmallCm(Number(t.target.value))}} /> ${this._t(this._imperial?"wallthick.unit_in":"wallthick.unit_cm")} - ${s?j` this._decorStyle={...this._decorStyle,fillColor:t.detail.color,fillOpacity:t.detail.opacity}}>`:W} `:W} - ${o?j`${this._t("decor.backdrop_hint")}`:W}`}:null}_withBackdropReset(t){if(!this._bdMoved||this._bdDrag||"palette"===t?.kind)return t;const e=this._editorSecondaryContextId,i=j``;return t?{...t,kind:"selection"===t.kind?"mixed":t.kind,content:j`${t.content}${i}`}:{contextId:e,kind:"tool",ariaLabel:this._t("editor.tool_options",{tool:this._t("decor.backdrop")}),content:i}}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._infoCard||this._rulesDialog||this._settingsDialog||this._alignDialog||this._importDialog||this._kioskDialog||this._wallDialog)}_renderEditorSecondary(){if(!this._editing)return W;const t=this._editorSecondary.activeGroup(this._editorToolbarGroups),e=t?this._renderEditorGroupModel(t):"plan"===this._mode?this._renderPlanSecondary():"decor"===this._mode?this._withBackdropReset(this._renderDecorSecondary()):null;return this._editorSecondary.render(e,this._editorSecondaryDialogBlocked)}_renderDecorBar(){const t=[["select","mdi:cursor-default-outline","decor.select"],...this._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._geometryHistory.undoName,i=this._geometryHistory.redoName;return j`
+ `;return t?{...t,kind:"selection"===t.kind?"mixed":t.kind,content:B`${t.content}${i}`}:{contextId:e,kind:"tool",ariaLabel:this._t("editor.tool_options",{tool:this._t("decor.backdrop")}),content:i}}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._infoCard||this._rulesDialog||this._settingsDialog||this._alignDialog||this._importDialog||this._kioskDialog||this._wallDialog)}_renderEditorSecondary(){if(!this._editing)return W;const t=this._editorSecondary.activeGroup(this._editorToolbarGroups),e=t?this._renderEditorGroupModel(t):"plan"===this._mode?this._renderPlanSecondary():"decor"===this._mode?this._withBackdropReset(this._renderDecorSecondary()):null;return this._editorSecondary.render(e,this._editorSecondaryDialogBlocked)}_renderDecorBar(){const t=[["select","mdi:cursor-default-outline","decor.select"],...this._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._geometryHistory.undoName,i=this._geometryHistory.redoName;return B`
- ${t.map(([t,e,i])=>j`
-
`}_renderDecorEraseConfirm(){const t=this._decorEraseConfirm,e=this._t(`decor.${t.kind}`);return j``}_renderDecorEraseConfirm(){const t=this._decorEraseConfirm,e=this._t(`decor.${t.kind}`);return B`this._decorEraseConfirm=null}>

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

@@ -3871,7 +3939,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${this._t("decor.erase")}
-
`}_renderDecorTextDialog(){const t=this._decorTextDialog,e=(t.pickerEntity||"").trim(),i=e?this.hass?.states?.[e]:null;return j``}_renderDecorTextDialog(){const t=this._decorTextDialog,e=(t.pickerEntity||"").trim(),i=e?this.hass?.states?.[e]:null;return B`this._decorTextDialog=null}>
@@ -3888,7 +3956,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 @hp-color-opacity-change=${e=>this._decorTextDialog={...t,...e.detail}}>
this._decorTextDialog={...t,sizeCm:this._decorTextCm(Number(e.target.value))}} /> ${this._t(this._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
@@ -3901,15 +3969,15 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 .value=${t.pickerEntity||""} @input=${e=>this._decorTextDialog={...t,pickerEntity:e.target.value}} /> - ${Object.keys(this.hass?.states||{}).map(t=>j``)} + ${Object.keys(this.hass?.states||{}).map(t=>B``)} - ${e?j` + ${e?B` `:W}
@@ -3918,16 +3986,16 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
- `}_renderDecorShapeDialog(){const t=this._decorShapeDialog,e="rect"===t.kind||"ellipse"===t.kind,i=this._t("decor."+t.kind),s=this._t(this._imperial?"gs.unit_ft":"gs.unit_m");return j``}_renderDecorShapeDialog(){const t=this._decorShapeDialog,e="rect"===t.kind||"ellipse"===t.kind,i=this._t("decor."+t.kind),s=this._t(this._imperial?"gs.unit_ft":"gs.unit_m");return B`this._decorShapeDialog=null}>
- ${"furniture"===t.kind?j` + ${"furniture"===t.kind?B` this._decorShapeDialog={...t,lengthCm:this._decorLargeCm(Number(e.target.value))}} /> - ${s}
`:j` + ${s}
`:B`
this._decorShapeDialog={...t,angle:e.target.value}} /> - ${e?j` this._decorShapeDialog=null}>${this._t("btn.cancel")}
- `}_renderBackdropDialog(){const t=this._backdropDialog,e=this._t(this._imperial?"gs.unit_ft":"gs.unit_m");return j``}_renderBackdropDialog(){const t=this._backdropDialog,e=this._t(this._imperial?"gs.unit_ft":"gs.unit_m");return B`this._backdropDialog=null}>
@@ -4000,33 +4068,33 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
-
`}_cssPxToRender(t){const e=this._stageEl,i=this._viewOr(this._baseVb());return e?.clientWidth&&e.clientHeight?Math.max(i.w/e.clientWidth,i.h/e.clientHeight)*t:this._gridPitch/8*t}get _boundaryCoarse(){return"touch"===this._boundaryPointerType||"pen"===this._boundaryPointerType}_boundaryTolerances(){return{hit:this._cssPxToRender(this._boundaryCoarse?22:12),cap:this._cssPxToRender(this._boundaryCoarse?10:6),ambiguity:this._cssPxToRender(6)}}_boundaryBlocked(t,e){const i=this._spaceModel(),s=i=>ra(t,i)||i.some((s,o)=>{const n=i[(o+1)%i.length];return gs(t,[s[0],s[1],n[0],n[1]])<=e});for(const t of i.wall_columns||[])if(s(ta(t,this._cellCm,this._gridPitch)))return!0;for(const s of i.partitions||[]){const i=ir(s.cm,this._cellCm,this._gridPitch)/2;if(gs(t,[s.a[0],s.a[1],s.b[0],s.b[1]])<=Math.max(e,i))return!0}for(const s of i.room_drafts||[])for(let i=0;i+10?ir(s,this._cellCm,this._gridPitch)/2:0)}_boundaryTargetAt(t){const e=this._viewOr(this._baseVb()),i=this._stageEl,s=[this._space,this._cfgEpoch,t[0],t[1],this._boundaryPointerType,e.x,e.y,e.w,e.h,i?.clientWidth||0,i?.clientHeight||0].join("|");if(this._boundaryTargetMemo?.key===s)return this._boundaryTargetMemo.value;const o=this._boundaryTolerances(),n=this._openCuts();let r=function(t,e,i,s){const{openPull:o,openEndCap:n,solidPull:r,ambiguity:a,eps:l}=s,c=rl(e,l),h=[];for(const e of i||[]){const i=hl(t,e,o,n);if(null==i)continue;const s=[(e[0]+e[2])/2,(e[1]+e[3])/2],r=c.find(t=>gs(s,t.seg)<=4*l);h.push({value:e,seg:e,semantic:r?.pair||`open:${e.join(",")}`,distance:i})}const d=pl(h,a,l);if("ambiguous"===d)return{kind:"ambiguous",group:"open"};if(d)return{kind:"open",seg:d.value,distance:d.distance};const p=[];for(const e of c){const i=hl(t,e.seg,r(e.seg));null!=i&&p.push({value:e,seg:e.seg,semantic:e.pair,distance:i})}const u=pl(p,a,l);if("ambiguous"===u)return{kind:"ambiguous",group:"shared"};if(u)return{kind:"shared",a:u.value.a,b:u.value.b,edge:u.value.seg,distance:u.distance};const _=[];for(const i of e||[]){if(!i?.id)continue;const e=Fe(i);if(e)for(let s=0;sgs(d,t.seg)<=4*l)||_.push({value:{room:i,edge:a},seg:a,semantic:String(i.id),distance:h})}}const m=pl(_,a,l);return"ambiguous"===m?{kind:"ambiguous",group:"outer"}:m?{kind:"outer",...m.value,distance:m.distance}:{kind:"none"}}(t,this._spaceModel().rooms,n,{openPull:o.hit,openEndCap:o.cap,ambiguity:o.ambiguity,eps:.02*this._gridPitch,solidPull:t=>this._solidBoundaryPull(t,n)});return"shared"!==r.kind&&"open"!==r.kind||!this._boundaryBlocked(t,o.hit)||(r={kind:"blocked"}),this._boundaryTargetMemo={key:s,value:r},r}get _boundaryTarget(){return this._markup&&"boundary"===this._tool&&this._cursorPt?this._boundaryTargetAt(this._cursorPt):null}get _boundaryPreview(){const t=this._viewOr(this._baseVb()),e=this._stageEl,i=this._cursorPt,s=this._openWallAnchor,o=[this._markup,this._tool,this._space,this._cfgEpoch,this._boundaryPointerType,i?.[0]??"none",i?.[1]??"none",s?.p?.[0]??"none",s?.p?.[1]??"none",s?.edge?.join(",")??"none",s?.aId??"none",s?.bId??"none",t.x,t.y,t.w,t.h,e?.clientWidth||0,e?.clientHeight||0].join("|");if(this._boundaryPreviewMemo?.key===o)return this._boundaryPreviewMemo.value;const n=t=>(this._boundaryPreviewMemo={key:o,value:t},t);if(!this._markup||"boundary"!==this._tool)return n(null);if(s&&!i)return n({kind:"anchor",point:[...s.p]});if(!i)return n(null);const r=this._openCuts(),a=.02*this._gridPitch;if(s){const{p:t,edge:e}=s,o=ol(nl(i,e,_l(e,r,a),this._gridPitch,1.5*this._gridPitch),e),l=this._boundaryBlocked(i,this._boundaryTolerances().hit)||gs(i,e)>this._solidBoundaryPull(e,r);return n({kind:"range",seg:[t[0],t[1],o[0],o[1]],invalid:l})}const l=this._boundaryTargetAt(i);if("shared"===l.kind){return n({kind:"anchor",point:nl(i,l.edge,_l(l.edge,r,a),this._gridPitch,1.5*this._gridPitch)})}if("open"===l.kind){const t=this._planClosedOpenSpan(l.seg),e=t?Qr([l.seg[0],l.seg[1]],[l.seg[2],l.seg[3]],t.cm,this._cellCm,this._gridPitch):null;return n({kind:"restore",seg:l.seg,body:e})}return"blocked"===l.kind||"ambiguous"===l.kind||"outer"===l.kind?n({kind:"invalid",point:i}):n(null)}get _boundaryHintKey(){if(this._openWallAnchor){const t=this._boundaryPreview;return"range"===t?.kind&&t.invalid?"markup.boundary_hint_retry":"markup.boundary_hint_second"}const t=this._boundaryTarget;return t&&"none"!==t.kind?"open"===t.kind?"markup.boundary_hint_restore":"shared"===t.kind?"markup.boundary_hint_open":"outer"===t.kind?"markup.boundary_hint_outer":"blocked"===t.kind?"markup.boundary_hint_blocked":"markup.boundary_hint_ambiguous":"markup.boundary_hint"}get _boundaryStageClass(){if(!this._markup||"boundary"!==this._tool)return"";if(this._openWallAnchor){const t=this._boundaryPreview;return"range"===t?.kind&&t.invalid?" boundary-invalid":" boundary-solid"}const t=this._boundaryTarget;return"open"===t?.kind?" boundary-open":"shared"===t?.kind?" boundary-solid":t&&"none"!==t.kind?" boundary-invalid":""}_renderOpenWalls(t){if(t&&!t.showBorders&&!this._editing)return B``;const e=this._openCuts(),i=this._boundaryPreview;if(!e.length&&!i)return B``;const s=(t,e=!1)=>e?B` +
`}_cssPxToRender(t){const e=this._stageEl,i=this._viewOr(this._baseVb());return e?.clientWidth&&e.clientHeight?Math.max(i.w/e.clientWidth,i.h/e.clientHeight)*t:this._gridPitch/8*t}get _boundaryCoarse(){return"touch"===this._boundaryPointerType||"pen"===this._boundaryPointerType}_boundaryTolerances(){return{hit:this._cssPxToRender(this._boundaryCoarse?22:12),cap:this._cssPxToRender(this._boundaryCoarse?10:6),ambiguity:this._cssPxToRender(6)}}_boundaryBlocked(t,e){const i=this._spaceModel(),s=i=>ya(t,i)||i.some((s,o)=>{const n=i[(o+1)%i.length];return Ss(t,[s[0],s[1],n[0],n[1]])<=e});for(const t of i.wall_columns||[])if(s(ha(t,this._cellCm,this._gridPitch)))return!0;for(const s of i.partitions||[]){const i=dr(s.cm,this._cellCm,this._gridPitch)/2;if(Ss(t,[s.a[0],s.a[1],s.b[0],s.b[1]])<=Math.max(e,i))return!0}for(const s of i.room_drafts||[])for(let i=0;i+10?dr(s,this._cellCm,this._gridPitch)/2:0)}_boundaryTargetAt(t){const e=this._viewOr(this._baseVb()),i=this._stageEl,s=[this._space,this._cfgEpoch,t[0],t[1],this._boundaryPointerType,e.x,e.y,e.w,e.h,i?.clientWidth||0,i?.clientHeight||0].join("|");if(this._boundaryTargetMemo?.key===s)return this._boundaryTargetMemo.value;const o=this._boundaryTolerances(),n=this._openCuts();let r=function(t,e,i,s){const{openPull:o,openEndCap:n,solidPull:r,ambiguity:a,eps:l}=s,c=yl(e,l),h=[];for(const e of i||[]){const i=$l(t,e,o,n);if(null==i)continue;const s=[(e[0]+e[2])/2,(e[1]+e[3])/2],r=c.find(t=>Ss(s,t.seg)<=4*l);h.push({value:e,seg:e,semantic:r?.pair||`open:${e.join(",")}`,distance:i})}const d=Sl(h,a,l);if("ambiguous"===d)return{kind:"ambiguous",group:"open"};if(d)return{kind:"open",seg:d.value,distance:d.distance};const p=[];for(const e of c){const i=$l(t,e.seg,r(e.seg));null!=i&&p.push({value:e,seg:e.seg,semantic:e.pair,distance:i})}const u=Sl(p,a,l);if("ambiguous"===u)return{kind:"ambiguous",group:"shared"};if(u)return{kind:"shared",a:u.value.a,b:u.value.b,edge:u.value.seg,distance:u.distance};const _=[];for(const i of e||[]){if(!i?.id)continue;const e=Je(i);if(e)for(let s=0;sSs(d,t.seg)<=4*l)||_.push({value:{room:i,edge:a},seg:a,semantic:String(i.id),distance:h})}}const m=Sl(_,a,l);return"ambiguous"===m?{kind:"ambiguous",group:"outer"}:m?{kind:"outer",...m.value,distance:m.distance}:{kind:"none"}}(t,this._spaceModel().rooms,n,{openPull:o.hit,openEndCap:o.cap,ambiguity:o.ambiguity,eps:.02*this._gridPitch,solidPull:t=>this._solidBoundaryPull(t,n)});return"shared"!==r.kind&&"open"!==r.kind||!this._boundaryBlocked(t,o.hit)||(r={kind:"blocked"}),this._boundaryTargetMemo={key:s,value:r},r}get _boundaryTarget(){return this._markup&&"boundary"===this._tool&&this._cursorPt?this._boundaryTargetAt(this._cursorPt):null}get _boundaryPreview(){const t=this._viewOr(this._baseVb()),e=this._stageEl,i=this._cursorPt,s=this._openWallAnchor,o=[this._markup,this._tool,this._space,this._cfgEpoch,this._boundaryPointerType,i?.[0]??"none",i?.[1]??"none",s?.p?.[0]??"none",s?.p?.[1]??"none",s?.edge?.join(",")??"none",s?.aId??"none",s?.bId??"none",t.x,t.y,t.w,t.h,e?.clientWidth||0,e?.clientHeight||0].join("|");if(this._boundaryPreviewMemo?.key===o)return this._boundaryPreviewMemo.value;const n=t=>(this._boundaryPreviewMemo={key:o,value:t},t);if(!this._markup||"boundary"!==this._tool)return n(null);if(s&&!i)return n({kind:"anchor",point:[...s.p]});if(!i)return n(null);const r=this._openCuts(),a=.02*this._gridPitch;if(s){const{p:t,edge:e}=s,o=fl(vl(i,e,Cl(e,r,a),this._gridPitch,1.5*this._gridPitch),e),l=this._boundaryBlocked(i,this._boundaryTolerances().hit)||Ss(i,e)>this._solidBoundaryPull(e,r);return n({kind:"range",seg:[t[0],t[1],o[0],o[1]],invalid:l})}const l=this._boundaryTargetAt(i);if("shared"===l.kind){return n({kind:"anchor",point:vl(i,l.edge,Cl(l.edge,r,a),this._gridPitch,1.5*this._gridPitch)})}if("open"===l.kind){const t=this._planClosedOpenSpan(l.seg),e=t?ca([l.seg[0],l.seg[1]],[l.seg[2],l.seg[3]],t.cm,this._cellCm,this._gridPitch):null;return n({kind:"restore",seg:l.seg,body:e})}return"blocked"===l.kind||"ambiguous"===l.kind||"outer"===l.kind?n({kind:"invalid",point:i}):n(null)}get _boundaryHintKey(){if(this._openWallAnchor){const t=this._boundaryPreview;return"range"===t?.kind&&t.invalid?"markup.boundary_hint_retry":"markup.boundary_hint_second"}const t=this._boundaryTarget;return t&&"none"!==t.kind?"open"===t.kind?"markup.boundary_hint_restore":"shared"===t.kind?"markup.boundary_hint_open":"outer"===t.kind?"markup.boundary_hint_outer":"blocked"===t.kind?"markup.boundary_hint_blocked":"markup.boundary_hint_ambiguous":"markup.boundary_hint"}get _boundaryStageClass(){if(!this._markup||"boundary"!==this._tool)return"";if(this._openWallAnchor){const t=this._boundaryPreview;return"range"===t?.kind&&t.invalid?" boundary-invalid":" boundary-solid"}const t=this._boundaryTarget;return"open"===t?.kind?" boundary-open":"shared"===t?.kind?" boundary-solid":t&&"none"!==t.kind?" boundary-invalid":""}_renderOpenWalls(t){if(t&&!t.showBorders&&!this._editing)return j``;const e=this._openCuts(),i=this._boundaryPreview;if(!e.length&&!i)return j``;const s=(t,e=!1)=>e?j` - `:B``;return B` - ${e.map(t=>B``:j``;return j` + ${e.map(t=>j``)} - ${"range"===i?.kind?B` ${s([i.seg[0],i.seg[1]])} ${s([i.seg[2],i.seg[3]],i.invalid)}`:W} - ${"restore"===i?.kind&&i.body?B``${t[0]} ${t[1]}`).join(" L ")} Z`}>`:W} ${"anchor"===i?.kind?s(i.point):"invalid"===i?.kind?s(i.point,!0):W} - `;var o}_openCuts(){const t=this._curSpaceCfg;return al(this._spaceModel().rooms,t?.open_spans,Nc,.02*this._gridPitch)}_openPairs(){const t=this._openCuts();if(!t.length)return[];const e=this._spaceModel().rooms.filter(t=>t.id),i=.02*this._gridPitch,s=[];for(let o=0;o{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return l.some(t=>gs(e,t)<4*i)});c.length&&s.push({a:e[o],b:e[n],segs:c})}return s}_commitOpenSpans(t){const e=this._curSpaceCfg;if(!e)return;const i=.02*this._gridPitch;this._cfgEpoch++;const s=this._spaceModel().rooms;let o=il(e.open_spans);o.length&&t?.old.length?o=gl(o,t.old,t.next,Nc):o.length||(o=ll(al(s,null,Nc,i),Nc)),o=ml(o,s,Nc,i),this._persistOpenCuts(o.map(t=>tl(t,Nc)))}_persistOpenCuts(t){const e=this._curSpaceCfg;if(!e)return;const i=.02*this._gridPitch,s=ml(ll(t,Nc),this._spaceModel().rooms,Nc,i),o=s.map(t=>tl(t,Nc));s.length?e.open_spans=s:delete e.open_spans,cl(e.rooms||[],this._spaceModel().rooms,o,i)}_planClosedOpenSpan(t){const e=this._curSpaceCfg;if(!e)return null;const i=.02*this._gridPitch,s=this._openCuts();let o=Array.isArray(e.walls)?e.walls.slice():[];for(const t of Rr(this._spaceModel().rooms,o,s,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc))!t.open&&t.cm>0&&(o=fr(o,t.a,t.b,t.cm,this._wallKeyPitch,Nc));const n=function(t,e,i){const s=[(e[0]+e[2])/2,(e[1]+e[3])/2];return t.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return Math.hypot(e[0]-s[0],e[1]-s[1])>4*i})}(s,t,i);let r=this._normalizeWalls(o,n),a=Ar(this._spaceModel().rooms,r,n,t,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc);if(!(a>0)){const e=[];for(const t of Rr(this._spaceModel().rooms,r,n,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc))t.open||e.push([t.a[0],t.a[1],t.b[0],t.b[1]]);r=ul(r,t,e,this._wallKeyPitch,Nc,Xn),r=this._normalizeWalls(r,n),a=Ar(this._spaceModel().rooms,r,n,t,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)}return{cuts:n,walls:r,cm:a>0?a:Xn}}_closeOpenSpan(t){const e=this._curSpaceCfg;if(!e)return;const i=this._geometrySnapshot(),s=this._planClosedOpenSpan(t);s&&(s.walls.length?e.walls=s.walls:delete e.walls,this._persistOpenCuts(s.cuts),this._showToast(this._t("toast.boundary_restored")),this._recordGeometry(this._t("history.close_boundary"),i),this._saveConfig(),this.requestUpdate())}_boundaryClick(t){const e=this._boundaryRestoreGuard;if(e&&Date.now()>e.until&&(this._boundaryRestoreGuard=null),e&&Date.now()<=e.until&&Math.hypot(t[0]-e.point[0],t[1]-e.point[1])<=this._boundaryTolerances().hit)return;const i=.02*this._gridPitch,s=this._openCuts();if(this._openWallAnchor){const{p:e,edge:l}=this._openWallAnchor;if(gs(t,l)>this._solidBoundaryPull(l,s))return void this._showToast(this._t("toast.boundary_same_edge"));if(this._boundaryBlocked(t,this._boundaryTolerances().hit))return void this._showToast(this._t("toast.boundary_blocked"));const c=ol(nl(t,l,_l(l,s,i),this._gridPitch,1.5*this._gridPitch),l),h=Math.hypot(c[0]-e[0],c[1]-e[1]);if(this._openWallAnchor=null,this._cursorPt=null,h<.5*this._gridPitch)return void this._showToast(this._t("toast.openwall_short"));const d=[e[0],e[1],c[0],c[1]],p=[...s,d],u=this._curSpaceCfg;if(!u)return;const _=this._geometrySnapshot(),m=this._normalizeWalls(u.walls,p);m.length?u.walls=m:delete u.walls;const g=(u.openings||[]).length;return u.openings=(o=u.openings,n=d,r=Nc,a=6*this._gridPitch,o?.length?o.filter(t=>gs([Number(t.x)*r,Number(t.y)*r],n)>a||!mr([n[0],n[1]],[n[2],n[3]],Number(t.angle)||0)):o?o.slice():[]),(u.openings||[]).lengththis._pointInRoom(t,e));if(!e)return void this._showToast(this._t("toast.delete_room_pick"));if(!confirm(this._t("confirm.delete_room",{name:e.name})))return;const i=this._curSpaceCfg;if(!i)return;const s=this._geometrySnapshot();i.rooms=i.rooms.filter(t=>t.id!==e.id),this._commitOpenSpans(),this._recordGeometry(this._t("history.delete_room"),s),this._saveConfig(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}get _wallKeyPitch(){return ya}get _spaceWalls(){const t=this._curSpaceCfg?.walls;return Array.isArray(t)?t:[]}_cfgOpenCuts(){return il(this._curSpaceCfg?.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]])}_intervalCm(t){return Ar(this._spaceModel().rooms,this._spaceWalls,this._openCuts(),t,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)}_normalizeWalls(t,e){return _r(zr(this._spaceModel().rooms,t,e,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc),this._curSpaceCfg?.rooms||[],ya,1,e.map(t=>[t[0]/Nc,t[1]/Nc,t[2]/Nc,t[3]/Nc]))}_paperShapes(t){const e=this._spaceWalls;if(!e.length)return Oe(t);const i=this._openPairs().flatMap(t=>t.segs);return Lr(t,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)}_thickWallCuts(){const t=this._spaceWalls;if(!t.length)return[];const e=this._openPairs().flatMap(t=>t.segs);return function(t,e,i,s,o,n,r=1){if(!e?.length)return[];const a=new Set,l=[];for(const c of t||[]){if(!c?.id)continue;const h=Pr(t,c.id,e,i,s,o,n,r);if(!h)continue;const d=h.poly;for(let t=0;t0))continue;const u=rr(e,i,s,r);if(a.has(u))continue;a.add(u);const _=ir(p,o,n),[m,g]=kr(d,t),f=-m,v=-g,y=_/2,b=[[e[0]+f*y,e[1]+v*y],[i[0]+f*y,i[1]+v*y],[i[0]+m*y,i[1]+g*y],[e[0]+m*y,e[1]+g*y]];l.push({key:u,kind:c,cm:p,quad:b,a:[e[0],e[1]],b:[i[0],i[1]],depthUnits:_})}}return l}(this._spaceModel().rooms,t,e,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]])}_wallThickHit(t){const e=6*this._gridPitch,i=this._openCuts();let s=null;for(const o of Rr(this._spaceModel().rooms,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)){const i=gs(t,[o.a[0],o.a[1],o.b[0],o.b[1]]);i<=e&&(!s||i0?ir(e,this._cellCm,this._gridPitch):3*this._gridPitch,s=Math.max(i/2,1.25*this._gridPitch);let o="";for(const e of t.segs)o+=(o?" ":"")+yr([[e[0],e[1]],[e[2],e[3]]],s,!1);return{segs:t.segs,open:t.open,d:o}}_wallThickClick(t){const e=this._wallThickHit(t);if(!e)return void this._showToast(this._t("toast.wallthick_pick"));if(e.open)return void this._showToast(this._t("toast.wallthick_open"));const i=e.cm,s=this._viewOr(this._baseVb()),o=(e.a[0]+e.b[0])/2,n=(e.a[1]+e.b[1])/2;this._wallDialog={a:e.a,b:e.b,value:er(i,this._imperial),roomId:e.roomId,sx:(o-s.x)/s.w*100,sy:(n-s.y)/s.h*100}}_wallThickApply(t){const e=this._wallDialog;if(!e)return;const i=this._curSpaceCfg;if(!i)return;const s=e.value.trim(),o=s?wc(s):0;if(null==o)return void this._showPhysicalRange(100);const n=this._imperial?2.54*o:o;if(s&&(!Number.isFinite(n)||n<0||n>0&&n<1||n>100))return void this._showPhysicalRange(100);const r=this._geometrySnapshot(),a=s&&n>0?n:null,l=this._openCuts();let c;c=t&&e.roomId?vr(i.walls,this._spaceModel().rooms,e.roomId,a,this._wallKeyPitch,l,Nc):fr(i.walls,e.a,e.b,a,this._wallKeyPitch,Nc),c=this._normalizeWalls(c,l),c.length?i.walls=c:delete i.walls,this._wallDialog=null,this._showToast(this._t(null==a?"toast.wallthick_cleared":"toast.wallthick_set")),this._recordGeometry(this._t("history.wall_thickness"),r),this._saveConfig(),this.requestUpdate()}_wallHatchDefs(t){if(!this._spaceWalls.length&&!this._physicalBodiesR().length&&!this._markup)return B``;const e=Math.max(.4,1/Math.max(this._zoom,.4)),i=t||"#607d8b";return B` + `;var o}_openCuts(){const t=this._curSpaceCfg;return bl(this._spaceModel().rooms,t?.open_spans,eh,.02*this._gridPitch)}_openPairs(){const t=this._openCuts();if(!t.length)return[];const e=this._spaceModel().rooms.filter(t=>t.id),i=.02*this._gridPitch,s=[];for(let o=0;o{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return l.some(t=>Ss(e,t)<4*i)});c.length&&s.push({a:e[o],b:e[n],segs:c})}return s}_commitOpenSpans(t){const e=this._curSpaceCfg;if(!e)return;const i=.02*this._gridPitch;this._cfgEpoch++;const s=this._spaceModel().rooms;let o=ml(e.open_spans);o.length&&t?.old.length?o=Tl(o,t.old,t.next,eh):o.length||(o=wl(bl(s,null,eh,i),eh)),o=Dl(o,s,eh,i),this._persistOpenCuts(o.map(t=>ul(t,eh)))}_persistOpenCuts(t){const e=this._curSpaceCfg;if(!e)return;const i=.02*this._gridPitch,s=Dl(wl(t,eh),this._spaceModel().rooms,eh,i),o=s.map(t=>ul(t,eh));s.length?e.open_spans=s:delete e.open_spans,kl(e.rooms||[],this._spaceModel().rooms,o,i)}_planClosedOpenSpan(t){const e=this._curSpaceCfg;if(!e)return null;const i=.02*this._gridPitch,s=this._openCuts();let o=Array.isArray(e.walls)?e.walls.slice():[];for(const t of Hr(this._spaceModel().rooms,o,s,this._wallKeyPitch,this._cellCm,this._gridPitch,eh))!t.open&&t.cm>0&&(o=Mr(o,t.a,t.b,t.cm,this._wallKeyPitch,eh));const n=function(t,e,i){const s=[(e[0]+e[2])/2,(e[1]+e[3])/2];return t.filter(t=>{const e=[(t[0]+t[2])/2,(t[1]+t[3])/2];return Math.hypot(e[0]-s[0],e[1]-s[1])>4*i})}(s,t,i);let r=this._normalizeWalls(o,n),a=Ur(this._spaceModel().rooms,r,n,t,this._wallKeyPitch,this._cellCm,this._gridPitch,eh);if(!(a>0)){const e=[];for(const t of Hr(this._spaceModel().rooms,r,n,this._wallKeyPitch,this._cellCm,this._gridPitch,eh))t.open||e.push([t.a[0],t.a[1],t.b[0],t.b[1]]);r=Ml(r,t,e,this._wallKeyPitch,eh,ar),r=this._normalizeWalls(r,n),a=Ur(this._spaceModel().rooms,r,n,t,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)}return{cuts:n,walls:r,cm:a>0?a:ar}}_closeOpenSpan(t){const e=this._curSpaceCfg;if(!e)return;const i=this._geometrySnapshot(),s=this._planClosedOpenSpan(t);s&&(s.walls.length?e.walls=s.walls:delete e.walls,this._persistOpenCuts(s.cuts),this._showToast(this._t("toast.boundary_restored")),this._recordGeometry(this._t("history.close_boundary"),i),this._saveConfig(),this.requestUpdate())}_boundaryClick(t){const e=this._boundaryRestoreGuard;if(e&&Date.now()>e.until&&(this._boundaryRestoreGuard=null),e&&Date.now()<=e.until&&Math.hypot(t[0]-e.point[0],t[1]-e.point[1])<=this._boundaryTolerances().hit)return;const i=.02*this._gridPitch,s=this._openCuts();if(this._openWallAnchor){const{p:e,edge:l}=this._openWallAnchor;if(Ss(t,l)>this._solidBoundaryPull(l,s))return void this._showToast(this._t("toast.boundary_same_edge"));if(this._boundaryBlocked(t,this._boundaryTolerances().hit))return void this._showToast(this._t("toast.boundary_blocked"));const c=fl(vl(t,l,Cl(l,s,i),this._gridPitch,1.5*this._gridPitch),l),h=Math.hypot(c[0]-e[0],c[1]-e[1]);if(this._openWallAnchor=null,this._cursorPt=null,h<.5*this._gridPitch)return void this._showToast(this._t("toast.openwall_short"));const d=[e[0],e[1],c[0],c[1]],p=[...s,d],u=this._curSpaceCfg;if(!u)return;const _=this._geometrySnapshot(),m=this._normalizeWalls(u.walls,p);m.length?u.walls=m:delete u.walls;const g=(u.openings||[]).length;return u.openings=(o=u.openings,n=d,r=eh,a=6*this._gridPitch,o?.length?o.filter(t=>Ss([Number(t.x)*r,Number(t.y)*r],n)>a||!xr([n[0],n[1]],[n[2],n[3]],Number(t.angle)||0)):o?o.slice():[]),(u.openings||[]).lengththis._pointInRoom(t,e));if(!e)return void this._showToast(this._t("toast.delete_room_pick"));if(!confirm(this._t("confirm.delete_room",{name:e.name})))return;const i=this._curSpaceCfg;if(!i)return;const s=this._geometrySnapshot();i.rooms=i.rooms.filter(t=>t.id!==e.id),this._commitOpenSpans(),this._recordGeometry(this._t("history.delete_room"),s),this._saveConfig(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}get _wallKeyPitch(){return Aa}get _spaceWalls(){const t=this._curSpaceCfg?.walls;return Array.isArray(t)?t:[]}_cfgOpenCuts(){return ml(this._curSpaceCfg?.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]])}_intervalCm(t){return Ur(this._spaceModel().rooms,this._spaceWalls,this._openCuts(),t,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)}_normalizeWalls(t,e){return $r(qr(this._spaceModel().rooms,t,e,this._wallKeyPitch,this._cellCm,this._gridPitch,eh),this._curSpaceCfg?.rooms||[],Aa,1,e.map(t=>[t[0]/eh,t[1]/eh,t[2]/eh,t[3]/eh]))}_paperShapes(t){const e=this._spaceWalls;if(!e.length)return Ze(t);const i=this._openPairs().flatMap(t=>t.segs);return Yr(t,e,i,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)}_thickWallCuts(){const t=this._spaceWalls;if(!t.length)return[];const e=this._openPairs().flatMap(t=>t.segs);return function(t,e,i,s,o,n,r=1){if(!e?.length)return[];const a=new Set,l=[];for(const c of t||[]){if(!c?.id)continue;const h=Lr(t,c.id,e,i,s,o,n,r);if(!h)continue;const d=h.poly;for(let t=0;t0))continue;const u=mr(e,i,s,r);if(a.has(u))continue;a.add(u);const _=dr(p,o,n),[m,g]=Rr(d,t),f=-m,v=-g,y=_/2,b=[[e[0]+f*y,e[1]+v*y],[i[0]+f*y,i[1]+v*y],[i[0]+m*y,i[1]+g*y],[e[0]+m*y,e[1]+g*y]];l.push({key:u,kind:c,cm:p,quad:b,a:[e[0],e[1]],b:[i[0],i[1]],depthUnits:_})}}return l}(this._spaceModel().rooms,t,e,this._wallKeyPitch,this._cellCm,this._gridPitch,eh).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]])}_wallThickHit(t){const e=6*this._gridPitch,i=this._openCuts();let s=null;for(const o of Hr(this._spaceModel().rooms,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)){const i=Ss(t,[o.a[0],o.a[1],o.b[0],o.b[1]]);i<=e&&(!s||i0?dr(e,this._cellCm,this._gridPitch):3*this._gridPitch,s=Math.max(i/2,1.25*this._gridPitch);let o="";for(const e of t.segs)o+=(o?" ":"")+Dr([[e[0],e[1]],[e[2],e[3]]],s,!1);return{segs:t.segs,open:t.open,d:o}}_wallThickClick(t){const e=this._wallThickHit(t);if(!e)return void this._showToast(this._t("toast.wallthick_pick"));if(e.open)return void this._showToast(this._t("toast.wallthick_open"));const i=e.cm,s=this._viewOr(this._baseVb()),o=(e.a[0]+e.b[0])/2,n=(e.a[1]+e.b[1])/2;this._wallDialog={a:e.a,b:e.b,value:hr(i,this._imperial),roomId:e.roomId,sx:(o-s.x)/s.w*100,sy:(n-s.y)/s.h*100}}_wallThickApply(t){const e=this._wallDialog;if(!e)return;const i=this._curSpaceCfg;if(!i)return;const s=e.value.trim(),o=s?Hc(s):0;if(null==o)return void this._showPhysicalRange(100);const n=this._imperial?2.54*o:o;if(s&&(!Number.isFinite(n)||n<0||n>0&&n<1||n>100))return void this._showPhysicalRange(100);const r=this._geometrySnapshot(),a=s&&n>0?n:null,l=this._openCuts();let c;c=t&&e.roomId?Cr(i.walls,this._spaceModel().rooms,e.roomId,a,this._wallKeyPitch,l,eh):Mr(i.walls,e.a,e.b,a,this._wallKeyPitch,eh),c=this._normalizeWalls(c,l),c.length?i.walls=c:delete i.walls,this._wallDialog=null,this._showToast(this._t(null==a?"toast.wallthick_cleared":"toast.wallthick_set")),this._recordGeometry(this._t("history.wall_thickness"),r),this._saveConfig(),this.requestUpdate()}_wallHatchDefs(t){if(!this._spaceWalls.length&&!this._physicalBodiesR().length&&!this._markup)return j``;const e=Math.max(.4,1/Math.max(this._zoom,.4)),i=t||"#607d8b";return j` - `}_resolvedRoomFills(t,e){const i=new Map,s=new Map;for(const o of t.rooms){const t=this._roomDialog&&o.id===this._roomEditId?this._roomFill||e.fill:ds(e.fill,o),n=this._roomDialog&&o.id===this._roomEditId?this._roomCustomFill||e.customFill:Ni(e.customFill,o),r=Ui(t,"lqi"===t&&o.area?this._roomLqi(o.area):null,"light"===t?fo(mo(this._planHass,this._devices,o)):"none","temp"===t?this._roomTemp(o):null,e.tempMin,e.tempMax,this._fillColors,n);i.set(o,r),o.id&&s.set(o.id,r)}return{byRoom:i,byId:s}}_spaceDisplayForRender(){const t=Fi(this._curSpaceCfg),e=this._spaceDialog;return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,showBorders:e.showBorders,showNames:e.showNames,hideDecor:e.hideDecor,hideOpenings:e.hideOpenings,color:e.roomColor,opacity:e.roomOpacity,fill:e.fillMode,customFill:e.customFill?Ei(e.customFill):Ii,glow:e.glowEnabled,tempMin:e.tempMin,tempMax:e.tempMax,showLqi:e.showLqi,cardFontScale:e.cardFontScale,labelTemp:e.labelTemp,labelHum:e.labelHum,labelLqi:e.labelLqi,labelLight:e.labelLight}:t}_openingWallIndexFor(t,e){const i=t.rooms.map(t=>`${t.id}:${t.poly?.map(t=>t.join(",")).join("/")||`${t.x},${t.y},${t.w},${t.h}`}`).join(";"),s=this._spaceWalls.map(t=>`${t.key}:${t.a?.join(",")||""}:${t.b?.join(",")||""}:${t.cm}`).join(";"),o=e.map(t=>t.join(",")).join(";"),n=[t.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,s,o].join("|");return this._openingWallIndexCache&&this._openingWallIndexCache.key===n||(this._openingWallIndexCache={key:n,value:Hr(t.rooms,this._spaceWalls,e,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)}),this._openingWallIndexCache}_renderOpeningTunnelFills(t,e,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return B``;if("glow-base"===i&&![...e.byRoom.values()].some(Boolean))return B``;const s=this._openPairs().flatMap(t=>t.segs),o=this._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),n=o.map(t=>`${t.x},${t.y},${t.angle},${t.length}`).join(";"),r=this._openingWallIndexFor(t,s),a=`${r.key}|${n}`;return this._openingTunnelCache&&this._openingTunnelCache.key===a||(this._openingTunnelCache={key:a,value:Vr(r.value,o)}),function({openings:t,geometries:e,fillsByRoomId:i,idPrefix:s="data",groupClass:o="opening-tunnels",dataLayer:n="data"}){const r=t.map((t,o)=>{const n=e[o];if(!n)return W;const r=n.faces.find(t=>-1===t.side),a=n.faces.find(t=>1===t.side);if(!r||!a)return W;const l=i.get(r.roomId)||null,c=i.get(a.roomId)||null;if(!l&&!c)return W;const h=`${r.d} ${a.d}`,d=!!l&&!!c&&l.color===c.color&&l.opacity===c.opacity,p=`translate(${t.rx} ${t.ry}) rotate(${t.angle})`;if(d)return B``}_resolvedRoomFills(t,e){const i=new Map,s=new Map;for(const o of t.rooms){const t=this._roomDialog&&o.id===this._roomEditId?this._roomFill||e.fill:bs(e.fill,o),n=this._roomDialog&&o.id===this._roomEditId?this._roomCustomFill||e.customFill:Ki(e.customFill,o),r=ts(t,"lqi"===t&&o.area?this._roomLqi(o.area):null,"light"===t?Mo(xo(this._planHass,this._devices,o)):"none","temp"===t?this._roomTemp(o):null,e.tempMin,e.tempMax,this._fillColors,n);i.set(o,r),o.id&&s.set(o.id,r)}return{byRoom:i,byId:s}}_spaceDisplayForRender(){const t=Yi(this._curSpaceCfg),e=this._spaceDialog;return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,showBorders:e.showBorders,showNames:e.showNames,hideDecor:e.hideDecor,hideOpenings:e.hideOpenings,color:e.roomColor,opacity:e.roomOpacity,fill:e.fillMode,customFill:e.customFill?Vi(e.customFill):Wi,glow:e.glowEnabled,tempMin:e.tempMin,tempMax:e.tempMax,showLqi:e.showLqi,cardFontScale:e.cardFontScale,labelTemp:e.labelTemp,labelHum:e.labelHum,labelLqi:e.labelLqi,labelLight:e.labelLight}:t}_openingWallIndexFor(t,e){const i=t.rooms.map(t=>`${t.id}:${t.poly?.map(t=>t.join(",")).join("/")||`${t.x},${t.y},${t.w},${t.h}`}`).join(";"),s=this._spaceWalls.map(t=>`${t.key}:${t.a?.join(",")||""}:${t.b?.join(",")||""}:${t.cm}`).join(";"),o=e.map(t=>t.join(",")).join(";"),n=[t.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,s,o].join("|");return this._openingWallIndexCache&&this._openingWallIndexCache.key===n||(this._openingWallIndexCache={key:n,value:Jr(t.rooms,this._spaceWalls,e,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)}),this._openingWallIndexCache}_renderOpeningTunnelFills(t,e,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return j``;if("glow-base"===i&&![...e.byRoom.values()].some(Boolean))return j``;const s=this._openPairs().flatMap(t=>t.segs),o=this._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),n=o.map(t=>`${t.x},${t.y},${t.angle},${t.length}`).join(";"),r=this._openingWallIndexFor(t,s),a=`${r.key}|${n}`;return this._openingTunnelCache&&this._openingTunnelCache.key===a||(this._openingTunnelCache={key:a,value:sa(r.value,o)}),function({openings:t,geometries:e,fillsByRoomId:i,idPrefix:s="data",groupClass:o="opening-tunnels",dataLayer:n="data"}){const r=t.map((t,o)=>{const n=e[o];if(!n)return W;const r=n.faces.find(t=>-1===t.side),a=n.faces.find(t=>1===t.side);if(!r||!a)return W;const l=i.get(r.roomId)||null,c=i.get(a.roomId)||null;if(!l&&!c)return W;const h=`${r.d} ${a.d}`,d=!!l&&!!c&&l.color===c.color&&l.opacity===c.opacity,p=`translate(${t.rx} ${t.ry}) rotate(${t.angle})`;if(d)return j``;const u=n.maxY-n.minY;if(!(u>0))return W;const _=`${(100*Math.max(0,Math.min(1,-n.minY/u))).toFixed(6)}%`,m=l||{color:"#000000",opacity:0},g=c||{color:"#000000",opacity:0},f=`hp-opening-tunnel-${s.replace(/[^a-zA-Z0-9_-]/g,"-")}-${o}`;return B``;const u=n.maxY-n.minY;if(!(u>0))return W;const _=`${(100*Math.max(0,Math.min(1,-n.minY/u))).toFixed(6)}%`,m=l||{color:"#000000",opacity:0},g=c||{color:"#000000",opacity:0},f=`hp-opening-tunnel-${s.replace(/[^a-zA-Z0-9_-]/g,"-")}-${o}`;return j``});return B``}({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:e.byId,idPrefix:`${t.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(t,e,i){const s=new Map,o=new Map,n=this._fillColors.glow_base;for(const r of t.rooms){const t=i.byRoom.get(r),a=ps(e.glow,r)&&(!t||t.opacity<=0)?{color:n.c,opacity:n.a,mode:"glow"}:null;s.set(r,a),r.id&&o.set(r.id,a)}return{byRoom:s,byId:o}}_renderGlowBaseRooms(t,e){if(this._markup||![...e.byRoom.values()].some(Boolean))return B``;const i=new Map(t.rooms.map(t=>[t,Fe(t)])),s=this._openPairs().flatMap(t=>t.segs),o=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",n=t.rooms.map(n=>{const r=e.byRoom.get(n)||null,a=i.get(n)||null;if(!r||!a)return W;const l=this._spaceWalls.length&&n.id&&Er(t.rooms,n.id,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)||a,c=ii(l,t.rooms.filter(t=>t!==n).map(t=>i.get(t)).filter(t=>!!t)),h=this._cleanFloor(n,l,t).path;return h||c.length?B``});return j``}({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:e.byId,idPrefix:`${t.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(t,e,i){const s=new Map,o=new Map,n=this._fillColors.glow_base;for(const r of t.rooms){const t=i.byRoom.get(r),a=ws(e.glow,r)&&(!t||t.opacity<=0)?{color:n.c,opacity:n.a,mode:"glow"}:null;s.set(r,a),r.id&&o.set(r.id,a)}return{byRoom:s,byId:o}}_renderGlowBaseRooms(t,e){if(this._markup||![...e.byRoom.values()].some(Boolean))return j``;const i=new Map(t.rooms.map(t=>[t,Je(t)])),s=this._openPairs().flatMap(t=>t.segs),o=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",n=t.rooms.map(n=>{const r=e.byRoom.get(n)||null,a=i.get(n)||null;if(!r||!a)return W;const l=this._spaceWalls.length&&n.id&&jr(t.rooms,n.id,this._spaceWalls,s,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)||a,c=_i(l,t.rooms.filter(t=>t!==n).map(t=>i.get(t)).filter(t=>!!t)),h=this._cleanFloor(n,l,t).path;return h||c.length?j``:n.poly||l!==a?B``:n.poly||l!==a?j``:B``:j``});return B``}_renderSvgRoomLabels(t,e){return t.bg||e.showNames||this._markup?B``:B`${t.rooms.map(t=>{const e=this._roomCenter(t);return B``});return j``}_renderSvgRoomLabels(t,e){return t.bg||e.showNames||this._markup?j``:j`${t.rooms.map(t=>{const e=this._roomCenter(t);return j`${t.name}`})}`}_renderWallBodies(t){if(t&&!t.showBorders&&("view"===this._mode||"devices"===this._mode))return B``;const e=this._spaceWalls,i=this._physicalBodiesR();if(!e.length&&!i.length)return B``;const s=this._openPairs().flatMap(t=>t.segs),o=(this._curSpaceCfg?.openings||[]).map(t=>({x:Number(t.x)*Nc,y:Number(t.y)*Nc,angle:Number(t.angle)||0,length:(Number(t.length)>0?Number(t.length):.9)*Nc})),n=`${this._space}|${this._cfgEpoch}|${this._spaceModel().rooms.length}`;this._wallUnionCache&&this._wallUnionCache.key===n||(this._wallUnionCache={key:n,value:Fr(this._spaceModel().rooms,e,s,o,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc,i)});const r=this._wallUnionCache.value;if(!r)return B``;const a=this._stageEl,l=this._viewOr(this._baseVb()),c=a&&a.clientWidth&&l.w?a.clientWidth/l.w:1,h=t?.color||"#607d8b",d=Qn(r.depthUnits,c),p=this._fillColors.wall_fill;return B` + x=${e[0]} y=${e[1]}>${t.name}`})}`}_renderWallBodies(t){if(t&&!t.showBorders&&("view"===this._mode||"devices"===this._mode))return j``;const e=this._spaceWalls,i=this._physicalBodiesR();if(!e.length&&!i.length)return j``;const s=this._openPairs().flatMap(t=>t.segs),o=(this._curSpaceCfg?.openings||[]).map(t=>({x:Number(t.x)*eh,y:Number(t.y)*eh,angle:Number(t.angle)||0,length:(Number(t.length)>0?Number(t.length):.9)*eh})),n=`${this._space}|${this._cfgEpoch}|${this._spaceModel().rooms.length}`;this._wallUnionCache&&this._wallUnionCache.key===n||(this._wallUnionCache={key:n,value:Vr(this._spaceModel().rooms,e,s,o,this._wallKeyPitch,this._cellCm,this._gridPitch,eh,i)});const r=this._wallUnionCache.value;if(!r)return j``;const a=this._stageEl,l=this._viewOr(this._baseVb()),c=a&&a.clientWidth&&l.w?a.clientWidth/l.w:1,h=t?.color||"#607d8b",d=lr(r.depthUnits,c),p=this._fillColors.wall_fill;return j` @@ -4055,8 +4123,12 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 data-hp="wall" data-id="union" data-kind="union" d="${r.d}" fill="${d?"none":"url(#hp-wall-hatch)"}" fill-rule=${r.fillRule} stroke="${h}" stroke-width="0.6" pointer-events="none"> - `}_renderRoomHover(t){const e=this._hoverRoom;if("view"!==this._mode||!e||e.space!==t.id)return B``;const i=t.rooms.find(t=>t===e.room||!!t.id&&t.id===e.room.id);if(!i)return B``;const s=Fe(i);if(!s)return B``;const o=t.rooms.filter(t=>t!==i).map(t=>({room:t,poly:Fe(t)})).filter(t=>!!t.poly),n=ii(s,o.map(t=>t.poly)),r=this._openPairs(),a=r.flatMap(t=>t.segs),l=i.id?r.filter(t=>t.a.id===i.id||t.b.id===i.id).flatMap(t=>t.segs):r.flatMap(t=>t.segs),c=this._spaceWalls,h=[{axis:s,face:c.length&&i.id&&Er(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)||s}];for(const e of n){const i=o.find(t=>t.poly===e)?.room;let s=e;if(c.length&&i?.id){const o=Pr(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc);o&&(s=Or(o.poly,o.offsets)||e)}h.push({axis:e,face:s})}const d=this._openingsR.map(t=>{const e=t.angle*Math.PI/180,i=Math.cos(e)*t.rlen/2,s=Math.sin(e)*t.rlen/2;return[t.rx-i,t.ry-s,t.rx+i,t.ry+s]}),p=.02*this._gridPitch,u=l.concat(d),_=h.map(({axis:t,face:e})=>{const i=u.map(i=>((t,e,i)=>{const s=t[2]-t[0],o=t[3]-t[1],n=Math.hypot(s,o);if(n.05)&&gs([l,c],[i[0],i[1],s[0],s[1]])<=4*p){h=!0;break}}if(!h)return null;let d=null;for(let t=0;t.05)continue;const u=gs([l,c],[e[0],e[1],s[0],s[1]]);(!d||u!!t);return i.length?rs(e,i,p).map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" "):`M ${e.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");return _?B``:B``}_renderWallThickUi(){const t=this._wallThickHover;return t&&t.d?B``:B``}_renderWallThickDialog(){const t=this._wallDialog;return t?j`
`}_renderRoomHover(t){const e=this._hoverRoom;if("view"!==this._mode||!e||e.space!==t.id)return j``;const i=t.rooms.find(t=>t===e.room||!!t.id&&t.id===e.room.id);if(!i)return j``;const s=Je(i);if(!s)return j``;const o=t.rooms.filter(t=>t!==i).map(t=>({room:t,poly:Je(t)})).filter(t=>!!t.poly),n=_i(s,o.map(t=>t.poly)),r=this._openPairs(),a=r.flatMap(t=>t.segs),l=i.id?r.filter(t=>t.a.id===i.id||t.b.id===i.id).flatMap(t=>t.segs):r.flatMap(t=>t.segs),c=this._spaceWalls,h=c.length&&i.id&&jr(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)||s,d=[{axis:s,face:h}];for(const e of n){const i=o.find(t=>t.poly===e)?.room;let s=e;if(c.length&&i?.id){const o=Lr(t.rooms,i.id,c,a,this._wallKeyPitch,this._cellCm,this._gridPitch,eh);o&&(s=Kr(o.poly,o.offsets)||e)}d.push({axis:e,face:s})}const p=this._openingsR.map(t=>{const e=t.angle*Math.PI/180,i=Math.cos(e)*t.rlen/2,s=Math.sin(e)*t.rlen/2;return[t.rx-i,t.ry-s,t.rx+i,t.ry+s]}),u=.02*this._gridPitch,_=l.concat(p),m=d.map(({axis:t,face:e})=>{const i=_.map(i=>((t,e,i)=>{const s=t[2]-t[0],o=t[3]-t[1],n=Math.hypot(s,o);if(n.05)&&Ss([l,c],[i[0],i[1],s[0],s[1]])<=4*u){h=!0;break}}if(!h)return null;let d=null;for(let t=0;t.05)continue;const p=Ss([l,c],[e[0],e[1],s[0],s[1]]);(!d||p!!t);return i.length?ms(e,i,u).map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" "):`M ${e.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return j``;const g=t=>`M ${t.map(t=>`${t[0]} ${t[1]}`).join(" L ")} Z`,f=[this._cleanFloor(i,h,t).path||g(h),...n.map(g)].join(" ");return j` + + + + `}_renderWallThickUi(){const t=this._wallThickHover;return t&&t.d?j``:j``}_renderWallThickDialog(){const t=this._wallDialog;return t?B`
t.stopPropagation()}>
@@ -4074,8 +4146,8 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
-
`:j``}_openingClick(t){const e=1.5*this._gridPitch,i=this._openingsR.find(i=>Math.hypot(t[0]-i.rx,t[1]-i.ry)<=Math.max(i.rlen/2,e));if(i)return void this._editOpening(i);const s=He(t,this._spaceModel().rooms,e);if(!s)return void this._showToast(this._t("toast.opening_no_wall"));if(function(t,e,i,s,o){for(const n of s)if(!(gs([t,e],n)>o)&&mr([n[0],n[1]],[n[2],n[3]],i))return!0;return!1}(s.x,s.y,s.angle,this._openCuts(),e))return void this._showToast(this._t("toast.opening_on_virtual"));const o=this._opRuler(s,this._cmToUnits(90));this._openingDialog={type:"door",lengthCm:90,contact:"",lock:"",invert:!1,flipH:!1,flipV:!1,x:o.x,y:o.y,angle:o.angle},this._cursorPt=null}_editOpening(t){this._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this._gridPitch*this._cellCm),contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this._mode&&"resize"!==this._tool){t.preventDefault(),t.stopPropagation();try{Uc(t)}catch{}this._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this._opDrag.sx)+Math.abs(t.clientY-this._opDrag.sy)<=3)return;const i=He(this._svgPoint(t),this._spaceModel().rooms,4*this._gridPitch);if(!i)return;this._opDrag.moved=!0;const s=this._curSpaceCfg,o=s?.openings?.find(t=>t.id===e.id);if(!o)return;const n=this._opRuler(i,o.length*Nc);this._opMeasure=n.measure;const r=n.x/Nc,a=n.y/this._spaceH,l=o.x!==r||o.y!==a||o.angle!==i.angle;l&&(this._opDrag.dirty=!0),o.x=r,o.y=a,o.angle=i.angle,l&&this._cfgEpoch++,this.requestUpdate()}_opRuler(t,e){const i=this._spaceModel().rooms,s=this._gridPitch/2;let o=t.x,n=t.y,r=qe([o,n],t.angle,e,i,s);if(r&&r.centered&&(o!==r.wallCenter[0]||n!==r.wallCenter[1]))[o,n]=r.wallCenter,r=qe([o,n],t.angle,e,i,s);else if(r){const[a,l]=r.wallA,[c,h]=r.wallB,d=c-a,p=h-l,u=Math.hypot(d,p);if(u>0){const c=this._gridPitch,h=Math.min(e/2,u/2);let _=Math.round(((o-a)*d+(n-l)*p)/u/c)*c;_=Math.max(h,Math.min(u-h,_)),o=a+_/u*d,n=l+_/u*p,r=qe([o,n],t.angle,e,i,s)||r}}if(!r)return{x:o,y:n,angle:t.angle,measure:null};const a="mi"===this.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:Ee(t/this._gridPitch*this._cellCm,a)});return{x:o,y:n,angle:t.angle,measure:{labels:[l(r.sideA,r.midA),l(r.sideB,r.midB)],guide:r.centered?{x:r.wallCenter[0],y:r.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;const i=this._opDrag,s=i.moved;this._opMeasure=null,s&&i.dirty&&(this._recordGeometry(this._t("history.move_opening"),i.before),this._saveConfig()),s?window.setTimeout(()=>this._opDrag=null,0):this._opDrag=null}_opClick(t,e){"plan"===this._mode&&"resize"===this._tool||(t.stopPropagation(),this._opDrag?.moved||"plan"===this._mode&&this._editOpening(e))}_saveOpening(){const t=this._openingDialog,e=this._curSpaceCfg;if(!t||!e)return;const i=this._geometrySnapshot(),s=this._spaceH,o={id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/Nc,y:t.y/s,angle:t.angle,length:this._cmToUnits(Math.max(20,t.lengthCm))/Nc,contact:t.contact||null,lock:"window"!==t.type&&t.lock||null,invert:t.invert||void 0,flip_h:"gate"!==t.type&&t.flipH||void 0,flip_v:t.flipV||void 0};e.openings=e.openings||[];const n=e.openings.findIndex(t=>t.id===o.id);n>=0?e.openings[n]=o:e.openings.push(o),this._recordGeometry(this._t(t.id?"history.edit_opening":"history.add_opening"),i),this._saveConfig(),this._openingDialog=null,this.requestUpdate()}_deleteOpening(){const t=this._openingDialog,e=this._curSpaceCfg;if(!t?.id||!e?.openings)return;const i=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._recordGeometry(this._t("history.delete_opening"),i),this._saveConfig(),this._openingDialog=null,this.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.hass.states)){if(!this._planEntityAvailable(e))continue;const i=e.split(".")[0];if("binary_sensor"!==i&&"cover"!==i)continue;const s=this.hass.states[e],o=["door","window","opening","garage_door","garage"].includes(s?.attributes?.device_class||"");("cover"!==i||o)&&t.push([e,s?.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.hass.states).filter(t=>t.startsWith("lock.")&&this._planEntityAvailable(t)).map(t=>({value:t,label:this.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_mergeClick(t){const e=this._spaceModel().rooms,i=[...e].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;const s=i.id;if(!this._mergeSel||this._mergeSel===s)return void(this._mergeSel=this._mergeSel===s?null:s);const o=e.find(t=>t.id===this._mergeSel),n=o?Fe(o):null,r=Fe(i),a=n&&r?function(t,e){if(!t||!e||t.length<3||e.length<3)return null;const i=Pe(oi(t),oi(e));if(1!==i.length)return null;if(1!==i[0].length)return null;const s=i[0][0].slice(0,-1).map(t=>[t[0],t[1]]);return s.length>=3?s:null}(n,r):null;if(!a)return this._showToast(this._t("toast.merge_not_adjacent")),void(this._mergeSel=null);this._mergeDialog={aId:this._mergeSel,bId:s,poly:a,pick:"a"},this._mergeSel=null}_commitMerge(){const t=this._mergeDialog,e=this._curSpaceCfg;if(!t||!e)return;const i=this._geometrySnapshot(),s=this._spaceH,o="a"===t.pick?t.aId:t.bId,n="a"===t.pick?t.bId:t.aId,r=e.rooms.find(t=>t.id===o);r?(r.poly=t.poly.map(t=>[t[0]/Nc,t[1]/s]),delete r.x,delete r.y,delete r.w,delete r.h,e.rooms=e.rooms.filter(t=>t.id!==n),this._commitOpenSpans(),this._recordGeometry(this._t("history.merge_rooms"),i),this._saveConfig(),this._mergeDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.rooms_merged",{name:r.name||""}))):this._mergeDialog=null}_splitClick(t){const e=this._spaceModel().rooms;if(!this._splitSel){const i=[...e].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;return void(this._splitSel={roomId:i.id,pts:[]})}const i=e.find(t=>t.id===this._splitSel.roomId),s=i?Fe(i):null;if(!i||!s)return void(this._splitSel=null);const o=.02*this._gridPitch,n=6*this._gridPitch,r=We(t,s),a=r&&function(t,e,i){let s=null,o=1/0;for(let n=0;n=o)continue;o=_;const m=Math.sqrt(p),g=(i>0?Math.max(0,Math.min(m,Math.round(u*m/i)*i)):u*m)/m;s=[r+g*h,a+g*d]}return s}(r,s,this._gridPitch)||r,l=r&&a&&Math.hypot(r[0]-t[0],r[1]-t[1])<=n?a:null,c=!!l&&Ve(l,s,o),h=this._splitSel.pts;if(!h.length)return c?void(this._splitSel={...this._splitSel,pts:[l]}):void this._showToast(this._t("toast.split_pick_wall"));if(!c){const e=this._snap(t);return Ke(e,s,o)?void(this._splitSel={...this._splitSel,pts:[...h,e]}):void this._showToast(this._t("toast.split_pick_inside"))}const d=function(t,e,i=1e-6){if(!t||t.length<3||!e||e.length<2)return null;const s=e[0],o=e[e.length-1];if(je(s,o,i))return null;const n=ni(t,s,i),r=ni(t,o,i);if(n<0||r<0)return null;const a=e.slice(1,-1);for(const e of a)if(!Ke(e,t,i))return null;for(let i=0;i{const r=[e];let a=(s+1)%t.length;for(let e=0;e<=t.length&&(r.push(t[a]),a!==n);e++)a=(a+1)%t.length;return r.push(o),ri(r,i)};let c,h;if(n===r){const r=ri([...e],i);if(r.length<3||si(r)<=i)return null;const a=[];for(let i=0;i=0?e:[...e].reverse();for(const t of i)a.push(t)}c=ri(a,i),h=r}else c=ri([...l(s,n,o,r),...[...a].reverse()],i),h=ri([...l(o,r,s,n),...a],i);return c.length<3||h.length<3||si(c)<=i||si(h)<=i||Math.abs(si(c)+si(h)-si(t))>Math.max(i,1e-6*si(t))?null:[c,h]}(s,[...h,l],o);if(!d)return void this._showToast(this._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[p,u]=d,_=si(p)>=si(u)?p:u,m=_===p?u:p;this._pendingSplit={roomId:i.id,mainPoly:_,newPoly:m},this._cursorPt=null,this._nameSel="",this._areaSel="",this._roomDialog=!0}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])}_markupMove(t){if(!this._markup)return;const e=t.pointerType;if(e&&(this._boundaryPointerType=e),"column"===this._tool)return void(this._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this._tool||"boundary"===this._tool||"wallthick"===this._tool)return void(this._cursorPt=this._svgPoint(t));const i=("draw"===this._tool||"partition"===this._tool)&&this._path.length&&!this._contourClosed,s="split"===this._tool&&!!this._splitSel?.pts?.length;if(!i&&!s)return;const o=this._svgPoint(t);this._cursorPt=i?this._snapDrawPoint(o,t.shiftKey):this._snap(o)}get _openingPreview(){if("opening"!==this._tool||!this._cursorPt)return null;const t=this._cursorPt,e=1.5*this._gridPitch,i=this._openingsR.find(i=>Math.hypot(t[0]-i.rx,t[1]-i.ry)<=Math.max(i.rlen/2,e));if(i)return null;const s=this._cmToUnits(90),o=He(t,this._spaceModel().rooms,e);if(!o)return null;const n=this._opRuler(o,s);return{x:n.x,y:n.y,angle:n.angle,rlen:s,measure:n.measure}}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){(this._areaSel||this._nameSel.trim())&&this._commitRoom()}_commitRoom(){const t=this._curSpaceCfg;if(!t)return;const e=this._geometrySnapshot(),i=this._spaceH,s=!!this._pendingSplit;let o;if(this._pendingSplit){const e=t.rooms.find(t=>t.id===this._pendingSplit.roomId);if(!e)return this._pendingSplit=null,this._splitSel=null,void(this._roomDialog=!1);e.poly=this._pendingSplit.mainPoly.map(t=>[t[0]/Nc,t[1]/i]),delete e.x,delete e.y,delete e.w,delete e.h,o=this._pendingSplit.newPoly}else{if(!this._contourClosed)return;o=this._path.slice(0,-1)}const n=this._areaSel?this.hass.areas[this._areaSel]?.name:"",r={id:"r"+Date.now().toString(36),name:this._nameSel||n||this._t("room.default_name"),area:this._areaSel||null,poly:o.map(t=>[t[0]/Nc,t[1]/i]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(t.rooms.push(r),!s&&this._activeDraftId&&Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),s&&this._commitOpenSpans(),!s){const e=[...this._draftSegmentCms,this._closingWallCm||this._drawWallCm||Xn],i=e[0]||this._drawWallCm;if(null!=i){this._cfgEpoch++;const s=this._openCuts();let n=function(t,e,i,s,o,n=[],r=1){if(null==s||s<1)return t?t.slice():[];const a=Dr(e,i,n,o,r,t);if(!a)return t?t.slice():[];const l=Tr(t,a,o,r);let c=t?t.slice():[];for(let t=0;t0||(c=fr(c,e,i,s,o,r))}return c}(t.walls,this._spaceModel().rooms,r.id,i,this._wallKeyPitch,s,Nc);for(const t of Rr(this._spaceModel().rooms,n,s,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)){if(t.roomId!==r.id||"outer"!==t.kind)continue;const s=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],a=o.findIndex((t,e)=>{const i=o[(e+1)%o.length];return gs(s,[t[0],t[1],i[0],i[1]])<=.02*this._gridPitch});a>=0&&(n=fr(n,t.a,t.b,e[a]||i,this._wallKeyPitch,Nc))}n=this._normalizeWalls(n,s),n.length?t.walls=n:delete t.walls}}this._recordGeometry(this._t(s?"history.split_room":"history.add_room"),e),this._saveConfig(),this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._pendingSplit=null,this._splitSel=null;const a=this._areaSel;this._areaSel="",this._nameSel="",this._roomDialog=!1,this._regSignature="",this._maybeRebuildDevices();let l=0;if(a){const t=Nc,e={...this._layout};for(const i of this._devices){if(i.area!==a||i.space!==this._space)continue;if(l++,this._layout[i.id])continue;const s=this._defPos[i.id];s&&(e[i.id]={s:this._space,x:s.x/Nc,y:s.y/t},this._dirtyPos.add(i.id))}this._layout=e,this._persistLayout()}const c=this._model.find(t=>t.id===this._space)?.rooms.length||0;this._showToast(a?this._t("toast.room_saved",{n:c,added:l}):this._t("toast.room_saved_no_area",{n:c}))}_cancelPath(){this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._cursorPt=null,this._roomDialog=!1,this._pendingSplit=null,this._splitSel=null,this._mergeSel=null,this._mergeDialog=null,this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null}_resumeLastDraft(){const t=this._resumeDraftBySpace[this._space];if(!t)return;const e=this._spaceModel().room_drafts.find(e=>e.id===t);e?(this._activeDraftId=t,this._path=e.points.map(t=>[...t]),this._draftSegmentCms=e.segments.map(t=>t.cm),this._cursorPt=null):delete this._resumeDraftBySpace[this._space]}_roomDialogCancel(){return this._roomDialog=!1,this._roomEditId?(this._roomEditId=null,this._nameSel="",void(this._areaSel="")):this._pendingSplit?(this._pendingSplit=null,void(this._splitSel=null)):void this._undoPoint()}get _freeAreas(){const t=new Set;for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area&&t.add(i.area);return Object.values(this.hass?.areas||{}).filter(e=>!t.has(e.area_id)).sort((t,e)=>(t.name||"").localeCompare(e.name||""))}_openMarkerDialog(t){if(this._vacAllCamerasFor=null,this._vacAllCameraCache=null,t&&this._ackNewDevice(t.id),this._norm)if(t){const e=t.marker,i=Object.prototype.hasOwnProperty.call(e||{},"is_light"),s=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),o=Ji(e?.glow_color);this._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:ui(t.marker?.display),rippleColor:_t(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):3,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:t.marker?.tap_action||"",tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",defaultTap:"light"===t.primary?.split(".")[0]?"toggle":"info",controls:co(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:i,originalIsLight:e?.is_light,glowMode:null!=o?.bri?"fixed":o?"color":"auto",glowColor:o?.c||this._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(o?.bri??1))),glowColorDrafted:!!o,glowBrightnessDrafted:null!=o?.bri,glowTouched:!1,originalHasGlowColor:s&&(!!o||null===e?.glow_color),originalGlowColor:o||(null===e?.glow_color?null:void 0),useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:3,size:1,angle:0,tapAction:"",tapTarget:"",tapConfirm:!1,runFilter:"",defaultTap:"info",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,glowMode:"auto",glowColor:this._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};else this._showToast(this._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of wi)for(const[i,s]of Object.entries(this.hass.states))i.startsWith(e+".")&&this._planEntityAvailable(i)&&t.push({value:i,label:s?.attributes?.friendly_name||i,sub:this._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=this._planHass,e=So(this._markers),i=new Set(this._markers.filter(t=>t.removed).map(t=>t.binding)),s=new Set;for(const t of this._devices)t.id!==this._markerDialog?.devId&&("device"===t.bindingKind&&t.bindingRef&&s.add("device:"+t.bindingRef),"entity"===t.bindingKind&&t.bindingRef&&s.add("entity:"+t.bindingRef));const o=new Set;for(const t of this._devices)"device"===t.bindingKind&&t.name&&o.add(t.name.trim()+"|"+(t.area||""));const n=[];for(const e of Object.values(t.devices)){if("service"===e.entry_type)continue;const t="device:"+e.id;if(s.has(t))continue;const r=(e.name_by_user||e.name||e.id).trim();t!==this._markerDialog?.binding&&!i.has(t)&&o.has(r+"|"+(e.area_id||""))||n.push({value:t,label:r,sub:(e.model||this._t("marker.sub_device"))+("Group"===e.model?this._t("marker.sub_z2m_group"):"")})}const r=new Set(["group","template","derivative","min_max","threshold","integration","statistics","trend","utility_meter","tod","switch_as_x","schedule"]);for(const[o,a]of Object.entries(t.entities)){const l="entity:"+o;if(s.has(l))continue;if(Mo(t,o,e)&&!i.has(l))continue;const c=r.has(a.platform),h="group"===a.platform;if(!c&&!h)continue;if(a.hidden&&!i.has(l))continue;const d=t.states[o];n.push({value:l,label:a.name||d?.attributes?.friendly_name||o,sub:o.split(".")[0]+" · "+("group"===a.platform?this._t("marker.sub_group"):this._t("marker.sub_helper"))})}if(this._markerDialog?.showEntities){const o=new Set(n.map(t=>t.value));for(const[r,a]of Object.entries(t.entities)){const l="entity:"+r;if(s.has(l)||o.has(l)||a.hidden&&!i.has(l))continue;if(Mo(t,r,e)&&!i.has(l))continue;const c=t.states[r],h=a.name||c?.attributes?.friendly_name||r,d=a.device_id?t.devices[a.device_id]:null,p=d&&(d.name_by_user||d.name)||"";n.push({value:l,label:h,sub:r.split(".")[0]+" · "+this._t("marker.sub_entity")+(p?" · "+p:"")})}}const a=(this._markerDialog?.bindingFilter||"").toLowerCase().trim(),l=a?n.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(a)):n;return l.sort((t,e)=>t.label.localeCompare(e.label)),l.slice(0,200)}_physicalBodiesR(t=this._spaceModel()){const e=`${t.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===e)return this._physicalBodiesCache.all;const i=(t.room_drafts||[]).flatMap(t=>ea(t,this._cellCm,this._gridPitch)),s=(t.partitions||[]).flatMap(t=>{const e=Qr(t.a,t.b,t.cm,this._cellCm,this._gridPitch);return e?[e]:[]}),o=(t.wall_columns||[]).map(t=>ta(t,this._cellCm,this._gridPitch)),n=[...i,...s,...o];return this._physicalBodiesCache={key:e,drafts:i,partitions:s,columns:o,all:n},n}_cleanFloor(t,e,i=this._spaceModel()){const s=t.id||`#${i.rooms.indexOf(t)}`,o=`${i.id}|${this._cfgEpoch}|${s}`;if(!this._rszPreview){const t=kc(this._cleanFloorCache,o);if(t.hit)return t.value}const n=e.map(t=>t[0]),r=e.map(t=>t[1]),a=[Math.min(...n),Math.min(...r),Math.max(...n),Math.max(...r)],l=this._physicalBodiesR(i).filter(t=>{const e=t.map(t=>t[0]),i=t.map(t=>t[1]);return Math.max(...e)>=a[0]&&Math.min(...e)<=a[2]&&Math.max(...i)>=a[1]&&Math.min(...i)<=a[3]}),c=l.length?ia(e,l):null,h={floor:e,geom:c,path:c?Xr(c):"",area:sa(c||[[[...e,e[0]]]])};return this._rszPreview||$c(this._cleanFloorCache,o,h,600),h}_autoIconForBinding(t){if("virtual"===t)return"mdi:map-marker";const[e,i]=t.split(":");if(!i)return"";const s=this._fullRegistryHass,o=this._bindingStatus(t),n="active"===o.kind?o.enabledEntityIds:o.allEntityIds;if("device"===e){const t=s.devices?.[i];if(!t)return"mdi:help-circle";const e=n;return e.some(t=>t.startsWith("lock."))?"mdi:lock":xo(s,t.name_by_user||t.name||"",t.model,e,this._iconRules)}if("entity"===e){const t=s.entities?.[i],e=this.hass.states?.[i],o=t?.name||e?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":xo(s,o,"",[i],this._iconRules)}return""}_allRoomsFlat(){const t=[];for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area?t.push({value:e.id+"#"+i.area,label:(e.title||e.id)+" · "+i.name}):i.id&&t.push({value:e.id+"#@"+i.id,label:(e.title||e.id)+" · "+i.name+" · "+this._t("marker.subarea")});return t}_errText(t){if(!t)return this._t("err.unknown");if("string"==typeof t)return t;if(t.message)return t.message;if(t.error)return t.error;if(null!=t.code)return this._t("err.code",{code:t.code});try{return JSON.stringify(t)}catch{return String(t)}}async _pickMarkerFiles(t){const e=t.target,i=e.files?[...e.files]:[];if(e.value="",!i.length||!this._markerDialog)return;const s=this._markerDialog.uploadId||this._markerDialog.devId||"new",o=[];for(const t of i)try{const e=new FormData;e.append("marker_id",s),e.append("file",t,t.name);const i=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}),n=await i.json().catch(()=>({}));if(!i.ok||n.error){const t={too_large:this._t("err.too_large",{mb:n.max_mb||50}),bad_ext:this._t("err.bad_ext"),unauthorized:this._t("err.unauthorized")};throw new Error(t[n.error]||n.error||"HTTP "+i.status)}o.push({name:n.name||t.name,url:n.url})}catch(e){this._showToast(this._t("toast.file_failed",{name:t.name,err:this._errText(e)}))}o.length&&this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:[...this._markerDialog.pdfs,...o]},this._showToast(this._t("toast.files_attached",{n:o.length})))}_removeMarkerPdf(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:this._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.glowTouched){if("auto"!==t.glowMode){const i={c:_t(t.glowColor,this._fillColors.glow_light.c)};"fixed"===t.glowMode&&(i.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=i}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}async _saveMarker(){const t=this._markerDialog;if(t&&!t.busy&&("ha"!==t.bindingMode||t.binding&&"virtual"!==t.binding))if("virtual"!==t.binding||t.name.trim())if("run"!==t.tapAction||t.tapTarget){if("ha"===t.bindingMode){const e=this._bindingStatus(t.binding),i=t.devId?this._markers.find(e=>e.id===t.devId):null,s=!i||i.binding!==t.binding;if("active"!==e.kind&&s)return void this._showToast(this._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===i?.hidden&&!t.hideFromPlan)return this._markerDialog={...t,hideFromPlan:!0},void this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}this._markerDialog={...t,busy:!0};try{const e=this._serverCfg;let i;e.markers=e.markers||[];const s=ys(t.room);let o=s?.space||null,n=s?.area||null;const r=s?.roomId||null;"virtual"!==t.binding||o||(o=this._space),i=ai(t.binding,t.devId,()=>"v_"+Date.now().toString(36));const a=t.devId,l="virtual"===t.binding?[]:e.markers.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),c=l.length>0,h=co(t.binding,t.controls,this._bindingEntities(t.binding)),d=e.markers.find(t=>t.id===i||t.id===a)?.vacuum||null,p={id:i,vacuum:d,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&&3!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,tap_action:t.tapAction||null,tap_target:"run"===t.tapAction&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:h.length?h:null,...this._markerLightFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=wc(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};("virtual"===t.binding||t.room)&&(p.space=o,p.area=n,p.room_id=r);const u=a?this._devices.find(t=>t.id===a):null,_=u?.marker?.room_id??null,m=!!t.room&&null!=u&&(u.space!==o||u.area!==n||_!==r);let g=!1;const f=t.uploadId||a;if(f&&f!==i&&p.pdfs?.length)try{const t=await this.hass.callWS({type:"houseplan/files/migrate",from_id:f,to_id:i}),e=t?.mapping||{};p.pdfs=function(t,e,i,s){if(!e||!i||e===i)return t;const o="/files/"+e+"/",n="/files/"+i+"/";return t.map(t=>{if(!t.url.includes(o))return t;const e=t.url.split(o)[1]||"",[i,r]=[e.split("?")[0],e.includes("?")?"?"+e.split("?")[1]:""];if(s){const e=s[decodeURIComponent(i)]??s[i];return e?{...t,url:t.url.split(o+i)[0]+n+encodeURIComponent(e)+r}:t}return{...t,url:t.url.split(o).join(n)}})}(p.pdfs,f,i,e),g=Object.keys(e).length>0}catch(t){this._showToast(this._t("toast.files_migrate_failed",{err:this._errText(t)}))}e.markers=e.markers.filter(t=>t.id!==i&&t.id!==a&&("virtual"===p.binding||t.binding!==p.binding)),e.markers.push(p);let v=null;const y=o||u?.space||this._space,b=a?this._layout[a]:null,w=b?{s:b.s||u?.space||this._space,x:b.x,y:b.y}:a&&u&&this._defPos[a]?this._normPos(u.space,this._defPos[a].x,this._defPos[a].y):null;if(!c&&w&&w.s===y)i===a&&this._layout[i]&&!m||(v={s:w.s,x:w.x,y:w.y},this._layout={...this._layout,[i]:v});else if(c||!this._layout[i]||m){const t=this._spaceModel(o||void 0);let e=t.vb[0]+t.vb[2]/2,s=t.vb[1]+t.vb[3]/2;const a=r?t.rooms.find(t=>t.id===r):n?t.rooms.find(t=>t.area===n):void 0;a&&([e,s]=this._roomCenter(a)),v=this._normPos(o||this._space,e,s),this._layout={...this._layout,[i]:v}}await this._saveConfigNow(),v&&this._noteLayoutRev(await this.hass.callWS({type:"houseplan/layout/update",device_id:i,pos:v}));const k=new Set(l);a&&a!==i&&k.add(a),k.delete(i);for(const t of k)delete this._layout[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{});g&&f&&await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:f}).catch(()=>{}),this._markerDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_saved"))}catch(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}else this._showToast(this._t("toast.run_target_required"));else this._showToast(this._t("toast.virtual_name_required"))}async _deleteMarker(){const t=this._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this._devices.find(e=>e.id===t.devId):null;if(!e)return;const i=t.name||this._t("device.fallback");if(!confirm(this._t("confirm.remove_marker",{name:i})))return;const s=this._serverCfg;s.markers=s.markers||[];const o=s.markers,n="virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"";if(!n)return;const r=function(t,e,i,s){const o=new Set([e]),n=t.filter(t=>{const n=t.id===e||!s&&t.binding===i;return n&&o.add(t.id),!n});return{markers:s?n:[...n,{id:e,binding:i,removed:!0,hidden:!0}],cleanupIds:o}}(s.markers,e.id,n,"virtual"===e.bindingKind);s.markers=r.markers;const a=r.cleanupIds;this._markerDialog={...t,busy:!0};try{await this._saveConfigNow();for(const t of a){delete this._layout[t],delete this._defPos[t],this._dirtyPos.delete(t),this._sentPos.delete(t);const e=this._activityRt.get(t);e&&clearTimeout(e.timer),this._activityRt.delete(t),this._vacRt.delete(t),delete this._vacSrvTrails[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{}),await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this._markerDialog=null,this._infoCard?.id===e.id&&this._closeInfoCard(),this._selId===e.id&&(this._selId=null),this._drag?.id===e.id&&(this._drag=null),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_removed"))}catch(t){this._serverCfg===s&&(s.markers=o),this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}_normPos(t,e,i){return{s:t,x:e/Nc,y:i/Nc}}_openSpaceDialog(t,e){if(this._serverStorage&&this._serverCfg)if("edit"===t){const i=this._serverCfg.spaces.find(t=>t.id===e);if(!i)return;const s=Fi(i),o=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?Ei(i.settings.custom_fill):null,n="none"===s.fill?{...o||Ii,a:0}:o;this._spaceDialog={mode:t,spaceId:e,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:s.showBorders,showNames:s.showNames,hideDecor:s.hideDecor,hideOpenings:s.hideOpenings,roomColor:s.color,roomOpacity:s.opacity,fillMode:"none"===s.fill?"custom":s.fill,customFill:n,glowEnabled:s.glow,bgColor:s.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:Nn({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:s.tempMin,tempMax:s.tempMax,showLqi:s.showLqi??this._config?.show_signal??!0,cardFontScale:s.cardFontScale,labelTemp:s.labelTemp,labelHum:s.labelHum,labelLqi:s.labelLqi,labelLight:s.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,busy:!1}}else this._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,source:"file",showBorders:!1,showNames:!1,hideDecor:!1,hideOpenings:!1,roomColor:zi,roomOpacity:Ai,fillMode:"custom",customFill:{...Ii,a:0},glowEnabled:!0,bgColor:null,bgMode:null,northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:5,busy:!1};else this._showToast(this._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,i=e.files?.[0];if(!i||!this._spaceDialog)return;const s={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[i.type]||(i.name.toLowerCase().endsWith(".svg")?"svg":"");if(!s)return void this._showToast(this._t("toast.plan_formats"));const o=new Uint8Array(await i.arrayBuffer());let n="";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=a});URL.revokeObjectURL(a),this._spaceDialog={...this._spaceDialog,planFile:{ext:s,b64:r,aspect:l,name:i.name}}}_useServerPlan(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this._display(t);if(e){const i=await new Promise(t=>{const i=new Image;i.onload=()=>t(i.naturalWidth&&i.naturalHeight?i.naturalWidth/i.naturalHeight:0),i.onerror=()=>t(0),i.src=e}),s=this._spaceDialog;return s&&s.planUrl===t&&Number.isFinite(i)&&i>0?(this._spaceDialog={...s,savedAspect:i},i):0}if(await new Promise(t=>setTimeout(t,150)),this._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this._t("confirm.delete_plan",{name:t})))try{await this.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this._spaceDialog;e?.saved&&(this._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this._showToast(this._t("toast.plan_delete_failed",{err:this._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return j`
${this._t("space.loading")}
`;const e=t.saved||[];if(!e.length)return j`
${this._t("space.no_saved")}
`;return j`
- ${e.map(e=>j` +
`:B``}_openingClick(t){const e=1.5*this._gridPitch,i=this._openingsR.find(i=>Math.hypot(t[0]-i.rx,t[1]-i.ry)<=Math.max(i.rlen/2,e));if(i)return void this._editOpening(i);const s=Qe(t,this._spaceModel().rooms,e);if(!s)return void this._showToast(this._t("toast.opening_no_wall"));if(function(t,e,i,s,o){for(const n of s)if(!(Ss([t,e],n)>o)&&xr([n[0],n[1]],[n[2],n[3]],i))return!0;return!1}(s.x,s.y,s.angle,this._openCuts(),e))return void this._showToast(this._t("toast.opening_on_virtual"));const o=this._opRuler(s,this._cmToUnits(90));this._openingDialog={type:"door",lengthCm:90,contact:"",lock:"",invert:!1,flipH:!1,flipV:!1,x:o.x,y:o.y,angle:o.angle},this._cursorPt=null}_editOpening(t){this._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this._gridPitch*this._cellCm),contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this._mode&&"resize"!==this._tool){t.preventDefault(),t.stopPropagation();try{lh(t)}catch{}this._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this._opDrag.sx)+Math.abs(t.clientY-this._opDrag.sy)<=3)return;const i=Qe(this._svgPoint(t),this._spaceModel().rooms,4*this._gridPitch);if(!i)return;this._opDrag.moved=!0;const s=this._curSpaceCfg,o=s?.openings?.find(t=>t.id===e.id);if(!o)return;const n=this._opRuler(i,o.length*eh);this._opMeasure=n.measure;const r=n.x/eh,a=n.y/this._spaceH,l=o.x!==r||o.y!==a||o.angle!==i.angle;l&&(this._opDrag.dirty=!0),o.x=r,o.y=a,o.angle=i.angle,l&&this._cfgEpoch++,this.requestUpdate()}_opRuler(t,e){const i=this._spaceModel().rooms,s=this._gridPitch/2;let o=t.x,n=t.y,r=ti([o,n],t.angle,e,i,s);if(r&&r.centered&&(o!==r.wallCenter[0]||n!==r.wallCenter[1]))[o,n]=r.wallCenter,r=ti([o,n],t.angle,e,i,s);else if(r){const[a,l]=r.wallA,[c,h]=r.wallB,d=c-a,p=h-l,u=Math.hypot(d,p);if(u>0){const c=this._gridPitch,h=Math.min(e/2,u/2);let _=Math.round(((o-a)*d+(n-l)*p)/u/c)*c;_=Math.max(h,Math.min(u-h,_)),o=a+_/u*d,n=l+_/u*p,r=ti([o,n],t.angle,e,i,s)||r}}if(!r)return{x:o,y:n,angle:t.angle,measure:null};const a="mi"===this.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:Ke(t/this._gridPitch*this._cellCm,a)});return{x:o,y:n,angle:t.angle,measure:{labels:[l(r.sideA,r.midA),l(r.sideB,r.midB)],guide:r.centered?{x:r.wallCenter[0],y:r.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this._opDrag||this._opDrag.id!==e.id)return;const i=this._opDrag,s=i.moved;this._opMeasure=null,s&&i.dirty&&(this._recordGeometry(this._t("history.move_opening"),i.before),this._saveConfig()),s?window.setTimeout(()=>this._opDrag=null,0):this._opDrag=null}_opClick(t,e){"plan"===this._mode&&"resize"===this._tool||(t.stopPropagation(),this._opDrag?.moved||"plan"===this._mode&&this._editOpening(e))}_saveOpening(){const t=this._openingDialog,e=this._curSpaceCfg;if(!t||!e)return;const i=this._geometrySnapshot(),s=this._spaceH,o={id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/eh,y:t.y/s,angle:t.angle,length:this._cmToUnits(Math.max(20,t.lengthCm))/eh,contact:t.contact||null,lock:"window"!==t.type&&t.lock||null,invert:t.invert||void 0,flip_h:"gate"!==t.type&&t.flipH||void 0,flip_v:t.flipV||void 0};e.openings=e.openings||[];const n=e.openings.findIndex(t=>t.id===o.id);n>=0?e.openings[n]=o:e.openings.push(o),this._recordGeometry(this._t(t.id?"history.edit_opening":"history.add_opening"),i),this._saveConfig(),this._openingDialog=null,this.requestUpdate()}_deleteOpening(){const t=this._openingDialog,e=this._curSpaceCfg;if(!t?.id||!e?.openings)return;const i=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._recordGeometry(this._t("history.delete_opening"),i),this._saveConfig(),this._openingDialog=null,this.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.hass.states)){if(!this._planEntityAvailable(e))continue;const i=e.split(".")[0];if("binary_sensor"!==i&&"cover"!==i)continue;const s=this.hass.states[e],o=["door","window","opening","garage_door","garage"].includes(s?.attributes?.device_class||"");("cover"!==i||o)&&t.push([e,s?.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.hass.states).filter(t=>t.startsWith("lock.")&&this._planEntityAvailable(t)).map(t=>({value:t,label:this.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_mergeClick(t){const e=this._spaceModel().rooms,i=[...e].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;const s=i.id;if(!this._mergeSel||this._mergeSel===s)return void(this._mergeSel=this._mergeSel===s?null:s);const o=e.find(t=>t.id===this._mergeSel),n=o?Je(o):null,r=Je(i),a=n&&r?function(t,e){if(!t||!e||t.length<3||e.length<3)return null;const i=Be(gi(t),gi(e));if(1!==i.length)return null;if(1!==i[0].length)return null;const s=i[0][0].slice(0,-1).map(t=>[t[0],t[1]]);return s.length>=3?s:null}(n,r):null;if(!a)return this._showToast(this._t("toast.merge_not_adjacent")),void(this._mergeSel=null);this._mergeDialog={aId:this._mergeSel,bId:s,poly:a,pick:"a"},this._mergeSel=null}_commitMerge(){const t=this._mergeDialog,e=this._curSpaceCfg;if(!t||!e)return;const i=this._geometrySnapshot(),s=this._spaceH,o="a"===t.pick?t.aId:t.bId,n="a"===t.pick?t.bId:t.aId,r=e.rooms.find(t=>t.id===o);r?(r.poly=t.poly.map(t=>[t[0]/eh,t[1]/s]),delete r.x,delete r.y,delete r.w,delete r.h,e.rooms=e.rooms.filter(t=>t.id!==n),this._commitOpenSpans(),this._recordGeometry(this._t("history.merge_rooms"),i),this._saveConfig(),this._mergeDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.rooms_merged",{name:r.name||""}))):this._mergeDialog=null}_splitClick(t){const e=this._spaceModel().rooms;if(!this._splitSel){const i=[...e].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;return void(this._splitSel={roomId:i.id,pts:[]})}const i=e.find(t=>t.id===this._splitSel.roomId),s=i?Je(i):null;if(!i||!s)return void(this._splitSel=null);const o=.02*this._gridPitch,n=6*this._gridPitch,r=function(t,e){if(!e||e.length<2)return null;let i=null,s=1/0;for(let o=0;o=o)continue;o=_;const m=Math.sqrt(p),g=(i>0?Math.max(0,Math.min(m,Math.round(u*m/i)*i)):u*m)/m;s=[r+g*h,a+g*d]}return s}(r,s,this._gridPitch)||r,l=r&&a&&Math.hypot(r[0]-t[0],r[1]-t[1])<=n?a:null,c=!!l&&ni(l,s,o),h=this._splitSel.pts;if(!h.length)return c?void(this._splitSel={...this._splitSel,pts:[l]}):void this._showToast(this._t("toast.split_pick_wall"));if(!c){const e=this._snap(t);return ri(e,s,o)?void(this._splitSel={...this._splitSel,pts:[...h,e]}):void this._showToast(this._t("toast.split_pick_inside"))}const d=function(t,e,i=1e-6){if(!t||t.length<3||!e||e.length<2)return null;const s=e[0],o=e[e.length-1];if(ii(s,o,i))return null;const n=fi(t,s,i),r=fi(t,o,i);if(n<0||r<0)return null;const a=e.slice(1,-1);for(const e of a)if(!ri(e,t,i))return null;for(let i=0;i{const r=[e];let a=(s+1)%t.length;for(let e=0;e<=t.length&&(r.push(t[a]),a!==n);e++)a=(a+1)%t.length;return r.push(o),vi(r,i)};let c,h;if(n===r){const r=vi([...e],i);if(r.length<3||mi(r)<=i)return null;const a=[];for(let i=0;i=0?e:[...e].reverse();for(const t of i)a.push(t)}c=vi(a,i),h=r}else c=vi([...l(s,n,o,r),...[...a].reverse()],i),h=vi([...l(o,r,s,n),...a],i);return c.length<3||h.length<3||mi(c)<=i||mi(h)<=i||Math.abs(mi(c)+mi(h)-mi(t))>Math.max(i,1e-6*mi(t))?null:[c,h]}(s,[...h,l],o);if(!d)return void this._showToast(this._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[p,u]=d,_=mi(p)>=mi(u)?p:u,m=_===p?u:p;this._pendingSplit={roomId:i.id,mainPoly:_,newPoly:m},this._cursorPt=null,this._nameSel="",this._areaSel="",this._roomDialog=!0}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])}_markupMove(t){if(!this._markup)return;const e=t.pointerType;if(e&&(this._boundaryPointerType=e),"column"===this._tool)return void(this._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this._tool||"boundary"===this._tool||"wallthick"===this._tool)return void(this._cursorPt=this._svgPoint(t));const i=("draw"===this._tool||"partition"===this._tool)&&this._path.length&&!this._contourClosed,s="split"===this._tool&&!!this._splitSel?.pts?.length;if(!i&&!s)return;const o=this._svgPoint(t);this._cursorPt=i?this._snapDrawPoint(o,t.shiftKey):this._snap(o)}get _openingPreview(){if("opening"!==this._tool||!this._cursorPt)return null;const t=this._cursorPt,e=1.5*this._gridPitch,i=this._openingsR.find(i=>Math.hypot(t[0]-i.rx,t[1]-i.ry)<=Math.max(i.rlen/2,e));if(i)return null;const s=this._cmToUnits(90),o=Qe(t,this._spaceModel().rooms,e);if(!o)return null;const n=this._opRuler(o,s);return{x:n.x,y:n.y,angle:n.angle,rlen:s,measure:n.measure}}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){(this._areaSel||this._nameSel.trim())&&this._commitRoom()}_commitRoom(){const t=this._curSpaceCfg;if(!t)return;const e=this._geometrySnapshot(),i=this._spaceH,s=!!this._pendingSplit;let o;if(this._pendingSplit){const e=t.rooms.find(t=>t.id===this._pendingSplit.roomId);if(!e)return this._pendingSplit=null,this._splitSel=null,void(this._roomDialog=!1);e.poly=this._pendingSplit.mainPoly.map(t=>[t[0]/eh,t[1]/i]),delete e.x,delete e.y,delete e.w,delete e.h,o=this._pendingSplit.newPoly}else{if(!this._contourClosed)return;o=this._path.slice(0,-1)}const n=this._areaSel?this.hass.areas[this._areaSel]?.name:"",r={id:"r"+Date.now().toString(36),name:this._nameSel||n||this._t("room.default_name"),area:this._areaSel||null,poly:o.map(t=>[t[0]/eh,t[1]/i]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(t.rooms.push(r),!s&&this._activeDraftId&&Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t.id!==this._activeDraftId),t.room_drafts.length||delete t.room_drafts),s&&this._commitOpenSpans(),!s){const e=[...this._draftSegmentCms,this._closingWallCm||this._drawWallCm||ar],i=e[0]||this._drawWallCm;if(null!=i){this._cfgEpoch++;const s=this._openCuts();let n=function(t,e,i,s,o,n=[],r=1){if(null==s||s<1)return t?t.slice():[];const a=Fr(e,i,n,o,r,t);if(!a)return t?t.slice():[];const l=Or(t,a,o,r);let c=t?t.slice():[];for(let t=0;t0||(c=Mr(c,e,i,s,o,r))}return c}(t.walls,this._spaceModel().rooms,r.id,i,this._wallKeyPitch,s,eh);for(const t of Hr(this._spaceModel().rooms,n,s,this._wallKeyPitch,this._cellCm,this._gridPitch,eh)){if(t.roomId!==r.id||"outer"!==t.kind)continue;const s=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],a=o.findIndex((t,e)=>{const i=o[(e+1)%o.length];return Ss(s,[t[0],t[1],i[0],i[1]])<=.02*this._gridPitch});a>=0&&(n=Mr(n,t.a,t.b,e[a]||i,this._wallKeyPitch,eh))}n=this._normalizeWalls(n,s),n.length?t.walls=n:delete t.walls}}this._recordGeometry(this._t(s?"history.split_room":"history.add_room"),e),this._saveConfig(),this._path=[],delete this._resumeDraftBySpace[this._space],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._pendingSplit=null,this._splitSel=null;const a=this._areaSel;this._areaSel="",this._nameSel="",this._roomDialog=!1,this._regSignature="",this._maybeRebuildDevices();let l=0;if(a){const t=eh,e={...this._layout};for(const i of this._devices){if(i.area!==a||i.space!==this._space)continue;if(l++,this._layout[i.id])continue;const s=this._defPos[i.id];s&&(e[i.id]={s:this._space,x:s.x/eh,y:s.y/t},this._dirtyPos.add(i.id))}this._layout=e,this._persistLayout()}const c=this._model.find(t=>t.id===this._space)?.rooms.length||0;this._showToast(a?this._t("toast.room_saved",{n:c,added:l}):this._t("toast.room_saved_no_area",{n:c}))}_cancelPath(){this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._path=[],this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._cursorPt=null,this._roomDialog=!1,this._pendingSplit=null,this._splitSel=null,this._mergeSel=null,this._mergeDialog=null,this._openWallAnchor=null,this._boundaryRestoreGuard=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null}_resumeLastDraft(){const t=this._resumeDraftBySpace[this._space];if(!t)return;const e=this._spaceModel().room_drafts.find(e=>e.id===t);e?(this._activeDraftId=t,this._path=e.points.map(t=>[...t]),this._draftSegmentCms=e.segments.map(t=>t.cm),this._cursorPt=null):delete this._resumeDraftBySpace[this._space]}_roomDialogCancel(){return this._roomDialog=!1,this._roomEditId?(this._roomEditId=null,this._nameSel="",void(this._areaSel="")):this._pendingSplit?(this._pendingSplit=null,void(this._splitSel=null)):void this._undoPoint()}get _freeAreas(){const t=new Set;for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area&&t.add(i.area);return Object.values(this.hass?.areas||{}).filter(e=>!t.has(e.area_id)).sort((t,e)=>(t.name||"").localeCompare(e.name||""))}_openMarkerDialog(t){if(this._vacAllCamerasFor=null,this._vacAllCameraCache=null,t&&this._ackNewDevice(t.id),this._norm)if(t){const e=t.marker,i=Object.prototype.hasOwnProperty.call(e||{},"is_light"),s=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),o=ls(e?.glow_color);this._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:Si(t.marker?.display),rippleColor:Ct(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):3,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:t.marker?.tap_action||"",tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",defaultTap:"light"===t.primary?.split(".")[0]?"toggle":"info",controls:yo(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:i,originalIsLight:e?.is_light,glowMode:null!=o?.bri?"fixed":o?"color":"auto",glowColor:o?.c||this._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(o?.bri??1))),glowColorDrafted:!!o,glowBrightnessDrafted:null!=o?.bri,glowTouched:!1,originalHasGlowColor:s&&(!!o||null===e?.glow_color),originalGlowColor:o||(null===e?.glow_color?null:void 0),useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:3,size:1,angle:0,tapAction:"",tapTarget:"",tapConfirm:!1,runFilter:"",defaultTap:"info",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,glowMode:"auto",glowColor:this._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};else this._showToast(this._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of zi)for(const[i,s]of Object.entries(this.hass.states))i.startsWith(e+".")&&this._planEntityAvailable(i)&&t.push({value:i,label:s?.attributes?.friendly_name||i,sub:this._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=this._planHass,e=Io(this._markers),i=new Set(this._markers.filter(t=>t.removed).map(t=>t.binding)),s=new Set;for(const t of this._devices)t.id!==this._markerDialog?.devId&&("device"===t.bindingKind&&t.bindingRef&&s.add("device:"+t.bindingRef),"entity"===t.bindingKind&&t.bindingRef&&s.add("entity:"+t.bindingRef));const o=new Set;for(const t of this._devices)"device"===t.bindingKind&&t.name&&o.add(t.name.trim()+"|"+(t.area||""));const n=[];for(const e of Object.values(t.devices)){if("service"===e.entry_type)continue;const t="device:"+e.id;if(s.has(t))continue;const r=(e.name_by_user||e.name||e.id).trim();t!==this._markerDialog?.binding&&!i.has(t)&&o.has(r+"|"+(e.area_id||""))||n.push({value:t,label:r,sub:(e.model||this._t("marker.sub_device"))+("Group"===e.model?this._t("marker.sub_z2m_group"):"")})}const r=new Set(["group","template","derivative","min_max","threshold","integration","statistics","trend","utility_meter","tod","switch_as_x","schedule"]);for(const[o,a]of Object.entries(t.entities)){const l="entity:"+o;if(s.has(l))continue;if(Eo(t,o,e)&&!i.has(l))continue;const c=r.has(a.platform),h="group"===a.platform;if(!c&&!h)continue;if(a.hidden&&!i.has(l))continue;const d=t.states[o];n.push({value:l,label:a.name||d?.attributes?.friendly_name||o,sub:o.split(".")[0]+" · "+("group"===a.platform?this._t("marker.sub_group"):this._t("marker.sub_helper"))})}if(this._markerDialog?.showEntities){const o=new Set(n.map(t=>t.value));for(const[r,a]of Object.entries(t.entities)){const l="entity:"+r;if(s.has(l)||o.has(l)||a.hidden&&!i.has(l))continue;if(Eo(t,r,e)&&!i.has(l))continue;const c=t.states[r],h=a.name||c?.attributes?.friendly_name||r,d=a.device_id?t.devices[a.device_id]:null,p=d&&(d.name_by_user||d.name)||"";n.push({value:l,label:h,sub:r.split(".")[0]+" · "+this._t("marker.sub_entity")+(p?" · "+p:"")})}}const a=(this._markerDialog?.bindingFilter||"").toLowerCase().trim(),l=a?n.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(a)):n;return l.sort((t,e)=>t.label.localeCompare(e.label)),l.slice(0,200)}_physicalBodiesR(t=this._spaceModel()){const e=`${t.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===e)return this._physicalBodiesCache.all;const i=(t.room_drafts||[]).flatMap(t=>da(t,this._cellCm,this._gridPitch)),s=(t.partitions||[]).flatMap(t=>{const e=ca(t.a,t.b,t.cm,this._cellCm,this._gridPitch);return e?[e]:[]}),o=(t.wall_columns||[]).map(t=>ha(t,this._cellCm,this._gridPitch)),n=[...i,...s,...o];return this._physicalBodiesCache={key:e,drafts:i,partitions:s,columns:o,all:n},n}_cleanFloor(t,e,i=this._spaceModel()){const s=t.id||`#${i.rooms.indexOf(t)}`,o=`${i.id}|${this._cfgEpoch}|${s}`;if(!this._rszPreview){const t=qc(this._cleanFloorCache,o);if(t.hit)return t.value}const n=e.map(t=>t[0]),r=e.map(t=>t[1]),a=[Math.min(...n),Math.min(...r),Math.max(...n),Math.max(...r)],l=this._physicalBodiesR(i).filter(t=>{const e=t.map(t=>t[0]),i=t.map(t=>t[1]);return Math.max(...e)>=a[0]&&Math.min(...e)<=a[2]&&Math.max(...i)>=a[1]&&Math.min(...i)<=a[3]}),c=l.length?ga(e,l):null,h={floor:e,geom:c,path:c?la(c):"",area:fa(c||[[[...e,e[0]]]])};return this._rszPreview||Uc(this._cleanFloorCache,o,h,600),h}_autoIconForBinding(t){if("virtual"===t)return"mdi:map-marker";const[e,i]=t.split(":");if(!i)return"";const s=this._fullRegistryHass,o=this._bindingStatus(t),n="active"===o.kind?o.enabledEntityIds:o.allEntityIds;if("device"===e){const t=s.devices?.[i];if(!t)return"mdi:help-circle";const e=n;return e.some(t=>t.startsWith("lock."))?"mdi:lock":zo(s,t.name_by_user||t.name||"",t.model,e,this._iconRules)}if("entity"===e){const t=s.entities?.[i],e=this.hass.states?.[i],o=t?.name||e?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":zo(s,o,"",[i],this._iconRules)}return""}_allRoomsFlat(){const t=[];for(const e of this._serverCfg?.spaces||[])for(const i of e.rooms||[])i.area?t.push({value:e.id+"#"+i.area,label:(e.title||e.id)+" · "+i.name}):i.id&&t.push({value:e.id+"#@"+i.id,label:(e.title||e.id)+" · "+i.name+" · "+this._t("marker.subarea")});return t}_errText(t){if(!t)return this._t("err.unknown");if("string"==typeof t)return t;if(t.message)return t.message;if(t.error)return t.error;if(null!=t.code)return this._t("err.code",{code:t.code});try{return JSON.stringify(t)}catch{return String(t)}}async _pickMarkerFiles(t){const e=t.target,i=e.files?[...e.files]:[];if(e.value="",!i.length||!this._markerDialog)return;const s=this._markerDialog.uploadId||this._markerDialog.devId||"new",o=[];for(const t of i)try{const e=new FormData;e.append("marker_id",s),e.append("file",t,t.name);const i=this.hass?.fetchWithAuth?await this.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.hass.auth.data.access_token}`}:{}}),n=await i.json().catch(()=>({}));if(!i.ok||n.error){const t={too_large:this._t("err.too_large",{mb:n.max_mb||50}),bad_ext:this._t("err.bad_ext"),unauthorized:this._t("err.unauthorized")};throw new Error(t[n.error]||n.error||"HTTP "+i.status)}o.push({name:n.name||t.name,url:n.url})}catch(e){this._showToast(this._t("toast.file_failed",{name:t.name,err:this._errText(e)}))}o.length&&this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:[...this._markerDialog.pdfs,...o]},this._showToast(this._t("toast.files_attached",{n:o.length})))}_removeMarkerPdf(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,pdfs:this._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.glowTouched){if("auto"!==t.glowMode){const i={c:Ct(t.glowColor,this._fillColors.glow_light.c)};"fixed"===t.glowMode&&(i.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=i}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}async _saveMarker(){const t=this._markerDialog;if(t&&!t.busy&&("ha"!==t.bindingMode||t.binding&&"virtual"!==t.binding))if("virtual"!==t.binding||t.name.trim())if("run"!==t.tapAction||t.tapTarget){if("ha"===t.bindingMode){const e=this._bindingStatus(t.binding),i=t.devId?this._markers.find(e=>e.id===t.devId):null,s=!i||i.binding!==t.binding;if("active"!==e.kind&&s)return void this._showToast(this._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===i?.hidden&&!t.hideFromPlan)return this._markerDialog={...t,hideFromPlan:!0},void this._showToast(this._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}this._markerDialog={...t,busy:!0};try{const e=this._serverCfg;let i;e.markers=e.markers||[];const s=Ds(t.room);let o=s?.space||null,n=s?.area||null;const r=s?.roomId||null;"virtual"!==t.binding||o||(o=this._space),i=yi(t.binding,t.devId,()=>"v_"+Date.now().toString(36));const a=t.devId,l="virtual"===t.binding?[]:e.markers.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),c=l.length>0,h=yo(t.binding,t.controls,this._bindingEntities(t.binding)),d=e.markers.find(t=>t.id===i||t.id===a)?.vacuum||null,p={id:i,vacuum:d,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&&3!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,tap_action:t.tapAction||null,tap_target:"run"===t.tapAction&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:h.length?h:null,...this._markerLightFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=Hc(t.glowRadius);return null==e||e<=0?null:Math.round(this._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};("virtual"===t.binding||t.room)&&(p.space=o,p.area=n,p.room_id=r);const u=a?this._devices.find(t=>t.id===a):null,_=u?.marker?.room_id??null,m=!!t.room&&null!=u&&(u.space!==o||u.area!==n||_!==r);let g=!1;const f=t.uploadId||a;if(f&&f!==i&&p.pdfs?.length)try{const t=await this.hass.callWS({type:"houseplan/files/migrate",from_id:f,to_id:i}),e=t?.mapping||{};p.pdfs=function(t,e,i,s){if(!e||!i||e===i)return t;const o="/files/"+e+"/",n="/files/"+i+"/";return t.map(t=>{if(!t.url.includes(o))return t;const e=t.url.split(o)[1]||"",[i,r]=[e.split("?")[0],e.includes("?")?"?"+e.split("?")[1]:""];if(s){const e=s[decodeURIComponent(i)]??s[i];return e?{...t,url:t.url.split(o+i)[0]+n+encodeURIComponent(e)+r}:t}return{...t,url:t.url.split(o).join(n)}})}(p.pdfs,f,i,e),g=Object.keys(e).length>0}catch(t){this._showToast(this._t("toast.files_migrate_failed",{err:this._errText(t)}))}e.markers=e.markers.filter(t=>t.id!==i&&t.id!==a&&("virtual"===p.binding||t.binding!==p.binding)),e.markers.push(p);let v=null;const y=o||u?.space||this._space,b=a?this._layout[a]:null,w=b?{s:b.s||u?.space||this._space,x:b.x,y:b.y}:a&&u&&this._defPos[a]?this._normPos(u.space,this._defPos[a].x,this._defPos[a].y):null;if(!c&&w&&w.s===y)i===a&&this._layout[i]&&!m||(v={s:w.s,x:w.x,y:w.y},this._layout={...this._layout,[i]:v});else if(c||!this._layout[i]||m){const t=this._spaceModel(o||void 0);let e=t.vb[0]+t.vb[2]/2,s=t.vb[1]+t.vb[3]/2;const a=r?t.rooms.find(t=>t.id===r):n?t.rooms.find(t=>t.area===n):void 0;a&&([e,s]=this._roomCenter(a)),v=this._normPos(o||this._space,e,s),this._layout={...this._layout,[i]:v}}await this._saveConfigNow(),v&&this._noteLayoutRev(await this.hass.callWS({type:"houseplan/layout/update",device_id:i,pos:v}));const k=new Set(l);a&&a!==i&&k.add(a),k.delete(i);for(const t of k)delete this._layout[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{});g&&f&&await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:f}).catch(()=>{}),this._markerDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_saved"))}catch(t){this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}else this._showToast(this._t("toast.run_target_required"));else this._showToast(this._t("toast.virtual_name_required"))}async _deleteMarker(){const t=this._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this._devices.find(e=>e.id===t.devId):null;if(!e)return;const i=t.name||this._t("device.fallback");if(!confirm(this._t("confirm.remove_marker",{name:i})))return;const s=this._serverCfg;s.markers=s.markers||[];const o=s.markers,n="virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"";if(!n)return;const r=function(t,e,i,s){const o=new Set([e]),n=t.filter(t=>{const n=t.id===e||!s&&t.binding===i;return n&&o.add(t.id),!n});return{markers:s?n:[...n,{id:e,binding:i,removed:!0,hidden:!0}],cleanupIds:o}}(s.markers,e.id,n,"virtual"===e.bindingKind);s.markers=r.markers;const a=r.cleanupIds;this._markerDialog={...t,busy:!0};try{await this._saveConfigNow();for(const t of a){delete this._layout[t],delete this._defPos[t],this._dirtyPos.delete(t),this._sentPos.delete(t);const e=this._activityRt.get(t);e&&clearTimeout(e.timer),this._activityRt.delete(t),this._vacRt.delete(t),delete this._vacSrvTrails[t],await this.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this._noteLayoutRev(t)).catch(()=>{}),await this.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this._markerDialog=null,this._infoCard?.id===e.id&&this._closeInfoCard(),this._selId===e.id&&(this._selId=null),this._drag?.id===e.id&&(this._drag=null),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.marker_removed"))}catch(t){this._serverCfg===s&&(s.markers=o),this._markerDialog&&(this._markerDialog={...this._markerDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}_normPos(t,e,i){return{s:t,x:e/eh,y:i/eh}}_openSpaceDialog(t,e){if(this._serverStorage&&this._serverCfg)if("edit"===t){const i=this._serverCfg.spaces.find(t=>t.id===e);if(!i)return;const s=Yi(i),o=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?Vi(i.settings.custom_fill):null,n="none"===s.fill?{...o||Wi,a:0}:o;this._spaceDialog={mode:t,spaceId:e,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:s.showBorders,showNames:s.showNames,hideDecor:s.hideDecor,hideOpenings:s.hideOpenings,roomColor:s.color,roomOpacity:s.opacity,fillMode:"none"===s.fill?"custom":s.fill,customFill:n,glowEnabled:s.glow,bgColor:s.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:Gn({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:s.tempMin,tempMax:s.tempMax,showLqi:s.showLqi??this._config?.show_signal??!0,cardFontScale:s.cardFontScale,labelTemp:s.labelTemp,labelHum:s.labelHum,labelLqi:s.labelLqi,labelLight:s.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,busy:!1}}else this._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,source:"file",showBorders:!1,showNames:!1,hideDecor:!1,hideOpenings:!1,roomColor:ji,roomOpacity:Gi,fillMode:"custom",customFill:{...Wi,a:0},glowEnabled:!0,bgColor:null,bgMode:null,northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:5,busy:!1};else this._showToast(this._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,i=e.files?.[0];if(!i||!this._spaceDialog)return;const s={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[i.type]||(i.name.toLowerCase().endsWith(".svg")?"svg":"");if(!s)return void this._showToast(this._t("toast.plan_formats"));const o=new Uint8Array(await i.arrayBuffer());let n="";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=a});URL.revokeObjectURL(a),this._spaceDialog={...this._spaceDialog,planFile:{ext:s,b64:r,aspect:l,name:i.name}}}_useServerPlan(t){const e=this._spaceDialog;e&&(this._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this._display(t);if(e){const i=await new Promise(t=>{const i=new Image;i.onload=()=>t(i.naturalWidth&&i.naturalHeight?i.naturalWidth/i.naturalHeight:0),i.onerror=()=>t(0),i.src=e}),s=this._spaceDialog;return s&&s.planUrl===t&&Number.isFinite(i)&&i>0?(this._spaceDialog={...s,savedAspect:i},i):0}if(await new Promise(t=>setTimeout(t,150)),this._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this._t("confirm.delete_plan",{name:t})))try{await this.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this._spaceDialog;e?.saved&&(this._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this._showToast(this._t("toast.plan_delete_failed",{err:this._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return B`
${this._t("space.loading")}
`;const e=t.saved||[];if(!e.length)return B`
${this._t("space.no_saved")}
`;return B`
+ ${e.map(e=>B`
@@ -4091,15 +4163,15 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
`)} -
`}async _saveSpaceDialog(){const t=this._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this._showToast(this._t("toast.plan_required"));const e="create"===t.mode&&0===(this._serverCfg?.spaces.length||0);this._spaceDialog={...t,busy:!0};try{const i="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let s=null;if("file"===t.source&&t.planFile){s={url:(await this.hass.callWS({type:"houseplan/plan/set",space_id:i,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let o=t.savedAspect||null;!s&&"file"===t.source&&t.planUrl&&!o&&this._aspectJob&&(o=await this._aspectJob||null);const n=this._serverCfg;let r;if("create"===t.mode)r={id:i,title:t.title.trim(),plan_url:null,view_box:[0,0,1,1],rooms:[]},n.spaces.push(r);else{if(r=n.spaces.find(t=>t.id===i),!r)throw new Error("space "+i+" is gone from the config");r.title=t.title.trim()}s?(r.plan_url=s.url,r.plan_aspect=s.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==r.plan_url&&(r.plan_url=t.planUrl,r.plan_aspect=o),"draw"===t.source&&(r.plan_url=null,r.plan_aspect=null,delete r.plan_x,delete r.plan_y,delete r.plan_scale,delete r.plan_scale_x,delete r.plan_scale_y,delete r.plan_angle);const a="draw"===t.source;r.settings={...r.settings||{},show_borders:!(!a||"create"!==t.mode)||t.showBorders,show_names:!(!a||"create"!==t.mode)||t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):20,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):25,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},r.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(vc,t.cellCm)):5,await this._saveConfigNow(),this._spaceDialog=null,"create"===t.mode&&(this._space=r.id),this._regSignature="",this._maybeRebuildDevices(),this._importQueue.length?this._openNextImport():e||this._importTotal>0?(this._importTotal=0,this._space=this._serverCfg.spaces[0]?.id||this._space,this._mode="plan",this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._showToast(this._t(e&&!this._importTotal?"toast.space_added_onboard":"import.done"))):(this._showToast("create"===t.mode?this._t("toast.space_added"):this._t("toast.space_saved")),"create"===t.mode&&("plan"!==this._mode?this._setMode("plan"):(this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._saveNav())))}catch(t){this._spaceDialog&&(this._spaceDialog={...this._spaceDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteSpace(){const t=this._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this._serverCfg.spaces.find(e=>e.id===t.spaceId);if(confirm(this._t("confirm.delete_space",{title:e.title}))){this._serverCfg.spaces=this._serverCfg.spaces.filter(e=>e.id!==t.spaceId);try{await this._saveConfigNow(),this._spaceDialog=null,this._space===t.spaceId&&(this._space=this._serverCfg.spaces[0]?.id||""),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.space_deleted"))}catch(t){this._showToast(this._t("toast.delete_failed",{err:this._errText(t)}))}}}async _saveConfigNow(){this._cfgEpoch++;try{await this._writeConfig()}catch(t){throw"conflict"===t?.code&&await this._reloadConfigOnly(),t}}_startImport(){const t=this._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this._importDialog=null,e.length?(this._importQueue=e,this._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this._importQueue.shift();void 0!==t&&(this._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,source:"file",showBorders:!1,showNames:!1,hideDecor:!1,hideOpenings:!1,roomColor:zi,roomOpacity:Ai,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:null,northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:5,busy:!1})}_skipImport(){this._spaceDialog=null,this._importQueue.length?this._openNextImport():this._importTotal>0&&this._model.length&&(this._importTotal=0,this._space=this._serverCfg.spaces[0]?.id||this._space,this._mode="plan",this._showToast(this._t("import.done")))}_renderImportDialog(){const t=this._importDialog,e=t.floors.filter(t=>t.checked).length;return j``}async _saveSpaceDialog(){const t=this._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this._showToast(this._t("toast.plan_required"));const e="create"===t.mode&&0===(this._serverCfg?.spaces.length||0);this._spaceDialog={...t,busy:!0};try{const i="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let s=null;if("file"===t.source&&t.planFile){s={url:(await this.hass.callWS({type:"houseplan/plan/set",space_id:i,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let o=t.savedAspect||null;!s&&"file"===t.source&&t.planUrl&&!o&&this._aspectJob&&(o=await this._aspectJob||null);const n=this._serverCfg;let r;if("create"===t.mode)r={id:i,title:t.title.trim(),plan_url:null,view_box:[0,0,1,1],rooms:[]},n.spaces.push(r);else{if(r=n.spaces.find(t=>t.id===i),!r)throw new Error("space "+i+" is gone from the config");r.title=t.title.trim()}s?(r.plan_url=s.url,r.plan_aspect=s.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==r.plan_url&&(r.plan_url=t.planUrl,r.plan_aspect=o),"draw"===t.source&&(r.plan_url=null,r.plan_aspect=null,delete r.plan_x,delete r.plan_y,delete r.plan_scale,delete r.plan_scale_x,delete r.plan_scale_y,delete r.plan_angle);const a="draw"===t.source;r.settings={...r.settings||{},show_borders:!(!a||"create"!==t.mode)||t.showBorders,show_names:!(!a||"create"!==t.mode)||t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):20,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):25,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},r.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(Fc,t.cellCm)):5,await this._saveConfigNow(),this._spaceDialog=null,"create"===t.mode&&(this._space=r.id),this._regSignature="",this._maybeRebuildDevices(),this._importQueue.length?this._openNextImport():e||this._importTotal>0?(this._importTotal=0,this._space=this._serverCfg.spaces[0]?.id||this._space,this._mode="plan",this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._showToast(this._t(e&&!this._importTotal?"toast.space_added_onboard":"import.done"))):(this._showToast("create"===t.mode?this._t("toast.space_added"):this._t("toast.space_saved")),"create"===t.mode&&("plan"!==this._mode?this._setMode("plan"):(this._tool="draw",this._path=[],this._cursorPt=null,this._primeDrawWallField(),this._saveNav())))}catch(t){this._spaceDialog&&(this._spaceDialog={...this._spaceDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}async _deleteSpace(){const t=this._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this._serverCfg.spaces.find(e=>e.id===t.spaceId);if(confirm(this._t("confirm.delete_space",{title:e.title}))){this._serverCfg.spaces=this._serverCfg.spaces.filter(e=>e.id!==t.spaceId);try{await this._saveConfigNow(),this._spaceDialog=null,this._space===t.spaceId&&(this._space=this._serverCfg.spaces[0]?.id||""),this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("toast.space_deleted"))}catch(t){this._showToast(this._t("toast.delete_failed",{err:this._errText(t)}))}}}async _saveConfigNow(){this._cfgEpoch++;try{await this._writeConfig()}catch(t){throw"conflict"===t?.code&&await this._reloadConfigOnly(),t}}_startImport(){const t=this._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this._importDialog=null,e.length?(this._importQueue=e,this._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this._importQueue.shift();void 0!==t&&(this._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,source:"file",showBorders:!1,showNames:!1,hideDecor:!1,hideOpenings:!1,roomColor:ji,roomOpacity:Gi,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:null,northDeg:null,sunRays:null,tempMin:20,tempMax:25,showLqi:this._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:5,busy:!1})}_skipImport(){this._spaceDialog=null,this._importQueue.length?this._openNextImport():this._importTotal>0&&this._model.length&&(this._importTotal=0,this._space=this._serverCfg.spaces[0]?.id||this._space,this._mode="plan",this._showToast(this._t("import.done")))}_renderImportDialog(){const t=this._importDialog,e=t.floors.filter(t=>t.checked).length;return B`this._importDialog=null}>
${this._t("import.hint")}
- ${t.floors.map((e,i)=>j`
@@ -4111,32 +4183,32 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${this._t("import.start",{n:e})}
-
`}_sunGlobal(){const t=this._settingsDialog;return t?{...this._settings,north_deg:t.northDeg??void 0,bg_mode:t.bgMode,sun_rays:t.sunRays}:this._settings}_sunSpace(){const t=this._spaceDialog,e=this._curSpaceCfg?.settings||{};return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,north_deg:t.northDeg??void 0,bg_mode:t.bgMode??void 0,sun_rays:t.sunRays??void 0}:e}_effNorth(){return Nn(this._sunGlobal(),this._sunSpace())}_effBgMode(){return Fn(this._sunGlobal(),this._sunSpace())}_effSunRays(){return On(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?Ln(this.hass):null}_renderSunRays(t){const e=B``;if(this._editing||!this._effSunRays())return this._sunFadeReset(),e;const i=this._effNorth(),s=null!==i?Ln(this.hass):null;if(!s||s.elevation<=0)return this._sunFadeReset(),e;if(o=s.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return e;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const n=`${t.id}|${s.azimuth}|${s.elevation}|${i}|${this._cfgEpoch}`;if(!this._sunRaysCache||this._sunRaysCache.key!==n){const e=t.rooms.map(t=>({id:t.id||"",poly:Fe(t)})).filter(t=>!!t.id&&!!t.poly),o=this._openingsR.filter(t=>"window"===t.type).map(t=>({id:t.id,x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),r=this._spaceWalls,a=this._openPairs().flatMap(t=>t.segs),l=this._openingWallIndexFor(t,a).value,c={},h={};if(r.length){for(const i of e){const e=Er(t.rooms,i.id,r,a,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc);e&&(c[i.id]=e)}for(const t of o){const e=Br(l,{x:t.x,y:t.y,angle:t.angle,length:t.length});e.cm>0&&(h[t.id]=ir(e.cm,this._cellCm,this._gridPitch))}}let d=An(e,o,s.azimuth,s.elevation,i,r.length?c:void 0,r.length?h:void 0);const p=this._physicalBodiesR(t);p.length&&(d=d.map(t=>{const e=function(t,e,i){return i>0?t.map(t=>function(t){const e=[...t].sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(e.length<=2)return e;const i=(t,e,i)=>(e[0]-t[0])*(i[1]-t[1])-(e[1]-t[1])*(i[0]-t[0]),s=[];for(const t of e){for(;s.length>=2&&i(s[s.length-2],s[s.length-1],t)<=0;)s.pop();s.push(t)}const o=[];for(let t=e.length-1;t>=0;t--){const s=e[t];for(;o.length>=2&&i(o[o.length-2],o[o.length-1],s)<=0;)o.pop();o.push(s)}return s.slice(0,-1).concat(o.slice(0,-1))}([...t,...t.map(t=>[t[0]+e[0]*i,t[1]+e[1]*i])])).filter(t=>t.length>=3):t}(p,t.dir,t.len),i=t.polys.map(t=>ia(t,e));return{...t,paths:i.map(Xr).filter(Boolean),polys:i.flatMap(oa)}}).filter(t=>t.paths?.length||t.polys.length)),this._sunRaysCache={key:n,rays:d,rims:d.map(t=>function(t,e=1e-4){const[i,s]=t.dir,o=-s,n=i,r=[];for(const a of[t.a,t.b]){const l=[];for(const r of t.polys)for(let t=0;te)continue;if(Math.abs((h[0]-a[0])*o+(h[1]-a[1])*n)>e)continue;const d=(c[0]-a[0])*i+(c[1]-a[1])*s,p=(h[0]-a[0])*i+(h[1]-a[1])*s;Math.abs(p-d)<=e||l.push(dt[0]-e[0]);const c=[];for(const t of l){const i=c[c.length-1];i&&t[0]<=i[1]+e?i[1]=Math.max(i[1],t[1]):c.push([t[0],t[1]])}for(const[t,e]of c)r.push([[a[0]+i*t,a[1]+s*t],[a[0]+i*e,a[1]+s*e]])}return r}(t))}}const r=this._sunRaysCache.rays,a=this._sunRaysCache.rims;if(!r.length)return e;const l=(c=Dn(s.elevation).warmth,qi("#ffe9c2","#ff9a45",Cn(c)));var c;const h=[[0,1],[.26,.86],[.46,.6],[.64,.32],[.77,.1],[.85,0],[1,0]],d=[[0,1],[.26,.86],[.46,.6],[.64,.32],[.77,.1],[.85,0],[1,0]];return B` - ${r.map((t,e)=>{const i=(t.a[0]+t.b[0])/2,s=(t.a[1]+t.b[1])/2,o=i+t.normal[0]*t.depth,n=s+t.normal[1]*t.depth;return B``}_sunGlobal(){const t=this._settingsDialog;return t?{...this._settings,north_deg:t.northDeg??void 0,bg_mode:t.bgMode,sun_rays:t.sunRays}:this._settings}_sunSpace(){const t=this._spaceDialog,e=this._curSpaceCfg?.settings||{};return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,north_deg:t.northDeg??void 0,bg_mode:t.bgMode??void 0,sun_rays:t.sunRays??void 0}:e}_effNorth(){return Gn(this._sunGlobal(),this._sunSpace())}_effBgMode(){return Wn(this._sunGlobal(),this._sunSpace())}_effSunRays(){return Vn(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?Kn(this.hass):null}_renderSunRays(t){const e=j``;if(this._editing||!this._effSunRays())return this._sunFadeReset(),e;const i=this._effNorth(),s=null!==i?Kn(this.hass):null;if(!s||s.elevation<=0)return this._sunFadeReset(),e;if(o=s.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return e;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const n=`${t.id}|${s.azimuth}|${s.elevation}|${i}|${this._cfgEpoch}`;if(!this._sunRaysCache||this._sunRaysCache.key!==n){const e=t.rooms.map(t=>({id:t.id||"",poly:Je(t)})).filter(t=>!!t.id&&!!t.poly),o=this._openingsR.filter(t=>"window"===t.type).map(t=>({id:t.id,x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),r=this._spaceWalls,a=this._openPairs().flatMap(t=>t.segs),l=this._openingWallIndexFor(t,a).value,c={},h={};if(r.length){for(const i of e){const e=jr(t.rooms,i.id,r,a,this._wallKeyPitch,this._cellCm,this._gridPitch,eh);e&&(c[i.id]=e)}for(const t of o){const e=ta(l,{x:t.x,y:t.y,angle:t.angle,length:t.length});e.cm>0&&(h[t.id]=dr(e.cm,this._cellCm,this._gridPitch))}}let d=Un(e,o,s.azimuth,s.elevation,i,r.length?c:void 0,r.length?h:void 0);const p=this._physicalBodiesR(t);p.length&&(d=d.map(t=>{const e=function(t,e,i){return i>0?t.map(t=>function(t){const e=[...t].sort((t,e)=>t[0]-e[0]||t[1]-e[1]);if(e.length<=2)return e;const i=(t,e,i)=>(e[0]-t[0])*(i[1]-t[1])-(e[1]-t[1])*(i[0]-t[0]),s=[];for(const t of e){for(;s.length>=2&&i(s[s.length-2],s[s.length-1],t)<=0;)s.pop();s.push(t)}const o=[];for(let t=e.length-1;t>=0;t--){const s=e[t];for(;o.length>=2&&i(o[o.length-2],o[o.length-1],s)<=0;)o.pop();o.push(s)}return s.slice(0,-1).concat(o.slice(0,-1))}([...t,...t.map(t=>[t[0]+e[0]*i,t[1]+e[1]*i])])).filter(t=>t.length>=3):t}(p,t.dir,t.len),i=t.polys.map(t=>ga(t,e));return{...t,paths:i.map(la).filter(Boolean),polys:i.flatMap(va)}}).filter(t=>t.paths?.length||t.polys.length)),this._sunRaysCache={key:n,rays:d,rims:d.map(t=>function(t,e=1e-4){const[i,s]=t.dir,o=-s,n=i,r=[];for(const a of[t.a,t.b]){const l=[];for(const r of t.polys)for(let t=0;te)continue;if(Math.abs((h[0]-a[0])*o+(h[1]-a[1])*n)>e)continue;const d=(c[0]-a[0])*i+(c[1]-a[1])*s,p=(h[0]-a[0])*i+(h[1]-a[1])*s;Math.abs(p-d)<=e||l.push(dt[0]-e[0]);const c=[];for(const t of l){const i=c[c.length-1];i&&t[0]<=i[1]+e?i[1]=Math.max(i[1],t[1]):c.push([t[0],t[1]])}for(const[t,e]of c)r.push([[a[0]+i*t,a[1]+s*t],[a[0]+i*e,a[1]+s*e]])}return r}(t))}}const r=this._sunRaysCache.rays,a=this._sunRaysCache.rims;if(!r.length)return e;const l=(c=Fn(s.elevation).warmth,Qi("#ffe9c2","#ff9a45",Nn(c)));var c;const h=[[0,1],[.26,.86],[.46,.6],[.64,.32],[.77,.1],[.85,0],[1,0]],d=[[0,1],[.26,.86],[.46,.6],[.64,.32],[.77,.1],[.85,0],[1,0]];return j` + ${r.map((t,e)=>{const i=(t.a[0]+t.b[0])/2,s=(t.a[1]+t.b[1])/2,o=i+t.normal[0]*t.depth,n=s+t.normal[1]*t.depth;return j` - ${h.map(([t,e])=>B`j``)} - ${d.map(([t,e])=>B`j``)} `})} - ${r.map((t,e)=>t.paths?.length?t.paths.map(t=>B``):t.polys.map(t=>B`t.paths?.length?t.paths.map(t=>j``):t.polys.map(t=>j``))} - ${r.map((t,e)=>(a[e]||[]).map(t=>B`(a[e]||[]).map(t=>j``))} - `}_skyPlan(){const t=this._editing||"daynight"!==this._effBgMode()?null:this._sunNow();if(!t)return this._skyElev=null,void(this._skySnap=!1);const e=In(t.elevation);var i,s;i=this._skyElev,s=e,(null===i||!Number.isFinite(i)||Math.abs(s-i)>=3)&&(this._skySnap=!0),this._skyElev=e}_skyRelease(){this._skySnap&&!this._skySnapRaf&&(this._skySnapRaf=requestAnimationFrame(()=>{this._skySnapRaf=requestAnimationFrame(()=>{this._skySnapRaf=0,this._skySnap=!1,this.requestUpdate()})}))}_sunFadeReset(){this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunShown=!1,this._sunOut=!1}_compassPoint(t){const e=t.currentTarget.getBoundingClientRect(),i=t.clientX-(e.left+e.width/2),s=t.clientY-(e.top+e.height/2);if(Math.hypot(i,s)<5)return;let o=Math.round(180*Math.atan2(i,-s)/Math.PI);t.shiftKey&&(o=15*Math.round(o/15)),o=(o%360+360)%360,this._settingsDialog={...this._settingsDialog,northDeg:o}}_renderCompass(){const t=this._settingsDialog.northDeg;return j``}_skyPlan(){const t=this._editing||"daynight"!==this._effBgMode()?null:this._sunNow();if(!t)return this._skyElev=null,void(this._skySnap=!1);const e=Bn(t.elevation);var i,s;i=this._skyElev,s=e,(null===i||!Number.isFinite(i)||Math.abs(s-i)>=3)&&(this._skySnap=!0),this._skyElev=e}_skyRelease(){this._skySnap&&!this._skySnapRaf&&(this._skySnapRaf=requestAnimationFrame(()=>{this._skySnapRaf=requestAnimationFrame(()=>{this._skySnapRaf=0,this._skySnap=!1,this.requestUpdate()})}))}_sunFadeReset(){this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunShown=!1,this._sunOut=!1}_compassPoint(t){const e=t.currentTarget.getBoundingClientRect(),i=t.clientX-(e.left+e.width/2),s=t.clientY-(e.top+e.height/2);if(Math.hypot(i,s)<5)return;let o=Math.round(180*Math.atan2(i,-s)/Math.PI);t.shiftKey&&(o=15*Math.round(o/15)),o=(o%360+360)%360,this._settingsDialog={...this._settingsDialog,northDeg:o}}_renderCompass(){const t=this._settingsDialog.northDeg;return B`{t.currentTarget.setPointerCapture(t.pointerId),this._compassDrag=!0,this._compassPoint(t)}} @pointermove=${t=>{this._compassDrag&&this._compassPoint(t)}} @pointerup=${()=>this._compassDrag=!1} @pointercancel=${()=>this._compassDrag=!1}> - ${[0,45,90,135,180,225,270,315].map(t=>B`j``)} @@ -4144,55 +4216,77 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${this._t("gs.north_letter")} ${null===t?"—":t+"°"} - `}_stageBg(t){if("daynight"===this._effBgMode()){const t=this._sunNow();if(t)return Dn(In(t.elevation)).bg}const e=this._settingsDialog,i=this._spaceDialog,s=e?e.bgColor||"":Oi(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":t.bgColor||"")||s}_stageBgHex(){const t=this._stageEl;if(t){const e=getComputedStyle(t).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(e)return"#"+e.slice(1,4).map(t=>(+t).toString(16).padStart(2,"0")).join("")}return"#111111"}async _runAlignToGrid(){const t=this._alignDialog;if(t&&!t.busy&&this._serverCfg){this._clearGeometryGesture(),this._alignDialog={...t,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/plan/optimize",config:t.config,layout:t.layout,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});this._serverCfg=t.config,this._layout=t.layout,this._geometryHistory.clear(),this._cfgRev=e?.config_rev??this._cfgRev+1,this._layoutRev=e?.layout_rev??this._layoutRev+1,this._canOptimizeUndo=!!e?.can_undo,this._dirtyPos.clear(),this._sentPos.clear(),this._cfgEpoch++,this._modelCache=null,this._frame=null,this._cacheSnapshot(),this._alignDialog=null,this.requestUpdate(),this._showToast(this._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.wallsMerged+t.report.spansMerged)}))}catch(t){this._alignDialog&&(this._alignDialog={...this._alignDialog,busy:!1}),"conflict"===t?.code&&await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}}async _undoPlanOptimization(){if(this._canOptimizeUndo&&!this._optimizeUndoBusy){this._clearGeometryGesture(),this._optimizeUndoBusy=!0,this.requestUpdate();try{await this.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});const[t,e]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._serverCfg=t?.config||this._serverCfg,this._cfgRev=t?.rev??this._cfgRev,this._layout=e?.layout||this._layout,this._geometryHistory.clear(),this._layoutRev=e?.rev??this._layoutRev,this._canOptimizeUndo=!1,this._cfgEpoch++,this._modelCache=null,this._frame=null,this._cacheSnapshot(),this.requestUpdate(),this._showToast(this._t("gs.optimize_undone"))}catch(t){this._canOptimizeUndo=!1,this._showToast(this._t("toast.error",{err:this._errText(t)}))}finally{this._optimizeUndoBusy=!1,this.requestUpdate()}}}_setFillColor(t,e){const i=this._settingsDialog;this._settingsDialog={...i,colors:{...i.colors,[t]:{...i.colors[t],...e}}}}async _saveSettingsDialog(){const t=this._settingsDialog;if(t&&!t.busy){this._settingsDialog={...t,busy:!0};try{const e=this._serverCfg,i=JSON.stringify(t.colors)===JSON.stringify(Li),s={...e.settings};i?delete s.fill_colors:s.fill_colors=t.colors;const o=this._imperial?30.48*t.glowRadius:100*t.glowRadius;Number.isFinite(o)&&o>0&&300!==Math.round(o)?s.glow_radius_cm=Math.round(o):delete s.glow_radius_cm,t.bgColor?s.bg_color=t.bgColor:delete s.bg_color,null!==t.northDeg&&Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359?s.north_deg=t.northDeg:delete s.north_deg,"daynight"===t.bgMode?s.bg_mode="daynight":delete s.bg_mode,t.sunRays?s.sun_rays=!0:delete s.sun_rays,delete s.weather_entity,this._serverCfg={...e,settings:s},await this._saveConfigNow(),this._settingsDialog=null,this.requestUpdate(),this._showToast(this._t("gs.saved"))}catch(t){this._settingsDialog&&(this._settingsDialog={...this._settingsDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}}_boolInput(t,e,i=!1){const s=t=>e(!!t.target.checked);return customElements.get("ha-switch")?j``:j``}_rangeInput(t,e,i,s,o,n=!1,r){const a=t=>{const e=Number(t.target.value);Number.isFinite(e)&&o(e)};return customElements.get("ha-slider")?j``:j``}_renderColorRow(t,e){const i=this._settingsDialog.colors[t];return j`
+ `}_stageBg(t){if("daynight"===this._effBgMode()){const t=this._sunNow();if(t)return Fn(Bn(t.elevation)).bg}const e=this._settingsDialog,i=this._spaceDialog,s=e?e.bgColor||"":Ji(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":t.bgColor||"")||s}_stageBgHex(){const t=this._stageEl;if(t){const e=getComputedStyle(t).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(e)return"#"+e.slice(1,4).map(t=>(+t).toString(16).padStart(2,"0")).join("")}return"#111111"}async _runAlignToGrid(){const t=this._alignDialog;if(t&&!t.busy&&this._serverCfg){this._clearGeometryGesture(),this._alignDialog={...t,busy:!0};try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),await this._writeChain;const e=await this.hass.callWS({type:"houseplan/plan/optimize",config:t.config,layout:t.layout,expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});this._serverCfg=t.config,this._layout=t.layout,this._geometryHistory.clear(),this._cfgRev=e?.config_rev??this._cfgRev+1,this._layoutRev=e?.layout_rev??this._layoutRev+1,this._canOptimizeUndo=!!e?.can_undo,this._dirtyPos.clear(),this._sentPos.clear(),this._cfgEpoch++,this._modelCache=null,this._frame=null,this._cacheSnapshot(),this._alignDialog=null,this.requestUpdate(),this._showToast(this._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.wallsMerged+t.report.spansMerged)}))}catch(t){this._alignDialog&&(this._alignDialog={...this._alignDialog,busy:!1}),"conflict"===t?.code&&await Promise.all([this._reloadConfigOnly(!0),this._reloadLayoutOnly()]),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}}async _undoPlanOptimization(){if(this._canOptimizeUndo&&!this._optimizeUndoBusy){this._clearGeometryGesture(),this._optimizeUndoBusy=!0,this.requestUpdate();try{await this.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this._cfgRev,expected_layout_rev:this._layoutRev});const[t,e]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]);this._serverCfg=t?.config||this._serverCfg,this._cfgRev=t?.rev??this._cfgRev,this._layout=e?.layout||this._layout,this._geometryHistory.clear(),this._layoutRev=e?.rev??this._layoutRev,this._canOptimizeUndo=!1,this._cfgEpoch++,this._modelCache=null,this._frame=null,this._cacheSnapshot(),this.requestUpdate(),this._showToast(this._t("gs.optimize_undone"))}catch(t){this._canOptimizeUndo=!1,this._showToast(this._t("toast.error",{err:this._errText(t)}))}finally{this._optimizeUndoBusy=!1,this.requestUpdate()}}}_setFillColor(t,e){const i=this._settingsDialog;this._settingsDialog={...i,colors:{...i.colors,[t]:{...i.colors[t],...e}}}}async _saveSettingsDialog(){const t=this._settingsDialog;if(t&&!t.busy){this._settingsDialog={...t,busy:!0};try{const e=this._serverCfg,i=JSON.stringify(t.colors)===JSON.stringify(Zi),s={...e.settings};i?delete s.fill_colors:s.fill_colors=t.colors;const o=this._imperial?30.48*t.glowRadius:100*t.glowRadius;Number.isFinite(o)&&o>0&&300!==Math.round(o)?s.glow_radius_cm=Math.round(o):delete s.glow_radius_cm,t.bgColor?s.bg_color=t.bgColor:delete s.bg_color,null!==t.northDeg&&Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359?s.north_deg=t.northDeg:delete s.north_deg,"daynight"===t.bgMode?s.bg_mode="daynight":delete s.bg_mode,t.sunRays?s.sun_rays=!0:delete s.sun_rays,delete s.weather_entity,this._serverCfg={...e,settings:s},await this._saveConfigNow(),this._settingsDialog=null,this.requestUpdate(),this._showToast(this._t("gs.saved"))}catch(t){this._settingsDialog&&(this._settingsDialog={...this._settingsDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}}_boolInput(t,e,i=!1){const s=t=>e(!!t.target.checked);return customElements.get("ha-switch")?B``:B``}_rangeInput(t,e,i,s,o,n=!1,r){const a=t=>{const e=Number(t.target.value);Number.isFinite(e)&&o(e)};return customElements.get("ha-slider")?B``:B``}_renderColorRow(t,e){const i=this._settingsDialog.colors[t];return B`
${this._t(e)} this._setFillColor(t,{c:e.target.value})} /> ${this._rangeInput(0,100,1,Math.round(100*i.a),e=>this._setFillColor(t,{a:e/100}))} ${Math.round(100*i.a)}% -
`}get _glowRadiusCm(){const t=Number(this._settings.glow_radius_cm);return Number.isFinite(t)&&t>0?t:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const t=this._glowRadiusCm;return this._imperial?String(Math.round(t/30.48*10)/10):String(t/100)}_renderGlowLayer(t,e){const i=this._fillColors,s=this._glowRadiusCm/this._cellCm*this._gridPitch,o=this._gridPitch,n=t.rooms.map(t=>({r:t,poly:Fe(t)})).filter(t=>!!t.poly),r=n.filter(({r:t})=>ps(e.glow,t));if(!r.length)return B``;const a=this._openingsR.filter(t=>"window"!==t.type),l=this._spaceWalls,c=this._openPairs().flatMap(t=>t.segs),h=this._physicalBodiesR(t),d=new Map;if(l.length)for(const e of a){const i=e.angle*Math.PI/180,s=Math.cos(i)*e.rlen/2,o=Math.sin(i)*e.rlen/2,n=Ar(t.rooms,l,c,[e.rx-s,e.ry-o,e.rx+s,e.ry+o],this._wallKeyPitch,this._cellCm,this._gridPitch,Nc);n>0&&d.set(e.id,ir(n,this._cellCm,this._gridPitch))}const p=mo(this._planHass,this._devices.filter(e=>e.space===t.id)),u=new Map;for(const t of p){if(!t.device.id)continue;const e=u.get(t.device.id)||[];e.push(t),u.set(t.device.id,e)}const _=[];for(const e of this._devices){if(e.space!==t.id)continue;const r=go(u.get(e.id)||[]);if(!r)continue;const p=Xi(this._planHass.states[r.eid],e.marker?.glow_color,i.glow_light.c);if(!p)continue;const m=Number(e.marker?.glow_radius_cm),g=Number.isFinite(m)&&m>0?m/this._cellCm*this._gridPitch:s,f=this._pos(e),v=[...n].reverse().find(t=>this._pointInRoom([f.x,f.y],t.r));let y=null;const b=v?`${t.id}|${this._cfgEpoch}|${f.x.toFixed(4)},${f.y.toFixed(4)}|${g.toFixed(4)}`:"",w=v?kc(this._glowClipCache,b):{hit:!1};if(w.hit)y=w.value;else if(v){const e=h.length?na(h,[f.x,f.y],g):[],i=v.r.id?os(v.r.id,t.rooms):new Set([v.r.id]),s=n.filter(t=>t.r.id&&i.has(t.r.id)),r=s.length?s:[v],p=r.map(i=>{const s=l.length&&i.r.id&&Er(t.rooms,i.r.id,l,c,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)||i.poly;return e.length?Xr(ia(s,e)):"M "+s.map(t=>t[0]+" "+t[1]).join(" L ")+" Z"}),u=n.filter(t=>!r.includes(t)).map(t=>t.poly);for(const t of a){const i=r.some(e=>{const i=We([t.rx,t.ry],e.poly);return i&&Math.hypot(i[0]-t.rx,i[1]-t.ry)<=.75*o});if(!i)continue;const s=t.angle*Math.PI/180,n=Math.cos(s)*t.rlen/2,a=Math.sin(s)*t.rlen/2;if(!es([t.rx,t.ry],t.angle,[f.x,f.y],u,.6*o))continue;const l=ts([f.x,f.y],[t.rx-n,t.ry-a],[t.rx+n,t.ry+a],g,170,d.get(t.id)||0);l&&p.push(e.length?Xr(ia(l,e)):"M "+l.map(t=>t[0]+" "+t[1]).join(" L ")+" Z")}y=p,$c(this._glowClipCache,b,y,256)}_.push({pos:f,c:p.c,alpha:Qi(p.bri,i.glow_light.a),clip:y,r:g})}if(!_.length)return B``;const m=r.length===n.length?null:r.map(({r:e,poly:i})=>{const s=l.length&&e.id&&Er(t.rooms,e.id,l,c,this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)||i,o=this._cleanFloor(e,s,t).path,r=ii(s,n.filter(t=>t.r!==e).map(t=>t.poly)),a=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z";return[o||a(s),...r.map(a)].join(" ")});return B` - ${_.map((t,e)=>B` - - - - - - ${t.clip?B`${t.clip.map(t=>B``)}`:W}`)} - ${m?B`${m.map(t=>B``)}`:W} +
`}get _glowRadiusCm(){const t=Number(this._settings.glow_radius_cm);return Number.isFinite(t)&&t>0?t:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const t=this._glowRadiusCm;return this._imperial?String(Math.round(t/30.48*10)/10):String(t/100)}_glowTransition(t,e){let i=this._glowRenderedSources.get(t);if(e){const e=this._glowFadeTimers.get(t);if(null!=e&&(clearTimeout(e),this._glowFadeTimers.delete(t)),null==i){i=++this._glowSourceSeq,this._glowRenderedSources.set(t,i),this._glowEnteringSources.add(t);const e=requestAnimationFrame(()=>{this._glowEnterRafs.get(t)===e&&(this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(t,e)}return{domId:i,entering:this._glowEnteringSources.has(t),leaving:!1}}if(null==i)return null;const s=this._glowEnterRafs.get(t);if(null!=s&&cancelAnimationFrame(s),this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),!this._glowFadeTimers.has(t)){const e=window.setTimeout(()=>{this._glowFadeTimers.get(t)===e&&(this._glowFadeTimers.delete(t),this._glowRenderedSources.delete(t),this._glowLastAppearance.delete(t),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(t,e)}return{domId:i,entering:!1,leaving:!0}}_forgetGlowSource(t){const e=this._glowFadeTimers.get(t);null!=e&&clearTimeout(e);const i=this._glowEnterRafs.get(t);null!=i&&cancelAnimationFrame(i),this._glowFadeTimers.delete(t),this._glowEnterRafs.delete(t),this._glowEnteringSources.delete(t),this._glowRenderedSources.delete(t),this._glowLastAppearance.delete(t)}_forgetGlowSpace(t){const e=`${t}|`;for(const t of this._glowRenderedSources.keys())t.startsWith(e)&&this._forgetGlowSource(t)}_lightBarriers(t,e,i){const s=this._openPairs().flatMap(t=>t.segs),o=[...s],n=Math.max(this._cmToUnits(10),.5*this._gridPitch),r=t=>e.some(e=>this._pointInRoom(t,e.r)),a=this._openingsR.filter(t=>{if("window"===t.type)return!1;const e=t.angle*Math.PI/180,i=-Math.sin(e),s=Math.cos(e);return r([t.rx+i*n,t.ry+s*n])&&r([t.rx-i*n,t.ry-s*n])});for(const t of a){const e=t.angle*Math.PI/180,i=Math.cos(e)*t.rlen/2,s=Math.sin(e)*t.rlen/2;o.push([t.rx-i,t.ry-s,t.rx+i,t.ry+s])}let l=2166136261;const c=t=>{l^=Math.round(64*(Number.isFinite(t)?t:0)),l=Math.imul(l,16777619)>>>0},h=this._spaceWalls;for(const{poly:t}of e){c(t.length);for(const e of t)c(e[0]),c(e[1])}for(const t of o)for(const e of t)c(e);for(const t of i)c(t.length),c(t[0]?.[0]??0),c(t[0]?.[1]??0);for(const t of h)c(t.cm),c(t.a?.[0]??0),c(t.a?.[1]??0);const d=l.toString(36);if(this._lightBarrierCache?.key===d)return this._lightBarrierCache.value;const p=.02*this._gridPitch,u=[],_=h.length?Wr(t.rooms,h,s,a.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),this._wallKeyPitch,this._cellCm,this._gridPitch,eh):null;for(const t of function(t){const e=[];for(const i of t||[])for(const t of i||[])t?.length>=4&&e.push(t.slice(0,-1).map(t=>[t[0],t[1]]));return e}(_?.geom))u.push(...Ql(t));for(const{poly:t}of e)for(const e of o.length?ms(t,o,p):Ql(t))u.push(e);for(const t of i)u.push(...Ql(t));const m={occluders:Xl(u),floor:e.map(t=>t.poly),fingerprint:d};return this._lightBarrierCache={key:d,value:m},m}_renderGlowLayer(t,e){const i=this._fillColors,s=this._glowRadiusCm/this._cellCm*this._gridPitch;this._gridPitch;const o=t.rooms.map(t=>({r:t,poly:Je(t)})).filter(t=>!!t.poly),n=o.filter(({r:t})=>ws(e.glow,t));if(!n.length)return this._forgetGlowSpace(t.id),j``;const r=this._physicalBodiesR(t),{occluders:a,floor:l,fingerprint:c}=this._lightBarriers(t,o,r),h=xo(this._planHass,this._devices.filter(e=>e.space===t.id)),d=new Map;for(const t of h){if(!t.device.id)continue;const e=d.get(t.device.id)||[];e.push(t),d.set(t.device.id,e)}const p=[],u=new Set;for(const e of this._devices){if(e.space!==t.id)continue;const o=So(d.get(e.id)||[]);if(!o)continue;const n=`${t.id}|${e.id}`;u.add(n);const h=hs(this._planHass.states[o.eid],e.marker?.glow_color,i.glow_light.c),_=Number(e.marker?.glow_radius_cm),m=Number.isFinite(_)&&_>0?_/this._cellCm*this._gridPitch:s,g=this._pos(e);if(r.some(t=>ya([g.x,g.y],t))){this._glowTransition(n,!1);continue}const f=this._glowTransition(n,!!h);if(!f)continue;h&&this._glowLastAppearance.set(n,{c:h.c,alpha:ds(h.bri,i.glow_light.a)});const v=this._glowLastAppearance.get(n);if(!v)continue;let y=null;const b=`${t.id}|${c}|${g.x.toFixed(4)},${g.y.toFixed(4)}|${m.toFixed(4)}`,w=qc(this._glowClipCache,b);if(w.hit)y=w.value;else{const t=ic([g.x,g.y],m,a,96);y={lit:t.length>=3?ma([t],l):[]},Uc(this._glowClipCache,b,y,256)}p.push({key:n,sourceEid:o.eid,domId:f.domId,entering:f.entering,leaving:f.leaving,pos:g,c:v.c,alpha:v.alpha,geometry:y,r:m})}const _=`${t.id}|`;for(const t of this._glowRenderedSources.keys())t.startsWith(_)&&!u.has(t)&&this._forgetGlowSource(t);if(!p.length)return j``;const m=this._spaceWalls,g=n.length===o.length?null:n.map(({r:e,poly:i})=>{const s=m.length&&e.id&&jr(t.rooms,e.id,m,this._openPairs().flatMap(t=>t.segs),this._wallKeyPitch,this._cellCm,this._gridPitch,eh)||i,n=this._cleanFloor(e,s,t).path,r=_i(s,o.filter(t=>t.r!==e).map(t=>t.poly)),a=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z";return[n||a(s),...r.map(a)].join(" ")}),f=this._viewOr(this._baseVb()),v=this._stageEl?.clientWidth&&f.w?this._stageEl.clientWidth/f.w:1,y=1/(v>0?v:1),b=4*y,w=p.reduce((t,e)=>({x:Math.min(t.x,e.pos.x-e.r-b),y:Math.min(t.y,e.pos.y-e.r-b),maxX:Math.max(t.maxX,e.pos.x+e.r+b),maxY:Math.max(t.maxY,e.pos.y+e.r+b),w:0,h:0}),{x:1/0,y:1/0,maxX:-1/0,maxY:-1/0,w:0,h:0});return w.w=w.maxX-w.x,w.h=w.maxY-w.y,j` + ${kt(p,t=>t.key,t=>{const e=t.domId,i=t.geometry;return j` + ${""} + + ${ih.map(([e,i])=>j` + `)} + + ${""} + ${i?j` + + + `:W}`})} + ${g?j`${g.map(t=>j``)}`:W} + ${""} + + + ${""} - + - ${_.map((t,e)=>B``)} + data-feather-px="${2}" + clip-path=${g?"url(#hp-glow-enabled)":W}> + ${kt(p,t=>t.key,t=>{const e=t.domId;return j` + + + `})} - `}_renderAlignDialog(){const t=this._alignDialog,e=t.report;return j``}_renderAlignDialog(){const t=this._alignDialog,e=t.report;return B`this._alignDialog=null}>
- ${t.changed?j` - ${e.moved?j`

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

`:W} - ${t.where?j`

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

`:W} - ${e.rotated?j`

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

`:W} - ${e.removedDrafts?j`

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

`:W} + ${t.changed?B` + ${e.moved?B`

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

`:W} + ${t.where?B`

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

`:W} + ${e.rotated?B`

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

`:W} + ${e.removedDrafts?B`

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

`:W}

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

- ${e.glowSpacesMigrated||e.glowRoomsMigrated?j`

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

`:W} -
${this._t("gs.align_warn")}
`:j`

${this._t("gs.align_none")}

`} + ${e.glowSpacesMigrated||e.glowRoomsMigrated?B`

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

`:W} +
${this._t("gs.align_warn")}
`:B`

${this._t("gs.align_none")}

`}
- ${t.changed?j` + ${t.changed?B` `:W}
-
`}_renderSettingsDialog(){return j``}_renderSettingsDialog(){return B`this._settingsDialog=null}>
${this._t("gs.hint")}
@@ -4214,7 +4308,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${this._t("gs.glow_radius")} {const e=wc(t.target.value);null!=e&&e>0&&(this._settingsDialog={...this._settingsDialog,glowRadius:e})}} /> + @input=${t=>{const e=Hc(t.target.value);null!=e&&e>0&&(this._settingsDialog={...this._settingsDialog,glowRadius:e})}} /> ${this._imperial?this._t("gs.unit_ft"):this._t("gs.unit_m")}
@@ -4228,14 +4322,14 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
- ${"static"===this._settingsDialog.bgMode?j`
+ ${"static"===this._settingsDialog.bgMode?B`
${this._t("gs.bg_color")} this._settingsDialog={...this._settingsDialog,bgColor:t.target.value}} /> - ${this._settingsDialog.bgColor?j``:j`${this._t("gs.bg_theme")}`} -
`:j`
${this._t("gs.bg_daynight_hint")}
`} + ${this._settingsDialog.bgColor?B``:B`${this._t("gs.bg_theme")}`} +
`:B`
${this._t("gs.bg_daynight_hint")}
`} - ${Ln(this.hass)?W:j`
${this._t("gs.sun_missing")}
`} + ${Kn(this.hass)?W:B`
${this._t("gs.sun_missing")}
`}
${this._renderCompass()}
@@ -4245,9 +4339,9 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 placeholder=${this._t("gs.north_ph")} .value=${null===this._settingsDialog.northDeg?"":String(this._settingsDialog.northDeg)} @input=${t=>{const e=t.target.value.trim(),i=""===e?null:Math.round(Number(e));this._settingsDialog={...this._settingsDialog,northDeg:null!==i&&Number.isFinite(i)?Math.min(359,Math.max(0,i)):null}}} /> - ${null!==this._settingsDialog.northDeg?j``:W} + ${null!==this._settingsDialog.northDeg?B``:W}
- ${null===this._settingsDialog.northDeg?j`
${this._t("gs.north_hint")}
`:W} + ${null===this._settingsDialog.northDeg?B`
${this._t("gs.north_hint")}
`:W}
- ${this._canOptimizeUndo?j`
+ ${this._canOptimizeUndo?B`
`:W} -
${this._t("gs.about_version",{v:gc})}
+
${this._t("gs.about_version",{v:Ec})}
${this._t("gs.about_github")} ${this._t("gs.about_telegram")}
- @@ -4284,7 +4378,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${this._settingsDialog.busy?"…":this._t("btn.save")}
- `}_rulesSet(t){this._rulesDialog={...this._rulesDialog,rules:t}}async _saveRules(){const t=this._rulesDialog;if(!t||t.busy)return;const e=t.rules.filter(t=>t.pattern.trim()&&t.icon.trim());this._rulesDialog={...t,busy:!0};try{const t=this._serverCfg,i=JSON.stringify(e)===JSON.stringify($t),s={...t.settings};i?delete s.icon_rules:s.icon_rules=e,this._serverCfg={...t,settings:s},await this._saveConfigNow(),this._rulesDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("rules.saved"))}catch(t){this._rulesDialog&&(this._rulesDialog={...this._rulesDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}_renderRulesDialog(){const t=this._rulesDialog,e=xt(t.rules),i=t.test.trim()?Dt(t.test,"",e):null,s=(e,i)=>{const s=[...t.rules],o=e+i;o<0||o>=s.length||([s[e],s[o]]=[s[o],s[e]],this._rulesSet(s))};return j``}_rulesSet(t){this._rulesDialog={...this._rulesDialog,rules:t}}async _saveRules(){const t=this._rulesDialog;if(!t||t.busy)return;const e=t.rules.filter(t=>t.pattern.trim()&&t.icon.trim());this._rulesDialog={...t,busy:!0};try{const t=this._serverCfg,i=JSON.stringify(e)===JSON.stringify(Nt),s={...t.settings};i?delete s.icon_rules:s.icon_rules=e,this._serverCfg={...t,settings:s},await this._saveConfigNow(),this._rulesDialog=null,this._regSignature="",this._maybeRebuildDevices(),this._showToast(this._t("rules.saved"))}catch(t){this._rulesDialog&&(this._rulesDialog={...this._rulesDialog,busy:!1}),this._showToast(this._t("toast.error",{err:this._errText(t)}))}}_renderRulesDialog(){const t=this._rulesDialog,e=Ft(t.rules),i=t.test.trim()?qt(t.test,"",e):null,s=(e,i)=>{const s=[...t.rules],o=e+i;o<0||o>=s.length||([s[e],s[o]]=[s[o],s[e]],this._rulesSet(s))};return B`this._rulesDialog=null}>
${this._t("rules.hint")}
@@ -4292,9 +4386,9 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 this._rulesDialog={...t,test:e.target.value}} /> - ${i?j`${i}`:W} + ${i?B`${i}`:W}
- ${t.rules.map((e,i)=>{const o=""!==e.pattern.trim()&&!function(t){try{return new RegExp(t,"i"),!0}catch{return!1}}(e.pattern);return j`
+ ${t.rules.map((e,i)=>{const o=""!==e.pattern.trim()&&!function(t){try{return new RegExp(t,"i"),!0}catch{return!1}}(e.pattern);return B`
- @@ -4325,11 +4419,11 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${t.busy?"…":this._t("btn.save")}
- `}_saveKioskScale(t){this._kioskScale={...this._kioskScale,...t};try{localStorage.setItem(Ec,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const t=this._kioskScale,e=(e,i)=>j` + `}_saveKioskScale(t){this._kioskScale={...this._kioskScale,...t};try{localStorage.setItem(th,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const t=this._kioskScale,e=(e,i)=>B`
${this._rangeInput(50,300,5,Math.round(100*t[e]),t=>this._saveKioskScale({[e]:t/100}))} ${Math.round(100*t[e])}% -
`;return j``;return B`this._kioskDialog=!1}>
${this._t("kiosk.hint")}
@@ -4341,7 +4435,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
-
`}render(){if(!this._config||!this.hass)return W;const t=this._model,e=this.houseplanDiagnostics();if(!t.length)return j``}render(){if(!this._config||!this.hass)return W;const t=this._model,e=this.houseplanDiagnostics();if(!t.length)return B` @@ -4351,15 +4445,15 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51

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

- ${this._serverStorage?j`

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

+ ${this._serverStorage?B`

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

`:j`

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

`} + `:B`

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

`}
${this._spaceDialog?this._renderSpaceDialog():W} ${this._importDialog?this._renderImportDialog():W} - ${this._toast?j``:W} -
`;const i=this._spaceModel(),s=i.vb,o="devices"===this._mode&&this._showAll,n=this._devices.filter(t=>t.space===i.id&&(!t.hidden||o)),r=this._spaceDisplayForRender(),a=this._resolvedRoomFills(i,r),l=this._resolvedGlowBase(i,r,a),c=r.showLqi??this._config.show_signal??!0,h=this._config.icon_size??2.5,d=h>8?2.5:h,p=this._viewOr(s),u=this._editing?"":this._stageBg(r),_=this._editing||"daynight"!==this._effBgMode()?null:this._sunNow(),m=_?Dn(In(_.elevation)).planDim:0,g=this._opMeasureView,f=this._decorMeasure,v=this._bdLive,y=this._furnLive,b="view"===this._mode?this._editorChromeMode:this._mode;return j` + ${this._toast?B``:W} +
`;const i=this._spaceModel(),s=i.vb,o="devices"===this._mode&&this._showAll,n=this._devices.filter(t=>t.space===i.id&&(!t.hidden||o)),r=this._spaceDisplayForRender(),a=this._resolvedRoomFills(i,r),l=this._resolvedGlowBase(i,r,a),c=r.showLqi??this._config.show_signal??!0,h=this._config.icon_size??2.5,d=h>8?2.5:h,p=this._viewOr(s),u=this._editing?"":this._stageBg(r),_=this._editing||"daynight"!==this._effBgMode()?null:this._sunNow(),m=_?Fn(Bn(_.elevation)).planDim:0,g=this._opMeasureView,f=this._decorMeasure,v=this._bdLive,y=this._furnLive,b="view"===this._mode?this._editorChromeMode:this._mode;return B`
- ${t.map(t=>j``)} ${""} - ${this._canEdit&&!this._kiosk?j``:W}
- ${this._canEdit?j`
- ${[["plan","mdi:floor-plan"],["devices","mdi:tune-variant"],["decor","mdi:draw"]].map(([t,e])=>j``)}
`:W} @@ -4409,11 +4503,11 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 title=${this._t("title.zoom_fit")}>
- ${this._norm&&this._canEdit?j``:W}
- ${this._canEdit&&!this._kiosk?j`
${"plan"===b?this._renderMarkupBar():"devices"===b?this._renderDevicesBar():this._renderDecorBar()} @@ -4434,43 +4528,43 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 style="${_?`filter:brightness(${(1-m).toFixed(3)})`:""}"> ${""} - ${this._wallHatchDefs(r.color)}${B`${this._paperShapes(i.rooms).map(t=>"poly"in t?B``:B``)}`} + ${this._wallHatchDefs(r.color)}${j`${this._paperShapes(i.rooms).map(t=>"poly"in t?j``:j``)}`} ${this._editing?this._renderMarkupDefs(s):W} ${""} - ${this._editing&&!this._markup&&this._gridLevels()?B``:W} - ${i.bg&&this._display(i.bg.href)?B``:W} + ${i.bg&&this._display(i.bg.href)?j`this._openBackdropDialog(t)} preserveAspectRatio="none" />`:W} ${""} ${r.hideDecor&&"decor"!==this._mode?W:this._renderDecorLayer()} - ${(()=>{const t=this._openPairs(),e=new Map,s=t=>(e.has(t)||e.set(t,Fe(t)),e.get(t));return i.rooms.filter(t=>t.area||"view"===this._mode||this._markup||r.showBorders).map(e=>{let o="room "+(i.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||e.id!==this._mergeSel&&e.id!==this._splitSel?.roomId||(o+=" picked");let n="";const l=ds(r.fill,e);if(!this._markup&&(r.showBorders||"none"!==l)){o+=" styled";const t=[];t.push(`--room-stroke:${r.color}`,`--room-stroke-op:${r.showBorders?r.opacity:0}`);const i=a.byRoom.get(e)||null;i?(o+=" filled",t.push(`--room-fill:${i.color}`,`--room-fill-op:${i.opacity}`)):t.push("--room-fill:transparent","--room-fill-op:0"),n=t.join(";")}let h;const d=t=>{"view"===this._mode&&(void 0===h&&(h=this._roomArea(e)),this._showTip(t,e.name||this._t("room.unnamed"),h?this._t("tip.area",{value:h}):"",c?this._roomLqi(e.area):null,this._roomTemp(e)))},p=this._markup&&(e.id===this._mergeSel||e.id===this._splitSel?.roomId),u=e.id&&!p?t.filter(t=>t.a.id===e.id||t.b.id===e.id).flatMap(t=>t.segs):[],_=p?[]:this._thickWallCuts(),m=u.concat(_);m.length&&(o+=" noedge");const g=s(e),f=this._spaceWalls,v=f.length&&e.id&&g&&Er(i.rooms,e.id,f,this._openPairs().flatMap(t=>t.segs),this._wallKeyPitch,this._cellCm,this._gridPitch,Nc)||g,y=v?ii(v,(b=e,i.rooms.filter(t=>t!==b).map(s).filter(Boolean))):[];var b;const w=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",k=v?this._cleanFloor(e,v,i).path:"",$=e.id||W,x=e.area||W,S=k&&v?B`{const t=this._openPairs(),e=new Map,s=t=>(e.has(t)||e.set(t,Je(t)),e.get(t));return i.rooms.filter(t=>t.area||"view"===this._mode||this._markup||r.showBorders).map(e=>{let o="room "+(i.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||e.id!==this._mergeSel&&e.id!==this._splitSel?.roomId||(o+=" picked");let n="";const l=bs(r.fill,e);if(!this._markup&&(r.showBorders||"none"!==l)){o+=" styled";const t=[];t.push(`--room-stroke:${r.color}`,`--room-stroke-op:${r.showBorders?r.opacity:0}`);const i=a.byRoom.get(e)||null;i?(o+=" filled",t.push(`--room-fill:${i.color}`,`--room-fill-op:${i.opacity}`)):t.push("--room-fill:transparent","--room-fill-op:0"),n=t.join(";")}let h;const d=t=>{"view"===this._mode&&(void 0===h&&(h=this._roomArea(e)),this._showTip(t,e.name||this._t("room.unnamed"),h?this._t("tip.area",{value:h}):"",c?this._roomLqi(e.area):null,this._roomTemp(e)))},p=this._markup&&(e.id===this._mergeSel||e.id===this._splitSel?.roomId),u=e.id&&!p?t.filter(t=>t.a.id===e.id||t.b.id===e.id).flatMap(t=>t.segs):[],_=p?[]:this._thickWallCuts(),m=u.concat(_);m.length&&(o+=" noedge");const g=s(e),f=this._spaceWalls,v=f.length&&e.id&&g&&jr(i.rooms,e.id,f,this._openPairs().flatMap(t=>t.segs),this._wallKeyPitch,this._cellCm,this._gridPitch,eh)||g,y=v?_i(v,(b=e,i.rooms.filter(t=>t!==b).map(s).filter(Boolean))):[];var b;const w=t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z",k=v?this._cleanFloor(e,v,i).path:"",$=e.id||W,x=e.area||W,S=k&&v?j`this._hoverRoom={space:i.id,room:e}} @mousemove=${d} - @mouseleave=${()=>{this._tip=null,this._hoverRoom=null}}>`:y.length&&v?B`{this._tip=null,this._hoverRoom=null}}>`:y.length&&v?j`this._hoverRoom={space:i.id,room:e}} @mousemove=${d} - @mouseleave=${()=>{this._tip=null,this._hoverRoom=null}}>`:v&&v!==g?B`{this._tip=null,this._hoverRoom=null}}>`:v&&v!==g?j`this._hoverRoom={space:i.id,room:e}} @mousemove=${d} - @mouseleave=${()=>{this._tip=null,this._hoverRoom=null}}>`:e.poly?B`{this._tip=null,this._hoverRoom=null}}>`:e.poly?j`this._hoverRoom={space:i.id,room:e}} @mousemove=${d} - @mouseleave=${()=>{this._tip=null,this._hoverRoom=null}}>`:B`{this._tip=null,this._hoverRoom=null}}>`:j`this._hoverRoom={space:i.id,room:e}} @mousemove=${d} - @mouseleave=${()=>{this._tip=null,this._hoverRoom=null}}>`,M=m.length&&g?rs(g,m,.02*this._gridPitch):null,C=M?B`{this._tip=null,this._hoverRoom=null}}>`,M=m.length&&g?ms(g,m,.02*this._gridPitch):null,C=M?j``:W;return B`${S}${C}`})})()} + style=${this._markup?W:`stroke:${r.color};stroke-opacity:${r.showBorders?r.opacity:0}`}>`:W;return j`${S}${C}`})})()} ${this._renderOpeningTunnelFills(i,a)} ${this._renderGlowBaseRooms(i,l)} ${this._renderOpeningTunnelFills(i,l,"glow-base")} @@ -4495,7 +4589,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${this._renderTextFrame(p)} ${""} -
+
${n.map(t=>this._renderDevice(t,p,c))} ${this._renderVacuums(n,p)} ${this._renderVacFit(p)} @@ -4503,28 +4597,28 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${r.showNames||this._markup?i.rooms.map(t=>this._renderRoomLabel(t,i,p,r)):W} ${this._markup?i.rooms.map(t=>this._renderRoomGear(t,i,p)):W}
- ${this._measureAnchor?j`
${this._renderMeasureLabel(p)}
`:W} - ${this._rszLive?j`
${this._rszLive.map(t=>j`
${this._renderMeasureLabel(p)}
`:W} + ${this._rszLive?B`
${this._rszLive.map(t=>B`
${t.text}
`)}
`:W} - ${g?j`
${g.labels.map(t=>j`
${g.labels.map(t=>B`
${t.text}
`)}
`:W} - ${this._wallDialog?j`
${this._renderWallThickDialog()}
`:W} - ${f?j`
${this._renderWallThickDialog()}
`:W} + ${f?B`
${f.text}
`:W} - ${y?j`
${y.map(t=>j`
${y.map(t=>B`
${t.text}
`)}
`:W} - ${v?j`
${v.text}
`:W}
- ${this._zoom>1?j`
${Math.round(100*this._zoom)}%
`:W} + ${this._zoom>1?B`
${Math.round(100*this._zoom)}%
`:W} ${this._renderFarHint()} ${this._renderHomeArrow()} - ${this._booting||this._bootFading?j` @@ -4540,7 +4634,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${this._decorEraseConfirm?this._renderDecorEraseConfirm():W} ${this._spaceDialog?this._renderSpaceDialog():W} ${this._markerDialog?this._renderMarkerDialog():W} - ${this._vacCalConfirm?j`this._vacCalConfirm=null}>
@@ -4560,24 +4654,24 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51 ${this._settingsDialog?this._renderSettingsDialog():W} ${this._alignDialog?this._renderAlignDialog():W} ${this._importDialog?this._renderImportDialog():W} - ${this._tip?j`
- ${this._tip.title}${this._tip.meta?j`${this._tip.meta}`:W} - ${null!=this._tip.temp?j`${this._t("tip.temp_avg")} ${this._tip.temp}°`:W} - ${null!=this._tip.lqi?j`${this._t("tip.lqi")} - ${this._tip.lqi}`:W} + ${this._tip?B`
+ ${this._tip.title}${this._tip.meta?B`${this._tip.meta}`:W} + ${null!=this._tip.temp?B`${this._t("tip.temp_avg")} ${this._tip.temp}°`:W} + ${null!=this._tip.lqi?B`${this._t("tip.lqi")} + ${this._tip.lqi}`:W}
`:W} - ${this._kiosk&&this._kioskDots&&this._model.length>1?j`
- ${this._model.map(t=>j``)} + ${this._kiosk&&this._kioskDots&&this._model.length>1?B`
+ ${this._model.map(t=>B``)}
`:W} ${this._kioskDialog?this._renderKioskDialog():W} - ${this._vacFit?j`
+ ${this._vacFit?B`
${this._t("vac.fit_hint")}
`:W} - ${this._tapConfirm?j`this._tapConfirm=null}>

${this._tapConfirm.text}

@@ -4588,30 +4682,30 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
`:W} - ${this._toast?j``:W} + ${this._toast?B``:W} - `}_vacCandidateStatus(t,e){const i=this._bindingStatus("entity:"+t);if("ha_disabled"===i.kind)return"disabled";if("orphaned"===i.kind)return"missing";if("unverified"===i.kind)return"unverified";const s=this.hass?.states?.[t];return"unavailable"===s?.state?"unavailable":e?.hasPosition?"ok":"unsupported"}_vacOpenAllCameras(t){const e=this._haRegistry.entities||{},i=[];for(const[t,s]of Object.entries(this.hass?.states||{})){if(!t.startsWith("camera."))continue;const o=Dl(t,s,e[t]);o&&i.push(o)}this._vacAllCameraCache={devId:t.id,candidates:i},this._vacAllCamerasFor=t.id}_vacSourceResolution(t,e=!1){const i=t.marker?.vacuum,s="string"==typeof i?.source&&!!i.source,o=new Set(t.entities||[]),n=new Set(o);s&&n.add(i.source);const r=this._haRegistry.entities||{},a=[];for(const t of n){const e=this.hass?.states?.[t],o=Dl(t,e,r[t]);o?a.push(o):s&&t===i.source&&a.push({entityId:t,name:String(e?.attributes?.friendly_name||t),platform:r[t]?.platform?String(r[t].platform):null,category:t.startsWith("camera.")?"camera":"partial",hasPosition:!1,hasRooms:!1,hasPath:!1,hasMapId:!1,score:0})}if(e&&this._vacAllCameraCache?.devId===t.id){const t=new Set(a.map(t=>t.entityId));for(const e of this._vacAllCameraCache.candidates)t.has(e.entityId)||a.push(e)}const l={};for(const t of a)l[t.entityId]=this._vacCandidateStatus(t.entityId,t);return function(t,e,i,s){const o="string"==typeof t&&t.length>0,n=new Set(e),r=Array.from(i).sort((e,i)=>o&&e.entityId===t?-1:o&&i.entityId===t?1:i.score-e.score||e.entityId.localeCompare(i.entityId));if(o){const e=r.find(e=>e.entityId===t);return{entityId:t,status:s[t]||(e?.hasPosition?"ok":"unverified"),pinned:!0,candidates:r}}const a=r.find(t=>n.has(t.entityId)&&t.hasPosition&&"ok"===s[t.entityId]);return a?{entityId:a.entityId,status:"ok",pinned:!1,candidates:r}:{entityId:null,status:"none",pinned:!1,candidates:r}}(i?.source,o,a,l)}_vacSource(t){if(!1===t.marker?.vacuum?.live)return null;const e=this._vacSourceResolution(t);return"ok"===e.status||"unsupported"===e.status?e.entityId:null}_vacEntity(t){return t.primary?.startsWith("vacuum.")?t.primary:(t.entities||[]).find(t=>t.startsWith("vacuum."))||null}_isVacDev(t){return!!this._vacEntity(t)}_activitySourceKey(t){return Ho(this._planHass,t,!1!==this._config?.show_temperature)}_activitySnapshot(t){const e=Fo(this._planHass,t);return{samples:e.samples,sourceKey:Ho(this._planHass,t,!1!==this._config?.show_temperature,e)}}_stampActivity(t,e,i){let s=this._activityRt.get(t);s||(s={sources:i||"",last:{},flashTs:0,flashKind:null,timer:0,gen:0},this._activityRt.set(t,s)),null!=i&&(s.sources=i),s.flashTs&&Date.now()-s.flashTs<3300&&"event"===s.flashKind&&"transition"===e||(s.flashTs=Date.now(),s.flashKind=e,s.gen++,clearTimeout(s.timer),s.timer=window.setTimeout(()=>this.requestUpdate(),3360))}_syncActivityRuntime(){const t=new Map;if(!this.hass)return t;const e=new Set;for(const i of this._devices){if(i.hidden)continue;if("static_icon"===ui(i.marker?.display))continue;e.add(i.id);const s=this._activitySnapshot(i);t.set(i.id,s);const{samples:o,sourceKey:n}=s;let r=this._activityRt.get(i.id);if(r){if(r.sources!==n){clearTimeout(r.timer),r.sources=n,r.last={},r.flashTs=0,r.flashKind=null;for(const t of o)r.last[t.eid]=t.state}}else{r={sources:n,last:{},flashTs:0,flashKind:null,timer:0,gen:0};for(const t of o)r.last[t.eid]=t.state;this._activityRt.set(i.id,r)}}for(const[t,i]of this._activityRt)e.has(t)||(clearTimeout(i.timer),this._activityRt.delete(t));return t}_activityTick(){if(!this.hass)return;const t=this._syncActivityRuntime();for(const e of this._devices){if(e.hidden)continue;if("static_icon"===ui(e.marker?.display))continue;const i=t.get(e.id)||this._activitySnapshot(e),{samples:s,sourceKey:o}=i,n=this._activityRt.get(e.id);if(!n||n.sources!==o)continue;"transition"===n.flashKind&&s.some(t=>"transition"===t.activity)&&(clearTimeout(n.timer),n.flashTs=0,n.flashKind=null);let r=null;for(const t of s){const e=Is(n.last[t.eid],t);("event"===e||!r&&e)&&(r=e),n.last[t.eid]=t.state}r&&this._stampActivity(e.id,r,o)}}_vacTick(){if(this.hass)for(const t of this._devices){if(t.hidden||!this._isVacDev(t))continue;if("static_icon"===ui(t.marker?.display)){this._vacRt.delete(t.id);continue}const e=this._vacSource(t);if(!e)continue;const i=this._vacEntity(t),s=zl(this.hass.states[i||""]?.state),o=Cl(this.hass.states[e]?.attributes);let n=this._vacRt.get(t.id);n||(n={trail:[],lastKey:"",lastTs:0,moving:!1,jump:!1,endedTs:0,lastPos:null},this._vacRt.set(t.id,n)),s&&!n.moving&&(n.trail=[],n.lastPos=null);const r="never"!==Fl(t.marker?.vacuum)&&!o?.path.length;!s&&n.moving&&(n.endedTs=Date.now(),r&&n.lastPos&&(n.trail=Rl(n.trail,n.lastPos,40)),n.lastPos=null),n.moving=s;const a=o?.pos;if(s&&a){const t=a.x+":"+a.y;if(t!==n.lastKey){const e=Date.now();n.jump=n.lastTs>0&&e-n.lastTs>1e4,n.lastKey=t,n.lastTs=e,r&&n.lastPos&&(n.trail=Rl(n.trail,n.lastPos,40)),n.lastPos=[a.x,a.y]}}}}_vacEnsureMarker(t){const e=this._serverCfg;if(!e)return null;e.markers=e.markers||[];const i=e.markers.find(e=>e.id===t.id);if(i)return i;if("device"!==t.bindingKind&&"entity"!==t.bindingKind||!t.bindingRef)return null;const s={id:t.id,binding:t.bindingKind+":"+t.bindingRef,space:t.space||null,area:t.area||null,hidden:!!t.hidden};return e.markers.push(s),s}_renderVacSection(t){const e=this._devices.find(e=>e.id===t.devId);if(!e||!this._isVacDev(e))return W;const i=e.marker?.vacuum||{},s=this._vacAllCamerasFor===e.id,o=this._vacSourceResolution(e,s),n=o.entityId,r=o.candidates.find(t=>t.entityId===n)||null,a=n?Cl(this.hass?.states[n]?.attributes):null,l=!1!==i.live&&("ok"===o.status||"unsupported"===o.status),c=this._vacPlanRoomAnchors(e.space),h=a?function(t,e){const i=new Set(e.map(Tl).filter(Boolean)),s=new Set;for(const e of t){const t=Tl(e.name||"");t&&i.has(t)&&s.add(t)}return s.size}(a.rooms,c.map(t=>t.name)):0,d=!!(l&&a&&h>=3),p=Object.keys(i.calibration||{}),u=t=>{const i=this._vacEnsureMarker(e);i&&(i.vacuum={...i.vacuum||{},...t},this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate())},_=new Set(e.entities||[]),m=o.candidates.filter(t=>_.has(t.entityId)||t.entityId===i.source),g=s?o.candidates.filter(t=>t.entityId.startsWith("camera.")&&!m.some(e=>e.entityId===t.entityId)):[],f=t=>[t.hasPosition?this._t("vac.cap_position"):"",t.hasRooms?this._t("vac.cap_rooms_short"):"",t.hasPath?this._t("vac.cap_path"):"",t.hasMapId?this._t("vac.cap_map"):""].filter(Boolean).join(" · ")||this._t("vac.cap_none"),v=t=>j` + `}_vacCandidateStatus(t,e){const i=this._bindingStatus("entity:"+t);if("ha_disabled"===i.kind)return"disabled";if("orphaned"===i.kind)return"missing";if("unverified"===i.kind)return"unverified";const s=this.hass?.states?.[t];return"unavailable"===s?.state?"unavailable":e?.hasPosition?"ok":"unsupported"}_vacOpenAllCameras(t){const e=this._haRegistry.entities||{},i=[];for(const[t,s]of Object.entries(this.hass?.states||{})){if(!t.startsWith("camera."))continue;const o=ql(t,s,e[t]);o&&i.push(o)}this._vacAllCameraCache={devId:t.id,candidates:i},this._vacAllCamerasFor=t.id}_vacSourceResolution(t,e=!1){const i=t.marker?.vacuum,s="string"==typeof i?.source&&!!i.source,o=new Set(t.entities||[]),n=new Set(o);s&&n.add(i.source);const r=this._haRegistry.entities||{},a=[];for(const t of n){const e=this.hass?.states?.[t],o=ql(t,e,r[t]);o?a.push(o):s&&t===i.source&&a.push({entityId:t,name:String(e?.attributes?.friendly_name||t),platform:r[t]?.platform?String(r[t].platform):null,category:t.startsWith("camera.")?"camera":"partial",hasPosition:!1,hasRooms:!1,hasPath:!1,hasMapId:!1,score:0})}if(e&&this._vacAllCameraCache?.devId===t.id){const t=new Set(a.map(t=>t.entityId));for(const e of this._vacAllCameraCache.candidates)t.has(e.entityId)||a.push(e)}const l={};for(const t of a)l[t.entityId]=this._vacCandidateStatus(t.entityId,t);return function(t,e,i,s){const o="string"==typeof t&&t.length>0,n=new Set(e),r=Array.from(i).sort((e,i)=>o&&e.entityId===t?-1:o&&i.entityId===t?1:i.score-e.score||e.entityId.localeCompare(i.entityId));if(o){const e=r.find(e=>e.entityId===t);return{entityId:t,status:s[t]||(e?.hasPosition?"ok":"unverified"),pinned:!0,candidates:r}}const a=r.find(t=>n.has(t.entityId)&&t.hasPosition&&"ok"===s[t.entityId]);return a?{entityId:a.entityId,status:"ok",pinned:!1,candidates:r}:{entityId:null,status:"none",pinned:!1,candidates:r}}(i?.source,o,a,l)}_vacSource(t){if(!1===t.marker?.vacuum?.live)return null;const e=this._vacSourceResolution(t);return"ok"===e.status||"unsupported"===e.status?e.entityId:null}_vacEntity(t){return t.primary?.startsWith("vacuum.")?t.primary:(t.entities||[]).find(t=>t.startsWith("vacuum."))||null}_isVacDev(t){return!!this._vacEntity(t)}_activitySourceKey(t){return Yo(this._planHass,t,!1!==this._config?.show_temperature)}_activitySnapshot(t){const e=Wo(this._planHass,t);return{samples:e.samples,sourceKey:Yo(this._planHass,t,!1!==this._config?.show_temperature,e)}}_stampActivity(t,e,i){let s=this._activityRt.get(t);s||(s={sources:i||"",last:{},flashTs:0,flashKind:null,timer:0,gen:0},this._activityRt.set(t,s)),null!=i&&(s.sources=i),s.flashTs&&Date.now()-s.flashTs<3300&&"event"===s.flashKind&&"transition"===e||(s.flashTs=Date.now(),s.flashKind=e,s.gen++,clearTimeout(s.timer),s.timer=window.setTimeout(()=>this.requestUpdate(),3360))}_syncActivityRuntime(){const t=new Map;if(!this.hass)return t;const e=new Set;for(const i of this._devices){if(i.hidden)continue;if("static_icon"===Si(i.marker?.display))continue;e.add(i.id);const s=this._activitySnapshot(i);t.set(i.id,s);const{samples:o,sourceKey:n}=s;let r=this._activityRt.get(i.id);if(r){if(r.sources!==n){clearTimeout(r.timer),r.sources=n,r.last={},r.flashTs=0,r.flashKind=null;for(const t of o)r.last[t.eid]=t.state}}else{r={sources:n,last:{},flashTs:0,flashKind:null,timer:0,gen:0};for(const t of o)r.last[t.eid]=t.state;this._activityRt.set(i.id,r)}}for(const[t,i]of this._activityRt)e.has(t)||(clearTimeout(i.timer),this._activityRt.delete(t));return t}_activityTick(){if(!this.hass)return;const t=this._syncActivityRuntime();for(const e of this._devices){if(e.hidden)continue;if("static_icon"===Si(e.marker?.display))continue;const i=t.get(e.id)||this._activitySnapshot(e),{samples:s,sourceKey:o}=i,n=this._activityRt.get(e.id);if(!n||n.sources!==o)continue;"transition"===n.flashKind&&s.some(t=>"transition"===t.activity)&&(clearTimeout(n.timer),n.flashTs=0,n.flashKind=null);let r=null;for(const t of s){const e=Bs(n.last[t.eid],t);("event"===e||!r&&e)&&(r=e),n.last[t.eid]=t.state}r&&this._stampActivity(e.id,r,o)}}_vacTick(){if(this.hass)for(const t of this._devices){if(t.hidden||!this._isVacDev(t))continue;if("static_icon"===Si(t.marker?.display)){this._vacRt.delete(t.id);continue}const e=this._vacSource(t);if(!e)continue;const i=this._vacEntity(t),s=Gl(this.hass.states[i||""]?.state),o=Hl(this.hass.states[e]?.attributes);let n=this._vacRt.get(t.id);n||(n={trail:[],lastKey:"",lastTs:0,moving:!1,jump:!1,endedTs:0,lastPos:null},this._vacRt.set(t.id,n)),s&&!n.moving&&(n.trail=[],n.lastPos=null);const r="never"!==Jl(t.marker?.vacuum)&&!o?.path.length;!s&&n.moving&&(n.endedTs=Date.now(),r&&n.lastPos&&(n.trail=jl(n.trail,n.lastPos,40)),n.lastPos=null),n.moving=s;const a=o?.pos;if(s&&a){const t=a.x+":"+a.y;if(t!==n.lastKey){const e=Date.now();n.jump=n.lastTs>0&&e-n.lastTs>1e4,n.lastKey=t,n.lastTs=e,r&&n.lastPos&&(n.trail=jl(n.trail,n.lastPos,40)),n.lastPos=[a.x,a.y]}}}}_vacEnsureMarker(t){const e=this._serverCfg;if(!e)return null;e.markers=e.markers||[];const i=e.markers.find(e=>e.id===t.id);if(i)return i;if("device"!==t.bindingKind&&"entity"!==t.bindingKind||!t.bindingRef)return null;const s={id:t.id,binding:t.bindingKind+":"+t.bindingRef,space:t.space||null,area:t.area||null,hidden:!!t.hidden};return e.markers.push(s),s}_renderVacSection(t){const e=this._devices.find(e=>e.id===t.devId);if(!e||!this._isVacDev(e))return W;const i=e.marker?.vacuum||{},s=this._vacAllCamerasFor===e.id,o=this._vacSourceResolution(e,s),n=o.entityId,r=o.candidates.find(t=>t.entityId===n)||null,a=n?Hl(this.hass?.states[n]?.attributes):null,l=!1!==i.live&&("ok"===o.status||"unsupported"===o.status),c=this._vacPlanRoomAnchors(e.space),h=a?function(t,e){const i=new Set(e.map(Ul).filter(Boolean)),s=new Set;for(const e of t){const t=Ul(e.name||"");t&&i.has(t)&&s.add(t)}return s.size}(a.rooms,c.map(t=>t.name)):0,d=!!(l&&a&&h>=3),p=Object.keys(i.calibration||{}),u=t=>{const i=this._vacEnsureMarker(e);i&&(i.vacuum={...i.vacuum||{},...t},this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate())},_=new Set(e.entities||[]),m=o.candidates.filter(t=>_.has(t.entityId)||t.entityId===i.source),g=s?o.candidates.filter(t=>t.entityId.startsWith("camera.")&&!m.some(e=>e.entityId===t.entityId)):[],f=t=>[t.hasPosition?this._t("vac.cap_position"):"",t.hasRooms?this._t("vac.cap_rooms_short"):"",t.hasPath?this._t("vac.cap_path"):"",t.hasMapId?this._t("vac.cap_map"):""].filter(Boolean).join(" · ")||this._t("vac.cap_none"),v=t=>B` `,y=o.candidates.some(t=>_.has(t.entityId)&&"known_xcme_incomplete"===t.category)||!!o.pinned&&!!n?.startsWith("camera.")&&!r?.hasPosition;return j` + `,y=o.candidates.some(t=>_.has(t.entityId)&&"known_xcme_incomplete"===t.category)||!!o.pinned&&!!n?.startsWith("camera.")&&!r?.hasPosition;return B`
${this._t("vac.diag_source")}${n||this._t("vac.source_none")}
- ${r?.platform?j`
${this._t("vac.diag_platform")}${r.platform}
`:W} + ${r?.platform?B`
${this._t("vac.diag_platform")}${r.platform}
`:W}
${this._t("vac.diag_status")}${this._t(`vac.source_status_${o.status}`)}
${this._t("vac.diag_position")}${a?.pos?this._t("common.yes"):this._t("common.no")}
-
${this._t("vac.diag_rooms")}${Ri(this._t("vac.diag_rooms_value"),{total:String(a?.rooms.length||0),matched:String(h),readiness:this._t(h>=3?"vac.autocal_ready":"vac.autocal_not_ready")})}
+
${this._t("vac.diag_rooms")}${Bi(this._t("vac.diag_rooms_value"),{total:String(a?.rooms.length||0),matched:String(h),readiness:this._t(h>=3?"vac.autocal_ready":"vac.autocal_not_ready")})}
${this._t("vac.diag_path")}${a?.path.length?this._t("common.yes"):this._t("common.no")}
${this._t("vac.diag_map")}${a?.mapId??"default"}
- ${"missing"===o.status||"disabled"===o.status||"unverified"===o.status?j`
+ ${"missing"===o.status||"disabled"===o.status||"unverified"===o.status?B`
${this._t(`vac.source_banner_${o.status}`)}
`:W} - ${y?j`
+ ${y?B`
${this._t("vac.xcme_hint")}
attributes:
   - vacuum_position
@@ -4631,17 +4725,17 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="fc04a319d946937a0d7fb1f2df149fb0fe51
               @toggle=${t=>{t.currentTarget.open?this._vacOpenAllCameras(e):(this._vacAllCamerasFor=null,this._vacAllCameraCache=null)}}>
               ${this._t("vac.all_cameras")}
               
${this._t("vac.all_cameras_warn")}
- ${s?g.length?g.map(v):j`
${this._t("vac.all_cameras_empty")}
`:W} + ${s?g.length?g.map(v):B`
${this._t("vac.all_cameras_empty")}
`:W}
- ${d?j``:W} - ${l?j``:W} + ${d?B``:W} + ${l?B``:W} ${this._t("vac.documentation")}
- ${a?j` + ${a?B`